Skip to content

Commit 80fbfe3

Browse files
committed
initial commit
1 parent 6fcec9f commit 80fbfe3

18 files changed

+680
-0
lines changed

.github/CODE_OF_CONDUCT.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, sex characteristics, gender identity and expression,
9+
level of experience, education, socio-economic status, nationality, personal
10+
appearance, race, religion, or sexual identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at info@scivision.dev. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72+
73+
[homepage]: https://www.contributor-covenant.org
74+
75+
For answers to common questions about this code of conduct, see
76+
https://www.contributor-covenant.org/faq

.github/FUNDING.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# These are supported funding model platforms
2+
3+
github: [scivision]
4+
ko_fi: scivision

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
paths:
6+
- "**.m"
7+
- ".github/workflows/ci.yml"
8+
9+
jobs:
10+
11+
linux:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v2
15+
16+
- run: |
17+
sudo apt -yq update
18+
sudo apt install -yq --no-install-recommends octave octave-netcdf
19+
20+
- run: octave-cli --eval test_netcdf

Readme.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Matlab HDF5 and NetCDF4 high-level functions
2+
3+
![ci](https://github.com/scivision/matlab-hdf5/workflows/ci/badge.svg)
4+
5+
These functions are sorely needed in Matlab itself.
6+
The NetCDF4 functions also work with GNU Octave when octave-netcdf is installed.
7+
8+
## hdf5
9+
10+
* Check that a dataset exists in file:
11+
12+
```matlab
13+
h5exists(filename, dataset_name)
14+
```
15+
16+
* Save a varable to a dataset. If dataset exists, the existing dataset shape must match the variable.
17+
18+
```matlab
19+
h5save(filename, dataset_name, dataset)
20+
```
21+
22+
* Get the dataset size (shape)
23+
24+
```matlab
25+
h5size(filename, dataset_name)
26+
```
27+
28+
* Get the names of all datasets in a file
29+
30+
```matlab
31+
h5variables(filename)
32+
```
33+
34+
### netcdf
35+
36+
* Check that a variable exists in file:
37+
38+
```matlab
39+
ncexists(filename, variable_name)
40+
```
41+
42+
* Save a varable to a dataset. If dataset exists, the existing dataset shape must match the variable.
43+
44+
```matlab
45+
ncsave(filename, variable_name, variable)
46+
```
47+
48+
* Get the dataset size (shape)
49+
50+
```matlab
51+
ncsize(filename, variable_name)
52+
```
53+
54+
* Get the names of all datasets in a file
55+
56+
```matlab
57+
ncvariables(filename)
58+
```

coerce_ds.m

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
function A = coerce_ds(A, dtype)
2+
% used by h5save and ncsave
3+
narginchk(2,2)
4+
validateattributes(A, {'numeric'}, {'nonempty'},1)
5+
validateattributes(dtype, {'char'}, {'vector'},2)
6+
7+
switch dtype
8+
case {'float64', 'double'}
9+
if ~isa(A, 'double')
10+
A = double(A);
11+
end
12+
case {'float32', 'single'}
13+
if ~isa(A, 'single')
14+
A = single(A);
15+
end
16+
case {'int32'}
17+
if ~isa(A, 'int32')
18+
A = int32(A);
19+
end
20+
case {'int64'}
21+
if ~isa(A, 'int64')
22+
A = int64(A);
23+
end
24+
case {'char', 'string'}
25+
if ~isstring(A)
26+
A = string(A);
27+
end
28+
otherwise, error('create_ds:type_error', 'unknown data type %s', dtype)
29+
end
30+
31+
end % function

expanduser.m

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
%!assert(ischar(expanduser('~')))
2+
function expanded = expanduser(p)
3+
% expanded = expanduser(path)
4+
%
5+
% expands tilde ~ into user home directory for Matlab and GNU Octave.
6+
%
7+
% Useful for Matlab functions like h5read() and some Computer Vision toolbox functions
8+
% that can't handle ~ and Matlab does not consider it a bug per conversations with
9+
% Mathworks staff
10+
%
11+
% Benchmark: on laptop and Matlab R2020a
12+
%
13+
% about 200 microseconds
14+
% f = @() expanduser('~/foo');
15+
% timeit(f)
16+
%
17+
% about 2 microseconds:
18+
% f = @() expanduser('foo');
19+
% timeit(f)
20+
%
21+
% See also absolute_path
22+
23+
narginchk(1,1)
24+
25+
if isempty(p)
26+
expanded = '';
27+
return
28+
end
29+
30+
validateattributes(p, {'char'}, {'vector'})
31+
%% GNU Octave
32+
if isoctave
33+
expanded = tilde_expand(p);
34+
return
35+
end
36+
37+
%% Matlab
38+
expanded = p;
39+
40+
if strcmp(expanded(1), '~')
41+
42+
home = [];
43+
if isunix
44+
home = getenv('HOME');
45+
elseif ispc
46+
home = getenv('USERPROFILE');
47+
end
48+
49+
if isempty(home)
50+
% this is 100x slower than getenv() on Matlab R2020a
51+
home = char(java.lang.System.getProperty("user.home"));
52+
end
53+
54+
expanded = fullfile(home, expanded(2:end));
55+
end
56+
57+
end %function

h5exists.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
function exists = h5exists(filename, varname)
2+
% check if variable exists in HDF5 file
3+
%
4+
% filename: HDF5 filename
5+
% varname: name of variable inside HDF5 file
6+
%
7+
% exists: boolean
8+
9+
narginchk(2,2)
10+
validateattributes(varname, {'char'}, {'vector'}, 2)
11+
12+
filename = expanduser(filename);
13+
14+
vars = {};
15+
if is_file(filename)
16+
vars = h5variables(filename);
17+
end
18+
19+
exists = any(strcmp(vars, varname(2:end)));
20+
21+
end % function

h5save.m

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
function h5save(filename, varname, A, sizeA, dtype)
2+
3+
narginchk(3, 5)
4+
5+
if nargin < 4 || isempty(sizeA)
6+
if isvector(A)
7+
sizeA = length(A);
8+
else
9+
sizeA = size(A);
10+
end
11+
end
12+
13+
if nargin >= 5 && ~isempty(dtype)
14+
A = coerce_ds(A, dtype);
15+
end
16+
if ischar(A)
17+
A = string(A);
18+
sizeA = size(A);
19+
end
20+
21+
22+
23+
if h5exists(filename, varname)
24+
exist_file(filename, varname, A, sizeA)
25+
else
26+
new_file(filename, varname, A, sizeA)
27+
end % if
28+
29+
end % function
30+
31+
32+
function exist_file(filename, varname, A, sizeA)
33+
34+
diskshape = h5size(filename, varname);
35+
if length(diskshape) >= 2
36+
% start is always a row vector, regardless of shape of array
37+
start = ones(1,ndims(A));
38+
elseif ~isempty(diskshape)
39+
start = 1;
40+
end
41+
42+
if isscalar(A)
43+
h5write(filename, varname, A)
44+
elseif all(diskshape == sizeA)
45+
h5write(filename, varname, A, start, sizeA)
46+
elseif all(diskshape == fliplr(sizeA))
47+
h5write(filename, varname, A.', start, fliplr(sizeA))
48+
else
49+
error('h5save:value_error', ['shape of ',varname,': ', int2str(sizeA), ' does not match existing HDF5 shape ', int2str(diskshape)])
50+
end
51+
52+
end % function
53+
54+
55+
function new_file(filename, varname, A, sizeA)
56+
57+
if ~ismatrix(A)
58+
% enable Gzip compression--remember Matlab's dim order is flipped from
59+
% C / Python
60+
switch length(sizeA)
61+
case 4, chunksize = [sizeA(1), sizeA(2), 1, sizeA(4)];
62+
case 3, chunksize = [sizeA(1), sizeA(2), 1];
63+
otherwise, error('h5save:fixme', '%s is bigger than 4 dims', varname)
64+
end
65+
h5create(filename, varname, sizeA, 'DataType', class(A), ...
66+
'Deflate', 1, 'Fletcher32', true, 'Shuffle', true, 'ChunkSize', chunksize)
67+
else
68+
h5create(filename, varname, sizeA, 'DataType', class(A))
69+
end % if
70+
71+
h5write(filename, varname, A)
72+
73+
end % function
74+
75+
76+
77+
% Copyright 2020 Michael Hirsch, Ph.D.
78+
79+
% Licensed under the Apache License, Version 2.0 (the "License");
80+
% you may not use this file except in compliance with the License.
81+
% You may obtain a copy of the License at
82+
83+
% http://www.apache.org/licenses/LICENSE-2.0
84+
85+
% Unless required by applicable law or agreed to in writing, software
86+
% distributed under the License is distributed on an "AS IS" BASIS,
87+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
88+
% See the License for the specific language governing permissions and
89+
% limitations under the License.

h5size.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function fsize = h5size(filename, variable)
2+
% get size (shape) of an HDF5 dataset
3+
%
4+
% filename: HDF5 filename
5+
% variable: name of variable inside HDF5 file
6+
%
7+
% fsize: vector of variable size per dimension
8+
9+
narginchk(2,2)
10+
validateattributes(variable, {'char'}, {'vector'}, 2)
11+
12+
finf = h5info(expanduser(filename), variable);
13+
fsize = finf.Dataspace.Size;
14+
15+
end % function

h5variables.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function [names, groups] = h5variables(filename)
2+
% get dataset names and groups in an HDF5 file
3+
narginchk(1,1)
4+
5+
% use temporary variable to be R2017b OK
6+
finf = h5info(filename);
7+
ds = finf.Datasets;
8+
9+
names = {ds(:).Name};
10+
11+
if nargout > 1
12+
groups = {finf.Groups};
13+
end
14+
15+
end % function

0 commit comments

Comments
 (0)