From fa5144db5e0fe8317449953ae431338def1a8432 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 31 Jan 2025 14:56:18 +0000 Subject: [PATCH 01/21] Remove old Gadget and GadgetContainerMessage --- Dockerfile | 4 ++-- conda/build.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0b74d5b0..a00e8f8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -100,7 +100,7 @@ RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ - ninja && \ + ninja -j6 && \ ninja install FROM pingvin_dev_nocuda AS pingvin_build_nocuda @@ -115,7 +115,7 @@ RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ - ninja && \ + ninja -j6 && \ ninja install FROM pingvin_baseimage AS pingvin_rt_cuda diff --git a/conda/build.sh b/conda/build.sh index 9b7848a9..3c97a7dc 100755 --- a/conda/build.sh +++ b/conda/build.sh @@ -12,4 +12,4 @@ cmake -GNinja \ -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ ../ -ninja install +ninja -j6 install From be0deb325c2bac754f175de83671a292bdc54cc5 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 9 Jan 2025 18:05:34 +0000 Subject: [PATCH 02/21] Add emperor, a new prototype CLI --- apps/CMakeLists.txt | 2 + apps/emperor/CMakeLists.txt | 53 ++++++ apps/emperor/main.cc | 153 ++++++++++++++++ apps/emperor/pipelines/cartesian_grappa.h | 19 ++ apps/emperor/pipelines/default.h | 28 +++ apps/emperor/pipelines/noise.h | 18 ++ apps/emperor/pipelines/pipeline.h | 169 ++++++++++++++++++ apps/pingvin/CMakeLists.txt | 6 +- apps/pingvin/StreamConsumer.h | 42 ++++- apps/pingvin/main.cpp | 4 +- apps/pingvin/nodes/Parallel.h | 1 + apps/pingvin/nodes/ParallelProcess.h | 4 + apps/pingvin/nodes/PureStream.h | 1 + apps/pingvin/nodes/Stream.cpp | 2 - apps/pingvin/nodes/Stream.h | 5 +- apps/pingvin/system_info.cpp | 10 +- apps/pingvin/system_info.h | 4 +- core/Node.h | 24 +++ core/PropertyMixin.h | 8 +- gadgets/mri_core/NoiseAdjustGadget.cpp | 45 ++++- gadgets/mri_core/NoiseAdjustGadget.h | 21 ++- .../mri_core/RemoveROOversamplingGadget.cpp | 38 +++- gadgets/mri_core/RemoveROOversamplingGadget.h | 10 +- test/CMakeLists.txt | 1 + 24 files changed, 637 insertions(+), 31 deletions(-) create mode 100644 apps/emperor/CMakeLists.txt create mode 100644 apps/emperor/main.cc create mode 100644 apps/emperor/pipelines/cartesian_grappa.h create mode 100644 apps/emperor/pipelines/default.h create mode 100644 apps/emperor/pipelines/noise.h create mode 100644 apps/emperor/pipelines/pipeline.h diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index f09b2532..5c8d343a 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1 +1,3 @@ add_subdirectory(pingvin) + +add_subdirectory(emperor) \ No newline at end of file diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt new file mode 100644 index 00000000..f70e576c --- /dev/null +++ b/apps/emperor/CMakeLists.txt @@ -0,0 +1,53 @@ +configure_file(../pingvin/pingvin_config.in pingvin_config.h) + +add_executable(emperor + main.cc + + ../pingvin/Config.cpp + ../pingvin/Config.h + + ../../gadgets/mri_core/NoiseAdjustGadget.cpp + ../../gadgets/mri_core/RemoveROOversamplingGadget.cpp + + ../pingvin/StreamConsumer.h + + ../pingvin/ErrorHandler.h + + ../pingvin/nodes/Processable.h + ../pingvin/nodes/Processable.cpp + + ../pingvin/nodes/Stream.cpp + ../pingvin/nodes/Stream.h + ../pingvin/nodes/Parallel.cpp + ../pingvin/nodes/Parallel.h + ../pingvin/nodes/ParallelProcess.cpp + ../pingvin/nodes/ParallelProcess.h + ../pingvin/nodes/PureStream.cpp + ../pingvin/nodes/PureStream.h + ) + +# target_link_libraries(emperor +# # Boost::system +# # Boost::filesystem +# Boost::program_options +# ) +target_link_libraries(emperor + pingvin_core + pingvin_toolbox_log + pingvin_toolbox_mri_core + # pingvin_mricore + Boost::system + Boost::filesystem + Boost::program_options + ${PUGIXML_LIBRARIES} + GTBLAS) + +target_include_directories(emperor + PRIVATE + ${CMAKE_SOURCE_DIR}/apps/pingvin + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR} + ) + +install(TARGETS emperor DESTINATION bin COMPONENT main) \ No newline at end of file diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc new file mode 100644 index 00000000..dbef0883 --- /dev/null +++ b/apps/emperor/main.cc @@ -0,0 +1,153 @@ +#include "pipelines/noise.h" +#include "pipelines/cartesian_grappa.h" +#include "pipelines/default.h" + +#include "log.h" +#include "system_info.h" + +#include + +#include +#include +#include + +using namespace pingvin; + +namespace po = boost::program_options; +namespace fs = std::filesystem; + +int main(int argc, char** argv) +{ + po::options_description global("Global options"); + + std::filesystem::path pingvin_home("/tmp/pingvin"); + global.add_options() + ("help,h", "Prints this help message.") + ("info", "Prints build info about Pingvin.") + ("home,G", + po::value()->default_value(pingvin_home), + "Set the Pingvin home directory.") + ; + + po::options_description hidden("Hidden options"); + hidden.add_options() + ("pipeline", po::value(), "Pipeline to run.") + ("subargs", po::value>(), "Arguments for the pipeline.") + ; + + po::options_description help_options; + help_options.add(global); + + po::options_description allowed_options; + allowed_options.add(global).add(hidden); + + po::positional_options_description pos; + pos.add("pipeline", 1) + .add("subargs", -1); + + po::variables_map vm; + std::vector unrecognized; + try { + po::parsed_options parsed = po::basic_command_line_parser(argc, argv) + .options(allowed_options) + .positional(pos) + .allow_unregistered() + .run(); + po::store(parsed, vm); + po::notify(vm); + + // Collect all the unrecognized options from the first pass. This will include the + // (positional) command name, so we need to erase that. + unrecognized = po::collect_unrecognized(parsed.options, po::include_positional); + // Actually, it's not necessary... + // unrecognized.erase(unrecognized.begin()); + } catch (po::error& e) { + std::cerr << e.what() << std::endl; + return 1; + } + + if (vm.count("info")) { + std::cerr << "Pingvin Info: ..." << std::endl; + return 0; + } + + // "Register" all Pipelines + std::vector> pipelines; + pipelines.push_back(std::make_shared()); + pipelines.push_back(std::make_shared()); + pipelines.push_back(std::make_shared()); + std::map> pipeline_map; + for (auto& pipeline : pipelines) { + pipeline_map[pipeline->name()] = pipeline; + } + + if (!vm.count("pipeline")) { + if (vm.count("help")) { + fs::path progpath(argv[0]); + std::cerr << "Usage: " << progpath.filename().string() << " [global options] [pipeline options]" + << std::endl; + std::cerr << help_options << std::endl; + std::cerr << "Pipelines:" << std::endl; + for (auto& pipeline : pipelines) { + std::cerr << "┌ " << pipeline->name() << std::endl << "└──── " << pipeline->description() << std::endl; + } + return 0; + } else { + std::cerr << "No pipeline specified" << std::endl; + + return 1; + } + } + + std::string subcmd = vm["pipeline"].as(); + if (!pipeline_map.count(subcmd)) { + std::cerr << "Unknown pipeline: " << subcmd << std::endl; + return 1; + } + std::cerr << "You chose pipeline: " << subcmd << std::endl; + auto& pipeline = pipeline_map[subcmd]; + + pipeline->build(); + + po::options_description pipeline_desc("Pipeline Options"); + pipeline->install_cli(pipeline_desc); + + try { + // Parse again for Pipeline + po::parsed_options parsed = po::basic_command_line_parser(unrecognized).options(pipeline_desc).run(); + po::store(parsed, vm); + + if (vm.count("help")) { + std::cerr << pipeline->name() << ":" << std::endl << " " << pipeline->description() << std::endl << std::endl; + std::cerr << pipeline_desc << std::endl; + return 0; + } + + po::store(po::parse_environment(pipeline_desc, "PINGVIN_"), vm); + + if (vm.count("config")) { + auto config_filename = vm["config"].as(); + std::ifstream config_file(config_filename); + if (!config_file) { + std::cerr << "Could not open config file: " << config_filename << std::endl; + return 1; + } + po::store(po::parse_config_file(config_file, pipeline_desc), vm); + } + + po::notify(vm); + } + catch (po::error &e) + { + std::cerr << e.what() << std::endl; + return 1; + } + + std::cerr << "Pingvin Home: " << vm["home"].as() << std::endl; + + pipeline->run(vm); + + std::cout << "Pingvin finished successfully" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h new file mode 100644 index 00000000..32992cde --- /dev/null +++ b/apps/emperor/pipelines/cartesian_grappa.h @@ -0,0 +1,19 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" + +namespace pingvin { + +class CartesianGrappa : public Pipeline { + public: + CartesianGrappa() : Pipeline("cartesian-grappa", "Cartesian Grappa Recon") { } + + void build(void) override { + gadgets_.push_back(std::make_shared()); + // gadgets_.push_back(std::make_unique()); + } +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h new file mode 100644 index 00000000..e98c0bd1 --- /dev/null +++ b/apps/emperor/pipelines/default.h @@ -0,0 +1,28 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" + +namespace pingvin { + +class Default : public Pipeline { + public: + Default() : Pipeline("default", "Basic Cartesian Reconstruction") { } + + void build(void) override { + // gadgets_.push_back(std::make_shared()); + // gadgets_.push_back(std::make_shared()); + + // gadgets_ = Builder() + // .append() + // .append() + // .build(); + + this->append(); + this->append(); + } +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/noise.h b/apps/emperor/pipelines/noise.h new file mode 100644 index 00000000..14a65b05 --- /dev/null +++ b/apps/emperor/pipelines/noise.h @@ -0,0 +1,18 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" + +namespace pingvin { + +class NoiseDependency: public Pipeline { + public: + NoiseDependency() : Pipeline("noise", "Noise covariance computation") { } + + void build(void) override { + gadgets_.push_back(std::make_shared()); + } +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h new file mode 100644 index 00000000..2c965c36 --- /dev/null +++ b/apps/emperor/pipelines/pipeline.h @@ -0,0 +1,169 @@ +#pragma once + +#include + +#include +namespace po = boost::program_options; + +#include "StreamConsumer.h" + +namespace pingvin { + +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; +} + +class Pipeline { + public: + Pipeline(std::string name, std::string description) : name_(name), description_(description) {} + virtual ~Pipeline() = default; + + using TempGadget = NewChannelGadget; + + // class Builder { + // public: + // Builder() {} + + // template + // Builder& append(void) { + // auto n = std::make_shared(); + // nodes_.push_back(n); + // return *this; + // } + + // std::vector> build(void) { + // return nodes_; + // } + + // template + // T build_pipeline(std::string name, std::string description) { + // // T p(name, description); + // T p; + // p.gadgets_ = nodes_; + // return std::move(p); + // } + + // private: + // std::vector> nodes_; + // }; + + virtual void build(void) = 0; + + void run(po::variables_map& vm) { + std::cerr << "Running pipeline " << name_ << std::endl; + // for (auto& g: gadgets_) { + // g->process(); + // } + + std::cerr << "OK, now running Pingvin" << std::endl; + + std::unique_ptr input_file; + if (vm.count("input")) { + input_file = std::make_unique(vm["input"].as()); + if (!input_file->good()) { + GERROR_STREAM("Could not open input file: " << vm["input"].as()); + } + } + + std::unique_ptr output_file; + if (vm.count("output")) { + output_file = std::make_unique(vm["output"].as()); + if (!output_file->good()) { + GERROR_STREAM("Could not open output file: " << vm["output"].as()); + } + } + + std::istream& input_stream = input_file ? *input_file : std::cin; + std::ostream& output_stream = output_file ? *output_file : std::cout; + + Context::Paths paths{ + (vm.count("home")) + ? vm["home"].as().string() + : "/opt/pingvin" + }; + + mrd::binary::MrdReader mrd_reader(input_stream); + mrd::binary::MrdWriter mrd_writer(output_stream); + + StreamConsumer consumer(vm); + mrd::Header hdr = consumer.consume_mrd_header(mrd_reader, mrd_writer); + + auto context = StreamContext(hdr, paths, vm); + + GDEBUG_STREAM("Initializing Gadgets"); + for (auto& g : gadgets_) { + g->initialize(context, GadgetProperties()); + } + GDEBUG_STREAM("Initialized Gadgets"); + + auto stream = std::make_unique(processables_); + consumer.consume_stream(mrd_reader, mrd_writer, stream); + + std::flush(output_stream); + + GDEBUG_STREAM("Finished consuming stream"); + } + + void install_cli(po::options_description& desc) { + desc.add_options() + ("help,h", "Show help message") + ("config,c", po::value(), "Pipeline configuration file") + ("input,i", po::value(), "Input stream") + ("output,o", po::value(), "Output stream") + // TODO: Remove this once all Gadgets no longer use `parameters` + ("parameter", + po::value>(), + "Parameter to be passed to the Pingvin reconstruction config. Multiple parameters can be passed." + "Format: --parameter = --parameter = ..."); + ; + + po::options_description gadgets("Pipeline Nodes"); + + for (auto& g: gadgets_) { + po::options_description group(g->name()); + g->install_cli(group); + gadgets.add(group); + } + + desc.add(gadgets); + } + + std::string name(void) const { return name_; } + std::string description(void) const { return description_; } + + protected: + + template + void append(void) { + auto n = std::make_shared(); + gadgets_.push_back(n); + processables_.push_back(std::make_shared(n, "TODO")); + } + + // template + // void appendParallel() + + std::string name_; + std::string description_; + + std::vector> gadgets_; + std::vector> processables_; +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 6a829bd9..3d42726a 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -14,6 +14,8 @@ add_executable(pingvin Config.cpp Config.h + StreamConsumer.h + ErrorHandler.h nodes/Processable.h @@ -43,7 +45,9 @@ target_link_libraries(pingvin target_include_directories(pingvin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}) + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR} + ) if (REQUIRE_SIGNED_CONFIG) diff --git a/apps/pingvin/StreamConsumer.h b/apps/pingvin/StreamConsumer.h index 1c4c983a..67eb7984 100644 --- a/apps/pingvin/StreamConsumer.h +++ b/apps/pingvin/StreamConsumer.h @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -14,12 +13,15 @@ #include "ErrorHandler.h" #include "Loader.h" +#include "Node.h" + +#include "pingvin_config.h" + using namespace Gadgetron::Core; using namespace Gadgetron::Main; namespace { - class ErrorThrower : public ErrorReporter { public: @@ -41,6 +43,26 @@ std::filesystem::path find_config_path(const std::string& home_dir, const std::s return config_path; } + class NewNodeProcessable : public Processable { + public: + NewNodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} + + void process(GenericInputChannel input, + OutputChannel output, + ErrorHandler & + ) override { + node_->process(input, output); + } + + const std::string& name() override { + return name_; + } + + private: + std::shared_ptr node_; + const std::string name_; + }; + } // namespace class StreamConsumer @@ -53,7 +75,9 @@ class StreamConsumer void consume(std::istream& input_stream, std::ostream& output_stream, std::string config_xml_name) { Context::Paths paths{ - args_["home"].as().string() + (args_.count("home")) + ? args_["home"].as().string() + : "/opt/pingvin" }; mrd::binary::MrdReader mrd_reader(input_stream); @@ -63,7 +87,7 @@ class StreamConsumer auto context = StreamContext(hdr, paths, args_); auto loader = Loader(context); - auto config_path = find_config_path(args_["home"].as().string(), config_xml_name); + 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); @@ -73,8 +97,13 @@ class StreamConsumer auto config = Config::parse(file); file.close(); - auto stream = loader.load(config.stream); + + consume_stream(mrd_reader, mrd_writer, stream); + } + + void consume_stream(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer, const std::unique_ptr& stream) + { auto input_channel = make_channel(); auto output_channel = make_channel(); std::atomic processing = true; @@ -121,7 +150,6 @@ class StreamConsumer process_future.get(); } - private: mrd::Header consume_mrd_header(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer) { @@ -136,6 +164,8 @@ class StreamConsumer return hdr.value(); } + private: + void consume_input_stream(mrd::binary::MrdReader& mrd_reader, ChannelPair& input_channel) { mrd::StreamItem stream_item; diff --git a/apps/pingvin/main.cpp b/apps/pingvin/main.cpp index 0757ff5b..d8a12e01 100644 --- a/apps/pingvin/main.cpp +++ b/apps/pingvin/main.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include "log.h" @@ -12,7 +12,7 @@ #include "StreamConsumer.h" -using namespace boost::filesystem; +using namespace std::filesystem; using namespace boost::program_options; using namespace Gadgetron::Main; diff --git a/apps/pingvin/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h index 45d358fe..49d84613 100644 --- a/apps/pingvin/nodes/Parallel.h +++ b/apps/pingvin/nodes/Parallel.h @@ -19,6 +19,7 @@ namespace Gadgetron::Main::Nodes { using Merge = Core::Parallel::Merge; public: + Parallel(const Config::Parallel &, const Core::StreamContext &) {} Parallel(const Config::Parallel &, const Core::StreamContext &, Loader &); void process( diff --git a/apps/pingvin/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h index 21d8a527..9582770e 100644 --- a/apps/pingvin/nodes/ParallelProcess.h +++ b/apps/pingvin/nodes/ParallelProcess.h @@ -9,7 +9,11 @@ namespace Gadgetron::Main::Nodes { class ParallelProcess : public Processable { public: + ParallelProcess(const Config::ParallelProcess& conf, const Core::Context& context) + : pureStream{ conf.stream, context }, workers{ conf.workers } {} + ParallelProcess(const Config::ParallelProcess& conf, const Core::Context& context, Loader& loader); + void process(Core::GenericInputChannel input, Core::OutputChannel output, ErrorHandler& error_handler) override; const std::string& name() override; private: diff --git a/apps/pingvin/nodes/PureStream.h b/apps/pingvin/nodes/PureStream.h index c861271d..b9660962 100644 --- a/apps/pingvin/nodes/PureStream.h +++ b/apps/pingvin/nodes/PureStream.h @@ -7,6 +7,7 @@ namespace Gadgetron::Main::Nodes { class PureStream { public: + PureStream(const Config::PureStream&, const Core::Context&) {} PureStream(const Config::PureStream&, const Core::Context&, Loader&); Core::Message process_function(Core::Message) const; diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp index fbdebb99..2e69f9f8 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -4,8 +4,6 @@ #include "ParallelProcess.h" #include "Processable.h" -#include "Loader.h" - #include "Node.h" namespace { diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h index cbeb35ca..6977330a 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -20,7 +20,10 @@ namespace Gadgetron::Main::Nodes { class Stream : public Processable { public: const std::string key; - Stream(const Config::Stream &, const Core::StreamContext &, Loader &); + Stream(const Config::Stream& config, const Core::StreamContext&) : key(config.key) {} + Stream(const Config::Stream&, const Core::StreamContext&, Loader &); + + Stream(std::vector> nodes): nodes(std::move(nodes)), key("TODO") {} void process( Core::GenericInputChannel input, diff --git a/apps/pingvin/system_info.cpp b/apps/pingvin/system_info.cpp index c7ac99f6..e68073a7 100644 --- a/apps/pingvin/system_info.cpp +++ b/apps/pingvin/system_info.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #if defined(BSD) #include @@ -212,19 +212,19 @@ namespace Gadgetron::Main::Info { #endif } // namespace - const boost::filesystem::path default_pingvin_home() { + const std::filesystem::path default_pingvin_home() { const char *home = std::getenv("PINGVIN_HOME"); if (home != nullptr) { - return boost::filesystem::path(home); + return std::filesystem::path(home); } - boost::filesystem::path executable_path = get_executable_path(); + std::filesystem::path executable_path = get_executable_path(); GDEBUG_STREAM("Executable path: " << executable_path); - boost::filesystem::path pingvin_home = executable_path + std::filesystem::path pingvin_home = executable_path .parent_path() .parent_path(); diff --git a/apps/pingvin/system_info.h b/apps/pingvin/system_info.h index 6f58aac7..46dbd0c8 100644 --- a/apps/pingvin/system_info.h +++ b/apps/pingvin/system_info.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace Gadgetron::Main::Info { @@ -14,7 +14,7 @@ namespace Gadgetron::Main::Info { bool python_support(); bool matlab_support(); - const boost::filesystem::path default_pingvin_home(); + const std::filesystem::path default_pingvin_home(); namespace CUDA { bool cuda_support(); diff --git a/core/Node.h b/core/Node.h index 091c0b86..c01c30ca 100644 --- a/core/Node.h +++ b/core/Node.h @@ -5,6 +5,7 @@ #include "Context.h" #include +namespace po = boost::program_options; namespace Gadgetron::Core { /** @@ -57,6 +58,29 @@ namespace Gadgetron::Core { virtual void process(InputChannel& in, OutputChannel& out) = 0; }; + template class NewChannelGadget : public ChannelGadget { + public: + using ChannelGadget::ChannelGadget; + + NewChannelGadget(): ChannelGadget(Context{}, GadgetProperties{}) { + GDEBUG_STREAM("NewChannelGadget created"); + } + + virtual void install_cli(po::options_description& options) = 0; + + void initialize(const Core::Context& context, const GadgetProperties& properties) { + // this->context = context; + this->properties = properties; + this->initialize_(context); + } + + virtual std::string name() { return "Unnamed"; } + virtual std::string description() { return "Unknown description"; } + + protected: + virtual void initialize_(const Context& context) = 0; + }; + } #define GADGETRON_GADGET_EXPORT(GadgetClass) \ diff --git a/core/PropertyMixin.h b/core/PropertyMixin.h index d3678d9b..f8b3fdcc 100644 --- a/core/PropertyMixin.h +++ b/core/PropertyMixin.h @@ -20,8 +20,10 @@ namespace Gadgetron::Core { return IO::from_string(properties.at(name)); } - private: - const GadgetProperties properties; + /** TODO: These are no longer private or const, so they can be initialized *after* the Node has been constructed */ + // private: + // const GadgetProperties properties; + GadgetProperties properties; }; template<> @@ -32,4 +34,4 @@ namespace Gadgetron::Core { } #define NODE_PROPERTY(NAME, TYPE, DESCRIPTION, DEFAULT) const TYPE NAME = this->template get_property(#NAME, DEFAULT, DESCRIPTION) -#define NODE_PROPERTY_NON_CONST(NAME, TYPE, DESCRIPTION, DEFAULT) TYPE NAME = this->template get_property(#NAME, DEFAULT, DESCRIPTION) +#define NODE_PROPERTY_NON_CONST(NAME, TYPE, DESCRIPTION, DEFAULT) TYPE NAME = this->template get_property(#NAME, DEFAULT, DESCRIPTION) \ No newline at end of file diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index af171eec..83778624 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -18,8 +18,12 @@ #include #include +#include + + using namespace std::string_literals; namespace bf = boost::filesystem; +namespace po = boost::program_options; namespace Gadgetron { namespace { @@ -177,8 +181,45 @@ namespace Gadgetron { } } + void NoiseAdjustGadget::install_cli(po::options_description& options) { + // TODO + options.add_options() + ("noisecovariancein", po::value(&noise_covariance_in), "Input noise covariance matrix") + ("noisecovarianceout", po::value(&noise_covariance_out), "Output noise covariance matrix") + ; + } + + void NoiseAdjustGadget::initialize_(const Core::Context& context) { + this->current_mrd_header = context.header; + this->receiver_noise_bandwidth = bandwidth_from_header(context.header); + this->measurement_id = measurement_id_from_header(context.header); + + if (!perform_noise_adjust) + return; + + GDEBUG("perform_noise_adjust_ is %d\n", perform_noise_adjust); + GDEBUG("pass_nonconformant_data_ is %d\n", pass_nonconformant_data); + GDEBUG("receiver_noise_bandwidth_ is %f\n", receiver_noise_bandwidth); + +#ifdef USE_OMP + omp_set_num_threads(1); +#endif // USE_OMP + + // if (context.parameters.find("noisecovariancein") != context.parameters.end()) { + // noise_covariance_in = context.parameters.at("noisecovariancein"); + // GDEBUG_STREAM("Input noise covariance matrix is provided as a parameter: " << noise_covariance_in); + // } + + // if (context.parameters.find("noisecovarianceout") != context.parameters.end()) { + // noise_covariance_out = context.parameters.at("noisecovarianceout"); + // GDEBUG_STREAM("Output noise covariance matrix is provided as a parameter: " << noise_covariance_out); + // } + + noisehandler = load_or_gather(); + } + NoiseAdjustGadget::NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) + : Core::NewChannelGadget(context, props) , current_mrd_header(context.header) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } , measurement_id{ measurement_id_from_header(context.header) } @@ -421,6 +462,6 @@ namespace Gadgetron { return std::nullopt; } - GADGETRON_GADGET_EXPORT(NoiseAdjustGadget) +GADGETRON_GADGET_EXPORT(NoiseAdjustGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index b1572c5a..4d24828e 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -26,27 +26,40 @@ namespace Gadgetron { struct IgnoringNoise {}; - class NoiseAdjustGadget : public Core::ChannelGadget { + // class NoiseAdjustGadget : public Core::ChannelGadget { + class NoiseAdjustGadget : public Core::NewChannelGadget { public: + NoiseAdjustGadget(): Core::NewChannelGadget() {} + NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props); + void install_cli(po::options_description& options) override; + void process(Core::InputChannel& in, Core::OutputChannel& out) override; using NoiseHandler = std::variant; + virtual std::string name() override { return "NoiseAdjustGadget"; } + virtual std::string description() override { return "Adjusts noise in the data"; } + protected: NODE_PROPERTY(perform_noise_adjust, bool, "Whether to actually perform the noise adjust", true); NODE_PROPERTY(pass_nonconformant_data, bool, "Whether to pass data that does not conform", true); NODE_PROPERTY(noise_dwell_time_us_preset, float, "Preset dwell time for noise measurement", 0.0); NODE_PROPERTY(scale_only_channels_by_name, std::string, "List of named channels that should only be scaled", ""); - const float receiver_noise_bandwidth; + void initialize_(const Core::Context& context) override; + + // const float receiver_noise_bandwidth; + float receiver_noise_bandwidth; - const std::string measurement_id; + // const std::string measurement_id; + std::string measurement_id; std::vector scale_only_channels; // We will store/load a copy of the noise scans XML header to enable us to check which coil layout, etc. - const mrd::Header current_mrd_header; + // const mrd::Header current_mrd_header; + mrd::Header current_mrd_header; NoiseHandler noisehandler = IgnoringNoise{}; diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index 9c5f79d7..5d758517 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -6,7 +6,7 @@ namespace Gadgetron { RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) { + : Core::NewChannelGadget(context, props) { auto h = (context.header); if (h.encoding.size() == 0) { @@ -83,6 +83,42 @@ void RemoveROOversamplingGadget::process(Core::InputChannel& i } } +void RemoveROOversamplingGadget::install_cli(po::options_description& options) { + // TODO +} + +void RemoveROOversamplingGadget::initialize_(const Core::Context& context) { + auto h = (context.header); + + if (h.encoding.size() == 0) { + GDEBUG("Number of encoding spaces: %d\n", h.encoding.size()); + GERROR("This Gadget needs an encoding description\n"); + return; + } + + mrd::EncodingSpaceType e_space = h.encoding[0].encoded_space; + mrd::EncodingSpaceType r_space = h.encoding[0].recon_space; + + encodeNx_ = e_space.matrix_size.x; + encodeFOV_ = e_space.field_of_view_mm.x; + reconNx_ = r_space.matrix_size.x; + reconFOV_ = r_space.field_of_view_mm.x; + +#ifdef USE_OMP // TODO: Should this be removed? Its from the old version + omp_set_num_threads(1); + GDEBUG_STREAM("RemoveROOversamplingGadget:omp_set_num_threads(1) ... "); +#endif // USE_OMP + + // If the encoding and recon matrix size and FOV are the same + // then the data is not oversampled and we can safely pass + // the data onto the next gadget + if ((encodeNx_ == reconNx_) && (encodeFOV_ == reconFOV_)) { + dowork_ = false; + } else { + dowork_ = true; + } +} + GADGETRON_GADGET_EXPORT(RemoveROOversamplingGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index 1916c2ca..e26d0980 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -13,14 +13,20 @@ #endif // USE_OMP namespace Gadgetron { -class RemoveROOversamplingGadget : public Core::ChannelGadget { +class RemoveROOversamplingGadget : public Core::NewChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; + using Core::NewChannelGadget::NewChannelGadget; + + RemoveROOversamplingGadget() {}; RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props); ~RemoveROOversamplingGadget() override = default; void process(Core::InputChannel& input, Core::OutputChannel& output) override; + void install_cli(po::options_description& options) override; + protected: + void initialize_(const Core::Context& context) override; + hoNDArray> fft_res_; hoNDArray> ifft_res_; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b97d8cf4..b3c06064 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -78,6 +78,7 @@ target_link_libraries(test_all pingvin_toolbox_cpusdc ${GTEST_LIBRARIES} GTest::gmock + Boost::program_options ) if (BUILD_PYTHON_SUPPORT) From bc90bdb7583b30f51bea9d98fd3b238fa86a8ee2 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 9 Jan 2025 23:52:17 +0000 Subject: [PATCH 03/21] Implement default.xml in emperor --- apps/emperor/CMakeLists.txt | 5 ++ apps/emperor/gadgets/Gadget.h | 30 ++++++++++ apps/emperor/gadgets/NoiseAdjustGadget.h | 31 ++++++++++ apps/emperor/gadgets/RemoveOversampling.h | 28 +++++++++ apps/emperor/pipelines/default.h | 12 +++- apps/emperor/pipelines/pipeline.h | 4 +- core/Node.h | 50 ++++++++-------- .../AcquisitionAccumulateTriggerGadget.cpp | 38 ++++++++++++ .../AcquisitionAccumulateTriggerGadget.h | 5 +- gadgets/mri_core/BucketToBufferGadget.cpp | 40 +++++++++++-- gadgets/mri_core/BucketToBufferGadget.h | 7 ++- gadgets/mri_core/ExtractGadget.h | 59 ++++++++++++------- gadgets/mri_core/NoiseAdjustGadget.cpp | 17 +++--- gadgets/mri_core/NoiseAdjustGadget.h | 6 +- .../mri_core/RemoveROOversamplingGadget.cpp | 3 +- gadgets/mri_core/RemoveROOversamplingGadget.h | 4 +- gadgets/mri_core/SimpleReconGadget.cpp | 13 ++-- gadgets/mri_core/SimpleReconGadget.h | 8 +-- toolboxes/log/log.h | 4 +- 19 files changed, 276 insertions(+), 88 deletions(-) create mode 100644 apps/emperor/gadgets/Gadget.h create mode 100644 apps/emperor/gadgets/NoiseAdjustGadget.h create mode 100644 apps/emperor/gadgets/RemoveOversampling.h diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index f70e576c..ae99ff23 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -8,6 +8,11 @@ add_executable(emperor ../../gadgets/mri_core/NoiseAdjustGadget.cpp ../../gadgets/mri_core/RemoveROOversamplingGadget.cpp + ../../gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp + ../../gadgets/mri_core/BucketToBufferGadget.cpp + ../../gadgets/mri_core/SimpleReconGadget.cpp + ../../gadgets/mri_core/ImageArraySplitGadget.cpp + ../../gadgets/mri_core/ExtractGadget.cpp ../pingvin/StreamConsumer.h diff --git a/apps/emperor/gadgets/Gadget.h b/apps/emperor/gadgets/Gadget.h new file mode 100644 index 00000000..4842484c --- /dev/null +++ b/apps/emperor/gadgets/Gadget.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include +namespace po = boost::program_options; + +namespace pingvin { + +class Gadget { + public: + Gadget(std::string name, std::string description) : name_(name), description_(description) { + std::cerr << "Constructed Gadget " << name << std::endl; + } + + virtual ~Gadget() = default; + + virtual void process() = 0; + + virtual void install_cli(po::options_description&) = 0; + + std::string name() const { return name_; } + std::string description() const { return description_; } + +protected: + std::string name_; + std::string description_; +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/gadgets/NoiseAdjustGadget.h b/apps/emperor/gadgets/NoiseAdjustGadget.h new file mode 100644 index 00000000..e7066f4b --- /dev/null +++ b/apps/emperor/gadgets/NoiseAdjustGadget.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Gadget.h" + +namespace pingvin { + +class NoiseAdjustGadget : public Gadget { + public: + NoiseAdjustGadget() : Gadget("Noise Adjust", "Noise covariance estimation") {} + + virtual void process() override { + std::cerr << "NoiseAdjustGadget::process" << std::endl; + std::cerr << " noise_covariance_out: " << noise_covariance_out_ << std::endl; + std::cerr << " pass_nonconformant_data: " << pass_nonconformant_data_ << std::endl; + } + + virtual void install_cli(po::options_description& desc) override { + std::cerr << "NoiseAdjustGadget::install_cli" << std::endl; + + desc.add_options() + ("noise_covariance_out", po::value(&noise_covariance_out_), "Noise covariance output file") + ("pass_nonconformant_data", po::value(&pass_nonconformant_data_), "Pass data that does not conform") + ; + } + +private: + std::string noise_covariance_out_; + bool pass_nonconformant_data_ = true; +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/gadgets/RemoveOversampling.h b/apps/emperor/gadgets/RemoveOversampling.h new file mode 100644 index 00000000..cc17cc24 --- /dev/null +++ b/apps/emperor/gadgets/RemoveOversampling.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Gadget.h" + +namespace pingvin { + +class RemoveOversamplingGadget : public Gadget { + public: + RemoveOversamplingGadget() : Gadget("Remove Oversampling", "Remove readout oversampling") {} + + virtual void process() override { + std::cerr << "RemoveOversamplingGadget::process" << std::endl; + std::cerr << " skip: " << skip_ << std::endl; + } + + void install_cli(po::options_description& desc) override { + std::cerr << "RemoveOversamplingGadget::install_cli" << std::endl; + + desc.add_options() + ("skip", po::value(&skip_), "Skip this gadget") + ; + } + +private: + bool skip_ = false; +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h index e98c0bd1..abff508c 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/emperor/pipelines/default.h @@ -4,6 +4,11 @@ #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/SimpleReconGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ExtractGadget.h" namespace pingvin { @@ -20,8 +25,13 @@ class Default : public Pipeline { // .append() // .build(); - this->append(); + // this->append(); this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); } }; diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index 2c965c36..79f30684 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -34,7 +34,7 @@ class Pipeline { Pipeline(std::string name, std::string description) : name_(name), description_(description) {} virtual ~Pipeline() = default; - using TempGadget = NewChannelGadget; + // using TempGadget = NewChannelGadget; // class Builder { // public: @@ -162,7 +162,7 @@ class Pipeline { std::string name_; std::string description_; - std::vector> gadgets_; + std::vector> gadgets_; std::vector> processables_; }; diff --git a/core/Node.h b/core/Node.h index c01c30ca..bfdbd8b9 100644 --- a/core/Node.h +++ b/core/Node.h @@ -21,6 +21,7 @@ namespace Gadgetron::Core { * @param out Channel in which messages are sent on downstream */ virtual void process(GenericInputChannel& in, OutputChannel& out) = 0; + }; class GenericChannelGadget : public Node, public PropertyMixin { @@ -29,8 +30,25 @@ namespace Gadgetron::Core { // [[deprecated("ChannelGadget should be called with both context and properties")]] // GenericChannelGadget(const GadgetProperties& properties) : PropertyMixin(properties) {} + + GenericChannelGadget() : PropertyMixin(GadgetProperties{}) {} + + void initialize(const Core::Context& context, const GadgetProperties& properties) { + this->properties = properties; + this->header = context.header; + this->initialize_(context); + } + + virtual void install_cli(po::options_description& options) {} + virtual std::string name() { return "Unnamed"; } + virtual std::string description() { return "Unknown description"; } + protected: - const mrd::Header header ={}; + virtual void initialize_(const Context& context) {} + + /** TODO: No longer const, so it can be set in `initialize()` after construction */ + // const mrd::Header header ={}; + mrd::Header header ={}; }; /** @@ -44,8 +62,12 @@ namespace Gadgetron::Core { using GenericChannelGadget::GenericChannelGadget; + ChannelGadget(): GenericChannelGadget(Context{}, GadgetProperties{}) { + GDEBUG_STREAM("ChannelGadget created"); + } + /// - void process(GenericInputChannel& in, OutputChannel& out) final { + void process(GenericInputChannel& in, OutputChannel& out) override final { auto typed_input = InputChannel(in, out); this->process(typed_input, out); } @@ -57,30 +79,6 @@ namespace Gadgetron::Core { */ virtual void process(InputChannel& in, OutputChannel& out) = 0; }; - - template class NewChannelGadget : public ChannelGadget { - public: - using ChannelGadget::ChannelGadget; - - NewChannelGadget(): ChannelGadget(Context{}, GadgetProperties{}) { - GDEBUG_STREAM("NewChannelGadget created"); - } - - virtual void install_cli(po::options_description& options) = 0; - - void initialize(const Core::Context& context, const GadgetProperties& properties) { - // this->context = context; - this->properties = properties; - this->initialize_(context); - } - - virtual std::string name() { return "Unnamed"; } - virtual std::string description() { return "Unknown description"; } - - protected: - virtual void initialize_(const Context& context) = 0; - }; - } #define GADGETRON_GADGET_EXPORT(GadgetClass) \ diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp index a57068f8..20ef3e62 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp @@ -133,6 +133,7 @@ namespace Gadgetron { buckets.clear(); } + void AcquisitionAccumulateTriggerGadget::process(Core::InputChannel>& in, Core::OutputChannel& out) { auto waveforms = std::vector{}; @@ -168,6 +169,16 @@ namespace Gadgetron { GDEBUG_STREAM("AcquisitionAccumulateTriggerGadget processed " << count << " Acquisitions total"); send_data(out, buckets, waveforms); } + + void AcquisitionAccumulateTriggerGadget::install_cli(po::options_description& desc) + { + desc.add_options() + ("trigger_dimension", po::value(&trigger_dimension)->default_value(TriggerDimension::none), "Dimension to trigger on") + ("sorting_dimension", po::value(&sorting_dimension)->default_value(TriggerDimension::none), "Dimension to sort on") + ("n_acquisitions_before_trigger", po::value(&n_acquisitions_before_trigger)->default_value(40), "Number of acquisitions before first trigger") + ("n_acquisitions_before_ongoing_trigger", po::value(&n_acquisitions_before_ongoing_trigger)->default_value(40), "Number of acquisitions before ongoing triggers"); + } + GADGETRON_GADGET_EXPORT(AcquisitionAccumulateTriggerGadget); namespace { @@ -192,4 +203,31 @@ namespace Gadgetron { trigger = triggerdimension_from_name.at(lower); } + std::ostream& operator<<(std::ostream& out, const TriggerDimension& param) { + for (auto it = triggerdimension_from_name.begin(); it != triggerdimension_from_name.end(); ++it) { + if (it->second == param) { + out << it->first; + break; + } + } + return out; + } + + void validate(boost::any& v, const std::vector& values, TriggerDimension*, int) + { + // Make sure no previous assignment to 'a' was made. + po::validators::check_first_occurrence(v); + // Extract the first string from 'values'. If there is more than + // one string, it's an error, and exception will be thrown. + const std::string& s = po::validators::get_single_string(values); + + TriggerDimension td; + try { + Gadgetron::from_string(s, td); + } catch (std::exception& e) { + throw po::validation_error(po::validation_error::invalid_option_value); + } + v = boost::any(td); + } + } // namespace Gadgetron \ No newline at end of file diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h index d8230e29..b99c8423 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h @@ -8,14 +8,15 @@ namespace Gadgetron { - - class AcquisitionAccumulateTriggerGadget : public Core::ChannelGadget> { public: using Core::ChannelGadget>::ChannelGadget; void process(Core::InputChannel>& in, Core::OutputChannel& out) override; + + void install_cli(po::options_description& desc) override; + enum class TriggerDimension { kspace_encode_step_1, kspace_encode_step_2, diff --git a/gadgets/mri_core/BucketToBufferGadget.cpp b/gadgets/mri_core/BucketToBufferGadget.cpp index 7fec1447..99be6200 100644 --- a/gadgets/mri_core/BucketToBufferGadget.cpp +++ b/gadgets/mri_core/BucketToBufferGadget.cpp @@ -593,10 +593,6 @@ namespace Gadgetron { } } - - BucketToBufferGadget::BucketToBufferGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props), header{ context.header } {} - namespace { using Dimension = BucketToBufferGadget::Dimension; const std::map dimension_from_name @@ -606,12 +602,48 @@ namespace Gadgetron { }; } + void BucketToBufferGadget::install_cli(po::options_description& desc) { + desc.add_options() + ("N_dimension", po::value(&N_dimension)->default_value(Dimension::none), "N-Dimensions") + ("S_dimension", po::value(&S_dimension)->default_value(Dimension::none), "S-Dimensions") + ("split_slices", po::value(&split_slices)->default_value(false), "Split slices") + ("ignore_segment", po::value(&ignore_segment)->default_value(false), "Ignore segment") + ("verbose", po::value(&verbose)->default_value(false), "Whether to print more information"); + } + void from_string(const std::string& str, BucketToBufferGadget::Dimension& dim) { auto lower = str; boost::to_lower(lower); dim = dimension_from_name.at(lower); } + std::ostream& operator<<(std::ostream& out, const BucketToBufferGadget::Dimension& param) { + for (auto it = dimension_from_name.begin(); it != dimension_from_name.end(); ++it) { + if (it->second == param) { + out << it->first; + break; + } + } + return out; + } + + void validate(boost::any& v, const std::vector& values, BucketToBufferGadget::Dimension*, int) + { + // Make sure no previous assignment to 'a' was made. + po::validators::check_first_occurrence(v); + // Extract the first string from 'values'. If there is more than + // one string, it's an error, and exception will be thrown. + const std::string& s = po::validators::get_single_string(values); + + BucketToBufferGadget::Dimension d; + try { + Gadgetron::from_string(s, d); + } catch (std::exception& e) { + throw po::validation_error(po::validation_error::invalid_option_value); + } + v = boost::any(d); + } + GADGETRON_GADGET_EXPORT(BucketToBufferGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 4955c8d4..566bfd0a 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -19,9 +19,12 @@ namespace Gadgetron { class BucketToBufferGadget : public Core::ChannelGadget { public: - BucketToBufferGadget(const Core::Context& context, const Core::GadgetProperties& props); + // BucketToBufferGadget(const Core::Context& context, const Core::GadgetProperties& props); + using Core::ChannelGadget::ChannelGadget; enum class Dimension { average, contrast, phase, repetition, set, segment, slice, none }; + virtual void install_cli(po::options_description& desc) override; + struct BufferKey { uint32_t average,slice,contrast,phase,repetition,set,segment; BufferKey(const BufferKey&) = default; @@ -44,8 +47,6 @@ namespace Gadgetron { NODE_PROPERTY(ignore_segment, bool, "Ignore segment", false); NODE_PROPERTY(verbose, bool, "Whether to print more information", false); - mrd::Header header; - void process(Core::InputChannel& in, Core::OutputChannel& out) override; BufferKey getKey(const mrd::EncodingCounters& idx) const; diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index 0f06f9d9..333ec248 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -7,26 +7,43 @@ namespace Gadgetron { - class ExtractGadget : public Core::ChannelGadget>> +class ExtractGadget : public Core::ChannelGadget>> { + public: + using Core::ChannelGadget>>::ChannelGadget; + ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props); + + void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; + + virtual void install_cli(po::options_description& options) override { + options.add_options() + ("extract_magnitude", po::bool_switch(&extract_magnitude), "Extract absolute value") + ("extract_real", po::bool_switch(&extract_real), "Extract real components") + ("extract_imag", po::bool_switch(&extract_imag), "Extract imaginary component") + ("extract_phase", po::bool_switch(&extract_phase), "Extract phase") + ("real_imag_offset", po::value(&real_imag_offset)->default_value(0.0f), "Offset to add to real and imag images"); + } + + protected: + NODE_PROPERTY(extract_mask, std::bitset<4>, "(DEPRECATED) Extract mask, bitmask MAG=1, REAL=2, IMAG=4, PHASE=8", 0); + NODE_PROPERTY(extract_magnitude, bool, "Extract absolute value", true); + NODE_PROPERTY(extract_real, bool, "Extract real components", false); + NODE_PROPERTY(extract_imag, bool, "Extract imaginary component", false); + NODE_PROPERTY(extract_phase, bool, "Extract phase", false); + NODE_PROPERTY(real_imag_offset, float, "Offset to add to real and imag images", 0.0f); + + virtual void initialize_(const Core::Context& context) override { + if (!extract_magnitude && !extract_real && !extract_imag && !extract_phase) { + // throw std::runtime_error("No images selected for extraction"); + GADGET_THROW("No images selected for extraction"); + } + + if (extract_magnitude) image_types.insert(mrd::ImageType::kMagnitude); + if (extract_real) image_types.insert(mrd::ImageType::kReal); + if (extract_imag) image_types.insert(mrd::ImageType::kImag); + if (extract_phase) image_types.insert(mrd::ImageType::kPhase); + } + + std::set image_types; +}; - { - - public: - ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props); - - protected: - NODE_PROPERTY( - extract_mask, std::bitset<4>, "(DEPRECATED) Extract mask, bitmask MAG=1, REAL=2, IMAG=4, PHASE=8", 0); - NODE_PROPERTY(extract_magnitude, bool, "Extract absolute value", true); - NODE_PROPERTY(extract_real, bool, "Extract real components", false); - NODE_PROPERTY(extract_imag, bool, "Extract imaginary component", false); - NODE_PROPERTY(extract_phase, bool, "Extract phase", false); - NODE_PROPERTY(real_imag_offset, float, "Offset to add to real and imag images", 0.0f); - - public: - void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; - - protected: - std::set image_types; - }; } diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index 83778624..e856dc09 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -182,10 +182,13 @@ namespace Gadgetron { } void NoiseAdjustGadget::install_cli(po::options_description& options) { - // TODO options.add_options() - ("noisecovariancein", po::value(&noise_covariance_in), "Input noise covariance matrix") - ("noisecovarianceout", po::value(&noise_covariance_out), "Output noise covariance matrix") + ("noise_covariance_in", po::value(&noise_covariance_in), "Input noise covariance matrix") + ("noise_covariance_out", po::value(&noise_covariance_out), "Output noise covariance matrix") + ("perform_noise_adjust", po::value(&perform_noise_adjust)->default_value(true), "Whether to actually perform the noise adjust") + ("pass_nonconformant_data", po::value(&pass_nonconformant_data)->default_value(true), "Whether to pass data that does not conform") + ("noise_dwell_time_us_preset", po::value(&noise_dwell_time_us_preset)->default_value(0.0), "Preset dwell time for noise measurement") + ("scale_only_channels_by_name", po::value(&scale_only_channels_by_name), "List of named channels that should only be scaled") ; } @@ -194,13 +197,13 @@ namespace Gadgetron { this->receiver_noise_bandwidth = bandwidth_from_header(context.header); this->measurement_id = measurement_id_from_header(context.header); - if (!perform_noise_adjust) - return; - GDEBUG("perform_noise_adjust_ is %d\n", perform_noise_adjust); GDEBUG("pass_nonconformant_data_ is %d\n", pass_nonconformant_data); GDEBUG("receiver_noise_bandwidth_ is %f\n", receiver_noise_bandwidth); + if (!perform_noise_adjust) + return; + #ifdef USE_OMP omp_set_num_threads(1); #endif // USE_OMP @@ -219,7 +222,7 @@ namespace Gadgetron { } NoiseAdjustGadget::NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::NewChannelGadget(context, props) + : Core::ChannelGadget(context, props) , current_mrd_header(context.header) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } , measurement_id{ measurement_id_from_header(context.header) } diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index 4d24828e..dd58b845 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -26,11 +26,9 @@ namespace Gadgetron { struct IgnoringNoise {}; - // class NoiseAdjustGadget : public Core::ChannelGadget { - class NoiseAdjustGadget : public Core::NewChannelGadget { + class NoiseAdjustGadget : public Core::ChannelGadget { public: - NoiseAdjustGadget(): Core::NewChannelGadget() {} - + using Core::ChannelGadget::ChannelGadget; NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props); void install_cli(po::options_description& options) override; diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index 5d758517..06661f18 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -6,7 +6,8 @@ namespace Gadgetron { RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::NewChannelGadget(context, props) { + : Core::ChannelGadget(context, props) +{ auto h = (context.header); if (h.encoding.size() == 0) { diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index e26d0980..942c8740 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -13,9 +13,9 @@ #endif // USE_OMP namespace Gadgetron { -class RemoveROOversamplingGadget : public Core::NewChannelGadget { +class RemoveROOversamplingGadget : public Core::ChannelGadget { public: - using Core::NewChannelGadget::NewChannelGadget; + using Core::ChannelGadget::ChannelGadget; RemoveROOversamplingGadget() {}; RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props); diff --git a/gadgets/mri_core/SimpleReconGadget.cpp b/gadgets/mri_core/SimpleReconGadget.cpp index dae31491..d34817d5 100644 --- a/gadgets/mri_core/SimpleReconGadget.cpp +++ b/gadgets/mri_core/SimpleReconGadget.cpp @@ -2,15 +2,10 @@ namespace Gadgetron { - SimpleReconGadget::SimpleReconGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) - { - header = context.header; - image_counter_ = 0; - } - void SimpleReconGadget::process(Core::InputChannel& input, Core::OutputChannel& out) { + long long image_counter = 0; + for (mrd::ReconData reconData : input) { GDEBUG_STREAM("Processing reconData containing " << reconData.buffers.size() << " recon bits"); // Iterate over all the recon bits @@ -89,7 +84,7 @@ namespace Gadgetron { imghdr.acquisition_time_stamp = acqhdr.acquisition_time_stamp; imghdr.physiology_time_stamp = acqhdr.physiology_time_stamp; imghdr.image_type = mrd::ImageType::kComplex; - imghdr.image_index = ++image_counter_; + imghdr.image_index = ++image_counter; imghdr.image_series_index = 0; // Grab a wrapper around the relevant chunk of data [E0,E1,E2,CHA] for this loc, n, and s @@ -127,6 +122,6 @@ namespace Gadgetron { } } } - GADGETRON_GADGET_EXPORT(SimpleReconGadget); + GADGETRON_GADGET_EXPORT(SimpleReconGadget); } diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index 328df6ec..771bfaa4 100644 --- a/gadgets/mri_core/SimpleReconGadget.h +++ b/gadgets/mri_core/SimpleReconGadget.h @@ -16,11 +16,9 @@ namespace Gadgetron { class SimpleReconGadget : public Core::ChannelGadget { public: - SimpleReconGadget(const Core::Context& context, const Core::GadgetProperties& props); - void process(Core::InputChannel& input, Core::OutputChannel& out) override; + using Core::ChannelGadget::ChannelGadget; + // SimpleReconGadget(const Core::Context& context, const Core::GadgetProperties& props); - protected: - mrd::Header header; - long long image_counter_; + void process(Core::InputChannel& input, Core::OutputChannel& out) override; }; } \ No newline at end of file diff --git a/toolboxes/log/log.h b/toolboxes/log/log.h index c657aefc..790998f9 100644 --- a/toolboxes/log/log.h +++ b/toolboxes/log/log.h @@ -190,7 +190,9 @@ namespace Gadgetron #define GDEBUG_CONDITION_STREAM(con, message) { if ( con ) GDEBUG_STREAM(message) } #define GWARN_CONDITION_STREAM(con, message) { if ( con ) GWARN_STREAM(message) } -#define GADGET_THROW(msg) { GERROR_STREAM(msg); throw std::runtime_error(msg); } +// #define GADGET_THROW(msg) { GERROR_STREAM(msg); throw std::runtime_error(msg); } +#define GADGET_THROW(msg) { GERROR_STREAM(msg); throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + " -- " + msg); } + #define GADGET_CHECK_THROW(con) { if ( !(con) ) { GERROR_STREAM(#con); throw std::runtime_error(#con); } } #define GADGET_CATCH_THROW(con) { try { con; } catch(...) { GERROR_STREAM(#con); throw std::runtime_error(#con); } } From 82ccdd98ef8a33b3ca1bf6cb649206c8f91b0766 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Tue, 14 Jan 2025 18:48:38 +0000 Subject: [PATCH 04/21] Disable runtime library loading --- apps/CMakeLists.txt | 2 +- apps/emperor/CMakeLists.txt | 22 +----- apps/emperor/gadgets/Gadget.h | 30 --------- apps/emperor/gadgets/NoiseAdjustGadget.h | 31 --------- apps/emperor/gadgets/RemoveOversampling.h | 28 -------- apps/emperor/main.cc | 29 ++++++-- apps/emperor/pipelines/cartesian_grappa.h | 31 ++++++++- apps/emperor/pipelines/default.h | 4 +- apps/emperor/pipelines/grappa_cpu.h | 35 ++++++++++ apps/emperor/pipelines/noise.h | 2 +- apps/emperor/pipelines/pipeline.h | 38 ++--------- apps/pingvin/StreamConsumer.h | 40 +---------- apps/pingvin/nodes/Parallel.cpp | 44 ++++++------ apps/pingvin/nodes/Parallel.h | 3 - apps/pingvin/nodes/ParallelProcess.cpp | 6 -- apps/pingvin/nodes/ParallelProcess.h | 5 -- apps/pingvin/nodes/PureStream.cpp | 36 ---------- apps/pingvin/nodes/PureStream.h | 4 -- apps/pingvin/nodes/Stream.cpp | 67 ++++++------------- apps/pingvin/nodes/Stream.h | 11 +-- core/Node.h | 17 ++--- core/PureGadget.h | 1 + .../AcquisitionAccumulateTriggerGadget.h | 2 + .../mri_core/AsymmetricEchoAdjustROGadget.h | 1 + gadgets/mri_core/BucketToBufferGadget.h | 2 +- gadgets/mri_core/ComplexToFloatGadget.h | 1 + gadgets/mri_core/ExtractGadget.h | 1 + gadgets/mri_core/FloatToFixPointGadget.h | 2 +- gadgets/mri_core/ImageArraySplitGadget.h | 1 + gadgets/mri_core/NoiseAdjustGadget.cpp | 14 ++-- gadgets/mri_core/NoiseAdjustGadget.h | 8 +-- gadgets/mri_core/PCACoilGadget.cpp | 23 +++++++ gadgets/mri_core/PCACoilGadget.h | 3 + gadgets/mri_core/RemoveROOversamplingGadget.h | 5 +- gadgets/mri_core/SimpleReconGadget.h | 2 +- 35 files changed, 194 insertions(+), 357 deletions(-) delete mode 100644 apps/emperor/gadgets/Gadget.h delete mode 100644 apps/emperor/gadgets/NoiseAdjustGadget.h delete mode 100644 apps/emperor/gadgets/RemoveOversampling.h create mode 100644 apps/emperor/pipelines/grappa_cpu.h diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 5c8d343a..003e5874 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,3 +1,3 @@ -add_subdirectory(pingvin) +# add_subdirectory(pingvin) add_subdirectory(emperor) \ No newline at end of file diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index ae99ff23..d7c41767 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -3,17 +3,6 @@ configure_file(../pingvin/pingvin_config.in pingvin_config.h) add_executable(emperor main.cc - ../pingvin/Config.cpp - ../pingvin/Config.h - - ../../gadgets/mri_core/NoiseAdjustGadget.cpp - ../../gadgets/mri_core/RemoveROOversamplingGadget.cpp - ../../gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp - ../../gadgets/mri_core/BucketToBufferGadget.cpp - ../../gadgets/mri_core/SimpleReconGadget.cpp - ../../gadgets/mri_core/ImageArraySplitGadget.cpp - ../../gadgets/mri_core/ExtractGadget.cpp - ../pingvin/StreamConsumer.h ../pingvin/ErrorHandler.h @@ -31,20 +20,11 @@ add_executable(emperor ../pingvin/nodes/PureStream.h ) -# target_link_libraries(emperor -# # Boost::system -# # Boost::filesystem -# Boost::program_options -# ) target_link_libraries(emperor pingvin_core - pingvin_toolbox_log - pingvin_toolbox_mri_core - # pingvin_mricore + pingvin_mricore Boost::system - Boost::filesystem Boost::program_options - ${PUGIXML_LIBRARIES} GTBLAS) target_include_directories(emperor diff --git a/apps/emperor/gadgets/Gadget.h b/apps/emperor/gadgets/Gadget.h deleted file mode 100644 index 4842484c..00000000 --- a/apps/emperor/gadgets/Gadget.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -#include -namespace po = boost::program_options; - -namespace pingvin { - -class Gadget { - public: - Gadget(std::string name, std::string description) : name_(name), description_(description) { - std::cerr << "Constructed Gadget " << name << std::endl; - } - - virtual ~Gadget() = default; - - virtual void process() = 0; - - virtual void install_cli(po::options_description&) = 0; - - std::string name() const { return name_; } - std::string description() const { return description_; } - -protected: - std::string name_; - std::string description_; -}; - -} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/gadgets/NoiseAdjustGadget.h b/apps/emperor/gadgets/NoiseAdjustGadget.h deleted file mode 100644 index e7066f4b..00000000 --- a/apps/emperor/gadgets/NoiseAdjustGadget.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "Gadget.h" - -namespace pingvin { - -class NoiseAdjustGadget : public Gadget { - public: - NoiseAdjustGadget() : Gadget("Noise Adjust", "Noise covariance estimation") {} - - virtual void process() override { - std::cerr << "NoiseAdjustGadget::process" << std::endl; - std::cerr << " noise_covariance_out: " << noise_covariance_out_ << std::endl; - std::cerr << " pass_nonconformant_data: " << pass_nonconformant_data_ << std::endl; - } - - virtual void install_cli(po::options_description& desc) override { - std::cerr << "NoiseAdjustGadget::install_cli" << std::endl; - - desc.add_options() - ("noise_covariance_out", po::value(&noise_covariance_out_), "Noise covariance output file") - ("pass_nonconformant_data", po::value(&pass_nonconformant_data_), "Pass data that does not conform") - ; - } - -private: - std::string noise_covariance_out_; - bool pass_nonconformant_data_ = true; -}; - -} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/gadgets/RemoveOversampling.h b/apps/emperor/gadgets/RemoveOversampling.h deleted file mode 100644 index cc17cc24..00000000 --- a/apps/emperor/gadgets/RemoveOversampling.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Gadget.h" - -namespace pingvin { - -class RemoveOversamplingGadget : public Gadget { - public: - RemoveOversamplingGadget() : Gadget("Remove Oversampling", "Remove readout oversampling") {} - - virtual void process() override { - std::cerr << "RemoveOversamplingGadget::process" << std::endl; - std::cerr << " skip: " << skip_ << std::endl; - } - - void install_cli(po::options_description& desc) override { - std::cerr << "RemoveOversamplingGadget::install_cli" << std::endl; - - desc.add_options() - ("skip", po::value(&skip_), "Skip this gadget") - ; - } - -private: - bool skip_ = false; -}; - -} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index dbef0883..484e4b12 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -1,5 +1,5 @@ #include "pipelines/noise.h" -#include "pipelines/cartesian_grappa.h" +// #include "pipelines/cartesian_grappa.h" #include "pipelines/default.h" #include "log.h" @@ -16,6 +16,27 @@ using namespace pingvin; namespace po = boost::program_options; namespace fs = std::filesystem; +namespace { + +std::string envvar_to_parameter(const std::string& env_var) +{ + static const std::string prefix("PINGVIN_"); + + if (env_var.compare(0, prefix.size(), prefix) != 0) { + return std::string(); + } + + std::string option(env_var.substr(prefix.size())); + + option.replace(option.find("_"), 1, "."); + std::replace(option.begin(), option.end(), '_', '-'); + std::transform(option.begin(), option.end(), option.begin(), + [](unsigned char c){ return std::tolower(c); }); + return option; +} + +} + int main(int argc, char** argv) { po::options_description global("Global options"); @@ -24,7 +45,7 @@ int main(int argc, char** argv) global.add_options() ("help,h", "Prints this help message.") ("info", "Prints build info about Pingvin.") - ("home,G", + ("home", po::value()->default_value(pingvin_home), "Set the Pingvin home directory.") ; @@ -75,7 +96,7 @@ int main(int argc, char** argv) std::vector> pipelines; pipelines.push_back(std::make_shared()); pipelines.push_back(std::make_shared()); - pipelines.push_back(std::make_shared()); + // pipelines.push_back(std::make_shared()); std::map> pipeline_map; for (auto& pipeline : pipelines) { pipeline_map[pipeline->name()] = pipeline; @@ -123,7 +144,7 @@ int main(int argc, char** argv) return 0; } - po::store(po::parse_environment(pipeline_desc, "PINGVIN_"), vm); + po::store(po::parse_environment(pipeline_desc, envvar_to_parameter), vm); if (vm.count("config")) { auto config_filename = vm["config"].as(); diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h index 32992cde..3a223942 100644 --- a/apps/emperor/pipelines/cartesian_grappa.h +++ b/apps/emperor/pipelines/cartesian_grappa.h @@ -3,6 +3,20 @@ #include "pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixPointGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" namespace pingvin { @@ -11,8 +25,21 @@ class CartesianGrappa : public Pipeline { CartesianGrappa() : Pipeline("cartesian-grappa", "Cartesian Grappa Recon") { } void build(void) override { - gadgets_.push_back(std::make_shared()); - // gadgets_.push_back(std::make_unique()); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); } }; diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h index abff508c..2528e223 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/emperor/pipelines/default.h @@ -2,7 +2,6 @@ #include "pipeline.h" -#include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" #include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" #include "gadgets/mri_core/BucketToBufferGadget.h" @@ -21,11 +20,10 @@ class Default : public Pipeline { // gadgets_.push_back(std::make_shared()); // gadgets_ = Builder() - // .append() // .append() + // .append() // .build(); - // this->append(); this->append(); this->append(); this->append(); diff --git a/apps/emperor/pipelines/grappa_cpu.h b/apps/emperor/pipelines/grappa_cpu.h new file mode 100644 index 00000000..d843b363 --- /dev/null +++ b/apps/emperor/pipelines/grappa_cpu.h @@ -0,0 +1,35 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/ExtractGadget.h" + +namespace pingvin { + +class GrappaCPU : public Pipeline { + public: + GrappaCPU() : Pipeline("grappa_cpu", "Grappa Reconstruction on CPU") { } + + void build(void) override { + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + this->append(); + // Parallel + // Branch: AcquisitionFanout + // Stream + // ImageAccumulator + // Stream + // cpuWeightsCalculator + // Merge: Unmixing + this->append(); + this->append(); + this->append(); + } +}; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/noise.h b/apps/emperor/pipelines/noise.h index 14a65b05..70920cb6 100644 --- a/apps/emperor/pipelines/noise.h +++ b/apps/emperor/pipelines/noise.h @@ -8,7 +8,7 @@ namespace pingvin { class NoiseDependency: public Pipeline { public: - NoiseDependency() : Pipeline("noise", "Noise covariance computation") { } + NoiseDependency() : Pipeline("noise", "Compute noise covariance for measurement dependency") { } void build(void) override { gadgets_.push_back(std::make_shared()); diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index 79f30684..521af281 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -9,26 +9,6 @@ namespace po = boost::program_options; namespace pingvin { -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; -} - class Pipeline { public: Pipeline(std::string name, std::string description) : name_(name), description_(description) {} @@ -67,9 +47,6 @@ class Pipeline { void run(po::variables_map& vm) { std::cerr << "Running pipeline " << name_ << std::endl; - // for (auto& g: gadgets_) { - // g->process(); - // } std::cerr << "OK, now running Pingvin" << std::endl; @@ -101,7 +78,7 @@ class Pipeline { mrd::binary::MrdReader mrd_reader(input_stream); mrd::binary::MrdWriter mrd_writer(output_stream); - StreamConsumer consumer(vm); + StreamConsumer consumer; mrd::Header hdr = consumer.consume_mrd_header(mrd_reader, mrd_writer); auto context = StreamContext(hdr, paths, vm); @@ -126,11 +103,6 @@ class Pipeline { ("config,c", po::value(), "Pipeline configuration file") ("input,i", po::value(), "Input stream") ("output,o", po::value(), "Output stream") - // TODO: Remove this once all Gadgets no longer use `parameters` - ("parameter", - po::value>(), - "Parameter to be passed to the Pingvin reconstruction config. Multiple parameters can be passed." - "Format: --parameter = --parameter = ..."); ; po::options_description gadgets("Pipeline Nodes"); @@ -138,7 +110,9 @@ class Pipeline { for (auto& g: gadgets_) { po::options_description group(g->name()); g->install_cli(group); - gadgets.add(group); + if (!group.options().empty()) { + gadgets.add(group); + } } desc.add(gadgets); @@ -152,8 +126,8 @@ class Pipeline { template void append(void) { auto n = std::make_shared(); - gadgets_.push_back(n); - processables_.push_back(std::make_shared(n, "TODO")); + gadgets_.emplace_back(n); + processables_.emplace_back(std::make_shared(n, "TODO")); } // template diff --git a/apps/pingvin/StreamConsumer.h b/apps/pingvin/StreamConsumer.h index 67eb7984..3287b87e 100644 --- a/apps/pingvin/StreamConsumer.h +++ b/apps/pingvin/StreamConsumer.h @@ -4,14 +4,11 @@ #include #include -#include -#include - #include +#include "nodes/Stream.h" #include "Channel.h" #include "ErrorHandler.h" -#include "Loader.h" #include "Node.h" @@ -68,40 +65,9 @@ std::filesystem::path find_config_path(const std::string& home_dir, const std::s class StreamConsumer { public: - StreamConsumer(const boost::program_options::variables_map& args) - : args_(args) {} + StreamConsumer() {} ~StreamConsumer() {} - void consume(std::istream& input_stream, std::ostream& output_stream, std::string config_xml_name) - { - Context::Paths paths{ - (args_.count("home")) - ? args_["home"].as().string() - : "/opt/pingvin" - }; - - 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); - - consume_stream(mrd_reader, mrd_writer, stream); - } - void consume_stream(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer, const std::unique_ptr& stream) { auto input_channel = make_channel(); @@ -221,6 +187,4 @@ class StreamConsumer mrd_writer.EndData(); mrd_writer.Close(); } - - boost::program_options::variables_map args_; }; diff --git a/apps/pingvin/nodes/Parallel.cpp b/apps/pingvin/nodes/Parallel.cpp index 5909380f..1dd53ddf 100644 --- a/apps/pingvin/nodes/Parallel.cpp +++ b/apps/pingvin/nodes/Parallel.cpp @@ -3,8 +3,6 @@ #include #include -#include "Loader.h" - #include "Channel.h" #include "Context.h" @@ -17,18 +15,18 @@ namespace { 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; + // 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, Config::name(conf), conf.properties), Config::name(conf)); - } + // 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, 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, 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, Config::name(conf), conf.properties), Config::name(conf)); + // } template auto transform_map(std::map& input, F f) { @@ -68,17 +66,17 @@ namespace { namespace Gadgetron::Main::Nodes { - Parallel::Parallel( - const Config::Parallel &config, - const Core::StreamContext &context, - Loader &loader - ) : branch(load_branch(config.branch, context, loader)), merge(load_merge(config.merge, context, loader)) { - std::transform( - config.streams.begin(), config.streams.end(), - std::back_inserter(streams), - [&](auto &stream_config) { return std::make_shared(stream_config, context, loader); } - ); - } + // Parallel::Parallel( + // const Config::Parallel &config, + // const Core::StreamContext &context, + // Loader &loader + // ) : branch(load_branch(config.branch, context, loader)), merge(load_merge(config.merge, context, loader)) { + // std::transform( + // config.streams.begin(), config.streams.end(), + // std::back_inserter(streams), + // [&](auto &stream_config) { return std::make_shared(stream_config, context, loader); } + // ); + // } void Parallel::process( InputChannel input, diff --git a/apps/pingvin/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h index 49d84613..c9556887 100644 --- a/apps/pingvin/nodes/Parallel.h +++ b/apps/pingvin/nodes/Parallel.h @@ -19,9 +19,6 @@ namespace Gadgetron::Main::Nodes { using Merge = Core::Parallel::Merge; public: - Parallel(const Config::Parallel &, const Core::StreamContext &) {} - Parallel(const Config::Parallel &, const Core::StreamContext &, Loader &); - void process( Core::GenericInputChannel input, Core::OutputChannel output, diff --git a/apps/pingvin/nodes/ParallelProcess.cpp b/apps/pingvin/nodes/ParallelProcess.cpp index 5b65d269..e189ae4d 100644 --- a/apps/pingvin/nodes/ParallelProcess.cpp +++ b/apps/pingvin/nodes/ParallelProcess.cpp @@ -45,12 +45,6 @@ namespace Gadgetron::Main::Nodes { input_thread.join(); output_thread.join(); } - ParallelProcess::ParallelProcess( - const Config::ParallelProcess& conf, - const Context& context, - Loader& loader - ) : pureStream{ conf.stream, context, loader }, workers{ conf.workers } {} - const std::string& ParallelProcess::name() { const static std::string n = "ParallelProcess"; return n; diff --git a/apps/pingvin/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h index 9582770e..7854ee9f 100644 --- a/apps/pingvin/nodes/ParallelProcess.h +++ b/apps/pingvin/nodes/ParallelProcess.h @@ -9,11 +9,6 @@ namespace Gadgetron::Main::Nodes { class ParallelProcess : public Processable { public: - ParallelProcess(const Config::ParallelProcess& conf, const Core::Context& context) - : pureStream{ conf.stream, context }, workers{ conf.workers } {} - - ParallelProcess(const Config::ParallelProcess& conf, const Core::Context& context, Loader& loader); - void process(Core::GenericInputChannel input, Core::OutputChannel output, ErrorHandler& error_handler) override; const std::string& name() override; private: diff --git a/apps/pingvin/nodes/PureStream.cpp b/apps/pingvin/nodes/PureStream.cpp index 815ca93a..cdccb26f 100644 --- a/apps/pingvin/nodes/PureStream.cpp +++ b/apps/pingvin/nodes/PureStream.cpp @@ -1,41 +1,5 @@ #include "PureStream.h" -namespace { - using namespace Gadgetron::Core; - 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, Config::name(conf), conf.properties); - - if (dynamic_cast(gadget.get())) { - return std::unique_ptr(dynamic_cast(gadget.release())); - } - - throw std::runtime_error("Non-pure Gadget \"" + conf.classname + "\" in pure stream."); - } - - std::vector> load_pure_gadgets( - const std::vector& configs, - const Context& context, - Loader& loader - ) { - std::vector> gadgets; - for (auto& config : configs) { - gadgets.emplace_back(load_pure_gadget(config, context, loader)); - } - return gadgets; - } -} - -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::Main::Nodes::PureStream::process_function( Gadgetron::Core::Message message ) const { diff --git a/apps/pingvin/nodes/PureStream.h b/apps/pingvin/nodes/PureStream.h index b9660962..dd8833ef 100644 --- a/apps/pingvin/nodes/PureStream.h +++ b/apps/pingvin/nodes/PureStream.h @@ -1,14 +1,10 @@ #pragma once #include "Message.h" #include "PureGadget.h" -#include "Loader.h" -#include "Config.h" namespace Gadgetron::Main::Nodes { class PureStream { public: - PureStream(const Config::PureStream&, const Core::Context&) {} - PureStream(const Config::PureStream&, const Core::Context&, Loader&); Core::Message process_function(Core::Message) const; private: diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp index 2e69f9f8..714cda72 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -10,62 +10,33 @@ namespace { using namespace Gadgetron::Core; using namespace Gadgetron::Main; using namespace Gadgetron::Main::Nodes; - using namespace std::string_literals; - - class NodeProcessable : public Processable { - public: - NodeProcessable(std::function()> factory, std::string name) : factory(std::move(factory)), name_(std::move(name)) {} - - void process(GenericInputChannel input, - OutputChannel output, - ErrorHandler & - ) override { - auto node = factory(); - node->process(input, output); - } + // using namespace std::string_literals; - const std::string& name() override { - return name_; - } + // class NodeProcessable : public Processable { + // public: + // NodeProcessable(std::function()> factory, std::string name) : factory(std::move(factory)), name_(std::move(name)) {} - private: - std::function()> factory; - const std::string name_; - }; - - std::shared_ptr load_node(const Config::Gadget &conf, const StreamContext &context, Loader &loader) { - auto factory = loader.load_factory>("gadget_factory_export_", conf.classname, - conf.dll); - return std::make_shared( - [=]() { - 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) - ); - } + // void process(GenericInputChannel input, + // OutputChannel output, + // ErrorHandler & + // ) override { + // auto node = factory(); + // node->process(input, output); + // } - std::shared_ptr load_node(const Config::Parallel &conf, const StreamContext &context, Loader &loader) { - GDEBUG("Loading Parallel block\n"); - return std::make_shared(conf, context, loader); - } + // const std::string& name() override { + // return name_; + // } + + // private: + // std::function()> factory; + // const std::string name_; + // }; - 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); - } } 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( - std::visit([&](auto n) { return load_node(n, context, loader); }, node_config) - ); - } - } - void Stream::process(GenericInputChannel input, OutputChannel output, ErrorHandler &error_handler diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h index 6977330a..79ea2947 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -3,27 +3,18 @@ #include -#include "Loader.h" -#include "Config.h" - #include "Processable.h" #include "Channel.h" #include "Context.h" -namespace Gadgetron::Main { - class Loader; -} - namespace Gadgetron::Main::Nodes { class Stream : public Processable { public: const std::string key; - Stream(const Config::Stream& config, const Core::StreamContext&) : key(config.key) {} - Stream(const Config::Stream&, const Core::StreamContext&, Loader &); - Stream(std::vector> nodes): nodes(std::move(nodes)), key("TODO") {} + Stream(std::vector> nodes): nodes(std::move(nodes)), key("TODO-needed?") {} void process( Core::GenericInputChannel input, diff --git a/core/Node.h b/core/Node.h index bfdbd8b9..e47fe9d8 100644 --- a/core/Node.h +++ b/core/Node.h @@ -27,11 +27,7 @@ namespace Gadgetron::Core { class GenericChannelGadget : public Node, public PropertyMixin { public: GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header} {} - -// [[deprecated("ChannelGadget should be called with both context and properties")]] -// GenericChannelGadget(const GadgetProperties& properties) : PropertyMixin(properties) {} - - GenericChannelGadget() : PropertyMixin(GadgetProperties{}) {} + GenericChannelGadget(const std::string& name, const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header}, name_(name) {} void initialize(const Core::Context& context, const GadgetProperties& properties) { this->properties = properties; @@ -40,8 +36,9 @@ namespace Gadgetron::Core { } virtual void install_cli(po::options_description& options) {} - virtual std::string name() { return "Unnamed"; } - virtual std::string description() { return "Unknown description"; } + + /** TODO: Consider renaming to "key" or "label" */ + virtual std::string name() { return name_; } protected: virtual void initialize_(const Context& context) {} @@ -49,6 +46,8 @@ namespace Gadgetron::Core { /** TODO: No longer const, so it can be set in `initialize()` after construction */ // const mrd::Header header ={}; mrd::Header header ={}; + + std::string name_; }; /** @@ -62,9 +61,7 @@ namespace Gadgetron::Core { using GenericChannelGadget::GenericChannelGadget; - ChannelGadget(): GenericChannelGadget(Context{}, GadgetProperties{}) { - GDEBUG_STREAM("ChannelGadget created"); - } + ChannelGadget(const std::string name): GenericChannelGadget(name, Context{}, GadgetProperties{}) { } /// void process(GenericInputChannel& in, OutputChannel& out) override final { diff --git a/core/PureGadget.h b/core/PureGadget.h index 8fa7f9cd..5b307281 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -5,6 +5,7 @@ namespace Gadgetron::Core { class GenericPureGadget : public GenericChannelGadget { public: using GenericChannelGadget::GenericChannelGadget; + GenericPureGadget(const std::string name): GenericChannelGadget(name, Context{}, GadgetProperties{}) { } void process(GenericInputChannel&in, OutputChannel &out) final { for (auto message : in) diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h index b99c8423..d70885a6 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h @@ -12,6 +12,8 @@ namespace Gadgetron { : public Core::ChannelGadget> { public: using Core::ChannelGadget>::ChannelGadget; + AcquisitionAccumulateTriggerGadget() : ChannelGadget("accumulate_trigger") {} + void process(Core::InputChannel>& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h index f40b7ea0..fdec1907 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h @@ -15,6 +15,7 @@ namespace Gadgetron{ { public: using Core::ChannelGadget::ChannelGadget; + AsymmetricEchoAdjustROGadget() : ChannelGadget("asymmetric_echo_adjust") {} AsymmetricEchoAdjustROGadget(const Core::Context& context, const Core::GadgetProperties& props); ~AsymmetricEchoAdjustROGadget() override = default; void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 566bfd0a..274c8bb7 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -19,8 +19,8 @@ namespace Gadgetron { class BucketToBufferGadget : public Core::ChannelGadget { public: - // BucketToBufferGadget(const Core::Context& context, const Core::GadgetProperties& props); using Core::ChannelGadget::ChannelGadget; + BucketToBufferGadget() : ChannelGadget("bucket_to_buffer") {} enum class Dimension { average, contrast, phase, repetition, set, segment, slice, none }; virtual void install_cli(po::options_description& desc) override; diff --git a/gadgets/mri_core/ComplexToFloatGadget.h b/gadgets/mri_core/ComplexToFloatGadget.h index 5083ed57..52fb7ae4 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.h +++ b/gadgets/mri_core/ComplexToFloatGadget.h @@ -12,6 +12,7 @@ namespace Gadgetron class ComplexToFloatGadget: public Core::PureGadget,mrd::Image>> { public: + ComplexToFloatGadget() : Core::PureGadget,mrd::Image>>("complex_to_float") {} ComplexToFloatGadget(const Core::Context& context, const Core::GadgetProperties& props); mrd::Image process_function(mrd::Image> args) const override; diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index 333ec248..30b8c335 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -10,6 +10,7 @@ namespace Gadgetron { class ExtractGadget : public Core::ChannelGadget>> { public: using Core::ChannelGadget>>::ChannelGadget; + ExtractGadget() : ChannelGadget("extract") {} ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props); void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/FloatToFixPointGadget.h b/gadgets/mri_core/FloatToFixPointGadget.h index 88082cf5..95760e55 100644 --- a/gadgets/mri_core/FloatToFixPointGadget.h +++ b/gadgets/mri_core/FloatToFixPointGadget.h @@ -21,7 +21,7 @@ namespace Gadgetron public: using Core::ChannelGadget>::ChannelGadget; - + FloatToFixPointGadget() : ChannelGadget("float_to_fixpoint") {} ~FloatToFixPointGadget() override = default ; void process(Core::InputChannel>& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 86a43b2f..88bc73f7 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.h +++ b/gadgets/mri_core/ImageArraySplitGadget.h @@ -17,6 +17,7 @@ namespace Gadgetron{ { public: using Core::ChannelGadget::ChannelGadget; + ImageArraySplitGadget() : ChannelGadget("image_array_split") {} void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; } diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index e856dc09..cd5ca25c 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -193,7 +193,6 @@ namespace Gadgetron { } void NoiseAdjustGadget::initialize_(const Core::Context& context) { - this->current_mrd_header = context.header; this->receiver_noise_bandwidth = bandwidth_from_header(context.header); this->measurement_id = measurement_id_from_header(context.header); @@ -223,7 +222,6 @@ namespace Gadgetron { NoiseAdjustGadget::NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props) : Core::ChannelGadget(context, props) - , current_mrd_header(context.header) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } , measurement_id{ measurement_id_from_header(context.header) } { @@ -259,8 +257,8 @@ namespace Gadgetron { size_t CHA = noise_covariance->matrix.get_size(0); if (noise_covariance->coil_labels.size() == CHA) { std::vector current_coil_labels; - if (current_mrd_header.acquisition_system_information) { - for (auto& l : current_mrd_header.acquisition_system_information->coil_label) { + if (header.acquisition_system_information) { + for (auto& l : header.acquisition_system_information->coil_label) { current_coil_labels.push_back(l.coil_name); } } @@ -291,7 +289,7 @@ namespace Gadgetron { } return LoadedNoise{noise_covariance->matrix, noise_covariance->noise_dwell_time_us}; - } else if (current_mrd_header.acquisition_system_information) { + } else if (header.acquisition_system_information) { GERROR("Noise covariance matrix is malformed. Number of labels does not match number of channels."); } } @@ -338,7 +336,7 @@ namespace Gadgetron { normalize_covariance(ng); std::vector coil_labels; - for (auto& label : current_mrd_header.acquisition_system_information->coil_label) { + for (auto& label : header.acquisition_system_information->coil_label) { coil_labels.push_back(label); } @@ -427,9 +425,9 @@ namespace Gadgetron { void NoiseAdjustGadget::process(Core::InputChannel& input, Core::OutputChannel& output) { - scale_only_channels = current_mrd_header.acquisition_system_information + scale_only_channels = header.acquisition_system_information ? find_scale_only_channels(scale_only_channels_by_name, - current_mrd_header.acquisition_system_information->coil_label) + header.acquisition_system_information->coil_label) : std::vector{}; for (auto acq : input) { diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index dd58b845..e2a12afc 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -29,6 +29,7 @@ namespace Gadgetron { class NoiseAdjustGadget : public Core::ChannelGadget { public: using Core::ChannelGadget::ChannelGadget; + NoiseAdjustGadget() : ChannelGadget("noise_adjust") {} NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props); void install_cli(po::options_description& options) override; @@ -37,9 +38,6 @@ namespace Gadgetron { using NoiseHandler = std::variant; - virtual std::string name() override { return "NoiseAdjustGadget"; } - virtual std::string description() override { return "Adjusts noise in the data"; } - protected: NODE_PROPERTY(perform_noise_adjust, bool, "Whether to actually perform the noise adjust", true); NODE_PROPERTY(pass_nonconformant_data, bool, "Whether to pass data that does not conform", true); @@ -55,10 +53,6 @@ namespace Gadgetron { std::string measurement_id; std::vector scale_only_channels; - // We will store/load a copy of the noise scans XML header to enable us to check which coil layout, etc. - // const mrd::Header current_mrd_header; - mrd::Header current_mrd_header; - NoiseHandler noisehandler = IgnoringNoise{}; template diff --git a/gadgets/mri_core/PCACoilGadget.cpp b/gadgets/mri_core/PCACoilGadget.cpp index 4bb95230..b0df0fe8 100644 --- a/gadgets/mri_core/PCACoilGadget.cpp +++ b/gadgets/mri_core/PCACoilGadget.cpp @@ -64,6 +64,29 @@ namespace Gadgetron { } + void PCACoilGadget::initialize_(const Core::Context& context) { + std::vector uncomb; + if (uncombined_channels_by_name.size()) { + GDEBUG("uncomb_str: %s\n", uncombined_channels_by_name.c_str()); + boost::split(uncomb, uncombined_channels_by_name, boost::is_any_of(",")); + for (unsigned int i = 0; i < uncomb.size(); i++) { + std::string ch = boost::algorithm::trim_copy(uncomb[i]); + if (context.header.acquisition_system_information) { + for (size_t i = 0; i < context.header.acquisition_system_information->coil_label.size(); i++) { + if (ch == context.header.acquisition_system_information->coil_label[i].coil_name) { + uncombined_channels_.push_back(i);//This assumes that the channels are sorted in the header + break; + } + } + } + } + } + +#ifdef USE_OMP + omp_set_num_threads(1); +#endif // USE_OMP + } + PCACoilGadget::~PCACoilGadget() { std::map >* >::iterator it; diff --git a/gadgets/mri_core/PCACoilGadget.h b/gadgets/mri_core/PCACoilGadget.h index 5ab879ce..04657585 100644 --- a/gadgets/mri_core/PCACoilGadget.h +++ b/gadgets/mri_core/PCACoilGadget.h @@ -12,6 +12,7 @@ namespace Gadgetron { class PCACoilGadget : public Core::ChannelGadget { public: + PCACoilGadget() : ChannelGadget("pca_coil") {} PCACoilGadget(const Core::Context& context, const Core::GadgetProperties& props); ~PCACoilGadget() override; @@ -21,6 +22,8 @@ namespace Gadgetron { NODE_PROPERTY(uncombined_channels_by_name, std::string, "List of comma separated channels by name", ""); // GADGET_PROPERTY(present_uncombined_channels, int, "Number of uncombined channels found", 0); + void initialize_(const Core::Context& context) override; + void calculate_coefficients(int location); void do_pca(mrd::Acquisition& acq); diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index 942c8740..8c118b7e 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -16,10 +16,9 @@ namespace Gadgetron { class RemoveROOversamplingGadget : public Core::ChannelGadget { public: using Core::ChannelGadget::ChannelGadget; - - RemoveROOversamplingGadget() {}; + RemoveROOversamplingGadget(): ChannelGadget("remove_oversampling") {} RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props); - ~RemoveROOversamplingGadget() override = default; + void process(Core::InputChannel& input, Core::OutputChannel& output) override; void install_cli(po::options_description& options) override; diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index 771bfaa4..b28b2f6b 100644 --- a/gadgets/mri_core/SimpleReconGadget.h +++ b/gadgets/mri_core/SimpleReconGadget.h @@ -17,7 +17,7 @@ namespace Gadgetron { class SimpleReconGadget : public Core::ChannelGadget { public: using Core::ChannelGadget::ChannelGadget; - // SimpleReconGadget(const Core::Context& context, const Core::GadgetProperties& props); + SimpleReconGadget() : ChannelGadget("simple_recon") {} void process(Core::InputChannel& input, Core::OutputChannel& out) override; }; From b5d1941e7ac31aadcf55320243d21cc9d46703f3 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 16 Jan 2025 17:31:20 +0000 Subject: [PATCH 05/21] Switch to Pipeline::Builder approach --- apps/emperor/CMakeLists.txt | 2 - apps/emperor/main.cc | 73 ++-- apps/emperor/pipelines/cartesian_grappa.h | 40 +- apps/emperor/pipelines/default.h | 33 +- apps/emperor/pipelines/noise.h | 13 +- apps/emperor/pipelines/pipeline.h | 409 ++++++++++++++---- apps/pingvin/StreamConsumer.h | 25 +- core/Context.h | 6 + core/Node.h | 32 +- core/Parameters.h | 82 ++++ core/PureGadget.h | 2 +- .../AcquisitionAccumulateTriggerGadget.cpp | 17 +- .../AcquisitionAccumulateTriggerGadget.h | 45 +- .../mri_core/AsymmetricEchoAdjustROGadget.h | 1 - gadgets/mri_core/BucketToBufferGadget.cpp | 35 +- gadgets/mri_core/BucketToBufferGadget.h | 35 +- gadgets/mri_core/ComplexToFloatGadget.h | 1 - gadgets/mri_core/ExtractGadget.cpp | 28 +- gadgets/mri_core/ExtractGadget.h | 50 +-- gadgets/mri_core/ImageArraySplitGadget.h | 5 +- gadgets/mri_core/NoiseAdjustGadget.cpp | 81 +--- gadgets/mri_core/NoiseAdjustGadget.h | 44 +- gadgets/mri_core/PCACoilGadget.cpp | 23 - gadgets/mri_core/PCACoilGadget.h | 3 - .../mri_core/RemoveROOversamplingGadget.cpp | 45 +- gadgets/mri_core/RemoveROOversamplingGadget.h | 10 +- gadgets/mri_core/SimpleReconGadget.h | 5 +- 27 files changed, 680 insertions(+), 465 deletions(-) create mode 100644 core/Parameters.h diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index d7c41767..d8615ad9 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -3,8 +3,6 @@ configure_file(../pingvin/pingvin_config.in pingvin_config.h) add_executable(emperor main.cc - ../pingvin/StreamConsumer.h - ../pingvin/ErrorHandler.h ../pingvin/nodes/Processable.h diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index 484e4b12..1625ef20 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -18,7 +18,7 @@ namespace fs = std::filesystem; namespace { -std::string envvar_to_parameter(const std::string& env_var) +std::string envvar_to_node_parameter(const std::string& env_var) { static const std::string prefix("PINGVIN_"); @@ -35,7 +35,8 @@ std::string envvar_to_parameter(const std::string& env_var) return option; } -} +} // namespace + int main(int argc, char** argv) { @@ -48,6 +49,9 @@ int main(int argc, char** argv) ("home", po::value()->default_value(pingvin_home), "Set the Pingvin home directory.") + ("config,c", po::value(), "Configuration file.") + ("input,i", po::value(), "Input stream (default=stdin)") + ("output,o", po::value(), "Output stream (default=stdout)") ; po::options_description hidden("Hidden options"); @@ -92,14 +96,11 @@ int main(int argc, char** argv) return 0; } - // "Register" all Pipelines - std::vector> pipelines; - pipelines.push_back(std::make_shared()); - pipelines.push_back(std::make_shared()); - // pipelines.push_back(std::make_shared()); - std::map> pipeline_map; - for (auto& pipeline : pipelines) { - pipeline_map[pipeline->name()] = pipeline; + // "Choose" a Pipeline + std::vector builders{&default_mr, &noise_dependency}; + std::map builder_map; + for (auto& builder : builders) { + builder_map[builder->name] = builder; } if (!vm.count("pipeline")) { @@ -109,42 +110,39 @@ int main(int argc, char** argv) << std::endl; std::cerr << help_options << std::endl; std::cerr << "Pipelines:" << std::endl; - for (auto& pipeline : pipelines) { - std::cerr << "┌ " << pipeline->name() << std::endl << "└──── " << pipeline->description() << std::endl; + for (auto& builder : builders) { + // std::cerr << "┌ " << builder->name << std::endl << "└──── " << builder->description << std::endl; + std::cerr << "- " << builder->name << std::endl << " └── " << builder->description << std::endl; } return 0; } else { std::cerr << "No pipeline specified" << std::endl; - return 1; } } std::string subcmd = vm["pipeline"].as(); - if (!pipeline_map.count(subcmd)) { + if (!builder_map.count(subcmd)) { std::cerr << "Unknown pipeline: " << subcmd << std::endl; return 1; } - std::cerr << "You chose pipeline: " << subcmd << std::endl; - auto& pipeline = pipeline_map[subcmd]; - - pipeline->build(); + auto& builder = builder_map[subcmd]; - po::options_description pipeline_desc("Pipeline Options"); - pipeline->install_cli(pipeline_desc); + po::options_description pipeline_options = builder->collect_options(); try { // Parse again for Pipeline - po::parsed_options parsed = po::basic_command_line_parser(unrecognized).options(pipeline_desc).run(); + po::parsed_options parsed = po::basic_command_line_parser(unrecognized).options(pipeline_options).run(); po::store(parsed, vm); if (vm.count("help")) { - std::cerr << pipeline->name() << ":" << std::endl << " " << pipeline->description() << std::endl << std::endl; - std::cerr << pipeline_desc << std::endl; + std::cerr << help_options << std::endl; + std::cerr << "Pipeline:" << std::endl; + std::cerr << pipeline_options << std::endl; return 0; } - po::store(po::parse_environment(pipeline_desc, envvar_to_parameter), vm); + po::store(po::parse_environment(pipeline_options, envvar_to_node_parameter), vm); if (vm.count("config")) { auto config_filename = vm["config"].as(); @@ -153,7 +151,7 @@ int main(int argc, char** argv) std::cerr << "Could not open config file: " << config_filename << std::endl; return 1; } - po::store(po::parse_config_file(config_file, pipeline_desc), vm); + po::store(po::parse_config_file(config_file, pipeline_options), vm); } po::notify(vm); @@ -164,9 +162,32 @@ int main(int argc, char** argv) return 1; } + std::unique_ptr input_file; + if (vm.count("input")) { + input_file = std::make_unique(vm["input"].as()); + if (!input_file->good()) { + std::cerr << "Could not open input file: " << vm["input"].as() << std::endl; + } + } + + std::unique_ptr output_file; + if (vm.count("output")) { + output_file = std::make_unique(vm["output"].as()); + if (!output_file->good()) { + std::cerr << "Could not open output file: " << vm["output"].as() << std::endl; + } + } + + std::istream& input_stream = input_file ? *input_file : std::cin; + std::ostream& output_stream = output_file ? *output_file : std::cout; + std::cerr << "Pingvin Home: " << vm["home"].as() << std::endl; - pipeline->run(vm); + auto pipeline = builder->build(input_stream, output_stream); + + pipeline.run(); + + std::flush(output_stream); std::cout << "Pingvin finished successfully" << std::endl; diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h index 3a223942..6184ea20 100644 --- a/apps/emperor/pipelines/cartesian_grappa.h +++ b/apps/emperor/pipelines/cartesian_grappa.h @@ -20,27 +20,23 @@ namespace pingvin { -class CartesianGrappa : public Pipeline { - public: - CartesianGrappa() : Pipeline("cartesian-grappa", "Cartesian Grappa Recon") { } - - void build(void) override { - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - } -}; +static auto cartesian_grappa = Pipeline::Builder("cartesian-grappa", "Cartesian Grappa Recon") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acquisition-accumulate") + .withNode("bucket-to-buffer") + .withNode("reference-prep") + .withNode("eigen-channel") + .withNode("grappa") + .withNode("pf-handling") + .withNode("kspace-filtering") + .withNode("fov-adjustment") + .withNode("image-array-scaling") + .withNode("image-split") + .withNode("complex-to-float") + .withNode("float-to-ushort"); } // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h index 2528e223..b921867e 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/emperor/pipelines/default.h @@ -11,26 +11,17 @@ namespace pingvin { -class Default : public Pipeline { - public: - Default() : Pipeline("default", "Basic Cartesian Reconstruction") { } - - void build(void) override { - // gadgets_.push_back(std::make_shared()); - // gadgets_.push_back(std::make_shared()); - - // gadgets_ = Builder() - // .append() - // .append() - // .build(); - - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - } -}; + using namespace Gadgetron; + +static auto default_mr = Pipeline::Builder("default", "Basic Cartesian Reconstruction") + .withSource() + .withSink() + .withNode("ros") + .withNode("accumulate") + .withNode("buffer") + .withNode("recon") + .withNode("image-split") + .withNode("extract") + ; } // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/noise.h b/apps/emperor/pipelines/noise.h index 70920cb6..fdad651c 100644 --- a/apps/emperor/pipelines/noise.h +++ b/apps/emperor/pipelines/noise.h @@ -6,13 +6,12 @@ namespace pingvin { -class NoiseDependency: public Pipeline { - public: - NoiseDependency() : Pipeline("noise", "Compute noise covariance for measurement dependency") { } + using namespace Gadgetron; - void build(void) override { - gadgets_.push_back(std::make_shared()); - } -}; + static auto noise_dependency = Pipeline::Builder("noise", "Compute noise covariance for measurement dependency") + .withSource() + .withSink() + .withNode("noise") + ; } // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index 521af281..890066bd 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -1,121 +1,352 @@ #pragma once -#include +#include +#include #include namespace po = boost::program_options; -#include "StreamConsumer.h" +#include "mrd/binary/protocols.h" + +#include "nodes/Stream.h" +#include "Channel.h" +#include "ErrorHandler.h" + +#include "Node.h" + namespace pingvin { -class Pipeline { - public: - Pipeline(std::string name, std::string description) : name_(name), description_(description) {} - virtual ~Pipeline() = default; - // using TempGadget = NewChannelGadget; +struct ISource { + virtual ~ISource() = default; + virtual void consume_input(Gadgetron::Core::ChannelPair& input_channel) = 0; +}; - // class Builder { - // public: - // Builder() {} +template +struct Source : public ISource { + virtual void setContext(CTX&) = 0; +}; - // template - // Builder& append(void) { - // auto n = std::make_shared(); - // nodes_.push_back(n); - // return *this; - // } +struct ISink { + virtual ~ISink() = default; + virtual void produce_output(Gadgetron::Core::ChannelPair& output_channel) = 0; +}; - // std::vector> build(void) { - // return nodes_; - // } - // template - // T build_pipeline(std::string name, std::string description) { - // // T p(name, description); - // T p; - // p.gadgets_ = nodes_; - // return std::move(p); - // } - // private: - // std::vector> nodes_; - // }; +///// BEGIN MRD ///// - virtual void build(void) = 0; +#include "mrd/types.h" - void run(po::variables_map& vm) { - std::cerr << "Running pipeline " << name_ << std::endl; +using MrdContext = Gadgetron::Core::MrdContext; - std::cerr << "OK, now running Pingvin" << std::endl; +struct MrdSource : public Source { + MrdSource(std::istream& input_stream): mrd_reader_(input_stream) {} - std::unique_ptr input_file; - if (vm.count("input")) { - input_file = std::make_unique(vm["input"].as()); - if (!input_file->good()) { - GERROR_STREAM("Could not open input file: " << vm["input"].as()); - } + void setContext(MrdContext& ctx) override { + std::optional hdr; + mrd_reader_.ReadHeader(hdr); + if (!hdr.has_value()) { + GADGET_THROW("Failed to read MRD header"); } - std::unique_ptr output_file; - if (vm.count("output")) { - output_file = std::make_unique(vm["output"].as()); - if (!output_file->good()) { - GERROR_STREAM("Could not open output file: " << vm["output"].as()); + ctx.header = hdr.value(); + } + + void consume_input(Gadgetron::Core::ChannelPair& input_channel) override + { + mrd::StreamItem stream_item; + while (mrd_reader_.ReadData(stream_item)) { + std::visit([&](auto&& arg) { + Gadgetron::Core::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); + } + +private: + mrd::binary::MrdReader mrd_reader_; +}; + +struct MrdSink : public ISink { + MrdSink(std::ostream& output_stream, const MrdContext& ctx) + : mrd_writer_(output_stream) + { + mrd_writer_.WriteHeader(ctx.header); + } + + void produce_output(Gadgetron::Core::ChannelPair& output_channel) override + { + while (true) { + try { + auto message = output_channel.input.pop(); + + using namespace Gadgetron::Core; + + 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 Gadgetron::Core::ChannelClosed& exc) { + break; } } - std::istream& input_stream = input_file ? *input_file : std::cin; - std::ostream& output_stream = output_file ? *output_file : std::cout; + mrd_writer_.EndData(); + mrd_writer_.Close(); + } - Context::Paths paths{ - (vm.count("home")) - ? vm["home"].as().string() - : "/opt/pingvin" - }; +private: + mrd::binary::MrdWriter mrd_writer_; +}; - mrd::binary::MrdReader mrd_reader(input_stream); - mrd::binary::MrdWriter mrd_writer(output_stream); +///// END MRD ///// - StreamConsumer consumer; - mrd::Header hdr = consumer.consume_mrd_header(mrd_reader, mrd_writer); +template +struct INodeBuilder { + virtual ~INodeBuilder() = default; + virtual std::shared_ptr build(const C& ctx) const = 0; + virtual Gadgetron::Core::NodeParameters get_parameters(void) = 0; +}; - auto context = StreamContext(hdr, paths, vm); +template +class NodeBuilder : public INodeBuilder { +public: + NodeBuilder(const std::string& label): label_(label), parameters_(label) {} - GDEBUG_STREAM("Initializing Gadgets"); - for (auto& g : gadgets_) { - g->initialize(context, GadgetProperties()); - } - GDEBUG_STREAM("Initialized Gadgets"); + virtual std::shared_ptr build(const CTX& ctx) const override { + return std::make_shared(ctx, this->parameters_); + } + + virtual Gadgetron::Core::NodeParameters get_parameters(void) override { + return parameters_; + } - auto stream = std::make_unique(processables_); - consumer.consume_stream(mrd_reader, mrd_writer, stream); +private: + std::string label_; + typename N::Parameters parameters_; +}; - std::flush(output_stream); - GDEBUG_STREAM("Finished consuming stream"); +class ErrorThrower : public Gadgetron::Main::ErrorReporter +{ + public: + void operator()(const std::string& location, const std::string& message) override { + throw std::runtime_error(("[" + location + "] ERROR: " + message)); + } +}; + +class NewNodeProcessable : public Gadgetron::Main::Processable { +public: + NewNodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} + + void process(Gadgetron::Core::GenericInputChannel input, + Gadgetron::Core::OutputChannel output, + Gadgetron::Main::ErrorHandler & + ) override { + node_->process(input, output); } - void install_cli(po::options_description& desc) { - desc.add_options() - ("help,h", "Show help message") - ("config,c", po::value(), "Pipeline configuration file") - ("input,i", po::value(), "Input stream") - ("output,o", po::value(), "Output stream") - ; - - po::options_description gadgets("Pipeline Nodes"); - - for (auto& g: gadgets_) { - po::options_description group(g->name()); - g->install_cli(group); - if (!group.options().empty()) { - gadgets.add(group); + const std::string& name() override { + return name_; + } + +private: + std::shared_ptr node_; + const std::string name_; +}; + +class Pipeline { + public: + + struct IBuilder { + IBuilder(const std::string& name, const std::string& description): name(name), description(description) { } + virtual Pipeline build(std::istream& input_stream, std::ostream& output_stream) = 0; + virtual po::options_description collect_options(void) = 0; + virtual ~IBuilder() = default; + + const std::string name; + const std::string description; + }; + + template + struct Builder : public IBuilder{ + Builder(const std::string& pipeline_name, const std::string& pipeline_description) + : IBuilder(pipeline_name, pipeline_description) {} + + template + Builder& withSource(void) { + source_builder_ = [](std::istream& is) { return std::make_shared(is); }; + return *this; + } + + template + Builder& withSink(void) { + sink_builder_ = [](std::ostream& os, const CTX& ctx) { return std::make_shared(os, ctx); }; + return *this; + } + + template + Builder& withNode(const std::string& label) { + auto nb = std::make_shared>(label); + builders_.emplace_back(nb); + return *this; + } + + po::options_description collect_options(void) override { + po::options_description pipeline_desc(this->description); + + for (auto& nb: builders_) { + Gadgetron::Core::NodeParameters node_params = nb->get_parameters(); + po::options_description node_desc(node_params.description()); + + if (node_params.parameters().size() > 0) { + for (auto& p: node_params.parameters()) { + node_desc.add(p->as_boost_option()); + } + + pipeline_desc.add(node_desc); + } } + return pipeline_desc; } - desc.add(gadgets); + Pipeline build(std::istream& input_stream, std::ostream& output_stream) override { + std::cerr << "Building pipeline " << pipeline_name << std::endl; + + if (!source_builder_) { + throw std::runtime_error("No source specified"); + } + if (!sink_builder_) { + throw std::runtime_error("No sink specified"); + } + auto source = source_builder_(input_stream); + + CTX ctx; + source->setContext(ctx); + + auto sink = sink_builder_(output_stream, ctx); + + std::vector> nodes; + for (auto& builder : builders_) { + nodes.emplace_back(builder->build(ctx)); + } + + Pipeline pipeline; + pipeline.source_ = source; + pipeline.sink_ = sink; + pipeline.nodes_ = std::move(nodes); + + return std::move(pipeline); + } + + std::function>(std::istream&)> source_builder_; + std::function(std::ostream&, const CTX&)> sink_builder_; + + std::vector>> builders_; + + const std::string pipeline_name; + }; + + virtual ~Pipeline() = default; + + void run(void) { + /** TODO: This is the only thing not yet "ported" to the new Pipeline::Builder technique: + * + * The Context object previously held a `std::string gadgetron_home`, that could be configured + * from the CLI. + * + * However, this Path is only used in TWO Gadgets, and it is only used to load Python files. + * These Gadgets can be updated to read the Python file paths from its own CLI parameters... + * + * Otherwise, the GADGETRON_HOME path can be queried from the `static default_gadgetron_home()` function. + */ + // Context::Paths paths{ + // (vm.count("home")) + // ? vm["home"].as().string() + // : "/opt/pingvin" + // }; + // auto context = StreamContext(hdr, paths, vm); + + std::vector> processables; + for (auto& node: nodes_) { + processables.emplace_back(std::make_shared(node, "TODO")); + } + + auto stream = std::make_unique(processables); + + auto input_channel = Gadgetron::Core::make_channel(); + auto output_channel = Gadgetron::Core::make_channel(); + std::atomic processing = true; + + auto process_future = std::async(std::launch::async, [&]() { + try + { + ErrorThrower error_thrower; + Gadgetron::Main::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 + { + source_->consume_input(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, [&]() + { + sink_->produce_output(output_channel); + }); + + // Clean up and propagate exceptions if they occurred + input_future.get(); + output_future.get(); + process_future.get(); + + GDEBUG_STREAM("Finished consuming stream"); } std::string name(void) const { return name_; } @@ -123,21 +354,13 @@ class Pipeline { protected: - template - void append(void) { - auto n = std::make_shared(); - gadgets_.emplace_back(n); - processables_.emplace_back(std::make_shared(n, "TODO")); - } - - // template - // void appendParallel() - std::string name_; std::string description_; - std::vector> gadgets_; - std::vector> processables_; + std::shared_ptr source_; + std::shared_ptr sink_; + + std::vector> nodes_; }; } // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/StreamConsumer.h b/apps/pingvin/StreamConsumer.h index 3287b87e..b2dca9cc 100644 --- a/apps/pingvin/StreamConsumer.h +++ b/apps/pingvin/StreamConsumer.h @@ -116,19 +116,18 @@ class StreamConsumer process_future.get(); } - - 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(); - } + // 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(); + // } private: diff --git a/core/Context.h b/core/Context.h index 4a711e51..65a0ec61 100644 --- a/core/Context.h +++ b/core/Context.h @@ -6,6 +6,12 @@ namespace Gadgetron::Core { + /** TODO: Move to MR-specific location */ + struct MrdContext { + mrd::Header header; + }; + + struct Context { using Header = mrd::Header; diff --git a/core/Node.h b/core/Node.h index e47fe9d8..2dc488b8 100644 --- a/core/Node.h +++ b/core/Node.h @@ -1,5 +1,6 @@ #pragma once +#include "Parameters.h" #include "Channel.h" #include "PropertyMixin.h" #include "Context.h" @@ -26,28 +27,14 @@ namespace Gadgetron::Core { class GenericChannelGadget : public Node, public PropertyMixin { public: - GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header} {} - GenericChannelGadget(const std::string& name, const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header}, name_(name) {} - - void initialize(const Core::Context& context, const GadgetProperties& properties) { - this->properties = properties; - this->header = context.header; - this->initialize_(context); - } + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; - virtual void install_cli(po::options_description& options) {} - - /** TODO: Consider renaming to "key" or "label" */ - virtual std::string name() { return name_; } + GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header} {} protected: - virtual void initialize_(const Context& context) {} - - /** TODO: No longer const, so it can be set in `initialize()` after construction */ - // const mrd::Header header ={}; - mrd::Header header ={}; - - std::string name_; + const mrd::Header header ={}; }; /** @@ -61,8 +48,6 @@ namespace Gadgetron::Core { using GenericChannelGadget::GenericChannelGadget; - ChannelGadget(const std::string name): GenericChannelGadget(name, Context{}, GadgetProperties{}) { } - /// void process(GenericInputChannel& in, OutputChannel& out) override final { auto typed_input = InputChannel(in, out); @@ -78,6 +63,8 @@ namespace Gadgetron::Core { }; } +/** TODO: Delete everywhere */ +/* #define GADGETRON_GADGET_EXPORT(GadgetClass) \ std::unique_ptr gadget_factory_##GadgetClass( \ const Gadgetron::Core::Context& context, \ @@ -86,3 +73,6 @@ namespace Gadgetron::Core { return std::make_unique(context, props); \ } \ BOOST_DLL_ALIAS(gadget_factory_##GadgetClass, gadget_factory_export_##GadgetClass) +*/ + +#define GADGETRON_GADGET_EXPORT(GadgetClass) \ No newline at end of file diff --git a/core/Parameters.h b/core/Parameters.h new file mode 100644 index 00000000..433a35bf --- /dev/null +++ b/core/Parameters.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include + +namespace Gadgetron::Core { + +namespace po = boost::program_options; + + +struct IParameter { + virtual boost::shared_ptr as_boost_option(void) const = 0; + virtual ~IParameter() = default; +}; + +template +class Parameter : public IParameter { +public: + Parameter(const std::string& name, T* storage, const std::string& description) + : storage_(storage), name_(name), description_(description) {} + + boost::shared_ptr as_boost_option(void) const override + { + return boost::make_shared( + name_.c_str(), + po::value(storage_)->default_value(*storage_), + description_.c_str() + ); + } + +protected: + T* storage_; + std::string name_; + std::string description_; +}; + +class Flag : public Parameter { +public: + using Parameter::Parameter; + + boost::shared_ptr as_boost_option(void) const override + { + return boost::make_shared( + name_.c_str(), + po::bool_switch(this->storage_)->default_value(*this->storage_), + description_.c_str() + ); + } +}; + +class NodeParameters { +public: + NodeParameters(const std::string& prefix, const std::string& description): prefix_(prefix), description_(description) {} + NodeParameters(const std::string& prefix): prefix_(prefix) {} + + template + void register_parameter(const std::string& name, T* value, const std::string& description) { + auto argname = prefix_ + "." + name; + parameters_.push_back(std::make_shared>(argname, value, description)); + } + + void register_flag(const std::string& name, bool* value, const std::string& description) { + auto argname = prefix_ + "." + name; + parameters_.push_back(std::make_shared(argname, value, description)); + } + + const std::vector>& parameters() const { + return parameters_; + } + + std::string description(void) const { + return description_; + } + +private: + std::string prefix_; + std::string description_; + std::vector> parameters_; +}; + + +} // namespace Gadgetron::Core \ No newline at end of file diff --git a/core/PureGadget.h b/core/PureGadget.h index 5b307281..d64a831a 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -5,7 +5,7 @@ namespace Gadgetron::Core { class GenericPureGadget : public GenericChannelGadget { public: using GenericChannelGadget::GenericChannelGadget; - GenericPureGadget(const std::string name): GenericChannelGadget(name, Context{}, GadgetProperties{}) { } + GenericPureGadget(): GenericChannelGadget(Context{}, GadgetProperties{}) { } void process(GenericInputChannel&in, OutputChannel &out) final { for (auto message : in) diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp index 20ef3e62..663e4af5 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp @@ -85,7 +85,7 @@ namespace Gadgetron { using Trigger = std::variant; Trigger get_trigger(const AcquisitionAccumulateTriggerGadget& gadget) { - switch (gadget.trigger_dimension) { + switch (gadget.parameters_.trigger_dimension) { case TriggerDimension::kspace_encode_step_1: case TriggerDimension::kspace_encode_step_2: @@ -103,8 +103,8 @@ namespace Gadgetron { case TriggerDimension::user_4: case TriggerDimension::user_5: case TriggerDimension::user_6: - case TriggerDimension::user_7: return EqualityTrigger(gadget.trigger_dimension); - case TriggerDimension::n_acquisitions: return NumAcquisitionsTrigger(gadget.n_acquisitions_before_trigger,gadget.n_acquisitions_before_ongoing_trigger); + case TriggerDimension::user_7: return EqualityTrigger(gadget.parameters_.trigger_dimension); + case TriggerDimension::n_acquisitions: return NumAcquisitionsTrigger(gadget.parameters_.n_acquisitions_before_trigger, gadget.parameters_.n_acquisitions_before_ongoing_trigger); case TriggerDimension::none: return NoneTrigger(); default: throw std::runtime_error("ENUM TriggerDimension is in an invalid state."); } @@ -156,7 +156,7 @@ namespace Gadgetron { send_data(out, buckets, waveforms); } // It is enough to put the first one, since they are linked - auto sorting_index = get_index(acq.head, sorting_dimension); + auto sorting_index = get_index(acq.head, parameters_.sorting_dimension); mrd::AcquisitionBucket& bucket = buckets[sorting_index]; Gadgetron::add_acquisition_to_bucket(bucket, std::move(acq)); @@ -170,15 +170,6 @@ namespace Gadgetron { send_data(out, buckets, waveforms); } - void AcquisitionAccumulateTriggerGadget::install_cli(po::options_description& desc) - { - desc.add_options() - ("trigger_dimension", po::value(&trigger_dimension)->default_value(TriggerDimension::none), "Dimension to trigger on") - ("sorting_dimension", po::value(&sorting_dimension)->default_value(TriggerDimension::none), "Dimension to sort on") - ("n_acquisitions_before_trigger", po::value(&n_acquisitions_before_trigger)->default_value(40), "Number of acquisitions before first trigger") - ("n_acquisitions_before_ongoing_trigger", po::value(&n_acquisitions_before_ongoing_trigger)->default_value(40), "Number of acquisitions before ongoing triggers"); - } - GADGETRON_GADGET_EXPORT(AcquisitionAccumulateTriggerGadget); namespace { diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h index d70885a6..defe5a57 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h @@ -11,14 +11,6 @@ namespace Gadgetron { class AcquisitionAccumulateTriggerGadget : public Core::ChannelGadget> { public: - using Core::ChannelGadget>::ChannelGadget; - AcquisitionAccumulateTriggerGadget() : ChannelGadget("accumulate_trigger") {} - - void process(Core::InputChannel>& in, - Core::OutputChannel& out) override; - - void install_cli(po::options_description& desc) override; - enum class TriggerDimension { kspace_encode_step_1, kspace_encode_step_2, @@ -40,18 +32,47 @@ namespace Gadgetron { n_acquisitions, none }; - NODE_PROPERTY(trigger_dimension, TriggerDimension, "Dimension to trigger on", TriggerDimension::none); - NODE_PROPERTY(sorting_dimension, TriggerDimension, "Dimension to trigger on", TriggerDimension::none); - NODE_PROPERTY(n_acquisitions_before_trigger, unsigned long, "Number of acquisition before first trigger", 40); - NODE_PROPERTY(n_acquisitions_before_ongoing_trigger, unsigned long, "Number of acquisition before ongoing triggers", 40); + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Acquisition Accumulate Trigger Options") { + register_parameter("trigger-dimension", &trigger_dimension, "Dimension to trigger on"); + register_parameter("sorting-dimension", &sorting_dimension, "Dimension to sort on"); + register_parameter("n-acquisitions-before-trigger", &n_acquisitions_before_trigger, + "Number of acquisition before first trigger"); + register_parameter("n-acquisitions-before-ongoing-trigger", &n_acquisitions_before_ongoing_trigger, + "Number of acquisition before ongoing triggers"); + } + TriggerDimension trigger_dimension = TriggerDimension::none; + TriggerDimension sorting_dimension = TriggerDimension::none; + unsigned long n_acquisitions_before_trigger = 40; + unsigned long n_acquisitions_before_ongoing_trigger = 40; + }; + + AcquisitionAccumulateTriggerGadget(const Core::Context& context, const Core::GadgetProperties& props) + : Core::ChannelGadget>( + Core::Context{.header = context.header}, Core::GadgetProperties{}) + , parameters_("TODO: This constructor only exists because it is used by unit test") + { } + + AcquisitionAccumulateTriggerGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget>( + Core::Context{.header = context.header}, Core::GadgetProperties{}) + , parameters_(params) {} + + void process(Core::InputChannel>& in, + Core::OutputChannel& out) override; + const Parameters parameters_; size_t trigger_events = 0; private: void send_data(Core::OutputChannel& out, std::map& buckets, std::vector& waveforms); }; + std::ostream& operator<<(std::ostream& out, const AcquisitionAccumulateTriggerGadget::TriggerDimension& param); + void validate(boost::any& v, const std::vector& values, AcquisitionAccumulateTriggerGadget::TriggerDimension*, int); + void from_string(const std::string& str, AcquisitionAccumulateTriggerGadget::TriggerDimension& val); } diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h index fdec1907..f40b7ea0 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h @@ -15,7 +15,6 @@ namespace Gadgetron{ { public: using Core::ChannelGadget::ChannelGadget; - AsymmetricEchoAdjustROGadget() : ChannelGadget("asymmetric_echo_adjust") {} AsymmetricEchoAdjustROGadget(const Core::Context& context, const Core::GadgetProperties& props); ~AsymmetricEchoAdjustROGadget() override = default; void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/BucketToBufferGadget.cpp b/gadgets/mri_core/BucketToBufferGadget.cpp index 99be6200..0a6b9896 100644 --- a/gadgets/mri_core/BucketToBufferGadget.cpp +++ b/gadgets/mri_core/BucketToBufferGadget.cpp @@ -131,11 +131,11 @@ namespace Gadgetron { BufferKey BucketToBufferGadget::getKey(const mrd::EncodingCounters& idx) const { BufferKey key(idx); - clear(N_dimension, key); - clear(S_dimension, key); - if (!split_slices) + clear(parameters_.N_dimension, key); + clear(parameters_.S_dimension, key); + if (!parameters_.split_slices) key.slice = 0; - if (ignore_segment) + if (parameters_.ignore_segment) key.segment = 0; return key; } @@ -188,10 +188,10 @@ namespace Gadgetron { uint32_t NE2 = getNE2(encoding, stats, forref); size_t NCHA = acq.Coils(); uint32_t NLOC = getNLOC(encoding, stats); - uint32_t NN = getSizeFromDimension(N_dimension, stats); - uint32_t NS = getSizeFromDimension(S_dimension, stats); + uint32_t NN = getSizeFromDimension(parameters_.N_dimension, stats); + uint32_t NS = getSizeFromDimension(parameters_.S_dimension, stats); - GDEBUG_CONDITION_STREAM(verbose, "Data dimensions [RO E1 E2 CHA N S SLC] : [" + GDEBUG_CONDITION_STREAM(parameters_.verbose, "Data dimensions [RO E1 E2 CHA N S SLC] : [" << NE0 << " " << NE1 << " " << NE2 << " " << NCHA << " " << NN << " " << NS << " " << NLOC << "]"); @@ -221,7 +221,7 @@ namespace Gadgetron { uint32_t BucketToBufferGadget::getNLOC( const mrd::EncodingType& encoding, const mrd::EncodingLimitsType& stats) const { uint32_t NLOC; - if (split_slices) { + if (parameters_.split_slices) { NLOC = 1; } else { if (encoding.encoding_limits.slice.has_value()) { @@ -343,7 +343,7 @@ namespace Gadgetron { sampling.sampling_limits.kspace_encoding_step_2.maximum = encoding.encoding_limits.kspace_encoding_step_2->maximum; sampling.sampling_limits.kspace_encoding_step_2.center = encoding.encoding_limits.kspace_encoding_step_2->center; - if (verbose) { + if (parameters_.verbose) { GDEBUG_STREAM("Encoding space : " << acq.head.encoding_space_ref.value_or(0) << " - " << int(encoding.trajectory) << " - FOV : [ " << encoding.encoded_space.field_of_view_mm.x << " " << encoding.encoded_space.field_of_view_mm.y << " " << encoding.encoded_space.field_of_view_mm.z @@ -432,7 +432,7 @@ namespace Gadgetron { sampling.sampling_limits.kspace_encoding_step_2.center = encoding.encoding_limits.kspace_encoding_step_2->center; } - if (verbose) { + if (parameters_.verbose) { GDEBUG_STREAM("Encoding space : " << int(encoding.trajectory) << " - FOV : [ " << encoding.encoded_space.field_of_view_mm.x << " " << encoding.encoded_space.field_of_view_mm.y << " " << encoding.encoded_space.field_of_view_mm.z @@ -462,7 +462,7 @@ namespace Gadgetron { uint16_t NS = (uint16_t)dataBuffer.data.get_size(5); uint16_t NLOC = (uint16_t)dataBuffer.data.get_size(6); - const size_t slice_loc = split_slices || NLOC == 1 ? 0 : acq.head.idx.slice.value_or(0); + const size_t slice_loc = parameters_.split_slices || NLOC == 1 ? 0 : acq.head.idx.slice.value_or(0); // Stuff the data uint32_t npts_to_copy = acq.Samples() - acq.head.discard_pre.value_or(0) - acq.head.discard_post.value_or(0); @@ -488,11 +488,11 @@ namespace Gadgetron { throw std::runtime_error("Acquired reference data does not fit into the reference data buffer.\n"); } - uint32_t NUsed = (uint32_t)getDimensionKey(N_dimension, acq.head.idx); + uint32_t NUsed = (uint32_t)getDimensionKey(parameters_.N_dimension, acq.head.idx); if (NUsed >= NN) NUsed = NN - 1; - uint32_t SUsed = (uint32_t)getDimensionKey(S_dimension, acq.head.idx); + uint32_t SUsed = (uint32_t)getDimensionKey(parameters_.S_dimension, acq.head.idx); if (SUsed >= NS) SUsed = NS - 1; @@ -602,15 +602,6 @@ namespace Gadgetron { }; } - void BucketToBufferGadget::install_cli(po::options_description& desc) { - desc.add_options() - ("N_dimension", po::value(&N_dimension)->default_value(Dimension::none), "N-Dimensions") - ("S_dimension", po::value(&S_dimension)->default_value(Dimension::none), "S-Dimensions") - ("split_slices", po::value(&split_slices)->default_value(false), "Split slices") - ("ignore_segment", po::value(&ignore_segment)->default_value(false), "Ignore segment") - ("verbose", po::value(&verbose)->default_value(false), "Whether to print more information"); - } - void from_string(const std::string& str, BucketToBufferGadget::Dimension& dim) { auto lower = str; boost::to_lower(lower); diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 274c8bb7..2509d080 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -19,11 +19,31 @@ namespace Gadgetron { class BucketToBufferGadget : public Core::ChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - BucketToBufferGadget() : ChannelGadget("bucket_to_buffer") {} + enum class Dimension { average, contrast, phase, repetition, set, segment, slice, none }; - virtual void install_cli(po::options_description& desc) override; + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Bucket To Buffer Options") + { + register_parameter("N-dimensions", &N_dimension, "N-Dimensions"); + register_parameter("S-dimensions", &S_dimension, "S-Dimensions"); + register_flag("split-slices", &split_slices, "Split slices"); + register_flag("ignore-segment", &ignore_segment, "Ignore segment"); + register_flag("verbose", &verbose, "Whether to print more information"); + } + Dimension N_dimension = Dimension::none; + Dimension S_dimension = Dimension::none; + bool split_slices = false; + bool ignore_segment = false; + bool verbose = false; + }; + + using Core::ChannelGadget::ChannelGadget; + BucketToBufferGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + , parameters_(params) + { } struct BufferKey { uint32_t average,slice,contrast,phase,repetition,set,segment; @@ -40,12 +60,7 @@ namespace Gadgetron { }; protected: - NODE_PROPERTY(N_dimension, Dimension, "N-Dimensions", Dimension::none); - NODE_PROPERTY(S_dimension, Dimension, "S-Dimensions", Dimension::none); - - NODE_PROPERTY(split_slices, bool, "Split slices", false); - NODE_PROPERTY(ignore_segment, bool, "Ignore segment", false); - NODE_PROPERTY(verbose, bool, "Whether to print more information", false); + Parameters parameters_; void process(Core::InputChannel& in, Core::OutputChannel& out) override; BufferKey getKey(const mrd::EncodingCounters& idx) const; @@ -66,4 +81,6 @@ namespace Gadgetron { }; void from_string(const std::string&, BucketToBufferGadget::Dimension&); + std::ostream& operator<<(std::ostream& out, const BucketToBufferGadget::Dimension& param); + void validate(boost::any& v, const std::vector& values, BucketToBufferGadget::Dimension*, int); } diff --git a/gadgets/mri_core/ComplexToFloatGadget.h b/gadgets/mri_core/ComplexToFloatGadget.h index 52fb7ae4..5083ed57 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.h +++ b/gadgets/mri_core/ComplexToFloatGadget.h @@ -12,7 +12,6 @@ namespace Gadgetron class ComplexToFloatGadget: public Core::PureGadget,mrd::Image>> { public: - ComplexToFloatGadget() : Core::PureGadget,mrd::Image>>("complex_to_float") {} ComplexToFloatGadget(const Core::Context& context, const Core::GadgetProperties& props); mrd::Image process_function(mrd::Image> args) const override; diff --git a/gadgets/mri_core/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index 544ca329..63fd2b1b 100644 --- a/gadgets/mri_core/ExtractGadget.cpp +++ b/gadgets/mri_core/ExtractGadget.cpp @@ -57,7 +57,7 @@ namespace Gadgetron { extracted.head = image.head; extracted.head.image_type = imtype; extracted.head.image_series_index = image.head.image_series_index.value_or(0) + series_offset.at(imtype); - extracted.data = extract_image(image.data, imtype, real_imag_offset); + extracted.data = extract_image(image.data, imtype, parameters_.real_imag_offset); extracted.meta = image.meta; out.push(std::move(extracted)); @@ -65,26 +65,28 @@ namespace Gadgetron { } } - ExtractGadget::ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget>>(context, props) { - - for (int i = 0; i < extract_mask.size(); i++) { - if (extract_mask[i]) + ExtractGadget::ExtractGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget>>(Core::Context{.header = context.header}, Core::GadgetProperties{}) + , parameters_(params) + { + for (int i = 0; i < parameters_.extract_mask.size(); i++) { + if (parameters_.extract_mask[i]) { image_types.insert(mask_to_imtype.at(i)); + } } - if (extract_magnitude) + if (parameters_.extract_magnitude) image_types.insert(mrd::ImageType::kMagnitude); - if (extract_real) + if (parameters_.extract_real) image_types.insert(mrd::ImageType::kReal); - if (extract_imag) + if (parameters_.extract_imag) image_types.insert(mrd::ImageType::kImag); - if (extract_phase) + if (parameters_.extract_phase) image_types.insert(mrd::ImageType::kPhase); - if (image_types.empty()) - throw std::runtime_error("ExctractGadget: No valid extract functions specified"); + if (image_types.empty()) { + GADGET_THROW("ExtractGadget: No valid extract functions specified"); + } } GADGETRON_GADGET_EXPORT(ExtractGadget) - } diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index 30b8c335..2d5103c2 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -9,40 +9,30 @@ namespace Gadgetron { class ExtractGadget : public Core::ChannelGadget>> { public: - using Core::ChannelGadget>>::ChannelGadget; - ExtractGadget() : ChannelGadget("extract") {} - ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props); + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Extract Options") { + register_parameter("mask", &extract_mask, "(DEPRECATED) Extract mask, bitmask MAG=1, REAL=2, IMAG=4, PHASE=8"); + register_flag("magnitude", &extract_magnitude, "Extract absolute value"); + register_flag("real", &extract_real, "Extract real components"); + register_flag("imag", &extract_imag, "Extract imaginary component"); + register_flag("phase", &extract_phase, "Extract phase"); + register_parameter("real-imag-offset", &real_imag_offset, "Offset to add to real and imag images"); + } + std::bitset<4> extract_mask = 0; + bool extract_magnitude = false; + bool extract_real = false; + bool extract_imag = false; + bool extract_phase = false; + float real_imag_offset = 0.0f; + }; - void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; + ExtractGadget(const Core::MrdContext& context, const Parameters& params); - virtual void install_cli(po::options_description& options) override { - options.add_options() - ("extract_magnitude", po::bool_switch(&extract_magnitude), "Extract absolute value") - ("extract_real", po::bool_switch(&extract_real), "Extract real components") - ("extract_imag", po::bool_switch(&extract_imag), "Extract imaginary component") - ("extract_phase", po::bool_switch(&extract_phase), "Extract phase") - ("real_imag_offset", po::value(&real_imag_offset)->default_value(0.0f), "Offset to add to real and imag images"); - } + void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; protected: - NODE_PROPERTY(extract_mask, std::bitset<4>, "(DEPRECATED) Extract mask, bitmask MAG=1, REAL=2, IMAG=4, PHASE=8", 0); - NODE_PROPERTY(extract_magnitude, bool, "Extract absolute value", true); - NODE_PROPERTY(extract_real, bool, "Extract real components", false); - NODE_PROPERTY(extract_imag, bool, "Extract imaginary component", false); - NODE_PROPERTY(extract_phase, bool, "Extract phase", false); - NODE_PROPERTY(real_imag_offset, float, "Offset to add to real and imag images", 0.0f); - - virtual void initialize_(const Core::Context& context) override { - if (!extract_magnitude && !extract_real && !extract_imag && !extract_phase) { - // throw std::runtime_error("No images selected for extraction"); - GADGET_THROW("No images selected for extraction"); - } - - if (extract_magnitude) image_types.insert(mrd::ImageType::kMagnitude); - if (extract_real) image_types.insert(mrd::ImageType::kReal); - if (extract_imag) image_types.insert(mrd::ImageType::kImag); - if (extract_phase) image_types.insert(mrd::ImageType::kPhase); - } + Parameters parameters_; std::set image_types; }; diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 88bc73f7..8b8da45e 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.h +++ b/gadgets/mri_core/ImageArraySplitGadget.h @@ -16,8 +16,9 @@ namespace Gadgetron{ class ImageArraySplitGadget : public Core::ChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - ImageArraySplitGadget() : ChannelGadget("image_array_split") {} + ImageArraySplitGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + { } void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; } diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index cd5ca25c..fadd54a7 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -181,70 +181,29 @@ namespace Gadgetron { } } - void NoiseAdjustGadget::install_cli(po::options_description& options) { - options.add_options() - ("noise_covariance_in", po::value(&noise_covariance_in), "Input noise covariance matrix") - ("noise_covariance_out", po::value(&noise_covariance_out), "Output noise covariance matrix") - ("perform_noise_adjust", po::value(&perform_noise_adjust)->default_value(true), "Whether to actually perform the noise adjust") - ("pass_nonconformant_data", po::value(&pass_nonconformant_data)->default_value(true), "Whether to pass data that does not conform") - ("noise_dwell_time_us_preset", po::value(&noise_dwell_time_us_preset)->default_value(0.0), "Preset dwell time for noise measurement") - ("scale_only_channels_by_name", po::value(&scale_only_channels_by_name), "List of named channels that should only be scaled") - ; - } - - void NoiseAdjustGadget::initialize_(const Core::Context& context) { - this->receiver_noise_bandwidth = bandwidth_from_header(context.header); - this->measurement_id = measurement_id_from_header(context.header); - - GDEBUG("perform_noise_adjust_ is %d\n", perform_noise_adjust); - GDEBUG("pass_nonconformant_data_ is %d\n", pass_nonconformant_data); - GDEBUG("receiver_noise_bandwidth_ is %f\n", receiver_noise_bandwidth); - - if (!perform_noise_adjust) - return; - -#ifdef USE_OMP - omp_set_num_threads(1); -#endif // USE_OMP - - // if (context.parameters.find("noisecovariancein") != context.parameters.end()) { - // noise_covariance_in = context.parameters.at("noisecovariancein"); - // GDEBUG_STREAM("Input noise covariance matrix is provided as a parameter: " << noise_covariance_in); - // } - - // if (context.parameters.find("noisecovarianceout") != context.parameters.end()) { - // noise_covariance_out = context.parameters.at("noisecovarianceout"); - // GDEBUG_STREAM("Output noise covariance matrix is provided as a parameter: " << noise_covariance_out); - // } - - noisehandler = load_or_gather(); - } - - NoiseAdjustGadget::NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) + NoiseAdjustGadget::NoiseAdjustGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + , parameters_(params) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } , measurement_id{ measurement_id_from_header(context.header) } { + GDEBUG_STREAM("skip_noise_adjust is " << parameters_.skip_noise_adjust); + GDEBUG_STREAM("discard_nonconformant_data is " << parameters_.discard_nonconformant_data); + GDEBUG_STREAM("receiver_noise_bandwidth is " << receiver_noise_bandwidth); - if (!perform_noise_adjust) + if (parameters_.skip_noise_adjust) return; - GDEBUG("perform_noise_adjust_ is %d\n", perform_noise_adjust); - GDEBUG("pass_nonconformant_data_ is %d\n", pass_nonconformant_data); - GDEBUG("receiver_noise_bandwidth_ is %f\n", receiver_noise_bandwidth); - #ifdef USE_OMP omp_set_num_threads(1); #endif // USE_OMP - if (context.parameters.find("noisecovariancein") != context.parameters.end()) { - noise_covariance_in = context.parameters.at("noisecovariancein"); - GDEBUG_STREAM("Input noise covariance matrix is provided as a parameter: " << noise_covariance_in); + if (!parameters_.noise_covariance_in.empty()) { + GDEBUG_STREAM("Input noise covariance matrix provided as a parameter: " << parameters_.noise_covariance_in); } - if (context.parameters.find("noisecovarianceout") != context.parameters.end()) { - noise_covariance_out = context.parameters.at("noisecovarianceout"); - GDEBUG_STREAM("Output noise covariance matrix is provided as a parameter: " << noise_covariance_out); + if (!parameters_.noise_covariance_out.empty()) { + GDEBUG_STREAM("Output noise covariance matrix provided as a parameter: " << parameters_.noise_covariance_out); } noisehandler = load_or_gather(); @@ -347,17 +306,17 @@ namespace Gadgetron { noise_covariance.receiver_noise_bandwidth = receiver_noise_bandwidth; noise_covariance.matrix = ng.tmp_covariance; - if (!noise_covariance_out.empty()) { - std::ofstream os(noise_covariance_out, std::ios::out | std::ios::binary); + if (!parameters_.noise_covariance_out.empty()) { + std::ofstream os(parameters_.noise_covariance_out, std::ios::out | std::ios::binary); if (os.is_open()) { - GDEBUG("Writing noise covariance to %s\n", noise_covariance_out.c_str()); + GDEBUG_STREAM("Writing noise covariance to " << parameters_.noise_covariance_out); mrd::binary::MrdNoiseCovarianceWriter writer(os); writer.WriteNoiseCovariance(noise_covariance); writer.Close(); os.flush(); os.close(); } else { - GERROR("Unable to open file %s for writing noise covariance\n", noise_covariance_out.c_str()); + GERROR_STREAM("Unable to open file " << parameters_.noise_covariance_out << " for writing noise covariance"); throw std::runtime_error("Unable to open file for writing noise covariance"); } } else { @@ -384,7 +343,7 @@ namespace Gadgetron { auto dataM = as_arma_matrix(acq.data); auto pwm = as_arma_matrix(pw.prewhitening_matrix); dataM *= pwm; - } else if (!this->pass_nonconformant_data) { + } else if (!parameters_.discard_nonconformant_data) { throw std::runtime_error("Input data has different number of channels from noise data"); } return std::move(pw); @@ -426,7 +385,7 @@ namespace Gadgetron { void NoiseAdjustGadget::process(Core::InputChannel& input, Core::OutputChannel& output) { scale_only_channels = header.acquisition_system_information - ? find_scale_only_channels(scale_only_channels_by_name, + ? find_scale_only_channels(parameters_.scale_only_channels_by_name, header.acquisition_system_information->coil_label) : std::vector{}; @@ -444,10 +403,10 @@ namespace Gadgetron { /** Returns NoiseCovariance if loaded from file/stream, otherwise None */ std::optional NoiseAdjustGadget::load_noisedata() const { - if (!noise_covariance_in.empty()) { - std::ifstream file(noise_covariance_in, std::ios::binary); + if (!parameters_.noise_covariance_in.empty()) { + std::ifstream file(parameters_.noise_covariance_in, std::ios::binary); if (!file) { - GERROR("Could not open noise covariance file %s\n", noise_covariance_in.c_str()); + GERROR_STREAM("Could not open noise covariance file " << parameters_.noise_covariance_in); GWARN("Falling back to noise gathering\n"); // throw std::runtime_error("Could not open noise covariance file"); return std::nullopt; diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index e2a12afc..21c65c8b 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -28,29 +28,39 @@ namespace Gadgetron { class NoiseAdjustGadget : public Core::ChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - NoiseAdjustGadget() : ChannelGadget("noise_adjust") {} - NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props); - - void install_cli(po::options_description& options) override; + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + // File names for file storage and retrival of noise covariance + std::string noise_covariance_in = ""; + std::string noise_covariance_out = ""; + + bool skip_noise_adjust = false; + bool discard_nonconformant_data = false; + float noise_dwell_time_us_preset = 0.0; + std::string scale_only_channels_by_name = ""; + + Parameters(const std::string& prefix) : NodeParameters(prefix, "Noise Adjustment Options") { + register_parameter("covariance-input", &noise_covariance_in, "Input file containing noise covariance matrix"); + register_parameter("covariance-output", &noise_covariance_out, "Output file containing noise covariance matrix"); + register_flag("skip", &skip_noise_adjust, "Skip noise adjustment"); + register_flag("discard-nonconformant-data", &discard_nonconformant_data, "Discard data that does not conform"); + register_parameter("dwell-time-us-preset", &noise_dwell_time_us_preset, "Preset dwell time for noise measurement"); + register_parameter("scale-only-channels-by-name", &scale_only_channels_by_name, "List of named channels that should only be scaled"); + } + }; + + NoiseAdjustGadget(const Core::MrdContext& context, const Parameters& params); void process(Core::InputChannel& in, Core::OutputChannel& out) override; using NoiseHandler = std::variant; protected: - NODE_PROPERTY(perform_noise_adjust, bool, "Whether to actually perform the noise adjust", true); - NODE_PROPERTY(pass_nonconformant_data, bool, "Whether to pass data that does not conform", true); - NODE_PROPERTY(noise_dwell_time_us_preset, float, "Preset dwell time for noise measurement", 0.0); - NODE_PROPERTY(scale_only_channels_by_name, std::string, "List of named channels that should only be scaled", ""); - - void initialize_(const Core::Context& context) override; + const Parameters parameters_; - // const float receiver_noise_bandwidth; - float receiver_noise_bandwidth; + const float receiver_noise_bandwidth; - // const std::string measurement_id; - std::string measurement_id; + const std::string measurement_id; std::vector scale_only_channels; NoiseHandler noisehandler = IgnoringNoise{}; @@ -67,10 +77,6 @@ namespace Gadgetron { void save_noisedata(NOISEHANDLER& nh); NoiseHandler load_or_gather() const; - - // File names for file storage and retrival of noise covariance - std::string noise_covariance_out = ""; - std::string noise_covariance_in = ""; }; } diff --git a/gadgets/mri_core/PCACoilGadget.cpp b/gadgets/mri_core/PCACoilGadget.cpp index b0df0fe8..4bb95230 100644 --- a/gadgets/mri_core/PCACoilGadget.cpp +++ b/gadgets/mri_core/PCACoilGadget.cpp @@ -64,29 +64,6 @@ namespace Gadgetron { } - void PCACoilGadget::initialize_(const Core::Context& context) { - std::vector uncomb; - if (uncombined_channels_by_name.size()) { - GDEBUG("uncomb_str: %s\n", uncombined_channels_by_name.c_str()); - boost::split(uncomb, uncombined_channels_by_name, boost::is_any_of(",")); - for (unsigned int i = 0; i < uncomb.size(); i++) { - std::string ch = boost::algorithm::trim_copy(uncomb[i]); - if (context.header.acquisition_system_information) { - for (size_t i = 0; i < context.header.acquisition_system_information->coil_label.size(); i++) { - if (ch == context.header.acquisition_system_information->coil_label[i].coil_name) { - uncombined_channels_.push_back(i);//This assumes that the channels are sorted in the header - break; - } - } - } - } - } - -#ifdef USE_OMP - omp_set_num_threads(1); -#endif // USE_OMP - } - PCACoilGadget::~PCACoilGadget() { std::map >* >::iterator it; diff --git a/gadgets/mri_core/PCACoilGadget.h b/gadgets/mri_core/PCACoilGadget.h index 04657585..5ab879ce 100644 --- a/gadgets/mri_core/PCACoilGadget.h +++ b/gadgets/mri_core/PCACoilGadget.h @@ -12,7 +12,6 @@ namespace Gadgetron { class PCACoilGadget : public Core::ChannelGadget { public: - PCACoilGadget() : ChannelGadget("pca_coil") {} PCACoilGadget(const Core::Context& context, const Core::GadgetProperties& props); ~PCACoilGadget() override; @@ -22,8 +21,6 @@ namespace Gadgetron { NODE_PROPERTY(uncombined_channels_by_name, std::string, "List of comma separated channels by name", ""); // GADGET_PROPERTY(present_uncombined_channels, int, "Number of uncombined channels found", 0); - void initialize_(const Core::Context& context) override; - void calculate_coefficients(int location); void do_pca(mrd::Acquisition& acq); diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index 06661f18..ac50249f 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -4,41 +4,6 @@ namespace Gadgetron { -RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::Context& context, - const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) -{ - auto h = (context.header); - - if (h.encoding.size() == 0) { - GDEBUG("Number of encoding spaces: %d\n", h.encoding.size()); - GERROR("This Gadget needs an encoding description\n"); - return; - } - - mrd::EncodingSpaceType e_space = h.encoding[0].encoded_space; - mrd::EncodingSpaceType r_space = h.encoding[0].recon_space; - - encodeNx_ = e_space.matrix_size.x; - encodeFOV_ = e_space.field_of_view_mm.x; - reconNx_ = r_space.matrix_size.x; - reconFOV_ = r_space.field_of_view_mm.x; - -#ifdef USE_OMP // TODO: Should this be removed? Its from the old version - omp_set_num_threads(1); - GDEBUG_STREAM("RemoveROOversamplingGadget:omp_set_num_threads(1) ... "); -#endif // USE_OMP - - // If the encoding and recon matrix size and FOV are the same - // then the data is not oversampled and we can safely pass - // the data onto the next gadget - if ((encodeNx_ == reconNx_) && (encodeFOV_ == reconFOV_)) { - dowork_ = false; - } else { - dowork_ = true; - } -} - void RemoveROOversamplingGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto acq : in) { if (dowork_) { @@ -84,12 +49,10 @@ void RemoveROOversamplingGadget::process(Core::InputChannel& i } } -void RemoveROOversamplingGadget::install_cli(po::options_description& options) { - // TODO -} - -void RemoveROOversamplingGadget::initialize_(const Core::Context& context) { - auto h = (context.header); +RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{.header = context.header}, Core::GadgetProperties{}) +{ + auto h = context.header; if (h.encoding.size() == 0) { GDEBUG("Number of encoding spaces: %d\n", h.encoding.size()); diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index 8c118b7e..6f68388e 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -15,17 +15,13 @@ namespace Gadgetron { class RemoveROOversamplingGadget : public Core::ChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - RemoveROOversamplingGadget(): ChannelGadget("remove_oversampling") {} - RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props); + using GenericChannelGadget::Parameters; - void process(Core::InputChannel& input, Core::OutputChannel& output) override; + RemoveROOversamplingGadget(const Core::MrdContext& context, const Parameters& params); - void install_cli(po::options_description& options) override; + void process(Core::InputChannel& input, Core::OutputChannel& output) override; protected: - void initialize_(const Core::Context& context) override; - hoNDArray> fft_res_; hoNDArray> ifft_res_; diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index b28b2f6b..aaadca6c 100644 --- a/gadgets/mri_core/SimpleReconGadget.h +++ b/gadgets/mri_core/SimpleReconGadget.h @@ -16,8 +16,9 @@ namespace Gadgetron { class SimpleReconGadget : public Core::ChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - SimpleReconGadget() : ChannelGadget("simple_recon") {} + SimpleReconGadget(const Core::MrdContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + { } void process(Core::InputChannel& input, Core::OutputChannel& out) override; }; From f464c0f52e1d5bf83925711497a6d0021dbe0e34 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 16 Jan 2025 22:01:42 +0000 Subject: [PATCH 06/21] Remove MRD Header from GenericChannelGadget --- apps/emperor/CMakeLists.txt | 2 + apps/emperor/main.cc | 29 +++--- apps/emperor/pipelines/file_search.h | 89 +++++++++++++++++++ apps/emperor/pipelines/pipeline.h | 2 - core/Node.h | 18 ++-- core/Parameters.h | 1 + .../AcquisitionAccumulateTriggerGadget.h | 11 +-- gadgets/mri_core/BucketToBufferGadget.cpp | 8 +- gadgets/mri_core/BucketToBufferGadget.h | 13 +-- gadgets/mri_core/ExtractGadget.cpp | 2 +- gadgets/mri_core/ExtractGadget.h | 4 +- .../mri_core/FlowPhaseSubtractionGadget.cpp | 19 ++-- gadgets/mri_core/FlowPhaseSubtractionGadget.h | 5 +- gadgets/mri_core/ImageArraySplitGadget.h | 7 +- gadgets/mri_core/NoiseAdjustGadget.cpp | 15 ++-- gadgets/mri_core/NoiseAdjustGadget.h | 4 +- .../mri_core/PhysioInterpolationGadget.cpp | 7 +- gadgets/mri_core/PhysioInterpolationGadget.h | 11 ++- .../mri_core/RemoveROOversamplingGadget.cpp | 4 +- gadgets/mri_core/RemoveROOversamplingGadget.h | 6 +- gadgets/mri_core/SimpleReconGadget.h | 6 +- .../AcquisitionAccumulateTrigger_test.cpp | 4 +- test/gadgets/setup_gadget.h | 14 +-- 23 files changed, 188 insertions(+), 93 deletions(-) create mode 100644 apps/emperor/pipelines/file_search.h diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index d8615ad9..aa52c1a3 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -3,6 +3,8 @@ configure_file(../pingvin/pingvin_config.in pingvin_config.h) add_executable(emperor main.cc + ../pingvin/system_info.cpp + ../pingvin/ErrorHandler.h ../pingvin/nodes/Processable.h diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index 1625ef20..a62aeada 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -1,6 +1,7 @@ #include "pipelines/noise.h" // #include "pipelines/cartesian_grappa.h" #include "pipelines/default.h" +#include "pipelines/file_search.h" #include "log.h" #include "system_info.h" @@ -11,10 +12,9 @@ #include #include -using namespace pingvin; - namespace po = boost::program_options; -namespace fs = std::filesystem; + +using namespace pingvin; namespace { @@ -42,14 +42,13 @@ int main(int argc, char** argv) { po::options_description global("Global options"); - std::filesystem::path pingvin_home("/tmp/pingvin"); global.add_options() - ("help,h", "Prints this help message.") - ("info", "Prints build info about Pingvin.") + ("help,h", "Prints this help message") + ("info", "Prints build info about Pingvin") ("home", - po::value()->default_value(pingvin_home), - "Set the Pingvin home directory.") - ("config,c", po::value(), "Configuration file.") + po::value()->default_value(Gadgetron::Main::Info::default_pingvin_home()), + "Set the Pingvin home directory") + ("config,c", po::value(), "Pipeline configuration file") ("input,i", po::value(), "Input stream (default=stdin)") ("output,o", po::value(), "Output stream (default=stdout)") ; @@ -60,7 +59,7 @@ int main(int argc, char** argv) ("subargs", po::value>(), "Arguments for the pipeline.") ; - po::options_description help_options; + po::options_description help_options("Pingvin usage"); help_options.add(global); po::options_description allowed_options; @@ -97,7 +96,7 @@ int main(int argc, char** argv) } // "Choose" a Pipeline - std::vector builders{&default_mr, &noise_dependency}; + std::vector builders{&default_mr, &noise_dependency, &file_search}; std::map builder_map; for (auto& builder : builders) { builder_map[builder->name] = builder; @@ -105,7 +104,7 @@ int main(int argc, char** argv) if (!vm.count("pipeline")) { if (vm.count("help")) { - fs::path progpath(argv[0]); + std::filesystem::path progpath(argv[0]); std::cerr << "Usage: " << progpath.filename().string() << " [global options] [pipeline options]" << std::endl; std::cerr << help_options << std::endl; @@ -137,7 +136,7 @@ int main(int argc, char** argv) if (vm.count("help")) { std::cerr << help_options << std::endl; - std::cerr << "Pipeline:" << std::endl; + std::cerr << "--- " << subcmd << " ---" << std::endl; std::cerr << pipeline_options << std::endl; return 0; } @@ -181,15 +180,11 @@ int main(int argc, char** argv) std::istream& input_stream = input_file ? *input_file : std::cin; std::ostream& output_stream = output_file ? *output_file : std::cout; - std::cerr << "Pingvin Home: " << vm["home"].as() << std::endl; - auto pipeline = builder->build(input_stream, output_stream); pipeline.run(); std::flush(output_stream); - std::cout << "Pingvin finished successfully" << std::endl; - return 0; } \ No newline at end of file diff --git a/apps/emperor/pipelines/file_search.h b/apps/emperor/pipelines/file_search.h new file mode 100644 index 00000000..211da022 --- /dev/null +++ b/apps/emperor/pipelines/file_search.h @@ -0,0 +1,89 @@ +#pragma once + +#include "pipeline.h" + +namespace pingvin { + + using namespace Gadgetron; + + struct TextContext { + + }; + + class TextSource: public Source { + public: + TextSource(std::istream& input_stream) : input_stream_(input_stream) {} + + void setContext(TextContext& ctx) override { } + + void consume_input(Gadgetron::Core::ChannelPair& input_channel) override + { + std::string line; + while (std::getline(input_stream_, line)) { + Gadgetron::Core::Message msg(std::move(line)); + input_channel.output.push_message(std::move(msg)); + } + auto destruct_me = std::move(input_channel.output); + } + + private: + std::istream& input_stream_; + }; + + class TextSink: public ISink { + public: + TextSink(std::ostream& output_stream, const TextContext& ctx) : output_stream_(output_stream) {} + + void produce_output(Gadgetron::Core::ChannelPair& output_channel) override + { + while (true) { + try { + auto message = output_channel.input.pop(); + auto text = Gadgetron::Core::force_unpack(std::move(message)); + output_stream_ << text << std::endl; + } catch (const Gadgetron::Core::ChannelClosed& exc) { + break; + } + } + } + + private: + std::ostream& output_stream_; + }; + + class TextualSearch : public Core::ChannelGadget { + public: + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Textual Search Options") { + register_parameter("target", &target, "Text to search for"); + } + std::string target; + }; + + TextualSearch(const TextContext& context, const Parameters& params) + : Core::ChannelGadget(Core::Context{}, Core::GadgetProperties{}) + , parameters_(params) + { } + + void process(Core::InputChannel& input, Core::OutputChannel& out) override { + for (auto line : input) { + // out.push(line); + + if (line.find(parameters_.target) != std::string::npos) { + out.push(line); + } + } + } + + protected: + const Parameters parameters_; + }; + + static auto file_search = Pipeline::Builder("text-search", "Search for strings in text") + .withSource() + .withSink() + .withNode("search") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index 890066bd..0039c755 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -238,8 +238,6 @@ class Pipeline { } Pipeline build(std::istream& input_stream, std::ostream& output_stream) override { - std::cerr << "Building pipeline " << pipeline_name << std::endl; - if (!source_builder_) { throw std::runtime_error("No source specified"); } diff --git a/core/Node.h b/core/Node.h index 2dc488b8..ebe75b01 100644 --- a/core/Node.h +++ b/core/Node.h @@ -16,13 +16,13 @@ namespace Gadgetron::Core { public: virtual ~Node() = default; + /** * The function which processes the data coming from the InputChannel. Conceptually a coroutine. * @param in Channel from which messages are received from upstream * @param out Channel in which messages are sent on downstream */ virtual void process(GenericInputChannel& in, OutputChannel& out) = 0; - }; class GenericChannelGadget : public Node, public PropertyMixin { @@ -31,10 +31,7 @@ namespace Gadgetron::Core { using NodeParameters::NodeParameters; }; - GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties), header{context.header} {} - - protected: - const mrd::Header header ={}; + GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties) {} }; /** @@ -45,10 +42,8 @@ namespace Gadgetron::Core { */ template class ChannelGadget : public GenericChannelGadget { public: - using GenericChannelGadget::GenericChannelGadget; - /// void process(GenericInputChannel& in, OutputChannel& out) override final { auto typed_input = InputChannel(in, out); this->process(typed_input, out); @@ -61,6 +56,15 @@ namespace Gadgetron::Core { */ virtual void process(InputChannel& in, OutputChannel& out) = 0; }; + + /** TODO: Move to MR-specific location! */ + template class MRChannelGadget : public ChannelGadget { + public: + using ChannelGadget::ChannelGadget; + + MRChannelGadget(const MrdContext& context, const NodeParameters& parameters) + : ChannelGadget(Core::Context{}, Core::GadgetProperties{}) {} + }; } /** TODO: Delete everywhere */ diff --git a/core/Parameters.h b/core/Parameters.h index 433a35bf..5b962f80 100644 --- a/core/Parameters.h +++ b/core/Parameters.h @@ -52,6 +52,7 @@ class NodeParameters { public: NodeParameters(const std::string& prefix, const std::string& description): prefix_(prefix), description_(description) {} NodeParameters(const std::string& prefix): prefix_(prefix) {} + NodeParameters(): prefix_("unknown") {}; template void register_parameter(const std::string& name, T* value, const std::string& description) { diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h index defe5a57..e3157350 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h @@ -9,7 +9,7 @@ namespace Gadgetron { class AcquisitionAccumulateTriggerGadget - : public Core::ChannelGadget> { + : public Core::MRChannelGadget> { public: enum class TriggerDimension { kspace_encode_step_1, @@ -49,15 +49,8 @@ namespace Gadgetron { unsigned long n_acquisitions_before_ongoing_trigger = 40; }; - AcquisitionAccumulateTriggerGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget>( - Core::Context{.header = context.header}, Core::GadgetProperties{}) - , parameters_("TODO: This constructor only exists because it is used by unit test") - { } - AcquisitionAccumulateTriggerGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget>( - Core::Context{.header = context.header}, Core::GadgetProperties{}) + : Core::MRChannelGadget>(context, params) , parameters_(params) {} void process(Core::InputChannel>& in, diff --git a/gadgets/mri_core/BucketToBufferGadget.cpp b/gadgets/mri_core/BucketToBufferGadget.cpp index 0a6b9896..a23eac20 100644 --- a/gadgets/mri_core/BucketToBufferGadget.cpp +++ b/gadgets/mri_core/BucketToBufferGadget.cpp @@ -59,10 +59,10 @@ namespace Gadgetron { uint32_t espace = acq.head.encoding_space_ref.value_or(0); mrd::ReconAssembly& assembly = getReconAssembly(recon_data_buffers, key, espace); if (!assembly.ref) { - assembly.ref = makeDataBuffer(acq, header.encoding[espace], acq_bucket.refstats[espace], true); + assembly.ref = makeDataBuffer(acq, encoding_[espace], acq_bucket.refstats[espace], true); } - add_acquisition(*assembly.ref, acq, header.encoding[espace], acq_bucket.refstats[espace], true); + add_acquisition(*assembly.ref, acq, encoding_[espace], acq_bucket.refstats[espace], true); } // Buffer the bucketed Acquisitions @@ -71,10 +71,10 @@ namespace Gadgetron { uint32_t espace = acq.head.encoding_space_ref.value_or(0); mrd::ReconAssembly& assembly = getReconAssembly(recon_data_buffers, key, espace); if (assembly.data.data.empty()) { - assembly.data = makeDataBuffer(acq, header.encoding[espace], acq_bucket.datastats[espace], false); + assembly.data = makeDataBuffer(acq, encoding_[espace], acq_bucket.datastats[espace], false); } - add_acquisition(assembly.data, acq, header.encoding[espace], acq_bucket.datastats[espace], false); + add_acquisition(assembly.data, acq, encoding_[espace], acq_bucket.datastats[espace], false); } // Send all the ReconData messages diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 2509d080..07efd48a 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -17,7 +17,7 @@ namespace Gadgetron { // Since the order of data can be changed from its acquried time order, there is no easy way to resort waveform data // Therefore, the waveform data was copied and passed with every buffer - class BucketToBufferGadget : public Core::ChannelGadget { + class BucketToBufferGadget : public Core::MRChannelGadget { public: enum class Dimension { average, contrast, phase, repetition, set, segment, slice, none }; @@ -39,11 +39,12 @@ namespace Gadgetron { bool verbose = false; }; - using Core::ChannelGadget::ChannelGadget; BucketToBufferGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + : Core::MRChannelGadget(context, params) , parameters_(params) - { } + { + encoding_ = context.header.encoding; + } struct BufferKey { uint32_t average,slice,contrast,phase,repetition,set,segment; @@ -60,7 +61,9 @@ namespace Gadgetron { }; protected: - Parameters parameters_; + const Parameters parameters_; + + std::vector encoding_; void process(Core::InputChannel& in, Core::OutputChannel& out) override; BufferKey getKey(const mrd::EncodingCounters& idx) const; diff --git a/gadgets/mri_core/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index 63fd2b1b..d4b2686f 100644 --- a/gadgets/mri_core/ExtractGadget.cpp +++ b/gadgets/mri_core/ExtractGadget.cpp @@ -66,7 +66,7 @@ namespace Gadgetron { } ExtractGadget::ExtractGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget>>(Core::Context{.header = context.header}, Core::GadgetProperties{}) + : Core::MRChannelGadget>>(context, params) , parameters_(params) { for (int i = 0; i < parameters_.extract_mask.size(); i++) { diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index 2d5103c2..e08b54db 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -7,7 +7,7 @@ namespace Gadgetron { -class ExtractGadget : public Core::ChannelGadget>> { +class ExtractGadget : public Core::MRChannelGadget>> { public: struct Parameters : public Core::NodeParameters { using NodeParameters::NodeParameters; @@ -32,7 +32,7 @@ class ExtractGadget : public Core::ChannelGadget> void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; protected: - Parameters parameters_; + const Parameters parameters_; std::set image_types; }; diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp index 8822f6dd..653b227c 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp @@ -7,16 +7,21 @@ namespace Gadgetron { +FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::Context& context, const Core::GadgetProperties& props) + : Core::ChannelGadget>>(context, props) +{ + const auto e_limits = context.header.encoding[0].encoding_limits; + sets_ = e_limits.set ? e_limits.set->maximum + 1 : 1; + + if (sets_ > 2) { + GADGET_THROW("Phase subtraction only implemented for two sets"); + } +} + void FlowPhaseSubtractionGadget::process(Core::InputChannel>>& in, Core::OutputChannel& out) { - const auto e_limits = this->header.encoding[0].encoding_limits; - const auto sets = e_limits.set ? e_limits.set->maximum + 1 : 1; - - if (sets > 2) - throw std::runtime_error("Phase subtraction only implemented for two sets"); - - if (sets < 2) { + if (sets_ < 2) { std::move(in.begin(), in.end(), out.begin()); return; } diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.h b/gadgets/mri_core/FlowPhaseSubtractionGadget.h index 14ebae39..e7818ddb 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.h +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.h @@ -11,11 +11,14 @@ namespace Gadgetron{ { public: - using Core::ChannelGadget>>::ChannelGadget; + FlowPhaseSubtractionGadget(const Core::Context& context, const Core::GadgetProperties& props); ~FlowPhaseSubtractionGadget() override = default; void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; + + protected: + uint32_t sets_; }; } diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 8b8da45e..5145fddf 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.h +++ b/gadgets/mri_core/ImageArraySplitGadget.h @@ -13,12 +13,13 @@ namespace Gadgetron{ using ImageOrImageArray = std::variant; - class ImageArraySplitGadget : public Core::ChannelGadget + class ImageArraySplitGadget : public Core::MRChannelGadget { public: - ImageArraySplitGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + ImageArraySplitGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : Core::MRChannelGadget(context, params) { } + void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; } diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index fadd54a7..7dda6647 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -182,10 +182,11 @@ namespace Gadgetron { } NoiseAdjustGadget::NoiseAdjustGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) + : Core::MRChannelGadget(context, params) , parameters_(params) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } , measurement_id{ measurement_id_from_header(context.header) } + , acquisition_system_information_(context.header.acquisition_system_information) { GDEBUG_STREAM("skip_noise_adjust is " << parameters_.skip_noise_adjust); GDEBUG_STREAM("discard_nonconformant_data is " << parameters_.discard_nonconformant_data); @@ -216,8 +217,8 @@ namespace Gadgetron { size_t CHA = noise_covariance->matrix.get_size(0); if (noise_covariance->coil_labels.size() == CHA) { std::vector current_coil_labels; - if (header.acquisition_system_information) { - for (auto& l : header.acquisition_system_information->coil_label) { + if (acquisition_system_information_) { + for (auto& l : acquisition_system_information_->coil_label) { current_coil_labels.push_back(l.coil_name); } } @@ -248,7 +249,7 @@ namespace Gadgetron { } return LoadedNoise{noise_covariance->matrix, noise_covariance->noise_dwell_time_us}; - } else if (header.acquisition_system_information) { + } else if (acquisition_system_information_) { GERROR("Noise covariance matrix is malformed. Number of labels does not match number of channels."); } } @@ -295,7 +296,7 @@ namespace Gadgetron { normalize_covariance(ng); std::vector coil_labels; - for (auto& label : header.acquisition_system_information->coil_label) { + for (auto& label : acquisition_system_information_->coil_label) { coil_labels.push_back(label); } @@ -384,9 +385,9 @@ namespace Gadgetron { void NoiseAdjustGadget::process(Core::InputChannel& input, Core::OutputChannel& output) { - scale_only_channels = header.acquisition_system_information + scale_only_channels = acquisition_system_information_ ? find_scale_only_channels(parameters_.scale_only_channels_by_name, - header.acquisition_system_information->coil_label) + acquisition_system_information_->coil_label) : std::vector{}; for (auto acq : input) { diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index 21c65c8b..a2de5f3d 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -26,7 +26,7 @@ namespace Gadgetron { struct IgnoringNoise {}; - class NoiseAdjustGadget : public Core::ChannelGadget { + class NoiseAdjustGadget : public Core::MRChannelGadget { public: struct Parameters : public Core::NodeParameters { using NodeParameters::NodeParameters; @@ -63,6 +63,8 @@ namespace Gadgetron { const std::string measurement_id; std::vector scale_only_channels; + std::optional acquisition_system_information_; + NoiseHandler noisehandler = IgnoringNoise{}; template diff --git a/gadgets/mri_core/PhysioInterpolationGadget.cpp b/gadgets/mri_core/PhysioInterpolationGadget.cpp index 1197f883..4bc1a0a6 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.cpp +++ b/gadgets/mri_core/PhysioInterpolationGadget.cpp @@ -155,11 +155,6 @@ namespace Gadgetron { void PhysioInterpolationGadget::process(Core::InputChannel>> &in, Core::OutputChannel &out) { - - mrd::EncodingLimitsType e_limits = header.encoding[0].encoding_limits; - auto slc_limit = e_limits.slice ? e_limits.slice->maximum + 1 : 1; - - auto buffers = std::map>>>{}; auto time_stamp_buffer = std::map>{}; @@ -252,7 +247,7 @@ namespace Gadgetron { double cycle_length_in_ms = time_stamp_resolution_ * cycle_lengths[current_cycle]; std::ostringstream ostr; - if (slc_limit > 1) { + if (slice_limit_ > 1) { ostr << "_SLC_" << header.slice.value_or(0) << "_RR" << cycle_length_in_ms << "ms"; } else { ostr << "_RR" << cycle_length_in_ms << "ms"; diff --git a/gadgets/mri_core/PhysioInterpolationGadget.h b/gadgets/mri_core/PhysioInterpolationGadget.h index e02caf30..5f19cd62 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.h +++ b/gadgets/mri_core/PhysioInterpolationGadget.h @@ -34,12 +34,18 @@ class PhysioInterpolationGadget : public Core::ChannelGadget>>::ChannelGadget; + PhysioInterpolationGadget(const Core::Context& context, const Core::GadgetProperties& props) + : Core::ChannelGadget>>(context, props) + { + mrd::EncodingLimitsType e_limits = context.header.encoding[0].encoding_limits; + slice_limit_ = e_limits.slice ? e_limits.slice->maximum + 1 : 1; + } ~PhysioInterpolationGadget() override = default; - protected: + uint32_t slice_limit_; + NODE_PROPERTY(physiology_time_index, int, "Physiology time index", 0); NODE_PROPERTY(mode, PhysioInterpolationMode, "Mode, 0=separate series for each RR, 1=First complete RR only", PhysioInterpolationMode::separate); NODE_PROPERTY(phases, unsigned short, "Number of cardiac phases", 30); @@ -49,7 +55,6 @@ class PhysioInterpolationGadget : public Core::ChannelGadget>>& in, Core::OutputChannel& out) override; - }; } \ No newline at end of file diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index ac50249f..c8a0738f 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -49,8 +49,8 @@ void RemoveROOversamplingGadget::process(Core::InputChannel& i } } -RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{.header = context.header}, Core::GadgetProperties{}) +RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : Core::MRChannelGadget(context, params) { auto h = context.header; diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index 6f68388e..feee3178 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -13,11 +13,9 @@ #endif // USE_OMP namespace Gadgetron { -class RemoveROOversamplingGadget : public Core::ChannelGadget { +class RemoveROOversamplingGadget : public Core::MRChannelGadget { public: - using GenericChannelGadget::Parameters; - - RemoveROOversamplingGadget(const Core::MrdContext& context, const Parameters& params); + RemoveROOversamplingGadget(const Core::MrdContext& context, const Core::NodeParameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index aaadca6c..d9fcd150 100644 --- a/gadgets/mri_core/SimpleReconGadget.h +++ b/gadgets/mri_core/SimpleReconGadget.h @@ -14,11 +14,9 @@ namespace Gadgetron { - class SimpleReconGadget : public Core::ChannelGadget { + class SimpleReconGadget : public Core::MRChannelGadget { public: - SimpleReconGadget(const Core::MrdContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{.header=context.header}, Core::GadgetProperties{}) - { } + using Core::MRChannelGadget::MRChannelGadget; void process(Core::InputChannel& input, Core::OutputChannel& out) override; }; diff --git a/test/gadgets/AcquisitionAccumulateTrigger_test.cpp b/test/gadgets/AcquisitionAccumulateTrigger_test.cpp index 8833ae5b..c2789260 100644 --- a/test/gadgets/AcquisitionAccumulateTrigger_test.cpp +++ b/test/gadgets/AcquisitionAccumulateTrigger_test.cpp @@ -19,7 +19,9 @@ using namespace std::chrono_literals; TEST(AcquisitionAccumulateTriggerTest, slice_trigger) { try { - auto channels = setup_gadget({ { "trigger_dimension"s, "slice"s } }); + AcquisitionAccumulateTriggerGadget::Parameters params; + params.trigger_dimension = AcquisitionAccumulateTriggerGadget::TriggerDimension::slice; + auto channels = setup_gadget(params); for (size_t i = 0; i < 11; i++) { auto acq = generate_acquisition(192, 16); diff --git a/test/gadgets/setup_gadget.h b/test/gadgets/setup_gadget.h index e2e7854b..da509531 100644 --- a/test/gadgets/setup_gadget.h +++ b/test/gadgets/setup_gadget.h @@ -38,8 +38,8 @@ namespace Gadgetron { namespace Test { return header; } - inline Core::Context generate_context() { - Core::Context context; + inline Core::MrdContext generate_context() { + Core::MrdContext context; context.header = generate_header(); return context; } @@ -49,21 +49,21 @@ namespace Gadgetron { namespace Test { Core::GenericInputChannel output; }; - template - inline GadgetChannels setup_gadget(Core::GadgetProperties properties, Core::Context context = generate_context()) { + template + inline GadgetChannels setup_gadget(PARAMETERS& params, Core::MrdContext context = generate_context()) { auto channels = Core::make_channel(); auto channels2 = Core::make_channel(); auto thread = std::thread( - [](auto input, auto output, auto properties, auto context) { + [](auto input, auto output, auto params, auto context) { try { - GADGET gadget(context, properties); + GADGET gadget(context, params); Core::Node& node = gadget; node.process(input, output); } catch (const Core::ChannelClosed&){} }, - std::move(channels.input), std::move(channels2.output), properties, context); + std::move(channels.input), std::move(channels2.output), params, context); thread.detach(); return { std::move(channels.output), std::move(channels2.input) }; From 47afe3dbb573ac06c5d059a1060ce8364257d442 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Sat, 18 Jan 2025 17:57:10 +0000 Subject: [PATCH 07/21] Update half of mri_core Gadgets --- apps/emperor/main.cc | 2 +- apps/emperor/pipelines/default.h | 17 ++++ core/PureGadget.h | 10 ++ .../mri_core/AsymmetricEchoAdjustROGadget.cpp | 6 +- .../mri_core/AsymmetricEchoAdjustROGadget.h | 8 +- gadgets/mri_core/AugmentImageMetadataGadget.h | 13 +-- gadgets/mri_core/AutoScaleGadget.cpp | 2 +- gadgets/mri_core/AutoScaleGadget.h | 23 ++++- gadgets/mri_core/CMakeLists.txt | 44 +++++---- gadgets/mri_core/CoilReductionGadget.cpp | 15 +-- gadgets/mri_core/CoilReductionGadget.h | 22 ++++- gadgets/mri_core/CombineGadget.h | 5 +- gadgets/mri_core/ComplexToFloatGadget.cpp | 12 +-- gadgets/mri_core/ComplexToFloatGadget.h | 4 +- gadgets/mri_core/DenoiseGadget.cpp | 13 +-- gadgets/mri_core/DenoiseGadget.h | 26 +++-- gadgets/mri_core/FFTGadget.cpp | 4 - gadgets/mri_core/FFTGadget.h | 9 +- gadgets/mri_core/FlagTriggerGadget.cpp | 15 ++- gadgets/mri_core/FlagTriggerGadget.h | 18 ++-- gadgets/mri_core/ImageArraySplitGadget.h | 4 +- gadgets/mri_core/PCACoilGadget.cpp | 26 ++--- gadgets/mri_core/PCACoilGadget.h | 15 ++- .../mri_core/PhysioInterpolationGadget.cpp | 20 ++-- gadgets/mri_core/PhysioInterpolationGadget.h | 99 +++++++++++++++---- gadgets/mri_core/ScaleGadget.cpp | 2 +- gadgets/mri_core/ScaleGadget.h | 22 ++++- 27 files changed, 302 insertions(+), 154 deletions(-) diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index a62aeada..969cada5 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -96,7 +96,7 @@ int main(int argc, char** argv) } // "Choose" a Pipeline - std::vector builders{&default_mr, &noise_dependency, &file_search}; + std::vector builders{&default_mr, &default_mr_optimized, &noise_dependency, &file_search}; std::map builder_map; for (auto& builder : builders) { builder_map[builder->name] = builder; diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h index b921867e..d95920a3 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/emperor/pipelines/default.h @@ -2,6 +2,9 @@ #include "pipeline.h" +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/PCACoilGadget.h" +#include "gadgets/mri_core/CoilReductionGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" #include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" #include "gadgets/mri_core/BucketToBufferGadget.h" @@ -24,4 +27,18 @@ static auto default_mr = Pipeline::Builder("default", "Basic Cartesi .withNode("extract") ; +static auto default_mr_optimized = Pipeline::Builder("default-optimized", "Basic Cartesian Reconstruction") + .withSource() + .withSink() + .withNode("noise-adjust") + .withNode("pca") + .withNode("coil-reduction") // TODO: specify a default of `coils_out = 16`?? + .withNode("ros") + .withNode("accumulate") + .withNode("buffer") + .withNode("recon") + .withNode("image-split") + .withNode("extract") + ; + } // namespace pingvin \ No newline at end of file diff --git a/core/PureGadget.h b/core/PureGadget.h index d64a831a..3dd43ed5 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -35,4 +35,14 @@ class PureGadget : public GenericPureGadget { virtual RETURN process_function(INPUT args) const = 0; }; + + +/** TODO: Move to MR-specific location! */ +template +class MRPureGadget : public PureGadget { +public: + MRPureGadget(const MrdContext& context, const NodeParameters& parameters) + : PureGadget(Core::Context{}, Core::GadgetProperties{}) {} +}; + } diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp index fb0f0bac..05f3ffc9 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp @@ -19,8 +19,9 @@ namespace { } // namespace namespace Gadgetron { - AsymmetricEchoAdjustROGadget::AsymmetricEchoAdjustROGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) + + AsymmetricEchoAdjustROGadget::AsymmetricEchoAdjustROGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) { auto current_mrd_header = (context.header); maxRO_.resize(current_mrd_header.encoding.size()); @@ -30,6 +31,7 @@ namespace Gadgetron { GDEBUG_STREAM("max RO for encoding space " << e << " : " << maxRO_[e]); } } + void AsymmetricEchoAdjustROGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto acq : in) { bool is_noise = acq.head.flags.HasFlags(mrd::AcquisitionFlags::kIsNoiseMeasurement); diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h index f40b7ea0..ce1292de 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h @@ -11,13 +11,13 @@ #include "hoNDArray.h" namespace Gadgetron{ - class AsymmetricEchoAdjustROGadget : public Core::ChannelGadget + class AsymmetricEchoAdjustROGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - AsymmetricEchoAdjustROGadget(const Core::Context& context, const Core::GadgetProperties& props); - ~AsymmetricEchoAdjustROGadget() override = default; + AsymmetricEchoAdjustROGadget(const Core::MrdContext& context, const Parameters& params); + void process(Core::InputChannel& input, Core::OutputChannel& output) override; + protected: std::vector maxRO_; }; diff --git a/gadgets/mri_core/AugmentImageMetadataGadget.h b/gadgets/mri_core/AugmentImageMetadataGadget.h index 0e123cbc..f1a2500f 100644 --- a/gadgets/mri_core/AugmentImageMetadataGadget.h +++ b/gadgets/mri_core/AugmentImageMetadataGadget.h @@ -10,14 +10,11 @@ namespace Gadgetron { -class AugmentImageMetadataGadget: public Core::PureGadget>,mrd::Image>> - { - public: - using BaseClass = Core::PureGadget>,mrd::Image>>; - - AugmentImageMetadataGadget(const Core::Context& context, const Core::GadgetProperties& props) - : BaseClass(context,props) {} +class AugmentImageMetadataGadget: public Core::MRPureGadget>,mrd::Image>> +{ +public: + using Core::MRPureGadget>,mrd::Image>>::MRPureGadget; - mrd::Image> process_function(mrd::Image> args) const override; + mrd::Image> process_function(mrd::Image> args) const override; }; } diff --git a/gadgets/mri_core/AutoScaleGadget.cpp b/gadgets/mri_core/AutoScaleGadget.cpp index d116ac17..38795e4a 100644 --- a/gadgets/mri_core/AutoScaleGadget.cpp +++ b/gadgets/mri_core/AutoScaleGadget.cpp @@ -43,7 +43,7 @@ namespace { namespace Gadgetron { mrd::AnyImage AutoScaleGadget::process_function(mrd::AnyImage image) const { - return visit([&](auto &image) -> mrd::AnyImage { return autoscale(image, max_value, histogram_bins); }, image); + return visit([&](auto &image) -> mrd::AnyImage { return autoscale(image, parameters_.max_value, parameters_.histogram_bins); }, image); } GADGETRON_GADGET_EXPORT(AutoScaleGadget); } diff --git a/gadgets/mri_core/AutoScaleGadget.h b/gadgets/mri_core/AutoScaleGadget.h index da971483..4f410654 100644 --- a/gadgets/mri_core/AutoScaleGadget.h +++ b/gadgets/mri_core/AutoScaleGadget.h @@ -10,13 +10,28 @@ #include namespace Gadgetron{ - class AutoScaleGadget : public Core::PureGadget { + class AutoScaleGadget : public Core::MRPureGadget { public: - using Core::PureGadget::PureGadget; + struct Parameters : public Core::NodeParameters { + float max_value = 2048; + unsigned int histogram_bins = 100; + + Parameters(const std::string& prefix): Core::NodeParameters(prefix, "Scale images to a given percentile") { + register_parameter("max_value", &max_value, "Maximum value (after scaling)"); + register_parameter("histogram_bins", &histogram_bins, "Number of Histogram Bins"); + } + }; + + AutoScaleGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRPureGadget(context, params) + , parameters_(params) + {} + mrd::AnyImage process_function(mrd::AnyImage image) const override; + protected: - NODE_PROPERTY(max_value, float, "Maximum value (after scaling)", 2048); - NODE_PROPERTY(histogram_bins, unsigned int, "Number of Histogram Bins", 100); + const Parameters parameters_; + float current_scale_; std::vector histogram_; }; diff --git a/gadgets/mri_core/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index 6197a4a9..5fb5da02 100644 --- a/gadgets/mri_core/CMakeLists.txt +++ b/gadgets/mri_core/CMakeLists.txt @@ -43,35 +43,37 @@ set(pingvin_mricore_header_files ) set(pingvin_mricore_src_files + AcquisitionAccumulateTriggerGadget.cpp + AsymmetricEchoAdjustROGadget.cpp AugmentImageMetadataGadget.cpp - NoiseAdjustGadget.cpp - PCACoilGadget.cpp - FFTGadget.cpp - CombineGadget.cpp - ExtractGadget.cpp - FloatToFixPointGadget.cpp - RemoveROOversamplingGadget.cpp + AutoScaleGadget.cpp + BucketToBufferGadget.cpp CoilReductionGadget.cpp - FlowPhaseSubtractionGadget.cpp - PhysioInterpolationGadget.cpp - AsymmetricEchoAdjustROGadget.cpp - MaxwellCorrectionGadget.cpp + CombineGadget.cpp ComplexToFloatGadget.cpp - AcquisitionAccumulateTriggerGadget.cpp - BucketToBufferGadget.cpp - ImageArraySplitGadget.cpp - SimpleReconGadget.cpp - ImageSortGadget.cpp CompressedFloatBuffer.cpp - CompressedFloatBufferSse41.cpp CompressedFloatBufferAvx2.cpp + CompressedFloatBufferSse41.cpp cpuisa.cpp - AutoScaleGadget.cpp DenoiseGadget.cpp + ExtractGadget.cpp + FFTGadget.cpp FlagTriggerGadget.cpp - ImageIndexGadget.cpp - AccumulatorGadget.cpp - ScaleGadget.cpp + FloatToFixPointGadget.cpp + FlowPhaseSubtractionGadget.cpp + ImageArraySplitGadget.cpp + MaxwellCorrectionGadget.cpp + NoiseAdjustGadget.cpp + PCACoilGadget.cpp + PhysioInterpolationGadget.cpp + RemoveROOversamplingGadget.cpp + SimpleReconGadget.cpp + + # These Gadgets are NOT TESTED, but they HAVE BEEN upgraded to MRD v2 + # AccumulatorGadget.cpp + # ImageIndexGadget.cpp + # ImageSortGadget.cpp + # ScaleGadget.cpp # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 # CoilComputationGadget.cpp diff --git a/gadgets/mri_core/CoilReductionGadget.cpp b/gadgets/mri_core/CoilReductionGadget.cpp index 12b90911..cd85b113 100644 --- a/gadgets/mri_core/CoilReductionGadget.cpp +++ b/gadgets/mri_core/CoilReductionGadget.cpp @@ -2,21 +2,22 @@ namespace Gadgetron { -CoilReductionGadget::CoilReductionGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) +CoilReductionGadget::CoilReductionGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) + , parameters_(params) { auto h = context.header; coils_in_ = h.acquisition_system_information->receiver_channels.value_or(128); - if (coil_mask.empty()) { - if (coils_out <= 0) { - GERROR("Invalid number of output coils %d\n", coils_out); + if (parameters_.coil_mask.empty()) { + if (parameters_.coils_out > 128) { + GERROR_STREAM("Invalid number of output coils " << parameters_.coils_out); } - coil_mask_ = std::vector(coils_out, 1); + coil_mask_ = std::vector(parameters_.coils_out, 1); } else { std::vector chm; - boost::split(chm, coil_mask, boost::is_any_of(" ")); + boost::split(chm, parameters_.coil_mask, boost::is_any_of(" ")); for (size_t i = 0; i < chm.size(); i++) { std::string ch = boost::algorithm::trim_copy(chm[i]); if (ch.size() > 0) { diff --git a/gadgets/mri_core/CoilReductionGadget.h b/gadgets/mri_core/CoilReductionGadget.h index a074b197..8d7e3689 100644 --- a/gadgets/mri_core/CoilReductionGadget.h +++ b/gadgets/mri_core/CoilReductionGadget.h @@ -11,16 +11,28 @@ #include namespace Gadgetron{ - class CoilReductionGadget : public Core::ChannelGadget + class CoilReductionGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - CoilReductionGadget(const Core::Context& context, const Core::GadgetProperties& props); + struct Parameters : public Core::NodeParameters { + std::string coil_mask = ""; + unsigned int coils_out = 128; + + Parameters(const std::string& prefix) : NodeParameters(prefix, "Coil Reduction Options") { + register_parameter("coil-mask", &coil_mask, "String mask of zeros and ones, e.g. 000111000 indicating which coils to keep"); + register_parameter("coils-out", &coils_out, "Number of coils to keep, coils with higher indices will be discarded"); + } + + }; + + CoilReductionGadget(const Core::MrdContext& context, const Parameters& params); ~CoilReductionGadget() override = default; + void process(Core::InputChannel& input, Core::OutputChannel& output) override; + protected: - NODE_PROPERTY(coil_mask, std::string, "String mask of zeros and ones, e.g. 000111000 indicating which coils to keep", ""); - NODE_PROPERTY(coils_out, int, "Number of coils to keep, coils with higher indices will be discarded", 128); + const Parameters parameters_; + std::vector coil_mask_; unsigned int coils_in_; unsigned int coils_out_; diff --git a/gadgets/mri_core/CombineGadget.h b/gadgets/mri_core/CombineGadget.h index 16d859b5..83c7faaf 100644 --- a/gadgets/mri_core/CombineGadget.h +++ b/gadgets/mri_core/CombineGadget.h @@ -9,9 +9,10 @@ #include "hoNDArray_math.h" namespace Gadgetron{ - class CombineGadget : public Core::PureGadget { + class CombineGadget : public Core::MRPureGadget { public: - using Core::PureGadget::PureGadget; + using Core::MRPureGadget::PureGadget; + mrd::AnyImage process_function(mrd::AnyImage image) const override; }; } diff --git a/gadgets/mri_core/ComplexToFloatGadget.cpp b/gadgets/mri_core/ComplexToFloatGadget.cpp index 018b3392..99eb2da7 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.cpp +++ b/gadgets/mri_core/ComplexToFloatGadget.cpp @@ -9,9 +9,10 @@ #include "log.h" -Gadgetron::ComplexToFloatGadget::ComplexToFloatGadget( - const Gadgetron::Core::Context& context, const Gadgetron::Core::GadgetProperties& props) - : PureGadget(context,props) +namespace Gadgetron { + +ComplexToFloatGadget::ComplexToFloatGadget(const Core::MrdContext& context, const Parameters& params) + : MRPureGadget(context, params) { converters = { { mrd::ImageType::kMagnitude, [](const auto& image) { return abs(image); } }, @@ -20,7 +21,7 @@ Gadgetron::ComplexToFloatGadget::ComplexToFloatGadget( { mrd::ImageType::kImag, [](const auto& image) { return imag(image); } }}; }; -mrd::Image Gadgetron::ComplexToFloatGadget::process_function( +mrd::Image ComplexToFloatGadget::process_function( mrd::Image> input_image) const { mrd::Image out; @@ -41,6 +42,5 @@ mrd::Image Gadgetron::ComplexToFloatGadget::process_function( return out; } -namespace Gadgetron{ - GADGETRON_GADGET_EXPORT(ComplexToFloatGadget) +GADGETRON_GADGET_EXPORT(ComplexToFloatGadget) } \ No newline at end of file diff --git a/gadgets/mri_core/ComplexToFloatGadget.h b/gadgets/mri_core/ComplexToFloatGadget.h index 5083ed57..1fc2436d 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.h +++ b/gadgets/mri_core/ComplexToFloatGadget.h @@ -9,10 +9,10 @@ namespace Gadgetron { -class ComplexToFloatGadget: public Core::PureGadget,mrd::Image>> +class ComplexToFloatGadget: public Core::MRPureGadget,mrd::Image>> { public: - ComplexToFloatGadget(const Core::Context& context, const Core::GadgetProperties& props); + ComplexToFloatGadget(const Core::MrdContext&, const Parameters&); mrd::Image process_function(mrd::Image> args) const override; private: diff --git a/gadgets/mri_core/DenoiseGadget.cpp b/gadgets/mri_core/DenoiseGadget.cpp index 1d8d0d8e..70ddbbab 100644 --- a/gadgets/mri_core/DenoiseGadget.cpp +++ b/gadgets/mri_core/DenoiseGadget.cpp @@ -6,15 +6,16 @@ #include "mri_core_utility.h" namespace Gadgetron { + template - Gadgetron::hoNDArray Gadgetron::DenoiseGadget::denoise_function(const Gadgetron::hoNDArray& input) const { + hoNDArray DenoiseGadget::denoise_function(const hoNDArray& input) const { - if (denoiser == "non_local_bayes") { - return Denoise::non_local_bayes(input, image_std, search_radius); - } else if (denoiser == "non_local_means") { - return Denoise::non_local_means(input, image_std, search_radius); + if (parameters_.denoiser == "non_local_bayes") { + return Denoise::non_local_bayes(input, parameters_.image_std, parameters_.search_radius); + } else if (parameters_.denoiser == "non_local_means") { + return Denoise::non_local_means(input, parameters_.image_std, parameters_.search_radius); } else { - throw std::invalid_argument(std::string("DenoiseGadget: Unknown denoiser type: ") + std::string(denoiser)); + throw std::invalid_argument(std::string("DenoiseGadget: Unknown denoiser type: ") + std::string(parameters_.denoiser)); } } diff --git a/gadgets/mri_core/DenoiseGadget.h b/gadgets/mri_core/DenoiseGadget.h index 4bb5a929..7c80200b 100644 --- a/gadgets/mri_core/DenoiseGadget.h +++ b/gadgets/mri_core/DenoiseGadget.h @@ -11,18 +11,32 @@ namespace Gadgetron { using DenoiseSupportedTypes = std::variant, mrd::Image>, mrd::ImageArray>; - class DenoiseGadget - : public Core::PureGadget { + class DenoiseGadget : public Core::MRPureGadget { public: - using Core::PureGadget::PureGadget; + struct Parameters : public Core::NodeParameters { + float image_std = 1; + int search_radius = 25; + std::string denoiser = "non_local_bayes"; + + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Denoising Options") + { + register_parameter("image_std", &image_std, "Standard deviation of the noise in the produced image"); + register_parameter("search_radius", &search_radius, "Standard deviation of the noise in the produced image"); + register_parameter("denoiser", &denoiser, "Type of denoiser - non_local_means or non_local_bayes"); + } + }; + + DenoiseGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRPureGadget(context, params) + , parameters_(params) + {} DenoiseSupportedTypes process_function(DenoiseSupportedTypes input) const; - NODE_PROPERTY(image_std, float, "Standard deviation of the noise in the produced image", 1); - NODE_PROPERTY(search_radius, int, "Standard deviation of the noise in the produced image", 25); - NODE_PROPERTY(denoiser, std::string, "Type of denoiser - non_local_means or non_local_bayes", "non_local_bayes"); protected: + const Parameters parameters_; + template mrd::Image denoise(mrd::Image image) const; mrd::ImageArray denoise(mrd::ImageArray image_array) const; diff --git a/gadgets/mri_core/FFTGadget.cpp b/gadgets/mri_core/FFTGadget.cpp index 28ddd89b..05e4c62a 100644 --- a/gadgets/mri_core/FFTGadget.cpp +++ b/gadgets/mri_core/FFTGadget.cpp @@ -2,10 +2,6 @@ namespace Gadgetron{ - FFTGadget::FFTGadget(const Core::Context& context, const Core::GadgetProperties& props) : ChannelGadget(context, props){ - image_counter_ = 0; - } - mrd::Image> CreateAndFFTImage(mrd::ReconBuffer dbuff, uint16_t n, uint16_t s, uint16_t loc, long long image_index){ //7D, fixed order [E0, E1, E2, CHA, N, S, LOC] diff --git a/gadgets/mri_core/FFTGadget.h b/gadgets/mri_core/FFTGadget.h index 1b253c02..c5911251 100644 --- a/gadgets/mri_core/FFTGadget.h +++ b/gadgets/mri_core/FFTGadget.h @@ -12,14 +12,17 @@ namespace Gadgetron{ - class FFTGadget : public Core::ChannelGadget { + class FFTGadget : public Core::MRChannelGadget { public: - FFTGadget(const Core::Context& context, const Core::GadgetProperties& props); + FFTGadget(const Core::MrdContext& context, const Parameters& params) + : MRChannelGadget(context, params) + , image_counter_(0) + { } + void process(Core::InputChannel& input, Core::OutputChannel& out) override; protected: long long image_counter_; - }; } diff --git a/gadgets/mri_core/FlagTriggerGadget.cpp b/gadgets/mri_core/FlagTriggerGadget.cpp index 3d8bbb02..95613a32 100644 --- a/gadgets/mri_core/FlagTriggerGadget.cpp +++ b/gadgets/mri_core/FlagTriggerGadget.cpp @@ -169,6 +169,10 @@ auto const expression_def = andop | orop | negateop | term | x3::lit('(') >> exp BOOST_SPIRIT_DEFINE(expression, andop, orop, negateop, term); } // namespace boolean_grammer + + +namespace Gadgetron { + std::function FlagTriggerGadget::create_trigger_filter(const std::string& trigger_string) { namespace x3 = boost::spirit::x3; @@ -188,7 +192,7 @@ FlagTriggerGadget::create_trigger_filter(const std::string& trigger_string) { }; } -void Gadgetron::FlagTriggerGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { +void FlagTriggerGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (const auto& group : Core::Algorithm::buffer(in, this->predicate)) { auto bucket = mrd::AcquisitionBucket(); @@ -199,12 +203,13 @@ void Gadgetron::FlagTriggerGadget::process(Core::InputChannel& } } -Gadgetron::FlagTriggerGadget::FlagTriggerGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) { +FlagTriggerGadget::FlagTriggerGadget(const Core::MrdContext& context, const Parameters& params) + : MRChannelGadget(context, params) + , parameters_(params) +{ using namespace ranges; - this->predicate = create_trigger_filter(trigger_flags); + this->predicate = create_trigger_filter(parameters_.trigger_flags); } -namespace Gadgetron { GADGETRON_GADGET_EXPORT(FlagTriggerGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/FlagTriggerGadget.h b/gadgets/mri_core/FlagTriggerGadget.h index 8b850557..d970ca2a 100644 --- a/gadgets/mri_core/FlagTriggerGadget.h +++ b/gadgets/mri_core/FlagTriggerGadget.h @@ -6,7 +6,7 @@ namespace Gadgetron { -class FlagTriggerGadget : public Core::ChannelGadget { +class FlagTriggerGadget : public Core::MRChannelGadget { public: enum class TriggerFlags : uint64_t { first_in_encode_step1 = 0, @@ -55,16 +55,22 @@ class FlagTriggerGadget : public Core::ChannelGadget { user8 = 63 }; - FlagTriggerGadget(const Core::Context& context, const Core::GadgetProperties& props); - ~FlagTriggerGadget() override = default; + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix) : NodeParameters(prefix, "Flag Trigger Options") { + register_parameter("trigger-flags", &trigger_flags, "Trigger flags (separated by comma)"); + } + std::string trigger_flags = ""; + }; - void process(Core::InputChannel& input, - Core::OutputChannel& output) override; + FlagTriggerGadget(const Core::MrdContext& context, const Parameters& params); - NODE_PROPERTY(trigger_flags, std::string, "Trigger flags (separated by comma)", ""); + void process(Core::InputChannel& input, Core::OutputChannel& output) override; static std::function create_trigger_filter(const std::string& trigger_string); + protected: + const Parameters parameters_; + private: std::function predicate; }; diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 5145fddf..8c45320e 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.h +++ b/gadgets/mri_core/ImageArraySplitGadget.h @@ -16,9 +16,7 @@ namespace Gadgetron{ class ImageArraySplitGadget : public Core::MRChannelGadget { public: - ImageArraySplitGadget(const Core::MrdContext& context, const Core::NodeParameters& params) - : Core::MRChannelGadget(context, params) - { } + using Core::MRChannelGadget::MRChannelGadget; void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; diff --git a/gadgets/mri_core/PCACoilGadget.cpp b/gadgets/mri_core/PCACoilGadget.cpp index 4bb95230..8c5f9446 100644 --- a/gadgets/mri_core/PCACoilGadget.cpp +++ b/gadgets/mri_core/PCACoilGadget.cpp @@ -23,13 +23,14 @@ namespace Gadgetron { } } - PCACoilGadget::PCACoilGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) + PCACoilGadget::PCACoilGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) + , parameters_(params) { std::vector uncomb; - if (uncombined_channels_by_name.size()) { - GDEBUG("uncomb_str: %s\n", uncombined_channels_by_name.c_str()); - boost::split(uncomb, uncombined_channels_by_name, boost::is_any_of(",")); + if (parameters_.uncombined_channels_by_name.size()) { + GDEBUG_STREAM("uncomb_str: " << parameters_.uncombined_channels_by_name); + boost::split(uncomb, parameters_.uncombined_channels_by_name, boost::is_any_of(",")); for (unsigned int i = 0; i < uncomb.size(); i++) { std::string ch = boost::algorithm::trim_copy(uncomb[i]); if (context.header.acquisition_system_information) { @@ -43,21 +44,6 @@ namespace Gadgetron { } } - /** NOTE: - * - * This PCACoilGadget used to have a GADGET_PROPERTY "present_uncombined_channels" that was - * updated here to `uncombined_channels_.size()`, then later referenced by the NoiseAdjustGadget - * **only** in the `interventional_mri/grappa_device.xml` chain, which is untested. - * - * However, ChannelGadgets don't seem to support a non-const GADGET_PROPERTY. They only support - * NODE_PROPERTY, which declares a const member variable. - * - * Since the grappa_device chains is not tested anywhere, I think this is a "dead" feature. - * - */ - // present_uncombined_channels.value((int)uncombined_channels_.size()); - // GDEBUG("Number of uncombined channels (present_uncombined_channels) set to %d\n", uncombined_channels_.size()); - #ifdef USE_OMP omp_set_num_threads(1); #endif // USE_OMP diff --git a/gadgets/mri_core/PCACoilGadget.h b/gadgets/mri_core/PCACoilGadget.h index 5ab879ce..3de9772b 100644 --- a/gadgets/mri_core/PCACoilGadget.h +++ b/gadgets/mri_core/PCACoilGadget.h @@ -9,17 +9,24 @@ namespace Gadgetron { - class PCACoilGadget : public Core::ChannelGadget + class PCACoilGadget : public Core::MRChannelGadget { public: - PCACoilGadget(const Core::Context& context, const Core::GadgetProperties& props); + struct Parameters : public Core::NodeParameters { + std::string uncombined_channels_by_name = ""; + + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "PCA Coil Options") { + register_parameter("uncombined-channels-by-name", &uncombined_channels_by_name, "List of comma separated channels by name"); + } + }; + + PCACoilGadget(const Core::MrdContext& context, const Parameters& params); ~PCACoilGadget() override; void process(Core::InputChannel& input, Core::OutputChannel& output) override; protected: - NODE_PROPERTY(uncombined_channels_by_name, std::string, "List of comma separated channels by name", ""); - // GADGET_PROPERTY(present_uncombined_channels, int, "Number of uncombined channels found", 0); + const Parameters parameters_; void calculate_coefficients(int location); void do_pca(mrd::Acquisition& acq); diff --git a/gadgets/mri_core/PhysioInterpolationGadget.cpp b/gadgets/mri_core/PhysioInterpolationGadget.cpp index 4bc1a0a6..6cb647b6 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.cpp +++ b/gadgets/mri_core/PhysioInterpolationGadget.cpp @@ -161,7 +161,7 @@ namespace Gadgetron { for (auto image: in) { auto slice = image.head.slice.value_or(0); buffers[slice].emplace_back(image); - time_stamp_buffer[slice].push_back((float) (image.head.physiology_time_stamp[physiology_time_index])); + time_stamp_buffer[slice].push_back((float) (image.head.physiology_time_stamp[parameters_.physiology_time_index])); out.push(std::move(image)); } @@ -173,7 +173,7 @@ namespace Gadgetron { auto time_stamps = time_stamp_buffer[slc]; - auto[intervals, cycle_starts] = find_intervals(time_stamps, first_beat_on_trigger); + auto[intervals, cycle_starts] = find_intervals(time_stamps, parameters_.first_beat_on_trigger); if (intervals.empty()) continue; @@ -196,7 +196,7 @@ namespace Gadgetron { GDEBUG("Mean/Median cycle_length %f/%f\n", mean_cycle_length, median_cycle_length); //Correct the first cycle assuming it is of median length: - if (!first_beat_on_trigger) { + if (!parameters_.first_beat_on_trigger) { float first_cycle_offset = (median_cycle_length - median_interval) + time_stamps[cycle_starts[0]] - time_stamps[cycle_starts[0] - 1]; std::transform(time_stamps.begin(), time_stamps.end(), time_stamps.begin(), @@ -208,15 +208,15 @@ namespace Gadgetron { //Let's figure out which time points we would like to interpolate on: ///TODO: Deal with mode 1 and other future modes, we are only implementing mode 0 at the moment - float phase_interval = 1.0f / static_cast(phases); + float phase_interval = 1.0f / static_cast(parameters_.phases); float max_time = std::floor(relative_cycle_time[relative_cycle_time.size() - 1]); std::vector recon_cycle_time; for (float t = 1.0; t < (max_time - 0.001); t += phase_interval) { recon_cycle_time.push_back(t); } - if (mode == PhysioInterpolationMode::complete) { - recon_cycle_time.resize(phases); + if (parameters_.mode == PhysioInterpolationMode::complete) { + recon_cycle_time.resize(parameters_.phases); } //Now we can loop over each pixel and estimate the new frames, but first we have to have somewhere to put the data @@ -231,9 +231,9 @@ namespace Gadgetron { unsigned short current_cycle = static_cast(std::floor(cycle_time + 0.0001)); unsigned short current_phase = static_cast( - (cycle_time + 0.0001 - current_cycle) / (1.0 / static_cast(phases)) + 0.0001); + (cycle_time + 0.0001 - current_cycle) / (1.0 / static_cast(parameters_.phases)) + 0.0001); - header.physiology_time_stamp[physiology_time_index] = static_cast(std::floor( + header.physiology_time_stamp[parameters_.physiology_time_index] = static_cast(std::floor( (cycle_time + 0.0001 - current_cycle) * cycle_lengths[current_cycle])); header.phase = current_phase; header.image_index = current_phase + 1; @@ -245,7 +245,7 @@ namespace Gadgetron { meta[GADGETRON_IMAGENUMBER] = {long(header.image_index.value_or(0))}; meta[GADGETRON_DATA_ROLE].push_back("PhysionInterp"); - double cycle_length_in_ms = time_stamp_resolution_ * cycle_lengths[current_cycle]; + double cycle_length_in_ms = parameters_.time_stamp_resolution * cycle_lengths[current_cycle]; std::ostringstream ostr; if (slice_limit_ > 1) { ostr << "_SLC_" << header.slice.value_or(0) << "_RR" << cycle_length_in_ms << "ms"; @@ -271,7 +271,7 @@ namespace Gadgetron { auto output = ranges::transform_view(recon_cycle_time, image_generator) | to; - if ((interp_method == PhysioInterpolationMethod::Spline) || (mode != PhysioInterpolationMode::complete)) { + if ((parameters_.interp_method == PhysioInterpolationMethod::Spline) || (parameters_.mode != PhysioInterpolationMode::complete)) { spline_interpolate_series(buffer, relative_cycle_time, recon_cycle_time, output); } else { diff --git a/gadgets/mri_core/PhysioInterpolationGadget.h b/gadgets/mri_core/PhysioInterpolationGadget.h index 5f19cd62..d0b76f96 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.h +++ b/gadgets/mri_core/PhysioInterpolationGadget.h @@ -30,31 +30,92 @@ inline void from_string(const std::string& str, PhysioInterpolationMethod& metho else throw std::invalid_argument(str + " is not a valid input for PhysioInterpolationMethod"); } -class PhysioInterpolationGadget : public Core::ChannelGadget>> +std::ostream& operator<<(std::ostream& out, const PhysioInterpolationMode& mode) { + switch (mode) { + case PhysioInterpolationMode::separate: out << "separate"; break; + case PhysioInterpolationMode::complete: out << "complete"; break; + } + return out; +} + +void validate(boost::any& v, const std::vector& values, PhysioInterpolationMode*, int) { + // Make sure no previous assignment to 'a' was made. + po::validators::check_first_occurrence(v); + // Extract the first string from 'values'. If there is more than + // one string, it's an error, and exception will be thrown. + const std::string& s = po::validators::get_single_string(values); + + PhysioInterpolationMode mode; + try { + Gadgetron::from_string(s, mode); + } catch (std::exception& e) { + throw po::validation_error(po::validation_error::invalid_option_value); + } + v = boost::any(mode); +} + +std::ostream& operator<<(std::ostream& out, const PhysioInterpolationMethod& method) { + switch (method) { + case PhysioInterpolationMethod::Spline: out << "Spline"; break; + case PhysioInterpolationMethod::BSpline: out << "BSpline"; break; + } + return out; +} + +void validate(boost::any& v, const std::vector& values, PhysioInterpolationMethod*, int) { + // Make sure no previous assignment to 'a' was made. + po::validators::check_first_occurrence(v); + // Extract the first string from 'values'. If there is more than + // one string, it's an error, and exception will be thrown. + const std::string& s = po::validators::get_single_string(values); + + PhysioInterpolationMethod method; + try { + Gadgetron::from_string(s, method); + } catch (std::exception& e) { + throw po::validation_error(po::validation_error::invalid_option_value); + } + v = boost::any(method); +} + + +class PhysioInterpolationGadget : public Core::MRChannelGadget>> { public: + struct Parameters : public Core::NodeParameters { + int physiology_time_index = 0; + PhysioInterpolationMode mode = PhysioInterpolationMode::separate; + unsigned short phases = 30; + bool first_beat_on_trigger = false; + PhysioInterpolationMethod interp_method = PhysioInterpolationMethod::Spline; + double time_stamp_resolution = 2.5; - PhysioInterpolationGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget>>(context, props) - { - mrd::EncodingLimitsType e_limits = context.header.encoding[0].encoding_limits; - slice_limit_ = e_limits.slice ? e_limits.slice->maximum + 1 : 1; - } + Parameters(const std::string& prefix) + : Core::NodeParameters(prefix, "Interpolates images based on physiological data") + { + register_parameter("physiology_time_index", &physiology_time_index, "Physiology time index"); + register_parameter("mode", &mode, "Mode, 0=separate series for each RR, 1=First complete RR only"); + register_parameter("phases", &phases, "Number of cardiac phases"); + register_parameter("first_beat_on_trigger", &first_beat_on_trigger, "Indicates that acquisition was started on trigger"); + register_parameter("interp_method", &interp_method, "Interpolation method"); + register_parameter("time_stamp_resolution", &time_stamp_resolution, "Time stamp resolution in ms"); + } + }; - ~PhysioInterpolationGadget() override = default; + PhysioInterpolationGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget>>(context, params) + , parameters_(params) + { + mrd::EncodingLimitsType e_limits = context.header.encoding[0].encoding_limits; + slice_limit_ = e_limits.slice ? e_limits.slice->maximum + 1 : 1; + } - protected: - uint32_t slice_limit_; + void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; - NODE_PROPERTY(physiology_time_index, int, "Physiology time index", 0); - NODE_PROPERTY(mode, PhysioInterpolationMode, "Mode, 0=separate series for each RR, 1=First complete RR only", PhysioInterpolationMode::separate); - NODE_PROPERTY(phases, unsigned short, "Number of cardiac phases", 30); - NODE_PROPERTY(first_beat_on_trigger, bool, "Indicates that acquisition was started on trigger", false); - NODE_PROPERTY(interp_method, PhysioInterpolationMethod, "Interpolation method", PhysioInterpolationMethod::Spline); - NODE_PROPERTY(time_stamp_resolution_, double, "Time stamp resolution in ms", 2.5); + protected: + const Parameters parameters_; - public: - void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; -}; + uint32_t slice_limit_; + }; } \ No newline at end of file diff --git a/gadgets/mri_core/ScaleGadget.cpp b/gadgets/mri_core/ScaleGadget.cpp index 380fa961..bdee056a 100644 --- a/gadgets/mri_core/ScaleGadget.cpp +++ b/gadgets/mri_core/ScaleGadget.cpp @@ -36,7 +36,7 @@ namespace { GADGETRON_GADGET_EXPORT(ScaleGadget) PercentileScaleImageTypes ScaleGadget::process_function(PercentileScaleImageTypes args) const { - return std::visit([&](auto image) { return PercentileScaleImageTypes(autoscale(image, max_value, percentile)); }, + return std::visit([&](auto image) { return PercentileScaleImageTypes(autoscale(image, parameters_.max_value, parameters_.percentile)); }, args); } diff --git a/gadgets/mri_core/ScaleGadget.h b/gadgets/mri_core/ScaleGadget.h index 6a478c0f..5b0dfc6d 100644 --- a/gadgets/mri_core/ScaleGadget.h +++ b/gadgets/mri_core/ScaleGadget.h @@ -1,19 +1,33 @@ #pragma once #include "PureGadget.h" + namespace Gadgetron { using PercentileScaleImageTypes = std::variant, mrd::ImageArray>; /*** * This Gadget rescales magnitude images so that their 99% percentile becomes max_value */ - class ScaleGadget : public Core::PureGadget { + class ScaleGadget : public Core::MRPureGadget { public: - using PureGadget::PureGadget; + struct Parameters : public Core::NodeParameters { + float max_value = 2048; + float percentile = 98.5; + + Parameters(const std::string& prefix): Core::NodeParameters(prefix, "Scale images to a given percentile") { + register_parameter("max_value", &max_value, "Percentile value (after scaling)"); + register_parameter("percentile", &percentile, "Percentile to use."); + } + }; + + ScaleGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRPureGadget(context, params) + , parameters_(params) + {} + PercentileScaleImageTypes process_function(PercentileScaleImageTypes args) const override; protected: - NODE_PROPERTY(max_value, float, "Percentile value (after scaling)", 2048); - NODE_PROPERTY(percentile,float,"Percentile to use.",98.5); + const Parameters parameters_; }; } From 9b91463b529f616e08164d704aaa8c34dfdb33d1 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 31 Jan 2025 21:55:10 +0000 Subject: [PATCH 08/21] Update EPI gadgets and implement epi.xml chain --- apps/emperor/CMakeLists.txt | 1 + apps/emperor/main.cc | 5 +- apps/emperor/pipelines/cartesian_grappa.h | 2 +- apps/emperor/pipelines/epi.h | 38 +++++++ gadgets/.gitignore | 1 - gadgets/epi/CutXGadget.cpp | 4 +- gadgets/epi/CutXGadget.h | 6 +- gadgets/epi/EPICorrGadget.cpp | 85 ++++++++-------- gadgets/epi/EPICorrGadget.h | 38 ++++--- gadgets/epi/EPIPackNavigatorGadget.cpp | 4 +- gadgets/epi/EPIPackNavigatorGadget.h | 4 +- gadgets/epi/EPIReconXGadget.cpp | 4 +- gadgets/epi/EPIReconXGadget.h | 6 +- gadgets/epi/FFTXGadget.h | 5 +- gadgets/epi/OneEncodingGadget.h | 5 +- gadgets/mri_core/CMakeLists.txt | 4 +- gadgets/mri_core/CombineGadget.h | 4 +- gadgets/mri_core/ExtractGadget.cpp | 4 +- gadgets/mri_core/FloatToFixPointGadget.cpp | 80 --------------- gadgets/mri_core/FloatToFixPointGadget.h | 72 ------------- gadgets/mri_core/FloatToFixedPointGadget.cpp | 100 +++++++++++++++++++ gadgets/mri_core/FloatToFixedPointGadget.h | 48 +++++++++ gadgets/mri_core/NoiseAdjustGadget.cpp | 12 +-- gadgets/mri_core/NoiseAdjustGadget.h | 4 +- toolboxes/log/log.h | 13 ++- 25 files changed, 297 insertions(+), 252 deletions(-) create mode 100644 apps/emperor/pipelines/epi.h delete mode 100644 gadgets/.gitignore delete mode 100644 gadgets/mri_core/FloatToFixPointGadget.cpp delete mode 100644 gadgets/mri_core/FloatToFixPointGadget.h create mode 100644 gadgets/mri_core/FloatToFixedPointGadget.cpp create mode 100644 gadgets/mri_core/FloatToFixedPointGadget.h diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index aa52c1a3..400eaaba 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable(emperor target_link_libraries(emperor pingvin_core pingvin_mricore + pingvin_epi Boost::system Boost::program_options GTBLAS) diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index 969cada5..cf24aeb2 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -1,8 +1,11 @@ #include "pipelines/noise.h" // #include "pipelines/cartesian_grappa.h" #include "pipelines/default.h" +#include "pipelines/epi.h" + #include "pipelines/file_search.h" + #include "log.h" #include "system_info.h" @@ -96,7 +99,7 @@ int main(int argc, char** argv) } // "Choose" a Pipeline - std::vector builders{&default_mr, &default_mr_optimized, &noise_dependency, &file_search}; + std::vector builders{&epi_2d, &default_mr, &default_mr_optimized, &noise_dependency, &file_search}; std::map builder_map; for (auto& builder : builders) { builder_map[builder->name] = builder; diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h index 6184ea20..a90aff7b 100644 --- a/apps/emperor/pipelines/cartesian_grappa.h +++ b/apps/emperor/pipelines/cartesian_grappa.h @@ -9,7 +9,7 @@ #include "gadgets/mri_core/BucketToBufferGadget.h" #include "gadgets/mri_core/ImageArraySplitGadget.h" #include "gadgets/mri_core/ComplexToFloatGadget.h" -#include "gadgets/mri_core/FloatToFixPointGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" diff --git a/apps/emperor/pipelines/epi.h b/apps/emperor/pipelines/epi.h new file mode 100644 index 00000000..36ac159f --- /dev/null +++ b/apps/emperor/pipelines/epi.h @@ -0,0 +1,38 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ExtractGadget.h" +#include "gadgets/mri_core/FFTGadget.h" +#include "gadgets/mri_core/CombineGadget.h" +#include "gadgets/mri_core/AutoScaleGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" + +#include "gadgets/epi/EPIReconXGadget.h" +#include "gadgets/epi/EPICorrGadget.h" +#include "gadgets/epi/FFTXGadget.h" + +namespace pingvin { + + using namespace Gadgetron; + + static auto epi_2d = Pipeline::Builder("epi", "Basic EPI Reconstruction") + .withSource() + .withSink() + .withNode("noise-adjust") + .withNode("reconx") + .withNode("epicorr") + .withNode("fftx") + .withNode("acctrig") + .withNode("buffer") + .withNode("fft") + .withNode("combine") + .withNode("extract") + .withNode("autoscale") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/gadgets/.gitignore b/gadgets/.gitignore deleted file mode 100644 index afaf4316..00000000 --- a/gadgets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gputest/test \ No newline at end of file diff --git a/gadgets/epi/CutXGadget.cpp b/gadgets/epi/CutXGadget.cpp index cbf0fc51..d9e057bf 100644 --- a/gadgets/epi/CutXGadget.cpp +++ b/gadgets/epi/CutXGadget.cpp @@ -4,8 +4,8 @@ namespace Gadgetron{ - CutXGadget::CutXGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) + CutXGadget::CutXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters) + : CutXGadget::MRChannelGadget(context, parameters) { auto& h = context.header; diff --git a/gadgets/epi/CutXGadget.h b/gadgets/epi/CutXGadget.h index 5bc1a0f1..bd9a961d 100644 --- a/gadgets/epi/CutXGadget.h +++ b/gadgets/epi/CutXGadget.h @@ -8,14 +8,12 @@ namespace Gadgetron{ - class CutXGadget : public Core::ChannelGadget + class CutXGadget : public Core::MRChannelGadget { public: - CutXGadget(const Core::Context& context, const Core::GadgetProperties& props); + CutXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); protected: - NODE_PROPERTY(verbose_mode_, bool, "Verbose output", false); - void process(Core::InputChannel& input, Core::OutputChannel& out) override; size_t encodeNx_; diff --git a/gadgets/epi/EPICorrGadget.cpp b/gadgets/epi/EPICorrGadget.cpp index 35da5100..63bfac4d 100644 --- a/gadgets/epi/EPICorrGadget.cpp +++ b/gadgets/epi/EPICorrGadget.cpp @@ -13,8 +13,9 @@ namespace Gadgetron { #define OE_PHASE_CORR_POLY_ORDER 4 - EPICorrGadget::EPICorrGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) + EPICorrGadget::EPICorrGadget(const Core::MrdContext& context, const Parameters& params) + : EPICorrGadget::MRChannelGadget(context, params) + , parameters_(params) , corrComputed_(false), navNumber_(-1), epiEchoNumber_(-1) { auto& h = context.header; @@ -51,13 +52,13 @@ namespace Gadgetron { } // Make sure the reference navigator is properly set: - if (referenceNavigatorNumber > (numNavigators_ - 1)) { + if (parameters_.referenceNavigatorNumber > (numNavigators_ - 1)) { GADGET_THROW("Reference navigator number is larger than number of navigators acquired."); } // Initialize arrays needed for temporal filtering, if requested: - GDEBUG_STREAM("navigatorParameterFilterLength = " << navigatorParameterFilterLength); - if (navigatorParameterFilterLength > 1) { + GDEBUG_STREAM("navigatorParameterFilterLength = " << parameters_.navigatorParameterFilterLength); + if (parameters_.navigatorParameterFilterLength > 1) { init_arrays_for_nav_parameter_filtering(e_limits); } @@ -176,11 +177,11 @@ namespace Gadgetron { int p; // counter // mean of the reference navigator (across RO and channels): - std::complex navMean = mean(vectorise(navdata_.slice(referenceNavigatorNumber))); + std::complex navMean = mean(vectorise(navdata_.slice(parameters_.referenceNavigatorNumber))); // for clarity, we'll use the following when filtering navigator parameters: size_t set(hdr.idx.set.value_or(0)), slc(hdr.idx.slice.value_or(0)), exc(0); - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { // Careful: kspace_encode_step_2 for a navigator is always 0, and at this point we // don't have access to the kspace_encode_step_2 for the next line. Instead, // keep track of the excitation number for this set and slice: @@ -202,7 +203,7 @@ namespace Gadgetron { ////// B0 correction ////// ///////////////////////////////////// - if (B0CorrectionMode.compare("none") != 0) // If B0 correction is requested + if (parameters_.B0CorrectionMode.compare("none") != 0) // If B0 correction is requested { arma::cx_fvec ctemp = arma::zeros(Nx_); // temp column complex @@ -215,21 +216,21 @@ namespace Gadgetron { // Perform the fit: float slope = 0.; float intercept = 0.; - if ((B0CorrectionMode.compare("mean") == 0) || - (B0CorrectionMode.compare("linear") == 0)) { + if ((parameters_.B0CorrectionMode.compare("mean") == 0) || + (parameters_.B0CorrectionMode.compare("linear") == 0)) { // If a linear term is requested, compute it first (in the complex domain): - if (B0CorrectionMode.compare("linear") == 0) { // Robust fit to a straight line: + if (parameters_.B0CorrectionMode.compare("linear") == 0) { // Robust fit to a straight line: slope = (Nx_ - 1) * std::arg(arma::cdot(ctemp.rows(0, Nx_ - 2), ctemp.rows(1, Nx_ - 1))); //GDEBUG_STREAM("Slope = " << slope << std::endl); // If we need to filter the estimate: - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { // (Because to estimate the intercept (constant term) we need to use the slope estimate, // we want to filter it first): // - Store the value in the corresponding array (we want to store it before filtering) B0_slope_(exc, set, slc) = slope; // - Filter parameter: slope = filter_nav_correction_parameter(B0_slope_, Nav_mag_, exc, set, slc, - navigatorParameterFilterLength); + parameters_.navigatorParameterFilterLength); } // Correct for the slope, to be able to compute the average phase: @@ -239,13 +240,13 @@ namespace Gadgetron { // Now, compute the mean phase: intercept = arg(sum(ctemp)); //GDEBUG_STREAM("Intercept = " << intercept << std::endl); - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { // - Store the value found in the corresponding array: B0_intercept_(exc, set, slc) = intercept; // - Filter parameters: // Filter in the complex domain (last arg:"true"), to avoid smoothing across phase wraps: intercept = filter_nav_correction_parameter(B0_intercept_, Nav_mag_, exc, set, slc, - navigatorParameterFilterLength, true); + parameters_.navigatorParameterFilterLength, true); } // Then, our estimate of the phase: @@ -267,7 +268,7 @@ namespace Gadgetron { ////// Odd-Even correction -- Phase ////// //////////////////////////////////////////////////// - if (OEPhaseCorrectionMode.compare("none") != 0) // If Odd-Even phase correction is requested + if (parameters_.OEPhaseCorrectionMode.compare("none") != 0) // If Odd-Even phase correction is requested { // Accumulate over navigator triplets and sum over coils // this is the average phase difference between odd and even navigators @@ -281,25 +282,25 @@ namespace Gadgetron { float slope = 0.; float intercept = 0.; - if ((OEPhaseCorrectionMode.compare("mean") == 0) || - (OEPhaseCorrectionMode.compare("linear") == 0) || - (OEPhaseCorrectionMode.compare("polynomial") == 0)) { + if ((parameters_.OEPhaseCorrectionMode.compare("mean") == 0) || + (parameters_.OEPhaseCorrectionMode.compare("linear") == 0) || + (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0)) { // If a linear term is requested, compute it first (in the complex domain): // (This is important in case there are -pi/+pi phase wraps, since a polynomial // fit to the phase will not work) - if ((OEPhaseCorrectionMode.compare("linear") == 0) || - (OEPhaseCorrectionMode.compare("polynomial") == + if ((parameters_.OEPhaseCorrectionMode.compare("linear") == 0) || + (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0)) { // Robust fit to a straight line: slope = (Nx_ - 1) * std::arg(arma::cdot(ctemp.rows(0, Nx_ - 2), ctemp.rows(1, Nx_ - 1))); // If we need to filter the estimate: - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { // (Because to estimate the intercept (constant term) we need to use the slope estimate, // we want to filter it first): // - Store the value in the corresponding array (we want to store it before filtering) OE_phi_slope_(exc, set, slc) = slope; // - Filter parameter: slope = filter_nav_correction_parameter(OE_phi_slope_, Nav_mag_, exc, set, slc, - navigatorParameterFilterLength); + parameters_.navigatorParameterFilterLength); } // Now correct for the slope, to be able to compute the average phase: @@ -310,20 +311,20 @@ namespace Gadgetron { // Now, compute the mean phase: intercept = arg(sum(ctemp)); //GDEBUG_STREAM("Intercept = " << intercept << std::endl); - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { // - Store the value found in the corresponding array: OE_phi_intercept_(exc, set, slc) = intercept; // - Filter parameters: // Filter in the complex domain ("true"), to avoid smoothing across phase wraps: intercept = filter_nav_correction_parameter(OE_phi_intercept_, Nav_mag_, exc, set, slc, - navigatorParameterFilterLength, true); + parameters_.navigatorParameterFilterLength, true); } // Then, our estimate of the phase: tvec = slope * x + intercept; // If a polynomial fit is requested: - if (OEPhaseCorrectionMode.compare("polynomial") == 0) { + if (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0) { tvec += polynomial_correction(Nx_, x, ctemp, set, slc, exc, intercept); } // end of OEPhaseCorrectionMode == "polynomial" @@ -345,7 +346,7 @@ namespace Gadgetron { corrComputed_ = true; // Increase the excitation number for this slice and set (to be used for the next shot) - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { excitNo_[slc][set]++; } } @@ -372,7 +373,7 @@ namespace Gadgetron { } arma::fmat X; - if (OEPhaseCorrectionMode.compare("polynomial") == 0) { + if (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0) { X = arma::zeros(Nx_, OE_PHASE_CORR_POLY_ORDER + 1); X.col(0) = arma::ones(Nx_); @@ -389,7 +390,7 @@ namespace Gadgetron { // Solve for the polynomial coefficients: arma::fvec phase_poly_coef = solve(WX, Wctemp); - if (navigatorParameterFilterLength > 1) { + if (parameters_.navigatorParameterFilterLength > 1) { for (size_t i = 0; i < OE_phi_poly_coef_.size(); ++i) { // - Store the value found in the corresponding array: OE_phi_poly_coef_[i](exc, set, slc) = phase_poly_coef(i); @@ -397,7 +398,7 @@ namespace Gadgetron { // - Filter parameters: phase_poly_coef(i) = filter_nav_correction_parameter(OE_phi_poly_coef_[i], Nav_mag_, exc, set, slc, - navigatorParameterFilterLength); + parameters_.navigatorParameterFilterLength); } //GDEBUG_STREAM("OE_phi_poly_coef size: " << OE_phi_poly_coef_.size()); } @@ -439,14 +440,14 @@ namespace Gadgetron { // to do it also through e2. Bottom line: e2 and repetition are equivalent. Nav_mag_.create(E2_ * REP, SET, SLC); B0_intercept_.create(E2_ * REP, SET, SLC); - if (B0CorrectionMode.compare("linear") == 0) { + if (parameters_.B0CorrectionMode.compare("linear") == 0) { B0_slope_.create(E2_ * REP, SET, SLC); } OE_phi_intercept_.create(E2_ * REP, SET, SLC); - if ((OEPhaseCorrectionMode.compare("linear") == 0) || - (OEPhaseCorrectionMode.compare("polynomial") == 0)) { + if ((parameters_.OEPhaseCorrectionMode.compare("linear") == 0) || + (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0)) { OE_phi_slope_.create(E2_ * REP, SET, SLC); - if (OEPhaseCorrectionMode.compare("polynomial") == 0) { + if (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0) { OE_phi_poly_coef_.resize(OE_PHASE_CORR_POLY_ORDER + 1); for (size_t i = 0; i < OE_phi_poly_coef_.size(); ++i) { OE_phi_poly_coef_[i].create(E2_ * REP, SET, SLC); @@ -455,8 +456,8 @@ namespace Gadgetron { } // Armadillo vector of evenly-spaced timepoints to filter navigator parameters: - t_ = arma::linspace(0, navigatorParameterFilterLength - 1, - navigatorParameterFilterLength); + t_ = arma::linspace(0, parameters_.navigatorParameterFilterLength - 1, + parameters_.navigatorParameterFilterLength); } @@ -496,7 +497,7 @@ namespace Gadgetron { } // If this repetition number is less than then number of repetitions to exclude... - if (exc < navigatorParameterFilterExcludeVols * E2_) { + if (exc < parameters_.navigatorParameterFilterExcludeVols * E2_) { // no filtering is needed, just return the corresponding value: return nav_corr_param_array(exc, set, slc); } @@ -511,7 +512,7 @@ namespace Gadgetron { // make sure we don't use more timepoints (e2 phase encoding steps and repetitions) // that the currently acquired (minus the ones we have been asked to exclude // from the beginning of the run): - Nt = std::min(Nt, exc - (navigatorParameterFilterExcludeVols * E2_) + 1); + Nt = std::min(Nt, exc - (parameters_.navigatorParameterFilterExcludeVols * E2_) + 1); // create armadillo vectors, and stuff them in reverse order (from the // current timepoint, looking backwards). This way, the filtered value @@ -592,7 +593,7 @@ namespace Gadgetron { B0_intercept_ = tmpArray; // B0_slope_ : - if (B0CorrectionMode.compare("linear") == 0) { + if (parameters_.B0CorrectionMode.compare("linear") == 0) { for (size_t slc = 0; slc < SLC; ++slc) { for (size_t set = 0; set < SET; ++set) { memcpy(&tmpArray(0, set, slc), &B0_slope_(0, set, slc), @@ -612,8 +613,8 @@ namespace Gadgetron { OE_phi_intercept_ = tmpArray; // OE_phi_slope_ : - if ((OEPhaseCorrectionMode.compare("linear") == 0) || - (OEPhaseCorrectionMode.compare("polynomial") == 0)) { + if ((parameters_.OEPhaseCorrectionMode.compare("linear") == 0) || + (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0)) { for (size_t slc = 0; slc < SLC; ++slc) { for (size_t set = 0; set < SET; ++set) { memcpy(&tmpArray(0, set, slc), &OE_phi_slope_(0, set, slc), @@ -623,7 +624,7 @@ namespace Gadgetron { OE_phi_slope_ = tmpArray; // OE_phi_poly_coef_ : - if (OEPhaseCorrectionMode.compare("polynomial") == 0) { + if (parameters_.OEPhaseCorrectionMode.compare("polynomial") == 0) { for (size_t i = 0; i < OE_phi_poly_coef_.size(); ++i) { for (size_t slc = 0; slc < SLC; ++slc) { for (size_t set = 0; set < SET; ++set) { diff --git a/gadgets/epi/EPICorrGadget.h b/gadgets/epi/EPICorrGadget.h index 104e82e0..b8f8f043 100644 --- a/gadgets/epi/EPICorrGadget.h +++ b/gadgets/epi/EPICorrGadget.h @@ -12,23 +12,32 @@ namespace Gadgetron { - class EPICorrGadget : public Core::ChannelGadget { + class EPICorrGadget : public Core::MRChannelGadget { public: - EPICorrGadget(const Core::Context& context, const Core::GadgetProperties& props); + struct Parameters : public Core::NodeParameters { + size_t referenceNavigatorNumber = 1; + std::string B0CorrectionMode = "mean"; + std::string OEPhaseCorrectionMode = "polynomial"; + int navigatorParameterFilterLength = 0; + size_t navigatorParameterFilterExcludeVols = 0; + + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "EPICorr Options") + { + register_parameter("referenceNavigatorNumber", &referenceNavigatorNumber, + "Navigator number to be used as reference, both for phase correction and weights for filtering (default=1 -- second navigator)"); + register_parameter("B0CorrectionMode", &B0CorrectionMode, "B0 correction mode (none, mean, linear)"); + register_parameter("OEPhaseCorrectionMode", &OEPhaseCorrectionMode, + "Odd-Even phase-correction mode (none, mean, linear, polynomial)"); + register_parameter("navigatorParameterFilterLength", &navigatorParameterFilterLength, + "Number of repetitions to use to filter the navigator parameters (set to 0 or negative for no filtering)"); + register_parameter("navigatorParameterFilterExcludeVols", &navigatorParameterFilterExcludeVols, + "Number of volumes/repetitions to exclude from the beginning of the run when filtering the navigator parameters (e.g., to take into account dummy acquisitions. Default: 0)"); + } + }; + + EPICorrGadget(const Core::MrdContext& context, const Parameters& parameters); protected: - NODE_PROPERTY(referenceNavigatorNumber, size_t, - "Navigator number to be used as reference, both for phase correction and weights for filtering (default=1 -- second navigator)", - 1); - NODE_PROPERTY(B0CorrectionMode, std::string, "B0 correction mode (none, mean, linear)", "mean"); - NODE_PROPERTY(OEPhaseCorrectionMode, std::string, "Odd-Even phase-correction mode (none, mean, linear, polynomial)", "polynomial"); - NODE_PROPERTY(navigatorParameterFilterLength, int, - "Number of repetitions to use to filter the navigator parameters (set to 0 or negative for no filtering)", - 0); - NODE_PROPERTY(navigatorParameterFilterExcludeVols, size_t, - "Number of volumes/repetitions to exclude from the beginning of the run when filtering the navigator parameters (e.g., to take into account dummy acquisitions. Default: 0)", - 0); - void process(Core::InputChannel& input, Core::OutputChannel& out) override; void init_arrays_for_nav_parameter_filtering(mrd::EncodingLimitsType e_limits); @@ -43,6 +52,7 @@ namespace Gadgetron { void increase_no_repetitions(size_t delta_rep); + const Parameters parameters_; // -------------------------------------------------- // variables for navigator parameter computation diff --git a/gadgets/epi/EPIPackNavigatorGadget.cpp b/gadgets/epi/EPIPackNavigatorGadget.cpp index bb692126..c8d04527 100644 --- a/gadgets/epi/EPIPackNavigatorGadget.cpp +++ b/gadgets/epi/EPIPackNavigatorGadget.cpp @@ -2,8 +2,8 @@ namespace Gadgetron { -EPIPackNavigatorGadget::EPIPackNavigatorGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) +EPIPackNavigatorGadget::EPIPackNavigatorGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : EPIPackNavigatorGadget::MRChannelGadget(context, params) { auto& h = context.header; if (h.encoding.size() == 0) { diff --git a/gadgets/epi/EPIPackNavigatorGadget.h b/gadgets/epi/EPIPackNavigatorGadget.h index 412a056d..91d2442b 100644 --- a/gadgets/epi/EPIPackNavigatorGadget.h +++ b/gadgets/epi/EPIPackNavigatorGadget.h @@ -8,9 +8,9 @@ namespace Gadgetron{ - class EPIPackNavigatorGadget : public Core::ChannelGadget { + class EPIPackNavigatorGadget : public Core::MRChannelGadget { public: - EPIPackNavigatorGadget(const Core::Context& context, const Core::GadgetProperties& props); + EPIPackNavigatorGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; diff --git a/gadgets/epi/EPIReconXGadget.cpp b/gadgets/epi/EPIReconXGadget.cpp index 2128d6d0..4bd49287 100644 --- a/gadgets/epi/EPIReconXGadget.cpp +++ b/gadgets/epi/EPIReconXGadget.cpp @@ -8,8 +8,8 @@ namespace Gadgetron { - EPIReconXGadget::EPIReconXGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) + EPIReconXGadget::EPIReconXGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : EPIReconXGadget::MRChannelGadget(context, params) { auto& h = context.header; diff --git a/gadgets/epi/EPIReconXGadget.h b/gadgets/epi/EPIReconXGadget.h index dc9a08da..9a7e542d 100644 --- a/gadgets/epi/EPIReconXGadget.h +++ b/gadgets/epi/EPIReconXGadget.h @@ -6,13 +6,11 @@ namespace Gadgetron { - class EPIReconXGadget : public Core::ChannelGadget { + class EPIReconXGadget : public Core::MRChannelGadget { public: - EPIReconXGadget(const Core::Context& context, const Core::GadgetProperties& props); + EPIReconXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); protected: - NODE_PROPERTY(verbose_mode_, bool, "Verbose output", false); - void process(Core::InputChannel& input, Core::OutputChannel& out) override; // A set of reconstruction objects diff --git a/gadgets/epi/FFTXGadget.h b/gadgets/epi/FFTXGadget.h index edd8db35..851466d5 100644 --- a/gadgets/epi/FFTXGadget.h +++ b/gadgets/epi/FFTXGadget.h @@ -7,10 +7,9 @@ namespace Gadgetron{ - class FFTXGadget : public Core::ChannelGadget { + class FFTXGadget : public Core::MRChannelGadget { public: - FFTXGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) {} + using Core::MRChannelGadget::MRChannelGadget; protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; diff --git a/gadgets/epi/OneEncodingGadget.h b/gadgets/epi/OneEncodingGadget.h index 50443559..4d7c73f6 100644 --- a/gadgets/epi/OneEncodingGadget.h +++ b/gadgets/epi/OneEncodingGadget.h @@ -9,10 +9,9 @@ namespace Gadgetron { - class OneEncodingGadget : public Core::ChannelGadget { + class OneEncodingGadget : public Core::MRChannelGadget { public: - OneEncodingGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) {} + using Core::MRChannelGadget::MRChannelGadget; protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index 5fb5da02..81bd9d34 100644 --- a/gadgets/mri_core/CMakeLists.txt +++ b/gadgets/mri_core/CMakeLists.txt @@ -8,7 +8,7 @@ set(pingvin_mricore_header_files FFTGadget.h CombineGadget.h ExtractGadget.h - FloatToFixPointGadget.h + FloatToFixedPointGadget.h RemoveROOversamplingGadget.h CoilReductionGadget.h FlowPhaseSubtractionGadget.h @@ -59,7 +59,7 @@ set(pingvin_mricore_src_files ExtractGadget.cpp FFTGadget.cpp FlagTriggerGadget.cpp - FloatToFixPointGadget.cpp + FloatToFixedPointGadget.cpp FlowPhaseSubtractionGadget.cpp ImageArraySplitGadget.cpp MaxwellCorrectionGadget.cpp diff --git a/gadgets/mri_core/CombineGadget.h b/gadgets/mri_core/CombineGadget.h index 83c7faaf..77be3e3c 100644 --- a/gadgets/mri_core/CombineGadget.h +++ b/gadgets/mri_core/CombineGadget.h @@ -10,8 +10,8 @@ namespace Gadgetron{ class CombineGadget : public Core::MRPureGadget { - public: - using Core::MRPureGadget::PureGadget; + public: + using MRPureGadget::MRPureGadget; mrd::AnyImage process_function(mrd::AnyImage image) const override; }; diff --git a/gadgets/mri_core/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index d4b2686f..c2367b45 100644 --- a/gadgets/mri_core/ExtractGadget.cpp +++ b/gadgets/mri_core/ExtractGadget.cpp @@ -43,7 +43,7 @@ namespace Gadgetron { case IMTYPE::kImag: return extract(data, [&](auto& val) { return std::imag(val) + offset; }); default: - throw std::runtime_error("Illegal image type encountered in extract_image"); + GADGET_THROW("Illegal image type encountered in extract_image"); } } @@ -84,7 +84,7 @@ namespace Gadgetron { image_types.insert(mrd::ImageType::kPhase); if (image_types.empty()) { - GADGET_THROW("ExtractGadget: No valid extract functions specified"); + GADGET_THROW("No valid extract functions specified"); } } diff --git a/gadgets/mri_core/FloatToFixPointGadget.cpp b/gadgets/mri_core/FloatToFixPointGadget.cpp deleted file mode 100644 index 69c54f73..00000000 --- a/gadgets/mri_core/FloatToFixPointGadget.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -* FloatToFixPointGadget.cpp -* -* Created on: March 10, 2014 -* Author: Hui Xue -*/ - -#include "FloatToFixPointGadget.h" -#include "mri_core_def.h" -#include "hoNDArray_math.h" - - -#include - -namespace Gadgetron -{ - - template - void FloatToFixPointGadget::process(Core::InputChannel> &input, Core::OutputChannel &output) { - - auto self = static_cast(*this); - - auto clamp = [&](float val){ - return lround(std::min(std::max(val,self.min_intensity),self.max_intensity)); - }; - auto magnitude = [&](auto val){ - return T(clamp(std::abs(val))); - }; - - auto real_value = [&](auto val){ - return T(clamp(float(val)+self.intensity_offset)); - }; - - auto phase = [&](float val){ - return T(clamp((val*self.intensity_offset/boost::math::float_constants::pi)+self.intensity_offset)); - }; - - for (auto image_in: input) { - mrd::Image image_out; - image_out.head = image_in.head; - image_out.meta = image_in.meta; - image_out.data.create(image_in.data.dimensions()); - auto& output_data = image_out.data; - - // Now we're ready to transform the image data - switch (image_in.head.image_type) { - case mrd::ImageType::kMagnitude: { - std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), magnitude); - } - break; - - case mrd::ImageType::kReal: - case mrd::ImageType::kImag: { - std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), real_value); - - if (image_out.meta.count(GADGETRON_IMAGE_WINDOWCENTER) && image_out.meta[GADGETRON_IMAGE_WINDOWCENTER].size() > 0) { - long windowCenter = std::get(image_out.meta[GADGETRON_IMAGE_WINDOWCENTER].front()); - image_out.meta[GADGETRON_IMAGE_WINDOWCENTER] = {windowCenter + self.intensity_offset}; - } - } - break; - - case mrd::ImageType::kPhase: { - std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), phase); - } - break; - - default: - throw std::runtime_error("Unknown image type in Image"); - } - - output.push(std::move(image_out)); - } - } - - GADGETRON_GADGET_EXPORT(FloatToUShortGadget) - GADGETRON_GADGET_EXPORT(FloatToShortGadget) - GADGETRON_GADGET_EXPORT(FloatToIntGadget) - GADGETRON_GADGET_EXPORT(FloatToUIntGadget) -} diff --git a/gadgets/mri_core/FloatToFixPointGadget.h b/gadgets/mri_core/FloatToFixPointGadget.h deleted file mode 100644 index 95760e55..00000000 --- a/gadgets/mri_core/FloatToFixPointGadget.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "Node.h" - -namespace Gadgetron -{ - - /** - * This Gadget converts float values to fix point integer format. - * - * How the conversion is done will depend on the image type: - * Magnitude images: Values above 4095 will be clamped. - * Real or Imag: Values below -2048 and above 2047 will be clamped. Zero will be 2048. - * Phase: -pi will be 0, +pi will be 4095. - * - */ - - template - class FloatToFixPointGadget: public Core::ChannelGadget> - { - public: - - using Core::ChannelGadget>::ChannelGadget; - FloatToFixPointGadget() : ChannelGadget("float_to_fixpoint") {} - ~FloatToFixPointGadget() override = default ; - - void process(Core::InputChannel>& input, Core::OutputChannel& output) override; - }; - - class FloatToShortGadget :public FloatToFixPointGadget < short,FloatToShortGadget > - { - public: - using FloatToFixPointGadget::FloatToFixPointGadget; - NODE_PROPERTY(max_intensity, short, "Maximum intensity value", std::numeric_limits::max() ); - NODE_PROPERTY(min_intensity, short , "Minimal intensity value", std::numeric_limits::min()); - NODE_PROPERTY(intensity_offset, short , "Intensity offset", 0); - ~FloatToShortGadget() override = default; - }; - class FloatToUShortGadget :public FloatToFixPointGadget < unsigned short,FloatToUShortGadget > - { - public: - using FloatToFixPointGadget::FloatToFixPointGadget; - NODE_PROPERTY(max_intensity, short, "Maximum intensity value", 4095 ); - NODE_PROPERTY(min_intensity, short , "Minimal intensity value", 0); - NODE_PROPERTY(intensity_offset, short , "Intensity offset", 2048); - ~FloatToUShortGadget() override = default; - }; - class FloatToUIntGadget :public FloatToFixPointGadget < unsigned int,FloatToUIntGadget > - { - public: - using FloatToFixPointGadget::FloatToFixPointGadget; - NODE_PROPERTY(max_intensity, int, "Maximum intensity value", 4095 ); - NODE_PROPERTY(min_intensity, int , "Minimal intensity value", 0); - NODE_PROPERTY(intensity_offset, int , "Intensity offset", 2048); - ~FloatToUIntGadget() override = default; - }; - class FloatToIntGadget :public FloatToFixPointGadget < int,FloatToIntGadget > - { - public: - using FloatToFixPointGadget::FloatToFixPointGadget; - NODE_PROPERTY(max_intensity, int, "Maximum intensity value", 4095 ); - NODE_PROPERTY(min_intensity, int , "Minimal intensity value", 0); - NODE_PROPERTY(intensity_offset, int , "Intensity offset", 2048); - ~FloatToIntGadget() override = default; - }; - - - - - -} - diff --git a/gadgets/mri_core/FloatToFixedPointGadget.cpp b/gadgets/mri_core/FloatToFixedPointGadget.cpp new file mode 100644 index 00000000..9f12fb38 --- /dev/null +++ b/gadgets/mri_core/FloatToFixedPointGadget.cpp @@ -0,0 +1,100 @@ +#include "FloatToFixedPointGadget.h" +#include "mri_core_def.h" +#include "hoNDArray_math.h" + + +#include + +namespace Gadgetron +{ + + template + struct Converter { + Converter(float min, float max, float offset) : min_(min), max_(max), offset_(offset) {} + + mrd::Image convert(const mrd::Image& image_in) const { + auto clamp = [&](float val){ + return lround(std::min(std::max(val, min_), max_)); + }; + auto magnitude = [&](auto val){ + return T(clamp(std::abs(val))); + }; + + auto real_value = [&](auto val){ + return T(clamp(float(val) + offset_)); + }; + + auto phase = [&](float val){ + return T(clamp((val * offset_ / boost::math::float_constants::pi) + offset_)); + }; + + mrd::Image image_out; + image_out.head = image_in.head; + image_out.meta = image_in.meta; + image_out.data.create(image_in.data.dimensions()); + auto& output_data = image_out.data; + + // Now we're ready to transform the image data + switch (image_in.head.image_type) { + case mrd::ImageType::kMagnitude: { + std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), magnitude); + } + break; + + case mrd::ImageType::kReal: + case mrd::ImageType::kImag: { + std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), real_value); + + if (image_out.meta.count(GADGETRON_IMAGE_WINDOWCENTER) && image_out.meta[GADGETRON_IMAGE_WINDOWCENTER].size() > 0) { + long windowCenter = std::get(image_out.meta[GADGETRON_IMAGE_WINDOWCENTER].front()); + image_out.meta[GADGETRON_IMAGE_WINDOWCENTER] = {windowCenter + offset_}; + } + } + break; + + case mrd::ImageType::kPhase: { + std::transform(image_in.data.begin(), image_in.data.end(), output_data.begin(), phase); + } + break; + + default: + throw std::runtime_error("Unknown image type in Image"); + } + + return std::move(image_out); + } + + float min_; + float max_; + float offset_; + }; + + template + void convert_image(const Converter& converter, Core::InputChannel> &input, Core::OutputChannel &output) + { + for (auto img: input) { + output.push(converter.convert(img)); + } + } + + void FloatToFixedPointGadget::process(Core::InputChannel> &input, Core::OutputChannel &output) + { + if (parameters_.type == "ushort") { + Converter converter(parameters_.min_intensity, parameters_.max_intensity, parameters_.intensity_offset); + convert_image(converter, input, output); + } else if (parameters_.type == "short") { + Converter converter(parameters_.min_intensity, parameters_.max_intensity, parameters_.intensity_offset); + convert_image(converter, input, output); + } else if (parameters_.type == "uint") { + Converter converter(parameters_.min_intensity, parameters_.max_intensity, parameters_.intensity_offset); + convert_image(converter, input, output); + } else if (parameters_.type == "int") { + Converter converter(parameters_.min_intensity, parameters_.max_intensity, parameters_.intensity_offset); + convert_image(converter, input, output); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + GADGETRON_GADGET_EXPORT(FloatToFixedPointGadget) +} diff --git a/gadgets/mri_core/FloatToFixedPointGadget.h b/gadgets/mri_core/FloatToFixedPointGadget.h new file mode 100644 index 00000000..0f41b7b9 --- /dev/null +++ b/gadgets/mri_core/FloatToFixedPointGadget.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Node.h" + +namespace Gadgetron +{ + + /** + * This Gadget converts float values to fixed point integer format. + * + * How the conversion is done will depend on the image type: + * Magnitude images: Values above 4095 will be clamped. + * Real or Imag: Values below -2048 and above 2047 will be clamped. Zero will be 2048. + * Phase: -pi will be 0, +pi will be 4095. + * + */ + + class FloatToFixedPointGadget: public Core::MRChannelGadget> + { + public: + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Float to Fixed Point Conversion") + { + register_parameter("type", &type, "Output integer type (ushort, short, uint, int)"); + register_parameter("max_intensity", &max_intensity, "Maximum intensity value"); + register_parameter("min_intensity", &min_intensity, "Minimum intensity value"); + register_parameter("intensity_offset", &intensity_offset, "Intensity offset"); + } + + std::string type = "ushort"; + float max_intensity = 4095; + float min_intensity = 0; + float intensity_offset = 2048; + }; + + FloatToFixedPointGadget(const Core::MrdContext& context, const Parameters& params) + : MRChannelGadget(context, params) + , parameters_(params) + {} + + ~FloatToFixedPointGadget() override = default ; + + void process(Core::InputChannel>& input, Core::OutputChannel& output) override; + + protected: + Parameters parameters_; + }; +} \ No newline at end of file diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index 7dda6647..fd835c22 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -189,7 +189,7 @@ namespace Gadgetron { , acquisition_system_information_(context.header.acquisition_system_information) { GDEBUG_STREAM("skip_noise_adjust is " << parameters_.skip_noise_adjust); - GDEBUG_STREAM("discard_nonconformant_data is " << parameters_.discard_nonconformant_data); + GDEBUG_STREAM("reject_nonconformant_data is " << parameters_.reject_nonconformant_data); GDEBUG_STREAM("receiver_noise_bandwidth is " << receiver_noise_bandwidth); if (parameters_.skip_noise_adjust) @@ -317,12 +317,11 @@ namespace Gadgetron { os.flush(); os.close(); } else { - GERROR_STREAM("Unable to open file " << parameters_.noise_covariance_out << " for writing noise covariance"); - throw std::runtime_error("Unable to open file for writing noise covariance"); + GADGET_THROW("Unable to open file " << parameters_.noise_covariance_out << " for writing noise covariance"); } } else { GERROR_STREAM("Unable to save noise covariance. Noise covariance output file must be provided as a parameter"); - // throw std::runtime_error("Noise covariance output file must be provided as a parameter"); + // GADGET_THROW("Noise covariance output file must be provided as a parameter"); } } @@ -344,8 +343,8 @@ namespace Gadgetron { auto dataM = as_arma_matrix(acq.data); auto pwm = as_arma_matrix(pw.prewhitening_matrix); dataM *= pwm; - } else if (!parameters_.discard_nonconformant_data) { - throw std::runtime_error("Input data has different number of channels from noise data"); + } else if (parameters_.reject_nonconformant_data) { + GADGET_THROW("Input data has different number of channels from noise data"); } return std::move(pw); } @@ -409,7 +408,6 @@ namespace Gadgetron { if (!file) { GERROR_STREAM("Could not open noise covariance file " << parameters_.noise_covariance_in); GWARN("Falling back to noise gathering\n"); - // throw std::runtime_error("Could not open noise covariance file"); return std::nullopt; } mrd::binary::MrdNoiseCovarianceReader reader(file); diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index a2de5f3d..80f90aac 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -35,7 +35,7 @@ namespace Gadgetron { std::string noise_covariance_out = ""; bool skip_noise_adjust = false; - bool discard_nonconformant_data = false; + bool reject_nonconformant_data = false; float noise_dwell_time_us_preset = 0.0; std::string scale_only_channels_by_name = ""; @@ -43,7 +43,7 @@ namespace Gadgetron { register_parameter("covariance-input", &noise_covariance_in, "Input file containing noise covariance matrix"); register_parameter("covariance-output", &noise_covariance_out, "Output file containing noise covariance matrix"); register_flag("skip", &skip_noise_adjust, "Skip noise adjustment"); - register_flag("discard-nonconformant-data", &discard_nonconformant_data, "Discard data that does not conform"); + register_flag("reject-nonconformant-data", &reject_nonconformant_data, "Reject data that does not conform (i.e. channels mismatch)"); register_parameter("dwell-time-us-preset", &noise_dwell_time_us_preset, "Preset dwell time for noise measurement"); register_parameter("scale-only-channels-by-name", &scale_only_channels_by_name, "List of named channels that should only be scaled"); } diff --git a/toolboxes/log/log.h b/toolboxes/log/log.h index 790998f9..e9c84334 100644 --- a/toolboxes/log/log.h +++ b/toolboxes/log/log.h @@ -190,12 +190,17 @@ namespace Gadgetron #define GDEBUG_CONDITION_STREAM(con, message) { if ( con ) GDEBUG_STREAM(message) } #define GWARN_CONDITION_STREAM(con, message) { if ( con ) GWARN_STREAM(message) } -// #define GADGET_THROW(msg) { GERROR_STREAM(msg); throw std::runtime_error(msg); } -#define GADGET_THROW(msg) { GERROR_STREAM(msg); throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + " -- " + msg); } +#define GADGET_THROW(msg) \ + { \ + std::stringstream ss; \ + ss << msg << std::endl; \ + GERROR(ss.str().c_str()); \ + throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + " -- " + ss.str()); \ + } -#define GADGET_CHECK_THROW(con) { if ( !(con) ) { GERROR_STREAM(#con); throw std::runtime_error(#con); } } +#define GADGET_CHECK_THROW(con) { if ( !(con) ) { GADGET_THROW(#con); } } -#define GADGET_CATCH_THROW(con) { try { con; } catch(...) { GERROR_STREAM(#con); throw std::runtime_error(#con); } } +#define GADGET_CATCH_THROW(con) { try { con; } catch(...) { GADGET_THROW(#con); } } #define GADGET_CHECK_RETURN(con, value) { if ( ! (con) ) { GERROR_STREAM("Returning '" << value << "' due to failed check: '" << #con << "'"); return (value); } } #define GADGET_CHECK_RETURN_FALSE(con) { if ( ! (con) ) { GERROR_STREAM("Returning false due to failed check: '" << #con << "'"); return false; } } From 47568452cdde12b6174ca434a90a298cbf655aca Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Mon, 3 Feb 2025 15:46:24 +0000 Subject: [PATCH 09/21] Update remaining mri_core gadgets --- gadgets/examples/ImageInverter.h | 6 +-- gadgets/mri_core/AccumulatorGadget.cpp | 40 +++++-------------- gadgets/mri_core/AccumulatorGadget.h | 22 ++++++---- gadgets/mri_core/CMakeLists.txt | 12 +++--- .../mri_core/FlowPhaseSubtractionGadget.cpp | 4 +- gadgets/mri_core/FlowPhaseSubtractionGadget.h | 5 +-- gadgets/mri_core/ImageIndexGadget.cpp | 3 -- gadgets/mri_core/ImageIndexGadget.h | 4 +- gadgets/mri_core/ImageSortGadget.cpp | 17 ++++---- gadgets/mri_core/ImageSortGadget.h | 19 +++++++-- gadgets/mri_core/MaxwellCorrectionGadget.cpp | 11 +++-- gadgets/mri_core/MaxwellCorrectionGadget.h | 21 +++++----- 12 files changed, 78 insertions(+), 86 deletions(-) diff --git a/gadgets/examples/ImageInverter.h b/gadgets/examples/ImageInverter.h index 37d0ddcd..0b4fd750 100644 --- a/gadgets/examples/ImageInverter.h +++ b/gadgets/examples/ImageInverter.h @@ -3,9 +3,9 @@ #include "PureGadget.h" namespace Gadgetron::Examples { - class ImageInverter : public Core::PureGadget { + class ImageInverter : public Core::MRPureGadget { public: - using Core::PureGadget::PureGadget; - mrd::AnyImage process_function(mrd::AnyImage image) const override; + using Core::MRPureGadget::PureGadget; + mrd::AnyImage process_function(mrd::AnyImage image) const override; }; } diff --git a/gadgets/mri_core/AccumulatorGadget.cpp b/gadgets/mri_core/AccumulatorGadget.cpp index 7c8a754a..1d4f9755 100644 --- a/gadgets/mri_core/AccumulatorGadget.cpp +++ b/gadgets/mri_core/AccumulatorGadget.cpp @@ -20,12 +20,11 @@ int addPrePostZeros(size_t centre_column, size_t samples) { namespace Gadgetron { -AccumulatorGadget::AccumulatorGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) { - buffer_ = 0; - image_counter_ = 0; - image_series_ = 0; - +AccumulatorGadget::AccumulatorGadget(const Core::MrdContext& context, const Parameters& params) + : AccumulatorGadget::MRChannelGadget(context, params) + , parameters_(params) + , image_counter_(0) +{ auto h = (context.header); if (h.encoding.size() != 1) { GDEBUG("Number of encoding spaces: %d\n", h.encoding.size()); @@ -50,31 +49,13 @@ AccumulatorGadget::AccumulatorGadget(const Core::Context& context, const Core::G slices_ = e_limits.slice ? e_limits.slice->maximum + 1 : 1; } -AccumulatorGadget::~AccumulatorGadget() { - if (buffer_) - delete buffer_; -} - void AccumulatorGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { mrd::Acquisition ref_acq; for (auto acq : in) { - if (!buffer_) { + if (!(buffer_.size() > 0)) { dimensions_.push_back(acq.Coils()); dimensions_.push_back(slices_); - - if (!(buffer_ = new hoNDArray>())) { - GDEBUG("Failed create buffer\n"); - // TODO: How to throw Gadget failures? - } - - try { - buffer_->create(dimensions_); - } - catch (std::runtime_error& err) { - GEXCEPTION(err, "Failed allocate buffer array\n"); - // TODO: How to throw Gadget failures? - } - image_series_ = image_series; + buffer_.create(dimensions_); } bool is_first_scan_in_slice = acq.head.flags.HasFlags(mrd::AcquisitionFlags::kFirstInSlice); @@ -82,7 +63,7 @@ void AccumulatorGadget::process(Core::InputChannel& in, Core:: ref_acq = acq; } - std::complex* buffer_raw = buffer_->get_data_ptr(); + std::complex* buffer_raw = buffer_.get_data_ptr(); std::complex* data_raw = acq.data.data(); int samples = acq.Samples(); @@ -92,8 +73,7 @@ void AccumulatorGadget::process(Core::InputChannel& in, Core:: int center_sample = acq.head.center_sample.value_or(samples / 2); if (samples > dimensions_[0]) { - GDEBUG("Wrong number of samples received\n"); - // TODO: How to throw Gadget failures + GADGET_THROW("Wrong number of samples received\n"); } size_t offset = 0; @@ -140,7 +120,7 @@ void AccumulatorGadget::process(Core::InputChannel& in, Core:: img.head.physiology_time_stamp = acq.head.physiology_time_stamp; img.head.image_type = mrd::ImageType::kComplex; img.head.image_index = ++image_counter_; - img.head.image_series_index = image_series_; + img.head.image_series_index = parameters_.image_series; out.push(img); } diff --git a/gadgets/mri_core/AccumulatorGadget.h b/gadgets/mri_core/AccumulatorGadget.h index ae819bf6..694b1750 100644 --- a/gadgets/mri_core/AccumulatorGadget.h +++ b/gadgets/mri_core/AccumulatorGadget.h @@ -9,20 +9,28 @@ #include "hoNDArray.h" namespace Gadgetron{ - class AccumulatorGadget : public Core::ChannelGadget + class AccumulatorGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - AccumulatorGadget(const Core::Context& context, const Core::GadgetProperties& props); - ~AccumulatorGadget() override; + struct Parameters : public Core::NodeParameters + { + long long image_series = 1; + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Accumulator Gadget") + { + register_parameter("image_series", &image_series, "Image series number"); + } + }; + + AccumulatorGadget(const Core::MrdContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; + protected: - NODE_PROPERTY(image_series, int, "Image series", 0); - hoNDArray>* buffer_; + const Parameters parameters_; + + hoNDArray> buffer_; std::vector dimensions_; float field_of_view_[3]; size_t slices_; long long image_counter_; - long long image_series_; }; } \ No newline at end of file diff --git a/gadgets/mri_core/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index 81bd9d34..ec023f6a 100644 --- a/gadgets/mri_core/CMakeLists.txt +++ b/gadgets/mri_core/CMakeLists.txt @@ -60,9 +60,7 @@ set(pingvin_mricore_src_files FFTGadget.cpp FlagTriggerGadget.cpp FloatToFixedPointGadget.cpp - FlowPhaseSubtractionGadget.cpp ImageArraySplitGadget.cpp - MaxwellCorrectionGadget.cpp NoiseAdjustGadget.cpp PCACoilGadget.cpp PhysioInterpolationGadget.cpp @@ -70,10 +68,12 @@ set(pingvin_mricore_src_files SimpleReconGadget.cpp # These Gadgets are NOT TESTED, but they HAVE BEEN upgraded to MRD v2 - # AccumulatorGadget.cpp - # ImageIndexGadget.cpp - # ImageSortGadget.cpp - # ScaleGadget.cpp + AccumulatorGadget.cpp + FlowPhaseSubtractionGadget.cpp + ImageIndexGadget.cpp + ImageSortGadget.cpp + MaxwellCorrectionGadget.cpp + ScaleGadget.cpp # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 # CoilComputationGadget.cpp diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp index 653b227c..ea429c95 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp @@ -7,8 +7,8 @@ namespace Gadgetron { -FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget>>(context, props) +FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : FlowPhaseSubtractionGadget::MRChannelGadget(context, params) { const auto e_limits = context.header.encoding[0].encoding_limits; sets_ = e_limits.set ? e_limits.set->maximum + 1 : 1; diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.h b/gadgets/mri_core/FlowPhaseSubtractionGadget.h index e7818ddb..002df671 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.h +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.h @@ -7,12 +7,11 @@ namespace Gadgetron{ - class FlowPhaseSubtractionGadget : public Core::ChannelGadget>> + class FlowPhaseSubtractionGadget : public Core::MRChannelGadget>> { public: - FlowPhaseSubtractionGadget(const Core::Context& context, const Core::GadgetProperties& props); - + FlowPhaseSubtractionGadget(const Core::MrdContext& context, const Core::NodeParameters& params); ~FlowPhaseSubtractionGadget() override = default; void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/ImageIndexGadget.cpp b/gadgets/mri_core/ImageIndexGadget.cpp index 9b6f7e84..bb9dd7f0 100644 --- a/gadgets/mri_core/ImageIndexGadget.cpp +++ b/gadgets/mri_core/ImageIndexGadget.cpp @@ -17,9 +17,6 @@ namespace { namespace Gadgetron { - ImageIndexGadget::ImageIndexGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : ChannelGadget(context, properties) {} - void ImageIndexGadget::process(Core::InputChannel &input, Core::OutputChannel &output) { std::map indices{}; diff --git a/gadgets/mri_core/ImageIndexGadget.h b/gadgets/mri_core/ImageIndexGadget.h index ed342878..c7161c3f 100644 --- a/gadgets/mri_core/ImageIndexGadget.h +++ b/gadgets/mri_core/ImageIndexGadget.h @@ -10,9 +10,9 @@ namespace Gadgetron { * ImageIndexGadget will keep track of individual image series, and number images in each series * sequentially. */ - class ImageIndexGadget : public Core::ChannelGadget { + class ImageIndexGadget : public Core::MRChannelGadget { public: - ImageIndexGadget(const Core::Context &, const Core::GadgetProperties &); + using Core::MRChannelGadget::MRChannelGadget; void process(Core::InputChannel &, Core::OutputChannel &) override; }; } diff --git a/gadgets/mri_core/ImageSortGadget.cpp b/gadgets/mri_core/ImageSortGadget.cpp index 7a8a379c..344c7e36 100644 --- a/gadgets/mri_core/ImageSortGadget.cpp +++ b/gadgets/mri_core/ImageSortGadget.cpp @@ -4,27 +4,24 @@ namespace Gadgetron { - ImageSortGadget::ImageSortGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : ChannelGadget(context, properties) {} - void ImageSortGadget::process(Core::InputChannel &input, Core::OutputChannel &output) { // Lambda, gets index from correct field in ImageHeader based on parameterized sorting dimension auto getImageIndex = [&](const auto& i){ auto &header = i.head; - if (sorting_dimension.size() == 0) { + if (parameters_.sorting_dimension.size() == 0) { return uint32_t(-1); - } else if (sorting_dimension.compare("average") == 0) { + } else if (parameters_.sorting_dimension.compare("average") == 0) { return header.average.value_or(0); - } else if (sorting_dimension.compare("slice") == 0) { + } else if (parameters_.sorting_dimension.compare("slice") == 0) { return header.slice.value_or(0); - } else if (sorting_dimension.compare("contrast") == 0) { + } else if (parameters_.sorting_dimension.compare("contrast") == 0) { return header.contrast.value_or(0); - } else if (sorting_dimension.compare("phase") == 0) { + } else if (parameters_.sorting_dimension.compare("phase") == 0) { return header.phase.value_or(0); - } else if (sorting_dimension.compare("repetition") == 0) { + } else if (parameters_.sorting_dimension.compare("repetition") == 0) { return header.repetition.value_or(0); - } else if (sorting_dimension.compare("set") == 0) { + } else if (parameters_.sorting_dimension.compare("set") == 0) { return header.set.value_or(0); } else { return uint32_t(-1); diff --git a/gadgets/mri_core/ImageSortGadget.h b/gadgets/mri_core/ImageSortGadget.h index 5334078c..0c023046 100644 --- a/gadgets/mri_core/ImageSortGadget.h +++ b/gadgets/mri_core/ImageSortGadget.h @@ -16,13 +16,24 @@ namespace Gadgetron{ int index_; }; - class ImageSortGadget : public Core::ChannelGadget { + class ImageSortGadget : public Core::MRChannelGadget { public: - ImageSortGadget(const Core::Context &, const Core::GadgetProperties &); + struct Parameters : public Core::NodeParameters { + std::string sorting_dimension = "slice"; + Parameters(const std::string &prefix) : Core::NodeParameters(prefix, "Image Sorting Options") { + register_parameter("sorting_dimension", &sorting_dimension, "Dimension that data will be sorted by (average, slice, contrast, phase, repetition, set)"); + } + }; + + ImageSortGadget(const Core::MrdContext& context, const Parameters& params) + : ImageSortGadget::MRChannelGadget(context, params) + , parameters_(params) + {} + void process(Core::InputChannel &, Core::OutputChannel &) override; + protected: - // { "average", "slice", "contrast", "phase", "repetition", "set" } - NODE_PROPERTY(sorting_dimension, std::string, "Dimension that data will be sorted by", "slice"); + const Parameters parameters_; std::vector images_; }; } \ No newline at end of file diff --git a/gadgets/mri_core/MaxwellCorrectionGadget.cpp b/gadgets/mri_core/MaxwellCorrectionGadget.cpp index 3edd89ac..fd131c4b 100644 --- a/gadgets/mri_core/MaxwellCorrectionGadget.cpp +++ b/gadgets/mri_core/MaxwellCorrectionGadget.cpp @@ -7,12 +7,12 @@ namespace Gadgetron { #endif // M_PI #define M_PI 3.14159265358979323846 -MaxwellCorrectionGadget::MaxwellCorrectionGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget>>(context, props) { +MaxwellCorrectionGadget::MaxwellCorrectionGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + : MaxwellCorrectionGadget::MRChannelGadget(context, params) +{ maxwell_coefficients_present_ = false; maxwell_coefficients_ = std::vector(4, 0); - auto h = (context.header); - + auto h = context.header; if (h.user_parameters) { for (std::vector::const_iterator i(h.user_parameters->user_parameter_double.begin()); i != h.user_parameters->user_parameter_double.end(); i++) { @@ -29,8 +29,7 @@ MaxwellCorrectionGadget::MaxwellCorrectionGadget(const Core::Context& context, c } } } else { - GDEBUG("MaxwellCorrection coefficients are supposed to be in the UserParameters. No user parameter section " - "found\n"); + GDEBUG("MaxwellCorrection coefficients are supposed to be in the UserParameters. No user parameter section found\n"); return; } diff --git a/gadgets/mri_core/MaxwellCorrectionGadget.h b/gadgets/mri_core/MaxwellCorrectionGadget.h index 419fdadc..d72749ef 100644 --- a/gadgets/mri_core/MaxwellCorrectionGadget.h +++ b/gadgets/mri_core/MaxwellCorrectionGadget.h @@ -13,23 +13,24 @@ #endif namespace Gadgetron { -class MaxwellCorrectionGadget : public Core::ChannelGadget>> { +class MaxwellCorrectionGadget : public Core::MRChannelGadget>> { public: - using Core::ChannelGadget>>::ChannelGadget; - MaxwellCorrectionGadget(const Core::Context& context, const Core::GadgetProperties& props); + MaxwellCorrectionGadget(const Core::MrdContext& context, const Core::NodeParameters& params); ~MaxwellCorrectionGadget() override = default; + void process(Core::InputChannel>>& input, Core::OutputChannel& output) override; void patient_to_physical_coordinate(std::vector &norm_vec, mrd::PatientPosition patient_position); void find_flow_dir(mrd::Image> m1); + protected: std::vector maxwell_coefficients_; - std::vector RO_dir_Physical_; - std::vector PE_dir_Physical_; - std::vector SLC_dir_Physical_; - std::vector SLC_position_Physical_; + std::vector RO_dir_Physical_; + std::vector PE_dir_Physical_; + std::vector SLC_dir_Physical_; + std::vector SLC_position_Physical_; bool FlipPhaseDirection_ = false; - int FlowDirection_ = 4; //flow encoding direction: 4 through plane, 2 RO direction, 1 PE direction - mrd::PatientPosition patient_position_; - bool maxwell_coefficients_present_; + int FlowDirection_ = 4; // flow encoding direction: 4 through plane, 2 RO direction, 1 PE direction + mrd::PatientPosition patient_position_; + bool maxwell_coefficients_present_; }; } // namespace Gadgetron From f32be35ad04b1c24da1fd4a61ad2c1afce3af922 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Wed, 5 Feb 2025 20:44:22 +0000 Subject: [PATCH 10/21] Add parallel Pipeline streams. Update grappa gadgets. --- apps/emperor/CMakeLists.txt | 2 + apps/emperor/main.cc | 6 +- apps/emperor/pipelines/default.h | 4 +- apps/emperor/pipelines/epi.h | 2 +- apps/emperor/pipelines/file_search.h | 2 +- apps/emperor/pipelines/grappa.h | 51 +++ apps/emperor/pipelines/grappa_cpu.h | 35 -- apps/emperor/pipelines/noise.h | 2 +- apps/emperor/pipelines/pipeline.h | 368 ++++++++++++++------ apps/pingvin/nodes/NodeProcessable.h | 25 ++ apps/pingvin/nodes/Parallel.cpp | 25 -- apps/pingvin/nodes/Parallel.h | 6 + apps/pingvin/nodes/Stream.cpp | 31 +- apps/pingvin/nodes/Stream.h | 2 +- core/Node.h | 11 - core/parallel/Branch.h | 30 +- core/parallel/Fanout.h | 5 +- core/parallel/Fanout.hpp | 7 - core/parallel/Merge.h | 30 +- gadgets/grappa/ImageAccumulator.cpp | 8 - gadgets/grappa/ImageAccumulator.h | 10 +- gadgets/grappa/SliceAccumulator.cpp | 5 - gadgets/grappa/SliceAccumulator.h | 7 +- gadgets/grappa/Unmixing.cpp | 30 +- gadgets/grappa/Unmixing.h | 29 +- gadgets/grappa/WeightsCalculator.cpp | 22 +- gadgets/grappa/WeightsCalculator.h | 49 ++- gadgets/grappa/common/AcquisitionBuffer.cpp | 18 +- gadgets/grappa/common/AcquisitionBuffer.h | 5 +- 29 files changed, 490 insertions(+), 337 deletions(-) create mode 100644 apps/emperor/pipelines/grappa.h delete mode 100644 apps/emperor/pipelines/grappa_cpu.h create mode 100644 apps/pingvin/nodes/NodeProcessable.h diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index 400eaaba..139c84d1 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -22,8 +22,10 @@ add_executable(emperor target_link_libraries(emperor pingvin_core + pingvin_core_parallel pingvin_mricore pingvin_epi + pingvin_grappa Boost::system Boost::program_options GTBLAS) diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index cf24aeb2..abf66b39 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -1,5 +1,5 @@ #include "pipelines/noise.h" -// #include "pipelines/cartesian_grappa.h" +#include "pipelines/grappa.h" #include "pipelines/default.h" #include "pipelines/epi.h" @@ -99,8 +99,8 @@ int main(int argc, char** argv) } // "Choose" a Pipeline - std::vector builders{&epi_2d, &default_mr, &default_mr_optimized, &noise_dependency, &file_search}; - std::map builder_map; + std::vector builders{&epi_2d, &default_mr, &default_mr_optimized, &noise_dependency, &file_search, &grappa}; + std::map builder_map; for (auto& builder : builders) { builder_map[builder->name] = builder; } diff --git a/apps/emperor/pipelines/default.h b/apps/emperor/pipelines/default.h index d95920a3..043fafeb 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/emperor/pipelines/default.h @@ -16,7 +16,7 @@ namespace pingvin { using namespace Gadgetron; -static auto default_mr = Pipeline::Builder("default", "Basic Cartesian Reconstruction") +static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") .withSource() .withSink() .withNode("ros") @@ -27,7 +27,7 @@ static auto default_mr = Pipeline::Builder("default", "Basic Cartesi .withNode("extract") ; -static auto default_mr_optimized = Pipeline::Builder("default-optimized", "Basic Cartesian Reconstruction") +static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") .withSource() .withSink() .withNode("noise-adjust") diff --git a/apps/emperor/pipelines/epi.h b/apps/emperor/pipelines/epi.h index 36ac159f..f06c4711 100644 --- a/apps/emperor/pipelines/epi.h +++ b/apps/emperor/pipelines/epi.h @@ -19,7 +19,7 @@ namespace pingvin { using namespace Gadgetron; - static auto epi_2d = Pipeline::Builder("epi", "Basic EPI Reconstruction") + static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") .withSource() .withSink() .withNode("noise-adjust") diff --git a/apps/emperor/pipelines/file_search.h b/apps/emperor/pipelines/file_search.h index 211da022..14cd7e13 100644 --- a/apps/emperor/pipelines/file_search.h +++ b/apps/emperor/pipelines/file_search.h @@ -80,7 +80,7 @@ namespace pingvin { const Parameters parameters_; }; - static auto file_search = Pipeline::Builder("text-search", "Search for strings in text") + static auto file_search = PipelineBuilder("text-search", "Search for strings in text") .withSource() .withSink() .withNode("search") diff --git a/apps/emperor/pipelines/grappa.h b/apps/emperor/pipelines/grappa.h new file mode 100644 index 00000000..65f244ec --- /dev/null +++ b/apps/emperor/pipelines/grappa.h @@ -0,0 +1,51 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/PCACoilGadget.h" +#include "gadgets/mri_core/CoilReductionGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/grappa/SliceAccumulator.h" +#include "gadgets/grappa/AcquisitionFanout.h" +#include "gadgets/grappa/ImageAccumulator.h" +#include "gadgets/grappa/WeightsCalculator.h" +#include "gadgets/grappa/Unmixing.h" +#include "gadgets/mri_core/ExtractGadget.h" +#include "gadgets/mri_core/AutoScaleGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" + +namespace pingvin { + +using namespace Gadgetron; + +static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") + .withSource() + .withSink() + .withNode("noise-adjust") + .withNode("pca") + .withNode("coil-reduction") + .withNode("echo-adjust") + .withNode("remove-oversampling") + .withNode("slice-acc") + + // Parallel + // Branch: AcquisitionFanout + // Stream + // ImageAccumulator + // Stream + // cpuWeightsCalculator + // Merge: Unmixing + .withBranch("acq-fanout") + .withStream("images") + .withNode("image-acc") + .withStream("weights") + .withNode("weights") + .withMerge("unmixing") + + .withNode("extract") + .withNode("scale") + .withNode("convert"); + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/grappa_cpu.h b/apps/emperor/pipelines/grappa_cpu.h deleted file mode 100644 index d843b363..00000000 --- a/apps/emperor/pipelines/grappa_cpu.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "pipeline.h" - -#include "gadgets/mri_core/NoiseAdjustGadget.h" -#include "gadgets/mri_core/RemoveROOversamplingGadget.h" -#include "gadgets/mri_core/ExtractGadget.h" - -namespace pingvin { - -class GrappaCPU : public Pipeline { - public: - GrappaCPU() : Pipeline("grappa_cpu", "Grappa Reconstruction on CPU") { } - - void build(void) override { - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - this->append(); - // Parallel - // Branch: AcquisitionFanout - // Stream - // ImageAccumulator - // Stream - // cpuWeightsCalculator - // Merge: Unmixing - this->append(); - this->append(); - this->append(); - } -}; - -} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/noise.h b/apps/emperor/pipelines/noise.h index fdad651c..4e3082c0 100644 --- a/apps/emperor/pipelines/noise.h +++ b/apps/emperor/pipelines/noise.h @@ -8,7 +8,7 @@ namespace pingvin { using namespace Gadgetron; - static auto noise_dependency = Pipeline::Builder("noise", "Compute noise covariance for measurement dependency") + static auto noise_dependency = PipelineBuilder("noise", "Compute noise covariance for measurement dependency") .withSource() .withSink() .withNode("noise") diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index 0039c755..f0fae8f7 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -9,10 +9,14 @@ namespace po = boost::program_options; #include "mrd/binary/protocols.h" #include "nodes/Stream.h" +#include "nodes/NodeProcessable.h" +#include "nodes/Parallel.h" #include "Channel.h" #include "ErrorHandler.h" #include "Node.h" +#include "parallel/Branch.h" +#include "parallel/Merge.h" namespace pingvin { @@ -131,8 +135,8 @@ struct MrdSink : public ISink { template struct INodeBuilder { virtual ~INodeBuilder() = default; - virtual std::shared_ptr build(const C& ctx) const = 0; - virtual Gadgetron::Core::NodeParameters get_parameters(void) = 0; + virtual std::shared_ptr build(const C& ctx) const = 0; + virtual void collect_options(po::options_description& parent) = 0; }; template @@ -140,12 +144,21 @@ class NodeBuilder : public INodeBuilder { public: NodeBuilder(const std::string& label): label_(label), parameters_(label) {} - virtual std::shared_ptr build(const CTX& ctx) const override { - return std::make_shared(ctx, this->parameters_); + std::shared_ptr build(const CTX& ctx) const override { + auto node = std::make_shared(ctx, this->parameters_); + return std::make_shared(node, label_); } - virtual Gadgetron::Core::NodeParameters get_parameters(void) override { - return parameters_; + void collect_options(po::options_description& parent) override { + po::options_description desc(parameters_.description()); + + if (parameters_.parameters().size() > 0) { + for (auto& p: parameters_.parameters()) { + desc.add(p->as_boost_option()); + } + + parent.add(desc); + } } private: @@ -153,132 +166,214 @@ class NodeBuilder : public INodeBuilder { typename N::Parameters parameters_; }; +template +class StreamBuilder : public INodeBuilder { +public: + StreamBuilder() {} + StreamBuilder(const std::string& key): key_(key) {} -class ErrorThrower : public Gadgetron::Main::ErrorReporter -{ - public: - void operator()(const std::string& location, const std::string& message) override { - throw std::runtime_error(("[" + location + "] ERROR: " + message)); + void collect_options(po::options_description& stream_desc) override { + for (auto& nb: builders_) { + nb->collect_options(stream_desc); + } } + + std::shared_ptr build(const CTX& ctx) const override { + std::vector> processables; + for (auto& builder : builders_) { + processables.emplace_back( + builder->build(ctx) + ); + } + return std::make_shared(processables, key_); + } + + void append(std::shared_ptr> builder) { + builders_.emplace_back(builder); + } + +private: + std::string key_; + std::vector>> builders_; +}; + +template +struct IBranchBuilder { + virtual ~IBranchBuilder() = default; + virtual std::unique_ptr build(const CTX& ctx) const = 0; + virtual void collect_options(po::options_description& parent) = 0; }; -class NewNodeProcessable : public Gadgetron::Main::Processable { +template +class BranchBuilder : public IBranchBuilder { public: - NewNodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} + BranchBuilder(const std::string& label): label_(label), parameters_(label) {} - void process(Gadgetron::Core::GenericInputChannel input, - Gadgetron::Core::OutputChannel output, - Gadgetron::Main::ErrorHandler & - ) override { - node_->process(input, output); + std::unique_ptr build(const CTX& ctx) const override { + return std::move(std::make_unique(ctx, this->parameters_)); } - const std::string& name() override { - return name_; + void collect_options(po::options_description& parent) override { + po::options_description desc(parameters_.description()); + + if (parameters_.parameters().size() > 0) { + for (auto& p: parameters_.parameters()) { + desc.add(p->as_boost_option()); + } + + parent.add(desc); + } } private: - std::shared_ptr node_; - const std::string name_; + std::string label_; + typename N::Parameters parameters_; }; -class Pipeline { - public: +template +struct IMergeBuilder { + virtual ~IMergeBuilder() = default; + virtual std::unique_ptr build(const CTX& ctx) const = 0; + virtual void collect_options(po::options_description& parent) = 0; +}; - struct IBuilder { - IBuilder(const std::string& name, const std::string& description): name(name), description(description) { } - virtual Pipeline build(std::istream& input_stream, std::ostream& output_stream) = 0; - virtual po::options_description collect_options(void) = 0; - virtual ~IBuilder() = default; - - const std::string name; - const std::string description; - }; - - template - struct Builder : public IBuilder{ - Builder(const std::string& pipeline_name, const std::string& pipeline_description) - : IBuilder(pipeline_name, pipeline_description) {} - - template - Builder& withSource(void) { - source_builder_ = [](std::istream& is) { return std::make_shared(is); }; - return *this; - } +template +class MergeBuilder : public IMergeBuilder { +public: + MergeBuilder(const std::string& label): label_(label), parameters_(label) {} - template - Builder& withSink(void) { - sink_builder_ = [](std::ostream& os, const CTX& ctx) { return std::make_shared(os, ctx); }; - return *this; - } + std::unique_ptr build(const CTX& ctx) const override { + return std::move(std::make_unique(ctx, this->parameters_)); + } - template - Builder& withNode(const std::string& label) { - auto nb = std::make_shared>(label); - builders_.emplace_back(nb); - return *this; + void collect_options(po::options_description& parent) override { + po::options_description desc(parameters_.description()); + + if (parameters_.parameters().size() > 0) { + for (auto& p: parameters_.parameters()) { + desc.add(p->as_boost_option()); + } + + parent.add(desc); } + } - po::options_description collect_options(void) override { - po::options_description pipeline_desc(this->description); +private: + std::string label_; + typename N::Parameters parameters_; +}; + +template +struct PipelineBuilder; + +template +class ParallelBuilder : public INodeBuilder { +public: + ParallelBuilder(PipelineBuilder& parent) + : parent_(parent) + {} + + template + ParallelBuilder& withBranch(const std::string& label) { + branch_builder_ = std::make_unique>(label); + return *this; + } - for (auto& nb: builders_) { - Gadgetron::Core::NodeParameters node_params = nb->get_parameters(); - po::options_description node_desc(node_params.description()); + template + PipelineBuilder& withMerge(const std::string& label) { + merge_builder_ = std::make_unique>(label); + return parent_; + } - if (node_params.parameters().size() > 0) { - for (auto& p: node_params.parameters()) { - node_desc.add(p->as_boost_option()); - } + ParallelBuilder& withStream(const std::string& key) { + stream_builders_.emplace_back(key); + return *this; + } - pipeline_desc.add(node_desc); - } - } - return pipeline_desc; + template + ParallelBuilder& withNode(const std::string& label) { + auto nb = std::make_shared>(label); + if (stream_builders_.empty()) { + stream_builders_.emplace_back(); + } + stream_builders_.back().append(nb); + return *this; + } + + virtual std::shared_ptr build(const CTX& ctx) const override { + if (!branch_builder_) { + throw std::runtime_error("No branch specified"); + } + if (!merge_builder_) { + throw std::runtime_error("No merge specified"); + } + auto branch = branch_builder_->build(ctx); + std::vector> streams; + for (auto& stream_builder_: stream_builders_) { + auto stream = std::dynamic_pointer_cast(stream_builder_.build(ctx)); + streams.push_back(stream); } + auto merge = merge_builder_->build(ctx); - Pipeline build(std::istream& input_stream, std::ostream& output_stream) override { - if (!source_builder_) { - throw std::runtime_error("No source specified"); - } - if (!sink_builder_) { - throw std::runtime_error("No sink specified"); - } - auto source = source_builder_(input_stream); + return std::make_shared(std::move(branch), std::move(merge), streams); + } - CTX ctx; - source->setContext(ctx); + virtual void collect_options(po::options_description& parent) { + if (!branch_builder_) { + throw std::runtime_error("No branch specified"); + } + if (!merge_builder_) { + throw std::runtime_error("No merge specified"); + } + branch_builder_->collect_options(parent); + for (auto& stream_builder_: stream_builders_) { + stream_builder_.collect_options(parent); + } + merge_builder_->collect_options(parent); + } - auto sink = sink_builder_(output_stream, ctx); +private: + PipelineBuilder& parent_; + std::string label_; - std::vector> nodes; - for (auto& builder : builders_) { - nodes.emplace_back(builder->build(ctx)); - } + std::unique_ptr> branch_builder_; + std::unique_ptr> merge_builder_; + std::vector> stream_builders_; +}; - Pipeline pipeline; - pipeline.source_ = source; - pipeline.sink_ = sink; - pipeline.nodes_ = std::move(nodes); - return std::move(pipeline); - } +class ErrorThrower : public Gadgetron::Main::ErrorReporter +{ + public: + void operator()(const std::string& location, const std::string& message) override { + throw std::runtime_error(("[" + location + "] ERROR: " + message)); + } +}; + +// Forward declaration +class Pipeline; - std::function>(std::istream&)> source_builder_; - std::function(std::ostream&, const CTX&)> sink_builder_; +struct IPipelineBuilder { + IPipelineBuilder(const std::string& name, const std::string& description): name(name), description(description) { } + virtual Pipeline build(std::istream& input_stream, std::ostream& output_stream) = 0; + virtual po::options_description collect_options(void) = 0; + virtual ~IPipelineBuilder() = default; - std::vector>> builders_; + const std::string name; + const std::string description; +}; - const std::string pipeline_name; - }; + +class Pipeline { + public: + Pipeline(const std::shared_ptr& source_, const std::shared_ptr& sink_, const std::shared_ptr& stream_) + : source_(source_), sink_(sink_), stream_(stream_) + {} virtual ~Pipeline() = default; void run(void) { - /** TODO: This is the only thing not yet "ported" to the new Pipeline::Builder technique: - * - * The Context object previously held a `std::string gadgetron_home`, that could be configured - * from the CLI. + /** TODO: The Context object previously held a `std::string gadgetron_home`, that could be configured from the CLI. * * However, this Path is only used in TWO Gadgets, and it is only used to load Python files. * These Gadgets can be updated to read the Python file paths from its own CLI parameters... @@ -292,13 +387,6 @@ class Pipeline { // }; // auto context = StreamContext(hdr, paths, vm); - std::vector> processables; - for (auto& node: nodes_) { - processables.emplace_back(std::make_shared(node, "TODO")); - } - - auto stream = std::make_unique(processables); - auto input_channel = Gadgetron::Core::make_channel(); auto output_channel = Gadgetron::Core::make_channel(); std::atomic processing = true; @@ -308,7 +396,7 @@ class Pipeline { { ErrorThrower error_thrower; Gadgetron::Main::ErrorHandler error_handler(error_thrower, std::string(__FILE__)); - stream->process(std::move(input_channel.input), std::move(output_channel.output), error_handler); + stream_->process(std::move(input_channel.input), std::move(output_channel.output), error_handler); processing = false; } catch (const std::exception& exc) @@ -358,7 +446,75 @@ class Pipeline { std::shared_ptr source_; std::shared_ptr sink_; - std::vector> nodes_; + std::shared_ptr stream_; + + std::vector> processables_; }; +template +struct PipelineBuilder : public IPipelineBuilder{ + PipelineBuilder(const std::string& pipeline_name, const std::string& pipeline_description) + : IPipelineBuilder(pipeline_name, pipeline_description) {} + + template + PipelineBuilder& withSource(void) { + source_builder_ = [](std::istream& is) { return std::make_shared(is); }; + return *this; + } + + template + PipelineBuilder& withSink(void) { + sink_builder_ = [](std::ostream& os, const CTX& ctx) { return std::make_shared(os, ctx); }; + return *this; + } + + template + PipelineBuilder& withNode(const std::string& label) { + auto nb = std::make_shared>(label); + streambuilder_.append(nb); + return *this; + } + + template + ParallelBuilder& withBranch(const std::string& label) { + auto pb = std::make_shared>(*this); + streambuilder_.append(pb); + return pb->template withBranch(label); + // return *pb; + } + + po::options_description collect_options(void) override { + po::options_description pipeline_desc(this->description); + + streambuilder_.collect_options(pipeline_desc); + return pipeline_desc; + } + + Pipeline build(std::istream& input_stream, std::ostream& output_stream) override { + if (!source_builder_) { + throw std::runtime_error("No source specified"); + } + if (!sink_builder_) { + throw std::runtime_error("No sink specified"); + } + auto source = source_builder_(input_stream); + + CTX ctx; + source->setContext(ctx); + + auto sink = sink_builder_(output_stream, ctx); + + Pipeline pipeline(source, sink, streambuilder_.build(ctx)); + return std::move(pipeline); + } + + std::function>(std::istream&)> source_builder_; + std::function(std::ostream&, const CTX&)> sink_builder_; + + StreamBuilder streambuilder_; + + const std::string pipeline_name; +}; + + } // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/nodes/NodeProcessable.h b/apps/pingvin/nodes/NodeProcessable.h new file mode 100644 index 00000000..bd64441c --- /dev/null +++ b/apps/pingvin/nodes/NodeProcessable.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Processable.h" + +#include "Node.h" + +class NodeProcessable : public Gadgetron::Main::Processable { +public: + NodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} + + void process(Gadgetron::Core::GenericInputChannel input, + Gadgetron::Core::OutputChannel output, + Gadgetron::Main::ErrorHandler & + ) override { + node_->process(input, output); + } + + const std::string& name() override { + return name_; + } + +private: + std::shared_ptr node_; + const std::string name_; +}; diff --git a/apps/pingvin/nodes/Parallel.cpp b/apps/pingvin/nodes/Parallel.cpp index 1dd53ddf..afcd49a6 100644 --- a/apps/pingvin/nodes/Parallel.cpp +++ b/apps/pingvin/nodes/Parallel.cpp @@ -15,19 +15,6 @@ namespace { 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, 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, Config::name(conf), conf.properties), Config::name(conf)); - // } - template auto transform_map(std::map& input, F f) { using TRANSFORMED = std::remove_reference_tsecond))>; @@ -66,18 +53,6 @@ namespace { namespace Gadgetron::Main::Nodes { - // Parallel::Parallel( - // const Config::Parallel &config, - // const Core::StreamContext &context, - // Loader &loader - // ) : branch(load_branch(config.branch, context, loader)), merge(load_merge(config.merge, context, loader)) { - // std::transform( - // config.streams.begin(), config.streams.end(), - // std::back_inserter(streams), - // [&](auto &stream_config) { return std::make_shared(stream_config, context, loader); } - // ); - // } - void Parallel::process( InputChannel input, OutputChannel output, diff --git a/apps/pingvin/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h index c9556887..63608eee 100644 --- a/apps/pingvin/nodes/Parallel.h +++ b/apps/pingvin/nodes/Parallel.h @@ -19,6 +19,12 @@ namespace Gadgetron::Main::Nodes { using Merge = Core::Parallel::Merge; public: + Parallel(std::unique_ptr branch, std::unique_ptr merge, std::vector> streams) + : branch(std::make_unique(std::move(branch), "branch")), + merge(std::make_unique(std::move(merge), "merge")), + streams(std::move(streams)) + {} + void process( Core::GenericInputChannel input, Core::OutputChannel output, diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp index 714cda72..fffa601e 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -6,37 +6,10 @@ #include "Node.h" -namespace { - using namespace Gadgetron::Core; - using namespace Gadgetron::Main; - using namespace Gadgetron::Main::Nodes; - // using namespace std::string_literals; - - // class NodeProcessable : public Processable { - // public: - // NodeProcessable(std::function()> factory, std::string name) : factory(std::move(factory)), name_(std::move(name)) {} - - // void process(GenericInputChannel input, - // OutputChannel output, - // ErrorHandler & - // ) override { - // auto node = factory(); - // node->process(input, output); - // } - - // const std::string& name() override { - // return name_; - // } - - // private: - // std::function()> factory; - // const std::string name_; - // }; - -} - namespace Gadgetron::Main::Nodes { + using namespace Gadgetron::Core; + void Stream::process(GenericInputChannel input, OutputChannel output, ErrorHandler &error_handler diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h index 79ea2947..9f185699 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -14,7 +14,7 @@ namespace Gadgetron::Main::Nodes { public: const std::string key; - Stream(std::vector> nodes): nodes(std::move(nodes)), key("TODO-needed?") {} + Stream(std::vector> nodes, const std::string key=""): nodes(std::move(nodes)), key(key) {} void process( Core::GenericInputChannel input, diff --git a/core/Node.h b/core/Node.h index ebe75b01..3e1db93d 100644 --- a/core/Node.h +++ b/core/Node.h @@ -68,15 +68,4 @@ namespace Gadgetron::Core { } /** TODO: Delete everywhere */ -/* -#define GADGETRON_GADGET_EXPORT(GadgetClass) \ - std::unique_ptr gadget_factory_##GadgetClass( \ - const Gadgetron::Core::Context& context, \ - const std::string& name, \ - const Gadgetron::Core::GadgetProperties& props) { \ - return std::make_unique(context, props); \ - } \ -BOOST_DLL_ALIAS(gadget_factory_##GadgetClass, gadget_factory_export_##GadgetClass) -*/ - #define GADGETRON_GADGET_EXPORT(GadgetClass) \ No newline at end of file diff --git a/core/parallel/Branch.h b/core/parallel/Branch.h index fd97615b..05635afa 100644 --- a/core/parallel/Branch.h +++ b/core/parallel/Branch.h @@ -6,12 +6,17 @@ #include "Channel.h" #include "Context.h" +#include "Parameters.h" #include "PropertyMixin.h" namespace Gadgetron::Core::Parallel { class Branch : public PropertyMixin { public: + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; + virtual ~Branch() = default; virtual void process( GenericInputChannel input, @@ -39,21 +44,18 @@ namespace Gadgetron::Core::Parallel { virtual void process(InputChannel &, std::map) = 0; }; + /** TODO: Move to MR-specific location! */ + template class MRBranch : public TypedBranch { + public: + using TypedBranch::TypedBranch; + + MRBranch(const MrdContext& context, const NodeParameters& parameters) + : TypedBranch(Core::GadgetProperties{}) {} + }; + } #include "Branch.hpp" -#define GADGETRON_BRANCH_EXPORT(BranchClass) \ -std::unique_ptr \ -branch_factory_##BranchClass( \ - const Gadgetron::Core::Context &context, \ - const std::string& name, \ - const Gadgetron::Core::GadgetProperties &props \ -) { \ - return std::make_unique(context, props); \ -} \ - \ -BOOST_DLL_ALIAS( \ - branch_factory_##BranchClass, \ - branch_factory_export_##BranchClass \ -) +/** TODO: Delete everywhere */ +#define GADGETRON_BRANCH_EXPORT(BranchClass) \ No newline at end of file diff --git a/core/parallel/Fanout.h b/core/parallel/Fanout.h index 947113ea..b731e3ba 100644 --- a/core/parallel/Fanout.h +++ b/core/parallel/Fanout.h @@ -9,10 +9,11 @@ namespace Gadgetron::Core::Parallel { + /** TODO: Move to MR-specific location! */ template - class Fanout : public TypedBranch { + class Fanout : public MRBranch { public: - Fanout(const Context &context, const GadgetProperties &props); + using MRBranch::MRBranch; void process(InputChannel &, std::map) override; }; diff --git a/core/parallel/Fanout.hpp b/core/parallel/Fanout.hpp index 2a2cb97c..48dfe9c8 100644 --- a/core/parallel/Fanout.hpp +++ b/core/parallel/Fanout.hpp @@ -2,13 +2,6 @@ namespace Gadgetron::Core::Parallel { - template - Fanout::Fanout( - const Context &context, - const GadgetProperties &props - ) : TypedBranch(props) {} - - template void Fanout::process(InputChannel &input, std::map output) { for (auto thing : input) { diff --git a/core/parallel/Merge.h b/core/parallel/Merge.h index 01f41335..6bc627e7 100644 --- a/core/parallel/Merge.h +++ b/core/parallel/Merge.h @@ -6,30 +6,32 @@ #include "Channel.h" #include "Context.h" +#include "Parameters.h" #include "PropertyMixin.h" namespace Gadgetron::Core::Parallel { class Merge : public PropertyMixin { public: + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; + explicit Merge(const GadgetProperties &props); virtual ~Merge() = default; virtual void process(std::map, OutputChannel) = 0; }; + + /** TODO: Move to MR-specific location! */ + class MRMerge : public Merge { + public: + using Merge::Merge; + + MRMerge(const MrdContext& context, const NodeParameters& parameters) + : Merge(Core::GadgetProperties{}) {} + }; } -#define GADGETRON_MERGE_EXPORT(MergeClass) \ -std::unique_ptr \ -merge_factory_##MergeClass( \ - const Gadgetron::Core::Context &context, \ - const std::string& name, \ - const Gadgetron::Core::GadgetProperties &props \ -) { \ - return std::make_unique(context, props); \ -} \ - \ -BOOST_DLL_ALIAS( \ - merge_factory_##MergeClass, \ - merge_factory_export_##MergeClass \ -) +/** TODO: Delete everywhere */ +#define GADGETRON_MERGE_EXPORT(MergeClass) \ No newline at end of file diff --git a/gadgets/grappa/ImageAccumulator.cpp b/gadgets/grappa/ImageAccumulator.cpp index ab3eda25..cfbae511 100644 --- a/gadgets/grappa/ImageAccumulator.cpp +++ b/gadgets/grappa/ImageAccumulator.cpp @@ -4,7 +4,6 @@ #include #include "Unmixing.h" -#include "common/AcquisitionBuffer.h" #include "Node.h" #include "hoNDArray.h" @@ -47,15 +46,8 @@ namespace { namespace Gadgetron::Grappa { - ImageAccumulator::ImageAccumulator( - const Core::Context &context, - const std::unordered_map &props - ) : ChannelGadget(context,props), context(context) {} - void ImageAccumulator::process(Core::InputChannel &in, Core::OutputChannel &out) { - AcquisitionBuffer buffer{context}; - for (auto slice : in) { slice = std::move(slice) | ranges::actions::remove_if([](auto& acq){return std::get(acq).head.flags.HasFlags(mrd::AcquisitionFlags::kIsParallelCalibration);}); diff --git a/gadgets/grappa/ImageAccumulator.h b/gadgets/grappa/ImageAccumulator.h index 6782848d..4a87976c 100644 --- a/gadgets/grappa/ImageAccumulator.h +++ b/gadgets/grappa/ImageAccumulator.h @@ -1,19 +1,23 @@ #pragma once #include "SliceAccumulator.h" +#include "common/AcquisitionBuffer.h" #include "Channel.h" #include "Node.h" namespace Gadgetron::Grappa { - class ImageAccumulator : public Core::ChannelGadget { + class ImageAccumulator : public Core::MRChannelGadget { public: - ImageAccumulator(const Core::Context &, const std::unordered_map &); + ImageAccumulator(const Core::MrdContext &context, const Core::NodeParameters& params) + : Core::MRChannelGadget(context, params) + , buffer(context.header) + {} void process(Core::InputChannel &in, Core::OutputChannel &out) override; private: - const Core::Context context; + AcquisitionBuffer buffer; }; } diff --git a/gadgets/grappa/SliceAccumulator.cpp b/gadgets/grappa/SliceAccumulator.cpp index 4d7cd68a..7b5fe573 100644 --- a/gadgets/grappa/SliceAccumulator.cpp +++ b/gadgets/grappa/SliceAccumulator.cpp @@ -15,11 +15,6 @@ namespace { namespace Gadgetron::Grappa { - SliceAccumulator::SliceAccumulator( - const Core::Context &context, - const std::unordered_map &props - ) : ChannelGadget(context,props), context(context) {} - void SliceAccumulator::process(Core::InputChannel &in, Core::OutputChannel &out) { std::vector acquisitions{}; diff --git a/gadgets/grappa/SliceAccumulator.h b/gadgets/grappa/SliceAccumulator.h index 81774fc2..e072150b 100644 --- a/gadgets/grappa/SliceAccumulator.h +++ b/gadgets/grappa/SliceAccumulator.h @@ -10,14 +10,11 @@ namespace Gadgetron::Grappa { using Slice = std::vector; - class SliceAccumulator : public Core::ChannelGadget { + class SliceAccumulator : public Core::MRChannelGadget { public: - SliceAccumulator(const Core::Context &, const std::unordered_map &); + using Core::MRChannelGadget::MRChannelGadget; void process(Core::InputChannel &in, Core::OutputChannel &out) override; - - private: - const Core::Context context; }; } diff --git a/gadgets/grappa/Unmixing.cpp b/gadgets/grappa/Unmixing.cpp index f3ebbc8f..0be9a9b9 100644 --- a/gadgets/grappa/Unmixing.cpp +++ b/gadgets/grappa/Unmixing.cpp @@ -14,9 +14,8 @@ namespace { class WeightsProvider { public: - WeightsProvider( - const Core::Context &context, Core::InputChannel &source - ) : weights(number_of_slices(context), std::nullopt), source(source) {} + WeightsProvider(const mrd::Header& header, Core::InputChannel &source) + : weights(number_of_slices(header), std::nullopt), source(source) {} const Weights &operator[](size_t slice) { @@ -41,8 +40,8 @@ namespace { weights[w->meta.slice] = std::move(w); } - static size_t number_of_slices(const Core::Context &context) { - auto e_limits = context.header.encoding[0].encoding_limits; + static size_t number_of_slices(const mrd::Header& header) { + auto e_limits = header.encoding[0].encoding_limits; return e_limits.slice ? e_limits.slice->maximum + 1u : 1u; } @@ -54,13 +53,6 @@ namespace { namespace Gadgetron::Grappa { GADGETRON_MERGE_EXPORT(Unmixing); - Unmixing::Unmixing( - const Core::Context &context, - const std::unordered_map &props - ) : Merge(props), context(context), - image_dimensions(create_output_image_dimensions(context)), - image_fov(create_output_image_fov(context)) {} - void Unmixing::process( std::map input, Core::OutputChannel output @@ -68,7 +60,7 @@ namespace Gadgetron::Grappa { Core::InputChannel images(input.at("images"), output); Core::InputChannel weights(input.at("weights"), output); - WeightsProvider weights_provider(context, weights); + WeightsProvider weights_provider(header_, weights); for (auto image : images) { auto current_weights = weights_provider[image.meta.slice]; @@ -96,7 +88,7 @@ namespace Gadgetron::Grappa { unmixed_image[s * image_elements + p] += weights.data[s * image_elements * coils + c * image_elements + p] * image.data[c * image_elements + p] * - unmixing_scale; + parameters_.unmixing_scale; } } } @@ -120,13 +112,13 @@ namespace Gadgetron::Grappa { std::copy(image.meta.table_pos.begin(), image.meta.table_pos.end(), std::begin(header.patient_table_position)); header.image_index = ++image_index_counter; - header.image_series_index = image_series; + header.image_series_index = parameters_.image_series; return header; } - std::vector Unmixing::create_output_image_dimensions(const Core::Context &context) { - auto r_space = context.header.encoding[0].recon_space; + std::vector Unmixing::create_output_image_dimensions(const mrd::Header& header) { + auto r_space = header.encoding[0].recon_space; return { r_space.matrix_size.x, r_space.matrix_size.y, @@ -134,8 +126,8 @@ namespace Gadgetron::Grappa { }; } - std::vector Unmixing::create_output_image_fov(const Core::Context &context) { - auto r_space = context.header.encoding[0].recon_space; + std::vector Unmixing::create_output_image_fov(const mrd::Header& header) { + auto r_space = header.encoding[0].recon_space; return { r_space.field_of_view_mm.x, r_space.field_of_view_mm.y, diff --git a/gadgets/grappa/Unmixing.h b/gadgets/grappa/Unmixing.h index ca6913e2..0ce3b5d2 100644 --- a/gadgets/grappa/Unmixing.h +++ b/gadgets/grappa/Unmixing.h @@ -29,12 +29,23 @@ namespace Gadgetron::Grappa { hoNDArray> data; }; - class Unmixing : public Core::Parallel::Merge { + class Unmixing : public Core::Parallel::MRMerge { public: - Unmixing(const Core::Context &context, const std::unordered_map &props); - - NODE_PROPERTY(image_series, uint16_t, "Image series number for output images", 0); - NODE_PROPERTY(unmixing_scale, float, "", 1.0); + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Grappa Unmixing") { + register_parameter("image-series", &image_series, "Image series number for output images"); + register_parameter("unmixing-scale", &unmixing_scale, ""); + } + uint16_t image_series = 0; + float unmixing_scale = 1.0; + }; + + Unmixing(const Core::MrdContext &context, const Parameters& params) + : Core::Parallel::MRMerge(context, params) + , header_(context.header) + , image_dimensions(create_output_image_dimensions(context.header)) + , image_fov(create_output_image_fov(context.header)) {} void process( std::map input, @@ -42,15 +53,17 @@ namespace Gadgetron::Grappa { ) override; private: + const Parameters parameters_; + hoNDArray> unmix(const Image &image, const Weights &weights); std::vector create_unmixed_image_dimensions(const Weights &weights); - static std::vector create_output_image_dimensions(const Core::Context &context); - static std::vector create_output_image_fov(const Core::Context &context); + static std::vector create_output_image_dimensions(const mrd::Header& header); + static std::vector create_output_image_fov(const mrd::Header& header); mrd::ImageHeader create_image_header(const Image &image, const Weights &weights); - const Core::Context context; + const mrd::Header header_; const std::vector image_dimensions; const std::vector image_fov; diff --git a/gadgets/grappa/WeightsCalculator.cpp b/gadgets/grappa/WeightsCalculator.cpp index cd394527..4ab3fa0f 100644 --- a/gadgets/grappa/WeightsCalculator.cpp +++ b/gadgets/grappa/WeightsCalculator.cpp @@ -162,22 +162,16 @@ namespace Gadgetron::Grappa { }; } - template - WeightsCalculator::WeightsCalculator( - const Core::Context &context, - const std::unordered_map &props - ) : ChannelGadget(context,props), context(context) {} - template void WeightsCalculator::process(Core::InputChannel &in, Core::OutputChannel &out) { std::set updated_slices{}; uint16_t n_combined_channels = 0, n_uncombined_channels = 0; - const auto slice_limits = context.header.encoding[0].encoding_limits.slice; - const size_t max_slices = slice_limits ? context.header.encoding[0].encoding_limits.slice->maximum+1 : 1; + const auto slice_limits = header_.encoding[0].encoding_limits.slice; + const size_t max_slices = slice_limits ? header_.encoding[0].encoding_limits.slice->maximum+1 : 1; - AcquisitionBuffer buffer{context}; + AcquisitionBuffer buffer{header_}; AccelerationMonitor acceleration_monitor{max_slices}; buffer.add_pre_update_callback(DirectionMonitor{buffer, acceleration_monitor,max_slices}); @@ -189,8 +183,8 @@ namespace Gadgetron::Grappa { }); WeightsCore core{ - {coil_map_estimation_ks, coil_map_estimation_power}, - {block_size_samples, block_size_lines, convolution_kernel_threshold} + {parameters_.coil_map_estimation_ks, parameters_.coil_map_estimation_power}, + {parameters_.block_size_samples, parameters_.block_size_lines, parameters_.convolution_kernel_threshold} }; while (true) { @@ -213,11 +207,11 @@ namespace Gadgetron::Grappa { } } - using cpuWeightsCalculator = WeightsCalculator; - GADGETRON_GADGET_EXPORT(cpuWeightsCalculator); +template class WeightsCalculator; +GADGETRON_GADGET_EXPORT(cpuWeightsCalculator); #ifdef USE_CUDA - using gpuWeightsCalculator = WeightsCalculator; + template class WeightsCalculator; GADGETRON_GADGET_EXPORT(gpuWeightsCalculator); #endif } \ No newline at end of file diff --git a/gadgets/grappa/WeightsCalculator.h b/gadgets/grappa/WeightsCalculator.h index cedf16c9..dca3a120 100644 --- a/gadgets/grappa/WeightsCalculator.h +++ b/gadgets/grappa/WeightsCalculator.h @@ -6,24 +6,51 @@ #include "Channel.h" #include "Node.h" +#include "cpu/WeightsCore.h" +#ifdef USE_CUDA +#include "gpu/WeightsCore.h" +#endif + namespace Gadgetron::Grappa { template - class WeightsCalculator : public Core::ChannelGadget { + class WeightsCalculator : public Core::MRChannelGadget { public: - WeightsCalculator(const Core::Context &, const std::unordered_map &); - - // TODO: Descriptive descriptions. - NODE_PROPERTY(coil_map_estimation_ks, uint16_t, "", 5); - NODE_PROPERTY(coil_map_estimation_power, uint16_t, "", 3); - - NODE_PROPERTY(block_size_lines, uint16_t, "Block size used to estimate missing samples; number of lines.", 4); - NODE_PROPERTY(block_size_samples, uint16_t, "Block size used to estimate missing samples; number of samples.", 5); - NODE_PROPERTY(convolution_kernel_threshold, float, "Grappa convolution kernel calibration Tikhonov threshold.", 5e-4); + struct Parameters : public Core::NodeParameters { + uint16_t coil_map_estimation_ks = 5; + uint16_t coil_map_estimation_power = 3; + + uint16_t block_size_lines = 4; + uint16_t block_size_samples = 5; + float convolution_kernel_threshold = 5e-4; + + Parameters(const std::string &prefix) + : Core::NodeParameters(prefix, "Grappa Weights Calculator") { + register_parameter("coil-map-estimation-ks", &coil_map_estimation_ks, "Kernel size for coil map estimation"); + register_parameter("coil-map-estimation-power", &coil_map_estimation_power, "Power for coil map estimation"); + + register_parameter("block-size-lines", &block_size_lines, "Block size used to estimate missing samples; number of lines"); + register_parameter("block-size-samples", &block_size_samples, "Block size used to estimate missing samples; number of samples"); + register_parameter("convolution-kernel-threshold", &convolution_kernel_threshold, "Grappa convolution kernel calibration Tikhonov threshold"); + } + }; + + WeightsCalculator(const Core::MrdContext &context, const Parameters ¶ms) + : Core::MRChannelGadget(context, params) + , parameters_(params) + , header_(context.header) + {} void process(Core::InputChannel &in, Core::OutputChannel &out) override; private: - const Core::Context context; + const Parameters parameters_; + const mrd::Header header_; }; + + using cpuWeightsCalculator = WeightsCalculator; + + #ifdef USE_CUDA + using gpuWeightsCalculator = WeightsCalculator; + #endif } diff --git a/gadgets/grappa/common/AcquisitionBuffer.cpp b/gadgets/grappa/common/AcquisitionBuffer.cpp index 8462c965..a916a7d7 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.cpp +++ b/gadgets/grappa/common/AcquisitionBuffer.cpp @@ -3,7 +3,6 @@ #include #include -#include "Context.h" #include "Channel.h" #include "hoNDArray.h" @@ -29,18 +28,19 @@ namespace { namespace Gadgetron::Grappa { - AcquisitionBuffer::AcquisitionBuffer(Core::Context ctx) : context(std::move(ctx)) { - - if (context.header.encoding.size() != 1) { + AcquisitionBuffer::AcquisitionBuffer(const mrd::Header& header) + : header_(std::move(header)) + { + if (header.encoding.size() != 1) { throw std::runtime_error( "This gadget only supports one encoding space; found " + - std::to_string(context.header.encoding.size()) + std::to_string(header.encoding.size()) ); } - auto r_space = context.header.encoding[0].recon_space; - auto e_space = context.header.encoding[0].encoded_space; - auto e_limits = context.header.encoding[0].encoding_limits; + auto r_space = header.encoding[0].recon_space; + auto e_space = header.encoding[0].encoded_space; + auto e_limits = header.encoding[0].encoding_limits; if (r_space.matrix_size.z != 1) { throw std::runtime_error("RT Grappa works only with 2D images. 3D output requested."); @@ -110,7 +110,7 @@ namespace Gadgetron::Grappa { std::pair AcquisitionBuffer::fully_sampled_region(size_t slice) const { - const auto& e_limits = context.header.encoding[0].encoding_limits; + const auto& e_limits = header_.encoding[0].encoding_limits; const auto& sampled_lines = buffers.at(slice).sampled_lines; uint32_t lower_limit; diff --git a/gadgets/grappa/common/AcquisitionBuffer.h b/gadgets/grappa/common/AcquisitionBuffer.h index b5859308..279a4eb5 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.h +++ b/gadgets/grappa/common/AcquisitionBuffer.h @@ -6,7 +6,6 @@ #include "AnnotatedAcquisition.h" -#include "Context.h" #include "Channel.h" #include "hoNDArray.h" @@ -15,7 +14,7 @@ namespace Gadgetron::Grappa { class AcquisitionBuffer { public: - explicit AcquisitionBuffer(Core::Context); + explicit AcquisitionBuffer(const mrd::Header& header); void add(const AnnotatedAcquisition &acquisition); @@ -43,7 +42,7 @@ namespace Gadgetron::Grappa { void add_post_update_callback(std::function fn); private: - const Core::Context context; + const mrd::Header header_; struct { std::set expected_lines; From 37e736770849f306521cf4ba58d40b55fe65a4b5 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 7 Feb 2025 21:54:31 +0000 Subject: [PATCH 11/21] Update all generic recon gadgets --- apps/emperor/main.cc | 45 ++++- apps/emperor/pipelines/cartesian_grappa.h | 5 +- apps/emperor/pipelines/cartesian_spirit.h | 45 +++++ apps/emperor/pipelines/file_search.h | 2 +- apps/emperor/pipelines/pipeline.h | 32 ++- apps/pingvin/system_info.cpp | 8 +- apps/pingvin/system_info.h | 3 +- core/Context.h | 19 +- gadgets/CMakeLists.txt | 2 +- gadgets/mri_core/BucketToBufferGadget.h | 4 +- gadgets/mri_core/FloatToFixedPointGadget.h | 6 +- gadgets/mri_core/PhysioInterpolationGadget.h | 8 +- .../generic_recon_gadgets/GenericReconBase.h | 56 ++++-- .../GenericReconCartesianGrappaAIGadget.cpp | 68 +++---- .../GenericReconCartesianGrappaAIGadget.h | 7 +- .../GenericReconCartesianGrappaGadget.cpp | 95 ++++----- .../GenericReconCartesianGrappaGadget.h | 67 ++++--- ...ReconCartesianNonLinearSpirit2DTGadget.cpp | 185 +++++++++--------- ...icReconCartesianNonLinearSpirit2DTGadget.h | 69 ++++--- ...nericReconCartesianReferencePrepGadget.cpp | 29 +-- ...GenericReconCartesianReferencePrepGadget.h | 48 +++-- .../GenericReconCartesianSpiritGadget.cpp | 125 ++++++------ .../GenericReconCartesianSpiritGadget.h | 41 ++-- .../GenericReconEigenChannelGadget.cpp | 19 +- .../GenericReconEigenChannelGadget.h | 65 +++--- ...enericReconFieldOfViewAdjustmentGadget.cpp | 9 +- .../GenericReconFieldOfViewAdjustmentGadget.h | 8 +- .../GenericReconGadget.cpp | 39 ++-- .../GenericReconGadget.h | 37 ++-- .../GenericReconImageArrayScalingGadget.cpp | 51 ++--- .../GenericReconImageArrayScalingGadget.h | 48 +++-- .../GenericReconKSpaceFilteringGadget.cpp | 47 ++--- .../GenericReconKSpaceFilteringGadget.h | 61 +++--- ...GenericReconNoiseStdMapComputingGadget.cpp | 11 +- .../GenericReconNoiseStdMapComputingGadget.h | 19 +- ...econPartialFourierHandlingFilterGadget.cpp | 6 +- ...cReconPartialFourierHandlingFilterGadget.h | 31 +-- ...nericReconPartialFourierHandlingGadget.cpp | 20 +- ...GenericReconPartialFourierHandlingGadget.h | 27 ++- ...cReconPartialFourierHandlingPOCSGadget.cpp | 8 +- ...ricReconPartialFourierHandlingPOCSGadget.h | 38 ++-- toolboxes/mri_core/mri_core_def.h | 22 ++- 42 files changed, 893 insertions(+), 642 deletions(-) create mode 100644 apps/emperor/pipelines/cartesian_spirit.h diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index abf66b39..b455458f 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -2,6 +2,8 @@ #include "pipelines/grappa.h" #include "pipelines/default.h" #include "pipelines/epi.h" +#include "pipelines/cartesian_grappa.h" +#include "pipelines/cartesian_spirit.h" #include "pipelines/file_search.h" @@ -21,17 +23,27 @@ using namespace pingvin; namespace { +/// Parses a "PINGVIN_*" environment variable into a CLI parameter std::string envvar_to_node_parameter(const std::string& env_var) { static const std::string prefix("PINGVIN_"); + // Only match envvars starting with "PINGVIN_" if (env_var.compare(0, prefix.size(), prefix) != 0) { return std::string(); } std::string option(env_var.substr(prefix.size())); - option.replace(option.find("_"), 1, "."); + // Only match envvars with at least one underscore, which separates the + // node name from the parameter name (e.g. "PINGVIN_FOO_BAR" => "foo.bar") + size_t first_underscore_loc; + if ((first_underscore_loc = option.find("_")) == std::string::npos) { + return std::string(); + } else { + option.replace(first_underscore_loc, 1, "."); + } + std::replace(option.begin(), option.end(), '_', '-'); std::transform(option.begin(), option.end(), option.begin(), [](unsigned char c){ return std::tolower(c); }); @@ -49,7 +61,7 @@ int main(int argc, char** argv) ("help,h", "Prints this help message") ("info", "Prints build info about Pingvin") ("home", - po::value()->default_value(Gadgetron::Main::Info::default_pingvin_home()), + po::value()->default_value(Gadgetron::Main::Info::get_pingvin_home()), "Set the Pingvin home directory") ("config,c", po::value(), "Pipeline configuration file") ("input,i", po::value(), "Input stream (default=stdin)") @@ -98,8 +110,22 @@ int main(int argc, char** argv) return 0; } + if (vm.count("home")) { + Gadgetron::Main::Info::set_pingvin_home(vm["home"].as()); + std::cerr << "Set Pingvin home to: " << Gadgetron::Main::Info::get_pingvin_home() << std::endl; + } + // "Choose" a Pipeline - std::vector builders{&epi_2d, &default_mr, &default_mr_optimized, &noise_dependency, &file_search, &grappa}; + std::vector builders{ + &epi_2d, + &default_mr, + &default_mr_optimized, + &noise_dependency, + &file_search, + &grappa, + &cartesian_grappa, + &cartesian_spirit_nonlinear + }; std::map builder_map; for (auto& builder : builders) { builder_map[builder->name] = builder; @@ -144,7 +170,16 @@ int main(int argc, char** argv) return 0; } - po::store(po::parse_environment(pipeline_options, envvar_to_node_parameter), vm); + po::store(po::parse_environment(pipeline_options, + // This ceremony enables defining PINGVIN_ env vars that don't map directly to CLI options + // Otherwise, boost::program_options will complain about unrecognized PINGVIN_ env vars + [&pipeline_options](const std::string& var) { + auto parsed_option = envvar_to_node_parameter(var); + return std::any_of( + pipeline_options.options().cbegin(), + pipeline_options.options().cend(), + [parsed_option](auto opt) { return parsed_option == opt->long_name(); }) ? parsed_option : ""; + }), vm); if (vm.count("config")) { auto config_filename = vm["config"].as(); @@ -169,6 +204,7 @@ int main(int argc, char** argv) input_file = std::make_unique(vm["input"].as()); if (!input_file->good()) { std::cerr << "Could not open input file: " << vm["input"].as() << std::endl; + return 1; } } @@ -177,6 +213,7 @@ int main(int argc, char** argv) output_file = std::make_unique(vm["output"].as()); if (!output_file->good()) { std::cerr << "Could not open output file: " << vm["output"].as() << std::endl; + return 1; } } diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h index a90aff7b..fbeedf3c 100644 --- a/apps/emperor/pipelines/cartesian_grappa.h +++ b/apps/emperor/pipelines/cartesian_grappa.h @@ -20,7 +20,7 @@ namespace pingvin { -static auto cartesian_grappa = Pipeline::Builder("cartesian-grappa", "Cartesian Grappa Recon") +static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") .withSource() .withSink() .withNode("noise") @@ -37,6 +37,7 @@ static auto cartesian_grappa = Pipeline::Builder("cartesian-grappa", .withNode("image-array-scaling") .withNode("image-split") .withNode("complex-to-float") - .withNode("float-to-ushort"); + .withNode("convert") + ; } // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/cartesian_spirit.h b/apps/emperor/pipelines/cartesian_spirit.h new file mode 100644 index 00000000..6a46c07f --- /dev/null +++ b/apps/emperor/pipelines/cartesian_spirit.h @@ -0,0 +1,45 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/PhysioInterpolationGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" + +namespace pingvin { + +static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coil-comp") + .withNode("spirit") + .withNode("partial-fourier") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("image-split") + .withNode("physio-interp") + .withNode("complex-to-float") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/file_search.h b/apps/emperor/pipelines/file_search.h index 14cd7e13..08bd5a11 100644 --- a/apps/emperor/pipelines/file_search.h +++ b/apps/emperor/pipelines/file_search.h @@ -14,7 +14,7 @@ namespace pingvin { public: TextSource(std::istream& input_stream) : input_stream_(input_stream) {} - void setContext(TextContext& ctx) override { } + void initContext(TextContext& ctx) override { } void consume_input(Gadgetron::Core::ChannelPair& input_channel) override { diff --git a/apps/emperor/pipelines/pipeline.h b/apps/emperor/pipelines/pipeline.h index f0fae8f7..e68de79e 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/emperor/pipelines/pipeline.h @@ -8,6 +8,8 @@ namespace po = boost::program_options; #include "mrd/binary/protocols.h" +#include "system_info.h" + #include "nodes/Stream.h" #include "nodes/NodeProcessable.h" #include "nodes/Parallel.h" @@ -29,7 +31,7 @@ struct ISource { template struct Source : public ISource { - virtual void setContext(CTX&) = 0; + virtual void initContext(CTX&) = 0; }; struct ISink { @@ -48,7 +50,7 @@ using MrdContext = Gadgetron::Core::MrdContext; struct MrdSource : public Source { MrdSource(std::istream& input_stream): mrd_reader_(input_stream) {} - void setContext(MrdContext& ctx) override { + void initContext(MrdContext& ctx) override { std::optional hdr; mrd_reader_.ReadHeader(hdr); if (!hdr.has_value()) { @@ -56,6 +58,16 @@ struct MrdSource : public Source { } ctx.header = hdr.value(); + + for (char** raw = environ; *raw; ++raw) { + std::string s(*raw); + auto pos = s.find('='); + if (pos != std::string::npos) { + ctx.env[s.substr(0, pos)] = s.substr(pos + 1); + } + } + + ctx.paths.pingvin_home = Gadgetron::Main::Info::get_pingvin_home(); } void consume_input(Gadgetron::Core::ChannelPair& input_channel) override @@ -373,20 +385,6 @@ class Pipeline { virtual ~Pipeline() = default; void run(void) { - /** TODO: The Context object previously held a `std::string gadgetron_home`, that could be configured from the CLI. - * - * However, this Path is only used in TWO Gadgets, and it is only used to load Python files. - * These Gadgets can be updated to read the Python file paths from its own CLI parameters... - * - * Otherwise, the GADGETRON_HOME path can be queried from the `static default_gadgetron_home()` function. - */ - // Context::Paths paths{ - // (vm.count("home")) - // ? vm["home"].as().string() - // : "/opt/pingvin" - // }; - // auto context = StreamContext(hdr, paths, vm); - auto input_channel = Gadgetron::Core::make_channel(); auto output_channel = Gadgetron::Core::make_channel(); std::atomic processing = true; @@ -500,7 +498,7 @@ struct PipelineBuilder : public IPipelineBuilder{ auto source = source_builder_(input_stream); CTX ctx; - source->setContext(ctx); + source->initContext(ctx); auto sink = sink_builder_(output_stream, ctx); diff --git a/apps/pingvin/system_info.cpp b/apps/pingvin/system_info.cpp index e68073a7..5497d9a9 100644 --- a/apps/pingvin/system_info.cpp +++ b/apps/pingvin/system_info.cpp @@ -212,8 +212,14 @@ namespace Gadgetron::Main::Info { #endif } // namespace - const std::filesystem::path default_pingvin_home() { + void set_pingvin_home(const std::filesystem::path& home) + { + setenv("PINGVIN_HOME", home.c_str(), 1); + } + + const std::filesystem::path get_pingvin_home() + { const char *home = std::getenv("PINGVIN_HOME"); if (home != nullptr) { diff --git a/apps/pingvin/system_info.h b/apps/pingvin/system_info.h index 46dbd0c8..b2a50e3b 100644 --- a/apps/pingvin/system_info.h +++ b/apps/pingvin/system_info.h @@ -14,7 +14,8 @@ namespace Gadgetron::Main::Info { bool python_support(); bool matlab_support(); - const std::filesystem::path default_pingvin_home(); + void set_pingvin_home(const std::filesystem::path&); + const std::filesystem::path get_pingvin_home(); namespace CUDA { bool cuda_support(); diff --git a/core/Context.h b/core/Context.h index 65a0ec61..7e311f66 100644 --- a/core/Context.h +++ b/core/Context.h @@ -1,17 +1,34 @@ #pragma once + +#include + +#include + #include #include -#include namespace Gadgetron::Core { /** TODO: Move to MR-specific location */ struct MrdContext { + + /** TODO: This Path is only used in TWO Gadgets, and it is only used to load Python files. + * These Gadgets can be updated to read the Python file paths from its own CLI parameters... + * + * Otherwise, the PINGVIN_HOME path can be queried using the `static get_gadgetron_home()` function. + */ + struct Paths { + std::filesystem::path pingvin_home; + }; + mrd::Header header; + std::map env; + Paths paths; }; + /** TODO: Delete */ struct Context { using Header = mrd::Header; diff --git a/gadgets/CMakeLists.txt b/gadgets/CMakeLists.txt index feb5e1e8..f7d5be6e 100644 --- a/gadgets/CMakeLists.txt +++ b/gadgets/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(examples) add_subdirectory(debugging) add_subdirectory(mri_core) -add_subdirectory(cmr) +# add_subdirectory(cmr) add_subdirectory(epi) add_subdirectory(grappa) \ No newline at end of file diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 07efd48a..cea668c1 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -26,8 +26,8 @@ namespace Gadgetron { using NodeParameters::NodeParameters; Parameters(const std::string& prefix) : NodeParameters(prefix, "Bucket To Buffer Options") { - register_parameter("N-dimensions", &N_dimension, "N-Dimensions"); - register_parameter("S-dimensions", &S_dimension, "S-Dimensions"); + register_parameter("N-dimension", &N_dimension, "N-Dimension"); + register_parameter("S-dimension", &S_dimension, "S-Dimension"); register_flag("split-slices", &split_slices, "Split slices"); register_flag("ignore-segment", &ignore_segment, "Ignore segment"); register_flag("verbose", &verbose, "Whether to print more information"); diff --git a/gadgets/mri_core/FloatToFixedPointGadget.h b/gadgets/mri_core/FloatToFixedPointGadget.h index 0f41b7b9..7f13023c 100644 --- a/gadgets/mri_core/FloatToFixedPointGadget.h +++ b/gadgets/mri_core/FloatToFixedPointGadget.h @@ -22,9 +22,9 @@ namespace Gadgetron Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Float to Fixed Point Conversion") { register_parameter("type", &type, "Output integer type (ushort, short, uint, int)"); - register_parameter("max_intensity", &max_intensity, "Maximum intensity value"); - register_parameter("min_intensity", &min_intensity, "Minimum intensity value"); - register_parameter("intensity_offset", &intensity_offset, "Intensity offset"); + register_parameter("max-intensity", &max_intensity, "Maximum intensity value"); + register_parameter("min-intensity", &min_intensity, "Minimum intensity value"); + register_parameter("intensity-offset", &intensity_offset, "Intensity offset"); } std::string type = "ushort"; diff --git a/gadgets/mri_core/PhysioInterpolationGadget.h b/gadgets/mri_core/PhysioInterpolationGadget.h index d0b76f96..9303f74c 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.h +++ b/gadgets/mri_core/PhysioInterpolationGadget.h @@ -93,12 +93,12 @@ class PhysioInterpolationGadget : public Core::MRChannelGadget - class GenericReconBase : public Core::ChannelGadget + class GenericReconBase : public Core::MRChannelGadget { public: - typedef Core::ChannelGadget BaseClass; - - GenericReconBase(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) - , num_encoding_spaces_(context.header.encoding.size()), process_called_times_(0) + typedef Core::MRChannelGadget BaseClass; + + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix, const std::string& description) : NodeParameters(prefix, description) { + register_flag("verbose", &verbose, "Whether to print more information"); + register_flag("perform-timing", &perform_timing, "Whether to perform timing on some computational steps"); + register_parameter("debug-folder", &debug_folder, "If set, the debug output will be written out"); + // register_parameter("time-tick", &time_tick, "Time tick in ms"); + }; + bool verbose = false; + bool perform_timing = false; + std::string debug_folder; + // float time_tick = 2.5; + }; + + GenericReconBase(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) + , verbose(params_.verbose) + , num_encoding_spaces_(context.header.encoding.size()) + , process_called_times_(0) { gt_timer_.set_timing_in_destruction(false); gt_timer_local_.set_timing_in_destruction(false); - if (!debug_folder.empty()) + if (!params_.debug_folder.empty()) { - Gadgetron::get_debug_folder_path(debug_folder, debug_folder_full_path_); - GDEBUG_CONDITION_STREAM(verbose, "Debug folder is " << debug_folder_full_path_); + Gadgetron::get_debug_folder_path(params_.debug_folder, debug_folder_full_path_); + GDEBUG_CONDITION_STREAM(params_.verbose, "Debug folder is " << debug_folder_full_path_); // Create debug folder if necessary boost::filesystem::path boost_folder_path(debug_folder_full_path_); @@ -56,24 +72,22 @@ namespace Gadgetron { } else { - GDEBUG_CONDITION_STREAM(verbose, "Debug folder is not set ... "); + GDEBUG_CONDITION_STREAM(params_.verbose, "Debug folder is not set ... "); } - // find the buffer names if they are set - this->gt_streamer_.initialize_stream_name_buffer(context.parameters); - this->gt_streamer_.verbose_ = this->verbose; + this->gt_streamer_.verbose_ = this->params_.verbose; + this->gt_streamer_.initialize_stream_name_buffer(context.env); } - /// ------------------------------------------------------------------------------------ - /// debug and timing - NODE_PROPERTY(verbose, bool, "Whether to print more information", false); - NODE_PROPERTY(debug_folder, std::string, "If set, the debug output will be written out", ""); - NODE_PROPERTY(perform_timing, bool, "Whether to perform timing on some computational steps", false); - - /// ms for every time tick - NODE_PROPERTY(time_tick, float, "Time tick in ms", 2.5); + /** TODO: This is a duplicate of this->params_.verbose, for convenience, since it is used + * by external classes, such as ImageArraySendMixin. + * + * This should be fixed... + */ + const bool verbose; protected: + const Parameters params_; // number of encoding spaces in the protocol size_t num_encoding_spaces_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp index 90b1be48..b7115d29 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp @@ -5,14 +5,14 @@ namespace Gadgetron { - GenericReconCartesianGrappaAIGadget::GenericReconCartesianGrappaAIGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + GenericReconCartesianGrappaAIGadget::GenericReconCartesianGrappaAIGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) { - boost::filesystem::path gadgetron_python_path = context.paths.gadgetron_home / "share" / "gadgetron" / "python"; - GDEBUG_STREAM("PYTHON_PATH " << gadgetron_python_path.string()); + std::filesystem::path pingvin_python_path = context.paths.pingvin_home / "share" / "pingvin" / "python"; + GDEBUG_STREAM("PYTHON_PATH " << pingvin_python_path.string()); Gadgetron::initialize_python(); - Gadgetron::add_python_path(gadgetron_python_path.generic_string()); - this->gt_home_ = gadgetron_python_path.generic_string(); + Gadgetron::add_python_path(pingvin_python_path.generic_string()); + this->gt_home_ = pingvin_python_path.generic_string(); models_.resize(num_encoding_spaces_); kernels_.resize(num_encoding_spaces_); @@ -22,7 +22,7 @@ namespace Gadgetron { void GenericReconCartesianGrappaAIGadget::process(Core::InputChannel &in, Core::OutputChannel &out) { for (auto m1 : in) { - if (perform_timing) { gt_timer_local_.start("GenericReconCartesianGrappaAIGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("GenericReconCartesianGrappaAIGadget::process"); } process_called_times_++; @@ -65,9 +65,9 @@ namespace Gadgetron { // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::make_ref_coil_map"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::make_ref_coil_map"); } this->make_ref_coil_map(*recon_data->buffers[e].ref, recon_data->buffers[e].data.data.get_dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // ---------------------------------------------------------- // export prepared ref for calibration and coil map @@ -76,9 +76,9 @@ namespace Gadgetron { // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_dst_ and recon_obj_[e].ref_coil_map_ are modified - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::prepare_down_stream_coil_compression_ref_data"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::prepare_down_stream_coil_compression_ref_data"); } this->prepare_down_stream_coil_compression_ref_data(recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, recon_obj_[e].ref_calib_dst_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_dst_, debug_folder_full_path_ + "ref_calib_dst" + os.str()); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map_dst" + os.str()); } @@ -86,17 +86,17 @@ namespace Gadgetron { // --------------------------------------------------------------- // after this step, coil map is computed and stored in recon_obj_[e].coil_map_ - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_coil_map_estimation"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_coil_map_estimation"); } this->perform_coil_map_estimation(recon_obj_[e].ref_coil_map_, recon_obj_[e].coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled // gfactor is computed too - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_calib"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_calib"); } this->perform_calib(recon_data->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- recon_data->buffers[e].ref = std::nullopt; @@ -111,15 +111,15 @@ namespace Gadgetron { // --------------------------------------------------------------- - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_unwrapping"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::perform_unwrapping"); } this->perform_unwrapping(recon_data->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::compute_image_header"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::compute_image_header"); } this->compute_image_header(recon_data->buffers[e], recon_obj_[e].recon_res_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // set up recon_res_grappa_ai_ this->recon_res_grappa_ai_[e].headers = recon_obj_[e].recon_res_.headers; @@ -145,9 +145,9 @@ namespace Gadgetron { if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data, debug_folder_full_path_ + "recon_res" + os.str()); } if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(this->recon_res_grappa_ai_[e].data, debug_folder_full_path_ + "recon_res_grappa_ai" + os.str()); } - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::send_out_image_array"); } - this->send_out_image_array(this->recon_res_grappa_ai_[e], e, image_series + ((int)e + 2), GADGETRON_IMAGE_REGULAR, out); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaAIGadget::send_out_image_array"); } + this->send_out_image_array(this->recon_res_grappa_ai_[e], e, params_.image_series + ((int)e + 2), GADGETRON_IMAGE_REGULAR, out); + if (params_.perform_timing) { gt_timer_.stop(); } } recon_obj_[e].recon_res_.data.clear(); @@ -160,7 +160,7 @@ namespace Gadgetron { recon_res_grappa_ai_[e].meta.clear(); } - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -199,11 +199,11 @@ namespace Gadgetron { else { // allocate buffer for kernels - size_t kRO = grappa_kSize_RO; - size_t kNE1 = grappa_kSize_E1; - size_t kNE2 = grappa_kSize_E2; + size_t kRO = params_.grappa_kSize_RO; + size_t kNE1 = params_.grappa_kSize_E1; + size_t kNE2 = params_.grappa_kSize_E2; - bool fitItself = this->downstream_coil_compression; + bool fitItself = params_.downstream_coil_compression; size_t convKRO(1), convKE1(1), convKE2(1); @@ -260,15 +260,15 @@ namespace Gadgetron { if (fitItself) { Gadgetron::grappa3d_calib_convolution_kernel(ref_src, ref_dst, (size_t)acceFactorE1_[e], - (size_t)acceFactorE2_[e], grappa_reg_lamda, - grappa_calib_over_determine_ratio, kRO, kNE1, + (size_t)acceFactorE2_[e], params_.grappa_reg_lamda, + params_.grappa_calib_over_determine_ratio, kRO, kNE1, kNE2, ker); } else { Gadgetron::grappa3d_calib_convolution_kernel(ref_src, ref_src, (size_t)acceFactorE1_[e], - (size_t)acceFactorE2_[e], grappa_reg_lamda, - grappa_calib_over_determine_ratio, kRO, kNE1, + (size_t)acceFactorE2_[e], params_.grappa_reg_lamda, + params_.grappa_calib_over_determine_ratio, kRO, kNE1, kNE2, ker); } @@ -335,7 +335,7 @@ namespace Gadgetron { Gadgetron::grappa2d_prepare_calib(acsSrc, acsSrc, kRO, kE1, oE1, startRO, endRO, startE1, endE1, A, B); } - double thres = grappa_reg_lamda; + double thres = params_.grappa_reg_lamda; Gadgetron::grappa2d_perform_calib(A, B, kRO, kE1, oE1, thres, ker); kernels_[e][ii] = ker; @@ -477,8 +477,8 @@ namespace Gadgetron { { PythonFunction< hoNDArray > apply_grappa_ai("grappa_ai", "apply_grappa_ai_model"); - size_t kRO = grappa_kSize_RO; - size_t kNE1 = grappa_kSize_E1; + size_t kRO = params_.grappa_kSize_RO; + size_t kNE1 = params_.grappa_kSize_E1; std::vector kE1, oE1; bool fitItself = false; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h index 63d45026..8082e0c1 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h @@ -17,7 +17,12 @@ namespace Gadgetron { typedef typename BaseClass::ReconObjType ReconObjType; typedef std::complex T; - GenericReconCartesianGrappaAIGadget(const Core::Context& context, const Core::GadgetProperties& properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Cartesian Grappa AI") + { } + }; + + GenericReconCartesianGrappaAIGadget(const Core::MrdContext& context, const Parameters& params); protected: diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp index 0e0dd75d..41de01be 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp @@ -15,9 +15,9 @@ namespace Gadgetron { - GenericReconCartesianGrappaGadget::GenericReconCartesianGrappaGadget(const Core::Context &context, - const Core::GadgetProperties &properties) - : BaseClass(context, properties) + GenericReconCartesianGrappaGadget::GenericReconCartesianGrappaGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -25,7 +25,7 @@ namespace Gadgetron { recon_obj_.resize(num_encoding_spaces_); - GDEBUG_STREAM("PATHNAME " << context.paths.gadgetron_home); + GDEBUG_STREAM("PATHNAME " << context.paths.pingvin_home); this->gt_streamer_.stream_mrd_header(h); } @@ -33,7 +33,7 @@ namespace Gadgetron { void GenericReconCartesianGrappaGadget::process(Core::InputChannel &in, Core::OutputChannel &out) { for (auto m1 : in) { - if (perform_timing) { gt_timer_local_.start("GenericReconCartesianGrappaGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("GenericReconCartesianGrappaGadget::process"); } process_called_times_++; mrd::ReconData *recon_data = &m1; @@ -86,10 +86,10 @@ namespace Gadgetron { // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::make_ref_coil_map"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::make_ref_coil_map"); } this->make_ref_coil_map(*recon_data->buffers[e].ref, recon_data->buffers[e].data.data.dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // ---------------------------------------------------------- // export prepared ref for calibration and coil map @@ -105,13 +105,13 @@ namespace Gadgetron { // --------------------------------------------------------------- // after this step, the recon_obj_[e].ref_calib_dst_ and recon_obj_[e].ref_coil_map_ are modified - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::prepare_down_stream_coil_compression_ref_data"); } this->prepare_down_stream_coil_compression_ref_data(recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, recon_obj_[e].ref_calib_dst_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } this->gt_streamer_.stream_to_array_buffer(GENERIC_RECON_STREAM_REF_KSPACE_FOR_COILMAP, recon_obj_[e].ref_coil_map_); @@ -128,19 +128,19 @@ namespace Gadgetron { // --------------------------------------------------------------- // after this step, coil map is computed and stored in recon_obj_[e].coil_map_ - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_coil_map_estimation"); } this->perform_coil_map_estimation(recon_obj_[e].ref_coil_map_, recon_obj_[e].coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled // gfactor is computed too - if (perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_calib"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_calib"); } this->perform_calib(recon_data->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- @@ -163,19 +163,19 @@ namespace Gadgetron { // --------------------------------------------------------------- - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_unwrapping"); } this->perform_unwrapping(recon_data->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::compute_image_header"); } this->compute_image_header(recon_data->buffers[e], recon_obj_[e].recon_res_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- @@ -188,7 +188,7 @@ namespace Gadgetron { // } // --------------------------------------------------------------- - if (send_out_gfactor && recon_obj_[e].gfactor_.get_number_of_elements() > 0 && + if (params_.send_out_gfactor && recon_obj_[e].gfactor_.get_number_of_elements() > 0 && (acceFactorE1_[e] * acceFactorE2_[e] > 1)) { mrd::ImageArray res; Gadgetron::real_to_complex(recon_obj_[e].gfactor_, res.data); @@ -200,26 +200,26 @@ namespace Gadgetron { debug_folder_full_path_ + "gfactor_" + os.str()); } - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array, gfactor"); } - this->send_out_image_array(res, e, image_series + 10 * ((int) e + 2), + this->send_out_image_array(res, e, params_.image_series + 10 * ((int) e + 2), GADGETRON_IMAGE_GFACTOR, out); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } // --------------------------------------------------------------- - if (send_out_snr_map) { + if (params_.send_out_snr_map) { hoNDArray > snr_map; if (calib_mode_[e] == mrd::CalibrationMode::kNoacceleration) { snr_map = recon_obj_[e].recon_res_.data; } else { if (recon_obj_[e].gfactor_.get_number_of_elements() > 0) { - if (perform_timing) { gt_timer_.start("compute SNR map array"); } + if (params_.perform_timing) { gt_timer_.start("compute SNR map array"); } this->compute_snr_map(recon_obj_[e], snr_map); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } } @@ -229,16 +229,16 @@ namespace Gadgetron { debug_folder_full_path_ + "snr_map" + os.str()); } - if (perform_timing) { gt_timer_.start("send out gfactor array, snr map"); } + if (params_.perform_timing) { gt_timer_.start("send out gfactor array, snr map"); } mrd::ImageArray res; res.data = snr_map; res.headers = recon_obj_[e].recon_res_.headers; res.meta = recon_obj_[e].recon_res_.meta; - this->send_out_image_array(res, e, image_series + 100 * ((int) e + 3), GADGETRON_IMAGE_SNR_MAP, out); + this->send_out_image_array(res, e, params_.image_series + 100 * ((int) e + 3), GADGETRON_IMAGE_SNR_MAP, out); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } } @@ -253,13 +253,13 @@ namespace Gadgetron { if (recon_obj_[e].gfactor_.get_number_of_elements() > 0) this->gt_streamer_.stream_to_mrd_image_buffer(GENERIC_RECON_STREAM_GFACTOR_MAP, recon_obj_[e].gfactor_, recon_obj_[e].recon_res_.headers, recon_obj_[e].recon_res_.meta); this->gt_streamer_.stream_to_mrd_image_buffer(GENERIC_RECON_STREAM_RECONED_COMPLEX_IMAGE, recon_obj_[e].recon_res_.data, recon_obj_[e].recon_res_.headers, recon_obj_[e].recon_res_.meta); - if (perform_timing) { + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array"); } this->send_out_image_array(recon_obj_[e].recon_res_, e, - image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); - if (perform_timing) { gt_timer_.stop(); } + params_.image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); + if (params_.perform_timing) { gt_timer_.stop(); } } recon_obj_[e].recon_res_.data.clear(); @@ -268,7 +268,7 @@ namespace Gadgetron { recon_obj_[e].recon_res_.meta.clear(); } - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -276,13 +276,13 @@ namespace Gadgetron { const hoNDArray > &ref_src, hoNDArray > &ref_coil_map, hoNDArray > &ref_dst, size_t e) { - if (!downstream_coil_compression) { + if (!params_.downstream_coil_compression) { GDEBUG_CONDITION_STREAM(verbose, "Downstream coil compression is not prescribed ... "); ref_dst = ref_src; return; } - if (downstream_coil_compression_thres < 0 && downstream_coil_compression_num_modesKept == 0) { + if (params_.downstream_coil_compression_thres < 0 && params_.downstream_coil_compression_num_modesKept == 0) { GDEBUG_CONDITION_STREAM(verbose, "Downstream coil compression is prescribed to use all input channels ... "); ref_dst = ref_src; @@ -305,9 +305,9 @@ namespace Gadgetron { std::complex *pRef = const_cast< std::complex * >(ref_src.begin()); size_t dstCHA = CHA; - if (downstream_coil_compression_num_modesKept > 0 && - downstream_coil_compression_num_modesKept <= CHA) { - dstCHA = downstream_coil_compression_num_modesKept; + if (params_.downstream_coil_compression_num_modesKept > 0 && + params_.downstream_coil_compression_num_modesKept <= CHA) { + dstCHA = params_.downstream_coil_compression_num_modesKept; } else { std::vector E(CHA, 0); long long cha; @@ -324,7 +324,7 @@ namespace Gadgetron { } for (cha = 1; cha < (long long) CHA; cha++) { - if (std::abs(E[cha]) < downstream_coil_compression_thres * std::abs(E[0])) { + if (std::abs(E[cha]) < params_.downstream_coil_compression_thres * std::abs(E[0])) { break; } } @@ -391,13 +391,13 @@ namespace Gadgetron { Gadgetron::conjugate(recon_obj.coil_map_, recon_obj.unmixing_coeff_); } else { // allocate buffer for kernels - size_t kRO = grappa_kSize_RO; - size_t kNE1 = grappa_kSize_E1; - size_t kNE2 = grappa_kSize_E2; + size_t kRO = params_.grappa_kSize_RO; + size_t kNE1 = params_.grappa_kSize_E1; + size_t kNE2 = params_.grappa_kSize_E2; size_t convKRO(1), convKE1(1), convKE2(1); - bool fitItself = this->downstream_coil_compression; + bool fitItself = this->params_.downstream_coil_compression; if (E2 > 1) { std::vector kE1, oE1; @@ -446,15 +446,15 @@ namespace Gadgetron { if (fitItself) { Gadgetron::grappa3d_calib_convolution_kernel(ref_src, ref_dst, (size_t)acceFactorE1_[e], - (size_t)acceFactorE2_[e], grappa_reg_lamda, - grappa_calib_over_determine_ratio, kRO, kNE1, + (size_t)acceFactorE2_[e], params_.grappa_reg_lamda, + params_.grappa_calib_over_determine_ratio, kRO, kNE1, kNE2, ker); } else { Gadgetron::grappa3d_calib_convolution_kernel(ref_src, ref_src, (size_t)acceFactorE1_[e], - (size_t)acceFactorE2_[e], grappa_reg_lamda, - grappa_calib_over_determine_ratio, kRO, kNE1, + (size_t)acceFactorE2_[e], params_.grappa_reg_lamda, + params_.grappa_calib_over_determine_ratio, kRO, kNE1, kNE2, ker); } @@ -494,12 +494,12 @@ namespace Gadgetron { if (fitItself) { Gadgetron::grappa2d_calib_convolution_kernel(acsSrc, acsDst, (size_t)acceFactorE1_[e], - grappa_reg_lamda, kRO, kNE1, convKer); + params_.grappa_reg_lamda, kRO, kNE1, convKer); } else { Gadgetron::grappa2d_calib_convolution_kernel(acsSrc, acsSrc, (size_t)acceFactorE1_[e], - grappa_reg_lamda, kRO, kNE1, convKer); + params_.grappa_reg_lamda, kRO, kNE1, convKer); } Gadgetron::grappa2d_image_domain_kernel(convKer, RO, E1, kIm); @@ -704,6 +704,7 @@ namespace Gadgetron { GenericReconCartesianGrappaGadget::~GenericReconCartesianGrappaGadget() { + /** TODO: This is unnecessary, just make GenericReconMrdStreamer close the buffers in its own destructor... */ GDEBUG_CONDITION_STREAM(this->verbose, "GenericReconCartesianGrappaGadget - destructor"); this->gt_streamer_.close_stream_buffer(); } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h index a5139f5e..142101c4 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h @@ -56,36 +56,44 @@ namespace Gadgetron { typedef GenericReconGadget BaseClass; typedef Gadgetron::GenericReconCartesianGrappaObj< std::complex > ReconObjType; - GenericReconCartesianGrappaGadget(const Core::Context &context, const Core::GadgetProperties &properties); + struct Parameters : BaseClass::Parameters { + Parameters(const std::string& prefix) : Parameters(prefix, "Cartesian Grappa") + {} + + Parameters(const std::string& prefix, const std::string& description) : BaseClass::Parameters(prefix, description) + { + register_flag("send-out-gfactor", &send_out_gfactor, "Whether to send out gfactor map"); + register_flag("send-out-snr-map", &send_out_snr_map, "Whether to send out SNR map"); + register_parameter("grappa-kSize-RO", &grappa_kSize_RO, "Grappa kernel size RO"); + register_parameter("grappa-kSize-E1", &grappa_kSize_E1, "Grappa kernel size E1"); + register_parameter("grappa-kSize-E2", &grappa_kSize_E2, "Grappa kernel size E2"); + register_parameter("grappa-reg-lamda", &grappa_reg_lamda, "Grappa regularization threshold"); + register_parameter("grappa-calib-over-determine-ratio", &grappa_calib_over_determine_ratio, "Grappa calibration overdermination ratio"); + register_parameter("downstream-coil-compression", &downstream_coil_compression, "Whether to perform downstream coil compression"); + register_parameter("downstream-coil-compression-thres", &downstream_coil_compression_thres, "Threadhold for downstream coil compression"); + register_parameter("downstream-coil-compression-num-modesKept", &downstream_coil_compression_num_modesKept, "Number of modes to keep for downstream coil compression"); + } + bool send_out_gfactor = false; + bool send_out_snr_map = false; + int grappa_kSize_RO = 5; + int grappa_kSize_E1 = 4; + int grappa_kSize_E2 = 4; + double grappa_reg_lamda = 0.0005; + double grappa_calib_over_determine_ratio = 45; + + /// if downstream_coil_compression==true, down stream coil compression is used + bool downstream_coil_compression = true; + /// if downstream_coil_compression_num_modesKept > 0, this number of channels will be used as the dst channels + double downstream_coil_compression_thres = 0.002; + /// if downstream_coil_compression_num_modesKept==0 and downstream_coil_compression_thres>0, the number of dst channels will be determined by this threshold + size_t downstream_coil_compression_num_modesKept = 0; + }; + + GenericReconCartesianGrappaGadget(const Core::MrdContext &context, const Parameters& params); ~GenericReconCartesianGrappaGadget() override; - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - /// ------------------------------------------------------------------------------------ - /// image sending - NODE_PROPERTY(send_out_gfactor, bool, "Whether to send out gfactor map", false); - NODE_PROPERTY(send_out_snr_map, bool, "Whether to send out SNR map", false); - - /// ------------------------------------------------------------------------------------ - /// Grappa parameters - NODE_PROPERTY(grappa_kSize_RO, int, "Grappa kernel size RO", 5); - NODE_PROPERTY(grappa_kSize_E1, int, "Grappa kernel size E1", 4); - NODE_PROPERTY(grappa_kSize_E2, int, "Grappa kernel size E2", 4); - NODE_PROPERTY(grappa_reg_lamda, double, "Grappa regularization threshold", 0.0005); - NODE_PROPERTY(grappa_calib_over_determine_ratio, double, "Grappa calibration overdermination ratio", 45); - - /// ------------------------------------------------------------------------------------ - /// down stream coil compression - /// if downstream_coil_compression==true, down stream coil compression is used - /// if downstream_coil_compression_num_modesKept > 0, this number of channels will be used as the dst channels - /// if downstream_coil_compression_num_modesKept==0 and downstream_coil_compression_thres>0, the number of dst channels will be determined by this threshold - NODE_PROPERTY(downstream_coil_compression, bool, "Whether to perform downstream coil compression", true); - NODE_PROPERTY(downstream_coil_compression_thres, double, "Threadhold for downstream coil compression", 0.002); - NODE_PROPERTY(downstream_coil_compression_num_modesKept, size_t, "Number of modes to keep for downstream coil compression", 0); - protected: + const Parameters params_; // -------------------------------------------------- // variable for recon @@ -99,11 +107,6 @@ namespace Gadgetron { // default interface function virtual void process(Core::InputChannel< mrd::ReconData > &in, Core::OutputChannel &out) override; - /*** TODO: Delete */ - // virtual int process_config(const mrd::Header& header) override; - // virtual int process(Gadgetron::GadgetContainerMessage< mrd::ReconData >* m1) override; - // virtual int close(unsigned long flags) override; - // -------------------------------------------------- // recon step functions // -------------------------------------------------- diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp index afbca787..01bd6fed 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp @@ -11,65 +11,66 @@ namespace Gadgetron { - GenericReconCartesianNonLinearSpirit2DTGadget::GenericReconCartesianNonLinearSpirit2DTGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + GenericReconCartesianNonLinearSpirit2DTGadget::GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; // ------------------------------------------------- // check the parameters - if(this->spirit_nl_iter_max==0) + if(params_.spirit_nl_iter_max==0) { - this->spirit_nl_iter_max = 15; - GDEBUG_STREAM("spirit_iter_max: " << this->spirit_nl_iter_max); + params_.spirit_nl_iter_max = 15; + GDEBUG_STREAM("spirit_iter_max: " << params_.spirit_nl_iter_max); } - if (this->spirit_nl_iter_thresspirit_nl_iter_thres = 0.004; - GDEBUG_STREAM("spirit_nl_iter_thres: " << this->spirit_nl_iter_thres); + params_.spirit_nl_iter_thres = 0.004; + GDEBUG_STREAM("spirit_nl_iter_thres: " << params_.spirit_nl_iter_thres); } - if (this->spirit_image_reg_lamda < FLT_EPSILON) + if (params_.spirit_image_reg_lamda < FLT_EPSILON) { - if(this->spirit_reg_proximity_across_cha) + if(params_.spirit_reg_proximity_across_cha) { - if(spirit_reg_estimate_noise_floor) + if(params_.spirit_reg_estimate_noise_floor) { - this->spirit_image_reg_lamda = 0.001; + params_.spirit_image_reg_lamda = 0.001; } else { - this->spirit_image_reg_lamda = 0.0002; + params_.spirit_image_reg_lamda = 0.0002; } } else { - if(spirit_reg_estimate_noise_floor) + if(params_.spirit_reg_estimate_noise_floor) { - this->spirit_image_reg_lamda = 0.002; + params_.spirit_image_reg_lamda = 0.002; } else { - this->spirit_image_reg_lamda = 0.00005; + params_.spirit_image_reg_lamda = 0.00005; } } - GDEBUG_STREAM("spirit_image_reg_lamda: " << this->spirit_image_reg_lamda); + GDEBUG_STREAM("spirit_image_reg_lamda: " << params_.spirit_image_reg_lamda); } - if (this->spirit_reg_N_weighting_ratio < FLT_EPSILON) + if (params_.spirit_reg_N_weighting_ratio < FLT_EPSILON) { if(acceFactorE1_[0]<=5) { - this->spirit_reg_N_weighting_ratio = 10.0; + params_.spirit_reg_N_weighting_ratio = 10.0; } else { - this->spirit_reg_N_weighting_ratio = 20.0; + params_.spirit_reg_N_weighting_ratio = 20.0; } - GDEBUG_STREAM("spirit_reg_N_weighting_ratio: " << this->spirit_reg_N_weighting_ratio); + GDEBUG_STREAM("spirit_reg_N_weighting_ratio: " << params_.spirit_reg_N_weighting_ratio); } } @@ -135,20 +136,20 @@ namespace Gadgetron { hoNDArray< std::complex >& res = recon_obj.full_kspace_; hoNDArray< std::complex >& ref = recon_obj.ref_calib_; - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_parallel_imaging_lamda : " << this->spirit_parallel_imaging_lamda); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_image_reg_lamda : " << this->spirit_image_reg_lamda); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_data_fidelity_lamda : " << this->spirit_data_fidelity_lamda); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_nl_iter_max : " << this->spirit_nl_iter_max); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_nl_iter_thres : " << this->spirit_nl_iter_thres); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_name : " << this->spirit_reg_name); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_level : " << this->spirit_reg_level); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_keep_approx_coeff : " << this->spirit_reg_keep_approx_coeff); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_keep_redundant_dimension_coeff : " << this->spirit_reg_keep_redundant_dimension_coeff); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_proximity_across_cha : " << this->spirit_reg_proximity_across_cha); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_use_coil_sen_map : " << this->spirit_reg_use_coil_sen_map); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_RO_weighting_ratio : " << this->spirit_reg_RO_weighting_ratio); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_E1_weighting_ratio : " << this->spirit_reg_E1_weighting_ratio); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit_reg_N_weighting_ratio : " << this->spirit_reg_N_weighting_ratio); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_parallel_imaging_lamda : " << params_.spirit_parallel_imaging_lamda); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_image_reg_lamda : " << params_.spirit_image_reg_lamda); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_data_fidelity_lamda : " << params_.spirit_data_fidelity_lamda); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_nl_iter_max : " << params_.spirit_nl_iter_max); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_nl_iter_thres : " << params_.spirit_nl_iter_thres); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_name : " << params_.spirit_reg_name); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_level : " << params_.spirit_reg_level); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_keep_approx_coeff : " << params_.spirit_reg_keep_approx_coeff); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_keep_redundant_dimension_coeff : " << params_.spirit_reg_keep_redundant_dimension_coeff); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_proximity_across_cha : " << params_.spirit_reg_proximity_across_cha); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_use_coil_sen_map : " << params_.spirit_reg_use_coil_sen_map); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_RO_weighting_ratio : " << params_.spirit_reg_RO_weighting_ratio); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_E1_weighting_ratio : " << params_.spirit_reg_E1_weighting_ratio); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit_reg_N_weighting_ratio : " << params_.spirit_reg_N_weighting_ratio); size_t slc, s; @@ -202,9 +203,9 @@ namespace Gadgetron { // ------------------------------ std::string timing_str = "SPIRIT, Non-linear unwrapping, 2DT_" + suffix_2DT; - if (this->perform_timing) timer.start(timing_str.c_str()); + if (params_.perform_timing) timer.start(timing_str.c_str()); this->perform_nonlinear_spirit_unwrapping(kspace2DT, kIm2DT, ref2DT, coilMap2DT, res2DT, e); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "res_nl_spirit_2DT_" + suffix_2DT); } } @@ -214,9 +215,9 @@ namespace Gadgetron { // --------------------------------------------------------------------- // compute coil combined images // --------------------------------------------------------------------- - if (this->perform_timing) timer.start("SPIRIT Non linear, coil combination ... "); + if (params_.perform_timing) timer.start("SPIRIT Non linear, coil combination ... "); this->perform_spirit_coil_combine(recon_obj); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_obj.recon_res_.data, debug_folder_full_path_ + "unwrappedIm_" + suffix); } } @@ -247,7 +248,7 @@ namespace Gadgetron { { try { - bool print_iter = this->spirit_print_iter; + bool print_iter = params_.spirit_print_iter; size_t RO = kspace.get_size(0); size_t E1 = kspace.get_size(1); @@ -379,13 +380,13 @@ namespace Gadgetron { // compute linear solution as the initialization if(use_random_sampling) { - if (this->perform_timing) timer.start("SPIRIT Non linear, perform linear spirit recon ... "); + if (params_.perform_timing) timer.start("SPIRIT Non linear, perform linear spirit recon ... "); this->perform_spirit_unwrapping(kspace, kerIm, kspaceLinear); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); } else { - if (this->perform_timing) timer.start("SPIRIT Non linear, perform linear recon ... "); + if (params_.perform_timing) timer.start("SPIRIT Non linear, perform linear recon ... "); //size_t ref2DT_RO = ref2DT.get_size(0); //size_t ref2DT_E1 = ref2DT.get_size(1); @@ -426,14 +427,14 @@ namespace Gadgetron { Gadgetron::apply_unmix_coeff_aliased_image(aliasedImage, unmixC, complexIm); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); } if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(kspaceLinear, debug_folder_full_path_ + "spirit_nl_2DT_kspaceLinear"); if(hasCoilMap) { - if(N>=spirit_reg_minimal_num_images_for_noise_floor) + if(N>=params_.spirit_reg_minimal_num_images_for_noise_floor) { // estimate the noise level @@ -484,33 +485,33 @@ namespace Gadgetron { hoNDArray< std::complex > kspaceInitial(RO, E1, CHA, N, kspaceLinear.begin()); hoNDArray< std::complex > res2DT(RO, E1, CHA, N, res.begin()); - if (this->spirit_data_fidelity_lamda > 0) + if (params_.spirit_data_fidelity_lamda > 0) { - GDEBUG_STREAM("Start the NL SPIRIT data fidelity iteration - regularization strength : " << this->spirit_image_reg_lamda - << " - number of iteration : " << this->spirit_nl_iter_max - << " - proximity across cha : " << this->spirit_reg_proximity_across_cha - << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio - << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map - << " - iter thres : " << this->spirit_nl_iter_thres - << " - wavelet name : " << this->spirit_reg_name + GDEBUG_STREAM("Start the NL SPIRIT data fidelity iteration - regularization strength : " << params_.spirit_image_reg_lamda + << " - number of iteration : " << params_.spirit_nl_iter_max + << " - proximity across cha : " << params_.spirit_reg_proximity_across_cha + << " - redundant dimension weighting ratio : " << params_.spirit_reg_N_weighting_ratio + << " - using coil sen map : " << params_.spirit_reg_use_coil_sen_map + << " - iter thres : " << params_.spirit_nl_iter_thres + << " - wavelet name : " << params_.spirit_reg_name ); typedef hoGdSolver< hoNDArray< std::complex >, hoWavelet2DTOperator< std::complex > > SolverType; SolverType solver; - solver.iterations_ = this->spirit_nl_iter_max; - solver.set_output_mode(this->spirit_print_iter ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); - solver.grad_thres_ = this->spirit_nl_iter_thres; + solver.iterations_ = params_.spirit_nl_iter_max; + solver.set_output_mode(params_.spirit_print_iter ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); + solver.grad_thres_ = params_.spirit_nl_iter_thres; - if(spirit_reg_estimate_noise_floor && std::abs(smallest_eigen_value)>0) + if(params_.spirit_reg_estimate_noise_floor && std::abs(smallest_eigen_value)>0) { solver.scale_factor_ = smallest_eigen_value; - solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda * gfactorMedian; + solver.proximal_strength_ratio_ = params_.spirit_image_reg_lamda * gfactorMedian; GDEBUG_STREAM("SPIRIT Non linear, eigen value is used to derive the regularization strength : " << solver.proximal_strength_ratio_ << " - smallest eigen value : " << solver.scale_factor_); } else { - solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda; + solver.proximal_strength_ratio_ = params_.spirit_image_reg_lamda; } boost::shared_ptr< hoNDArray< std::complex > > x0 = boost::make_shared< hoNDArray< std::complex > >(kspaceInitial); @@ -526,17 +527,17 @@ namespace Gadgetron { // image reg term hoWavelet2DTOperator< std::complex > wav3DOperator(dims); wav3DOperator.set_acquired_points(*acq); - wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio; - wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio; - wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio; - wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff; - wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff; - wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha; + wav3DOperator.scale_factor_first_dimension_ = params_.spirit_reg_RO_weighting_ratio; + wav3DOperator.scale_factor_second_dimension_ = params_.spirit_reg_E1_weighting_ratio; + wav3DOperator.scale_factor_third_dimension_ = params_.spirit_reg_N_weighting_ratio; + wav3DOperator.with_approx_coeff_ = !params_.spirit_reg_keep_approx_coeff; + wav3DOperator.change_coeffcients_third_dimension_boundary_ = !params_.spirit_reg_keep_redundant_dimension_coeff; + wav3DOperator.proximity_across_cha_ = params_.spirit_reg_proximity_across_cha; wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; - wav3DOperator.select_wavelet(this->spirit_reg_name); + wav3DOperator.select_wavelet(params_.spirit_reg_name); - if (this->spirit_reg_use_coil_sen_map && hasCoilMap) + if (params_.spirit_reg_use_coil_sen_map && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } @@ -546,39 +547,39 @@ namespace Gadgetron { solver.oper_system_ = &spirit; solver.oper_reg_ = &wav3DOperator; - if (this->perform_timing) timer.start("NonLinear SPIRIT solver for 2DT with data fidelity ... "); + if (params_.perform_timing) timer.start("NonLinear SPIRIT solver for 2DT with data fidelity ... "); solver.solve(*acq, res2DT); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_data_fidelity_res"); } else { - GDEBUG_STREAM("Start the NL SPIRIT iteration with regularization strength : "<< this->spirit_image_reg_lamda - << " - number of iteration : " << this->spirit_nl_iter_max - << " - proximity across cha : " << this->spirit_reg_proximity_across_cha - << " - redundant dimension weighting ratio : " << this->spirit_reg_N_weighting_ratio - << " - using coil sen map : " << this->spirit_reg_use_coil_sen_map - << " - iter thres : " << this->spirit_nl_iter_thres - << " - wavelet name : " << this->spirit_reg_name + GDEBUG_STREAM("Start the NL SPIRIT iteration with regularization strength : "<< params_.spirit_image_reg_lamda + << " - number of iteration : " << params_.spirit_nl_iter_max + << " - proximity across cha : " << params_.spirit_reg_proximity_across_cha + << " - redundant dimension weighting ratio : " << params_.spirit_reg_N_weighting_ratio + << " - using coil sen map : " << params_.spirit_reg_use_coil_sen_map + << " - iter thres : " << params_.spirit_nl_iter_thres + << " - wavelet name : " << params_.spirit_reg_name ); typedef hoGdSolver< hoNDArray< std::complex >, hoWavelet2DTOperator< std::complex > > SolverType; SolverType solver; - solver.iterations_ = this->spirit_nl_iter_max; - solver.set_output_mode(this->spirit_print_iter ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); - solver.grad_thres_ = this->spirit_nl_iter_thres; + solver.iterations_ = params_.spirit_nl_iter_max; + solver.set_output_mode(params_.spirit_print_iter ? SolverType::OUTPUT_VERBOSE : SolverType::OUTPUT_SILENT); + solver.grad_thres_ = params_.spirit_nl_iter_thres; - if(spirit_reg_estimate_noise_floor && std::abs(smallest_eigen_value)>0) + if(params_.spirit_reg_estimate_noise_floor && std::abs(smallest_eigen_value)>0) { solver.scale_factor_ = smallest_eigen_value; - solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda * gfactorMedian; + solver.proximal_strength_ratio_ = params_.spirit_image_reg_lamda * gfactorMedian; GDEBUG_STREAM("SPIRIT Non linear, eigen value is used to derive the regularization strength : " << solver.proximal_strength_ratio_ << " - smallest eigen value : " << solver.scale_factor_); } else { - solver.proximal_strength_ratio_ = this->spirit_image_reg_lamda; + solver.proximal_strength_ratio_ = params_.spirit_image_reg_lamda; } boost::shared_ptr< hoNDArray< std::complex > > x0 = boost::make_shared< hoNDArray< std::complex > >(kspaceInitial); @@ -600,17 +601,17 @@ namespace Gadgetron { hoWavelet2DTOperator< std::complex > wav3DOperator(dim); wav3DOperator.set_acquired_points(*acq); - wav3DOperator.scale_factor_first_dimension_ = this->spirit_reg_RO_weighting_ratio; - wav3DOperator.scale_factor_second_dimension_ = this->spirit_reg_E1_weighting_ratio; - wav3DOperator.scale_factor_third_dimension_ = this->spirit_reg_N_weighting_ratio; - wav3DOperator.with_approx_coeff_ = !this->spirit_reg_keep_approx_coeff; - wav3DOperator.change_coeffcients_third_dimension_boundary_ = !this->spirit_reg_keep_redundant_dimension_coeff; - wav3DOperator.proximity_across_cha_ = this->spirit_reg_proximity_across_cha; + wav3DOperator.scale_factor_first_dimension_ = params_.spirit_reg_RO_weighting_ratio; + wav3DOperator.scale_factor_second_dimension_ = params_.spirit_reg_E1_weighting_ratio; + wav3DOperator.scale_factor_third_dimension_ = params_.spirit_reg_N_weighting_ratio; + wav3DOperator.with_approx_coeff_ = !params_.spirit_reg_keep_approx_coeff; + wav3DOperator.change_coeffcients_third_dimension_boundary_ = !params_.spirit_reg_keep_redundant_dimension_coeff; + wav3DOperator.proximity_across_cha_ = params_.spirit_reg_proximity_across_cha; wav3DOperator.no_null_space_ = true; wav3DOperator.input_in_kspace_ = true; - wav3DOperator.select_wavelet(this->spirit_reg_name); + wav3DOperator.select_wavelet(params_.spirit_reg_name); - if (this->spirit_reg_use_coil_sen_map && hasCoilMap) + if (params_.spirit_reg_use_coil_sen_map && hasCoilMap) { wav3DOperator.coil_map_ = *coilMap; } @@ -627,9 +628,9 @@ namespace Gadgetron { hoNDArray< std::complex > b(kspaceInitial); Gadgetron::clear(b); - if (this->perform_timing) timer.start("NonLinear SPIRIT solver for 2DT ... "); + if (params_.perform_timing) timer.start("NonLinear SPIRIT solver for 2DT ... "); solver.solve(b, res2DT); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); if (!debug_folder_full_path_.empty()) gt_exporter_.export_array_complex(res2DT, debug_folder_full_path_ + "spirit_nl_2DT_res"); diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h index fcd510d0..73832c84 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h @@ -21,32 +21,55 @@ namespace Gadgetron { typedef GenericReconCartesianSpiritGadget BaseClass; typedef Gadgetron::GenericReconCartesianSpiritObj< std::complex > ReconObjType; - GenericReconCartesianNonLinearSpirit2DTGadget(const Core::Context& context, const Core::GadgetProperties& properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Cartesian Non-linear SPIRIT") + { + register_parameter("spirit-parallel-imaging-lamda", &spirit_parallel_imaging_lamda, "Spirit regularization strength for parallel imaging term"); + register_parameter("spirit-image-reg-lamda", &spirit_image_reg_lamda, "Spirit regularization strength for imaging term"); + register_parameter("spirit-data-fidelity-lamda", &spirit_data_fidelity_lamda, "Spirit regularization strength for data fidelity term"); + register_parameter("spirit-nl-iter-max", &spirit_nl_iter_max, "Spirit maximal number of iterations for nonlinear optimization"); + register_parameter("spirit-nl-iter-thres", &spirit_nl_iter_thres, "Spirit threshold to stop iteration for nonlinear optimization"); + register_parameter("spirit-reg-name", &spirit_reg_name, "Spirit image domain regularizer (db1, db2, db3, db4, db5)"); + register_parameter("spirit-reg-level", &spirit_reg_level, "Spirit image domain regularizer, number of transformation levels"); + register_parameter("spirit-reg-keep-approx-coeff", &spirit_reg_keep_approx_coeff, "Spirit whether to keep the approximation coefficients from being regularized"); + register_flag("spirit-reg-keep-redundant-dimension-coeff", &spirit_reg_keep_redundant_dimension_coeff, "Spirit whether to keep the boundary coefficients of N dimension from being regularized"); + register_flag("spirit-reg-proximity-across-cha", &spirit_reg_proximity_across_cha, "Spirit whether to perform proximity operation across channels"); + register_flag("spirit-reg-use-coil-sen-map", &spirit_reg_use_coil_sen_map, "Spirit whether to use coil map in the imaging term"); + register_flag("spirit-reg-estimate-noise-floor", &spirit_reg_estimate_noise_floor, "Spirit whether to estimate noise floor for the imaging term"); + register_parameter("spirit-reg-minimal-num-images-for-noise-floor", &spirit_reg_minimal_num_images_for_noise_floor, "Spirit minimal number of images for noise floor estimation"); + register_parameter("spirit-reg-RO-weighting-ratio", &spirit_reg_RO_weighting_ratio, "Spirit regularization weigthing ratio for RO"); + register_parameter("spirit-reg-E1-weighting-ratio", &spirit_reg_E1_weighting_ratio, "Spirit regularization weigthing ratio for E1"); + register_parameter("spirit-reg-N-weighting-ratio", &spirit_reg_N_weighting_ratio, "Spirit regularization weigthing ratio for N"); + } - /// parameters for workflow - // NODE_PROPERTY(spirit_perform_linear , bool, "Spirit whether to perform linear reconstruction as the initialization", true); - /// parameters for regularization - NODE_PROPERTY(spirit_parallel_imaging_lamda , double, "Spirit regularization strength for parallel imaging term", 1.0); - NODE_PROPERTY_NON_CONST(spirit_image_reg_lamda , double, "Spirit regularization strength for imaging term", 0); - NODE_PROPERTY(spirit_data_fidelity_lamda , double, "Spirit regularization strength for data fidelity term", 1.0); - /// parameters for non-linear iteration - NODE_PROPERTY_NON_CONST(spirit_nl_iter_max , int, "Spirit maximal number of iterations for nonlinear optimization", 0); - NODE_PROPERTY_NON_CONST(spirit_nl_iter_thres , double, "Spirit threshold to stop iteration for nonlinear optimization", 0); - /// parameters for image domain regularization, wavelet type regularizer is used here - NODE_PROPERTY(spirit_reg_name , std::string, "Spirit image domain regularizer (db1, db2, db3, db4, db5)", "db1"); - NODE_PROPERTY(spirit_reg_level , int, "Spirit image domain regularizer, number of transformation levels", 1); - NODE_PROPERTY(spirit_reg_keep_approx_coeff , bool, "Spirit whether to keep the approximation coefficients from being regularized", true); - NODE_PROPERTY(spirit_reg_keep_redundant_dimension_coeff, bool, "Spirit whether to keep the boundary coefficients of N dimension from being regularized", false); - NODE_PROPERTY(spirit_reg_proximity_across_cha , bool, "Spirit whether to perform proximity operation across channels", false); - NODE_PROPERTY(spirit_reg_use_coil_sen_map , bool, "Spirit whether to use coil map in the imaging term", false); - NODE_PROPERTY(spirit_reg_estimate_noise_floor , bool, "Spirit whether to estimate noise floor for the imaging term", false); - NODE_PROPERTY(spirit_reg_minimal_num_images_for_noise_floor, int, "Spirit minimal number of images for noise floor estimation", 16); - /// W matrix of equation 3 and 4 in ref [1] - NODE_PROPERTY(spirit_reg_RO_weighting_ratio , double, "Spirit regularization weigthing ratio for RO", 1.0); - NODE_PROPERTY(spirit_reg_E1_weighting_ratio , double, "Spirit regularization weigthing ratio for E1", 1.0); - NODE_PROPERTY_NON_CONST(spirit_reg_N_weighting_ratio , double, "Spirit regularization weigthing ratio for N", 0); + /// parameters for workflow + // bool spirit_perform_linear = true; // "Spirit whether to perform linear reconstruction as the initialization" + /// parameters for regularization + double spirit_parallel_imaging_lamda = 1.0; + double spirit_image_reg_lamda = 0; + double spirit_data_fidelity_lamda = 1.0; + /// parameters for non-linear iteration + int spirit_nl_iter_max = 0; + double spirit_nl_iter_thres = 0; + /// parameters for image domain regularization, wavelet type regularizer is used here + std::string spirit_reg_name = "db1"; + int spirit_reg_level = 1; + bool spirit_reg_keep_approx_coeff = true; + bool spirit_reg_keep_redundant_dimension_coeff = false; + bool spirit_reg_proximity_across_cha = false; + bool spirit_reg_use_coil_sen_map = false; + bool spirit_reg_estimate_noise_floor = false; + int spirit_reg_minimal_num_images_for_noise_floor = 16; + /// W matrix of equation 3 and 4 in ref [1] + double spirit_reg_RO_weighting_ratio = 1.0; + double spirit_reg_E1_weighting_ratio = 1.0; + double spirit_reg_N_weighting_ratio = 0; + }; + + GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MrdContext& context, const Parameters& params); protected: + Parameters params_; // -------------------------------------------------- // variable for recon diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp index c7fc3c92..2a906849 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp @@ -7,8 +7,9 @@ namespace Gadgetron { GenericReconCartesianReferencePrepGadget::GenericReconCartesianReferencePrepGadget( - const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -59,7 +60,7 @@ namespace Gadgetron { { for (auto m1 : in) { - if (perform_timing) { gt_timer_.start("GenericReconCartesianReferencePrepGadget::process"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianReferencePrepGadget::process"); } process_called_times_++; mrd::ReconData* recon_data = &m1; @@ -83,7 +84,7 @@ namespace Gadgetron { // no acceleration mode // check the availability of ref data // ----------------------------------------- - if (prepare_ref_always || !ref_prepared_[e]) + if (params_.prepare_ref_always || !ref_prepared_[e]) { // if no ref data is set, make copy the ref point from the data if (!rbit.ref) @@ -135,7 +136,7 @@ namespace Gadgetron { // ----------------------------------------- // if embedded mode, fill back ref if required - if((calib_mode_[e] == mrd::CalibrationMode::kEmbedded) && ref_fill_into_data_embedded) + if((calib_mode_[e] == mrd::CalibrationMode::kEmbedded) && params_.ref_fill_into_data_embedded) { hoNDArray< std::complex >& data = rbit.data.data; @@ -180,30 +181,30 @@ namespace Gadgetron { // step 1 bool count_sampling_freq = (calib_mode_[e] == mrd::CalibrationMode::kInterleaved); - bool valid_N_for_ref = (N_for_ref= 0); - bool valid_S_for_ref = (S_for_ref= 0); + bool valid_N_for_ref = (params_.N_for_ref= 0); + bool valid_S_for_ref = (params_.S_for_ref= 0); if (!valid_N_for_ref && !valid_S_for_ref) { // use average N S - GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref, average_all_ref_N, average_all_ref_S, count_sampling_freq, ref_calib)); + GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref, params_.average_all_ref_N, params_.average_all_ref_S, count_sampling_freq, ref_calib)); } else if(valid_N_for_ref && !valid_S_for_ref) { // pick N, average S if needed - GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, true, N_for_ref, false, 0, ref_selected_N_S)); - GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref_selected_N_S, false, average_all_ref_S, count_sampling_freq, ref_calib)); + GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, true, params_.N_for_ref, false, 0, ref_selected_N_S)); + GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref_selected_N_S, false, params_.average_all_ref_S, count_sampling_freq, ref_calib)); } else if(!valid_N_for_ref && valid_S_for_ref) { // pick S, average N if needed - GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, false, 0, true, S_for_ref, ref_selected_N_S)); - GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref_selected_N_S, false, average_all_ref_S, count_sampling_freq, ref_calib)); + GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, false, 0, true, params_.S_for_ref, ref_selected_N_S)); + GADGET_CATCH_THROW(Gadgetron::compute_averaged_data_N_S(ref_selected_N_S, false, params_.average_all_ref_S, count_sampling_freq, ref_calib)); } else if (valid_N_for_ref && valid_S_for_ref) { // pick N and S - GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, true, N_for_ref, true, S_for_ref, ref_calib)); + GADGET_CATCH_THROW(Gadgetron::select_data_N_S(ref, true, params_.N_for_ref, true, params_.S_for_ref, ref_calib)); } if (!debug_folder_full_path_.empty()) @@ -301,7 +302,7 @@ namespace Gadgetron { out.push(std::move(m1)); } - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } GADGETRON_GADGET_EXPORT(GenericReconCartesianReferencePrepGadget) diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h index 72e59675..14bb1e4d 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h @@ -17,32 +17,40 @@ namespace Gadgetron { public: typedef GenericReconDataBase BaseClass; - GenericReconCartesianReferencePrepGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - /// ref preparation - /// whether to average all N for ref generation - /// for the interleaved mode, the sampling times will be counted and used for averaging - /// it is recommended to set N as the interleaved dimension - NODE_PROPERTY(average_all_ref_N, bool, "Whether to average all N for ref generation", true); - /// whether to average all S for ref generation - NODE_PROPERTY(average_all_ref_S, bool, "Whether to average all S for ref generation", false); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string &prefix) : BaseClass::Parameters(prefix, "Cartesian Reference Prep") { + register_parameter("average-all-ref-N", &average_all_ref_N, "Whether to average all N for ref generation"); + register_parameter("average-all-ref-S", &average_all_ref_S, "Whether to average all S for ref generation"); + register_parameter("N-for-ref", &N_for_ref, "If N >= 0, this N will be used for ref preparation"); + register_parameter("S-for-ref", &S_for_ref, "If S >= 0, this S will be used for ref preparation"); + register_flag("ref-fill-into-data-embedded", &ref_fill_into_data_embedded, "If true and calibration is in embedded mode, fill the full sampled data from ref array into the data array"); + register_parameter("prepare-ref-always", &prepare_ref_always, "Whether to prepare ref for every incoming ReconData"); + } + + /// ref preparation + /// whether to average all N for ref generation + /// for the interleaved mode, the sampling times will be counted and used for averaging + /// it is recommended to set N as the interleaved dimension + bool average_all_ref_N = true; + /// whether to average all S for ref generation + bool average_all_ref_S = false; /// pick specific N or S for ref, these options overwrites average_all_ref_N and average_all_ref_S - NODE_PROPERTY(N_for_ref, int, "If N_for_ref >=0, this N will be used for ref preparation", -1); - NODE_PROPERTY(S_for_ref, int, "If S_for_ref >=0, this S will be used for ref preparation", -1); + int N_for_ref = -1; + int S_for_ref = -1; + + /// some reconstruction will benefit to fill back the ref data into data array for the embedded mode + bool ref_fill_into_data_embedded = false; - /// some reconstruction will benefit to fill back the ref data into data array for the embedded mode - NODE_PROPERTY(ref_fill_into_data_embedded, bool, "If true and calibration is in embedded mode, fill the full sampled data from ref array into the data array", false); + /// whether to update ref for every incoming ReconData; for some applications, we may want to only compute ref data once + /// if false, the ref will only be prepared for the first incoming ReconData + bool prepare_ref_always = true; + }; - /// whether to update ref for every incoming ReconData; for some applications, we may want to only compute ref data once - /// if false, the ref will only be prepared for the first incoming ReconData - NODE_PROPERTY(prepare_ref_always, bool, "Whether to prepare ref for every incoming ReconData", true); + GenericReconCartesianReferencePrepGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp index 96a05e75..ff16b7ef 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp @@ -8,8 +8,9 @@ namespace Gadgetron { - GenericReconCartesianSpiritGadget::GenericReconCartesianSpiritGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + GenericReconCartesianSpiritGadget::GenericReconCartesianSpiritGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -19,58 +20,58 @@ namespace Gadgetron { // ------------------------------------------------- // check the parameters - if(this->spirit_iter_max==0) + if(params_.spirit_iter_max==0) { size_t acceFactor = acceFactorE1_[0] * acceFactorE2_[0]; if(acceFactor>=6) { - this->spirit_iter_max = 150; + params_.spirit_iter_max = 150; } else if (acceFactor >= 5) { - this->spirit_iter_max = 120; + params_.spirit_iter_max = 120; } else if (acceFactor >= 4) { - this->spirit_iter_max = 100; + params_.spirit_iter_max = 100; } else if (acceFactor >= 3) { - this->spirit_iter_max = 60; + params_.spirit_iter_max = 60; } else { - this->spirit_iter_max = 50; + params_.spirit_iter_max = 50; } - GDEBUG_STREAM("spirit_iter_max: " << this->spirit_iter_max); + GDEBUG_STREAM("spirit_iter_max: " << params_.spirit_iter_max); } - if (this->spirit_iter_thresspirit_iter_thres = 0.0015; - GDEBUG_STREAM("spirit_iter_thres: " << this->spirit_iter_thres); + params_.spirit_iter_thres = 0.0015; + GDEBUG_STREAM("spirit_iter_thres: " << params_.spirit_iter_thres); } - if (this->spirit_reg_lamda1) { - this->spirit_reg_lamda = 0.01; + params_.spirit_reg_lamda = 0.01; } else { - this->spirit_reg_lamda = 0.005; + params_.spirit_reg_lamda = 0.005; } - GDEBUG_STREAM("spirit_reg_lamda: " << this->spirit_reg_lamda); + GDEBUG_STREAM("spirit_reg_lamda: " << params_.spirit_reg_lamda); } } void GenericReconCartesianSpiritGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto m1 : in) { - if (perform_timing) { gt_timer_local_.start("GenericReconCartesianSpiritGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("GenericReconCartesianSpiritGadget::process"); } process_called_times_++; @@ -98,9 +99,9 @@ namespace Gadgetron { // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::make_ref_coil_map"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::make_ref_coil_map"); } this->make_ref_coil_map(*recon_bit_->buffers[e].ref, recon_bit_->buffers[e].data.data.get_dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_, debug_folder_full_path_ + "ref_calib" + os.str()); } // if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map" + os.str()); } @@ -108,18 +109,18 @@ namespace Gadgetron { // ---------------------------------------------------------- // after this step, coil map is computed and stored in recon_obj_[e].coil_map_ - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_coil_map_estimation"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_coil_map_estimation"); } this->perform_coil_map_estimation(recon_obj_[e].ref_coil_map_, recon_obj_[e].coil_map_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].coil_map_, debug_folder_full_path_ + "coil_map_" + os.str()); } // --------------------------------------------------------------- // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_ or recon_obj_[e].kernelIm3D_ are filled - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_calib"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_calib"); } this->perform_calib(recon_bit_->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- @@ -130,15 +131,15 @@ namespace Gadgetron { { // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data_before_unwrapping" + os.str()); } - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_unwrapping"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::perform_unwrapping"); } this->perform_unwrapping(recon_bit_->buffers[e], recon_obj_[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::compute_image_header"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::compute_image_header"); } this->compute_image_header(recon_bit_->buffers[e], recon_obj_[e].recon_res_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } /*** TODO: Waveforms not yet available to any GenericReconBase... They are "dropped" after BucketToBufferGadget */ // if (wav) recon_obj_[e].recon_res_.waveforms = *wav->getObjectPtr(); @@ -147,9 +148,9 @@ namespace Gadgetron { // if (!debug_folder_full_path_.empty()) { this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data_, debug_folder_full_path_ + "recon_res" + os.str()); } - if (perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::send_out_image_array"); } - this->send_out_image_array(recon_obj_[e].recon_res_, e, image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.start("GenericReconCartesianSpiritGadget::send_out_image_array"); } + this->send_out_image_array(recon_obj_[e].recon_res_, e, params_.image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); + if (params_.perform_timing) { gt_timer_.stop(); } } recon_bit_->buffers[e].ref = std::nullopt; @@ -158,7 +159,7 @@ namespace Gadgetron { recon_obj_[e].recon_res_.meta.clear(); } - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -188,9 +189,9 @@ namespace Gadgetron { if (acceFactorE1_[e] > 1 || acceFactorE2_[e] > 1) { // allocate buffer for kernels - size_t kRO = spirit_kSize_RO; - size_t kE1 = spirit_kSize_E1; - size_t kE2 = spirit_kSize_E2; + size_t kRO = params_.spirit_kSize_RO; + size_t kE1 = params_.spirit_kSize_E1; + size_t kE2 = params_.spirit_kSize_E2; GDEBUG_CONDITION_STREAM(this->verbose, "spirit, kRO : " << kRO); GDEBUG_CONDITION_STREAM(this->verbose, "spirit, kE1 : " << kE1); @@ -217,11 +218,11 @@ namespace Gadgetron { long long num = ref_N*ref_S*ref_SLC; - double reg_lamda = this->spirit_reg_lamda; - double over_determine_ratio = this->spirit_calib_over_determine_ratio; + double reg_lamda = params_.spirit_reg_lamda; + double over_determine_ratio = params_.spirit_calib_over_determine_ratio; - GDEBUG_CONDITION_STREAM(this->verbose, "spirit, reg_lamda : " << reg_lamda); - GDEBUG_CONDITION_STREAM(this->verbose, "spirit, over_determine_ratio : " << over_determine_ratio); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit, reg_lamda : " << reg_lamda); + GDEBUG_CONDITION_STREAM(params_.verbose, "spirit, over_determine_ratio : " << over_determine_ratio); long long ii; @@ -349,9 +350,9 @@ namespace Gadgetron { { hoNDArray< std::complex >& kspace = recon_bit.data.data; hoNDArray< std::complex >& res = recon_obj.full_kspace_; - size_t iter_max = this->spirit_iter_max; - double iter_thres = this->spirit_iter_thres; - bool print_iter = this->spirit_print_iter; + size_t iter_max = params_.spirit_iter_max; + double iter_thres = params_.spirit_iter_thres; + bool print_iter = params_.spirit_print_iter; size_t RO_recon_size = 32; // every 32 images were computed together @@ -409,12 +410,12 @@ namespace Gadgetron { std::complex* pKSpace = &(kspace(0, 0, 0, 0, n, s, slc)); hoNDArray< std::complex > kspace3D(RO, E1, E2, srcCHA, pKSpace); - if (this->perform_timing) timer.start("SPIRIT linear 3D, ifft1c along RO ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, ifft1c along RO ... "); Gadgetron::hoNDFFT::instance()->ifft1c(kspace3D, kspaceIfftRO); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kspaceIfftRO, debug_folder_full_path_ + "kspaceIfftRO_" + suffix_3D); } - if (this->perform_timing) timer.start("SPIRIT linear 3D, permute along RO ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, permute along RO ... "); std::complex* pKspaceRO = kspaceIfftRO.begin(); std::complex* pKspacePermutedRO = kspaceIfftROPermuted.begin(); for (scha = 0; scha < srcCHA; scha++) @@ -433,7 +434,7 @@ namespace Gadgetron { } } } - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kspaceIfftROPermuted, debug_folder_full_path_ + "kspaceIfftROPermuted_" + suffix_3D); } // --------------------------------------------------------------------- @@ -477,26 +478,26 @@ namespace Gadgetron { if(num==RO_recon_size) { - if (this->perform_timing) timer.start("SPIRIT linear 3D, image domain kernel along E1 and E2 ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, image domain kernel along E1 and E2 ... "); Gadgetron::spirit3d_image_domain_kernel(kIm3D_recon_ro, E1, E2, kIm); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kIm, debug_folder_full_path_ + "kIm_" + suffix_3D_ro); } - if (this->perform_timing) timer.start("SPIRIT linear 3D, linear unwrapping ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, linear unwrapping ... "); this->perform_spirit_unwrapping(kspace3D_recon_ro, kIm, res_ro_recon); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); } else { - if (this->perform_timing) timer.start("SPIRIT linear 3D, image domain kernel along E1 and E2, last ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, image domain kernel along E1 and E2, last ... "); hoNDArray< std::complex > kIm_last(E1, E2, srcCHA, dstCHA, num); Gadgetron::spirit3d_image_domain_kernel(kIm3D_recon_ro, E1, E2, kIm_last); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kIm_last, debug_folder_full_path_ + "kIm_last_" + suffix_3D_ro); } - if (this->perform_timing) timer.start("SPIRIT linear 3D, linear unwrapping ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, linear unwrapping ... "); this->perform_spirit_unwrapping(kspace3D_recon_ro, kIm_last, res_ro_recon); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); } // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(res_ro_recon, debug_folder_full_path_ + "res_ro_recon_" + suffix_3D_ro); } @@ -523,17 +524,17 @@ namespace Gadgetron { // --------------------------------------------------------------------- // go back to kspace for RO // --------------------------------------------------------------------- - if (this->perform_timing) timer.start("SPIRIT linear 3D, fft along RO for res ... "); + if (this->params_.perform_timing) timer.start("SPIRIT linear 3D, fft along RO for res ... "); Gadgetron::hoNDFFT::instance()->fft1c(res_recon); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(res_recon, debug_folder_full_path_ + "res_recon_" + suffix_3D); } } } else { - if (this->perform_timing) timer.start("SPIRIT 2D, linear unwrapping ... "); + if (this->params_.perform_timing) timer.start("SPIRIT 2D, linear unwrapping ... "); this->perform_spirit_unwrapping(kspace, recon_obj.kernelIm2D_, res); - if (this->perform_timing) timer.stop(); + if (this->params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(res, debug_folder_full_path_ + "res_spirit_2D_" + suffix); } } @@ -542,9 +543,9 @@ namespace Gadgetron { // --------------------------------------------------------------------- // compute coil combined images // --------------------------------------------------------------------- - if (this->perform_timing) timer.start("SPIRIT linear, coil combination ... "); + if (params_.perform_timing) timer.start("SPIRIT linear, coil combination ... "); this->perform_spirit_coil_combine(recon_obj); - if (this->perform_timing) timer.stop(); + if (params_.perform_timing) timer.stop(); // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_obj.recon_res_.data_, debug_folder_full_path_ + "unwrappedIm_" + suffix); } } @@ -614,9 +615,9 @@ namespace Gadgetron { { try { - size_t iter_max = this->spirit_iter_max; - double iter_thres = this->spirit_iter_thres; - bool print_iter = this->spirit_print_iter; + size_t iter_max = params_.spirit_iter_max; + double iter_thres = params_.spirit_iter_thres; + bool print_iter = params_.spirit_print_iter; size_t RO = kspace.get_size(0); size_t E1 = kspace.get_size(1); diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h index 1187c13b..1ada4677 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h @@ -65,20 +65,37 @@ namespace Gadgetron { typedef GenericReconGadget BaseClass; typedef Gadgetron::GenericReconCartesianSpiritObj< std::complex > ReconObjType; - GenericReconCartesianSpiritGadget(const Core::Context& context, const Core::GadgetProperties& properties); - - /// ------------------------------------------------------------------------------------ - /// Spirit parameters - NODE_PROPERTY(spirit_kSize_RO, int, "Spirit kernel size RO", 7); - NODE_PROPERTY(spirit_kSize_E1, int, "Spirit kernel size E1", 7); - NODE_PROPERTY(spirit_kSize_E2, int, "Spirit kernel size E2", 5); - NODE_PROPERTY_NON_CONST(spirit_reg_lamda, double, "Spirit regularization threshold", 0); - NODE_PROPERTY(spirit_calib_over_determine_ratio, double, "Spirit calibration overdermination ratio", 45); - NODE_PROPERTY_NON_CONST(spirit_iter_max, int, "Spirit maximal number of iterations", 0); - NODE_PROPERTY_NON_CONST(spirit_iter_thres, double, "Spirit threshold to stop iteration", 0); - NODE_PROPERTY(spirit_print_iter, bool, "Spirit print out iterations", false); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : Parameters(prefix, "Cartesian SPIRIT") + {} + + Parameters(const std::string& prefix, const std::string& description) + : BaseClass::Parameters(prefix, description) + { + register_parameter("spirit-kSize-RO", &spirit_kSize_RO, "Spirit kernel size RO"); + register_parameter("spirit-kSize-E1", &spirit_kSize_E1, "Spirit kernel size E1"); + register_parameter("spirit-kSize-E2", &spirit_kSize_E2, "Spirit kernel size E2"); + register_parameter("spirit-reg-lamda", &spirit_reg_lamda, "Spirit regularization threshold"); + register_parameter("spirit-calib-over-determine-ratio", &spirit_calib_over_determine_ratio, "Spirit calibration overdermination ratio"); + register_parameter("spirit-iter-max", &spirit_iter_max, "Spirit maximal number of iterations"); + register_parameter("spirit-iter-thres", &spirit_iter_thres, "Spirit threshold to stop iteration"); + register_flag("spirit-print-iter", &spirit_print_iter, "Spirit print out iterations"); + } + + int spirit_kSize_RO = 7; + int spirit_kSize_E1 = 7; + int spirit_kSize_E2 = 5; + double spirit_reg_lamda = 0; + double spirit_calib_over_determine_ratio = 45; + int spirit_iter_max = 0; + double spirit_iter_thres = 0; + bool spirit_print_iter = false; + }; + + GenericReconCartesianSpiritGadget(const Core::MrdContext& context, const Parameters& params); protected: + Parameters params_; // -------------------------------------------------- // variable for recon diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp index fb35e841..45f29d3d 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp @@ -7,8 +7,9 @@ namespace Gadgetron { - GenericReconEigenChannelGadget::GenericReconEigenChannelGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + GenericReconEigenChannelGadget::GenericReconEigenChannelGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -53,7 +54,7 @@ namespace Gadgetron { { for (auto m1 : in) { - if (perform_timing) { gt_timer_.start("GenericReconEigenChannelGadget::process"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconEigenChannelGadget::process"); } process_called_times_++; mrd::ReconData* recon_data = &m1; @@ -89,7 +90,7 @@ namespace Gadgetron { // whether it is needed to update coefficients bool recompute_coeff = false; - if ( (KLT_[e].size()!=SLC) || update_eigen_channel_coefficients ) + if ( (KLT_[e].size()!=SLC) || params_.update_eigen_channel_coefficients ) { recompute_coeff = true; } @@ -119,8 +120,8 @@ namespace Gadgetron { } } - bool average_N = average_all_ref_N; - bool average_S = average_all_ref_S; + bool average_N = params_.average_all_ref_N; + bool average_S = params_.average_all_ref_S; if(recompute_coeff) { @@ -128,13 +129,13 @@ namespace Gadgetron { { // use ref to compute coefficients Gadgetron::compute_eigen_channel_coefficients(rbit.ref->data, average_N, average_S, - (calib_mode_[e] == mrd::CalibrationMode::kInterleaved), N, S, upstream_coil_compression_thres, upstream_coil_compression_num_modesKept, KLT_[e]); + (calib_mode_[e] == mrd::CalibrationMode::kInterleaved), N, S, params_.upstream_coil_compression_thres, params_.upstream_coil_compression_num_modesKept, KLT_[e]); } else { // use data to compute coefficients Gadgetron::compute_eigen_channel_coefficients(data, average_N, average_S, - (calib_mode_[e] == mrd::CalibrationMode::kInterleaved), N, S, upstream_coil_compression_thres, upstream_coil_compression_num_modesKept, KLT_[e]); + (calib_mode_[e] == mrd::CalibrationMode::kInterleaved), N, S, params_.upstream_coil_compression_thres, params_.upstream_coil_compression_num_modesKept, KLT_[e]); } if (verbose) @@ -229,7 +230,7 @@ namespace Gadgetron { } } - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } out.push(std::move(m1)); } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h index f5f66f1a..e2427813 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h @@ -20,35 +20,46 @@ namespace Gadgetron { typedef GenericReconDataBase BaseClass; typedef hoNDKLT< std::complex > KLTType; - GenericReconEigenChannelGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - /// compute KLT coefficients - /// whether to average all N for coefficient computation - /// for the interleaved mode, the sampling times will be counted and used for averaging - NODE_PROPERTY(average_all_ref_N, bool, "Whether to average all N for ref generation", true); - /// whether to average all S for coefficient computation - NODE_PROPERTY(average_all_ref_S, bool, "Whether to average all S for ref generation", false); - - /// if update_eigen_channel_coefficients==true, every incoming ReconData will be used to compute KLT coefficients - /// and the older one will be replaced - /// if update_eigen_channel_coefficients==false, the KLT coefficients will be computed only once for the first incoming ReconData - NODE_PROPERTY(update_eigen_channel_coefficients, bool, "Whether to update KLT coefficients for eigen channel computation", false); - - /// optionally, upstream coil compression can be applied - /// if upstream_coil_compression==true, only kept channels will be sent out to next gadgets and other channels will be removed - /// no matter whether upstream_coil_compression is true or false, all channels will be converted into eigen channel - NODE_PROPERTY(upstream_coil_compression, bool, "Whether to perform upstream coil compression", true); - /// the logic here is that if upstream_coil_compression_num_modesKept>0, only upstream_coil_compression_num_modesKept channels will be kept - /// if upstream_coil_compression_num_modesKept<=0 and upstream_coil_compression_thres>0, this threshold will be used to determine how many channels to keep - /// the first N and first S will be used to compute number of channels to keep - NODE_PROPERTY(upstream_coil_compression_thres, double, "Threadhold for upstream coil compression", -1); - NODE_PROPERTY(upstream_coil_compression_num_modesKept, int, "Number of modes to keep for upstream coil compression", 0); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string &prefix) : BaseClass::Parameters(prefix, "Eigen Channel") + { + register_parameter("average-all-ref-N", &average_all_ref_N, "Whether to average all N for ref generation"); + register_parameter("average-all-ref-S", &average_all_ref_S, "Whether to average all S for ref generation"); + register_parameter("update-eigen-channel-coefficients", &update_eigen_channel_coefficients, "Whether to update KLT coefficients for eigen channel computation"); + register_parameter("upstream-coil-compression", &upstream_coil_compression, "Whether to perform upstream coil compression"); + register_parameter("upstream-coil-compression-thres", &upstream_coil_compression_thres, "Threadhold for upstream coil compression"); + register_parameter("upstream-coil-compression-num-modesKept", &upstream_coil_compression_num_modesKept, "Number of modes to keep for upstream coil compression"); + } + + /// compute KLT coefficients + /// whether to average all N for coefficient computation + /// for the interleaved mode, the sampling times will be counted and used for averaging + bool average_all_ref_N = true; + /// whether to average all S for coefficient computation + bool average_all_ref_S = false; + + /// if update_eigen_channel_coefficients==true, every incoming ReconData will be used to compute KLT coefficients + /// and the older one will be replaced + /// if update_eigen_channel_coefficients==false, the KLT coefficients will be computed only once for the first incoming ReconData + bool update_eigen_channel_coefficients = false; + + /// optionally, upstream coil compression can be applied + /// if upstream_coil_compression==true, only kept channels will be sent out to next gadgets and other channels will be removed + /// no matter whether upstream_coil_compression is true or false, all channels will be converted into eigen channel + bool upstream_coil_compression = true; + /// the logic here is that if upstream_coil_compression_num_modesKept>0, only upstream_coil_compression_num_modesKept channels will be kept + /// if upstream_coil_compression_num_modesKept<=0 and upstream_coil_compression_thres>0, this threshold will be used to determine how many channels to keep + /// the first N and first S will be used to compute number of channels to keep + double upstream_coil_compression_thres = -1; + int upstream_coil_compression_num_modesKept = 0; + + + }; + + GenericReconEigenChannelGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp index f7f1bfdf..2f6b7b4c 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp @@ -15,8 +15,8 @@ static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; namespace Gadgetron { - GenericReconFieldOfViewAdjustmentGadget::GenericReconFieldOfViewAdjustmentGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + GenericReconFieldOfViewAdjustmentGadget::GenericReconFieldOfViewAdjustmentGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) { auto& h = context.header; @@ -63,7 +63,7 @@ namespace Gadgetron { { for (auto m1 : in) { - if (perform_timing) { gt_timer_.start("GenericReconFieldOfViewAdjustmentGadget::process"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconFieldOfViewAdjustmentGadget::process"); } GDEBUG_CONDITION_STREAM(verbose, "GenericReconFieldOfViewAdjustmentGadget::process(...) starts ... "); @@ -99,7 +99,7 @@ namespace Gadgetron { // ---------------------------------------------------------- out.push(std::move(m1)); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } } @@ -278,6 +278,7 @@ namespace Gadgetron { GenericReconFieldOfViewAdjustmentGadget::~GenericReconFieldOfViewAdjustmentGadget() { + /** TODO: This is unnecessary, just make GenericReconMrdStreamer close the buffers in its own destructor... */ this->gt_streamer_.close_stream_buffer(); } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h index f89cea3c..21cf16ff 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h @@ -18,7 +18,13 @@ namespace Gadgetron { public: typedef GenericReconImageArrayBase BaseClass; - GenericReconFieldOfViewAdjustmentGadget(const Core::Context &context, const Core::GadgetProperties &properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) + : BaseClass::Parameters(prefix, "Field Of View Adjustment") + {} + }; + + GenericReconFieldOfViewAdjustmentGadget(const Core::MrdContext &context, const Parameters& params); ~GenericReconFieldOfViewAdjustmentGadget() override; protected: diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp index fa317256..88b836fe 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp @@ -5,8 +5,9 @@ namespace Gadgetron { - GenericReconGadget::GenericReconGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + GenericReconGadget::GenericReconGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -17,7 +18,7 @@ namespace Gadgetron { this->initialize_encoding_space_limits(h); // ------------------------------------------------- - GDEBUG_CONDITION_STREAM(verbose, "Number of encoding spaces: " << num_encoding_spaces_); + GDEBUG_CONDITION_STREAM(params_.verbose, "Number of encoding spaces: " << num_encoding_spaces_); acceFactorE1_.resize(num_encoding_spaces_, 1); acceFactorE2_.resize(num_encoding_spaces_, 1); @@ -39,8 +40,8 @@ namespace Gadgetron { acceFactorE1_[e] = p_imaging.acceleration_factor.kspace_encoding_step_1; acceFactorE2_[e] = p_imaging.acceleration_factor.kspace_encoding_step_2; - GDEBUG_CONDITION_STREAM(verbose, "acceFactorE1 is " << acceFactorE1_[e]); - GDEBUG_CONDITION_STREAM(verbose, "acceFactorE2 is " << acceFactorE2_[e]); + GDEBUG_CONDITION_STREAM(params_.verbose, "acceFactorE1 is " << acceFactorE1_[e]); + GDEBUG_CONDITION_STREAM(params_.verbose, "acceFactorE2 is " << acceFactorE2_[e]); calib_mode_[e] = mrd::CalibrationMode::kNoacceleration; if (acceFactorE1_[e] > 1 || acceFactorE2_[e] > 1) { @@ -72,13 +73,13 @@ namespace Gadgetron { if (!h.measurement_information) { - GDEBUG("measurementInformation not found in header"); + GDEBUG_STREAM("measurementInformation not found in header"); } else { if (!h.measurement_information->protocol_name) { - GDEBUG("measurementInformation->protocolName not found in header"); + GDEBUG_STREAM("measurementInformation->protocolName not found in header"); } else { @@ -147,9 +148,9 @@ namespace Gadgetron { os << "_encoding_" << e; GDEBUG_CONDITION_STREAM( - verbose, "Calling " << process_called_times_ << " , encoding space : " << e); + params_.verbose, "Calling " << process_called_times_ << " , encoding space : " << e); GDEBUG_CONDITION_STREAM( - verbose, "======================================================================"); + params_.verbose, "======================================================================"); // --------------------------------------------------------------- // export incoming data @@ -393,17 +394,17 @@ namespace Gadgetron { complex_im_recon_buf_, debug_folder_full_path_ + "complex_im_for_coil_map_" + os.str()); } - if (coil_map_algorithm == "Inati") { - size_t ks = this->coil_map_kernel_size_readout; - size_t kz = this->coil_map_kernel_size_phase; + if (params_.coil_map_algorithm == "Inati") { + size_t ks = this->params_.coil_map_kernel_size_readout; + size_t kz = this->params_.coil_map_kernel_size_phase; size_t power = 3; Gadgetron::coil_map_Inati(complex_im_recon_buf_, coil_map, ks, kz, power); } else { - size_t ks = this->coil_map_kernel_size_readout; - size_t kz = this->coil_map_kernel_size_phase; - size_t iterNum = this->coil_map_num_iter; - float thres = this->coil_map_thres_iter; + size_t ks = this->params_.coil_map_kernel_size_readout; + size_t kz = this->params_.coil_map_kernel_size_phase; + size_t iterNum = this->params_.coil_map_num_iter; + float thres = this->params_.coil_map_thres_iter; Gadgetron::coil_map_Inati_Iter(complex_im_recon_buf_, coil_map, ks, kz, iterNum, thres); } @@ -642,18 +643,18 @@ namespace Gadgetron { if ((start_RO < RO) && (end_RO < RO) && (end_RO - start_RO + 1 < RO)) { lenRO = (end_RO - start_RO + 1); } - if (this->verbose) + if (this->params_.verbose) GDEBUG_STREAM("length for RO : " << lenRO << " - " << lenRO / RO); effective_acce_factor = (float)(S * N * E1 * E2) / (num_readout_lines); - if (this->verbose) + if (this->params_.verbose) GDEBUG_STREAM("effective_acce_factor : " << effective_acce_factor); float ROScalingFactor = (float)RO / (float)lenRO; snr_scaling_ratio = (float)(std::sqrt(ROScalingFactor * effective_acce_factor)); - if (this->verbose) + if (this->params_.verbose) GDEBUG_STREAM("snr_scaling_ratio : " << snr_scaling_ratio); } else { GWARN_STREAM("Cannot find any sampled lines ... "); diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h index 9e9e64fd..a31d880b 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h @@ -21,24 +21,29 @@ namespace Gadgetron { public: typedef GenericReconDataBase BaseClass; - GenericReconGadget(const Core::Context& context, const Core::GadgetProperties& properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - /// image series - NODE_PROPERTY(image_series, int, "Image series number", 0); - - /// coil map estimation method - NODE_PROPERTY(coil_map_algorithm, std::string, "Method for coil map estimation (Inati, Inati_Iter)", "Inati"); - - NODE_PROPERTY(coil_map_kernel_size_readout, size_t, "Coil map estimation, kernel size along read out", 7); - NODE_PROPERTY(coil_map_kernel_size_phase, size_t, "Coil map estimation, kernel size along phase/slice encoding", 5); - NODE_PROPERTY(coil_map_num_iter, size_t, "Coil map estimation, number of iterations", 10); - NODE_PROPERTY(coil_map_thres_iter, double, "Coil map estimation, threshold to stop iteration", 1e-4); + struct Parameters : BaseClass::Parameters { + Parameters(const std::string& prefix, const std::string& description) + : BaseClass::Parameters(prefix, description) + { + register_parameter("image-series", &image_series, "Image series number"); + register_parameter("coil-map-algorithm", &coil_map_algorithm, "Method for coil map estimation (Inati, Inati_Iter)"); + register_parameter("coil-map-kernel-size-readout", &coil_map_kernel_size_readout, "Coil map estimation, kernel size along read out"); + register_parameter("coil-map-kernel-size-phase", &coil_map_kernel_size_phase, "Coil map estimation, kernel size along phase/slice encoding"); + register_parameter("coil-map-num-iter", &coil_map_num_iter, "Coil map estimation, number of iterations"); + register_parameter("coil-map-thres-iter", &coil_map_thres_iter, "Coil map estimation, threshold to stop iteration"); + } + int image_series = 0; + std::string coil_map_algorithm = "Inati"; + size_t coil_map_kernel_size_readout = 7; + size_t coil_map_kernel_size_phase = 5; + size_t coil_map_num_iter = 10; + double coil_map_thres_iter = 1e-4; + }; + + GenericReconGadget(const Core::MrdContext& context, const Parameters& params); protected: + const Parameters params_; void send_out_image_array(mrd::ImageArray& res, size_t encoding, int series_num, const std::string& data_role, Core::OutputChannel& out); // -------------------------------------------------- diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp index 5952fd1b..23bedfd7 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp @@ -14,8 +14,9 @@ static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; namespace Gadgetron { - GenericReconImageArrayScalingGadget::GenericReconImageArrayScalingGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + GenericReconImageArrayScalingGadget::GenericReconImageArrayScalingGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -24,18 +25,18 @@ namespace Gadgetron { // resize the scaling_factor_ vector and set to negative scaling_factor_.resize(num_encoding_spaces_, -1); - if (use_constant_scalingFactor) + if (params_.use_constant_scalingFactor) { - float v = scalingFactor; + float v = params_.scalingFactor; if (v > 0) { for (size_t e = 0; e < num_encoding_spaces_; e++) - scaling_factor_[e] = scalingFactor; + scaling_factor_[e] = params_.scalingFactor; } else { - use_constant_scalingFactor = false; + params_.use_constant_scalingFactor = false; } } } @@ -43,7 +44,7 @@ namespace Gadgetron { void GenericReconImageArrayScalingGadget::process(Core::InputChannel< mrd::ImageArray >& in, Core::OutputChannel& out) { for (auto m1: in) { - if (perform_timing) { gt_timer_.start("GenericReconImageArrayScalingGadget::process"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconImageArrayScalingGadget::process"); } GDEBUG_CONDITION_STREAM(verbose, "GenericReconImageArrayScalingGadget::process(...) starts ... "); @@ -66,50 +67,50 @@ namespace Gadgetron { // snr map if (dataRole == GADGETRON_IMAGE_SNR_MAP) { - scale_factor = this->scalingFactor_snr_map; + scale_factor = this->params_.scalingFactor_snr_map; Gadgetron::scal((real_value_type)(scale_factor), recon_res_->data); std::ostringstream ostr_image; - ostr_image << "x" << std::setprecision(4) << this->scalingFactor_snr_map; + ostr_image << "x" << std::setprecision(4) << this->params_.scalingFactor_snr_map; imageInfo = ostr_image.str(); } // gfactor else if (dataRole == GADGETRON_IMAGE_GFACTOR) { - scale_factor = this->scalingFactor_gfactor_map; + scale_factor = this->params_.scalingFactor_gfactor_map; Gadgetron::scal((real_value_type)(scale_factor), recon_res_->data); std::ostringstream ostr_image; - ostr_image << "x" << std::setprecision(4) << this->scalingFactor_gfactor_map; + ostr_image << "x" << std::setprecision(4) << this->params_.scalingFactor_gfactor_map; imageInfo = ostr_image.str(); } // snr std map else if (dataRole == GADGETRON_IMAGE_STD_MAP) { - scale_factor = this->scalingFactor_snr_std_map; + scale_factor = this->params_.scalingFactor_snr_std_map; Gadgetron::scal((real_value_type)(scale_factor), recon_res_->data); std::ostringstream ostr_image; - ostr_image << "x" << std::setprecision(4) << this->scalingFactor_snr_std_map; + ostr_image << "x" << std::setprecision(4) << this->params_.scalingFactor_snr_std_map; imageInfo = ostr_image.str(); } // if the config file asks to use the specified scaling factor - else if (recon_res_->meta[0].count(use_dedicated_scalingFactor_meta_field) - && recon_res_->meta[0][use_dedicated_scalingFactor_meta_field].size() > 0) + else if (recon_res_->meta[0].count(params_.use_dedicated_scalingFactor_meta_field) + && recon_res_->meta[0][params_.use_dedicated_scalingFactor_meta_field].size() > 0) { - scale_factor = this->scalingFactor_dedicated; + scale_factor = this->params_.scalingFactor_dedicated; Gadgetron::scal((real_value_type)(scale_factor), recon_res_->data); std::ostringstream ostr_image; - ostr_image << "x" << std::setprecision(4) << this->scalingFactor_dedicated; + ostr_image << "x" << std::setprecision(4) << this->params_.scalingFactor_dedicated; imageInfo = ostr_image.str(); } else { // compute scaling factor from image and apply it - if (perform_timing) { gt_timer_.start("compute_and_apply_scaling_factor"); } + if (params_.perform_timing) { gt_timer_.start("compute_and_apply_scaling_factor"); } this->compute_and_apply_scaling_factor(*recon_res_, encoding); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } scale_factor = this->scaling_factor_[encoding]; @@ -132,7 +133,7 @@ namespace Gadgetron { out.push(std::move(m1)); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } } @@ -141,7 +142,7 @@ namespace Gadgetron { // if the scaling factor for this encoding space has not been set yet (it was initialized negative), // compute it. If it has already been set (therefore, it will be positive), only compute again if // the auto-scaling factor is to be computed for every incoming image array - if ((scaling_factor_[encoding]<0 || !auto_scaling_only_once) && !use_constant_scalingFactor) + if ((scaling_factor_[encoding]<0 || !params_.auto_scaling_only_once) && !params_.use_constant_scalingFactor) { hoNDArray mag; GADGET_CHECK_EXCEPTION_RETURN(Gadgetron::abs(res.data, mag), GADGET_FAIL); @@ -168,7 +169,7 @@ namespace Gadgetron { if ( maxInten < FLT_EPSILON ) maxInten = 1.0f; // if the maximum image intensity is too small or too large - if ( (maxIntenmax_intensity_value) ) + if ( (maxIntenparams_.max_intensity_value) ) { GDEBUG_CONDITION_STREAM(verbose, "Using the dynamic intensity scaling factor - may not have noise prewhitening performed ... "); // scale the image (so that the maximum image intensity is the default one) @@ -181,17 +182,17 @@ namespace Gadgetron { // starting with the fixed intensity scaling factor, check if the image will // be clipped and, if so, try halving it (up to a minimum) scaling_factor_[encoding] = GENERICRECON_DEFAULT_INTENSITY_SCALING_FACTOR; - while ((maxInten*scaling_factor_[encoding] > max_intensity_value) && (scaling_factor_[encoding] >= 2)) + while ((maxInten*scaling_factor_[encoding] > params_.max_intensity_value) && (scaling_factor_[encoding] >= 2)) { scaling_factor_[encoding] /= 2; } // if even at the minimum we are still clipping, issue a warning and // calculate a scaling factor to cover the whole dynamic range - if (maxInten*scaling_factor_[encoding] > max_intensity_value) + if (maxInten*scaling_factor_[encoding] > params_.max_intensity_value) { GDEBUG_CONDITION_STREAM(verbose, "The fixed intensity scaling factor leads to dynamic range overflow - switch to dynamic intensity scaling ... "); - scaling_factor_[encoding] = (float)(max_intensity_value) / maxInten; + scaling_factor_[encoding] = (float)(params_.max_intensity_value) / maxInten; } } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h index c7535dfd..2bcaa92f 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h @@ -22,25 +22,39 @@ namespace Gadgetron { typedef GenericReconImageArrayBase BaseClass; - GenericReconImageArrayScalingGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - /// image scaling - NODE_PROPERTY_NON_CONST(use_constant_scalingFactor, bool, "Whether to use constraint scaling; if not, the auto-scaling factor will be computed only ONCE", true); - NODE_PROPERTY(scalingFactor, float, "Default scaling ratio", 4.0); - NODE_PROPERTY(min_intensity_value, int, "Minimal intensity value for auto image scaling", 64); - NODE_PROPERTY(max_intensity_value, int, "Maximal intensity value for auto image scaling", 4095); - NODE_PROPERTY(auto_scaling_only_once, bool, "Whether to compute auto-scaling factor only once; if false, an auto-scaling factor is computed for every incoming image array", true); - - NODE_PROPERTY(use_dedicated_scalingFactor_meta_field, std::string, "If this meta field exists, scale the images with the dedicated scaling factor", "Use_dedicated_scaling_factor"); - NODE_PROPERTY(scalingFactor_dedicated, float, "Dedicated scaling ratio", 100.0); - NODE_PROPERTY(scalingFactor_gfactor_map, float, "Scaling ratio for gfactor map", 100.0); - NODE_PROPERTY(scalingFactor_snr_map, float, "Scaling ratio for snr map", 10.0); - NODE_PROPERTY(scalingFactor_snr_std_map, float, "Scaling ratio for snr standard deviation map", 1000.0); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Image Array Scaling") + { + register_parameter("use-constant-scalingFactor", &use_constant_scalingFactor, "Whether to use constraint scaling; if not, the auto-scaling factor will be computed only ONCE"); + register_parameter("scalingFactor", &scalingFactor, "Default scaling ratio"); + register_parameter("min-intensity-value", &min_intensity_value, "Minimal intensity value for auto image scaling"); + register_parameter("max-intensity-value", &max_intensity_value, "Maximal intensity value for auto image scaling"); + register_parameter("auto-scaling-only-once", &auto_scaling_only_once, "Whether to compute auto-scaling factor only once; if false, an auto-scaling factor is computed for every incoming image array"); + + register_parameter("use-dedicated-scalingFactor-meta-field", &use_dedicated_scalingFactor_meta_field, "If this meta field exists, scale the images with the dedicated scaling factor"); + register_parameter("scalingFactor-dedicated", &scalingFactor_dedicated, "Dedicated scaling ratio"); + register_parameter("scalingFactor-gfactor-map", &scalingFactor_gfactor_map, "Scaling ratio for gfactor map"); + register_parameter("scalingFactor-snr-map", &scalingFactor_snr_map, "Scaling ratio for snr map"); + register_parameter("scalingFactor-snr-std-map", &scalingFactor_snr_std_map, "Scaling ratio for snr standard deviation map"); + } + + bool use_constant_scalingFactor = true; + float scalingFactor = 4.0; + int min_intensity_value = 64; + int max_intensity_value = 4095; + bool auto_scaling_only_once = true; + + std::string use_dedicated_scalingFactor_meta_field = "Use_dedicated_scaling_factor"; + float scalingFactor_dedicated = 100.0; + float scalingFactor_gfactor_map = 100.0; + float scalingFactor_snr_map = 10.0; + float scalingFactor_snr_std_map = 1000.0; + }; + + GenericReconImageArrayScalingGadget(const Core::MrdContext &context, const Parameters& params); protected: + Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp index c130772d..7fee8c29 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp @@ -12,8 +12,9 @@ namespace Gadgetron { - GenericReconKSpaceFilteringGadget::GenericReconKSpaceFilteringGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + GenericReconKSpaceFilteringGadget::GenericReconKSpaceFilteringGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -57,7 +58,7 @@ namespace Gadgetron { { for (auto m1 : in) { - if (perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget::process"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget::process"); } GDEBUG_CONDITION_STREAM(verbose, "GenericReconKSpaceFilteringGadget::process(...) starts ... "); @@ -75,7 +76,7 @@ namespace Gadgetron { } // some images do not need kspace filter - if (recon_res_->meta[0].count(skip_processing_meta_field) && recon_res_->meta[0][skip_processing_meta_field].size() > 0) + if (recon_res_->meta[0].count(params_.skip_processing_meta_field) && recon_res_->meta[0][params_.skip_processing_meta_field].size() > 0) { GDEBUG_CONDITION_STREAM(verbose, "Skip kspace filtering for this image array ... "); @@ -155,21 +156,21 @@ namespace Gadgetron { { if (sampling_limits.kspace_encoding_step_0.minimum == 0 || sampling_limits.kspace_encoding_step_0.maximum == RO - 1) { - if (filterRO != "None") + if (params_.filterRO != "None") { filter_RO_[encoding].create(RO); - Gadgetron::generate_symmetric_filter(RO, filter_RO_[encoding], Gadgetron::get_kspace_filter_type(filterRO), filterRO_sigma, (size_t)std::ceil(filterRO_width*RO)); + Gadgetron::generate_symmetric_filter(RO, filter_RO_[encoding], Gadgetron::get_kspace_filter_type(params_.filterRO), params_.filterRO_sigma, (size_t)std::ceil(params_.filterRO_width*RO)); } } else { - if (filterRO != "None") + if (params_.filterRO != "None") { size_t len; this->find_kspace_sampled_range(sampling_limits.kspace_encoding_step_0.minimum, sampling_limits.kspace_encoding_step_0.maximum, RO, len); hoNDArray< std::complex > f; - Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterRO), filterRO_sigma, (size_t)std::ceil(filterRO_width*len)); + Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(params_.filterRO), params_.filterRO_sigma, (size_t)std::ceil(params_.filterRO_width*len)); Gadgetron::pad(RO, f, filter_RO_[encoding]); } } @@ -200,21 +201,21 @@ namespace Gadgetron { { if (sampling_limits.kspace_encoding_step_1.minimum == 0 || sampling_limits.kspace_encoding_step_1.maximum == E1 - 1) { - if (filterE1 != "None") + if (params_.filterE1 != "None") { filter_E1_[encoding].create(E1); - Gadgetron::generate_symmetric_filter(E1, filter_E1_[encoding], Gadgetron::get_kspace_filter_type(filterE1), filterE1_sigma, (size_t)std::ceil(filterE1_width*E1)); + Gadgetron::generate_symmetric_filter(E1, filter_E1_[encoding], Gadgetron::get_kspace_filter_type(params_.filterE1), params_.filterE1_sigma, (size_t)std::ceil(params_.filterE1_width*E1)); } } else { - if (filterE1 != "None") + if (params_.filterE1 != "None") { size_t len; this->find_kspace_sampled_range(sampling_limits.kspace_encoding_step_1.minimum, sampling_limits.kspace_encoding_step_1.maximum, E1, len); hoNDArray< std::complex > f; - Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterE1), filterE1_sigma, (size_t)std::ceil(filterE1_width*len)); + Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(params_.filterE1), params_.filterE1_sigma, (size_t)std::ceil(params_.filterE1_width*len)); Gadgetron::pad(E1, f, filter_E1_[encoding]); } } @@ -245,21 +246,21 @@ namespace Gadgetron { { if (sampling_limits.kspace_encoding_step_2.minimum == 0 || sampling_limits.kspace_encoding_step_2.maximum == E1 - 1) { - if (filterE2 != "None") + if (params_.filterE2 != "None") { filter_E2_[encoding].create(E2); - Gadgetron::generate_symmetric_filter(E2, filter_E2_[encoding], Gadgetron::get_kspace_filter_type(filterE2), filterE2_sigma, (size_t)std::ceil(filterE2_width*E2)); + Gadgetron::generate_symmetric_filter(E2, filter_E2_[encoding], Gadgetron::get_kspace_filter_type(params_.filterE2), params_.filterE2_sigma, (size_t)std::ceil(params_.filterE2_width*E2)); } } else { - if (filterE2 != "None") + if (params_.filterE2 != "None") { size_t len; this->find_kspace_sampled_range(sampling_limits.kspace_encoding_step_2.minimum, sampling_limits.kspace_encoding_step_2.maximum, E2, len); hoNDArray< std::complex > f; - Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(filterE2), filterE2_sigma, (size_t)std::ceil(filterE2_width*len)); + Gadgetron::generate_symmetric_filter(len, f, Gadgetron::get_kspace_filter_type(params_.filterE2), params_.filterE2_sigma, (size_t)std::ceil(params_.filterE2_width*len)); Gadgetron::pad(E2, f, filter_E2_[encoding]); } } @@ -298,7 +299,7 @@ namespace Gadgetron { // ---------------------------------------------------------- if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(recon_res_->data, debug_folder_full_path_ + "image_before_filtering_" + str); } - if (perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget: fftc"); } + if (params_.perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget: fftc"); } if (E2 > 1) { Gadgetron::hoNDFFT::instance()->fft3c(recon_res_->data, kspace_buf_); @@ -307,7 +308,7 @@ namespace Gadgetron { { Gadgetron::hoNDFFT::instance()->fft2c(recon_res_->data, kspace_buf_); } - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(kspace_buf_, debug_folder_full_path_ + "kspace_before_filtering_" + str); } @@ -321,18 +322,18 @@ namespace Gadgetron { && (filter_E1_[encoding].get_number_of_elements() == E1) && (E2>1) && (filter_E2_[encoding].get_number_of_elements() == E2) ) { - if (perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1E2 ... "); } + if (params_.perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1E2 ... "); } Gadgetron::apply_kspace_filter_ROE1E2(kspace_buf_, filter_RO_[encoding], filter_E1_[encoding], filter_E2_[encoding], filter_res_); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(filter_res_, debug_folder_full_path_ + "kspace_after_filtered_" + str); } inKSpace = true; } else if ( (filter_RO_[encoding].get_number_of_elements() == RO) && (filter_E1_[encoding].get_number_of_elements() == E1) ) { - if (perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1 ... "); } + if (params_.perform_timing) { gt_timer_.start("GenericReconKSpaceFilteringGadget, apply_kspace_filter_ROE1 ... "); } Gadgetron::apply_kspace_filter_ROE1(kspace_buf_, filter_RO_[encoding], filter_E1_[encoding], filter_res_); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(filter_res_, debug_folder_full_path_ + "kspace_after_filtered_" + str); } @@ -403,7 +404,7 @@ namespace Gadgetron { // ---------------------------------------------------------- out.push(std::move(m1)); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h index ad787dc8..a41e3482 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h @@ -23,37 +23,40 @@ namespace Gadgetron { public: typedef GenericReconImageArrayBase BaseClass; - GenericReconKSpaceFilteringGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - NODE_PROPERTY(skip_processing_meta_field, std::string, "If this meta field exists, pass the incoming image array to next gadget without processing", "Skip_processing_after_recon"); - - /// ------------------------------------------------------------------------------------ - /// kspace filter parameters - NODE_PROPERTY(filterRO, std::string, "Kspace filter for RO dimension (Gaussian, Hanning, TaperedHanning, None)", "Gaussian"); - - NODE_PROPERTY(filterRO_sigma, double, "Filter sigma for gaussian for RO dimension", 1.0); - NODE_PROPERTY(filterRO_width, double, "Filter width for tapered hanning for RO dimension", 0.15); - - // ------------------------------------------------------------------------------------ - - NODE_PROPERTY(filterE1, std::string, "Kspace filter for E1 dimension (Gaussian, Hanning, TaperedHanning, None)", "Gaussian"); - - NODE_PROPERTY(filterE1_sigma, double, "Filter sigma for gaussian for E1 dimension", 1.0); - NODE_PROPERTY(filterE1_width, double, "Filter width for tapered hanning for E1 dimension", 0.15); - - // ------------------------------------------------------------------------------------ - - NODE_PROPERTY(filterE2, std::string, "Kspace filter for E2 dimension (Gaussian, Hanning, TaperedHanning, None)", "Gaussian"); - - NODE_PROPERTY(filterE2_sigma, double, "Filter sigma for gaussian for E2 dimension", 1.0); - NODE_PROPERTY(filterE2_width, double, "Filter width for tapered hanning for E2 dimension", 0.15); - - // ------------------------------------------------------------------------------------ + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "KSpace Filtering") + { + register_parameter("skip-processing-meta-field", &skip_processing_meta_field, "If this meta field exists, pass the incoming image array to next gadget without processing"); + register_parameter("filterRO", &filterRO, "Kspace filter for RO dimension (Gaussian, Hanning, TaperedHanning, None)"); + register_parameter("filterRO-sigma", &filterRO_sigma, "Filter sigma for gaussian for RO dimension"); + register_parameter("filterRO-width", &filterRO_width, "Filter width for tapered hanning for RO dimension"); + register_parameter("filterE1", &filterE1, "Kspace filter for E1 dimension (Gaussian, Hanning, TaperedHanning, None)"); + register_parameter("filterE1-sigma", &filterE1_sigma, "Filter sigma for gaussian for E1 dimension"); + register_parameter("filterE1-width", &filterE1_width, "Filter width for tapered hanning for E1 dimension"); + register_parameter("filterE2", &filterE2, "Kspace filter for E2 dimension (Gaussian, Hanning, TaperedHanning, None)"); + register_parameter("filterE2-sigma", &filterE2_sigma, "Filter sigma for gaussian for E2 dimension"); + register_parameter("filterE2-width", &filterE2_width, "Filter width for tapered hanning for E2 dimension"); + } + + std::string skip_processing_meta_field = "Skip_processing_after_recon"; + + std::string filterRO = "Gaussian"; + double filterRO_sigma = 1.0; + double filterRO_width = 0.15; + + std::string filterE1 = "Gaussian"; + double filterE1_sigma = 1.0; + double filterE1_width = 0.15; + + std::string filterE2 = "Gaussian"; + double filterE2_sigma = 1.0; + double filterE2_width = 0.15; + }; + + GenericReconKSpaceFilteringGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp index b121fe4c..a662061b 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp @@ -11,8 +11,9 @@ namespace Gadgetron { - GenericReconNoiseStdMapComputingGadget::GenericReconNoiseStdMapComputingGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + GenericReconNoiseStdMapComputingGadget::GenericReconNoiseStdMapComputingGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -64,9 +65,9 @@ namespace Gadgetron { size_t SLC = recon_res_->data.get_size(6); // perform std map computation - if (N < start_N_for_std_map) + if (N < params_.start_N_for_std_map) { - GWARN_STREAM("GenericReconNoiseStdMapComputingGadget, N < start_N_for_std_map - " << N << " - " << start_N_for_std_map); + GWARN_STREAM("GenericReconNoiseStdMapComputingGadget, N < start_N_for_std_map - " << N << " - " << params_.start_N_for_std_map); continue; } @@ -83,7 +84,7 @@ namespace Gadgetron { } // compute std map - size_t startN = start_N_for_std_map; + size_t startN = params_.start_N_for_std_map; hoNDArray repBuf(RO, E1, E2, CHA, N - startN); hoNDArray repBufMag(RO, E1, E2, CHA, N - startN); diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h index 290a6495..3c225fda 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h @@ -21,19 +21,18 @@ namespace Gadgetron { typedef GenericReconImageArrayBase BaseClass; - GenericReconNoiseStdMapComputingGadget(const Core::Context& context, const Core::GadgetProperties& properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Computed Noise Std Map") + { + register_parameter("start_N_for_std_map", &start_N_for_std_map, "Start N index to compute std map"); + } - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - /// ------------------------------------------------------------------------------------ - /// start N index to compute std map - NODE_PROPERTY(start_N_for_std_map, int, "Start N index to compute std map", 5); - - // ------------------------------------------------------------------------------------ + int start_N_for_std_map = 5; + }; + GenericReconNoiseStdMapComputingGadget(const Core::MrdContext& context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // functional functions diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp index b53aa122..8082f2eb 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp @@ -14,7 +14,7 @@ namespace Gadgetron { { std::optional gt_timer; - if (perform_timing) { gt_timer = GadgetronTimer("GenericReconPartialFourierHandlingFilterGadget, partial_fourier_filter"); } + if (params_.perform_timing) { gt_timer = GadgetronTimer("GenericReconPartialFourierHandlingFilterGadget, partial_fourier_filter"); } std::lock_guard guard(filter_mutex); @@ -23,8 +23,8 @@ namespace Gadgetron { Gadgetron::partial_fourier_filter(kspace_buf, start_RO, end_RO, start_E1, end_E1, start_E2, end_E2, - partial_fourier_filter_RO_width, partial_fourier_filter_E1_width, - partial_fourier_filter_E2_width, partial_fourier_filter_densityComp, + params_.partial_fourier_filter_RO_width, params_.partial_fourier_filter_E1_width, + params_.partial_fourier_filter_E2_width, params_.partial_fourier_filter_densityComp, filter_pf_RO_, filter_pf_E1_, filter_pf_E2_, pf_res); return pf_res; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h index f3092e73..9c5a4c70 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h @@ -12,32 +12,37 @@ namespace Gadgetron { class GenericReconPartialFourierHandlingFilterGadget : public GenericReconPartialFourierHandlingGadget { public: - typedef float real_value_type; typedef std::complex ValueType; typedef ValueType T; typedef GenericReconPartialFourierHandlingGadget BaseClass; - using GenericReconPartialFourierHandlingGadget::GenericReconPartialFourierHandlingGadget; - - ~GenericReconPartialFourierHandlingFilterGadget() override =default; + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Partial Fourier Handling Filter") { + register_parameter("partial-fourier-filter-RO-width", &partial_fourier_filter_RO_width, "Partial fourier filter width for tapered hanning for RO dimension"); + register_parameter("partial-fourier-filter-E1-width", &partial_fourier_filter_E1_width, "Partial fourier filter width for tapered hanning for E1 dimension"); + register_parameter("partial-fourier-filter-E2-width", &partial_fourier_filter_E2_width, "Partial fourier filter width for tapered hanning for E2 dimension"); - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ + register_parameter("partial-fourier-filter-densityComp", &partial_fourier_filter_densityComp, "Whether to apply density compensation for RO dimension"); + } - // ------------------------------------------------------------------------------------ + double partial_fourier_filter_RO_width = 0.15; + double partial_fourier_filter_E1_width = 0.15; + double partial_fourier_filter_E2_width = 0.15; - NODE_PROPERTY(partial_fourier_filter_RO_width, double, "Partial fourier filter width for tapered hanning for RO dimension", 0.15); - NODE_PROPERTY(partial_fourier_filter_E1_width, double, "Partial fourier filter width for tapered hanning for E1 dimension", 0.15); - NODE_PROPERTY(partial_fourier_filter_E2_width, double, "Partial fourier filter width for tapered hanning for E2 dimension", 0.15); + bool partial_fourier_filter_densityComp = false; + }; - NODE_PROPERTY(partial_fourier_filter_densityComp, bool, "Whether to apply density compensation for RO dimension", false); + GenericReconPartialFourierHandlingFilterGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) + {} - // ------------------------------------------------------------------------------------ + ~GenericReconPartialFourierHandlingFilterGadget() override =default; protected: + const Parameters params_; // partial fourier filters, avoid recomputing. Must be mutable and locked to respect PureGadgets promise of being thread safe diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp index 24d11c4c..143aae7e 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp @@ -10,13 +10,15 @@ namespace Gadgetron { GenericReconPartialFourierHandlingGadget::GenericReconPartialFourierHandlingGadget( - const Core::Context& context, const Core::GadgetProperties& props) : BaseClass(context,props) + const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { const auto& h = context.header; num_encoding_spaces = h.encoding.size(); - GDEBUG_CONDITION_STREAM(verbose, "Number of encoding spaces: " << num_encoding_spaces); + GDEBUG_CONDITION_STREAM(params_.verbose, "Number of encoding spaces: " << num_encoding_spaces); acceFactorE1_.resize(num_encoding_spaces, 1); acceFactorE2_.resize(num_encoding_spaces, 1); @@ -32,22 +34,22 @@ namespace Gadgetron { acceFactorE1_[e] = p_imaging.acceleration_factor.kspace_encoding_step_1; acceFactorE2_[e] = p_imaging.acceleration_factor.kspace_encoding_step_2; - GDEBUG_CONDITION_STREAM(verbose, "acceFactorE1 is " << acceFactorE1_[e]); - GDEBUG_CONDITION_STREAM(verbose, "acceFactorE2 is " << acceFactorE2_[e]); + GDEBUG_CONDITION_STREAM(params_.verbose, "acceFactorE1 is " << acceFactorE1_[e]); + GDEBUG_CONDITION_STREAM(params_.verbose, "acceFactorE2 is " << acceFactorE2_[e]); } } } mrd::ImageArray GenericReconPartialFourierHandlingGadget::process_function(mrd::ImageArray recon_res) const { std::optional gt_timer; - if (perform_timing) { + if (params_.perform_timing) { gt_timer = GadgetronTimer("GenericReconPartialFourierHandlingGadget::process"); } - GDEBUG_CONDITION_STREAM(verbose, "GenericReconPartialFourierHandlingGadget::process(...) starts ... "); + GDEBUG_CONDITION_STREAM(params_.verbose, "GenericReconPartialFourierHandlingGadget::process(...) starts ... "); // some images do not need partial fourier handling processing - if (recon_res.meta[0].count(skip_processing_meta_field) && recon_res.meta[0][skip_processing_meta_field].size() > 0) { + if (recon_res.meta[0].count(params_.skip_processing_meta_field) && recon_res.meta[0][params_.skip_processing_meta_field].size() > 0) { return std::move(recon_res); } @@ -147,7 +149,7 @@ namespace Gadgetron { long lenE2 = endE2_ - startE2_ + 1; if (lenRO == RO && lenE1 == E1 && lenE2 == E2) { - GDEBUG_CONDITION_STREAM(verbose, "lenRO == RO && lenE1 == E1 && lenE2 == E2"); + GDEBUG_CONDITION_STREAM(params_.verbose, "lenRO == RO && lenE1 == E1 && lenE2 == E2"); return recon_res; } @@ -176,7 +178,7 @@ namespace Gadgetron { Gadgetron::hoNDFFT::Type>::instance()->ifft2c(pf_res, recon_res.data); } - GDEBUG_CONDITION_STREAM(verbose, "GenericReconPartialFourierHandlingGadget::process(...) ends ... "); + GDEBUG_CONDITION_STREAM(params_.verbose, "GenericReconPartialFourierHandlingGadget::process(...) ends ... "); return std::move(recon_res); } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h index 20e4c511..7da0e126 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h @@ -24,28 +24,35 @@ namespace Gadgetron { -class GenericReconPartialFourierHandlingGadget : public Core::PureGadget +class GenericReconPartialFourierHandlingGadget : public Core::MRPureGadget { public: - typedef float real_value_type; typedef std::complex ValueType; typedef ValueType T; - using BaseClass = Core::PureGadget; + using BaseClass = Core::MRPureGadget; + + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix, const std::string& description) : NodeParameters(prefix, description) { + register_parameter("verbose", &verbose, "Verbose"); + register_parameter("perform-timing", &perform_timing, "Perform timing"); + register_parameter("skip-processing-meta-field", &skip_processing_meta_field, "If this meta field exists, pass the incoming image array to next gadget without processing"); + } - GenericReconPartialFourierHandlingGadget(const Core::Context& context, const Core::GadgetProperties& props); + bool verbose = false; + bool perform_timing = false; + std::string skip_processing_meta_field = "Skip_processing_after_recon"; + }; + + GenericReconPartialFourierHandlingGadget(const Core::MrdContext& context, const Parameters& params); virtual ~GenericReconPartialFourierHandlingGadget() = default; mrd::ImageArray process_function(mrd::ImageArray array) const override; - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - NODE_PROPERTY(skip_processing_meta_field, std::string, "If this meta field exists, pass the incoming image array to next gadget without processing", "Skip_processing_after_recon"); - NODE_PROPERTY(verbose, bool, "Verbose",false); - NODE_PROPERTY(perform_timing, bool, "Perform timing",false); protected: + const Parameters params_; + size_t num_encoding_spaces; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp index 1d6740e3..69be8a55 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp @@ -11,15 +11,15 @@ namespace Gadgetron { hoNDArray> GenericReconPartialFourierHandlingPOCSGadget::perform_partial_fourier_handling(const hoNDArray> & kspace_buffer, size_t start_RO, size_t end_RO, size_t start_E1, size_t end_E1, size_t start_E2, size_t end_E2) const{ std::optional gt_timer; - if (perform_timing) { gt_timer = GadgetronTimer("GenericReconPartialFourierHandlingFilterGadget, partial_fourier_filter"); } + if (params_.perform_timing) { gt_timer = GadgetronTimer("GenericReconPartialFourierHandlingFilterGadget, partial_fourier_filter"); } hoNDArray> pf_res; Gadgetron::partial_fourier_POCS(kspace_buffer, start_RO,end_RO,start_E1,end_E1,start_E2,end_E2, - partial_fourier_POCS_transitBand, partial_fourier_POCS_transitBand, - partial_fourier_POCS_transitBand_E2, partial_fourier_POCS_iters, - partial_fourier_POCS_thres, pf_res); + params_.partial_fourier_POCS_transitBand, params_.partial_fourier_POCS_transitBand, + params_.partial_fourier_POCS_transitBand_E2, params_.partial_fourier_POCS_iters, + params_.partial_fourier_POCS_thres, pf_res); return std::move(pf_res); diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h index a32a515a..aaa7129c 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h @@ -17,21 +17,33 @@ namespace Gadgetron { typedef GenericReconPartialFourierHandlingGadget BaseClass; - using GenericReconPartialFourierHandlingGadget::GenericReconPartialFourierHandlingGadget; - - /// ------------------------------------------------------------------------------------ - /// parameters to control the reconstruction - /// ------------------------------------------------------------------------------------ - - NODE_PROPERTY(partial_fourier_POCS_iters, size_t, "Number of iterations for POCS PF handling", 6); - NODE_PROPERTY(partial_fourier_POCS_thres, double, "Threshold for POSC PF handling", 0.01); - NODE_PROPERTY(partial_fourier_POCS_transitBand, size_t, "Transition band width for POCS PF handling", 24); - NODE_PROPERTY(partial_fourier_POCS_transitBand_E2, size_t, - "Transition band width for POCS PF handling for E2 dimension", 16); - - // ------------------------------------------------------------------------------------ + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix) : BaseClass::Parameters(prefix, "Partial Fourier Handling POCS") + { + register_parameter("partial-fourier-POCS-iters", &partial_fourier_POCS_iters, + "Number of iterations for POCS PF handling"); + register_parameter("partial-fourier-POCS-thres", &partial_fourier_POCS_thres, + "Threshold for POSC PF handling"); + register_parameter("partial-fourier-POCS-transitBand", &partial_fourier_POCS_transitBand, + "Transition band width for POCS PF handling"); + register_parameter("partial-fourier-POCS-transitBand-E2", &partial_fourier_POCS_transitBand_E2, + "Transition band width for POCS PF handling for E2 dimension"); + } + + size_t partial_fourier_POCS_iters = 6; + double partial_fourier_POCS_thres = 0.01; + size_t partial_fourier_POCS_transitBand = 24; + size_t partial_fourier_POCS_transitBand_E2 = 16; + }; + + GenericReconPartialFourierHandlingPOCSGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) + {} protected: + const Parameters params_; + hoNDArray> perform_partial_fourier_handling( const hoNDArray>& kspace_buffer, size_t start_RO, size_t end_RO, size_t start_E1, size_t end_E1, size_t start_E2, size_t end_E2) const override; diff --git a/toolboxes/mri_core/mri_core_def.h b/toolboxes/mri_core/mri_core_def.h index 3e96ad9f..4ac878de 100644 --- a/toolboxes/mri_core/mri_core_def.h +++ b/toolboxes/mri_core/mri_core_def.h @@ -137,14 +137,16 @@ namespace Gadgetron #define GADGETRON_PASS_IMMEDIATE "GT_PASSIMAGE_IMMEDIATE" /// data stream key - #define GENERIC_RECON_STREAM_MRD_HEADER "recon_header" - #define GENERIC_RECON_STREAM_UNDERSAMPLED_KSPACE "undersampled_kspace" - #define GENERIC_RECON_STREAM_REF_KSPACE "ref_kspace" - #define GENERIC_RECON_STREAM_REF_KSPACE_FOR_COILMAP "ref_kspace_for_coil_map" - #define GENERIC_RECON_STREAM_COILMAP "coil_map" - #define GENERIC_RECON_STREAM_GFACTOR_MAP "gfactor" - #define GENERIC_RECON_STREAM_RECONED_KSPACE "reconed_kspace" - #define GENERIC_RECON_STREAM_RECONED_COMPLEX_IMAGE "reconed_images" - #define GENERIC_RECON_STREAM_RECONED_COMPLEX_IMAGE_AFTER_POSTPROCESSING "reconed_images_after_post_processing" - #define GENERIC_RECON_STREAM_WAVEFORM "waveform" + /// if these ENVIRONMENT VARIABLES are set to a file path, the corresponding data will be + /// streamed directly to the specified file + #define GENERIC_RECON_STREAM_MRD_HEADER "PINGVIN_STREAM_RECON_HEADER" + #define GENERIC_RECON_STREAM_UNDERSAMPLED_KSPACE "PINGVIN_STREAM_UNDERSAMPLED_KSPACE" + #define GENERIC_RECON_STREAM_REF_KSPACE "PINGVIN_STREAM_REF_KSPACE" + #define GENERIC_RECON_STREAM_REF_KSPACE_FOR_COILMAP "PINGVIN_STREAM_REF_KSPACE_FOR_COIL_MAP" + #define GENERIC_RECON_STREAM_COILMAP "PINGVIN_STREAM_COIL_MAP" + #define GENERIC_RECON_STREAM_GFACTOR_MAP "PINGVIN_STREAM_GFACTOR" + #define GENERIC_RECON_STREAM_RECONED_KSPACE "PINGVIN_STREAM_RECONED_KSPACE" + #define GENERIC_RECON_STREAM_RECONED_COMPLEX_IMAGE "PINGVIN_STREAM_RECONED_IMAGES" + #define GENERIC_RECON_STREAM_RECONED_COMPLEX_IMAGE_AFTER_POSTPROCESSING "PINGVIN_STREAM_RECONED_IMAGES_AFTER_POST_PROCESSING" + #define GENERIC_RECON_STREAM_WAVEFORM "PINGVIN_STREAM_WAVEFORM" } From 8632362027dc4db697b40b2da9b241a20ff519f6 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Mon, 10 Feb 2025 20:58:13 +0000 Subject: [PATCH 12/21] Update CMR and all remaining gadgets --- apps/emperor/CMakeLists.txt | 1 + apps/emperor/main.cc | 5 +- apps/emperor/pipelines/cmr.h | 66 +++++++ apps/emperor/pipelines/file_search.h | 2 +- core/Node.h | 20 +- core/Parameters.h | 47 ++++- core/PureGadget.h | 31 ++- gadgets/CMakeLists.txt | 2 +- .../CmrCartesianKSpaceBinningCineGadget.cpp | 119 ++++++------ .../cmr/CmrCartesianKSpaceBinningCineGadget.h | 153 ++++++++++----- gadgets/cmr/CmrParametricMappingGadget.cpp | 49 ++--- gadgets/cmr/CmrParametricMappingGadget.h | 77 +++++--- .../cmr/CmrParametricT1SRMappingGadget.cpp | 39 ++-- gadgets/cmr/CmrParametricT1SRMappingGadget.h | 26 ++- gadgets/cmr/CmrParametricT2MappingGadget.cpp | 33 ++-- gadgets/cmr/CmrParametricT2MappingGadget.h | 21 +- .../CmrRealTimeLAXCineAIAnalysisGadget.cpp | 31 +-- .../cmr/CmrRealTimeLAXCineAIAnalysisGadget.h | 39 ++-- ...ureCmrCartesianKSpaceBinningCineGadget.cpp | 79 ++++---- .../PureCmrCartesianKSpaceBinningCineGadget.h | 182 ++++++++++-------- gadgets/debugging/PseudoReplicatorGadget.cpp | 7 +- gadgets/debugging/PseudoReplicatorGadget.h | 19 +- gadgets/debugging/RateLimitGadget.cpp | 7 +- gadgets/debugging/RateLimitGadget.h | 14 +- .../debugging/WhiteNoiseInjectorGadget.cpp | 15 +- gadgets/debugging/WhiteNoiseInjectorGadget.h | 20 +- .../examples/AcquisitionWaveformBranch.cpp | 5 - gadgets/examples/AcquisitionWaveformBranch.h | 7 +- gadgets/examples/ImageLayerer.cpp | 4 - gadgets/examples/ImageLayerer.h | 7 +- gadgets/grappa/CMakeLists.txt | 2 - gadgets/grappa/ChannelReorderer.cpp | 128 ------------ gadgets/grappa/ChannelReorderer.h | 41 ---- gadgets/grappa/SliceAccumulator.h | 3 +- gadgets/grappa/grappa_cpu.ini | 20 ++ 35 files changed, 714 insertions(+), 607 deletions(-) create mode 100644 apps/emperor/pipelines/cmr.h delete mode 100644 gadgets/grappa/ChannelReorderer.cpp delete mode 100644 gadgets/grappa/ChannelReorderer.h create mode 100644 gadgets/grappa/grappa_cpu.ini diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt index 139c84d1..6032e9a2 100644 --- a/apps/emperor/CMakeLists.txt +++ b/apps/emperor/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries(emperor pingvin_mricore pingvin_epi pingvin_grappa + pingvin_cmr Boost::system Boost::program_options GTBLAS) diff --git a/apps/emperor/main.cc b/apps/emperor/main.cc index b455458f..9d1bf481 100644 --- a/apps/emperor/main.cc +++ b/apps/emperor/main.cc @@ -4,6 +4,7 @@ #include "pipelines/epi.h" #include "pipelines/cartesian_grappa.h" #include "pipelines/cartesian_spirit.h" +#include "pipelines/cmr.h" #include "pipelines/file_search.h" @@ -124,7 +125,9 @@ int main(int argc, char** argv) &file_search, &grappa, &cartesian_grappa, - &cartesian_spirit_nonlinear + &cartesian_spirit_nonlinear, + &cmr_cine_binning, + &cmr_mapping_t1_sr }; std::map builder_map; for (auto& builder : builders) { diff --git a/apps/emperor/pipelines/cmr.h b/apps/emperor/pipelines/cmr.h new file mode 100644 index 00000000..d3525826 --- /dev/null +++ b/apps/emperor/pipelines/cmr.h @@ -0,0 +1,66 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" +#include "gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h" +#include "gadgets/cmr/CmrParametricT1SRMappingGadget.h" + +namespace pingvin { + +static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("cmr") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("sasha") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/file_search.h b/apps/emperor/pipelines/file_search.h index 08bd5a11..ddcda390 100644 --- a/apps/emperor/pipelines/file_search.h +++ b/apps/emperor/pipelines/file_search.h @@ -62,7 +62,7 @@ namespace pingvin { }; TextualSearch(const TextContext& context, const Parameters& params) - : Core::ChannelGadget(Core::Context{}, Core::GadgetProperties{}) + : Core::ChannelGadget() , parameters_(params) { } diff --git a/core/Node.h b/core/Node.h index 3e1db93d..035a0551 100644 --- a/core/Node.h +++ b/core/Node.h @@ -15,6 +15,10 @@ namespace Gadgetron::Core { class Node { public: + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; + virtual ~Node() = default; /** @@ -25,25 +29,14 @@ namespace Gadgetron::Core { virtual void process(GenericInputChannel& in, OutputChannel& out) = 0; }; - class GenericChannelGadget : public Node, public PropertyMixin { - public: - struct Parameters : NodeParameters { - using NodeParameters::NodeParameters; - }; - - GenericChannelGadget(const Context& context, const GadgetProperties& properties) : PropertyMixin(properties) {} - }; - /** * A Node providing typed access to input data. Messages not matching the TYPELIST are simply passed to the next * Node in the chain. * Should be the first choice for writing new Gadgets. * @tparam TYPELIST The type(s) of the messages to be received */ - template class ChannelGadget : public GenericChannelGadget { + template class ChannelGadget : public Node { public: - using GenericChannelGadget::GenericChannelGadget; - void process(GenericInputChannel& in, OutputChannel& out) override final { auto typed_input = InputChannel(in, out); this->process(typed_input, out); @@ -62,8 +55,7 @@ namespace Gadgetron::Core { public: using ChannelGadget::ChannelGadget; - MRChannelGadget(const MrdContext& context, const NodeParameters& parameters) - : ChannelGadget(Core::Context{}, Core::GadgetProperties{}) {} + MRChannelGadget(const MrdContext& context, const NodeParameters& parameters) {} }; } diff --git a/core/Parameters.h b/core/Parameters.h index 5b962f80..f0c841e5 100644 --- a/core/Parameters.h +++ b/core/Parameters.h @@ -3,11 +3,29 @@ #include #include + +namespace std { + +/** TODO: This pollutes the `std` namespace... + * + * It is used to enable setting a `default_value` on multitoken parameters (i.e. a vector of numbers) + */ +template +std::ostream& operator<<(std::ostream& os, const std::vector& vec) +{ + for (auto item : vec) { + os << item << " "; + } + return os; +} + +} + + namespace Gadgetron::Core { namespace po = boost::program_options; - struct IParameter { virtual boost::shared_ptr as_boost_option(void) const = 0; virtual ~IParameter() = default; @@ -34,6 +52,27 @@ class Parameter : public IParameter { std::string description_; }; +template +class MultitokenParameter : public IParameter { +public: + MultitokenParameter(const std::string& name, std::vector* storage, const std::string& description) + : storage_(storage), name_(name), description_(description) {} + + boost::shared_ptr as_boost_option(void) const override + { + return boost::make_shared( + name_.c_str(), + po::value>(storage_)->default_value(*storage_)->multitoken(), + description_.c_str() + ); + } + +protected: + std::vector* storage_; + std::string name_; + std::string description_; +}; + class Flag : public Parameter { public: using Parameter::Parameter; @@ -60,6 +99,12 @@ class NodeParameters { parameters_.push_back(std::make_shared>(argname, value, description)); } + template + void register_multitoken(const std::string& name, std::vector* value, const std::string& description) { + auto argname = prefix_ + "." + name; + parameters_.push_back(std::make_shared>(argname, value, description)); + } + void register_flag(const std::string& name, bool* value, const std::string& description) { auto argname = prefix_ + "." + name; parameters_.push_back(std::make_shared(argname, value, description)); diff --git a/core/PureGadget.h b/core/PureGadget.h index 3dd43ed5..7b0bcc83 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -2,27 +2,24 @@ #include "Node.h" namespace Gadgetron::Core { -class GenericPureGadget : public GenericChannelGadget { -public: - using GenericChannelGadget::GenericChannelGadget; - GenericPureGadget(): GenericChannelGadget(Context{}, GadgetProperties{}) { } - void process(GenericInputChannel&in, OutputChannel &out) final { - for (auto message : in) - out.push(this->process_function(std::move(message))); - } +class GenericPureGadget : public Node { +public: + void process(GenericInputChannel&in, OutputChannel &out) final { + for (auto message : in) + out.push(this->process_function(std::move(message))); + } - /*** - * Takes in a single Message, and produces another message as output - * @return The processed Message - */ - virtual Message process_function(Message) const = 0; - }; + /*** + * Takes in a single Message, and produces another message as output + * @return The processed Message + */ + virtual Message process_function(Message) const = 0; +}; template class PureGadget : public GenericPureGadget { public: - using GenericPureGadget::GenericPureGadget; Message process_function(Message message) const override{ if (!convertible_to(message)) return message; return Message(process_function(force_unpack(std::move(message)))); @@ -33,7 +30,6 @@ class PureGadget : public GenericPureGadget { * @return The processed message */ virtual RETURN process_function(INPUT args) const = 0; - }; @@ -41,8 +37,7 @@ class PureGadget : public GenericPureGadget { template class MRPureGadget : public PureGadget { public: - MRPureGadget(const MrdContext& context, const NodeParameters& parameters) - : PureGadget(Core::Context{}, Core::GadgetProperties{}) {} + MRPureGadget(const MrdContext& context, const NodeParameters& parameters) {} }; } diff --git a/gadgets/CMakeLists.txt b/gadgets/CMakeLists.txt index f7d5be6e..feb5e1e8 100644 --- a/gadgets/CMakeLists.txt +++ b/gadgets/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(examples) add_subdirectory(debugging) add_subdirectory(mri_core) -# add_subdirectory(cmr) +add_subdirectory(cmr) add_subdirectory(epi) add_subdirectory(grappa) \ No newline at end of file diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp index 806647c3..7bae2b57 100644 --- a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp +++ b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp @@ -6,11 +6,12 @@ namespace Gadgetron { static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; - CmrCartesianKSpaceBinningCineGadget::CmrCartesianKSpaceBinningCineGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + CmrCartesianKSpaceBinningCineGadget::CmrCartesianKSpaceBinningCineGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) , send_out_multiple_series_by_slice_(false) { - this->send_out_multiple_series_by_slice_ = this->send_out_multiple_series_by_slice; + this->send_out_multiple_series_by_slice_ = params_.send_out_multiple_series_by_slice; auto& h = context.header; @@ -30,54 +31,54 @@ namespace Gadgetron { // ------------------------------------------------- binning_reconer_.debug_folder_ = this->debug_folder_full_path_; - binning_reconer_.perform_timing_ = this->perform_timing; - binning_reconer_.verbose_ = this->verbose; + binning_reconer_.perform_timing_ = params_.perform_timing; + binning_reconer_.verbose_ = params_.verbose; - binning_reconer_.use_multiple_channel_recon_ = this->use_multiple_channel_recon; + binning_reconer_.use_multiple_channel_recon_ = params_.use_multiple_channel_recon; binning_reconer_.use_paralell_imaging_binning_recon_ = true; - binning_reconer_.use_nonlinear_binning_recon_ = this->use_nonlinear_binning_recon; + binning_reconer_.use_nonlinear_binning_recon_ = params_.use_nonlinear_binning_recon; binning_reconer_.estimate_respiratory_navigator_ = true; - binning_reconer_.respiratory_navigator_moco_reg_strength_ = this->respiratory_navigator_moco_reg_strength; - binning_reconer_.respiratory_navigator_moco_iters_ = this->respiratory_navigator_moco_iters; + binning_reconer_.respiratory_navigator_moco_reg_strength_ = params_.respiratory_navigator_moco_reg_strength; + binning_reconer_.respiratory_navigator_moco_iters_ = params_.respiratory_navigator_moco_iters; - binning_reconer_.time_tick_ = this->time_tick; + binning_reconer_.time_tick_ = params_.time_tick; binning_reconer_.trigger_time_index_ = 0; - binning_reconer_.arrhythmia_rejector_factor_ = this->arrhythmia_rejector_factor; - - binning_reconer_.grappa_kSize_RO_ = this->grappa_kSize_RO; - binning_reconer_.grappa_kSize_E1_ = this->grappa_kSize_E1; - binning_reconer_.grappa_reg_lamda_ = this->grappa_reg_lamda; - binning_reconer_.downstream_coil_compression_num_modesKept_ = this->downstream_coil_compression_num_modesKept; - binning_reconer_.downstream_coil_compression_thres_ = this->downstream_coil_compression_thres; - - binning_reconer_.kspace_binning_interpolate_heart_beat_images_ = this->kspace_binning_interpolate_heart_beat_images; - binning_reconer_.kspace_binning_navigator_acceptance_window_ = this->kspace_binning_navigator_acceptance_window; - - binning_reconer_.kspace_binning_moco_reg_strength_ = this->kspace_binning_moco_reg_strength; - binning_reconer_.kspace_binning_moco_iters_ = this->kspace_binning_moco_iters; - - binning_reconer_.kspace_binning_max_temporal_window_ = this->kspace_binning_max_temporal_window; - binning_reconer_.kspace_binning_minimal_cardiac_phase_width_ = this->kspace_binning_minimal_cardiac_phase_width; - binning_reconer_.kspace_binning_kSize_RO_ = this->kspace_binning_kSize_RO; - binning_reconer_.kspace_binning_kSize_E1_ = this->kspace_binning_kSize_E1; - binning_reconer_.kspace_binning_reg_lamda_ = this->kspace_binning_reg_lamda; - binning_reconer_.kspace_binning_linear_iter_max_ = this->kspace_binning_linear_iter_max; - binning_reconer_.kspace_binning_linear_iter_thres_ = this->kspace_binning_linear_iter_thres; - binning_reconer_.kspace_binning_nonlinear_iter_max_ = this->kspace_binning_nonlinear_iter_max; - binning_reconer_.kspace_binning_nonlinear_iter_thres_ = this->kspace_binning_nonlinear_iter_thres; - binning_reconer_.kspace_binning_nonlinear_data_fidelity_lamda_ = this->kspace_binning_nonlinear_data_fidelity_lamda; - binning_reconer_.kspace_binning_nonlinear_image_reg_lamda_ = this->kspace_binning_nonlinear_image_reg_lamda; - binning_reconer_.kspace_binning_nonlinear_reg_N_weighting_ratio_ = this->kspace_binning_nonlinear_reg_N_weighting_ratio; - binning_reconer_.kspace_binning_nonlinear_reg_use_coil_sen_map_ = this->kspace_binning_nonlinear_reg_use_coil_sen_map; - binning_reconer_.kspace_binning_nonlinear_reg_with_approx_coeff_ = this->kspace_binning_nonlinear_reg_with_approx_coeff; - binning_reconer_.kspace_binning_nonlinear_reg_wav_name_ = this->kspace_binning_nonlinear_reg_wav_name; + binning_reconer_.arrhythmia_rejector_factor_ = params_.arrhythmia_rejector_factor; + + binning_reconer_.grappa_kSize_RO_ = params_.grappa_kSize_RO; + binning_reconer_.grappa_kSize_E1_ = params_.grappa_kSize_E1; + binning_reconer_.grappa_reg_lamda_ = params_.grappa_reg_lamda; + binning_reconer_.downstream_coil_compression_num_modesKept_ = params_.downstream_coil_compression_num_modesKept; + binning_reconer_.downstream_coil_compression_thres_ = params_.downstream_coil_compression_thres; + + binning_reconer_.kspace_binning_interpolate_heart_beat_images_ = params_.kspace_binning_interpolate_heart_beat_images; + binning_reconer_.kspace_binning_navigator_acceptance_window_ = params_.kspace_binning_navigator_acceptance_window; + + binning_reconer_.kspace_binning_moco_reg_strength_ = params_.kspace_binning_moco_reg_strength; + binning_reconer_.kspace_binning_moco_iters_ = params_.kspace_binning_moco_iters; + + binning_reconer_.kspace_binning_max_temporal_window_ = params_.kspace_binning_max_temporal_window; + binning_reconer_.kspace_binning_minimal_cardiac_phase_width_ = params_.kspace_binning_minimal_cardiac_phase_width; + binning_reconer_.kspace_binning_kSize_RO_ = params_.kspace_binning_kSize_RO; + binning_reconer_.kspace_binning_kSize_E1_ = params_.kspace_binning_kSize_E1; + binning_reconer_.kspace_binning_reg_lamda_ = params_.kspace_binning_reg_lamda; + binning_reconer_.kspace_binning_linear_iter_max_ = params_.kspace_binning_linear_iter_max; + binning_reconer_.kspace_binning_linear_iter_thres_ = params_.kspace_binning_linear_iter_thres; + binning_reconer_.kspace_binning_nonlinear_iter_max_ = params_.kspace_binning_nonlinear_iter_max; + binning_reconer_.kspace_binning_nonlinear_iter_thres_ = params_.kspace_binning_nonlinear_iter_thres; + binning_reconer_.kspace_binning_nonlinear_data_fidelity_lamda_ = params_.kspace_binning_nonlinear_data_fidelity_lamda; + binning_reconer_.kspace_binning_nonlinear_image_reg_lamda_ = params_.kspace_binning_nonlinear_image_reg_lamda; + binning_reconer_.kspace_binning_nonlinear_reg_N_weighting_ratio_ = params_.kspace_binning_nonlinear_reg_N_weighting_ratio; + binning_reconer_.kspace_binning_nonlinear_reg_use_coil_sen_map_ = params_.kspace_binning_nonlinear_reg_use_coil_sen_map; + binning_reconer_.kspace_binning_nonlinear_reg_with_approx_coeff_ = params_.kspace_binning_nonlinear_reg_with_approx_coeff; + binning_reconer_.kspace_binning_nonlinear_reg_wav_name_ = params_.kspace_binning_nonlinear_reg_wav_name; } void CmrCartesianKSpaceBinningCineGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto m1: in) { - if (perform_timing) { gt_timer_local_.start("CmrCartesianKSpaceBinningCineGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("CmrCartesianKSpaceBinningCineGadget::process"); } process_called_times_++; @@ -87,7 +88,7 @@ namespace Gadgetron { GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->buffers.size() << " instead of " << num_encoding_spaces_); } - std::vector processed_slices = kspace_binning_processed_slices; + std::vector processed_slices = params_.kspace_binning_processed_slices; if(processed_slices.size()>0) { size_t ii; @@ -161,15 +162,15 @@ namespace Gadgetron { // --------------------------------------------------------------- - if (perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::perform_binning"); } + if (params_.perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::perform_binning"); } this->perform_binning(recon_bit_->buffers[e], e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } // --------------------------------------------------------------- - if (perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::compute_image_header, raw images"); } + if (params_.perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::compute_image_header, raw images"); } this->compute_image_header(recon_bit_->buffers[e], res_raw_, e); - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } this->set_time_stamps(res_raw_, acq_time_raw_, cpt_time_raw_); @@ -180,13 +181,13 @@ namespace Gadgetron { this->gt_exporter_.export_array_complex(res_raw_.data, debug_folder_full_path_ + "recon_res_raw" + os.str()); } - if(this->send_out_raw) + if(this->params_.send_out_raw) { - if (perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::send_out_image_array, raw"); } + if (params_.perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::send_out_image_array, raw"); } // Copy the image array before sending so we can reuse it on the next encoding space auto copy = res_raw_; - this->send_out_image_array(copy, e, image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); - if (perform_timing) { gt_timer_.stop(); } + this->send_out_image_array(copy, e, params_.image_series + ((int)e + 1), GADGETRON_IMAGE_REGULAR, out); + if (params_.perform_timing) { gt_timer_.stop(); } } // --------------------------------------------------------------- @@ -198,15 +199,15 @@ namespace Gadgetron { this->gt_exporter_.export_array_complex(res_binning_.data, debug_folder_full_path_ + "recon_res_binning" + os.str()); } - if (perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::send_out_image_array, binning"); } + if (params_.perform_timing) { gt_timer_.start("CmrCartesianKSpaceBinningCineGadget::send_out_image_array, binning"); } // Copy the image array before sending so we can reuse it on the next encoding space auto copy = res_binning_; - this->send_out_image_array(copy, e, image_series + (int)e + 2, GADGETRON_IMAGE_RETRO, out); - if (perform_timing) { gt_timer_.stop(); } + this->send_out_image_array(copy, e, params_.image_series + (int)e + 2, GADGETRON_IMAGE_RETRO, out); + if (params_.perform_timing) { gt_timer_.stop(); } } } - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -222,7 +223,7 @@ namespace Gadgetron { size_t S = recon_bit.data.data.get_size(5); size_t SLC = recon_bit.data.data.get_size(6); - size_t binned_N = this->number_of_output_phases; + size_t binned_N = this->params_.number_of_output_phases; GADGET_CHECK_THROW(E2==1); GADGET_CHECK_THROW(N>binned_N); @@ -273,7 +274,7 @@ namespace Gadgetron { // if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(binning_reconer_.binning_obj_.data, debug_folder_full_path_ + "binning_obj_data" + os.str()); } // compute the binning - if (perform_timing) { timer.start("compute binning ... "); } + if (params_.perform_timing) { timer.start("compute binning ... "); } try { binning_reconer_.process_binning_recon(); @@ -283,7 +284,7 @@ namespace Gadgetron { GERROR_STREAM("Exceptions happened in binning_reconer_.process_binning_recon() for slice " << slc); continue; } - if (perform_timing) { timer.stop(); } + if (params_.perform_timing) { timer.stop(); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(binning_reconer_.binning_obj_.complex_image_raw_, debug_folder_full_path_ + "binning_obj_complex_image_raw" + os.str()); } if (!debug_folder_full_path_.empty()) { gt_exporter_.export_array_complex(binning_reconer_.binning_obj_.complex_image_binning_, debug_folder_full_path_ + "binning_obj_complex_image_binning" + os.str()); } @@ -339,7 +340,7 @@ namespace Gadgetron { size_t S = res_raw_.headers.get_size(1); size_t SLC = res_raw_.headers.get_size(2); - size_t binned_N = this->number_of_output_phases; + size_t binned_N = this->params_.number_of_output_phases; res_binning_.headers.create(binned_N, S, SLC); res_binning_.meta.create(binned_N, S, SLC); @@ -378,8 +379,8 @@ namespace Gadgetron { { for (n=0; ntime_tick + 0.5); - res.headers(n, s, slc).physiology_time_stamp[0] = (uint32_t)(cpt_time(n, s, slc)/ this->time_tick + 0.5); + res.headers(n, s, slc).acquisition_time_stamp = (uint32_t)(acq_time(n, s, slc)/ this->params_.time_tick + 0.5); + res.headers(n, s, slc).physiology_time_stamp[0] = (uint32_t)(cpt_time(n, s, slc)/ this->params_.time_tick + 0.5); } } } diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h index 45337158..7db7e91a 100644 --- a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h +++ b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h @@ -30,59 +30,110 @@ namespace Gadgetron { public: typedef GenericReconGadget BaseClass; - CmrCartesianKSpaceBinningCineGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// parameters for workflow - NODE_PROPERTY(use_multiple_channel_recon, bool, "Whether to perform multi-channel recon in the raw data step", true); - NODE_PROPERTY(use_nonlinear_binning_recon, bool, "Whether to non-linear recon in the binning step", true); - NODE_PROPERTY(number_of_output_phases, int, "Number of output phases after binning", 30); - - NODE_PROPERTY(send_out_raw, bool, "Whether to set out raw images", false); - NODE_PROPERTY(send_out_multiple_series_by_slice, bool, "Whether to set out binning images as multiple series", false); - - /// parameters for raw image reconstruction - NODE_PROPERTY(arrhythmia_rejector_factor, float, "If a heart beat RR is not in the range of [ (1-arrhythmiaRejectorFactor)*meanRR (1+arrhythmiaRejectorFactor)*meanRR], it will be rejected", 0.25); - - NODE_PROPERTY(grappa_kSize_RO, int, "Raw data recon, kernel size RO", 5); - NODE_PROPERTY(grappa_kSize_E1, int, "Raw data recon, kernel size E1", 4); - NODE_PROPERTY(grappa_reg_lamda, double, "Raw data recon, kernel calibration regularization", 0.0005); - - NODE_PROPERTY(downstream_coil_compression_num_modesKept, size_t, "Number of modes kept for down stream coil compression in raw recon step", 0); - NODE_PROPERTY(downstream_coil_compression_thres, double, "Threshold for determining number of kept modes in the down stream coil compression", 0.01); - - /// parameters for kspace binning - NODE_PROPERTY(respiratory_navigator_moco_reg_strength, double, "Regularization strength of respiratory moco", 6.0); - NODE_PROPERTY(respiratory_navigator_moco_iters, std::vector, "Number of iterations for respiratory moco", (std::vector{1, 32, 100, 100})); - - NODE_PROPERTY(kspace_binning_interpolate_heart_beat_images, bool, "Whether to interpolate best heart beat images", true); - NODE_PROPERTY(kspace_binning_navigator_acceptance_window, double, "Respiratory navigator acceptance window", 0.65); - NODE_PROPERTY(kspace_binning_max_temporal_window, double, "Maximally allowed temporal window ratio for binned kspace", 2.0); - NODE_PROPERTY(kspace_binning_minimal_cardiac_phase_width, double, "Allowed minimal temporal window for binned kspace, in ms", 25.0); - - NODE_PROPERTY(kspace_binning_moco_reg_strength, double, "Regularization strength of binning moco", 12.0); - NODE_PROPERTY(kspace_binning_moco_iters, std::vector, "Number of iterations for binning moco", (std::vector{24, 64, 100, 100, 100})); - - /// parameters for recon on binned kspace - NODE_PROPERTY(kspace_binning_kSize_RO, int, "Binned kspace recon, kernel size RO", 7); - NODE_PROPERTY(kspace_binning_kSize_E1, int, "Binned kspace recon, kernel size E1", 7); - NODE_PROPERTY(kspace_binning_reg_lamda, double, "Binned kspace recon, kernel calibration regularization", 0.005); - /// linear recon step - NODE_PROPERTY(kspace_binning_linear_iter_max, size_t, "Binned kspace recon, maximal number of iterations, linear recon", 90); - NODE_PROPERTY(kspace_binning_linear_iter_thres, double, "Binned kspace recon, iteration threshold, linear recon", 0.0015); - /// Non-linear recon step - NODE_PROPERTY(kspace_binning_nonlinear_iter_max, size_t, "Binned kspace recon, maximal number of iterations, non-linear recon", 25); - NODE_PROPERTY(kspace_binning_nonlinear_iter_thres, double, "Binned kspace recon, iteration threshold, non-linear recon", 0.004); - NODE_PROPERTY(kspace_binning_nonlinear_data_fidelity_lamda, double, "Binned kspace recon, strength of data fidelity term, non-linear recon", 1.0); - NODE_PROPERTY(kspace_binning_nonlinear_image_reg_lamda, double, "Binned kspace recon, strength of image term, non-linear recon", 0.00015); - NODE_PROPERTY(kspace_binning_nonlinear_reg_N_weighting_ratio, double, "Binned kspace recon, regularization weighting ratio along the N dimension, non-linear recon", 10.0); - NODE_PROPERTY(kspace_binning_nonlinear_reg_use_coil_sen_map, bool, "Binned kspace recon, whether to use coil map, non-linear recon", false); - NODE_PROPERTY(kspace_binning_nonlinear_reg_with_approx_coeff, bool, "Binned kspace recon, whether to keep approximal coefficients, non-linear recon", true); - NODE_PROPERTY(kspace_binning_nonlinear_reg_wav_name, std::string, "Binned kspace recon, wavelet name, non-linear recon (db1, db2, db3, db4, db5)", "db1"); - - // for debug - NODE_PROPERTY(kspace_binning_processed_slices, std::vector, "If set, these slices will be processed", {}); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix): BaseClass::Parameters(prefix, "CmrCartesianKSpaceBinningCine") { + register_parameter("use-multiple-channel-recon", &use_multiple_channel_recon, "Whether to perform multi-channel recon in the raw data step"); + register_parameter("use-nonlinear-binning-recon", &use_nonlinear_binning_recon, "Whether to non-linear recon in the binning step"); + register_parameter("number-of-output-phases", &number_of_output_phases, "Number of output phases after binning"); + + register_parameter("send-out-raw", &send_out_raw, "Whether to set out raw images"); + register_parameter("send-out-multiple-series-by-slice", &send_out_multiple_series_by_slice, "Whether to set out binning images as multiple series"); + + register_parameter("arrhythmia-rejector-factor", &arrhythmia_rejector_factor, "If a heart beat RR is not in the range of [ (1-arrhythmiaRejectorFactor)*meanRR (1+arrhythmiaRejectorFactor)*meanRR], it will be rejected"); + + register_parameter("grappa-kSize-RO", &grappa_kSize_RO, "Raw data recon, kernel size RO"); + register_parameter("grappa-kSize-E1", &grappa_kSize_E1, "Raw data recon, kernel size E1"); + register_parameter("grappa-reg-lamda", &grappa_reg_lamda, "Raw data recon, kernel calibration regularization"); + + register_parameter("downstream-coil-compression-num-modesKept", &downstream_coil_compression_num_modesKept, "Number of modes kept for down stream coil compression in raw recon step"); + register_parameter("downstream-coil-compression-thres", &downstream_coil_compression_thres, "Threshold for determining number of kept modes in the down stream coil compression"); + + register_parameter("respiratory-navigator-moco-reg-strength", &respiratory_navigator_moco_reg_strength, "Regularization strength of respiratory moco"); + register_multitoken("respiratory-navigator-moco-iters", &respiratory_navigator_moco_iters, "Number of iterations for respiratory moco"); + + register_parameter("kspace-binning-interpolate-heart-beat-images", &kspace_binning_interpolate_heart_beat_images, "Whether to interpolate best heart beat images"); + register_parameter("kspace-binning-navigator-acceptance-window", &kspace_binning_navigator_acceptance_window, "Respiratory navigator acceptance window"); + register_parameter("kspace-binning-max-temporal-window", &kspace_binning_max_temporal_window, "Maximally allowed temporal window ratio for binned kspace"); + register_parameter("kspace-binning-minimal-cardiac-phase-width", &kspace_binning_minimal_cardiac_phase_width, "Allowed minimal temporal window for binned kspace, in ms"); + + register_parameter("kspace-binning-moco-reg-strength", &kspace_binning_moco_reg_strength, "Regularization strength of binning moco"); + register_multitoken("kspace-binning-moco-iters", &kspace_binning_moco_iters, "Number of iterations for binning moco"); + + register_parameter("kspace-binning-kSize-RO", &kspace_binning_kSize_RO, "Binned kspace recon, kernel size RO"); + register_parameter("kspace-binning-kSize-E1", &kspace_binning_kSize_E1, "Binned kspace recon, kernel size E1"); + register_parameter("kspace-binning-reg-lamda", &kspace_binning_reg_lamda, "Binned kspace recon, kernel calibration regularization"); + register_parameter("kspace-binning-linear-iter-max", &kspace_binning_linear_iter_max, "Binned kspace recon, maximal number of iterations, linear recon"); + register_parameter("kspace-binning-linear-iter-thres", &kspace_binning_linear_iter_thres, "Binned kspace recon, iteration threshold, linear recon"); + register_parameter("kspace-binning-nonlinear-iter-max", &kspace_binning_nonlinear_iter_max, "Binned kspace recon, maximal number of iterations, non-linear recon"); + register_parameter("kspace-binning-nonlinear-iter-thres", &kspace_binning_nonlinear_iter_thres, "Binned kspace recon, iteration threshold, non-linear recon"); + register_parameter("kspace-binning-nonlinear-data-fidelity-lamda", &kspace_binning_nonlinear_data_fidelity_lamda, "Binned kspace recon, strength of data fidelity term, non-linear recon"); + register_parameter("kspace-binning-nonlinear-image-reg-lamda", &kspace_binning_nonlinear_image_reg_lamda, "Binned kspace recon, strength of image term, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-N-weighting-ratio", &kspace_binning_nonlinear_reg_N_weighting_ratio, "Binned kspace recon, regularization weighting ratio along the N dimension, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-use-coil-sen-map", &kspace_binning_nonlinear_reg_use_coil_sen_map, "Binned kspace recon, whether to use coil map, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-with-approx-coeff", &kspace_binning_nonlinear_reg_with_approx_coeff, "Binned kspace recon, whether to keep approximal coefficients, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-wav-name", &kspace_binning_nonlinear_reg_wav_name, "Binned kspace recon, wavelet name, non-linear recon"); + + register_parameter("time-tick", &time_tick, "Time tick in ms"); + register_multitoken("kspace-binning-processed-slices", &kspace_binning_processed_slices, "If set, these slices will be processed"); + } + + // parameters for workflow + bool use_multiple_channel_recon = true; + bool use_nonlinear_binning_recon = true; + int number_of_output_phases = 30; + + bool send_out_raw = false; + bool send_out_multiple_series_by_slice = false; + + // parameters for raw image reconstruction + float arrhythmia_rejector_factor = 0.25; + + int grappa_kSize_RO = 5; + int grappa_kSize_E1 = 4; + double grappa_reg_lamda = 0.0005; + + size_t downstream_coil_compression_num_modesKept = 0; + double downstream_coil_compression_thres = 0.01; + + // parameters for kspace binning + double respiratory_navigator_moco_reg_strength = 6.0; + std::vector respiratory_navigator_moco_iters = {1, 32, 100, 100}; + + bool kspace_binning_interpolate_heart_beat_images = true; + double kspace_binning_navigator_acceptance_window = 0.65; + double kspace_binning_max_temporal_window = 2.0; + double kspace_binning_minimal_cardiac_phase_width = 25.0; + + double kspace_binning_moco_reg_strength = 12.0; + std::vector kspace_binning_moco_iters = {24, 64, 100, 100, 100}; + + // parameters for recon on binned kspace + int kspace_binning_kSize_RO = 7; + int kspace_binning_kSize_E1 = 7; + double kspace_binning_reg_lamda = 0.005; + // linear recon step + size_t kspace_binning_linear_iter_max = 90; + double kspace_binning_linear_iter_thres = 0.0015; + // Non-linear recon step + size_t kspace_binning_nonlinear_iter_max = 25; + double kspace_binning_nonlinear_iter_thres = 0.004; + double kspace_binning_nonlinear_data_fidelity_lamda = 1.0; + double kspace_binning_nonlinear_image_reg_lamda = 0.00015; + double kspace_binning_nonlinear_reg_N_weighting_ratio = 10.0; + bool kspace_binning_nonlinear_reg_use_coil_sen_map = false; + bool kspace_binning_nonlinear_reg_with_approx_coeff = true; + std::string kspace_binning_nonlinear_reg_wav_name = "db1"; + + float time_tick = 2.5; + + // for debug + std::vector kspace_binning_processed_slices = {}; + }; + + CmrCartesianKSpaceBinningCineGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variable for recon diff --git a/gadgets/cmr/CmrParametricMappingGadget.cpp b/gadgets/cmr/CmrParametricMappingGadget.cpp index 5ebf33e7..71d80877 100644 --- a/gadgets/cmr/CmrParametricMappingGadget.cpp +++ b/gadgets/cmr/CmrParametricMappingGadget.cpp @@ -12,8 +12,9 @@ namespace Gadgetron { - CmrParametricMappingGadget::CmrParametricMappingGadget(const Core::Context &context, const Core::GadgetProperties &properties) - : BaseClass(context, properties) + CmrParametricMappingGadget::CmrParametricMappingGadget(const Core::MrdContext &context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -51,7 +52,7 @@ namespace Gadgetron { void CmrParametricMappingGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto m1: in) { - if (perform_timing) { gt_timer_local_.start("CmrParametricMappingGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("CmrParametricMappingGadget::process"); } GDEBUG_CONDITION_STREAM(verbose, "CmrParametricMappingGadget::process(...) starts ... "); @@ -75,7 +76,7 @@ namespace Gadgetron { // ------------------------------------------------------------- // some images do not need mapping - if (data->meta[0].count(skip_processing_meta_field) > 0) + if (data->meta[0].count(params_.skip_processing_meta_field) > 0) { out.push(std::move(m1)); continue; @@ -109,7 +110,7 @@ namespace Gadgetron { // ------------------------------------------------------------- // if prep times are not read from protocol, find them from image header - if (!imaging_prep_time_from_protocol) + if (!params_.imaging_prep_time_from_protocol) { this->prep_times_.resize(N, 0); @@ -160,18 +161,18 @@ namespace Gadgetron { // fill in image header and meta // send out results // ---------------------------------------------------------- - if ( send_sd_map && (this->fill_sd_header(map_sd) == GADGET_OK) ) + if ( params_.send_sd_map && (this->fill_sd_header(map_sd) == GADGET_OK) ) { out.push(std::move(map_sd)); } - if (send_map && (this->fill_map_header(map) == GADGET_OK)) + if (params_.send_map && (this->fill_map_header(map) == GADGET_OK)) { out.push(std::move(map)); } } - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -189,18 +190,18 @@ namespace Gadgetron { size_t e2, cha, n, s, slc; - std::string lut = color_lut_map; + std::string lut = params_.color_lut_map; if (this->field_strength_T_ > 2) { - lut = color_lut_map_3T; + lut = params_.color_lut_map_3T; } std::ostringstream ostr; - ostr << "x" << (double)scaling_factor_map; + ostr << "x" << (double)params_.scaling_factor_map; std::string scalingStr = ostr.str(); std::ostringstream ostr_unit; - ostr_unit << std::setprecision(3) << 1.0f / scaling_factor_map << "ms"; + ostr_unit << std::setprecision(3) << 1.0f / params_.scaling_factor_map << "ms"; std::string unitStr = ostr_unit.str(); for (slc = 0; slc < SLC; slc++) @@ -210,9 +211,9 @@ namespace Gadgetron { for (n = 0; n < N; n++) { auto& meta = map.meta(n, s, slc); - meta[GADGETRON_IMAGE_SCALE_RATIO] = {(double)scaling_factor_map}; - meta[GADGETRON_IMAGE_WINDOWCENTER] = {(long)(window_center_map*scaling_factor_map)}; - meta[GADGETRON_IMAGE_WINDOWWIDTH] = {(long)(window_width_map*scaling_factor_map)}; + meta[GADGETRON_IMAGE_SCALE_RATIO] = {(double)params_.scaling_factor_map}; + meta[GADGETRON_IMAGE_WINDOWCENTER] = {(long)(params_.window_center_map*params_.scaling_factor_map)}; + meta[GADGETRON_IMAGE_WINDOWWIDTH] = {(long)(params_.window_width_map*params_.scaling_factor_map)}; meta[GADGETRON_IMAGE_COLORMAP] = {lut}; meta[GADGETRON_IMAGECOMMENT] = meta[GADGETRON_DATA_ROLE]; @@ -222,7 +223,7 @@ namespace Gadgetron { } } - Gadgetron::scal( (float)(scaling_factor_map), map.data); + Gadgetron::scal( (float)(params_.scaling_factor_map), map.data); } catch (...) { @@ -245,14 +246,14 @@ namespace Gadgetron { size_t S = map_sd.data.get_size(5); size_t SLC = map_sd.data.get_size(6); - std::string lut = color_lut_sd_map; + std::string lut = params_.color_lut_sd_map; std::ostringstream ostr; - ostr << "x" << (double)scaling_factor_sd_map; + ostr << "x" << (double)params_.scaling_factor_sd_map; std::string scalingStr = ostr.str(); std::ostringstream ostr_unit; - ostr_unit << std::setprecision(3) << 1.0f / scaling_factor_sd_map << "ms"; + ostr_unit << std::setprecision(3) << 1.0f / params_.scaling_factor_sd_map << "ms"; std::string unitStr = ostr_unit.str(); size_t e2, cha, n, s, slc; @@ -264,9 +265,9 @@ namespace Gadgetron { for (n = 0; n < N; n++) { auto& meta = map_sd.meta(n, s, slc); - meta[GADGETRON_IMAGE_SCALE_RATIO] = {(double)scaling_factor_sd_map}; - meta[GADGETRON_IMAGE_WINDOWCENTER] = {(long)(window_center_sd_map*scaling_factor_sd_map)}; - meta[GADGETRON_IMAGE_WINDOWWIDTH] = {(long)(window_width_sd_map*scaling_factor_sd_map)}; + meta[GADGETRON_IMAGE_SCALE_RATIO] = {(double)params_.scaling_factor_sd_map}; + meta[GADGETRON_IMAGE_WINDOWCENTER] = {(long)(params_.window_center_sd_map*params_.scaling_factor_sd_map)}; + meta[GADGETRON_IMAGE_WINDOWWIDTH] = {(long)(params_.window_width_sd_map*params_.scaling_factor_sd_map)}; meta[GADGETRON_IMAGE_COLORMAP] = {lut}; meta[GADGETRON_IMAGECOMMENT] = meta[GADGETRON_DATA_ROLE]; @@ -276,7 +277,7 @@ namespace Gadgetron { } } - Gadgetron::scal((float)(scaling_factor_map), map_sd.data); + Gadgetron::scal((float)(params_.scaling_factor_map), map_sd.data); } catch (...) { @@ -298,7 +299,7 @@ namespace Gadgetron { mask_initial.create(RO, E1, SLC); Gadgetron::fill(mask_initial, (float)1); - double std_thres = std_thres_masking; + double std_thres = params_.std_thres_masking; size_t n; for (n = 0; n < RO*E1*SLC; n++) diff --git a/gadgets/cmr/CmrParametricMappingGadget.h b/gadgets/cmr/CmrParametricMappingGadget.h index b13abf87..e246ae46 100644 --- a/gadgets/cmr/CmrParametricMappingGadget.h +++ b/gadgets/cmr/CmrParametricMappingGadget.h @@ -17,47 +17,72 @@ namespace Gadgetron { public: typedef GenericReconImageArrayBase BaseClass; - CmrParametricMappingGadget(const Core::Context &context, const Core::GadgetProperties &properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix): Parameters(prefix, "CmrParametricMapping") + {} - /// ------------------------------------------------------------------------------------ - /// parameters to control the mapping - /// ------------------------------------------------------------------------------------ + Parameters(const std::string& prefix, const std::string& description): BaseClass::Parameters(prefix, description) { + register_parameter("skip-processing-meta-field", &skip_processing_meta_field, "If this meta field exists, pass the incoming image array to next gadget without processing"); + register_parameter("imaging-prep-time-from-protocol", &imaging_prep_time_from_protocol, "If true, read in imaging prep time from protocols; if false, read in from meta fields"); - NODE_PROPERTY(skip_processing_meta_field, std::string, "If this meta field exists, pass the incoming image array to next gadget without processing", GADGETRON_SKIP_PROCESSING_AFTER_RECON); + register_parameter("send-map", &send_map, "Whether to send out maps"); + register_parameter("send-sd-map", &send_sd_map, "Whether to send out sd maps"); - NODE_PROPERTY(imaging_prep_time_from_protocol, bool, "If true, read in imaging prep time from protocols; if false, read in from meta fields", true); + register_parameter("color-lut-map", &color_lut_map, "Color lookup table for map"); + register_parameter("window-center-map", &window_center_map, "Window center for map"); + register_parameter("window-width-map", &window_width_map, "Window width for map"); - // ------------------------------------------- + register_parameter("color-lut-map-3T", &color_lut_map_3T, "Color lookup table for map at 3T"); + register_parameter("window-center-map-3T", &window_center_map_3T, "Window center for map at 3T"); + register_parameter("window-width-map-3T", &window_width_map_3T, "Window width for map at 3T"); - NODE_PROPERTY(send_map, bool, "Whether to send out maps", true); - NODE_PROPERTY(send_sd_map, bool, "Whether to send out sd maps", true); + register_parameter("scaling-factor-map", &scaling_factor_map, "Scale factor for map"); - NODE_PROPERTY(color_lut_map, std::string, "Color lookup table for map", "GadgetronParametricMap.pal"); - NODE_PROPERTY(window_center_map, double, "Window center for map", 4.0); - NODE_PROPERTY(window_width_map, double, "Window width for map", 8.0); + register_parameter("color-lut-sd-map", &color_lut_sd_map, "Color lookup table for sd map"); + register_parameter("window-center-sd-map", &window_center_sd_map, "Window center for sd map"); + register_parameter("window-width-sd-map", &window_width_sd_map, "Window width for sd map"); + register_parameter("scaling-factor-sd-map", &scaling_factor_sd_map, "Scale factor for sd map"); - NODE_PROPERTY(color_lut_map_3T, std::string, "Color lookup table for map at 3T", "GadgetronParametricMap_3T.pal"); - NODE_PROPERTY(window_center_map_3T, double, "Window center for map at 3T", 4.0); - NODE_PROPERTY(window_width_map_3T, double, "Window width for map at 3T", 8.0); + register_parameter("perform-hole-filling", &perform_hole_filling, "Whether to perform hole filling on map"); + register_parameter("max-size-hole", &max_size_hole, "Maximal size for hole"); - NODE_PROPERTY(scaling_factor_map, double, "Scale factor for map", 10.0); + register_parameter("std-thres-masking", &std_thres_masking, "Number of noise std for masking"); + register_parameter("mapping-with-masking", &mapping_with_masking, "Whether to compute and apply a mask for mapping"); + }; - // ------------------------------------------- + std::string skip_processing_meta_field = GADGETRON_SKIP_PROCESSING_AFTER_RECON; - NODE_PROPERTY(color_lut_sd_map, std::string, "Color lookup table for sd map", "GadgetronParametricSDMap.pal"); - NODE_PROPERTY(window_center_sd_map, double, "Window center for sd map", 4.0); - NODE_PROPERTY(window_width_sd_map, double, "Window width for sd map", 8.0); - NODE_PROPERTY(scaling_factor_sd_map, double, "Scale factor for sd map", 100.0); + bool imaging_prep_time_from_protocol = true; - NODE_PROPERTY(perform_hole_filling, bool, "Whether to perform hole filling on map", true); - NODE_PROPERTY(max_size_hole, int, "Maximal size for hole", 20); + bool send_map = true; + bool send_sd_map = true; - NODE_PROPERTY(std_thres_masking, double, "Number of noise std for masking", 3.0); - NODE_PROPERTY(mapping_with_masking, bool, "Whether to compute and apply a mask for mapping", true); + std::string color_lut_map = "GadgetronParametricMap.pal"; + double window_center_map = 4.0; + double window_width_map = 8.0; - // ------------------------------------------------------------------------------------ + std::string color_lut_map_3T = "GadgetronParametricMap_3T.pal"; + double window_center_map_3T = 4.0; + double window_width_map_3T = 8.0; + + double scaling_factor_map = 10.0; + + std::string color_lut_sd_map = "GadgetronParametricSDMap.pal"; + double window_center_sd_map = 4.0; + double window_width_sd_map = 8.0; + double scaling_factor_sd_map = 100.0; + + bool perform_hole_filling = true; + int max_size_hole = 20; + + double std_thres_masking = 3.0; + bool mapping_with_masking = true; + }; + + CmrParametricMappingGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp index 45340038..5b6740f7 100644 --- a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp @@ -12,8 +12,9 @@ namespace Gadgetron { - CmrParametricT1SRMappingGadget::CmrParametricT1SRMappingGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + CmrParametricT1SRMappingGadget::CmrParametricT1SRMappingGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -22,7 +23,7 @@ namespace Gadgetron { GADGET_THROW("acquisitionSystemInformation not found in header. Bailing out"); } - if (this->imaging_prep_time_from_protocol) + if (params_.imaging_prep_time_from_protocol) { this->prep_times_ = h.sequence_parameters->t_i; // TI is in the unit of seconds GDEBUG_STREAM("Read prep times from from protocol : " << this->prep_times_.size() << " [ "); @@ -39,7 +40,7 @@ namespace Gadgetron { { try { - if (perform_timing) { gt_timer_.start("CmrParametricT1SRMappingGadget::perform_mapping"); } + if (params_.perform_timing) { gt_timer_.start("CmrParametricT1SRMappingGadget::perform_mapping"); } GDEBUG_CONDITION_STREAM(verbose, "CmrParametricT1SRMappingGadget::perform_mapping(...) starts ... "); @@ -65,7 +66,7 @@ namespace Gadgetron { gt_exporter_.export_array(mag, debug_folder_full_path_ + "CmrParametricT1SRMapping_data_mag"); } - bool need_sd_map = send_sd_map; + bool need_sd_map = params_.send_sd_map; Gadgetron::GadgetronTimer gt_timer(false); @@ -74,33 +75,33 @@ namespace Gadgetron { Gadgetron::CmrT1SRMapping t1_sr; - t1_sr.fill_holes_in_maps_ = perform_hole_filling; - t1_sr.max_size_of_holes_ = max_size_hole; + t1_sr.fill_holes_in_maps_ = params_.perform_hole_filling; + t1_sr.max_size_of_holes_ = params_.max_size_hole; t1_sr.compute_SD_maps_ = need_sd_map; t1_sr.ti_.resize(N, 0); memcpy(&(t1_sr.ti_)[0], &this->prep_times_[0], sizeof(float)*N); // set the anchor image TS - size_t anchor_ind = this->anchor_image_index; + size_t anchor_ind = params_.anchor_image_index; if (anchor_ind < N) { - t1_sr.ti_[anchor_ind] = this->anchor_TS; + t1_sr.ti_[anchor_ind] = params_.anchor_TS; } t1_sr.data_.create(RO, E1, N, S, SLC, mag.begin()); - t1_sr.max_iter_ = max_iter; - t1_sr.thres_fun_ = thres_func; - t1_sr.max_map_value_ = max_T1; + t1_sr.max_iter_ = params_.max_iter; + t1_sr.thres_fun_ = params_.thres_func; + t1_sr.max_map_value_ = params_.max_T1; t1_sr.verbose_ = verbose; t1_sr.debug_folder_ = debug_folder_full_path_; - t1_sr.perform_timing_ = perform_timing; + t1_sr.perform_timing_ = params_.perform_timing; // ------------------------------------------------------------- // compute mask if needed - if (mapping_with_masking) + if (params_.mapping_with_masking) { t1_sr.mask_for_mapping_.create(RO, E1, SLC); @@ -144,9 +145,9 @@ namespace Gadgetron { GDEBUG_STREAM("CmrParametricT1SRMappingGadget, find incoming image has scale factor of " << scale_factor); - if (perform_timing) { gt_timer.start("CmrParametricT1SRMappingGadget::compute_mask_for_mapping"); } + if (params_.perform_timing) { gt_timer.start("CmrParametricT1SRMappingGadget::compute_mask_for_mapping"); } this->compute_mask_for_mapping(mag, t1_sr.mask_for_mapping_, (float)scale_factor); - if (perform_timing) { gt_timer.stop(); } + if (params_.perform_timing) { gt_timer.stop(); } if (!debug_folder_full_path_.empty()) { @@ -157,9 +158,9 @@ namespace Gadgetron { // ------------------------------------------------------------- // perform mapping - if (perform_timing) { gt_timer.start("CmrParametricT1SRMappingGadget, t1_sr.perform_parametric_mapping"); } + if (params_.perform_timing) { gt_timer.start("CmrParametricT1SRMappingGadget, t1_sr.perform_parametric_mapping"); } t1_sr.perform_parametric_mapping(); - if (perform_timing) { gt_timer.stop(); } + if (params_.perform_timing) { gt_timer.stop(); } size_t num_para = t1_sr.get_num_of_paras(); @@ -256,7 +257,7 @@ namespace Gadgetron { // ------------------------------------------------------------- - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } catch (...) { diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.h b/gadgets/cmr/CmrParametricT1SRMappingGadget.h index 97968444..a76bf230 100644 --- a/gadgets/cmr/CmrParametricT1SRMappingGadget.h +++ b/gadgets/cmr/CmrParametricT1SRMappingGadget.h @@ -15,20 +15,28 @@ namespace Gadgetron { public: typedef CmrParametricMappingGadget BaseClass; - CmrParametricT1SRMappingGadget(const Core::Context& context, const Core::GadgetProperties& properties); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix): BaseClass::Parameters(prefix, "T1SR Mapping") { + register_parameter("max-iter", &max_iter, "Maximal number of iterations"); + register_parameter("thres-func", &thres_func, "Threshold for minimal change of cost function"); + register_parameter("max-T1", &max_T1, "Maximal T1 allowed in mapping (ms)"); - /// ------------------------------------------------------------------------------------ - /// parameters to control the mapping - /// ------------------------------------------------------------------------------------ + register_parameter("anchor-image-index", &anchor_image_index, "Index for anchor image; by default, the first image is the anchor (without SR pulse)"); + register_parameter("anchor-TS", &anchor_TS, "Saturation time for anchor"); + } - NODE_PROPERTY(max_iter, size_t, "Maximal number of iterations", 150); - NODE_PROPERTY(thres_func, double, "Threshold for minimal change of cost function", 1e-4); - NODE_PROPERTY(max_T1, double, "Maximal T1 allowed in mapping (ms)", 4000); + size_t max_iter = 150; + double thres_func = 1e-4; + double max_T1 = 4000; - NODE_PROPERTY(anchor_image_index, size_t, "Index for anchor image; by default, the first image is the anchor (without SR pulse)", 0); - NODE_PROPERTY(anchor_TS, double, "Saturation time for anchor", 10000); + size_t anchor_image_index = 0; + double anchor_TS = 10000; + }; + + CmrParametricT1SRMappingGadget(const Core::MrdContext& context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.cpp b/gadgets/cmr/CmrParametricT2MappingGadget.cpp index b6330de5..5750b3ea 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT2MappingGadget.cpp @@ -12,8 +12,9 @@ namespace Gadgetron { - CmrParametricT2MappingGadget::CmrParametricT2MappingGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + CmrParametricT2MappingGadget::CmrParametricT2MappingGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { auto& h = context.header; @@ -57,7 +58,7 @@ namespace Gadgetron { { try { - if (perform_timing) { gt_timer_.start("CmrParametricT2MappingGadget::perform_mapping"); } + if (params_.perform_timing) { gt_timer_.start("CmrParametricT2MappingGadget::perform_mapping"); } GDEBUG_CONDITION_STREAM(verbose, "CmrParametricT2MappingGadget::perform_mapping(...) starts ... "); @@ -83,7 +84,7 @@ namespace Gadgetron { gt_exporter_.export_array(mag, debug_folder_full_path_ + "CmrParametricT2Mapping_data_mag"); } - bool need_sd_map = send_sd_map; + bool need_sd_map = params_.send_sd_map; Gadgetron::GadgetronTimer gt_timer(false); @@ -92,8 +93,8 @@ namespace Gadgetron { Gadgetron::CmrT2Mapping t2_mapper; - t2_mapper.fill_holes_in_maps_ = perform_hole_filling; - t2_mapper.max_size_of_holes_ = max_size_hole; + t2_mapper.fill_holes_in_maps_ = params_.perform_hole_filling; + t2_mapper.max_size_of_holes_ = params_.max_size_hole; t2_mapper.compute_SD_maps_ = need_sd_map; t2_mapper.ti_.resize(N, 0); @@ -101,17 +102,17 @@ namespace Gadgetron { t2_mapper.data_.create(RO, E1, N, S, SLC, mag.begin()); - t2_mapper.max_iter_ = max_iter; - t2_mapper.thres_fun_ = thres_func; - t2_mapper.max_map_value_ = max_T2; + t2_mapper.max_iter_ = params_.max_iter; + t2_mapper.thres_fun_ = params_.thres_func; + t2_mapper.max_map_value_ = params_.max_T2; t2_mapper.verbose_ = verbose; t2_mapper.debug_folder_ = debug_folder_full_path_; - t2_mapper.perform_timing_ = perform_timing; + t2_mapper.perform_timing_ = params_.perform_timing; // ------------------------------------------------------------- // compute mask if needed - if (mapping_with_masking) + if (params_.mapping_with_masking) { t2_mapper.mask_for_mapping_.create(RO, E1, SLC); @@ -149,9 +150,9 @@ namespace Gadgetron { GDEBUG_STREAM("CmrParametricT2MappingGadget, find incoming image has scale factor of " << scale_factor); - if (perform_timing) { gt_timer.start("CmrParametricT2MappingGadget::compute_mask_for_mapping"); } + if (params_.perform_timing) { gt_timer.start("CmrParametricT2MappingGadget::compute_mask_for_mapping"); } this->compute_mask_for_mapping(mag, t2_mapper.mask_for_mapping_, (float)scale_factor); - if (perform_timing) { gt_timer.stop(); } + if (params_.perform_timing) { gt_timer.stop(); } if (!debug_folder_full_path_.empty()) { @@ -162,9 +163,9 @@ namespace Gadgetron { // ------------------------------------------------------------- // perform mapping - if (perform_timing) { gt_timer.start("CmrParametricT2MappingGadget, t2_mapper.perform_parametric_mapping"); } + if (params_.perform_timing) { gt_timer.start("CmrParametricT2MappingGadget, t2_mapper.perform_parametric_mapping"); } t2_mapper.perform_parametric_mapping(); - if (perform_timing) { gt_timer.stop(); } + if (params_.perform_timing) { gt_timer.stop(); } size_t num_para = t2_mapper.get_num_of_paras(); @@ -261,7 +262,7 @@ namespace Gadgetron { // ------------------------------------------------------------- - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } } catch (...) { diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.h b/gadgets/cmr/CmrParametricT2MappingGadget.h index a06eaab4..0bbda7b3 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.h +++ b/gadgets/cmr/CmrParametricT2MappingGadget.h @@ -14,18 +14,23 @@ namespace Gadgetron { { public: typedef CmrParametricMappingGadget BaseClass; + + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix): BaseClass::Parameters(prefix, "T2 Mapping") { + register_parameter("max-iter", &max_iter, "Maximal number of iterations"); + register_parameter("thres-func", &thres_func, "Threshold for minimal change of cost function"); + register_parameter("max-T2", &max_T2, "Maximal T2 allowed in mapping (ms)"); + } - CmrParametricT2MappingGadget(const Core::Context& context, const Core::GadgetProperties& properties); + size_t max_iter = 150; + double thres_func = 1e-4; + double max_T2 = 4000; + }; - /// ------------------------------------------------------------------------------------ - /// parameters to control the mapping - /// ------------------------------------------------------------------------------------ - - NODE_PROPERTY(max_iter, size_t, "Maximal number of iterations", 150); - NODE_PROPERTY(thres_func, double, "Threshold for minimal change of cost function", 1e-4); - NODE_PROPERTY(max_T2, double, "Maximal T2 allowed in mapping (ms)", 4000); + CmrParametricT2MappingGadget(const Core::MrdContext& context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp index 8dd2ef44..232b0a06 100644 --- a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp +++ b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp @@ -79,19 +79,20 @@ namespace Gadgetron { // ---------------------------------------------------- - CmrRealTimeLAXCineAIAnalysisGadget::CmrRealTimeLAXCineAIAnalysisGadget(const Core::Context& context, const Core::GadgetProperties& properties) - : BaseClass(context, properties) + CmrRealTimeLAXCineAIAnalysisGadget::CmrRealTimeLAXCineAIAnalysisGadget(const Core::MrdContext& context, const Parameters& params) + : BaseClass(context, params) + , params_(params) { try { - std::string gadgetron_home = context.paths.gadgetron_home.generic_string(); - boost::filesystem::path gadgetron_python_path = context.paths.gadgetron_home / "share" / "gadgetron" / "python"; + std::string pingvin_home = context.paths.pingvin_home.generic_string(); + std::filesystem::path pingvin_python_path = context.paths.pingvin_home / "share" / "pingvin" / "python"; Gadgetron::initialize_python(); - Gadgetron::add_python_path(gadgetron_python_path.generic_string()); - this->gt_home_ = gadgetron_python_path.generic_string(); + Gadgetron::add_python_path(pingvin_python_path.generic_string()); + this->gt_home_ = pingvin_python_path.generic_string(); - boost::filesystem::path model_path = context.paths.gadgetron_home / "share" / "gadgetron" / "python" / this->model_dest; + std::filesystem::path model_path = context.paths.pingvin_home / "share" / "pingvin" / "python" / params_.model_dest; Gadgetron::add_python_path(model_path.generic_string()); this->gt_model_home_ = model_path.generic_string(); @@ -134,9 +135,9 @@ namespace Gadgetron { GDEBUG_STREAM("meas_max_idx_.slice is " << meas_max_idx_.slice.value_or(0)); // load the model - if (this->perform_AI) + if (params_.perform_AI) { - std::string model_file_name = this->gt_model_home_ + "/" + this->model_file; + std::string model_file_name = this->gt_model_home_ + "/" + params_.model_file; boost::filesystem::path p(model_file_name); if (boost::filesystem::exists(p) && boost::filesystem::is_regular_file(p)) @@ -151,12 +152,12 @@ namespace Gadgetron { // check the model file, if not exists or invalid, download it gt_timer_.start("gadgetron_cmr_landmark_detection_util, check_and_get_model"); PythonFunction<> check_and_get_model("gadgetron_cmr_landmark_detection_util", "check_and_get_model"); - check_and_get_model(this->model_url, this->model_file, this->gt_model_home_, this->model_file_sha256); + check_and_get_model(params_.model_url, params_.model_file, this->gt_model_home_, params_.model_file_sha256); gt_timer_.stop(); // load model using the singleton gt_timer_.start("CmrRealTimeLAXCineAIModel, load model"); - model_ = CmrRealTimeLAXCineAIModel::instance()->get_model(this->gt_model_home_, this->model_file); + model_ = CmrRealTimeLAXCineAIModel::instance()->get_model(this->gt_model_home_, params_.model_file); gt_timer_.stop(); } } @@ -164,7 +165,7 @@ namespace Gadgetron { void CmrRealTimeLAXCineAIAnalysisGadget::process(Core::InputChannel& in, Core::OutputChannel& out) { for (auto m1 : in) { - if (perform_timing) { gt_timer_local_.start("CmrRealTimeLAXCineAIAnalysisGadget::process"); } + if (params_.perform_timing) { gt_timer_local_.start("CmrRealTimeLAXCineAIAnalysisGadget::process"); } GDEBUG_CONDITION_STREAM(verbose, "CmrRealTimeLAXCineAIAnalysisGadget::process(...) starts ... "); @@ -226,7 +227,7 @@ namespace Gadgetron { // ------------------------------------------------------------- - if (perform_timing) { gt_timer_local_.stop(); } + if (params_.perform_timing) { gt_timer_local_.stop(); } } } @@ -409,7 +410,7 @@ namespace Gadgetron { double FOV_RO = lax_container(0, 0).header_.field_of_view[0]; double FOV_E1 = lax_container(0, 0).header_.field_of_view[1]; - double pixel_size = this->pixel_size_send; + double pixel_size = this->params_.pixel_size_send; size_t new_RO = (size_t)(FOV_RO / pixel_size + 0.5); size_t new_E1 = (size_t)(FOV_E1 / pixel_size + 0.5); @@ -489,7 +490,7 @@ namespace Gadgetron { gt_timer_.start("gadgetron_cmr_landmark_detection_util, perform_cmr_landmark_detection"); PythonFunction< hoNDArray, hoNDArray > perform_cmr_landmark_detection("gadgetron_cmr_landmark_detection", "perform_cmr_landmark_detection"); float p_thresh=0.1; - std::tie(pts, probs) = perform_cmr_landmark_detection(lax_images, this->model_, p_thresh, this->oper_RO, this->oper_E1); + std::tie(pts, probs) = perform_cmr_landmark_detection(lax_images, this->model_, p_thresh, this->params_.oper_RO, this->params_.oper_E1); gt_timer_.stop(); std::stringstream pts_stream; diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h index c9d8b770..d926a881 100644 --- a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h +++ b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h @@ -18,23 +18,32 @@ namespace Gadgetron { typedef GenericReconImageArrayBase BaseClass; typedef hoNDImageContainer2D < hoMRImage > ImageContainerMagType; - CmrRealTimeLAXCineAIAnalysisGadget(const Core::Context &context, const Core::GadgetProperties &properties); - - /// ------------------------------------------------------------------------------------ - /// parameters to control the AI - /// ------------------------------------------------------------------------------------ - NODE_PROPERTY(perform_AI, bool, "Whether to perform AI", true); - - NODE_PROPERTY(model_file, std::string, "Cine AI ONNX model file for lax landmark detection", "CMR_landmark_network_RO_320_E1_320_CH2_CH3_CH4_Myo_Pts_sFOV_LossMultiSoftProb_KLD_Dice_Pytorch_1.8.0a0+37c1f4a_2021-08-08_20210808_085042.onnx"); - NODE_PROPERTY(model_file_sha256, std::string, "Checksum sha256 of the model to check its integrity", "48efe3e70b1ff083c9dd0066469f62bf495e52857d68893296e7375b69f691e4"); - NODE_PROPERTY(oper_RO, size_t, "Operation image size for AI, RO", 320); - NODE_PROPERTY(oper_E1, size_t, "Operation image size for AI, E1", 320); - NODE_PROPERTY(pixel_size_send, double, "Pixel size used for AI and image sending", 1.0); - - NODE_PROPERTY(model_url, std::string, "url to download the model", "https://gadgetrondata.blob.core.windows.net/cmr-ai-models/"); - NODE_PROPERTY(model_dest, std::string, "destination folder to install model, under ${GADGETRON_INSTALL_PYTHON_MODULE_PATH}", "cmr_lax_landmark_detection"); + struct Parameters : public BaseClass::Parameters { + Parameters(const std::string& prefix): BaseClass::Parameters(prefix, "CmrRealTimeLAXCineAIAnalysisGadget") { + register_parameter("perform-AI", &perform_AI, "Whether to perform AI"); + register_parameter("model-file", &model_file, "Cine AI ONNX model file for lax landmark detection"); + register_parameter("model-file-sha256", &model_file_sha256, "Checksum sha256 of the model to check its integrity"); + register_parameter("oper-RO", &oper_RO, "Operation image size for AI, RO"); + register_parameter("oper-E1", &oper_E1, "Operation image size for AI, E1"); + register_parameter("pixel-size-send", &pixel_size_send, "Pixel size used for AI and image sending"); + register_parameter("model-url", &model_url, "url to download the model"); + register_parameter("model-dest", &model_dest, "destination folder to install model, under ${GADGETRON_INSTALL_PYTHON_MODULE_PATH}"); + }; + + bool perform_AI = true; + std::string model_file = "CMR_landmark_network_RO_320_E1_320_CH2_CH3_CH4_Myo_Pts_sFOV_LossMultiSoftProb_KLD_Dice_Pytorch_1.8.0a0+37c1f4a_2021-08-08_20210808_085042.onnx"; + std::string model_file_sha256 = "48efe3e70b1ff083c9dd0066469f62bf495e52857d68893296e7375b69f691e4"; + size_t oper_RO = 320; + size_t oper_E1 = 320; + double pixel_size_send = 1.0; + std::string model_url = "https://gadgetrondata.blob.core.windows.net/cmr-ai-models/"; + std::string model_dest = "cmr_lax_landmark_detection"; + }; + + CmrRealTimeLAXCineAIAnalysisGadget(const Core::MrdContext &context, const Parameters& params); protected: + const Parameters params_; std::string gt_home_; std::string gt_model_home_; diff --git a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp index 290a55ac..55aa9029 100644 --- a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp +++ b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp @@ -35,7 +35,7 @@ mrd::ImageArray Gadgetron::PureCmrCartesianKSpaceBinningCineGadget::process_func size_t encoding = 0; auto result = perform_binning(args.buffers[encoding], encoding); set_image_header(args.buffers[encoding], result.image, encoding); - set_time_stamps(result.image, result.acquisition_time, result.capture_time, time_tick); + set_time_stamps(result.image, result.acquisition_time, result.capture_time, params_.time_tick); prepare_image_array(result.image, 0, 2, GADGETRON_IMAGE_RETRO); return std::move(result.image); } @@ -45,45 +45,45 @@ CmrKSpaceBinning PureCmrCartesianKSpaceBinningCineGadget::create_binner() // binner.perform_timing_ = this->perform_timing; // binner.verbose_ = this->verbose; - binner.use_multiple_channel_recon_ = this->use_multiple_channel_recon; + binner.use_multiple_channel_recon_ = params_.use_multiple_channel_recon; binner.use_paralell_imaging_binning_recon_ = true; - binner.use_nonlinear_binning_recon_ = this->use_nonlinear_binning_recon; + binner.use_nonlinear_binning_recon_ = params_.use_nonlinear_binning_recon; binner.estimate_respiratory_navigator_ = true; - binner.respiratory_navigator_moco_reg_strength_ = this->respiratory_navigator_moco_reg_strength; - binner.respiratory_navigator_moco_iters_ = this->respiratory_navigator_moco_iters; + binner.respiratory_navigator_moco_reg_strength_ = params_.respiratory_navigator_moco_reg_strength; + binner.respiratory_navigator_moco_iters_ = params_.respiratory_navigator_moco_iters; - binner.time_tick_ = this->time_tick; + binner.time_tick_ = params_.time_tick; binner.trigger_time_index_ = 0; - binner.arrhythmia_rejector_factor_ = this->arrhythmia_rejector_factor; - - binner.grappa_kSize_RO_ = this->grappa_kSize_RO; - binner.grappa_kSize_E1_ = this->grappa_kSize_E1; - binner.grappa_reg_lamda_ = this->grappa_reg_lamda; - binner.downstream_coil_compression_num_modesKept_ = this->downstream_coil_compression_num_modesKept; - binner.downstream_coil_compression_thres_ = this->downstream_coil_compression_thres; - - binner.kspace_binning_interpolate_heart_beat_images_ = this->kspace_binning_interpolate_heart_beat_images; - binner.kspace_binning_navigator_acceptance_window_ = this->kspace_binning_navigator_acceptance_window; - - binner.kspace_binning_moco_reg_strength_ = this->kspace_binning_moco_reg_strength; - binner.kspace_binning_moco_iters_ = this->kspace_binning_moco_iters; - - binner.kspace_binning_max_temporal_window_ = this->kspace_binning_max_temporal_window; - binner.kspace_binning_minimal_cardiac_phase_width_ = this->kspace_binning_minimal_cardiac_phase_width; - binner.kspace_binning_kSize_RO_ = this->kspace_binning_kSize_RO; - binner.kspace_binning_kSize_E1_ = this->kspace_binning_kSize_E1; - binner.kspace_binning_reg_lamda_ = this->kspace_binning_reg_lamda; - binner.kspace_binning_linear_iter_max_ = this->kspace_binning_linear_iter_max; - binner.kspace_binning_linear_iter_thres_ = this->kspace_binning_linear_iter_thres; - binner.kspace_binning_nonlinear_iter_max_ = this->kspace_binning_nonlinear_iter_max; - binner.kspace_binning_nonlinear_iter_thres_ = this->kspace_binning_nonlinear_iter_thres; - binner.kspace_binning_nonlinear_data_fidelity_lamda_ = this->kspace_binning_nonlinear_data_fidelity_lamda; - binner.kspace_binning_nonlinear_image_reg_lamda_ = this->kspace_binning_nonlinear_image_reg_lamda; - binner.kspace_binning_nonlinear_reg_N_weighting_ratio_ = this->kspace_binning_nonlinear_reg_N_weighting_ratio; - binner.kspace_binning_nonlinear_reg_use_coil_sen_map_ = this->kspace_binning_nonlinear_reg_use_coil_sen_map; - binner.kspace_binning_nonlinear_reg_with_approx_coeff_ = this->kspace_binning_nonlinear_reg_with_approx_coeff; - binner.kspace_binning_nonlinear_reg_wav_name_ = this->kspace_binning_nonlinear_reg_wav_name; + binner.arrhythmia_rejector_factor_ = params_.arrhythmia_rejector_factor; + + binner.grappa_kSize_RO_ = params_.grappa_kSize_RO; + binner.grappa_kSize_E1_ = params_.grappa_kSize_E1; + binner.grappa_reg_lamda_ = params_.grappa_reg_lamda; + binner.downstream_coil_compression_num_modesKept_ = params_.downstream_coil_compression_num_modesKept; + binner.downstream_coil_compression_thres_ = params_.downstream_coil_compression_thres; + + binner.kspace_binning_interpolate_heart_beat_images_ = params_.kspace_binning_interpolate_heart_beat_images; + binner.kspace_binning_navigator_acceptance_window_ = params_.kspace_binning_navigator_acceptance_window; + + binner.kspace_binning_moco_reg_strength_ = params_.kspace_binning_moco_reg_strength; + binner.kspace_binning_moco_iters_ = params_.kspace_binning_moco_iters; + + binner.kspace_binning_max_temporal_window_ = params_.kspace_binning_max_temporal_window; + binner.kspace_binning_minimal_cardiac_phase_width_ = params_.kspace_binning_minimal_cardiac_phase_width; + binner.kspace_binning_kSize_RO_ = params_.kspace_binning_kSize_RO; + binner.kspace_binning_kSize_E1_ = params_.kspace_binning_kSize_E1; + binner.kspace_binning_reg_lamda_ = params_.kspace_binning_reg_lamda; + binner.kspace_binning_linear_iter_max_ = params_.kspace_binning_linear_iter_max; + binner.kspace_binning_linear_iter_thres_ = params_.kspace_binning_linear_iter_thres; + binner.kspace_binning_nonlinear_iter_max_ = params_.kspace_binning_nonlinear_iter_max; + binner.kspace_binning_nonlinear_iter_thres_ = params_.kspace_binning_nonlinear_iter_thres; + binner.kspace_binning_nonlinear_data_fidelity_lamda_ = params_.kspace_binning_nonlinear_data_fidelity_lamda; + binner.kspace_binning_nonlinear_image_reg_lamda_ = params_.kspace_binning_nonlinear_image_reg_lamda; + binner.kspace_binning_nonlinear_reg_N_weighting_ratio_ = params_.kspace_binning_nonlinear_reg_N_weighting_ratio; + binner.kspace_binning_nonlinear_reg_use_coil_sen_map_ = params_.kspace_binning_nonlinear_reg_use_coil_sen_map; + binner.kspace_binning_nonlinear_reg_with_approx_coeff_ = params_.kspace_binning_nonlinear_reg_with_approx_coeff; + binner.kspace_binning_nonlinear_reg_wav_name_ = params_.kspace_binning_nonlinear_reg_wav_name; return binner; } @@ -97,7 +97,7 @@ PureCmrCartesianKSpaceBinningCineGadget::BinningResult PureCmrCartesianKSpaceBin size_t S = recon_bit.data.data.get_size(5); size_t SLC = recon_bit.data.data.get_size(6); - size_t binned_N = number_of_output_phases; + size_t binned_N = params_.number_of_output_phases; auto binner = create_binner(); BinningResult result; @@ -138,8 +138,11 @@ PureCmrCartesianKSpaceBinningCineGadget::BinningResult PureCmrCartesianKSpaceBin } PureCmrCartesianKSpaceBinningCineGadget::PureCmrCartesianKSpaceBinningCineGadget( - const Core::Context& context, const Core::GadgetProperties& props) - : PureGadget(context,props) { + const Core::MrdContext& context, const Parameters& params) + : MRPureGadget(context, params) + , params_(params) + , verbose(params_.verbose) +{ auto h = context.header; size_t NE = h.encoding.size(); diff --git a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h index 9894cbd1..1aa267cf 100644 --- a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h +++ b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h @@ -9,88 +9,118 @@ #include "ImageArraySendMixin.h" namespace Gadgetron { - class PureCmrCartesianKSpaceBinningCineGadget : public Core::PureGadget, public ImageArraySendMixin { + class PureCmrCartesianKSpaceBinningCineGadget : public Core::MRPureGadget, public ImageArraySendMixin { public: - PureCmrCartesianKSpaceBinningCineGadget(const Core::Context& context, const Core::GadgetProperties& props); - - mrd::ImageArray process_function(mrd::ReconData args) const override; - - NODE_PROPERTY(verbose,bool,"Verbose",false); - /// parameters for workflow - NODE_PROPERTY( - use_multiple_channel_recon, bool, "Whether to perform multi-channel recon in the raw data step", true); - NODE_PROPERTY(use_nonlinear_binning_recon, bool, "Whether to non-linear recon in the binning step", true); - NODE_PROPERTY(number_of_output_phases, size_t, "Number of output phases after binning", 30); - - NODE_PROPERTY(send_out_raw, bool, "Whether to set out raw images", false); - NODE_PROPERTY( - send_out_multiple_series_by_slice, bool, "Whether to set out binning images as multiple series", false); - - /// parameters for raw image reconstruction - NODE_PROPERTY(arrhythmia_rejector_factor, float, - "If a heart beat RR is not in the range of [ (1-arrhythmiaRejectorFactor)*meanRR " - "(1+arrhythmiaRejectorFactor)*meanRR], it will be rejected", - 0.25); - - NODE_PROPERTY(grappa_kSize_RO, int, "Raw data recon, kernel size RO", 5); - NODE_PROPERTY(grappa_kSize_E1, int, "Raw data recon, kernel size E1", 4); - NODE_PROPERTY(grappa_reg_lamda, double, "Raw data recon, kernel calibration regularization", 0.0005); - - NODE_PROPERTY(downstream_coil_compression_num_modesKept, size_t, - "Number of modes kept for down stream coil compression in raw recon step", 0); - NODE_PROPERTY(downstream_coil_compression_thres, double, - "Threshold for determining number of kept modes in the down stream coil compression", 0.01); - - /// parameters for kspace binning - NODE_PROPERTY( - respiratory_navigator_moco_reg_strength, double, "Regularization strength of respiratory moco", 6.0); - - NODE_PROPERTY(respiratory_navigator_moco_iters, std::vector, - "Number of iterations for respiratory moco", (std::vector{ 1, 32, 100, 100 })); + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix) : Core::NodeParameters(prefix) { + register_parameter("verbose", &verbose, "Verbose"); + register_parameter("use-multiple-channel-recon", &use_multiple_channel_recon, "Whether to perform multi-channel recon in the raw data step"); + register_parameter("use-nonlinear-binning-recon", &use_nonlinear_binning_recon, "Whether to non-linear recon in the binning step"); + register_parameter("number-of-output-phases", &number_of_output_phases, "Number of output phases after binning"); + register_parameter("send-out-raw", &send_out_raw, "Whether to set out raw images"); + register_parameter("send-out-multiple-series-by-slice", &send_out_multiple_series_by_slice, "Whether to set out binning images as multiple series"); + register_parameter("arrhythmia-rejector-factor", &arrhythmia_rejector_factor, + "If a heart beat RR is not in the range of [ (1-arrhythmiaRejectorFactor)*meanRR " + "(1+arrhythmiaRejectorFactor)*meanRR], it will be rejected"); + register_parameter("grappa-kSize-RO", &grappa_kSize_RO, "Raw data recon, kernel size RO"); + register_parameter("grappa-kSize-E1", &grappa_kSize_E1, "Raw data recon, kernel size E1"); + register_parameter("grappa-reg-lamda", &grappa_reg_lamda, "Raw data recon, kernel calibration regularization"); + register_parameter("downstream-coil-compression-num-modesKept", &downstream_coil_compression_num_modesKept, + "Number of modes kept for down stream coil compression in raw recon step"); + register_parameter("downstream-coil-compression-thres", &downstream_coil_compression_thres, + "Threshold for determining number of kept modes in the down stream coil compression"); + register_parameter("respiratory-navigator-moco-reg-strength", &respiratory_navigator_moco_reg_strength, + "Regularization strength of respiratory moco"); + register_multitoken("respiratory-navigator-moco-iters", &respiratory_navigator_moco_iters, + "Number of iterations for respiratory moco"); + register_parameter("kspace-binning-interpolate-heart-beat-images", &kspace_binning_interpolate_heart_beat_images, + "Whether to interpolate best heart beat images"); + register_parameter("kspace-binning-navigator-acceptance-window", &kspace_binning_navigator_acceptance_window, + "Respiratory navigator acceptance window"); + register_parameter("kspace-binning-max-temporal-window", &kspace_binning_max_temporal_window, + "Maximally allowed temporal window ratio for binned kspace"); + register_parameter("kspace-binning-minimal-cardiac-phase-width", &kspace_binning_minimal_cardiac_phase_width, + "Allowed minimal temporal window for binned kspace, in ms"); + register_parameter("kspace-binning-moco-reg-strength", &kspace_binning_moco_reg_strength, + "Regularization strength of binning moco"); + register_multitoken("kspace-binning-moco-iters", &kspace_binning_moco_iters, + "Number of iterations for binning moco"); + register_parameter("kspace-binning-kSize-RO", &kspace_binning_kSize_RO, "Binned kspace recon, kernel size RO"); + register_parameter("kspace-binning-kSize-E1", &kspace_binning_kSize_E1, "Binned kspace recon, kernel size E1"); + register_parameter("kspace-binning-reg-lamda", &kspace_binning_reg_lamda, "Binned kspace recon, kernel calibration regularization"); + register_parameter("kspace-binning-linear-iter-max", &kspace_binning_linear_iter_max, + "Binned kspace recon, maximal number of iterations, linear recon"); + register_parameter("kspace-binning-linear-iter-thres", &kspace_binning_linear_iter_thres, + "Binned kspace recon, iteration threshold, linear recon"); + register_parameter("kspace-binning-nonlinear-iter-max", &kspace_binning_nonlinear_iter_max, + "Binned kspace recon, maximal number of iterations, non-linear recon"); + register_parameter("kspace-binning-nonlinear-iter-thres", &kspace_binning_nonlinear_iter_thres, + "Binned kspace recon, iteration threshold, non-linear recon"); + register_parameter("kspace-binning-nonlinear-data-fidelity-lamda", &kspace_binning_nonlinear_data_fidelity_lamda, + "Binned kspace recon, strength of data fidelity term, non-linear recon"); + register_parameter("kspace-binning-nonlinear-image-reg-lamda", &kspace_binning_nonlinear_image_reg_lamda, + "Binned kspace recon, strength of image term, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-N-weighting-ratio", &kspace_binning_nonlinear_reg_N_weighting_ratio, + "Binned kspace recon, regularization weighting ratio along the N dimension, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-use-coil-sen-map", &kspace_binning_nonlinear_reg_use_coil_sen_map, + "Binned kspace recon, whether to use coil map, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-with-approx-coeff", &kspace_binning_nonlinear_reg_with_approx_coeff, + "Binned kspace recon, whether to keep approximal coefficients, non-linear recon"); + register_parameter("kspace-binning-nonlinear-reg-wav-name", &kspace_binning_nonlinear_reg_wav_name, + "Binned kspace recon, wavelet name, non-linear recon. Possible values: db1, db2, db3, db4, db5"); + register_parameter("time-tick", &time_tick, "Time tick in ms"); + } + + bool verbose = false; + // parameters for workflow + bool use_multiple_channel_recon = true; + bool use_nonlinear_binning_recon = true; + size_t number_of_output_phases = 30; + bool send_out_raw = false; + bool send_out_multiple_series_by_slice = false; + // parameters for raw image reconstruction + float arrhythmia_rejector_factor = 0.25; + int grappa_kSize_RO = 5; + int grappa_kSize_E1 = 4; + double grappa_reg_lamda = 0.0005; + size_t downstream_coil_compression_num_modesKept = 0; + double downstream_coil_compression_thres = 0.01; + // parameters for kspace binning + double respiratory_navigator_moco_reg_strength = 6.0; + std::vector respiratory_navigator_moco_iters = { 1, 32, 100, 100 }; + bool kspace_binning_interpolate_heart_beat_images = true; + double kspace_binning_navigator_acceptance_window = 0.65; + double kspace_binning_max_temporal_window = 2.0; + double kspace_binning_minimal_cardiac_phase_width = 25.0; + double kspace_binning_moco_reg_strength = 12.0; + std::vector kspace_binning_moco_iters = { 24, 64, 100, 100, 100 }; + // parameters for recon on binned kspace + int kspace_binning_kSize_RO = 7; + int kspace_binning_kSize_E1 = 7; + double kspace_binning_reg_lamda = 0.005; + // linear recon step + size_t kspace_binning_linear_iter_max = 90; + double kspace_binning_linear_iter_thres = 0.0015; + // Non-linear recon step + size_t kspace_binning_nonlinear_iter_max = 25; + double kspace_binning_nonlinear_iter_thres = 0.004; + double kspace_binning_nonlinear_data_fidelity_lamda = 1.0; + double kspace_binning_nonlinear_image_reg_lamda = 0.00015; + double kspace_binning_nonlinear_reg_N_weighting_ratio = 10.0; + bool kspace_binning_nonlinear_reg_use_coil_sen_map = false; + bool kspace_binning_nonlinear_reg_with_approx_coeff = true; + std::string kspace_binning_nonlinear_reg_wav_name = "db1"; + float time_tick = 2.5f; + }; - NODE_PROPERTY( - kspace_binning_interpolate_heart_beat_images, bool, "Whether to interpolate best heart beat images", true); - NODE_PROPERTY( - kspace_binning_navigator_acceptance_window, double, "Respiratory navigator acceptance window", 0.65); - NODE_PROPERTY(kspace_binning_max_temporal_window, double, - "Maximally allowed temporal window ratio for binned kspace", 2.0); - NODE_PROPERTY(kspace_binning_minimal_cardiac_phase_width, double, - "Allowed minimal temporal window for binned kspace, in ms", 25.0); + PureCmrCartesianKSpaceBinningCineGadget(const Core::MrdContext& context, const Parameters& params); - NODE_PROPERTY(kspace_binning_moco_reg_strength, double, "Regularization strength of binning moco", 12.0); - NODE_PROPERTY(kspace_binning_moco_iters, std::vector, "Number of iterations for binning moco", - (std::vector{ 24, 64, 100, 100, 100 })); + mrd::ImageArray process_function(mrd::ReconData args) const override; - /// parameters for recon on binned kspace - NODE_PROPERTY(kspace_binning_kSize_RO, int, "Binned kspace recon, kernel size RO", 7); - NODE_PROPERTY(kspace_binning_kSize_E1, int, "Binned kspace recon, kernel size E1", 7); - NODE_PROPERTY( - kspace_binning_reg_lamda, double, "Binned kspace recon, kernel calibration regularization", 0.005); - /// linear recon step - NODE_PROPERTY(kspace_binning_linear_iter_max, size_t, - "Binned kspace recon, maximal number of iterations, linear recon", 90); - NODE_PROPERTY( - kspace_binning_linear_iter_thres, double, "Binned kspace recon, iteration threshold, linear recon", 0.0015); - /// Non-linear recon step - NODE_PROPERTY(kspace_binning_nonlinear_iter_max, size_t, - "Binned kspace recon, maximal number of iterations, non-linear recon", 25); - NODE_PROPERTY(kspace_binning_nonlinear_iter_thres, double, - "Binned kspace recon, iteration threshold, non-linear recon", 0.004); - NODE_PROPERTY(kspace_binning_nonlinear_data_fidelity_lamda, double, - "Binned kspace recon, strength of data fidelity term, non-linear recon", 1.0); - NODE_PROPERTY(kspace_binning_nonlinear_image_reg_lamda, double, - "Binned kspace recon, strength of image term, non-linear recon", 0.00015); - NODE_PROPERTY(kspace_binning_nonlinear_reg_N_weighting_ratio, double, - "Binned kspace recon, regularization weighting ratio along the N dimension, non-linear recon", 10.0); - NODE_PROPERTY(kspace_binning_nonlinear_reg_use_coil_sen_map, bool, - "Binned kspace recon, whether to use coil map, non-linear recon", false); - NODE_PROPERTY(kspace_binning_nonlinear_reg_with_approx_coeff, bool, - "Binned kspace recon, whether to keep approximal coefficients, non-linear recon", true); - NODE_PROPERTY(kspace_binning_nonlinear_reg_wav_name, std::string, - "Binned kspace recon, wavelet name, non-linear recon. Possible values: db1, db2, db3, db4, db5", "db1"); - NODE_PROPERTY(time_tick, float, "Time tick in ms", 2.5f); + bool verbose; private: + const Parameters params_; CmrKSpaceBinning create_binner() const; struct BinningResult { diff --git a/gadgets/debugging/PseudoReplicatorGadget.cpp b/gadgets/debugging/PseudoReplicatorGadget.cpp index e039ed3b..70b1d0c6 100644 --- a/gadgets/debugging/PseudoReplicatorGadget.cpp +++ b/gadgets/debugging/PseudoReplicatorGadget.cpp @@ -3,11 +3,6 @@ namespace Gadgetron { -PseudoReplicatorGadget::PseudoReplicatorGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) -{ -} - void PseudoReplicatorGadget::process(Core::InputChannel& input, Core::OutputChannel& output) { std::mt19937 engine(5489UL); @@ -17,7 +12,7 @@ void PseudoReplicatorGadget::process(Core::InputChannel& input, // First just send the normal data to obtain standard image output.push(reconData); - for (int i = 0; i < repetitions; i++) { + for (int i = 0; i < params_.repetitions; i++) { for (auto& rbit : reconData.buffers) { auto& data = rbit.data.data; diff --git a/gadgets/debugging/PseudoReplicatorGadget.h b/gadgets/debugging/PseudoReplicatorGadget.h index d7440440..a7a9c0e6 100644 --- a/gadgets/debugging/PseudoReplicatorGadget.h +++ b/gadgets/debugging/PseudoReplicatorGadget.h @@ -4,13 +4,24 @@ namespace Gadgetron { -class PseudoReplicatorGadget : public Core::ChannelGadget +class PseudoReplicatorGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Pseudo Replicator") { + register_parameter("repetitions", &repetitions, "Number of pseudoreplicas to produce"); + } - NODE_PROPERTY(repetitions, int, "Number of pseudoreplicas to produce", 10); - PseudoReplicatorGadget(const Core::Context& context, const Core::GadgetProperties& props); + int repetitions = 10; + }; + + PseudoReplicatorGadget(const Core::MrdContext& context, const Parameters& params) + : MRChannelGadget(context, params) + , params_(params) + { } + +protected: + const Parameters params_; void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; diff --git a/gadgets/debugging/RateLimitGadget.cpp b/gadgets/debugging/RateLimitGadget.cpp index 2b5e0688..df3f7388 100644 --- a/gadgets/debugging/RateLimitGadget.cpp +++ b/gadgets/debugging/RateLimitGadget.cpp @@ -5,10 +5,11 @@ namespace Gadgetron { -RateLimitGadget::RateLimitGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) +RateLimitGadget::RateLimitGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) + , params_(params) { - this->sleep_time_ = std::chrono::milliseconds(this->sleep_time_int); + this->sleep_time_ = std::chrono::milliseconds(params_.sleep_time_int); } void RateLimitGadget::process(Core::InputChannel& in, Core::OutputChannel& out) diff --git a/gadgets/debugging/RateLimitGadget.h b/gadgets/debugging/RateLimitGadget.h index 01436bb8..917fb485 100644 --- a/gadgets/debugging/RateLimitGadget.h +++ b/gadgets/debugging/RateLimitGadget.h @@ -5,17 +5,23 @@ namespace Gadgetron{ - class RateLimitGadget : public Core::ChannelGadget + class RateLimitGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix): Core::NodeParameters(prefix, "Rate Limiter") { + register_parameter("sleep-time", &sleep_time_int, "Sleep time in milliseconds"); + } - RateLimitGadget(const Core::Context& context, const Core::GadgetProperties& props); + int sleep_time_int = 0; + }; + + RateLimitGadget(const Core::MrdContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; protected: - NODE_PROPERTY(sleep_time_int, int, "sleep_time", 0); + const Parameters params_; std::chrono::milliseconds sleep_time_; }; diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp index 7e782c08..3359679c 100644 --- a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp +++ b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp @@ -79,17 +79,18 @@ inline void RandNormGenerator::gen(hoNDArray< std::complex >& randNum) } } -WhiteNoiseInjectorGadget::WhiteNoiseInjectorGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) +WhiteNoiseInjectorGadget::WhiteNoiseInjectorGadget(const Core::MrdContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) + , params_(params) , acceFactorE1_(1), acceFactorE2_(1) , is_interleaved_(false), is_embeded_(false), is_seperate_(false), is_external_(false), is_other_(false), is_no_acceleration_(false) { - GDEBUG_STREAM("noise mean is " << noise_mean_); - GDEBUG_STREAM("noise std is " << noise_std_); - GDEBUG_STREAM("add_noise_ref is " << add_noise_ref_); + GDEBUG_STREAM("noise mean is " << params_.noise_mean_); + GDEBUG_STREAM("noise std is " << params_.noise_std_); + GDEBUG_STREAM("add_noise_ref is " << params_.add_noise_ref_); randn_ = new RandGenType(); - randn_->setPara(noise_mean_, noise_std_); + randn_->setPara(params_.noise_mean_, params_.noise_std_); // get the current time and generate a seed time_t rawtime; @@ -191,7 +192,7 @@ void WhiteNoiseInjectorGadget::process(Core::InputChannel& in, bool add_noise = true; if ( is_ref && !is_ref_kspace && (is_seperate_||is_external_) ) { - add_noise = add_noise_ref_; + add_noise = params_.add_noise_ref_; if ( !add_noise ) { diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.h b/gadgets/debugging/WhiteNoiseInjectorGadget.h index 71d101d2..bb6921b7 100644 --- a/gadgets/debugging/WhiteNoiseInjectorGadget.h +++ b/gadgets/debugging/WhiteNoiseInjectorGadget.h @@ -36,18 +36,28 @@ class RandNormGenerator }; /// add white noise to the kspace data -class WhiteNoiseInjectorGadget : public Core::ChannelGadget +class WhiteNoiseInjectorGadget : public Core::MRChannelGadget { public: typedef Gadgetron::RandNormGenerator RandGenType; - WhiteNoiseInjectorGadget(const Core::Context& context, const Core::GadgetProperties& props); + struct Parameters : public Core::NodeParameters { + Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "White Noise Injector") { + register_parameter("noise-mean", &noise_mean_, "Noise mean"); + register_parameter("noise-std", &noise_std_, "Noise standard deviation"); + register_parameter("add-noise-ref", &add_noise_ref_, "Add noise to reference scans"); + } + + float noise_mean_ = 0.0; + float noise_std_ = 1.0; + bool add_noise_ref_ = false; + }; + + WhiteNoiseInjectorGadget(const Core::MrdContext& context, const Parameters& params); ~WhiteNoiseInjectorGadget() override; protected: - NODE_PROPERTY(noise_mean_, float, "Noise mean", 0.0); - NODE_PROPERTY(noise_std_, float, "Noise standard deviation", 1.0); - NODE_PROPERTY(add_noise_ref_, bool, "Add noise to reference scans", false); + const Parameters params_; void process(Core::InputChannel& in, Core::OutputChannel& out) override; diff --git a/gadgets/examples/AcquisitionWaveformBranch.cpp b/gadgets/examples/AcquisitionWaveformBranch.cpp index fa9c3d9e..1afb8367 100644 --- a/gadgets/examples/AcquisitionWaveformBranch.cpp +++ b/gadgets/examples/AcquisitionWaveformBranch.cpp @@ -9,11 +9,6 @@ namespace { namespace Gadgetron::Examples { - AcquisitionWaveformBranch::AcquisitionWaveformBranch( - const Core::Context &, - const Core::GadgetProperties &properties - ) : TypedBranch(properties) {} - void AcquisitionWaveformBranch::process( Core::InputChannel &input, std::map output diff --git a/gadgets/examples/AcquisitionWaveformBranch.h b/gadgets/examples/AcquisitionWaveformBranch.h index b6ef07d5..b06a6b89 100644 --- a/gadgets/examples/AcquisitionWaveformBranch.h +++ b/gadgets/examples/AcquisitionWaveformBranch.h @@ -6,9 +6,12 @@ namespace Gadgetron::Examples { using AcquisitionOrWaveform = std::variant; - class AcquisitionWaveformBranch : public Core::Parallel::TypedBranch { + class AcquisitionWaveformBranch : public Core::Parallel::MRBranch { public: - AcquisitionWaveformBranch(const Core::Context &, const Core::GadgetProperties &); + AcquisitionWaveformBranch(const Core::MrdContext &context, const Core::NodeParameters ¶ms) + : MRBranch(context, params) + {} + void process( Core::InputChannel &, std::map diff --git a/gadgets/examples/ImageLayerer.cpp b/gadgets/examples/ImageLayerer.cpp index 8cba5efa..a193ca98 100644 --- a/gadgets/examples/ImageLayerer.cpp +++ b/gadgets/examples/ImageLayerer.cpp @@ -43,8 +43,6 @@ namespace { namespace Gadgetron::Examples { - ImageLayerer::ImageLayerer(const Core::Context &, const Core::GadgetProperties &properties) : Merge(properties) {} - void ImageLayerer::process(std::map input, Core::OutputChannel output) { auto unchanged = Core::InputChannel(input.at("unchanged"), output); @@ -57,8 +55,6 @@ namespace Gadgetron::Examples { inverted.pop() ); - - GINFO_STREAM("Images combined; pushing out result."); output.push(std::move(merged)); diff --git a/gadgets/examples/ImageLayerer.h b/gadgets/examples/ImageLayerer.h index 81d90d42..d8fcd056 100644 --- a/gadgets/examples/ImageLayerer.h +++ b/gadgets/examples/ImageLayerer.h @@ -5,9 +5,12 @@ namespace Gadgetron::Examples { - class ImageLayerer : public Core::Parallel::Merge { + class ImageLayerer : public Core::Parallel::MRMerge { public: - ImageLayerer(const Core::Context &, const Core::GadgetProperties &); + ImageLayerer(const Core::MrdContext &context, const Core::NodeParameters ¶ms) + : MRMerge(context, params) + {} + void process(std::map, Core::OutputChannel) override; }; } diff --git a/gadgets/grappa/CMakeLists.txt b/gadgets/grappa/CMakeLists.txt index b93cbe0a..50c7a67a 100644 --- a/gadgets/grappa/CMakeLists.txt +++ b/gadgets/grappa/CMakeLists.txt @@ -8,8 +8,6 @@ set(RTGRAPPA_SOURCES common/AcquisitionBuffer.h common/grappa_common.h common/AnnotatedAcquisition.h - ChannelReorderer.cpp - ChannelReorderer.h cpu/WeightsCore.cpp cpu/WeightsCore.h) diff --git a/gadgets/grappa/ChannelReorderer.cpp b/gadgets/grappa/ChannelReorderer.cpp deleted file mode 100644 index d2e0af2d..00000000 --- a/gadgets/grappa/ChannelReorderer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "ChannelReorderer.h" - -#include -#include -#include -#include - -#include "hoNDArray_iterators.h" -#include "hoNDArray_utils.h" - -namespace { - - template - std::vector reorder(std::vector v, const std::vector &reordering) { - std::vector reordered; reordered.reserve(reordering.size()); - for (auto i : reordering) reordered.push_back(v[i]); - return reordered; - } - - mrd::AcquisitionHeader reorder(const mrd::AcquisitionHeader &header, const std::vector &reordering) { - auto reordered_header = header; - - for (uint16_t out_idx = 0; out_idx < reordering.size(); out_idx++) { - auto in_idx = uint16_t(reordering[out_idx]); - } - - return reordered_header; - } -} - -namespace Gadgetron::Grappa -{ - ChannelReorderer::ChannelReorderer( - const Gadgetron::Core::Context &context, - const std::unordered_map &props - ) : PureGadget(context,props), - context(context), - channel_labels(build_channel_label_map()), - uncombined_indices(parse_uncombined_channels()) {} - - AnnotatedAcquisition ChannelReorderer::process_function(mrd::Acquisition acquisition) const { - - auto header = acquisition.head; - auto trajectory = acquisition.trajectory; - auto data = acquisition.data; - - auto reordering = create_reordering(acquisition.Coils()); - - auto channels = spans(data, 1); - auto reordered_channels = reorder( - std::vector>>(channels.begin(), channels.end()), - reordering - ); - - acquisition.head = reorder(header, reordering); - acquisition.data = concat(reordered_channels); - return AnnotatedAcquisition{acquisition, ChannelAnnotation{acquisition.Coils() - uncombined_indices.size(), uncombined_indices.size(), std::move(reordering)}}; - } - - std::map ChannelReorderer::build_channel_label_map() { - - if (!context.header.user_parameters) return std::map{}; - - std::map labels{}; - std::regex pattern{"COIL_(.*)"}; std::smatch match; - - for (auto &pair : context.header.user_parameters->user_parameter_string) { - if (std::regex_search(pair.name, match, pattern)) { - labels[match[0]] = size_t(std::stoi(pair.value)); - } - } - - return std::move(labels); - } - - std::vector ChannelReorderer::parse_uncombined_channels() { - - auto raw = uncombined_channels; - - std::set uncombined{}; - std::vector tokens{}; - boost::split(tokens, raw, boost::is_any_of(",")); - - for (auto token : tokens) { - boost::trim(token); - if (!token.empty()) uncombined.insert(parse_uncombined_channel(token)); - } - - std::vector sorted{uncombined.begin(), uncombined.end()}; - std::sort(sorted.begin(), sorted.end()); - - return sorted; - } - - size_t ChannelReorderer::parse_uncombined_channel(const std::string &token) { - - std::smatch result{}; - - std::regex label_pattern("'(.*)'"); - std::regex index_pattern("(\\d+)"); - - if (std::regex_match(token, result, label_pattern)) { - return channel_labels.at(result[0]); - } - - if (std::regex_match(token, result, index_pattern)) { - return size_t(std::stoi(result[0])); - } - - throw std::runtime_error("Unable to parse uncombined channel list token: " + token); - } - - std::vector ChannelReorderer::create_reordering(size_t number_of_channels) const { - - std::vector reordering(number_of_channels); - std::iota(reordering.begin(), reordering.end(), 0); - - reordering.erase(std::remove_if(reordering.begin(), reordering.end(), [&](auto index) { - return std::find(uncombined_indices.begin(), uncombined_indices.end(), index) != uncombined_indices.end(); - }), reordering.end()); - - reordering.insert(reordering.end(), uncombined_indices.begin(), uncombined_indices.end()); - - return reordering; - } - - GADGETRON_GADGET_EXPORT(ChannelReorderer) -} diff --git a/gadgets/grappa/ChannelReorderer.h b/gadgets/grappa/ChannelReorderer.h deleted file mode 100644 index 0e4c09b7..00000000 --- a/gadgets/grappa/ChannelReorderer.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -#include "common/AnnotatedAcquisition.h" - -#include "PureGadget.h" - -namespace Gadgetron::Grappa { - - /** TODO: This Gadget is not used anywhere anymore... */ - class ChannelReorderer : public Core::PureGadget { - public: - ChannelReorderer(const Core::Context &, const std::unordered_map &); - - AnnotatedAcquisition process_function(mrd::Acquisition acquisition) const override; - - NODE_PROPERTY( - uncombined_channels, std::string, - "Uncombined channels as a comma separated list of channel indices or names (single quoted).", "" - ); - - private: - const Core::Context context; - const std::map channel_labels; - const std::vector uncombined_indices; - - std::map - build_channel_label_map(); - - std::vector - parse_uncombined_channels(); - - size_t - parse_uncombined_channel(const std::string &); - - std::vector - create_reordering(size_t number_of_channels) const; - }; -} \ No newline at end of file diff --git a/gadgets/grappa/SliceAccumulator.h b/gadgets/grappa/SliceAccumulator.h index e072150b..3d8ca220 100644 --- a/gadgets/grappa/SliceAccumulator.h +++ b/gadgets/grappa/SliceAccumulator.h @@ -2,9 +2,8 @@ #include -#include "ChannelReorderer.h" - #include "Node.h" +#include "common/AnnotatedAcquisition.h" namespace Gadgetron::Grappa { diff --git a/gadgets/grappa/grappa_cpu.ini b/gadgets/grappa/grappa_cpu.ini new file mode 100644 index 00000000..2d80f508 --- /dev/null +++ b/gadgets/grappa/grappa_cpu.ini @@ -0,0 +1,20 @@ +[noise] + +[pca] + +[coil-reduction] +coils-out=8 + +[weights] +coil-map-estimation-ks=5 + +[unmixing] +image-series=42 + +[extract] +magnitude=true + +[scale] + +[convert] +type=ushort \ No newline at end of file From b3320599b4749647b0245d6e98fcb009a268ac0b Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 13 Feb 2025 17:28:42 +0000 Subject: [PATCH 13/21] Update all end-to-end tests --- apps/CMakeLists.txt | 4 +- apps/emperor/CMakeLists.txt | 42 -- apps/emperor/pipelines/cartesian_grappa.h | 43 -- apps/pingvin/CMakeLists.txt | 31 +- apps/pingvin/Config.cpp | 415 ------------------ apps/pingvin/Config.h | 60 --- apps/pingvin/Loader.cpp | 33 -- apps/pingvin/Loader.h | 52 --- apps/pingvin/StreamConsumer.h | 189 -------- apps/{emperor => pingvin}/main.cc | 67 ++- apps/pingvin/main.cpp | 133 ------ apps/pingvin/nodes/ParallelProcess.cpp | 4 +- apps/pingvin/nodes/ParallelProcess.h | 8 +- apps/pingvin/nodes/PureStream.cpp | 4 +- apps/pingvin/nodes/PureStream.h | 5 +- .../pipelines/cartesian_grappa.h} | 20 +- apps/pingvin/pipelines/cartesian_spirit.h | 65 +++ apps/pingvin/pipelines/cmr.h | 88 ++++ .../config/cartesian-cine-denoise.conf | 29 ++ .../config/cartesian-grappa-snr.conf | 43 ++ .../config/cartesian-grappa-t2w.conf | 29 ++ .../pipelines/config/cartesian-grappa.conf | 32 ++ ...rtesian-nonlinear-spirit-realtimecine.conf | 38 ++ ...ampling-nonlinear-spirit-realtimecine.conf | 37 ++ .../pipelines/config/cartesian-spirit.conf | 32 ++ .../pipelines/config/cmr-cine-binning.conf | 41 ++ .../pipelines/config/cmr-mapping-t1-sr.conf | 47 ++ .../pipelines/config/cmr-rtcine-lax-ai.conf | 24 + apps/pingvin/pipelines/config/epi.conf | 29 ++ apps/pingvin/pipelines/config/grappa-epi.conf | 40 ++ .../config/stream-cartesian-grappa.conf | 21 + apps/{emperor => pingvin}/pipelines/default.h | 6 +- .../pipelines/denoise.h} | 25 +- apps/{emperor => pingvin}/pipelines/epi.h | 2 +- .../pipelines/file_search.h | 0 apps/{emperor => pingvin}/pipelines/grappa.h | 22 +- apps/pingvin/pipelines/grappa_epi.h | 52 +++ apps/{emperor => pingvin}/pipelines/noise.h | 0 apps/pingvin/pipelines/parallel_bypass.h | 39 ++ .../{emperor => pingvin}/pipelines/pipeline.h | 189 +++++++- apps/pingvin/pipelines/streams.h | 72 +++ apps/pingvin/schema/gadgetron.xsd | 37 -- core/Parameters.h | 63 ++- .../gadgetron_cmr_landmark_detection_util.py | 8 +- gadgets/examples/ImageInverter.h | 2 +- gadgets/grappa/grappa_cpu.ini | 20 - gadgets/mri_core/AccumulatorGadget.cpp | 3 +- gadgets/mri_core/DenoiseGadget.h | 4 +- .../GenericReconImageArrayScalingGadget.h | 2 +- test/e2e/cases/cmr_cine_binning.yml | 4 +- test/e2e/cases/cmr_cine_binning_2slices.yml | 2 +- test/e2e/cases/cmr_mapping_t1_sr.yml | 6 +- test/e2e/cases/cpu_grappa_simple.yml | 2 +- test/e2e/cases/epi_2d.yml | 4 +- .../cases/generic_cartesian_cine_denoise.yml | 4 +- .../cases/generic_cartesian_cine_python.yml | 22 - test/e2e/cases/generic_grappa2x1_3d.yml | 2 +- test/e2e/cases/generic_grappa2x2_3d.yml | 2 +- test/e2e/cases/generic_grappa_T2W.yml | 4 +- test/e2e/cases/generic_grappa_epi_ave.yml | 2 +- ...eneric_grappa_snr_R1_PEFOV100_PERes100.yml | 4 +- ...a_snr_R1_PEFOV100_PERes100_compression.yml | 4 +- ...eneric_grappa_snr_R1_PEFOV100_PERes120.yml | 4 +- .../generic_grappa_snr_R1_PEFOV75_PERes75.yml | 4 +- ...ic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml | 4 +- ...nr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 4 +- ...OV75_PERes75_PF6_8_AsymStrong_InterpON.yml | 4 +- ...ipat_PEFOV75_PERes75_PEOverSampling120.yml | 4 +- ..._ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 4 +- ...c_grappa_snr_R2_spat_PEFOV100_PERes100.yml | 4 +- ...c_grappa_snr_R2_spat_PEFOV100_PERes120.yml | 4 +- ...ric_grappa_snr_R2_spat_PEFOV75_PERes75.yml | 4 +- ...appa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml | 4 +- ..._spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 4 +- ...OV75_PERes75_PF6_8_AsymStrong_InterpON.yml | 4 +- ...c_grappa_snr_R2_tpat_PEFOV100_PERes100.yml | 4 +- ...ric_grappa_snr_R2_tpat_PEFOV75_PERes75.yml | 4 +- ...appa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml | 4 +- ..._tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 4 +- ...spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml | 4 +- ...c_grappa_snr_R3_tpat_PEFOV100_PERes120.yml | 4 +- ...tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml | 4 +- test/e2e/cases/generic_grappa_tse.yml | 4 +- ...eric_nl_spirit_cartesian_sampling_cine.yml | 4 +- ...generic_nl_spirit_random_sampling_cine.yml | 2 +- test/e2e/cases/generic_rtcine_ai_landmark.yml | 4 +- ...eneric_spirit_cartesian_sampling_spat2.yml | 2 +- test/e2e/cases/gpu_grappa_simple.yml | 2 +- test/e2e/cases/parallel_bypass_example.yml | 2 +- test/e2e/cases/simple_gre.yml | 2 +- test/e2e/cases/simple_gre_3d.yml | 2 +- test/e2e/cases/stream_image.yml | 8 +- test/e2e/cases/stream_image_array.yml | 12 +- test/e2e/conftest.py | 8 + test/e2e/test_e2e.py | 4 +- toolboxes/core/cpu/math/CMakeLists.txt | 3 - 96 files changed, 1216 insertions(+), 1236 deletions(-) delete mode 100644 apps/emperor/CMakeLists.txt delete mode 100644 apps/emperor/pipelines/cartesian_grappa.h delete mode 100644 apps/pingvin/Config.cpp delete mode 100644 apps/pingvin/Config.h delete mode 100644 apps/pingvin/Loader.cpp delete mode 100644 apps/pingvin/Loader.h delete mode 100644 apps/pingvin/StreamConsumer.h rename apps/{emperor => pingvin}/main.cc (81%) delete mode 100644 apps/pingvin/main.cpp rename apps/{emperor/pipelines/cmr.h => pingvin/pipelines/cartesian_grappa.h} (77%) create mode 100644 apps/pingvin/pipelines/cartesian_spirit.h create mode 100644 apps/pingvin/pipelines/cmr.h create mode 100644 apps/pingvin/pipelines/config/cartesian-cine-denoise.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-grappa-snr.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-grappa.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf create mode 100644 apps/pingvin/pipelines/config/cartesian-spirit.conf create mode 100644 apps/pingvin/pipelines/config/cmr-cine-binning.conf create mode 100644 apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf create mode 100644 apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf create mode 100644 apps/pingvin/pipelines/config/epi.conf create mode 100644 apps/pingvin/pipelines/config/grappa-epi.conf create mode 100644 apps/pingvin/pipelines/config/stream-cartesian-grappa.conf rename apps/{emperor => pingvin}/pipelines/default.h (86%) rename apps/{emperor/pipelines/cartesian_spirit.h => pingvin/pipelines/denoise.h} (71%) rename apps/{emperor => pingvin}/pipelines/epi.h (95%) rename apps/{emperor => pingvin}/pipelines/file_search.h (100%) rename apps/{emperor => pingvin}/pipelines/grappa.h (64%) create mode 100644 apps/pingvin/pipelines/grappa_epi.h rename apps/{emperor => pingvin}/pipelines/noise.h (100%) create mode 100644 apps/pingvin/pipelines/parallel_bypass.h rename apps/{emperor => pingvin}/pipelines/pipeline.h (73%) create mode 100644 apps/pingvin/pipelines/streams.h delete mode 100644 apps/pingvin/schema/gadgetron.xsd delete mode 100644 gadgets/grappa/grappa_cpu.ini delete mode 100644 test/e2e/cases/generic_cartesian_cine_python.yml diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 003e5874..351c7412 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,3 +1 @@ -# add_subdirectory(pingvin) - -add_subdirectory(emperor) \ No newline at end of file +add_subdirectory(pingvin) \ No newline at end of file diff --git a/apps/emperor/CMakeLists.txt b/apps/emperor/CMakeLists.txt deleted file mode 100644 index 6032e9a2..00000000 --- a/apps/emperor/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -configure_file(../pingvin/pingvin_config.in pingvin_config.h) - -add_executable(emperor - main.cc - - ../pingvin/system_info.cpp - - ../pingvin/ErrorHandler.h - - ../pingvin/nodes/Processable.h - ../pingvin/nodes/Processable.cpp - - ../pingvin/nodes/Stream.cpp - ../pingvin/nodes/Stream.h - ../pingvin/nodes/Parallel.cpp - ../pingvin/nodes/Parallel.h - ../pingvin/nodes/ParallelProcess.cpp - ../pingvin/nodes/ParallelProcess.h - ../pingvin/nodes/PureStream.cpp - ../pingvin/nodes/PureStream.h - ) - -target_link_libraries(emperor - pingvin_core - pingvin_core_parallel - pingvin_mricore - pingvin_epi - pingvin_grappa - pingvin_cmr - Boost::system - Boost::program_options - GTBLAS) - -target_include_directories(emperor - PRIVATE - ${CMAKE_SOURCE_DIR}/apps/pingvin - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ) - -install(TARGETS emperor DESTINATION bin COMPONENT main) \ No newline at end of file diff --git a/apps/emperor/pipelines/cartesian_grappa.h b/apps/emperor/pipelines/cartesian_grappa.h deleted file mode 100644 index fbeedf3c..00000000 --- a/apps/emperor/pipelines/cartesian_grappa.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "pipeline.h" - -#include "gadgets/mri_core/NoiseAdjustGadget.h" -#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" -#include "gadgets/mri_core/RemoveROOversamplingGadget.h" -#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" -#include "gadgets/mri_core/BucketToBufferGadget.h" -#include "gadgets/mri_core/ImageArraySplitGadget.h" -#include "gadgets/mri_core/ComplexToFloatGadget.h" -#include "gadgets/mri_core/FloatToFixedPointGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" - -namespace pingvin { - -static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") - .withSource() - .withSink() - .withNode("noise") - .withNode("asymmetric-echo") - .withNode("ros") - .withNode("acquisition-accumulate") - .withNode("bucket-to-buffer") - .withNode("reference-prep") - .withNode("eigen-channel") - .withNode("grappa") - .withNode("pf-handling") - .withNode("kspace-filtering") - .withNode("fov-adjustment") - .withNode("image-array-scaling") - .withNode("image-split") - .withNode("complex-to-float") - .withNode("convert") - ; - -} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 3d42726a..3cc3a751 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -1,21 +1,11 @@ -find_package(PugiXML REQUIRED) - configure_file(pingvin_config.in pingvin_config.h) add_executable(pingvin - main.cpp + main.cc + initialization.cpp - initialization.h system_info.cpp - Loader.cpp - Loader.h - - Config.cpp - Config.h - - StreamConsumer.h - ErrorHandler.h nodes/Processable.h @@ -23,6 +13,7 @@ add_executable(pingvin nodes/Stream.cpp nodes/Stream.h + nodes/NodeProcessable.h nodes/Parallel.cpp nodes/Parallel.h nodes/ParallelProcess.cpp @@ -33,14 +24,15 @@ add_executable(pingvin target_link_libraries(pingvin pingvin_core - pingvin_toolbox_log - pingvin_toolbox_mri_core + pingvin_core_parallel + pingvin_mricore + pingvin_epi + pingvin_grappa + pingvin_cmr + pingvin_examples Boost::system - Boost::filesystem Boost::program_options - ${PUGIXML_LIBRARIES} - GTBLAS - ${CMAKE_DL_LIBS}) + GTBLAS) target_include_directories(pingvin PRIVATE @@ -64,3 +56,6 @@ if (GPERFTOOLS_PROFILER) endif () install(TARGETS pingvin DESTINATION bin COMPONENT main) + +file(GLOB_RECURSE PIPELINE_CONFIG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pipelines/config/*.conf) +install(FILES ${PIPELINE_CONFIG_FILES} DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) \ No newline at end of file diff --git a/apps/pingvin/Config.cpp b/apps/pingvin/Config.cpp deleted file mode 100644 index 980a606c..00000000 --- a/apps/pingvin/Config.cpp +++ /dev/null @@ -1,415 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "log.h" - -#include "Config.h" - -using namespace Gadgetron::Main; - -namespace { - - class ConfigNodeError : public std::runtime_error { - public: - ConfigNodeError(const std::string &message, const pugi::xml_node &node) : std::runtime_error( - make_message(message, node)) {} - - private: - static std::string make_message(const std::string &message, const pugi::xml_node &node) { - std::stringstream stream; - stream << message << "\n"; - node.print(stream); - return stream.str(); - } - }; - - template - constexpr const char *xml_name(); - - template<> - constexpr const char *xml_name() { return "gadget"; } - - template<> - constexpr const char *xml_name() { return "branch"; } - - template<> - constexpr const char *xml_name() { return "merge"; } - - struct XMLSerializer { - - template - static pugi::xml_node add_name(const ConfigNode &config, pugi::xml_node &node) { - auto name = node.append_child("name"); - name.text().set(Config::name(config).c_str()); - return name; - } - - template - static pugi::xml_node add_basenode(const ConfigNode &configNode, pugi::xml_node &node) { - auto child_node = node.append_child(xml_name()); - auto dll = child_node.append_child("dll"); - dll.append_child(pugi::node_pcdata).set_value(configNode.dll.c_str()); - auto classname = child_node.append_child("classname"); - classname.append_child(pugi::node_pcdata).set_value(configNode.classname.c_str()); - return child_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()); - property_node.append_attribute("value").set_value(property.second.c_str()); - } - - template - static pugi::xml_node add_node(const ConfigNode &configNode, pugi::xml_node &node) { - auto gadget_node = add_basenode(configNode, node); - add_name(configNode, gadget_node); - for (auto &property : configNode.properties) add_property(property, gadget_node); - return gadget_node; - } - - static pugi::xml_node add_node(const Config::Parallel ¶llel, pugi::xml_node &node) { - auto parallel_node = node.append_child("parallel"); - add_node(parallel.merge, parallel_node); - add_node(parallel.branch, parallel_node); - for (auto &stream : parallel.streams) { - add_node(stream, parallel_node); - } - return parallel_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()); - for (auto n : stream.nodes) { - visit([&stream_node](auto &typed_node) { add_node(typed_node, stream_node); }, n); - } - return stream_node; - } - - static pugi::xml_node add_node(const Config::ParallelProcess& parallelProcess, pugi::xml_node & node){ - auto parallel_node = node.append_child("parallelprocess"); - parallel_node.append_attribute("workers").set_value((long long unsigned int)parallelProcess.workers); - add_node(parallelProcess.stream, parallel_node); - return parallel_node; - } - - static pugi::xml_node add_node(const Config::PureStream& stream, pugi::xml_node& node){ - auto purestream_node = node.append_child("purestream"); - for (auto& gadget : stream.gadgets){ - add_node(gadget,purestream_node); - } - return purestream_node; - } - }; - - struct Property { - std::string name; - std::string value; - }; - using Location = std::string; - using Value = std::string; - using PropertyMap = std::map; - - - class LegacySource { - public: - static std::string name(const pugi::xml_node &node) { - return node.child_value("name"); - } - - static std::string value(const pugi::xml_node &node) { - return node.child_value("value"); - } - - static bool accepts(const pugi::xml_node &node) { - return node.child("name") && node.child("value"); - } - }; - - class V2Source { - public: - - static std::string name(const pugi::xml_node &node) { - return node.attribute("name").value(); - } - - static std::string value(const pugi::xml_node &node) { - return node.attribute("value").value(); - } - - static bool accepts(const pugi::xml_node &node) { - return node.attribute("name") && node.attribute("value"); - } - }; - - - bool is_reference(const std::string &value) { - return value.find('@') != std::string::npos; - } - - - template - 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)...}; - auto to_bool = [](auto &potential) { return bool(potential); }; - - auto n_valid = boost::count_if(potentials, to_bool); - if (n_valid < 1) { throw ConfigNodeError("Unable to parse property", node); } - if (n_valid > 1) { throw ConfigNodeError("Ambiguous property parse", node); } - return **boost::find_if(potentials, to_bool); - } - - - template - class Parser { - - protected: - - explicit Parser(const pugi::xml_document &doc) : referenceable_properties( - create_referenceable_properties(doc)) {} - - std::unordered_map - parse_properties(const pugi::xml_node &gadget_node) { - - std::unordered_map properties; - - for (auto &node : gadget_node.children("property")) { - auto property = parse_property(node); - properties[property.name] = dereference(property.value); - } - - return properties; - } - - std::string dereference(const std::string &value_string) { - if (is_reference(value_string)) return referenceable_properties[value_string]; - return value_string; - } - - 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")); - - if (dll.empty()) { - throw ConfigNodeError("Missing dll for gadget " + name, gadget_node); - } - if (classname.empty()) { - throw ConfigNodeError("Missing classname for gadget " + name, gadget_node); - } - - return NODE{name, dll, classname, parse_properties(gadget_node)}; - } - - private: - PropertyMap referenceable_properties; - - static std::string value_of(const PropertyMap &map, const std::string &key, std::set visited) { - - if (visited.count(key)) - throw std::runtime_error("Cyclic reference detected in Gadget xml property: " + key); - - auto value = map.at(key); - - if (is_reference(value)) { - visited.insert(key); - return value_of(map, value, visited); - } - - return value; - } - - static PropertyMap dereference_map(const PropertyMap &propertyMap) { - PropertyMap resultMap = propertyMap; - for (const auto &property : resultMap) { - resultMap[property.first] = value_of(resultMap, property.first, std::set()); - } - return resultMap; - } - - static PropertyMap create_referenceable_properties(const pugi::xml_node &root) { - - PropertyMap propertyMap; - - for (auto selector : root.select_nodes("//*[child::name and child::property]")) { - auto node = selector.node(); - auto parent_name = node.child_value("name"); - - for (auto p_node : node.children("property")) { - auto property = parse_property(p_node); - auto location = property.name + "@" + parent_name; - - propertyMap[location] = property.value; - } - } - - return dereference_map(propertyMap); - } - }; - - class Legacy : public Parser { - public: - - static Config parse(const pugi::xml_document &config) { - - auto parser = Legacy(config); - pugi::xml_node root = config.child("gadgetronStreamConfiguration"); - - return Config{ parser.parse_stream(root) }; - } - - static bool accepts(const pugi::xml_document &config) { - return config.child("gadgetronStreamConfiguration"); - } - - private: - explicit Legacy(const pugi::xml_document &config) : Parser(config) {} - - const std::list, - std::function>> node_transformations{ - std::make_pair([](auto _) { return true; }, [=](auto c) { return Config::Node(c); }) - }; - - Config::Node apply_transformation(Config::Gadget gadget) { - - auto pair = *std::find_if( - node_transformations.begin(), - node_transformations.end(), - [&](auto p) { return std::get<0>(p)(gadget); } - ); - - return std::get<1>(pair)(gadget); - } - - std::vector parse_gadgets(const pugi::xml_node &gadget_node) { - std::vector gadgets{}; - for (const auto &node : gadget_node.children("gadget")) { - gadgets.push_back(parse_node(node)); - } - return gadgets; - } - - Config::Stream parse_stream(const pugi::xml_node &stream_node) { - std::vector nodes; - boost::transform( - parse_gadgets(stream_node), - std::back_inserter(nodes), - [&](auto gadget) { return apply_transformation(gadget); } - ); - - return Config::Stream{"main", nodes}; - } - }; - - class V2 : public Parser { - public: - static Config parse(const pugi::xml_document &config) { - - auto parser = V2(config); - auto root = config.child("configuration"); - - return Config{ parser.parse_stream(root.child("stream")) }; - } - - static bool accepts(const pugi::xml_document &config) { - auto configuration = config.child("configuration"); - return std::string(configuration.child_value("version")) == "2"; - } - - private: - - 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["parallelprocess"] = [&](const pugi::xml_node &n) { return this->parse_parallelprocess(n); }; - } - - std::unordered_map> node_parsers; - - Config::Parallel parse_parallel(const pugi::xml_node ¶llel_node) { - - auto branch = parse_node(parallel_node.child("branch")); - auto merge = parse_node(parallel_node.child("merge")); - - std::vector streams{}; - for (const auto &stream_node : parallel_node.children("stream")) { - streams.push_back(parse_stream(stream_node)); - } - return Config::Parallel{branch, merge, streams}; - } - - Config::Stream parse_stream(const pugi::xml_node &stream_node) { - std::vector nodes; - for (auto &node : stream_node.children()) { - nodes.push_back(node_parsers.at(node.name())(node)); - } - return Config::Stream{stream_node.attribute("key").value(), nodes}; - } - - Config::PureStream parse_purestream(const pugi::xml_node &purestream_node){ - std::vector gadgets; - boost::transform(purestream_node.children(), std::back_inserter(gadgets), - [&,this](auto node) { return this->parse_node(node); }); - return {gadgets}; - } - - Config::ParallelProcess parse_parallelprocess(const pugi::xml_node& parallelprocess_node) - { - size_t workers = std::stoul(parallelprocess_node.attribute("workers").value()); - return Config::ParallelProcess{workers,parse_purestream(parallelprocess_node.child("purestream"))}; - } - - }; -} - -namespace Gadgetron::Main { - - Config Config::parse(std::istream &stream) { - - auto parsers = { - std::make_pair(Legacy::accepts, Legacy::parse), - std::make_pair(V2::accepts, V2::parse) - }; - - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load(stream); - - if (result.status != pugi::status_ok) { - GERROR("Loading config file failed with following error: %s (%d)\n", result.description(), result.status); - throw std::runtime_error(result.description()); - } - - auto parser = std::find_if(parsers.begin(), parsers.end(), [&](auto pair) { return std::get<0>(pair)(doc); }); - if (parser == parsers.end()) throw std::runtime_error("No parser accepted config file."); - return std::get<1>(*parser)(doc); - } - - 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_node(config.stream, config_node); - - std::stringstream stream; - doc.save(stream); - return stream.str(); - } -} diff --git a/apps/pingvin/Config.h b/apps/pingvin/Config.h deleted file mode 100644 index c9522a13..00000000 --- a/apps/pingvin/Config.h +++ /dev/null @@ -1,60 +0,0 @@ -#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/pingvin/Loader.cpp b/apps/pingvin/Loader.cpp deleted file mode 100644 index 227f591c..00000000 --- a/apps/pingvin/Loader.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#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 deleted file mode 100644 index 494a537b..00000000 --- a/apps/pingvin/Loader.h +++ /dev/null @@ -1,52 +0,0 @@ -#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 deleted file mode 100644 index b2dca9cc..00000000 --- a/apps/pingvin/StreamConsumer.h +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "nodes/Stream.h" -#include "Channel.h" -#include "ErrorHandler.h" - -#include "Node.h" - -#include "pingvin_config.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; -} - - class NewNodeProcessable : public Processable { - public: - NewNodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} - - void process(GenericInputChannel input, - OutputChannel output, - ErrorHandler & - ) override { - node_->process(input, output); - } - - const std::string& name() override { - return name_; - } - - private: - std::shared_ptr node_; - const std::string name_; - }; - -} // namespace - -class StreamConsumer -{ -public: - StreamConsumer() {} - ~StreamConsumer() {} - - void consume_stream(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer, const std::unique_ptr& 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(); - } - - // 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(); - // } - - private: - - 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(); - } -}; diff --git a/apps/emperor/main.cc b/apps/pingvin/main.cc similarity index 81% rename from apps/emperor/main.cc rename to apps/pingvin/main.cc index 9d1bf481..2b581ba2 100644 --- a/apps/emperor/main.cc +++ b/apps/pingvin/main.cc @@ -4,13 +4,18 @@ #include "pipelines/epi.h" #include "pipelines/cartesian_grappa.h" #include "pipelines/cartesian_spirit.h" +#include "pipelines/grappa_epi.h" #include "pipelines/cmr.h" +#include "pipelines/parallel_bypass.h" +#include "pipelines/streams.h" +#include "pipelines/denoise.h" #include "pipelines/file_search.h" - #include "log.h" +#include "initialization.h" #include "system_info.h" +#include "pingvin_config.h" #include @@ -64,6 +69,8 @@ int main(int argc, char** argv) ("home", po::value()->default_value(Gadgetron::Main::Info::get_pingvin_home()), "Set the Pingvin home directory") + ("genconf,g", "Generate a full configuration file for the given pipeline") + ("dumpconf,d", "Dump the current configuration for the given pipeline") ("config,c", po::value(), "Pipeline configuration file") ("input,i", po::value(), "Input stream (default=stdin)") ("output,o", po::value(), "Output stream (default=stdout)") @@ -106,32 +113,62 @@ int main(int argc, char** argv) return 1; } + Gadgetron::Main::check_environment_variables(); + Gadgetron::Main::configure_blas_libraries(); + Gadgetron::Main::set_locale(); + + GINFO_STREAM("Pingvin " << PINGVIN_VERSION_STRING << " [" << PINGVIN_GIT_SHA1_HASH << "]"); + if (vm.count("info")) { - std::cerr << "Pingvin Info: ..." << std::endl; + std::stringstream str; + Gadgetron::Main::Info::print_system_information(str); + GINFO_STREAM(str.str()); return 0; } - if (vm.count("home")) { + if (vm.count("home") && !vm["home"].defaulted()) { Gadgetron::Main::Info::set_pingvin_home(vm["home"].as()); - std::cerr << "Set Pingvin home to: " << Gadgetron::Main::Info::get_pingvin_home() << std::endl; + GINFO_STREAM("Set Pingvin home to: " << Gadgetron::Main::Info::get_pingvin_home()); } // "Choose" a Pipeline std::vector builders{ - &epi_2d, + &file_search, + + &noise_dependency, &default_mr, &default_mr_optimized, - &noise_dependency, - &file_search, + + &epi_2d, + &grappa, + &grappa_cpu, + &cartesian_grappa, + &cartesian_grappa_snr, + &grappa_denoise, + + &cartesian_spirit, &cartesian_spirit_nonlinear, + + &grappa_epi, + &cmr_cine_binning, - &cmr_mapping_t1_sr + &cmr_mapping_t1_sr, + &cmr_rtcine_lax_ai, + + &example_parallel_bypass, + + &stream_cartesian_grappa_imagearray, + &stream_cartesian_grappa, + &stream_image_array_scaling, + &stream_image_array_split, + &stream_complex_to_float, + &stream_float_to_fixed_point, }; std::map builder_map; for (auto& builder : builders) { - builder_map[builder->name] = builder; + builder_map[builder->name()] = builder; } if (!vm.count("pipeline")) { @@ -143,7 +180,7 @@ int main(int argc, char** argv) std::cerr << "Pipelines:" << std::endl; for (auto& builder : builders) { // std::cerr << "┌ " << builder->name << std::endl << "└──── " << builder->description << std::endl; - std::cerr << "- " << builder->name << std::endl << " └── " << builder->description << std::endl; + std::cerr << "- " << builder->name() << std::endl << " └── " << builder->description() << std::endl; } return 0; } else { @@ -166,6 +203,7 @@ int main(int argc, char** argv) po::parsed_options parsed = po::basic_command_line_parser(unrecognized).options(pipeline_options).run(); po::store(parsed, vm); + if (vm.count("help")) { std::cerr << help_options << std::endl; std::cerr << "--- " << subcmd << " ---" << std::endl; @@ -202,6 +240,15 @@ int main(int argc, char** argv) return 1; } + if (vm.count("dumpconf")) { + builder->dump_config(std::cout, true); + return 0; + } + if (vm.count("genconf")) { + builder->dump_config(std::cout, false); + return 0; + } + std::unique_ptr input_file; if (vm.count("input")) { input_file = std::make_unique(vm["input"].as()); diff --git a/apps/pingvin/main.cpp b/apps/pingvin/main.cpp deleted file mode 100644 index d8a12e01..00000000 --- a/apps/pingvin/main.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include - -#include -#include - -#include "log.h" -#include "initialization.h" - -#include "system_info.h" -#include "pingvin_config.h" - -#include "StreamConsumer.h" - - -using namespace std::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/pingvin/nodes/ParallelProcess.cpp b/apps/pingvin/nodes/ParallelProcess.cpp index e189ae4d..fed134fb 100644 --- a/apps/pingvin/nodes/ParallelProcess.cpp +++ b/apps/pingvin/nodes/ParallelProcess.cpp @@ -8,12 +8,12 @@ namespace Gadgetron::Main::Nodes { void ParallelProcess::process_input(GenericInputChannel input, Queue &queue) { - ThreadPool pool(workers ? workers : std::thread::hardware_concurrency()); + ThreadPool pool(workers_ ? workers_ : std::thread::hardware_concurrency()); for (auto message : input) { queue.push( pool.async( - [&](auto message) { return pureStream.process_function(std::move(message)); }, + [&](auto message) { return pure_stream_.process_function(std::move(message)); }, std::move(message) ) ); diff --git a/apps/pingvin/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h index 7854ee9f..7a733c26 100644 --- a/apps/pingvin/nodes/ParallelProcess.h +++ b/apps/pingvin/nodes/ParallelProcess.h @@ -9,8 +9,12 @@ namespace Gadgetron::Main::Nodes { class ParallelProcess : public Processable { public: + ParallelProcess(const PureStream& pureStream, size_t workers) + : workers_(workers), pure_stream_(pureStream) {} + void process(Core::GenericInputChannel input, Core::OutputChannel output, ErrorHandler& error_handler) override; const std::string& name() override; + private: using Queue = Core::MPMCChannel>; @@ -18,7 +22,7 @@ namespace Gadgetron::Main::Nodes { void process_input(Core::GenericInputChannel input, Queue &queue); void process_output(Core::OutputChannel output, Queue &queue); - const size_t workers; - const PureStream pureStream; + const size_t workers_; + const PureStream pure_stream_; }; } diff --git a/apps/pingvin/nodes/PureStream.cpp b/apps/pingvin/nodes/PureStream.cpp index cdccb26f..4b532964 100644 --- a/apps/pingvin/nodes/PureStream.cpp +++ b/apps/pingvin/nodes/PureStream.cpp @@ -4,8 +4,8 @@ Gadgetron::Core::Message Gadgetron::Main::Nodes::PureStream::process_function( Gadgetron::Core::Message message ) const { return std::accumulate( - pure_gadgets.begin(), - pure_gadgets.end(), + pure_gadgets_.begin(), + pure_gadgets_.end(), std::move(message), [](auto&& message, auto&& gadget) { return gadget->process_function(std::move(message)); diff --git a/apps/pingvin/nodes/PureStream.h b/apps/pingvin/nodes/PureStream.h index dd8833ef..9fbcc8f9 100644 --- a/apps/pingvin/nodes/PureStream.h +++ b/apps/pingvin/nodes/PureStream.h @@ -5,9 +5,12 @@ namespace Gadgetron::Main::Nodes { class PureStream { public: + PureStream(const std::vector>& pure_gadgets) + : pure_gadgets_(std::move(pure_gadgets)) {} + Core::Message process_function(Core::Message) const; private: - const std::vector> pure_gadgets; + const std::vector> pure_gadgets_; }; } diff --git a/apps/emperor/pipelines/cmr.h b/apps/pingvin/pipelines/cartesian_grappa.h similarity index 77% rename from apps/emperor/pipelines/cmr.h rename to apps/pingvin/pipelines/cartesian_grappa.h index d3525826..ef5a3c9e 100644 --- a/apps/emperor/pipelines/cmr.h +++ b/apps/pingvin/pipelines/cartesian_grappa.h @@ -17,23 +17,22 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" -#include "gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h" -#include "gadgets/cmr/CmrParametricT1SRMappingGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" namespace pingvin { -static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") +static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") .withSource() .withSink() .withNode("noise") - .withNode("asymmetric-echo") + .withNode("echo-adjust") .withNode("ros") .withNode("acctrig") .withNode("buffer") .withNode("refprep") .withNode("coilcomp") - .withNode("cmr") - .withNode("pf") + .withNode("grappa") + .withNode("pf") .withNode("kspace-filter") .withNode("fov-adjust") .withNode("scale") @@ -42,22 +41,21 @@ static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", " .withNode("convert") ; -static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") +static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") .withSource() .withSink() .withNode("noise") - .withNode("asymmetric-echo") + .withNode("echo-adjust") .withNode("ros") .withNode("acctrig") .withNode("buffer") .withNode("refprep") - .withNode("coilcomp") .withNode("grappa") - .withNode("pf") + .withNode("pf") .withNode("kspace-filter") .withNode("fov-adjust") + .withNode("std-map") .withNode("scale") - .withNode("sasha") .withNode("split") .withNode("complex-to-float") .withNode("convert") diff --git a/apps/pingvin/pipelines/cartesian_spirit.h b/apps/pingvin/pipelines/cartesian_spirit.h new file mode 100644 index 00000000..85c38c49 --- /dev/null +++ b/apps/pingvin/pipelines/cartesian_spirit.h @@ -0,0 +1,65 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/PhysioInterpolationGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" + +namespace pingvin { + +static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", "Cartesian SPIRIT Recon") + .withSource() + .withSink() + .withNode("noise") + .withNode("echo-adjust") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("spirit") + .withNode("partial-fourier") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") + .withSource() + .withSink() + .withNode("noise") + .withNode("echo-adjust") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coil-comp") + .withNode("spirit") + .withNode("partial-fourier") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("image-split") + .withNode("physio-interp") + .withNode("complex-to-float") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/cmr.h b/apps/pingvin/pipelines/cmr.h new file mode 100644 index 00000000..129843bb --- /dev/null +++ b/apps/pingvin/pipelines/cmr.h @@ -0,0 +1,88 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" +#include "gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h" +#include "gadgets/cmr/CmrParametricT1SRMappingGadget.h" +#include "gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h" + +namespace pingvin { + +static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("binning") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("sasha") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +static auto cmr_rtcine_lax_ai = PipelineBuilder("cmr-rtcine-lax-ai", "CMR real-time cine LAX AI") + .withSource() + .withSink() + .withNode("noise") + .withNode("asymmetric-echo") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("laxai") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cartesian-cine-denoise.conf b/apps/pingvin/pipelines/config/cartesian-cine-denoise.conf new file mode 100644 index 00000000..a6d81106 --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-cine-denoise.conf @@ -0,0 +1,29 @@ +# Replaces Generic_Cartesian_Grappa_Cine_Denoise.xml + +[acctrig] +trigger-dimension = slice + +[buffer] +N-dimension = phase +S-dimension = set +split-slices = 1 +ignore-segment = 1 + +[refprep] +verbose = 1 +perform-timing = 1 + +[coilcomp] +verbose = 1 +perform-timing = 1 +average-all-ref-S = 1 + +[grappa] +verbose = 1 +perform-timing = 1 +send-out-gfactor = 1 + +[denoise] +image-std = 10 +search-radius = 5 + diff --git a/apps/pingvin/pipelines/config/cartesian-grappa-snr.conf b/apps/pingvin/pipelines/config/cartesian-grappa-snr.conf new file mode 100644 index 00000000..4dcc5975 --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-grappa-snr.conf @@ -0,0 +1,43 @@ +# Replaces Generic_Cartesian_Grappa_SNR.xml + +[buffer] +N-dimension=repetition +S-dimension=set +split-slices=false +ignore-segment=true +verbose=true + +[refprep] +verbose=true +perform-timing=true +average-all-ref-N=true +average-all-ref-S=true +prepare-ref-always=true + +[grappa] +verbose=true +perform-timing=true +send-out-gfactor=true +send-out-snr-map=true + +[pf] +verbose=true + +[kspace-filter] +verbose=true + +[fov-adjust] +verbose=true + +[std-map] +verbose=true + +[scale] +verbose=true +scalingFactor-dedicated=1000 + +[convert] +type=ushort +max-intensity=32767 +min-intensity=0 +intensity-offset=0 diff --git a/apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf b/apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf new file mode 100644 index 00000000..c5ac7bf8 --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf @@ -0,0 +1,29 @@ +# Replaces Generic_Cartesian_Grappa_T2W.xml + +[acctrig] +trigger-dimension = repetition + +[buffer] +N-dimension = repetition +S-dimension = set +split-slices = true +ignore-segment = true + +[refprep] +verbose = true +perform-timing = true +prepare-ref-always = false + +[coilcomp] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true + +[grappa] +verbose = true +perform-timing = true +send-out-gfactor = true + +[convert] +type = ushort \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cartesian-grappa.conf b/apps/pingvin/pipelines/config/cartesian-grappa.conf new file mode 100644 index 00000000..3881f8eb --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-grappa.conf @@ -0,0 +1,32 @@ +# Replaces Generic_Cartesian_Grappa.xml + +[buffer] +N-dimension = contrast +S-dimension = average +split-slices = false +ignore-segment = true +verbose = true + +[refprep] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true + +[coilcomp] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true +upstream-coil-compression-thres = 0.002 + +[grappa] +verbose = true +perform-timing = true +downstream-coil-compression-thres = 0.01 + +[convert] +type = ushort +max-intensity = 32767 +min-intensity = 0 +intensity-offset = 0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf new file mode 100644 index 00000000..c93d7611 --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf @@ -0,0 +1,38 @@ +# Replaces Generic_Cartesian_Nonlinear_Spirit_RealtimeCine.xml + +[acctrig] +trigger-dimension=slice + +[buffer] +N-dimension=phase +S-dimension=set +ignore-segment=true + +[refprep] +perform-timing=true +average-all-ref-S=true + +[coil-comp] +perform-timing=true +average-all-ref-S=true +upstream-coil-compression-thres=0.001 + +[spirit] +verbose=true +perform-timing=true +spirit-print-iter=true +spirit-image-reg-lamda=0.0015 +spirit-reg-estimate-noise-floor=true +spirit-reg-N-weighting-ratio=10 + +[partial-fourier] +verbose=true + +[physio-interp] +first-beat-on-trigger=true +interp-method=BSpline + +[convert] +type=ushort +max-intensity=32767 +intensity-offset=0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf new file mode 100644 index 00000000..583ed9e4 --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf @@ -0,0 +1,37 @@ +# Replaces Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml + +[acctrig] +trigger-dimension=slice + +[buffer] +N-dimension=phase +S-dimension=set +ignore-segment=true + +[refprep] +perform-timing=true +average-all-ref-S=true + +[coil-comp] +perform-timing=true +average-all-ref-S=true +upstream-coil-compression-thres=0.001 + +[spirit] +verbose=true +perform-timing=true +spirit-print-iter=true +spirit-image-reg-lamda=0.0001 +spirit-reg-name=db2 +spirit-reg-N-weighting-ratio=10 + +[physio-interp] +phases=30 +mode=0 +first-beat-on-trigger=true +interp-method=BSpline + +[convert] +type=ushort +max-intensity=32767 +intensity-offset=0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cartesian-spirit.conf b/apps/pingvin/pipelines/config/cartesian-spirit.conf new file mode 100644 index 00000000..d5a363ca --- /dev/null +++ b/apps/pingvin/pipelines/config/cartesian-spirit.conf @@ -0,0 +1,32 @@ +# Replaces Generic_Cartesian_Spirit_SASHA.xml + +[acctrig] +trigger-dimension = slice + +[buffer] +N-dimension = set +S-dimension = repetition +ignore-segment = true +verbose = true + +[refprep] +verbose = true +perform-timing = true +average-all-ref-S = true + +[coilcomp] +verbose = true +perform-timing = true +average-all-ref-S = true +upstream-coil-compression-thres = 0.001 + +[spirit] +verbose = true +perform-timing = true +spirit-print-iter = true + +[convert] +type = ushort +max-intensity = 32767 +min-intensity = 0 +intensity-offset = 0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cmr-cine-binning.conf b/apps/pingvin/pipelines/config/cmr-cine-binning.conf new file mode 100644 index 00000000..69d8f26b --- /dev/null +++ b/apps/pingvin/pipelines/config/cmr-cine-binning.conf @@ -0,0 +1,41 @@ +# Replaces CMR_2DT_RTCine_KspaceBinning.xml + +[acctrig] +trigger-dimension = slice + +[buffer] +N-dimension = phase +S-dimension = set +split-slices = true +ignore-segment = true + +[refprep] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true + +[coilcomp] +average-all-ref-N = true +average-all-ref-S = true + +[binning] +verbose = true +perform-timing = true +downstream-coil-compression-thres = 0.025 +kspace-binning-moco-iters = 32 +kspace-binning-moco-iters = 64 +kspace-binning-moco-iters = 100 +kspace-binning-moco-iters = 100 +kspace-binning-moco-iters = 100 +kspace-binning-linear-iter-thres = 0.0005 +kspace-binning-nonlinear-reg-wav-name = db2 + +[pf] +verbose = true + +[convert] +type = ushort +max-intensity = 32767 +min-intensity = 0 +intensity-offset = 0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf b/apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf new file mode 100644 index 00000000..1b4b7e1c --- /dev/null +++ b/apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf @@ -0,0 +1,47 @@ +# Replaces CMR_2DT_T1Mapping_SASHA.xml + +[acctrig] +trigger-dimension = slice + +[buffer] +N-dimension = set +S-dimension = contrast +split-slices = 0 +ignore-segment = 1 + +[refprep] +verbose = 1 +perform-timing = 1 +average-all-ref-S = 1 + +[coilcomp] +average-all-ref-S = 1 + +[grappa] +verbose = 1 +perform-timing = 1 +send-out-gfactor = 1 +downstream-coil-compression-thres = 0.01 + +[kspace-filter] +filterRO-sigma=1.5 +filterE1-sigma=1.5 +filterE2-sigma=1.5 + +[sasha] +verbose = 1 +perform-timing = 1 +color-lut-map = GadgetronT1_SR_1_5T.pal +window-center-map = 1300 +window-width-map = 1300 +color-lut-map-3T = GadgetronT1_SR_3T.pal +window-center-map-3T = 1300 +window-width-map-3T = 1300 +scaling-factor-map = 1 +color-lut-sd-map = GadgetronT1_SD.pal +window-center-sd-map = 2 +window-width-sd-map = 4 + +[convert] +max-intensity = 32767 +intensity-offset = 0 \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf b/apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf new file mode 100644 index 00000000..36fb80a0 --- /dev/null +++ b/apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf @@ -0,0 +1,24 @@ +[acctrig] +trigger-dimension = slice + +[buffer] +N-dimension = phase +S-dimension = set +split-slices = 1 +ignore-segment = 1 + +[refprep] +perform-timing = 1 + +[coilcomp] +perform-timing = 1 +average-all-ref-S = 1 + +[grappa] +verbose = 1 +perform-timing = 1 + +[laxai] +verbose = 1 +perform-timing = 1 + diff --git a/apps/pingvin/pipelines/config/epi.conf b/apps/pingvin/pipelines/config/epi.conf new file mode 100644 index 00000000..9b424bf3 --- /dev/null +++ b/apps/pingvin/pipelines/config/epi.conf @@ -0,0 +1,29 @@ +# Replaces epi.xml + +[noise] + +[reconx] + +[epicorr] + +[fftx] + +[acctrig] +trigger-dimension=repetition +sorting-dimension=slice + +[buffer] +split-slices=true +ignore-segment=true + +[fft] + +[combine] + +[extract] +magnitude=true + +[autoscale] + +[convert] +type=ushort diff --git a/apps/pingvin/pipelines/config/grappa-epi.conf b/apps/pingvin/pipelines/config/grappa-epi.conf new file mode 100644 index 00000000..7f272deb --- /dev/null +++ b/apps/pingvin/pipelines/config/grappa-epi.conf @@ -0,0 +1,40 @@ +# Replaces Generic_Cartesian_Grappa_EPI_AVE.xml + +[noise] + +[reconx] + +[epicorr] + +[fftx] + +[acctrig] +trigger-dimension=average +sorting-dimension=repetition + +[buffer] +N-dimension=average +S-dimension=repetition +split-slices=false +ignore-segment=true + +[refprep] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true +prepare-ref-always=false + +[coilcomp] +verbose = true +perform-timing = true +average-all-ref-N = true +average-all-ref-S = true + +[grappa] +verbose = true +perform-timing = true + +[scale] +scalingFactor = 4.0 +use-constant-scalingFactor = false \ No newline at end of file diff --git a/apps/pingvin/pipelines/config/stream-cartesian-grappa.conf b/apps/pingvin/pipelines/config/stream-cartesian-grappa.conf new file mode 100644 index 00000000..292ee765 --- /dev/null +++ b/apps/pingvin/pipelines/config/stream-cartesian-grappa.conf @@ -0,0 +1,21 @@ +[buffer] +N-dimension = contrast +S-dimension = average +ignore-segment = true +verbose = true + +[refprep] +verbose = true +perform-timing = true +average-all-ref-S = true + +[coilcomp] +verbose = true +perform-timing = true +average-all-ref-S = true +upstream-coil-compression-thres = 0.002 + +[grappa] +verbose = true +perform-timing = true +downstream-coil-compression-thres = 0.01 \ No newline at end of file diff --git a/apps/emperor/pipelines/default.h b/apps/pingvin/pipelines/default.h similarity index 86% rename from apps/emperor/pipelines/default.h rename to apps/pingvin/pipelines/default.h index 043fafeb..e45d184a 100644 --- a/apps/emperor/pipelines/default.h +++ b/apps/pingvin/pipelines/default.h @@ -20,7 +20,7 @@ static auto default_mr = PipelineBuilder("default", "Basic Cartesian .withSource() .withSink() .withNode("ros") - .withNode("accumulate") + .withNode("acctrig") .withNode("buffer") .withNode("recon") .withNode("image-split") @@ -32,9 +32,9 @@ static auto default_mr_optimized = PipelineBuilder("default-optimize .withSink() .withNode("noise-adjust") .withNode("pca") - .withNode("coil-reduction") // TODO: specify a default of `coils_out = 16`?? + .withNode("coil-reduction") .withNode("ros") - .withNode("accumulate") + .withNode("acctrig") .withNode("buffer") .withNode("recon") .withNode("image-split") diff --git a/apps/emperor/pipelines/cartesian_spirit.h b/apps/pingvin/pipelines/denoise.h similarity index 71% rename from apps/emperor/pipelines/cartesian_spirit.h rename to apps/pingvin/pipelines/denoise.h index 6a46c07f..866e381b 100644 --- a/apps/emperor/pipelines/cartesian_spirit.h +++ b/apps/pingvin/pipelines/denoise.h @@ -8,38 +8,41 @@ #include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" #include "gadgets/mri_core/BucketToBufferGadget.h" #include "gadgets/mri_core/ImageArraySplitGadget.h" -#include "gadgets/mri_core/PhysioInterpolationGadget.h" #include "gadgets/mri_core/ComplexToFloatGadget.h" #include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/DenoiseGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" -#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" namespace pingvin { -static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") +using namespace Gadgetron; + +static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") .withSource() .withSink() .withNode("noise") - .withNode("asymmetric-echo") + .withNode("echo-adjust") .withNode("ros") .withNode("acctrig") .withNode("buffer") .withNode("refprep") - .withNode("coil-comp") - .withNode("spirit") - .withNode("partial-fourier") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") .withNode("kspace-filter") .withNode("fov-adjust") - .withNode("scale") - .withNode("image-split") - .withNode("physio-interp") + .withNode("split") + .withParallelProcessStream() + .withPureNode("denoise") + .withWorkers(6) .withNode("complex-to-float") - .withNode("convert") ; } // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/epi.h b/apps/pingvin/pipelines/epi.h similarity index 95% rename from apps/emperor/pipelines/epi.h rename to apps/pingvin/pipelines/epi.h index f06c4711..f2fa4945 100644 --- a/apps/emperor/pipelines/epi.h +++ b/apps/pingvin/pipelines/epi.h @@ -22,7 +22,7 @@ namespace pingvin { static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") .withSource() .withSink() - .withNode("noise-adjust") + .withNode("noise") .withNode("reconx") .withNode("epicorr") .withNode("fftx") diff --git a/apps/emperor/pipelines/file_search.h b/apps/pingvin/pipelines/file_search.h similarity index 100% rename from apps/emperor/pipelines/file_search.h rename to apps/pingvin/pipelines/file_search.h diff --git a/apps/emperor/pipelines/grappa.h b/apps/pingvin/pipelines/grappa.h similarity index 64% rename from apps/emperor/pipelines/grappa.h rename to apps/pingvin/pipelines/grappa.h index 65f244ec..4a74ec5a 100644 --- a/apps/emperor/pipelines/grappa.h +++ b/apps/pingvin/pipelines/grappa.h @@ -43,9 +43,27 @@ static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconst .withStream("weights") .withNode("weights") .withMerge("unmixing") + .withNode("extract") + ; + +static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") + .withSource() + .withSink() + .withNode("noise-adjust") + .withNode("pca") + .withNode("coil-reduction") + .withNode("echo-adjust") + .withNode("remove-oversampling") + .withNode("slice-acc") + + .withBranch("acq-fanout") + .withStream("images") + .withNode("image-acc") + .withStream("weights") + .withNode("weights") + .withMerge("unmixing") .withNode("extract") - .withNode("scale") - .withNode("convert"); + ; } // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/grappa_epi.h b/apps/pingvin/pipelines/grappa_epi.h new file mode 100644 index 00000000..06c22cc4 --- /dev/null +++ b/apps/pingvin/pipelines/grappa_epi.h @@ -0,0 +1,52 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/epi/EPIReconXGadget.h" +#include "gadgets/epi/EPICorrGadget.h" +#include "gadgets/epi/FFTXGadget.h" +#include "gadgets/epi/OneEncodingGadget.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" + +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" + +namespace pingvin { + + using namespace Gadgetron; + + static auto grappa_epi = PipelineBuilder("grappa-epi", "Basic EPI Reconstruction") + .withSource() + .withSink() + .withNode("noise") + .withNode("reconx") + .withNode("epicorr") + .withNode("fftx") + .withNode("encoding") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/noise.h b/apps/pingvin/pipelines/noise.h similarity index 100% rename from apps/emperor/pipelines/noise.h rename to apps/pingvin/pipelines/noise.h diff --git a/apps/pingvin/pipelines/parallel_bypass.h b/apps/pingvin/pipelines/parallel_bypass.h new file mode 100644 index 00000000..c43b40bb --- /dev/null +++ b/apps/pingvin/pipelines/parallel_bypass.h @@ -0,0 +1,39 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/PCACoilGadget.h" +#include "gadgets/mri_core/CoilReductionGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/SimpleReconGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ExtractGadget.h" +#include "core/parallel/Fanout.h" +#include "gadgets/examples/ImageInverter.h" +#include "gadgets/examples/ImageLayerer.h" + +namespace pingvin { + + using namespace Gadgetron; + +static auto example_parallel_bypass = PipelineBuilder("parallel-bypass", "Basic Parallel Bypass Example") + .withSource() + .withSink() + .withNode("noise") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("recon") + .withNode("image-split") + .withNode("extract") + .withBranch("fanout") + .withStream("unchanged") + .withStream("inverted") + .withNode("invert") + .withMerge("layer") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/emperor/pipelines/pipeline.h b/apps/pingvin/pipelines/pipeline.h similarity index 73% rename from apps/emperor/pipelines/pipeline.h rename to apps/pingvin/pipelines/pipeline.h index e68de79e..7d244ea2 100644 --- a/apps/emperor/pipelines/pipeline.h +++ b/apps/pingvin/pipelines/pipeline.h @@ -13,6 +13,7 @@ namespace po = boost::program_options; #include "nodes/Stream.h" #include "nodes/NodeProcessable.h" #include "nodes/Parallel.h" +#include "nodes/ParallelProcess.h" #include "Channel.h" #include "ErrorHandler.h" @@ -149,6 +150,7 @@ struct INodeBuilder { virtual ~INodeBuilder() = default; virtual std::shared_ptr build(const C& ctx) const = 0; virtual void collect_options(po::options_description& parent) = 0; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; }; template @@ -173,6 +175,23 @@ class NodeBuilder : public INodeBuilder { } } + void dump_config(std::ostream& os, bool only_modified) override { + std::stringstream ss; + ss.imbue(std::locale::classic()); + for (auto& p: parameters_.parameters()) { + if (!p->modified() && only_modified) { + continue; + } + p->print(ss); + ss << std::endl; + } + auto s = ss.str(); + if (!s.empty()) { + os << "[" << parameters_.prefix() << "]" << std::endl; + os << s << std::endl; + } + } + private: std::string label_; typename N::Parameters parameters_; @@ -190,6 +209,12 @@ class StreamBuilder : public INodeBuilder { } } + void dump_config(std::ostream& os, bool only_modified) { + for (auto& nb: builders_) { + nb->dump_config(os, only_modified); + } + } + std::shared_ptr build(const CTX& ctx) const override { std::vector> processables; for (auto& builder : builders_) { @@ -214,6 +239,7 @@ struct IBranchBuilder { virtual ~IBranchBuilder() = default; virtual std::unique_ptr build(const CTX& ctx) const = 0; virtual void collect_options(po::options_description& parent) = 0; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; }; template @@ -237,6 +263,18 @@ class BranchBuilder : public IBranchBuilder { } } + void dump_config(std::ostream& os, bool only_modified) override { + os << "[" << parameters_.prefix() << "]" << std::endl; + for (auto& p: parameters_.parameters()) { + if (!p->modified() && only_modified) { + continue; + } + p->print(os); + os << std::endl; + } + os << std::endl; + } + private: std::string label_; typename N::Parameters parameters_; @@ -247,6 +285,7 @@ struct IMergeBuilder { virtual ~IMergeBuilder() = default; virtual std::unique_ptr build(const CTX& ctx) const = 0; virtual void collect_options(po::options_description& parent) = 0; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; }; template @@ -270,6 +309,18 @@ class MergeBuilder : public IMergeBuilder { } } + void dump_config(std::ostream& os, bool only_modified) override { + os << "[" << parameters_.prefix() << "]" << std::endl; + for (auto& p: parameters_.parameters()) { + if (!p->modified() && only_modified) { + continue; + } + p->print(os); + os << std::endl; + } + os << std::endl; + } + private: std::string label_; typename N::Parameters parameters_; @@ -330,7 +381,7 @@ class ParallelBuilder : public INodeBuilder { return std::make_shared(std::move(branch), std::move(merge), streams); } - virtual void collect_options(po::options_description& parent) { + void collect_options(po::options_description& parent) override { if (!branch_builder_) { throw std::runtime_error("No branch specified"); } @@ -344,15 +395,118 @@ class ParallelBuilder : public INodeBuilder { merge_builder_->collect_options(parent); } + void dump_config(std::ostream& os, bool only_modified) override { + branch_builder_->dump_config(os, only_modified); + for (auto& stream_builder_: stream_builders_) { + stream_builder_.dump_config(os, only_modified); + } + merge_builder_->dump_config(os, only_modified); + } + private: PipelineBuilder& parent_; - std::string label_; std::unique_ptr> branch_builder_; std::unique_ptr> merge_builder_; std::vector> stream_builders_; }; +template +struct IPureNodeBuilder { + virtual ~IPureNodeBuilder() = default; + virtual std::unique_ptr build(const CTX& ctx) const = 0; + virtual void collect_options(po::options_description& parent) = 0; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; +}; + +template +class PureNodeBuilder : public IPureNodeBuilder { +public: + PureNodeBuilder(const std::string& label): label_(label), parameters_(label) {} + + std::unique_ptr build(const CTX& ctx) const override { + return std::move(std::make_unique(ctx, this->parameters_)); + } + + void collect_options(po::options_description& parent) override { + po::options_description desc(parameters_.description()); + + if (parameters_.parameters().size() > 0) { + for (auto& p: parameters_.parameters()) { + desc.add(p->as_boost_option()); + } + + parent.add(desc); + } + } + + void dump_config(std::ostream& os, bool only_modified) override { + os << "[" << parameters_.prefix() << "]" << std::endl; + for (auto& p: parameters_.parameters()) { + if (!p->modified() && only_modified) { + continue; + } + p->print(os); + os << std::endl; + } + os << std::endl; + } + +private: + std::string label_; + typename N::Parameters parameters_; +}; + +template +class ParallelProcessBuilder : public INodeBuilder { +public: + ParallelProcessBuilder(PipelineBuilder& parent) + : parent_(parent) + {} + + template + ParallelProcessBuilder& withPureNode(const std::string& label) { + auto nb = std::make_shared>(label); + builders_.emplace_back(nb); + return *this; + } + + PipelineBuilder& withWorkers(size_t workers) { + workers_ = workers; + return parent_; + } + + virtual std::shared_ptr build(const CTX& ctx) const override { + std::vector> pure_gadgets; + for (auto& builder : builders_) { + auto node = builder->build(ctx); + pure_gadgets.emplace_back(std::move(node)); + } + + Gadgetron::Main::Nodes::PureStream pure_stream(pure_gadgets); + + return std::make_shared(pure_stream, workers_); + } + + void collect_options(po::options_description& parent) override { + for (auto& builder: builders_) { + builder->collect_options(parent); + } + } + + void dump_config(std::ostream& os, bool only_modified) override { + for (auto& builder: builders_) { + builder->dump_config(os, only_modified); + } + } + +private: + PipelineBuilder& parent_; + size_t workers_; + + std::vector>> builders_; +}; + class ErrorThrower : public Gadgetron::Main::ErrorReporter { @@ -366,13 +520,18 @@ class ErrorThrower : public Gadgetron::Main::ErrorReporter class Pipeline; struct IPipelineBuilder { - IPipelineBuilder(const std::string& name, const std::string& description): name(name), description(description) { } + IPipelineBuilder(const std::string& name, const std::string& description): name_(name), description_(description) { } virtual Pipeline build(std::istream& input_stream, std::ostream& output_stream) = 0; virtual po::options_description collect_options(void) = 0; + virtual void dump_config(std::ostream& os, bool only_modified = false) = 0; virtual ~IPipelineBuilder() = default; - const std::string name; - const std::string description; + std::string name(void) const { return name_; } + std::string description(void) const { return description_; } + +protected: + std::string name_; + std::string description_; }; @@ -454,6 +613,13 @@ struct PipelineBuilder : public IPipelineBuilder{ PipelineBuilder(const std::string& pipeline_name, const std::string& pipeline_description) : IPipelineBuilder(pipeline_name, pipeline_description) {} + PipelineBuilder duplicate(const std::string& pipeline_name, const std::string& pipeline_description) const { + auto pb = *this; + pb.name_ = pipeline_name; + pb.description_ = pipeline_description; + return std::move(pb); + } + template PipelineBuilder& withSource(void) { source_builder_ = [](std::istream& is) { return std::make_shared(is); }; @@ -478,16 +644,25 @@ struct PipelineBuilder : public IPipelineBuilder{ auto pb = std::make_shared>(*this); streambuilder_.append(pb); return pb->template withBranch(label); - // return *pb; } + ParallelProcessBuilder& withParallelProcessStream(void) { + auto pb = std::make_shared>(*this); + streambuilder_.append(pb); + return *pb; + } + po::options_description collect_options(void) override { - po::options_description pipeline_desc(this->description); + po::options_description pipeline_desc(this->description_); streambuilder_.collect_options(pipeline_desc); return pipeline_desc; } + void dump_config(std::ostream& os, bool only_modified) override { + streambuilder_.dump_config(os, only_modified); + } + Pipeline build(std::istream& input_stream, std::ostream& output_stream) override { if (!source_builder_) { throw std::runtime_error("No source specified"); diff --git a/apps/pingvin/pipelines/streams.h b/apps/pingvin/pipelines/streams.h new file mode 100644 index 00000000..dcb0c93d --- /dev/null +++ b/apps/pingvin/pipelines/streams.h @@ -0,0 +1,72 @@ +#pragma once + +#include "pipeline.h" + +#include "gadgets/mri_core/NoiseAdjustGadget.h" +#include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" +#include "gadgets/mri_core/RemoveROOversamplingGadget.h" +#include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" +#include "gadgets/mri_core/BucketToBufferGadget.h" +#include "gadgets/mri_core/ImageArraySplitGadget.h" +#include "gadgets/mri_core/ComplexToFloatGadget.h" +#include "gadgets/mri_core/FloatToFixedPointGadget.h" +#include "gadgets/mri_core/AugmentImageMetadataGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" +#include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" + +namespace pingvin { + +static auto stream_cartesian_grappa_imagearray = PipelineBuilder("stream-cartesian-grappa-imagearray", "Cartesian Grappa Recon to ImageArray") + .withSource() + .withSink() + .withNode("noise") + .withNode("echo-adjust") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("coilcomp") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + ; + +static auto stream_cartesian_grappa = stream_cartesian_grappa_imagearray + .duplicate("stream-cartesian-grappa", "Cartesian Grappa Recon to complex Image") + .withNode("scale") + .withNode("split") + .withNode("augment-metadata") + ; + +static auto stream_image_array_scaling = PipelineBuilder("stream-image-array-scaling", "Image Array Scaling") + .withSource() + .withSink() + .withNode("scale") + ; + +static auto stream_image_array_split = PipelineBuilder("stream-image-array-split", "Image Array split") + .withSource() + .withSink() + .withNode("split") + ; + +static auto stream_complex_to_float = PipelineBuilder("stream-complex-to-float", "Complex to Float") + .withSource() + .withSink() + .withNode("complex-to-float") + ; + +static auto stream_float_to_fixed_point = PipelineBuilder("stream-float-to-fixed-point", "Float to Fixed-Point") + .withSource() + .withSink() + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/schema/gadgetron.xsd b/apps/pingvin/schema/gadgetron.xsd deleted file mode 100644 index 6b9602a3..00000000 --- a/apps/pingvin/schema/gadgetron.xsd +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/Parameters.h b/core/Parameters.h index f0c841e5..138e47a3 100644 --- a/core/Parameters.h +++ b/core/Parameters.h @@ -27,27 +27,46 @@ namespace Gadgetron::Core { namespace po = boost::program_options; struct IParameter { + IParameter(const std::string& prefix, const std::string& name, const std::string& description) + : prefix_(prefix), shortname_(name), fullname_(prefix + "." + name), description_(description) {} virtual boost::shared_ptr as_boost_option(void) const = 0; + virtual void print(std::ostream&) const = 0; + virtual bool modified(void) = 0; virtual ~IParameter() = default; + +protected: + std::string prefix_; + std::string shortname_; + std::string fullname_; + std::string description_; }; template class Parameter : public IParameter { public: - Parameter(const std::string& name, T* storage, const std::string& description) - : storage_(storage), name_(name), description_(description) {} + Parameter(const std::string& prefix, const std::string& name, const std::string& description, T* storage) + : IParameter(prefix, name, description), storage_(storage), default_value_(*storage) {} boost::shared_ptr as_boost_option(void) const override { return boost::make_shared( - name_.c_str(), - po::value(storage_)->default_value(*storage_), + fullname_.c_str(), + po::value(storage_)->default_value(default_value_), description_.c_str() ); } + void print(std::ostream& os) const override { + os << shortname_ << " = " << *storage_; + } + + bool modified(void) override { + return *storage_ != default_value_; + } + protected: T* storage_; + T default_value_; std::string name_; std::string description_; }; @@ -55,22 +74,30 @@ class Parameter : public IParameter { template class MultitokenParameter : public IParameter { public: - MultitokenParameter(const std::string& name, std::vector* storage, const std::string& description) - : storage_(storage), name_(name), description_(description) {} + MultitokenParameter(const std::string& prefix, const std::string& name + , const std::string& description, std::vector* storage) + : IParameter(prefix, name, description), storage_(storage), default_value_(*storage) {} boost::shared_ptr as_boost_option(void) const override { return boost::make_shared( - name_.c_str(), + fullname_.c_str(), po::value>(storage_)->default_value(*storage_)->multitoken(), description_.c_str() ); } + void print(std::ostream& os) const override { + os << shortname_ << " = " << *storage_; + } + + bool modified(void) override { + return *storage_ != default_value_; + } + protected: std::vector* storage_; - std::string name_; - std::string description_; + std::vector default_value_; }; class Flag : public Parameter { @@ -80,8 +107,8 @@ class Flag : public Parameter { boost::shared_ptr as_boost_option(void) const override { return boost::make_shared( - name_.c_str(), - po::bool_switch(this->storage_)->default_value(*this->storage_), + fullname_.c_str(), + po::bool_switch(this->storage_)->default_value(this->default_value_), description_.c_str() ); } @@ -95,28 +122,24 @@ class NodeParameters { template void register_parameter(const std::string& name, T* value, const std::string& description) { - auto argname = prefix_ + "." + name; - parameters_.push_back(std::make_shared>(argname, value, description)); + parameters_.push_back(std::make_shared>(prefix_, name, description, value)); } template void register_multitoken(const std::string& name, std::vector* value, const std::string& description) { - auto argname = prefix_ + "." + name; - parameters_.push_back(std::make_shared>(argname, value, description)); + parameters_.push_back(std::make_shared>(prefix_, name, description, value)); } void register_flag(const std::string& name, bool* value, const std::string& description) { - auto argname = prefix_ + "." + name; - parameters_.push_back(std::make_shared(argname, value, description)); + parameters_.push_back(std::make_shared(prefix_, name, description, value)); } const std::vector>& parameters() const { return parameters_; } - std::string description(void) const { - return description_; - } + std::string prefix(void) const { return prefix_; } + std::string description(void) const { return description_; } private: std::string prefix_; diff --git a/gadgets/cmr/config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py b/gadgets/cmr/config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py index 1fe36ba5..3d696c4d 100644 --- a/gadgets/cmr/config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py +++ b/gadgets/cmr/config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py @@ -233,14 +233,14 @@ def adaptive_thresh_cpu(probs, p_thresh=0.5, p_thresh_max=0.988): if __name__=="__main__": - GT_HOME = os.environ['GADGETRON_HOME'] - GT_PYTHON_DIR = os.path.join(GT_HOME, 'share/gadgetron/python') - print("GT_HOME is", GT_HOME) + PINGVIN_HOME = os.environ['PINGVIN_HOME'] + PINGVIN_PYTHON_DIR = os.path.join(PINGVIN_HOME, 'share/pingvin/python') + print("PINGVIN_HOME is", PINGVIN_HOME) # test get_model model_host = 'https://gadgetrondata.blob.core.windows.net/cmr-ai-models/' model_file = 'CMR_landmark_network_RO_320_E1_320_CH2_CH3_CH4_Myo_Pts_sFOV_LossMultiSoftProb_KLD_Dice_Pytorch_1.8.0a0+37c1f4a_2021-08-08_20210808_085042.onnx' - model_dest = os.path.join(GT_PYTHON_DIR, 'cmr_lax_landmark_detection') + model_dest = os.path.join(PINGVIN_PYTHON_DIR, 'cmr_lax_landmark_detection') model_sha256 = '48efe3e70b1ff083c9dd0066469f62bf495e52857d68893296e7375b69f691e4' res = check_and_get_model(model_host, model_file, model_dest, model_sha256) diff --git a/gadgets/examples/ImageInverter.h b/gadgets/examples/ImageInverter.h index 0b4fd750..0e67f278 100644 --- a/gadgets/examples/ImageInverter.h +++ b/gadgets/examples/ImageInverter.h @@ -5,7 +5,7 @@ namespace Gadgetron::Examples { class ImageInverter : public Core::MRPureGadget { public: - using Core::MRPureGadget::PureGadget; + using MRPureGadget::MRPureGadget; mrd::AnyImage process_function(mrd::AnyImage image) const override; }; } diff --git a/gadgets/grappa/grappa_cpu.ini b/gadgets/grappa/grappa_cpu.ini deleted file mode 100644 index 2d80f508..00000000 --- a/gadgets/grappa/grappa_cpu.ini +++ /dev/null @@ -1,20 +0,0 @@ -[noise] - -[pca] - -[coil-reduction] -coils-out=8 - -[weights] -coil-map-estimation-ks=5 - -[unmixing] -image-series=42 - -[extract] -magnitude=true - -[scale] - -[convert] -type=ushort \ No newline at end of file diff --git a/gadgets/mri_core/AccumulatorGadget.cpp b/gadgets/mri_core/AccumulatorGadget.cpp index 1d4f9755..df0a3817 100644 --- a/gadgets/mri_core/AccumulatorGadget.cpp +++ b/gadgets/mri_core/AccumulatorGadget.cpp @@ -28,8 +28,7 @@ AccumulatorGadget::AccumulatorGadget(const Core::MrdContext& context, const Para auto h = (context.header); if (h.encoding.size() != 1) { GDEBUG("Number of encoding spaces: %d\n", h.encoding.size()); - GDEBUG("This simple AccumulatorGadget only supports one encoding space\n"); - // TODO: How to throw Gadget failures? + GADGET_THROW("This simple AccumulatorGadget only supports one encoding space"); } mrd::EncodingSpaceType e_space = h.encoding[0].encoded_space; diff --git a/gadgets/mri_core/DenoiseGadget.h b/gadgets/mri_core/DenoiseGadget.h index 7c80200b..106b1161 100644 --- a/gadgets/mri_core/DenoiseGadget.h +++ b/gadgets/mri_core/DenoiseGadget.h @@ -21,8 +21,8 @@ namespace Gadgetron { Parameters(const std::string& prefix) : Core::NodeParameters(prefix, "Denoising Options") { - register_parameter("image_std", &image_std, "Standard deviation of the noise in the produced image"); - register_parameter("search_radius", &search_radius, "Standard deviation of the noise in the produced image"); + register_parameter("image-std", &image_std, "Standard deviation of the noise in the produced image"); + register_parameter("search-radius", &search_radius, "Standard deviation of the noise in the produced image"); register_parameter("denoiser", &denoiser, "Type of denoiser - non_local_means or non_local_bayes"); } }; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h index 2bcaa92f..9204b413 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h @@ -39,7 +39,7 @@ namespace Gadgetron { } bool use_constant_scalingFactor = true; - float scalingFactor = 4.0; + float scalingFactor = 10.0; int min_intensity_value = 64; int max_intensity_value = 4095; bool auto_scaling_only_once = true; diff --git a/test/e2e/cases/cmr_cine_binning.yml b/test/e2e/cases/cmr_cine_binning.yml index 3e6e1e4a..e410b36d 100644 --- a/test/e2e/cases/cmr_cine_binning.yml +++ b/test/e2e/cases/cmr_cine_binning.yml @@ -1,12 +1,12 @@ dependency: data: cmr/CineBinning/meas_MID00247_FID39104_PK_realtime_gt_TPAT4_6_8/meas_MID00247_FID39104_PK_realtime_gt_TPAT4_6_8_meas1.mrd checksum: 2d1a20b2ae5848b595de2838bc0b4d6d - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./mycov.bin + args: noise --noise.covariance-output=./mycov.bin reconstruction: data: cmr/CineBinning/meas_MID00247_FID39104_PK_realtime_gt_TPAT4_6_8/meas_MID00247_FID39104_PK_realtime_gt_TPAT4_6_8_meas2.mrd checksum: d36c3f68c11305109e0c71f59d08e546 run: - - args: --config CMR_2DT_RTCine_KspaceBinning.xml --parameter noisecovariancein=./mycov.bin + - args: cmr-cine-binning -c ${PINGVIN_CONFIG_DIR}/cmr-cine-binning.conf --noise.covariance-input=./mycov.bin validation: reference: cmr/CineBinning/meas_MID00247_FID39104_PK_realtime_gt_TPAT4_6_8/cmr_cine_binning_ref_20220817_CMR_2DT_RTCine_KspaceBinning.xml.mrd checksum: 2b4c536b5798bcb16915175b6dc18fb0 diff --git a/test/e2e/cases/cmr_cine_binning_2slices.yml b/test/e2e/cases/cmr_cine_binning_2slices.yml index d43a8404..1292f5ed 100644 --- a/test/e2e/cases/cmr_cine_binning_2slices.yml +++ b/test/e2e/cases/cmr_cine_binning_2slices.yml @@ -2,7 +2,7 @@ reconstruction: data: cmr/CineBinning/meas_MID838_PK_rt_test_2slice_FID22519/meas_MID838_PK_rt_test_2slice_FID22519_meas2.mrd checksum: 74a86376c119141f42088b906c33ed7d run: - - args: --config CMR_2DT_RTCine_KspaceBinning.xml + - args: cmr-cine-binning -c ${PINGVIN_CONFIG_DIR}/cmr-cine-binning.conf validation: reference: cmr/CineBinning/meas_MID838_PK_rt_test_2slice_FID22519/cmr_cine_binning_2slice_ref_20220817_CMR_2DT_RTCine_KspaceBinning.xml.mrd checksum: cd2db40590514e5d6b27125e5284217f diff --git a/test/e2e/cases/cmr_mapping_t1_sr.yml b/test/e2e/cases/cmr_mapping_t1_sr.yml index 5a3ccd9a..685f8500 100644 --- a/test/e2e/cases/cmr_mapping_t1_sr.yml +++ b/test/e2e/cases/cmr_mapping_t1_sr.yml @@ -1,19 +1,19 @@ dependency: data: cmr/T1SRmapping/meas_MID00613_FID40909_pre_SASHA_10pt_TS600_256/meas_MID00613_FID40909_pre_SASHA_10pt_TS600_256_meas1.mrd checksum: f35780e08c94a595ceec035cb34b4867 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./mycov.bin + args: noise --noise.covariance-output=./mycov.bin reconstruction: data: cmr/T1SRmapping/meas_MID00613_FID40909_pre_SASHA_10pt_TS600_256/meas_MID00613_FID40909_pre_SASHA_10pt_TS600_256_meas2.mrd checksum: 831b03b5afe093226b33aef192bb7bd3 run: - - args: --config CMR_2DT_T1Mapping_SASHA.xml --parameter noisecovariancein=./mycov.bin + - args: cmr-mapping-t1-sr -c ${PINGVIN_CONFIG_DIR}/cmr-mapping-t1-sr.conf --noise.covariance-input=./mycov.bin validation: reference: cmr/T1SRmapping/meas_MID00613_FID40909_pre_SASHA_10pt_TS600_256/ref_20170427_CMR_2DT_T1Mapping_SASHA.xml.mrd checksum: 159c8cc597e49dd528752f439e59d5b6 tests: - image_series: 1 - - image_series: 12 - image_series: 11 + - image_series: 12 - image_series: 20 requirements: system_memory: 16384 diff --git a/test/e2e/cases/cpu_grappa_simple.yml b/test/e2e/cases/cpu_grappa_simple.yml index 0ed0c0c4..4e042264 100644 --- a/test/e2e/cases/cpu_grappa_simple.yml +++ b/test/e2e/cases/cpu_grappa_simple.yml @@ -2,7 +2,7 @@ reconstruction: data: rtgrappa/acc_data_with_device_2_meas1.mrd checksum: 7fa1d38320b2a544148096ce09041b2a run: - - args: --config grappa_float_cpu.xml + - args: grappa-cpu --coil-reduction.coils-out=8 --extract.magnitude validation: reference: rtgrappa/grappa_rate2_cpu_out_grappa_float_cpu.xml.mrd checksum: f24f9b93670cfa0c1723493ce52c07c5 diff --git a/test/e2e/cases/epi_2d.yml b/test/e2e/cases/epi_2d.yml index eb920abd..0d913438 100644 --- a/test/e2e/cases/epi_2d.yml +++ b/test/e2e/cases/epi_2d.yml @@ -1,12 +1,12 @@ dependency: data: epi/meas_MID517_nih_ep2d_bold_fa60_FID82077_meas1.mrd checksum: 00d10ca0c8f3ce7d09daa4122ccec060 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./mycov.bin + args: noise --noise.covariance-output=./mycov.bin reconstruction: data: epi/meas_MID517_nih_ep2d_bold_fa60_FID82077_meas2.mrd checksum: f81ae88921596e86104d2300a36da67a run: - - args: --config epi.xml --parameter noisecovariancein=./mycov.bin + - args: epi -c ${PINGVIN_CONFIG_DIR}/epi.conf --noise.covariance-input=./mycov.bin validation: reference: epi/epi_2d_out_20161020_pjv_epi.xml.mrd checksum: 5650ee6e4c5a8a94b012efadc871a31d diff --git a/test/e2e/cases/generic_cartesian_cine_denoise.yml b/test/e2e/cases/generic_cartesian_cine_denoise.yml index 4fb705f2..8c86bc0a 100644 --- a/test/e2e/cases/generic_cartesian_cine_denoise.yml +++ b/test/e2e/cases/generic_cartesian_cine_denoise.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4_meas1.mrd checksum: 7a3a0428caf5f124244cd480496697ff - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4_meas2.mrd checksum: 0aca9a1366649448ce81ae7c74bd53b7 run: - - args: --config Generic_Cartesian_Grappa_Cine_Denoise.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-cine-denoise -c ${PINGVIN_CONFIG_DIR}/cartesian-cine-denoise.conf --noise.covariance-input=./noisecovariance.bin validation: reference: denoise/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/denoise_ref_20220817_Generic_Cartesian_Grappa_Cine_Denoise.xml.mrd checksum: b22acff9870723ccebb81083134d8f94 diff --git a/test/e2e/cases/generic_cartesian_cine_python.yml b/test/e2e/cases/generic_cartesian_cine_python.yml deleted file mode 100644 index 222aaa9f..00000000 --- a/test/e2e/cases/generic_cartesian_cine_python.yml +++ /dev/null @@ -1,22 +0,0 @@ -dependency: - data: generic/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4_meas1.mrd - checksum: 7a3a0428caf5f124244cd480496697ff - args: --config default_measurement_dependencies.xml -reconstruction: - data: generic/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4_meas2.mrd - checksum: 0aca9a1366649448ce81ae7c74bd53b7 - run: - - args: --config Generic_Cartesian_Grappa_RealTimeCine_Python.xml -validation: - reference: generic/meas_MID00051_FID110020_SAX_realtime_gt_TPAT4/ref/ref_20220831_Generic_Cartesian_Grappa_RealTimeCine_Python.xml.mrd - checksum: 3ac8f97a914e205aa235513109519fb5 - tests: - - image_series: 1 - value_comparison_threshold: 0.005 - scale_comparison_threshold: 0.001 -requirements: - system_memory: 6384 - python_support: 1 -tags: -- generic -- skip diff --git a/test/e2e/cases/generic_grappa2x1_3d.yml b/test/e2e/cases/generic_grappa2x1_3d.yml index a32c6379..c0404d08 100644 --- a/test/e2e/cases/generic_grappa2x1_3d.yml +++ b/test/e2e/cases/generic_grappa2x1_3d.yml @@ -2,7 +2,7 @@ reconstruction: data: grappa_3d/gre_3D_Grappa2x1.mrd checksum: 3ada3323ee3880837afc45eb73596c9f run: - - args: --config Generic_Cartesian_Grappa.xml + - args: cartesian-grappa -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa.conf validation: reference: grappa_3d/grappa2x1_ref_20210917_Generic_Cartesian_Grappa.xml.mrd checksum: 1bf4fc3d687131a7f88cb21d32f5e5ce diff --git a/test/e2e/cases/generic_grappa2x2_3d.yml b/test/e2e/cases/generic_grappa2x2_3d.yml index 90702f56..25205804 100644 --- a/test/e2e/cases/generic_grappa2x2_3d.yml +++ b/test/e2e/cases/generic_grappa2x2_3d.yml @@ -2,7 +2,7 @@ reconstruction: data: grappa_3d/gre_3D_Grappa2x2.mrd checksum: bb5cdd47277b73adc0ffb68ae3366423 run: - - args: --config Generic_Cartesian_Grappa.xml + - args: cartesian-grappa -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa.conf validation: reference: grappa_3d/grappa2x2_ref_20210917_Generic_Cartesian_Grappa.xml.mrd checksum: 9ef157c7ab4c78dd55fc3e4cefdd4307 diff --git a/test/e2e/cases/generic_grappa_T2W.yml b/test/e2e/cases/generic_grappa_T2W.yml index 9084f009..b2ae92f0 100644 --- a/test/e2e/cases/generic_grappa_T2W.yml +++ b/test/e2e/cases/generic_grappa_T2W.yml @@ -1,12 +1,12 @@ dependency: data: T2W/meas_MID00057_T2w_meas1.mrd checksum: 5b911eb6764b0fcd83a7982b5a6ba58f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: T2W/meas_MID00057_T2w_meas2.mrd checksum: 9f62098a12acf87d4c1f132b1338c382 run: - - args: --config Generic_Cartesian_Grappa_T2W.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-t2w.conf --noise.covariance-input=./noisecovariance.bin validation: reference: T2W/generic_grappa_T2W_ref_20220817_klk_Generic_Cartesian_Grappa_T2W.xml.mrd checksum: bfb41fe6b7e7684427178330a76be631 diff --git a/test/e2e/cases/generic_grappa_epi_ave.yml b/test/e2e/cases/generic_grappa_epi_ave.yml index 2fc7f074..87877a22 100644 --- a/test/e2e/cases/generic_grappa_epi_ave.yml +++ b/test/e2e/cases/generic_grappa_epi_ave.yml @@ -2,7 +2,7 @@ reconstruction: data: epi_ave/meas_MID01349_FID12150_amri_ep2d_bold_96x72x5_R2_16avg_gadgetron/meas_MID01349_FID12150_amri_ep2d_bold_96x72x5_R2_16avg_gadgetron_meas1.mrd checksum: d40c03ad7baf11c3632ff98fd76990a2 run: - - args: --config Generic_Cartesian_Grappa_EPI_AVE.xml + - args: grappa-epi -c ${PINGVIN_CONFIG_DIR}/grappa-epi.conf validation: reference: epi_ave/meas_MID01349_FID12150_amri_ep2d_bold_96x72x5_R2_16avg_gadgetron/ref_20161020_Generic_Cartesian_Grappa_EPI_AVE.xml.mrd checksum: 205130be2eda57c17b72b38cd06143c4 diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100.yml index bbcb611a..59005978 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/meas_MID00393_FID114595_R1_PEFOV100_PERes100_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/meas_MID00393_FID114595_R1_PEFOV100_PERes100_meas2.mrd checksum: ceb074080aaecc3d91ad10b1af68c1c1 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: e48efebf8c418e4bdbf2e0039e93b3ef diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100_compression.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100_compression.yml index bbcb611a..59005978 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100_compression.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100_compression.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/meas_MID00393_FID114595_R1_PEFOV100_PERes100_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/meas_MID00393_FID114595_R1_PEFOV100_PERes100_meas2.mrd checksum: ceb074080aaecc3d91ad10b1af68c1c1 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00393_FID114595_R1_PEFOV100_PERes100/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: e48efebf8c418e4bdbf2e0039e93b3ef diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes120.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes120.yml index 9c8fb163..3f737b9f 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes120.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes120.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00423_FID114625_R1_PEFOV100_PERes120/meas_MID00423_FID114625_R1_PEFOV100_PERes120_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00423_FID114625_R1_PEFOV100_PERes120/meas_MID00423_FID114625_R1_PEFOV100_PERes120_meas2.mrd checksum: 1b698800ab9279924e4639e58fd5b467 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00423_FID114625_R1_PEFOV100_PERes120/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 1fa20855df1e212b89b2b4636a3cb5d6 diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75.yml index 29502d76..8be437a9 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00394_FID114596_R1_PEFOV75_PERes75/meas_MID00394_FID114596_R1_PEFOV75_PERes75_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00394_FID114596_R1_PEFOV75_PERes75/meas_MID00394_FID114596_R1_PEFOV75_PERes75_meas2.mrd checksum: 64c38da334dc8e6eae0dee8648bd3afe run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00394_FID114596_R1_PEFOV75_PERes75/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 27bf23e391b2885437b8f7a8518e26fa diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml index 731b895e..8162036c 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00395_FID114597_R1_PEFOV75_PERes75_PF6_8/meas_MID00395_FID114597_R1_PEFOV75_PERes75_PF6_8_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00395_FID114597_R1_PEFOV75_PERes75_PF6_8/meas_MID00395_FID114597_R1_PEFOV75_PERes75_PF6_8_meas2.mrd checksum: a237e39855d33874c5aa3ef188a11c25 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00395_FID114597_R1_PEFOV75_PERes75_PF6_8/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 9fd6e26ed3f4a88fb402f399e2f0d0f4 diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml index 3b0d469f..73a2793b 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00396_FID114598_R1_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00396_FID114598_R1_PEFOV75_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00396_FID114598_R1_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00396_FID114598_R1_PEFOV75_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: 71e2a767bc3943f8d7ab24f6bd9f2177 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00396_FID114598_R1_PEFOV75_PERes75_PF6_8_AsymStrong/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 423491521cc2e636f0bc7f75875fa48c diff --git a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml index 94fa90b6..b00c6746 100644 --- a/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml +++ b/test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00397_FID114599_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/meas_MID00397_FID114599_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00397_FID114599_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/meas_MID00397_FID114599_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON_meas2.mrd checksum: f307331910b778bc5d79f4522a638ffb run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00397_FID114599_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: c57c0b25dd7bbbd225e3158fe30d2e9c diff --git a/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PEOverSampling120.yml b/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PEOverSampling120.yml index 85ed9d8a..20d13a18 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PEOverSampling120.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PEOverSampling120.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00077_FID115844_R2_ipat_PEFOV75_PERes75_PEOverSampling120/meas_MID00077_FID115844_R2_ipat_PEFOV75_PERes75_PEOverSampling120_meas1.mrd checksum: 4ed9f2d7be765d00437ab13729bcfff6 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00077_FID115844_R2_ipat_PEFOV75_PERes75_PEOverSampling120/meas_MID00077_FID115844_R2_ipat_PEFOV75_PERes75_PEOverSampling120_meas2.mrd checksum: aeb6b8d24f0626db2a99c2f62ff29c49 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00077_FID115844_R2_ipat_PEFOV75_PERes75_PEOverSampling120/ref_20220817_klk_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: de28a78d7c751df6f676ebf4408bbc61 diff --git a/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml index d8977e69..8327bb9a 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00411_FID114613_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00411_FID114613_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00411_FID114613_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00411_FID114613_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: add48b9db61462d3772d3deb01ce3df4 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00411_FID114613_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 193e0869a015daa525fe49b790322b8d diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes100.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes100.yml index d8af948a..fc366d1e 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes100.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes100.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00398_FID114600_R2_spat_PEFOV100_PERes100/meas_MID00398_FID114600_R2_spat_PEFOV100_PERes100_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00398_FID114600_R2_spat_PEFOV100_PERes100/meas_MID00398_FID114600_R2_spat_PEFOV100_PERes100_meas2.mrd checksum: 7bfdcd5cfd3f877a7dde771345953186 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00398_FID114600_R2_spat_PEFOV100_PERes100/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: e36e2e5890ac341d040792ca40fc9ecb diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes120.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes120.yml index 067beddc..84b9b364 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes120.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes120.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00424_FID114626_R2_spat__PEFOV100_PERes120/meas_MID00424_FID114626_R2_spat__PEFOV100_PERes120_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00424_FID114626_R2_spat__PEFOV100_PERes120/meas_MID00424_FID114626_R2_spat__PEFOV100_PERes120_meas2.mrd checksum: ed86f567f579c65dd678b78c8a5ede9c run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00424_FID114626_R2_spat__PEFOV100_PERes120/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: efbb2277ccc715173f53e16ac3f5ff42 diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75.yml index 88d883b5..5b4fb734 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00399_FID114601_R2_spat_PEFOV75_PERes75/meas_MID00399_FID114601_R2_spat_PEFOV75_PERes75_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00399_FID114601_R2_spat_PEFOV75_PERes75/meas_MID00399_FID114601_R2_spat_PEFOV75_PERes75_meas2.mrd checksum: 2996f7c0c3e14f75e9db4afcaab22171 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00399_FID114601_R2_spat_PEFOV75_PERes75/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 6b2d12741716aafe2be96b7fd933e4b8 diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml index 5f48d066..305dca67 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00400_FID114602_R2_spat_PEFOV75_PERes75_PF6_8/meas_MID00400_FID114602_R2_spat_PEFOV75_PERes75_PF6_8_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00400_FID114602_R2_spat_PEFOV75_PERes75_PF6_8/meas_MID00400_FID114602_R2_spat_PEFOV75_PERes75_PF6_8_meas2.mrd checksum: 4fc3f6e35802dd1a63c9c38c43f216f8 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00400_FID114602_R2_spat_PEFOV75_PERes75_PF6_8/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 5fc582d52972cbd92018d6529d075502 diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml index 6e9b22e6..790eb55f 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00401_FID114603_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00401_FID114603_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00401_FID114603_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00401_FID114603_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: 095d0c344d37bba6e9607db78a4602ad run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00401_FID114603_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: e73a694feb5795b537d7ea086b659e1e diff --git a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml index 589ec03e..ccadd301 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00402_FID114604_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/meas_MID00402_FID114604_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00402_FID114604_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/meas_MID00402_FID114604_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON_meas2.mrd checksum: 445ef397044a9cea98d028fe1241a004 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00402_FID114604_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: b3364f512c986b96b2637de4b00c97ed diff --git a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV100_PERes100.yml b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV100_PERes100.yml index 0ce393d2..9316d490 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV100_PERes100.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV100_PERes100.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00403_FID114605_R2_tpat_PEFOV100_PERes100/meas_MID00403_FID114605_R2_tpat_PEFOV100_PERes100_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00403_FID114605_R2_tpat_PEFOV100_PERes100/meas_MID00403_FID114605_R2_tpat_PEFOV100_PERes100_meas2.mrd checksum: 569f13f7e117e0edc2e524d891628670 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00403_FID114605_R2_tpat_PEFOV100_PERes100/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 6f63582615a834bea41cd6b299ad77a8 diff --git a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75.yml b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75.yml index fc19bc35..e012c8d2 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00404_FID114606_R2_tpat_PEFOV75_PERes75/meas_MID00404_FID114606_R2_tpat_PEFOV75_PERes75_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00404_FID114606_R2_tpat_PEFOV75_PERes75/meas_MID00404_FID114606_R2_tpat_PEFOV75_PERes75_meas2.mrd checksum: e69e5be72fdc74ce59d0f6cb730fdcc8 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00404_FID114606_R2_tpat_PEFOV75_PERes75/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 157c9727504907b5d45aba13ca5910fb diff --git a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml index 1aaa19e9..497c400c 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00405_FID114607_R2_tpat_PEFOV75_PERes75_PF6_8/meas_MID00405_FID114607_R2_tpat_PEFOV75_PERes75_PF6_8_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00405_FID114607_R2_tpat_PEFOV75_PERes75_PF6_8/meas_MID00405_FID114607_R2_tpat_PEFOV75_PERes75_PF6_8_meas2.mrd checksum: 3337ec90fe8ad2656ec569c2f88ae945 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00405_FID114607_R2_tpat_PEFOV75_PERes75_PF6_8/ref_20210921_klk_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 45aeb1f5dbeab9c94edc6c1754c71f2f diff --git a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml index 81d31038..2ff2e09f 100644 --- a/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00406_FID114608_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00406_FID114608_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00406_FID114608_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong/meas_MID00406_FID114608_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: e5543ebc1cc23305017d44a2db9181b9 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00406_FID114608_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong/ref_20210921_klk_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: d40fb9a29927bbe665bf084071b6db0b diff --git a/test/e2e/cases/generic_grappa_snr_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml index d13954ad..f1ab2e3b 100644 --- a/test/e2e/cases/generic_grappa_snr_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00416_FID114618_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong/meas_MID00416_FID114618_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00416_FID114618_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong/meas_MID00416_FID114618_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: b5a17ff56421d7556801a5e41e068801 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00416_FID114618_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong/ref_20160401_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 97c8c4ed1ed79d9f962bfe946b038972 diff --git a/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes120.yml b/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes120.yml index 495c4c8c..ec5d53b9 100644 --- a/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes120.yml +++ b/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes120.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00427_FID114629_R3_tpat__PEFOV100_PERes120/meas_MID00427_FID114629_R3_tpat__PEFOV100_PERes120_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00427_FID114629_R3_tpat__PEFOV100_PERes120/meas_MID00427_FID114629_R3_tpat__PEFOV100_PERes120_meas2.mrd checksum: 560b4c0dfcb3d4b69f8b4bf1852b346b run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00427_FID114629_R3_tpat__PEFOV100_PERes120/ref_20210923_klk_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: 01cd4b56de5042c8c14e52d7744d604e diff --git a/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml b/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml index e1f84eb2..d4e7ba78 100644 --- a/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml +++ b/test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID00421_FID114623_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong/meas_MID00421_FID114623_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong_meas1.mrd checksum: d43bf8c9efa72ffe5fdaa911f6cafb4f - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: generic/meas_MID00421_FID114623_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong/meas_MID00421_FID114623_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong_meas2.mrd checksum: f767be2f9f62bde21026d66e3d0c3cc2 run: - - args: --config Generic_Cartesian_Grappa_SNR.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa-snr -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa-snr.conf --noise.covariance-input=./noisecovariance.bin validation: reference: generic/meas_MID00421_FID114623_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong/ref_20210923_klk_Generic_Cartesian_Grappa_SNR.xml.mrd checksum: ba201226bb3b60ddd5d0f2cd790d80e1 diff --git a/test/e2e/cases/generic_grappa_tse.yml b/test/e2e/cases/generic_grappa_tse.yml index a7463e37..932a36e5 100644 --- a/test/e2e/cases/generic_grappa_tse.yml +++ b/test/e2e/cases/generic_grappa_tse.yml @@ -1,12 +1,12 @@ dependency: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas1.mrd checksum: c22ac7f599bd09a5947081567c39d945 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./noisecovariance.bin + args: noise --noise.covariance-output=./noisecovariance.bin reconstruction: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas2.mrd checksum: 58d3a0bb4dec00d5315f8ddb22679189 run: - - args: --config Generic_Cartesian_Grappa.xml --parameter noisecovariancein=./noisecovariance.bin + - args: cartesian-grappa -c ${PINGVIN_CONFIG_DIR}/cartesian-grappa.conf --noise.covariance-input=./noisecovariance.bin validation: reference: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/ref_20220817_klk_Generic_Cartesian_Grappa.xml.mrd checksum: ce76e05ce86d65b501663c19f7b252e3 diff --git a/test/e2e/cases/generic_nl_spirit_cartesian_sampling_cine.yml b/test/e2e/cases/generic_nl_spirit_cartesian_sampling_cine.yml index ff537160..4da97dd5 100644 --- a/test/e2e/cases/generic_nl_spirit_cartesian_sampling_cine.yml +++ b/test/e2e/cases/generic_nl_spirit_cartesian_sampling_cine.yml @@ -1,12 +1,12 @@ dependency: data: generic/meas_MID836_1slice_FID22517/meas_MID836_1slice_FID22517_meas1.mrd checksum: 597bebf9348947443f18012d88805c2d - args: --config default_measurement_dependencies.xml + args: noise reconstruction: data: generic/meas_MID836_1slice_FID22517/meas_MID836_1slice_FID22517_meas2.mrd checksum: 7744e379a2433bf279219d60b5eb927b run: - - args: --config Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml + - args: cartesian-nonlinear-spirit -c ${PINGVIN_CONFIG_DIR}/cartesian-nonlinear-spirit-realtimecine.conf validation: reference: generic/meas_MID836_1slice_FID22517/ref_20220817_klk_Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml.mrd checksum: c89fd653df87cba4f28c05c28540826d diff --git a/test/e2e/cases/generic_nl_spirit_random_sampling_cine.yml b/test/e2e/cases/generic_nl_spirit_random_sampling_cine.yml index c07de9b5..95653338 100644 --- a/test/e2e/cases/generic_nl_spirit_random_sampling_cine.yml +++ b/test/e2e/cases/generic_nl_spirit_random_sampling_cine.yml @@ -2,7 +2,7 @@ reconstruction: data: generic/meas_MID01095_FID40115/meas_MID01095_FID40115.mrd checksum: 91b2560e7e1ecce9416de870884adaa6 run: - - args: --config Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml + - args: cartesian-nonlinear-spirit -c ${PINGVIN_CONFIG_DIR}/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf validation: reference: generic/meas_MID01095_FID40115/ref_20210923_klk_Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml.mrd checksum: 4b0ea481e7f3f7ada0ef9c6642baa47d diff --git a/test/e2e/cases/generic_rtcine_ai_landmark.yml b/test/e2e/cases/generic_rtcine_ai_landmark.yml index b3dc799c..c6a61fcb 100644 --- a/test/e2e/cases/generic_rtcine_ai_landmark.yml +++ b/test/e2e/cases/generic_rtcine_ai_landmark.yml @@ -2,7 +2,7 @@ reconstruction: data: cmr/RTCine/CH4/rtcine_R4_CH2.mrd checksum: 5bf49331b41432b244d12654b9c6a446 run: - - args: --config CMR_RTCine_LAX_AI.xml + - args: cmr-rtcine-lax-ai -c ${PINGVIN_CONFIG_DIR}/cmr-rtcine-lax-ai.conf validation: reference: cmr/RTCine/CH4/ref_20220124_173736_CMR_RTCine_LAX_AI.xml.mrd checksum: 491f51de1fc3b9982766fac94318f25e @@ -19,4 +19,4 @@ requirements: tags: - slow - generic -- skip +- skip # The Python code applying the AI model needs to be updated \ No newline at end of file diff --git a/test/e2e/cases/generic_spirit_cartesian_sampling_spat2.yml b/test/e2e/cases/generic_spirit_cartesian_sampling_spat2.yml index 7adaad6c..aa1b2f58 100644 --- a/test/e2e/cases/generic_spirit_cartesian_sampling_spat2.yml +++ b/test/e2e/cases/generic_spirit_cartesian_sampling_spat2.yml @@ -2,7 +2,7 @@ reconstruction: data: generic/meas_MID00062_FID114726_SAX_SASHA/meas_MID00062_FID114726_SAX_SASHA_meas1.mrd checksum: cf48dfa0563cb30a7517d39b75866eda run: - - args: --config Generic_Cartesian_Spirit_SASHA.xml + - args: cartesian-spirit -c ${PINGVIN_CONFIG_DIR}/cartesian-spirit.conf validation: reference: generic/meas_MID00062_FID114726_SAX_SASHA/ref_20220817_klk_Generic_Cartesian_Spirit_SASHA.xml.mrd checksum: 6233d3fc7aa000c33712af1dfb27f9a3 diff --git a/test/e2e/cases/gpu_grappa_simple.yml b/test/e2e/cases/gpu_grappa_simple.yml index 9bdf6acd..78191454 100644 --- a/test/e2e/cases/gpu_grappa_simple.yml +++ b/test/e2e/cases/gpu_grappa_simple.yml @@ -2,7 +2,7 @@ reconstruction: data: rtgrappa/acc_data_with_device_2_meas1.mrd checksum: 7fa1d38320b2a544148096ce09041b2a run: - - args: --config grappa_float.xml + - args: grappa --coil-reduction.coils-out=8 --extract.magnitude validation: reference: rtgrappa/grappa_rate2_cpu_out_grappa_float_cpu.xml.mrd checksum: f24f9b93670cfa0c1723493ce52c07c5 diff --git a/test/e2e/cases/parallel_bypass_example.yml b/test/e2e/cases/parallel_bypass_example.yml index b8597a64..39ffe602 100644 --- a/test/e2e/cases/parallel_bypass_example.yml +++ b/test/e2e/cases/parallel_bypass_example.yml @@ -2,7 +2,7 @@ reconstruction: data: simple_gre/meas_MiniGadgetron_GRE_meas1.mrd checksum: 382b7f32b77d3a078d8af75a365cec4c run: - - args: --config parallel_bypass_example.xml + - args: parallel-bypass --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude validation: reference: simple_gre/simple_gre_out_20210909_klk_inverted.mrd checksum: 303a2e4286e9c51783879325a5efb635 diff --git a/test/e2e/cases/simple_gre.yml b/test/e2e/cases/simple_gre.yml index 6cd5051f..cd84fee5 100644 --- a/test/e2e/cases/simple_gre.yml +++ b/test/e2e/cases/simple_gre.yml @@ -2,7 +2,7 @@ reconstruction: data: simple_gre/meas_MiniGadgetron_GRE_meas1.mrd checksum: 382b7f32b77d3a078d8af75a365cec4c run: - - args: --config default.xml + - args: default --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude validation: reference: simple_gre/simple_gre_out_20210909_klk_default.xml.mrd checksum: 5539627da4affccf396a39ffae0005e0 diff --git a/test/e2e/cases/simple_gre_3d.yml b/test/e2e/cases/simple_gre_3d.yml index 93db2478..701fda40 100644 --- a/test/e2e/cases/simple_gre_3d.yml +++ b/test/e2e/cases/simple_gre_3d.yml @@ -2,7 +2,7 @@ reconstruction: data: gre_3d/meas_MID248_gre_FID30644_meas1.mrd checksum: f744396f98767c09df7b9a33c7fd263b run: - - args: --config default_optimized.xml + - args: default-optimized --coil-reduction.coils-out=16 --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude validation: reference: gre_3d/simple_gre_out_3d_20210910_klk_default_optimized.xml.mrd checksum: 745c71b36b03f78570f8296a9dbf5b71 diff --git a/test/e2e/cases/stream_image.yml b/test/e2e/cases/stream_image.yml index cae81d3a..6f8b4b0e 100644 --- a/test/e2e/cases/stream_image.yml +++ b/test/e2e/cases/stream_image.yml @@ -1,14 +1,14 @@ dependency: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas1.mrd checksum: c22ac7f599bd09a5947081567c39d945 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./mycov.bin + args: noise --noise.covariance-output=./mycov.bin reconstruction: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas2.mrd checksum: 58d3a0bb4dec00d5315f8ddb22679189 run: - - args: --config Generic_Cartesian_Grappa_Complex.xml --parameter noisecovariancein=./mycov.bin - - args: --config stream_complex_to_float.xml - - args: --config stream_float_to_short.xml + - args: stream-cartesian-grappa -c ${PINGVIN_CONFIG_DIR}/stream-cartesian-grappa.conf --noise.covariance-input=./mycov.bin + - args: stream-complex-to-float + - args: stream-float-to-fixed-point --convert.type=ushort --convert.max-intensity=32767 --convert.intensity-offset=0 validation: reference: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/ref_20220817_klk_Generic_Cartesian_Grappa.xml.mrd checksum: ce76e05ce86d65b501663c19f7b252e3 diff --git a/test/e2e/cases/stream_image_array.yml b/test/e2e/cases/stream_image_array.yml index 1fda40f2..5b30a019 100644 --- a/test/e2e/cases/stream_image_array.yml +++ b/test/e2e/cases/stream_image_array.yml @@ -1,16 +1,16 @@ dependency: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas1.mrd checksum: c22ac7f599bd09a5947081567c39d945 - args: --config default_measurement_dependencies.xml --parameter noisecovarianceout=./mycov.bin + args: noise --noise.covariance-output=./mycov.bin reconstruction: data: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/meas_MID00450_FID76726_SAX_TE62_DIR_TSE_meas2.mrd checksum: 58d3a0bb4dec00d5315f8ddb22679189 run: - - args: --config Generic_Cartesian_Grappa_ImageArray.xml --parameter noisecovariancein=./mycov.bin - - args: --config stream_image_array_scaling.xml - - args: --config stream_image_array_split.xml - - args: --config stream_complex_to_float.xml - - args: --config stream_float_to_short.xml + - args: stream-cartesian-grappa-imagearray -c ${PINGVIN_CONFIG_DIR}/stream-cartesian-grappa.conf --noise.covariance-input=./mycov.bin + - args: stream-image-array-scaling + - args: stream-image-array-split + - args: stream-complex-to-float + - args: stream-float-to-fixed-point --convert.type=ushort --convert.max-intensity=32767 --convert.intensity-offset=0 validation: reference: tse/meas_MID00450_FID76726_SAX_TE62_DIR_TSE/ref_20220817_klk_Generic_Cartesian_Grappa.xml.mrd checksum: ce76e05ce86d65b501663c19f7b252e3 diff --git a/test/e2e/conftest.py b/test/e2e/conftest.py index c15c1cb6..821b741e 100644 --- a/test/e2e/conftest.py +++ b/test/e2e/conftest.py @@ -87,6 +87,14 @@ def cache_path(request, cache_disable) -> Path: return None return Path(os.path.abspath(request.config.getoption('--cache-path'))) +@pytest.fixture(scope="session") +def test_env(request) -> Dict[str,str]: + pingvin_path = Path(shutil.which("pingvin")) + config_path = pingvin_path.parent.parent / "share" / "pingvin" / "config" + env = os.environ.copy() + env["PINGVIN_CONFIG_DIR"] = str(config_path) + return env + @pytest.fixture(scope="session") def ignore_requirements(request) -> Set[str]: reqs = request.config.getoption('--ignore-requirements') diff --git a/test/e2e/test_e2e.py b/test/e2e/test_e2e.py index b634a56c..ea8a547b 100644 --- a/test/e2e/test_e2e.py +++ b/test/e2e/test_e2e.py @@ -27,7 +27,7 @@ def test_e2e(spec, check_requirements, request, fetch_test_data, process_data, v @pytest.fixture -def process_data(local_test_data_path, tmp_path): +def process_data(local_test_data_path, tmp_path, test_env): """Runs the Pingvin on the input test data, producing an output file.""" def _process_data(job): input_file = local_test_data_path(job.datafile) @@ -48,7 +48,7 @@ def _process_data(job): log_stderr_filename = os.path.join(tmp_path, f"pingvin_{job.name}.log.err") with open(log_stdout_filename, 'w') as log_stdout: with open(log_stderr_filename, 'w') as log_stderr: - result = subprocess.run(command, stdout=log_stdout, stderr=log_stderr, cwd=tmp_path) + result = subprocess.run(command, stdout=log_stdout, stderr=log_stderr, cwd=tmp_path, env=test_env) if result.returncode != 0: pytest.fail(f"Pingvin failed with return code {result.returncode}. See {log_stderr_filename} for details.") diff --git a/toolboxes/core/cpu/math/CMakeLists.txt b/toolboxes/core/cpu/math/CMakeLists.txt index 6976e607..9b27bb0a 100644 --- a/toolboxes/core/cpu/math/CMakeLists.txt +++ b/toolboxes/core/cpu/math/CMakeLists.txt @@ -1,6 +1,3 @@ -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") -# TODO: DELETE ^^^^^ - set(cpucore_math_header_files hoNDArray_math.h hoNDImage_util.h From de9ffe0f27579a22ecd7a1217e9b0bf174126f39 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 13 Feb 2025 20:20:53 +0000 Subject: [PATCH 14/21] Remove unused code --- core/CMakeLists.txt | 1 - core/Node.h | 6 +- core/PropertyMixin.h | 37 ---------- core/parallel/Branch.cpp | 9 --- core/parallel/Branch.h | 28 +++----- core/parallel/Branch.hpp | 16 ----- core/parallel/CMakeLists.txt | 9 +-- core/parallel/Fanout.cpp | 9 --- core/parallel/Fanout.h | 14 ++-- core/parallel/Fanout.hpp | 14 ---- core/parallel/Merge.cpp | 8 --- core/parallel/Merge.h | 13 +--- core/parallel/UnorderedMerge.cpp | 4 -- core/parallel/UnorderedMerge.h | 3 +- doc/source/gadget.rst | 2 - .../CmrCartesianKSpaceBinningCineGadget.cpp | 1 - .../cmr/CmrParametricT1SRMappingGadget.cpp | 1 - gadgets/cmr/CmrParametricT2MappingGadget.cpp | 1 - .../CmrRealTimeLAXCineAIAnalysisGadget.cpp | 1 - gadgets/debugging/PseudoReplicatorGadget.cpp | 1 - gadgets/debugging/RateLimitGadget.cpp | 1 - .../debugging/WhiteNoiseInjectorGadget.cpp | 1 - gadgets/epi/CutXGadget.cpp | 1 - gadgets/epi/EPICorrGadget.cpp | 1 - gadgets/epi/EPIPackNavigatorGadget.cpp | 1 - gadgets/epi/EPIReconXGadget.cpp | 1 - gadgets/epi/FFTXGadget.cpp | 1 - gadgets/epi/OneEncodingGadget.cpp | 1 - .../examples/AcquisitionWaveformBranch.cpp | 2 - gadgets/examples/ImageInverter.cpp | 1 - gadgets/examples/ImageLayerer.cpp | 2 - gadgets/grappa/AcquisitionFanout.cpp | 5 -- gadgets/grappa/CMakeLists.txt | 3 - gadgets/grappa/ImageAccumulator.cpp | 9 +-- gadgets/grappa/SliceAccumulator.cpp | 12 ++-- gadgets/grappa/SliceAccumulator.h | 9 ++- gadgets/grappa/Unmixing.cpp | 1 - gadgets/grappa/WeightsCalculator.cpp | 68 +++++++++++++++---- gadgets/grappa/common/AcquisitionBuffer.cpp | 15 ++-- gadgets/grappa/common/AcquisitionBuffer.h | 12 ++-- gadgets/grappa/common/AnnotatedAcquisition.h | 18 ----- gadgets/grappa/common/grappa_common.h | 57 ---------------- gadgets/grappa/gpu/WeightsCore.cpp | 2 - gadgets/mri_core/AccumulatorGadget.cpp | 1 - .../AcquisitionAccumulateTriggerGadget.cpp | 1 - .../mri_core/AsymmetricEchoAdjustROGadget.cpp | 1 - .../mri_core/AugmentImageMetadataGadget.cpp | 1 - gadgets/mri_core/AutoScaleGadget.cpp | 1 - gadgets/mri_core/BucketToBufferGadget.cpp | 1 - gadgets/mri_core/CoilReductionGadget.cpp | 1 - gadgets/mri_core/CombineGadget.cpp | 1 - gadgets/mri_core/ComplexToFloatGadget.cpp | 1 - gadgets/mri_core/DenoiseGadget.cpp | 1 - gadgets/mri_core/ExtractGadget.cpp | 1 - gadgets/mri_core/FFTGadget.cpp | 1 - gadgets/mri_core/FlagTriggerGadget.cpp | 1 - gadgets/mri_core/FloatToFixedPointGadget.cpp | 1 - .../mri_core/FlowPhaseSubtractionGadget.cpp | 1 - gadgets/mri_core/ImageArraySplitGadget.cpp | 1 - gadgets/mri_core/ImageIndexGadget.cpp | 1 - gadgets/mri_core/ImageSortGadget.cpp | 1 - gadgets/mri_core/MaxwellCorrectionGadget.cpp | 1 - gadgets/mri_core/NoiseAdjustGadget.cpp | 1 - gadgets/mri_core/PCACoilGadget.cpp | 1 - .../mri_core/PhysioInterpolationGadget.cpp | 1 - .../mri_core/RemoveROOversamplingGadget.cpp | 1 - gadgets/mri_core/ScaleGadget.cpp | 1 - gadgets/mri_core/SimpleReconGadget.cpp | 1 - .../GenericReconCartesianGrappaAIGadget.cpp | 1 - .../GenericReconCartesianGrappaGadget.cpp | 1 - ...ReconCartesianNonLinearSpirit2DTGadget.cpp | 1 - ...nericReconCartesianReferencePrepGadget.cpp | 1 - .../GenericReconCartesianSpiritGadget.cpp | 1 - .../GenericReconEigenChannelGadget.cpp | 1 - ...enericReconFieldOfViewAdjustmentGadget.cpp | 1 - .../GenericReconGadget.cpp | 1 - .../GenericReconImageArrayScalingGadget.cpp | 1 - .../GenericReconKSpaceFilteringGadget.cpp | 1 - ...GenericReconNoiseStdMapComputingGadget.cpp | 1 - ...econPartialFourierHandlingFilterGadget.cpp | 1 - ...cReconPartialFourierHandlingPOCSGadget.cpp | 1 - test/gadgets/setup_gadget.h | 1 - 82 files changed, 103 insertions(+), 338 deletions(-) delete mode 100644 core/PropertyMixin.h delete mode 100644 core/parallel/Branch.cpp delete mode 100644 core/parallel/Branch.hpp delete mode 100644 core/parallel/Fanout.cpp delete mode 100644 core/parallel/Fanout.hpp delete mode 100644 core/parallel/Merge.cpp delete mode 100644 gadgets/grappa/AcquisitionFanout.cpp delete mode 100644 gadgets/grappa/common/AnnotatedAcquisition.h delete mode 100644 gadgets/grappa/common/grappa_common.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 31015e01..62640b1a 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -42,7 +42,6 @@ install(FILES Context.h Node.h PureGadget.h - PropertyMixin.h ChannelAlgorithms.h Process.h DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) diff --git a/core/Node.h b/core/Node.h index 035a0551..bf2baf8e 100644 --- a/core/Node.h +++ b/core/Node.h @@ -2,7 +2,6 @@ #include "Parameters.h" #include "Channel.h" -#include "PropertyMixin.h" #include "Context.h" #include @@ -57,7 +56,4 @@ namespace Gadgetron::Core { MRChannelGadget(const MrdContext& context, const NodeParameters& parameters) {} }; -} - -/** TODO: Delete everywhere */ -#define GADGETRON_GADGET_EXPORT(GadgetClass) \ No newline at end of file +} \ No newline at end of file diff --git a/core/PropertyMixin.h b/core/PropertyMixin.h deleted file mode 100644 index f8b3fdcc..00000000 --- a/core/PropertyMixin.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include "io/from_string.h" - -namespace Gadgetron::Core { - - using GadgetProperties = std::unordered_map; - - class PropertyMixin { - - protected: - - template - explicit PropertyMixin(const KEY_VALUE_STORAGE &pairs) : properties(pairs.begin(), pairs.end()) {} - - template - inline T get_property(const std::string &name, T default_value, const std::string &) { - if (!properties.count(name)) return default_value; - return IO::from_string(properties.at(name)); - } - - /** TODO: These are no longer private or const, so they can be initialized *after* the Node has been constructed */ - // private: - // const GadgetProperties properties; - GadgetProperties properties; - }; - - template<> - inline std::string PropertyMixin::get_property(const std::string &name, std::string default_value, const std::string &) { - if (!properties.count(name)) return default_value; - return properties.at(name); - } -} - -#define NODE_PROPERTY(NAME, TYPE, DESCRIPTION, DEFAULT) const TYPE NAME = this->template get_property(#NAME, DEFAULT, DESCRIPTION) -#define NODE_PROPERTY_NON_CONST(NAME, TYPE, DESCRIPTION, DEFAULT) TYPE NAME = this->template get_property(#NAME, DEFAULT, DESCRIPTION) \ No newline at end of file diff --git a/core/parallel/Branch.cpp b/core/parallel/Branch.cpp deleted file mode 100644 index 8f5db918..00000000 --- a/core/parallel/Branch.cpp +++ /dev/null @@ -1,9 +0,0 @@ - -#include "Branch.h" - -#include "Context.h" - -namespace Gadgetron::Core::Parallel { - Branch::Branch(const GadgetProperties &props) : PropertyMixin(props) {} -} - diff --git a/core/parallel/Branch.h b/core/parallel/Branch.h index 05635afa..c3c1382b 100644 --- a/core/parallel/Branch.h +++ b/core/parallel/Branch.h @@ -7,11 +7,10 @@ #include "Channel.h" #include "Context.h" #include "Parameters.h" -#include "PropertyMixin.h" namespace Gadgetron::Core::Parallel { - class Branch : public PropertyMixin { + class Branch { public: struct Parameters : NodeParameters { using NodeParameters::NodeParameters; @@ -25,21 +24,18 @@ namespace Gadgetron::Core::Parallel { ) = 0; private: - explicit Branch(const GadgetProperties &props); - template friend class TypedBranch; }; template class TypedBranch : public Branch { public: - explicit TypedBranch(const GadgetProperties &props); - - void process( - GenericInputChannel input, - std::map output, - OutputChannel bypass - ) final; + void process(GenericInputChannel input, + std::map output, OutputChannel bypass) final + { + auto typed_input = InputChannel(input, bypass); + process(typed_input, std::move(output)); + } virtual void process(InputChannel &, std::map) = 0; }; @@ -49,13 +45,7 @@ namespace Gadgetron::Core::Parallel { public: using TypedBranch::TypedBranch; - MRBranch(const MrdContext& context, const NodeParameters& parameters) - : TypedBranch(Core::GadgetProperties{}) {} + MRBranch(const MrdContext& context, const NodeParameters& parameters) {} }; -} - -#include "Branch.hpp" - -/** TODO: Delete everywhere */ -#define GADGETRON_BRANCH_EXPORT(BranchClass) \ No newline at end of file +} \ No newline at end of file diff --git a/core/parallel/Branch.hpp b/core/parallel/Branch.hpp deleted file mode 100644 index 845f35d8..00000000 --- a/core/parallel/Branch.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -namespace Gadgetron::Core::Parallel { - - template - TypedBranch::TypedBranch(const GadgetProperties &props) : Branch(props) {} - - template - void TypedBranch::process( - GenericInputChannel input, - std::map output, - OutputChannel bypass) { - auto typed_input = InputChannel(input, bypass); - process(typed_input, std::move(output)); - } -} diff --git a/core/parallel/CMakeLists.txt b/core/parallel/CMakeLists.txt index 28b630ee..f57a27a2 100644 --- a/core/parallel/CMakeLists.txt +++ b/core/parallel/CMakeLists.txt @@ -1,13 +1,7 @@ - add_library(pingvin_core_parallel SHARED Branch.h - Branch.hpp - Branch.cpp Merge.h - Merge.cpp Fanout.h - Fanout.hpp - Fanout.cpp UnorderedMerge.h UnorderedMerge.cpp) @@ -28,8 +22,7 @@ install(TARGETS pingvin_core_parallel install(FILES Branch.h - Branch.hpp Merge.h Fanout.h - Fanout.hpp + UnorderedMerge.h DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) \ No newline at end of file diff --git a/core/parallel/Fanout.cpp b/core/parallel/Fanout.cpp deleted file mode 100644 index d1336953..00000000 --- a/core/parallel/Fanout.cpp +++ /dev/null @@ -1,9 +0,0 @@ - -#include "Fanout.h" - -namespace Gadgetron::Core::Parallel { - GADGETRON_BRANCH_EXPORT(AcquisitionFanout); - GADGETRON_BRANCH_EXPORT(WaveformFanout); - GADGETRON_BRANCH_EXPORT(ImageFanout); -} - diff --git a/core/parallel/Fanout.h b/core/parallel/Fanout.h index b731e3ba..754fe640 100644 --- a/core/parallel/Fanout.h +++ b/core/parallel/Fanout.h @@ -14,12 +14,18 @@ namespace Gadgetron::Core::Parallel { class Fanout : public MRBranch { public: using MRBranch::MRBranch; - void process(InputChannel &, std::map) override; + + void process(InputChannel& input, std::map output) override { + for (auto thing : input) { + for (auto &pair : output) { + auto copy_of_thing = thing; + pair.second.push(std::move(copy_of_thing)); + } + } + } }; using AcquisitionFanout = Core::Parallel::Fanout; using WaveformFanout = Core::Parallel::Fanout; using ImageFanout = Core::Parallel::Fanout; -} - -#include "Fanout.hpp" +} \ No newline at end of file diff --git a/core/parallel/Fanout.hpp b/core/parallel/Fanout.hpp deleted file mode 100644 index 48dfe9c8..00000000 --- a/core/parallel/Fanout.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace Gadgetron::Core::Parallel { - - template - void Fanout::process(InputChannel &input, std::map output) { - for (auto thing : input) { - for (auto &pair : output) { - auto copy_of_thing = thing; - pair.second.push(std::move(copy_of_thing)); - } - } - } -} diff --git a/core/parallel/Merge.cpp b/core/parallel/Merge.cpp deleted file mode 100644 index e338a2a2..00000000 --- a/core/parallel/Merge.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -#include "Merge.h" - -#include "log.h" - -namespace Gadgetron::Core::Parallel { - Merge::Merge(const GadgetProperties &props) : PropertyMixin(props) {} -} diff --git a/core/parallel/Merge.h b/core/parallel/Merge.h index 6bc627e7..66953a93 100644 --- a/core/parallel/Merge.h +++ b/core/parallel/Merge.h @@ -7,18 +7,15 @@ #include "Channel.h" #include "Context.h" #include "Parameters.h" -#include "PropertyMixin.h" namespace Gadgetron::Core::Parallel { - class Merge : public PropertyMixin { + class Merge { public: struct Parameters : NodeParameters { using NodeParameters::NodeParameters; }; - explicit Merge(const GadgetProperties &props); - virtual ~Merge() = default; virtual void process(std::map, OutputChannel) = 0; }; @@ -28,10 +25,6 @@ namespace Gadgetron::Core::Parallel { public: using Merge::Merge; - MRMerge(const MrdContext& context, const NodeParameters& parameters) - : Merge(Core::GadgetProperties{}) {} + MRMerge(const MrdContext& context, const NodeParameters& parameters) {} }; -} - -/** TODO: Delete everywhere */ -#define GADGETRON_MERGE_EXPORT(MergeClass) \ No newline at end of file +} \ No newline at end of file diff --git a/core/parallel/UnorderedMerge.cpp b/core/parallel/UnorderedMerge.cpp index c9f9a7bf..94adadb6 100644 --- a/core/parallel/UnorderedMerge.cpp +++ b/core/parallel/UnorderedMerge.cpp @@ -18,8 +18,6 @@ namespace { namespace Gadgetron::Core::Parallel { - UnorderedMerge::UnorderedMerge(const Context &, const GadgetProperties &props) : Merge(props) {} - void UnorderedMerge::process(std::map input, OutputChannel output) { std::vector threads; @@ -36,7 +34,5 @@ namespace Gadgetron::Core::Parallel { for (auto &thread : threads) thread.join(); } - - GADGETRON_MERGE_EXPORT(UnorderedMerge) } diff --git a/core/parallel/UnorderedMerge.h b/core/parallel/UnorderedMerge.h index bb8a9f82..4c2067b2 100644 --- a/core/parallel/UnorderedMerge.h +++ b/core/parallel/UnorderedMerge.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include "Merge.h" @@ -10,7 +9,7 @@ namespace Gadgetron::Core::Parallel { class UnorderedMerge : public Merge { public: - UnorderedMerge(const Context &context, const GadgetProperties &props); + using Merge::Merge; void process(std::map, OutputChannel) override; }; } \ No newline at end of file diff --git a/doc/source/gadget.rst b/doc/source/gadget.rst index 06ffffb6..742cd1a9 100644 --- a/doc/source/gadget.rst +++ b/doc/source/gadget.rst @@ -32,7 +32,6 @@ The **NODE_PROPERTY** macro defines a variable on the AutoScaleGadget which can .. literalinclude:: ../../gadgets/mri_core/AutoScaleGadget.cpp :language: cpp -Note the **GADGETRON_GADGET_EXPORT** declaration, which produces the code causing the AutoScaleGadget to be loadable by Pingvin. ChannelGadget @@ -141,5 +140,4 @@ We want to gather acquisitions until we have enough for a (possibly undersampled const mrd::Header header; }; - GADGETRON_GADGET_EXPORT(SimpleRecon) diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp index 7bae2b57..00ac44e1 100644 --- a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp +++ b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp @@ -425,5 +425,4 @@ namespace Gadgetron { return GADGET_OK; } - GADGETRON_GADGET_EXPORT(CmrCartesianKSpaceBinningCineGadget) } diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp index 5b6740f7..5ae60bfc 100644 --- a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp @@ -270,6 +270,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrParametricT1SRMappingGadget) } diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.cpp b/gadgets/cmr/CmrParametricT2MappingGadget.cpp index 5750b3ea..dc808fbe 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT2MappingGadget.cpp @@ -274,6 +274,5 @@ namespace Gadgetron { } // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrParametricT2MappingGadget) } diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp index 232b0a06..ef3fd0d1 100644 --- a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp +++ b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp @@ -557,5 +557,4 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrRealTimeLAXCineAIAnalysisGadget) } diff --git a/gadgets/debugging/PseudoReplicatorGadget.cpp b/gadgets/debugging/PseudoReplicatorGadget.cpp index 70b1d0c6..769d6dbb 100644 --- a/gadgets/debugging/PseudoReplicatorGadget.cpp +++ b/gadgets/debugging/PseudoReplicatorGadget.cpp @@ -28,5 +28,4 @@ void PseudoReplicatorGadget::process(Core::InputChannel& input, } } -GADGETRON_GADGET_EXPORT(PseudoReplicatorGadget) } // namespace Gadgetron diff --git a/gadgets/debugging/RateLimitGadget.cpp b/gadgets/debugging/RateLimitGadget.cpp index df3f7388..2cea7205 100644 --- a/gadgets/debugging/RateLimitGadget.cpp +++ b/gadgets/debugging/RateLimitGadget.cpp @@ -20,5 +20,4 @@ void RateLimitGadget::process(Core::InputChannel& in, Core::Out } } -GADGETRON_GADGET_EXPORT(RateLimitGadget) } // namespace Gadgetron diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp index 3359679c..bd12a9f7 100644 --- a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp +++ b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp @@ -237,5 +237,4 @@ void WhiteNoiseInjectorGadget::process(Core::InputChannel& in, } } -GADGETRON_GADGET_EXPORT(WhiteNoiseInjectorGadget) } diff --git a/gadgets/epi/CutXGadget.cpp b/gadgets/epi/CutXGadget.cpp index d9e057bf..e3ea6921 100644 --- a/gadgets/epi/CutXGadget.cpp +++ b/gadgets/epi/CutXGadget.cpp @@ -65,5 +65,4 @@ namespace Gadgetron{ } } - GADGETRON_GADGET_EXPORT(CutXGadget) } diff --git a/gadgets/epi/EPICorrGadget.cpp b/gadgets/epi/EPICorrGadget.cpp index 63bfac4d..5a31690a 100644 --- a/gadgets/epi/EPICorrGadget.cpp +++ b/gadgets/epi/EPICorrGadget.cpp @@ -639,5 +639,4 @@ namespace Gadgetron { } - GADGETRON_GADGET_EXPORT(EPICorrGadget) } diff --git a/gadgets/epi/EPIPackNavigatorGadget.cpp b/gadgets/epi/EPIPackNavigatorGadget.cpp index c8d04527..886cd212 100644 --- a/gadgets/epi/EPIPackNavigatorGadget.cpp +++ b/gadgets/epi/EPIPackNavigatorGadget.cpp @@ -88,5 +88,4 @@ void EPIPackNavigatorGadget::process(Core::InputChannel& input } } -GADGETRON_GADGET_EXPORT(EPIPackNavigatorGadget) } // namespace Gadgetron diff --git a/gadgets/epi/EPIReconXGadget.cpp b/gadgets/epi/EPIReconXGadget.cpp index 4bd49287..dc3fd465 100644 --- a/gadgets/epi/EPIReconXGadget.cpp +++ b/gadgets/epi/EPIReconXGadget.cpp @@ -132,7 +132,6 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(EPIReconXGadget) } // namespace Gadgetron diff --git a/gadgets/epi/FFTXGadget.cpp b/gadgets/epi/FFTXGadget.cpp index e3c80642..ff8f0b6e 100644 --- a/gadgets/epi/FFTXGadget.cpp +++ b/gadgets/epi/FFTXGadget.cpp @@ -24,5 +24,4 @@ namespace Gadgetron{ } } - GADGETRON_GADGET_EXPORT(FFTXGadget) } diff --git a/gadgets/epi/OneEncodingGadget.cpp b/gadgets/epi/OneEncodingGadget.cpp index 4688b9f5..8ae101b3 100644 --- a/gadgets/epi/OneEncodingGadget.cpp +++ b/gadgets/epi/OneEncodingGadget.cpp @@ -9,5 +9,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(OneEncodingGadget) } diff --git a/gadgets/examples/AcquisitionWaveformBranch.cpp b/gadgets/examples/AcquisitionWaveformBranch.cpp index 1afb8367..d126391f 100644 --- a/gadgets/examples/AcquisitionWaveformBranch.cpp +++ b/gadgets/examples/AcquisitionWaveformBranch.cpp @@ -18,6 +18,4 @@ namespace Gadgetron::Examples { channel.push(std::move(acq_or_wav)); } } - - GADGETRON_BRANCH_EXPORT(AcquisitionWaveformBranch) } \ No newline at end of file diff --git a/gadgets/examples/ImageInverter.cpp b/gadgets/examples/ImageInverter.cpp index 67e8b795..8425c3a9 100644 --- a/gadgets/examples/ImageInverter.cpp +++ b/gadgets/examples/ImageInverter.cpp @@ -32,6 +32,5 @@ namespace Gadgetron::Examples { return visit([](const auto &image) -> mrd::AnyImage { return invert_image(image); }, image); } - GADGETRON_GADGET_EXPORT(ImageInverter); } diff --git a/gadgets/examples/ImageLayerer.cpp b/gadgets/examples/ImageLayerer.cpp index a193ca98..1e2b12be 100644 --- a/gadgets/examples/ImageLayerer.cpp +++ b/gadgets/examples/ImageLayerer.cpp @@ -60,6 +60,4 @@ namespace Gadgetron::Examples { output.push(std::move(merged)); } } - - GADGETRON_MERGE_EXPORT(ImageLayerer) } diff --git a/gadgets/grappa/AcquisitionFanout.cpp b/gadgets/grappa/AcquisitionFanout.cpp deleted file mode 100644 index 9503b103..00000000 --- a/gadgets/grappa/AcquisitionFanout.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "AcquisitionFanout.h" - -namespace Gadgetron::Grappa { - GADGETRON_BRANCH_EXPORT(AcquisitionFanout); -} diff --git a/gadgets/grappa/CMakeLists.txt b/gadgets/grappa/CMakeLists.txt index 50c7a67a..bf0c135d 100644 --- a/gadgets/grappa/CMakeLists.txt +++ b/gadgets/grappa/CMakeLists.txt @@ -2,12 +2,9 @@ set(RTGRAPPA_SOURCES ImageAccumulator.cpp WeightsCalculator.cpp Unmixing.cpp - AcquisitionFanout.cpp SliceAccumulator.cpp common/AcquisitionBuffer.cpp common/AcquisitionBuffer.h - common/grappa_common.h - common/AnnotatedAcquisition.h cpu/WeightsCore.cpp cpu/WeightsCore.h) diff --git a/gadgets/grappa/ImageAccumulator.cpp b/gadgets/grappa/ImageAccumulator.cpp index cfbae511..4dd11d82 100644 --- a/gadgets/grappa/ImageAccumulator.cpp +++ b/gadgets/grappa/ImageAccumulator.cpp @@ -18,12 +18,10 @@ namespace { Grappa::Image create_reconstruction_job( - const AnnotatedAcquisition &first, - const AnnotatedAcquisition &last, + const mrd::Acquisition &first_acq, + const mrd::Acquisition &last_acq, AcquisitionBuffer &buffer ) { - auto &first_acq = std::get(first); - auto &last_acq = std::get(last); auto slice = last_acq.head.idx.slice.value_or(0); Grappa::Image image{}; @@ -50,12 +48,11 @@ namespace Gadgetron::Grappa { for (auto slice : in) { - slice = std::move(slice) | ranges::actions::remove_if([](auto& acq){return std::get(acq).head.flags.HasFlags(mrd::AcquisitionFlags::kIsParallelCalibration);}); + slice = std::move(slice) | ranges::actions::remove_if([](auto& acq){return acq.head.flags.HasFlags(mrd::AcquisitionFlags::kIsParallelCalibration);}); buffer.add(slice); out.push(create_reconstruction_job(slice.front(), slice.back(), buffer)); } } - GADGETRON_GADGET_EXPORT(ImageAccumulator); } diff --git a/gadgets/grappa/SliceAccumulator.cpp b/gadgets/grappa/SliceAccumulator.cpp index 7b5fe573..6bea8eeb 100644 --- a/gadgets/grappa/SliceAccumulator.cpp +++ b/gadgets/grappa/SliceAccumulator.cpp @@ -1,8 +1,5 @@ #include "SliceAccumulator.h" -#include "common/AnnotatedAcquisition.h" -#include "common/grappa_common.h" - #include "Context.h" #include "Channel.h" @@ -15,19 +12,18 @@ namespace { namespace Gadgetron::Grappa { - void SliceAccumulator::process(Core::InputChannel &in, Core::OutputChannel &out) { + void SliceAccumulator::process(Core::InputChannel &in, Core::OutputChannel &out) { - std::vector acquisitions{}; + std::vector acquisitions{}; for (auto acquisition : in) { acquisitions.emplace_back(std::move(acquisition)); - if (is_last_in_slice(acquisitions.back())) { + if (acquisitions.back().head.flags.HasFlags(mrd::AcquisitionFlags::kLastInSlice)) { out.push(std::move(acquisitions)); - acquisitions = std::vector{}; + acquisitions = std::vector{}; } } } - GADGETRON_GADGET_EXPORT(SliceAccumulator); } \ No newline at end of file diff --git a/gadgets/grappa/SliceAccumulator.h b/gadgets/grappa/SliceAccumulator.h index 3d8ca220..a060aa2f 100644 --- a/gadgets/grappa/SliceAccumulator.h +++ b/gadgets/grappa/SliceAccumulator.h @@ -3,17 +3,16 @@ #include #include "Node.h" -#include "common/AnnotatedAcquisition.h" namespace Gadgetron::Grappa { - using Slice = std::vector; + using Slice = std::vector; - class SliceAccumulator : public Core::MRChannelGadget { + class SliceAccumulator : public Core::MRChannelGadget { public: - using Core::MRChannelGadget::MRChannelGadget; + using Core::MRChannelGadget::MRChannelGadget; - void process(Core::InputChannel &in, Core::OutputChannel &out) override; + void process(Core::InputChannel &in, Core::OutputChannel &out) override; }; } diff --git a/gadgets/grappa/Unmixing.cpp b/gadgets/grappa/Unmixing.cpp index 0be9a9b9..67d64960 100644 --- a/gadgets/grappa/Unmixing.cpp +++ b/gadgets/grappa/Unmixing.cpp @@ -51,7 +51,6 @@ namespace { } namespace Gadgetron::Grappa { - GADGETRON_MERGE_EXPORT(Unmixing); void Unmixing::process( std::map input, diff --git a/gadgets/grappa/WeightsCalculator.cpp b/gadgets/grappa/WeightsCalculator.cpp index 4ab3fa0f..97ce07a1 100644 --- a/gadgets/grappa/WeightsCalculator.cpp +++ b/gadgets/grappa/WeightsCalculator.cpp @@ -3,7 +3,6 @@ #include #include "common/AcquisitionBuffer.h" -#include "common/grappa_common.h" #ifdef USE_CUDA #include "gpu/WeightsCore.h" @@ -15,6 +14,51 @@ #include "Unmixing.h" +namespace Gadgetron::Grappa { + + bool is_last_in_slice(const mrd::Acquisition &acquisition) { + return acquisition.head.flags.HasFlags(mrd::AcquisitionFlags::kLastInSlice); + } + + uint16_t slice_of(const mrd::Acquisition &acquisition) { + return acquisition.head.idx.slice.value_or(0); + } + + uint16_t line_of(const mrd::Acquisition &acquisition) { + return acquisition.head.idx.kspace_encode_step_1.value_or(0); + } + + uint16_t samples_in(const mrd::Acquisition &acquisition) { + return acquisition.Samples(); + } + + uint16_t channels_in(const mrd::Acquisition &acquisition) { + return acquisition.Coils(); + } + + uint64_t combined_channels(const mrd::Acquisition &acquisition) { + return channels_in(acquisition); + } + + uint64_t uncombined_channels(const mrd::Acquisition &acquisition) { + return 0; + } + + template + std::string to_string(Coll collection) { + + if (collection.empty()) return "[]"; + + std::stringstream stream; + + stream << "["; + for (auto i : collection) stream << i << ", "; + stream << "\b\b]"; + + return stream.str(); + } +} + namespace { using namespace Gadgetron; namespace Grappa = Gadgetron::Grappa; @@ -52,17 +96,17 @@ namespace { acceleration = std::vector>(max_slices, std::nullopt); } - void operator()(const Grappa::AnnotatedAcquisition &acquisition) { + void operator()(const mrd::Acquisition& acquisition) { - if(previous_line[slice_of(acquisition)]) { - if (line_of(acquisition) < previous_line[slice_of(acquisition)].value()) { - acceleration[slice_of(acquisition)] = std::nullopt; + if(previous_line[Grappa::slice_of(acquisition)]) { + if (Grappa::line_of(acquisition) < previous_line[Grappa::slice_of(acquisition)].value()) { + acceleration[Grappa::slice_of(acquisition)] = std::nullopt; } else { - acceleration[slice_of(acquisition)] = line_of(acquisition) - previous_line[slice_of(acquisition)].value(); + acceleration[Grappa::slice_of(acquisition)] = Grappa::line_of(acquisition) - previous_line[Grappa::slice_of(acquisition)].value(); } } - previous_line[slice_of(acquisition)] = line_of(acquisition); + previous_line[Grappa::slice_of(acquisition)] = Grappa::line_of(acquisition); } size_t acceleration_factor(size_t slice) const { @@ -85,11 +129,11 @@ namespace { } - void operator()(const Grappa::AnnotatedAcquisition &acquisition) { + void operator()(const mrd::Acquisition &acquisition) { - auto header = std::get(acquisition).head; + auto header = acquisition.head; - auto& [position, read_dir, slice_dir,phase_dir] = orientations.at(slice_of(acquisition)); + auto& [position, read_dir, slice_dir,phase_dir] = orientations.at(Grappa::slice_of(acquisition)); std::array header_position; std::copy(std::begin(header.position), std::end(header.position), std::begin(header_position)); @@ -112,7 +156,7 @@ namespace { phase_dir = header_phase_dir; slice_dir = header_slice_dir; - clear(slice_of(acquisition)); + clear(Grappa::slice_of(acquisition)); } void clear(size_t slice) { @@ -208,10 +252,8 @@ namespace Gadgetron::Grappa { } template class WeightsCalculator; -GADGETRON_GADGET_EXPORT(cpuWeightsCalculator); #ifdef USE_CUDA template class WeightsCalculator; - GADGETRON_GADGET_EXPORT(gpuWeightsCalculator); #endif } \ No newline at end of file diff --git a/gadgets/grappa/common/AcquisitionBuffer.cpp b/gadgets/grappa/common/AcquisitionBuffer.cpp index a916a7d7..4d593b17 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.cpp +++ b/gadgets/grappa/common/AcquisitionBuffer.cpp @@ -1,5 +1,3 @@ -#include "AcquisitionBuffer.h" - #include #include @@ -7,7 +5,7 @@ #include "hoNDArray.h" -#include "grappa_common.h" +#include "AcquisitionBuffer.h" #include #include @@ -58,11 +56,10 @@ namespace Gadgetron::Grappa { buffers = std::map{}; } - void AcquisitionBuffer::add(const AnnotatedAcquisition &acquisition) { + void AcquisitionBuffer::add(const mrd::Acquisition &acq) { - for (auto &fn : pre_update_callbacks) fn(acquisition); + for (auto &fn : pre_update_callbacks) fn(acq); - auto& acq = std::get(acquisition); auto &header = acq.head; const auto &data = acq.data; @@ -91,7 +88,7 @@ namespace Gadgetron::Grappa { buffer.data(slice,current_line,channel) = data(slice,channel); } - for (auto &fn : post_update_callbacks) fn(acquisition); + for (auto &fn : post_update_callbacks) fn(acq); } hoNDArray> AcquisitionBuffer::take(size_t index) { @@ -150,11 +147,11 @@ namespace Gadgetron::Grappa { } - void AcquisitionBuffer::add_pre_update_callback(std::function fn) { + void AcquisitionBuffer::add_pre_update_callback(std::function fn) { pre_update_callbacks.emplace_back(std::move(fn)); } - void AcquisitionBuffer::add_post_update_callback(std::function fn) { + void AcquisitionBuffer::add_post_update_callback(std::function fn) { post_update_callbacks.emplace_back(std::move(fn)); } } diff --git a/gadgets/grappa/common/AcquisitionBuffer.h b/gadgets/grappa/common/AcquisitionBuffer.h index 279a4eb5..e4dd8423 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.h +++ b/gadgets/grappa/common/AcquisitionBuffer.h @@ -4,7 +4,7 @@ #include #include -#include "AnnotatedAcquisition.h" +#include "mrd/types.h" #include "Channel.h" @@ -16,7 +16,7 @@ namespace Gadgetron::Grappa { public: explicit AcquisitionBuffer(const mrd::Header& header); - void add(const AnnotatedAcquisition &acquisition); + void add(const mrd::Acquisition& acquisition); template void add(const T &acquisitions) { @@ -38,8 +38,8 @@ namespace Gadgetron::Grappa { std::array region_of_support(size_t index) const; - void add_pre_update_callback(std::function fn); - void add_post_update_callback(std::function fn); + void add_pre_update_callback(std::function fn); + void add_post_update_callback(std::function fn); private: const mrd::Header header_; @@ -62,7 +62,7 @@ namespace Gadgetron::Grappa { const int minimum_calibration_region = 8; - std::vector> pre_update_callbacks; - std::vector> post_update_callbacks; + std::vector> pre_update_callbacks; + std::vector> post_update_callbacks; }; } \ No newline at end of file diff --git a/gadgets/grappa/common/AnnotatedAcquisition.h b/gadgets/grappa/common/AnnotatedAcquisition.h deleted file mode 100644 index 34cb8a21..00000000 --- a/gadgets/grappa/common/AnnotatedAcquisition.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "hoNDArray.h" - -#include "mrd/types.h" - -namespace Gadgetron::Grappa { - - struct ChannelAnnotation { - uint64_t number_of_combined_channels, number_of_uncombined_channels; - std::vector reordering; - }; - - /** TODO: The ChannelReorderer is no longer used, so all Gadgets using this - * AnnotatedAcquisition can be updated to just use mrd::Acquisition. - */ - using AnnotatedAcquisition = std::tuple>; -} diff --git a/gadgets/grappa/common/grappa_common.h b/gadgets/grappa/common/grappa_common.h deleted file mode 100644 index f1a720c1..00000000 --- a/gadgets/grappa/common/grappa_common.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "AnnotatedAcquisition.h" - -namespace Gadgetron::Grappa { - - template - bool is_last_in_slice(const T &acquisition) { - return std::get(acquisition).head.flags.HasFlags(mrd::AcquisitionFlags::kLastInSlice); - } - - template - uint16_t slice_of(const T &acquisition) { - return std::get(acquisition).head.idx.slice.value_or(0); - } - - template - uint16_t line_of(const T &acquisition) { - return std::get(acquisition).head.idx.kspace_encode_step_1.value_or(0); - } - - template - uint16_t samples_in(const T &acquisition) { - return std::get(acquisition).Samples(); - } - - template - uint16_t channels_in(const T &acquisition) { - return std::get(acquisition).Coils(); - } - - template - uint64_t combined_channels(const T &acquisition) { - std::optional optional_annotation = std::get>(acquisition); - return optional_annotation ? optional_annotation->number_of_combined_channels : channels_in(acquisition); - } - - template - uint64_t uncombined_channels(const T &acquisition) { - std::optional optional_annotation = std::get>(acquisition); - return optional_annotation ? optional_annotation->number_of_uncombined_channels : 0; - } - - template - std::string to_string(Coll collection) { - - if (collection.empty()) return "[]"; - - std::stringstream stream; - - stream << "["; - for (auto i : collection) stream << i << ", "; - stream << "\b\b]"; - - return stream.str(); - } -} \ No newline at end of file diff --git a/gadgets/grappa/gpu/WeightsCore.cpp b/gadgets/grappa/gpu/WeightsCore.cpp index 334bfd4d..6b0d97fa 100644 --- a/gadgets/grappa/gpu/WeightsCore.cpp +++ b/gadgets/grappa/gpu/WeightsCore.cpp @@ -1,7 +1,5 @@ #include "WeightsCore.h" -#include "../common/grappa_common.h" - #include "cuNDArray.h" #include "htgrappa.h" #include "b1_map.h" diff --git a/gadgets/mri_core/AccumulatorGadget.cpp b/gadgets/mri_core/AccumulatorGadget.cpp index df0a3817..ec43079c 100644 --- a/gadgets/mri_core/AccumulatorGadget.cpp +++ b/gadgets/mri_core/AccumulatorGadget.cpp @@ -125,5 +125,4 @@ void AccumulatorGadget::process(Core::InputChannel& in, Core:: } } } -GADGETRON_GADGET_EXPORT(AccumulatorGadget) } // namespace Gadgetron \ No newline at end of file diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp index 663e4af5..48eb891c 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp @@ -170,7 +170,6 @@ namespace Gadgetron { send_data(out, buckets, waveforms); } - GADGETRON_GADGET_EXPORT(AcquisitionAccumulateTriggerGadget); namespace { const std::map triggerdimension_from_name = { diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp index 05f3ffc9..49748f5c 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp @@ -77,5 +77,4 @@ namespace Gadgetron { out.push(std::move(acq)); } } - GADGETRON_GADGET_EXPORT(AsymmetricEchoAdjustROGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/AugmentImageMetadataGadget.cpp b/gadgets/mri_core/AugmentImageMetadataGadget.cpp index 5f3b2788..154a68fe 100644 --- a/gadgets/mri_core/AugmentImageMetadataGadget.cpp +++ b/gadgets/mri_core/AugmentImageMetadataGadget.cpp @@ -23,5 +23,4 @@ mrd::Image> AugmentImageMetadataGadget::process_function( return input_image; } -GADGETRON_GADGET_EXPORT(AugmentImageMetadataGadget) } \ No newline at end of file diff --git a/gadgets/mri_core/AutoScaleGadget.cpp b/gadgets/mri_core/AutoScaleGadget.cpp index 38795e4a..772cfc68 100644 --- a/gadgets/mri_core/AutoScaleGadget.cpp +++ b/gadgets/mri_core/AutoScaleGadget.cpp @@ -45,5 +45,4 @@ namespace Gadgetron { mrd::AnyImage AutoScaleGadget::process_function(mrd::AnyImage image) const { return visit([&](auto &image) -> mrd::AnyImage { return autoscale(image, parameters_.max_value, parameters_.histogram_bins); }, image); } - GADGETRON_GADGET_EXPORT(AutoScaleGadget); } diff --git a/gadgets/mri_core/BucketToBufferGadget.cpp b/gadgets/mri_core/BucketToBufferGadget.cpp index a23eac20..ff59a176 100644 --- a/gadgets/mri_core/BucketToBufferGadget.cpp +++ b/gadgets/mri_core/BucketToBufferGadget.cpp @@ -635,6 +635,5 @@ namespace Gadgetron { v = boost::any(d); } - GADGETRON_GADGET_EXPORT(BucketToBufferGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/CoilReductionGadget.cpp b/gadgets/mri_core/CoilReductionGadget.cpp index cd85b113..cbefd9de 100644 --- a/gadgets/mri_core/CoilReductionGadget.cpp +++ b/gadgets/mri_core/CoilReductionGadget.cpp @@ -89,5 +89,4 @@ void CoilReductionGadget::process(Core::InputChannel& in, Core out.push(std::move(acq)); } } -GADGETRON_GADGET_EXPORT(CoilReductionGadget) } diff --git a/gadgets/mri_core/CombineGadget.cpp b/gadgets/mri_core/CombineGadget.cpp index 47425547..6706e068 100644 --- a/gadgets/mri_core/CombineGadget.cpp +++ b/gadgets/mri_core/CombineGadget.cpp @@ -54,5 +54,4 @@ namespace Gadgetron { mrd::AnyImage CombineGadget::process_function(mrd::AnyImage image) const { return visit([&](auto& image) -> mrd::AnyImage { return combine(image); }, image); } - GADGETRON_GADGET_EXPORT(CombineGadget); } // namespace Gadgetron diff --git a/gadgets/mri_core/ComplexToFloatGadget.cpp b/gadgets/mri_core/ComplexToFloatGadget.cpp index 99eb2da7..fb02dec4 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.cpp +++ b/gadgets/mri_core/ComplexToFloatGadget.cpp @@ -42,5 +42,4 @@ mrd::Image ComplexToFloatGadget::process_function( return out; } -GADGETRON_GADGET_EXPORT(ComplexToFloatGadget) } \ No newline at end of file diff --git a/gadgets/mri_core/DenoiseGadget.cpp b/gadgets/mri_core/DenoiseGadget.cpp index 70ddbbab..2b6987e6 100644 --- a/gadgets/mri_core/DenoiseGadget.cpp +++ b/gadgets/mri_core/DenoiseGadget.cpp @@ -34,5 +34,4 @@ namespace Gadgetron { return std::move(image_array); } - GADGETRON_GADGET_EXPORT(DenoiseGadget) } \ No newline at end of file diff --git a/gadgets/mri_core/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index c2367b45..cc20093f 100644 --- a/gadgets/mri_core/ExtractGadget.cpp +++ b/gadgets/mri_core/ExtractGadget.cpp @@ -88,5 +88,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(ExtractGadget) } diff --git a/gadgets/mri_core/FFTGadget.cpp b/gadgets/mri_core/FFTGadget.cpp index 05e4c62a..601ba027 100644 --- a/gadgets/mri_core/FFTGadget.cpp +++ b/gadgets/mri_core/FFTGadget.cpp @@ -86,5 +86,4 @@ namespace Gadgetron{ } } } - GADGETRON_GADGET_EXPORT(FFTGadget); } diff --git a/gadgets/mri_core/FlagTriggerGadget.cpp b/gadgets/mri_core/FlagTriggerGadget.cpp index 95613a32..7ba83b1d 100644 --- a/gadgets/mri_core/FlagTriggerGadget.cpp +++ b/gadgets/mri_core/FlagTriggerGadget.cpp @@ -211,5 +211,4 @@ FlagTriggerGadget::FlagTriggerGadget(const Core::MrdContext& context, const Para this->predicate = create_trigger_filter(parameters_.trigger_flags); } -GADGETRON_GADGET_EXPORT(FlagTriggerGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/FloatToFixedPointGadget.cpp b/gadgets/mri_core/FloatToFixedPointGadget.cpp index 9f12fb38..50ed1915 100644 --- a/gadgets/mri_core/FloatToFixedPointGadget.cpp +++ b/gadgets/mri_core/FloatToFixedPointGadget.cpp @@ -96,5 +96,4 @@ namespace Gadgetron } } - GADGETRON_GADGET_EXPORT(FloatToFixedPointGadget) } diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp index ea429c95..8e13db99 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp @@ -59,5 +59,4 @@ void FlowPhaseSubtractionGadget::process(Core::InputChannel& in, C } } -GADGETRON_GADGET_EXPORT(ImageArraySplitGadget); } // namespace Gadgetron diff --git a/gadgets/mri_core/ImageIndexGadget.cpp b/gadgets/mri_core/ImageIndexGadget.cpp index bb9dd7f0..596283b1 100644 --- a/gadgets/mri_core/ImageIndexGadget.cpp +++ b/gadgets/mri_core/ImageIndexGadget.cpp @@ -36,5 +36,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(ImageIndexGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/ImageSortGadget.cpp b/gadgets/mri_core/ImageSortGadget.cpp index 344c7e36..c7672f6c 100644 --- a/gadgets/mri_core/ImageSortGadget.cpp +++ b/gadgets/mri_core/ImageSortGadget.cpp @@ -54,5 +54,4 @@ namespace Gadgetron { images_.clear(); } } - GADGETRON_GADGET_EXPORT(ImageSortGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/MaxwellCorrectionGadget.cpp b/gadgets/mri_core/MaxwellCorrectionGadget.cpp index fd131c4b..8a264322 100644 --- a/gadgets/mri_core/MaxwellCorrectionGadget.cpp +++ b/gadgets/mri_core/MaxwellCorrectionGadget.cpp @@ -193,6 +193,5 @@ void MaxwellCorrectionGadget::process(Core::InputChannelgt_streamer_.close_stream_buffer(); } - GADGETRON_GADGET_EXPORT(GenericReconCartesianGrappaGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp index 01bd6fed..42c03af8 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp @@ -646,5 +646,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianNonLinearSpirit2DTGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp index 2a906849..e1351464 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp @@ -305,5 +305,4 @@ namespace Gadgetron { if (params_.perform_timing) { gt_timer_.stop(); } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianReferencePrepGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp index ff16b7ef..e6e9f46b 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp @@ -741,5 +741,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianSpiritGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp index 45f29d3d..29db2416 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp @@ -236,5 +236,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconEigenChannelGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp index 2f6b7b4c..15cd4fb0 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp @@ -285,6 +285,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconFieldOfViewAdjustmentGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp index 88b836fe..afdce80c 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp @@ -667,5 +667,4 @@ namespace Gadgetron { out.push(std::move(res)); } - GADGETRON_GADGET_EXPORT(GenericReconGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp index 23bedfd7..8de09d00 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp @@ -213,6 +213,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconImageArrayScalingGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp index 7fee8c29..3fdbea69 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp @@ -425,6 +425,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconKSpaceFilteringGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp index a662061b..985d927b 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp @@ -170,6 +170,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconNoiseStdMapComputingGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp index 8082f2eb..0f3650ef 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.cpp @@ -32,6 +32,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconPartialFourierHandlingFilterGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp index 69be8a55..7bf85371 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp @@ -25,5 +25,4 @@ hoNDArray> GenericReconPartialFourierHandlingPOCSGadget::per } -GADGETRON_GADGET_EXPORT(GenericReconPartialFourierHandlingPOCSGadget) } diff --git a/test/gadgets/setup_gadget.h b/test/gadgets/setup_gadget.h index da509531..0e2d8d81 100644 --- a/test/gadgets/setup_gadget.h +++ b/test/gadgets/setup_gadget.h @@ -6,7 +6,6 @@ #include "Channel.h" #include "Context.h" #include "Node.h" -#include "PropertyMixin.h" #include #include #include From fb5e85f89a4283610eb3066e7144599a2cf69284 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Thu, 13 Feb 2025 22:04:10 +0000 Subject: [PATCH 15/21] Remove unused ErrorHandler --- apps/pingvin/CMakeLists.txt | 2 - apps/pingvin/ErrorHandler.h | 89 -------------------------- apps/pingvin/nodes/NodeProcessable.h | 3 +- apps/pingvin/nodes/Parallel.cpp | 25 ++++---- apps/pingvin/nodes/Parallel.h | 3 +- apps/pingvin/nodes/ParallelProcess.cpp | 10 +-- apps/pingvin/nodes/ParallelProcess.h | 2 +- apps/pingvin/nodes/Processable.cpp | 19 +++--- apps/pingvin/nodes/Processable.h | 7 +- apps/pingvin/nodes/Stream.cpp | 19 +++--- apps/pingvin/nodes/Stream.h | 3 +- apps/pingvin/pipelines/pipeline.h | 40 +++--------- 12 files changed, 52 insertions(+), 170 deletions(-) delete mode 100644 apps/pingvin/ErrorHandler.h diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 3cc3a751..7d4cf9dd 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -6,8 +6,6 @@ add_executable(pingvin initialization.cpp system_info.cpp - ErrorHandler.h - nodes/Processable.h nodes/Processable.cpp diff --git a/apps/pingvin/ErrorHandler.h b/apps/pingvin/ErrorHandler.h deleted file mode 100644 index fc7a4ead..00000000 --- a/apps/pingvin/ErrorHandler.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include -#include -#include - - -#include "io/primitives.h" -#include "Channel.h" -#include "Context.h" - -namespace Gadgetron::Main { - - class ErrorReporter { - public: - virtual void operator()(const std::string&, const std::string&) = 0; - virtual ~ErrorReporter() = default; - }; - - class ErrorHandler { - public: - - ErrorHandler( ErrorReporter &callback, std::string location) - : location{ - std::move(location)}, push_error{callback} {} - - ErrorHandler( const ErrorHandler &parent,const std::string &new_location) : push_error{parent.push_error}, location{ - add_location(parent.location, new_location)} { - - } - - ErrorHandler(const ErrorHandler &parent) = default; - - -#if defined(NDEBUG) - - template - void handle(F fn, ARGS &&... args) { - // When debugging, it is useful to have all exceptions bubble up to the - // debugger. To enable this, we sabotage the error handler on debug builds. - try { - fn(std::forward(args)...); - } - catch (const Core::ChannelClosed &e) { - // Ignored. - } - catch (const std::exception &e) { - push_error(location, e.what()); - } - catch (...) { - push_error(location, "Unknown error."); - } - } -#else - - template - void handle(F fn, ARGS &&... args) { - try { - fn(std::forward(args)...); - } - catch (const Core::ChannelClosed &e) { - // Ignored. - } - } - -#endif - - template - std::thread run(F fn, ARGS &&... args) { - return std::thread( - []( auto handler, auto fn, auto &&... iargs) { - handler.handle(fn, std::forward(iargs)...); - }, - *this, - std::forward(fn), - std::forward(args)... - ); - } - - private: - - static std::string add_location(const std::string &old_location, const std::string &new_location) { - return old_location + "/" + new_location; - } - - const std::string location; - ErrorReporter &push_error; - }; -} \ No newline at end of file diff --git a/apps/pingvin/nodes/NodeProcessable.h b/apps/pingvin/nodes/NodeProcessable.h index bd64441c..8d9be42e 100644 --- a/apps/pingvin/nodes/NodeProcessable.h +++ b/apps/pingvin/nodes/NodeProcessable.h @@ -9,8 +9,7 @@ class NodeProcessable : public Gadgetron::Main::Processable { NodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} void process(Gadgetron::Core::GenericInputChannel input, - Gadgetron::Core::OutputChannel output, - Gadgetron::Main::ErrorHandler & + Gadgetron::Core::OutputChannel output ) override { node_->process(input, output); } diff --git a/apps/pingvin/nodes/Parallel.cpp b/apps/pingvin/nodes/Parallel.cpp index afcd49a6..2c21b846 100644 --- a/apps/pingvin/nodes/Parallel.cpp +++ b/apps/pingvin/nodes/Parallel.cpp @@ -55,11 +55,8 @@ namespace Gadgetron::Main::Nodes { void Parallel::process( InputChannel input, - OutputChannel output, - ErrorHandler &error_handler + OutputChannel output ) { - ErrorHandler nested_handler{error_handler, branch->key}; - std::vector threads; std::map input_channels; std::map output_channels; @@ -68,7 +65,7 @@ namespace Gadgetron::Main::Nodes { emplace_channels(*stream, input_channels, output_channels); } - threads.emplace_back(nested_handler.run( + threads.emplace_back(std::thread( [&](auto input, auto output, auto bypass) { branch->process(std::move(input), std::move(output), std::move(bypass)); }, @@ -77,7 +74,7 @@ namespace Gadgetron::Main::Nodes { split(output) )); - threads.emplace_back(nested_handler.run( + threads.emplace_back(std::thread( [&](auto input, auto output) { merge->process(std::move(input), std::move(output)); }, @@ -86,14 +83,14 @@ namespace Gadgetron::Main::Nodes { )); for (auto &stream : streams) { - threads.emplace_back( - Processable::process_async( - stream, - std::move(input_channels.at(stream->key).input), - std::move(output_channels.at(stream->key).output), - nested_handler - ) - ); + threads.emplace_back(std::thread( + [&](auto stream, auto input, auto output) { + stream->process(std::move(input), std::move(output)); + }, + stream, + std::move(input_channels.at(stream->key).input), + std::move(output_channels.at(stream->key).output) + )); } for (auto &thread : threads) { thread.join(); } diff --git a/apps/pingvin/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h index 63608eee..e832600e 100644 --- a/apps/pingvin/nodes/Parallel.h +++ b/apps/pingvin/nodes/Parallel.h @@ -27,8 +27,7 @@ namespace Gadgetron::Main::Nodes { void process( Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler &error_handler + Core::OutputChannel output ) override; const std::string &name() override; diff --git a/apps/pingvin/nodes/ParallelProcess.cpp b/apps/pingvin/nodes/ParallelProcess.cpp index fed134fb..cfc4a960 100644 --- a/apps/pingvin/nodes/ParallelProcess.cpp +++ b/apps/pingvin/nodes/ParallelProcess.cpp @@ -27,22 +27,22 @@ namespace Gadgetron::Main::Nodes { } void ParallelProcess::process(GenericInputChannel input, - OutputChannel output, - ErrorHandler& error_handler + OutputChannel output ) { Queue queue; - auto input_thread = error_handler.run( + std::thread input_thread( [&](auto input) { this->process_input(std::move(input), queue); }, std::move(input) ); - auto output_thread = error_handler.run( + std::thread output_thread( [&](auto output) { this->process_output(std::move(output), queue); }, std::move(output) ); - input_thread.join(); output_thread.join(); + input_thread.join(); + output_thread.join(); } const std::string& ParallelProcess::name() { diff --git a/apps/pingvin/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h index 7a733c26..9f98a899 100644 --- a/apps/pingvin/nodes/ParallelProcess.h +++ b/apps/pingvin/nodes/ParallelProcess.h @@ -12,7 +12,7 @@ namespace Gadgetron::Main::Nodes { ParallelProcess(const PureStream& pureStream, size_t workers) : workers_(workers), pure_stream_(pureStream) {} - void process(Core::GenericInputChannel input, Core::OutputChannel output, ErrorHandler& error_handler) override; + void process(Core::GenericInputChannel input, Core::OutputChannel output) override; const std::string& name() override; private: diff --git a/apps/pingvin/nodes/Processable.cpp b/apps/pingvin/nodes/Processable.cpp index 547cb736..457e9497 100644 --- a/apps/pingvin/nodes/Processable.cpp +++ b/apps/pingvin/nodes/Processable.cpp @@ -4,17 +4,18 @@ std::thread Gadgetron::Main::Processable::process_async( std::shared_ptr processable, Core::GenericInputChannel input, - Core::OutputChannel output, - const ErrorHandler &error_handler + Core::OutputChannel output ) { - ErrorHandler nested_handler{error_handler, processable->name()}; - - return nested_handler.run( - [=](auto input, auto output, auto error_handler) { - processable->process(std::move(input), std::move(output), error_handler); + // return processable->process(std::move(input), std::move(output)); + // std::move(input), + // std::move(output), + // nested_handler + // ); + return std::thread( + [&processable](auto input, auto output) { + processable->process(std::move(input), std::move(output)); }, std::move(input), - std::move(output), - nested_handler + std::move(output) ); } diff --git a/apps/pingvin/nodes/Processable.h b/apps/pingvin/nodes/Processable.h index 76a6b69c..1866005d 100644 --- a/apps/pingvin/nodes/Processable.h +++ b/apps/pingvin/nodes/Processable.h @@ -1,6 +1,5 @@ #pragma once -#include "ErrorHandler.h" #include "Channel.h" #include "Context.h" @@ -15,8 +14,7 @@ namespace Gadgetron::Main { virtual void process( Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler &error_handler + Core::OutputChannel output ) = 0; virtual const std::string& name() = 0; @@ -24,8 +22,7 @@ namespace Gadgetron::Main { static std::thread process_async( std::shared_ptr processable, Core::GenericInputChannel input, - Core::OutputChannel output, - const ErrorHandler &errorHandler + Core::OutputChannel output ); }; } \ No newline at end of file diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp index fffa601e..6bafdb5b 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -10,10 +10,7 @@ namespace Gadgetron::Main::Nodes { using namespace Gadgetron::Core; - void Stream::process(GenericInputChannel input, - OutputChannel output, - ErrorHandler &error_handler - ) { + void Stream::process(GenericInputChannel input, OutputChannel output) { if (empty()) return; std::vector input_channels{}; @@ -28,15 +25,19 @@ namespace Gadgetron::Main::Nodes { output_channels.emplace_back(std::move(output)); - ErrorHandler nested_handler{error_handler, name()}; - std::vector threads(nodes.size()); for (auto i = 0; i < nodes.size(); i++) { - threads[i] = Processable::process_async( + threads[i] = std::thread( + [](auto node, auto input_channel, auto output_channel) { + try { + node->process(std::move(input_channel), std::move(output_channel)); + } catch (const Core::ChannelClosed &e) { + // Ignored + } + }, nodes[i], std::move(input_channels[i]), - std::move(output_channels[i]), - nested_handler + std::move(output_channels[i]) ); } diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h index 9f185699..482ed7cb 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -18,8 +18,7 @@ namespace Gadgetron::Main::Nodes { void process( Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler & + Core::OutputChannel output ) override; bool empty() const; diff --git a/apps/pingvin/pipelines/pipeline.h b/apps/pingvin/pipelines/pipeline.h index 7d244ea2..41f31087 100644 --- a/apps/pingvin/pipelines/pipeline.h +++ b/apps/pingvin/pipelines/pipeline.h @@ -15,7 +15,6 @@ namespace po = boost::program_options; #include "nodes/Parallel.h" #include "nodes/ParallelProcess.h" #include "Channel.h" -#include "ErrorHandler.h" #include "Node.h" #include "parallel/Branch.h" @@ -507,15 +506,6 @@ class ParallelProcessBuilder : public INodeBuilder { std::vector>> builders_; }; - -class ErrorThrower : public Gadgetron::Main::ErrorReporter -{ - public: - void operator()(const std::string& location, const std::string& message) override { - throw std::runtime_error(("[" + location + "] ERROR: " + message)); - } -}; - // Forward declaration class Pipeline; @@ -546,36 +536,26 @@ class Pipeline { void run(void) { auto input_channel = Gadgetron::Core::make_channel(); auto output_channel = Gadgetron::Core::make_channel(); - std::atomic processing = true; auto process_future = std::async(std::launch::async, [&]() { - try - { - ErrorThrower error_thrower; - Gadgetron::Main::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; + try { + stream_->process(std::move(input_channel.input), std::move(output_channel.output)); + } catch (const std::exception& exc) { + GERROR_STREAM("Exception in process_future: " << exc.what()); + // Induce a ChannelClosed exception upon readers of the channel. + auto destruct_me = std::move(output_channel.output); throw; } }); auto input_future = std::async(std::launch::async, [&]() { - try - { + try { source_->consume_input(input_channel); - } - catch(std::ios_base::failure& exc) - { + } catch(const std::exception& exc) { + GERROR_STREAM("Exception in input_future: " << exc.what()); // Induce a ChannelClosed exception upon readers of the channel. auto destruct_me = std::move(input_channel.output); + throw; } }); From b4d8daae05dc703506ab17b9a690e5c1c57110ed Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 14 Feb 2025 20:55:13 +0000 Subject: [PATCH 16/21] Replace the Processable interface with Nodes --- apps/pingvin/CMakeLists.txt | 12 ++-- apps/pingvin/nodes/MultiprocessStream.cpp | 58 ++++++++++++++++ apps/pingvin/nodes/MultiprocessStream.h | 26 +++++++ apps/pingvin/nodes/NodeProcessable.h | 24 ------- apps/pingvin/nodes/Parallel.h | 68 ------------------- apps/pingvin/nodes/ParallelProcess.cpp | 54 --------------- apps/pingvin/nodes/ParallelProcess.h | 28 -------- .../{Parallel.cpp => ParallelStream.cpp} | 54 ++------------- apps/pingvin/nodes/ParallelStream.h | 37 ++++++++++ apps/pingvin/nodes/Processable.cpp | 21 ------ apps/pingvin/nodes/Processable.h | 28 -------- apps/pingvin/nodes/PureStream.cpp | 9 ++- apps/pingvin/nodes/PureStream.h | 3 +- apps/pingvin/nodes/Stream.cpp | 20 ++---- apps/pingvin/nodes/Stream.h | 15 ++-- apps/pingvin/pipelines/denoise.h | 2 +- apps/pingvin/pipelines/pipeline.h | 53 +++++++-------- 17 files changed, 176 insertions(+), 336 deletions(-) create mode 100644 apps/pingvin/nodes/MultiprocessStream.cpp create mode 100644 apps/pingvin/nodes/MultiprocessStream.h delete mode 100644 apps/pingvin/nodes/NodeProcessable.h delete mode 100644 apps/pingvin/nodes/Parallel.h delete mode 100644 apps/pingvin/nodes/ParallelProcess.cpp delete mode 100644 apps/pingvin/nodes/ParallelProcess.h rename apps/pingvin/nodes/{Parallel.cpp => ParallelStream.cpp} (60%) create mode 100644 apps/pingvin/nodes/ParallelStream.h delete mode 100644 apps/pingvin/nodes/Processable.cpp delete mode 100644 apps/pingvin/nodes/Processable.h diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 7d4cf9dd..501ce36e 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -6,16 +6,12 @@ add_executable(pingvin initialization.cpp system_info.cpp - nodes/Processable.h - nodes/Processable.cpp - nodes/Stream.cpp nodes/Stream.h - nodes/NodeProcessable.h - nodes/Parallel.cpp - nodes/Parallel.h - nodes/ParallelProcess.cpp - nodes/ParallelProcess.h + nodes/ParallelStream.cpp + nodes/ParallelStream.h + nodes/MultiprocessStream.cpp + nodes/MultiprocessStream.h nodes/PureStream.cpp nodes/PureStream.h ) diff --git a/apps/pingvin/nodes/MultiprocessStream.cpp b/apps/pingvin/nodes/MultiprocessStream.cpp new file mode 100644 index 00000000..c0eb081e --- /dev/null +++ b/apps/pingvin/nodes/MultiprocessStream.cpp @@ -0,0 +1,58 @@ +#include "MultiprocessStream.h" + +#include "ThreadPool.h" + +namespace Gadgetron::Core { + + void MultiprocessStream::process_input(GenericInputChannel input, Queue &queue) { + + ThreadPool pool(workers_ ? workers_ : std::thread::hardware_concurrency()); + + for (auto message : input) { + queue.push( + pool.async( + [&](auto message) { return pure_stream_.process_function(std::move(message)); }, + std::move(message) + ) + ); + } + + pool.join(); queue.close(); + } + + void MultiprocessStream::process_output(OutputChannel output, Queue &queue) { + while(true) output.push_message(queue.pop().get()); + } + + void MultiprocessStream::process(GenericInputChannel& input, OutputChannel& output) + { + Queue queue; + + std::thread input_thread( + [&](auto input) { + try { + this->process_input(std::move(input), queue); + } catch (const Core::ChannelClosed& e) { + // Ignored + } + }, + std::move(input) + ); + + std::thread output_thread( + [&](auto output) { + try { + this->process_output(std::move(output), queue); + } catch (const Core::ChannelClosed& e) { + // Ignored + } + }, + std::move(output) + ); + + input_thread.join(); + output_thread.join(); + } +} + + diff --git a/apps/pingvin/nodes/MultiprocessStream.h b/apps/pingvin/nodes/MultiprocessStream.h new file mode 100644 index 00000000..02408885 --- /dev/null +++ b/apps/pingvin/nodes/MultiprocessStream.h @@ -0,0 +1,26 @@ +#pragma once + +#include "PureStream.h" + +#include + +namespace Gadgetron::Core { + class MultiprocessStream : public Node { + + public: + MultiprocessStream(const PureStream& pureStream, size_t workers) + : workers_(workers), pure_stream_(pureStream) {} + + void process(GenericInputChannel& input, OutputChannel& output) override; + + private: + + using Queue = MPMCChannel>; + + void process_input(GenericInputChannel input, Queue &queue); + void process_output(OutputChannel output, Queue &queue); + + const size_t workers_; + const PureStream pure_stream_; + }; +} diff --git a/apps/pingvin/nodes/NodeProcessable.h b/apps/pingvin/nodes/NodeProcessable.h deleted file mode 100644 index 8d9be42e..00000000 --- a/apps/pingvin/nodes/NodeProcessable.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "Processable.h" - -#include "Node.h" - -class NodeProcessable : public Gadgetron::Main::Processable { -public: - NodeProcessable(const std::shared_ptr& node, std::string name) : node_(node), name_(std::move(name)) {} - - void process(Gadgetron::Core::GenericInputChannel input, - Gadgetron::Core::OutputChannel output - ) override { - node_->process(input, output); - } - - const std::string& name() override { - return name_; - } - -private: - std::shared_ptr node_; - const std::string name_; -}; diff --git a/apps/pingvin/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h deleted file mode 100644 index e832600e..00000000 --- a/apps/pingvin/nodes/Parallel.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "Stream.h" -#include "Processable.h" - -#include "parallel/Branch.h" -#include "parallel/Merge.h" - -#include "Channel.h" -#include "Context.h" - -namespace Gadgetron::Main::Nodes { - - class Parallel : public Processable { - using Channel = Core::Channel; - using InputChannel = Core::GenericInputChannel; - using OutputChannel = Core::OutputChannel; - using Branch = Core::Parallel::Branch; - using Merge = Core::Parallel::Merge; - - public: - Parallel(std::unique_ptr branch, std::unique_ptr merge, std::vector> streams) - : branch(std::make_unique(std::move(branch), "branch")), - merge(std::make_unique(std::move(merge), "merge")), - streams(std::move(streams)) - {} - - void process( - Core::GenericInputChannel input, - Core::OutputChannel output - ) override; - - const std::string &name() override; - - class DecoratedBranch { - public: - DecoratedBranch(std::unique_ptr branch, std::string key); - - const std::string key; - void process( - InputChannel input, - std::map output, - OutputChannel bypass - ); - private: - std::unique_ptr branch; - }; - - class DecoratedMerge { - public: - DecoratedMerge(std::unique_ptr merge, std::string key); - - const std::string key; - void process( - std::map input, - OutputChannel output - ); - private: - std::unique_ptr merge; - }; - - private: - std::unique_ptr branch; - std::unique_ptr merge; - std::vector> streams; - }; - -} \ No newline at end of file diff --git a/apps/pingvin/nodes/ParallelProcess.cpp b/apps/pingvin/nodes/ParallelProcess.cpp deleted file mode 100644 index cfc4a960..00000000 --- a/apps/pingvin/nodes/ParallelProcess.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "ParallelProcess.h" - -#include "ThreadPool.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Main::Nodes { - - void ParallelProcess::process_input(GenericInputChannel input, Queue &queue) { - - ThreadPool pool(workers_ ? workers_ : std::thread::hardware_concurrency()); - - for (auto message : input) { - queue.push( - pool.async( - [&](auto message) { return pure_stream_.process_function(std::move(message)); }, - std::move(message) - ) - ); - } - - pool.join(); queue.close(); - } - - void ParallelProcess::process_output(OutputChannel output, Queue &queue) { - while(true) output.push_message(queue.pop().get()); - } - - void ParallelProcess::process(GenericInputChannel input, - OutputChannel output - ) { - Queue queue; - - std::thread input_thread( - [&](auto input) { this->process_input(std::move(input), queue); }, - std::move(input) - ); - - std::thread output_thread( - [&](auto output) { this->process_output(std::move(output), queue); }, - std::move(output) - ); - - input_thread.join(); - output_thread.join(); - } - - const std::string& ParallelProcess::name() { - const static std::string n = "ParallelProcess"; - return n; - } -} - - diff --git a/apps/pingvin/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h deleted file mode 100644 index 9f98a899..00000000 --- a/apps/pingvin/nodes/ParallelProcess.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "PureStream.h" -#include "Processable.h" - -#include - -namespace Gadgetron::Main::Nodes { - class ParallelProcess : public Processable { - - public: - ParallelProcess(const PureStream& pureStream, size_t workers) - : workers_(workers), pure_stream_(pureStream) {} - - void process(Core::GenericInputChannel input, Core::OutputChannel output) override; - const std::string& name() override; - - private: - - using Queue = Core::MPMCChannel>; - - void process_input(Core::GenericInputChannel input, Queue &queue); - void process_output(Core::OutputChannel output, Queue &queue); - - const size_t workers_; - const PureStream pure_stream_; - }; -} diff --git a/apps/pingvin/nodes/Parallel.cpp b/apps/pingvin/nodes/ParallelStream.cpp similarity index 60% rename from apps/pingvin/nodes/Parallel.cpp rename to apps/pingvin/nodes/ParallelStream.cpp index 2c21b846..fa33c5b7 100644 --- a/apps/pingvin/nodes/Parallel.cpp +++ b/apps/pingvin/nodes/ParallelStream.cpp @@ -1,20 +1,13 @@ -#include "Parallel.h" +#include "ParallelStream.h" #include #include +#include #include "Channel.h" #include "Context.h" namespace { - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::Parallel; - using namespace Gadgetron::Main; - using namespace Gadgetron::Main::Nodes; - - using DecoratedBranch = Gadgetron::Main::Nodes::Parallel::DecoratedBranch; - using DecoratedMerge = Gadgetron::Main::Nodes::Parallel::DecoratedMerge; - template auto transform_map(std::map& input, F f) { using TRANSFORMED = std::remove_reference_tsecond))>; @@ -28,9 +21,6 @@ namespace { namespace { using namespace Gadgetron::Core; - using namespace Gadgetron::Core::Parallel; - using namespace Gadgetron::Main; - using namespace Gadgetron::Main::Nodes; ChannelPair split(const ChannelPair &in) { return ChannelPair{ split(in.input), split(in.output) }; @@ -51,12 +41,9 @@ namespace { } } -namespace Gadgetron::Main::Nodes { +namespace Gadgetron::Core { - void Parallel::process( - InputChannel input, - OutputChannel output - ) { + void ParallelStream::process(GenericInputChannel& input, OutputChannel& output) { std::vector threads; std::map input_channels; std::map output_channels; @@ -85,7 +72,7 @@ namespace Gadgetron::Main::Nodes { for (auto &stream : streams) { threads.emplace_back(std::thread( [&](auto stream, auto input, auto output) { - stream->process(std::move(input), std::move(output)); + stream->process(input, output); }, stream, std::move(input_channels.at(stream->key).input), @@ -95,35 +82,4 @@ namespace Gadgetron::Main::Nodes { for (auto &thread : threads) { thread.join(); } } - - - const std::string &Parallel::name() { - static const std::string n = "Parallel"; - return n; - } - - void Parallel::DecoratedBranch::process( - InputChannel input, - std::map output, - OutputChannel bypass - ) { - branch->process(std::move(input), std::move(output), std::move(bypass)); - } - - Parallel::DecoratedBranch::DecoratedBranch( - std::unique_ptr branch, - std::string key - ) : branch(std::move(branch)), key(std::move(key)) {} - - void Parallel::DecoratedMerge::process( - std::map input, - OutputChannel output - ) { - merge->process(std::move(input), std::move(output)); - } - - Parallel::DecoratedMerge::DecoratedMerge( - std::unique_ptr merge, - std::string key - ) : merge(std::move(merge)), key(std::move(key)) {} } \ No newline at end of file diff --git a/apps/pingvin/nodes/ParallelStream.h b/apps/pingvin/nodes/ParallelStream.h new file mode 100644 index 00000000..5bd26d0f --- /dev/null +++ b/apps/pingvin/nodes/ParallelStream.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Node.h" + +#include "Stream.h" + +#include "parallel/Branch.h" +#include "parallel/Merge.h" + +#include "Channel.h" +#include "Context.h" + +namespace Gadgetron::Core { + + class ParallelStream : public Node { + using Branch = Core::Parallel::Branch; + using Merge = Core::Parallel::Merge; + + public: + ParallelStream(std::unique_ptr branch, std::unique_ptr merge, std::vector> streams) + : branch(std::move(branch)), + merge(std::move(merge)), + streams(std::move(streams)) + {} + + void process( + Core::GenericInputChannel& input, + Core::OutputChannel& output + ) override; + + private: + std::unique_ptr branch; + std::unique_ptr merge; + std::vector> streams; + }; + +} \ No newline at end of file diff --git a/apps/pingvin/nodes/Processable.cpp b/apps/pingvin/nodes/Processable.cpp deleted file mode 100644 index 457e9497..00000000 --- a/apps/pingvin/nodes/Processable.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Processable.h" - - -std::thread Gadgetron::Main::Processable::process_async( - std::shared_ptr processable, - Core::GenericInputChannel input, - Core::OutputChannel output -) { - // return processable->process(std::move(input), std::move(output)); - // std::move(input), - // std::move(output), - // nested_handler - // ); - return std::thread( - [&processable](auto input, auto output) { - processable->process(std::move(input), std::move(output)); - }, - std::move(input), - std::move(output) - ); -} diff --git a/apps/pingvin/nodes/Processable.h b/apps/pingvin/nodes/Processable.h deleted file mode 100644 index 1866005d..00000000 --- a/apps/pingvin/nodes/Processable.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Channel.h" -#include "Context.h" - -#include -#include - -namespace Gadgetron::Main { - - class Processable { - public: - virtual ~Processable() = default; - - virtual void process( - Core::GenericInputChannel input, - Core::OutputChannel output - ) = 0; - - virtual const std::string& name() = 0; - - static std::thread process_async( - std::shared_ptr processable, - Core::GenericInputChannel input, - Core::OutputChannel output - ); - }; -} \ No newline at end of file diff --git a/apps/pingvin/nodes/PureStream.cpp b/apps/pingvin/nodes/PureStream.cpp index 4b532964..f56d4f78 100644 --- a/apps/pingvin/nodes/PureStream.cpp +++ b/apps/pingvin/nodes/PureStream.cpp @@ -1,8 +1,9 @@ #include "PureStream.h" -Gadgetron::Core::Message Gadgetron::Main::Nodes::PureStream::process_function( - Gadgetron::Core::Message message -) const { +namespace Gadgetron::Core { + +Message PureStream::process_function(Message message) const +{ return std::accumulate( pure_gadgets_.begin(), pure_gadgets_.end(), @@ -12,3 +13,5 @@ Gadgetron::Core::Message Gadgetron::Main::Nodes::PureStream::process_function( } ); } + +} \ No newline at end of file diff --git a/apps/pingvin/nodes/PureStream.h b/apps/pingvin/nodes/PureStream.h index 9fbcc8f9..a988224f 100644 --- a/apps/pingvin/nodes/PureStream.h +++ b/apps/pingvin/nodes/PureStream.h @@ -1,8 +1,9 @@ #pragma once + #include "Message.h" #include "PureGadget.h" -namespace Gadgetron::Main::Nodes { +namespace Gadgetron::Core { class PureStream { public: PureStream(const std::vector>& pure_gadgets) diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp index 6bafdb5b..c73b736d 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -1,16 +1,11 @@ #include "Stream.h" -#include "Parallel.h" -#include "ParallelProcess.h" -#include "Processable.h" +#include -#include "Node.h" -namespace Gadgetron::Main::Nodes { +namespace Gadgetron::Core { - using namespace Gadgetron::Core; - - void Stream::process(GenericInputChannel input, OutputChannel output) { + void Stream::process(GenericInputChannel& input, OutputChannel& output) { if (empty()) return; std::vector input_channels{}; @@ -30,7 +25,7 @@ namespace Gadgetron::Main::Nodes { threads[i] = std::thread( [](auto node, auto input_channel, auto output_channel) { try { - node->process(std::move(input_channel), std::move(output_channel)); + node->process(input_channel, output_channel); } catch (const Core::ChannelClosed &e) { // Ignored } @@ -47,9 +42,4 @@ namespace Gadgetron::Main::Nodes { } bool Stream::empty() const { return nodes.empty(); } -} - -const std::string &Gadgetron::Main::Nodes::Stream::name() { - static const std::string name = "Stream"; - return key.empty() ? name : key; -} +} \ No newline at end of file diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h index 482ed7cb..1b1fe096 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -3,28 +3,27 @@ #include -#include "Processable.h" +#include "Node.h" #include "Channel.h" #include "Context.h" -namespace Gadgetron::Main::Nodes { +namespace Gadgetron::Core { - class Stream : public Processable { + class Stream : public Node { public: const std::string key; - Stream(std::vector> nodes, const std::string key=""): nodes(std::move(nodes)), key(key) {} + Stream(std::vector> nodes, const std::string key=""): nodes(std::move(nodes)), key(key) {} void process( - Core::GenericInputChannel input, - Core::OutputChannel output + Core::GenericInputChannel& input, + Core::OutputChannel& output ) override; bool empty() const; - const std::string &name() override; private: - std::vector> nodes; + std::vector> nodes; }; } diff --git a/apps/pingvin/pipelines/denoise.h b/apps/pingvin/pipelines/denoise.h index 866e381b..d5b238a5 100644 --- a/apps/pingvin/pipelines/denoise.h +++ b/apps/pingvin/pipelines/denoise.h @@ -39,7 +39,7 @@ static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine- .withNode("kspace-filter") .withNode("fov-adjust") .withNode("split") - .withParallelProcessStream() + .withMultiprocessStream() .withPureNode("denoise") .withWorkers(6) .withNode("complex-to-float") diff --git a/apps/pingvin/pipelines/pipeline.h b/apps/pingvin/pipelines/pipeline.h index 41f31087..63bf93a1 100644 --- a/apps/pingvin/pipelines/pipeline.h +++ b/apps/pingvin/pipelines/pipeline.h @@ -11,9 +11,8 @@ namespace po = boost::program_options; #include "system_info.h" #include "nodes/Stream.h" -#include "nodes/NodeProcessable.h" -#include "nodes/Parallel.h" -#include "nodes/ParallelProcess.h" +#include "nodes/ParallelStream.h" +#include "nodes/MultiprocessStream.h" #include "Channel.h" #include "Node.h" @@ -147,7 +146,7 @@ struct MrdSink : public ISink { template struct INodeBuilder { virtual ~INodeBuilder() = default; - virtual std::shared_ptr build(const C& ctx) const = 0; + virtual std::shared_ptr build(const C& ctx) const = 0; virtual void collect_options(po::options_description& parent) = 0; virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; }; @@ -157,9 +156,8 @@ class NodeBuilder : public INodeBuilder { public: NodeBuilder(const std::string& label): label_(label), parameters_(label) {} - std::shared_ptr build(const CTX& ctx) const override { - auto node = std::make_shared(ctx, this->parameters_); - return std::make_shared(node, label_); + std::shared_ptr build(const CTX& ctx) const override { + return std::make_shared(ctx, this->parameters_); } void collect_options(po::options_description& parent) override { @@ -214,14 +212,14 @@ class StreamBuilder : public INodeBuilder { } } - std::shared_ptr build(const CTX& ctx) const override { - std::vector> processables; + std::shared_ptr build(const CTX& ctx) const override { + std::vector> nodes; for (auto& builder : builders_) { - processables.emplace_back( + nodes.emplace_back( builder->build(ctx) ); } - return std::make_shared(processables, key_); + return std::make_shared(nodes, key_); } void append(std::shared_ptr> builder) { @@ -362,7 +360,7 @@ class ParallelBuilder : public INodeBuilder { return *this; } - virtual std::shared_ptr build(const CTX& ctx) const override { + virtual std::shared_ptr build(const CTX& ctx) const override { if (!branch_builder_) { throw std::runtime_error("No branch specified"); } @@ -370,14 +368,14 @@ class ParallelBuilder : public INodeBuilder { throw std::runtime_error("No merge specified"); } auto branch = branch_builder_->build(ctx); - std::vector> streams; + std::vector> streams; for (auto& stream_builder_: stream_builders_) { - auto stream = std::dynamic_pointer_cast(stream_builder_.build(ctx)); + auto stream = std::dynamic_pointer_cast(stream_builder_.build(ctx)); streams.push_back(stream); } auto merge = merge_builder_->build(ctx); - return std::make_shared(std::move(branch), std::move(merge), streams); + return std::make_shared(std::move(branch), std::move(merge), streams); } void collect_options(po::options_description& parent) override { @@ -457,14 +455,14 @@ class PureNodeBuilder : public IPureNodeBuilder { }; template -class ParallelProcessBuilder : public INodeBuilder { +class MultiprocessStreamBuilder : public INodeBuilder { public: - ParallelProcessBuilder(PipelineBuilder& parent) + MultiprocessStreamBuilder(PipelineBuilder& parent) : parent_(parent) {} template - ParallelProcessBuilder& withPureNode(const std::string& label) { + MultiprocessStreamBuilder& withPureNode(const std::string& label) { auto nb = std::make_shared>(label); builders_.emplace_back(nb); return *this; @@ -475,16 +473,16 @@ class ParallelProcessBuilder : public INodeBuilder { return parent_; } - virtual std::shared_ptr build(const CTX& ctx) const override { + virtual std::shared_ptr build(const CTX& ctx) const override { std::vector> pure_gadgets; for (auto& builder : builders_) { auto node = builder->build(ctx); pure_gadgets.emplace_back(std::move(node)); } - Gadgetron::Main::Nodes::PureStream pure_stream(pure_gadgets); + Gadgetron::Core::PureStream pure_stream(pure_gadgets); - return std::make_shared(pure_stream, workers_); + return std::make_shared(pure_stream, workers_); } void collect_options(po::options_description& parent) override { @@ -527,7 +525,7 @@ struct IPipelineBuilder { class Pipeline { public: - Pipeline(const std::shared_ptr& source_, const std::shared_ptr& sink_, const std::shared_ptr& stream_) + Pipeline(const std::shared_ptr& source_, const std::shared_ptr& sink_, const std::shared_ptr& stream_) : source_(source_), sink_(sink_), stream_(stream_) {} @@ -539,7 +537,8 @@ class Pipeline { auto process_future = std::async(std::launch::async, [&]() { try { - stream_->process(std::move(input_channel.input), std::move(output_channel.output)); + // stream_->process(std::move(input_channel.input), std::move(output_channel.output)); + stream_->process(input_channel.input, output_channel.output); } catch (const std::exception& exc) { GERROR_STREAM("Exception in process_future: " << exc.what()); // Induce a ChannelClosed exception upon readers of the channel. @@ -583,9 +582,7 @@ class Pipeline { std::shared_ptr source_; std::shared_ptr sink_; - std::shared_ptr stream_; - - std::vector> processables_; + std::shared_ptr stream_; }; template @@ -626,8 +623,8 @@ struct PipelineBuilder : public IPipelineBuilder{ return pb->template withBranch(label); } - ParallelProcessBuilder& withParallelProcessStream(void) { - auto pb = std::make_shared>(*this); + MultiprocessStreamBuilder& withMultiprocessStream(void) { + auto pb = std::make_shared>(*this); streambuilder_.append(pb); return *pb; } From dca7eea902f5c5567c4b3b292c5dea1f0e70e24e Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Wed, 19 Feb 2025 15:58:38 +0000 Subject: [PATCH 17/21] Move Pipeline and Builders to core/ --- apps/pingvin/CMakeLists.txt | 20 +- apps/pingvin/initialization.cpp | 51 ---- apps/pingvin/initialization.h | 10 - apps/pingvin/main.cc | 143 ++++------ apps/pingvin/pipeline_registry.h | 86 ++++++ apps/pingvin/pipelines/cartesian_grappa.h | 8 +- apps/pingvin/pipelines/cartesian_spirit.h | 8 +- apps/pingvin/pipelines/cmr.h | 10 +- apps/pingvin/pipelines/config/epi.conf | 17 -- apps/pingvin/pipelines/default.h | 8 +- apps/pingvin/pipelines/denoise.h | 6 +- apps/pingvin/pipelines/epi.h | 6 +- apps/pingvin/pipelines/file_search.h | 4 +- apps/pingvin/pipelines/grappa.h | 8 +- apps/pingvin/pipelines/grappa_epi.h | 6 +- apps/pingvin/pipelines/noise.h | 6 +- apps/pingvin/pipelines/parallel_bypass.h | 6 +- apps/pingvin/pipelines/streams.h | 14 +- core/CMakeLists.txt | 23 +- .../nodes => core}/MultiprocessStream.cpp | 0 .../nodes => core}/MultiprocessStream.h | 0 .../pingvin/nodes => core}/ParallelStream.cpp | 0 {apps/pingvin/nodes => core}/ParallelStream.h | 0 .../pipelines/pipeline.h => core/Pipeline.h | 265 ++++-------------- {apps/pingvin/nodes => core}/PureStream.cpp | 0 {apps/pingvin/nodes => core}/PureStream.h | 0 core/Sink.h | 68 +++++ core/Source.h | 58 ++++ {apps/pingvin/nodes => core}/Stream.cpp | 4 +- {apps/pingvin/nodes => core}/Stream.h | 4 +- core/ThreadPool.h | 2 +- {apps/pingvin => core}/pingvin_config.in | 7 +- {apps/pingvin => core}/system_info.cpp | 6 +- {apps/pingvin => core}/system_info.h | 4 +- gadgets/mri_core/ExtractGadget.h | 10 +- test/e2e/cases/cpu_grappa_simple.yml | 2 +- test/e2e/cases/gpu_grappa_simple.yml | 2 +- test/e2e/cases/parallel_bypass_example.yml | 2 +- test/e2e/cases/simple_gre.yml | 2 +- test/e2e/cases/simple_gre_3d.yml | 2 +- 40 files changed, 412 insertions(+), 466 deletions(-) delete mode 100644 apps/pingvin/initialization.cpp delete mode 100644 apps/pingvin/initialization.h create mode 100644 apps/pingvin/pipeline_registry.h rename {apps/pingvin/nodes => core}/MultiprocessStream.cpp (100%) rename {apps/pingvin/nodes => core}/MultiprocessStream.h (100%) rename {apps/pingvin/nodes => core}/ParallelStream.cpp (100%) rename {apps/pingvin/nodes => core}/ParallelStream.h (100%) rename apps/pingvin/pipelines/pipeline.h => core/Pipeline.h (66%) rename {apps/pingvin/nodes => core}/PureStream.cpp (100%) rename {apps/pingvin/nodes => core}/PureStream.h (100%) create mode 100644 core/Sink.h create mode 100644 core/Source.h rename {apps/pingvin/nodes => core}/Stream.cpp (92%) rename {apps/pingvin/nodes => core}/Stream.h (86%) rename {apps/pingvin => core}/pingvin_config.in (75%) rename {apps/pingvin => core}/system_info.cpp (97%) rename {apps/pingvin => core}/system_info.h (87%) diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 501ce36e..91c528bb 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -1,20 +1,4 @@ -configure_file(pingvin_config.in pingvin_config.h) - -add_executable(pingvin - main.cc - - initialization.cpp - system_info.cpp - - nodes/Stream.cpp - nodes/Stream.h - nodes/ParallelStream.cpp - nodes/ParallelStream.h - nodes/MultiprocessStream.cpp - nodes/MultiprocessStream.h - nodes/PureStream.cpp - nodes/PureStream.h - ) +add_executable(pingvin main.cc) target_link_libraries(pingvin pingvin_core @@ -31,7 +15,7 @@ target_link_libraries(pingvin target_include_directories(pingvin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} ) diff --git a/apps/pingvin/initialization.cpp b/apps/pingvin/initialization.cpp deleted file mode 100644 index ea39ce95..00000000 --- a/apps/pingvin/initialization.cpp +++ /dev/null @@ -1,51 +0,0 @@ - -#include "log.h" -#include "initialization.h" - -#include -#include - -#include - -#ifdef FORCE_LIMIT_OPENBLAS_NUM_THREADS -#include -#endif -#include -namespace Gadgetron::Main { - - void configure_blas_libraries() { - -#ifdef FORCE_LIMIT_OPENBLAS_NUM_THREADS - /* - * Certain distributions (Ubuntu) doesn't ship OpenMP OpenBLAS, so we have to make do with - * a version compiled for pthreads. It'll work - maybe even without degrading performance - * a lot, but only if we limit the number of threads to one. - */ - openblas_set_num_threads(1); -#endif - - } - - - void check_environment_variables() { - - auto get_policy = []() -> std::string { - auto raw = std::getenv("OMP_WAIT_POLICY"); - return boost::algorithm::to_lower_copy(raw ? std::string(raw) : std::string()); - }; - - if ("passive" != get_policy()) { - GWARN_STREAM("Environment variable 'OMP_WAIT_POLICY' not set to 'PASSIVE'."); - GWARN_STREAM("Pingvin may experience serious performance issues under heavy load " << - "(multiple simultaneous reconstructions, etc.)") - } - } - - void set_locale() { - try { - std::locale::global(std::locale("")); - } catch (...) { - std::locale::global(std::locale::classic()); - } - } -} diff --git a/apps/pingvin/initialization.h b/apps/pingvin/initialization.h deleted file mode 100644 index d3edfe98..00000000 --- a/apps/pingvin/initialization.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace Gadgetron::Main { - void configure_blas_libraries(); - - void check_environment_variables(); - - void set_locale(); - -} \ No newline at end of file diff --git a/apps/pingvin/main.cc b/apps/pingvin/main.cc index 2b581ba2..c6f1bcc4 100644 --- a/apps/pingvin/main.cc +++ b/apps/pingvin/main.cc @@ -1,21 +1,7 @@ -#include "pipelines/noise.h" -#include "pipelines/grappa.h" -#include "pipelines/default.h" -#include "pipelines/epi.h" -#include "pipelines/cartesian_grappa.h" -#include "pipelines/cartesian_spirit.h" -#include "pipelines/grappa_epi.h" -#include "pipelines/cmr.h" -#include "pipelines/parallel_bypass.h" -#include "pipelines/streams.h" -#include "pipelines/denoise.h" - -#include "pipelines/file_search.h" - #include "log.h" -#include "initialization.h" #include "system_info.h" #include "pingvin_config.h" +#include "pipeline_registry.h" #include @@ -25,10 +11,33 @@ namespace po = boost::program_options; -using namespace pingvin; +using namespace Pingvin; namespace { +void set_locale() { + try { + std::locale::global(std::locale("")); + } catch (...) { + std::locale::global(std::locale::classic()); + } +} + +/** TODO: Is this still relevant and necessary in 2025? */ +void check_environment_variables() { + + auto get_policy = []() -> std::string { + auto raw = std::getenv("OMP_WAIT_POLICY"); + return boost::algorithm::to_lower_copy(raw ? std::string(raw) : std::string()); + }; + + if ("passive" != get_policy()) { + GWARN_STREAM("Environment variable 'OMP_WAIT_POLICY' not set to 'PASSIVE'."); + GWARN_STREAM("Pingvin may experience serious performance issues under heavy load " << + "(multiple simultaneous reconstructions, etc.)") + } +} + /// Parses a "PINGVIN_*" environment variable into a CLI parameter std::string envvar_to_node_parameter(const std::string& env_var) { @@ -61,19 +70,26 @@ std::string envvar_to_node_parameter(const std::string& env_var) int main(int argc, char** argv) { + set_locale(); + po::options_description global("Global options"); global.add_options() ("help,h", "Prints this help message") ("info", "Prints build info about Pingvin") - ("home", - po::value()->default_value(Gadgetron::Main::Info::get_pingvin_home()), - "Set the Pingvin home directory") + ("list,l", "List available pipelines") ("genconf,g", "Generate a full configuration file for the given pipeline") ("dumpconf,d", "Dump the current configuration for the given pipeline") + ; + + po::options_description pipeline_opts("Pipeline options"); + pipeline_opts.add_options() ("config,c", po::value(), "Pipeline configuration file") ("input,i", po::value(), "Input stream (default=stdin)") ("output,o", po::value(), "Output stream (default=stdout)") + ("home", + po::value()->default_value(Pingvin::Main::get_pingvin_home()), + "(Deprecated) Set the Pingvin home directory") ; po::options_description hidden("Hidden options"); @@ -86,7 +102,7 @@ int main(int argc, char** argv) help_options.add(global); po::options_description allowed_options; - allowed_options.add(global).add(hidden); + allowed_options.add(global).add(pipeline_opts).add(hidden); po::positional_options_description pos; pos.add("pipeline", 1) @@ -113,75 +129,34 @@ int main(int argc, char** argv) return 1; } - Gadgetron::Main::check_environment_variables(); - Gadgetron::Main::configure_blas_libraries(); - Gadgetron::Main::set_locale(); - - GINFO_STREAM("Pingvin " << PINGVIN_VERSION_STRING << " [" << PINGVIN_GIT_SHA1_HASH << "]"); - if (vm.count("info")) { std::stringstream str; - Gadgetron::Main::Info::print_system_information(str); + Pingvin::Main::print_system_information(str); GINFO_STREAM(str.str()); return 0; } if (vm.count("home") && !vm["home"].defaulted()) { - Gadgetron::Main::Info::set_pingvin_home(vm["home"].as()); - GINFO_STREAM("Set Pingvin home to: " << Gadgetron::Main::Info::get_pingvin_home()); + Pingvin::Main::set_pingvin_home(vm["home"].as()); + GINFO_STREAM("Set Pingvin home to: " << Pingvin::Main::get_pingvin_home()); } - // "Choose" a Pipeline - std::vector builders{ - &file_search, - - &noise_dependency, - &default_mr, - &default_mr_optimized, - - &epi_2d, - - &grappa, - &grappa_cpu, - - &cartesian_grappa, - &cartesian_grappa_snr, - &grappa_denoise, + PipelineRegistry registry; - &cartesian_spirit, - &cartesian_spirit_nonlinear, - - &grappa_epi, - - &cmr_cine_binning, - &cmr_mapping_t1_sr, - &cmr_rtcine_lax_ai, - - &example_parallel_bypass, - - &stream_cartesian_grappa_imagearray, - &stream_cartesian_grappa, - &stream_image_array_scaling, - &stream_image_array_split, - &stream_complex_to_float, - &stream_float_to_fixed_point, - }; - std::map builder_map; - for (auto& builder : builders) { - builder_map[builder->name()] = builder; + if (vm.count("list")) { + std::cout << "Pipeline / Description" << std::endl; + for (auto& builder : registry.builders()) { + std::cout << builder->name() << " / " << builder->description() << std::endl; + } + return 0; } if (!vm.count("pipeline")) { if (vm.count("help")) { std::filesystem::path progpath(argv[0]); - std::cerr << "Usage: " << progpath.filename().string() << " [global options] [pipeline options]" - << std::endl; - std::cerr << help_options << std::endl; - std::cerr << "Pipelines:" << std::endl; - for (auto& builder : builders) { - // std::cerr << "┌ " << builder->name << std::endl << "└──── " << builder->description << std::endl; - std::cerr << "- " << builder->name() << std::endl << " └── " << builder->description() << std::endl; - } + std::cout << "Usage: " + << progpath.filename().string() << " [global options] [pipeline options]" << std::endl + << help_options << std::endl; return 0; } else { std::cerr << "No pipeline specified" << std::endl; @@ -189,12 +164,13 @@ int main(int argc, char** argv) } } + // "Choose" a Pipeline std::string subcmd = vm["pipeline"].as(); - if (!builder_map.count(subcmd)) { + auto builder = registry.get(subcmd); + if (!builder) { std::cerr << "Unknown pipeline: " << subcmd << std::endl; return 1; } - auto& builder = builder_map[subcmd]; po::options_description pipeline_options = builder->collect_options(); @@ -203,15 +179,16 @@ int main(int argc, char** argv) po::parsed_options parsed = po::basic_command_line_parser(unrecognized).options(pipeline_options).run(); po::store(parsed, vm); - if (vm.count("help")) { - std::cerr << help_options << std::endl; - std::cerr << "--- " << subcmd << " ---" << std::endl; - std::cerr << pipeline_options << std::endl; + std::filesystem::path progpath(argv[0]); + std::cout << "Usage: " + << progpath.filename().string() << " " << subcmd << " [pipeline options]" << std::endl << std::endl + << pipeline_opts << std::endl + << subcmd << " - " << pipeline_options << std::endl; return 0; } - po::store(po::parse_environment(pipeline_options, + po::store(po::parse_environment(pipeline_options, // This ceremony enables defining PINGVIN_ env vars that don't map directly to CLI options // Otherwise, boost::program_options will complain about unrecognized PINGVIN_ env vars [&pipeline_options](const std::string& var) { @@ -249,6 +226,10 @@ int main(int argc, char** argv) return 0; } + check_environment_variables(); + + GINFO_STREAM("Pingvin " << PINGVIN_VERSION_STRING << " [" << PINGVIN_GIT_SHA1_HASH << "]"); + std::unique_ptr input_file; if (vm.count("input")) { input_file = std::make_unique(vm["input"].as()); diff --git a/apps/pingvin/pipeline_registry.h b/apps/pingvin/pipeline_registry.h new file mode 100644 index 00000000..a6f3269f --- /dev/null +++ b/apps/pingvin/pipeline_registry.h @@ -0,0 +1,86 @@ +#pragma once + +#include "Pipeline.h" + +#include "pipelines/noise.h" +#include "pipelines/grappa.h" +#include "pipelines/default.h" +#include "pipelines/epi.h" +#include "pipelines/cartesian_grappa.h" +#include "pipelines/cartesian_spirit.h" +#include "pipelines/grappa_epi.h" +#include "pipelines/cmr.h" +#include "pipelines/parallel_bypass.h" +#include "pipelines/streams.h" +#include "pipelines/denoise.h" + +#include "pipelines/file_search.h" + + +namespace Pingvin { + +class PipelineRegistry { +public: + PipelineRegistry() { + register_pipeline(&file_search); + + register_pipeline(&noise_dependency); + register_pipeline(&default_mr); + register_pipeline(&default_mr_optimized); + + register_pipeline(&epi_2d); + + register_pipeline(&grappa); + register_pipeline(&grappa_cpu); + + register_pipeline(&cartesian_grappa); + register_pipeline(&cartesian_grappa_snr); + register_pipeline(&grappa_denoise); + + register_pipeline(&cartesian_spirit); + register_pipeline(&cartesian_spirit_nonlinear); + + register_pipeline(&grappa_epi); + + register_pipeline(&cmr_cine_binning); + register_pipeline(&cmr_mapping_t1_sr); + register_pipeline(&cmr_rtcine_lax_ai); + + register_pipeline(&example_parallel_bypass); + + register_pipeline(&stream_cartesian_grappa_imagearray); + register_pipeline(&stream_cartesian_grappa); + register_pipeline(&stream_image_array_scaling); + register_pipeline(&stream_image_array_split); + register_pipeline(&stream_complex_to_float); + register_pipeline(&stream_float_to_fixed_point); + } + + IPipelineBuilder* get(const std::string& name) const + { + if (builders_.count(name)) { + return builders_.at(name); + } + return nullptr; + } + + auto builders() const + { + std::vector result; + for (const auto& [name, builder] : builders_) { + result.push_back(builder); + } + return result; + } + +protected: + void register_pipeline(IPipelineBuilder* builder) + { + builders_[builder->name()] = builder; + } + +private: + std::map builders_; +}; + +} \ No newline at end of file diff --git a/apps/pingvin/pipelines/cartesian_grappa.h b/apps/pingvin/pipelines/cartesian_grappa.h index ef5a3c9e..aacb0433 100644 --- a/apps/pingvin/pipelines/cartesian_grappa.h +++ b/apps/pingvin/pipelines/cartesian_grappa.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" @@ -19,9 +19,9 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" -namespace pingvin { +namespace Pingvin { -static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") +static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") .withSource() .withSink() .withNode("noise") @@ -41,7 +41,7 @@ static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", " .withNode("convert") ; -static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") +static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/cartesian_spirit.h b/apps/pingvin/pipelines/cartesian_spirit.h index 85c38c49..e991ee14 100644 --- a/apps/pingvin/pipelines/cartesian_spirit.h +++ b/apps/pingvin/pipelines/cartesian_spirit.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" @@ -19,9 +19,9 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" -namespace pingvin { +namespace Pingvin { -static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", "Cartesian SPIRIT Recon") +static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", "Cartesian SPIRIT Recon") .withSource() .withSink() .withNode("noise") @@ -41,7 +41,7 @@ static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", " .withNode("convert") ; -static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") +static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/cmr.h b/apps/pingvin/pipelines/cmr.h index 129843bb..3191067a 100644 --- a/apps/pingvin/pipelines/cmr.h +++ b/apps/pingvin/pipelines/cmr.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" @@ -21,9 +21,9 @@ #include "gadgets/cmr/CmrParametricT1SRMappingGadget.h" #include "gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h" -namespace pingvin { +namespace Pingvin { -static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") +static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") .withSource() .withSink() .withNode("noise") @@ -43,7 +43,7 @@ static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", " .withNode("convert") ; -static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") +static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") .withSource() .withSink() .withNode("noise") @@ -64,7 +64,7 @@ static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", .withNode("convert") ; -static auto cmr_rtcine_lax_ai = PipelineBuilder("cmr-rtcine-lax-ai", "CMR real-time cine LAX AI") +static auto cmr_rtcine_lax_ai = PipelineBuilder("cmr-rtcine-lax-ai", "CMR real-time cine LAX AI") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/config/epi.conf b/apps/pingvin/pipelines/config/epi.conf index 9b424bf3..34efb327 100644 --- a/apps/pingvin/pipelines/config/epi.conf +++ b/apps/pingvin/pipelines/config/epi.conf @@ -1,13 +1,5 @@ # Replaces epi.xml -[noise] - -[reconx] - -[epicorr] - -[fftx] - [acctrig] trigger-dimension=repetition sorting-dimension=slice @@ -16,14 +8,5 @@ sorting-dimension=slice split-slices=true ignore-segment=true -[fft] - -[combine] - -[extract] -magnitude=true - -[autoscale] - [convert] type=ushort diff --git a/apps/pingvin/pipelines/default.h b/apps/pingvin/pipelines/default.h index e45d184a..fa5b5b6e 100644 --- a/apps/pingvin/pipelines/default.h +++ b/apps/pingvin/pipelines/default.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" @@ -12,11 +12,11 @@ #include "gadgets/mri_core/ImageArraySplitGadget.h" #include "gadgets/mri_core/ExtractGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; -static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") +static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") .withSource() .withSink() .withNode("ros") @@ -27,7 +27,7 @@ static auto default_mr = PipelineBuilder("default", "Basic Cartesian .withNode("extract") ; -static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") +static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") .withSource() .withSink() .withNode("noise-adjust") diff --git a/apps/pingvin/pipelines/denoise.h b/apps/pingvin/pipelines/denoise.h index d5b238a5..7cd153d5 100644 --- a/apps/pingvin/pipelines/denoise.h +++ b/apps/pingvin/pipelines/denoise.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" @@ -20,11 +20,11 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; -static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") +static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/epi.h b/apps/pingvin/pipelines/epi.h index f2fa4945..f6af27c8 100644 --- a/apps/pingvin/pipelines/epi.h +++ b/apps/pingvin/pipelines/epi.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" @@ -15,11 +15,11 @@ #include "gadgets/epi/EPICorrGadget.h" #include "gadgets/epi/FFTXGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; - static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") + static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/file_search.h b/apps/pingvin/pipelines/file_search.h index ddcda390..ac2f17b1 100644 --- a/apps/pingvin/pipelines/file_search.h +++ b/apps/pingvin/pipelines/file_search.h @@ -1,8 +1,8 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; diff --git a/apps/pingvin/pipelines/grappa.h b/apps/pingvin/pipelines/grappa.h index 4a74ec5a..7168109e 100644 --- a/apps/pingvin/pipelines/grappa.h +++ b/apps/pingvin/pipelines/grappa.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" @@ -16,11 +16,11 @@ #include "gadgets/mri_core/AutoScaleGadget.h" #include "gadgets/mri_core/FloatToFixedPointGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; -static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") +static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") .withSource() .withSink() .withNode("noise-adjust") @@ -46,7 +46,7 @@ static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconst .withNode("extract") ; -static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") +static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") .withSource() .withSink() .withNode("noise-adjust") diff --git a/apps/pingvin/pipelines/grappa_epi.h b/apps/pingvin/pipelines/grappa_epi.h index 06c22cc4..0490674c 100644 --- a/apps/pingvin/pipelines/grappa_epi.h +++ b/apps/pingvin/pipelines/grappa_epi.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/epi/EPIReconXGadget.h" #include "gadgets/epi/EPICorrGadget.h" @@ -22,11 +22,11 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; - static auto grappa_epi = PipelineBuilder("grappa-epi", "Basic EPI Reconstruction") + static auto grappa_epi = PipelineBuilder("grappa-epi", "Basic EPI Reconstruction") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/noise.h b/apps/pingvin/pipelines/noise.h index 4e3082c0..ab23a48c 100644 --- a/apps/pingvin/pipelines/noise.h +++ b/apps/pingvin/pipelines/noise.h @@ -1,14 +1,14 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; - static auto noise_dependency = PipelineBuilder("noise", "Compute noise covariance for measurement dependency") + static auto noise_dependency = PipelineBuilder("noise", "Compute noise covariance for measurement dependency") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/parallel_bypass.h b/apps/pingvin/pipelines/parallel_bypass.h index c43b40bb..677aea88 100644 --- a/apps/pingvin/pipelines/parallel_bypass.h +++ b/apps/pingvin/pipelines/parallel_bypass.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" @@ -15,11 +15,11 @@ #include "gadgets/examples/ImageInverter.h" #include "gadgets/examples/ImageLayerer.h" -namespace pingvin { +namespace Pingvin { using namespace Gadgetron; -static auto example_parallel_bypass = PipelineBuilder("parallel-bypass", "Basic Parallel Bypass Example") +static auto example_parallel_bypass = PipelineBuilder("parallel-bypass", "Basic Parallel Bypass Example") .withSource() .withSink() .withNode("noise") diff --git a/apps/pingvin/pipelines/streams.h b/apps/pingvin/pipelines/streams.h index dcb0c93d..aa33093f 100644 --- a/apps/pingvin/pipelines/streams.h +++ b/apps/pingvin/pipelines/streams.h @@ -1,6 +1,6 @@ #pragma once -#include "pipeline.h" +#include "Pipeline.h" #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" @@ -20,9 +20,9 @@ #include "gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h" #include "gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" -namespace pingvin { +namespace Pingvin { -static auto stream_cartesian_grappa_imagearray = PipelineBuilder("stream-cartesian-grappa-imagearray", "Cartesian Grappa Recon to ImageArray") +static auto stream_cartesian_grappa_imagearray = PipelineBuilder("stream-cartesian-grappa-imagearray", "Cartesian Grappa Recon to ImageArray") .withSource() .withSink() .withNode("noise") @@ -45,25 +45,25 @@ static auto stream_cartesian_grappa = stream_cartesian_grappa_imagearray .withNode("augment-metadata") ; -static auto stream_image_array_scaling = PipelineBuilder("stream-image-array-scaling", "Image Array Scaling") +static auto stream_image_array_scaling = PipelineBuilder("stream-image-array-scaling", "Image Array Scaling") .withSource() .withSink() .withNode("scale") ; -static auto stream_image_array_split = PipelineBuilder("stream-image-array-split", "Image Array split") +static auto stream_image_array_split = PipelineBuilder("stream-image-array-split", "Image Array split") .withSource() .withSink() .withNode("split") ; -static auto stream_complex_to_float = PipelineBuilder("stream-complex-to-float", "Complex to Float") +static auto stream_complex_to_float = PipelineBuilder("stream-complex-to-float", "Complex to Float") .withSource() .withSink() .withNode("complex-to-float") ; -static auto stream_float_to_fixed_point = PipelineBuilder("stream-float-to-fixed-point", "Float to Fixed-Point") +static auto stream_float_to_fixed_point = PipelineBuilder("stream-float-to-fixed-point", "Float to Fixed-Point") .withSource() .withSink() .withNode("convert") diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 62640b1a..8adc70ea 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,10 +1,17 @@ add_compile_options(-Wall -Werror) add_subdirectory(parallel) +configure_file(pingvin_config.in ${CMAKE_BINARY_DIR}/pingvin_config.h) + add_library(pingvin_core SHARED Channel.cpp Message.cpp Process.cpp + Stream.cpp + ParallelStream.cpp + MultiprocessStream.cpp + PureStream.cpp + system_info.cpp io/from_string.cpp) set_target_properties(pingvin_core PROPERTIES @@ -18,9 +25,12 @@ target_link_libraries(pingvin_core Boost::filesystem ) -target_include_directories(pingvin_core PUBLIC +target_include_directories(pingvin_core + PUBLIC $ $ + PRIVATE + ${CMAKE_BINARY_DIR} ) install(TARGETS pingvin_core @@ -40,10 +50,21 @@ install(FILES Message.hpp MPMCChannel.h Context.h + Source.h + Sink.h Node.h PureGadget.h ChannelAlgorithms.h Process.h + + Pipeline.h + Stream.h + ParallelStream.h + MultiprocessStream.h + PureStream.h + + system_info.h + DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) install(FILES diff --git a/apps/pingvin/nodes/MultiprocessStream.cpp b/core/MultiprocessStream.cpp similarity index 100% rename from apps/pingvin/nodes/MultiprocessStream.cpp rename to core/MultiprocessStream.cpp diff --git a/apps/pingvin/nodes/MultiprocessStream.h b/core/MultiprocessStream.h similarity index 100% rename from apps/pingvin/nodes/MultiprocessStream.h rename to core/MultiprocessStream.h diff --git a/apps/pingvin/nodes/ParallelStream.cpp b/core/ParallelStream.cpp similarity index 100% rename from apps/pingvin/nodes/ParallelStream.cpp rename to core/ParallelStream.cpp diff --git a/apps/pingvin/nodes/ParallelStream.h b/core/ParallelStream.h similarity index 100% rename from apps/pingvin/nodes/ParallelStream.h rename to core/ParallelStream.h diff --git a/apps/pingvin/pipelines/pipeline.h b/core/Pipeline.h similarity index 66% rename from apps/pingvin/pipelines/pipeline.h rename to core/Pipeline.h index 63bf93a1..54a00214 100644 --- a/apps/pingvin/pipelines/pipeline.h +++ b/core/Pipeline.h @@ -10,139 +10,56 @@ namespace po = boost::program_options; #include "system_info.h" -#include "nodes/Stream.h" -#include "nodes/ParallelStream.h" -#include "nodes/MultiprocessStream.h" #include "Channel.h" - #include "Node.h" +#include "Source.h" +#include "Sink.h" +#include "Stream.h" +#include "ParallelStream.h" #include "parallel/Branch.h" #include "parallel/Merge.h" +#include "MultiprocessStream.h" -namespace pingvin { - - -struct ISource { - virtual ~ISource() = default; - virtual void consume_input(Gadgetron::Core::ChannelPair& input_channel) = 0; -}; - -template -struct Source : public ISource { - virtual void initContext(CTX&) = 0; -}; - -struct ISink { - virtual ~ISink() = default; - virtual void produce_output(Gadgetron::Core::ChannelPair& output_channel) = 0; -}; - - - -///// BEGIN MRD ///// - -#include "mrd/types.h" - -using MrdContext = Gadgetron::Core::MrdContext; - -struct MrdSource : public Source { - MrdSource(std::istream& input_stream): mrd_reader_(input_stream) {} +namespace Pingvin { - void initContext(MrdContext& ctx) override { - std::optional hdr; - mrd_reader_.ReadHeader(hdr); - if (!hdr.has_value()) { - GADGET_THROW("Failed to read MRD header"); - } +template +struct NodeParametersBuilder { + NodeParametersBuilder(const std::string& label): label_(label), parameters_(label) {} - ctx.header = hdr.value(); + void collect_options(po::options_description& parent) { + po::options_description desc(parameters_.description()); - for (char** raw = environ; *raw; ++raw) { - std::string s(*raw); - auto pos = s.find('='); - if (pos != std::string::npos) { - ctx.env[s.substr(0, pos)] = s.substr(pos + 1); + if (parameters_.parameters().size() > 0) { + for (auto& p: parameters_.parameters()) { + desc.add(p->as_boost_option()); } - } - - ctx.paths.pingvin_home = Gadgetron::Main::Info::get_pingvin_home(); - } - void consume_input(Gadgetron::Core::ChannelPair& input_channel) override - { - mrd::StreamItem stream_item; - while (mrd_reader_.ReadData(stream_item)) { - std::visit([&](auto&& arg) { - Gadgetron::Core::Message msg(std::move(arg)); - input_channel.output.push_message(std::move(msg)); - }, stream_item); + parent.add(desc); } - mrd_reader_.Close(); - auto destruct_me = std::move(input_channel.output); } -private: - mrd::binary::MrdReader mrd_reader_; -}; - -struct MrdSink : public ISink { - MrdSink(std::ostream& output_stream, const MrdContext& ctx) - : mrd_writer_(output_stream) - { - mrd_writer_.WriteHeader(ctx.header); - } - - void produce_output(Gadgetron::Core::ChannelPair& output_channel) override - { - while (true) { - try { - auto message = output_channel.input.pop(); - - using namespace Gadgetron::Core; - - 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 Gadgetron::Core::ChannelClosed& exc) { - break; + void dump_config(std::ostream& os, bool only_modified) { + std::stringstream ss; + ss.imbue(std::locale::classic()); + for (auto& p: parameters_.parameters()) { + if (!p->modified() && only_modified) { + continue; } + p->print(ss); + ss << std::endl; + } + auto s = ss.str(); + if (!s.empty()) { + os << "[" << parameters_.prefix() << "]" << std::endl; + os << s << std::endl; } - - mrd_writer_.EndData(); - mrd_writer_.Close(); } -private: - mrd::binary::MrdWriter mrd_writer_; + const std::string label_; + typename CLS::Parameters parameters_; }; -///// END MRD ///// - template struct INodeBuilder { virtual ~INodeBuilder() = default; @@ -152,46 +69,21 @@ struct INodeBuilder { }; template -class NodeBuilder : public INodeBuilder { +class NodeBuilder : public INodeBuilder, NodeParametersBuilder { public: - NodeBuilder(const std::string& label): label_(label), parameters_(label) {} + NodeBuilder(const std::string& label): NodeParametersBuilder(label) {} std::shared_ptr build(const CTX& ctx) const override { return std::make_shared(ctx, this->parameters_); } void collect_options(po::options_description& parent) override { - po::options_description desc(parameters_.description()); - - if (parameters_.parameters().size() > 0) { - for (auto& p: parameters_.parameters()) { - desc.add(p->as_boost_option()); - } - - parent.add(desc); - } + NodeParametersBuilder::collect_options(parent); } void dump_config(std::ostream& os, bool only_modified) override { - std::stringstream ss; - ss.imbue(std::locale::classic()); - for (auto& p: parameters_.parameters()) { - if (!p->modified() && only_modified) { - continue; - } - p->print(ss); - ss << std::endl; - } - auto s = ss.str(); - if (!s.empty()) { - os << "[" << parameters_.prefix() << "]" << std::endl; - os << s << std::endl; - } + NodeParametersBuilder::dump_config(os, only_modified); } - -private: - std::string label_; - typename N::Parameters parameters_; }; template @@ -240,41 +132,21 @@ struct IBranchBuilder { }; template -class BranchBuilder : public IBranchBuilder { +class BranchBuilder : public IBranchBuilder, NodeParametersBuilder { public: - BranchBuilder(const std::string& label): label_(label), parameters_(label) {} + BranchBuilder(const std::string& label): NodeParametersBuilder(label) {} std::unique_ptr build(const CTX& ctx) const override { return std::move(std::make_unique(ctx, this->parameters_)); } void collect_options(po::options_description& parent) override { - po::options_description desc(parameters_.description()); - - if (parameters_.parameters().size() > 0) { - for (auto& p: parameters_.parameters()) { - desc.add(p->as_boost_option()); - } - - parent.add(desc); - } + NodeParametersBuilder::collect_options(parent); } void dump_config(std::ostream& os, bool only_modified) override { - os << "[" << parameters_.prefix() << "]" << std::endl; - for (auto& p: parameters_.parameters()) { - if (!p->modified() && only_modified) { - continue; - } - p->print(os); - os << std::endl; - } - os << std::endl; + NodeParametersBuilder::dump_config(os, only_modified); } - -private: - std::string label_; - typename N::Parameters parameters_; }; template @@ -286,41 +158,21 @@ struct IMergeBuilder { }; template -class MergeBuilder : public IMergeBuilder { +class MergeBuilder : public IMergeBuilder, NodeParametersBuilder { public: - MergeBuilder(const std::string& label): label_(label), parameters_(label) {} + MergeBuilder(const std::string& label): NodeParametersBuilder(label) {} std::unique_ptr build(const CTX& ctx) const override { return std::move(std::make_unique(ctx, this->parameters_)); } void collect_options(po::options_description& parent) override { - po::options_description desc(parameters_.description()); - - if (parameters_.parameters().size() > 0) { - for (auto& p: parameters_.parameters()) { - desc.add(p->as_boost_option()); - } - - parent.add(desc); - } + NodeParametersBuilder::collect_options(parent); } void dump_config(std::ostream& os, bool only_modified) override { - os << "[" << parameters_.prefix() << "]" << std::endl; - for (auto& p: parameters_.parameters()) { - if (!p->modified() && only_modified) { - continue; - } - p->print(os); - os << std::endl; - } - os << std::endl; + NodeParametersBuilder::dump_config(os, only_modified); } - -private: - std::string label_; - typename N::Parameters parameters_; }; template @@ -375,7 +227,7 @@ class ParallelBuilder : public INodeBuilder { } auto merge = merge_builder_->build(ctx); - return std::make_shared(std::move(branch), std::move(merge), streams); + return std::make_shared(std::move(branch), std::move(merge), std::move(streams)); } void collect_options(po::options_description& parent) override { @@ -417,41 +269,21 @@ struct IPureNodeBuilder { }; template -class PureNodeBuilder : public IPureNodeBuilder { +class PureNodeBuilder : public IPureNodeBuilder, NodeParametersBuilder { public: - PureNodeBuilder(const std::string& label): label_(label), parameters_(label) {} + PureNodeBuilder(const std::string& label): NodeParametersBuilder(label) {} std::unique_ptr build(const CTX& ctx) const override { return std::move(std::make_unique(ctx, this->parameters_)); } void collect_options(po::options_description& parent) override { - po::options_description desc(parameters_.description()); - - if (parameters_.parameters().size() > 0) { - for (auto& p: parameters_.parameters()) { - desc.add(p->as_boost_option()); - } - - parent.add(desc); - } + NodeParametersBuilder::collect_options(parent); } void dump_config(std::ostream& os, bool only_modified) override { - os << "[" << parameters_.prefix() << "]" << std::endl; - for (auto& p: parameters_.parameters()) { - if (!p->modified() && only_modified) { - continue; - } - p->print(os); - os << std::endl; - } - os << std::endl; + NodeParametersBuilder::dump_config(os, only_modified); } - -private: - std::string label_; - typename N::Parameters parameters_; }; template @@ -658,6 +490,7 @@ struct PipelineBuilder : public IPipelineBuilder{ return std::move(pipeline); } +private: std::function>(std::istream&)> source_builder_; std::function(std::ostream&, const CTX&)> sink_builder_; @@ -667,4 +500,4 @@ struct PipelineBuilder : public IPipelineBuilder{ }; -} // namespace pingvin \ No newline at end of file +} // namespace Pingvin \ No newline at end of file diff --git a/apps/pingvin/nodes/PureStream.cpp b/core/PureStream.cpp similarity index 100% rename from apps/pingvin/nodes/PureStream.cpp rename to core/PureStream.cpp diff --git a/apps/pingvin/nodes/PureStream.h b/core/PureStream.h similarity index 100% rename from apps/pingvin/nodes/PureStream.h rename to core/PureStream.h diff --git a/core/Sink.h b/core/Sink.h new file mode 100644 index 00000000..1569eea3 --- /dev/null +++ b/core/Sink.h @@ -0,0 +1,68 @@ +#include "Node.h" + +namespace Pingvin { + +struct ISink { + virtual ~ISink() = default; + virtual void produce_output(Gadgetron::Core::ChannelPair& output_channel) = 0; +}; + + +/** TODO: Move to MR-specific location! */ +struct MrdSink : public ISink { + MrdSink(std::ostream& output_stream, const Gadgetron::Core::MrdContext& ctx) + : mrd_writer_(output_stream) + { + mrd_writer_.WriteHeader(ctx.header); + } + + void produce_output(Gadgetron::Core::ChannelPair& output_channel) override + { + while (true) { + try { + auto message = output_channel.input.pop(); + + using namespace Gadgetron::Core; + + 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 Gadgetron::Core::ChannelClosed& exc) { + break; + } + } + + mrd_writer_.EndData(); + mrd_writer_.Close(); + } + +private: + mrd::binary::MrdWriter mrd_writer_; +}; + + +} \ No newline at end of file diff --git a/core/Source.h b/core/Source.h new file mode 100644 index 00000000..349ff83d --- /dev/null +++ b/core/Source.h @@ -0,0 +1,58 @@ +#include "Node.h" + +namespace Pingvin { + +struct ISource { + virtual ~ISource() = default; + virtual void consume_input(Gadgetron::Core::ChannelPair& input_channel) = 0; +}; + +template +struct Source : public ISource { + virtual void initContext(CTX&) = 0; +}; + + +/** TODO: Move to MR-specific location! */ +struct MrdSource : public Source { + MrdSource(std::istream& input_stream): mrd_reader_(input_stream) {} + + void initContext(Gadgetron::Core::MrdContext& ctx) override { + std::optional hdr; + mrd_reader_.ReadHeader(hdr); + if (!hdr.has_value()) { + GADGET_THROW("Failed to read MRD header"); + } + + ctx.header = hdr.value(); + + for (char** raw = environ; *raw; ++raw) { + std::string s(*raw); + auto pos = s.find('='); + if (pos != std::string::npos) { + ctx.env[s.substr(0, pos)] = s.substr(pos + 1); + } + } + + ctx.paths.pingvin_home = Pingvin::Main::get_pingvin_home(); + } + + void consume_input(Gadgetron::Core::ChannelPair& input_channel) override + { + mrd::StreamItem stream_item; + while (mrd_reader_.ReadData(stream_item)) { + std::visit([&](auto&& arg) { + Gadgetron::Core::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); + } + +private: + mrd::binary::MrdReader mrd_reader_; +}; + + +} \ No newline at end of file diff --git a/apps/pingvin/nodes/Stream.cpp b/core/Stream.cpp similarity index 92% rename from apps/pingvin/nodes/Stream.cpp rename to core/Stream.cpp index c73b736d..400ba9e8 100644 --- a/apps/pingvin/nodes/Stream.cpp +++ b/core/Stream.cpp @@ -12,7 +12,7 @@ namespace Gadgetron::Core { input_channels.emplace_back(std::move(input)); std::vector output_channels{}; - for (auto i = 0; i < nodes.size()-1; i++) { + for (size_t i = 0; i < nodes.size()-1; i++) { auto channel = make_channel(); input_channels.emplace_back(std::move(channel.input)); output_channels.emplace_back(std::move(channel.output)); @@ -21,7 +21,7 @@ namespace Gadgetron::Core { output_channels.emplace_back(std::move(output)); std::vector threads(nodes.size()); - for (auto i = 0; i < nodes.size(); i++) { + for (size_t i = 0; i < nodes.size(); i++) { threads[i] = std::thread( [](auto node, auto input_channel, auto output_channel) { try { diff --git a/apps/pingvin/nodes/Stream.h b/core/Stream.h similarity index 86% rename from apps/pingvin/nodes/Stream.h rename to core/Stream.h index 1b1fe096..60f786ea 100644 --- a/apps/pingvin/nodes/Stream.h +++ b/core/Stream.h @@ -14,7 +14,9 @@ namespace Gadgetron::Core { public: const std::string key; - Stream(std::vector> nodes, const std::string key=""): nodes(std::move(nodes)), key(key) {} + Stream(std::vector> nodes, const std::string key="") + : key(key), nodes(std::move(nodes)) + {} void process( Core::GenericInputChannel& input, diff --git a/core/ThreadPool.h b/core/ThreadPool.h index 5a9fb391..7958663d 100644 --- a/core/ThreadPool.h +++ b/core/ThreadPool.h @@ -87,7 +87,7 @@ namespace Gadgetron::Core { auto work = std::make_unique>(std::forward(f), std::forward(args)...); auto future_result = work->get_future(); work_queue.push(std::move(work)); - return std::move(future_result); + return future_result; } void join(){ diff --git a/apps/pingvin/pingvin_config.in b/core/pingvin_config.in similarity index 75% rename from apps/pingvin/pingvin_config.in rename to core/pingvin_config.in index eead2bbf..2e360284 100644 --- a/apps/pingvin/pingvin_config.in +++ b/core/pingvin_config.in @@ -1,5 +1,4 @@ -#ifndef PINGVIN_CONFIG_H -#define PINGVIN_CONFIG_H +#pragma once #define PINGVIN_VERSION_MAJOR @PINGVIN_VERSION_MAJOR@ #define PINGVIN_VERSION_MINOR @PINGVIN_VERSION_MINOR@ @@ -8,6 +7,4 @@ #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 +#define PINGVIN_CUDA_NVCC_FLAGS "@CUDA_NVCC_FLAGS@" \ No newline at end of file diff --git a/apps/pingvin/system_info.cpp b/core/system_info.cpp similarity index 97% rename from apps/pingvin/system_info.cpp rename to core/system_info.cpp index 5497d9a9..594e0e0a 100644 --- a/apps/pingvin/system_info.cpp +++ b/core/system_info.cpp @@ -24,7 +24,7 @@ #endif -namespace Gadgetron::Main::Info { +namespace Pingvin::Main { std::string pingvin_version() { return PINGVIN_VERSION_STRING; @@ -228,14 +228,10 @@ namespace Gadgetron::Main::Info { std::filesystem::path executable_path = get_executable_path(); - GDEBUG_STREAM("Executable path: " << executable_path); - std::filesystem::path pingvin_home = executable_path .parent_path() .parent_path(); - GDEBUG_STREAM("Default Pingvin home: " << pingvin_home); - return pingvin_home; } diff --git a/apps/pingvin/system_info.h b/core/system_info.h similarity index 87% rename from apps/pingvin/system_info.h rename to core/system_info.h index b2a50e3b..306f549b 100644 --- a/apps/pingvin/system_info.h +++ b/core/system_info.h @@ -3,7 +3,7 @@ #include #include -namespace Gadgetron::Main::Info { +namespace Pingvin::Main { void print_system_information(std::ostream &); @@ -11,8 +11,6 @@ namespace Gadgetron::Main::Info { std::string pingvin_build(); size_t system_memory(); - bool python_support(); - bool matlab_support(); void set_pingvin_home(const std::filesystem::path&); const std::filesystem::path get_pingvin_home(); diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index e08b54db..ae82b2fb 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -13,14 +13,14 @@ class ExtractGadget : public Core::MRChannelGadget extract_mask = 0; - bool extract_magnitude = false; + bool extract_magnitude = true; bool extract_real = false; bool extract_imag = false; bool extract_phase = false; diff --git a/test/e2e/cases/cpu_grappa_simple.yml b/test/e2e/cases/cpu_grappa_simple.yml index 4e042264..cfa1c219 100644 --- a/test/e2e/cases/cpu_grappa_simple.yml +++ b/test/e2e/cases/cpu_grappa_simple.yml @@ -2,7 +2,7 @@ reconstruction: data: rtgrappa/acc_data_with_device_2_meas1.mrd checksum: 7fa1d38320b2a544148096ce09041b2a run: - - args: grappa-cpu --coil-reduction.coils-out=8 --extract.magnitude + - args: grappa-cpu --coil-reduction.coils-out=8 validation: reference: rtgrappa/grappa_rate2_cpu_out_grappa_float_cpu.xml.mrd checksum: f24f9b93670cfa0c1723493ce52c07c5 diff --git a/test/e2e/cases/gpu_grappa_simple.yml b/test/e2e/cases/gpu_grappa_simple.yml index 78191454..5753ee00 100644 --- a/test/e2e/cases/gpu_grappa_simple.yml +++ b/test/e2e/cases/gpu_grappa_simple.yml @@ -2,7 +2,7 @@ reconstruction: data: rtgrappa/acc_data_with_device_2_meas1.mrd checksum: 7fa1d38320b2a544148096ce09041b2a run: - - args: grappa --coil-reduction.coils-out=8 --extract.magnitude + - args: grappa --coil-reduction.coils-out=8 validation: reference: rtgrappa/grappa_rate2_cpu_out_grappa_float_cpu.xml.mrd checksum: f24f9b93670cfa0c1723493ce52c07c5 diff --git a/test/e2e/cases/parallel_bypass_example.yml b/test/e2e/cases/parallel_bypass_example.yml index 39ffe602..488bb9ba 100644 --- a/test/e2e/cases/parallel_bypass_example.yml +++ b/test/e2e/cases/parallel_bypass_example.yml @@ -2,7 +2,7 @@ reconstruction: data: simple_gre/meas_MiniGadgetron_GRE_meas1.mrd checksum: 382b7f32b77d3a078d8af75a365cec4c run: - - args: parallel-bypass --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude + - args: parallel-bypass --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices validation: reference: simple_gre/simple_gre_out_20210909_klk_inverted.mrd checksum: 303a2e4286e9c51783879325a5efb635 diff --git a/test/e2e/cases/simple_gre.yml b/test/e2e/cases/simple_gre.yml index cd84fee5..42c8e8ab 100644 --- a/test/e2e/cases/simple_gre.yml +++ b/test/e2e/cases/simple_gre.yml @@ -2,7 +2,7 @@ reconstruction: data: simple_gre/meas_MiniGadgetron_GRE_meas1.mrd checksum: 382b7f32b77d3a078d8af75a365cec4c run: - - args: default --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude + - args: default --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices validation: reference: simple_gre/simple_gre_out_20210909_klk_default.xml.mrd checksum: 5539627da4affccf396a39ffae0005e0 diff --git a/test/e2e/cases/simple_gre_3d.yml b/test/e2e/cases/simple_gre_3d.yml index 701fda40..cf878021 100644 --- a/test/e2e/cases/simple_gre_3d.yml +++ b/test/e2e/cases/simple_gre_3d.yml @@ -2,7 +2,7 @@ reconstruction: data: gre_3d/meas_MID248_gre_FID30644_meas1.mrd checksum: f744396f98767c09df7b9a33c7fd263b run: - - args: default-optimized --coil-reduction.coils-out=16 --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices --extract.magnitude + - args: default-optimized --coil-reduction.coils-out=16 --acctrig.trigger-dimension=repetition --acctrig.sorting-dimension=slice --buffer.split-slices validation: reference: gre_3d/simple_gre_out_3d_20210910_klk_default_optimized.xml.mrd checksum: 745c71b36b03f78570f8296a9dbf5b71 From 67c80ca26f3f3ccdec5d1f0ea4972bac1a365ab8 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Wed, 19 Feb 2025 18:39:39 +0000 Subject: [PATCH 18/21] Remove all MR-specific code from the core library --- CMakeLists.txt | 1 + apps/pingvin/CMakeLists.txt | 6 +- apps/pingvin/main.cc | 2 +- .../pipelines/{ => mri}/cartesian_grappa.h | 15 ++-- .../pipelines/{ => mri}/cartesian_spirit.h | 15 ++-- apps/pingvin/pipelines/{ => mri}/cmr.h | 21 +++--- .../config/cartesian-cine-denoise.conf | 0 .../config/cartesian-grappa-snr.conf | 0 .../config/cartesian-grappa-t2w.conf | 0 .../{ => mri}/config/cartesian-grappa.conf | 0 ...rtesian-nonlinear-spirit-realtimecine.conf | 0 ...ampling-nonlinear-spirit-realtimecine.conf | 0 .../{ => mri}/config/cartesian-spirit.conf | 0 .../{ => mri}/config/cmr-cine-binning.conf | 0 .../{ => mri}/config/cmr-mapping-t1-sr.conf | 0 .../{ => mri}/config/cmr-rtcine-lax-ai.conf | 0 .../pipelines/{ => mri}/config/epi.conf | 0 .../{ => mri}/config/grappa-epi.conf | 0 .../config/stream-cartesian-grappa.conf | 0 apps/pingvin/pipelines/{ => mri}/default.h | 15 ++-- apps/pingvin/pipelines/{ => mri}/denoise.h | 9 ++- apps/pingvin/pipelines/{ => mri}/epi.h | 9 ++- apps/pingvin/pipelines/{ => mri}/grappa.h | 15 ++-- apps/pingvin/pipelines/{ => mri}/grappa_epi.h | 9 ++- apps/pingvin/pipelines/{ => mri}/noise.h | 9 ++- .../pipelines/{ => mri}/parallel_bypass.h | 11 ++- apps/pingvin/pipelines/{ => mri}/streams.h | 33 +++++---- .../registry.h} | 26 +++---- core/CMakeLists.txt | 10 ++- core/Context.h | 74 ------------------- core/Node.h | 10 --- core/ParallelStream.cpp | 1 - core/ParallelStream.h | 3 - core/Pipeline.h | 5 +- core/PureGadget.h | 8 -- core/Sink.h | 62 +--------------- core/Source.h | 47 +----------- core/Stream.h | 3 - core/parallel/Branch.h | 11 --- core/parallel/CMakeLists.txt | 28 ------- core/parallel/Merge.h | 11 --- core/parallel/UnorderedMerge.h | 3 - gadgets/cmr/CMakeLists.txt | 2 +- .../CmrCartesianKSpaceBinningCineGadget.cpp | 2 +- .../cmr/CmrCartesianKSpaceBinningCineGadget.h | 20 ++--- gadgets/cmr/CmrParametricMappingGadget.cpp | 2 +- gadgets/cmr/CmrParametricMappingGadget.h | 2 +- .../cmr/CmrParametricT1SRMappingGadget.cpp | 2 +- gadgets/cmr/CmrParametricT1SRMappingGadget.h | 2 +- gadgets/cmr/CmrParametricT2MappingGadget.cpp | 2 +- gadgets/cmr/CmrParametricT2MappingGadget.h | 4 +- .../CmrRealTimeLAXCineAIAnalysisGadget.cpp | 2 +- .../cmr/CmrRealTimeLAXCineAIAnalysisGadget.h | 2 +- ...ureCmrCartesianKSpaceBinningCineGadget.cpp | 2 +- .../PureCmrCartesianKSpaceBinningCineGadget.h | 10 +-- gadgets/debugging/CMakeLists.txt | 4 +- gadgets/debugging/PseudoReplicatorGadget.h | 4 +- gadgets/debugging/RateLimitGadget.cpp | 2 +- gadgets/debugging/RateLimitGadget.h | 4 +- .../debugging/WhiteNoiseInjectorGadget.cpp | 2 +- gadgets/debugging/WhiteNoiseInjectorGadget.h | 4 +- gadgets/epi/CMakeLists.txt | 5 +- gadgets/epi/CutXGadget.cpp | 2 +- gadgets/epi/CutXGadget.h | 11 ++- gadgets/epi/EPICorrGadget.cpp | 4 +- gadgets/epi/EPICorrGadget.h | 6 +- gadgets/epi/EPIPackNavigatorGadget.cpp | 2 +- gadgets/epi/EPIPackNavigatorGadget.h | 4 +- gadgets/epi/EPIReconXGadget.cpp | 2 +- gadgets/epi/EPIReconXGadget.h | 4 +- gadgets/epi/FFTXGadget.h | 2 +- gadgets/epi/OneEncodingGadget.h | 2 +- gadgets/examples/AcquisitionWaveformBranch.h | 4 +- gadgets/examples/CMakeLists.txt | 4 +- gadgets/examples/ImageInverter.h | 2 +- gadgets/examples/ImageLayerer.cpp | 2 - gadgets/examples/ImageLayerer.h | 5 +- gadgets/grappa/AcquisitionFanout.h | 2 +- gadgets/grappa/CMakeLists.txt | 3 +- gadgets/grappa/ImageAccumulator.h | 5 +- gadgets/grappa/SliceAccumulator.cpp | 3 - gadgets/grappa/SliceAccumulator.h | 4 +- gadgets/grappa/Unmixing.h | 8 +- gadgets/grappa/WeightsCalculator.h | 6 +- gadgets/mri_core/AccumulatorGadget.cpp | 2 +- gadgets/mri_core/AccumulatorGadget.h | 4 +- .../AcquisitionAccumulateTriggerGadget.h | 4 +- .../mri_core/AsymmetricEchoAdjustROGadget.cpp | 2 +- .../mri_core/AsymmetricEchoAdjustROGadget.h | 4 +- gadgets/mri_core/AugmentImageMetadataGadget.h | 2 +- gadgets/mri_core/AutoScaleGadget.h | 4 +- gadgets/mri_core/BucketToBufferGadget.h | 4 +- gadgets/mri_core/CMakeLists.txt | 36 +-------- gadgets/mri_core/CoilReductionGadget.cpp | 2 +- gadgets/mri_core/CoilReductionGadget.h | 4 +- gadgets/mri_core/CombineGadget.h | 2 +- gadgets/mri_core/ComplexToFloatGadget.cpp | 2 +- gadgets/mri_core/ComplexToFloatGadget.h | 4 +- gadgets/mri_core/DenoiseGadget.h | 6 +- gadgets/mri_core/ExtractGadget.cpp | 2 +- gadgets/mri_core/ExtractGadget.h | 4 +- gadgets/mri_core/FFTGadget.h | 4 +- gadgets/mri_core/FlagTriggerGadget.cpp | 2 +- gadgets/mri_core/FlagTriggerGadget.h | 4 +- gadgets/mri_core/FloatToFixedPointGadget.h | 4 +- .../mri_core/FlowPhaseSubtractionGadget.cpp | 2 +- gadgets/mri_core/FlowPhaseSubtractionGadget.h | 4 +- gadgets/mri_core/ImageArraySplitGadget.h | 2 +- gadgets/mri_core/ImageIndexGadget.h | 2 +- gadgets/mri_core/ImageSortGadget.h | 4 +- gadgets/mri_core/MaxwellCorrectionGadget.cpp | 2 +- gadgets/mri_core/MaxwellCorrectionGadget.h | 4 +- gadgets/mri_core/NoiseAdjustGadget.cpp | 4 +- gadgets/mri_core/NoiseAdjustGadget.h | 4 +- gadgets/mri_core/PCACoilGadget.cpp | 2 +- gadgets/mri_core/PCACoilGadget.h | 4 +- gadgets/mri_core/PhysioInterpolationGadget.h | 4 +- .../mri_core/RemoveROOversamplingGadget.cpp | 2 +- gadgets/mri_core/RemoveROOversamplingGadget.h | 4 +- gadgets/mri_core/ScaleGadget.h | 4 +- gadgets/mri_core/SimpleReconGadget.h | 2 +- .../generic_recon_gadgets/GenericReconBase.h | 6 +- .../GenericReconCartesianGrappaAIGadget.cpp | 2 +- .../GenericReconCartesianGrappaAIGadget.h | 2 +- .../GenericReconCartesianGrappaGadget.cpp | 2 +- .../GenericReconCartesianGrappaGadget.h | 2 +- ...ReconCartesianNonLinearSpirit2DTGadget.cpp | 2 +- ...icReconCartesianNonLinearSpirit2DTGadget.h | 2 +- ...nericReconCartesianReferencePrepGadget.cpp | 2 +- ...GenericReconCartesianReferencePrepGadget.h | 2 +- .../GenericReconCartesianSpiritGadget.cpp | 2 +- .../GenericReconCartesianSpiritGadget.h | 2 +- .../GenericReconEigenChannelGadget.cpp | 2 +- .../GenericReconEigenChannelGadget.h | 2 +- ...enericReconFieldOfViewAdjustmentGadget.cpp | 2 +- .../GenericReconFieldOfViewAdjustmentGadget.h | 2 +- .../GenericReconGadget.cpp | 2 +- .../GenericReconGadget.h | 2 +- .../GenericReconImageArrayScalingGadget.cpp | 2 +- .../GenericReconImageArrayScalingGadget.h | 2 +- .../GenericReconKSpaceFilteringGadget.cpp | 2 +- .../GenericReconKSpaceFilteringGadget.h | 2 +- ...GenericReconNoiseStdMapComputingGadget.cpp | 2 +- .../GenericReconNoiseStdMapComputingGadget.h | 2 +- ...cReconPartialFourierHandlingFilterGadget.h | 2 +- ...nericReconPartialFourierHandlingGadget.cpp | 2 +- ...GenericReconPartialFourierHandlingGadget.h | 4 +- ...ricReconPartialFourierHandlingPOCSGadget.h | 2 +- .../GenericImageReconArrayToImageGadget.cpp | 0 .../GenericImageReconArrayToImageGadget.h | 0 .../GenericImageReconGadget.cpp | 0 .../{ => untested}/GenericImageReconGadget.h | 0 ...nericReconAccumulateImageTriggerGadget.cpp | 0 ...GenericReconAccumulateImageTriggerGadget.h | 0 .../GenericReconCartesianFFTGadget.cpp | 0 .../GenericReconCartesianFFTGadget.h | 0 .../GenericReconImageToImageArrayGadget.cpp | 0 .../GenericReconImageToImageArrayGadget.h | 0 ...econReferenceKSpaceDelayedBufferGadget.cpp | 0 ...cReconReferenceKSpaceDelayedBufferGadget.h | 0 .../generic_recon_gadgets/untested/README.md | 1 + .../{ => untested}/CoilComputationGadget.cpp | 0 .../{ => untested}/CoilComputationGadget.h | 0 .../{ => untested}/CropAndCombineGadget.cpp | 0 .../{ => untested}/CropAndCombineGadget.h | 0 .../{ => untested}/ImageAccumulatorGadget.cpp | 0 .../{ => untested}/ImageAccumulatorGadget.h | 0 .../{ => untested}/ImageFFTGadget.cpp | 0 .../mri_core/{ => untested}/ImageFFTGadget.h | 0 .../{ => untested}/ImageResizingGadget.cpp | 0 .../{ => untested}/ImageResizingGadget.h | 0 .../NoiseAdjustGadget_unoptimized.cpp | 0 .../NoiseAdjustGadget_unoptimized.h | 0 .../PartialFourierAdjustROGadget.cpp | 0 .../PartialFourierAdjustROGadget.h | 0 gadgets/mri_core/untested/README.md | 1 + mri/CMakeLists.txt | 37 ++++++++++ mri/MRContext.h | 25 +++++++ mri/MRNode.h | 17 +++++ core/parallel/Fanout.h => mri/MRParallel.h | 26 +++++-- mri/MRPureNode.h | 15 ++++ mri/MRSink.h | 66 +++++++++++++++++ mri/MRSource.h | 51 +++++++++++++ test/gadgets/setup_gadget.h | 8 +- toolboxes/mri_core/CMakeLists.txt | 1 + toolboxes/python/CMakeLists.txt | 1 + 186 files changed, 523 insertions(+), 576 deletions(-) rename apps/pingvin/pipelines/{ => mri}/cartesian_grappa.h (91%) rename apps/pingvin/pipelines/{ => mri}/cartesian_spirit.h (91%) rename apps/pingvin/pipelines/{ => mri}/cmr.h (91%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-cine-denoise.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-grappa-snr.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-grappa-t2w.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-grappa.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-nonlinear-spirit-realtimecine.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cartesian-spirit.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cmr-cine-binning.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cmr-mapping-t1-sr.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/cmr-rtcine-lax-ai.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/epi.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/grappa-epi.conf (100%) rename apps/pingvin/pipelines/{ => mri}/config/stream-cartesian-grappa.conf (100%) rename apps/pingvin/pipelines/{ => mri}/default.h (80%) rename apps/pingvin/pipelines/{ => mri}/denoise.h (89%) rename apps/pingvin/pipelines/{ => mri}/epi.h (84%) rename apps/pingvin/pipelines/{ => mri}/grappa.h (86%) rename apps/pingvin/pipelines/{ => mri}/grappa_epi.h (90%) rename apps/pingvin/pipelines/{ => mri}/noise.h (60%) rename apps/pingvin/pipelines/{ => mri}/parallel_bypass.h (87%) rename apps/pingvin/pipelines/{ => mri}/streams.h (80%) rename apps/pingvin/{pipeline_registry.h => pipelines/registry.h} (82%) delete mode 100644 core/Context.h delete mode 100644 core/parallel/CMakeLists.txt rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericImageReconArrayToImageGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericImageReconArrayToImageGadget.h (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericImageReconGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericImageReconGadget.h (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconAccumulateImageTriggerGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconAccumulateImageTriggerGadget.h (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconCartesianFFTGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconCartesianFFTGadget.h (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconImageToImageArrayGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconImageToImageArrayGadget.h (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconReferenceKSpaceDelayedBufferGadget.cpp (100%) rename gadgets/mri_core/generic_recon_gadgets/{ => untested}/GenericReconReferenceKSpaceDelayedBufferGadget.h (100%) create mode 100644 gadgets/mri_core/generic_recon_gadgets/untested/README.md rename gadgets/mri_core/{ => untested}/CoilComputationGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/CoilComputationGadget.h (100%) rename gadgets/mri_core/{ => untested}/CropAndCombineGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/CropAndCombineGadget.h (100%) rename gadgets/mri_core/{ => untested}/ImageAccumulatorGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/ImageAccumulatorGadget.h (100%) rename gadgets/mri_core/{ => untested}/ImageFFTGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/ImageFFTGadget.h (100%) rename gadgets/mri_core/{ => untested}/ImageResizingGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/ImageResizingGadget.h (100%) rename gadgets/mri_core/{ => untested}/NoiseAdjustGadget_unoptimized.cpp (100%) rename gadgets/mri_core/{ => untested}/NoiseAdjustGadget_unoptimized.h (100%) rename gadgets/mri_core/{ => untested}/PartialFourierAdjustROGadget.cpp (100%) rename gadgets/mri_core/{ => untested}/PartialFourierAdjustROGadget.h (100%) create mode 100644 gadgets/mri_core/untested/README.md create mode 100644 mri/CMakeLists.txt create mode 100644 mri/MRContext.h create mode 100644 mri/MRNode.h rename core/parallel/Fanout.h => mri/MRParallel.h (58%) create mode 100644 mri/MRPureNode.h create mode 100644 mri/MRSink.h create mode 100644 mri/MRSource.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 76a50a4d..c44326bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -318,6 +318,7 @@ add_subdirectory(cmake) add_subdirectory(core) add_subdirectory(gadgets) add_subdirectory(toolboxes) +add_subdirectory(mri) option(BUILD_WITH_GPERFTOOLS_PROFILER "Build with the gperftools profiler." Off) if (BUILD_WITH_GPERFTOOLS_PROFILER) diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 91c528bb..8d858177 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -1,8 +1,7 @@ add_executable(pingvin main.cc) target_link_libraries(pingvin - pingvin_core - pingvin_core_parallel + pingvin_mri pingvin_mricore pingvin_epi pingvin_grappa @@ -19,7 +18,6 @@ target_include_directories(pingvin ${CMAKE_SOURCE_DIR} ) - if (REQUIRE_SIGNED_CONFIG) target_link_libraries(pingvin GTBabylon) endif() @@ -35,5 +33,5 @@ endif () install(TARGETS pingvin DESTINATION bin COMPONENT main) -file(GLOB_RECURSE PIPELINE_CONFIG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pipelines/config/*.conf) +file(GLOB_RECURSE PIPELINE_CONFIG_FILES ${CMAKE_CURRENT_SOURCE_DIR}/pipelines/*/config/*.conf) install(FILES ${PIPELINE_CONFIG_FILES} DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) \ No newline at end of file diff --git a/apps/pingvin/main.cc b/apps/pingvin/main.cc index c6f1bcc4..65642dd4 100644 --- a/apps/pingvin/main.cc +++ b/apps/pingvin/main.cc @@ -1,7 +1,7 @@ #include "log.h" #include "system_info.h" #include "pingvin_config.h" -#include "pipeline_registry.h" +#include "pipelines/registry.h" #include diff --git a/apps/pingvin/pipelines/cartesian_grappa.h b/apps/pingvin/pipelines/mri/cartesian_grappa.h similarity index 91% rename from apps/pingvin/pipelines/cartesian_grappa.h rename to apps/pingvin/pipelines/mri/cartesian_grappa.h index aacb0433..79538f6b 100644 --- a/apps/pingvin/pipelines/cartesian_grappa.h +++ b/apps/pingvin/pipelines/mri/cartesian_grappa.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" @@ -21,9 +24,9 @@ namespace Pingvin { -static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") - .withSource() - .withSink() +static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") @@ -41,9 +44,9 @@ static auto cartesian_grappa = PipelineBuilder("car .withNode("convert") ; -static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") - .withSource() - .withSink() +static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") diff --git a/apps/pingvin/pipelines/cartesian_spirit.h b/apps/pingvin/pipelines/mri/cartesian_spirit.h similarity index 91% rename from apps/pingvin/pipelines/cartesian_spirit.h rename to apps/pingvin/pipelines/mri/cartesian_spirit.h index e991ee14..b701b860 100644 --- a/apps/pingvin/pipelines/cartesian_spirit.h +++ b/apps/pingvin/pipelines/mri/cartesian_spirit.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" @@ -21,9 +24,9 @@ namespace Pingvin { -static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", "Cartesian SPIRIT Recon") - .withSource() - .withSink() +static auto cartesian_spirit = PipelineBuilder("cartesian-spirit", "Cartesian SPIRIT Recon") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") @@ -41,9 +44,9 @@ static auto cartesian_spirit = PipelineBuilder("car .withNode("convert") ; -static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") - .withSource() - .withSink() +static auto cartesian_spirit_nonlinear = PipelineBuilder("cartesian-nonlinear-spirit", "Cartesian NonLinear Spirit RealTimeCine") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") diff --git a/apps/pingvin/pipelines/cmr.h b/apps/pingvin/pipelines/mri/cmr.h similarity index 91% rename from apps/pingvin/pipelines/cmr.h rename to apps/pingvin/pipelines/mri/cmr.h index 3191067a..c5709760 100644 --- a/apps/pingvin/pipelines/cmr.h +++ b/apps/pingvin/pipelines/mri/cmr.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" @@ -23,9 +26,9 @@ namespace Pingvin { -static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") - .withSource() - .withSink() +static auto cmr_cine_binning = PipelineBuilder("cmr-cine-binning", "CMR cine binning 2slices") + .withSource() + .withSink() .withNode("noise") .withNode("asymmetric-echo") .withNode("ros") @@ -43,9 +46,9 @@ static auto cmr_cine_binning = PipelineBuilder("cmr .withNode("convert") ; -static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") - .withSource() - .withSink() +static auto cmr_mapping_t1_sr = PipelineBuilder("cmr-mapping-t1-sr", "CMR 2DT T1 mapping SASHA") + .withSource() + .withSink() .withNode("noise") .withNode("asymmetric-echo") .withNode("ros") @@ -64,9 +67,9 @@ static auto cmr_mapping_t1_sr = PipelineBuilder("cm .withNode("convert") ; -static auto cmr_rtcine_lax_ai = PipelineBuilder("cmr-rtcine-lax-ai", "CMR real-time cine LAX AI") - .withSource() - .withSink() +static auto cmr_rtcine_lax_ai = PipelineBuilder("cmr-rtcine-lax-ai", "CMR real-time cine LAX AI") + .withSource() + .withSink() .withNode("noise") .withNode("asymmetric-echo") .withNode("ros") diff --git a/apps/pingvin/pipelines/config/cartesian-cine-denoise.conf b/apps/pingvin/pipelines/mri/config/cartesian-cine-denoise.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-cine-denoise.conf rename to apps/pingvin/pipelines/mri/config/cartesian-cine-denoise.conf diff --git a/apps/pingvin/pipelines/config/cartesian-grappa-snr.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa-snr.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-grappa-snr.conf rename to apps/pingvin/pipelines/mri/config/cartesian-grappa-snr.conf diff --git a/apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa-t2w.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-grappa-t2w.conf rename to apps/pingvin/pipelines/mri/config/cartesian-grappa-t2w.conf diff --git a/apps/pingvin/pipelines/config/cartesian-grappa.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-grappa.conf rename to apps/pingvin/pipelines/mri/config/cartesian-grappa.conf diff --git a/apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/mri/config/cartesian-nonlinear-spirit-realtimecine.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-nonlinear-spirit-realtimecine.conf rename to apps/pingvin/pipelines/mri/config/cartesian-nonlinear-spirit-realtimecine.conf diff --git a/apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/mri/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf rename to apps/pingvin/pipelines/mri/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf diff --git a/apps/pingvin/pipelines/config/cartesian-spirit.conf b/apps/pingvin/pipelines/mri/config/cartesian-spirit.conf similarity index 100% rename from apps/pingvin/pipelines/config/cartesian-spirit.conf rename to apps/pingvin/pipelines/mri/config/cartesian-spirit.conf diff --git a/apps/pingvin/pipelines/config/cmr-cine-binning.conf b/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf similarity index 100% rename from apps/pingvin/pipelines/config/cmr-cine-binning.conf rename to apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf diff --git a/apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf b/apps/pingvin/pipelines/mri/config/cmr-mapping-t1-sr.conf similarity index 100% rename from apps/pingvin/pipelines/config/cmr-mapping-t1-sr.conf rename to apps/pingvin/pipelines/mri/config/cmr-mapping-t1-sr.conf diff --git a/apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf b/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf similarity index 100% rename from apps/pingvin/pipelines/config/cmr-rtcine-lax-ai.conf rename to apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf diff --git a/apps/pingvin/pipelines/config/epi.conf b/apps/pingvin/pipelines/mri/config/epi.conf similarity index 100% rename from apps/pingvin/pipelines/config/epi.conf rename to apps/pingvin/pipelines/mri/config/epi.conf diff --git a/apps/pingvin/pipelines/config/grappa-epi.conf b/apps/pingvin/pipelines/mri/config/grappa-epi.conf similarity index 100% rename from apps/pingvin/pipelines/config/grappa-epi.conf rename to apps/pingvin/pipelines/mri/config/grappa-epi.conf diff --git a/apps/pingvin/pipelines/config/stream-cartesian-grappa.conf b/apps/pingvin/pipelines/mri/config/stream-cartesian-grappa.conf similarity index 100% rename from apps/pingvin/pipelines/config/stream-cartesian-grappa.conf rename to apps/pingvin/pipelines/mri/config/stream-cartesian-grappa.conf diff --git a/apps/pingvin/pipelines/default.h b/apps/pingvin/pipelines/mri/default.h similarity index 80% rename from apps/pingvin/pipelines/default.h rename to apps/pingvin/pipelines/mri/default.h index fa5b5b6e..c690474d 100644 --- a/apps/pingvin/pipelines/default.h +++ b/apps/pingvin/pipelines/mri/default.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" #include "gadgets/mri_core/CoilReductionGadget.h" @@ -16,9 +19,9 @@ namespace Pingvin { using namespace Gadgetron; -static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") - .withSource() - .withSink() +static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") + .withSource() + .withSink() .withNode("ros") .withNode("acctrig") .withNode("buffer") @@ -27,9 +30,9 @@ static auto default_mr = PipelineBuilder("default", .withNode("extract") ; -static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") - .withSource() - .withSink() +static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") + .withSource() + .withSink() .withNode("noise-adjust") .withNode("pca") .withNode("coil-reduction") diff --git a/apps/pingvin/pipelines/denoise.h b/apps/pingvin/pipelines/mri/denoise.h similarity index 89% rename from apps/pingvin/pipelines/denoise.h rename to apps/pingvin/pipelines/mri/denoise.h index 7cd153d5..cc61e6a8 100644 --- a/apps/pingvin/pipelines/denoise.h +++ b/apps/pingvin/pipelines/mri/denoise.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" @@ -24,9 +27,9 @@ namespace Pingvin { using namespace Gadgetron; -static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") - .withSource() - .withSink() +static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") diff --git a/apps/pingvin/pipelines/epi.h b/apps/pingvin/pipelines/mri/epi.h similarity index 84% rename from apps/pingvin/pipelines/epi.h rename to apps/pingvin/pipelines/mri/epi.h index f6af27c8..6db0a734 100644 --- a/apps/pingvin/pipelines/epi.h +++ b/apps/pingvin/pipelines/mri/epi.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h" #include "gadgets/mri_core/BucketToBufferGadget.h" @@ -19,9 +22,9 @@ namespace Pingvin { using namespace Gadgetron; - static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") - .withSource() - .withSink() + static auto epi_2d = PipelineBuilder("epi", "Basic EPI Reconstruction") + .withSource() + .withSink() .withNode("noise") .withNode("reconx") .withNode("epicorr") diff --git a/apps/pingvin/pipelines/grappa.h b/apps/pingvin/pipelines/mri/grappa.h similarity index 86% rename from apps/pingvin/pipelines/grappa.h rename to apps/pingvin/pipelines/mri/grappa.h index 7168109e..9ff05294 100644 --- a/apps/pingvin/pipelines/grappa.h +++ b/apps/pingvin/pipelines/mri/grappa.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" #include "gadgets/mri_core/CoilReductionGadget.h" @@ -20,9 +23,9 @@ namespace Pingvin { using namespace Gadgetron; -static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") - .withSource() - .withSink() +static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") + .withSource() + .withSink() .withNode("noise-adjust") .withNode("pca") .withNode("coil-reduction") @@ -46,9 +49,9 @@ static auto grappa = PipelineBuilder("grappa", "Bas .withNode("extract") ; -static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") - .withSource() - .withSink() +static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") + .withSource() + .withSink() .withNode("noise-adjust") .withNode("pca") .withNode("coil-reduction") diff --git a/apps/pingvin/pipelines/grappa_epi.h b/apps/pingvin/pipelines/mri/grappa_epi.h similarity index 90% rename from apps/pingvin/pipelines/grappa_epi.h rename to apps/pingvin/pipelines/mri/grappa_epi.h index 0490674c..749d8385 100644 --- a/apps/pingvin/pipelines/grappa_epi.h +++ b/apps/pingvin/pipelines/mri/grappa_epi.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/epi/EPIReconXGadget.h" #include "gadgets/epi/EPICorrGadget.h" #include "gadgets/epi/FFTXGadget.h" @@ -26,9 +29,9 @@ namespace Pingvin { using namespace Gadgetron; - static auto grappa_epi = PipelineBuilder("grappa-epi", "Basic EPI Reconstruction") - .withSource() - .withSink() + static auto grappa_epi = PipelineBuilder("grappa-epi", "Basic EPI Reconstruction") + .withSource() + .withSink() .withNode("noise") .withNode("reconx") .withNode("epicorr") diff --git a/apps/pingvin/pipelines/noise.h b/apps/pingvin/pipelines/mri/noise.h similarity index 60% rename from apps/pingvin/pipelines/noise.h rename to apps/pingvin/pipelines/mri/noise.h index ab23a48c..c0ecbecb 100644 --- a/apps/pingvin/pipelines/noise.h +++ b/apps/pingvin/pipelines/mri/noise.h @@ -2,15 +2,18 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" namespace Pingvin { using namespace Gadgetron; - static auto noise_dependency = PipelineBuilder("noise", "Compute noise covariance for measurement dependency") - .withSource() - .withSink() + static auto noise_dependency = PipelineBuilder("noise", "Compute noise covariance for measurement dependency") + .withSource() + .withSink() .withNode("noise") ; diff --git a/apps/pingvin/pipelines/parallel_bypass.h b/apps/pingvin/pipelines/mri/parallel_bypass.h similarity index 87% rename from apps/pingvin/pipelines/parallel_bypass.h rename to apps/pingvin/pipelines/mri/parallel_bypass.h index 677aea88..0b858b12 100644 --- a/apps/pingvin/pipelines/parallel_bypass.h +++ b/apps/pingvin/pipelines/mri/parallel_bypass.h @@ -2,6 +2,10 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" +#include "MRParallel.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/PCACoilGadget.h" #include "gadgets/mri_core/CoilReductionGadget.h" @@ -11,7 +15,6 @@ #include "gadgets/mri_core/SimpleReconGadget.h" #include "gadgets/mri_core/ImageArraySplitGadget.h" #include "gadgets/mri_core/ExtractGadget.h" -#include "core/parallel/Fanout.h" #include "gadgets/examples/ImageInverter.h" #include "gadgets/examples/ImageLayerer.h" @@ -19,9 +22,9 @@ namespace Pingvin { using namespace Gadgetron; -static auto example_parallel_bypass = PipelineBuilder("parallel-bypass", "Basic Parallel Bypass Example") - .withSource() - .withSink() +static auto example_parallel_bypass = PipelineBuilder("parallel-bypass", "Basic Parallel Bypass Example") + .withSource() + .withSink() .withNode("noise") .withNode("ros") .withNode("acctrig") diff --git a/apps/pingvin/pipelines/streams.h b/apps/pingvin/pipelines/mri/streams.h similarity index 80% rename from apps/pingvin/pipelines/streams.h rename to apps/pingvin/pipelines/mri/streams.h index aa33093f..b01cb710 100644 --- a/apps/pingvin/pipelines/streams.h +++ b/apps/pingvin/pipelines/mri/streams.h @@ -2,6 +2,9 @@ #include "Pipeline.h" +#include "MRSource.h" +#include "MRSink.h" + #include "gadgets/mri_core/NoiseAdjustGadget.h" #include "gadgets/mri_core/AsymmetricEchoAdjustROGadget.h" #include "gadgets/mri_core/RemoveROOversamplingGadget.h" @@ -22,9 +25,9 @@ namespace Pingvin { -static auto stream_cartesian_grappa_imagearray = PipelineBuilder("stream-cartesian-grappa-imagearray", "Cartesian Grappa Recon to ImageArray") - .withSource() - .withSink() +static auto stream_cartesian_grappa_imagearray = PipelineBuilder("stream-cartesian-grappa-imagearray", "Cartesian Grappa Recon to ImageArray") + .withSource() + .withSink() .withNode("noise") .withNode("echo-adjust") .withNode("ros") @@ -45,27 +48,27 @@ static auto stream_cartesian_grappa = stream_cartesian_grappa_imagearray .withNode("augment-metadata") ; -static auto stream_image_array_scaling = PipelineBuilder("stream-image-array-scaling", "Image Array Scaling") - .withSource() - .withSink() +static auto stream_image_array_scaling = PipelineBuilder("stream-image-array-scaling", "Image Array Scaling") + .withSource() + .withSink() .withNode("scale") ; -static auto stream_image_array_split = PipelineBuilder("stream-image-array-split", "Image Array split") - .withSource() - .withSink() +static auto stream_image_array_split = PipelineBuilder("stream-image-array-split", "Image Array split") + .withSource() + .withSink() .withNode("split") ; -static auto stream_complex_to_float = PipelineBuilder("stream-complex-to-float", "Complex to Float") - .withSource() - .withSink() +static auto stream_complex_to_float = PipelineBuilder("stream-complex-to-float", "Complex to Float") + .withSource() + .withSink() .withNode("complex-to-float") ; -static auto stream_float_to_fixed_point = PipelineBuilder("stream-float-to-fixed-point", "Float to Fixed-Point") - .withSource() - .withSink() +static auto stream_float_to_fixed_point = PipelineBuilder("stream-float-to-fixed-point", "Float to Fixed-Point") + .withSource() + .withSink() .withNode("convert") ; diff --git a/apps/pingvin/pipeline_registry.h b/apps/pingvin/pipelines/registry.h similarity index 82% rename from apps/pingvin/pipeline_registry.h rename to apps/pingvin/pipelines/registry.h index a6f3269f..fc88776f 100644 --- a/apps/pingvin/pipeline_registry.h +++ b/apps/pingvin/pipelines/registry.h @@ -2,19 +2,19 @@ #include "Pipeline.h" -#include "pipelines/noise.h" -#include "pipelines/grappa.h" -#include "pipelines/default.h" -#include "pipelines/epi.h" -#include "pipelines/cartesian_grappa.h" -#include "pipelines/cartesian_spirit.h" -#include "pipelines/grappa_epi.h" -#include "pipelines/cmr.h" -#include "pipelines/parallel_bypass.h" -#include "pipelines/streams.h" -#include "pipelines/denoise.h" - -#include "pipelines/file_search.h" +#include "mri/noise.h" +#include "mri/grappa.h" +#include "mri/default.h" +#include "mri/epi.h" +#include "mri/cartesian_grappa.h" +#include "mri/cartesian_spirit.h" +#include "mri/grappa_epi.h" +#include "mri/cmr.h" +#include "mri/parallel_bypass.h" +#include "mri/streams.h" +#include "mri/denoise.h" + +#include "file_search.h" namespace Pingvin { diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8adc70ea..6d439bd2 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,5 +1,4 @@ add_compile_options(-Wall -Werror) -add_subdirectory(parallel) configure_file(pingvin_config.in ${CMAKE_BINARY_DIR}/pingvin_config.h) @@ -11,6 +10,7 @@ add_library(pingvin_core SHARED ParallelStream.cpp MultiprocessStream.cpp PureStream.cpp + parallel/UnorderedMerge.cpp system_info.cpp io/from_string.cpp) @@ -19,7 +19,6 @@ set_target_properties(pingvin_core PROPERTIES SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_core - mrd::mrd pingvin_toolbox_cpucore Boost::boost Boost::filesystem @@ -49,7 +48,6 @@ install(FILES Message.h Message.hpp MPMCChannel.h - Context.h Source.h Sink.h Node.h @@ -67,6 +65,12 @@ install(FILES DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) +install(FILES + parallel/Branch.h + parallel/Merge.h + parallel/UnorderedMerge.h + DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH}/parallel COMPONENT main) + install(FILES io/from_string.h io/primitives.h diff --git a/core/Context.h b/core/Context.h deleted file mode 100644 index 7e311f66..00000000 --- a/core/Context.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include - - -namespace Gadgetron::Core { - - /** TODO: Move to MR-specific location */ - struct MrdContext { - - /** TODO: This Path is only used in TWO Gadgets, and it is only used to load Python files. - * These Gadgets can be updated to read the Python file paths from its own CLI parameters... - * - * Otherwise, the PINGVIN_HOME path can be queried using the `static get_gadgetron_home()` function. - */ - struct Paths { - std::filesystem::path pingvin_home; - }; - - mrd::Header header; - std::map env; - Paths paths; - }; - - - /** TODO: Delete */ - struct Context { - using Header = mrd::Header; - - struct Paths { - boost::filesystem::path gadgetron_home; - }; - - Header header; - Paths paths; - std::map parameters; - }; - - struct StreamContext : Context { - using Args = boost::program_options::variables_map; - - StreamContext( - mrd::Header header, - const Paths paths, - const Args args - ) : Context{ - std::move(header), - paths, - GetParameters(args) - }, - args{args} {} - - - Args args; - - private: - static std::map GetParameters(const boost::program_options::variables_map& args) { - std::map parameters; - if (args.count("parameter")) { - auto params = args["parameter"].as>>(); - for (auto &arg : params) { - parameters[arg.first] = arg.second; - } - } - return parameters; - } - - }; -} diff --git a/core/Node.h b/core/Node.h index bf2baf8e..c8c07a5b 100644 --- a/core/Node.h +++ b/core/Node.h @@ -2,8 +2,6 @@ #include "Parameters.h" #include "Channel.h" -#include "Context.h" -#include namespace po = boost::program_options; namespace Gadgetron::Core { @@ -48,12 +46,4 @@ namespace Gadgetron::Core { */ virtual void process(InputChannel& in, OutputChannel& out) = 0; }; - - /** TODO: Move to MR-specific location! */ - template class MRChannelGadget : public ChannelGadget { - public: - using ChannelGadget::ChannelGadget; - - MRChannelGadget(const MrdContext& context, const NodeParameters& parameters) {} - }; } \ No newline at end of file diff --git a/core/ParallelStream.cpp b/core/ParallelStream.cpp index fa33c5b7..d6da8b70 100644 --- a/core/ParallelStream.cpp +++ b/core/ParallelStream.cpp @@ -5,7 +5,6 @@ #include #include "Channel.h" -#include "Context.h" namespace { template diff --git a/core/ParallelStream.h b/core/ParallelStream.h index 5bd26d0f..b4107c71 100644 --- a/core/ParallelStream.h +++ b/core/ParallelStream.h @@ -7,9 +7,6 @@ #include "parallel/Branch.h" #include "parallel/Merge.h" -#include "Channel.h" -#include "Context.h" - namespace Gadgetron::Core { class ParallelStream : public Node { diff --git a/core/Pipeline.h b/core/Pipeline.h index 54a00214..20f13c09 100644 --- a/core/Pipeline.h +++ b/core/Pipeline.h @@ -6,11 +6,8 @@ #include namespace po = boost::program_options; -#include "mrd/binary/protocols.h" - #include "system_info.h" -#include "Channel.h" #include "Node.h" #include "Source.h" #include "Sink.h" @@ -459,7 +456,7 @@ struct PipelineBuilder : public IPipelineBuilder{ auto pb = std::make_shared>(*this); streambuilder_.append(pb); return *pb; - } + } po::options_description collect_options(void) override { po::options_description pipeline_desc(this->description_); diff --git a/core/PureGadget.h b/core/PureGadget.h index 7b0bcc83..618befd6 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -32,12 +32,4 @@ class PureGadget : public GenericPureGadget { virtual RETURN process_function(INPUT args) const = 0; }; - -/** TODO: Move to MR-specific location! */ -template -class MRPureGadget : public PureGadget { -public: - MRPureGadget(const MrdContext& context, const NodeParameters& parameters) {} -}; - } diff --git a/core/Sink.h b/core/Sink.h index 1569eea3..3e03e159 100644 --- a/core/Sink.h +++ b/core/Sink.h @@ -1,4 +1,6 @@ -#include "Node.h" +#pragma once + +#include "Channel.h" namespace Pingvin { @@ -7,62 +9,4 @@ struct ISink { virtual void produce_output(Gadgetron::Core::ChannelPair& output_channel) = 0; }; - -/** TODO: Move to MR-specific location! */ -struct MrdSink : public ISink { - MrdSink(std::ostream& output_stream, const Gadgetron::Core::MrdContext& ctx) - : mrd_writer_(output_stream) - { - mrd_writer_.WriteHeader(ctx.header); - } - - void produce_output(Gadgetron::Core::ChannelPair& output_channel) override - { - while (true) { - try { - auto message = output_channel.input.pop(); - - using namespace Gadgetron::Core; - - 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 Gadgetron::Core::ChannelClosed& exc) { - break; - } - } - - mrd_writer_.EndData(); - mrd_writer_.Close(); - } - -private: - mrd::binary::MrdWriter mrd_writer_; -}; - - } \ No newline at end of file diff --git a/core/Source.h b/core/Source.h index 349ff83d..02bc973c 100644 --- a/core/Source.h +++ b/core/Source.h @@ -1,4 +1,6 @@ -#include "Node.h" +#pragma once + +#include "Channel.h" namespace Pingvin { @@ -12,47 +14,4 @@ struct Source : public ISource { virtual void initContext(CTX&) = 0; }; - -/** TODO: Move to MR-specific location! */ -struct MrdSource : public Source { - MrdSource(std::istream& input_stream): mrd_reader_(input_stream) {} - - void initContext(Gadgetron::Core::MrdContext& ctx) override { - std::optional hdr; - mrd_reader_.ReadHeader(hdr); - if (!hdr.has_value()) { - GADGET_THROW("Failed to read MRD header"); - } - - ctx.header = hdr.value(); - - for (char** raw = environ; *raw; ++raw) { - std::string s(*raw); - auto pos = s.find('='); - if (pos != std::string::npos) { - ctx.env[s.substr(0, pos)] = s.substr(pos + 1); - } - } - - ctx.paths.pingvin_home = Pingvin::Main::get_pingvin_home(); - } - - void consume_input(Gadgetron::Core::ChannelPair& input_channel) override - { - mrd::StreamItem stream_item; - while (mrd_reader_.ReadData(stream_item)) { - std::visit([&](auto&& arg) { - Gadgetron::Core::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); - } - -private: - mrd::binary::MrdReader mrd_reader_; -}; - - } \ No newline at end of file diff --git a/core/Stream.h b/core/Stream.h index 60f786ea..88e133f4 100644 --- a/core/Stream.h +++ b/core/Stream.h @@ -5,9 +5,6 @@ #include "Node.h" -#include "Channel.h" -#include "Context.h" - namespace Gadgetron::Core { class Stream : public Node { diff --git a/core/parallel/Branch.h b/core/parallel/Branch.h index c3c1382b..95318db6 100644 --- a/core/parallel/Branch.h +++ b/core/parallel/Branch.h @@ -1,11 +1,8 @@ #pragma once #include -#include -#include #include "Channel.h" -#include "Context.h" #include "Parameters.h" namespace Gadgetron::Core::Parallel { @@ -40,12 +37,4 @@ namespace Gadgetron::Core::Parallel { virtual void process(InputChannel &, std::map) = 0; }; - /** TODO: Move to MR-specific location! */ - template class MRBranch : public TypedBranch { - public: - using TypedBranch::TypedBranch; - - MRBranch(const MrdContext& context, const NodeParameters& parameters) {} - }; - } \ No newline at end of file diff --git a/core/parallel/CMakeLists.txt b/core/parallel/CMakeLists.txt deleted file mode 100644 index f57a27a2..00000000 --- a/core/parallel/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -add_library(pingvin_core_parallel SHARED - Branch.h - Merge.h - Fanout.h - UnorderedMerge.h - UnorderedMerge.cpp) - -target_link_libraries(pingvin_core_parallel - pingvin_core) - -set_target_properties(pingvin_core_parallel PROPERTIES - VERSION ${PINGVIN_VERSION_STRING} - SOVERSION ${PINGVIN_SOVERSION}) - -install(TARGETS pingvin_core_parallel - EXPORT pingvin-export - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - COMPONENT main -) - -install(FILES - Branch.h - Merge.h - Fanout.h - UnorderedMerge.h - DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) \ No newline at end of file diff --git a/core/parallel/Merge.h b/core/parallel/Merge.h index 66953a93..99b2cd43 100644 --- a/core/parallel/Merge.h +++ b/core/parallel/Merge.h @@ -1,11 +1,8 @@ #pragma once #include -#include -#include #include "Channel.h" -#include "Context.h" #include "Parameters.h" namespace Gadgetron::Core::Parallel { @@ -19,12 +16,4 @@ namespace Gadgetron::Core::Parallel { virtual ~Merge() = default; virtual void process(std::map, OutputChannel) = 0; }; - - /** TODO: Move to MR-specific location! */ - class MRMerge : public Merge { - public: - using Merge::Merge; - - MRMerge(const MrdContext& context, const NodeParameters& parameters) {} - }; } \ No newline at end of file diff --git a/core/parallel/UnorderedMerge.h b/core/parallel/UnorderedMerge.h index 4c2067b2..4e55bf30 100644 --- a/core/parallel/UnorderedMerge.h +++ b/core/parallel/UnorderedMerge.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - #include "Merge.h" namespace Gadgetron::Core::Parallel { diff --git a/gadgets/cmr/CMakeLists.txt b/gadgets/cmr/CMakeLists.txt index 1445d6b9..fda373d0 100644 --- a/gadgets/cmr/CMakeLists.txt +++ b/gadgets/cmr/CMakeLists.txt @@ -75,7 +75,7 @@ add_library(pingvin_cmr SHARED set_target_properties(pingvin_cmr PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_cmr - pingvin_core + pingvin_mri pingvin_mricore pingvin_toolbox_log pingvin_toolbox_cpucore diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp index 00ac44e1..8056d8af 100644 --- a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp +++ b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp @@ -6,7 +6,7 @@ namespace Gadgetron { static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; - CmrCartesianKSpaceBinningCineGadget::CmrCartesianKSpaceBinningCineGadget(const Core::MrdContext &context, const Parameters& params) + CmrCartesianKSpaceBinningCineGadget::CmrCartesianKSpaceBinningCineGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) , send_out_multiple_series_by_slice_(false) diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h index 7db7e91a..1b5b2fac 100644 --- a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h +++ b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h @@ -35,30 +35,30 @@ namespace Gadgetron { register_parameter("use-multiple-channel-recon", &use_multiple_channel_recon, "Whether to perform multi-channel recon in the raw data step"); register_parameter("use-nonlinear-binning-recon", &use_nonlinear_binning_recon, "Whether to non-linear recon in the binning step"); register_parameter("number-of-output-phases", &number_of_output_phases, "Number of output phases after binning"); - + register_parameter("send-out-raw", &send_out_raw, "Whether to set out raw images"); register_parameter("send-out-multiple-series-by-slice", &send_out_multiple_series_by_slice, "Whether to set out binning images as multiple series"); - + register_parameter("arrhythmia-rejector-factor", &arrhythmia_rejector_factor, "If a heart beat RR is not in the range of [ (1-arrhythmiaRejectorFactor)*meanRR (1+arrhythmiaRejectorFactor)*meanRR], it will be rejected"); - + register_parameter("grappa-kSize-RO", &grappa_kSize_RO, "Raw data recon, kernel size RO"); register_parameter("grappa-kSize-E1", &grappa_kSize_E1, "Raw data recon, kernel size E1"); register_parameter("grappa-reg-lamda", &grappa_reg_lamda, "Raw data recon, kernel calibration regularization"); - + register_parameter("downstream-coil-compression-num-modesKept", &downstream_coil_compression_num_modesKept, "Number of modes kept for down stream coil compression in raw recon step"); register_parameter("downstream-coil-compression-thres", &downstream_coil_compression_thres, "Threshold for determining number of kept modes in the down stream coil compression"); - + register_parameter("respiratory-navigator-moco-reg-strength", &respiratory_navigator_moco_reg_strength, "Regularization strength of respiratory moco"); register_multitoken("respiratory-navigator-moco-iters", &respiratory_navigator_moco_iters, "Number of iterations for respiratory moco"); - + register_parameter("kspace-binning-interpolate-heart-beat-images", &kspace_binning_interpolate_heart_beat_images, "Whether to interpolate best heart beat images"); register_parameter("kspace-binning-navigator-acceptance-window", &kspace_binning_navigator_acceptance_window, "Respiratory navigator acceptance window"); register_parameter("kspace-binning-max-temporal-window", &kspace_binning_max_temporal_window, "Maximally allowed temporal window ratio for binned kspace"); register_parameter("kspace-binning-minimal-cardiac-phase-width", &kspace_binning_minimal_cardiac_phase_width, "Allowed minimal temporal window for binned kspace, in ms"); - + register_parameter("kspace-binning-moco-reg-strength", &kspace_binning_moco_reg_strength, "Regularization strength of binning moco"); register_multitoken("kspace-binning-moco-iters", &kspace_binning_moco_iters, "Number of iterations for binning moco"); - + register_parameter("kspace-binning-kSize-RO", &kspace_binning_kSize_RO, "Binned kspace recon, kernel size RO"); register_parameter("kspace-binning-kSize-E1", &kspace_binning_kSize_E1, "Binned kspace recon, kernel size E1"); register_parameter("kspace-binning-reg-lamda", &kspace_binning_reg_lamda, "Binned kspace recon, kernel calibration regularization"); @@ -72,7 +72,7 @@ namespace Gadgetron { register_parameter("kspace-binning-nonlinear-reg-use-coil-sen-map", &kspace_binning_nonlinear_reg_use_coil_sen_map, "Binned kspace recon, whether to use coil map, non-linear recon"); register_parameter("kspace-binning-nonlinear-reg-with-approx-coeff", &kspace_binning_nonlinear_reg_with_approx_coeff, "Binned kspace recon, whether to keep approximal coefficients, non-linear recon"); register_parameter("kspace-binning-nonlinear-reg-wav-name", &kspace_binning_nonlinear_reg_wav_name, "Binned kspace recon, wavelet name, non-linear recon"); - + register_parameter("time-tick", &time_tick, "Time tick in ms"); register_multitoken("kspace-binning-processed-slices", &kspace_binning_processed_slices, "If set, these slices will be processed"); } @@ -130,7 +130,7 @@ namespace Gadgetron { std::vector kspace_binning_processed_slices = {}; }; - CmrCartesianKSpaceBinningCineGadget(const Core::MrdContext &context, const Parameters& params); + CmrCartesianKSpaceBinningCineGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/cmr/CmrParametricMappingGadget.cpp b/gadgets/cmr/CmrParametricMappingGadget.cpp index 71d80877..4a54a722 100644 --- a/gadgets/cmr/CmrParametricMappingGadget.cpp +++ b/gadgets/cmr/CmrParametricMappingGadget.cpp @@ -12,7 +12,7 @@ namespace Gadgetron { - CmrParametricMappingGadget::CmrParametricMappingGadget(const Core::MrdContext &context, const Parameters& params) + CmrParametricMappingGadget::CmrParametricMappingGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/cmr/CmrParametricMappingGadget.h b/gadgets/cmr/CmrParametricMappingGadget.h index e246ae46..83d3d3cf 100644 --- a/gadgets/cmr/CmrParametricMappingGadget.h +++ b/gadgets/cmr/CmrParametricMappingGadget.h @@ -79,7 +79,7 @@ namespace Gadgetron { bool mapping_with_masking = true; }; - CmrParametricMappingGadget(const Core::MrdContext &context, const Parameters& params); + CmrParametricMappingGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp index 5ae60bfc..5357188a 100644 --- a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp @@ -12,7 +12,7 @@ namespace Gadgetron { - CmrParametricT1SRMappingGadget::CmrParametricT1SRMappingGadget(const Core::MrdContext& context, const Parameters& params) + CmrParametricT1SRMappingGadget::CmrParametricT1SRMappingGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.h b/gadgets/cmr/CmrParametricT1SRMappingGadget.h index a76bf230..fc582d5a 100644 --- a/gadgets/cmr/CmrParametricT1SRMappingGadget.h +++ b/gadgets/cmr/CmrParametricT1SRMappingGadget.h @@ -33,7 +33,7 @@ namespace Gadgetron { double anchor_TS = 10000; }; - CmrParametricT1SRMappingGadget(const Core::MrdContext& context, const Parameters& params); + CmrParametricT1SRMappingGadget(const Core::MRContext& context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.cpp b/gadgets/cmr/CmrParametricT2MappingGadget.cpp index dc808fbe..6aa721ea 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.cpp +++ b/gadgets/cmr/CmrParametricT2MappingGadget.cpp @@ -12,7 +12,7 @@ namespace Gadgetron { - CmrParametricT2MappingGadget::CmrParametricT2MappingGadget(const Core::MrdContext& context, const Parameters& params) + CmrParametricT2MappingGadget::CmrParametricT2MappingGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.h b/gadgets/cmr/CmrParametricT2MappingGadget.h index 0bbda7b3..c24233ac 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.h +++ b/gadgets/cmr/CmrParametricT2MappingGadget.h @@ -14,7 +14,7 @@ namespace Gadgetron { { public: typedef CmrParametricMappingGadget BaseClass; - + struct Parameters : public BaseClass::Parameters { Parameters(const std::string& prefix): BaseClass::Parameters(prefix, "T2 Mapping") { register_parameter("max-iter", &max_iter, "Maximal number of iterations"); @@ -27,7 +27,7 @@ namespace Gadgetron { double max_T2 = 4000; }; - CmrParametricT2MappingGadget(const Core::MrdContext& context, const Parameters& params); + CmrParametricT2MappingGadget(const Core::MRContext& context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp index ef3fd0d1..fd7aedac 100644 --- a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp +++ b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp @@ -79,7 +79,7 @@ namespace Gadgetron { // ---------------------------------------------------- - CmrRealTimeLAXCineAIAnalysisGadget::CmrRealTimeLAXCineAIAnalysisGadget(const Core::MrdContext& context, const Parameters& params) + CmrRealTimeLAXCineAIAnalysisGadget::CmrRealTimeLAXCineAIAnalysisGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h index d926a881..fb427a77 100644 --- a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h +++ b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h @@ -40,7 +40,7 @@ namespace Gadgetron { std::string model_dest = "cmr_lax_landmark_detection"; }; - CmrRealTimeLAXCineAIAnalysisGadget(const Core::MrdContext &context, const Parameters& params); + CmrRealTimeLAXCineAIAnalysisGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp index 55aa9029..35820486 100644 --- a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp +++ b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.cpp @@ -138,7 +138,7 @@ PureCmrCartesianKSpaceBinningCineGadget::BinningResult PureCmrCartesianKSpaceBin } PureCmrCartesianKSpaceBinningCineGadget::PureCmrCartesianKSpaceBinningCineGadget( - const Core::MrdContext& context, const Parameters& params) + const Core::MRContext& context, const Parameters& params) : MRPureGadget(context, params) , params_(params) , verbose(params_.verbose) diff --git a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h index 1aa267cf..fcf63e0a 100644 --- a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h +++ b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h @@ -1,10 +1,6 @@ -// -// Created by dchansen on 2/21/19. -// - #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "cmr_kspace_binning.h" #include "ImageArraySendMixin.h" @@ -45,7 +41,7 @@ namespace Gadgetron { "Regularization strength of binning moco"); register_multitoken("kspace-binning-moco-iters", &kspace_binning_moco_iters, "Number of iterations for binning moco"); - register_parameter("kspace-binning-kSize-RO", &kspace_binning_kSize_RO, "Binned kspace recon, kernel size RO"); + register_parameter("kspace-binning-kSize-RO", &kspace_binning_kSize_RO, "Binned kspace recon, kernel size RO"); register_parameter("kspace-binning-kSize-E1", &kspace_binning_kSize_E1, "Binned kspace recon, kernel size E1"); register_parameter("kspace-binning-reg-lamda", &kspace_binning_reg_lamda, "Binned kspace recon, kernel calibration regularization"); register_parameter("kspace-binning-linear-iter-max", &kspace_binning_linear_iter_max, @@ -113,7 +109,7 @@ namespace Gadgetron { float time_tick = 2.5f; }; - PureCmrCartesianKSpaceBinningCineGadget(const Core::MrdContext& context, const Parameters& params); + PureCmrCartesianKSpaceBinningCineGadget(const Core::MRContext& context, const Parameters& params); mrd::ImageArray process_function(mrd::ReconData args) const override; diff --git a/gadgets/debugging/CMakeLists.txt b/gadgets/debugging/CMakeLists.txt index b17a4dfa..a128571d 100644 --- a/gadgets/debugging/CMakeLists.txt +++ b/gadgets/debugging/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(${HDF5_INCLUDE_DIRS}) - set(pingvin_debugging_header_files PseudoReplicatorGadget.h RateLimitGadget.h @@ -19,7 +17,7 @@ add_library(pingvin_debugging SHARED set_target_properties(pingvin_debugging PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) -target_link_libraries(pingvin_debugging pingvin_core) +target_link_libraries(pingvin_debugging pingvin_mri) target_include_directories(pingvin_debugging PUBLIC diff --git a/gadgets/debugging/PseudoReplicatorGadget.h b/gadgets/debugging/PseudoReplicatorGadget.h index a7a9c0e6..3afced4a 100644 --- a/gadgets/debugging/PseudoReplicatorGadget.h +++ b/gadgets/debugging/PseudoReplicatorGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" namespace Gadgetron { @@ -15,7 +15,7 @@ class PseudoReplicatorGadget : public Core::MRChannelGadget int repetitions = 10; }; - PseudoReplicatorGadget(const Core::MrdContext& context, const Parameters& params) + PseudoReplicatorGadget(const Core::MRContext& context, const Parameters& params) : MRChannelGadget(context, params) , params_(params) { } diff --git a/gadgets/debugging/RateLimitGadget.cpp b/gadgets/debugging/RateLimitGadget.cpp index 2cea7205..c8120841 100644 --- a/gadgets/debugging/RateLimitGadget.cpp +++ b/gadgets/debugging/RateLimitGadget.cpp @@ -5,7 +5,7 @@ namespace Gadgetron { -RateLimitGadget::RateLimitGadget(const Core::MrdContext& context, const Parameters& params) +RateLimitGadget::RateLimitGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , params_(params) { diff --git a/gadgets/debugging/RateLimitGadget.h b/gadgets/debugging/RateLimitGadget.h index 917fb485..476113e0 100644 --- a/gadgets/debugging/RateLimitGadget.h +++ b/gadgets/debugging/RateLimitGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" namespace Gadgetron{ @@ -16,7 +16,7 @@ namespace Gadgetron{ int sleep_time_int = 0; }; - RateLimitGadget(const Core::MrdContext& context, const Parameters& params); + RateLimitGadget(const Core::MRContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp index bd12a9f7..a0d23325 100644 --- a/gadgets/debugging/WhiteNoiseInjectorGadget.cpp +++ b/gadgets/debugging/WhiteNoiseInjectorGadget.cpp @@ -79,7 +79,7 @@ inline void RandNormGenerator::gen(hoNDArray< std::complex >& randNum) } } -WhiteNoiseInjectorGadget::WhiteNoiseInjectorGadget(const Core::MrdContext& context, const Parameters& params) +WhiteNoiseInjectorGadget::WhiteNoiseInjectorGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , params_(params) , acceFactorE1_(1), acceFactorE2_(1) diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.h b/gadgets/debugging/WhiteNoiseInjectorGadget.h index bb6921b7..72809f34 100644 --- a/gadgets/debugging/WhiteNoiseInjectorGadget.h +++ b/gadgets/debugging/WhiteNoiseInjectorGadget.h @@ -1,7 +1,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -53,7 +53,7 @@ class WhiteNoiseInjectorGadget : public Core::MRChannelGadget bool add_noise_ref_ = false; }; - WhiteNoiseInjectorGadget(const Core::MrdContext& context, const Parameters& params); + WhiteNoiseInjectorGadget(const Core::MRContext& context, const Parameters& params); ~WhiteNoiseInjectorGadget() override; protected: diff --git a/gadgets/epi/CMakeLists.txt b/gadgets/epi/CMakeLists.txt index 7f7f6a93..ee5427b3 100644 --- a/gadgets/epi/CMakeLists.txt +++ b/gadgets/epi/CMakeLists.txt @@ -11,9 +11,8 @@ add_library(pingvin_epi SHARED set_target_properties(pingvin_epi PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) -target_link_libraries( - pingvin_epi - pingvin_core +target_link_libraries(pingvin_epi + pingvin_mri pingvin_mricore pingvin_toolbox_cpucore pingvin_toolbox_cpufft diff --git a/gadgets/epi/CutXGadget.cpp b/gadgets/epi/CutXGadget.cpp index e3ea6921..cbd703d6 100644 --- a/gadgets/epi/CutXGadget.cpp +++ b/gadgets/epi/CutXGadget.cpp @@ -4,7 +4,7 @@ namespace Gadgetron{ - CutXGadget::CutXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters) + CutXGadget::CutXGadget(const Core::MRContext& context, const Core::NodeParameters& parameters) : CutXGadget::MRChannelGadget(context, parameters) { auto& h = context.header; diff --git a/gadgets/epi/CutXGadget.h b/gadgets/epi/CutXGadget.h index bd9a961d..4ac08cef 100644 --- a/gadgets/epi/CutXGadget.h +++ b/gadgets/epi/CutXGadget.h @@ -1,7 +1,6 @@ -#ifndef CutXGADGET_H -#define CutXGADGET_H +#pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -11,7 +10,7 @@ namespace Gadgetron{ class CutXGadget : public Core::MRChannelGadget { public: - CutXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); + CutXGadget(const Core::MRContext& context, const Core::NodeParameters& parameters); protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; @@ -23,5 +22,5 @@ namespace Gadgetron{ size_t cutNx_; }; -} -#endif //CutXGADGET_H + +} \ No newline at end of file diff --git a/gadgets/epi/EPICorrGadget.cpp b/gadgets/epi/EPICorrGadget.cpp index 5a31690a..4a9ed5be 100644 --- a/gadgets/epi/EPICorrGadget.cpp +++ b/gadgets/epi/EPICorrGadget.cpp @@ -13,7 +13,7 @@ namespace Gadgetron { #define OE_PHASE_CORR_POLY_ORDER 4 - EPICorrGadget::EPICorrGadget(const Core::MrdContext& context, const Parameters& params) + EPICorrGadget::EPICorrGadget(const Core::MRContext& context, const Parameters& params) : EPICorrGadget::MRChannelGadget(context, params) , parameters_(params) , corrComputed_(false), navNumber_(-1), epiEchoNumber_(-1) @@ -178,7 +178,7 @@ namespace Gadgetron { // mean of the reference navigator (across RO and channels): std::complex navMean = mean(vectorise(navdata_.slice(parameters_.referenceNavigatorNumber))); - + // for clarity, we'll use the following when filtering navigator parameters: size_t set(hdr.idx.set.value_or(0)), slc(hdr.idx.slice.value_or(0)), exc(0); if (parameters_.navigatorParameterFilterLength > 1) { diff --git a/gadgets/epi/EPICorrGadget.h b/gadgets/epi/EPICorrGadget.h index b8f8f043..97d2ff8a 100644 --- a/gadgets/epi/EPICorrGadget.h +++ b/gadgets/epi/EPICorrGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoArmadillo.h" @@ -35,7 +35,7 @@ namespace Gadgetron { } }; - EPICorrGadget(const Core::MrdContext& context, const Parameters& parameters); + EPICorrGadget(const Core::MRContext& context, const Parameters& parameters); protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; @@ -58,7 +58,7 @@ namespace Gadgetron { // variables for navigator parameter computation // -------------------------------------------------- - float RefNav_to_Echo0_time_ES_; // Time (in echo-spacing uints) between the reference navigator and the first RO echo (used for B0 correction) + float RefNav_to_Echo0_time_ES_; // Time (in echo-spacing uints) between the reference navigator and the first RO echo (used for B0 correction) arma::cx_fvec corrB0_; // B0 correction arma::cx_fvec corrpos_; // Odd-Even correction -- positive readouts arma::cx_fvec corrneg_; // Odd-Even correction -- negative readouts diff --git a/gadgets/epi/EPIPackNavigatorGadget.cpp b/gadgets/epi/EPIPackNavigatorGadget.cpp index 886cd212..6052713f 100644 --- a/gadgets/epi/EPIPackNavigatorGadget.cpp +++ b/gadgets/epi/EPIPackNavigatorGadget.cpp @@ -2,7 +2,7 @@ namespace Gadgetron { -EPIPackNavigatorGadget::EPIPackNavigatorGadget(const Core::MrdContext& context, const Core::NodeParameters& params) +EPIPackNavigatorGadget::EPIPackNavigatorGadget(const Core::MRContext& context, const Core::NodeParameters& params) : EPIPackNavigatorGadget::MRChannelGadget(context, params) { auto& h = context.header; diff --git a/gadgets/epi/EPIPackNavigatorGadget.h b/gadgets/epi/EPIPackNavigatorGadget.h index 91d2442b..83a8f278 100644 --- a/gadgets/epi/EPIPackNavigatorGadget.h +++ b/gadgets/epi/EPIPackNavigatorGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoArmadillo.h" @@ -10,7 +10,7 @@ namespace Gadgetron{ class EPIPackNavigatorGadget : public Core::MRChannelGadget { public: - EPIPackNavigatorGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); + EPIPackNavigatorGadget(const Core::MRContext& context, const Core::NodeParameters& parameters); protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; diff --git a/gadgets/epi/EPIReconXGadget.cpp b/gadgets/epi/EPIReconXGadget.cpp index dc3fd465..f8624bf7 100644 --- a/gadgets/epi/EPIReconXGadget.cpp +++ b/gadgets/epi/EPIReconXGadget.cpp @@ -8,7 +8,7 @@ namespace Gadgetron { - EPIReconXGadget::EPIReconXGadget(const Core::MrdContext& context, const Core::NodeParameters& params) + EPIReconXGadget::EPIReconXGadget(const Core::MRContext& context, const Core::NodeParameters& params) : EPIReconXGadget::MRChannelGadget(context, params) { auto& h = context.header; diff --git a/gadgets/epi/EPIReconXGadget.h b/gadgets/epi/EPIReconXGadget.h index 9a7e542d..e6713ed5 100644 --- a/gadgets/epi/EPIReconXGadget.h +++ b/gadgets/epi/EPIReconXGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "EPIReconXObjectTrapezoid.h" #include "EPIReconXObjectFlat.h" @@ -8,7 +8,7 @@ namespace Gadgetron { class EPIReconXGadget : public Core::MRChannelGadget { public: - EPIReconXGadget(const Core::MrdContext& context, const Core::NodeParameters& parameters); + EPIReconXGadget(const Core::MRContext& context, const Core::NodeParameters& parameters); protected: void process(Core::InputChannel& input, Core::OutputChannel& out) override; diff --git a/gadgets/epi/FFTXGadget.h b/gadgets/epi/FFTXGadget.h index 851466d5..9acbb4fe 100644 --- a/gadgets/epi/FFTXGadget.h +++ b/gadgets/epi/FFTXGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include diff --git a/gadgets/epi/OneEncodingGadget.h b/gadgets/epi/OneEncodingGadget.h index 4d7c73f6..3ca168dc 100644 --- a/gadgets/epi/OneEncodingGadget.h +++ b/gadgets/epi/OneEncodingGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" namespace Gadgetron { diff --git a/gadgets/examples/AcquisitionWaveformBranch.h b/gadgets/examples/AcquisitionWaveformBranch.h index b06a6b89..1a13d545 100644 --- a/gadgets/examples/AcquisitionWaveformBranch.h +++ b/gadgets/examples/AcquisitionWaveformBranch.h @@ -1,6 +1,6 @@ #pragma once -#include "parallel/Branch.h" +#include "MRParallel.h" namespace Gadgetron::Examples { @@ -8,7 +8,7 @@ namespace Gadgetron::Examples { class AcquisitionWaveformBranch : public Core::Parallel::MRBranch { public: - AcquisitionWaveformBranch(const Core::MrdContext &context, const Core::NodeParameters ¶ms) + AcquisitionWaveformBranch(const Core::MRContext &context, const Core::NodeParameters ¶ms) : MRBranch(context, params) {} diff --git a/gadgets/examples/CMakeLists.txt b/gadgets/examples/CMakeLists.txt index 1a9665f0..dd7ae815 100644 --- a/gadgets/examples/CMakeLists.txt +++ b/gadgets/examples/CMakeLists.txt @@ -13,9 +13,7 @@ set_target_properties(pingvin_examples PROPERTIES SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_examples - pingvin_core - pingvin_core_parallel - pingvin_mricore + pingvin_mri pingvin_toolbox_cpucore) install(TARGETS pingvin_examples diff --git a/gadgets/examples/ImageInverter.h b/gadgets/examples/ImageInverter.h index 0e67f278..4fa72e9c 100644 --- a/gadgets/examples/ImageInverter.h +++ b/gadgets/examples/ImageInverter.h @@ -1,6 +1,6 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" namespace Gadgetron::Examples { class ImageInverter : public Core::MRPureGadget { diff --git a/gadgets/examples/ImageLayerer.cpp b/gadgets/examples/ImageLayerer.cpp index 1e2b12be..7aadaf3e 100644 --- a/gadgets/examples/ImageLayerer.cpp +++ b/gadgets/examples/ImageLayerer.cpp @@ -5,8 +5,6 @@ #include "hoNDArray_math.h" #include "hoNDArray_utils.h" -#include "mri_core_utility.h" - using namespace Gadgetron; namespace { diff --git a/gadgets/examples/ImageLayerer.h b/gadgets/examples/ImageLayerer.h index d8fcd056..daa8f894 100644 --- a/gadgets/examples/ImageLayerer.h +++ b/gadgets/examples/ImageLayerer.h @@ -1,13 +1,12 @@ #pragma once -#include "Node.h" -#include "parallel/Merge.h" +#include "MRParallel.h" namespace Gadgetron::Examples { class ImageLayerer : public Core::Parallel::MRMerge { public: - ImageLayerer(const Core::MrdContext &context, const Core::NodeParameters ¶ms) + ImageLayerer(const Core::MRContext &context, const Core::NodeParameters ¶ms) : MRMerge(context, params) {} diff --git a/gadgets/grappa/AcquisitionFanout.h b/gadgets/grappa/AcquisitionFanout.h index 198c1fdc..8fc001b8 100644 --- a/gadgets/grappa/AcquisitionFanout.h +++ b/gadgets/grappa/AcquisitionFanout.h @@ -2,7 +2,7 @@ #include "SliceAccumulator.h" -#include "parallel/Fanout.h" +#include "MRParallel.h" namespace Gadgetron::Grappa { using AcquisitionFanout = Core::Parallel::Fanout; diff --git a/gadgets/grappa/CMakeLists.txt b/gadgets/grappa/CMakeLists.txt index bf0c135d..c16e73f4 100644 --- a/gadgets/grappa/CMakeLists.txt +++ b/gadgets/grappa/CMakeLists.txt @@ -18,8 +18,7 @@ add_library(pingvin_grappa SHARED ${RTGRAPPA_SOURCES}) set_target_properties(pingvin_grappa PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_grappa - pingvin_core - pingvin_core_parallel + pingvin_mri pingvin_mricore pingvin_toolbox_cpucore pingvin_toolbox_cpucore_math diff --git a/gadgets/grappa/ImageAccumulator.h b/gadgets/grappa/ImageAccumulator.h index 4a87976c..3d1afc72 100644 --- a/gadgets/grappa/ImageAccumulator.h +++ b/gadgets/grappa/ImageAccumulator.h @@ -3,14 +3,13 @@ #include "SliceAccumulator.h" #include "common/AcquisitionBuffer.h" -#include "Channel.h" -#include "Node.h" +#include "MRNode.h" namespace Gadgetron::Grappa { class ImageAccumulator : public Core::MRChannelGadget { public: - ImageAccumulator(const Core::MrdContext &context, const Core::NodeParameters& params) + ImageAccumulator(const Core::MRContext &context, const Core::NodeParameters& params) : Core::MRChannelGadget(context, params) , buffer(context.header) {} diff --git a/gadgets/grappa/SliceAccumulator.cpp b/gadgets/grappa/SliceAccumulator.cpp index 6bea8eeb..16e17d1d 100644 --- a/gadgets/grappa/SliceAccumulator.cpp +++ b/gadgets/grappa/SliceAccumulator.cpp @@ -1,8 +1,5 @@ #include "SliceAccumulator.h" -#include "Context.h" -#include "Channel.h" - #include "hoNDArray.h" namespace { diff --git a/gadgets/grappa/SliceAccumulator.h b/gadgets/grappa/SliceAccumulator.h index a060aa2f..f0a8a655 100644 --- a/gadgets/grappa/SliceAccumulator.h +++ b/gadgets/grappa/SliceAccumulator.h @@ -1,8 +1,6 @@ #pragma once -#include - -#include "Node.h" +#include "MRNode.h" namespace Gadgetron::Grappa { diff --git a/gadgets/grappa/Unmixing.h b/gadgets/grappa/Unmixing.h index 0ce3b5d2..d0c7c353 100644 --- a/gadgets/grappa/Unmixing.h +++ b/gadgets/grappa/Unmixing.h @@ -1,10 +1,6 @@ #pragma once -#include -#include - -#include "parallel/Merge.h" -#include "Channel.h" +#include "MRParallel.h" namespace Gadgetron::Grappa { @@ -41,7 +37,7 @@ namespace Gadgetron::Grappa { float unmixing_scale = 1.0; }; - Unmixing(const Core::MrdContext &context, const Parameters& params) + Unmixing(const Core::MRContext &context, const Parameters& params) : Core::Parallel::MRMerge(context, params) , header_(context.header) , image_dimensions(create_output_image_dimensions(context.header)) diff --git a/gadgets/grappa/WeightsCalculator.h b/gadgets/grappa/WeightsCalculator.h index dca3a120..7ce75a9f 100644 --- a/gadgets/grappa/WeightsCalculator.h +++ b/gadgets/grappa/WeightsCalculator.h @@ -2,9 +2,7 @@ #include "SliceAccumulator.h" -#include "Context.h" -#include "Channel.h" -#include "Node.h" +#include "MRNode.h" #include "cpu/WeightsCore.h" #ifdef USE_CUDA @@ -35,7 +33,7 @@ namespace Gadgetron::Grappa { } }; - WeightsCalculator(const Core::MrdContext &context, const Parameters ¶ms) + WeightsCalculator(const Core::MRContext &context, const Parameters ¶ms) : Core::MRChannelGadget(context, params) , parameters_(params) , header_(context.header) diff --git a/gadgets/mri_core/AccumulatorGadget.cpp b/gadgets/mri_core/AccumulatorGadget.cpp index ec43079c..5d9092b7 100644 --- a/gadgets/mri_core/AccumulatorGadget.cpp +++ b/gadgets/mri_core/AccumulatorGadget.cpp @@ -20,7 +20,7 @@ int addPrePostZeros(size_t centre_column, size_t samples) { namespace Gadgetron { -AccumulatorGadget::AccumulatorGadget(const Core::MrdContext& context, const Parameters& params) +AccumulatorGadget::AccumulatorGadget(const Core::MRContext& context, const Parameters& params) : AccumulatorGadget::MRChannelGadget(context, params) , parameters_(params) , image_counter_(0) diff --git a/gadgets/mri_core/AccumulatorGadget.h b/gadgets/mri_core/AccumulatorGadget.h index 694b1750..fd0525a1 100644 --- a/gadgets/mri_core/AccumulatorGadget.h +++ b/gadgets/mri_core/AccumulatorGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" namespace Gadgetron{ @@ -21,7 +21,7 @@ namespace Gadgetron{ } }; - AccumulatorGadget(const Core::MrdContext& context, const Parameters& params); + AccumulatorGadget(const Core::MRContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; protected: diff --git a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h index e3157350..33e2e372 100644 --- a/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h +++ b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -49,7 +49,7 @@ namespace Gadgetron { unsigned long n_acquisitions_before_ongoing_trigger = 40; }; - AcquisitionAccumulateTriggerGadget(const Core::MrdContext& context, const Parameters& params) + AcquisitionAccumulateTriggerGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget>(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp index 49748f5c..9fd20fca 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp @@ -20,7 +20,7 @@ namespace { namespace Gadgetron { - AsymmetricEchoAdjustROGadget::AsymmetricEchoAdjustROGadget(const Core::MrdContext& context, const Parameters& params) + AsymmetricEchoAdjustROGadget::AsymmetricEchoAdjustROGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) { auto current_mrd_header = (context.header); diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h index ce1292de..b6cc938a 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h @@ -7,14 +7,14 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" namespace Gadgetron{ class AsymmetricEchoAdjustROGadget : public Core::MRChannelGadget { public: - AsymmetricEchoAdjustROGadget(const Core::MrdContext& context, const Parameters& params); + AsymmetricEchoAdjustROGadget(const Core::MRContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/AugmentImageMetadataGadget.h b/gadgets/mri_core/AugmentImageMetadataGadget.h index f1a2500f..4ee4d64f 100644 --- a/gadgets/mri_core/AugmentImageMetadataGadget.h +++ b/gadgets/mri_core/AugmentImageMetadataGadget.h @@ -6,7 +6,7 @@ #pragma once #include "hoNDArray.h" -#include "PureGadget.h" +#include "MRPureNode.h" namespace Gadgetron { diff --git a/gadgets/mri_core/AutoScaleGadget.h b/gadgets/mri_core/AutoScaleGadget.h index 4f410654..759dd416 100644 --- a/gadgets/mri_core/AutoScaleGadget.h +++ b/gadgets/mri_core/AutoScaleGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "hoNDArray_math.h" #include @@ -22,7 +22,7 @@ namespace Gadgetron{ } }; - AutoScaleGadget(const Core::MrdContext& context, const Parameters& params) + AutoScaleGadget(const Core::MRContext& context, const Parameters& params) : Core::MRPureGadget(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index cea668c1..0e067a3a 100644 --- a/gadgets/mri_core/BucketToBufferGadget.h +++ b/gadgets/mri_core/BucketToBufferGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -39,7 +39,7 @@ namespace Gadgetron { bool verbose = false; }; - BucketToBufferGadget(const Core::MrdContext& context, const Parameters& params) + BucketToBufferGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index ec023f6a..d0d8de67 100644 --- a/gadgets/mri_core/CMakeLists.txt +++ b/gadgets/mri_core/CMakeLists.txt @@ -31,15 +31,6 @@ set(pingvin_mricore_header_files ImageIndexGadget.h AccumulatorGadget.h ScaleGadget.h - - # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 - # CoilComputationGadget.h - # CropAndCombineGadget.h - # ImageAccumulatorGadget.h - # ImageFFTGadget.h - # ImageResizingGadget.h - # NoiseAdjustGadget_unoptimized.h - # PartialFourierAdjustROGadget.h ) set(pingvin_mricore_src_files @@ -74,15 +65,6 @@ set(pingvin_mricore_src_files ImageSortGadget.cpp MaxwellCorrectionGadget.cpp ScaleGadget.cpp - - # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 - # CoilComputationGadget.cpp - # CropAndCombineGadget.cpp - # ImageAccumulatorGadget.cpp - # ImageFFTGadget.cpp - # ImageResizingGadget.cpp - # NoiseAdjustGadget_unoptimized.cpp - # PartialFourierAdjustROGadget.cpp ) set(pingvin_mricore_config_files @@ -106,14 +88,6 @@ set(pingvin_mricore_generic_recon_gadgets_header_files generic_recon_gadgets/GenericReconEigenChannelGadget.h generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h generic_recon_gadgets/GenericReconStreamDef.h - - # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 - # generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.h - # generic_recon_gadgets/GenericReconCartesianFFTGadget.h - # generic_recon_gadgets/GenericReconImageToImageArrayGadget.h - # generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.h - # generic_recon_gadgets/GenericImageReconGadget.h - # generic_recon_gadgets/GenericImageReconArrayToImageGadget.h ) set(pingvin_mricore_generic_recon_gadgets_src_files @@ -130,14 +104,6 @@ set(pingvin_mricore_generic_recon_gadgets_src_files generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp generic_recon_gadgets/GenericReconEigenChannelGadget.cpp generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp - - # These Gadgets are NOT TESTED and have not been upgraded to MRD v2 - # generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.cpp - # generic_recon_gadgets/GenericReconCartesianFFTGadget.cpp - # generic_recon_gadgets/GenericReconImageToImageArrayGadget.cpp - # generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.cpp - # generic_recon_gadgets/GenericImageReconGadget.cpp - # generic_recon_gadgets/GenericImageReconArrayToImageGadget.cpp ) set(pingvin_mricore_generic_recon_gadgets_config_files @@ -188,7 +154,7 @@ add_library(pingvin_mricore SHARED set_target_properties(pingvin_mricore PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_mricore - pingvin_core + pingvin_mri pingvin_toolbox_log pingvin_toolbox_cpucore pingvin_toolbox_cpufft diff --git a/gadgets/mri_core/CoilReductionGadget.cpp b/gadgets/mri_core/CoilReductionGadget.cpp index cbefd9de..f2c2e9b4 100644 --- a/gadgets/mri_core/CoilReductionGadget.cpp +++ b/gadgets/mri_core/CoilReductionGadget.cpp @@ -2,7 +2,7 @@ namespace Gadgetron { -CoilReductionGadget::CoilReductionGadget(const Core::MrdContext& context, const Parameters& params) +CoilReductionGadget::CoilReductionGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/CoilReductionGadget.h b/gadgets/mri_core/CoilReductionGadget.h index 8d7e3689..fe027b6b 100644 --- a/gadgets/mri_core/CoilReductionGadget.h +++ b/gadgets/mri_core/CoilReductionGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include #include @@ -25,7 +25,7 @@ namespace Gadgetron{ }; - CoilReductionGadget(const Core::MrdContext& context, const Parameters& params); + CoilReductionGadget(const Core::MRContext& context, const Parameters& params); ~CoilReductionGadget() override = default; void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/CombineGadget.h b/gadgets/mri_core/CombineGadget.h index 77be3e3c..9954fe04 100644 --- a/gadgets/mri_core/CombineGadget.h +++ b/gadgets/mri_core/CombineGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "hoNDArray_math.h" namespace Gadgetron{ diff --git a/gadgets/mri_core/ComplexToFloatGadget.cpp b/gadgets/mri_core/ComplexToFloatGadget.cpp index fb02dec4..29dcf417 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.cpp +++ b/gadgets/mri_core/ComplexToFloatGadget.cpp @@ -11,7 +11,7 @@ namespace Gadgetron { -ComplexToFloatGadget::ComplexToFloatGadget(const Core::MrdContext& context, const Parameters& params) +ComplexToFloatGadget::ComplexToFloatGadget(const Core::MRContext& context, const Parameters& params) : MRPureGadget(context, params) { diff --git a/gadgets/mri_core/ComplexToFloatGadget.h b/gadgets/mri_core/ComplexToFloatGadget.h index 1fc2436d..d34c23c6 100644 --- a/gadgets/mri_core/ComplexToFloatGadget.h +++ b/gadgets/mri_core/ComplexToFloatGadget.h @@ -5,14 +5,14 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" namespace Gadgetron { class ComplexToFloatGadget: public Core::MRPureGadget,mrd::Image>> { public: - ComplexToFloatGadget(const Core::MrdContext&, const Parameters&); + ComplexToFloatGadget(const Core::MRContext&, const Parameters&); mrd::Image process_function(mrd::Image> args) const override; private: diff --git a/gadgets/mri_core/DenoiseGadget.h b/gadgets/mri_core/DenoiseGadget.h index 106b1161..b7aabb5a 100644 --- a/gadgets/mri_core/DenoiseGadget.h +++ b/gadgets/mri_core/DenoiseGadget.h @@ -1,9 +1,9 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" -#include "PureGadget.h" +#include "MRPureNode.h" #include namespace Gadgetron { @@ -27,7 +27,7 @@ namespace Gadgetron { } }; - DenoiseGadget(const Core::MrdContext& context, const Parameters& params) + DenoiseGadget(const Core::MRContext& context, const Parameters& params) : Core::MRPureGadget(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index cc20093f..f1717fb7 100644 --- a/gadgets/mri_core/ExtractGadget.cpp +++ b/gadgets/mri_core/ExtractGadget.cpp @@ -65,7 +65,7 @@ namespace Gadgetron { } } - ExtractGadget::ExtractGadget(const Core::MrdContext& context, const Parameters& params) + ExtractGadget::ExtractGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget>>(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index ae82b2fb..911f7051 100644 --- a/gadgets/mri_core/ExtractGadget.h +++ b/gadgets/mri_core/ExtractGadget.h @@ -1,5 +1,5 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -27,7 +27,7 @@ class ExtractGadget : public Core::MRChannelGadget>>& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/FFTGadget.h b/gadgets/mri_core/FFTGadget.h index c5911251..c07779cc 100644 --- a/gadgets/mri_core/FFTGadget.h +++ b/gadgets/mri_core/FFTGadget.h @@ -4,7 +4,7 @@ */ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -14,7 +14,7 @@ namespace Gadgetron{ class FFTGadget : public Core::MRChannelGadget { public: - FFTGadget(const Core::MrdContext& context, const Parameters& params) + FFTGadget(const Core::MRContext& context, const Parameters& params) : MRChannelGadget(context, params) , image_counter_(0) { } diff --git a/gadgets/mri_core/FlagTriggerGadget.cpp b/gadgets/mri_core/FlagTriggerGadget.cpp index 7ba83b1d..125b14f3 100644 --- a/gadgets/mri_core/FlagTriggerGadget.cpp +++ b/gadgets/mri_core/FlagTriggerGadget.cpp @@ -203,7 +203,7 @@ void FlagTriggerGadget::process(Core::InputChannel& in, Core:: } } -FlagTriggerGadget::FlagTriggerGadget(const Core::MrdContext& context, const Parameters& params) +FlagTriggerGadget::FlagTriggerGadget(const Core::MRContext& context, const Parameters& params) : MRChannelGadget(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/FlagTriggerGadget.h b/gadgets/mri_core/FlagTriggerGadget.h index d970ca2a..80f27f6f 100644 --- a/gadgets/mri_core/FlagTriggerGadget.h +++ b/gadgets/mri_core/FlagTriggerGadget.h @@ -2,7 +2,7 @@ // Created by david on 24/08/2020. // #pragma once -#include "Node.h" +#include "MRNode.h" namespace Gadgetron { @@ -62,7 +62,7 @@ class FlagTriggerGadget : public Core::MRChannelGadget { std::string trigger_flags = ""; }; - FlagTriggerGadget(const Core::MrdContext& context, const Parameters& params); + FlagTriggerGadget(const Core::MRContext& context, const Parameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/FloatToFixedPointGadget.h b/gadgets/mri_core/FloatToFixedPointGadget.h index 7f13023c..3ca18bd4 100644 --- a/gadgets/mri_core/FloatToFixedPointGadget.h +++ b/gadgets/mri_core/FloatToFixedPointGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" namespace Gadgetron { @@ -33,7 +33,7 @@ namespace Gadgetron float intensity_offset = 2048; }; - FloatToFixedPointGadget(const Core::MrdContext& context, const Parameters& params) + FloatToFixedPointGadget(const Core::MRContext& context, const Parameters& params) : MRChannelGadget(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp index 8e13db99..35115bc2 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp @@ -7,7 +7,7 @@ namespace Gadgetron { -FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::MrdContext& context, const Core::NodeParameters& params) +FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::MRContext& context, const Core::NodeParameters& params) : FlowPhaseSubtractionGadget::MRChannelGadget(context, params) { const auto e_limits = context.header.encoding[0].encoding_limits; diff --git a/gadgets/mri_core/FlowPhaseSubtractionGadget.h b/gadgets/mri_core/FlowPhaseSubtractionGadget.h index 002df671..034e6af4 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.h +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -11,7 +11,7 @@ namespace Gadgetron{ { public: - FlowPhaseSubtractionGadget(const Core::MrdContext& context, const Core::NodeParameters& params); + FlowPhaseSubtractionGadget(const Core::MRContext& context, const Core::NodeParameters& params); ~FlowPhaseSubtractionGadget() override = default; void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 8c45320e..c19f4cae 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.h +++ b/gadgets/mri_core/ImageArraySplitGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoNDArray_math.h" diff --git a/gadgets/mri_core/ImageIndexGadget.h b/gadgets/mri_core/ImageIndexGadget.h index c7161c3f..3bc9fdb4 100644 --- a/gadgets/mri_core/ImageIndexGadget.h +++ b/gadgets/mri_core/ImageIndexGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" namespace Gadgetron { diff --git a/gadgets/mri_core/ImageSortGadget.h b/gadgets/mri_core/ImageSortGadget.h index 0c023046..163121d6 100644 --- a/gadgets/mri_core/ImageSortGadget.h +++ b/gadgets/mri_core/ImageSortGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" namespace Gadgetron{ @@ -25,7 +25,7 @@ namespace Gadgetron{ } }; - ImageSortGadget(const Core::MrdContext& context, const Parameters& params) + ImageSortGadget(const Core::MRContext& context, const Parameters& params) : ImageSortGadget::MRChannelGadget(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/MaxwellCorrectionGadget.cpp b/gadgets/mri_core/MaxwellCorrectionGadget.cpp index 8a264322..0f3e4ee7 100644 --- a/gadgets/mri_core/MaxwellCorrectionGadget.cpp +++ b/gadgets/mri_core/MaxwellCorrectionGadget.cpp @@ -7,7 +7,7 @@ namespace Gadgetron { #endif // M_PI #define M_PI 3.14159265358979323846 -MaxwellCorrectionGadget::MaxwellCorrectionGadget(const Core::MrdContext& context, const Core::NodeParameters& params) +MaxwellCorrectionGadget::MaxwellCorrectionGadget(const Core::MRContext& context, const Core::NodeParameters& params) : MaxwellCorrectionGadget::MRChannelGadget(context, params) { maxwell_coefficients_present_ = false; diff --git a/gadgets/mri_core/MaxwellCorrectionGadget.h b/gadgets/mri_core/MaxwellCorrectionGadget.h index d72749ef..c10fcff2 100644 --- a/gadgets/mri_core/MaxwellCorrectionGadget.h +++ b/gadgets/mri_core/MaxwellCorrectionGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include #ifdef USE_OMP @@ -15,7 +15,7 @@ namespace Gadgetron { class MaxwellCorrectionGadget : public Core::MRChannelGadget>> { public: - MaxwellCorrectionGadget(const Core::MrdContext& context, const Core::NodeParameters& params); + MaxwellCorrectionGadget(const Core::MRContext& context, const Core::NodeParameters& params); ~MaxwellCorrectionGadget() override = default; void process(Core::InputChannel>>& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index 12d727f7..7f24d59b 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -22,8 +22,6 @@ using namespace std::string_literals; -namespace bf = boost::filesystem; -namespace po = boost::program_options; namespace Gadgetron { namespace { @@ -181,7 +179,7 @@ namespace Gadgetron { } } - NoiseAdjustGadget::NoiseAdjustGadget(const Core::MrdContext& context, const Parameters& params) + NoiseAdjustGadget::NoiseAdjustGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , parameters_(params) , receiver_noise_bandwidth{ bandwidth_from_header(context.header) } diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index 80f90aac..aeaa223c 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.h +++ b/gadgets/mri_core/NoiseAdjustGadget.h @@ -1,7 +1,7 @@ #pragma once #include "GadgetronTimer.h" -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -49,7 +49,7 @@ namespace Gadgetron { } }; - NoiseAdjustGadget(const Core::MrdContext& context, const Parameters& params); + NoiseAdjustGadget(const Core::MRContext& context, const Parameters& params); void process(Core::InputChannel& in, Core::OutputChannel& out) override; diff --git a/gadgets/mri_core/PCACoilGadget.cpp b/gadgets/mri_core/PCACoilGadget.cpp index 9cf8e7e9..020ad5c1 100644 --- a/gadgets/mri_core/PCACoilGadget.cpp +++ b/gadgets/mri_core/PCACoilGadget.cpp @@ -23,7 +23,7 @@ namespace Gadgetron { } } - PCACoilGadget::PCACoilGadget(const Core::MrdContext& context, const Parameters& params) + PCACoilGadget::PCACoilGadget(const Core::MRContext& context, const Parameters& params) : Core::MRChannelGadget(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/PCACoilGadget.h b/gadgets/mri_core/PCACoilGadget.h index 3de9772b..0548ecd4 100644 --- a/gadgets/mri_core/PCACoilGadget.h +++ b/gadgets/mri_core/PCACoilGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoNDKLT.h" @@ -20,7 +20,7 @@ namespace Gadgetron { } }; - PCACoilGadget(const Core::MrdContext& context, const Parameters& params); + PCACoilGadget(const Core::MRContext& context, const Parameters& params); ~PCACoilGadget() override; void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/PhysioInterpolationGadget.h b/gadgets/mri_core/PhysioInterpolationGadget.h index 9303f74c..1df703e9 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.h +++ b/gadgets/mri_core/PhysioInterpolationGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include @@ -102,7 +102,7 @@ class PhysioInterpolationGadget : public Core::MRChannelGadget>>(context, params) , parameters_(params) { diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index 3caf4c42..12774169 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -49,7 +49,7 @@ void RemoveROOversamplingGadget::process(Core::InputChannel& i } } -RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MrdContext& context, const Core::NodeParameters& params) +RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MRContext& context, const Core::NodeParameters& params) : Core::MRChannelGadget(context, params) { auto h = context.header; diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index feee3178..b0a846af 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.h +++ b/gadgets/mri_core/RemoveROOversamplingGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoNDFFT.h" #ifdef USE_OMP // TODO: Should this be removed? Its from the old version @@ -15,7 +15,7 @@ namespace Gadgetron { class RemoveROOversamplingGadget : public Core::MRChannelGadget { public: - RemoveROOversamplingGadget(const Core::MrdContext& context, const Core::NodeParameters& params); + RemoveROOversamplingGadget(const Core::MRContext& context, const Core::NodeParameters& params); void process(Core::InputChannel& input, Core::OutputChannel& output) override; diff --git a/gadgets/mri_core/ScaleGadget.h b/gadgets/mri_core/ScaleGadget.h index 5b0dfc6d..f300ed61 100644 --- a/gadgets/mri_core/ScaleGadget.h +++ b/gadgets/mri_core/ScaleGadget.h @@ -1,6 +1,6 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" namespace Gadgetron { using PercentileScaleImageTypes = std::variant, mrd::ImageArray>; @@ -19,7 +19,7 @@ namespace Gadgetron { } }; - ScaleGadget(const Core::MrdContext& context, const Parameters& params) + ScaleGadget(const Core::MRContext& context, const Parameters& params) : Core::MRPureGadget(context, params) , parameters_(params) {} diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index d9fcd150..9faebbe7 100644 --- a/gadgets/mri_core/SimpleReconGadget.h +++ b/gadgets/mri_core/SimpleReconGadget.h @@ -5,7 +5,7 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include "hoNDArray_math.h" diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconBase.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconBase.h index 03b77960..bd809ac6 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconBase.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconBase.h @@ -8,7 +8,7 @@ #pragma once #include -#include "Node.h" +#include "MRNode.h" #include "GadgetronTimer.h" #include "mri_core_def.h" @@ -44,7 +44,7 @@ namespace Gadgetron { // float time_tick = 2.5; }; - GenericReconBase(const Core::MrdContext& context, const Parameters& params) + GenericReconBase(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) , verbose(params_.verbose) @@ -81,7 +81,7 @@ namespace Gadgetron { /** TODO: This is a duplicate of this->params_.verbose, for convenience, since it is used * by external classes, such as ImageArraySendMixin. - * + * * This should be fixed... */ const bool verbose; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp index 7e10ad34..b525c4da 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp @@ -5,7 +5,7 @@ namespace Gadgetron { - GenericReconCartesianGrappaAIGadget::GenericReconCartesianGrappaAIGadget(const Core::MrdContext &context, const Parameters& params) + GenericReconCartesianGrappaAIGadget::GenericReconCartesianGrappaAIGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) { std::filesystem::path pingvin_python_path = context.paths.pingvin_home / "share" / "pingvin" / "python"; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h index 8082e0c1..3e17d448 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h @@ -22,7 +22,7 @@ namespace Gadgetron { { } }; - GenericReconCartesianGrappaAIGadget(const Core::MrdContext& context, const Parameters& params); + GenericReconCartesianGrappaAIGadget(const Core::MRContext& context, const Parameters& params); protected: diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp index 0eee48a2..864119e0 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.cpp @@ -15,7 +15,7 @@ namespace Gadgetron { - GenericReconCartesianGrappaGadget::GenericReconCartesianGrappaGadget(const Core::MrdContext &context, const Parameters& params) + GenericReconCartesianGrappaGadget::GenericReconCartesianGrappaGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h index 142101c4..00db8552 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h @@ -89,7 +89,7 @@ namespace Gadgetron { size_t downstream_coil_compression_num_modesKept = 0; }; - GenericReconCartesianGrappaGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconCartesianGrappaGadget(const Core::MRContext &context, const Parameters& params); ~GenericReconCartesianGrappaGadget() override; protected: diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp index 42c03af8..3256d7b5 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.cpp @@ -11,7 +11,7 @@ namespace Gadgetron { - GenericReconCartesianNonLinearSpirit2DTGadget::GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconCartesianNonLinearSpirit2DTGadget::GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h index 73832c84..fc004ab8 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h @@ -66,7 +66,7 @@ namespace Gadgetron { double spirit_reg_N_weighting_ratio = 0; }; - GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MrdContext& context, const Parameters& params); + GenericReconCartesianNonLinearSpirit2DTGadget(const Core::MRContext& context, const Parameters& params); protected: Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp index e1351464..658945ff 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.cpp @@ -7,7 +7,7 @@ namespace Gadgetron { GenericReconCartesianReferencePrepGadget::GenericReconCartesianReferencePrepGadget( - const Core::MrdContext &context, const Parameters& params) + const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h index 14bb1e4d..b4872780 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianReferencePrepGadget.h @@ -47,7 +47,7 @@ namespace Gadgetron { bool prepare_ref_always = true; }; - GenericReconCartesianReferencePrepGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconCartesianReferencePrepGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp index e6e9f46b..48f7b6b1 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.cpp @@ -8,7 +8,7 @@ namespace Gadgetron { - GenericReconCartesianSpiritGadget::GenericReconCartesianSpiritGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconCartesianSpiritGadget::GenericReconCartesianSpiritGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h index 1ada4677..edbef833 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h @@ -92,7 +92,7 @@ namespace Gadgetron { bool spirit_print_iter = false; }; - GenericReconCartesianSpiritGadget(const Core::MrdContext& context, const Parameters& params); + GenericReconCartesianSpiritGadget(const Core::MRContext& context, const Parameters& params); protected: Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp index 29db2416..043afc4c 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.cpp @@ -7,7 +7,7 @@ namespace Gadgetron { - GenericReconEigenChannelGadget::GenericReconEigenChannelGadget(const Core::MrdContext &context, const Parameters& params) + GenericReconEigenChannelGadget::GenericReconEigenChannelGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h index e2427813..a7ccc0f4 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h @@ -56,7 +56,7 @@ namespace Gadgetron { }; - GenericReconEigenChannelGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconEigenChannelGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp index 15cd4fb0..d6a137ea 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.cpp @@ -15,7 +15,7 @@ static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; namespace Gadgetron { - GenericReconFieldOfViewAdjustmentGadget::GenericReconFieldOfViewAdjustmentGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconFieldOfViewAdjustmentGadget::GenericReconFieldOfViewAdjustmentGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) { auto& h = context.header; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h index 21cf16ff..f8d4c930 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h @@ -24,7 +24,7 @@ namespace Gadgetron { {} }; - GenericReconFieldOfViewAdjustmentGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconFieldOfViewAdjustmentGadget(const Core::MRContext &context, const Parameters& params); ~GenericReconFieldOfViewAdjustmentGadget() override; protected: diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp index afdce80c..1ae766de 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.cpp @@ -5,7 +5,7 @@ namespace Gadgetron { - GenericReconGadget::GenericReconGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconGadget::GenericReconGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h index a31d880b..ed424f27 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h @@ -40,7 +40,7 @@ namespace Gadgetron { double coil_map_thres_iter = 1e-4; }; - GenericReconGadget(const Core::MrdContext& context, const Parameters& params); + GenericReconGadget(const Core::MRContext& context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp index 8de09d00..46fbf52a 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.cpp @@ -14,7 +14,7 @@ static const int GADGET_FAIL = -1; static const int GADGET_OK = 0; namespace Gadgetron { - GenericReconImageArrayScalingGadget::GenericReconImageArrayScalingGadget(const Core::MrdContext &context, const Parameters& params) + GenericReconImageArrayScalingGadget::GenericReconImageArrayScalingGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h index 9204b413..8ced199d 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h @@ -51,7 +51,7 @@ namespace Gadgetron { float scalingFactor_snr_std_map = 1000.0; }; - GenericReconImageArrayScalingGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconImageArrayScalingGadget(const Core::MRContext &context, const Parameters& params); protected: Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp index 3fdbea69..b38a95e5 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.cpp @@ -12,7 +12,7 @@ namespace Gadgetron { - GenericReconKSpaceFilteringGadget::GenericReconKSpaceFilteringGadget(const Core::MrdContext &context, const Parameters& params) + GenericReconKSpaceFilteringGadget::GenericReconKSpaceFilteringGadget(const Core::MRContext &context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h index a41e3482..bdc4a3cf 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h @@ -53,7 +53,7 @@ namespace Gadgetron { double filterE2_width = 0.15; }; - GenericReconKSpaceFilteringGadget(const Core::MrdContext &context, const Parameters& params); + GenericReconKSpaceFilteringGadget(const Core::MRContext &context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp index 985d927b..df91f1b3 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp @@ -11,7 +11,7 @@ namespace Gadgetron { - GenericReconNoiseStdMapComputingGadget::GenericReconNoiseStdMapComputingGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconNoiseStdMapComputingGadget::GenericReconNoiseStdMapComputingGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h index 3c225fda..7b66b96a 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h @@ -30,7 +30,7 @@ namespace Gadgetron { int start_N_for_std_map = 5; }; - GenericReconNoiseStdMapComputingGadget(const Core::MrdContext& context, const Parameters& params); + GenericReconNoiseStdMapComputingGadget(const Core::MRContext& context, const Parameters& params); protected: const Parameters params_; diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h index 9c5a4c70..ad450b25 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h @@ -34,7 +34,7 @@ namespace Gadgetron { bool partial_fourier_filter_densityComp = false; }; - GenericReconPartialFourierHandlingFilterGadget(const Core::MrdContext& context, const Parameters& params) + GenericReconPartialFourierHandlingFilterGadget(const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) {} diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp index 143aae7e..14106f24 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.cpp @@ -10,7 +10,7 @@ namespace Gadgetron { GenericReconPartialFourierHandlingGadget::GenericReconPartialFourierHandlingGadget( - const Core::MrdContext& context, const Parameters& params) + const Core::MRContext& context, const Parameters& params) : BaseClass(context, params) , params_(params) { diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h index 7da0e126..b90108cf 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h @@ -20,7 +20,7 @@ #include "hoNDFFT.h" #include "mri_core_partial_fourier.h" -#include "PureGadget.h" +#include "MRPureNode.h" namespace Gadgetron { @@ -44,7 +44,7 @@ class GenericReconPartialFourierHandlingGadget : public Core::MRPureGadget + $ + ) + +install(TARGETS pingvin_mri + EXPORT pingvin-export + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + COMPONENT main + ) + +install(FILES + MRContext.h + MRNode.h + MRPureNode.h + MRParallel.h + MRSource.h + MRSink.h + DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH}/mri + ) \ No newline at end of file diff --git a/mri/MRContext.h b/mri/MRContext.h new file mode 100644 index 00000000..266a3644 --- /dev/null +++ b/mri/MRContext.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "mrd/types.h" + +namespace Gadgetron::Core { + + struct MRContext { + + /** TODO: This Path is only used in TWO Gadgets, and it is only used to load Python files. + * These Gadgets can be updated to read the Python file paths from its own CLI parameters... + * + * Otherwise, the PINGVIN_HOME path can be queried using the `static get_gadgetron_home()` function. + */ + struct Paths { + std::filesystem::path pingvin_home; + }; + + mrd::Header header; + std::map env; + Paths paths; + }; + +} // namespace Gadgetron::Core \ No newline at end of file diff --git a/mri/MRNode.h b/mri/MRNode.h new file mode 100644 index 00000000..69ab5604 --- /dev/null +++ b/mri/MRNode.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Node.h" + +#include "MRContext.h" + + +namespace Gadgetron::Core { + +template class MRChannelGadget : public ChannelGadget { +public: + using ChannelGadget::ChannelGadget; + + MRChannelGadget(const MRContext& context, const NodeParameters& parameters) {} +}; + +} // namespace Gadgetron::Core diff --git a/core/parallel/Fanout.h b/mri/MRParallel.h similarity index 58% rename from core/parallel/Fanout.h rename to mri/MRParallel.h index 754fe640..a1ec347f 100644 --- a/core/parallel/Fanout.h +++ b/mri/MRParallel.h @@ -1,15 +1,26 @@ #pragma once -#include -#include +#include "parallel/Branch.h" +#include "parallel/Merge.h" -#include "Branch.h" - -#include "Channel.h" +#include "MRContext.h" namespace Gadgetron::Core::Parallel { - /** TODO: Move to MR-specific location! */ + template class MRBranch : public TypedBranch { + public: + using TypedBranch::TypedBranch; + + MRBranch(const MRContext& context, const NodeParameters& parameters) {} + }; + + class MRMerge : public Merge { + public: + using Merge::Merge; + + MRMerge(const MRContext& context, const NodeParameters& parameters) {} + }; + template class Fanout : public MRBranch { public: @@ -28,4 +39,5 @@ namespace Gadgetron::Core::Parallel { using AcquisitionFanout = Core::Parallel::Fanout; using WaveformFanout = Core::Parallel::Fanout; using ImageFanout = Core::Parallel::Fanout; -} \ No newline at end of file + +} // namespace Gadgetron::Core::Parallel diff --git a/mri/MRPureNode.h b/mri/MRPureNode.h new file mode 100644 index 00000000..e89013f6 --- /dev/null +++ b/mri/MRPureNode.h @@ -0,0 +1,15 @@ +#pragma once + +#include "PureGadget.h" + +#include "MRContext.h" + +namespace Gadgetron::Core { + +template +class MRPureGadget : public PureGadget { +public: + MRPureGadget(const MRContext& context, const NodeParameters& parameters) {} +}; + +} \ No newline at end of file diff --git a/mri/MRSink.h b/mri/MRSink.h new file mode 100644 index 00000000..01cde910 --- /dev/null +++ b/mri/MRSink.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Sink.h" + +#include "MRContext.h" + +#include "mrd/binary/protocols.h" + +namespace Pingvin { + +struct MRSink : public ISink { + MRSink(std::ostream& output_stream, const Gadgetron::Core::MRContext& ctx) + : mrd_writer_(output_stream) + { + mrd_writer_.WriteHeader(ctx.header); + } + + void produce_output(Gadgetron::Core::ChannelPair& output_channel) override + { + while (true) { + try { + auto message = output_channel.input.pop(); + + using namespace Gadgetron::Core; + + 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 Gadgetron::Core::ChannelClosed& exc) { + break; + } + } + + mrd_writer_.EndData(); + mrd_writer_.Close(); + } + +private: + mrd::binary::MrdWriter mrd_writer_; +}; + +} \ No newline at end of file diff --git a/mri/MRSource.h b/mri/MRSource.h new file mode 100644 index 00000000..59947aef --- /dev/null +++ b/mri/MRSource.h @@ -0,0 +1,51 @@ +#pragma once + +#include "Source.h" + +#include "MRContext.h" + +#include "mrd/binary/protocols.h" + +namespace Pingvin { + +struct MRSource : public Source { + MRSource(std::istream& input_stream): mrd_reader_(input_stream) {} + + void initContext(Gadgetron::Core::MRContext& ctx) override { + std::optional hdr; + mrd_reader_.ReadHeader(hdr); + if (!hdr.has_value()) { + GADGET_THROW("Failed to read MRD header"); + } + + ctx.header = hdr.value(); + + for (char** raw = environ; *raw; ++raw) { + std::string s(*raw); + auto pos = s.find('='); + if (pos != std::string::npos) { + ctx.env[s.substr(0, pos)] = s.substr(pos + 1); + } + } + + ctx.paths.pingvin_home = Pingvin::Main::get_pingvin_home(); + } + + void consume_input(Gadgetron::Core::ChannelPair& input_channel) override + { + mrd::StreamItem stream_item; + while (mrd_reader_.ReadData(stream_item)) { + std::visit([&](auto&& arg) { + Gadgetron::Core::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); + } + +private: + mrd::binary::MrdReader mrd_reader_; +}; + +} \ No newline at end of file diff --git a/test/gadgets/setup_gadget.h b/test/gadgets/setup_gadget.h index 0e2d8d81..87deed11 100644 --- a/test/gadgets/setup_gadget.h +++ b/test/gadgets/setup_gadget.h @@ -3,8 +3,6 @@ // #pragma once -#include "Channel.h" -#include "Context.h" #include "Node.h" #include #include @@ -37,8 +35,8 @@ namespace Gadgetron { namespace Test { return header; } - inline Core::MrdContext generate_context() { - Core::MrdContext context; + inline Core::MRContext generate_context() { + Core::MRContext context; context.header = generate_header(); return context; } @@ -49,7 +47,7 @@ namespace Gadgetron { namespace Test { }; template - inline GadgetChannels setup_gadget(PARAMETERS& params, Core::MrdContext context = generate_context()) { + inline GadgetChannels setup_gadget(PARAMETERS& params, Core::MRContext context = generate_context()) { auto channels = Core::make_channel(); auto channels2 = Core::make_channel(); diff --git a/toolboxes/mri_core/CMakeLists.txt b/toolboxes/mri_core/CMakeLists.txt index 6d6298a5..55a18e9e 100644 --- a/toolboxes/mri_core/CMakeLists.txt +++ b/toolboxes/mri_core/CMakeLists.txt @@ -28,6 +28,7 @@ set_target_properties(pingvin_toolbox_mri_core PROPERTIES VERSION ${PINGVIN_VERS set_target_properties(pingvin_toolbox_mri_core PROPERTIES LINKER_LANGUAGE CXX) target_link_libraries(pingvin_toolbox_mri_core + mrd::mrd pingvin_core pingvin_toolbox_cpucore pingvin_toolbox_cpucore_math diff --git a/toolboxes/python/CMakeLists.txt b/toolboxes/python/CMakeLists.txt index 53c2269d..384f4c92 100644 --- a/toolboxes/python/CMakeLists.txt +++ b/toolboxes/python/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(pingvin_toolbox_python SHARED target_link_libraries(pingvin_toolbox_python pingvin_core + mrd::mrd pingvin_toolbox_mri_core pingvin_toolbox_cpucore Boost::system From 38d6751d9912e459f932fcd7398ed1ebcc8125c2 Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Wed, 19 Feb 2025 19:12:54 +0000 Subject: [PATCH 19/21] Remove old XML config files --- Dockerfile | 2 +- LICENSE | 2 +- .../mri/config/cmr-cine-binning.conf | 8 +- .../mri/config/cmr-rtcine-lax-ai.conf | 2 + conda/build.sh | 2 +- gadgets/cmr/CMakeLists.txt | 33 +- .../CMR_2DT_RTCine_KspaceBinning.xml | 240 ---------- ...R_2DT_RTCine_KspaceBinning_MultiSeries.xml | 240 ---------- .../CMR_Image_Chain_RTCine_LAX_AI.xml | 19 - .../LandmarkDetection/CMR_RTCine_LAX_AI.xml | 224 ---------- .../LandmarkDetection/CMR_RTCine_Recon.xml | 191 -------- .../LandmarkDetection/stream_image_array.xml | 25 -- .../Mapping/CMR_2DT_T1Mapping_SASHA.xml | 274 ------------ gadgets/epi/CMakeLists.txt | 10 +- gadgets/epi/epi.xml | 97 ---- gadgets/epi/epi_gtplus_grappa.xml | 420 ------------------ gadgets/examples/CMakeLists.txt | 10 +- .../config/parallel_bypass_example.xml | 67 --- .../config/stream_complex_to_float.xml | 12 - .../examples/config/stream_float_to_short.xml | 16 - .../config/stream_image_array_scaling.xml | 24 - .../config/stream_image_array_split.xml | 14 - gadgets/grappa/CMakeLists.txt | 11 +- gadgets/grappa/config/grappa.xml | 78 ---- gadgets/grappa/config/grappa_cpu.xml | 78 ---- gadgets/grappa/config/grappa_float.xml | 68 --- gadgets/grappa/config/grappa_float_cpu.xml | 68 --- gadgets/grappa/config/grappa_unoptimized.xml | 63 --- .../config/grappa_unoptimized_float.xml | 53 --- gadgets/mri_core/CMakeLists.txt | 33 -- gadgets/mri_core/config/default.xml | 64 --- .../default_measurement_dependencies.xml | 22 - gadgets/mri_core/config/default_optimized.xml | 81 ---- .../config/Generic_Cartesian_FFT.xml | 208 --------- .../config/Generic_Cartesian_Grappa.xml | 215 --------- .../config/Generic_Cartesian_Grappa_AI.xml | 215 --------- .../Generic_Cartesian_Grappa_Cine_Denoise.xml | 371 ---------------- .../Generic_Cartesian_Grappa_Complex.xml | 201 --------- .../config/Generic_Cartesian_Grappa_EPI.xml | 230 ---------- .../Generic_Cartesian_Grappa_EPI_AVE.xml | 230 ---------- .../Generic_Cartesian_Grappa_ImageArray.xml | 172 ------- .../Generic_Cartesian_Grappa_RealTimeCine.xml | 211 --------- .../config/Generic_Cartesian_Grappa_SNR.xml | 203 --------- .../config/Generic_Cartesian_Grappa_T2W.xml | 213 --------- .../Generic_Cartesian_Image_Chain_FFT.xml | 41 -- ...artesian_NonLinear_Spirit_RealTimeCine.xml | 239 ---------- ...Sampling_NonLinear_Spirit_RealTimeCine.xml | 239 ---------- .../config/Generic_Cartesian_Spirit.xml | 210 --------- .../Generic_Cartesian_Spirit_RealTimeCine.xml | 211 --------- .../config/Generic_Cartesian_Spirit_SASHA.xml | 210 --------- 50 files changed, 14 insertions(+), 6156 deletions(-) delete mode 100644 gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml delete mode 100644 gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries.xml delete mode 100644 gadgets/cmr/config/LandmarkDetection/CMR_Image_Chain_RTCine_LAX_AI.xml delete mode 100644 gadgets/cmr/config/LandmarkDetection/CMR_RTCine_LAX_AI.xml delete mode 100644 gadgets/cmr/config/LandmarkDetection/CMR_RTCine_Recon.xml delete mode 100644 gadgets/cmr/config/LandmarkDetection/stream_image_array.xml delete mode 100644 gadgets/cmr/config/Mapping/CMR_2DT_T1Mapping_SASHA.xml delete mode 100644 gadgets/epi/epi.xml delete mode 100644 gadgets/epi/epi_gtplus_grappa.xml delete mode 100644 gadgets/examples/config/parallel_bypass_example.xml delete mode 100644 gadgets/examples/config/stream_complex_to_float.xml delete mode 100644 gadgets/examples/config/stream_float_to_short.xml delete mode 100644 gadgets/examples/config/stream_image_array_scaling.xml delete mode 100644 gadgets/examples/config/stream_image_array_split.xml delete mode 100644 gadgets/grappa/config/grappa.xml delete mode 100644 gadgets/grappa/config/grappa_cpu.xml delete mode 100644 gadgets/grappa/config/grappa_float.xml delete mode 100644 gadgets/grappa/config/grappa_float_cpu.xml delete mode 100644 gadgets/grappa/config/grappa_unoptimized.xml delete mode 100644 gadgets/grappa/config/grappa_unoptimized_float.xml delete mode 100644 gadgets/mri_core/config/default.xml delete mode 100644 gadgets/mri_core/config/default_measurement_dependencies.xml delete mode 100644 gadgets/mri_core/config/default_optimized.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_FFT.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_AI.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Cine_Denoise.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Complex.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI_AVE.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_ImageArray.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_SNR.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_T2W.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Image_Chain_FFT.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_RealTimeCine.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_SASHA.xml diff --git a/Dockerfile b/Dockerfile index a00e8f8e..59b06292 100644 --- a/Dockerfile +++ b/Dockerfile @@ -100,7 +100,7 @@ RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ - ninja -j6 && \ + ninja && \ ninja install FROM pingvin_dev_nocuda AS pingvin_build_nocuda diff --git a/LICENSE b/LICENSE index f0a9e146..c50e934c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Gadgetron +Copyright (c) 2025 Gadgetron Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf b/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf index 69d8f26b..87d5cb9f 100644 --- a/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf +++ b/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf @@ -22,12 +22,14 @@ average-all-ref-S = true [binning] verbose = true perform-timing = true +# For MultiSeries, uncomment the following line +#send-out-multiple-series-by-slice = true downstream-coil-compression-thres = 0.025 kspace-binning-moco-iters = 32 kspace-binning-moco-iters = 64 -kspace-binning-moco-iters = 100 -kspace-binning-moco-iters = 100 -kspace-binning-moco-iters = 100 +kspace-binning-moco-iters = 100 +kspace-binning-moco-iters = 100 +kspace-binning-moco-iters = 100 kspace-binning-linear-iter-thres = 0.0005 kspace-binning-nonlinear-reg-wav-name = db2 diff --git a/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf b/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf index 36fb80a0..30f04a49 100644 --- a/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf +++ b/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf @@ -1,3 +1,5 @@ +# Replaces CMR_RTCine_LAX_AI.xml + [acctrig] trigger-dimension = slice diff --git a/conda/build.sh b/conda/build.sh index 3c97a7dc..9b7848a9 100755 --- a/conda/build.sh +++ b/conda/build.sh @@ -12,4 +12,4 @@ cmake -GNinja \ -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ ../ -ninja -j6 install +ninja install diff --git a/gadgets/cmr/CMakeLists.txt b/gadgets/cmr/CMakeLists.txt index fda373d0..35427fb9 100644 --- a/gadgets/cmr/CMakeLists.txt +++ b/gadgets/cmr/CMakeLists.txt @@ -21,21 +21,6 @@ set( pingvin_cmr_src_files CmrParametricT2MappingGadget.cpp PureCmrCartesianKSpaceBinningCineGadget.cpp) -set( config_BinningCine_files - config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml - config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries.xml) - -source_group(config/BinningCine FILES ${config_BinningCine_files}) - -set( config_Mapping_files - config/Mapping/CMR_2DT_T1Mapping_SASHA.xml) - -source_group(config/Mapping FILES ${config_Mapping_files}) - -set( config_cmr_files - ${config_BinningCine_files} - ${config_Mapping_files}) - if (BUILD_PYTHON_SUPPORT) message("Build python cmr gadgets ... ") @@ -45,32 +30,18 @@ if (BUILD_PYTHON_SUPPORT) set( pingvin_cmr_header_files ${pingvin_cmr_header_files} CmrRealTimeLAXCineAIAnalysisGadget.h) set( pingvin_cmr_src_files ${pingvin_cmr_src_files} CmrRealTimeLAXCineAIAnalysisGadget.cpp) - set( config_LandmarkDetection_files - config/LandmarkDetection/CMR_RTCine_LAX_AI.xml - config/LandmarkDetection/CMR_RTCine_Recon.xml - config/LandmarkDetection/CMR_Image_Chain_RTCine_LAX_AI.xml - config/LandmarkDetection/stream_image_array.xml - ) - set( python_LandmarkDetection_files config/LandmarkDetection/gadgetron_cmr_landmark_detection.py config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py ) - source_group(config/LandmarkDetection FILES ${config_LandmarkDetection_files} ${python_LandmarkDetection_files}) - - set( config_cmr_files - ${config_cmr_files} - ${config_LandmarkDetection_files} - ${python_LandmarkDetection_files} ) - install(FILES ${python_LandmarkDetection_files} DESTINATION ${PINGVIN_INSTALL_PYTHON_MODULE_PATH}/cmr_lax_landmark_detection COMPONENT main) endif () add_library(pingvin_cmr SHARED ${pingvin_cmr_header_files} ${pingvin_cmr_src_files} - ${config_cmr_files} ) + ) set_target_properties(pingvin_cmr PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) @@ -93,8 +64,6 @@ endif () install(FILES ${pingvin_cmr_header_files} DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) -install(FILES ${config_cmr_files} DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) - install(TARGETS pingvin_cmr EXPORT pingvin-export LIBRARY DESTINATION lib diff --git a/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml b/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml deleted file mode 100644 index 73f2fad9..00000000 --- a/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingfalse - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_cmr - CmrCartesianKSpaceBinningCineGadget - - number_of_output_phases30 - send_out_rawfalse - send_out_multiple_series_by_slicefalse - - use_multiple_channel_recontrue - use_nonlinear_binning_recontrue - - time_tick2.5 - arrhythmia_rejector_factor0.25 - - - grappa_kSize_RO5 - grappa_kSize_E14 - grappa_reg_lamda0.0005 - downstream_coil_compression_num_modesKept0 - downstream_coil_compression_thres0.025 - - - kspace_binning_interpolate_heart_beat_imagestrue - kspace_binning_navigator_acceptance_window0.65 - kspace_binning_max_temporal_window2.0 - kspace_binning_minimal_cardiac_phase_width25.0 - - kspace_binning_moco_reg_strength12.0 - kspace_binning_moco_iters32 64 100 100 100 - - kspace_binning_kSize_RO7 - kspace_binning_kSize_E17 - kspace_binning_reg_lamda0.005 - kspace_binning_linear_iter_max90 - kspace_binning_linear_iter_thres0.0005 - - kspace_binning_nonlinear_iter_max25 - kspace_binning_nonlinear_iter_thres0.004 - kspace_binning_nonlinear_data_fidelity_lamda1.0 - kspace_binning_nonlinear_image_reg_lamda0.00015 - kspace_binning_nonlinear_reg_N_weighting_ratio10.0 - kspace_binning_nonlinear_reg_use_coil_sen_mapfalse - kspace_binning_nonlinear_reg_with_approx_coefftrue - kspace_binning_nonlinear_reg_wav_namedb2 - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries.xml b/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries.xml deleted file mode 100644 index a5a52b9a..00000000 --- a/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingfalse - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_cmr - CmrCartesianKSpaceBinningCineGadget - - number_of_output_phases30 - send_out_rawfalse - send_out_multiple_series_by_slicetrue - - use_multiple_channel_recontrue - use_nonlinear_binning_recontrue - - time_tick2.5 - arrhythmia_rejector_factor0.25 - - - grappa_kSize_RO5 - grappa_kSize_E14 - grappa_reg_lamda0.0005 - downstream_coil_compression_num_modesKept0 - downstream_coil_compression_thres0.025 - - - kspace_binning_interpolate_heart_beat_imagestrue - kspace_binning_navigator_acceptance_window0.65 - kspace_binning_max_temporal_window2.0 - kspace_binning_minimal_cardiac_phase_width25.0 - - kspace_binning_moco_reg_strength12.0 - kspace_binning_moco_iters32 64 100 100 100 - - kspace_binning_kSize_RO7 - kspace_binning_kSize_E17 - kspace_binning_reg_lamda0.005 - kspace_binning_linear_iter_max90 - kspace_binning_linear_iter_thres0.0005 - - kspace_binning_nonlinear_iter_max25 - kspace_binning_nonlinear_iter_thres0.004 - kspace_binning_nonlinear_data_fidelity_lamda1.0 - kspace_binning_nonlinear_image_reg_lamda0.00015 - kspace_binning_nonlinear_reg_N_weighting_ratio10.0 - kspace_binning_nonlinear_reg_use_coil_sen_mapfalse - kspace_binning_nonlinear_reg_with_approx_coefftrue - kspace_binning_nonlinear_reg_wav_namedb2 - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/cmr/config/LandmarkDetection/CMR_Image_Chain_RTCine_LAX_AI.xml b/gadgets/cmr/config/LandmarkDetection/CMR_Image_Chain_RTCine_LAX_AI.xml deleted file mode 100644 index db6c0909..00000000 --- a/gadgets/cmr/config/LandmarkDetection/CMR_Image_Chain_RTCine_LAX_AI.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - LAXAI - pingvin_cmr - CmrRealTimeLAXCineAIAnalysisGadget - - perform_AItrue - - - perform_timingtrue - verbosetrue - debug_folder - - - \ No newline at end of file diff --git a/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_LAX_AI.xml b/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_LAX_AI.xml deleted file mode 100644 index 67d94e38..00000000 --- a/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_LAX_AI.xml +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosefalse - - - average_all_ref_Ntrue - - average_all_ref_Sfalse - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - LAXAI - pingvin_cmr - CmrRealTimeLAXCineAIAnalysisGadget - - perform_AItrue - - - perform_timingtrue - verbosetrue - debug_folder - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_Recon.xml b/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_Recon.xml deleted file mode 100644 index fa981f9b..00000000 --- a/gadgets/cmr/config/LandmarkDetection/CMR_RTCine_Recon.xml +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosefalse - - - average_all_ref_Ntrue - - average_all_ref_Sfalse - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - diff --git a/gadgets/cmr/config/LandmarkDetection/stream_image_array.xml b/gadgets/cmr/config/LandmarkDetection/stream_image_array.xml deleted file mode 100644 index cc97dd6c..00000000 --- a/gadgets/cmr/config/LandmarkDetection/stream_image_array.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/cmr/config/Mapping/CMR_2DT_T1Mapping_SASHA.xml b/gadgets/cmr/config/Mapping/CMR_2DT_T1Mapping_SASHA.xml deleted file mode 100644 index 5035a0cd..00000000 --- a/gadgets/cmr/config/Mapping/CMR_2DT_T1Mapping_SASHA.xml +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionset - S_dimensioncontrast - split_slicesfalse - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingfalse - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.01 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactortrue - - - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.5 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.5 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.5 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - SASHA - pingvin_cmr - CmrParametricT1SRMappingGadget - - - perform_timingtrue - verbosetrue - debug_folder - - imaging_prep_time_from_protocoltrue - - send_maptrue - send_sd_maptrue - - color_lut_mapGadgetronT1_SR_1_5T.pal - window_center_map1300 - window_width_map1300 - - color_lut_map_3TGadgetronT1_SR_3T.pal - window_center_map_3T1300 - window_width_map_3T1300 - - scaling_factor_map1.0 - - color_lut_sd_mapGadgetronT1_SD.pal - window_center_sd_map2.0 - window_width_sd_map4.0 - scaling_factor_sd_map100.0 - - perform_hole_fillingtrue - max_size_hole20 - - std_thres_masking3.0 - mapping_with_maskingtrue - - max_iter150 - thres_func0.0001 - max_T14000.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/epi/CMakeLists.txt b/gadgets/epi/CMakeLists.txt index ee5427b3..6f7dc68a 100644 --- a/gadgets/epi/CMakeLists.txt +++ b/gadgets/epi/CMakeLists.txt @@ -5,8 +5,6 @@ add_library(pingvin_epi SHARED FFTXGadget.h FFTXGadget.cpp CutXGadget.h CutXGadget.cpp OneEncodingGadget.h OneEncodingGadget.cpp - epi.xml - epi_gtplus_grappa.xml ) set_target_properties(pingvin_epi PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) @@ -21,7 +19,6 @@ target_link_libraries(pingvin_epi pingvin_toolbox_epi ) - install(FILES EPIReconXGadget.h EPICorrGadget.h @@ -34,9 +31,4 @@ install(TARGETS pingvin_epi ARCHIVE DESTINATION lib RUNTIME DESTINATION bin COMPONENT main -) - -install(FILES - epi.xml - epi_gtplus_grappa.xml - DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) \ No newline at end of file +) \ No newline at end of file diff --git a/gadgets/epi/epi.xml b/gadgets/epi/epi.xml deleted file mode 100644 index 5e0b9b42..00000000 --- a/gadgets/epi/epi.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - NoiseAdjust - pingvin_mricore - NoiseAdjustGadget - - - - ReconX - pingvin_epi - EPIReconXGadget - - - - EPICorr - pingvin_epi - EPICorrGadget - - - - - FFTX - pingvin_epi - FFTXGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - - trigger_dimension - repetition - - - sorting_dimension - slice - - - - - Buff - pingvin_mricore - BucketToBufferGadget - - N_dimension - - - - S_dimension - - - - split_slices - true - - - ignore_segment - true - - - - - FFT - pingvin_mricore - FFTGadget - - - - Combine - pingvin_mricore - CombineGadget - - - - Extract - pingvin_mricore - ExtractGadget - - - - AutoScale - pingvin_mricore - AutoScaleGadget - - - - FloatToShort - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/epi/epi_gtplus_grappa.xml b/gadgets/epi/epi_gtplus_grappa.xml deleted file mode 100644 index ece6e290..00000000 --- a/gadgets/epi/epi_gtplus_grappa.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - NoiseAdjust - pingvin_mricore - NoiseAdjustGadget - - - - - ReconX - pingvin_epi - EPIReconXGadget - - - - - EPICorr - pingvin_epi - EPICorrGadget - - - - - FFTX - pingvin_epi - FFTXGadget - - - - - Acc - gadgetronPlus - GtPlusAccumulatorWorkOrderTriggerGadget - - - - verboseMode - false - - - - - noacceleration_triggerDim1 - DIM_Repetition - - - - noacceleration_triggerDim2 - DIM_NONE - - - - noacceleration_numOfKSpace_triggerDim1 - 1 - - - - - separate_triggerDim1 - DIM_Repetition - - - - separate_triggerDim2 - DIM_NONE - - - - separate_numOfKSpace_triggerDim1 - 1 - - - - - other_kspace_matching_Dim - DIM_Repetition - - - - - - - Recon - gadgetronPlus - GtPlusRecon2DTGadget - - - - dim_4th - DIM_Contrast - - - dim_5th - DIM_Slice - - - - - workOrder_ShareDim - DIM_Repetition - - - - - no_acceleration_averageall_ref - true - - - no_acceleration_ref_numOfModes - 0 - - - no_acceleration_same_combinationcoeff_allS - false - - - no_acceleration_whichS_combinationcoeff - 0 - - - - - separate_averageall_ref - true - - - separate_ref_numOfModes - 0 - - - separate_fullres_coilmap - false - - - separate_same_combinationcoeff_allS - false - - - separate_whichS_combinationcoeff - 0 - - - - - same_coil_compression_coeff_allS - false - - - - downstream_coil_compression - false - - - - coil_compression_thres - -1 - - - - coil_compression_num_modesKept - -1 - - - - - coil_map_algorithm - ISMRMRD_SOUHEIL - - - csm_kSize - 7 - - - - csm_powermethod_num - 3 - - - - csm_true_3D - false - - - - csm_iter_num - 5 - - - - csm_iter_thres - 0.001 - - - - - recon_algorithm - ISMRMRD_GRAPPA - - - - recon_kspace_needed - false - - - - recon_auto_parameters - true - - - - - grappa_kSize_RO - 5 - - - grappa_kSize_E1 - 4 - - - grappa_kSize_E2 - 4 - - - grappa_reg_lamda - 0.0005 - - - grappa_calib_over_determine_ratio - 0 - - - - - min_intensity_value - 64 - - - - max_intensity_value - 4095 - - - - scalingFactor - -1.0 - - - - use_constant_scalingFactor - false - - - - - filterRO - Gaussian - - - filterRO_sigma - 1.0 - - - filterRO_width - 0.15 - - - - filterE1 - Gaussian - - - filterE1_sigma - 1.0 - - - filterE1_width - 0.15 - - - - filterE2 - Gaussian - - - filterE2_sigma - 1.0 - - - filterE2_width - 0.15 - - - - - filterRefRO - Hanning - - - filterRefRO_sigma - 1.5 - - - filterRefRO_width - 0.15 - - - - filterRefE1 - Hanning - - - filterRefE1_sigma - 1.5 - - - filterRefE1_width - 0.15 - - - - filterRefE2 - Hanning - - - filterRefE2_sigma - 1.5 - - - filterRefE2_width - 0.15 - - - - - debugFolder - - - - - debugFolder2 - - - - - cloudNodeFile - myCloud_2DT.txt - - - - performTiming - true - - - - verboseMode - false - - - - - timeStampResolution - 0.0025 - - - - - job_split_by_S - false - - - job_num_of_N - 32 - - - job_max_Megabytes - 10240 - - - job_overlap - 2 - - - job_perform_on_control_node - true - - - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/examples/CMakeLists.txt b/gadgets/examples/CMakeLists.txt index dd7ae815..3ee92130 100644 --- a/gadgets/examples/CMakeLists.txt +++ b/gadgets/examples/CMakeLists.txt @@ -21,12 +21,4 @@ install(TARGETS pingvin_examples ARCHIVE DESTINATION lib RUNTIME DESTINATION bin COMPONENT main -) - -install(FILES - config/parallel_bypass_example.xml - config/stream_complex_to_float.xml - config/stream_float_to_short.xml - config/stream_image_array_split.xml - config/stream_image_array_scaling.xml - DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) +) \ No newline at end of file diff --git a/gadgets/examples/config/parallel_bypass_example.xml b/gadgets/examples/config/parallel_bypass_example.xml deleted file mode 100644 index 6345fbf6..00000000 --- a/gadgets/examples/config/parallel_bypass_example.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - 2 - - - - pingvin_mricore - NoiseAdjustGadget - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_mricore - AcquisitionAccumulateTriggerGadget - - - - - - pingvin_mricore - BucketToBufferGadget - - - - - pingvin_mricore - SimpleReconGadget - - - - pingvin_mricore - ImageArraySplitGadget - - - - pingvin_mricore - ExtractGadget - - - - - - - pingvin_core_parallel - ImageFanout - - - - - - pingvin_examples - ImageInverter - - - - - pingvin_examples - ImageLayerer - - - - diff --git a/gadgets/examples/config/stream_complex_to_float.xml b/gadgets/examples/config/stream_complex_to_float.xml deleted file mode 100644 index 621f5c8f..00000000 --- a/gadgets/examples/config/stream_complex_to_float.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - diff --git a/gadgets/examples/config/stream_float_to_short.xml b/gadgets/examples/config/stream_float_to_short.xml deleted file mode 100644 index ea490ce0..00000000 --- a/gadgets/examples/config/stream_float_to_short.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/examples/config/stream_image_array_scaling.xml b/gadgets/examples/config/stream_image_array_scaling.xml deleted file mode 100644 index dc0cb2cb..00000000 --- a/gadgets/examples/config/stream_image_array_scaling.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - diff --git a/gadgets/examples/config/stream_image_array_split.xml b/gadgets/examples/config/stream_image_array_split.xml deleted file mode 100644 index 14f63141..00000000 --- a/gadgets/examples/config/stream_image_array_split.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - diff --git a/gadgets/grappa/CMakeLists.txt b/gadgets/grappa/CMakeLists.txt index c16e73f4..00fd3426 100644 --- a/gadgets/grappa/CMakeLists.txt +++ b/gadgets/grappa/CMakeLists.txt @@ -35,13 +35,4 @@ install(TARGETS pingvin_grappa ARCHIVE DESTINATION lib RUNTIME DESTINATION bin COMPONENT main -) - -install(FILES - config/grappa.xml - config/grappa_cpu.xml - config/grappa_float.xml - config/grappa_float_cpu.xml - config/grappa_unoptimized.xml - config/grappa_unoptimized_float.xml - DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) \ No newline at end of file +) \ No newline at end of file diff --git a/gadgets/grappa/config/grappa.xml b/gadgets/grappa/config/grappa.xml deleted file mode 100644 index c26f01c2..00000000 --- a/gadgets/grappa/config/grappa.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - 2 - - - - pingvin_mricore - NoiseAdjustGadget - - - - pingvin_mricore - PCACoilGadget - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - AsymmetricEchoAdjustROGadget - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - gpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - - pingvin_mricore - AutoScaleGadget - - - - pingvin_mricore - FloatToUShortGadget - - - \ No newline at end of file diff --git a/gadgets/grappa/config/grappa_cpu.xml b/gadgets/grappa/config/grappa_cpu.xml deleted file mode 100644 index eb05b6cb..00000000 --- a/gadgets/grappa/config/grappa_cpu.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - 2 - - - - pingvin_mricore - NoiseAdjustGadget - - - - pingvin_mricore - PCACoilGadget - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - AsymmetricEchoAdjustROGadget - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - cpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - - pingvin_mricore - AutoScaleGadget - - - - pingvin_mricore - FloatToUShortGadget - - - \ No newline at end of file diff --git a/gadgets/grappa/config/grappa_float.xml b/gadgets/grappa/config/grappa_float.xml deleted file mode 100644 index 1be49c58..00000000 --- a/gadgets/grappa/config/grappa_float.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 2 - - - - pingvin_mricore - NoiseAdjustGadget - - - - pingvin_mricore - PCACoilGadget - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - AsymmetricEchoAdjustROGadget - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - gpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - \ No newline at end of file diff --git a/gadgets/grappa/config/grappa_float_cpu.xml b/gadgets/grappa/config/grappa_float_cpu.xml deleted file mode 100644 index b36e0e45..00000000 --- a/gadgets/grappa/config/grappa_float_cpu.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 2 - - - - pingvin_mricore - NoiseAdjustGadget - - - - pingvin_mricore - PCACoilGadget - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - AsymmetricEchoAdjustROGadget - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - cpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - \ No newline at end of file diff --git a/gadgets/grappa/config/grappa_unoptimized.xml b/gadgets/grappa/config/grappa_unoptimized.xml deleted file mode 100644 index 7cdbda3f..00000000 --- a/gadgets/grappa/config/grappa_unoptimized.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - 2 - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - gpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - - pingvin_mricore - AutoScaleGadget - - - - pingvin_mricore - FloatToUShortGadget - - - \ No newline at end of file diff --git a/gadgets/grappa/config/grappa_unoptimized_float.xml b/gadgets/grappa/config/grappa_unoptimized_float.xml deleted file mode 100644 index 8580cf59..00000000 --- a/gadgets/grappa/config/grappa_unoptimized_float.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - 2 - - - - pingvin_mricore - CoilReductionGadget - - - - - pingvin_mricore - RemoveROOversamplingGadget - - - - pingvin_grappa - SliceAccumulator - - - - - pingvin_grappa - AcquisitionFanout - - - - - pingvin_grappa - ImageAccumulator - - - - - - pingvin_grappa - gpuWeightsCalculator - - - - - pingvin_grappa - Unmixing - - - - - pingvin_mricore - ExtractGadget - - - \ No newline at end of file diff --git a/gadgets/mri_core/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index d0d8de67..a329ad2c 100644 --- a/gadgets/mri_core/CMakeLists.txt +++ b/gadgets/mri_core/CMakeLists.txt @@ -67,11 +67,6 @@ set(pingvin_mricore_src_files ScaleGadget.cpp ) -set(pingvin_mricore_config_files - config/default.xml - config/default_optimized.xml - config/default_measurement_dependencies.xml - ) set(pingvin_mricore_generic_recon_gadgets_header_files generic_recon_gadgets/GenericReconBase.h generic_recon_gadgets/GenericReconGadget.h @@ -106,25 +101,6 @@ set(pingvin_mricore_generic_recon_gadgets_src_files generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.cpp ) -set(pingvin_mricore_generic_recon_gadgets_config_files - generic_recon_gadgets/config/Generic_Cartesian_FFT.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_Cine_Denoise.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_Complex.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI_AVE.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_ImageArray.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_SNR.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa_T2W.xml - generic_recon_gadgets/config/Generic_Cartesian_Grappa.xml - generic_recon_gadgets/config/Generic_Cartesian_Image_Chain_FFT.xml - generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml - generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml - generic_recon_gadgets/config/Generic_Cartesian_Spirit_RealTimeCine.xml - generic_recon_gadgets/config/Generic_Cartesian_Spirit_SASHA.xml - generic_recon_gadgets/config/Generic_Cartesian_Spirit.xml -) - # if there is python, add gadgets using python if (BUILD_PYTHON_SUPPORT) message(STATUS "Build python generic gadgets ... ") @@ -138,17 +114,14 @@ if (BUILD_PYTHON_SUPPORT) set( pingvin_mricore_generic_recon_gadgets_header_files ${pingvin_mricore_generic_recon_gadgets_header_files} generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h) set( pingvin_mricore_generic_recon_gadgets_src_files ${pingvin_mricore_generic_recon_gadgets_src_files} generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.cpp) - set( pingvin_mricore_generic_recon_gadgets_config_files ${pingvin_mricore_generic_recon_gadgets_config_files} generic_recon_gadgets/config/Generic_Cartesian_Grappa_AI.xml) set( pingvin_python_models_files models/grappa_ai.py ) endif () add_library(pingvin_mricore SHARED ${pingvin_mricore_header_files} ${pingvin_mricore_src_files} - ${pingvin_mricore_config_files} ${pingvin_mricore_generic_recon_gadgets_header_files} ${pingvin_mricore_generic_recon_gadgets_src_files} - ${pingvin_mricore_generic_recon_gadgets_config_files} ) set_target_properties(pingvin_mricore PROPERTIES VERSION ${PINGVIN_VERSION_STRING} SOVERSION ${PINGVIN_SOVERSION}) @@ -184,12 +157,6 @@ install(FILES ${pingvin_mricore_generic_recon_gadgets_header_files} DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH}/generic_recon_gadgets COMPONENT main) - -install(FILES - ${pingvin_mricore_config_files} - ${pingvin_mricore_generic_recon_gadgets_config_files} - DESTINATION ${PINGVIN_INSTALL_CONFIG_PATH} COMPONENT main) - install(TARGETS pingvin_mricore EXPORT pingvin-export LIBRARY DESTINATION lib diff --git a/gadgets/mri_core/config/default.xml b/gadgets/mri_core/config/default.xml deleted file mode 100644 index 089ef9a2..00000000 --- a/gadgets/mri_core/config/default.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - 2 - - - - RemoveROOversampling - pingvin_mricore - RemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - - trigger_dimension - repetition - - - sorting_dimension - slice - - - - - Buff - pingvin_mricore - BucketToBufferGadget - - N_dimension - - - - S_dimension - - - - split_slices - true - - - - - SimpleRecon - pingvin_mricore - SimpleReconGadget - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - Extract - pingvin_mricore - ExtractGadget - - - - - diff --git a/gadgets/mri_core/config/default_measurement_dependencies.xml b/gadgets/mri_core/config/default_measurement_dependencies.xml deleted file mode 100644 index 5325b410..00000000 --- a/gadgets/mri_core/config/default_measurement_dependencies.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - NoiseAdjust - pingvin_mricore - NoiseAdjustGadget - - - - pass_nonconformant_data - true - - - - diff --git a/gadgets/mri_core/config/default_optimized.xml b/gadgets/mri_core/config/default_optimized.xml deleted file mode 100644 index 16995a33..00000000 --- a/gadgets/mri_core/config/default_optimized.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - NoiseAdjust - pingvin_mricore - NoiseAdjustGadget - - - - PCA - pingvin_mricore - PCACoilGadget - - - - CoilReduction - pingvin_mricore - CoilReductionGadget - coils_out16 - - - - RemoveROOversampling - pingvin_mricore - RemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - - trigger_dimension - repetition - - - sorting_dimension - slice - - - - - Buff - pingvin_mricore - BucketToBufferGadget - - N_dimension - - - - S_dimension - - - - split_slices - true - - - - - SimpleRecon - pingvin_mricore - SimpleReconGadget - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - Extract - pingvin_mricore - ExtractGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_FFT.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_FFT.xml deleted file mode 100644 index 846b7c18..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_FFT.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.002 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianFFTGadget - - - image_series0 - - - coil_map_algorithmInati - - - debug_folder - perform_timingtrue - verbosetrue - - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor1.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa.xml deleted file mode 100644 index 612fd7ad..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa.xml +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.002 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.01 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_AI.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_AI.xml deleted file mode 100644 index afef5e3f..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_AI.xml +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.002 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaAIGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.01 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Cine_Denoise.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Cine_Denoise.xml deleted file mode 100644 index 670ce81a..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Cine_Denoise.xml +++ /dev/null @@ -1,371 +0,0 @@ - - - 2 - - - - - - - NoiseAdjust - pingvin_mricore - NoiseAdjustGadget - - - - - AsymmetricEcho - pingvin_mricore - AsymmetricEchoAdjustROGadget - - - - - RemoveROOversampling - pingvin_mricore - RemoveROOversamplingGadget - - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - - trigger_dimension - slice - - - sorting_dimension - - - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - - N_dimension - phase - - - S_dimension - set - - - split_slices - true - - - ignore_segment - true - - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - - debug_folder - - - - perform_timing - true - - - verbose - true - - - - - average_all_ref_N - true - - - - average_all_ref_S - false - - - - prepare_ref_always - true - - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - - debug_folder - - - - perform_timing - true - - - verbose - true - - - - average_all_ref_N - true - - - average_all_ref_S - true - - - - - upstream_coil_compression - true - - - upstream_coil_compression_thres - -1 - - - upstream_coil_compression_num_modesKept - 0 - - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - - image_series - 0 - - - - - coil_map_algorithm - Inati - - - - - downstream_coil_compression - true - - - downstream_coil_compression_thres - 0.002 - - - downstream_coil_compression_num_modesKept - 0 - - - - - debug_folder - - - - perform_timing - true - - - verbose - true - - - - - send_out_gfactor - true - - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - - debug_folder - - - - perform_timing - false - - - verbose - false - - - - - skip_processing_meta_field - Skip_processing_after_recon - - - - - partial_fourier_POCS_iters - 6 - - - partial_fourier_POCS_thres - 0.01 - - - partial_fourier_POCS_transitBand - 24 - - - partial_fourier_POCS_transitBand_E2 - 16 - - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - - debug_folder - - - - perform_timing - false - - - verbose - false - - - - - skip_processing_meta_field - Skip_processing_after_recon - - - - - filterRO - Gaussian - - - filterRO_sigma - 1.0 - - - filterRO_width - 0.15 - - - - filterE1 - Gaussian - - - filterE1_sigma - 1.0 - - - filterE1_width - 0.15 - - - - filterE2 - Gaussian - - - filterE2_sigma - 1.0 - - - filterE2_width - 0.15 - - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - - debug_folder - - - - perform_timing - false - - - verbose - false - - - - ArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - - Denoiser - pingvin_mricore - DenoiseGadget - - - - - - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Complex.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Complex.xml deleted file mode 100644 index c76831ea..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_Complex.xml +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.002 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.01 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - AugmentImageMetadataGadget - pingvin_mricore - AugmentImageMetadataGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI.xml deleted file mode 100644 index 0f5d72b2..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI.xml +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - - ReconX - pingvin_epi - EPIReconXGadget - - - - EPICorr - pingvin_epi - EPICorrGadget - - - - FFTX - pingvin_epi - FFTXGadget - - - - OneEncodingSpace - pingvin_epi - OneEncodingGadget - - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionrepetition - sorting_dimensionaverage - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionrepetition - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaysfalse - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor4.0 - use_constant_scalingFactorfalse - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI_AVE.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI_AVE.xml deleted file mode 100644 index 9b499470..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_EPI_AVE.xml +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - - ReconX - pingvin_epi - EPIReconXGadget - - - - EPICorr - pingvin_epi - EPICorrGadget - - - - FFTX - pingvin_epi - FFTXGadget - - - - OneEncodingSpace - pingvin_epi - OneEncodingGadget - - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionaverage - sorting_dimensionrepetition - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionaverage - S_dimensionrepetition - split_slicesfalse - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaysfalse - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor4.0 - use_constant_scalingFactorfalse - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_ImageArray.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_ImageArray.xml deleted file mode 100644 index a4ada1f7..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_ImageArray.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.002 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.01 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactorfalse - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine.xml deleted file mode 100644 index 1eebb2d8..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine.xml +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Sfalse - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactortrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_SNR.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_SNR.xml deleted file mode 100644 index 6b14bdc7..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_SNR.xml +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionrepetition - S_dimensionset - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactortrue - send_out_snr_maptrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - - - StdMap - pingvin_mricore - GenericReconNoiseStdMapComputingGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosetrue - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated1000.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_T2W.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_T2W.xml deleted file mode 100644 index a32385d7..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_T2W.xml +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionrepetition - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionrepetition - S_dimensionset - split_slicestrue - ignore_segmenttrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Sfalse - - prepare_ref_alwaysfalse - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres-1 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianGrappaGadget - - - image_series0 - - - coil_map_algorithmInati - - - downstream_coil_compressiontrue - downstream_coil_compression_thres0.002 - downstream_coil_compression_num_modesKept0 - - - debug_folder - perform_timingtrue - verbosetrue - - - send_out_gfactortrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Image_Chain_FFT.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Image_Chain_FFT.xml deleted file mode 100644 index e93637d2..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Image_Chain_FFT.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - ImageFFT - pingvin_mricore - ImageFFTGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml deleted file mode 100644 index dfa96dad..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine.xml +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicesfalse - ignore_segmenttrue - verbosefalse - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosefalse - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.001 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianNonLinearSpirit2DTGadget - - - image_series0 - - - coil_map_algorithmInati - - - spirit_parallel_imaging_lamda1.0 - spirit_data_fidelity_lamda1.0 - spirit_image_reg_lamda0.0015 - spirit_reg_namedb1 - spirit_reg_level1 - spirit_reg_keep_approx_coefftrue - spirit_reg_keep_redundant_dimension_coefffalse - spirit_reg_proximity_across_chafalse - spirit_reg_use_coil_sen_mapfalse - spirit_reg_RO_weighting_ratio1.0 - spirit_reg_E1_weighting_ratio1.0 - spirit_reg_N_weighting_ratio10 - spirit_reg_estimate_noise_floortrue - spirit_reg_minimal_num_images_for_noise_floor16 - spirit_print_itertrue - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - PhysioInterpolation - pingvin_mricore - PhysioInterpolationGadget - phases30 - - - mode0 - first_beat_on_triggertrue - - interp_methodBSpline - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml deleted file mode 100644 index 02d78ebe..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine.xml +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicesfalse - ignore_segmenttrue - verbosefalse - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosefalse - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosefalse - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.001 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianNonLinearSpirit2DTGadget - - - image_series0 - - - coil_map_algorithmInati - - - spirit_parallel_imaging_lamda1.0 - spirit_data_fidelity_lamda1.0 - spirit_image_reg_lamda0.0001 - spirit_reg_namedb2 - spirit_reg_level1 - spirit_reg_keep_approx_coefftrue - spirit_reg_keep_redundant_dimension_coefffalse - spirit_reg_proximity_across_chafalse - spirit_reg_use_coil_sen_mapfalse - spirit_reg_RO_weighting_ratio1.0 - spirit_reg_E1_weighting_ratio1.0 - spirit_reg_N_weighting_ratio10 - spirit_reg_estimate_noise_floorfalse - spirit_reg_minimal_num_images_for_noise_floor16 - spirit_print_itertrue - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - PhysioInterpolation - pingvin_mricore - PhysioInterpolationGadget - phases30 - - - mode0 - first_beat_on_triggertrue - - interp_methodBSpline - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit.xml deleted file mode 100644 index 7a63b565..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit.xml +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimension - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensioncontrast - S_dimensionaverage - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.001 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianSpiritGadget - - - image_series0 - - - coil_map_algorithmInati - - - spirit_print_itertrue - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_RealTimeCine.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_RealTimeCine.xml deleted file mode 100644 index b034b6a8..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_RealTimeCine.xml +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionphase - S_dimensionset - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.001 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianSpiritGadget - - - image_series0 - - - coil_map_algorithmInati - - - spirit_print_itertrue - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingPOCSGadget - - - debug_folder - perform_timingfalse - verbosetrue - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_POCS_iters6 - partial_fourier_POCS_thres0.01 - partial_fourier_POCS_transitBand24 - partial_fourier_POCS_transitBand_E216 - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_SASHA.xml b/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_SASHA.xml deleted file mode 100644 index 310e602d..00000000 --- a/gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Spirit_SASHA.xml +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - NoiseAdjustpingvin_mricoreNoiseAdjustGadget - - - AsymmetricEchopingvin_mricoreAsymmetricEchoAdjustROGadget - - - RemoveROOversamplingpingvin_mricoreRemoveROOversamplingGadget - - - - AccTrig - pingvin_mricore - AcquisitionAccumulateTriggerGadget - trigger_dimensionslice - sorting_dimension - - - - BucketToBuffer - pingvin_mricore - BucketToBufferGadget - N_dimensionset - S_dimensionrepetition - split_slicesfalse - ignore_segmenttrue - verbosetrue - - - - - PrepRef - pingvin_mricore - GenericReconCartesianReferencePrepGadget - - - debug_folder - perform_timingtrue - verbosetrue - - - average_all_ref_Ntrue - - average_all_ref_Strue - - prepare_ref_alwaystrue - - - - - CoilCompression - pingvin_mricore - GenericReconEigenChannelGadget - - - debug_folder - perform_timingtrue - verbosetrue - - average_all_ref_Ntrue - average_all_ref_Strue - - - upstream_coil_compressiontrue - upstream_coil_compression_thres0.001 - upstream_coil_compression_num_modesKept0 - - - - - Recon - pingvin_mricore - GenericReconCartesianSpiritGadget - - - image_series0 - - - coil_map_algorithmInati - - - spirit_print_itertrue - - - debug_folder - perform_timingtrue - verbosetrue - - - - - PartialFourierHandling - pingvin_mricore - GenericReconPartialFourierHandlingFilterGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - partial_fourier_filter_RO_width0.15 - partial_fourier_filter_E1_width0.15 - partial_fourier_filter_E2_width0.15 - partial_fourier_filter_densityCompfalse - - - - - KSpaceFilter - pingvin_mricore - GenericReconKSpaceFilteringGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - skip_processing_meta_fieldSkip_processing_after_recon - - - filterROGaussian - filterRO_sigma1.0 - filterRO_width0.15 - - filterE1Gaussian - filterE1_sigma1.0 - filterE1_width0.15 - - filterE2Gaussian - filterE2_sigma1.0 - filterE2_width0.15 - - - - - FOVAdjustment - pingvin_mricore - GenericReconFieldOfViewAdjustmentGadget - - - debug_folder - perform_timingfalse - verbosefalse - - - - - Scaling - pingvin_mricore - GenericReconImageArrayScalingGadget - - - perform_timingfalse - verbosefalse - - min_intensity_value64 - max_intensity_value4095 - scalingFactor10.0 - use_constant_scalingFactortrue - auto_scaling_only_oncetrue - scalingFactor_dedicated100.0 - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - - ComplexToFloatAttrib - pingvin_mricore - ComplexToFloatGadget - - - - FloatToShortAttrib - pingvin_mricore - FloatToUShortGadget - - max_intensity32767 - min_intensity0 - intensity_offset0 - - - From 765035a51a46fc5a764f8da99c5507940af1adab Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 21 Feb 2025 19:43:03 +0000 Subject: [PATCH 20/21] Fix CI issues --- .dockerignore | 1 + .github/workflows/pingvin-ci.yml | 9 ++-- CMakeLists.txt | 1 - Dockerfile | 19 ++++---- ...{environment.yml => build-environment.yml} | 3 +- conda/build.sh | 2 +- conda/meta.yaml | 48 +++++++------------ conda/package.sh | 9 ++-- conda/run_test.sh | 3 +- environment.yml | 26 ++-------- gadgets/mri_core/models/grappa_ai.py | 10 ++-- 11 files changed, 51 insertions(+), 80 deletions(-) rename conda/{environment.yml => build-environment.yml} (72%) diff --git a/.dockerignore b/.dockerignore index 211bdbf8..fb476fae 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,6 +11,7 @@ !gadgets/ !justfile !libmrd/ +!mri/ !test/ !toolboxes/ !environment.yml diff --git a/.github/workflows/pingvin-ci.yml b/.github/workflows/pingvin-ci.yml index 4209f09e..1fb6b1dd 100644 --- a/.github/workflows/pingvin-ci.yml +++ b/.github/workflows/pingvin-ci.yml @@ -14,6 +14,7 @@ permissions: env: imageBaseName: ghcr.io/gadgetron/pingvin/ubuntu22.04 + miniforgeVersion: 24.11.3-0 defaults: run: @@ -105,8 +106,8 @@ jobs: - name: Setup Miniforge uses: conda-incubator/setup-miniconda@v3 with: - miniforge-version: latest - environment-file: conda/environment.yml + miniforge-version: ${{env.miniforgeVersion}} + environment-file: conda/build-environment.yml activate-environment: pingvin-build - name: Build conda package @@ -129,8 +130,8 @@ jobs: - name: Setup Miniforge uses: conda-incubator/setup-miniconda@v3 with: - miniforge-version: latest - environment-file: conda/environment.yml + miniforge-version: ${{env.miniforgeVersion}} + environment-file: conda/build-environment.yml activate-environment: pingvin-build - name: Download Conda package diff --git a/CMakeLists.txt b/CMakeLists.txt index c44326bd..c062b8e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,7 +273,6 @@ if (BUILD_PYTHON_SUPPORT) 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) diff --git a/Dockerfile b/Dockerfile index 59b06292..92ed97d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ RUN groupadd --gid $USER_GID $USERNAME \ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ && chmod 0440 /etc/sudoers.d/$USERNAME -ARG MINIFORGE_VERSION=24.3.0-0 +ARG MINIFORGE_VERSION=24.11.3-0 ARG CONDA_GID=900 # Based on https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -70,13 +70,16 @@ RUN wget --quiet "https://github.com/microsoft/yardl/releases/download/v${YARDL_ && mv yardl "/usr/local/bin/" \ && rm "yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" +# Set OMP wait policy for better OpenMP performance on Ubuntu +ENV OMP_WAIT_POLICY=PASSIVE + 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/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda USER root FROM pingvin_baseimage AS pingvin_dev_nocuda @@ -85,7 +88,7 @@ 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/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda USER root FROM pingvin_dev_cuda AS pingvin_build_cuda @@ -100,8 +103,7 @@ RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ - ninja && \ - ninja install + ninja -j $(nproc) install FROM pingvin_dev_nocuda AS pingvin_build_nocuda ARG USER_UID @@ -115,8 +117,7 @@ RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ - ninja -j6 && \ - ninja install + ninja -j $(nproc) install FROM pingvin_baseimage AS pingvin_rt_cuda ARG USER_UID @@ -124,7 +125,7 @@ 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/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/mamba 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 @@ -138,7 +139,7 @@ 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/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/mamba 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 diff --git a/conda/environment.yml b/conda/build-environment.yml similarity index 72% rename from conda/environment.yml rename to conda/build-environment.yml index 7cbfcf65..e1510bbb 100644 --- a/conda/environment.yml +++ b/conda/build-environment.yml @@ -2,6 +2,7 @@ name: pingvin-build channels: - conda-forge dependencies: - - conda-build + - conda-build=24.7.1 + - conda-verify - anaconda-client - conda-libmamba-solver \ No newline at end of file diff --git a/conda/build.sh b/conda/build.sh index 9b7848a9..5b2bba1a 100755 --- a/conda/build.sh +++ b/conda/build.sh @@ -12,4 +12,4 @@ cmake -GNinja \ -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ ../ -ninja install +ninja -j $(nproc) install diff --git a/conda/meta.yaml b/conda/meta.yaml index ed2dbed0..1751e190 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -9,78 +9,66 @@ package: source: path: ../ +build: + detect_binary_files_with_prefix: False + ignore_prefix_files: True + requirements: build: + - cmake=3.25.1 + - gcc_linux-64=9.4.0 + - gxx_linux-64=9.4.0 + - ninja=1.12.1 + + host: - armadillo=12.8.4 - boost=1.80.0 - - cmake=3.25.1 - - cuda-libraries-dev=12.3.0 # [linux64] - - cuda-libraries=12.3.0 # [linux64] - - cuda-nvcc=12.3.52 # [linux64] - - cuda-runtime=12.3.0 # [linux64] + - cuda=12.3.0 - fftw=3.3.9 - - gcc_linux-64=9.4.0 # [linux64] - gmock=1.14.0 - - gxx_linux-64=9.4.0 # [linux64] - gtest=1.14.0 - h5py=3.7.0 - hdf5=1.10.6 - howardhinnant_date=3.0.1 - - imagemagick=7.0.11_13 # dev + - imagemagick=7.0.11_13 - ismrmrd=1.14.2 - ismrmrd-python=1.14.0 - - just=1.31.0 # dev + - just=1.31.0 - libblas=*=*mkl - - libcurl=7.86.0 - libxml2=2.9.14 - mkl>=2024.1.0 - mkl-include>=2024.1.0 - - ninja=1.12.1 - nlohmann_json=3.11.3 - numpy=1.26.4 - - packaging=24.0 - pugixml=1.12.1 - - pyfftw=0.13.1 - - pytest=8.3.3 # dev - - pyyaml=6.0.1 - python=3.10 - range-v3=0.12.0 - sysroot_linux-64=2.12 - xtensor=0.24.2 + run: - - armadillo=12.8.4 - boost=1.80.0 - - cuda-libraries=12.3.0 # [linux64] - - cuda-runtime=12.3.0 # [linux64] + - cuda-runtime=12.3.0 - fftw=3.3.9 - - h5py=3.7.0 - - hdf5=1.10.6 - - ismrmrd=1.14.2 - - ismrmrd-python=1.14.0 - - jq=1.7.1 - libblas=*=*mkl - - libcurl=7.86.0 - - libxml2=2.9.14 - mkl>=2024.1.0 - mrd-python=2.1.1 - numpy=1.26.4 - onnxruntime=1.18.1 - - pugixml=1.12.1 - - pyfftw=0.13.1 - python=3.10 - - pyyaml=6.0.1 - scipy=1.13.1 - - sysroot_linux-64=2.12 # [linux64] - - xtensor=0.24.2 test: source_files: - test/e2e requires: - pytest=8.3.3 + - pyyaml=6.0.1 about: home: https://github.com/gadgetron/pingvin + license: MIT + license_file: LICENSE summary: 'Streaming Image Reconstruction Framework' description: | Pingvin reconstruction engine with support libraries and example pipelines. diff --git a/conda/package.sh b/conda/package.sh index 6114a582..bd5c2a99 100755 --- a/conda/package.sh +++ b/conda/package.sh @@ -11,21 +11,20 @@ Usage: $0 EOF } -conda_path=$(dirname "$0") -output_path="${conda_path}/build_pkg" +recipe_path=$(dirname "$0") +output_path="${recipe_path}/build_pkg" # Build up channel directives channels=( nvidia/label/cuda-12.3.0 ismrmrd conda-forge - bioconda defaults ) channel_directives=$(printf -- "-c %s " "${channels[@]}") -python3 "${conda_path}"/validate_versions.py +python3 "${recipe_path}"/validate_versions.py mkdir -p "$output_path" -bash -c "conda build --no-anaconda-upload --output-folder $output_path $channel_directives ${conda_path}" +bash -c "conda build --no-anaconda-upload --output-folder $output_path $channel_directives ${recipe_path}" diff --git a/conda/run_test.sh b/conda/run_test.sh index 441fbb2c..62ff6561 100755 --- a/conda/run_test.sh +++ b/conda/run_test.sh @@ -6,4 +6,5 @@ cd test/e2e/ test -d cases test -f conftest.py -pytest --download-all \ No newline at end of file +export OMP_WAIT_POLICY=PASSIVE +pytest -k gpu_grappa --echo-log-on-failure diff --git a/environment.yml b/environment.yml index 9adeff12..4f876397 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,6 @@ channels: - ismrmrd - nvidia/label/cuda-12.3.0 - conda-forge - - bioconda - defaults dependencies: - anaconda-client=1.12.3 # dev @@ -12,20 +11,8 @@ dependencies: - ccache=4.10.1 # dev - breathe=4.34.0 # dev - cmake=3.25.1 # dev - - conda-build=24.5.1 # dev - - conda-verify=3.1.1 # dev - - cuda-cccl=12.3.52 # cuda - - cuda-cudart=12.3.52 # cuda - - cuda-cudart-dev=12.3.52 # cuda, dev - - cuda-driver-dev=12.3.52 # cuda, dev - - cuda-libraries=12.3.0 # cuda - - cuda-libraries-dev=12.3.0 # cuda, dev - - cuda-nvcc=12.3.52 # cuda, dev - - cuda-nvrtc=12.3.52 # cuda - - cuda-nvrtc-dev=12.3.52 # cuda, dev + - cuda=12.3.0 # cuda - cuda-runtime=12.3.0 # cuda - - deepdiff=7.0.1 - - doxygen=1.10.0 # dev - eigen=3.4.0 - fftw=3.3.9 - fmt=8.1.1 @@ -41,13 +28,9 @@ dependencies: - ismrmrd=1.14.2 - ismrmrd-python=1.14.0 - junitparser=3.1.2 - - jupyter=1.0.0 # dev - just=1.31.0 # dev - - jq=1.7.1 - libblas=*=*mkl - - libcurl=7.86.0 # dev - libxml2=2.9.14 # dev - - make=4.3 # dev - matplotlib=3.8.4 # dev - mkl>=2024.1.0 - mkl-include>=2024.1.0 # dev @@ -57,20 +40,17 @@ dependencies: - nlohmann_json=3.11.3 # dev - numpy=1.26.4 - onnxruntime=1.18.1 - - packaging=24.0 + - packaging=24.0 # dev - pip=24.0 # dev - pugixml=1.12.1 - - pyfftw=0.13.1 - pytest=8.3.3 - python=3.10 - pyyaml=6.0.1 - range-v3=0.12.0 - - recommonmark=0.7.1 # dev + - ripgrep>=14.0.0 # dev - scipy=1.13.1 - shellcheck=0.10.0 # dev - siemens_to_ismrmrd=1.2.13 - - sphinx=4.4.0 # dev - - sphinx_rtd_theme=1.3.0 # dev - sysroot_linux-64=2.12 - valgrind=3.23.0 # dev - xsdata=24.5 diff --git a/gadgets/mri_core/models/grappa_ai.py b/gadgets/mri_core/models/grappa_ai.py index 73722055..eb8fbaaa 100644 --- a/gadgets/mri_core/models/grappa_ai.py +++ b/gadgets/mri_core/models/grappa_ai.py @@ -92,8 +92,8 @@ def create_grappa_ai_model(gt_ker): model = None try: - print("Grappa ai", file=sys.stderr, file=sys.stderr) - print("----------------------------------------", file=sys.stderr, file=sys.stderr) + print("Grappa ai", file=sys.stderr) + print("----------------------------------------", file=sys.stderr) try: kRO, kNE1, srcCHA, dstCHA, oE1 = gt_ker.shape @@ -115,12 +115,12 @@ def create_grappa_ai_model(gt_ker): model = GrappaAI(Din, Dout, params) print(model, file=sys.stderr) - print("----------------------------------------", file=sys.stderr, file=sys.stderr) + print("----------------------------------------", file=sys.stderr) sys.stderr.flush() except Exception as e: - print("Error happened in create_grappa_ai_model", file=sys.stderr, file=sys.stderr) + print("Error happened in create_grappa_ai_model", file=sys.stderr) print(e, file=sys.stderr) return model @@ -151,7 +151,7 @@ def apply_grappa_ai_model(gt_dataA, model, device = torch.device('cpu')): recon = recon.detach().cpu().numpy().astype(np.float32) recon_kspace = real_2_complex(recon) except Exception as e: - print("Error happened in apply_grappa_ai_model", file=sys.stderr, file=sys.stderr) + print("Error happened in apply_grappa_ai_model", file=sys.stderr) print(e, file=sys.stderr) return recon_kspace From e1ffe33193ff3aa1f864c9481ba5b4e07876a99a Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Fri, 21 Feb 2025 20:33:56 +0000 Subject: [PATCH 21/21] Disable GPU pipelines in nocuda docker build --- apps/pingvin/pipelines/mri/grappa.h | 7 +++++-- apps/pingvin/pipelines/registry.h | 4 +++- test/e2e/cases/gpu_grappa_simple.yml | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/pingvin/pipelines/mri/grappa.h b/apps/pingvin/pipelines/mri/grappa.h index 9ff05294..cd4919fa 100644 --- a/apps/pingvin/pipelines/mri/grappa.h +++ b/apps/pingvin/pipelines/mri/grappa.h @@ -23,7 +23,7 @@ namespace Pingvin { using namespace Gadgetron; -static auto grappa = PipelineBuilder("grappa", "Basic GRAPPA Reconstruction") +static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") .withSource() .withSink() .withNode("noise-adjust") @@ -49,7 +49,9 @@ static auto grappa = PipelineBuilder("grappa", "Basi .withNode("extract") ; -static auto grappa_cpu = PipelineBuilder("grappa-cpu", "Basic GRAPPA Reconstruction") +#ifdef USE_CUDA + +static auto grappa_gpu = PipelineBuilder("grappa-gpu", "Basic GRAPPA Reconstruction") .withSource() .withSink() .withNode("noise-adjust") @@ -68,5 +70,6 @@ static auto grappa_cpu = PipelineBuilder("grappa-cpu .withNode("extract") ; +#endif // USE_CUDA } // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/registry.h b/apps/pingvin/pipelines/registry.h index fc88776f..29e24976 100644 --- a/apps/pingvin/pipelines/registry.h +++ b/apps/pingvin/pipelines/registry.h @@ -30,8 +30,10 @@ class PipelineRegistry { register_pipeline(&epi_2d); - register_pipeline(&grappa); register_pipeline(&grappa_cpu); +#ifdef USE_CUDA + register_pipeline(&grappa_gpu); +#endif // USE_CUDA register_pipeline(&cartesian_grappa); register_pipeline(&cartesian_grappa_snr); diff --git a/test/e2e/cases/gpu_grappa_simple.yml b/test/e2e/cases/gpu_grappa_simple.yml index 5753ee00..d854568e 100644 --- a/test/e2e/cases/gpu_grappa_simple.yml +++ b/test/e2e/cases/gpu_grappa_simple.yml @@ -2,7 +2,7 @@ reconstruction: data: rtgrappa/acc_data_with_device_2_meas1.mrd checksum: 7fa1d38320b2a544148096ce09041b2a run: - - args: grappa --coil-reduction.coils-out=8 + - args: grappa-gpu --coil-reduction.coils-out=8 validation: reference: rtgrappa/grappa_rate2_cpu_out_grappa_float_cpu.xml.mrd checksum: f24f9b93670cfa0c1723493ce52c07c5