[med-svn] [Git][med-team/ismrmrd][upstream] New upstream version 1.8.0

Andreas Tille (@tille) gitlab at salsa.debian.org
Sun Apr 10 19:49:06 BST 2022



Andreas Tille pushed to branch upstream at Debian Med / ismrmrd


Commits:
cbc6808c by Andreas Tille at 2022-04-10T08:05:16+02:00
New upstream version 1.8.0
- - - - -


29 changed files:

- + .github/workflows/ismrmrd_matlab.yml
- CMakeLists.txt
- README.md
- + doc/.gitignore
- + doc/Makefile
- + doc/api.rst
- + doc/building.md
- + doc/c-api.rst
- + doc/conf.py
- + doc/cpp-api.rst
- + doc/cpplibrary.rst
- + doc/filestorage.rst
- + doc/index.rst
- + doc/make.bat
- + doc/meta.rst
- + doc/overview.rst
- + doc/requirements.txt
- + doc/xml.rst
- examples/matlab/test_create_dataset.m → examples/matlab/create_dataset.m
- examples/matlab/test_create_undersampled_dataset.m → examples/matlab/create_undersampled_dataset.m
- examples/matlab/test_recon_dataset.m → examples/matlab/recon_dataset.m
- include/ismrmrd/meta.h
- include/ismrmrd/xml.h
- libsrc/xml.cpp
- matlab/+ismrmrd/+xml/deserialize.m
- matlab/+ismrmrd/+xml/serialize.m
- matlab/test/xml/ismrmrd_example.xml
- schema/ismrmrd.xsd
- schema/ismrmrd_example_extended.xml


Changes:

=====================================
.github/workflows/ismrmrd_matlab.yml
=====================================
@@ -0,0 +1,24 @@
+name: Matlab
+
+on:
+  push:
+    branches:
+      - master
+  
+  pull_request:
+    branches:
+      - master
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout at v2
+
+    - name: Set up MATLAB
+      uses: matlab-actions/setup-matlab at v1
+    - name: Run tests and generate artifacts
+      uses: matlab-actions/run-tests at v1
+      with:
+        test-results-junit: test-results/results.xml
+        source-folder: matlab
\ No newline at end of file


=====================================
CMakeLists.txt
=====================================
@@ -80,12 +80,12 @@ endif ()
 #in the utility libraries, that don't affect the data format itself.
 # For more information see http://semver.org/
 set(ISMRMRD_VERSION_MAJOR 1)
-set(ISMRMRD_VERSION_MINOR 7)
-set(ISMRMRD_VERSION_PATCH 1)
+set(ISMRMRD_VERSION_MINOR 8)
+set(ISMRMRD_VERSION_PATCH 0)
 set(ISMRMRD_VERSION_STRING ${ISMRMRD_VERSION_MAJOR}.${ISMRMRD_VERSION_MINOR}.${ISMRMRD_VERSION_PATCH})
 set(ISMRMRD_SOVERSION ${ISMRMRD_VERSION_MAJOR}.${ISMRMRD_VERSION_MINOR})
 
-set(ISMRMRD_XML_SCHEMA_SHA1 "9f159b9cc0bbca2fefbbd059701d931426ed7176")
+set(ISMRMRD_XML_SCHEMA_SHA1 "5464ea590ded027471b0740bba7472c4919b895b")
 
 #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


=====================================
README.md
=====================================
@@ -8,288 +8,4 @@ Inati SJ, Naegele JD, Zwart NR, Roopchansingh V, Lizak MJ, Hansen DC, Liu CY, At
 
 Please cite this paper if you use the format.
 
-## Build instructions
-The ISMRM Raw Data format is described by an XML schema and some C-style structs with fixed memory layout and as such does not have dependencies. However, it uses HDF5 files for storage and a C++ library for reading and writing the ISMRMRD files is included in this distribution. Furthermore, since the XML header is defined with an XML schema, we encourage using XML data binding when writing software using the format. To compile all components of this distribution you need:
-
-* HDF5 (version 1.8 or higher) libraries. Available from http://www.hdfgroup.org/downloads/index.html.
-* Boost (http://www.boost.org/)
-* Cmake build tool (http://www.cmake.org/)
-* Git if you would like to use the source code archive (http://git-scm.com/)
-* FFTW if you would like to compile some of the example applications
-  (http://www.fftw.org)
-* Doxygen if you would like to generate API documentation (http://www.doxygen.org)
-
-> It is only necessary to install the dependencies if you wish to develop compiled C/C++ software, which uses the ISMRMRD format. The format can be read in Matlab or Python without installing any additional software.
-
-### Linux installation
-
-The dependencies mentioned above should be included in most linux distributions. On Ubuntu you can install all required dependencies with::
-
-```bash
-sudo apt-get -y install doxygen git-core graphviz libboost-all-dev libfftw3-dev libhdf5-serial-dev
-```
-
-After installation of dependencies, the library can be installed with:
-
-```bash
-git clone https://github.com/ismrmrd/ismrmrd
-cd ismrmrd/
-mkdir build
-cd build
-cmake ../
-make
-sudo make install
-```
-
-This will install the library in `/usr/local/` by default. To specify
-an alternative installation directory, pass `-D CMAKE_INSTALL_PREFIX=<install dir>` to `cmake`.
-
-# Format Details
-
-The raw data format combines a mix of flexible data structures (XML header) and fixed structures (equivalent to C-structs). A raw data set consist mainly of 2 sections:
-
-1. A flexible XML format document that can contain an arbitrary number of fields and accommodate everything from simple values (b-values, etc.) to entire vendor protocols, etc. This purpose of this XML document is to provide parameters that may be meaningful for some experiments but not for others. This XML format is defined by an XML Schema Definition file [`schema/ismrmrd.xsd`](https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd.xsd).
-2. 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`](https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h)
-
-In addition to these sections, the ISMRMRD format also specifies an image header for storing reconstructed images and the accompanying 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.
-
-## Flexible Data Header
-
-The flexible data structure is defined by the xml schema definition in [`schema/ismrmrd.xsd`](https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd.xsd). An example of an XML file for a Cartesian 3D acquisition can be found [`schema/ismrmrd_example.xml`](https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd_example.xml)
-
-The most critical elements for image reconstruction are contained in the `<encoding>` section of the document, which describes the encoded spaced and also the target reconstructed space. Along with the `<encodingLimits>` this section allows the reconstruction program to determine matrix sizes, oversampling factors, partial Fourier, etc. In the example above, data is acquired with two-fold oversampling in the read-out (`x`) direction, which is reflected in the larger matrix size in the encoded space compared to the reconstruction space. The field of view is also twice as large in the encoded space. For the first phase encoding dimension (`y`), we have a combination of oversampling (20%), reduced phase resolution (only 83 lines of k-space acquired, and partial Fourier sampling, which is reflected in the asymmetric center of the encoding limits of the `<kspace_encoding_step_1>`. Specifically, the data lines would be placed into the encoding space like this:
-
-```
-   0                                     70                                         139
-   |-------------------------------------|-------------------------------------------|
-                         ****************************************************
-                         ^               ^                                  ^
-                         0              28                                  83
-```
-
-After FFT, only the central 116 lines are kept, i.e. there is a reduced field of view in the phase encoding direction. Center and encoding limits for the readout dimension is not given in the XML header. This is to accommodate sequences where the center of the readout may change from readout to readout (alternating directions of readout). There is a field on the individual data headers (see below) to indicate the center of the readout.
-
-An experiment can have multiple encoding spaces and it is possible to indicate on each acquired data readout, which encoding space the data belongs to (see below).
-
-In addition to the defined field in the xml header, it is possible to add an arbitrary number of user defined parameters to accommodate special sequence parameters. Please consult the xml schema_ to see how user parameters are defined. Briefly, the XML header can have a section at the end which looks like:
-
-```xml
-<userParameters>
-  <userParameterLong>
-    <name>MyVar1</name><value>1003</value>
-  </userParameterLong>
-  <userParameterLong>
-    <name>MyVar2</name><value>1999</value>
-  </userParameterLong>
-  <userParameterDouble>
-    <name>MyDoubleVar</name><value>87.6676</value>
-  </userParameterDouble>
-</userParameters>
-```
-
-## Fixed Data structures
-Each raw data acquisition is preceded by the following fixed layout structures in [`ismrmrd.h`](https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h#L225).
-
-The interpretation of some of these fields may vary from sequence to sequence, i.e. for a Cartesian sequence, `kspace_encode_step_1` would be the phase encoding step, for a spiral sequence where phase encoding direction does not make sense, it would be the spiral interleave number. The `encoding_space_ref` enables the user to tie an acquisition to a specific encoding space (see above) in case there are multiple, e.g. in situations where a calibration scan may be integrated in the acquisition.
-
-The flags field is a bit mask, which in principle can be used freely by the user, but suggested flag values are given in `ismrmrd.h`, it is recommended not to use already designated flag bits for custom purposes. There are a set of bits reserved for prototyping (bits 57-64), please see `ismrmrd.h` for details.
-
-The header contains a `trajectory_dimensions` field. If the value of this field is larger than 0, it means that trajectories are stored with each individual acquisition. For a 2D acquisition, the `trajectory_dimensions` would typically be 2 and the convention (for memory layout) is that the header is followed immediately by the trajectory before the complex data. There is an example of how this memory layout could be implemented with a C++ class in the `ismrmrd.h` file:
-
-```cpp
-class Acquisition
-{
-
-//....
-
-AcquisitionHeader head_; //Header, see above
-
-float* traj_;            //Trajectory, elements = head_.trajectory_dimensions*head_.number_of_samples
-                        //   [kx,ky,kx,ky.....]        (for head_.trajectory_dimensions = 2)
-                        //   [kx,ky,kz,kx,ky,kz,.....] (for head_.trajectory_dimensions = 3)
-
-float* data_;            //Actual data, elements = head_.number_of_samples*head_.active_channels*2
-                        //   [re,im,re,im,.....,re,im,re,im,.....,re,im,re,im,.....]
-                        //    ---channel 1-------channel 2---------channel 3-----
-
-};
-```
-
-This suggested memory layout is only a suggestion. The HDF5 interface (see below) can be used to read the data into many different data structures. In fact, the user can choose to read only part of the header or not read the data, etc.
-
-As mentioned above, the ISMRMRD format also suggests a way to store reconstructed images (or maybe image data used for calibration). An `ImageHeader` structure is defined in [`ismrmrd.h`](https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h#L286).
-
-In a similar fashion to the raw data acquisition data, the intention is to store a header followed by the image data. Since image data can be in several different format (e.g. float, complex, etc.), the memory layout is less well defined but can be described as:
-
-```cpp
-template <typename T> class Image {
-
-ImageHeader head_;     //ImageHeader as defined above
-T* data_;              //Data, array of size (matrix_size[0]*matrix_size[1]*matrix_size[2]*channels),
-                        //first spatial dimension is fastest changing array index, channels outer most (slowest changing).
-};
-```
-
-## File Storage
-The ISMRM Raw Data format is stored in [HDF5 format](https://www.hdfgroup.org/solutions/hdf5). Briefly it is a hierarchical data format (much like a file system), which can contain multiple variable organized in groups (like folders in a file system). The variables can contain arrays of data values, custom defined structs, or simple text fields. It is the convention (but not a requirement) that the ISMRMRD datasets are stored in a group called `/dataset`. The XML configuration is stored in the variable `/dataset/xml` and the data is stored in `/dataset/data`. HDF5 files can be viewed with the HDFView application which is available on the HDF5 website for multiple platforms. Files can also be read directly in Matlab, in fact Matlab uses (since file format v7.3) HDF5 as its internal data format in the `.mat` files. As an example the data from an ISMRMRD file with name `myfile.h5` can be read in matlab with a command like:
-
-```
-   >> data = h5read('simple_gre.h5', '/dataset/data');
-   >> data
-
-   data =
-
-   head: [1x1 struct]
-   traj: {1x1281 cell}
-   data: {1x1281 cell}
-
-    >> data.head
-
-    ans =
-
-                   version: [1x1281 uint16]
-                     flags: [1x1281 uint64]
-           measurement_uid: [1x1281 uint32]
-              scan_counter: [1x1281 uint32]
-    acquisition_time_stamp: [1x1281 uint32]
-     physiology_time_stamp: [3x1281 uint32]
-         number_of_samples: [1x1281 uint16]
-        available_channels: [1x1281 uint16]
-           active_channels: [1x1281 uint16]
-              channel_mask: [16x1281 uint64]
-               discard_pre: [1x1281 uint16]
-              discard_post: [1x1281 uint16]
-             center_sample: [1x1281 uint16]
-        encoding_space_ref: [1x1281 uint16]
-     trajectory_dimensions: [1x1281 uint16]
-            sample_time_us: [1x1281 single]
-                  position: [3x1281 single]
-                  read_dir: [3x1281 single]
-                 phase_dir: [3x1281 single]
-                 slice_dir: [3x1281 single]
-    patient_table_position: [3x1281 single]
-                       idx: [1x1 struct]
-                  user_int: [8x1281 int32]
-                user_float: [8x1281 single]
-
-    >>
-```
-
-The HDF5 file format can be accessed from C, C++, and java using the libraries provided on the HDF5 website. The ISMRMRD distribution also comes with some C++ wrappers that can be used for easy access (read and write) from C++ programs. See below.
-
-In addition to storing acquisition data and images as defined by the headers above, the HDF5 format also enables storage of generic multi-dimensional arrays. The ISMRMRD format does not explicitly define how such data should be stored, but leaves it open for the user to add variables and data as dictated by a given application.
-
-
-## C++ Support Library
-To enable easy prototyping of C++ software using the ISMRMRD data format, a simple C++ wrapper class is provided (defined in [`dataset.h`](https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/dataset.h)):
-
-Using this wrapper, C++ applications can be programmed as:
-
-```cpp
-// Open dataset
-ISMRMRD::Dataset d(datafile.c_str(), "dataset", false);
-
-std::string xml;
-d.readHeader(xml);
-ISMRMRD::IsmrmrdHeader hdr;
-ISMRMRD::deserialize(xml.c_str(),hdr);
-
-// Do something with the header
-
-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);
-
-    // Do something with the data
-}
-```
-
-Since the XML header is defined in the `schema/ismrmrd.xsd` file, it can be
-parsed with numerous xml parsing libraries. The ISMRMRD library includes an API
-that allows for programmatically deserializing, manipulating, and serializing the
-XML header. See the code in the [`utilities`](https://github.com/ismrmrd/ismrmrd/blob/master/utilities/) directory for examples of how to
-use the XML API.
-
-## C++ Example Applications
-
-The distribution includes two example applications, one that creates a simple 2D single-channel dataset from scratch and one that reconstructs this dataset (you need FFTW installed to compile these test applications). The data generation application can be found in [`utilities/generate_cartesian_shepp_logan.cpp`](https://github.com/ismrmrd/ismrmrd/blob/master/utilities/generate_cartesian_shepp_logan.cpp):
-
-To reconstruct this synthetic dataset, you can use the test reconstruction application [`utilities/recon_cartesian_2d.cpp`](https://github.com/ismrmrd/ismrmrd/blob/master/utilities/recon_cartesian_2d.cpp):
-
-
-## External use of ISMRMRD C++ library in other projects
-
-To use ISMRMRD for your externally developed projects, add the following to your CMakeLists.txt file:
-
-```
-find_package( ISMRMRD REQUIRED )
-link_directories( ${ISMRMRD_LIBRARY_DIRS} )
-include_directories( ${ISMRMRD_INCLUDE_DIRS} )
-target_link_libraries( mytarget ${ISMRMRD_LIBRARIES} )
-```
-
-then when configuring your package use set the following cmake variables (command line variant shown):
-
-```
-cmake -DISMRMRD_DIR:PATH=<path to build/install tree of ISMRMRD> <path to my source tree>
-```
-
-## Matlab Example Code and Datasets
-
-The `examples` folder contains some matlab code to illustrate simple interaction with the ISMRMRD data format. Go to the `examples/data` folder and type the following to download the data::
-
-```bash
-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
-```
-
-For instance, to reconstruct a 2D Cartesian acquisition (10 image repetitions), type (from the `examples/matlab` folder):
-
-```
->> images = simple_cartesian_recon('../data/simple_gre.h5');
-Reconstructing image 1....done
-Reconstructing image 2....done
-Reconstructing image 3....done
-Reconstructing image 4....done
-Reconstructing image 5....done
-Reconstructing image 6....done
-Reconstructing image 7....done
-Reconstructing image 8....done
-Reconstructing image 9....done
-Reconstructing image 10....done
->>
-```
-
-You should see one of the reconstructed images display. An example is also given of a 3D acquisition with partial Fourier, phase and slice oversampling, etc. Reconstruct this dataset with:
-
-```
->> images = simple_cartesian_recon('../data/3D_partial_fourier.h5');
-Reconstructing image 1....done
-```
-
-The center slice of the volume should be displayed at the end of the reconstruction.
-
-Finally, there is also a spiral dataset. This dataset illustrates how the flexible section of the `<trajectoryDescription>` can be used to add user defined parameters and an identifier to describe the trajectory. This dataset is also an example of storing the trajectory with the data for direct reconstruction. Reconstruct this dataset with:
-
-```
->> images = simple_spiral_recon('../data/simple_spiral.h5');
-Reconstructing image 1....done
-Reconstructing image 2....done
-Reconstructing image 3....done
-Reconstructing image 4....done
-Reconstructing image 5....done
-Reconstructing image 6....done
-Reconstructing image 7....done
-Reconstructing image 8....done
-Reconstructing image 9....done
-Reconstructing image 10....done
->>
-```
-
-## Python implementation
-The Python implementation of the API is maintained in ## Other [ismrmrd-python](https://www.github.com/ismrmrd/ismrmrd-python)
-
-
+Please the [ISMRMRD documentation](https://ismrmrd.readthedocs.io) for details.


=====================================
doc/.gitignore
=====================================
@@ -0,0 +1,3 @@
+_build/
+doxygen/
+Doxyfile
\ No newline at end of file


=====================================
doc/Makefile
=====================================
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS    ?=
+SPHINXBUILD   ?= sphinx-build
+SOURCEDIR     = .
+BUILDDIR      = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)


=====================================
doc/api.rst
=====================================
@@ -0,0 +1,14 @@
+ISMRMRD API
+###########
+
+The project includes both a C and A C++ API:
+
+
+.. toctree::
+   :maxdepth: 3
+   :caption: Contents:
+
+   c-api.rst
+   cpp-api.rst
+   meta.rst
+   xml.rst


=====================================
doc/building.md
=====================================
@@ -0,0 +1,54 @@
+# Build instructions
+
+The ISMRM Raw Data format is described by an XML schema and some C-style structs with fixed memory layout and as such does not have dependencies. However, it uses HDF5 files for storage and a C++ library for reading and writing the ISMRMRD files is included in this distribution. Furthermore, since the XML header is defined with an XML schema, we encourage using XML data binding when writing software using the format. To compile all components of this distribution you need:
+
+* HDF5 (version 1.8 or higher) libraries. Available from http://www.hdfgroup.org/downloads/index.html.
+* Boost (http://www.boost.org/)
+* Cmake build tool (http://www.cmake.org/)
+* Git if you would like to use the source code archive (http://git-scm.com/)
+* FFTW if you would like to compile some of the example applications
+  (http://www.fftw.org)
+* Doxygen if you would like to generate API documentation (http://www.doxygen.org)
+
+> It is only necessary to install the dependencies if you wish to develop compiled C/C++ software, which uses the ISMRMRD format. The format can be read in Matlab or Python without installing any additional software.
+
+## Linux installation
+
+The dependencies mentioned above should be included in most linux distributions. On Ubuntu you can install all required dependencies with::
+
+```bash
+sudo apt-get -y install doxygen git-core graphviz libboost-all-dev libfftw3-dev libhdf5-serial-dev
+```
+
+After installation of dependencies, the library can be installed with:
+
+```bash
+git clone https://github.com/ismrmrd/ismrmrd
+cd ismrmrd/
+mkdir build
+cd build
+cmake ../
+make
+sudo make install
+```
+
+This will install the library in `/usr/local/` by default. To specify
+an alternative installation directory, pass `-D CMAKE_INSTALL_PREFIX=<install dir>` to `cmake`.
+
+
+## External use of ISMRMRD C++ library in other projects
+
+To use ISMRMRD for your externally developed projects, add the following to your CMakeLists.txt file:
+
+```
+find_package( ISMRMRD REQUIRED )
+link_directories( ${ISMRMRD_LIBRARY_DIRS} )
+include_directories( ${ISMRMRD_INCLUDE_DIRS} )
+target_link_libraries( mytarget ${ISMRMRD_LIBRARIES} )
+```
+
+then when configuring your package use set the following cmake variables (command line variant shown):
+
+```
+cmake -DISMRMRD_DIR:PATH=<path to build/install tree of ISMRMRD> <path to my source tree>
+```
\ No newline at end of file


=====================================
doc/c-api.rst
=====================================
@@ -0,0 +1,12 @@
+C API
+######
+
+.. doxygengroup:: capi
+   :project: ISMRMRD
+   :content-only:
+   :outline:
+   :members:
+   :protected-members:
+   :private-members:
+   :undoc-members:
+   :inner:


=====================================
doc/conf.py
=====================================
@@ -0,0 +1,77 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- Doxygen generation
+
+from pathlib import Path
+import subprocess
+
+this_folder = Path(__file__).parent
+
+def configureDoxyfile(input_dir, output_dir):
+    with open(this_folder/'Doxyfile.in', 'r') as file :
+        filedata = file.read()
+
+    filedata = filedata.replace('@CMAKE_SOURCE_DIR@', str(input_dir))
+    filedata = filedata.replace('@CMAKE_CURRENT_BINARY_DIR@', str(output_dir))
+
+    with open('Doxyfile', 'w') as file:
+        file.write(filedata)
+
+doxygen_inputdir = (this_folder/"..").resolve()
+doxygen_output = (this_folder/"doxygen").resolve()
+
+if not Path(this_folder/"doxygen").exists():
+    configureDoxyfile(doxygen_inputdir, doxygen_output)
+    subprocess.check_call('doxygen', cwd=this_folder)
+
+breathe_projects = {'ISMRMRD': str(doxygen_output/"xml")}
+breathe_default_project = 'ISMRMRD'
+
+# -- Project information -----------------------------------------------------
+
+project = 'ISMRMRD'
+copyright = '2022, ISMRMRD Working Group'
+author = 'ISMRMRD Working Group'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['breathe', 'myst_parser']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css"..
+html_static_path = ['_static']
\ No newline at end of file


=====================================
doc/cpp-api.rst
=====================================
@@ -0,0 +1,12 @@
+C++ API
+#######
+
+.. doxygengroup:: cxxapi
+   :project: ISMRMRD
+   :content-only:
+   :outline:
+   :members:
+   :protected-members:
+   :private-members:
+   :undoc-members:
+   :inner:
\ No newline at end of file


=====================================
doc/cpplibrary.rst
=====================================
@@ -0,0 +1,51 @@
+C++ Support Library
+####################
+
+To enable easy prototyping of C++ software using the ISMRMRD data format, a simple C++ wrapper class is provided (defined in `dataset.h <https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/dataset.h>_.
+
+Using this wrapper, C++ applications can be programmed as::
+
+    // Open dataset
+    ISMRMRD::Dataset d(datafile.c_str(), "dataset", false);
+
+    std::string xml;
+    d.readHeader(xml);
+    ISMRMRD::IsmrmrdHeader hdr;
+    ISMRMRD::deserialize(xml.c_str(),hdr);
+
+    // Do something with the header
+
+    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);
+
+        // Do something with the data
+    }
+
+Since the XML header is defined in the `schema/ismrmrd.xsd` file, it can be
+parsed with numerous xml parsing libraries. The ISMRMRD library includes an API
+that allows for programmatically deserializing, manipulating, and serializing the
+XML header. See the code in the `utilities <https://github.com/ismrmrd/ismrmrd/blob/master/utilities/>`_ directory for examples of how to use the XML API.
+
+C++ Example Applications
+************************
+
+The distribution includes two example applications, one that creates a simple 2D single-channel dataset from scratch and one that reconstructs this dataset (you need FFTW installed to compile these test applications). The data generation application can be found in `utilities/generate_cartesian_shepp_logan.cpp <https://github.com/ismrmrd/ismrmrd/blob/master/utilities/generate_cartesian_shepp_logan.cpp>`_:
+
+To reconstruct this synthetic dataset, you can use the test reconstruction application `utilities/recon_cartesian_2d.cpp <https://github.com/ismrmrd/ismrmrd/blob/master/utilities/recon_cartesian_2d.cpp>`_.
+
+
+External use of ISMRMRD C++ library in other projects
+******************************************************
+
+To use ISMRMRD for your externally developed projects, add the following to your CMakeLists.txt file::
+
+  find_package( ISMRMRD REQUIRED )
+  include_directories( ${ISMRMRD_INCLUDE_DIR} )
+  target_link_libraries( mytarget ISMRMRD::ISMRMRD )
+
+then when configuring your package use set the following cmake variables (command line variant shown)::
+
+  cmake <path to my source tree>


=====================================
doc/filestorage.rst
=====================================
@@ -0,0 +1,86 @@
+HDF5 File Storage
+************
+
+The ISMRM Raw Data format can really be stored in any format that you choose, but most commonly it is stored in `HDF5 format https://www.hdfgroup.org/solutions/hdf5`_. Briefly it is a hierarchical data format (much like a file system), which can contain multiple variable organized in groups (like folders in a file system). The variables can contain arrays of data values, custom defined structs, or simple text fields. It is the convention (but not a requirement) that the ISMRMRD datasets are stored in a group called `/dataset`. The XML configuration is stored in the variable `/dataset/xml` and the data is stored in `/dataset/data`. HDF5 files can be viewed with the HDFView application which is available on the HDF5 website for multiple platforms. Many programming languages also have support for working with HDF5 files. 
+
+In Python, the `h5py <https://www.h5py.org/>`_ package can be used to read the files::
+
+    import h5py
+    import numpy as np
+    f = h5py.File('testdata.h5')
+    acq = np.array(f['dataset']['data'][0])
+    { k: acq['head'][k] for k in acq['head'].dtype.fields.keys() }
+
+    {'version': array(1, dtype=uint16),
+    'flags': array(64, dtype=uint64),
+    'measurement_uid': array(0, dtype=uint32),
+    'scan_counter': array(0, dtype=uint32),
+    'acquisition_time_stamp': array(0, dtype=uint32),
+    'physiology_time_stamp': array([0, 0, 0], dtype=uint32),
+    'number_of_samples': array(512, dtype=uint16),
+    'available_channels': array(8, dtype=uint16),
+    'active_channels': array(8, dtype=uint16),
+    'channel_mask': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=uint64),
+    'discard_pre': array(0, dtype=uint16),
+    'discard_post': array(0, dtype=uint16),
+    'center_sample': array(256, dtype=uint16),
+    'encoding_space_ref': array(0, dtype=uint16),
+    'trajectory_dimensions': array(0, dtype=uint16),
+    'sample_time_us': array(5., dtype=float32),
+    'position': array([0., 0., 0.], dtype=float32),
+    'read_dir': array([0., 0., 0.], dtype=float32),
+    'phase_dir': array([0., 0., 0.], dtype=float32),
+    'slice_dir': array([0., 0., 0.], dtype=float32),
+    'patient_table_position': array([0., 0., 0.], dtype=float32),
+    'idx': array((0, 0, 0, 0, 0, 0, 0, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0]),
+        dtype=[('kspace_encode_step_1', '<u2'), ('kspace_encode_step_2', '<u2'), ('average', '<u2'), ('slice', '<u2'), ('contrast', '<u2'), ('phase', '<u2'), ('repetition', '<u2'), ('set', '<u2'), ('segment', '<u2'), ('user', '<u2', (8,))]),
+    'user_int': array([0, 0, 0, 0, 0, 0, 0, 0], dtype=int32),
+    'user_float': array([0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)}
+
+There is also a dedicated python libarary for working with the ISMRMRD files. The Python implementation of the API is maintained in `ismrmrd-python <https://www.github.com/ismrmrd/ismrmrd-python>_`
+
+Files can also be read directly in Matlab, in fact Matlab uses (since file format v7.3) HDF5 as its internal data format in the `.mat` files. As an example the data from an ISMRMRD file with name `myfile.h5` can be read in Matlab with a command like::
+
+    >> data = h5read('simple_gre.h5', '/dataset/data');
+    >> data
+
+    data =
+
+    head: [1x1 struct]
+    traj: {1x1281 cell}
+    data: {1x1281 cell}
+
+      >> data.head
+
+      ans =
+
+                    version: [1x1281 uint16]
+                      flags: [1x1281 uint64]
+            measurement_uid: [1x1281 uint32]
+                scan_counter: [1x1281 uint32]
+      acquisition_time_stamp: [1x1281 uint32]
+      physiology_time_stamp: [3x1281 uint32]
+          number_of_samples: [1x1281 uint16]
+          available_channels: [1x1281 uint16]
+            active_channels: [1x1281 uint16]
+                channel_mask: [16x1281 uint64]
+                discard_pre: [1x1281 uint16]
+                discard_post: [1x1281 uint16]
+              center_sample: [1x1281 uint16]
+          encoding_space_ref: [1x1281 uint16]
+      trajectory_dimensions: [1x1281 uint16]
+              sample_time_us: [1x1281 single]
+                    position: [3x1281 single]
+                    read_dir: [3x1281 single]
+                  phase_dir: [3x1281 single]
+                  slice_dir: [3x1281 single]
+      patient_table_position: [3x1281 single]
+                        idx: [1x1 struct]
+                    user_int: [8x1281 int32]
+                  user_float: [8x1281 single]
+
+      >>
+
+The HDF5 file format can be accessed from C, C++, and java using the libraries provided on the HDF5 website. The ISMRMRD distribution also comes with some C++ wrappers that can be used for easy access (read and write) from C++ programs. 
+
+


=====================================
doc/index.rst
=====================================
@@ -0,0 +1,19 @@
+ISMRM Raw Data Format (ISMRMRD)
+################################
+
+A prerequisite for sharing magnetic resonance (imaging) reconstruction algorithms and code is a common raw data format. The ISMRMRD project describes such a common raw data format, which attempts to capture the data fields that are required to describe the magnetic resonance experiment with enough detail to reconstruct images. The repository also contains a C/C++ library for working with the format. This standard was developed by a subcommittee of the ISMRM Sedona 2013 workshop and is described in detail in:
+
+Inati SJ, Naegele JD, Zwart NR, Roopchansingh V, Lizak MJ, Hansen DC, Liu CY, Atkinson D, Kellman P, Kozerke S, Xue H, Campbell-Washburn AE, Sørensen TS, Hansen MS. ISMRM Raw data format: A proposed standard for MRI raw datasets. `Magn Reson Med. 2017 Jan;77(1):411-421. <https://onlinelibrary.wiley.com/doi/10.1002/mrm.26089>`_
+
+Please cite this paper if you use the format.
+
+.. toctree::
+  :maxdepth: 2
+  :caption: Contents:
+
+  overview
+  building
+  filestorage
+  cpplibrary
+  api
+


=====================================
doc/make.bat
=====================================
@@ -0,0 +1,35 @@
+ at ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.https://www.sphinx-doc.org/
+	exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd


=====================================
doc/meta.rst
=====================================
@@ -0,0 +1,12 @@
+Meta API
+#########
+
+.. doxygengroup:: meta
+   :project: ISMRMRD
+   :content-only:
+   :outline:
+   :members:
+   :protected-members:
+   :private-members:
+   :undoc-members:
+   :inner:
\ No newline at end of file


=====================================
doc/overview.rst
=====================================
@@ -0,0 +1,81 @@
+Overview
+#########
+
+The raw data format combines a mix of flexible data structures (XML header) and fixed structures (equivalent to C-structs). A raw data set consist mainly of 2 sections:
+
+1. A flexible XML format document that can contain an arbitrary number of fields and accommodate everything from simple values (b-values, etc.) to entire vendor protocols, etc. This purpose of this XML document is to provide parameters that may be meaningful for some experiments but not for others. This XML format is defined by an XML Schema Definition file `schema/ismrmrd.xsd <https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd.xsd>`_.
+2. 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 <https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h>`_
+
+In addition to these sections, the ISMRMRD format also specifies an image header for storing reconstructed images and the accompanying 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.
+
+Flexible Data Header
+********************
+
+The flexible data structure is defined by the xml schema definition in `schema/ismrmrd.xsd <https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd.xsd>`_. An example of an XML file for a Cartesian 3D acquisition can be found `schema/ismrmrd_example.xml <https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd_example.xml>_
+
+The most critical elements for image reconstruction are contained in the `<encoding>` section of the document, which describes the encoded spaced and also the target reconstructed space. Along with the `<encodingLimits>` this section allows the reconstruction program to determine matrix sizes, oversampling factors, partial Fourier, etc. In the example above, data is acquired with two-fold oversampling in the read-out (`x`) direction, which is reflected in the larger matrix size in the encoded space compared to the reconstruction space. The field of view is also twice as large in the encoded space. For the first phase encoding dimension (`y`), we have a combination of oversampling (20%), reduced phase resolution (only 83 lines of k-space acquired, and partial Fourier sampling, which is reflected in the asymmetric center of the encoding limits of the `<kspace_encoding_step_1>`. Specifically, the data lines would be placed into the encoding space like this::
+
+    0                                     70                                         139
+    |-------------------------------------|-------------------------------------------|
+                            ****************************************************
+                            ^               ^                                  ^
+                            0              28                                  83
+
+After FFT, only the central 116 lines are kept, i.e. there is a reduced field of view in the phase encoding direction. Center and encoding limits for the readout dimension is not given in the XML header. This is to accommodate sequences where the center of the readout may change from readout to readout (alternating directions of readout). There is a field on the individual data headers (see below) to indicate the center of the readout.
+
+An experiment can have multiple encoding spaces and it is possible to indicate on each acquired data readout, which encoding space the data belongs to (see below).
+
+In addition to the defined field in the xml header, it is possible to add an arbitrary number of user defined parameters to accommodate special sequence parameters. Please consult the xml `schema <https://github.com/ismrmrd/ismrmrd/blob/master/schema/ismrmrd.xsd>`_ to see how user parameters are defined. Briefly, the XML header can have a section at the end which looks like::
+
+    <userParameters>
+      <userParameterLong>
+        <name>MyVar1</name><value>1003</value>
+      </userParameterLong>
+      <userParameterLong>
+        <name>MyVar2</name><value>1999</value>
+      </userParameterLong>
+      <userParameterDouble>
+        <name>MyDoubleVar</name><value>87.6676</value>
+      </userParameterDouble>
+    </userParameters>
+
+Fixed Data structures
+**********************
+
+Each raw data acquisition is preceded by the following fixed layout structures in `ismrmrd.h <https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h#L225>`_.
+
+The interpretation of some of these fields may vary from sequence to sequence, i.e. for a Cartesian sequence, `kspace_encode_step_1` would be the phase encoding step, for a spiral sequence where phase encoding direction does not make sense, it would be the spiral interleave number. The `encoding_space_ref` enables the user to tie an acquisition to a specific encoding space (see above) in case there are multiple, e.g. in situations where a calibration scan may be integrated in the acquisition.
+
+The flags field is a bit mask, which in principle can be used freely by the user, but suggested flag values are given in `ismrmrd.h`, it is recommended not to use already designated flag bits for custom purposes. There are a set of bits reserved for prototyping (bits 57-64), please see `ismrmrd.h` for details.
+
+The header contains a `trajectory_dimensions` field. If the value of this field is larger than 0, it means that trajectories are stored with each individual acquisition. For a 2D acquisition, the `trajectory_dimensions` would typically be 2 and the convention (for memory layout) is that the header is followed immediately by the trajectory before the complex data. There is an example of how this memory layout could be implemented with a C++ class in the `ismrmrd.h` file::
+
+    class Acquisition
+    {
+
+    //....
+
+    AcquisitionHeader head_; //Header, see above
+
+    float* traj_;            //Trajectory, elements = head_.trajectory_dimensions*head_.number_of_samples
+                            //   [kx,ky,kx,ky.....]        (for head_.trajectory_dimensions = 2)
+                            //   [kx,ky,kz,kx,ky,kz,.....] (for head_.trajectory_dimensions = 3)
+
+    float* data_;            //Actual data, elements = head_.number_of_samples*head_.active_channels*2
+                            //   [re,im,re,im,.....,re,im,re,im,.....,re,im,re,im,.....]
+                            //    ---channel 1-------channel 2---------channel 3-----
+
+    };
+
+This suggested memory layout is only a suggestion. The HDF5 interface (see below) can be used to read the data into many different data structures. In fact, the user can choose to read only part of the header or not read the data, etc.
+
+As mentioned above, the ISMRMRD format also suggests a way to store reconstructed images (or maybe image data used for calibration). An `ImageHeader` structure is defined in `ismrmrd.h <https://github.com/ismrmrd/ismrmrd/blob/master/include/ismrmrd/ismrmrd.h#L286>_.
+
+In a similar fashion to the raw data acquisition data, the intention is to store a header followed by the image data. Since image data can be in several different format (e.g. float, complex, etc.), the memory layout is less well defined but can be described as::
+
+    template <typename T> class Image {
+
+    ImageHeader head_;     //ImageHeader as defined above
+    T* data_;              //Data, array of size (matrix_size[0]*matrix_size[1]*matrix_size[2]*channels),
+                            //first spatial dimension is fastest changing array index, channels outer most (slowest changing).
+    };


=====================================
doc/requirements.txt
=====================================
@@ -0,0 +1,5 @@
+myst-parser
+sphinx~=4.3.0
+breathe
+sphinx-rtd-theme
+sphinxcontrib-mermaid


=====================================
doc/xml.rst
=====================================
@@ -0,0 +1,12 @@
+XML API
+#######
+
+.. doxygengroup:: xml
+   :project: ISMRMRD
+   :content-only:
+   :outline:
+   :members:
+   :protected-members:
+   :private-members:
+   :undoc-members:
+   :inner:
\ No newline at end of file


=====================================
examples/matlab/test_create_dataset.m → examples/matlab/create_dataset.m
=====================================


=====================================
examples/matlab/test_create_undersampled_dataset.m → examples/matlab/create_undersampled_dataset.m
=====================================


=====================================
examples/matlab/test_recon_dataset.m → examples/matlab/recon_dataset.m
=====================================


=====================================
include/ismrmrd/meta.h
=====================================
@@ -45,6 +45,7 @@ namespace ISMRMRD {
      */
 
 
+
     /**
        This class can represent a meta data value of any
        type and it guarantees that any value will have a
@@ -249,6 +250,8 @@ namespace ISMRMRD {
         map_t map_;
     };
 
+    /** @} */
+
     //Template function instantiations
     /*
     template void MetaContainer::set<const char*>(const char* name, const char* value);
@@ -260,6 +263,5 @@ namespace ISMRMRD {
     */
 }
 
-/** @} */
 
 #endif //ISMRMRDMETA_H


=====================================
include/ismrmrd/xml.h
=====================================
@@ -1,7 +1,6 @@
 /**
  * @file xml.h
  * @defgroup xml XML API
- * @{
  */
 
 #ifndef ISMRMRDXML_H
@@ -26,6 +25,10 @@
 
  */
 
+/**
+ * @addtogroup xml
+ * @{
+ */
 
 namespace ISMRMRD
 {
@@ -157,6 +160,13 @@ namespace ISMRMRD
 
   }; 
 
+  struct threeDimensionalFloat
+  {    
+    float x;
+    float y;
+    float z;
+  };
+
   struct SubjectInformation 
   {
     Optional<std::string> patientName;
@@ -194,6 +204,7 @@ namespace ISMRMRD
     Optional<std::string> seriesDate;
     Optional<std::string> seriesTime;
     std::string patientPosition;
+    Optional<threeDimensionalFloat> relativeTablePosition;
     Optional<long int> initialSeriesNumber;
     Optional<std::string> protocolName;
     Optional<std::string> seriesDescription;
@@ -420,10 +431,11 @@ namespace ISMRMRD
   };
 
 
-
   EXPORTISMRMRD void deserialize(const char* xml, IsmrmrdHeader& h);
   EXPORTISMRMRD void serialize(const IsmrmrdHeader& h, std::ostream& o);
-}
 
 /** @} */
+
+}
+
 #endif //ISMRMRDXML_H


=====================================
libsrc/xml.cpp
=====================================
@@ -118,6 +118,22 @@ namespace ISMRMRD
     return r;
   }
 
+  Optional<threeDimensionalFloat> parse_optional_threeDimensionalFloat(pugi::xml_node &n, const char *child) {
+
+      Optional<threeDimensionalFloat> r;
+    
+      pugi::xml_node nc = n.child(child);
+      if (nc) {
+          threeDimensionalFloat s;
+          s.x = std::strtof(nc.child_value("x"), nullptr);
+          s.y = std::strtof(nc.child_value("y"), nullptr);
+          s.z = std::strtof(nc.child_value("z"), nullptr);
+          r = s;
+      }
+
+      return r;
+  }
+
   std::vector<UserParameterLong> parse_user_parameter_long(pugi::xml_node& n, const char* child) 
   {
     std::vector<UserParameterLong> r;
@@ -373,6 +389,7 @@ namespace ISMRMRD
 	info.seriesDate = parse_optional_string(measurementInformation, "seriesDate");
 	info.seriesTime = parse_optional_string(measurementInformation, "seriesTime");
 	info.patientPosition = parse_string(measurementInformation, "patientPosition");
+	info.relativeTablePosition = parse_optional_threeDimensionalFloat(measurementInformation, "relativeTablePosition");
 	info.initialSeriesNumber = parse_optional_long(measurementInformation, "initialSeriesNumber");
 	info.protocolName = parse_optional_string(measurementInformation, "protocolName");
 	info.seriesDescription = parse_optional_string(measurementInformation, "seriesDescription");
@@ -601,6 +618,15 @@ namespace ISMRMRD
     append_node(n3,"z",s.fieldOfView_mm.z);
   }
 
+void append_optional_three_dimensional_float(pugi::xml_node& n, const char* child, const Optional<threeDimensionalFloat>& s) 
+  {
+    if (s){
+      pugi::xml_node n2 = n.append_child(child);  
+      append_node(n2,"x",s->x);
+      append_node(n2,"y",s->y);
+      append_node(n2,"z",s->z);
+    }
+  }
   void append_encoding_limit(pugi::xml_node& n, const char* child, const Optional<Limit>& l) 
   {
     if (l) {
@@ -695,6 +721,7 @@ namespace ISMRMRD
       append_optional_node(n1,"seriesDate",h.measurementInformation->seriesDate);
       append_optional_node(n1,"seriesTime",h.measurementInformation->seriesTime);
       append_node(n1,"patientPosition",h.measurementInformation->patientPosition);
+      append_optional_three_dimensional_float(n1,"relativeTablePosition",h.measurementInformation->relativeTablePosition);
       append_optional_node(n1,"initialSeriesNumber",h.measurementInformation->initialSeriesNumber);
       append_optional_node(n1,"protocolName",h.measurementInformation->protocolName);
       append_optional_node(n1,"seriesDescription",h.measurementInformation->seriesDescription);


=====================================
matlab/+ismrmrd/+xml/deserialize.m
=====================================
@@ -35,6 +35,11 @@ for n = 1:numChildNodes
 
     %Some elements occur more than once
     if isfield(info, name)
+        % Use cell arrays for multiple valued strings and dates
+        if (isStringType(name) || isDateType(name)) && ~iscell(info.(name))
+            info.(name) = {info.(name)};
+        end
+
         num = length(info.(name))+1;
     else
         num = 1;
@@ -88,7 +93,7 @@ for n = 1:numChildNodes
         if num == 1
             info.(name) = char(getTextContent(theChild));
         else
-            info.(name)(num) = char(getTextContent(theChild));
+            info.(name){num} = char(getTextContent(theChild));
         end
         continue;
     end
@@ -106,7 +111,7 @@ for n = 1:numChildNodes
         if num == 1
             info.(name) = char(getTextContent(theChild));
         else
-            info.(name)(num) = char(getTextContent(theChild));
+            info.(name){num} = char(getTextContent(theChild));
         end
         continue;
     end
@@ -166,6 +171,7 @@ function status = isCompoundType(name)
         'accelerationFactor', ...
         'matrixSize', ...
         'fieldOfView_mm', ...
+        'relativeTablePosition', ...
         'kspace_encoding_step_0', ...
         'kspace_encoding_step_1', ...
         'kspace_encoding_step_2', ...
@@ -185,7 +191,7 @@ end
 function status = isNumericalType(name)
     headerNumericalTypes = { ...
       'version', ...
-      'patientWeight', ...
+      'patientWeight_kg', ...
       'accessionNumber', ...
       'initialSeriesNumber', ...
       'systemFieldStrength_T', ...
@@ -227,8 +233,10 @@ function status = isStringType(name)
       'systemModel', ...
       'institutionName', ...
       'stationName', ...
+      'deviceID', ...
       'trajectory', ...
       'identifier', ...
+      'comment', ...
       'coilName', ...
       'calibrationMode',...
       'interleavingDimension',...


=====================================
matlab/+ismrmrd/+xml/serialize.m
=====================================
@@ -43,6 +43,7 @@ if isfield(header,'measurementInformation')
     append_optional(docNode,measurementInformationNode,measurementInformation,'seriesTime');
 
     append_node(docNode,measurementInformationNode,measurementInformation,'patientPosition');
+    append_optional_three_dimensional_float(docNode,measurementInformationNode,measurementInformation,'relativeTablePosition');
 
     append_optional(docNode,measurementInformationNode,measurementInformation,'initialSeriesNumber', at int2str);
     append_optional(docNode,measurementInformationNode,measurementInformation,'protocolName');
@@ -67,6 +68,7 @@ if isfield(header,'measurementInformation')
         for ref = referencedImageSequence(:)
             append_node(docNode,referencedImageSequenceNode,ref,'referencedSOPInstanceUID');
         end
+        measurementInformationNode.appendChild(referencedImageSequenceNode)
     end
 
     docRootNode.appendChild(measurementInformationNode);
@@ -93,6 +95,7 @@ if isfield(header,'acquisitionSystemInformation')
 
     append_optional(docNode,acquisitionSystemInformationNode,acquisitionSystemInformation,'institutionName');
     append_optional(docNode,acquisitionSystemInformationNode,acquisitionSystemInformation,'stationName', at num2str);
+    append_optional(docNode,acquisitionSystemInformationNode,acquisitionSystemInformation,'deviceID', at num2str);
     docRootNode.appendChild(acquisitionSystemInformationNode);
 end
 
@@ -105,7 +108,7 @@ if ~isfield(header,'encoding')
     error('Illegal header: missing encoding section');
 end
 
-for enc = header.encoding(:)
+for enc = header.encoding(:)'
     node = docNode.createElement('encoding');
 
     append_encoding_space(docNode,node,'encodedSpace',enc.encodedSpace);
@@ -126,7 +129,6 @@ for enc = header.encoding(:)
     node.appendChild(n2);
 
     append_node(docNode,node,enc,'trajectory');
-    node.appendChild(n2);
 
     % sometimes the encoding has the fields, but they are empty
     if isfield(enc,'trajectoryDescription')
@@ -279,6 +281,16 @@ function append_encoding_space(docNode,subnode,name,encodedSpace)
     subnode.appendChild(n2);
 end
 
+function append_optional_three_dimensional_float(docNode, subnode, subheader, name)
+    if isfield(subheader,name)
+        n2 = docNode.createElement(name);
+        threeDimensionalFloat = subheader.(matlab.lang.makeValidName(name));
+        append_optional(docNode,n2,threeDimensionalFloat,'x', at num2str);
+        append_optional(docNode,n2,threeDimensionalFloat,'y', at num2str);
+        append_optional(docNode,n2,threeDimensionalFloat,'z', at num2str);
+        subnode.appendChild(n2);
+    end
+end
 
 function append_optional(docNode,subnode,subheader,name,tostr)
     if isfield(subheader,name)
@@ -291,6 +303,9 @@ function append_optional(docNode,subnode,subheader,name,tostr)
 end
 
 function append_node(docNode,subnode,subheader,name,tostr)
+    if ~exist('tostr', 'var')
+        tostr = @char;
+    end
 
     if ischar(subheader.(name))
         n1 = docNode.createElement(name);
@@ -302,8 +317,11 @@ function append_node(docNode,subnode,subheader,name,tostr)
         val = subheader.(name)(:);
         for thisval = 1:length(val)
             n1 = docNode.createElement(name);
-            n1.appendChild...
-                (docNode.createTextNode(tostr(val(thisval))));
+            if iscell(val)
+	            n1.appendChild(docNode.createTextNode(tostr(val{thisval})));
+            else
+	            n1.appendChild(docNode.createTextNode(tostr(val(thisval))));
+            end
             subnode.appendChild(n1);
         end
     end


=====================================
matlab/test/xml/ismrmrd_example.xml
=====================================
@@ -8,14 +8,13 @@
     <systemVendor>SIEMENS</systemVendor>
     <systemModel>Avanto</systemModel>
     <systemFieldStrength_T>1.494</systemFieldStrength_T>
-    <receiverChannels>32</receiverChannels>
     <relativeReceiverNoiseBandwidth>0.79</relativeReceiverNoiseBandwidth>
+    <receiverChannels>32</receiverChannels>
   </acquisitionSystemInformation>
   <experimentalConditions>
     <H1resonanceFrequency_Hz>63642459</H1resonanceFrequency_Hz>
   </experimentalConditions>
   <encoding>
-    <trajectory>cartesian</trajectory>
     <encodedSpace>
       <matrixSize>
         <x>256</x>
@@ -62,6 +61,7 @@
         <center>0</center>
       </set>
     </encodingLimits>
+    <trajectory>cartesian</trajectory>
     <parallelImaging>
       <accelerationFactor>
         <kspace_encoding_step_1>1</kspace_encoding_step_1>


=====================================
schema/ismrmrd.xsd
=====================================
@@ -65,6 +65,7 @@
       <xs:element minOccurs="0" name="seriesDate" type="xs:date" />
       <xs:element minOccurs="0" name="seriesTime" type="xs:time" />
       <xs:element minOccurs="1" name="patientPosition" type="patientPositionType" />
+      <xs:element minOccurs="0" name="relativeTablePosition" type="threeDimensionalFloat" />
       <xs:element minOccurs="0" name="initialSeriesNumber" type="xs:long" />
       <xs:element minOccurs="0" name="protocolName" type="xs:string" />
       <xs:element minOccurs="0" name="seriesDescription" type="xs:string" />
@@ -144,6 +145,15 @@
     </xs:sequence>
   </xs:complexType>
 
+  <xs:complexType name="threeDimensionalFloat">
+    <xs:sequence>
+      <xs:element maxOccurs="1" minOccurs="1" name="x" type="xs:float" />
+      <xs:element maxOccurs="1" minOccurs="1" name="y" type="xs:float" />
+      <xs:element maxOccurs="1" minOccurs="1" name="z" type="xs:float" />
+    </xs:sequence>
+  </xs:complexType>
+
+
   <xs:complexType name="limitType">
     <xs:all>
       <xs:element default="0" name="minimum" type="xs:unsignedShort" />


=====================================
schema/ismrmrd_example_extended.xml
=====================================
@@ -21,6 +21,11 @@
     <seriesDate>2012-08-13</seriesDate>
     <seriesTime>09:10:12</seriesTime>
     <patientPosition>HFS</patientPosition>
+    <relativeTablePosition>
+      <x>0</x>
+      <y>0</y>
+      <z>10</z>
+    </relativeTablePosition>
     <initialSeriesNumber>1</initialSeriesNumber>
     <protocolName>ExampleProt</protocolName>
     <seriesDescription>MRIStudy1</seriesDescription>



View it on GitLab: https://salsa.debian.org/med-team/ismrmrd/-/commit/cbc6808c2860f5d9913f598cdcfe8e1adba1a4be

-- 
View it on GitLab: https://salsa.debian.org/med-team/ismrmrd/-/commit/cbc6808c2860f5d9913f598cdcfe8e1adba1a4be
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20220410/59dcc0a2/attachment-0001.htm>


More information about the debian-med-commit mailing list