##// END OF EJS Templates
Add fill gaps to plots and rm tmp summary files in upload
Add fill gaps to plots and rm tmp summary files in upload

File last commit:

r0:b84e1135c2c4
r15:83785b54e857
Show More
MadrigalHdf5File.m
391 lines | 17.2 KiB | text/octave | ObjectiveCLexer
classdef MadrigalHdf5File
% class MadrigalHdf5File allows the creation of Madrigal Hdf5 files via
% Matlab. The general idea of this class is to simply write out all
% data for the file in a Matlab struct array. Then the python script
% createMadrigalHdf5FromMatlab.py is called from this scriptto create all
% metadata and alternate array layouts. This keeps the amount of Matlab
% code here at a minimum. If the output file extension is *.mat, then
% only the *.mat is created, and the user must call createMadrigalHdf5FromMatlab.py
% at a later time themselves. See file testMadrigalHdf5File.m for example
% usage.
%
% $Id: MadrigalHdf5File.m 6538 2018-07-05 19:26:34Z brideout $
properties
filename
extension % either .hdf5, .h5. .hdf, or .mat
oneDParms
independent2DParms
twoDParms
arraySplittingParms
allParms % a combination of oneDParms, independent2DParms, and twoDParms
recordCount % number of records in file so far
lastRecord % index of last records added. Starts with 0. -1 if no records
data % structure array with fields = stdParms + oneDParms + independent2DParms + twoDParms
principleInvestigator % the following are strings that used fill up catalog record
expPurpose % default for all is empty string
expMode
cycleTime
correlativeExp
sciRemarks
instRemarks
kindatDesc % the following are strings that used fill up header record
analyst % default for all is empty string
comments
history
skipArray % bool that determines whether to skip array layout.
end
properties (Constant)
stdParms = cellstr(char('recno', 'kinst', 'kindat', 'ut1_unix', 'ut2_unix'));
end
methods
function madFile = MadrigalHdf5File(filename, oneDParms, ...
independent2DParms, twoDParms, arraySplittingParms, ...
skipArray)
% Object constructor for MadrigalHdf5File
% Inputs:
% filename - the filename to write to. Must end *.hdf5, .h5,
% .hdf, or .mat. If .mat, writes a Matlab file that must
% later be converted to Madrigal using createMadrigalHdf5FromMatlab.py
% oneDParms - a cell array of strings representing 1D parms. May be
% empty. Example:
% cellstr(char('azm', 'elm', 'sn', 'beamid'))
% independent2DParms - a cell array of strings representing independent
% 2D parms. May be empty (ie, {}). Examples:
% cellstr(char('range'))
% cellstr(char('gdlat', 'glon'))
% cellstr(char())
% twoDParms - a cell array of strings representing dependent
% 2D parms. May be empty (ie, {}). Examples:
% cellstr(char('ti', 'dti', 'ne', 'dne'))
% cellstr(char())
% arraySplittingParms - a cell array of strings representing
% parameters whose values are used to split arrays. May
% be empty, in which case set to {}. Example:
% cellstr(char('beamid'))
% skipArray - optional argument. If set to true, no array
% layout created. If false or not passed in, array layout
% created if any 2D variables.
madFile.filename = filename;
% verify a valid file extension
[pathstr,name,ext] = fileparts(filename);
if (~(strcmp(ext, '.hdf5') | ...
strcmp(ext, '.h5') | ...
strcmp(ext, '.hdf') | ...
strcmp(ext, '.mat')))
ME = MException('MadrigalHdf5File:invalidExtenstion', ...
'Illegal extension %s found', ext);
throw(ME)
end
madFile.extension = ext;
madFile.oneDParms = cellstr(oneDParms);
% change all parameters with + to be __plus__
madFile.oneDParms = strrep(madFile.oneDParms, '+', '__plus__');
madFile.independent2DParms = cellstr(independent2DParms);
% change all parameters with + to be __plus__
madFile.independent2DParms = strrep(madFile.independent2DParms, '+', '__plus__');
madFile.twoDParms = cellstr(twoDParms);
% change all parameters with + to be __plus__
madFile.twoDParms = strrep(madFile.twoDParms, '+', '__plus__');
madFile.arraySplittingParms = cellstr(arraySplittingParms);
% change all parameters with + to be __plus__
madFile.arraySplittingParms = strrep(madFile.arraySplittingParms, '+', '__plus__');
madFile.recordCount = 0; % no records added yet
madFile.lastRecord = -1; % index of last record added.
madFile.data = struct([]);
madFile.allParms = cellstr(char(char(madFile.stdParms), ...
char(madFile.oneDParms), char(madFile.independent2DParms), ...
char(madFile.twoDParms)));
% verify no overlapping
if (length(madFile.allParms) ~= length(unique(madFile.allParms)))
ME = MException('MadrigalHdf5File:invalidParameters', ...
'Illegal duplicate parameters found in inputs');
throw(ME)
end
% set all catalog and header strings to default empty strings
madFile.principleInvestigator = '';
madFile.expPurpose = '';
madFile.expMode = '';
madFile.cycleTime = '';
madFile.correlativeExp = '';
madFile.sciRemarks = '';
madFile.instRemarks = '';
madFile.kindatDesc = '';
madFile.analyst = '';
madFile.comments = '';
madFile.history = '';
if (nargin > 5)
madFile.skipArray = skipArray;
else
madFile.skipArray = false;
end
end % end MadrigalHdf5File constructor
function madFile = appendRecord(madFile, ut1_unix, ut2_unix, kindat, ...
kinst, numRows)
% appendRecord adds a new record to MadrigalHdf5File. It
% returns the record number of the present row (first will be
% 0)
% Inputs:
% madFile - the created MadrigalHdf5File object
% ut1_unix, ut2_unix - unix start and end time of record in
% float seconds since 1970-01-01
% kindat - integer kind of data code. See metadata.
% kinst - integer instrument code. See metadata.
% numRows - number of rows of 2D data. If all 1D data, set
% to 1
% Returns:
% the record number of the present row (first will be 0)
% Affects:
% Updates madFile.recordCount, appends to madFile.data the
% number of rows numRows with all data except stdParms set
% to NaN. Use set1D and set2D to populate that record using
% recNum as index.
if (ut1_unix > ut2_unix)
ME = MException('MadrigalHdf5File:invalidTimes', ...
'ut1_unix > ut2_unix - illegal');
throw(ME)
end
thisArr = NaN(numRows, length(madFile.allParms));
thisTable = array2table(thisArr, 'VariableNames',madFile.allParms);
% set all stdParms
tmp_arr = ones(numRows,1);
tmp_arr = ut1_unix;
thisTable(:,'ut1_unix') = num2cell(tmp_arr);
tmp_arr = ut2_unix;
thisTable(:,'ut2_unix') = num2cell(tmp_arr);
tmp_arr = kindat;
thisTable(:,'kindat') = num2cell(tmp_arr);
tmp_arr = kinst;
thisTable(:,'kinst') = num2cell(tmp_arr);
tmp_arr = madFile.recordCount;
thisTable(:,'recno') = num2cell(tmp_arr);
d = size(madFile.data);
if (d(1) == 0)
madFile.data = thisTable;
else
madFile.data = [madFile.data; thisTable];
end
madFile.recordCount = 1 + madFile.recordCount;
madFile.lastRecord = 1 + madFile.lastRecord;
end % end appendRecord
function lastRecord = get.lastRecord(madFile)
lastRecord = madFile.lastRecord;
end % lastRecord get function
function data = get.data(madFile)
data = madFile.data;
end % lastRecord get function
function madFile = set1DParm(madFile, parm, value, lastRec)
% set1DParm sets the values of 1D parm parm to value value for
% record with lastRecord value lastRec
% change all parameters with + to be __plus__
parm = strrep(parm, '+', '__plus__');
if (~ismember(parm, madFile.oneDParms))
ME = MException('MadrigalHdf5File:invalidparm', ...
'parm %s not in oneDParms', parm );
throw(ME)
end
rows = madFile.data.recno == lastRec;
tmpArr = ones(length(find(rows)),1);
tmpArr = value;
madFile.data(rows,parm) = num2cell(tmpArr);
end % end set1DParm
function madFile = set2DParm(madFile, parm, values, lastRec)
% set2DParm sets the values of 2D parm parm to value values for
% record with lastRecord value lastRec
% change all parameters with + to be __plus__
parm = strrep(parm, '+', '__plus__');
if (~ismember(parm, madFile.twoDParms) & ...
~ismember(parm, madFile.independent2DParms))
ME = MException('MadrigalHdf5File:invalidparm', ...
'parm %s not in twoDParms or independent2DParms', parm );
throw(ME)
end
rows = madFile.data.recno == lastRec;
newValues = reshape(values, [length(values) ,1]);
madFile.data(rows,parm) = num2cell(newValues);
end % end set2DParm
function madFile = setCatalog(madFile, principleInvestigator, expPurpose, expMode, ...
cycleTime, correlativeExp, sciRemarks, instRemarks)
% setCatalog allows setting extra information in the catalog
% record. This method is optional. Even if this method is not
% called, the catalog record will contain a description of the
% instrument (kinst code and name) and kind of data brief
% description, along with a list of description of the
% parameters in the file, and the first and last times of the
% measurements.
%
% Inputs:
%
% principleInvestigator - Names of responsible Principal Investigator(s) or
% others knowledgeable about the experiment.
% expPurpose - Brief description of the experiment purpose
% expMode - Further elaboration of meaning of MODEXP; e.g. antenna patterns
% and pulse sequences.
% cycleTime - Minutes for one full measurement cycle - must
% be numeric
% correlativeExp - Correlative experiments (experiments with related data)
% sciRemarks - scientific remarks
% instRemarks - instrument remarks
%
if nargin > 1
madFile.principleInvestigator = principleInvestigator;
end
if nargin > 2
madFile.expPurpose = expPurpose;
end
if nargin > 3
madFile.expMode = expMode;
end
if nargin > 4
if ~isnumeric(cycleTime)
ME = MException('MadrigalHdf5File:invalidArgument', ...
'cycleTime not numeric');
throw(ME)
end
madFile.cycleTime = cycleTime;
end
if nargin > 5
madFile.correlativeExp = correlativeExp;
end
if nargin > 6
madFile.sciRemarks = sciRemarks;
end
if nargin > 7
madFile.instRemarks = instRemarks;
end
end % end setCatalog
function madFile = setHeader(madFile, kindatDesc, analyst, comments, history)
% setHeader allows setting extra information in the header
% record. This method is optional.
%
% Inputs:
%
% kindatDesc - description of how this data was analyzed (the kind of data)
% analyst - name of person who analyzed this data
% comments - additional comments about data (describe any instrument-specific parameters)
% history - a description of the history of the processing of this file
%
if nargin > 1
madFile.kindatDesc = kindatDesc;
end
if nargin > 2
madFile.analyst = analyst;
end
if nargin > 3
madFile.comments = comments;
end
if nargin > 4
madFile.history = history;
end
end % end setHeader
function write(madFile)
% write writes out the complete Hdf5 file to madFile.filename,
% or if the extension is *.mat, only writes out Matlab file
% without conversion to Hdf5 (which user must do later with
% createMadrigalHdf5FromMatlab.py
filename = madFile.filename;
oneDParms = madFile.oneDParms;
independent2DParms = madFile.independent2DParms;
twoDParms = madFile.twoDParms;
arraySplittingParms = madFile.arraySplittingParms;
data = table2array(madFile.data);
principleInvestigator = madFile.principleInvestigator;
expPurpose = madFile.expPurpose;
expMode = madFile.expMode;
cycleTime = madFile.cycleTime;
correlativeExp = madFile.correlativeExp;
sciRemarks = madFile.sciRemarks;
instRemarks = madFile.instRemarks;
kindatDesc = madFile.kindatDesc;
analyst = madFile.analyst;
comments = madFile.comments;
history = madFile.history;
skipArray = madFile.skipArray;
if ~strcmp(madFile.extension, '.mat')
outputMatlabFile = strcat(madFile.filename, '.mat');
save(outputMatlabFile, 'filename', 'oneDParms', ...
'independent2DParms', 'twoDParms', 'arraySplittingParms', ...
'data', 'principleInvestigator', 'expPurpose', 'expMode', ...
'cycleTime', 'correlativeExp', 'sciRemarks', 'instRemarks', ...
'madFile', 'kindatDesc', 'analyst', 'comments', 'history', ...
'skipArray');
else
outputMatlabFile = madFile.filename;
save(madFile.filename, 'filename', 'oneDParms', ...
'independent2DParms', 'twoDParms', 'arraySplittingParms', ...
'data', 'principleInvestigator', 'expPurpose', 'expMode', ...
'cycleTime', 'correlativeExp', 'sciRemarks', 'instRemarks', ...
'madFile', 'kindatDesc', 'analyst', 'comments', 'history', ...
'skipArray');
return % because not converting to Hdf5 yet
end
% create python command to create Hdf5 file from *.mat file if
% creating a Madrigal Hdf5 file
madroot = getenv('MADROOT');
if length(madroot) == 0
ME = MException('MadrigalHdf5File:missingEnvVariable', ...
'MADROOT env variable not set - required');
throw(ME)
end
execScript = fullfile(madroot, 'bin', 'createMadrigalHdf5FromMatlab.py');
cmd = sprintf('%s %s', execScript, outputMatlabFile);
disp(cmd);
[status,cmdout] = system(cmd);
disp(cmdout);
end
end % end methods
end % classdef
function convertToMadrigal(matFile, madrigalFile)
% convertToMadrigal converts a matlab mat file to Madrigal Hdf5 file
% Inputs:
% matFile - existing Matlab .mat file created earlier
% madrigalFile - madrigal file to create. Must end *.hdf5, .h5,
% .hdf, or .mat.
%
% create python command to create Hdf5 file from *.mat file
madroot = getenv('MADROOT');
if length(madroot) == 0
ME = MException('MadrigalHdf5File:missingEnvVariable', ...
'MADROOT env variable not set - required');
throw(ME)
end
execScript = fullfile(madroot, 'bin', 'createMadrigalHdf5FromMatlab.py');
cmd = sprintf('%s %s', execScript, matFile);
disp(cmd);
[status,cmdout] = system(cmd);
disp(cmdout);
end % end convertToMadrigal