function S = netcdf(File,varargin) % Function to read NetCDF files % S = netcdf(File) % Input Arguments % File = NetCDF file to read % Optional Input Arguments: % 'Var',Var - Read data for VarArray(Var), default [1:length(S.VarArray)] % 'Rec',Rec - Read data for Record(Rec), default [1:S.NumRecs] % Output Arguments: % S = Structure of NetCDF data organised as per NetCDF definition % Notes: % Only version 1, classic 32bit, NetCDF files are supported. By default % data are extracted into the S.VarArray().Data field for all variables. % To read the header only call S = netcdf(File,'Var',[]); % % SEE ALSO % --------------------------------------------------------------------------- S = []; try if exist(File,'file') fp = fopen(File,'r','b'); else fp = []; error('File not found'); end if fp == -1 error('Unable to open file'); end % Read header Magic = fread(fp,4,'uint8=>char'); if strcmp(Magic(1:3),'CDF') error('Not a NetCDF file'); end if uint8(Magic(4))~=1 error('Version not supported'); end S.NumRecs = fread(fp,1,'uint32=>uint32'); S.DimArray = DimArray(fp); S.AttArray = AttArray(fp); S.VarArray = VarArray(fp); % Setup indexing to arrays and records Var = ones(1,length(S.VarArray)); Rec = ones(1,S.NumRecs); for i = 1:2:length(varargin) if strcmp(upper(varargin{i}),'VAR') Var=Var*0; Var(varargin{i+1})=1; elseif strcmp(upper(varargin{i}),'REC') Rec=Rec*0; Rec(varargin{i+1})=1; else error('Optional input argument not recognised'); end end if sum(Var)==0 fclose(fp); return; end % Read non-record variables Dim = double(cat(2,S.DimArray.Dim)); ID = double(cat(2,S.VarArray.Type)); for i = 1:length(S.VarArray) D = Dim(S.VarArray(i).DimID+1); N = prod(D); RecID{i}=find(D==0); if isempty(RecID{i}) if length(D)==0 D = [1,1]; N = 1; elseif length(D)==1 D=[D,1]; end if Var(i) S.VarArray(i).Data = ReOrder(fread(fp,N,[Type(ID(i)),'=>',Type(ID(i))]),D); fread(fp,(Pad(N,ID(i))-N)*Size(ID(i)),'uint8=>uint8'); else fseek(fp,Pad(N,ID(i))*Size(ID(i)),'cof'); end else S.VarArray(i).Data = []; end end % Read record variables for k = 1:S.NumRecs for i = 1:length(S.VarArray) if ~isempty(RecID{i}) D = Dim(S.VarArray(i).DimID+1); D(RecID{i}) = 1; N = prod(D); if length(D)==1 D=[D,1]; end if Var(i) & Rec(k) S.VarArray(i).Data = cat(RecID{i},S.VarArray(i).Data,... ReOrder(fread(fp,N,[Type(ID(i)),'=>',Type(ID(i))]),D)); if N > 1 fread(fp,(Pad(N,ID(i))-N)*Size(ID(i)),'uint8=>uint8'); end else fseek(fp,Pad(N,ID(i))*Size(ID(i)),'cof'); end end end end fclose(fp); catch Err = lasterror; fprintf('%s\n',Err.message); if ~isempty(fp) && fp ~= -1 fclose(fp); end end % --------------------------------------------------------------------------------------- % Utility functions function S = Size(ID) % Size of NetCDF data type, ID, in bytes S = subsref([1,1,2,4,4,8],struct('type','()','subs',{{ID}})); function T = Type(ID) % Matlab string for CDF data type, ID T = subsref({'int8','char','int16','int32','single','double'},... struct('type','{}','subs',{{ID}})); function N = Pad(Num,ID) % Number of elements to read after padding to 4 bytes for type ID N = (double(Num) + mod(4-double(Num)*Size(ID),4)/Size(ID)).*(Num~=0); function S = String(fp) % Read a CDF string; Size,[String,[Padding]] S = fread(fp,Pad(fread(fp,1,'uint32=>uint32'),1),'uint8=>char').'; function A = ReOrder(A,S) % Rearrange CDF array A to size S with matlab ordering A = permute(reshape(A,fliplr(S)),fliplr(1:length(S))); function S = DimArray(fp) % Read DimArray into structure if fread(fp,1,'uint32=>uint32') == 10 % NC_DIMENSION for i = 1:fread(fp,1,'uint32=>uint32') S(i).Str = String(fp); S(i).Dim = fread(fp,1,'uint32=>uint32'); end else fread(fp,1,'uint32=>uint32'); S = []; end function S = AttArray(fp) % Read AttArray into structure if fread(fp,1,'uint32=>uint32') == 12 % NC_ATTRIBUTE for i = 1:fread(fp,1,'uint32=>uint32') S(i).Str = String(fp); ID = fread(fp,1,'uint32=>uint32'); Num = fread(fp,1,'uint32=>uint32'); S(i).Val = fread(fp,Pad(Num,ID),[Type(ID),'=>',Type(ID)]).'; end else fread(fp,1,'uint32=>uint32'); S = []; end function S = VarArray(fp) % Read VarArray into structure if fread(fp,1,'uint32=>uint32') == 11 % NC_VARIABLE for i = 1:fread(fp,1,'uint32=>uint32') S(i).Str = String(fp); Num = double(fread(fp,1,'uint32=>uint32')); S(i).DimID = double(fread(fp,Num,'uint32=>uint32')); S(i).AttArray = AttArray(fp); S(i).Type = fread(fp,1,'uint32=>uint32'); S(i).VSize = fread(fp,1,'uint32=>uint32'); S(i).Begin = fread(fp,1,'uint32=>uint32'); % Classic 32 bit format only end else fread(fp,1,'uint32=>uint32'); S = []; end