function [out] = nc4loadN(fname, varargin)
% nc4loadN -- Load NetCDF4 variables.  This was designed to work for
%  NetCDF4, but it should also work for NetCDF3 (Classic) since they
%  are supposed to the backwards compatible.
% 
%  nc4loadN reads netCDF4 files using the matlab 7 HD5 interface.
%  This avoids issues with netcdf4 read routines when opening 1000s of
%  files, where the netcdf read routines do not close handles associated 
%  with variables. This leads to a massive slowdown when opening many
%  files in a single session.  The donwside is that compatability with
%  NetCDF3 (Classic) is not assured.  Info on teh functions used for 
%  HDF5 is avaulable at teh C API:
%     http://www.hdfgroup.org/HDF5/doc/RM/RM_H5Front.html
%
%
%  nc4load(fname, 'var1', 'var2', ...) loads the
%   specified variables of the NetCDF file, fname, into the 
%   workspace or into a structure if an output is given
%   If no attributes are given, the function fails but returns 
%   the variable names in the fileloads the whole file
%   Global attributes are also loaded into a structure called GlobAtts.
%
% EXAMPLES:
%   % return only a list of variables
%   nc4loadN('base_file.nc');  
%
%   % read two variables and save in a structure
%   ncstruct=nc4loadN('base_file.nc', 'ta19v', 'ta19h')

%   Written by Matt Sapiano, May 2011


if nargin < 1, help(mfilename), return, end;
if nargout > 1, help(mfilename), return, end;
clear out; out={}; out.GlobAtts={};




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% if no variables are specified, get variable names
% using regular netcdf calls and exit
if isempty(varargin), out={};
  ncid = netcdf.open(fname,'NOWRITE');
    [ndims,nvars,ngatts,unlimdimid] = netcdf.inq(ncid);
    for varid=0:(nvars-1), 
      out{varid+1}=netcdf.inqVar(ncid,varid); 
    end;
  netcdf.close(ncid); 
  disp('You must specify variables to read.  Variables in this file are:');
  disp(char(out)); return;
end;



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Read global attributes


% open NetCDF4 file
fid = H5F.open(deblank(fname),'H5F_ACC_RDONLY','H5P_DEFAULT');
if isempty(fid)|(fid==-1), disp('Could not read file'); return; end


% get number of attributes
GlobInfo = H5O.get_info(fid);

% read attributes and save them to the output structure
clear GlobAtts;
for idx=0:(GlobInfo.num_attrs-1),
  attr_id = H5A.open_by_idx(fid,'/',...
       'H5_INDEX_NAME','H5_ITER_DEC',idx,'H5P_DEFAULT','H5P_DEFAULT');
    % get name by index
    attname=H5A.get_name(attr_id);
    % read attribute data
    eval(['GlobAtts.' attname '=H5A.read(attr_id,''H5ML_DEFAULT'');']);
  % close attribute handle
  H5A.close(attr_id);
end;

% store the global attributes structure
if nargout==1,
  out.GlobAtts=GlobAtts;
else,
  assignin('caller','GlobAtts',GlobAtts);
end;





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% read each variable
for i = 1:length(varargin),
  try, % just in case a variable doesnt load...

    % get actual data and save
    dset_id=H5D.open(fid,char(varargin{i}));


    if nargout==1,
      eval(['out.' char(varargin{i}) '=double(H5D.read(dset_id,' ...
        '''H5ML_DEFAULT'',''H5S_ALL'',''H5S_ALL'',''H5P_DEFAULT''));'])
    else,
      assignin('caller',char(varargin{i}),double(H5D.read(dset_id,...
               'H5ML_DEFAULT','H5S_ALL','H5S_ALL','H5P_DEFAULT')));
    end;
    H5D.close(dset_id);

  catch,
    disp(['Variable ' char(varargin{i}) ' not found; skipping to next']);
  end;
end;


% close NetCDF4 file
H5F.close(fid);


