Skip to content

Extending with Custom Properties (Code Examples)

What if you want to store other datasets in your file, like electron density -- or other attributes, like run number?

You can write and read your own custom, non-pradformat datasets and attributes to/from any pradformat HDF5 file without violating its Format Specs. To do this, utilize the native HDF5 readers/writers for MATLAB and Python.

Below is an example of how you would append a few of your own custom HDF5 datasets and attributes to a Simple Fields file. We will add the datasets "nele" and "nion", and the attribute "run_number", to our HDF5 file.

Extending a pradformat file

% write_extended.m: Example of writing an extended pradformat HDF5 file
%   That is, adding your own non-pradformat datasets and attributes to the
%       pradformat HDF5 file

%% Construct pradformat object
fld = SimpleFields;

%% Create some 3D test matrices
nx = 100;
ny = 150;
nz = 125;
x = linspace(-10.0, 10.0, nx);
y = linspace(-15.0, 15.0, ny);
z = linspace(-12.5, 12.5, nz);
[X,Y,Z] = meshgrid(x,y,z);

%% Set pradformat datasets and attributes
fld.X = X; % required | X values | meters
fld.Y = Y; % required | Y values | meters
fld.Z = Z; % required | Z values | meters
fld.Ex = X.^2 + Y.^2; % required | Electric field, x-component | Volts/meter
fld.Ey = 0.0; % required | Electric field, y-component | Volts/meter
fld.Ez = 5.823 * X.^2 + Z.^2; % required | Electric field, z-component | Volts/meter
fld.Bx = X.^4 + Z.^2; % required | Magnetic field, x-component | Tesla
fld.By = 2.191 + Y + Z.^2; % required | Magnetic field, y-component | Tesla
fld.Bz = 8.123; % required | Magnetic field, z-component | Tesla
fld.rho = X + Y + Z; % optional | Mass density | kg / m**3

% disp(fld.object_type) % already-set | Specification of the HDF5 object type | "fields" (always this value)
% disp(fld.fields_type) % already-set | Specification of the fields sub-type | "simple" (always this value)
% disp(fld.pradformat_version) % already-set | HDF5 pradformat file format version followed | e.g. "0.1.0"

fld.rho_description = "Six-ionized CH plasma and chamber walls";
fld.label = "Fields_10"; % optional | Short, identifying label for this file (with no spaces or crazy characters). This can be stamped onto plots, etc.
fld.description = "Fields test example with lots of X, Y, and Z dependence."; % optional | Longer description of this file. This can be read by people trying to figure out where this file came from.
% disp(fld.file_date); % automatically-set | Date the (future) file will be created, in the format "YYYY-MM-DD" | You don't need to set this, it will be set automatically
% fld.raw_data_filename = "SimulationMain/DISC_OMEGA/chk0013"; % optional | Filename of the raw data file (e.g. simulation output) from which this derivative file was created, if applicable.

%% Create some custom, non-pradformat datasets and attributes
nele = X.^3; % electron density
nion = Y + Z.^2; % ion density
run_number = 5; % simulation run number for this dataset

%% Save pradformat object to HDF5 file
[status, msg, msgID] = mkdir('outs');
h5filename = fullfile('outs', 'myextendedfields.h5');
prad_save(fld, h5filename);

%% Append your custom, non-pradformat datasets and attributes to the HDF5 file
% Append (and compress) dataset 'nele'
h5create(h5filename, '/nele', size(nele),...
    'DataType', class(nele), ...
    'ChunkSize', autochunksize(nele), 'Deflate', 4);
h5write(h5filename, '/nele', nele);

% Append (and compress) dataset 'nion'
h5create(h5filename, '/nion', size(nion),...
    'DataType', class(nion), ...
    'ChunkSize', autochunksize(nion), 'Deflate', 4);
h5write(h5filename, '/nion', nion);

% Append custom attribute 'run_number'
h5writeatt(h5filename, '/', 'run_number', run_number)
# write_extended.py: Example of writing an extended pradformat HDF5 file
#   That is, adding your own non-pradformat datasets and attributes to the
#       pradformat HDF5 file

import os
import h5py
import numpy as np
import pradformat as prf

## Construct pradformat object
fld = prf.SimpleFields()

## Create some 3D test matrices
nx = 100
ny = 150
nz = 125
x = np.linspace(-10.0, 10.0, nx)
y = np.linspace(-15.0, 15.0, ny)
z = np.linspace(-12.5, 12.5, nz)
[X,Y,Z] = np.meshgrid(x,y,z)

## Set pradformat datasets and attributes
fld.X = X # required | X values | meters
fld.Y = Y # required | Y values | meters
fld.Z = Z # required | Z values | meters
fld.Ex = X**2 + Y**2 # required | Electric field, x-component | Volts/meter
fld.Ey = 0.0 # required | Electric field, y-component | Volts/meter
fld.Ez = 5.823 * X**2 + Z**2 # required | Electric field, z-component | Volts/meter
fld.Bx = X**4 + Z**2 # required | Magnetic field, x-component | Tesla
fld.By = 2.191 + Y + Z**2 # required | Magnetic field, y-component | Tesla
fld.Bz = 8.123 # required | Magnetic field, z-component | Tesla
fld.rho = X + Y + Z # optional | Mass density | kg / m**3

# print(fld.object_type) # already-set | Specification of the HDF5 object type | "fields" (always this value)
# print(fld.fields_type) # already-set | Specification of the fields sub-type | "simple" (always this value)
# print(fld.pradformat_version) # already-set | HDF5 pradformat file format version followed | e.g. "0.1.0"

fld.rho_description = "Six-ionized CH plasma and chamber walls"
fld.label = "Fields_10" # optional | Short, identifying label for this file (with no spaces or crazy characters). This can be stamped onto plots, etc.
fld.description = "Fields test example with lots of X, Y, and Z dependence." # optional | Longer description of this file. This can be read by people trying to figure out where this file came from.
# print(fld.file_date) # automatically-set | Date the (future) file will be created, in the format "YYYY-MM-DD" | You don't need to set this, it will be set automatically
# fld.raw_data_filename = "SimulationMain/DISC_OMEGA/chk0013" # optional | Filename of the raw data file (e.g. simulation output) from which this derivative file was created, if applicable.

## Create some custom, non-pradformat datasets and attributes
nele = X**3 # electron density
nion = Y + Z**2 # ion density
run_number = 5 # simulation run number for this dataset

## Save pradformat object to HDF5 file
if not os.path.isdir("outs"):
    os.mkdir("outs")
h5filename = os.path.join('outs', 'myextendedfields.h5')
fld.save(h5filename)

## Append your custom, non-pradformat datasets and attributes to the HDF5 file
with h5py.File(h5filename, 'a') as f:
    f.create_dataset('nele', data=nele, compression="gzip", compression_opts=4)
    f.create_dataset('nion', data=nion, compression="gzip", compression_opts=4)
    f.attrs['run_number'] = run_number

Reading your extended pradformat file

% read_extended.m: Example of reading in an extended pradformat HDF5 file
%   That is, reading in your own non-pradformat datasets and attributes
%       that you added to a pradformat HDF5 file

%% Load pradformat object as usual (only reads in the pradformat HDF5 items)
h5filename = fullfile('outs', 'myextendedfields.h5');
fld = prad_load(h5filename);

%% Load in any custom datasets and attributes you added to the HDF5 file
nele = h5read(h5filename, '/nele');
nion = h5read(h5filename, '/nion');
run_number = h5readatt(h5filename, '/', 'run_number');

%% Utilize datasets and attributes in your own scripts
assert(isa(fld, 'SimpleFields'));

disp(fld.pradformat_version)
disp(mean(fld.Ex(:)))
disp(mean(nele(:)))
disp(mean(nion(:)))
disp(run_number)
# read_extended.py: Example of reading in an extended pradformat HDF5 file
#   That is, reading in your own non-pradformat datasets and attributes
#       that you added to a pradformat HDF5 file

import os
import h5py
import numpy as np
import pradformat as prf

## Load pradformat object as usual (only reads in the pradformat HDF5 items)
h5filename = os.path.join('outs', 'myextendedfields.h5')
fld = prf.prad_load(h5filename)

## Load in any custom datasets and attributes you added to the HDF5 file
with h5py.File(h5filename, "r") as f:
    nele = f['nele'][()]
    nion = f['nion'][()]
    run_number = f.attrs['run_number']

## Utilize datasets and attributes in your own scripts
assert isinstance(fld, prf.SimpleFields)

print(fld.pradformat_version)
print(np.mean(fld.Ex))
print(np.mean(nele))
print(np.mean(nion))
print(run_number)