[med-svn] [ismrmrd] 01/11: Imported Upstream version 1.3.1

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Tue Sep 22 07:43:21 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch master
in repository ismrmrd.

commit 1e83341414e47a8c96db86a97f53a0f9da1a9ec7
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date:   Fri Sep 18 09:34:54 2015 +0100

    Imported Upstream version 1.3.1
---
 .travis.yml                               |  17 +++
 CMakeLists.txt                            |  86 ++++++------
 README.md                                 |   9 +-
 cmake/FindJava.cmake                      | 212 ------------------------------
 cmake/FindNumPy.cmake                     | 101 --------------
 cmake/cpack_options.cmake.in              |  12 +-
 cmake/ismrmrd_cpack.cmake                 |  40 +++---
 examples/c/CMakeLists.txt                 |  26 +++-
 examples/c/README.md                      |  13 ++
 examples/c/README.txt                     |  11 --
 examples/c/main.c                         |  20 ++-
 examples/data/.gitignore                  |   1 -
 examples/data/README.txt                  |  17 ---
 examples/matlab/todo.txt                  |   1 -
 examples/python/ismrmrd_create_dataset.py | 174 ------------------------
 examples/python/ismrmrd_recon_dataset.py  | 132 -------------------
 include/ismrmrd/ismrmrd.h                 |   4 +-
 include/ismrmrd/xml.h                     |  10 +-
 include/version.in                        |   1 +
 libsrc/dataset.c                          |  41 +++---
 libsrc/dataset.cpp                        |  20 +++
 libsrc/ismrmrd.c                          |   9 +-
 libsrc/ismrmrd.cpp                        |  29 +++-
 libsrc/xml.cpp                            |  68 +++++++---
 matlab/+ismrmrd/+xml/deserialize.m        |   5 +-
 matlab/+ismrmrd/+xml/serialize.m          |   2 +
 schema/ismrmrd.xsd                        |   6 +-
 tests/CMakeLists.txt                      |  21 +++
 tests/test_acquisitions.cpp               | 172 ++++++++++++++++++++++++
 tests/test_channels.cpp                   |  76 +++++++++++
 tests/test_flags.cpp                      |  65 +++++++++
 tests/test_images.cpp                     | 169 ++++++++++++++++++++++++
 tests/test_ismrmrd.h                      |   4 +
 tests/test_main.cpp                       |  26 ++++
 tests/test_ndarray.cpp                    |  71 ++++++++++
 tests/test_quaternions.cpp                |  60 +++++++++
 utilities/CMakeLists.txt                  | 106 +++++++--------
 utilities/ismrmrd_info.cpp                |   6 +-
 utilities/recon_cartesian_2d.cpp          |  95 +++++++------
 39 files changed, 1056 insertions(+), 882 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..c5219cc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,17 @@
+language: cpp
+
+compiler:
+    - gcc
+    - clang
+
+before_install:
+    - sudo apt-get update
+install:
+    - sudo apt-get install libboost-all-dev libhdf5-serial-dev h5utils doxygen
+
+before_script:
+    - mkdir build
+    - cd build
+    - cmake ..
+
+script: make && make check
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a8c27f2..0616fe8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,10 +50,10 @@ endif (WIN32)
 #the flexible header. The micro number changes when there are small changes
 #in the utility libraries, that don't affect the data format itself.
 set(ISMRMRD_VERSION_MAJOR 1)
-set(ISMRMRD_VERSION_MINOR 2)
-set(ISMRMRD_VERSION_PATCH 3) 
+set(ISMRMRD_VERSION_MINOR 3)
+set(ISMRMRD_VERSION_PATCH 1)
 
-set(ISMRMRD_XML_SCHEMA_SHA1 "99a63f4e8cf08ffc268f5ee8b8c8b2a1edf69412")
+set(ISMRMRD_XML_SCHEMA_SHA1 "9b899c6ad806bc2388c70461d6e5affe5cc6d750")
 
 #Remove line breaks and white space that does not change the meaning of the schema
 file(STRINGS ${CMAKE_SOURCE_DIR}/schema/ismrmrd.xsd SCHEMA_STRINGS) #Read all strings from file 
@@ -91,6 +91,19 @@ endif()
 set(ISMRMRD_VERSION_STRING ${ISMRMRD_VERSION_MAJOR}.${ISMRMRD_VERSION_MINOR}.${ISMRMRD_VERSION_PATCH})
 set(ISMRMRD_SOVERSION ${ISMRMRD_VERSION_MAJOR}.${ISMRMRD_VERSION_MINOR})
 
+# Find HDF5 for dataset support
+find_package(HDF5 1.8 COMPONENTS C)
+
+if (HDF5_FOUND)
+    set (ISMRMRD_DATASET_SUPPORT true)
+    set (ISMRMRD_DATASET_SOURCES libsrc/dataset.c libsrc/dataset.cpp)
+    set (ISMRMRD_DATASET_INCLUDE_DIR ${HDF5_C_INCLUDE_DIR})
+    set (ISMRMRD_DATASET_LIBRARIES ${HDF5_LIBRARIES})
+else (HDF5_FOUND)
+    set (ISMRMRD_DATASET_SUPPORT false)
+    message (WARNING "HDF5 not found. Dataset and file support unavailable!")
+endif (HDF5_FOUND)
+
 # Generate the version.h header file
 find_package(Git)
 if (GIT_FOUND)
@@ -111,43 +124,35 @@ install(FILES ${CMAKE_BINARY_DIR}/include/ismrmrd/version.h DESTINATION include/
 # remember to add ${CMAKE_BINARY_DIR}/include to the include path
 
 #  ---   VERSIONING  (end) ----
- 
-#  ---   Main Library  (begin) ----
-# required packages for main library
-find_package(HDF5 1.8 COMPONENTS C REQUIRED)
 
+#  ---   Main Library  (begin) ----
 # in windows, install the HDF5 dependencies
-if (WIN32)
-    if (ISMRMRD_INSTALL_DEPENDENCIES)
-        if ( HDF5_FOUND )
-            if(DEFINED ENV{HDF5_ROOT})
-                set(HDF5_BIN_DIR $ENV{HDF5_ROOT}/bin)
-            else (DEFINED ENV{HDF5_ROOT})
-                set(HDF5_BIN_DIR ${HDF5_C_INCLUDE_DIR}/../bin)
-            endif (DEFINED ENV{HDF5_ROOT})
-            message("Install hdf5 libraries from ${HDF5_BIN_DIR} ")
-            install( DIRECTORY ${HDF5_BIN_DIR} DESTINATION bin/.. FILES_MATCHING PATTERN "*.dll" )
-        endif (HDF5_FOUND)
-    endif (ISMRMRD_INSTALL_DEPENDENCIES)
-endif (WIN32)
+if (HDF5_FOUND AND WIN32 AND ISMRMRD_INSTALL_DEPENDENCIES)
+    if(DEFINED ENV{HDF5_ROOT})
+        set(HDF5_BIN_DIR $ENV{HDF5_ROOT}/bin)
+    else (DEFINED ENV{HDF5_ROOT})
+        set(HDF5_BIN_DIR ${HDF5_C_INCLUDE_DIR}/../bin)
+    endif (DEFINED ENV{HDF5_ROOT})
+    message("Install hdf5 libraries from ${HDF5_BIN_DIR} ")
+    install( DIRECTORY ${HDF5_BIN_DIR} DESTINATION bin/.. FILES_MATCHING PATTERN "*.dll" )
+endif (HDF5_FOUND AND WIN32 AND ISMRMRD_INSTALL_DEPENDENCIES)
 
 # include directories for main library
 set(ISMRMRD_TARGET_INCLUDE_DIRS
   include
   ${CMAKE_BINARY_DIR}/include
-  ${HDF5_C_INCLUDE_DIR}
+  ${ISMRMRD_DATASET_INCLUDE_DIR}
 )
 
 set(ISMRMRD_TARGET_SOURCES
   libsrc/ismrmrd.c
   libsrc/ismrmrd.cpp
-  libsrc/dataset.c
-  libsrc/dataset.cpp
   libsrc/xml.cpp
   libsrc/meta.cpp
+  ${ISMRMRD_DATASET_SOURCES}
 )
 
-set(ISMRMRD_TARGET_LINK_LIBS ${HDF5_LIBRARIES})
+set(ISMRMRD_TARGET_LINK_LIBS ${ISMRMRD_DATASET_LIBRARIES})
 
 # optional handling of system-installed pugixml
 if(USE_SYSTEM_PUGIXML)
@@ -183,40 +188,35 @@ install(TARGETS ismrmrd DESTINATION lib)
 install(DIRECTORY include/ismrmrd  DESTINATION include)
 
 # install the schema file
-install(FILES schema/ismrmrd.xsd
-  DESTINATION share/ismrmrd/schema)
+install(FILES schema/ismrmrd.xsd DESTINATION share/ismrmrd/schema)
 
 # install the cmake modules
-install(FILES
-  cmake/FindIsmrmrd.cmake
-  cmake/FindFFTW3.cmake
-  cmake/FindNumPy.cmake
-DESTINATION
-  share/ismrmrd/cmake
-)
+install(FILES cmake/FindIsmrmrd.cmake cmake/FindFFTW3.cmake DESTINATION share/ismrmrd/cmake)
 
 #  ---   Main Library  (end) ----
 
-# turn on testing
-enable_testing()
-
 # process subdirectories
 add_subdirectory(doc)
-add_subdirectory(examples/c)
+
 add_subdirectory(utilities)
+if (HDF5_FOUND)
+    add_subdirectory(examples/c)
+endif (HDF5_FOUND)
+
+# TODO: make this work on Windows
+if (NOT WIN32)
+    add_subdirectory(tests)
+endif (NOT WIN32)
 
 # install the matlab api
 install(DIRECTORY matlab DESTINATION share/ismrmrd)
 
-# TODO build and install the python bindings
-
 # Create package
 string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
 include(${ISMRMRD_CMAKE_DIR}/ismrmrd_cpack.cmake)
 if(CPACK_GENERATOR)
   message(STATUS "Found CPack generators: ${CPACK_GENERATOR}")
-  configure_file("${ISMRMRD_CMAKE_DIR}/cpack_options.cmake.in"
-    ${ISMRMRD_CPACK_CFG_FILE} @ONLY)
+  configure_file("${ISMRMRD_CMAKE_DIR}/cpack_options.cmake.in" ${ISMRMRD_CPACK_CFG_FILE} @ONLY)
   set(CPACK_PROJECT_CONFIG_FILE ${ISMRMRD_CPACK_CFG_FILE})
-  include (CPack)
-endif()
+  include(CPack)
+endif(CPACK_GENERATOR)
diff --git a/README.md b/README.md
index 1f2be2d..2e1a516 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![Build Status](https://travis-ci.org/ismrmrd/ismrmrd.svg?branch=master)](https://travis-ci.org/ismrmrd/ismrmrd)
+
 ISMRM Raw Data Format (ISMRMRD)
 ===============================
 
@@ -12,7 +14,7 @@ To download the source code, clone the git archive:
 
 API Documentation can be found at https://ismrmrd.github.io/api/.
 
-You will need CMake, HDF5, Boost and optionally Doxygen and FFTW to build the C/C++ code. Please see the ISMRMRD documentation for specific installation instructions for [Linux](https://ismrmrd.github.io/index.html#linux-installation), [Mac OS X](https://ismrmrd.github.io/index.html#mac-osx-installation), and [Windows](https://ismrmrd.github.io/index.html#windows-installation).
+You will need CMake, HDF5, and optionally Boost and FFTW to build the C/C++ code. To generate the API documentation you will need Doxygen. Please see the ISMRMRD documentation for specific installation instructions for [Linux](https://ismrmrd.github.io/index.html#linux-installation), [Mac OS X](https://ismrmrd.github.io/index.html#mac-osx-installation), and [Windows](https://ismrmrd.github.io/index.html#windows-installation).
 
 Overview
 ---------
@@ -26,3 +28,8 @@ A raw data set consist mainly of 2 sections:
 1.  Raw data section. This section contains all the acquired data in the experiment. Each data item is preceded by a C-struct with encoding numbers, etc. Following this data header is a channel header and data for each acquired channel. The raw data headers are defined in a C/C++ header file (ismrmrd.h).  Please see the [C header](https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h) and the [documentation](https://ismrmrd.github.io/index.html#fixed-data-structures) f [...]
 
 In addition to these sections, the ISMRMRD format also specifies an image header for storing reconstructed images and the accompanying C/C++ library provides a convenient way of writing such images into HDF5 files along with generic arrays for storing less well defined data structures, e.g. coil sensitivity maps or other calibration data.
+
+Other Resources
+---------------
+
+- [Python implementation](https://www.github.com/ismrmrd/ismrmrd-python)
diff --git a/cmake/FindJava.cmake b/cmake/FindJava.cmake
deleted file mode 100644
index 4d6f888..0000000
--- a/cmake/FindJava.cmake
+++ /dev/null
@@ -1,212 +0,0 @@
-# - Find Java
-# This module finds if Java is installed and determines where the
-# include files and libraries are. This code sets the following
-# variables:
-#
-#  Java_JAVA_EXECUTABLE    = the full path to the Java runtime
-#  Java_JAVAC_EXECUTABLE   = the full path to the Java compiler
-#  Java_JAVAH_EXECUTABLE   = the full path to the Java header generator
-#  Java_JAVADOC_EXECUTABLE = the full path to the Java documention generator
-#  Java_XJC_EXECUTABLE     = the full path to the Java JAXB generator
-#  Java_JAR_EXECUTABLE     = the full path to the Java archiver
-#  Java_VERSION_STRING     = Version of the package found (java version), eg. 1.6.0_12
-#  Java_VERSION_MAJOR      = The major version of the package found.
-#  Java_VERSION_MINOR      = The minor version of the package found.
-#  Java_VERSION_PATCH      = The patch version of the package found.
-#  Java_VERSION_TWEAK      = The tweak version of the package found (after '_')
-#  Java_VERSION            = This is set to: $major.$minor.$patch(.$tweak)
-#
-# The minimum required version of Java can be specified using the
-# standard CMake syntax, e.g. find_package(Java 1.5)
-#
-# NOTE: ${Java_VERSION} and ${Java_VERSION_STRING} are not guaranteed to be
-# identical. For example some java version may return:
-# Java_VERSION_STRING = 1.5.0_17
-# and
-# Java_VERSION        = 1.5.0.17
-#
-# another example is the Java OEM, with:
-# Java_VERSION_STRING = 1.6.0-oem
-# and
-# Java_VERSION        = 1.6.0
-#
-# For these components the following variables are set:
-#
-#  Java_FOUND                    - TRUE if all components are found.
-#  Java_INCLUDE_DIRS             - Full paths to all include dirs.
-#  Java_LIBRARIES                - Full paths to all libraries.
-#  Java_<component>_FOUND        - TRUE if <component> is found.
-#
-# Example Usages:
-#  find_package(Java)
-#  find_package(Java COMPONENTS Runtime)
-#  find_package(Java COMPONENTS Development)
-#
-
-#=============================================================================
-# Copyright 2002-2009 Kitware, Inc.
-# Copyright 2009-2011 Mathieu Malaterre <mathieu.malaterre at gmail.com>
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-#  License text for the above reference.)
-
-# The HINTS option should only be used for values computed from the system.
-set(_JAVA_HINTS
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
-  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
-  $ENV{JAVA_HOME}/bin
-  )
-# Hard-coded guesses should still go in PATHS. This ensures that the user
-# environment can always override hard guesses.
-set(_JAVA_PATHS
-  /usr/lib/java/bin
-  /usr/share/java/bin
-  /usr/local/java/bin
-  /usr/local/java/share/bin
-  /usr/java/j2sdk1.4.2_04
-  /usr/lib/j2sdk1.4-sun/bin
-  /usr/java/j2sdk1.4.2_09/bin
-  /usr/lib/j2sdk1.5-sun/bin
-  /opt/sun-jdk-1.5.0.04/bin
-  )
-find_program(Java_JAVA_EXECUTABLE
-  NAMES java
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-if(Java_JAVA_EXECUTABLE)
-    execute_process(COMMAND ${Java_JAVA_EXECUTABLE} -version
-      RESULT_VARIABLE res
-      OUTPUT_VARIABLE var
-      ERROR_VARIABLE var # sun-java output to stderr
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      ERROR_STRIP_TRAILING_WHITESPACE)
-    if( res )
-      if(${Java_FIND_REQUIRED})
-        message( FATAL_ERROR "Error executing java -version" )
-      else()
-        message( STATUS "Warning, could not run java --version")
-      endif()
-    else()
-      # extract major/minor version and patch level from "java -version" output
-      # Tested on linux using
-      # 1. Sun / Sun OEM
-      # 2. OpenJDK 1.6
-      # 3. GCJ 1.5
-      # 4. Kaffe 1.4.2
-      if(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*")
-        # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer
-        string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\".*"
-                "\\1" Java_VERSION_STRING "${var}" )
-      elseif(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*")
-        # Kaffe style
-        string( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*"
-                "\\1" Java_VERSION_STRING "${var}" )
-      else()
-        if(NOT Java_FIND_QUIETLY)
-          message(WARNING "regex not supported: ${var}. Please report")
-        endif()
-      endif()
-      string( REGEX REPLACE "([0-9]+).*" "\\1" Java_VERSION_MAJOR "${Java_VERSION_STRING}" )
-      string( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_MINOR "${Java_VERSION_STRING}" )
-      string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_PATCH "${Java_VERSION_STRING}" )
-      # warning tweak version can be empty:
-      string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.[0-9]+[_\\.]?([0-9]*).*$" "\\1" Java_VERSION_TWEAK "${Java_VERSION_STRING}" )
-      if( Java_VERSION_TWEAK STREQUAL "" ) # check case where tweak is not defined
-        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH})
-      else()
-        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}.${Java_VERSION_TWEAK})
-      endif()
-    endif()
-
-endif()
-
-
-find_program(Java_JAR_EXECUTABLE
-  NAMES jar
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-find_program(Java_JAVAC_EXECUTABLE
-  NAMES javac
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-find_program(Java_XJC_EXECUTABLE
-  NAMES xjc
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-find_program(Java_JAVAH_EXECUTABLE
-  NAMES javah
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-find_program(Java_JAVADOC_EXECUTABLE
-  NAMES javadoc
-  HINTS ${_JAVA_HINTS}
-  PATHS ${_JAVA_PATHS}
-)
-
-include(FindPackageHandleStandardArgs)
-if(Java_FIND_COMPONENTS)
-  foreach(component ${Java_FIND_COMPONENTS})
-    # User just want to execute some Java byte-compiled
-    if(component STREQUAL "Runtime")
-      find_package_handle_standard_args(Java
-        REQUIRED_VARS Java_JAVA_EXECUTABLE
-        VERSION_VAR Java_VERSION
-        )
-    elseif(component STREQUAL "Development")
-      find_package_handle_standard_args(Java
-        REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
-                      Java_XJC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
-        VERSION_VAR Java_VERSION
-        )
-    else()
-      message(FATAL_ERROR "Comp: ${component} is not handled")
-    endif()
-    set(Java_${component}_FOUND TRUE)
-  endforeach()
-else()
-  # Check for everything
-  find_package_handle_standard_args(Java
-    REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
-                  Java_XJC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
-    VERSION_VAR Java_VERSION
-    )
-endif()
-
-
-mark_as_advanced(
-  Java_JAVA_EXECUTABLE
-  Java_JAR_EXECUTABLE
-  Java_JAVAC_EXECUTABLE
-  Java_XJC_EXECUTABLE
-  Java_JAVAH_EXECUTABLE
-  Java_JAVADOC_EXECUTABLE
-  )
-
-# LEGACY
-set(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE})
-set(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE})
-set(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE})
-
diff --git a/cmake/FindNumPy.cmake b/cmake/FindNumPy.cmake
deleted file mode 100644
index 6feeb73..0000000
--- a/cmake/FindNumPy.cmake
+++ /dev/null
@@ -1,101 +0,0 @@
-# - Find the NumPy libraries
-# This module finds if NumPy is installed, and sets the following variables
-# indicating where it is.
-#
-# TODO: Update to provide the libraries and paths for linking npymath lib.
-#
-#  NUMPY_FOUND               - was NumPy found
-#  NUMPY_VERSION             - the version of NumPy found as a string
-#  NUMPY_VERSION_MAJOR       - the major version number of NumPy
-#  NUMPY_VERSION_MINOR       - the minor version number of NumPy
-#  NUMPY_VERSION_PATCH       - the patch version number of NumPy
-#  NUMPY_VERSION_DECIMAL     - e.g. version 1.6.1 is 10601
-#  NUMPY_INCLUDE_DIRS        - path to the NumPy include files
-
-#============================================================================
-# Copyright 2012 Continuum Analytics, Inc.
-#
-# MIT License
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-#============================================================================
-
-# Finding NumPy involves calling the Python interpreter
-if(NumPy_FIND_REQUIRED)
-    find_package(PythonInterp REQUIRED)
-else()
-    find_package(PythonInterp)
-endif()
-
-if(NOT PYTHONINTERP_FOUND)
-    set(NUMPY_FOUND FALSE)
-    return()
-endif()
-
-execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
-    "import numpy as n; print(n.__version__); print(n.get_include());"
-    RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS
-    OUTPUT_VARIABLE _NUMPY_VALUES_OUTPUT
-    ERROR_VARIABLE _NUMPY_ERROR_VALUE
-    OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0)
-    if(NumPy_FIND_REQUIRED)
-        message(FATAL_ERROR
-            "NumPy import failure:\n${_NUMPY_ERROR_VALUE}")
-    endif()
-    set(NUMPY_FOUND FALSE)
-    return()
-endif()
-
-# Convert the process output into a list
-string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES_OUTPUT})
-string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES})
-list(GET _NUMPY_VALUES 0 NUMPY_VERSION)
-list(GET _NUMPY_VALUES 1 NUMPY_INCLUDE_DIRS)
-
-string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" _VER_CHECK "${NUMPY_VERSION}")
-if("${_VER_CHECK}" STREQUAL "")
-    # The output from Python was unexpected. Raise an error always
-    # here, because we found NumPy, but it appears to be corrupted somehow.
-    message(FATAL_ERROR
-        "Requested version and include path from NumPy, got instead:\n${_NUMPY_VALUES_OUTPUT}\n")
-    return()
-endif()
-
-# Make sure all directory separators are '/'
-string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS})
-
-# Get the major and minor version numbers
-string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION})
-list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR)
-list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR)
-list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH)
-string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH})
-math(EXPR NUMPY_VERSION_DECIMAL
-    "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}")
-
-find_package_message(NUMPY
-    "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}"
-    "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}")
-
-set(NUMPY_FOUND TRUE)
-
diff --git a/cmake/cpack_options.cmake.in b/cmake/cpack_options.cmake.in
index cd82556..6a8f5ef 100644
--- a/cmake/cpack_options.cmake.in
+++ b/cmake/cpack_options.cmake.in
@@ -8,7 +8,7 @@ set(CPACK_PACKAGE_VERSION_MAJOR "@ISMRMRD_VERSION_MAJOR@")
 set(CPACK_PACKAGE_VERSION_MINOR "@ISMRMRD_VERSION_MINOR@")
 set(CPACK_PACKAGE_VERSION_PATCH "@ISMRMRD_VERSION_PATCH@")
 set(CPACK_PACKAGE_NAME "@PROJECT_NAME@")
-set(CPACK_PACKAGE_VENDOR "https://sourceforge.net/p/ismrmrd")
+set(CPACK_PACKAGE_VENDOR "http://ismrmrd.github.io/")
 set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ISMRM Raw Data Format (ISMRMRD)")
 set(CPACK_PACKAGE_INSTALL_DIRECTORY "@PROJECT_NAME_LOWER@")
 set(CPACK_RESOURCE_FILE_LICENSE "@CMAKE_SOURCE_DIR@/LICENSE")
@@ -18,19 +18,13 @@ set(CPACK_PACKAGE_MAINTAINER "Michael S. Hansen <michael.hansen at nih.gov>")
 set(CPACK_PACKAGE_CONTACT "Michael S. Hansen <michael.hansen at nih.gov>")
 
 # DEB specific
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "@DEBIAN_PACKAGE_DEPENDS@")
 set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
 set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
-set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
 set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Implementation of the ISMRMRD format.")
 
-# RPM specific
-# TODO: set(CPACK_RPM_PACKAGE_REQUIRES "@RPM_PACKAGE_DEPENDS@")
-# TODO: set(CPACK_RPM_PACKAGE_DESCRIPTION "Implementation of the ISMRMRD format.")
-
 # NSIS specific
-set(CPACK_NSIS_HELP_LINK "http:\\\\\\\\ismrmrd.sourceforge.net")
-set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\ismrmrd.sourceforge.net")
+set(CPACK_NSIS_HELP_LINK "http://ismrmrd.github.io")
+set(CPACK_NSIS_URL_INFO_ABOUT "http://ismrmrd.github.io")
 set(CPACK_NSIS_MODIFY_PATH ON)
 set(CPACK_NSIS_DISPLAY_NAME "ismrmrd")
 
diff --git a/cmake/ismrmrd_cpack.cmake b/cmake/ismrmrd_cpack.cmake
index eee956c..94ad624 100644
--- a/cmake/ismrmrd_cpack.cmake
+++ b/cmake/ismrmrd_cpack.cmake
@@ -8,31 +8,33 @@ if(UNIX)
   if(EXISTS ${DPKG_PROGRAM})
     list(APPEND CPACK_GENERATOR "DEB")
   endif(EXISTS ${DPKG_PROGRAM})
-  # TODO: RPM
-  #find_program(RPMBUILD_PROGRAM rpmbuild)
-  #if(EXISTS ${RPMBUILD_PROGRAM})
-  #  list(APPEND CPACK_GENERATOR "RPM")
-  #endif(EXISTS ${RPMBUILD_PROGRAM})
 endif(UNIX)
 
-if(WIN32)
-    # NSLS
-    list(APPEND CPACK_GENERATOR "NSIS")    
-endif(WIN32)
+# Enable/Disable automatic search for dependencies:
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
 
-# TODO: list(APPEND CPACK_SOURCE_GENERATOR "TGZ")
-# TODO: list(APPEND CPACK_SOURCE_GENERATOR "ZIP")
-list(APPEND CPACK_SOURCE_IGNORE_FILES ";.git;.gitignore;todo.txt;_clang-format;build/")
+# Enable/Disable component install for CPack generator DEB
+set(CPACK_DEB_COMPONENT_INSTALL OFF)
+set(CPACK_DEB_PACKAGE_COMPONENT OFF)
 
-# set dependencies explicitly
-include(InstallRequiredSystemLibraries)
-set(DEBIAN_PACKAGE_DEPENDS "libhdf5-7, libfftw3-3, libboost-program-options-dev")
-# TODO: set(RPM_PACKAGE_DEPENDS "hdf5-devel")
+# Set dependencies explicitly
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libhdf5-7, libfftw3-3, libboost-program-options-dev")
 
-# where the package metadata are
+# Where the package metadata are
 set(ISMRMRD_CPACK_CFG_FILE "${PROJECT_BINARY_DIR}/cpack_options.cmake")
 
-# Where the package to be installed
-#set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CMAKE_INSTALL_PREFIX})
+# Where the package to be installed 
 set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
 message("CPACK_PACKAGING_INSTALL_PREFIX: " ${CPACK_PACKAGING_INSTALL_PREFIX})
+
+if(WIN32)
+  # NSLS
+  list(APPEND CPACK_GENERATOR "NSIS")    
+endif(WIN32)
+
+list(APPEND CPACK_SOURCE_GENERATOR "TGZ")
+list(APPEND CPACK_SOURCE_GENERATOR "ZIP")
+list(APPEND CPACK_SOURCE_IGNORE_FILES ";.git;.gitignore;todo.txt;_clang-format;build/")
+
+# set dependencies explicitly
+include(InstallRequiredSystemLibraries)
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index 3ab0884..8988f17 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -1,5 +1,23 @@
-include_directories(${CMAKE_SOURCE_DIR}/include)
+cmake_minimum_required(VERSION 2.8)
+project(ISMRMRD-C-EXAMPLE)
 
-add_executable(ismrmrd_c_demo main.c)
-target_link_libraries(ismrmrd_c_demo ismrmrd)
-install(TARGETS ismrmrd_c_demo DESTINATION bin)
+# if building this example as a standalone project
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+    if(NOT DEFINED ENV{ISMRMRD_HOME})
+        message(FATAL_ERROR "ISMRMRD_HOME environment variable must be defined")
+    endif(NOT DEFINED ENV{ISMRMRD_HOME})
+
+    list(APPEND CMAKE_MODULE_PATH "$ENV{ISMRMRD_HOME}/share/ismrmrd/cmake")
+
+    find_package(Ismrmrd REQUIRED)
+
+# otherwise, building it as part of ISMRMRD itself
+else(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+    set(ISMRMRD_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include")
+    set(ISMRMRD_LIBRARIES ismrmrd)
+endif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+
+include_directories(${ISMRMRD_INCLUDE_DIR})
+add_executable(ismrmrd_c_example main.c)
+target_link_libraries(ismrmrd_c_example ${ISMRMRD_LIBRARIES})
+install(TARGETS ismrmrd_c_example DESTINATION bin)
diff --git a/examples/c/README.md b/examples/c/README.md
new file mode 100644
index 0000000..a20d781
--- /dev/null
+++ b/examples/c/README.md
@@ -0,0 +1,13 @@
+This is an example of a simple C project that is built on ISMRMRD.
+
+Instructions for building:
+
+1. Install ISMRMRD and CMake
+2. Define the environment variable ISMRMRD_HOME,
+   e.g. `export ISMRMRD_HOME=/usr/local/ismrmrd`
+3. Compile the example:
+
+        mkdir build
+        cmake ..
+        make
+        ./ismrmrd_c_example
diff --git a/examples/c/README.txt b/examples/c/README.txt
deleted file mode 100644
index e430630..0000000
--- a/examples/c/README.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is an example of a simple C project that is built on ISMRMRD.
-
-Instructions for building:
-1. Install ISMRMRD
-2. Define the environment variable ISMRMRD_HOME,
-   e.g. ISMRMRD_HOME=/usr/local/ismrmrd
-3. In a directory of your choosing:
-   mkdir buildcdemo
-   cmake ${ISMRMRD_HOME}/examples/c
-   make
-   ./ismrmrd_c_demo
\ No newline at end of file
diff --git a/examples/c/main.c b/examples/c/main.c
index 6bb5d07..a2f265e 100644
--- a/examples/c/main.c
+++ b/examples/c/main.c
@@ -45,12 +45,9 @@ int main(void)
     ismrmrd_write_header(&dataset1, xmlhdr);
 
     /* Append some acquisitions */
-    /* must initialize an acquisition before you can use it */
-    ismrmrd_init_acquisition(&acq);
     nacq_write = 5;
     for (n=0; n < nacq_write; n++) {
-        /* must free an acquisition before you can reinitialize it */
-        ismrmrd_init_acquisition(&acq);
+        /* must initialize an acquisition before you can use it */
         ismrmrd_init_acquisition(&acq);
         acq.head.number_of_samples = 128;
         acq.head.active_channels = 4;
@@ -76,6 +73,7 @@ int main(void)
             ismrmrd_set_flag(&(acq.head.flags), ISMRMRD_ACQ_LAST_IN_SLICE);
         }
         ismrmrd_append_acquisition(&dataset1, &acq);
+        ismrmrd_cleanup_acquisition(&acq);
     }
     
     /* Close the dataset */
@@ -91,6 +89,7 @@ int main(void)
     /* Read the header */
     xmlstring = ismrmrd_read_header(&dataset2);
     printf("Header: %s\n", xmlstring);
+    free(xmlstring);
 
     /* Get the number of acquisitions */
     nacq_read = ismrmrd_get_number_of_acquisitions(&dataset2);
@@ -131,6 +130,8 @@ int main(void)
 #else
     printf("Data 3: %f\t 2: %f\n", creal(acq3.data[4]), creal(acq2.data[4]));
 #endif
+    ismrmrd_cleanup_acquisition(&acq2);
+    ismrmrd_cleanup_acquisition(&acq3);
 
     /* Create and store an image */
     ismrmrd_init_image(&im);
@@ -152,6 +153,7 @@ int main(void)
         ((float*)im.data)[loc] = 2.0;
     }
     ismrmrd_append_image(&dataset2, "testimages", &im);
+    ismrmrd_cleanup_image(&im);
 
     numim = ismrmrd_get_number_of_images(&dataset2, "testimages");
     printf("Number of images stored = %d\n", numim);
@@ -160,6 +162,7 @@ int main(void)
     ismrmrd_read_image(&dataset2, "testimages", 1, &im2);
     printf("Image 1 attribute string = %s\n", im2.attribute_string);
     printf("Image 1 at position 10 has value = %f\n", ((float*)im2.data)[10]);
+    ismrmrd_cleanup_image(&im2);
 
     /* Create and store an array */
     ismrmrd_init_ndarray(&arr);
@@ -174,19 +177,14 @@ int main(void)
     }
     ismrmrd_append_array(&dataset2, "testarray", &arr);
     printf("Number of arrays stored = %d\n", ismrmrd_get_number_of_arrays(&dataset2, "testarray"));
+    ismrmrd_cleanup_ndarray(&arr);
 
     /* Read it back in */
     ismrmrd_init_ndarray(&arr2);
     ismrmrd_read_array(&dataset2, "testarray", 0, &arr2);
     printf("Array 2 at position 10 has value = %f\n", ((float*)arr2.data)[10]);
+    ismrmrd_cleanup_ndarray(&arr2);
     
-    /* Clean up */
-    /* This frees the internal memory of the acquisitions */
-    ismrmrd_cleanup_acquisition(&acq);
-    ismrmrd_cleanup_acquisition(&acq2);
-    ismrmrd_cleanup_acquisition(&acq3);
-    free(xmlstring);
-
     /* Close the dataset */
     ismrmrd_close_dataset(&dataset2);
 
diff --git a/examples/data/.gitignore b/examples/data/.gitignore
deleted file mode 100644
index 424e4bc..0000000
--- a/examples/data/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.h5
\ No newline at end of file
diff --git a/examples/data/README.txt b/examples/data/README.txt
deleted file mode 100644
index 92962b7..0000000
--- a/examples/data/README.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-ISMRM Raw Data Example files
------------------------------
-
-
-
-Please download the example data files from:
-
-https://sourceforge.net/projects/ismrmrd/files/data/
-
-On Linux command line, simply type:
-
-wget https://sourceforge.net/projects/ismrmrd/files/data/3D_partial_fourier.h5
-wget https://sourceforge.net/projects/ismrmrd/files/data/simple_gre.h5
-wget https://sourceforge.net/projects/ismrmrd/files/data/simple_spiral.h5
-
-
-
diff --git a/examples/matlab/todo.txt b/examples/matlab/todo.txt
deleted file mode 100644
index 50b1078..0000000
--- a/examples/matlab/todo.txt
+++ /dev/null
@@ -1 +0,0 @@
-Put Michaels spiral and gridder example back.
diff --git a/examples/python/ismrmrd_create_dataset.py b/examples/python/ismrmrd_create_dataset.py
deleted file mode 100644
index 0ac2939..0000000
--- a/examples/python/ismrmrd_create_dataset.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# coding: utf-8
-import os
-import ismrmrd
-import numpy as np
-import matplotlib.pyplot as plt
-
-
-filename = 'testdata.h5'
-if os.path.isfile(filename):
-    os.remove(filename)
-# Create an empty ISMRMRD dataset
-dset = ismrmrd.Dataset(filename, "dataset")
-
-# Synthesize the object
-nX, nY = 256, 256
-rho = np.zeros((nX, nY))
-x0, x1 = nX / 4, 3 * nX / 4
-y0, y1 = nY / 4, 3 * nY / 4
-rho[x0:x1, y0:y1] = 1
-
-plt.imshow(rho)
-
-# Synthesize some coil sensitivities
-X, Y = np.meshgrid(np.arange(nX) / nX / 2.0, np.arange(nY) / nY / 2.0)
-C = np.zeros((nX, nY, 4), dtype=np.complex64)
-C[:,:,0] = np.exp(-((X - 0.5) ** 2 + Y ** 2) + 1j * (X - 0.5))
-C[:,:,1] = np.exp(-((X + 0.5) ** 2 + Y ** 2) - 1j * (X + 0.5))
-C[:,:,2] = np.exp(-(X ** 2 + (Y - 0.5) ** 2) + 1j * (Y - 0.5))
-C[:,:,3] = np.exp(-(X ** 2 + (Y + 0.5) ** 2) - 1j * (Y + 0.5))
-ncoils = np.size(C, 2)
-
-# Synthesize the k-space data
-nreps = 5
-noiselevel = 0.05
-K = np.zeros((nX, nY, ncoils, nreps), dtype=np.complex64)
-for rep in range(nreps):
-    for coil in range(ncoils):
-        noise = noiselevel * (np.random.randn(nX, nY) + 1j * np.random.randn(nX, nY))
-        K[:,:,coil,rep] = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(C[:,:,coil] * rho + noise)))
-
-rep0 = np.sqrt(np.sum(np.abs(K) ** 2, 2))
-plt.imshow(rep0[:,:,0])
-
-
-for rep in range(nreps):
-    for line in range(nY):
-        # Generate header
-        head = ismrmrd.AcquisitionHeader()
-        counter = ismrmrd.EncodingCounters()
-        head.version = 1
-        head.number_of_samples = nX
-        head.center_sample = nX / 2
-        head.active_channels = ncoils
-        head.read_dir  = [1., 0., 0.]
-        head.phase_dir = [0., 1., 0.]
-        head.slice_dir = [0., 0., 1.]
-        head.scan_counter = rep * nY + line
-        counter.kspace_encode_step_1 = line
-        counter.repetition = rep
-        head.idx = counter
-        # Note: the correct API for setting Acquisition flags looks like this:
-        #   acq.setFlag(ismrmrd.FlagBit(ismrmrd.ACQ_FIRST_IN_ENCODE_STEP1))
-        # but using this API would require using only ugly "acq.setXXX" methods
-        # since the call to "acq.setHead()" below overwrites the Acquisition's header
-        head.flags = 0
-        if line == 0:
-            head.flags |= 1 << ismrmrd.ACQ_LAST_IN_ENCODE_STEP1
-            head.flags |= 1 << ismrmrd.ACQ_FIRST_IN_SLICE
-            head.flags |= 1 << ismrmrd.ACQ_FIRST_IN_REPETITION
-        elif line == nY - 1:
-            head.flags |= 1 << ismrmrd.ACQ_LAST_IN_ENCODE_STEP1
-            head.flags |= 1 << ismrmrd.ACQ_LAST_IN_SLICE
-            head.flags |= 1 << ismrmrd.ACQ_LAST_IN_REPETITION
-        
-        # Generate k-space data
-        data = (np.array([c.real for c in np.array(K[:,line,:,rep])]) +
-                1j * np.array([c.imag for c in np.array(K[:,line,:,rep])]))
-        
-        # Construct acquisition object from header
-        acq = ismrmrd.Acquisition(head=head)
-        
-        # Fill in the internal data array
-        acq.data = data
-        
-        # Append to HDF5 dataset
-        dset.append_acquisition(acq)
-
-# Fill the XML header
-try:
-    import ismrmrd_xsd
-    HAS_XSD = True
-except ImportError:
-    HAS_XSD = False
-
-if HAS_XSD:
-    header = ismrmrd_xsd.ismrmrdHeader()
-    
-    # Experimental Conditions
-    exp = ismrmrd_xsd.experimentalConditionsType()
-    exp.H1resonanceFrequency_Hz = 128000000
-    header.experimentalConditions = exp
-    
-    # Acquisition System Information
-    sys = ismrmrd_xsd.acquisitionSystemInformationType()
-    sys.receiverChannels = ncoils
-    header.acquisitionSystemInformation = sys
-    
-    # Encoding
-    encoding = ismrmrd_xsd.encoding()
-    encoding.trajectory = ismrmrd_xsd.trajectoryType.cartesian
-    
-    # Encoded Space
-    fov = ismrmrd_xsd.fieldOfView_mm()
-    fov.x = 256
-    fov.y = 256
-    fov.z = 5
-    
-    matrix = ismrmrd_xsd.matrixSize()
-    matrix.x = np.size(K, 0)
-    matrix.y = np.size(K, 1)
-    matrix.z = 1
-    
-    space = ismrmrd_xsd.encodingSpaceType()
-    space.matrixSize = matrix
-    space.fieldOfView_mm = fov
-    
-    # Set encoded and recon space (same)
-    encoding.encodedSpace = space
-    encoding.reconSpace = space
-    
-    # Encoding limits
-    limits = ismrmrd_xsd.encodingLimitsType()
-    
-    limits0 = ismrmrd_xsd.limitType()
-    limits0.minimum = 0
-    limits0.center = np.size(K, 0) / 2
-    limits0.maximum = np.size(K, 0) - 1
-    limits.kspaceEncodingStep0 = limits0
-    
-    limits1 = ismrmrd_xsd.limitType()
-    limits1.minimum = 0
-    limits1.center = np.size(K, 1) / 2
-    limits1.maximum = np.size(K, 1) - 1
-    limits.kspaceEncodingStep1 = limits1
-    
-    limits_rep = ismrmrd_xsd.limitType()
-    limits_rep.minimum = 0
-    limits_rep.center = nreps / 2
-    limits_rep.maximum = nreps - 1
-    limits.repetition = limits_rep
-    
-    limits_slice = ismrmrd_xsd.limitType()
-    limits_slice.minimum = 0
-    limits_slice.center = 0
-    limits_slice.maximum = 0
-    limits.slice = limits_slice
-    
-    limits_rest = ismrmrd_xsd.limitType()
-    limits_rest.minimum = 0
-    limits_rest.center = 0
-    limits_rest.maximum = 0
-    limits.average = limits_rest
-    limits.contrast = limits_rest
-    limits.kspaceEncodingStep2 = limits_rest
-    limits.phase = limits_rest
-    limits.segment = limits_rest
-    limits.set = limits_rest
-    
-    encoding.encodingLimits = limits
-    header.encoding.append(encoding)
-    
-    dset.write_header(header.toxml('utf-8'))
-
-dset.close()
diff --git a/examples/python/ismrmrd_recon_dataset.py b/examples/python/ismrmrd_recon_dataset.py
deleted file mode 100644
index a0ccd49..0000000
--- a/examples/python/ismrmrd_recon_dataset.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# coding: utf-8
-
-import os
-import ismrmrd
-import ismrmrd_xsd
-import numpy as np
-from numpy.fft import ifft, fftshift
-import matplotlib.pyplot as plt
-
-# Load file
-filename = 'testdata.h5'
-if not os.path.isfile(filename):
-    print("%s is not a valid file" % filename)
-    raise SystemExit
-dset = ismrmrd.Dataset(filename, 'dataset', create_if_needed=False)
-
-header = ismrmrd_xsd.CreateFromDocument(dset.read_header())
-enc = header.encoding[0]
-
-# Matrix size
-eNx = enc.encodedSpace.matrixSize.x
-eNy = enc.encodedSpace.matrixSize.y
-eNz = enc.encodedSpace.matrixSize.z
-rNx = enc.reconSpace.matrixSize.x
-rNy = enc.reconSpace.matrixSize.y
-rNz = enc.reconSpace.matrixSize.z
-
-# Field of View
-eFOVx = enc.encodedSpace.fieldOfView_mm.x
-eFOVy = enc.encodedSpace.fieldOfView_mm.y
-eFOVz = enc.encodedSpace.fieldOfView_mm.z
-rFOVx = enc.reconSpace.fieldOfView_mm.x
-rFOVy = enc.reconSpace.fieldOfView_mm.y
-rFOVz = enc.reconSpace.fieldOfView_mm.z
-
-# Number of Slices, Reps, Contrasts, etc.
-ncoils = header.acquisitionSystemInformation.receiverChannels
-if enc.encodingLimits.slice != None:
-    nslices = enc.encodingLimits.slice.maximum + 1
-else:
-    nslices = 1
-
-if enc.encodingLimits.repetition != None:
-    nreps = enc.encodingLimits.repetition.maximum + 1
-else:
-    nreps = 1
-
-if enc.encodingLimits.contrast != None:
-    ncontrasts = enc.encodingLimits.contrast.maximum + 1
-else:
-    ncontrasts = 1
-
-
-all_data = np.zeros((nreps, ncontrasts, nslices, ncoils, eNz, eNy, eNx), dtype=np.complex64)
-for acqnum in range(dset.number_of_acquisitions):
-    acq = dset.read_acquisition(acqnum)
-
-    # TODO: Currently ignoring noise scans
-    if acq.head.flags & ismrmrd.ACQ_IS_NOISE_MEASUREMENT:
-        continue
-        
-    rep = acq.head.idx.repetition
-    contrast = acq.head.idx.contrast
-    slice = acq.head.idx.slice
-    y = acq.head.idx.kspace_encode_step_1
-    z = acq.head.idx.kspace_encode_step_2
-    all_data[rep, contrast, slice, :, z, y, :] = acq.data
-
-#fig = plt.figure()
-#h, w = nreps * ncontrasts, eNz * nslices
-#i = 0
-#for rep in range(nreps):
-#    for contrast in range(ncontrasts):
-#        for slice in range(nslices):
-#            for z in range(eNz):
-#                K = all_data[rep,contrast,slice,:,z,:,:]
-#                comb = np.sqrt(np.squeeze(np.sum(np.abs(K) ** 2, 2)))
-#                a = fig.add_subplot(h, w, i)
-#                plt.imshow(comb)
-#                i += 1
-#fig.set_size_inches(16, 16)
-
-images = []
-for rep in range(nreps):
-    for contrast in range(ncontrasts):
-        for slice in range(nslices):
-            K = all_data[rep,contrast,slice,:,:,:,:]
-            K = fftshift(ifft(fftshift(K, axes=3), axis=3), axes=3)
-
-            # chop if needed
-            if eNx != rNx:
-                i0 = (eNx - rNx) / 2
-                i1 = (eNx - rNx) / 2 + rNx
-                im = K[:,:,:,i0:i1]
-            else:
-                im = K
-
-            im = fftshift(ifft(fftshift(im, axes=2), axis=2), axes=2)
-            if np.size(im, 1) > 1:
-                im = fftshift(ifft(fftshift(im, axes=1), axis=1), axes=1)
-
-            im = np.squeeze(np.sqrt(np.sum(np.abs(im) ** 2, 0)))
-            images.append(im)
-
-l = len(images)
-fig = plt.figure()
-for n, im in enumerate(images):
-    a = fig.add_subplot(1, 5, n)
-    plt.imshow(im)
-fig.set_size_inches(16, 4)
-
-## # grab the first acquisition for extra info
-## acqh = dset.read_acquisition(0).head
-
-## for n, img in enumerate(images):
-##     hdr = ismrmrd.ImageHeader()
-##     hdr.acquisition_time_stamp = acqh.acquisition_time_stamp
-##     hdr.flags = 0
-##     hdr.measurement_uid = acqh.measurement_uid
-##     hdr.phase_dir = acqh.phase_dir
-##     hdr.physiology_time_stamp = acqh.physiology_time_stamp
-##     hdr.position = acqh.position
-##     hdr.read_dir = acqh.read_dir
-##     hdr.slice_dir = acqh.slice_dir
-##     hdr.channels = 1
-##     hdr.image_data_type = ismrmrd.DATA_FLOAT
-##     hdr.image_type = ismrmrd.TYPE_MAGNITUDE
-##     hdr.image_index = n
-##     hdr.slice = n
-
-##     dset.appendImageHeader(hdr, "image_%d.hdr" % n)
-##     dset.appendArray(img, "image_%d.img" % n)
diff --git a/include/ismrmrd/ismrmrd.h b/include/ismrmrd/ismrmrd.h
index 24bfeab..a4539b0 100644
--- a/include/ismrmrd/ismrmrd.h
+++ b/include/ismrmrd/ismrmrd.h
@@ -755,8 +755,10 @@ public:
     void setHead(const ImageHeader& head);
     
     // Attribute string
-    void getAttributeString(std::string &atrr) const;
+    void getAttributeString(std::string &attr) const;
+    const char *getAttributeString() const;
     void setAttributeString(const std::string &attr);
+    void setAttributeString(const char *attr);
     size_t getAttributeStringLength() const;
     
     // Data
diff --git a/include/ismrmrd/xml.h b/include/ismrmrd/xml.h
index 5695532..1e4b782 100644
--- a/include/ismrmrd/xml.h
+++ b/include/ismrmrd/xml.h
@@ -302,10 +302,12 @@ namespace ISMRMRD
 
   struct SequenceParameters
   {
-    std::vector<float> TR;
-    std::vector<float> TE;
-    std::vector<float> TI;
-    std::vector<float> flipAngle_deg;
+    Optional<std::vector<float> > TR;
+    Optional<std::vector<float> > TE;
+    Optional<std::vector<float> > TI;
+    Optional<std::vector<float> > flipAngle_deg;
+    Optional<std::string> sequence_type;
+    Optional<std::vector<float> > echo_spacing;
   };
 
   struct IsmrmrdHeader
diff --git a/include/version.in b/include/version.in
index 5239d4f..43378ae 100644
--- a/include/version.in
+++ b/include/version.in
@@ -6,5 +6,6 @@
 #define ISMRMRD_VERSION_PATCH @ISMRMRD_VERSION_PATCH@
 #define ISMRMRD_XMLHDR_VERSION @ISMRMRD_VERSION_MINOR@
 #define ISMRMRD_GIT_SHA1_HASH "@ISMRMRD_GIT_SHA1@"
+#define ISMRMRD_DATASET_SUPPORT @ISMRMRD_DATASET_SUPPORT@
 
 #endif /* ISMRMRD_VERSION_H */
diff --git a/libsrc/dataset.c b/libsrc/dataset.c
index b1ee935..1379e4d 100644
--- a/libsrc/dataset.c
+++ b/libsrc/dataset.c
@@ -419,6 +419,7 @@ static hid_t get_hdf5type_image_attribute_string(void) {
     hid_t datatype = H5Tcopy(H5T_C_S1);
     herr_t h5status = H5Tset_size(datatype, H5T_VARIABLE);
     if (h5status < 0) {
+        H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, walk_hdf5_errors, NULL);
         ISMRMRD_PUSH_ERR(ISMRMRD_FILEERROR, "Failed get image attribute string data type");
     }
     return datatype;
@@ -738,6 +739,8 @@ static int get_array_properties(const ISMRMRD_Dataset *dset, const char *path,
         dims[n] = hdfdims[rank-n-1];
     }
 
+    free(hdfdims);
+
     /* clean up */
     h5status = H5Tclose(hdf5type);
     if (h5status < 0) {
@@ -858,7 +861,7 @@ int ismrmrd_init_dataset(ISMRMRD_Dataset *dset, const char *filename,
 
     dset->filename = (char *) malloc(strlen(filename) + 1);
     if (dset->filename == NULL) {
-        return ISMRMRD_PUSH_ERR(ISMRMRD_MEMORYERROR, "Failed to malloc dataset groupname");
+        return ISMRMRD_PUSH_ERR(ISMRMRD_MEMORYERROR, "Failed to malloc dataset filename");
     }
     strcpy(dset->filename, filename);
 
@@ -889,9 +892,16 @@ int ismrmrd_open_dataset(ISMRMRD_Dataset *dset, const bool create_if_needed) {
         dset->fileid = fileid;
     }
     else if (create_if_needed == false) {
-        H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, walk_hdf5_errors, NULL);
-        /* Some sort of error opening the file - Maybe it doesn't exist? */
-        return ISMRMRD_PUSH_ERR(ISMRMRD_FILEERROR, "Failed to open file.");
+        /*Try opening the file as read-only*/
+        fileid = H5Fopen(dset->filename, H5F_ACC_RDONLY, H5P_DEFAULT);
+        if (fileid > 0) {
+            dset->fileid = fileid;
+        }
+        else{
+            H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, walk_hdf5_errors, NULL);
+            /* Some sort of error opening the file - Maybe it doesn't exist? */
+            return ISMRMRD_PUSH_ERR(ISMRMRD_FILEERROR, "Failed to open file.");
+        }
     }
     else {
         /* Try creating a new file using the default properties. */
@@ -1027,26 +1037,16 @@ char * ismrmrd_read_header(const ISMRMRD_Dataset *dset) {
         goto cleanup_path;
     }
 
-    void *buff[1] = { NULL };
     dataset = H5Dopen2(dset->fileid, path, H5P_DEFAULT);
     datatype = get_hdf5type_xmlheader();
     /* Read it into a 1D buffer*/
-    h5status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buff);
-    if (h5status < 0 || buff[0] == NULL) {
+    h5status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &xmlstring);
+    if (h5status < 0 || xmlstring == NULL) {
         H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, walk_hdf5_errors, NULL);
         ISMRMRD_PUSH_ERR(ISMRMRD_FILEERROR, "Failed to read header.");
         goto cleanup_path;
     }
 
-    /* Unpack */
-    xmlstring = (char *) malloc(strlen(buff[0])+1);
-    if (NULL == xmlstring) {
-        ISMRMRD_PUSH_ERR(ISMRMRD_MEMORYERROR, "Failed to malloc xmlstring");
-        goto cleanup_path;
-    } else {
-        memcpy(xmlstring, buff[0], strlen(buff[0])+1);
-    }
-
     /* Clean up */
     h5status = H5Tclose(datatype);
     if (h5status < 0) {
@@ -1157,6 +1157,7 @@ int ismrmrd_read_acquisition(const ISMRMRD_Dataset *dset, uint32_t index, ISMRMR
     memcpy(acq->data, hdf5acq.data.p, ismrmrd_size_of_acquisition_data(acq));
 
     /* clean up */
+    free(path);
     free(hdf5acq.traj.p);
     free(hdf5acq.data.p);
 
@@ -1266,7 +1267,7 @@ int ismrmrd_read_image(const ISMRMRD_Dataset *dset, const char *varname,
 
     int status;
     hid_t datatype;
-    char *path, *headerpath, *attrpath, *datapath;
+    char *path, *headerpath, *attrpath, *datapath, *attr_string;
     uint32_t numims;
 
     if (dset==NULL) {
@@ -1305,13 +1306,17 @@ int ismrmrd_read_image(const ISMRMRD_Dataset *dset, const char *varname,
     /* Handle the attribute string */
     attrpath = append_to_path(dset, path, "attributes");
     datatype = get_hdf5type_image_attribute_string();
-    status = read_element(dset, attrpath, (void *) &im->attribute_string, datatype, index);
+    status = read_element(dset, attrpath, (void *) &attr_string, datatype, index);
     if (status != ISMRMRD_NOERROR) {
         return ISMRMRD_PUSH_ERR(ISMRMRD_FILEERROR, "Failed to read image attribute string.");
     }
     free(attrpath);
     H5Tclose(datatype);
 
+    /* copy the attribute string read from the file into the Image */
+    memcpy(im->attribute_string, attr_string, ismrmrd_size_of_image_attribute_string(im));
+    free(attr_string);
+
     /* Handle the data */
     datapath = append_to_path(dset, path, "data");
     datatype = get_hdf5type_ndarray(im->head.data_type);
diff --git a/libsrc/dataset.cpp b/libsrc/dataset.cpp
index e679f99..a87bdfc 100644
--- a/libsrc/dataset.cpp
+++ b/libsrc/dataset.cpp
@@ -111,6 +111,16 @@ template <typename T> void Dataset::readImage(const std::string &var, uint32_t i
     }
 }
 
+// Specific instantiations
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<uint16_t> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<int16_t> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<uint32_t> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<int32_t> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<float> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<double> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<complex_float_t> &im);
+template EXPORTISMRMRD void Dataset::readImage(const std::string &var, uint32_t index, Image<complex_double_t> &im);
+
 uint32_t Dataset::getNumberOfImages(const std::string &var)
 {
     uint32_t num =  ismrmrd_get_number_of_images(&dset_, var.c_str());
@@ -152,6 +162,16 @@ template <typename T> void Dataset::readNDArray(const std::string &var, uint32_t
     }
 }
 
+// Specific instantiations
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<uint16_t> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<int16_t> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<uint32_t> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<int32_t> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<float> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<double> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<complex_float_t> &arr);
+template EXPORTISMRMRD void Dataset::readNDArray(const std::string &var, uint32_t index, NDArray<complex_double_t> &arr);
+
 uint32_t Dataset::getNumberOfNDArrays(const std::string &var)
 {
     uint32_t num = ismrmrd_get_number_of_arrays(&dset_, var.c_str());
diff --git a/libsrc/ismrmrd.c b/libsrc/ismrmrd.c
index 3d687d4..3fba17c 100644
--- a/libsrc/ismrmrd.c
+++ b/libsrc/ismrmrd.c
@@ -268,10 +268,13 @@ int ismrmrd_make_consistent_image(ISMRMRD_Image *im) {
    
     attr_size = ismrmrd_size_of_image_attribute_string(im);
     if (attr_size > 0) {
-        im->attribute_string = (char *)realloc(im->attribute_string, attr_size);
+        // Allocate space plus a null-terminating character
+        im->attribute_string = (char *)realloc(im->attribute_string, attr_size + sizeof(*im->attribute_string));
         if (im->attribute_string == NULL) {
             return ISMRMRD_PUSH_ERR(ISMRMRD_MEMORYERROR, "Failed to realloc image attribute string");
         }
+        // Set the null terminating character
+        im->attribute_string[im->head.attribute_string_len] = '\0';
     }
         
     data_size = ismrmrd_size_of_image_data(im);
@@ -528,8 +531,8 @@ int ismrmrd_set_channel_on(uint64_t channel_mask[ISMRMRD_CHANNEL_MASKS], const u
     if (channel_mask==NULL) {
         return ISMRMRD_PUSH_ERR(ISMRMRD_RUNTIMEERROR, "Pointer to channel_mask should not be NULL.");
     }
-    bitmask = 1 << (chan % ISMRMRD_CHANNEL_MASKS);
-    offset = chan / ISMRMRD_CHANNEL_MASKS;
+    bitmask = 1 << (chan % 64);
+    offset = chan / 64;
     channel_mask[offset] |= bitmask;
     return ISMRMRD_NOERROR;
 }
diff --git a/libsrc/ismrmrd.cpp b/libsrc/ismrmrd.cpp
index baa6dd1..d33c1b1 100644
--- a/libsrc/ismrmrd.cpp
+++ b/libsrc/ismrmrd.cpp
@@ -931,19 +931,34 @@ template <typename T> void Image<T>::getAttributeString(std::string &attr) const
       attr.assign("");
 }
 
+template <typename T> const char *Image<T>::getAttributeString() const
+{
+   return im.attribute_string;
+}
+
 template <typename T> void Image<T>::setAttributeString(const std::string &attr)
 {
-    size_t length = attr.length();
-    im.head.attribute_string_len = static_cast<uint32_t>(length);
+    this->setAttributeString(attr.c_str());
+}
 
-    // Add null terminating character
-    length++;
+template <typename T> void Image<T>::setAttributeString(const char *attr)
+{
+    // Get the string length
+    size_t length = strlen(attr);
 
-    im.attribute_string = (char *)realloc(im.attribute_string, length);
-    if (NULL==im.attribute_string) {
+    // Allocate space plus a null terminator and check for success
+    char *newPointer = (char *)realloc(im.attribute_string, (length+1) * sizeof(*im.attribute_string));
+    if (NULL==newPointer) {
         throw std::runtime_error(build_exception_string());
     }
-    strncpy(im.attribute_string, attr.c_str(), length);
+
+    // Make changes only if reallocation was successful
+    im.attribute_string = newPointer;
+    im.head.attribute_string_len = static_cast<uint32_t>(length);
+
+    // Set the null terminator and copy the string
+    im.attribute_string[length] = '\0';
+    strncpy(im.attribute_string, attr, length);
 }
 
 template <typename T> size_t Image<T>::getAttributeStringLength() const
diff --git a/libsrc/xml.cpp b/libsrc/xml.cpp
index 5e6a3d7..fde4e2b 100644
--- a/libsrc/xml.cpp
+++ b/libsrc/xml.cpp
@@ -222,7 +222,7 @@ namespace ISMRMRD
 	throw std::runtime_error("experimentalConditions not defined in ismrmrdHeader");
       } else {
 	ExperimentalConditions e;
-	e.H1resonanceFrequency_Hz = std::atoi(experimentalConditions.child_value("H1resonanceFrequency_Hz"));
+	e.H1resonanceFrequency_Hz = std::atol(experimentalConditions.child_value("H1resonanceFrequency_Hz"));
 	h.experimentalConditions = e;
       }
       
@@ -396,10 +396,24 @@ namespace ISMRMRD
 
       if (sequenceParameters) {
 	SequenceParameters p;
-	p.TR = parse_vector_float(sequenceParameters,"TR");
-	p.TE = parse_vector_float(sequenceParameters,"TE");
-	p.TI = parse_vector_float(sequenceParameters,"TI");
-	p.flipAngle_deg = parse_vector_float(sequenceParameters, "flipAngle_deg");
+
+    std::vector<float> r;
+    r = parse_vector_float(sequenceParameters, "TR");
+    if (!r.empty()) p.TR = r;
+
+    r = parse_vector_float(sequenceParameters, "TE");
+    if (!r.empty()) p.TE = r;
+
+    r = parse_vector_float(sequenceParameters, "TI");
+    if (!r.empty()) p.TI = r;
+
+    r = parse_vector_float(sequenceParameters, "flipAngle_deg");
+    if (!r.empty()) p.flipAngle_deg = r;
+
+    p.sequence_type = parse_optional_string(sequenceParameters, "sequence_type");
+
+    r = parse_vector_float(sequenceParameters, "echo_spacing");
+    if (!r.empty()) p.echo_spacing = r;
 
 	h.sequenceParameters = p;
       }
@@ -655,24 +669,42 @@ namespace ISMRMRD
 
     if (h.sequenceParameters) {
       n1 = root.append_child("sequenceParameters");
-      if (!h.sequenceParameters->TR.size()) {
-	throw std::runtime_error("TR section of sequenceParameters does not contain any values");
-      }
-      if (!h.sequenceParameters->TE.size()) {
-	throw std::runtime_error("TE section of sequenceParameters does not contain any values");
+
+      if (h.sequenceParameters->TR.is_present())
+      {
+          for (size_t i = 0; i < h.sequenceParameters->TR->size(); i++) {
+              append_node(n1, "TR", h.sequenceParameters->TR->operator[](i));
+          }
       }
 
-      for (size_t i = 0; i < h.sequenceParameters->TR.size(); i++) {
-	append_node(n1,"TR",h.sequenceParameters->TR[i]);
+      if (h.sequenceParameters->TE.is_present())
+      {
+          for (size_t i = 0; i < h.sequenceParameters->TE->size(); i++) {
+              append_node(n1, "TE", h.sequenceParameters->TE->operator[](i));
+          }
       }
-      for (size_t i = 0; i < h.sequenceParameters->TE.size(); i++) {
-	append_node(n1,"TE",h.sequenceParameters->TE[i]);
+
+      if (h.sequenceParameters->TI.is_present())
+      {
+          for (size_t i = 0; i < h.sequenceParameters->TI->size(); i++) {
+              append_node(n1, "TI", h.sequenceParameters->TI->operator[](i));
+          }
       }
-      for (size_t i = 0; i < h.sequenceParameters->TI.size(); i++) {
-	append_node(n1,"TI",h.sequenceParameters->TI[i]);
+
+      if (h.sequenceParameters->flipAngle_deg.is_present())
+      {
+          for (size_t i = 0; i < h.sequenceParameters->flipAngle_deg->size(); i++) {
+              append_node(n1, "flipAngle_deg", h.sequenceParameters->flipAngle_deg->operator[](i));
+          }
       }
-      for (size_t i = 0; i < h.sequenceParameters->flipAngle_deg.size(); i++) {
-	append_node(n1,"flipAngle_deg",h.sequenceParameters->flipAngle_deg[i]);
+
+      append_optional_node(n2, "sequence_type", h.sequenceParameters->sequence_type);
+
+      if (h.sequenceParameters->echo_spacing.is_present())
+      {
+          for (size_t i = 0; i < h.sequenceParameters->echo_spacing->size(); i++) {
+              append_node(n1, "echo_spacing", h.sequenceParameters->echo_spacing->operator[](i));
+          }
       }
     }
 
diff --git a/matlab/+ismrmrd/+xml/deserialize.m b/matlab/+ismrmrd/+xml/deserialize.m
index d0b5b96..7aabf82 100644
--- a/matlab/+ismrmrd/+xml/deserialize.m
+++ b/matlab/+ismrmrd/+xml/deserialize.m
@@ -202,6 +202,8 @@ function status = isNumericalType(name)
       'TE', ...
       'TI', ...
       'flipAngle_deg', ...
+      'sequence_type', ...
+      'echo_spacing', ...
       'x', 'y', 'z', ...
       'minimum', 'maximum', 'center'};
   
@@ -233,7 +235,8 @@ function status = isStringType(name)
       'trajectory', ...
       'coilName', ...
       'calibrationMode',...
-      'interleavingDimension'};
+      'interleavingDimension',...
+      'sequence_type'};
 
       status = ismember(name, headerStringTypes);
 end
diff --git a/matlab/+ismrmrd/+xml/serialize.m b/matlab/+ismrmrd/+xml/serialize.m
index 7eb5740..874752f 100644
--- a/matlab/+ismrmrd/+xml/serialize.m
+++ b/matlab/+ismrmrd/+xml/serialize.m
@@ -175,6 +175,8 @@ if isfield(header,'sequenceParameters')
     append_optional(docNode,n1,sequenceParameters,'TE', at num2str);
     append_optional(docNode,n1,sequenceParameters,'TI', at num2str);
     append_optional(docNode,n1,sequenceParameters,'flipAngle_deg', at num2str);
+    append_optional(docNode,n1,sequenceParameters,'sequence_type');
+    append_optional(docNode,n1,sequenceParameters,'echo_spacing', at num2str);
     docRootNode.appendChild(n1);
 end
 
diff --git a/schema/ismrmrd.xsd b/schema/ismrmrd.xsd
index 9553980..02168e4 100644
--- a/schema/ismrmrd.xsd
+++ b/schema/ismrmrd.xsd
@@ -187,10 +187,12 @@
 
   <xs:complexType name="sequenceParametersType">
     <xs:sequence>
-      <xs:element minOccurs="1" maxOccurs="unbounded" type="xs:float" name="TR"/>
-      <xs:element minOccurs="1" maxOccurs="unbounded" type="xs:float" name="TE"/>
+      <xs:element minOccurs="0" maxOccurs="unbounded" type="xs:float" name="TR"/>
+      <xs:element minOccurs="0" maxOccurs="unbounded" type="xs:float" name="TE"/>
       <xs:element minOccurs="0" maxOccurs="unbounded" type="xs:float" name="TI"/>
       <xs:element minOccurs="0" maxOccurs="unbounded" type="xs:float" name="flipAngle_deg"/>
+      <xs:element minOccurs="0" maxOccurs="1" type="xs:string" name="sequence_type"/>
+      <xs:element minOccurs="0" maxOccurs="unbounded" type="xs:float" name="echo_spacing"/>
 
     </xs:sequence>
   </xs:complexType>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..5d8d2c0
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,21 @@
+find_package(Boost 1.43 COMPONENTS unit_test_framework)
+
+if (NOT Boost_UNIT_TEST_FRAMEWORK_FOUND)
+    message("Boost Unit Test Framework not found. Not compiling tests")
+    return()
+endif (NOT Boost_UNIT_TEST_FRAMEWORK_FOUND)
+
+include_directories(${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include ${Boost_INCLUDE_DIR})
+
+add_executable(test_ismrmrd
+    test_main.cpp
+    test_acquisitions.cpp
+    test_images.cpp
+    test_ndarray.cpp
+    test_flags.cpp
+    test_channels.cpp
+    test_quaternions.cpp)
+
+target_link_libraries(test_ismrmrd ismrmrd ${Boost_LIBRARIES})
+
+add_custom_target(check COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_ismrmrd DEPENDS test_ismrmrd)
diff --git a/tests/test_acquisitions.cpp b/tests/test_acquisitions.cpp
new file mode 100644
index 0000000..7cc5532
--- /dev/null
+++ b/tests/test_acquisitions.cpp
@@ -0,0 +1,172 @@
+#include "ismrmrd/ismrmrd.h"
+#include "ismrmrd/version.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(AcquisitionsTest)
+
+static void check_header(ISMRMRD_AcquisitionHeader* chead);
+
+BOOST_AUTO_TEST_CASE(test_acquisition_header)
+{
+    ISMRMRD_AcquisitionHeader chead;
+
+    // Check that header is of expected size
+    size_t expected_size = 9 * sizeof(uint16_t) +
+            (3 + ISMRMRD_PHYS_STAMPS) * sizeof(uint32_t) +
+            ISMRMRD_USER_INTS * sizeof(int32_t) +
+            (1 + ISMRMRD_CHANNEL_MASKS) * sizeof(uint64_t) +
+            ((2 * ISMRMRD_POSITION_LENGTH) + (3 * ISMRMRD_DIRECTION_LENGTH) +
+                    1 + ISMRMRD_USER_FLOATS) * sizeof(float) +
+            (9 + ISMRMRD_USER_INTS) * sizeof(uint16_t);
+    BOOST_CHECK_EQUAL(sizeof(chead), expected_size);
+
+    // Check that header is initialized properly
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition_header(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition_header(&chead), ISMRMRD_NOERROR);
+    check_header(&chead);
+}
+
+BOOST_AUTO_TEST_CASE(test_acquisition_init_cleanup)
+{
+    ISMRMRD_Acquisition acq;
+
+    // Check initialization of acquisition
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition(&acq), ISMRMRD_NOERROR);
+    BOOST_CHECK(!acq.traj);
+    BOOST_CHECK(!acq.data);
+
+    // Check cleanup of acquisition
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_acquisition(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_acquisition(&acq), ISMRMRD_NOERROR);
+    BOOST_CHECK(!acq.traj);
+    BOOST_CHECK(!acq.data);
+}
+
+BOOST_AUTO_TEST_CASE(test_acquisition_create_free)
+{
+    ISMRMRD_Acquisition* cacqp = NULL;
+
+    // Check creation of new acquisition
+    BOOST_CHECK(cacqp = ismrmrd_create_acquisition());
+    // Check that it's initialized
+    check_header(&cacqp->head);
+    BOOST_CHECK(!cacqp->traj);
+    BOOST_CHECK(!cacqp->data);
+
+    // Check cleanup
+    BOOST_CHECK_EQUAL(ismrmrd_free_acquisition(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_free_acquisition(cacqp), ISMRMRD_NOERROR);
+    BOOST_CHECK(!cacqp->traj);
+    BOOST_CHECK(!cacqp->data);
+}
+
+BOOST_AUTO_TEST_CASE(test_acquisition_copy)
+{
+    // Weak check of acquisition copying
+    ISMRMRD_Acquisition csrc, cdst;
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition(&csrc), ISMRMRD_NOERROR);
+    // TODO: it is necessary to call init_acquisition on the destination acquisition
+    // before copying, in case its traj or data are non-NULL!
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition(&cdst), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_acquisition(&cdst, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_acquisition(NULL, &csrc), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_acquisition(NULL, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_acquisition(&cdst, &csrc), ISMRMRD_NOERROR);
+    check_header(&cdst.head);
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_acquisition_data(&cdst), 0);
+    BOOST_CHECK(!cdst.traj);
+    BOOST_CHECK(!cdst.data);
+}
+
+BOOST_AUTO_TEST_CASE(test_acquisition_make_consistent)
+{
+    ISMRMRD_Acquisition acq;
+    BOOST_CHECK_EQUAL(ismrmrd_init_acquisition(&acq), ISMRMRD_NOERROR);
+
+    BOOST_CHECK_EQUAL(ismrmrd_make_consistent_acquisition(NULL), ISMRMRD_RUNTIMEERROR);
+
+    uint16_t nsamples = 512;
+    uint16_t nchannels = 8;
+    uint16_t ntrajd = 2;
+    acq.head.number_of_samples = nsamples;
+    acq.head.active_channels = nchannels;
+    acq.head.trajectory_dimensions = ntrajd;
+
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_acquisition_traj(&acq), nsamples * ntrajd * sizeof(*acq.traj));
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_acquisition_data(&acq), nsamples * nchannels * sizeof(*acq.data));
+    BOOST_CHECK_EQUAL(ismrmrd_make_consistent_acquisition(&acq), ISMRMRD_NOERROR);
+
+    BOOST_CHECK_EQUAL(acq.head.available_channels, nchannels);
+    // check that traj and data were allocated
+    BOOST_CHECK(acq.traj);
+    BOOST_CHECK(acq.data);
+
+    ismrmrd_cleanup_acquisition(&acq);
+}
+
+static void check_header(ISMRMRD_AcquisitionHeader* chead)
+{
+    BOOST_CHECK_EQUAL(chead->version, ISMRMRD_VERSION_MAJOR);
+    BOOST_CHECK_EQUAL(chead->number_of_samples, 0);
+    BOOST_CHECK_EQUAL(chead->available_channels, 1);
+    BOOST_CHECK_EQUAL(chead->active_channels, 1);
+    BOOST_CHECK_EQUAL(chead->flags, 0);
+    BOOST_CHECK_EQUAL(chead->measurement_uid, 0);
+    BOOST_CHECK_EQUAL(chead->scan_counter, 0);
+    BOOST_CHECK_EQUAL(chead->acquisition_time_stamp, 0);
+    for (int idx = 0; idx < ISMRMRD_PHYS_STAMPS; idx++) {
+        BOOST_CHECK_EQUAL(chead->physiology_time_stamp[idx], 0);
+    }
+
+    for (int idx = 0; idx < ISMRMRD_CHANNEL_MASKS; idx++) {
+        BOOST_CHECK_EQUAL(chead->channel_mask[idx], 0);
+    }
+    BOOST_CHECK_EQUAL(chead->discard_pre, 0);
+    BOOST_CHECK_EQUAL(chead->discard_post, 0);
+    BOOST_CHECK_EQUAL(chead->center_sample, 0);
+    BOOST_CHECK_EQUAL(chead->encoding_space_ref, 0);
+    BOOST_CHECK_EQUAL(chead->trajectory_dimensions, 0);
+    BOOST_CHECK_EQUAL(chead->sample_time_us, 0);
+    for (int idx = 0; idx < ISMRMRD_POSITION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->position[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->read_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->phase_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->slice_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_POSITION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->patient_table_position[idx], 0);
+    }
+
+    // EncodingCounters
+    BOOST_CHECK_EQUAL(chead->idx.kspace_encode_step_1, 0);
+    BOOST_CHECK_EQUAL(chead->idx.kspace_encode_step_2, 0);
+    BOOST_CHECK_EQUAL(chead->idx.average, 0);
+    BOOST_CHECK_EQUAL(chead->idx.slice, 0);
+    BOOST_CHECK_EQUAL(chead->idx.contrast, 0);
+    BOOST_CHECK_EQUAL(chead->idx.phase, 0);
+    BOOST_CHECK_EQUAL(chead->idx.repetition, 0);
+    BOOST_CHECK_EQUAL(chead->idx.set, 0);
+    BOOST_CHECK_EQUAL(chead->idx.segment, 0);
+
+    for (int idx = 0; idx < ISMRMRD_USER_INTS; idx++) {
+        BOOST_CHECK_EQUAL(chead->idx.user[idx], 0);
+    }
+
+    for (int idx = 0; idx < ISMRMRD_USER_INTS; idx++) {
+        BOOST_CHECK_EQUAL(chead->user_int[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_USER_FLOATS; idx++) {
+        BOOST_CHECK_EQUAL(chead->user_float[idx], 0);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_channels.cpp b/tests/test_channels.cpp
new file mode 100644
index 0000000..54a1c8a
--- /dev/null
+++ b/tests/test_channels.cpp
@@ -0,0 +1,76 @@
+#include "ismrmrd/ismrmrd.h"
+#include "ismrmrd/version.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(ChannelTest)
+
+void fill_channels(uint64_t mask[ISMRMRD_CHANNEL_MASKS])
+{
+    for (int i = 0; i < ISMRMRD_CHANNEL_MASKS; i++) {
+        mask[i] = 0xFFFFFFFFFFFFFFFF;
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_is_channel_on)
+{
+    uint64_t channel_mask[ISMRMRD_CHANNEL_MASKS] = {0};
+
+    // TODO: this returns and ISMRMRD_RUNTIMEERROR, which casts to "true"
+    /* BOOST_CHECK_EQUAL(ismrmrd_is_channel_on(NULL, 0), false); */
+
+    for (int chan = 0; chan < 64 * ISMRMRD_CHANNEL_MASKS; chan++) {
+        BOOST_CHECK_EQUAL(ismrmrd_is_channel_on(channel_mask, chan), false);
+    }
+
+    fill_channels(channel_mask);
+    for (int chan = 0; chan < 64 * ISMRMRD_CHANNEL_MASKS; chan++) {
+        BOOST_CHECK_EQUAL(ismrmrd_is_channel_on(channel_mask, chan), true);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_set_channel_on)
+{
+    uint64_t channel_mask[ISMRMRD_CHANNEL_MASKS] = {0};
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_channel_on(NULL, 0), ISMRMRD_RUNTIMEERROR);
+
+    for (int chan = 0; chan < 64 * ISMRMRD_CHANNEL_MASKS; chan++) {
+        BOOST_CHECK_EQUAL(ismrmrd_set_channel_on(channel_mask, chan), ISMRMRD_NOERROR);
+        uint64_t bitmask = 1 << (chan % 64);
+        size_t offset = chan / 64;
+        BOOST_REQUIRE((channel_mask[offset] & bitmask) != 0);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_set_channel_off)
+{
+    uint64_t channel_mask[ISMRMRD_CHANNEL_MASKS] = {0};
+    fill_channels(channel_mask);
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_channel_off(NULL, 0), ISMRMRD_RUNTIMEERROR);
+
+    for (int chan = 0; chan < 64 * ISMRMRD_CHANNEL_MASKS; chan++) {
+        BOOST_CHECK_EQUAL(ismrmrd_set_channel_off(channel_mask, chan), ISMRMRD_NOERROR);
+
+        uint64_t bitmask = 1 << (chan % 64);
+        size_t offset = chan / 64;
+        BOOST_REQUIRE((channel_mask[offset] & bitmask) == 0);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_set_all_channels_off)
+{
+    uint64_t channel_mask[ISMRMRD_CHANNEL_MASKS] = {0};
+    fill_channels(channel_mask);
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_all_channels_off(NULL), ISMRMRD_RUNTIMEERROR);
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_all_channels_off(channel_mask), ISMRMRD_NOERROR);
+    for (int idx = 0; idx < ISMRMRD_CHANNEL_MASKS; idx++) {
+        BOOST_REQUIRE(channel_mask[idx] == 0);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_flags.cpp b/tests/test_flags.cpp
new file mode 100644
index 0000000..7402f0a
--- /dev/null
+++ b/tests/test_flags.cpp
@@ -0,0 +1,65 @@
+#include "ismrmrd/ismrmrd.h"
+#include "ismrmrd/version.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(FlagTest)
+
+BOOST_AUTO_TEST_CASE(test_is_flag_set)
+{
+    uint64_t flags = 0;
+
+    for (int f = 1; f <= 64; f++) {
+        BOOST_CHECK_EQUAL(ismrmrd_is_flag_set(flags, f), false);
+    }
+
+    for (int f = 1; f <= 64; f++) {
+        flags |= (1 << (f - 1));
+        BOOST_CHECK_EQUAL(ismrmrd_is_flag_set(flags, f), true);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_set_flag)
+{
+    uint64_t flags = 0;
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_flag(NULL, ISMRMRD_ACQ_USER8), ISMRMRD_RUNTIMEERROR);
+
+    for (int f = 1; f <= 64; f++) {
+        BOOST_CHECK_EQUAL(ismrmrd_set_flag(&flags, f), ISMRMRD_NOERROR);
+        BOOST_REQUIRE((flags & (1 << (f - 1))) != 0);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_set_flags)
+{
+    uint64_t flags = 0;
+
+    BOOST_CHECK_EQUAL(ismrmrd_set_flags(NULL, 0xFFFFFFFFFFFFFFFF), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_set_flags(&flags, 0xFFFFFFFFFFFFFFFF), ISMRMRD_NOERROR);
+
+    BOOST_CHECK_EQUAL(flags, 0xFFFFFFFFFFFFFFFF);
+}
+
+BOOST_AUTO_TEST_CASE(test_clear_flag)
+{
+    uint64_t flags = 0xFFFFFFFFFFFFFFFF;
+
+    BOOST_CHECK_EQUAL(ismrmrd_clear_flag(NULL, ISMRMRD_IMAGE_USER8), ISMRMRD_RUNTIMEERROR);
+    for (int f = 1; f <= 64; f++) {
+        BOOST_CHECK_EQUAL(ismrmrd_clear_flag(&flags, f), ISMRMRD_NOERROR);
+        BOOST_REQUIRE((flags & (1 << (f - 1))) == 0);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(test_clear_all_flags)
+{
+    uint64_t flags = 0xFFFFFFFFFFFFFFFF;
+
+    BOOST_CHECK_EQUAL(ismrmrd_clear_all_flags(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_clear_all_flags(&flags), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(flags, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_images.cpp b/tests/test_images.cpp
new file mode 100644
index 0000000..374c603
--- /dev/null
+++ b/tests/test_images.cpp
@@ -0,0 +1,169 @@
+#include "ismrmrd/ismrmrd.h"
+#include "ismrmrd/version.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(ImagesTest)
+
+static void check_header(ISMRMRD_ImageHeader* chead);
+
+BOOST_AUTO_TEST_CASE(test_image_header)
+{
+    ISMRMRD_ImageHeader chead;
+
+    // Check that header is of expected size
+    size_t expected_size = 15 * sizeof(uint16_t) +
+            (3 + ISMRMRD_PHYS_STAMPS) * sizeof(uint32_t) +
+            ISMRMRD_USER_INTS * sizeof(int32_t) +
+            1 * sizeof(uint64_t) +
+            ((2 * ISMRMRD_POSITION_LENGTH) + (3 * ISMRMRD_DIRECTION_LENGTH) +
+                    3 + ISMRMRD_USER_FLOATS) * sizeof(float);
+    BOOST_CHECK_EQUAL(sizeof(chead), expected_size);
+
+    // Check that header is initialized properly
+    BOOST_CHECK_EQUAL(ismrmrd_init_image_header(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_init_image_header(&chead), ISMRMRD_NOERROR);
+    check_header(&chead);
+}
+
+BOOST_AUTO_TEST_CASE(test_image_init_cleanup)
+{
+    ISMRMRD_Image cimg;
+
+    // Check initialization of image
+    BOOST_CHECK_EQUAL(ismrmrd_init_image(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_init_image(&cimg), ISMRMRD_NOERROR);
+    check_header(&cimg.head);
+    BOOST_CHECK(!cimg.attribute_string);
+    BOOST_CHECK(!cimg.data);
+
+    // Check cleanup of image
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_image(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_image(&cimg), ISMRMRD_NOERROR);
+    BOOST_CHECK(!cimg.attribute_string);
+    BOOST_CHECK(!cimg.data);
+}
+
+BOOST_AUTO_TEST_CASE(test_image_create_free)
+{
+    ISMRMRD_Image* cimgp = NULL;
+
+    // Check creation of new image
+    BOOST_CHECK(cimgp = ismrmrd_create_image());
+    // Check that it's initialized
+    check_header(&cimgp->head);
+    BOOST_CHECK(!cimgp->attribute_string);
+    BOOST_CHECK(!cimgp->data);
+
+    // Check cleanup
+    BOOST_CHECK_EQUAL(ismrmrd_free_image(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_free_image(cimgp), ISMRMRD_NOERROR);
+    BOOST_CHECK(!cimgp->attribute_string);
+    BOOST_CHECK(!cimgp->data);
+}
+
+BOOST_AUTO_TEST_CASE(test_image_copy)
+{
+    // Weak check of image copying
+    ISMRMRD_Image csrc, cdst;
+    BOOST_CHECK_EQUAL(ismrmrd_init_image(&csrc), ISMRMRD_NOERROR);
+    // TODO: it is necessary to call init_image on the destination image
+    // before copying, in case its attribute_string or data are non-NULL!
+    BOOST_CHECK_EQUAL(ismrmrd_init_image(&cdst), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_image(&cdst, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_image(NULL, &csrc), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_image(NULL, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_image(&cdst, &csrc), ISMRMRD_NOERROR);
+    check_header(&cdst.head);
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_image_attribute_string(&cdst), 0);
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_image_data(&cdst), 0);
+    BOOST_CHECK(!cdst.attribute_string);
+    BOOST_CHECK(!cdst.data);
+}
+
+BOOST_AUTO_TEST_CASE(test_image_make_consistent)
+{
+    ISMRMRD_Image img;
+    BOOST_CHECK_EQUAL(ismrmrd_init_image(&img), ISMRMRD_NOERROR);
+
+    BOOST_CHECK_EQUAL(ismrmrd_make_consistent_image(NULL), ISMRMRD_RUNTIMEERROR);
+
+    uint16_t matrix_size[] = {128, 128, 1};
+    uint16_t nchannels = 8;
+    uint16_t dtype = ISMRMRD_FLOAT;
+    uint16_t attrlen = 65;
+    img.head.matrix_size[0] = matrix_size[0];
+    img.head.matrix_size[1] = matrix_size[1];
+    img.head.matrix_size[2] = matrix_size[2];
+    img.head.channels = nchannels;
+    img.head.data_type = dtype;
+    img.head.attribute_string_len = attrlen;
+
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_image_data(&img),
+            matrix_size[0] * matrix_size[1] * matrix_size[2] *
+            nchannels * ismrmrd_sizeof_data_type(dtype));
+    BOOST_CHECK_EQUAL(ismrmrd_size_of_image_attribute_string(&img),
+            attrlen * sizeof(*img.attribute_string));
+    BOOST_CHECK_EQUAL(ismrmrd_make_consistent_image(&img), ISMRMRD_NOERROR);
+
+    // check that data and attribute_string were allocated
+    BOOST_CHECK(img.data);
+    BOOST_CHECK(img.attribute_string);
+
+    ismrmrd_cleanup_image(&img);
+}
+
+static void check_header(ISMRMRD_ImageHeader* chead)
+{
+    BOOST_CHECK_EQUAL(chead->version, ISMRMRD_VERSION_MAJOR);
+    BOOST_CHECK_EQUAL(chead->matrix_size[0], 0);
+    BOOST_CHECK_EQUAL(chead->matrix_size[1], 1);
+    BOOST_CHECK_EQUAL(chead->matrix_size[2], 1);
+    BOOST_CHECK_EQUAL(chead->channels, 1);
+
+    BOOST_CHECK_EQUAL(chead->data_type, 0);
+    BOOST_CHECK_EQUAL(chead->flags, 0);
+    BOOST_CHECK_EQUAL(chead->measurement_uid, 0);
+    for (int idx = 0; idx < 3; idx++) {
+        BOOST_CHECK_EQUAL(chead->field_of_view[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_POSITION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->position[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->read_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->phase_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_DIRECTION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->slice_dir[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_POSITION_LENGTH; idx++) {
+        BOOST_CHECK_EQUAL(chead->patient_table_position[idx], 0);
+    }
+    BOOST_CHECK_EQUAL(chead->average, 0);
+    BOOST_CHECK_EQUAL(chead->slice, 0);
+    BOOST_CHECK_EQUAL(chead->contrast, 0);
+    BOOST_CHECK_EQUAL(chead->phase, 0);
+    BOOST_CHECK_EQUAL(chead->repetition, 0);
+    BOOST_CHECK_EQUAL(chead->set, 0);
+    BOOST_CHECK_EQUAL(chead->acquisition_time_stamp, 0);
+    for (int idx = 0; idx < ISMRMRD_PHYS_STAMPS; idx++) {
+        BOOST_CHECK_EQUAL(chead->physiology_time_stamp[idx], 0);
+    }
+    BOOST_CHECK_EQUAL(chead->image_type, 0);
+    BOOST_CHECK_EQUAL(chead->image_index, 0);
+    BOOST_CHECK_EQUAL(chead->image_series_index, 0);
+
+    for (int idx = 0; idx < ISMRMRD_USER_INTS; idx++) {
+        BOOST_CHECK_EQUAL(chead->user_int[idx], 0);
+    }
+    for (int idx = 0; idx < ISMRMRD_USER_FLOATS; idx++) {
+        BOOST_CHECK_EQUAL(chead->user_float[idx], 0);
+    }
+    BOOST_CHECK_EQUAL(chead->attribute_string_len, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_ismrmrd.h b/tests/test_ismrmrd.h
new file mode 100644
index 0000000..ece311f
--- /dev/null
+++ b/tests/test_ismrmrd.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void silent_error_handler(const char *file, int line,
+        const char *function, int code, const char *msg);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
new file mode 100644
index 0000000..4b1809d
--- /dev/null
+++ b/tests/test_main.cpp
@@ -0,0 +1,26 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "ISMRMRD Unit Tests"
+#include <boost/test/unit_test.hpp>
+
+#include "ismrmrd/ismrmrd.h"
+using namespace ISMRMRD;
+
+void silent_error_handler(const char *file, int line,
+        const char *function, int code, const char *msg)
+{
+}
+
+struct GlobalConfig {
+    // global setup
+    GlobalConfig()
+    {
+        // enable more verbose testing output
+        boost::unit_test::unit_test_log.set_threshold_level(boost::unit_test::log_test_units);
+        // silence ISMRMRD errors on stdout
+        ismrmrd_set_error_handler(silent_error_handler);
+    }
+    // global teardown
+    ~GlobalConfig() { }
+};
+
+BOOST_GLOBAL_FIXTURE(GlobalConfig);
diff --git a/tests/test_ndarray.cpp b/tests/test_ndarray.cpp
new file mode 100644
index 0000000..abea4ab
--- /dev/null
+++ b/tests/test_ndarray.cpp
@@ -0,0 +1,71 @@
+#include "ismrmrd/ismrmrd.h"
+#include "ismrmrd/version.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(NDArrayTest)
+
+BOOST_AUTO_TEST_CASE(test_ndarray_init_cleanup)
+{
+    ISMRMRD_NDArray carr;
+
+    // Check initialization of ndarray
+    BOOST_CHECK_EQUAL(ismrmrd_init_ndarray(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_init_ndarray(&carr), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(carr.version, ISMRMRD_VERSION_MAJOR);
+    BOOST_CHECK_EQUAL(carr.data_type, 0);   // TODO: enumerate ISMRMRD_NO_DATATYPE
+    BOOST_CHECK_EQUAL(carr.ndim, 0);
+    for (int idx = 0; idx < ISMRMRD_NDARRAY_MAXDIM; idx++) {
+        BOOST_CHECK_EQUAL(carr.dims[idx], 0);
+    }
+    BOOST_CHECK(!carr.data);
+
+    // Check cleanup of ndarray
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_ndarray(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_cleanup_ndarray(&carr), ISMRMRD_NOERROR);
+    BOOST_CHECK(!carr.data);
+}
+
+BOOST_AUTO_TEST_CASE(test_ndarray_create_free)
+{
+    ISMRMRD_NDArray* carrp = NULL;
+
+    // Check creation of new ndarray
+    BOOST_CHECK(carrp = ismrmrd_create_ndarray());
+    BOOST_CHECK_EQUAL(carrp->version, ISMRMRD_VERSION_MAJOR);
+    BOOST_CHECK_EQUAL(carrp->data_type, 0);   // TODO: enumerate ISMRMRD_NO_DATATYPE
+    BOOST_CHECK_EQUAL(carrp->ndim, 0);
+    for (int idx = 0; idx < ISMRMRD_NDARRAY_MAXDIM; idx++) {
+        BOOST_CHECK_EQUAL(carrp->dims[idx], 0);
+    }
+    BOOST_CHECK(!carrp->data);
+
+    // Check cleanup
+    BOOST_CHECK_EQUAL(ismrmrd_free_ndarray(NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_free_ndarray(carrp), ISMRMRD_NOERROR);
+    BOOST_CHECK(!carrp->data);
+}
+
+BOOST_AUTO_TEST_CASE(test_ndarray_copy)
+{
+    // Weak check of ndarray copying
+    ISMRMRD_NDArray csrc, cdst;
+    BOOST_CHECK_EQUAL(ismrmrd_init_ndarray(&csrc), ISMRMRD_NOERROR);
+    // NOTE: it is necessary to call init_ndarray on the destination ndarray
+    // before copying, in case its data is non-NULL!
+    BOOST_CHECK_EQUAL(ismrmrd_init_ndarray(&cdst), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_ndarray(&cdst, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_ndarray(NULL, &csrc), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_ndarray(NULL, NULL), ISMRMRD_RUNTIMEERROR);
+    BOOST_CHECK_EQUAL(ismrmrd_copy_ndarray(&cdst, &csrc), ISMRMRD_NOERROR);
+    BOOST_CHECK_EQUAL(cdst.version, ISMRMRD_VERSION_MAJOR);
+    BOOST_CHECK_EQUAL(cdst.data_type, 0);   // TODO: enumerate ISMRMRD_NO_DATATYPE
+    BOOST_CHECK_EQUAL(cdst.ndim, 0);
+    for (int idx = 0; idx < ISMRMRD_NDARRAY_MAXDIM; idx++) {
+        BOOST_CHECK_EQUAL(cdst.dims[idx], 0);
+    }
+    BOOST_CHECK(!cdst.data);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_quaternions.cpp b/tests/test_quaternions.cpp
new file mode 100644
index 0000000..f73ef36
--- /dev/null
+++ b/tests/test_quaternions.cpp
@@ -0,0 +1,60 @@
+#include "ismrmrd/ismrmrd.h"
+#include <boost/test/unit_test.hpp>
+
+using namespace ISMRMRD;
+
+BOOST_AUTO_TEST_SUITE(QuaternionTest)
+
+BOOST_AUTO_TEST_CASE(test_directions_to_quaternion)
+{
+    float read_dir[3] = {1.0, 0, 0};
+    float phase_dir[3] = {0, 1.0, 0};
+    float slice_dir[3] = {0, 0, 1.0};
+    float quaternion[4];
+
+    /* convert the direction vectors to a quaternion and verify */
+    ismrmrd_directions_to_quaternion(read_dir, phase_dir, slice_dir, quaternion);
+
+    BOOST_CHECK_EQUAL(quaternion[0], 0.0);
+    BOOST_CHECK_EQUAL(quaternion[1], 0.0);
+    BOOST_CHECK_EQUAL(quaternion[2], 0.0);
+    BOOST_CHECK_EQUAL(quaternion[3], 1.0);
+}
+
+BOOST_AUTO_TEST_CASE(test_quaternion_to_directions)
+{
+    float read_dir[3];
+    float phase_dir[3];
+    float slice_dir[3];
+    float quaternion[4] = {0.0, 0.0, 0.0, 1.0};
+
+    /* convert the quaternion back to direction cosines and verify */
+    ismrmrd_quaternion_to_directions(quaternion, read_dir, phase_dir, slice_dir);
+    BOOST_CHECK_EQUAL(read_dir[0], 1.0);
+    BOOST_CHECK_EQUAL(read_dir[1], 0.0);
+    BOOST_CHECK_EQUAL(read_dir[2], 0.0);
+    BOOST_CHECK_EQUAL(phase_dir[0], 0.0);
+    BOOST_CHECK_EQUAL(phase_dir[1], 1.0);
+    BOOST_CHECK_EQUAL(phase_dir[2], 0.0);
+    BOOST_CHECK_EQUAL(slice_dir[0], 0.0);
+    BOOST_CHECK_EQUAL(slice_dir[1], 0.0);
+    BOOST_CHECK_EQUAL(slice_dir[2], 1.0);
+}
+
+BOOST_AUTO_TEST_CASE(test_sign_of_directions)
+{
+    float read_dir[3] = {1.0, 0, 0};
+    float phase_dir[3] = {0, 1.0, 0};
+    float slice_dir[3] = {0, 0, 1.0};
+
+    /* check that determinant is > 0 */
+    BOOST_REQUIRE(ismrmrd_sign_of_directions(read_dir, phase_dir, slice_dir) > 0);
+
+    /* flip sign of third column and check that determinant is < 0 */
+    slice_dir[0] = -slice_dir[0];
+    slice_dir[1] = -slice_dir[1];
+    slice_dir[2] = -slice_dir[2];
+    BOOST_REQUIRE(ismrmrd_sign_of_directions(read_dir, phase_dir, slice_dir) < 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt
index 2257dec..73dc095 100644
--- a/utilities/CMakeLists.txt
+++ b/utilities/CMakeLists.txt
@@ -8,66 +8,68 @@ add_executable(ismrmrd_info ismrmrd_info.cpp)
 target_link_libraries(ismrmrd_info ismrmrd)
 install(TARGETS ismrmrd_info DESTINATION bin)
 
-add_executable(ismrmrd_read_timing_test read_timing_test.cpp)
-target_link_libraries(ismrmrd_read_timing_test ismrmrd)
-install(TARGETS ismrmrd_read_timing_test DESTINATION bin)
-
 if (NOT WIN32)
-  add_executable(ismrmrd_test_xml 
-    ismrmrd_test_xml.cpp 
+  add_executable(ismrmrd_test_xml
+    ismrmrd_test_xml.cpp
     ${CMAKE_SOURCE_DIR}/libsrc/pugixml.cpp )
   target_link_libraries(ismrmrd_test_xml ismrmrd)
   install(TARGETS ismrmrd_test_xml DESTINATION bin)
 endif(NOT WIN32)
 
-find_package(Boost 1.43 COMPONENTS program_options)
-find_package(FFTW3 COMPONENTS single)
+if (HDF5_FOUND)
+    add_executable(ismrmrd_read_timing_test read_timing_test.cpp)
+    target_link_libraries(ismrmrd_read_timing_test ismrmrd)
+    install(TARGETS ismrmrd_read_timing_test DESTINATION bin)
+
+    find_package(Boost 1.43 COMPONENTS program_options)
+    find_package(FFTW3 COMPONENTS single)
+
+    if(FFTW3_FOUND AND Boost_FOUND)
+        message("FFTW3 and Boost Found... building utilities")
 
-if(FFTW3_FOUND AND Boost_FOUND)
-    message("FFTW3 and Boost Found, building utilities")
-    
-    if(WIN32)
-        link_directories(${Boost_LIBRARY_DIRS})
-    endif(WIN32)
+        if(WIN32)
+            link_directories(${Boost_LIBRARY_DIRS})
+        endif(WIN32)
 
-    include_directories(
-        ${CMAKE_SOURCE_DIR/include}
-        ${Boost_INCLUDE_DIR}
-        ${FFTW3_INCLUDE_DIR})
+        include_directories(
+            ${CMAKE_SOURCE_DIR/include}
+            ${Boost_INCLUDE_DIR}
+            ${FFTW3_INCLUDE_DIR})
 
-    # Shepp-Logan phantom
-    add_executable(ismrmrd_generate_cartesian_shepp_logan
-        generate_cartesian_shepp_logan.cpp
-        ismrmrd_phantom.cpp)
-    if(WIN32)
-        target_link_libraries( ismrmrd_generate_cartesian_shepp_logan
-            ismrmrd
-            ${FFTW3_LIBRARIES})
-    else(WIN32)
-        target_link_libraries( ismrmrd_generate_cartesian_shepp_logan
-            ismrmrd
-            ${Boost_PROGRAM_OPTIONS_LIBRARY}
-            ${FFTW3_LIBRARIES})
-    endif(WIN32)
-    install(TARGETS ismrmrd_generate_cartesian_shepp_logan
-			DESTINATION bin)
+        # Shepp-Logan phantom
+        add_executable(ismrmrd_generate_cartesian_shepp_logan
+            generate_cartesian_shepp_logan.cpp
+            ismrmrd_phantom.cpp)
+        if(WIN32)
+            target_link_libraries( ismrmrd_generate_cartesian_shepp_logan
+                ismrmrd
+                ${FFTW3_LIBRARIES})
+        else(WIN32)
+            target_link_libraries( ismrmrd_generate_cartesian_shepp_logan
+                ismrmrd
+                ${Boost_PROGRAM_OPTIONS_LIBRARY}
+                ${FFTW3_LIBRARIES})
+        endif(WIN32)
+        install(TARGETS ismrmrd_generate_cartesian_shepp_logan DESTINATION bin)
 
-    # Shepp-Logan phantom
-    add_executable(ismrmrd_recon_cartesian_2d
-	recon_cartesian_2d.cpp)
-    if(WIN32)
-        target_link_libraries( ismrmrd_recon_cartesian_2d
-            ismrmrd
-            ${FFTW3_LIBRARIES})
-    else(WIN32)
-        target_link_libraries( ismrmrd_recon_cartesian_2d
-            ismrmrd
-            ${Boost_PROGRAM_OPTIONS_LIBRARY}
-            ${FFTW3_LIBRARIES})
-    endif(WIN32)
-    install(TARGETS ismrmrd_recon_cartesian_2d
-			DESTINATION bin)
+        # Shepp-Logan phantom
+        add_executable(ismrmrd_recon_cartesian_2d
+            recon_cartesian_2d.cpp)
+        if(WIN32)
+            target_link_libraries( ismrmrd_recon_cartesian_2d
+                ismrmrd
+                ${FFTW3_LIBRARIES})
+        else(WIN32)
+            target_link_libraries( ismrmrd_recon_cartesian_2d
+                ismrmrd
+                ${Boost_PROGRAM_OPTIONS_LIBRARY}
+                ${FFTW3_LIBRARIES})
+        endif(WIN32)
+        install(TARGETS ismrmrd_recon_cartesian_2d DESTINATION bin)
 
-else(FFTW3_FOUND AND Boost_FOUND)
-	message("FFTW3 or Boost NOT Found, cannot build utilities")
-endif(FFTW3_FOUND AND Boost_FOUND)
+    else(FFTW3_FOUND AND Boost_FOUND)
+        message("FFTW3 or Boost NOT Found, cannot build utilities")
+    endif(FFTW3_FOUND AND Boost_FOUND)
+else (HDF5_FOUND)
+    message("HDF5 NOT Found, cannot build utilities")
+endif (HDF5_FOUND)
diff --git a/utilities/ismrmrd_info.cpp b/utilities/ismrmrd_info.cpp
index 77a94ef..e869b8c 100644
--- a/utilities/ismrmrd_info.cpp
+++ b/utilities/ismrmrd_info.cpp
@@ -4,7 +4,9 @@
 int main(int argc, char** argv)
 {
   std::cout << "ISMRMRD VERSION INFO: " << std::endl;
-  std::cout << "   -- version " << ISMRMRD_VERSION_MAJOR << "." << ISMRMRD_VERSION_MINOR << "." << ISMRMRD_VERSION_PATCH << std::endl;
-  std::cout << "   -- SHA1    " << ISMRMRD_GIT_SHA1_HASH << std::endl;
+  std::cout << "   -- Version:         " << ISMRMRD_VERSION_MAJOR << "." <<
+        ISMRMRD_VERSION_MINOR << "." << ISMRMRD_VERSION_PATCH << std::endl;
+  std::cout << "   -- SHA1:            " << ISMRMRD_GIT_SHA1_HASH << std::endl;
+  std::cout << "   -- Dataset support: " << (ISMRMRD_DATASET_SUPPORT ? "yes" : "no") << std::endl;
   return 0;
 }
diff --git a/utilities/recon_cartesian_2d.cpp b/utilities/recon_cartesian_2d.cpp
index 3c09b0b..424296f 100644
--- a/utilities/recon_cartesian_2d.cpp
+++ b/utilities/recon_cartesian_2d.cpp
@@ -70,67 +70,86 @@ int main(int argc, char** argv)
     ISMRMRD::EncodingSpace e_space = hdr.encoding[0].encodedSpace;
     ISMRMRD::EncodingSpace r_space = hdr.encoding[0].reconSpace;
 
-    std::cout << "Encoding Matrix Size        : [" << e_space.matrixSize.x << ", " << e_space.matrixSize.y << ", " << e_space.matrixSize.z << "]" << std::endl;
-    std::cout << "Reconstruction Matrix Size  : [" << r_space.matrixSize.x << ", " << r_space.matrixSize.y << ", " << r_space.matrixSize.z << "]" << std::endl;
-    std::cout << "Number of acquisitions      : " << d.getNumberOfAcquisitions() << std::endl;
-
     if (e_space.matrixSize.z != 1) {
         std::cout << "This simple reconstruction application only supports 2D encoding spaces" << std::endl;
         return -1;
     }
+    
+    uint16_t nX = e_space.matrixSize.x;
+    uint16_t nY = e_space.matrixSize.y;
+    
+    // The number of channels is optional, so read the first line
+    ISMRMRD::Acquisition acq;
+    d.readAcquisition(0, acq);
+    uint16_t nCoils = acq.active_channels();
+    
+    std::cout << "Encoding Matrix Size        : [" << e_space.matrixSize.x << ", " << e_space.matrixSize.y << ", " << e_space.matrixSize.z << "]" << std::endl;
+    std::cout << "Reconstruction Matrix Size  : [" << r_space.matrixSize.x << ", " << r_space.matrixSize.y << ", " << r_space.matrixSize.z << "]" << std::endl;
+    std::cout << "Number of Channels          : " << nCoils << std::endl;
+    std::cout << "Number of acquisitions      : " << d.getNumberOfAcquisitions() << std::endl;
 
     //Allocate a buffer for the data
     std::vector<size_t> dims;
-    dims.push_back(e_space.matrixSize.x);
-    dims.push_back(e_space.matrixSize.y);
+    dims.push_back(nX);
+    dims.push_back(nY);
+    dims.push_back(nCoils);
     ISMRMRD::NDArray<complex_float_t> buffer(dims);
+    memset(buffer.getDataPtr(), 0, sizeof(complex_float_t)*nX*nY*nCoils);
     
     //Now loop through and copy data
     unsigned int number_of_acquisitions = d.getNumberOfAcquisitions();
-    ISMRMRD::Acquisition acq;
     for (unsigned int i = 0; i < number_of_acquisitions; i++) {
         //Read one acquisition at a time
         d.readAcquisition(i, acq);
 
         //Copy data, we should probably be more careful here and do more tests....
-        //We are not considering multiple channels here.
-        unsigned int offset = acq.idx().kspace_encode_step_1*dims[0];
-        memcpy(&buffer.getDataPtr()[offset], acq.getDataPtr(),sizeof(complex_float_t)*dims[0]);
-    }
-
-    //Let's FFT the k-space to image
-    fftwf_complex* tmp = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*buffer.getNumberOfElements());
-
-    if (!tmp) {
-        std::cout << "Error allocating temporary storage for FFTW" << std::endl;
-        return -1;
+        for (uint16_t c=0; c<nCoils; c++) {
+            memcpy(&buffer(0,acq.idx().kspace_encode_step_1,c), &acq.data(0, c), sizeof(complex_float_t)*nX);
+        }
     }
 
-    //FFTSHIFT
-    fftshift(reinterpret_cast<complex_float_t*>(tmp), buffer.getDataPtr(), dims[0], dims[1]);
-
-    //Create the FFTW plan
-    fftwf_plan p = fftwf_plan_dft_2d(dims[1], dims[0], tmp ,tmp, FFTW_BACKWARD, FFTW_ESTIMATE);
+    // Do the recon one slice at a time
+    for (uint16_t c=0; c<nCoils; c++) {
+        
+        //Let's FFT the k-space to image (in-place)
+        fftwf_complex* tmp = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*(nX*nY));
 
-    //Execute the FFT
-    fftwf_execute(p);
-
-    //FFTSHIFT
-    fftshift( buffer.getDataPtr(), reinterpret_cast<std::complex<float>*>(tmp), dims[0], dims[1]);
+        if (!tmp) {
+            std::cout << "Error allocating temporary storage for FFTW" << std::endl;
+            return -1;
+        }
+    
+        //Create the FFTW plan
+        fftwf_plan p = fftwf_plan_dft_2d(nY, nX, tmp ,tmp, FFTW_BACKWARD, FFTW_ESTIMATE);
+
+        //FFTSHIFT
+        fftshift(reinterpret_cast<complex_float_t*>(tmp), &buffer(0,0,c), nX, nY);
+        
+        //Execute the FFT
+        fftwf_execute(p);
+        
+        //FFTSHIFT
+        fftshift( &buffer(0,0,c), reinterpret_cast<std::complex<float>*>(tmp), nX, nY);
+
+        //Clean up.
+        fftwf_destroy_plan(p);
+        fftwf_free(tmp);
 
-    //Clean up.
-    fftwf_destroy_plan(p);
-    fftwf_free(tmp);
+    }
 
     //Allocate an image
     ISMRMRD::Image<float> img_out(r_space.matrixSize.x, r_space.matrixSize.y, 1, 1);
-
+    memset(img_out.getDataPtr(), 0, sizeof(float_t)*r_space.matrixSize.x*r_space.matrixSize.y);
+           
     //f there is oversampling in the readout direction remove it
-    //Take the magnitude
-    size_t offset = ((e_space.matrixSize.x - r_space.matrixSize.x)>>1);
-    for (unsigned int y = 0; y < r_space.matrixSize.y; y++) {
-        for (unsigned int x = 0; x < r_space.matrixSize.x; x++) {
-            img_out(x,y) = std::abs(buffer(x+offset, y));
+    //Take the sqrt of the sum of squares
+    uint16_t offset = ((e_space.matrixSize.x - r_space.matrixSize.x)>>1);
+    for (uint16_t y = 0; y < r_space.matrixSize.y; y++) {
+        for (uint16_t x = 0; x < r_space.matrixSize.x; x++) {
+            for (uint16_t c=0; c<nCoils; c++) {
+                img_out(x,y) += (std::abs(buffer(x+offset, y, c)))*(std::abs(buffer(x+offset, y, c)));
+            }
+            img_out(x,y) = std::sqrt(img_out(x,y));            
         }
     }
     
@@ -141,7 +160,7 @@ int main(int argc, char** argv)
     //And so on
     
     //Let's write the reconstructed image into the same data file
-    d.appendImage("myimage", img_out);
+    d.appendImage("cpp", img_out);
 
     return 0;
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/ismrmrd.git



More information about the debian-med-commit mailing list