diff --git a/.dockerignore b/.dockerignore index 211bdbf89..fb476fae0 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 4209f09ed..1fb6b1dd9 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 76a50a4d3..c062b8e6a 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) @@ -318,6 +317,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/Dockerfile b/Dockerfile index 0b74d5b0b..92ed97d66 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 && \ - 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/LICENSE b/LICENSE index f0a9e1467..c50e934cc 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/CMakeLists.txt b/apps/CMakeLists.txt index f09b25327..351c74122 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(pingvin) +add_subdirectory(pingvin) \ No newline at end of file diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt index 6a829bd9a..8d858177b 100644 --- a/apps/pingvin/CMakeLists.txt +++ b/apps/pingvin/CMakeLists.txt @@ -1,50 +1,22 @@ -find_package(PugiXML REQUIRED) - -configure_file(pingvin_config.in pingvin_config.h) - -add_executable(pingvin - main.cpp - initialization.cpp - initialization.h - system_info.cpp - - Loader.cpp - Loader.h - - Config.cpp - Config.h - - ErrorHandler.h - - nodes/Processable.h - nodes/Processable.cpp - - nodes/Stream.cpp - nodes/Stream.h - nodes/Parallel.cpp - nodes/Parallel.h - nodes/ParallelProcess.cpp - nodes/ParallelProcess.h - nodes/PureStream.cpp - nodes/PureStream.h - ) +add_executable(pingvin main.cc) target_link_libraries(pingvin - pingvin_core - pingvin_toolbox_log - pingvin_toolbox_mri_core + pingvin_mri + 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 ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}) - + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR} + ) if (REQUIRE_SIGNED_CONFIG) target_link_libraries(pingvin GTBabylon) @@ -60,3 +32,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 980a606cf..000000000 --- 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 c9522a134..000000000 --- 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/ErrorHandler.h b/apps/pingvin/ErrorHandler.h deleted file mode 100644 index fc7a4eade..000000000 --- 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/Loader.cpp b/apps/pingvin/Loader.cpp deleted file mode 100644 index 227f591c5..000000000 --- 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 494a537b2..000000000 --- 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 1c4c983ab..000000000 --- a/apps/pingvin/StreamConsumer.h +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "Channel.h" -#include "ErrorHandler.h" -#include "Loader.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Main; - -namespace -{ - -class ErrorThrower : public ErrorReporter -{ - public: - void operator()(const std::string& location, const std::string& message) override { - throw std::runtime_error(("[" + location + "] ERROR: " + message)); - } -}; - -std::filesystem::path find_config_path(const std::string& home_dir, const std::string& config_xml) -{ - auto config_path = std::filesystem::path(home_dir) / std::filesystem::path(PINGVIN_CONFIG_PATH) / - std::filesystem::path(config_xml); - - if (!std::filesystem::is_regular_file(config_path)) { - throw std::runtime_error("Failed to find Pingvin configuration at the expected path: " + - config_path.string()); - } - - return config_path; -} - -} // namespace - -class StreamConsumer -{ -public: - StreamConsumer(const boost::program_options::variables_map& args) - : args_(args) {} - ~StreamConsumer() {} - - void consume(std::istream& input_stream, std::ostream& output_stream, std::string config_xml_name) - { - Context::Paths paths{ - args_["home"].as().string() - }; - - mrd::binary::MrdReader mrd_reader(input_stream); - mrd::binary::MrdWriter mrd_writer(output_stream); - - mrd::Header hdr = consume_mrd_header(mrd_reader, mrd_writer); - - auto context = StreamContext(hdr, paths, args_); - auto loader = Loader(context); - auto config_path = find_config_path(args_["home"].as().string(), config_xml_name); - - GINFO_STREAM("Loading configuration from: " << config_path.string()); - std::ifstream file(config_path, std::ios::in | std::ios::binary); - if (!file.is_open()) { - throw std::runtime_error("Failed to open file at path: " + config_path.string()); - } - - auto config = Config::parse(file); - file.close(); - - auto stream = loader.load(config.stream); - auto input_channel = make_channel(); - auto output_channel = make_channel(); - std::atomic processing = true; - - auto process_future = std::async(std::launch::async, [&]() { - try - { - ErrorThrower error_thrower; - ErrorHandler error_handler(error_thrower, std::string(__FILE__)); - stream->process(std::move(input_channel.input), std::move(output_channel.output), error_handler); - processing = false; - } - catch (const std::exception& exc) - { - { - // Induce a ChannelClosed exception upon readers of the channel. - auto destruct_me = std::move(output_channel.output); - } - processing = false; - throw; - } - }); - - auto input_future = std::async(std::launch::async, [&]() { - try - { - consume_input_stream(mrd_reader, input_channel); - } - catch(std::ios_base::failure& exc) - { - // Induce a ChannelClosed exception upon readers of the channel. - auto destruct_me = std::move(input_channel.output); - } - }); - - auto output_future = std::async(std::launch::async, [&]() - { - process_output_stream(output_channel, mrd_writer); - }); - - // Clean up and propagate exceptions if they occurred - input_future.get(); - output_future.get(); - process_future.get(); - } - - private: - - mrd::Header consume_mrd_header(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer) - { - std::optional hdr; - - mrd_reader.ReadHeader(hdr); - mrd_writer.WriteHeader(hdr); - - if (!hdr.has_value()) { - GADGET_THROW("Failed to read ISMRMRD header"); - } - return hdr.value(); - } - - void consume_input_stream(mrd::binary::MrdReader& mrd_reader, ChannelPair& input_channel) - { - mrd::StreamItem stream_item; - while (mrd_reader.ReadData(stream_item)) { - std::visit([&](auto&& arg) { - Message msg(std::move(arg)); - input_channel.output.push_message(std::move(msg)); - }, stream_item); - } - - mrd_reader.Close(); - auto destruct_me = std::move(input_channel.output); - } - - void process_output_stream(ChannelPair& output_channel, mrd::binary::MrdWriter& mrd_writer) - { - while (true) { - try { - auto message = output_channel.input.pop(); - - if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else if (convertible_to(message) ) { - mrd_writer.WriteData(force_unpack(std::move(message))); - } else { - GADGET_THROW("Unsupported Message type for MrdWriter! Check that the last Gadget emits a valid MRD type."); - } - } catch (const ChannelClosed& exc) { - break; - } - } - - mrd_writer.EndData(); - mrd_writer.Close(); - } - - boost::program_options::variables_map args_; -}; diff --git a/apps/pingvin/initialization.cpp b/apps/pingvin/initialization.cpp deleted file mode 100644 index ea39ce959..000000000 --- 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 d3edfe984..000000000 --- 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 new file mode 100644 index 000000000..65642dd49 --- /dev/null +++ b/apps/pingvin/main.cc @@ -0,0 +1,261 @@ +#include "log.h" +#include "system_info.h" +#include "pingvin_config.h" +#include "pipelines/registry.h" + +#include + +#include +#include +#include + +namespace po = boost::program_options; + +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) +{ + 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())); + + // 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); }); + return option; +} + +} // namespace + + +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") + ("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"); + hidden.add_options() + ("pipeline", po::value(), "Pipeline to run.") + ("subargs", po::value>(), "Arguments for the pipeline.") + ; + + po::options_description help_options("Pingvin usage"); + help_options.add(global); + + po::options_description allowed_options; + allowed_options.add(global).add(pipeline_opts).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::stringstream str; + Pingvin::Main::print_system_information(str); + GINFO_STREAM(str.str()); + return 0; + } + + if (vm.count("home") && !vm["home"].defaulted()) { + Pingvin::Main::set_pingvin_home(vm["home"].as()); + GINFO_STREAM("Set Pingvin home to: " << Pingvin::Main::get_pingvin_home()); + } + + PipelineRegistry registry; + + 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::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; + return 1; + } + } + + // "Choose" a Pipeline + std::string subcmd = vm["pipeline"].as(); + auto builder = registry.get(subcmd); + if (!builder) { + std::cerr << "Unknown pipeline: " << subcmd << std::endl; + return 1; + } + + 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_options).run(); + po::store(parsed, vm); + + if (vm.count("help")) { + 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, + // 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(); + 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_options), vm); + } + + po::notify(vm); + } + catch (po::error &e) + { + std::cerr << e.what() << std::endl; + 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; + } + + 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()); + if (!input_file->good()) { + std::cerr << "Could not open input file: " << vm["input"].as() << std::endl; + return 1; + } + } + + 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; + return 1; + } + } + + std::istream& input_stream = input_file ? *input_file : std::cin; + std::ostream& output_stream = output_file ? *output_file : std::cout; + + auto pipeline = builder->build(input_stream, output_stream); + + pipeline.run(); + + std::flush(output_stream); + + return 0; +} \ No newline at end of file diff --git a/apps/pingvin/main.cpp b/apps/pingvin/main.cpp deleted file mode 100644 index 0757ff5bf..000000000 --- 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 boost::filesystem; -using namespace boost::program_options; -using namespace Gadgetron::Main; - -using gadget_parameter = std::pair; - -std::istream& operator>>(std::istream& in, gadget_parameter& param) { - std::string token; - in >> token; - // parse = into a gadget_parameter - auto pos = token.find('='); - if (pos == std::string::npos) { - throw std::runtime_error("Invalid gadget parameter: " + token); - } - param.first = token.substr(0, pos); - param.second = token.substr(pos + 1); - return in; -} - -std::ostream& operator<<(std::ostream& out, const gadget_parameter& param) { - out << param.first << "=" << param.second; - return out; -} - -int main(int argc, char *argv[]) { - options_description gadgetron_options("Allowed options:"); - gadgetron_options.add_options() - ("help,h", "Prints this help message.") - ("info", "Prints build info about Pingvin.") - ("home,G", - value()->default_value(Info::default_pingvin_home()), - "Set the Pingvin home directory.") - ("input,i", - value(), - "Input file for binary data to perform a local reconstruction with") - ("output,o", - value(), - "Output file for binary data as a result of a local reconstruction") - ("config,c", - value(), - "Filename of the desired Pingvin reconstruction config.") - ("parameter", - value>(), - "Parameter to be passed to the Pingvin reconstruction config. Multiple parameters can be passed." - "Format: --parameter = --parameter = ..."); - - options_description desc; - desc.add(gadgetron_options); - - variables_map args; - store(parse_command_line(argc, argv, desc), args); - notify(args); - - try { - check_environment_variables(); - configure_blas_libraries(); - set_locale(); - - if (args.count("help")) { - GINFO_STREAM(desc); - return 0; - } - - if (args.count("info")) { - std::stringstream str; - Info::print_system_information(str); - GINFO(str.str().c_str()); - return 0; - } - - GINFO("Pingvin %s [%s]\n", PINGVIN_VERSION_STRING, PINGVIN_GIT_SHA1_HASH); - - if (!args.count("config")) - { - GERROR_STREAM("No config file provided. Use --config/-c"); - return 1; - } - - auto cfg = args["config"].as(); - StreamConsumer consumer(args); - - std::unique_ptr input_file; - if (args.count("input")) { - input_file = std::make_unique(args["input"].as()); - if (!input_file->good()) { - GERROR_STREAM("Could not open input file: " << args["input"].as()); - return 1; - } - } - - std::unique_ptr output_file; - if (args.count("output")) { - output_file = std::make_unique(args["output"].as()); - if (!output_file->good()) { - GERROR_STREAM("Could not open output file: " << args["output"].as()); - return 1; - } - } - - std::istream& input = input_file ? *input_file : std::cin; - std::ostream& output = output_file ? *output_file : std::cout; - consumer.consume(input, output, cfg); - std::flush(output); - - GDEBUG_STREAM("Finished consuming stream"); - } - catch (std::exception &e) - { - GERROR_STREAM(e.what() << std::endl); - std::exit(EXIT_FAILURE); - } - catch(...) - { - GERROR_STREAM("Unhandled exception, exiting" << std::endl); - std::exit(EXIT_FAILURE); - } - - return 0; -} diff --git a/apps/pingvin/nodes/Parallel.cpp b/apps/pingvin/nodes/Parallel.cpp deleted file mode 100644 index 5909380fe..000000000 --- a/apps/pingvin/nodes/Parallel.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "Parallel.h" - -#include -#include - -#include "Loader.h" - -#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; - - 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))>; - auto result = std::map(); - - for (auto &key_val : input) result.emplace(key_val.first, f(key_val.second)); - - return result; - } -} - -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) }; - } - - void emplace_channels( - const Stream &stream, - std::map &input, - std::map &output - ) { - ChannelPair in_pair = make_channel(); - ChannelPair out_pair = make_channel(); - - if (stream.empty()) out_pair = split(in_pair); - - input.emplace(stream.key, std::move(in_pair)); - output.emplace(stream.key, std::move(out_pair)); - } -} - -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, - ErrorHandler &error_handler - ) { - ErrorHandler nested_handler{error_handler, branch->key}; - - std::vector threads; - std::map input_channels; - std::map output_channels; - - for (auto &stream : streams) { - emplace_channels(*stream, input_channels, output_channels); - } - - threads.emplace_back(nested_handler.run( - [&](auto input, auto output, auto bypass) { - branch->process(std::move(input), std::move(output), std::move(bypass)); - }, - std::move(input), - transform_map(input_channels, [](auto& val) { return std::move(val.output); }), - split(output) - )); - - threads.emplace_back(nested_handler.run( - [&](auto input, auto output) { - merge->process(std::move(input), std::move(output)); - }, - transform_map(output_channels, [](auto &val) { return std::move(val.input); }), - std::move(output) - )); - - 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 - ) - ); - } - - 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/Parallel.h b/apps/pingvin/nodes/Parallel.h deleted file mode 100644 index 45d358fe7..000000000 --- a/apps/pingvin/nodes/Parallel.h +++ /dev/null @@ -1,65 +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(const Config::Parallel &, const Core::StreamContext &, Loader &); - - void process( - Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler &error_handler - ) 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 5b65d2697..000000000 --- a/apps/pingvin/nodes/ParallelProcess.cpp +++ /dev/null @@ -1,60 +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 pureStream.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, - ErrorHandler& error_handler - ) { - Queue queue; - - auto input_thread = error_handler.run( - [&](auto input) { this->process_input(std::move(input), queue); }, - std::move(input) - ); - - auto output_thread = error_handler.run( - [&](auto output) { this->process_output(std::move(output), queue); }, - std::move(output) - ); - - 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 deleted file mode 100644 index 21d8a527e..000000000 --- a/apps/pingvin/nodes/ParallelProcess.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "PureStream.h" -#include "Processable.h" - -#include - -namespace Gadgetron::Main::Nodes { - class ParallelProcess : public Processable { - - public: - 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: - - 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 pureStream; - }; -} diff --git a/apps/pingvin/nodes/Processable.cpp b/apps/pingvin/nodes/Processable.cpp deleted file mode 100644 index 547cb7367..000000000 --- a/apps/pingvin/nodes/Processable.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Processable.h" - - -std::thread Gadgetron::Main::Processable::process_async( - std::shared_ptr processable, - Core::GenericInputChannel input, - Core::OutputChannel output, - const ErrorHandler &error_handler -) { - 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); - }, - std::move(input), - std::move(output), - nested_handler - ); -} diff --git a/apps/pingvin/nodes/Processable.h b/apps/pingvin/nodes/Processable.h deleted file mode 100644 index 76a6b69c6..000000000 --- a/apps/pingvin/nodes/Processable.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "ErrorHandler.h" -#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, - ErrorHandler &error_handler - ) = 0; - - virtual const std::string& name() = 0; - - static std::thread process_async( - std::shared_ptr processable, - Core::GenericInputChannel input, - Core::OutputChannel output, - const ErrorHandler &errorHandler - ); - }; -} \ No newline at end of file diff --git a/apps/pingvin/nodes/PureStream.cpp b/apps/pingvin/nodes/PureStream.cpp deleted file mode 100644 index 815ca93a0..000000000 --- a/apps/pingvin/nodes/PureStream.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#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 { - return std::accumulate( - 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 deleted file mode 100644 index c861271d0..000000000 --- a/apps/pingvin/nodes/PureStream.h +++ /dev/null @@ -1,16 +0,0 @@ -#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&, Loader&); - Core::Message process_function(Core::Message) const; - - private: - const std::vector> pure_gadgets; - }; -} diff --git a/apps/pingvin/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp deleted file mode 100644 index fbdebb995..000000000 --- a/apps/pingvin/nodes/Stream.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "Stream.h" - -#include "Parallel.h" -#include "ParallelProcess.h" -#include "Processable.h" - -#include "Loader.h" - -#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_; - }; - - 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) - ); - } - - 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); - } - - 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 - ) { - if (empty()) return; - - std::vector input_channels{}; - input_channels.emplace_back(std::move(input)); - std::vector output_channels{}; - - for (auto 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)); - } - - 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( - nodes[i], - std::move(input_channels[i]), - std::move(output_channels[i]), - nested_handler - ); - } - - for (auto &thread : threads) { - thread.join(); - } - } - - 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; -} diff --git a/apps/pingvin/nodes/Stream.h b/apps/pingvin/nodes/Stream.h deleted file mode 100644 index cbeb35ca9..000000000 --- a/apps/pingvin/nodes/Stream.h +++ /dev/null @@ -1,37 +0,0 @@ - -#pragma once - -#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 &, const Core::StreamContext &, Loader &); - - void process( - Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler & - ) override; - - bool empty() const; - const std::string &name() override; - - private: - std::vector> nodes; - }; -} diff --git a/apps/pingvin/pipelines/file_search.h b/apps/pingvin/pipelines/file_search.h new file mode 100644 index 000000000..ac2f17b1a --- /dev/null +++ b/apps/pingvin/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 initContext(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() + , 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 = PipelineBuilder("text-search", "Search for strings in text") + .withSource() + .withSink() + .withNode("search") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/cartesian_grappa.h b/apps/pingvin/pipelines/mri/cartesian_grappa.h new file mode 100644 index 000000000..79538f6bd --- /dev/null +++ b/apps/pingvin/pipelines/mri/cartesian_grappa.h @@ -0,0 +1,67 @@ +#pragma once + +#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" +#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/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h" + +namespace Pingvin { + +static auto cartesian_grappa = PipelineBuilder("cartesian-grappa", "Cartesian Grappa Recon") + .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") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +static auto cartesian_grappa_snr = PipelineBuilder("cartesian-grappa-snr", "Cartesian Grappa Recon with SNR") + .withSource() + .withSink() + .withNode("noise") + .withNode("echo-adjust") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("refprep") + .withNode("grappa") + .withNode("pf") + .withNode("kspace-filter") + .withNode("fov-adjust") + .withNode("std-map") + .withNode("scale") + .withNode("split") + .withNode("complex-to-float") + .withNode("convert") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/cartesian_spirit.h b/apps/pingvin/pipelines/mri/cartesian_spirit.h new file mode 100644 index 000000000..b701b860c --- /dev/null +++ b/apps/pingvin/pipelines/mri/cartesian_spirit.h @@ -0,0 +1,68 @@ +#pragma once + +#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" +#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/mri/cmr.h b/apps/pingvin/pipelines/mri/cmr.h new file mode 100644 index 000000000..c5709760e --- /dev/null +++ b/apps/pingvin/pipelines/mri/cmr.h @@ -0,0 +1,91 @@ +#pragma once + +#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" +#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/mri/config/cartesian-cine-denoise.conf b/apps/pingvin/pipelines/mri/config/cartesian-cine-denoise.conf new file mode 100644 index 000000000..a6d81106d --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-grappa-snr.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa-snr.conf new file mode 100644 index 000000000..4dcc5975b --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-grappa-t2w.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa-t2w.conf new file mode 100644 index 000000000..c5ac7bf8b --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-grappa.conf b/apps/pingvin/pipelines/mri/config/cartesian-grappa.conf new file mode 100644 index 000000000..3881f8ebe --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/mri/config/cartesian-nonlinear-spirit-realtimecine.conf new file mode 100644 index 000000000..c93d76112 --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf b/apps/pingvin/pipelines/mri/config/cartesian-randomsampling-nonlinear-spirit-realtimecine.conf new file mode 100644 index 000000000..583ed9e42 --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cartesian-spirit.conf b/apps/pingvin/pipelines/mri/config/cartesian-spirit.conf new file mode 100644 index 000000000..d5a363ca1 --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cmr-cine-binning.conf b/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf new file mode 100644 index 000000000..87d5cb9f3 --- /dev/null +++ b/apps/pingvin/pipelines/mri/config/cmr-cine-binning.conf @@ -0,0 +1,43 @@ +# 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 +# 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-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/mri/config/cmr-mapping-t1-sr.conf b/apps/pingvin/pipelines/mri/config/cmr-mapping-t1-sr.conf new file mode 100644 index 000000000..1b4b7e1ca --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/cmr-rtcine-lax-ai.conf b/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf new file mode 100644 index 000000000..30f04a490 --- /dev/null +++ b/apps/pingvin/pipelines/mri/config/cmr-rtcine-lax-ai.conf @@ -0,0 +1,26 @@ +# Replaces CMR_RTCine_LAX_AI.xml + +[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/mri/config/epi.conf b/apps/pingvin/pipelines/mri/config/epi.conf new file mode 100644 index 000000000..34efb3276 --- /dev/null +++ b/apps/pingvin/pipelines/mri/config/epi.conf @@ -0,0 +1,12 @@ +# Replaces epi.xml + +[acctrig] +trigger-dimension=repetition +sorting-dimension=slice + +[buffer] +split-slices=true +ignore-segment=true + +[convert] +type=ushort diff --git a/apps/pingvin/pipelines/mri/config/grappa-epi.conf b/apps/pingvin/pipelines/mri/config/grappa-epi.conf new file mode 100644 index 000000000..7f272deb8 --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/mri/config/stream-cartesian-grappa.conf b/apps/pingvin/pipelines/mri/config/stream-cartesian-grappa.conf new file mode 100644 index 000000000..292ee7650 --- /dev/null +++ b/apps/pingvin/pipelines/mri/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/pingvin/pipelines/mri/default.h b/apps/pingvin/pipelines/mri/default.h new file mode 100644 index 000000000..c690474d6 --- /dev/null +++ b/apps/pingvin/pipelines/mri/default.h @@ -0,0 +1,47 @@ +#pragma once + +#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" +#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 { + + using namespace Gadgetron; + +static auto default_mr = PipelineBuilder("default", "Basic Cartesian Reconstruction") + .withSource() + .withSink() + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("recon") + .withNode("image-split") + .withNode("extract") + ; + +static auto default_mr_optimized = PipelineBuilder("default-optimized", "Basic Cartesian Reconstruction") + .withSource() + .withSink() + .withNode("noise-adjust") + .withNode("pca") + .withNode("coil-reduction") + .withNode("ros") + .withNode("acctrig") + .withNode("buffer") + .withNode("recon") + .withNode("image-split") + .withNode("extract") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/denoise.h b/apps/pingvin/pipelines/mri/denoise.h new file mode 100644 index 000000000..cc61e6a81 --- /dev/null +++ b/apps/pingvin/pipelines/mri/denoise.h @@ -0,0 +1,51 @@ +#pragma once + +#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" +#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/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/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 { + +using namespace Gadgetron; + +static auto grappa_denoise = PipelineBuilder("cartesian-grappa-cine-denoise", "Cartesian Grappa with Cine Denoising") + .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") + .withNode("split") + .withMultiprocessStream() + .withPureNode("denoise") + .withWorkers(6) + .withNode("complex-to-float") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/epi.h b/apps/pingvin/pipelines/mri/epi.h new file mode 100644 index 000000000..6db0a7340 --- /dev/null +++ b/apps/pingvin/pipelines/mri/epi.h @@ -0,0 +1,41 @@ +#pragma once + +#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" +#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 = PipelineBuilder("epi", "Basic EPI Reconstruction") + .withSource() + .withSink() + .withNode("noise") + .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/apps/pingvin/pipelines/mri/grappa.h b/apps/pingvin/pipelines/mri/grappa.h new file mode 100644 index 000000000..cd4919fa2 --- /dev/null +++ b/apps/pingvin/pipelines/mri/grappa.h @@ -0,0 +1,75 @@ +#pragma once + +#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" +#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_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") + + // 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") + ; + +#ifdef USE_CUDA + +static auto grappa_gpu = PipelineBuilder("grappa-gpu", "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") + ; +#endif // USE_CUDA + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/grappa_epi.h b/apps/pingvin/pipelines/mri/grappa_epi.h new file mode 100644 index 000000000..749d83859 --- /dev/null +++ b/apps/pingvin/pipelines/mri/grappa_epi.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Pipeline.h" + +#include "MRSource.h" +#include "MRSink.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/pingvin/pipelines/mri/noise.h b/apps/pingvin/pipelines/mri/noise.h new file mode 100644 index 000000000..c0ecbecbe --- /dev/null +++ b/apps/pingvin/pipelines/mri/noise.h @@ -0,0 +1,20 @@ +#pragma once + +#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() + .withNode("noise") + ; + +} // namespace pingvin \ No newline at end of file diff --git a/apps/pingvin/pipelines/mri/parallel_bypass.h b/apps/pingvin/pipelines/mri/parallel_bypass.h new file mode 100644 index 000000000..0b858b124 --- /dev/null +++ b/apps/pingvin/pipelines/mri/parallel_bypass.h @@ -0,0 +1,42 @@ +#pragma once + +#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" +#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 "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/pingvin/pipelines/mri/streams.h b/apps/pingvin/pipelines/mri/streams.h new file mode 100644 index 000000000..b01cb7108 --- /dev/null +++ b/apps/pingvin/pipelines/mri/streams.h @@ -0,0 +1,75 @@ +#pragma once + +#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" +#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/pipelines/registry.h b/apps/pingvin/pipelines/registry.h new file mode 100644 index 000000000..29e249762 --- /dev/null +++ b/apps/pingvin/pipelines/registry.h @@ -0,0 +1,88 @@ +#pragma once + +#include "Pipeline.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 { + +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_cpu); +#ifdef USE_CUDA + register_pipeline(&grappa_gpu); +#endif // USE_CUDA + + 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/schema/gadgetron.xsd b/apps/pingvin/schema/gadgetron.xsd deleted file mode 100644 index 6b9602a37..000000000 --- a/apps/pingvin/schema/gadgetron.xsd +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 7cbfcf65d..e1510bbbc 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 9b7848a93..5b2bba1aa 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 ed2dbed09..1751e190d 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 6114a5822..bd5c2a990 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 441fbb2cc..62ff6561b 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/core/CMakeLists.txt b/core/CMakeLists.txt index 31015e01a..6d439bd23 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 + parallel/UnorderedMerge.cpp + system_info.cpp io/from_string.cpp) set_target_properties(pingvin_core PROPERTIES @@ -12,15 +19,17 @@ set_target_properties(pingvin_core PROPERTIES SOVERSION ${PINGVIN_SOVERSION}) target_link_libraries(pingvin_core - mrd::mrd pingvin_toolbox_cpucore Boost::boost Boost::filesystem ) -target_include_directories(pingvin_core PUBLIC +target_include_directories(pingvin_core + PUBLIC $ $ + PRIVATE + ${CMAKE_BINARY_DIR} ) install(TARGETS pingvin_core @@ -39,14 +48,29 @@ install(FILES Message.h Message.hpp MPMCChannel.h - Context.h + Source.h + Sink.h Node.h PureGadget.h - PropertyMixin.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 + 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 4a711e51d..000000000 --- a/core/Context.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include - -#include - -namespace Gadgetron::Core { - - 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/MultiprocessStream.cpp b/core/MultiprocessStream.cpp new file mode 100644 index 000000000..c0eb081e2 --- /dev/null +++ b/core/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/core/MultiprocessStream.h b/core/MultiprocessStream.h new file mode 100644 index 000000000..024088853 --- /dev/null +++ b/core/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/core/Node.h b/core/Node.h index 091c0b86d..c8c07a5b0 100644 --- a/core/Node.h +++ b/core/Node.h @@ -1,10 +1,9 @@ #pragma once +#include "Parameters.h" #include "Channel.h" -#include "PropertyMixin.h" -#include "Context.h" -#include +namespace po = boost::program_options; namespace Gadgetron::Core { /** @@ -13,7 +12,12 @@ namespace Gadgetron::Core { class Node { public: + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; + 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 @@ -22,29 +26,15 @@ namespace Gadgetron::Core { virtual void process(GenericInputChannel& in, OutputChannel& out) = 0; }; - 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) {} - protected: - const mrd::Header header ={}; - }; - /** * 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) final { + void process(GenericInputChannel& in, OutputChannel& out) override final { auto typed_input = InputChannel(in, out); this->process(typed_input, out); } @@ -56,14 +46,4 @@ namespace Gadgetron::Core { */ virtual void process(InputChannel& in, OutputChannel& out) = 0; }; - -} - -#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) +} \ No newline at end of file diff --git a/core/ParallelStream.cpp b/core/ParallelStream.cpp new file mode 100644 index 000000000..d6da8b70e --- /dev/null +++ b/core/ParallelStream.cpp @@ -0,0 +1,84 @@ +#include "ParallelStream.h" + +#include +#include +#include + +#include "Channel.h" + +namespace { + template + auto transform_map(std::map& input, F f) { + using TRANSFORMED = std::remove_reference_tsecond))>; + auto result = std::map(); + + for (auto &key_val : input) result.emplace(key_val.first, f(key_val.second)); + + return result; + } +} + +namespace { + using namespace Gadgetron::Core; + + ChannelPair split(const ChannelPair &in) { + return ChannelPair{ split(in.input), split(in.output) }; + } + + void emplace_channels( + const Stream &stream, + std::map &input, + std::map &output + ) { + ChannelPair in_pair = make_channel(); + ChannelPair out_pair = make_channel(); + + if (stream.empty()) out_pair = split(in_pair); + + input.emplace(stream.key, std::move(in_pair)); + output.emplace(stream.key, std::move(out_pair)); + } +} + +namespace Gadgetron::Core { + + void ParallelStream::process(GenericInputChannel& input, OutputChannel& output) { + std::vector threads; + std::map input_channels; + std::map output_channels; + + for (auto &stream : streams) { + emplace_channels(*stream, input_channels, output_channels); + } + + threads.emplace_back(std::thread( + [&](auto input, auto output, auto bypass) { + branch->process(std::move(input), std::move(output), std::move(bypass)); + }, + std::move(input), + transform_map(input_channels, [](auto& val) { return std::move(val.output); }), + split(output) + )); + + threads.emplace_back(std::thread( + [&](auto input, auto output) { + merge->process(std::move(input), std::move(output)); + }, + transform_map(output_channels, [](auto &val) { return std::move(val.input); }), + std::move(output) + )); + + for (auto &stream : streams) { + threads.emplace_back(std::thread( + [&](auto stream, auto input, auto output) { + stream->process(input, output); + }, + stream, + std::move(input_channels.at(stream->key).input), + std::move(output_channels.at(stream->key).output) + )); + } + + for (auto &thread : threads) { thread.join(); } + } +} \ No newline at end of file diff --git a/core/ParallelStream.h b/core/ParallelStream.h new file mode 100644 index 000000000..b4107c715 --- /dev/null +++ b/core/ParallelStream.h @@ -0,0 +1,34 @@ +#pragma once + +#include "Node.h" + +#include "Stream.h" + +#include "parallel/Branch.h" +#include "parallel/Merge.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/core/Parameters.h b/core/Parameters.h new file mode 100644 index 000000000..138e47a3b --- /dev/null +++ b/core/Parameters.h @@ -0,0 +1,151 @@ +#pragma once + +#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 { + 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& 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( + 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_; +}; + +template +class MultitokenParameter : public IParameter { +public: + 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( + 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::vector default_value_; +}; + +class Flag : public Parameter { +public: + using Parameter::Parameter; + + boost::shared_ptr as_boost_option(void) const override + { + return boost::make_shared( + fullname_.c_str(), + po::bool_switch(this->storage_)->default_value(this->default_value_), + 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) {} + NodeParameters(): prefix_("unknown") {}; + + template + void register_parameter(const std::string& name, T* value, const std::string& 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) { + parameters_.push_back(std::make_shared>(prefix_, name, description, value)); + } + + void register_flag(const std::string& name, bool* value, const std::string& description) { + parameters_.push_back(std::make_shared(prefix_, name, description, value)); + } + + const std::vector>& parameters() const { + return parameters_; + } + + std::string prefix(void) const { return prefix_; } + 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/Pipeline.h b/core/Pipeline.h new file mode 100644 index 000000000..20f13c09a --- /dev/null +++ b/core/Pipeline.h @@ -0,0 +1,500 @@ +#pragma once + +#include +#include + +#include +namespace po = boost::program_options; + +#include "system_info.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 { + +template +struct NodeParametersBuilder { + NodeParametersBuilder(const std::string& label): label_(label), parameters_(label) {} + + void collect_options(po::options_description& parent) { + 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) { + 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; + } + } + + const std::string label_; + typename CLS::Parameters parameters_; +}; + +template +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 +class NodeBuilder : public INodeBuilder, NodeParametersBuilder { +public: + 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 { + NodeParametersBuilder::collect_options(parent); + } + + void dump_config(std::ostream& os, bool only_modified) override { + NodeParametersBuilder::dump_config(os, only_modified); + } +}; + +template +class StreamBuilder : public INodeBuilder { +public: + StreamBuilder() {} + StreamBuilder(const std::string& key): key_(key) {} + + void collect_options(po::options_description& stream_desc) override { + for (auto& nb: builders_) { + nb->collect_options(stream_desc); + } + } + + 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> nodes; + for (auto& builder : builders_) { + nodes.emplace_back( + builder->build(ctx) + ); + } + return std::make_shared(nodes, 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; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; +}; + +template +class BranchBuilder : public IBranchBuilder, NodeParametersBuilder { +public: + 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 { + NodeParametersBuilder::collect_options(parent); + } + + void dump_config(std::ostream& os, bool only_modified) override { + NodeParametersBuilder::dump_config(os, only_modified); + } +}; + +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; + virtual void dump_config(std::ostream& os, bool only_modified=false) = 0; +}; + +template +class MergeBuilder : public IMergeBuilder, NodeParametersBuilder { +public: + 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 { + NodeParametersBuilder::collect_options(parent); + } + + void dump_config(std::ostream& os, bool only_modified) override { + NodeParametersBuilder::dump_config(os, only_modified); + } +}; + +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; + } + + template + PipelineBuilder& withMerge(const std::string& label) { + merge_builder_ = std::make_unique>(label); + return parent_; + } + + ParallelBuilder& withStream(const std::string& key) { + stream_builders_.emplace_back(key); + return *this; + } + + 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); + + return std::make_shared(std::move(branch), std::move(merge), std::move(streams)); + } + + void collect_options(po::options_description& parent) override { + 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); + } + + 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::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, NodeParametersBuilder { +public: + 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 { + NodeParametersBuilder::collect_options(parent); + } + + void dump_config(std::ostream& os, bool only_modified) override { + NodeParametersBuilder::dump_config(os, only_modified); + } +}; + +template +class MultiprocessStreamBuilder : public INodeBuilder { +public: + MultiprocessStreamBuilder(PipelineBuilder& parent) + : parent_(parent) + {} + + template + MultiprocessStreamBuilder& 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::Core::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_; +}; + +// Forward declaration +class Pipeline; + +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 void dump_config(std::ostream& os, bool only_modified = false) = 0; + virtual ~IPipelineBuilder() = default; + + std::string name(void) const { return name_; } + std::string description(void) const { return description_; } + +protected: + std::string name_; + std::string description_; +}; + + +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) { + auto input_channel = Gadgetron::Core::make_channel(); + auto output_channel = Gadgetron::Core::make_channel(); + + auto process_future = std::async(std::launch::async, [&]() { + try { + // 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. + auto destruct_me = std::move(output_channel.output); + throw; + } + }); + + auto input_future = std::async(std::launch::async, [&]() { + try { + source_->consume_input(input_channel); + } 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; + } + }); + + 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_; } + std::string description(void) const { return description_; } + + protected: + + std::string name_; + std::string description_; + + std::shared_ptr source_; + std::shared_ptr sink_; + + std::shared_ptr stream_; +}; + +template +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); }; + 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); + } + + MultiprocessStreamBuilder& withMultiprocessStream(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_); + + 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"); + } + if (!sink_builder_) { + throw std::runtime_error("No sink specified"); + } + auto source = source_builder_(input_stream); + + CTX ctx; + source->initContext(ctx); + + auto sink = sink_builder_(output_stream, ctx); + + Pipeline pipeline(source, sink, streambuilder_.build(ctx)); + return std::move(pipeline); + } + +private: + 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/core/PropertyMixin.h b/core/PropertyMixin.h deleted file mode 100644 index d3678d9bf..000000000 --- a/core/PropertyMixin.h +++ /dev/null @@ -1,35 +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)); - } - - private: - const 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) diff --git a/core/PureGadget.h b/core/PureGadget.h index 8fa7f9cd6..618befd67 100644 --- a/core/PureGadget.h +++ b/core/PureGadget.h @@ -2,26 +2,24 @@ #include "Node.h" namespace Gadgetron::Core { -class GenericPureGadget : public GenericChannelGadget { -public: - using GenericChannelGadget::GenericChannelGadget; - 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)))); @@ -32,6 +30,6 @@ class PureGadget : public GenericPureGadget { * @return The processed message */ virtual RETURN process_function(INPUT args) const = 0; - }; + } diff --git a/core/PureStream.cpp b/core/PureStream.cpp new file mode 100644 index 000000000..f56d4f783 --- /dev/null +++ b/core/PureStream.cpp @@ -0,0 +1,17 @@ +#include "PureStream.h" + +namespace Gadgetron::Core { + +Message PureStream::process_function(Message message) const +{ + return std::accumulate( + pure_gadgets_.begin(), + pure_gadgets_.end(), + std::move(message), + [](auto&& message, auto&& gadget) { + return gadget->process_function(std::move(message)); + } + ); +} + +} \ No newline at end of file diff --git a/core/PureStream.h b/core/PureStream.h new file mode 100644 index 000000000..a988224fd --- /dev/null +++ b/core/PureStream.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Message.h" +#include "PureGadget.h" + +namespace Gadgetron::Core { + 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_; + }; +} diff --git a/core/Sink.h b/core/Sink.h new file mode 100644 index 000000000..3e03e159c --- /dev/null +++ b/core/Sink.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Channel.h" + +namespace Pingvin { + +struct ISink { + virtual ~ISink() = default; + virtual void produce_output(Gadgetron::Core::ChannelPair& output_channel) = 0; +}; + +} \ No newline at end of file diff --git a/core/Source.h b/core/Source.h new file mode 100644 index 000000000..02bc973c3 --- /dev/null +++ b/core/Source.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Channel.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; +}; + +} \ No newline at end of file diff --git a/core/Stream.cpp b/core/Stream.cpp new file mode 100644 index 000000000..400ba9e82 --- /dev/null +++ b/core/Stream.cpp @@ -0,0 +1,45 @@ +#include "Stream.h" + +#include + + +namespace Gadgetron::Core { + + void Stream::process(GenericInputChannel& input, OutputChannel& output) { + if (empty()) return; + + std::vector input_channels{}; + input_channels.emplace_back(std::move(input)); + std::vector output_channels{}; + + 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)); + } + + output_channels.emplace_back(std::move(output)); + + std::vector threads(nodes.size()); + for (size_t i = 0; i < nodes.size(); i++) { + threads[i] = std::thread( + [](auto node, auto input_channel, auto output_channel) { + try { + node->process(input_channel, output_channel); + } catch (const Core::ChannelClosed &e) { + // Ignored + } + }, + nodes[i], + std::move(input_channels[i]), + std::move(output_channels[i]) + ); + } + + for (auto &thread : threads) { + thread.join(); + } + } + + bool Stream::empty() const { return nodes.empty(); } +} \ No newline at end of file diff --git a/core/Stream.h b/core/Stream.h new file mode 100644 index 000000000..88e133f4e --- /dev/null +++ b/core/Stream.h @@ -0,0 +1,28 @@ + +#pragma once + +#include + +#include "Node.h" + +namespace Gadgetron::Core { + + class Stream : public Node { + public: + const std::string key; + + Stream(std::vector> nodes, const std::string key="") + : key(key), nodes(std::move(nodes)) + {} + + void process( + Core::GenericInputChannel& input, + Core::OutputChannel& output + ) override; + + bool empty() const; + + private: + std::vector> nodes; + }; +} diff --git a/core/ThreadPool.h b/core/ThreadPool.h index 5a9fb3912..7958663d1 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/core/parallel/Branch.cpp b/core/parallel/Branch.cpp deleted file mode 100644 index 8f5db918b..000000000 --- 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 fd97615b5..95318db63 100644 --- a/core/parallel/Branch.h +++ b/core/parallel/Branch.h @@ -1,17 +1,18 @@ #pragma once #include -#include -#include #include "Channel.h" -#include "Context.h" -#include "PropertyMixin.h" +#include "Parameters.h" namespace Gadgetron::Core::Parallel { - class Branch : public PropertyMixin { + class Branch { public: + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; + virtual ~Branch() = default; virtual void process( GenericInputChannel input, @@ -20,40 +21,20 @@ 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; }; -} - -#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 \ -) +} \ No newline at end of file diff --git a/core/parallel/Branch.hpp b/core/parallel/Branch.hpp deleted file mode 100644 index 845f35d85..000000000 --- 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 deleted file mode 100644 index 28b630ee8..000000000 --- a/core/parallel/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ - -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) - -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 - Branch.hpp - Merge.h - Fanout.h - Fanout.hpp - 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 d13369531..000000000 --- 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 deleted file mode 100644 index 947113ead..000000000 --- a/core/parallel/Fanout.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -#include "Branch.h" - -#include "Channel.h" - -namespace Gadgetron::Core::Parallel { - - template - class Fanout : public TypedBranch { - public: - Fanout(const Context &context, const GadgetProperties &props); - void process(InputChannel &, std::map) override; - }; - - using AcquisitionFanout = Core::Parallel::Fanout; - using WaveformFanout = Core::Parallel::Fanout; - using ImageFanout = Core::Parallel::Fanout; -} - -#include "Fanout.hpp" diff --git a/core/parallel/Fanout.hpp b/core/parallel/Fanout.hpp deleted file mode 100644 index 2a2cb97ce..000000000 --- a/core/parallel/Fanout.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -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) { - 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 e338a2a20..000000000 --- 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 01f413352..99b2cd438 100644 --- a/core/parallel/Merge.h +++ b/core/parallel/Merge.h @@ -1,35 +1,19 @@ #pragma once #include -#include -#include #include "Channel.h" -#include "Context.h" -#include "PropertyMixin.h" +#include "Parameters.h" namespace Gadgetron::Core::Parallel { - class Merge : public PropertyMixin { + class Merge { public: - explicit Merge(const GadgetProperties &props); + struct Parameters : NodeParameters { + using NodeParameters::NodeParameters; + }; virtual ~Merge() = default; virtual void process(std::map, OutputChannel) = 0; }; -} - -#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 \ -) +} \ No newline at end of file diff --git a/core/parallel/UnorderedMerge.cpp b/core/parallel/UnorderedMerge.cpp index c9f9a7bfe..94adadb64 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 bb8a9f820..4e55bf300 100644 --- a/core/parallel/UnorderedMerge.h +++ b/core/parallel/UnorderedMerge.h @@ -1,16 +1,12 @@ #pragma once -#include -#include -#include - #include "Merge.h" 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/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 eead2bbfd..2e360284f 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 93% rename from apps/pingvin/system_info.cpp rename to core/system_info.cpp index c7ac99f61..594e0e0a2 100644 --- a/apps/pingvin/system_info.cpp +++ b/core/system_info.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #if defined(BSD) #include @@ -24,7 +24,7 @@ #endif -namespace Gadgetron::Main::Info { +namespace Pingvin::Main { std::string pingvin_version() { return PINGVIN_VERSION_STRING; @@ -212,24 +212,26 @@ namespace Gadgetron::Main::Info { #endif } // namespace - const boost::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) { - 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(); - 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 73% rename from apps/pingvin/system_info.h rename to core/system_info.h index 6f58aac7f..306f549b5 100644 --- a/apps/pingvin/system_info.h +++ b/core/system_info.h @@ -1,9 +1,9 @@ #pragma once #include -#include +#include -namespace Gadgetron::Main::Info { +namespace Pingvin::Main { void print_system_information(std::ostream &); @@ -11,10 +11,9 @@ namespace Gadgetron::Main::Info { std::string pingvin_build(); size_t system_memory(); - bool python_support(); - bool matlab_support(); - const boost::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/doc/source/gadget.rst b/doc/source/gadget.rst index 06ffffb64..742cd1a93 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/environment.yml b/environment.yml index 9adeff126..4f8763976 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/.gitignore b/gadgets/.gitignore deleted file mode 100644 index afaf4316f..000000000 --- a/gadgets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gputest/test \ No newline at end of file diff --git a/gadgets/cmr/CMakeLists.txt b/gadgets/cmr/CMakeLists.txt index 1445d6b95..35427fb9d 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,37 +30,23 @@ 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}) target_link_libraries(pingvin_cmr - pingvin_core + pingvin_mri pingvin_mricore pingvin_toolbox_log pingvin_toolbox_cpucore @@ -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/CmrCartesianKSpaceBinningCineGadget.cpp b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.cpp index 806647c30..8056d8af7 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::MRContext &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); } } } @@ -424,5 +425,4 @@ namespace Gadgetron { return GADGET_OK; } - GADGETRON_GADGET_EXPORT(CmrCartesianKSpaceBinningCineGadget) } diff --git a/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h b/gadgets/cmr/CmrCartesianKSpaceBinningCineGadget.h index 453371583..1b5b2facd 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::MRContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variable for recon diff --git a/gadgets/cmr/CmrParametricMappingGadget.cpp b/gadgets/cmr/CmrParametricMappingGadget.cpp index 5ebf33e77..4a54a722e 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::MRContext &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 b13abf872..83d3d3cf2 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::MRContext &context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp b/gadgets/cmr/CmrParametricT1SRMappingGadget.cpp index 45340038e..5357188a3 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::MRContext& 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 (...) { @@ -269,6 +270,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrParametricT1SRMappingGadget) } diff --git a/gadgets/cmr/CmrParametricT1SRMappingGadget.h b/gadgets/cmr/CmrParametricT1SRMappingGadget.h index 979684445..fc582d5a9 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::MRContext& context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.cpp b/gadgets/cmr/CmrParametricT2MappingGadget.cpp index b6330de5c..6aa721eac 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::MRContext& 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 (...) { @@ -273,6 +274,5 @@ namespace Gadgetron { } // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrParametricT2MappingGadget) } diff --git a/gadgets/cmr/CmrParametricT2MappingGadget.h b/gadgets/cmr/CmrParametricT2MappingGadget.h index a06eaab4c..c24233ac4 100644 --- a/gadgets/cmr/CmrParametricT2MappingGadget.h +++ b/gadgets/cmr/CmrParametricT2MappingGadget.h @@ -15,17 +15,22 @@ namespace Gadgetron { public: typedef CmrParametricMappingGadget BaseClass; - CmrParametricT2MappingGadget(const Core::Context& context, const Core::GadgetProperties& properties); + 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)"); + } - /// ------------------------------------------------------------------------------------ - /// parameters to control the mapping - /// ------------------------------------------------------------------------------------ + size_t max_iter = 150; + double thres_func = 1e-4; + double max_T2 = 4000; + }; - 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::MRContext& context, const Parameters& params); protected: + const Parameters params_; // -------------------------------------------------- // variables for protocol diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.cpp index 8dd2ef44d..fd7aedac3 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::MRContext& 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; @@ -556,5 +557,4 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(CmrRealTimeLAXCineAIAnalysisGadget) } diff --git a/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h b/gadgets/cmr/CmrRealTimeLAXCineAIAnalysisGadget.h index c9d8b7706..fb427a770 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::MRContext &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 290a55ac1..358204869 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::MRContext& 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 9894cbd1e..fcf63e0a7 100644 --- a/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h +++ b/gadgets/cmr/PureCmrCartesianKSpaceBinningCineGadget.h @@ -1,96 +1,122 @@ -// -// Created by dchansen on 2/21/19. -// - #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "cmr_kspace_binning.h" #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::MRContext& 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/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml b/gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning.xml deleted file mode 100644 index 73f2fad94..000000000 --- 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 a5a52b9ae..000000000 --- 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 db6c0909b..000000000 --- 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 67d94e385..000000000 --- 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 fa981f9bc..000000000 --- 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/gadgetron_cmr_landmark_detection_util.py b/gadgets/cmr/config/LandmarkDetection/gadgetron_cmr_landmark_detection_util.py index 1fe36ba5c..3d696c4d5 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/cmr/config/LandmarkDetection/stream_image_array.xml b/gadgets/cmr/config/LandmarkDetection/stream_image_array.xml deleted file mode 100644 index cc97dd6c2..000000000 --- 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 5035a0cd7..000000000 --- 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/debugging/CMakeLists.txt b/gadgets/debugging/CMakeLists.txt index b17a4dfa4..a128571d6 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.cpp b/gadgets/debugging/PseudoReplicatorGadget.cpp index e039ed3be..769d6dbb7 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; @@ -33,5 +28,4 @@ void PseudoReplicatorGadget::process(Core::InputChannel& input, } } -GADGETRON_GADGET_EXPORT(PseudoReplicatorGadget) } // namespace Gadgetron diff --git a/gadgets/debugging/PseudoReplicatorGadget.h b/gadgets/debugging/PseudoReplicatorGadget.h index d74404407..3afced4a2 100644 --- a/gadgets/debugging/PseudoReplicatorGadget.h +++ b/gadgets/debugging/PseudoReplicatorGadget.h @@ -1,16 +1,27 @@ #pragma once -#include "Node.h" +#include "MRNode.h" 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::MRContext& 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 2b5e0688f..c8120841d 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::MRContext& 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) @@ -19,5 +20,4 @@ void RateLimitGadget::process(Core::InputChannel& in, Core::Out } } -GADGETRON_GADGET_EXPORT(RateLimitGadget) } // namespace Gadgetron diff --git a/gadgets/debugging/RateLimitGadget.h b/gadgets/debugging/RateLimitGadget.h index 01436bb86..476113e06 100644 --- a/gadgets/debugging/RateLimitGadget.h +++ b/gadgets/debugging/RateLimitGadget.h @@ -1,21 +1,27 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" 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::MRContext& 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 7e782c08a..a0d233251 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::MRContext& 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 ) { @@ -236,5 +237,4 @@ void WhiteNoiseInjectorGadget::process(Core::InputChannel& in, } } -GADGETRON_GADGET_EXPORT(WhiteNoiseInjectorGadget) } diff --git a/gadgets/debugging/WhiteNoiseInjectorGadget.h b/gadgets/debugging/WhiteNoiseInjectorGadget.h index 71d101d22..72809f34f 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 @@ -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::MRContext& 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/epi/CMakeLists.txt b/gadgets/epi/CMakeLists.txt index 7f7f6a931..6f7dc68a8 100644 --- a/gadgets/epi/CMakeLists.txt +++ b/gadgets/epi/CMakeLists.txt @@ -5,15 +5,12 @@ 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}) -target_link_libraries( - pingvin_epi - pingvin_core +target_link_libraries(pingvin_epi + pingvin_mri pingvin_mricore pingvin_toolbox_cpucore pingvin_toolbox_cpufft @@ -22,7 +19,6 @@ target_link_libraries( pingvin_toolbox_epi ) - install(FILES EPIReconXGadget.h EPICorrGadget.h @@ -35,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/CutXGadget.cpp b/gadgets/epi/CutXGadget.cpp index cbf0fc51d..cbd703d66 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::MRContext& context, const Core::NodeParameters& parameters) + : CutXGadget::MRChannelGadget(context, parameters) { auto& h = context.header; @@ -65,5 +65,4 @@ namespace Gadgetron{ } } - GADGETRON_GADGET_EXPORT(CutXGadget) } diff --git a/gadgets/epi/CutXGadget.h b/gadgets/epi/CutXGadget.h index 5bc1a0f15..4ac08cef1 100644 --- a/gadgets/epi/CutXGadget.h +++ b/gadgets/epi/CutXGadget.h @@ -1,21 +1,18 @@ -#ifndef CutXGADGET_H -#define CutXGADGET_H +#pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include 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::MRContext& 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_; @@ -25,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 35da5100d..4a9ed5be8 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::MRContext& 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) { @@ -638,5 +639,4 @@ namespace Gadgetron { } - GADGETRON_GADGET_EXPORT(EPICorrGadget) } diff --git a/gadgets/epi/EPICorrGadget.h b/gadgets/epi/EPICorrGadget.h index 104e82e0b..97d2ff8a5 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" @@ -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::MRContext& 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,12 +52,13 @@ namespace Gadgetron { void increase_no_repetitions(size_t delta_rep); + const Parameters parameters_; // -------------------------------------------------- // 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 bb6921260..6052713f5 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::MRContext& context, const Core::NodeParameters& params) + : EPIPackNavigatorGadget::MRChannelGadget(context, params) { auto& h = context.header; if (h.encoding.size() == 0) { @@ -88,5 +88,4 @@ void EPIPackNavigatorGadget::process(Core::InputChannel& input } } -GADGETRON_GADGET_EXPORT(EPIPackNavigatorGadget) } // namespace Gadgetron diff --git a/gadgets/epi/EPIPackNavigatorGadget.h b/gadgets/epi/EPIPackNavigatorGadget.h index 412a056d8..83a8f2787 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" @@ -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::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 2128d6d07..f8624bf7c 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::MRContext& context, const Core::NodeParameters& params) + : EPIReconXGadget::MRChannelGadget(context, params) { auto& h = context.header; @@ -132,7 +132,6 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(EPIReconXGadget) } // namespace Gadgetron diff --git a/gadgets/epi/EPIReconXGadget.h b/gadgets/epi/EPIReconXGadget.h index dc9a08dad..e6713ed57 100644 --- a/gadgets/epi/EPIReconXGadget.h +++ b/gadgets/epi/EPIReconXGadget.h @@ -1,18 +1,16 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "EPIReconXObjectTrapezoid.h" #include "EPIReconXObjectFlat.h" 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::MRContext& 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.cpp b/gadgets/epi/FFTXGadget.cpp index e3c806425..ff8f0b6ed 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/FFTXGadget.h b/gadgets/epi/FFTXGadget.h index edd8db35a..9acbb4fe6 100644 --- a/gadgets/epi/FFTXGadget.h +++ b/gadgets/epi/FFTXGadget.h @@ -1,16 +1,15 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include 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.cpp b/gadgets/epi/OneEncodingGadget.cpp index 4688b9f56..8ae101b30 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/epi/OneEncodingGadget.h b/gadgets/epi/OneEncodingGadget.h index 504435599..3ca168dce 100644 --- a/gadgets/epi/OneEncodingGadget.h +++ b/gadgets/epi/OneEncodingGadget.h @@ -5,14 +5,13 @@ #pragma once -#include "Node.h" +#include "MRNode.h" 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/epi/epi.xml b/gadgets/epi/epi.xml deleted file mode 100644 index 5e0b9b421..000000000 --- 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 ece6e2903..000000000 --- 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/AcquisitionWaveformBranch.cpp b/gadgets/examples/AcquisitionWaveformBranch.cpp index fa9c3d9e5..d126391f9 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 @@ -23,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/AcquisitionWaveformBranch.h b/gadgets/examples/AcquisitionWaveformBranch.h index b6ef07d52..1a13d545d 100644 --- a/gadgets/examples/AcquisitionWaveformBranch.h +++ b/gadgets/examples/AcquisitionWaveformBranch.h @@ -1,14 +1,17 @@ #pragma once -#include "parallel/Branch.h" +#include "MRParallel.h" 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::MRContext &context, const Core::NodeParameters ¶ms) + : MRBranch(context, params) + {} + void process( Core::InputChannel &, std::map diff --git a/gadgets/examples/CMakeLists.txt b/gadgets/examples/CMakeLists.txt index 1a9665f0a..3ee921303 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 @@ -23,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/ImageInverter.cpp b/gadgets/examples/ImageInverter.cpp index 67e8b7956..8425c3a94 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/ImageInverter.h b/gadgets/examples/ImageInverter.h index 37d0ddcd3..4fa72e9c4 100644 --- a/gadgets/examples/ImageInverter.h +++ b/gadgets/examples/ImageInverter.h @@ -1,11 +1,11 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.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 MRPureGadget::MRPureGadget; + mrd::AnyImage process_function(mrd::AnyImage image) const override; }; } diff --git a/gadgets/examples/ImageLayerer.cpp b/gadgets/examples/ImageLayerer.cpp index 8cba5efab..7aadaf3e1 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 { @@ -43,8 +41,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,13 +53,9 @@ namespace Gadgetron::Examples { inverted.pop() ); - - GINFO_STREAM("Images combined; pushing out result."); output.push(std::move(merged)); } } - - GADGETRON_MERGE_EXPORT(ImageLayerer) } diff --git a/gadgets/examples/ImageLayerer.h b/gadgets/examples/ImageLayerer.h index 81d90d421..daa8f8941 100644 --- a/gadgets/examples/ImageLayerer.h +++ b/gadgets/examples/ImageLayerer.h @@ -1,13 +1,15 @@ #pragma once -#include "Node.h" -#include "parallel/Merge.h" +#include "MRParallel.h" 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::MRContext &context, const Core::NodeParameters ¶ms) + : MRMerge(context, params) + {} + void process(std::map, Core::OutputChannel) override; }; } diff --git a/gadgets/examples/config/parallel_bypass_example.xml b/gadgets/examples/config/parallel_bypass_example.xml deleted file mode 100644 index 6345fbf6b..000000000 --- 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 621f5c8f9..000000000 --- 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 ea490ce0a..000000000 --- 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 dc0cb2cb2..000000000 --- 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 14f631415..000000000 --- a/gadgets/examples/config/stream_image_array_split.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - ImageArraySplit - pingvin_mricore - ImageArraySplitGadget - - - - diff --git a/gadgets/grappa/AcquisitionFanout.cpp b/gadgets/grappa/AcquisitionFanout.cpp deleted file mode 100644 index 9503b103a..000000000 --- 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/AcquisitionFanout.h b/gadgets/grappa/AcquisitionFanout.h index 198c1fdca..8fc001b82 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 b93cbe0a9..00fd34267 100644 --- a/gadgets/grappa/CMakeLists.txt +++ b/gadgets/grappa/CMakeLists.txt @@ -2,14 +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 - ChannelReorderer.cpp - ChannelReorderer.h cpu/WeightsCore.cpp cpu/WeightsCore.h) @@ -23,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 @@ -41,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/ChannelReorderer.cpp b/gadgets/grappa/ChannelReorderer.cpp deleted file mode 100644 index d2e0af2df..000000000 --- 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 0e4c09b79..000000000 --- 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/ImageAccumulator.cpp b/gadgets/grappa/ImageAccumulator.cpp index ab3eda253..4dd11d82d 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" @@ -19,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{}; @@ -47,23 +44,15 @@ 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);}); + 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/ImageAccumulator.h b/gadgets/grappa/ImageAccumulator.h index 6782848d4..3d1afc724 100644 --- a/gadgets/grappa/ImageAccumulator.h +++ b/gadgets/grappa/ImageAccumulator.h @@ -1,19 +1,22 @@ #pragma once #include "SliceAccumulator.h" +#include "common/AcquisitionBuffer.h" -#include "Channel.h" -#include "Node.h" +#include "MRNode.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::MRContext &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 4d7cd68ae..16e17d1db 100644 --- a/gadgets/grappa/SliceAccumulator.cpp +++ b/gadgets/grappa/SliceAccumulator.cpp @@ -1,11 +1,5 @@ #include "SliceAccumulator.h" -#include "common/AnnotatedAcquisition.h" -#include "common/grappa_common.h" - -#include "Context.h" -#include "Channel.h" - #include "hoNDArray.h" namespace { @@ -15,24 +9,18 @@ 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) { + 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 81774fc2e..f0a8a655c 100644 --- a/gadgets/grappa/SliceAccumulator.h +++ b/gadgets/grappa/SliceAccumulator.h @@ -1,23 +1,16 @@ #pragma once -#include - -#include "ChannelReorderer.h" - -#include "Node.h" +#include "MRNode.h" namespace Gadgetron::Grappa { - using Slice = std::vector; + using Slice = std::vector; - class SliceAccumulator : public Core::ChannelGadget { + class SliceAccumulator : public Core::MRChannelGadget { public: - SliceAccumulator(const Core::Context &, const std::unordered_map &); - - void process(Core::InputChannel &in, Core::OutputChannel &out) override; + using Core::MRChannelGadget::MRChannelGadget; - private: - const Core::Context context; + void process(Core::InputChannel &in, Core::OutputChannel &out) override; }; } diff --git a/gadgets/grappa/Unmixing.cpp b/gadgets/grappa/Unmixing.cpp index f3ebbc8ff..67d64960c 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; } @@ -52,14 +51,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, @@ -68,7 +59,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 +87,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 +111,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 +125,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 ca6913e26..d0c7c353c 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 { @@ -29,12 +25,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::MRContext &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 +49,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 cd3945279..97ce07a1d 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) { @@ -162,22 +206,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 +227,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 +251,9 @@ namespace Gadgetron::Grappa { } } - using cpuWeightsCalculator = WeightsCalculator; - GADGETRON_GADGET_EXPORT(cpuWeightsCalculator); +template class WeightsCalculator; #ifdef USE_CUDA - using gpuWeightsCalculator = WeightsCalculator; - GADGETRON_GADGET_EXPORT(gpuWeightsCalculator); + template class WeightsCalculator; #endif } \ No newline at end of file diff --git a/gadgets/grappa/WeightsCalculator.h b/gadgets/grappa/WeightsCalculator.h index cedf16c9d..7ce75a9f6 100644 --- a/gadgets/grappa/WeightsCalculator.h +++ b/gadgets/grappa/WeightsCalculator.h @@ -2,28 +2,53 @@ #include "SliceAccumulator.h" -#include "Context.h" -#include "Channel.h" -#include "Node.h" +#include "MRNode.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::MRContext &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 8462c9655..4d593b17d 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.cpp +++ b/gadgets/grappa/common/AcquisitionBuffer.cpp @@ -1,14 +1,11 @@ -#include "AcquisitionBuffer.h" - #include #include -#include "Context.h" #include "Channel.h" #include "hoNDArray.h" -#include "grappa_common.h" +#include "AcquisitionBuffer.h" #include #include @@ -29,18 +26,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."); @@ -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) { @@ -110,7 +107,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; @@ -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 b58593087..e4dd84231 100644 --- a/gadgets/grappa/common/AcquisitionBuffer.h +++ b/gadgets/grappa/common/AcquisitionBuffer.h @@ -4,9 +4,8 @@ #include #include -#include "AnnotatedAcquisition.h" +#include "mrd/types.h" -#include "Context.h" #include "Channel.h" #include "hoNDArray.h" @@ -15,9 +14,9 @@ namespace Gadgetron::Grappa { class AcquisitionBuffer { public: - explicit AcquisitionBuffer(Core::Context); + explicit AcquisitionBuffer(const mrd::Header& header); - void add(const AnnotatedAcquisition &acquisition); + void add(const mrd::Acquisition& acquisition); template void add(const T &acquisitions) { @@ -39,11 +38,11 @@ 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 Core::Context context; + const mrd::Header header_; struct { std::set expected_lines; @@ -63,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 34cb8a21a..000000000 --- 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 f1a720c17..000000000 --- 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/config/grappa.xml b/gadgets/grappa/config/grappa.xml deleted file mode 100644 index c26f01c25..000000000 --- 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 eb05b6cbb..000000000 --- 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 1be49c589..000000000 --- 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 b36e0e45c..000000000 --- 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 7cdbda3fc..000000000 --- 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 8580cf594..000000000 --- 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/grappa/gpu/WeightsCore.cpp b/gadgets/grappa/gpu/WeightsCore.cpp index 334bfd4d5..6b0d97fac 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 7c8a754a4..5d9092b7c 100644 --- a/gadgets/mri_core/AccumulatorGadget.cpp +++ b/gadgets/mri_core/AccumulatorGadget.cpp @@ -20,17 +20,15 @@ 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::MRContext& 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()); - 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; @@ -50,31 +48,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 +62,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 +72,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,11 +119,10 @@ 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); } } } -GADGETRON_GADGET_EXPORT(AccumulatorGadget) } // namespace Gadgetron \ No newline at end of file diff --git a/gadgets/mri_core/AccumulatorGadget.h b/gadgets/mri_core/AccumulatorGadget.h index ae819bf62..fd0525a11 100644 --- a/gadgets/mri_core/AccumulatorGadget.h +++ b/gadgets/mri_core/AccumulatorGadget.h @@ -5,24 +5,32 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #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::MRContext& 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/AcquisitionAccumulateTriggerGadget.cpp b/gadgets/mri_core/AcquisitionAccumulateTriggerGadget.cpp index a57068f8f..48eb891c4 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."); } @@ -133,6 +133,7 @@ namespace Gadgetron { buckets.clear(); } + void AcquisitionAccumulateTriggerGadget::process(Core::InputChannel>& in, Core::OutputChannel& out) { auto waveforms = std::vector{}; @@ -155,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)); @@ -168,7 +169,7 @@ namespace Gadgetron { GDEBUG_STREAM("AcquisitionAccumulateTriggerGadget processed " << count << " Acquisitions total"); send_data(out, buckets, waveforms); } - GADGETRON_GADGET_EXPORT(AcquisitionAccumulateTriggerGadget); + namespace { const std::map triggerdimension_from_name = { @@ -192,4 +193,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 d8230e292..33e2e3723 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 @@ -8,14 +8,9 @@ namespace Gadgetron { - - class AcquisitionAccumulateTriggerGadget - : public Core::ChannelGadget> { + : public Core::MRChannelGadget> { public: - using Core::ChannelGadget>::ChannelGadget; - void process(Core::InputChannel>& in, - Core::OutputChannel& out) override; enum class TriggerDimension { kspace_encode_step_1, kspace_encode_step_2, @@ -37,18 +32,40 @@ 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::MRContext& context, const Parameters& params) + : Core::MRChannelGadget>(context, params) + , 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.cpp b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.cpp index fb0f0bacd..9fd20fcae 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::MRContext& 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); @@ -75,5 +77,4 @@ namespace Gadgetron { out.push(std::move(acq)); } } - GADGETRON_GADGET_EXPORT(AsymmetricEchoAdjustROGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h index f40b7ea06..b6cc938ac 100644 --- a/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h +++ b/gadgets/mri_core/AsymmetricEchoAdjustROGadget.h @@ -7,17 +7,17 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #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::MRContext& context, const Parameters& params); + void process(Core::InputChannel& input, Core::OutputChannel& output) override; + protected: std::vector maxRO_; }; diff --git a/gadgets/mri_core/AugmentImageMetadataGadget.cpp b/gadgets/mri_core/AugmentImageMetadataGadget.cpp index 5f3b2788c..154a68fe4 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/AugmentImageMetadataGadget.h b/gadgets/mri_core/AugmentImageMetadataGadget.h index 0e123cbc4..4ee4d64f5 100644 --- a/gadgets/mri_core/AugmentImageMetadataGadget.h +++ b/gadgets/mri_core/AugmentImageMetadataGadget.h @@ -6,18 +6,15 @@ #pragma once #include "hoNDArray.h" -#include "PureGadget.h" +#include "MRPureNode.h" 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 d116ac177..772cfc685 100644 --- a/gadgets/mri_core/AutoScaleGadget.cpp +++ b/gadgets/mri_core/AutoScaleGadget.cpp @@ -43,7 +43,6 @@ 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 da971483b..759dd416a 100644 --- a/gadgets/mri_core/AutoScaleGadget.h +++ b/gadgets/mri_core/AutoScaleGadget.h @@ -5,18 +5,33 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "hoNDArray_math.h" #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::MRContext& 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/BucketToBufferGadget.cpp b/gadgets/mri_core/BucketToBufferGadget.cpp index 7fec14472..ff59a1769 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 @@ -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; @@ -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 @@ -612,6 +608,32 @@ namespace Gadgetron { dim = dimension_from_name.at(lower); } - GADGETRON_GADGET_EXPORT(BucketToBufferGadget) + 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); + } + } // namespace Gadgetron diff --git a/gadgets/mri_core/BucketToBufferGadget.h b/gadgets/mri_core/BucketToBufferGadget.h index 4955c8d4e..0e067a3a4 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 @@ -17,11 +17,35 @@ 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: - BucketToBufferGadget(const Core::Context& context, const Core::GadgetProperties& props); + enum class Dimension { average, contrast, phase, repetition, set, segment, slice, none }; + struct Parameters : public Core::NodeParameters { + using NodeParameters::NodeParameters; + Parameters(const std::string& prefix) : NodeParameters(prefix, "Bucket To Buffer Options") + { + 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"); + } + Dimension N_dimension = Dimension::none; + Dimension S_dimension = Dimension::none; + bool split_slices = false; + bool ignore_segment = false; + bool verbose = false; + }; + + BucketToBufferGadget(const Core::MRContext& context, const Parameters& params) + : Core::MRChannelGadget(context, params) + , parameters_(params) + { + encoding_ = context.header.encoding; + } + struct BufferKey { uint32_t average,slice,contrast,phase,repetition,set,segment; BufferKey(const BufferKey&) = default; @@ -37,14 +61,9 @@ 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); + const Parameters parameters_; - mrd::Header header; + std::vector encoding_; void process(Core::InputChannel& in, Core::OutputChannel& out) override; BufferKey getKey(const mrd::EncodingCounters& idx) const; @@ -65,4 +84,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/CMakeLists.txt b/gadgets/mri_core/CMakeLists.txt index 6197a4a96..a329ad2ce 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 @@ -31,63 +31,42 @@ 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 + 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 + FloatToFixedPointGadget.cpp + ImageArraySplitGadget.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 + 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 - # CropAndCombineGadget.cpp - # ImageAccumulatorGadget.cpp - # ImageFFTGadget.cpp - # ImageResizingGadget.cpp - # NoiseAdjustGadget_unoptimized.cpp - # PartialFourierAdjustROGadget.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 @@ -104,14 +83,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 @@ -128,33 +99,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 - 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 @@ -170,23 +114,20 @@ 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}) target_link_libraries(pingvin_mricore - pingvin_core + pingvin_mri pingvin_toolbox_log pingvin_toolbox_cpucore pingvin_toolbox_cpufft @@ -216,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/CoilReductionGadget.cpp b/gadgets/mri_core/CoilReductionGadget.cpp index 12b909116..f2c2e9b4d 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::MRContext& 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) { @@ -88,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/CoilReductionGadget.h b/gadgets/mri_core/CoilReductionGadget.h index a074b1970..fe027b6b7 100644 --- a/gadgets/mri_core/CoilReductionGadget.h +++ b/gadgets/mri_core/CoilReductionGadget.h @@ -5,22 +5,34 @@ #pragma once -#include "Node.h" +#include "MRNode.h" #include "hoNDArray.h" #include #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::MRContext& 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.cpp b/gadgets/mri_core/CombineGadget.cpp index 474255472..6706e0680 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/CombineGadget.h b/gadgets/mri_core/CombineGadget.h index 16d859b52..9954fe049 100644 --- a/gadgets/mri_core/CombineGadget.h +++ b/gadgets/mri_core/CombineGadget.h @@ -5,13 +5,14 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.h" #include "hoNDArray_math.h" namespace Gadgetron{ - class CombineGadget : public Core::PureGadget { - public: - using Core::PureGadget::PureGadget; + class CombineGadget : public Core::MRPureGadget { + public: + using MRPureGadget::MRPureGadget; + mrd::AnyImage process_function(mrd::AnyImage image) const override; }; } diff --git a/gadgets/mri_core/ComplexToFloatGadget.cpp b/gadgets/mri_core/ComplexToFloatGadget.cpp index 018b3392e..29dcf417c 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::MRContext& 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,4 @@ mrd::Image Gadgetron::ComplexToFloatGadget::process_function( return out; } -namespace Gadgetron{ - 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 5083ed574..d34c23c69 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::PureGadget,mrd::Image>> +class ComplexToFloatGadget: public Core::MRPureGadget,mrd::Image>> { public: - ComplexToFloatGadget(const Core::Context& context, const Core::GadgetProperties& props); + ComplexToFloatGadget(const Core::MRContext&, 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 1d8d0d8e3..2b6987e67 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)); } } @@ -33,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/DenoiseGadget.h b/gadgets/mri_core/DenoiseGadget.h index 4bb5a9290..b7aabb5ab 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 { @@ -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::MRContext& 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/ExtractGadget.cpp b/gadgets/mri_core/ExtractGadget.cpp index 544ca329f..f1717fb79 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"); } } @@ -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,27 @@ 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::MRContext& context, const Parameters& params) + : Core::MRChannelGadget>>(context, params) + , 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("No valid extract functions specified"); + } } - GADGETRON_GADGET_EXPORT(ExtractGadget) - } diff --git a/gadgets/mri_core/ExtractGadget.h b/gadgets/mri_core/ExtractGadget.h index 0f06f9d92..911f7051c 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 @@ -7,26 +7,34 @@ namespace Gadgetron { - class ExtractGadget : public Core::ChannelGadget>> +class ExtractGadget : public Core::MRChannelGadget>> { + public: + 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_parameter("magnitude", &extract_magnitude, "Extract absolute value"); + register_parameter("real", &extract_real, "Extract real components"); + register_parameter("imag", &extract_imag, "Extract imaginary component"); + register_parameter("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 = true; + bool extract_real = false; + bool extract_imag = false; + bool extract_phase = false; + float real_imag_offset = 0.0f; + }; - { + ExtractGadget(const Core::MRContext& context, const Parameters& params); - public: - ExtractGadget(const Core::Context& context, const Core::GadgetProperties& props); + 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); + protected: + const Parameters parameters_; - public: - void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; + std::set image_types; +}; - protected: - std::set image_types; - }; } diff --git a/gadgets/mri_core/FFTGadget.cpp b/gadgets/mri_core/FFTGadget.cpp index 28ddd89be..601ba0276 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] @@ -90,5 +86,4 @@ namespace Gadgetron{ } } } - GADGETRON_GADGET_EXPORT(FFTGadget); } diff --git a/gadgets/mri_core/FFTGadget.h b/gadgets/mri_core/FFTGadget.h index 1b253c024..c07779cc5 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 @@ -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::MRContext& 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 3d8bbb02d..125b14f3d 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,12 @@ void Gadgetron::FlagTriggerGadget::process(Core::InputChannel& } } -Gadgetron::FlagTriggerGadget::FlagTriggerGadget(const Core::Context& context, const Core::GadgetProperties& props) - : ChannelGadget(context, props) { +FlagTriggerGadget::FlagTriggerGadget(const Core::MRContext& 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 8b850557a..80f27f6fc 100644 --- a/gadgets/mri_core/FlagTriggerGadget.h +++ b/gadgets/mri_core/FlagTriggerGadget.h @@ -2,11 +2,11 @@ // Created by david on 24/08/2020. // #pragma once -#include "Node.h" +#include "MRNode.h" 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::MRContext& 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/FloatToFixPointGadget.cpp b/gadgets/mri_core/FloatToFixPointGadget.cpp deleted file mode 100644 index 69c54f734..000000000 --- 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 88082cf5b..000000000 --- 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() 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 000000000..50ed19153 --- /dev/null +++ b/gadgets/mri_core/FloatToFixedPointGadget.cpp @@ -0,0 +1,99 @@ +#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"); + } + } + +} diff --git a/gadgets/mri_core/FloatToFixedPointGadget.h b/gadgets/mri_core/FloatToFixedPointGadget.h new file mode 100644 index 000000000..3ca18bd47 --- /dev/null +++ b/gadgets/mri_core/FloatToFixedPointGadget.h @@ -0,0 +1,48 @@ +#pragma once + +#include "MRNode.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::MRContext& 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/FlowPhaseSubtractionGadget.cpp b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp index 8822f6ddf..35115bc2c 100644 --- a/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp +++ b/gadgets/mri_core/FlowPhaseSubtractionGadget.cpp @@ -7,16 +7,21 @@ namespace Gadgetron { +FlowPhaseSubtractionGadget::FlowPhaseSubtractionGadget(const Core::MRContext& 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; + + 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; } @@ -54,5 +59,4 @@ void FlowPhaseSubtractionGadget::process(Core::InputChannel namespace Gadgetron{ - class FlowPhaseSubtractionGadget : public Core::ChannelGadget>> + class FlowPhaseSubtractionGadget : public Core::MRChannelGadget>> { public: - using Core::ChannelGadget>>::ChannelGadget; - + FlowPhaseSubtractionGadget(const Core::MRContext& context, const Core::NodeParameters& params); ~FlowPhaseSubtractionGadget() override = default; void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; + + protected: + uint32_t sets_; }; } diff --git a/gadgets/mri_core/ImageArraySplitGadget.cpp b/gadgets/mri_core/ImageArraySplitGadget.cpp index 73eb1f00b..dca0463a6 100644 --- a/gadgets/mri_core/ImageArraySplitGadget.cpp +++ b/gadgets/mri_core/ImageArraySplitGadget.cpp @@ -57,5 +57,4 @@ void ImageArraySplitGadget::process(Core::InputChannel& in, C } } -GADGETRON_GADGET_EXPORT(ImageArraySplitGadget); } // namespace Gadgetron diff --git a/gadgets/mri_core/ImageArraySplitGadget.h b/gadgets/mri_core/ImageArraySplitGadget.h index 86a43b2ff..c19f4caed 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" @@ -13,10 +13,11 @@ namespace Gadgetron{ using ImageOrImageArray = std::variant; - class ImageArraySplitGadget : public Core::ChannelGadget + class ImageArraySplitGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; + using Core::MRChannelGadget::MRChannelGadget; + void process(Core::InputChannel& input, Core::OutputChannel& output) override; }; } diff --git a/gadgets/mri_core/ImageIndexGadget.cpp b/gadgets/mri_core/ImageIndexGadget.cpp index 9b6f7e84d..596283b10 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{}; @@ -39,5 +36,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(ImageIndexGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/ImageIndexGadget.h b/gadgets/mri_core/ImageIndexGadget.h index ed342878b..3bc9fdb44 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 { @@ -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 7a8a379c1..c7672f6ca 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); @@ -57,5 +54,4 @@ namespace Gadgetron { images_.clear(); } } - GADGETRON_GADGET_EXPORT(ImageSortGadget); } \ No newline at end of file diff --git a/gadgets/mri_core/ImageSortGadget.h b/gadgets/mri_core/ImageSortGadget.h index 5334078ce..163121d66 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{ @@ -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::MRContext& 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 3edd89ac5..0f3e4ee75 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::MRContext& 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; } @@ -194,6 +193,5 @@ void MaxwellCorrectionGadget::process(Core::InputChannel #ifdef USE_OMP @@ -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::MRContext& 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 diff --git a/gadgets/mri_core/NoiseAdjustGadget.cpp b/gadgets/mri_core/NoiseAdjustGadget.cpp index af171eec5..7f24d59b7 100644 --- a/gadgets/mri_core/NoiseAdjustGadget.cpp +++ b/gadgets/mri_core/NoiseAdjustGadget.cpp @@ -18,8 +18,10 @@ #include #include +#include + + using namespace std::string_literals; -namespace bf = boost::filesystem; namespace Gadgetron { namespace { @@ -177,32 +179,30 @@ namespace Gadgetron { } } - NoiseAdjustGadget::NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props) - : Core::ChannelGadget(context, props) - , current_mrd_header(context.header) + NoiseAdjustGadget::NoiseAdjustGadget(const Core::MRContext& context, const Parameters& params) + : 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("reject_nonconformant_data is " << parameters_.reject_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(); @@ -215,8 +215,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 (acquisition_system_information_) { + for (auto& l : acquisition_system_information_->coil_label) { current_coil_labels.push_back(l.coil_name); } } @@ -247,7 +247,7 @@ namespace Gadgetron { } return LoadedNoise{noise_covariance->matrix, noise_covariance->noise_dwell_time_us}; - } else if (current_mrd_header.acquisition_system_information) { + } else if (acquisition_system_information_) { GERROR("Noise covariance matrix is malformed. Number of labels does not match number of channels."); } } @@ -294,7 +294,7 @@ namespace Gadgetron { normalize_covariance(ng); std::vector coil_labels; - for (auto& label : current_mrd_header.acquisition_system_information->coil_label) { + for (auto& label : acquisition_system_information_->coil_label) { coil_labels.push_back(label); } @@ -305,22 +305,21 @@ 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()); - 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"); } } @@ -342,8 +341,8 @@ 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) { - 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); } @@ -383,9 +382,9 @@ namespace Gadgetron { void NoiseAdjustGadget::process(Core::InputChannel& input, Core::OutputChannel& output) { - scale_only_channels = current_mrd_header.acquisition_system_information - ? find_scale_only_channels(scale_only_channels_by_name, - current_mrd_header.acquisition_system_information->coil_label) + scale_only_channels = acquisition_system_information_ + ? find_scale_only_channels(parameters_.scale_only_channels_by_name, + acquisition_system_information_->coil_label) : std::vector{}; for (auto acq : input) { @@ -402,12 +401,11 @@ 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; } mrd::binary::MrdNoiseCovarianceReader reader(file); @@ -421,6 +419,5 @@ namespace Gadgetron { return std::nullopt; } - GADGETRON_GADGET_EXPORT(NoiseAdjustGadget) } // namespace Gadgetron diff --git a/gadgets/mri_core/NoiseAdjustGadget.h b/gadgets/mri_core/NoiseAdjustGadget.h index b1572c5a6..aeaa223cc 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 @@ -26,27 +26,44 @@ namespace Gadgetron { struct IgnoringNoise {}; - class NoiseAdjustGadget : public Core::ChannelGadget { + class NoiseAdjustGadget : public Core::MRChannelGadget { public: - NoiseAdjustGadget(const Core::Context& context, const Core::GadgetProperties& props); + 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 reject_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("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"); + } + }; + + NoiseAdjustGadget(const Core::MRContext& 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", ""); + const Parameters parameters_; const float receiver_noise_bandwidth; const 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; + std::optional acquisition_system_information_; NoiseHandler noisehandler = IgnoringNoise{}; @@ -62,10 +79,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 4bb952305..020ad5c12 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::MRContext& 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 @@ -234,5 +220,4 @@ namespace Gadgetron { acq.data = data_out; } - GADGETRON_GADGET_EXPORT(PCACoilGadget) } diff --git a/gadgets/mri_core/PCACoilGadget.h b/gadgets/mri_core/PCACoilGadget.h index 5ab879cef..0548ecd4a 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" @@ -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::MRContext& 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 1197f8837..b2290ab43 100644 --- a/gadgets/mri_core/PhysioInterpolationGadget.cpp +++ b/gadgets/mri_core/PhysioInterpolationGadget.cpp @@ -155,18 +155,13 @@ 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>{}; 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)); } @@ -178,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; @@ -201,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(), @@ -213,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 @@ -236,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; @@ -250,9 +245,9 @@ 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 (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"; @@ -276,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 { @@ -288,5 +283,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(PhysioInterpolationGadget) } diff --git a/gadgets/mri_core/PhysioInterpolationGadget.h b/gadgets/mri_core/PhysioInterpolationGadget.h index e02caf307..1df703e9e 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 @@ -30,26 +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>> - { - public: +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; +} - using Core::ChannelGadget>>::ChannelGadget; +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); +} - ~PhysioInterpolationGadget() override = default; +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; + + 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(const Core::MRContext& 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: - 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); - - public: void process(Core::InputChannel>>& in, Core::OutputChannel& out) override; -}; + protected: + const Parameters parameters_; + + uint32_t slice_limit_; + }; } \ No newline at end of file diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.cpp b/gadgets/mri_core/RemoveROOversamplingGadget.cpp index 9c5f79d78..12774169b 100644 --- a/gadgets/mri_core/RemoveROOversamplingGadget.cpp +++ b/gadgets/mri_core/RemoveROOversamplingGadget.cpp @@ -4,40 +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_) { @@ -83,6 +49,39 @@ void RemoveROOversamplingGadget::process(Core::InputChannel& i } } -GADGETRON_GADGET_EXPORT(RemoveROOversamplingGadget) +RemoveROOversamplingGadget::RemoveROOversamplingGadget(const Core::MRContext& context, const Core::NodeParameters& params) + : Core::MRChannelGadget(context, params) +{ + 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; + } +} + } // namespace Gadgetron diff --git a/gadgets/mri_core/RemoveROOversamplingGadget.h b/gadgets/mri_core/RemoveROOversamplingGadget.h index 1916c2ca3..b0a846afa 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 @@ -13,11 +13,10 @@ #endif // USE_OMP namespace Gadgetron { -class RemoveROOversamplingGadget : public Core::ChannelGadget { +class RemoveROOversamplingGadget : public Core::MRChannelGadget { public: - using Core::ChannelGadget::ChannelGadget; - RemoveROOversamplingGadget(const Core::Context& context, const Core::GadgetProperties& props); - ~RemoveROOversamplingGadget() override = default; + RemoveROOversamplingGadget(const Core::MRContext& context, const Core::NodeParameters& params); + void process(Core::InputChannel& input, Core::OutputChannel& output) override; protected: diff --git a/gadgets/mri_core/ScaleGadget.cpp b/gadgets/mri_core/ScaleGadget.cpp index 380fa9618..5ba296c54 100644 --- a/gadgets/mri_core/ScaleGadget.cpp +++ b/gadgets/mri_core/ScaleGadget.cpp @@ -33,10 +33,9 @@ namespace { } // 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 6a478c0f1..f300ed611 100644 --- a/gadgets/mri_core/ScaleGadget.h +++ b/gadgets/mri_core/ScaleGadget.h @@ -1,19 +1,33 @@ #pragma once -#include "PureGadget.h" +#include "MRPureNode.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::MRContext& 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_; }; } diff --git a/gadgets/mri_core/SimpleReconGadget.cpp b/gadgets/mri_core/SimpleReconGadget.cpp index dae314910..cba659144 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,5 @@ namespace Gadgetron { } } } - GADGETRON_GADGET_EXPORT(SimpleReconGadget); } diff --git a/gadgets/mri_core/SimpleReconGadget.h b/gadgets/mri_core/SimpleReconGadget.h index 328df6ec1..9faebbe79 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" @@ -14,13 +14,10 @@ namespace Gadgetron { - class SimpleReconGadget : public Core::ChannelGadget { + class SimpleReconGadget : public Core::MRChannelGadget { public: - SimpleReconGadget(const Core::Context& context, const Core::GadgetProperties& props); - void process(Core::InputChannel& input, Core::OutputChannel& out) override; + using Core::MRChannelGadget::MRChannelGadget; - 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/gadgets/mri_core/config/default.xml b/gadgets/mri_core/config/default.xml deleted file mode 100644 index 089ef9a29..000000000 --- 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 5325b410d..000000000 --- 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 16995a331..000000000 --- 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/GenericReconBase.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconBase.h index 10edfee1e..bd809ac64 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" @@ -26,22 +26,38 @@ namespace Gadgetron { template - 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::MRContext& 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 90b1be480..b525c4da4 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::MRContext &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; @@ -554,5 +554,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianGrappaAIGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaAIGadget.h index 63d450268..3e17d448b 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::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 0e0dd75dc..864119e00 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::MRContext &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,9 +704,9 @@ 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(); } - GADGETRON_GADGET_EXPORT(GenericReconCartesianGrappaGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianGrappaGadget.h index a5139f5e9..00db85523 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::MRContext &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 afbca787d..3256d7b5c 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::MRContext& 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"); @@ -645,5 +646,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianNonLinearSpirit2DTGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianNonLinearSpirit2DTGadget.h index fcd510d05..fc004ab82 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::MRContext& 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 c7fc3c924..658945ff7 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::MRContext &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,8 +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 72e596756..b4872780e 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::MRContext &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 96a05e759..48f7b6b18 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::MRContext& 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); @@ -740,5 +741,4 @@ namespace Gadgetron { } } - GADGETRON_GADGET_EXPORT(GenericReconCartesianSpiritGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianSpiritGadget.h index 1187c13bf..edbef833b 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::MRContext& 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 fb35e8418..043afc4ca 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::MRContext &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,11 +230,10 @@ namespace Gadgetron { } } - if (perform_timing) { gt_timer_.stop(); } + if (params_.perform_timing) { gt_timer_.stop(); } out.push(std::move(m1)); } } - GADGETRON_GADGET_EXPORT(GenericReconEigenChannelGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconEigenChannelGadget.h index f5f66f1a6..a7ccc0f4d 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::MRContext &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 f7f1bfdfc..d6a137eae 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::MRContext& 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,12 +278,12 @@ namespace Gadgetron { GenericReconFieldOfViewAdjustmentGadget::~GenericReconFieldOfViewAdjustmentGadget() { + /** TODO: This is unnecessary, just make GenericReconMrdStreamer close the buffers in its own destructor... */ this->gt_streamer_.close_stream_buffer(); } // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconFieldOfViewAdjustmentGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconFieldOfViewAdjustmentGadget.h index f89cea3ca..f8d4c9300 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::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 fa3172560..1ae766de7 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::MRContext& 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 ... "); @@ -666,5 +667,4 @@ namespace Gadgetron { out.push(std::move(res)); } - GADGETRON_GADGET_EXPORT(GenericReconGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconGadget.h index 9e9e64fd6..ed424f274 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::MRContext& 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 5952fd1bd..46fbf52a0 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::MRContext &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; } } @@ -212,6 +213,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconImageArrayScalingGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconImageArrayScalingGadget.h index c7535dfd8..8ced199da 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 = 10.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::MRContext &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 c130772dd..b38a95e5f 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::MRContext &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(); } } } @@ -424,6 +425,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconKSpaceFilteringGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconKSpaceFilteringGadget.h index ad787dc84..bdc4a3cf7 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::MRContext &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 b121fe4c2..df91f1b30 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::MRContext& 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); @@ -169,6 +170,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconNoiseStdMapComputingGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconNoiseStdMapComputingGadget.h index 290a6495d..7b66b96a5 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::MRContext& 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 b53aa122e..0f3650ef7 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; @@ -32,6 +32,5 @@ namespace Gadgetron { // ---------------------------------------------------------------------------------------- - GADGETRON_GADGET_EXPORT(GenericReconPartialFourierHandlingFilterGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingFilterGadget.h index f3092e733..ad450b25c 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::MRContext& 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 24d11c4c9..14106f246 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::MRContext& 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 20e4c5118..b90108cfd 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingGadget.h @@ -20,32 +20,39 @@ #include "hoNDFFT.h" #include "mri_core_partial_fourier.h" -#include "PureGadget.h" +#include "MRPureNode.h" 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::MRContext& 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 1d6740e3e..7bf853711 100644 --- a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp +++ b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.cpp @@ -11,19 +11,18 @@ 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); } -GADGETRON_GADGET_EXPORT(GenericReconPartialFourierHandlingPOCSGadget) } diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h b/gadgets/mri_core/generic_recon_gadgets/GenericReconPartialFourierHandlingPOCSGadget.h index a32a515a8..06f93c51b 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::MRContext& 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/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 846b7c185..000000000 --- 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 612fd7ad4..000000000 --- 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 afef5e3f7..000000000 --- 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 670ce81a2..000000000 --- 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 c76831ea9..000000000 --- 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 0f5d72b21..000000000 --- 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 9b4994701..000000000 --- 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 a4ada1f70..000000000 --- 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 1eebb2d83..000000000 --- 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 6b14bdc70..000000000 --- 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 a32385d74..000000000 --- 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 e93637d20..000000000 --- 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 dfa96dad7..000000000 --- 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 02d78ebeb..000000000 --- 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 7a63b565b..000000000 --- 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 b034b6a89..000000000 --- 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 310e602d4..000000000 --- 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 - - - diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericImageReconArrayToImageGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconArrayToImageGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericImageReconArrayToImageGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconArrayToImageGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericImageReconArrayToImageGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconArrayToImageGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericImageReconArrayToImageGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconArrayToImageGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericImageReconGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericImageReconGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericImageReconGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericImageReconGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericImageReconGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconAccumulateImageTriggerGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconAccumulateImageTriggerGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconAccumulateImageTriggerGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconAccumulateImageTriggerGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconAccumulateImageTriggerGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianFFTGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconCartesianFFTGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianFFTGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconCartesianFFTGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianFFTGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconCartesianFFTGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconCartesianFFTGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconCartesianFFTGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageToImageArrayGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconImageToImageArrayGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconImageToImageArrayGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconImageToImageArrayGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconImageToImageArrayGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconImageToImageArrayGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconImageToImageArrayGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconImageToImageArrayGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.cpp b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconReferenceKSpaceDelayedBufferGadget.cpp similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.cpp rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconReferenceKSpaceDelayedBufferGadget.cpp diff --git a/gadgets/mri_core/generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.h b/gadgets/mri_core/generic_recon_gadgets/untested/GenericReconReferenceKSpaceDelayedBufferGadget.h similarity index 100% rename from gadgets/mri_core/generic_recon_gadgets/GenericReconReferenceKSpaceDelayedBufferGadget.h rename to gadgets/mri_core/generic_recon_gadgets/untested/GenericReconReferenceKSpaceDelayedBufferGadget.h diff --git a/gadgets/mri_core/generic_recon_gadgets/untested/README.md b/gadgets/mri_core/generic_recon_gadgets/untested/README.md new file mode 100644 index 000000000..95c35712a --- /dev/null +++ b/gadgets/mri_core/generic_recon_gadgets/untested/README.md @@ -0,0 +1 @@ +The Gadgets in this directory are NOT TESTED and have not been upgraded to MRD v2. \ No newline at end of file diff --git a/gadgets/mri_core/models/grappa_ai.py b/gadgets/mri_core/models/grappa_ai.py index 737220552..eb8fbaaae 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 diff --git a/gadgets/mri_core/CoilComputationGadget.cpp b/gadgets/mri_core/untested/CoilComputationGadget.cpp similarity index 100% rename from gadgets/mri_core/CoilComputationGadget.cpp rename to gadgets/mri_core/untested/CoilComputationGadget.cpp diff --git a/gadgets/mri_core/CoilComputationGadget.h b/gadgets/mri_core/untested/CoilComputationGadget.h similarity index 100% rename from gadgets/mri_core/CoilComputationGadget.h rename to gadgets/mri_core/untested/CoilComputationGadget.h diff --git a/gadgets/mri_core/CropAndCombineGadget.cpp b/gadgets/mri_core/untested/CropAndCombineGadget.cpp similarity index 100% rename from gadgets/mri_core/CropAndCombineGadget.cpp rename to gadgets/mri_core/untested/CropAndCombineGadget.cpp diff --git a/gadgets/mri_core/CropAndCombineGadget.h b/gadgets/mri_core/untested/CropAndCombineGadget.h similarity index 100% rename from gadgets/mri_core/CropAndCombineGadget.h rename to gadgets/mri_core/untested/CropAndCombineGadget.h diff --git a/gadgets/mri_core/ImageAccumulatorGadget.cpp b/gadgets/mri_core/untested/ImageAccumulatorGadget.cpp similarity index 100% rename from gadgets/mri_core/ImageAccumulatorGadget.cpp rename to gadgets/mri_core/untested/ImageAccumulatorGadget.cpp diff --git a/gadgets/mri_core/ImageAccumulatorGadget.h b/gadgets/mri_core/untested/ImageAccumulatorGadget.h similarity index 100% rename from gadgets/mri_core/ImageAccumulatorGadget.h rename to gadgets/mri_core/untested/ImageAccumulatorGadget.h diff --git a/gadgets/mri_core/ImageFFTGadget.cpp b/gadgets/mri_core/untested/ImageFFTGadget.cpp similarity index 100% rename from gadgets/mri_core/ImageFFTGadget.cpp rename to gadgets/mri_core/untested/ImageFFTGadget.cpp diff --git a/gadgets/mri_core/ImageFFTGadget.h b/gadgets/mri_core/untested/ImageFFTGadget.h similarity index 100% rename from gadgets/mri_core/ImageFFTGadget.h rename to gadgets/mri_core/untested/ImageFFTGadget.h diff --git a/gadgets/mri_core/ImageResizingGadget.cpp b/gadgets/mri_core/untested/ImageResizingGadget.cpp similarity index 100% rename from gadgets/mri_core/ImageResizingGadget.cpp rename to gadgets/mri_core/untested/ImageResizingGadget.cpp diff --git a/gadgets/mri_core/ImageResizingGadget.h b/gadgets/mri_core/untested/ImageResizingGadget.h similarity index 100% rename from gadgets/mri_core/ImageResizingGadget.h rename to gadgets/mri_core/untested/ImageResizingGadget.h diff --git a/gadgets/mri_core/NoiseAdjustGadget_unoptimized.cpp b/gadgets/mri_core/untested/NoiseAdjustGadget_unoptimized.cpp similarity index 100% rename from gadgets/mri_core/NoiseAdjustGadget_unoptimized.cpp rename to gadgets/mri_core/untested/NoiseAdjustGadget_unoptimized.cpp diff --git a/gadgets/mri_core/NoiseAdjustGadget_unoptimized.h b/gadgets/mri_core/untested/NoiseAdjustGadget_unoptimized.h similarity index 100% rename from gadgets/mri_core/NoiseAdjustGadget_unoptimized.h rename to gadgets/mri_core/untested/NoiseAdjustGadget_unoptimized.h diff --git a/gadgets/mri_core/PartialFourierAdjustROGadget.cpp b/gadgets/mri_core/untested/PartialFourierAdjustROGadget.cpp similarity index 100% rename from gadgets/mri_core/PartialFourierAdjustROGadget.cpp rename to gadgets/mri_core/untested/PartialFourierAdjustROGadget.cpp diff --git a/gadgets/mri_core/PartialFourierAdjustROGadget.h b/gadgets/mri_core/untested/PartialFourierAdjustROGadget.h similarity index 100% rename from gadgets/mri_core/PartialFourierAdjustROGadget.h rename to gadgets/mri_core/untested/PartialFourierAdjustROGadget.h diff --git a/gadgets/mri_core/untested/README.md b/gadgets/mri_core/untested/README.md new file mode 100644 index 000000000..95c35712a --- /dev/null +++ b/gadgets/mri_core/untested/README.md @@ -0,0 +1 @@ +The Gadgets in this directory are NOT TESTED and have not been upgraded to MRD v2. \ No newline at end of file diff --git a/mri/CMakeLists.txt b/mri/CMakeLists.txt new file mode 100644 index 000000000..79d18bb28 --- /dev/null +++ b/mri/CMakeLists.txt @@ -0,0 +1,37 @@ +add_library(pingvin_mri INTERFACE + MRContext.h + MRNode.h + MRPureNode.h + MRParallel.h + MRSource.h + MRSink.h + ) + +target_link_libraries(pingvin_mri INTERFACE + mrd::mrd + pingvin_core + ) + +target_include_directories(pingvin_mri + INTERFACE + $ + $ + ) + +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 000000000..266a36440 --- /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 000000000..69ab5604d --- /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/mri/MRParallel.h b/mri/MRParallel.h new file mode 100644 index 000000000..a1ec347f4 --- /dev/null +++ b/mri/MRParallel.h @@ -0,0 +1,43 @@ +#pragma once + +#include "parallel/Branch.h" +#include "parallel/Merge.h" + +#include "MRContext.h" + +namespace Gadgetron::Core::Parallel { + + 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: + using MRBranch::MRBranch; + + 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; + +} // namespace Gadgetron::Core::Parallel diff --git a/mri/MRPureNode.h b/mri/MRPureNode.h new file mode 100644 index 000000000..e89013f69 --- /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 000000000..01cde9100 --- /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 000000000..59947aef6 --- /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/CMakeLists.txt b/test/CMakeLists.txt index b97d8cf49..b3c060646 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) diff --git a/test/e2e/cases/cmr_cine_binning.yml b/test/e2e/cases/cmr_cine_binning.yml index 3e6e1e4a0..e410b36d5 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 d43a8404a..1292f5ed4 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 5a3ccd9ab..685f85006 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 0ed0c0c4e..cfa1c2193 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 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 eb920abd0..0d9134385 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 4fb705f2e..8c86bc0a8 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 222aaa9f2..000000000 --- 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 a32c6379f..c0404d08d 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 90702f561..252058041 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 9084f0094..b2ae92f09 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 2fc7f074c..87877a22b 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 bbcb611ae..59005978c 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 bbcb611ae..59005978c 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 9c8fb1631..3f737b9f4 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 29502d76c..8be437a95 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 731b895e8..8162036c3 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 3b0d469fe..73a2793ba 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 94fa90b62..b00c67463 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 85ed9d8ab..20d13a18e 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 d8977e69e..8327bb9a7 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 d8af948a9..fc366d1ea 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 067beddcf..84b9b3646 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 88d883b5b..5b4fb7347 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 5f48d066b..305dca676 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 6e9b22e6a..790eb55f3 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 589ec03e6..ccadd3015 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 0ce393d2c..9316d4907 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 fc19bc35b..e012c8d2c 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 1aaa19e9d..497c400c7 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 81d310389..2ff2e09f7 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 d13954ad4..f1ab2e3b5 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 495c4c8ce..ec5d53b93 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 e1f84eb2c..d4e7ba78e 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 a7463e376..932a36e58 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 ff5371603..4da97dd50 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 c07de9b5a..95653338a 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 b3dc799c1..c6a61fcbc 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 7adaad6c2..aa1b2f586 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 9bdf6acdb..d854568ee 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-gpu --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 b8597a64c..488bb9ba8 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 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 6cd5051ff..42c8e8abb 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 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 93db24785..cf878021e 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 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 cae81d3ae..6f8b4b0e0 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 1fda40f2b..5b30a0193 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 c15c1cb63..821b741e3 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 b634a56c9..ea8a547b6 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/test/gadgets/AcquisitionAccumulateTrigger_test.cpp b/test/gadgets/AcquisitionAccumulateTrigger_test.cpp index 8833ae5bd..c2789260b 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 e2e7854b2..87deed11e 100644 --- a/test/gadgets/setup_gadget.h +++ b/test/gadgets/setup_gadget.h @@ -3,10 +3,7 @@ // #pragma once -#include "Channel.h" -#include "Context.h" #include "Node.h" -#include "PropertyMixin.h" #include #include #include @@ -38,8 +35,8 @@ namespace Gadgetron { namespace Test { return header; } - inline Core::Context generate_context() { - Core::Context context; + inline Core::MRContext generate_context() { + Core::MRContext context; context.header = generate_header(); return context; } @@ -49,21 +46,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::MRContext 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) }; diff --git a/toolboxes/core/cpu/math/CMakeLists.txt b/toolboxes/core/cpu/math/CMakeLists.txt index 6976e6070..9b27bb0a9 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 diff --git a/toolboxes/log/log.h b/toolboxes/log/log.h index c657aefca..e9c84334f 100644 --- a/toolboxes/log/log.h +++ b/toolboxes/log/log.h @@ -190,10 +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_CHECK_THROW(con) { if ( !(con) ) { GERROR_STREAM(#con); throw std::runtime_error(#con); } } +#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) ) { 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; } } diff --git a/toolboxes/mri_core/CMakeLists.txt b/toolboxes/mri_core/CMakeLists.txt index 6d6298a52..55a18e9e6 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/mri_core/mri_core_def.h b/toolboxes/mri_core/mri_core_def.h index 3e96ad9f4..4ac878de9 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" } diff --git a/toolboxes/python/CMakeLists.txt b/toolboxes/python/CMakeLists.txt index 53c2269df..384f4c921 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