initial commit

This commit is contained in:
2026-08-07 15:56:42 +09:00
commit 91ad25aca9
1012 changed files with 159314 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
%ADD_CONTENT write matlab structure to H5 file
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function add_content(data, gid, plist, comp, overwrite)
import io.HDF.*
fn = fieldnames(data);
for jj=1:length(fn)
if isstruct(data.(fn{jj}))
fn_sub = fieldnames(data.(fn{jj}));
if length(fn_sub) <= 2 && isfield(data.(fn{jj}), 'Value')
% found dataset
if isfield(data.(fn{jj}), 'Attributes')
Attributes.MATLAB_class = class(data.(fn{jj}).Value);
write_dataset(data.(fn{jj}).Value, gid, fn{jj}, plist, comp, overwrite, data.(fn{jj}).Attributes);
else
Attributes.MATLAB_class = class(data.(fn{jj}).Value);
write_dataset(data.(fn{jj}).Value, gid, fn{jj}, plist, comp, overwrite, Attributes);
end
elseif strcmpi(fn{jj}, 'Attributes')
% add attributes to group
fn_attr = fieldnames(data.Attributes);
for ii=1:length(fn_attr)
write_attribute(gid, data.Attributes.(fn_attr{ii}), fn_attr{ii});
end
else
% found group
gid_new = add_groups(gid, fn{jj}, plist, true);
if length(data.(fn{jj})) == 1
add_content(data.(fn{jj}), gid_new, plist, comp, overwrite)
else
fn_names = cell(1,length(data.(fn{jj})));
for ii=1:length(data.(fn{jj}))
fn_names{ii} = sprintf([fn{jj} '_%d'],ii-1);
gid_new_sub = add_groups(gid_new, fn_names{ii}, plist, true);
add_content(data.(fn{jj})(ii), gid_new_sub, plist, comp, overwrite);
end
write_attribute(gid_new, 'structure array', 'MATLAB_class');
end
end
else
% append dataset
Attributes.MATLAB_class = class(data.(fn{jj}));
write_dataset(data.(fn{jj}), gid, fn{jj}, plist, comp, overwrite, Attributes);
end
end
end
+65
View File
@@ -0,0 +1,65 @@
%ADD_GROUPS add groups or open them if they exist
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function gid = add_groups(fileID, gpath, plist, varargin)
if nargin > 3
single_data = varargin{1};
else
single_data = true;
end
if ~single_data
gpath_depth = length(gpath);
gid{1} = fileID;
for ii=1:gpath_depth
try
gid{end+1} = H5G.open(gid{ii}, gpath{ii}, plist);
catch
gid{end+1} = H5G.create(gid{ii},gpath{ii},plist,plist,plist);
end
end
else
try
gid = H5G.open(fileID, gpath, plist);
catch
gid = H5G.create(fileID,gpath,plist,plist,plist);
end
end
end
+84
View File
@@ -0,0 +1,84 @@
% Determine datatype for HDF files
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function [datatype_h5, data] = get_datatype(data)
if isempty(data)
data = '';
end
switch class(data)
case 'uint32'
datatype_h5 = 'H5T_STD_U32LE';
case 'int32'
datatype_h5 = 'H5T_STD_I32LE';
case 'int64'
datatype_h5 = 'H5T_STD_I64LE';
case 'uint64'
datatype_h5 = 'H5T_STD_U64LE';
case 'double'
if isreal(data)
datatype_h5 = 'H5T_NATIVE_DOUBLE';
else
datatype_h5 = 'complex';
end
case 'single'
if isreal(data)
datatype_h5 = 'H5T_NATIVE_FLOAT';
else
datatype_h5 = 'complex';
end
case 'logical'
data = uint32(data);
datatype_h5 = 'H5T_STD_U32LE';
case 'char'
if size(data,1)>1
data = cellstr(data);
datatype_h5 = 'char_array';
else
datatype_h5 = 'H5T_UNIX_D32BE'; %'H5T_UNIX_D32LE';
end
case 'cell'
datatype_h5 = 'H5T_C_S1';
case 'struct'
datatype_h5 = 'struct';
otherwise
error('Unknown data type %s', class(data))
end
end
+69
View File
@@ -0,0 +1,69 @@
%HDF5_APPEND_ATTR Append an attribute to a dataset
%
% file... HDF filename
% attr... structure of attributes
% loc... location of the dataset that needs to be removed
%
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function hdf5_append_attr( file, attr, loc)
import io.HDF.*
plist = 'H5P_DEFAULT';
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
gpath = strsplit(rm_delimiter(loc), '/');
gpath_depth = length(gpath);
gid{1} = fileID;
for ii=1:gpath_depth
try
gid{end+1} = H5G.open(gid{ii}, gpath{ii}, plist);
catch
gid{end+1} = H5D.open(gid{ii}, gpath{ii});
end
end
fn = fieldnames(attr);
for ii=1:length(fn)
write_attribute(gid{end}, attr.(fn{ii}), fn{ii}, true);
end
H5F.close(fileID);
end
+65
View File
@@ -0,0 +1,65 @@
%HDF5_ATTR_EXISTS check if attribute exists in given file
% file... h5 file path
% attr... dataset name
%
% *optional*
% gpath... path within the h5 file; default root (/)
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function [ out ] = hdf5_attr_exists(file, name, varargin)
out = false;
% load info
if nargin > 2
h = h5info(file, varargin{1});
else
h = h5info(file);
end
% loop through datasets and check if name exists
for ii=1:numel(h.Attributes)
if strcmpi(h.Attributes(ii).Name, name)
out = true;
break
end
end
end
+132
View File
@@ -0,0 +1,132 @@
%HDF5_CP_FILE copy HDF files
% orig_filename... source file
% duplicate_filename... target file
%
% *optional* given as name/value pair
% groups... groups to copy; either string or cell of
% strings; default: everything in root
% copy_type... 'deep', 'normal' or 'shallow' copy;
% 'shallow' creates external links in target file;
% 'normal' is similar to linux 'cp' command;
% 'deep' dereferences all internal and external links;
% default: 'shallow'
%
% EXAMPLES:
% hdf5_cp_file('./test.h5', './test_new.h5')
% hdf5_cp_file('./test.h5', './test_new.h5', 'copy_type', 'deep');
%
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function hdf5_cp_file(orig_filename, duplicate_filename, varargin)
import io.HDF.*
% take care of input arguments
groups = [];
copy_type = 'shallow';
% parse the variable input arguments vararg = cell(0,0);
if ~isempty(varargin)
for ind = 1:2:length(varargin)
name = varargin{ind};
value = varargin{ind+1};
switch lower(name)
case 'groups'
groups = value;
case 'copy_type'
copy_type = value;
end
end
end
switch copy_type
case 'shallow'
if isempty(groups)
% if no groups are specified, use h5info to get all datasets and groups
% from root
h = h5info(orig_filename, '/');
lng = length(h.Groups);
lnd = length(h.Datasets);
lna = length(h.Attributes);
groups = cell([1 lng+lnd]);
attributes = [];
for ii=1:lng
groups{ii} = h.Groups(ii).Name;
end
for ii=1:lnd
groups{ii+lng} = h.Datasets(ii).Name;
end
for ii=1:lna
attributes.(h.Attributes(ii).Name) = h.Attributes(ii).Value;
if iscell(h.Attributes(ii).Value)
attributes.(h.Attributes(ii).Name) = attributes.(h.Attributes(ii).Name){1};
end
end
else
attributes = [];
end
s = [];
if iscell(groups)
for ii=1:length(groups)
subgrps = strsplit(rm_delimiter(groups{ii}), '/');
s = setfield(s, subgrps{:}, ['ext:' orig_filename ':' groups{ii}]);
end
else
s.groups = ['ext:' orig_filename ':' groups];
end
% append attributes
if ~isempty(attributes)
s.Attributes = attributes;
end
save2hdf5(duplicate_filename, s, 'overwrite', true, 'iscopy', true);
case 'deep'
s = io.HDF.hdf5_load(orig_filename, '-ca');
save2hdf5(duplicate_filename, s, 'overwrite', true, 'iscopy', true);
case 'normal'
copyfile(orig_filename, duplicate_filename)
otherwise
error('Unknown copy type!')
end
end
+99
View File
@@ -0,0 +1,99 @@
%HDF5_DSET_EXISTS check if dataset exists in given file
% file... h5 file path
% dset... dataset name
%
% *optional*
% gpath... path within the h5 file; default root (/)
% check_links... include links; default true
%
% EXAMPLES:
% out = io.HDF.hdf5_dset_exists('./recons.h5',
% 'object_phase_unwrapped', '/reconstruction', true);
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function [out] = hdf5_dset_exists(file, dset, varargin)
out = false;
% load info
if nargin > 2
h = h5info(file, varargin{1});
else
h = h5info(file);
end
if nargin > 3
check_links = varargin{2};
else
check_links = true;
end
if nargin > 4
check_groups = varargin{3};
else
check_groups = true;
end
% loop through datasets and check if name exists
for ii=1:numel(h.Datasets)
if strcmpi(h.Datasets(ii).Name, dset)
out = true;
break
end
end
if check_links
for ii=1:numel(h.Links)
if strcmpi(h.Links(ii).Name, dset)
out = true;
break
end
end
end
if check_groups
for ii=1:numel(h.Groups)
[~, gname] = fileparts(h.Groups(ii).Name);
if strcmpi(gname, dset)
out = true;
break
end
end
end
end
+642
View File
@@ -0,0 +1,642 @@
% HDF5_LOAD Load an hdf5 file
%
% DATA = HDF5_LOAD(filename) reads a complete file hierarchy recursively, with
% file name/path being specified by the 'filename' argument
%
% DATA = HDF5_LOAD(filename, '-a') reads a complete file hierarchy
% recursively, including attributes
%
% DATA = HDF5_LOAD(filename, location) reads a particular group, link, or a single dataset
% specified by the 'location' argument
%
% ATT = HDF5_LOAD(filename, location, '-a') reads all datasets and attributes associated
% with a particular location in the file (group, link or dataset)
%
% ATT = HDF5_LOAD(filename, location, '-ca') reads all datasets and attributes associated
% with a particular location in the file (group, link or dataset) and
% converts datasets to a specific matlab class based on attribute 'MATLAB_class'
%
% SLICE = HDF5_LOAD(filename, location, {rowRange, colRange, frameRange, ...}) reads a
% portion of a dataset along specified dimentions, where slicing ranges can be defined in
% the following ways (negative indexes count from the end of the corresponding dimensions):
% range = scalar_index - reads a particular row/col/frame/... (indentical to
% 'range = [scalar_index, scalar_index]')
% range = [start_index, end_index] - reads all data between start and end
% indexes
% range = [start_index, Inf] - reads all data from start_index to the last
% existing element in the file
% range = [], or range is omitted at the end - reads the full range of values for that
% dimention (indentical to 'range = [1, Inf]')
%
% Examples:
% hdf5_load('scan_003.hdf5')
% hdf5_load('scan_003.hdf5', '/entry/sample/description')
% hdf5_load('scan_003.hdf5', '/entry/collection/data/spec', '-a')
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {5})
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {[-100, Inf]})
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {5, [500, Inf], [1, 100]})
% hdf5_load('scan_003.hdf5', '/entry/instrument/Pilatus_2M/data', {[], [], [1, 100]})
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group
% and the Science IT group, Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function data = hdf5_load(filename, varargin)
import io.HDF.*
load_attr = false;
convert2matlab = false;
narginchk(1, 3);
if nargin == 1
% Read the complete file hierarchy recursively
try
info = h5info(filename);
info.Name = ''; % a special case of the root group
catch ME
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
ME = MException('hdf5_load:h5info', ...
strjoin({'File', filename, 'does not exist'}));
end
throwAsCaller(ME);
end
[data, links] = hdf5_loadGroup(filename, info);
data = assign_links(data, info, links);
elseif nargin == 2
if any(strcmp(varargin{1}, {'-a', '-ca', '-c'}))
% second argument is an attribute flag
try
info = h5info(filename);
info.Name = ''; % a special case of the root group
catch ME
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
ME = MException('hdf5_load:h5info', ...
strjoin({'File', filename, 'does not exist or is not valid h5 file'}));
end
throwAsCaller(ME);
end
if any(strcmp(varargin{1}, {'-a', '-ca'}))
load_attr = true;
end
if any(strcmp(varargin{1}, {'-ca', '-c'}))
convert2matlab = true;
end
[data, links] = hdf5_loadGroup(filename, info, convert2matlab, load_attr);
data = assign_links(data, info, links, varargin{1});
else
% Read a group or a single dataset
location = varargin{1};
try
info = h5info(filename, location);
if strcmp(info.Name, '/') % a special case of the root group
info.Name = '';
end
catch ME
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
ME = MException('hdf5_load:h5info', ...
strjoin({'File', filename, 'does not exist'}));
elseif strcmp(ME.identifier, 'MATLAB:imagesci:h5info:libraryError')
ME = MException('hdf5_load:h5info', ...
strjoin({'H5Location', location, 'was not found in', filename, 'file'}));
end
throwAsCaller(ME);
end
if isfield(info, 'Groups')
% Read a group with its internal hierarchy
[data, links] = hdf5_loadGroup(filename, info);
data = assign_links(data, info, links);
elseif isfield(info, 'Datatype')
% Read a data set
type = info.Datatype.Class;
data = hdf5_loadDataset(filename, location, type);
elseif isfield(info, 'Type')
% Read a link
data = hdf5_loadLink(info);
else
error('hdf5_load:parse_argument', ...
'The 2-nd argument must be a name of a group, dataset, or link');
end
end
elseif nargin == 3
% Read attributes of a group or a data set, or slices of a data set
location = varargin{1};
try
info = h5info(filename, location);
if strcmp(info.Name, '/') % a special case of the root group
info.Name = '';
end
catch ME
if strcmp(ME.identifier, 'MATLAB:imagesci:h5info:fileOpenErr')
ME = MException('hdf5_load:h5info', ...
strjoin({'File', filename, 'does not exist or is not HDF5 format'}));
elseif strcmp(ME.identifier, 'MATLAB:imagesci:h5info:libraryError')
ME = MException('hdf5_load:h5info', ...
strjoin({'H5Location', location, 'was not found in', filename, 'file'}));
end
throwAsCaller(ME);
end
if iscell(varargin{2})
% Read slices of a data set
slices = varargin{2};
% Check if the specified location is a data set
if ~isfield(info, 'Dataspace')
error('hdf5_load:invalid_location', ...
'Slicing ranges are not applicable, the location is not a data set');
end
data_size = info.Dataspace.Size;
if length(slices) > length(data_size)
error('hdf5_load:invalid_slicing', ...
'A number of slicing ranges is larger than a dimention of a data set')
end
% Parse ranges
startIndex = ones(1, length(data_size));
nElements = Inf(1, length(data_size));
for i = 1:length(slices)
[startIndex(i), nElements(i)] = parse_range(slices{i}, data_size(i));
end
% Read data
data = h5read(filename, location, startIndex, nElements);
elseif any(strcmp(varargin{2}, {'-a', '-ca', '-c'}))
% Read attributes and/or convert to matlab structures
if any(strcmp(varargin{2}, {'-a', '-ca'}))
load_attr = true;
end
if any(strcmp(varargin{2}, {'-ca', '-c'}))
convert2matlab = true;
end
if isfield(info, 'Groups')
% Read a group with its internal hierarchy
[data, links] = hdf5_loadGroup(filename, info, convert2matlab, load_attr);
data = assign_links(data, info, links, varargin{2});
elseif isfield(info, 'Datatype')
% Read a data set
type = info.Datatype.Class;
dset_val = hdf5_loadDataset(filename, location, type);
if load_attr || convert2matlab
[dset_attr, ml_class_dset] = hdf5_loadAttributes(info, convert2matlab, load_attr);
else
ml_class_dset = [];
end
if ~isempty(ml_class_dset)
switch ml_class_dset
case 'complex'
dset_val = dset_val.r + 1i*dset_val.i;
case 'cell'
if ~iscell(dset_val)
dset_val = {dset_val};
end
case 'char_array'
dset_val = char(dset_val);
otherwise
conv2ml = str2func(ml_class_dset);
dset_val = conv2ml(dset_val);
end
end
if load_attr
data.Attributes = dset_attr;
data.Value = dset_val;
else
data = dset_val;
end
elseif isfield(info, 'Type')
% Read a link
data = hdf5_loadLink(info, convert2matlab, load_attr);
end
else
error('hdf5_load:parse_argument', ...
'Incorrect 3-rd argument');
end
end
function [data, links] = hdf5_loadGroup(filename, info, varargin)
import io.HDF.*
if nargin > 2
convert2matlab = varargin{1};
load_attr = varargin{2};
else
convert2matlab = false;
load_attr = false;
end
data = [];
% Collect links
links = info.Links.'; % transform to a row for easier indexing
if ~isempty(links)
for link_ind = 1:length(links)
links(link_ind).Name = [info.Name, '/', links(link_ind).Name];
end
end
% Load the datasets
for dataset_ind = 1:length(info.Datasets)
dset_info = info.Datasets(dataset_ind);
dset_name = dset_info.Name;
location = [info.Name, '/', dset_name];
type = dset_info.Datatype.Class;
dset_val = hdf5_loadDataset(filename, location, type);
% Load attributes of a dataset
if load_attr || convert2matlab
[dset_attr, ml_class_dset] = hdf5_loadAttributes(dset_info, convert2matlab, load_attr);
else
ml_class_dset = [];
end
if ~isempty(ml_class_dset)
switch ml_class_dset
case 'complex'
dset_val = dset_val.r + 1i*dset_val.i;
case 'cell'
if ~iscell(dset_val)
dset_val = {dset_val};
end
case 'char_array'
dset_val = char(dset_val);
otherwise
conv2ml = str2func(ml_class_dset);
dset_val = conv2ml(dset_val);
end
end
if load_attr
data.(dset_name).Attributes = dset_attr;
data.(dset_name).Value = dset_val;
else
data.(dset_name) = dset_val;
end
end
% Load attributes of a group
if load_attr || convert2matlab
[group_attr, ml_class_group] = hdf5_loadAttributes(info, convert2matlab, load_attr);
if load_attr
data.Attributes = group_attr;
end
else
ml_class_group = [];
end
% Load the internal groups recursively
for group_ind = 1:length(info.Groups)
[group_data, child_links] = hdf5_loadGroup(filename, info.Groups(group_ind), convert2matlab, load_attr);
[~, group_name] = fileparts(info.Groups(group_ind).Name);
data.(group_name) = group_data;
% Aggregate links
links = [links, child_links]; %#ok<AGROW> There shouldn't be too many links present
end
if ~isempty(ml_class_group)
% convert the groups
data_temp = data;
data = [];
if isfield(data_temp, 'Attributes')
data.Attributes = data_temp.Attributes;
data_temp = rmfield(data_temp, 'Attributes');
fn = fieldnames(data_temp);
for group_ind = 1:length(fn)
switch ml_class_group
case 'cell'
data.Value{group_ind} = data_temp.(fn{group_ind});
case 'structure array'
data.Value(group_ind) = data_temp.(fn{group_ind});
otherwise
keyboard
end
end
else
fn = fieldnames(data_temp);
for group_ind = 1:length(fn)
switch ml_class_group
case 'cell'
data{group_ind} = data_temp.(fn{group_ind});
case 'structure array'
data(group_ind) = data_temp.(fn{group_ind});
otherwise
keyboard
end
end
end
end
function [data, ml_class] = hdf5_loadAttributes(info, convert2matlab, load_attr)
data = [];
ml_class = [];
if isfield(info, 'Attributes') % info structure may not contain Attributes field
attr_info = info.Attributes;
for attr_ind = 1:length(attr_info)
attr = attr_info(attr_ind);
attr_name = attr.Name;
if ~isvarname(attr_name)
if ~any(strcmpi({attr_info.Name}, ['MATLAB' attr_name])) && ~strcmpi(attr_name, '_class')
warning('Invalid attribute name! Added "MATLAB" prefix to %s.', attr_name)
attr_name = ['MATLAB' attr_name];
else
error('Invalid attribute name.')
end
end
if convert2matlab && strcmpi(attr_name, 'MATLAB_class')
ml_class = attr.Value{1};
elseif load_attr
if iscell(attr.Value)
data.(attr_name) = attr.Value{1};
else
data.(attr_name) = attr.Value;
end
end
end
end
function data = hdf5_loadDataset(filename, location, type)
if strcmp(type, 'H5T_ENUM')
% Workaround for a bug in h5postprocessenums (part of h5read) function
data = read_enum(filename, location);
else
data = h5read(filename, location);
if iscell(data) && numel(data) == 1 && ischar(data{1})
data = data{1}; % utility string unwrapping from a single cell
end
end
function data = hdf5_loadLink(link, varargin)
if nargin > 2
convert2matlab = varargin{1};
load_attr = varargin{2};
else
convert2matlab = false;
load_attr = false;
end
switch link.Type
case {'hard link', 'soft link'}
filename = link.Filename;
location = link.Value{1};
case 'external link'
filename = absolute_path(link.Value{1}, link.Filename);
location = link.Value{2};
otherwise
error('hdf5_load:hdf5_loadLink', ...
strjoin({'Unknown link type at', link.Name}));
end
link_info = h5info(filename, location);
if strcmp(link_info.Name, '/') % a special case of the root group
link_info.Name = '';
end
if isfield(link_info, 'Groups')
[data, links] = hdf5_loadGroup(filename, link_info, convert2matlab, load_attr);
data = assign_links(data, link_info, links);
elseif isfield(link_info, 'Datatype')
type = link_info.Datatype.Class;
data = hdf5_loadDataset(filename, location, type);
elseif isfield(link_info, 'Type')
data = hdf5_loadLink(link_info, convert2matlab, load_attr);
else
error('hdf5_load:hdf5_loadLink', ...
strjoin({'A link at', link_info.Name, 'must be a name of a group, dataset, or link'}));
end
function data = assign_links(data, info, links, varargin)
import io.HDF.*
if ~isempty(varargin)
flag = varargin{1};
else
flag = [];
end
if ~isempty(links)
cut_start = length(info.Name) + 1;
while true
resolved_links = false(size(links));
for ind = 1:length(links)
link = links(ind);
place = strrep(link.Name(cut_start:end), '/', '.');
target = [];
target_struc = [];
if ~isempty(flag) && contains(flag, 'a') && contains(flag, 'c')
target_struc = ['.Value'];
end
switch link.Type
case {'hard link', 'soft link'}
try
parent = strsplit(link.Value{1}, '/');
parent = strjoin(parent(1:end-1), '/');
parent_info = h5info(info.Filename, parent);
if isfield(parent_info, 'Attributes') && ~isempty(parent_info.Attributes)
for ii=1:numel(parent_info.Attributes)
if strcmp(parent_info.Attributes(ii).Name, 'MATLAB_class') && ~isempty(flag) && contains(flag, 'c')
% get pointer index
pnt_indx = strsplit(link.Value{1}, '_');
pnt_indx = str2double(pnt_indx(end));
target_add = [];
switch parent_info.Attributes(ii).Value{1}
case 'cell'
target_add = sprintf('{%d}', pnt_indx+1);
case 'structure array'
target_add = sprintf('(%d)', pnt_indx+1);
otherwise
keyboard
end
target = [strrep(parent, '/', '.') target_struc target_add];
break
end
end
end
if isempty(target)
target = [strrep(link.Value{1}(cut_start:end), '/', '.') target_struc];
end
evalc(['data', place, ' = data', target]);
catch
continue % postpone this link resolution
end
case 'external link'
ext_link = absolute_path(link.Value{1}, info.Filename);
% make sure to reference the same variable in evalc!
if ~isempty(flag)
target_data = hdf5_load(ext_link, link.Value{2}, flag); %#ok<NASGU>
else
target_data = hdf5_load(ext_link, link.Value{2});
end
evalc(['data', place, ' = target_data']);
otherwise
error('hdf5_load:assign_links', ...
strjoin({'Unknown link type at', place}));
end
resolved_links(ind) = true;
end
if all(resolved_links)
% all links have been assigned
return
end
if ~any(resolved_links)
% none of the links has been assigned in this iteration
error('hdf5_load:assign_links', ...
strjoin({'Cannot assign link(s) at', ''}));
end
links = links(~resolved_links);
end
end
function filepath = absolute_path(filepath, current_filepath)
if ~startsWith(filepath, '/')
path = fileparts(current_filepath);
filepath = fullfile(path, filepath);
end
function [startVal, nVals] = parse_range(valRange, maxVal)
if isempty(valRange) % empty
startVal = 1;
nVals = Inf;
elseif isscalar(valRange) % single value
if valRange <= -1
valRange = maxVal + valRange + 1;
end
startVal = valRange;
nVals = 1;
elseif isvector(valRange) && numel(valRange) == 2 % vector with two values
if valRange(1) <= -1
if isinf(valRange(1))
valRange(1) = 1; % = -Inf
else
valRange(1) = maxVal + valRange(1) + 1;
end
end
startVal = valRange(1);
if valRange(2) <= -1
if isinf(valRange(2))
valRange(2) = 1; % = -Inf
else
valRange(2) = maxVal + valRange(2) + 1;
end
end
nVals = valRange(2) - startVal + 1;
else
error('hdf5_load:parse_range', ...
'A range should be specified with <= 2 parameters');
end
if startVal < 1 || startVal > maxVal || nVals < 1 || (nVals > maxVal && ~isinf(nVals))
error('hdf5_load:parse_range', ...
'The resulting range is out of data borders');
end
function data = read_enum(filename, location)
file_id = H5F.open(filename);
dset_id = H5D.open(file_id, location);
type_id = H5D.get_type(dset_id);
data = H5D.read(dset_id); % numerical member of enumeration
data = H5T.enum_nameof(type_id, data); % associated symbol name
H5T.close(type_id);
H5D.close(dset_id);
H5F.close(file_id);
+80
View File
@@ -0,0 +1,80 @@
%HDF5_MV_DATA Move data within an HDF5 file
% hdf5_mv_data creates a new (UNIX-like) hard link at loc_dest to the dataset at
% loc_origin and deletes the hard link to the dataset at loc_origin.
%
% file... HDF filename
% loc_origin... location of the data that needs to be moved
% loc_dest... destination and name of the new data
%
% EXAMPLE:
% % move dataset probe from root to group measurements
% hdf5_mv_data('./awesome_file.h5', 'probe', 'measurements/probe')
%
% Please notice that all groups and datasets have to exist before running
% the script!
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function hdf5_mv_data( file, loc_origin, loc_dest)
import io.HDF.*
plist = 'H5P_DEFAULT';
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
gpath1 = strsplit(rm_delimiter(loc_origin), '/');
gid1 = add_groups(fileID, gpath1(1:end-1), plist, false);
gpath2 = strsplit(rm_delimiter(loc_dest), '/');
gid2 = add_groups(fileID, gpath2(1:end-1), plist, false);
try
datasetID = H5D.open(gid1{end}, gpath1{end});
dataset = true;
catch
gid1 = add_groups(fileID,gpath1,plist, false);
datasetID = gid1{end};
dataset = false;
end
H5O.link(datasetID,gid2{end},gpath2{end},plist,plist);
if dataset
H5L.delete(gid1{end}, gpath1{end}, plist);
else
H5L.delete(gid1{end-1}, gpath1{end}, plist);
end
H5F.close(fileID);
end
+65
View File
@@ -0,0 +1,65 @@
%HDF5_RM_ATTR Delete attribute(s) from HDF file
%
% file... HDF filename
% loc... location within the HDF file
% attr_name... string or cell of strings containing the names of the
% obsolete attributes
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function hdf5_rm_attr( file, loc, attr_name)
import io.HDF.*
plist = 'H5P_DEFAULT';
% open file
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
% get group ID
gpath = strsplit(rm_delimiter(loc), '/');
gid = add_groups(fileID, gpath(1:end-1), plist, false);
% delete attributes
if iscell(attr_name)
for ii=1:length(attr_name)
H5A.delete(gid{end}, attr_name{ii})
end
else
H5A.delete(gid{end}, attr_name)
end
end
+57
View File
@@ -0,0 +1,57 @@
%HDF5_RM_DATA Delete a dataset within an HDF5 file
%
% file... HDF filename
% loc... location of the dataset that needs to be removed
%
% Please notice that HDF5 does not free the space after removing datasets!
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function hdf5_rm_data( file, loc)
import io.HDF.*
plist = 'H5P_DEFAULT';
fileID = H5F.open(file,'H5F_ACC_RDWR',plist);
gpath1 = strsplit(rm_delimiter(loc), '/');
gid1 = add_groups(fileID, gpath1(1:end-1), plist, false);
H5L.delete(gid1{end}, gpath1{end}, plist);
H5F.close(fileID);
end
+143
View File
@@ -0,0 +1,143 @@
% Call function without arguments for instructions on how to use it
% Filename: $RCSfile: hdf5read_main.m,v $
%
% $Revision: 1.1 $ $Date: 2010/10/02 07:58:50 $
% $Author: $
% $Tag: $
%
% Description:
% Macro for reading HDF5 files written for example by the EIGER server
% program cbd_server
%
% Note:
% So far this is mainly a place holder for a thorough implementation.
%
% Dependencies:
% - image_read_set_default
% - fopen_until_exists
% - get_hdr_val
%
%
% history:
%
% September 30th 2010: 1st version
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function [frame,vararg_remain] = hdf5read_main(filename,varargin)
import io.HDF.*
import io.image_read
import utils.fopen_until_exists
import utils.get_hdr_val
% 0: no debug information
% 1: some feedback
% 2: a lot of information
debug_level = 0;
% initialize return argument
frame = struct('header',[], 'data',[]);
% check minimum number of input arguments
if (nargin < 1)
image_read_sub_help(mfilename,'h5');
error('At least the filename has to be specified as input parameter.');
end
% accept cell array with name/value pairs as well
no_of_in_arg = nargin;
if (nargin == 2)
if (isempty(varargin))
% ignore empty cell array
no_of_in_arg = no_of_in_arg -1;
else
if (iscell(varargin{1}))
% use a filled one given as first and only variable parameter
varargin = varargin{1};
no_of_in_arg = 1 + length(varargin);
end
end
end
% check number of input arguments
if (rem(no_of_in_arg,2) ~= 1)
error('The optional parameters have to be specified as ''name'',value pairs');
end
% set default values for the variable input arguments and parse the named
% parameters:
vararg = cell(0,0);
for ind = 1:2:length(varargin)
name = varargin{ind};
value = varargin{ind+1};
switch name
otherwise
% pass further arguments on to fopen_until_exists
vararg{end+1} = name;
vararg{end+1} = value;
end
end
% try to open the data file
if (debug_level >= 1)
fprintf('Opening %s.\n',filename);
end
[fid,vararg_remain] = fopen_until_exists(filename,vararg);
if (fid < 0)
return;
end
% close input data file
fclose(fid);
% get file header
hdr = hdf5info(filename);
% store part of the file header in the return argument
frame.header = {};
frame.header{end+1} = 'Exposure_time 1.0';
% add the file modification date to the header
dir_entry = dir(filename);
frame.header{end+1} = [ 'DateTime ' dir_entry.date ];
% read all data of first data set at once
frame.data = hdf5read(hdr.GroupHierarchy(1).Groups(1).Datasets(1));
if (debug_level >= 2)
fprintf('%dx%dx%dx%s data bytes read\n',...
size(fdat,1),size(fdat,2),size(fdat,3),size(fdat,4));
end
+43
View File
@@ -0,0 +1,43 @@
%RM_DELIMITER makes sure that the path does not start with /
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function path = rm_delimiter(path)
% make sure that the path does not start with /
if strcmp(path(1), '/')
path = path(2:end);
end
end
+242
View File
@@ -0,0 +1,242 @@
%SAVE2HDF5 saves matlab data to a Hierarchical Data Format file (hdf5)
%
% filename... full path to file, including file extension
% data... matlab structure or array or link
% data_name... needed if input data is not a matlab structure, needs
% to be given as name/value pair
%
% *optional*
% overwrite... replace existing file if it exists
% gpath... specify the group to which you want to append the data
% (only if data is an array); default root ('/')
% Attributes... structure of attributes; will be appended to current
% gpath
% comp... compression level; default 0 (no compression)
% creator... attribute in root; default 'ptycho_recons'
%
%
% If you want to save a structure, everything declared within an 'Attributes'
% fieldname will be treated as an attribute to the current group.
% If you want to add attributes to a dataset, you have to define your
% data within .Value and your attributes within .Attributes.
%
% A simple structure could look like:
% h5_struc = [];
% h5_struc.probe_mask = ones(256,256);
% h5_struc.Attributes.probe_id = 1;
% h5_struc.measurement.n0.diff = fmag(:,:,1);
% h5_struc.measurement.n0.Attributes.detector = 0;
% h5_struc.measurement.n1.diff.Value = fmag(:,:,2);
% h5_struc.measurement.n1.diff.Attributes.slice = 2;
%
% fmag(:,:,1) will be written to dataset 'diff' in group '/measurement/n0'
% fmag(:,:,2) with attribute 'slice' will be written to dataset 'diff' in
% group '/measurement/n1'
%
%
% EXAMPLES:
% -) if data is a matlab structure:
% save2hdf5('./awesome_file.h5', data);
% save2hdf5('./awesome_file.h5', data, 'overwrite', true);
%
%
% -) if data is a matlab array:
% save2hdf5('./awesome_file.h5', data, 'data_name', data_name);
% save2hdf5('./awesome_file.h5', data, 'data_name', 'my_dataset',...
% 'gpath', 'group1/group2', 'Attributes', attr_struc);
%
% -) if data is a link:
% currently, only external links ('ext') and internal soft links
% ('int_soft') are supported
%
% external links have to be specified by a single string with
% 3 sections: '<link_type>:<file_path>:<target_object>'
%
% e.g.: 'ext:./awesome_file2.h5:/data'
% save2hdf5('./awesome_file.h5',...
% 'ext:./awesome_file2.h5:/data', 'data_name', data_name)
%
% will create a link called $data_name to dataset (or group) '/data'
% in './awesome_file2.h5'
%
% internal links have to be specified by a single string with
% 2 sections: '<link_type>:<target_object>'
%
% e.g.: 'int_soft:/data'
% save2hdf5('./awesome_file.h5',...
% 'int_soft:/data', 'data_name', data_name, 'gpath', 'g1/g2')
%
% will create a link called $data_name to dataset (or group) '/data'
% in '/g1/g2'
%
%
% Please notice that structures are not supported as attributes, i.e.
% h5_struc = [];
% h5_struc.attr.probe.probe_id = 1;
%
% save2hdf5('./awesome_file.h5', h5_struc)
%
% will crash!
%
%
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function save2hdf5( filename, data, varargin)
import io.HDF.*
% take care of input arguments
overwrite = false;
gpath_full = '';
attr = [];
data_name = '';
comp = 0;
creator = 'ptycho_recons';
iscopy = false;
extend_dim = 0;
extendable = false;
extend_offset = 0;
extend_maxdims = 0;
vararg = cell(0,0);
% parse the variable input arguments vararg = cell(0,0);
if ~isempty(varargin)
for ind = 1:2:length(varargin)
name = varargin{ind};
value = varargin{ind+1};
switch lower(name)
case 'data_name'
data_name = value;
case 'overwrite'
overwrite = value;
case 'gpath'
gpath_full = value;
case 'attr'
attr = value;
case 'comp'
comp = value;
case 'creator'
creator = value;
case 'iscopy'
iscopy = value;
case 'extend_dim'
extend_dim = value;
case 'extendable'
extendable = value;
case 'extend_offset'
extend_offset = value;
case 'extend_maxdims'
extend_maxdims = value;
otherwise
vararg{end+1} = name;
vararg{end+1} = value;
end
end
end
if ~isstruct(data)
full_data = false;
else
full_data = true;
end
if ~isstruct(data) && isempty(data_name)
data_name = inputname(2);
if isempty(data_name)
error('Please specify the data_name.')
end
end
if extendable && extend_dim
error('Extending the dimension of an unlimited dataset is currently not supported.');
end
plist = 'H5P_DEFAULT';
%%% create file if it does not exist
if exist(filename, 'file')&&~overwrite
fileID = H5F.open(filename,'H5F_ACC_RDWR',plist);
else
fileID = H5F.create(filename,'H5F_ACC_TRUNC','H5P_DEFAULT','H5P_DEFAULT');
if ~iscopy
write_attribute(fileID, filename, 'filename');
write_attribute(fileID, creator,'creator');
write_attribute(fileID, datestr(now),'file_time');
end
end
if full_data
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% data as structure %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
add_content(data, fileID, plist, comp, overwrite)
else
%%%%%%%%%%%%%%%%%%%%%
%%% data as array %%%
%%%%%%%%%%%%%%%%%%%%%
% prepare group handles
if ~isempty(gpath_full)
gpath = strsplit(rm_delimiter(gpath_full), '/');
gid = add_groups(fileID, gpath, plist, false);
else
gid{1} = fileID;
end
% write data to file
write_dataset(data, gid{end}, data_name, plist, comp, overwrite, [], extend_dim, extendable, extend_offset, extend_maxdims);
% append attributes
if ~isempty(attr)
attr_fn = fieldnames(attr);
for ii=1:length(attr_fn)
write_attribute(gid{end}, attr.(attr_fn{ii}), attr_fn{ii}, true);
end
end
end
% close handles
H5F.close(fileID);
end
+119
View File
@@ -0,0 +1,119 @@
%WRITE_ATTRIBUTE write attribute data_name with value data to ID gid
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function write_attribute(gid, data, data_name, varargin)
import io.HDF.*
if nargin > 3
safe = varargin{1};
else
safe = false;
end
[datatypeID, data] = get_datatype(data);
if ischar(data)
% The ptycho C++ code expects strings as H5S_SCALAR, so we have to
% convert it
data = {data};
filetype = H5T.copy ('H5T_FORTRAN_S1');
H5T.set_size (filetype,'H5T_VARIABLE');
memtype = H5T.copy ('H5T_C_S1');
H5T.set_size (memtype, 'H5T_VARIABLE');
space = H5S.create ('H5S_SCALAR');
if safe
try
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
catch
H5A.delete(gid, data_name);
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
end
else
attr = H5A.create (gid, data_name, filetype, space, 'H5P_DEFAULT');
end
H5A.write (attr, memtype, data);
elseif iscell(data)
% If it is a cell, save it as 1D dataset
H5T.set_size(datatypeID,'H5T_VARIABLE');
agcv = H5ML.get_constant_value('H5S_UNLIMITED');
dspace = H5S.create_simple(1,numel(data),agcv);
plist = H5P.create('H5P_ATTRIBUTE_CREATE');
if safe
try
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
catch
H5A.delete(gid, data_name);
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
end
else
attr = H5A.create(gid,data_name,datatypeID,dspace,plist);
end
H5A.write(attr,'H5ML_DEFAULT',data);
else
acpl = H5P.create('H5P_ATTRIBUTE_CREATE');
dims = size(data);
if length(dims)>1 && dims(2)~=1
if dims(1) == 1
space_id = H5S.create_simple(dims(1), dims(2), []);
else
space_id = H5S.create_simple(dims(1), dims, []);
end
else
space_id = H5S.create('H5S_SCALAR');
end
if safe
try
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
catch
H5A.delete(gid, data_name);
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
end
else
attr = H5A.create(gid,data_name,datatypeID,space_id,acpl);
end
H5A.write(attr,'H5ML_DEFAULT',data)
end
H5A.close(attr);
end
+370
View File
@@ -0,0 +1,370 @@
%WRITE_DATASET write dataset data_name, containing data to ID gid
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: Data processing was carried out
% using the cSAXS matlab package developed by the CXS group,
% Paul Scherrer Institut, Switzerland.
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided as they are without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function write_dataset(data, gid, data_name, plist, varargin)
import io.HDF.*
extend_data = false;
link = false;
link_type = '';
cellstrdata = false;
write_data = true;
if ~isempty(varargin)
comp = varargin{1};
else
comp = true;
end
if nargin > 5
overwrite = varargin{2};
else
overwrite = true;
end
if nargin > 6
data_attr = varargin{3};
else
data_attr = [];
end
if nargin > 7
extend_dim = varargin{4};
else
extend_dim = 0;
end
if nargin > 8
extendable = varargin{5};
else
extendable = false;
end
if nargin > 9
extend_offset = varargin{6};
else
extend_offset = 0;
end
if nargin > 10
extend_maxdims = varargin{7};
else
extend_maxdims = 0;
end
[datatype, data] = get_datatype(data);
filespaceID = [];
function create_dataspace()
if extendable
unlimited = H5ML.get_constant_value('H5S_UNLIMITED');
dims_max = repmat(unlimited, 1, numel(dims));
else
dims_max = dims;
end
if ~extend_dim
if ~extendable
dataspaceID = H5S.create_simple(length(dims), fliplr(dims), fliplr(dims_max));
else
try
datasetID = H5D.open(gid, data_name);
filespaceID = H5D.get_space(datasetID);
[~, spaceDims] = H5S.get_simple_extent_dims(filespaceID);
% spaceDims = fliplr(spaceDims);
start = ones(1,numel(dims))-1;
count = dims;
stride = ones(1, numel(start));
boundsEnd = start + (count).*stride;
new_dims = fliplr(boundsEnd);
H5S.close(filespaceID);
H5D.set_extent(datasetID,new_dims);
filespaceID = H5D.get_space(datasetID);
H5S.select_hyperslab(filespaceID, 'H5S_SELECT_SET', fliplr(start), fliplr(stride), ...
fliplr(count), ones(1,length(start)));
dataspaceID = H5S.create_simple(numel(count),fliplr(count),[]);
extend_data = true;
catch
dataspaceID = H5S.create_simple(length(dims), fliplr(dims), fliplr(dims_max));
end
end
else
try
datasetID = H5D.open(gid, data_name);
filespaceID = H5D.get_space(datasetID);
[~, spaceDims] = H5S.get_simple_extent_dims(filespaceID);
spaceDims = fliplr(spaceDims);
if extend_offset
start = [ones(1,extend_dim-1) extend_offset+1]-1;
else
start = [ones(1,extend_dim-1) spaceDims(end)+1]-1;
end
if numel(spaceDims) > numel(dims)
count = [dims 1];
else
count = dims;
end
stride = ones(1, numel(start));
boundsEnd = start + (count-1).*stride;
if extend_maxdims
boundsStart = spaceDims;
boundsStart(end) = extend_maxdims;
else
boundsStart = spaceDims;
end
new_dims = fliplr(max(boundsStart,boundsEnd+1));
H5S.close(filespaceID);
H5D.set_extent(datasetID,new_dims);
filespaceID = H5D.get_space(datasetID);
H5S.select_hyperslab(filespaceID, 'H5S_SELECT_SET', fliplr(start), fliplr(stride), ...
fliplr(count), ones(1,length(start)));
dataspaceID = H5S.create_simple(numel(count),fliplr(count),[]);
extend_data = true;
catch
unlimited = H5ML.get_constant_value('H5S_UNLIMITED');
maxdims = [dims(1:extend_dim-1) unlimited];
% maxdims = repmat(-1, 1, extend_dim);
if numel(maxdims) > numel(dims)
dims = [dims 1];
end
dataspaceID = H5S.create_simple(length(dims), [fliplr(dims)], fliplr(maxdims));
end
end
end
if strcmp(datatype, 'complex')
%%% prepare compound dataset for complex input data
dims = size(data);
data_temp = data;
data = [];
data.r = real(data_temp);
data.i = imag(data_temp);
create_dataspace();
% Create the required data types
complexType = H5T.copy(get_datatype(data.r));
sz = H5T.get_size(complexType);
% Create the compound datatype for memory.
datatypeID = H5T.create ('H5T_COMPOUND', 2*sz);
H5T.insert (datatypeID, 'r',0, complexType);
H5T.insert (datatypeID, 'i',sz, complexType);
memtype = datatypeID;
data_attr.MATLAB_class = 'complex';
elseif ischar(data)
% check if char is a link
ch_entrs = strsplit(data, ':');
if length(ch_entrs) >= 2
link = true;
if strcmp(ch_entrs{1}, 'ext')
% prepare external link
link_type = 'ext';
elseif strcmp(ch_entrs{1}, 'int_soft')
% prepare internal soft link
link_type = 'int_soft';
elseif strcmp(ch_entrs{1}, 'int_hard')
% prepare internal hard link
link_type = 'int_hard';
end
else
data = {data};
datatypeID = H5T.copy ('H5T_FORTRAN_S1');
H5T.set_size (datatypeID,'H5T_VARIABLE');
memtype = H5T.copy ('H5T_C_S1');
H5T.set_size (memtype, 'H5T_VARIABLE');
dataspaceID = H5S.create ('H5S_SCALAR');
end
elseif iscell(data) || strcmp(datatype, 'char_array')
if iscellstr(data)
cellstrdata = true;
datatypeID = H5T.copy ('H5T_C_S1');
H5T.set_size (datatypeID, 'H5T_VARIABLE');
dgcv = H5ML.get_constant_value('H5S_UNLIMITED');
dataspaceID = H5S.create_simple(1,numel(data),dgcv);
memtype = datatypeID;
plist_cr = H5P.create('H5P_DATASET_CREATE');
H5P.set_chunk(plist_cr,1);
if strcmp(datatype, 'char_array')
data_attr.MATLAB_class = 'char_array';
end
else
write_data = false;
fn_names = cell(1,length(data));
cell_gid = add_groups(gid, data_name, plist, true);
for ii=1:length(data)
fn_names{ii} = sprintf([data_name '_%d'],ii-1);
write_dataset(data{ii}, cell_gid, fn_names{ii}, plist, comp, overwrite);
end
write_attribute(cell_gid, 'cell', 'MATLAB_class');
end
elseif isstruct(data)
write_data = false;
struct_gid = add_groups(gid, data_name, plist, true);
add_content(data, struct_gid, plist, comp, overwrite);
else
datatypeID = H5T.copy(datatype);
dims = size(data);
if isfield(data_attr, 'save2hdf5DataShape')
dims = data_attr.save2hdf5DataShape;
end
% prepare dataspace
create_dataspace();
memtype = 'H5ML_DEFAULT';
end
%%% create groups and write data
if comp && ~iscell(data) && ~ischar(data) && write_data || extend_dim || extendable
% define compression and chunk size
plist_ch = H5P.create('H5P_DATASET_CREATE');
if length(dims)>=3
chunk_dims = [dims(1) dims(2) ones(1, numel(dims)-2)];
else
chunk_dims = dims;
end
h5_chunk_dims = fliplr(chunk_dims);
H5P.set_chunk(plist_ch,h5_chunk_dims);
H5P.set_shuffle(plist_ch);
if comp
H5P.set_deflate(plist_ch,comp);
end
% Try to create a new dataset. If it exists, try to open it.
try
if ~extend_data
if cellstrdata
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_cr);
else
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_ch);
% create_dataspace();
end
end
catch
if ~overwrite
try
datasetID = H5D.open(gid, data_name);
catch
error('Could not create dataset %s! Try a different name or overwrite the already existing file.', data_name);
end
else
keyboard
error('Dataset %s already exists! Try a different name or overwrite the already existing file.', data_name);
end
end
elseif ~link && write_data
% Same as above but without compression:
% Try to create a new dataset. If it exists, try to open it.
try
if cellstrdata
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist_cr);
else
datasetID = H5D.create(gid,data_name,datatypeID,dataspaceID,plist);
end
catch
if ~overwrite
try
datasetID = H5D.open(gid, data_name);
catch
error('Could not open dataset %s! Try a different name or overwrite the already existing file.', data_name);
end
else
error('Dataset %s already exists! Try a different name or overwrite the already existing file.', data_name);
end
end
end
if write_data
% write data to disk or link data
if ~link && ~extend_data
H5D.write(datasetID,memtype,'H5S_ALL','H5S_ALL',plist ,data);
% append attributes if needed
if ~isempty(data_attr)
fn = fieldnames(data_attr);
for ii=1:length(fn)
write_attribute(datasetID, data_attr.(fn{ii}), fn{ii}, true);
end
end
H5D.close(datasetID);
elseif extend_data
H5D.write(datasetID,memtype,dataspaceID, filespaceID, plist, data)
elseif strcmp(link_type, 'ext')
H5L.create_external(ch_entrs{2},ch_entrs{3},gid,data_name,plist,plist);
elseif strcmp(link_type, 'int_hard')
error('Currently not supported, sorry!')
% H5L.create_hard(ch_entrs{2},'g3',gid1,'g4',plist,plist);
elseif strcmp(link_type, 'int_soft')
H5L.create_soft(ch_entrs{2},gid,data_name,plist,plist);
end
end
end