827 lines
31 KiB
Matlab
827 lines
31 KiB
Matlab
classdef ucf < handle
|
|
% Low-level utilities for UCF files.
|
|
properties (Access = public)
|
|
File % file name
|
|
Type % file type
|
|
Class % file class
|
|
Endian % endianess
|
|
CodeVersion % version of the simulation code
|
|
UCFVersion % version of the data format ("unified container format")
|
|
NumDataset % maximum number of datasets in this file (over all time steps)
|
|
NumTimestep % number of time steps in this file
|
|
FileSize % file size
|
|
CreationTime % time of creation
|
|
IOMode % file opened in read-only or read-write mode?
|
|
IORank % rank of processor + col,row,pln
|
|
Verbosity % verbose output?
|
|
Debug % debug information?
|
|
end
|
|
properties (Access = private)
|
|
% File info
|
|
fileID
|
|
fileBeg
|
|
fileEnd
|
|
typeID
|
|
ioflag
|
|
tarflag
|
|
creationTimeUnix
|
|
versionMajor
|
|
versionMinor
|
|
versionPatch
|
|
versionFile
|
|
% Step pointers and info
|
|
posStep
|
|
numSetPerStep
|
|
timeStep
|
|
% Write-mode
|
|
isFileHeaderWritten
|
|
isStepHeaderWritten
|
|
% Current step information (should be resetable by resetCurrentStep())
|
|
currentStep
|
|
currentStepPosHeader
|
|
currentStepPosData
|
|
currentStepSize
|
|
currentStepTime
|
|
currentStepNumSet
|
|
% Current set information (should be resetable by resetCurrentSet())
|
|
currentSet
|
|
currentSetPosHeader
|
|
currentSetPosData
|
|
currentSetSize
|
|
currentSetDatatype
|
|
currentSetDatatypeNumeric
|
|
currentSetSizeof
|
|
currentSetNumParams
|
|
currentSetParams
|
|
currentSetNumElements
|
|
% Constants
|
|
magicFile = int64(81985529216486895);
|
|
magicStep = int64(11944304052957);
|
|
magicSet = int64(240217520921210);
|
|
nHeaderFile = 8;
|
|
nHeaderStep = 4;
|
|
nHeaderSet = 4;
|
|
nByteHeaderFile = 8;
|
|
nByteHeaderStep = 8;
|
|
nByteHeaderSet = 8;
|
|
nSetParamsField = 10;
|
|
nSetParamsParticle = 16;
|
|
factorMajor = 1000000000;
|
|
factorMinor = 1000000;
|
|
factorPatch = 1000;
|
|
factorTypeIDClass = 1000;
|
|
factorTypeIDKind = 10;
|
|
typeIDmatlabField = 1999;
|
|
typeIDmatlabParticle = 2999;
|
|
scanBuffSize = 4096;
|
|
end
|
|
%% ------------------------------------------------------------------------%%
|
|
%% CONSTRUCORS/DESTRUCTORS %%
|
|
%% ------------------------------------------------------------------------%%
|
|
methods(Access=public)
|
|
function obj = ucf(varargin)
|
|
% obj = ucf(varargin)
|
|
% Default contructor
|
|
% Input
|
|
% ? verbosity verbose output? (default: false)
|
|
% ? debug debug output? (default: false)
|
|
par = inputParser;
|
|
addParamValue(par,'verbosity',0,@isnumeric);
|
|
addParamValue(par,'debug',0,@isnumeric);
|
|
parse(par,varargin{:});
|
|
obj.resetPublicProperties();
|
|
obj.resetPrivateProperties();
|
|
obj.resetCurrentStep();
|
|
obj.resetCurrentSet();
|
|
obj.fileID = -1;
|
|
obj.tarflag = false;
|
|
obj.setVerbosity(par.Results.verbosity);
|
|
obj.setDebug(par.Results.debug);
|
|
end
|
|
function delete(obj)
|
|
% obj.delete()
|
|
% Default destructor
|
|
obj.close();
|
|
end
|
|
end
|
|
%% ------------------------------------------------------------------------%%
|
|
%% INITIALIZATION METHODS %%
|
|
%% ------------------------------------------------------------------------%%
|
|
methods(Access=public)
|
|
function open(obj,file)
|
|
% obj.open(file)
|
|
% Opens a file in read-only mode
|
|
obj.File = file; % add filename as object property
|
|
obj.IOMode = 'read'; % abstract IO mode
|
|
obj.ioflag = 'r'; % internal IO mode
|
|
obj.tarflag = false; % data is within a tar file?
|
|
% Try to open the file
|
|
obj.fileID = fopen(obj.File,obj.ioflag);
|
|
if obj.fileID<0
|
|
error('Unable to open file: %s',obj.File);
|
|
end
|
|
obj.fileBeg = ftell(obj.fileID);
|
|
fseek(obj.fileID,0,'eof');
|
|
obj.fileEnd = ftell(obj.fileID);
|
|
fseek(obj.fileID,0,'bof');
|
|
obj.FileSize = obj.fileEnd-obj.fileBeg;
|
|
% Read the file header
|
|
obj.readHeaderFile()
|
|
% Scan through file to get the basic structure (steps/sets)
|
|
obj.timeStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.posStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.numSetPerStep = zeros(1,obj.scanBuffSize,'double');
|
|
istep = 0;
|
|
while ftell(obj.fileID)<obj.FileSize
|
|
obj.readHeaderStep();
|
|
istep = istep+1;
|
|
obj.timeStep(istep) = obj.currentStepTime;
|
|
obj.posStep(istep) = ftell(obj.fileID);
|
|
obj.numSetPerStep(istep) = obj.currentStepNumSet;
|
|
if obj.currentStepSize==-1
|
|
break;
|
|
else
|
|
fseek(obj.fileID,obj.currentStepSize,'cof');
|
|
end
|
|
end
|
|
nstep = istep;
|
|
% Truncate buffered arrays
|
|
if nstep>obj.scanBuffSize
|
|
warning('Buffer overflow detected: increase scanBuffSize.');
|
|
end
|
|
obj.timeStep = obj.timeStep(1:nstep);
|
|
obj.posStep = obj.posStep(1:nstep);
|
|
obj.numSetPerStep = obj.numSetPerStep(1:nstep);
|
|
% Set some internal variables
|
|
obj.NumDataset = max(obj.numSetPerStep);
|
|
obj.NumTimestep = nstep;
|
|
obj.isFileHeaderWritten = true;
|
|
obj.isStepHeaderWritten = true;
|
|
end
|
|
function edit(obj,file)
|
|
% obj.edit(file)
|
|
% Opens a file in read-write mode
|
|
obj.File = file; % add filename as object property
|
|
obj.IOMode = 'edit'; % abstract IO mode
|
|
obj.ioflag = 'r+'; % internal IO mode
|
|
obj.tarflag = false; % data is within a tar file?
|
|
% Try to open the file
|
|
obj.fileID = fopen(obj.File,obj.ioflag);
|
|
if obj.fileID<0
|
|
error('Unable to open file: %s',obj.File);
|
|
end
|
|
obj.fileBeg = ftell(obj.fileID);
|
|
fseek(obj.fileID,0,'eof');
|
|
obj.fileEnd = ftell(obj.fileID);
|
|
fseek(obj.fileID,0,'bof');
|
|
obj.FileSize = obj.fileEnd-obj.fileBeg;
|
|
% Read the file header
|
|
obj.readHeaderFile()
|
|
% Scan through file to get the basic structure (steps/sets)
|
|
obj.timeStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.posStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.numSetPerStep = zeros(1,obj.scanBuffSize,'double');
|
|
istep = 0;
|
|
while ftell(obj.fileID)<obj.FileSize
|
|
obj.readHeaderStep();
|
|
istep = istep+1;
|
|
obj.timeStep(istep) = obj.currentStepTime;
|
|
obj.posStep(istep) = ftell(obj.fileID);
|
|
obj.numSetPerStep(istep) = obj.currentStepNumSet;
|
|
if obj.currentStepSize==-1
|
|
break;
|
|
else
|
|
fseek(obj.fileID,obj.currentStepSize,'cof');
|
|
end
|
|
end
|
|
nstep = istep;
|
|
% Truncate buffered arrays
|
|
if nstep>obj.scanBuffSize
|
|
warning('Buffer overflow detected: increase scanBuffSize.');
|
|
end
|
|
obj.timeStep = obj.timeStep(1:nstep);
|
|
obj.posStep = obj.posStep(1:nstep);
|
|
obj.numSetPerStep = obj.numSetPerStep(1:nstep);
|
|
% Set some internal variables
|
|
obj.NumDataset = max(obj.numSetPerStep);
|
|
obj.NumTimestep = nstep;
|
|
obj.isFileHeaderWritten = true;
|
|
obj.isStepHeaderWritten = true;
|
|
end
|
|
function create(obj,file,varargin)
|
|
% obj.create(file,varargin)
|
|
% Creates a new file and writes file header
|
|
% Input
|
|
% file file name/path
|
|
% ? type file type {'field' (default),'particle'}
|
|
% ? rank proc rank (default: [0,0,0,0])
|
|
% ? endian endianess {'n' (dafault),'a','l','s','b'}
|
|
par = inputParser;
|
|
addParamValue(par,'type','field',@ischar);
|
|
addParamValue(par,'rank',[0,0,0,0],@(x)(isnumeric(x)&&numel(x)==4));
|
|
addParamValue(par,'endian','n',@ischar);
|
|
parse(par,varargin{:});
|
|
%
|
|
obj.File = file; % add filename as object property
|
|
obj.IOMode = 'create'; % abstract IO mode
|
|
obj.ioflag = 'w+'; % internal IO mode
|
|
obj.tarflag = false; % data is within a tar file?
|
|
obj.isFileHeaderWritten = false;
|
|
obj.isStepHeaderWritten = false;
|
|
% Try to create the file
|
|
obj.fileID = fopen(obj.File,obj.ioflag);
|
|
if obj.fileID<0
|
|
error('Unable to create file: %s',obj.File);
|
|
end
|
|
obj.fileBeg = ftell(obj.fileID);
|
|
obj.fileEnd = ftell(obj.fileID);
|
|
obj.FileSize = obj.fileEnd-obj.fileBeg;
|
|
switch par.Results.type
|
|
case 'field'
|
|
obj.typeID = obj.typeIDmatlabField;
|
|
obj.Class = 'field';
|
|
case 'particle'
|
|
obj.typeID = obj.typeIDmatlabParticle;
|
|
obj.Class = 'particle';
|
|
otherwise
|
|
error('Unknown file type: %s',par.Results.type);
|
|
end
|
|
obj.IORank = par.Results.rank;
|
|
obj.Endian = par.Results.endian;
|
|
obj.versionMajor = 0;
|
|
obj.versionMinor = 0;
|
|
obj.versionPatch = 0;
|
|
obj.versionFile = 1;
|
|
obj.writeHeaderFile();
|
|
end
|
|
function opentar(obj,ptr)
|
|
% obj.opentar(ptr)
|
|
% Opens a subfile from tar in read-only mode
|
|
obj.File = 'tar-mode'; % Set generic file name
|
|
obj.IOMode = 'read'; % abstract IO mode
|
|
obj.ioflag = 'r'; % internal IO mode
|
|
obj.tarflag = true; % data is within a tar file?
|
|
% Set file ID to tar file ID
|
|
obj.fileID = ptr(1);
|
|
if obj.fileID<0
|
|
error('Unable to access file: %s',obj.File);
|
|
end
|
|
obj.fileBeg = ptr(2);
|
|
obj.fileEnd = ptr(2)+ptr(3);
|
|
obj.FileSize = ptr(3);
|
|
% Read the file header
|
|
obj.readHeaderFile()
|
|
% Scan through file to get the basic structure (steps/sets)
|
|
obj.timeStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.posStep = zeros(1,obj.scanBuffSize,'double');
|
|
obj.numSetPerStep = zeros(1,obj.scanBuffSize,'double');
|
|
istep = 0;
|
|
while ftell(obj.fileID)<obj.fileEnd
|
|
obj.readHeaderStep();
|
|
istep = istep+1;
|
|
obj.timeStep(istep) = obj.currentStepTime;
|
|
obj.posStep(istep) = ftell(obj.fileID);
|
|
obj.numSetPerStep(istep) = obj.currentStepNumSet;
|
|
if obj.currentStepSize==-1
|
|
break;
|
|
else
|
|
fseek(obj.fileID,obj.currentStepSize,'cof');
|
|
end
|
|
end
|
|
nstep = istep;
|
|
% Truncate buffered arrays
|
|
if nstep>obj.scanBuffSize
|
|
warning('Buffer overflow detected: increase scanBuffSize.');
|
|
end
|
|
obj.timeStep = obj.timeStep(1:nstep);
|
|
obj.posStep = obj.posStep(1:nstep);
|
|
obj.numSetPerStep = obj.numSetPerStep(1:nstep);
|
|
% Set some internal variables
|
|
obj.NumDataset = max(obj.numSetPerStep);
|
|
obj.NumTimestep = nstep;
|
|
obj.isFileHeaderWritten = true;
|
|
obj.isStepHeaderWritten = true;
|
|
end
|
|
end
|
|
%% ------------------------------------------------------------------------%%
|
|
%% PUBLIC METHODS %%
|
|
%% ------------------------------------------------------------------------%%
|
|
methods(Access=public)
|
|
function close(obj)
|
|
% obj.close()
|
|
% Closes a file
|
|
obj.resetPublicProperties();
|
|
obj.resetPrivateProperties();
|
|
obj.resetCurrentStep();
|
|
obj.resetCurrentSet();
|
|
if obj.tarflag
|
|
obj.tarflag = false;
|
|
obj.fileID = -1;
|
|
return;
|
|
end
|
|
if obj.fileID<0
|
|
return;
|
|
end
|
|
status = fclose(obj.fileID);
|
|
if status<0
|
|
warning('Unable to close file (exit code: %d)',status);
|
|
return;
|
|
end
|
|
obj.fileID = -1;
|
|
end
|
|
function [isType] = validateType(obj,type)
|
|
switch type
|
|
case 'grid'
|
|
isType = (obj.typeID==0);
|
|
case 'procgrid'
|
|
isType = (obj.typeID==10);
|
|
case 'field'
|
|
isType = (floor(obj.typeID/obj.factorTypeIDClass)==1);
|
|
case 'particle'
|
|
isType = (floor(obj.typeID/obj.factorTypeIDClass)==2);
|
|
case 'snapshot'
|
|
isType = (mod(obj.typeID,obj.factorTypeIDKind)==0);
|
|
case 'append'
|
|
isType = (mod(obj.typeID,obj.factorTypeIDKind)==1);
|
|
case {'uvwp','fluid'}
|
|
isType = (obj.typeID==1000);
|
|
case 'scalar'
|
|
isType = (obj.typeID==1010);
|
|
case 'matlab'
|
|
isType = (mod(obj.typeID,obj.factorTypeIDKind)==9);
|
|
otherwise
|
|
error('Unknown type: %s',type);
|
|
end
|
|
end
|
|
% ------------------------------------------------------------------------%
|
|
% Read %
|
|
% ------------------------------------------------------------------------%
|
|
function [data,params] = readSet(obj,tstep,dset)
|
|
% [data,params] = obj.readSet(tstep,dset)
|
|
% Reads a raw dataset from file (no reshaping or parsing of parameters)
|
|
% Input
|
|
% tstep index of timestep to be read
|
|
% dset index of dataset to be read
|
|
% Output
|
|
% data raw data with dim(1,nelements)
|
|
% params raw parameters with dim(1,nparams)
|
|
fseek(obj.fileID,obj.findSet(tstep,dset),'bof');
|
|
obj.readHeaderSet();
|
|
params = obj.currentSetParams;
|
|
data = fread(obj.fileID,[1,obj.currentSetNumElements],...
|
|
[obj.currentSetDatatype,'=>',obj.currentSetDatatype]);
|
|
end
|
|
function [params] = readParameters(obj,tstep,dset)
|
|
% [params] = obj.readParameters(tstep,dset)
|
|
% Reads a raw set of parameters without parsing.
|
|
% Input
|
|
% tstep index of timestep to be read
|
|
% dset index of dataset to be read
|
|
% Output
|
|
% params raw parameters with dim(1,nparams)
|
|
fseek(obj.fileID,obj.findSet(tstep,dset),'bof');
|
|
if obj.Debug
|
|
fprintf('Skipped to position %d\n',ftell(obj.fileID));
|
|
end
|
|
obj.readHeaderSet();
|
|
params = obj.currentSetParams;
|
|
end
|
|
% ------------------------------------------------------------------------%
|
|
% Append %
|
|
% ------------------------------------------------------------------------%
|
|
function appendStep(obj,time)
|
|
% [] = obj.appendStep(time)
|
|
% Creates a new step at the end of opened file.
|
|
% Input
|
|
% time simulation time
|
|
if ~obj.verifyWriteMode()
|
|
error('File must be opened in create/edit mode.');
|
|
end
|
|
%
|
|
obj.resetCurrentStep();
|
|
obj.resetCurrentSet();
|
|
%
|
|
fseek(obj.fileID,0,'eof');
|
|
obj.currentStep = obj.NumTimestep+1;
|
|
obj.currentStepPosHeader = ftell(obj.fileID);
|
|
obj.currentStepSize = 0;
|
|
obj.currentStepTime = time;
|
|
obj.currentStepNumSet = 0;
|
|
obj.writeHeaderStep();
|
|
obj.currentStepPosData = ftell(obj.fileID);
|
|
obj.currentSet = 0;
|
|
%
|
|
obj.NumTimestep = obj.currentStep;
|
|
obj.posStep(obj.currentStep) = obj.currentStepPosData;
|
|
obj.numSetPerStep(obj.currentStep) = obj.currentStepNumSet;
|
|
obj.timeStep(obj.currentStep) = obj.currentStepTime;
|
|
%
|
|
if obj.Verbosity
|
|
fprintf('Created timestep #%d with time = %f\n',obj.NumTimestep,obj.currentStepTime);
|
|
end
|
|
end
|
|
function appendSet(obj,data,params)
|
|
% [] = obj.appendSet(data,params)
|
|
% Creates a new dataset at the end of opened file and writes data.
|
|
% Input
|
|
% data data to append
|
|
% parameters dataset header parameters
|
|
if ~obj.verifyWriteMode()
|
|
error('File must be opened in create/edit mode.');
|
|
end
|
|
% Evaluate datatype
|
|
obj.currentSetDatatype = class(data);
|
|
switch obj.currentSetDatatype
|
|
case 'int32'; obj.currentSetDatatypeNumeric = 11; obj.currentSetSizeof = 4;
|
|
case 'int64'; obj.currentSetDatatypeNumeric = 12; obj.currentSetSizeof = 8;
|
|
case 'single'; obj.currentSetDatatypeNumeric = 21; obj.currentSetSizeof = 4;
|
|
case 'double'; obj.currentSetDatatypeNumeric = 22; obj.currentSetSizeof = 8;
|
|
otherwise
|
|
error('Datatype not implemented: %s',obj.currentSetDatatype);
|
|
end
|
|
% Append a new set header
|
|
fseek(obj.fileID,0,'eof');
|
|
obj.currentSet = obj.numSetPerStep(obj.currentStep)+1;
|
|
obj.currentSetPosHeader = ftell(obj.fileID);
|
|
obj.currentSetSize = numel(data)*obj.currentSetSizeof;
|
|
switch obj.Class
|
|
case 'field'; obj.currentSetNumParams = obj.nSetParamsField;
|
|
case 'particle'; obj.currentSetNumParams = obj.nSetParamsParticle;
|
|
otherwise; error('Invalid file class: %s',obj.Class);
|
|
end
|
|
obj.currentSetParams = zeros(1,obj.currentSetNumParams,'int64');
|
|
obj.currentSetParams(1:numel(params)) = params;
|
|
obj.writeHeaderSet();
|
|
% Append actual data
|
|
obj.currentSetPosData = ftell(obj.fileID);
|
|
fwrite(obj.fileID,data(:),obj.currentSetDatatype,0,obj.Endian);
|
|
% Rewrite step header
|
|
obj.currentStepNumSet = obj.currentStepNumSet+1;
|
|
obj.currentStepSize = obj.currentStepSize+...
|
|
(4+obj.currentSetNumParams)*obj.nByteHeaderStep+...
|
|
obj.currentSetSize;
|
|
obj.writeHeaderStep();
|
|
% Update internal variables
|
|
obj.numSetPerStep(obj.currentStep) = obj.currentSet;
|
|
obj.NumDataset = max(obj.currentSet,obj.NumDataset);
|
|
% Verbose output
|
|
if obj.Verbosity
|
|
fprintf('Created dataset %d at timestep #%d\n',obj.currentSet,obj.currentStep);
|
|
end
|
|
end
|
|
function exchangeSet(obj,istep,iset,data)
|
|
% [] = obj.exchangeSet(istep,iset,data)
|
|
% Exchanges the data stored in dataset (istep,iset) with the data provided.
|
|
% Input
|
|
% data data, which replaces dataset (must be same size and type)
|
|
if ~obj.verifyWriteMode()
|
|
error('File must be opened in create/edit mode.');
|
|
end
|
|
% Evaluate datatype and datasize
|
|
dtype = class(data);
|
|
switch dtype
|
|
case 'int32'; dtypeNumeric = 11; dtypeSizeof = 4;
|
|
case 'int64'; dtypeNumeric = 12; dtypeSizeof = 8;
|
|
case 'single'; dtypeNumeric = 21; dtypeSizeof = 4;
|
|
case 'double'; dtypeNumeric = 22; dtypeSizeof = 8;
|
|
otherwise
|
|
error('Datatype not implemented: %s',dtype);
|
|
end
|
|
dsize = numel(data)*dtypeSizeof;
|
|
% Navigate to correct dataset
|
|
fseek(obj.fileID,obj.findSet(istep,iset),'bof');
|
|
obj.readHeaderSet();
|
|
% Check if datatype/datasize match
|
|
if dtypeNumeric~=obj.currentSetDatatypeNumeric
|
|
error('Datatype mismatch: %s,%s',dtype,obj.currentSetDatatype)
|
|
end
|
|
if dsize~=obj.currentSetSize
|
|
error('Datasize mismatch: %d,%d',dsize,obj.currentSetSize)
|
|
end
|
|
% Write data
|
|
fwrite(obj.fileID,data(:),obj.currentSetDatatype,0,obj.Endian);
|
|
% Verbose output
|
|
if obj.Verbosity
|
|
fprintf('Edited dataset %d at timestep #%d\n',obj.currentSet,obj.currentStep);
|
|
end
|
|
end
|
|
% ------------------------------------------------------------------------%
|
|
% Setter %
|
|
% ------------------------------------------------------------------------%
|
|
function setVerbosity(obj,flag)
|
|
% obj.setVerbosity(flag)
|
|
% Sets verbosity
|
|
% Input
|
|
% flag '1' -> verbose output
|
|
obj.Verbosity = flag;
|
|
end
|
|
function setDebug(obj,flag)
|
|
% obj.setDebug(flag)
|
|
% Sets debug flag
|
|
% Input
|
|
% flag '1' -> debug output
|
|
obj.Debug = flag;
|
|
end
|
|
% ------------------------------------------------------------------------%
|
|
% Getter %
|
|
% ------------------------------------------------------------------------%
|
|
function [nstep] = getNumTimesteps(obj)
|
|
% [nstep] = obj.getNumTimesteps()
|
|
% Gets total number of time steps.
|
|
nstep = obj.NumTimestep;
|
|
end
|
|
function [stime] = getSimulationTime(obj,varargin)
|
|
% [stime] = obj.getSimulationTime(varargin)
|
|
% Gets simulation time for one/all time steps
|
|
% Input
|
|
% ? istep step index (default: -1, all steps)
|
|
par = inputParser;
|
|
addParamValue(par,'istep',-1,@isnumeric);
|
|
parse(par,varargin{:});
|
|
if par.Results.istep==-1
|
|
stime = obj.timeStep;
|
|
else
|
|
stime = obj.timeStep(par.Results.istep);
|
|
end
|
|
end
|
|
function [ndset] = getNumDatasets(obj,istep)
|
|
% [ndset] = obj.getNumDatasets(istep)
|
|
% Gets number datasets for a given time step.
|
|
% Input
|
|
% istep step index
|
|
ndset = obj.numSetPerStep(istep);
|
|
end
|
|
function [dpos,dsize,dtype,dnum] = getDataSetPosition(obj,tstep,dset)
|
|
% [params] = obj.readParameters(tstep,dset)
|
|
% Reads a raw set of parameters without parsing.
|
|
% Input
|
|
% tstep index of timestep to be read
|
|
% dset index of dataset to be read
|
|
% Output
|
|
% fpos offset to beginning of dataset
|
|
fseek(obj.fileID,obj.findSet(tstep,dset),'bof');
|
|
if obj.Debug
|
|
fprintf('Skipped to position %d\n',ftell(obj.fileID));
|
|
end
|
|
obj.readHeaderSet();
|
|
dpos = ftell(obj.fileID);
|
|
dsize = obj.currentSetSize;
|
|
dtype = obj.currentSetDatatype;
|
|
dnum = obj.currentSetNumElements;
|
|
end
|
|
end
|
|
%% ------------------------------------------------------------------------%%
|
|
%% PRIVATE METHODS %%
|
|
%% ------------------------------------------------------------------------%%
|
|
methods (Access = private)
|
|
function readHeaderFile(obj)
|
|
% Skip to beginning of file
|
|
fseek(obj.fileID,obj.fileBeg,'bof');
|
|
% Determine endianess
|
|
mfmt = 'aslb';
|
|
for fmt=mfmt
|
|
currentMagic = fread(obj.fileID,1,'int64=>int64',0,fmt);
|
|
fseek(obj.fileID,obj.fileBeg,'bof');
|
|
if currentMagic==obj.magicFile
|
|
break;
|
|
end
|
|
end
|
|
if currentMagic~=obj.magicFile
|
|
error('Magic mismatch: invalid file header. %d',currentMagic);
|
|
end
|
|
obj.Endian = fmt;
|
|
% Read header
|
|
header = fread(obj.fileID,[1,obj.nHeaderFile],'int64=>int64',0,obj.Endian);
|
|
if obj.Debug
|
|
fprintf('Read the following file header at %d bytes\n',0);
|
|
fprintf('%d,%d,%d,%d,%d,%d,%d,%d\n',header);
|
|
end
|
|
% Parse version
|
|
obj.versionMajor = floor(double(header(2))/obj.factorMajor);
|
|
obj.versionMinor = floor(mod(double(header(2)),obj.factorMajor)/obj.factorMinor);
|
|
obj.versionPatch = floor(mod(double(header(2)),obj.factorMinor)/obj.factorPatch);
|
|
obj.CodeVersion = sprintf('%d.%d.%d',obj.versionMajor,obj.versionMinor,obj.versionPatch);
|
|
obj.UCFVersion = mod(double(header(2)),obj.factorPatch);
|
|
% Parse time stamp (UTC)
|
|
obj.creationTimeUnix = double(header(3));
|
|
obj.CreationTime = datestr(obj.creationTimeUnix/86400 + datenum(1970,1,1));
|
|
% Parse file type
|
|
obj.typeID = double(header(4));
|
|
switch obj.typeID
|
|
case 0000; obj.Type = 'grid';
|
|
case 0010; obj.Type = 'processor grid';
|
|
case 1000; obj.Type = 'fluid snapshot';
|
|
case 1010; obj.Type = 'scalar snapshot';
|
|
case 1999; obj.Type = 'matlab field data';
|
|
case 2000; obj.Type = 'particle snapshot';
|
|
case 2001; obj.Type = 'particle append';
|
|
case 2011; obj.Type = 'particle lagrange';
|
|
case 2021; obj.Type = 'particle balancing';
|
|
case 2999; obj.Type = 'matlab particle data';
|
|
case 3000; obj.Type = 'statistics fluid';
|
|
case 3010; obj.Type = 'statistics fluid pure';
|
|
case 3020; obj.Type = 'statistics scalar';
|
|
otherwise; obj.Type = 'unknown';
|
|
end
|
|
% Parse file class
|
|
switch floor(obj.typeID/obj.factorTypeIDClass)
|
|
case 1; obj.Class = 'field';
|
|
case 2; obj.Class = 'particle';
|
|
case 3; obj.Class = 'statistics';
|
|
otherwise; obj.Class = 'unknown';
|
|
end
|
|
% Parse IO rank
|
|
obj.IORank = double(header(5:8));
|
|
end
|
|
function readHeaderStep(obj)
|
|
% Read and parse
|
|
obj.currentStepPosHeader = ftell(obj.fileID);
|
|
header = fread(obj.fileID,[1,obj.nHeaderStep],'int64=>int64',0,obj.Endian);
|
|
obj.currentStepPosData = ftell(obj.fileID);
|
|
currentMagic = header(1);
|
|
obj.currentStepSize = double(header(2));
|
|
obj.currentStepTime = typecast(header(3),'double');
|
|
obj.currentStepNumSet = double(header(4));
|
|
if obj.Debug
|
|
fprintf('Read the following step header at %d bytes\n',obj.currentStepPosHeader);
|
|
fprintf('%d,%d,%f,%d\n',header(1),header(2),typecast(header(3),'double'),header(4));
|
|
end
|
|
% Check if magic is correct
|
|
if currentMagic~=obj.magicStep
|
|
error('Magic mismatch: invalid step header. %d',currentMagic);
|
|
end
|
|
end
|
|
function readHeaderSet(obj)
|
|
% Read and parse
|
|
obj.currentSetPosHeader = ftell(obj.fileID);
|
|
header = fread(obj.fileID,[1,obj.nHeaderSet],'int64=>int64',0,obj.Endian);
|
|
obj.currentSetPosData = ftell(obj.fileID);
|
|
currentMagic = header(1);
|
|
obj.currentSetSize = double(header(2));
|
|
obj.currentSetDatatypeNumeric = double(header(3));
|
|
switch obj.currentSetDatatypeNumeric
|
|
case 11; obj.currentSetSizeof = 4; obj.currentSetDatatype = 'int32';
|
|
case 12; obj.currentSetSizeof = 8; obj.currentSetDatatype = 'int64';
|
|
case 21; obj.currentSetSizeof = 4; obj.currentSetDatatype = 'single';
|
|
case 22; obj.currentSetSizeof = 8; obj.currentSetDatatype = 'double';
|
|
otherwise
|
|
error('Unknown datatype: %d',obj.currentSetDatatypeNumeric);
|
|
end
|
|
obj.currentSetNumParams = double(header(4));
|
|
obj.currentSetNumElements = round(obj.currentSetSize/obj.currentSetSizeof);
|
|
if obj.Debug
|
|
fprintf('Read the following set header at %d bytes\n',obj.currentSetPosHeader);
|
|
fprintf('%d,%d,%d,%d\n',header(1),header(2),header(3),header(4));
|
|
end
|
|
% Check if magic is correct
|
|
if currentMagic~=obj.magicSet
|
|
error('Magic mismatch: invalid dataset header. %d',currentMagic);
|
|
end
|
|
% Read variable number of parameters
|
|
obj.currentSetParams = fread(obj.fileID,[1,obj.currentSetNumParams],'int64=>int64',0,obj.Endian);
|
|
if obj.Debug
|
|
fprintf('with parameters:')
|
|
for ii=1:obj.currentSetNumParams
|
|
fprintf(' %d',obj.currentSetParams(ii));
|
|
end
|
|
fprintf('\n');
|
|
end
|
|
end
|
|
function [flag] = verifyWriteMode(obj)
|
|
flag = false;
|
|
switch obj.IOMode
|
|
case {'edit','create'}
|
|
flag = true;
|
|
end
|
|
end
|
|
function writeHeaderFile(obj)
|
|
obj.creationTimeUnix = int64(java.lang.System.currentTimeMillis/1000); % using java for compatability before Matlab2014a
|
|
header = zeros(1,obj.nHeaderFile,'int64');
|
|
header(1) = obj.magicFile;
|
|
header(2) = obj.versionMajor*obj.factorMajor + ...
|
|
obj.versionMinor*obj.factorMinor + ...
|
|
obj.versionPatch*obj.factorPatch + ...
|
|
obj.versionFile;
|
|
header(3) = obj.creationTimeUnix;
|
|
header(4) = int64(obj.typeID);
|
|
header(5:8) = int64(obj.IORank);
|
|
fseek(obj.fileID,obj.fileBeg,'bof');
|
|
if obj.Debug
|
|
fprintf('Writing the following file header at %d bytes\n',ftell(obj.fileID));
|
|
fprintf('%d,%d,%d,%d,%d,%d,%d,%d\n',header);
|
|
end
|
|
fwrite(obj.fileID,header,'int64',0,obj.Endian);
|
|
obj.isFileHeaderWritten = true;
|
|
end
|
|
function writeHeaderStep(obj)
|
|
if ~obj.isFileHeaderWritten
|
|
error('No file header has been written yet.');
|
|
end
|
|
fseek(obj.fileID,obj.currentStepPosHeader,'bof');
|
|
if obj.Debug
|
|
fprintf('Writing the following step header at %d bytes\n',ftell(obj.fileID));
|
|
fprintf('%d,%d,%f,%d\n',obj.magicStep,obj.currentStepSize,obj.currentStepTime,obj.currentStepNumSet);
|
|
end
|
|
fwrite(obj.fileID,obj.magicStep,'int64',0,obj.Endian);
|
|
fwrite(obj.fileID,obj.currentStepSize,'int64',0,obj.Endian);
|
|
fwrite(obj.fileID,obj.currentStepTime,'double',0,obj.Endian);
|
|
fwrite(obj.fileID,obj.currentStepNumSet,'int64',0,obj.Endian);
|
|
obj.isStepHeaderWritten = true;
|
|
end
|
|
function writeHeaderSet(obj)
|
|
if ~obj.isStepHeaderWritten
|
|
error('No step header has been written yet.');
|
|
end
|
|
fseek(obj.fileID,obj.currentSetPosHeader,'bof');
|
|
header = zeros(1,obj.nHeaderSet,'int64');
|
|
header(1) = obj.magicSet;
|
|
header(2) = obj.currentSetSize;
|
|
header(3) = obj.currentSetDatatypeNumeric;
|
|
header(4) = obj.currentSetNumParams;
|
|
obj.currentSetParams = obj.currentSetParams(1:obj.currentSetNumParams);
|
|
if obj.Debug
|
|
fprintf('Writing the following set header at %d bytes\n',ftell(obj.fileID));
|
|
fprintf('%d,%d,%d,%d\n',header);
|
|
fprintf('with parameters:')
|
|
for ii=1:obj.currentSetNumParams
|
|
fprintf(' %d',obj.currentSetParams(ii));
|
|
end
|
|
fprintf('\n');
|
|
end
|
|
fwrite(obj.fileID,header,'int64',0,obj.Endian);
|
|
fwrite(obj.fileID,obj.currentSetParams,'int64',0,obj.Endian);
|
|
end
|
|
function [posHeader] = findSet(obj,tstep,dset)
|
|
% Check input
|
|
if tstep>obj.NumTimestep
|
|
error('Out of bounds: timestep. %d, %d',tstep,obj.NumTimestep);
|
|
end
|
|
if dset>obj.numSetPerStep(tstep)
|
|
error('Out of bounds: dataset. %d, %d',dset,obj.NumDataset);
|
|
end
|
|
% Navigate to correct set
|
|
fseek(obj.fileID,obj.posStep(tstep),'bof');
|
|
for iset=1:dset-1
|
|
obj.readHeaderSet();
|
|
fseek(obj.fileID,obj.currentSetSize,'cof');
|
|
end
|
|
posHeader = ftell(obj.fileID);
|
|
if obj.Debug
|
|
fprintf('Found step #%d, set #%d at position %d\n',tstep,dset,posHeader)
|
|
end
|
|
end
|
|
function resetPublicProperties(obj)
|
|
obj.File = [];
|
|
obj.Type = [];
|
|
obj.Class = [];
|
|
obj.Endian = [];
|
|
obj.CodeVersion = [];
|
|
obj.UCFVersion = [];
|
|
obj.NumDataset = [];
|
|
obj.NumTimestep = [];
|
|
obj.FileSize = [];
|
|
obj.CreationTime = [];
|
|
obj.IOMode = [];
|
|
obj.IORank = [];
|
|
obj.Verbosity = [];
|
|
obj.Debug = [];
|
|
end
|
|
function resetPrivateProperties(obj)
|
|
obj.fileBeg = [];
|
|
obj.fileEnd = [];
|
|
obj.typeID = [];
|
|
obj.ioflag = [];
|
|
obj.creationTimeUnix = [];
|
|
obj.versionMajor = [];
|
|
obj.versionMinor = [];
|
|
obj.versionPatch = [];
|
|
obj.versionFile = [];
|
|
obj.posStep = [];
|
|
obj.numSetPerStep = [];
|
|
obj.timeStep = [];
|
|
obj.isFileHeaderWritten = [];
|
|
obj.isStepHeaderWritten = [];
|
|
end
|
|
function resetCurrentStep(obj)
|
|
obj.currentStep = [];
|
|
obj.currentStepPosHeader = [];
|
|
obj.currentStepPosData = [];
|
|
obj.currentStepSize = [];
|
|
obj.currentStepTime = [];
|
|
obj.currentStepNumSet = [];
|
|
end
|
|
function resetCurrentSet(obj)
|
|
obj.currentSet = [];
|
|
obj.currentSetPosHeader = [];
|
|
obj.currentSetPosData = [];
|
|
obj.currentSetSize = [];
|
|
obj.currentSetDatatype = [];
|
|
obj.currentSetDatatypeNumeric = [];
|
|
obj.currentSetSizeof = [];
|
|
obj.currentSetNumParams = [];
|
|
obj.currentSetParams = [];
|
|
obj.currentSetNumElements = [];
|
|
end
|
|
end
|
|
end
|