-
jacques.grelet_ird.fr authored
corrige un bug de l'implementation de la toolbox netcdf native, lorsqu'il n'y avait pas d'echantillon, la dimension DAYD_EXT etait crée à 0, unlimited, mais pas en premier dans le fichier, ainsi que les variables. Sous R2011b, la toolbox netcdf plantait à la lecture.
jacques.grelet_ird.fr authoredcorrige un bug de l'implementation de la toolbox netcdf native, lorsqu'il n'y avait pas d'echantillon, la dimension DAYD_EXT etait crée à 0, unlimited, mais pas en premier dans le fichier, ainsi que les variables. Sous R2011b, la toolbox netcdf plantait à la lecture.
write.m 13.29 KiB
function write(self, varargin)
% self = write(self, varargin)
% write method from netcdf class, create and write data to netcdf file
% also call by save method
%
% % Input
% -----
% self ........... netcdf object
% varargin{1} ........... netcdf file
% varargin{2} ........... file mode
% varargin{3} ........... waitbar (boolean)
%
% Output
% ------
% self ........... netcd object
%
% $Id$
%% check arguments
% TODOS: modify and test
% ----------------------
wbool = false;
self.file = char(varargin{1});
if nargin > 2
self.mode = char(varargin{2});
end
if nargin > 3
if varargin{3}
wbool = true;
end
end
% get keys list of dimensions, variables and attributes from netcdf instance
% --------------------------------------------------------------------------
ncd_keys = keys( get(self.dynaload, 'DIMENSIONS'));
ncv_keys = keys( get(self.dynaload, 'VARIABLES'));
nca_keys = keys( get(self.dynaload, 'ATTRIBUTES'));
% display more info about write file on console
% ---------------------------------------------
fprintf('\nWRITE_NETCDF_FILE\n'); tic;
fprintf('...writing %s : ', self.file);
% Initialize loading NetCDF file waitbar
% --------------------------------------
if wbool
wb = waitbar(0, 'Initializing NetCDF file. Please wait...');
% We cannot change title property to 'none' (default set as 'tex') inside
% waitbar function (line 81), see
% http://www.mathworks.co.uk/matlabcentral/newsreader/view_thread/115725
% -----------------------------------------------------------------------
hchild = get(wb,'children');
htitle = get(hchild,'title');
set(htitle,'Interpreter','None');
end
%% Open or create netcdf file
% -------------------------
switch(self.mode)
case {'NC_CLOBBER'}
self.nc_id = netcdf.create(self.file, self.mode);
case 'NC_WRITE'
self.nc_id = netcdf.open(self.file, self.mode);
otherwise
end
%% Create NetCDF DIMENSIONS
% -------------------------
for i=1:numel(ncd_keys)
key__ = ncd_keys{i};
s = get(get(self.dynaload, 'DIMENSIONS'), key__);
%value = s.value;
dimlen = s.dimlen;
% % create unlimited dimension. Any unlimited dimension is therefore last
% % in the list of dimension IDs in defVar function, todo below...
% % ---------------------------------------------------------------------
% if s.unlimited
% unlimDimId = netcdf.defDim(self.nc_id, key__, ...
% netcdf.getConstant('NC_UNLIMITED'));
% end
% if dimension is not set, get size from variable
% a faire evoluer car peu sur, et a voir pour tableaux
% -----------------------------------------------
if isempty(dimlen)
t = get(get(self.dynaload, 'VARIABLES'), key__);
if isfield(t, 'data__')
% if empty data, don't create unlimited (0) dimension
% ---------------------------------------------------
if numel(t.data__)
netcdf.defDim(self.nc_id, key__, numel(t.data__));
end
end
else
try
netcdf.defDim(self.nc_id, key__, dimlen);
catch ME
error('\nError: netcdf.%s (line %d), nc_id: %d, key__: %s dimlen: %d\n\tin function call: %s (%s)',...
ME.stack(2).name, ME.stack(2).line, self.nc_id, key__, dimlen, ME.stack(1).name, ME.message);
end
end
end
% display filename after 'Interpreter','None' initialization to prevent
% display console warning
% ---------------------------------------------------------------------
if wbool
waitbar(1/50,wb, ['Writing file: ' self.file ' Please wait...']);
end
%% Create and write NetCDF GLOBAL ATTRIBUTES
% -----------------------------------
% get netcdf global attribute constant
% ------------------------------------
nga = self.NC_GLOBAL;
%nga = netcdf.getConstant('NC_GLOBAL');
for i=1:numel(nca_keys)
key = nca_keys{i};
s = get(get(self.dynaload, 'ATTRIBUTES'), key);
%value = s.data__;
if isfield(s, 'data__')
% Create an attribute associated with the variable.
% -------------------------------------------------
try
netcdf.putAtt(self.nc_id, nga, key, s.data__);
catch ME
fprintf('\nError: netcdf.%s (line %d)\n\tin function call: %s (%s)',...
ME.stack(2).name, ME.stack(2).line, ME.stack(1).name, ME.message);
end
end
end
% Leave define mode.
% ------------------
netcdf.endDef(self.nc_id)
%% Adds NetCDF VARIABLES
% ----------------------
for i=1:numel(ncv_keys)
% Re-enter define mode.
% ---------------------
netcdf.reDef(self.nc_id);
% initialise varstruct
% nc_addvar use a structure with four fields:
% Name
% Nctype
% Dimension
% Attribute is also a structure array
% see help nc_addvar
% -----------------------------------
%varstruct = [];
% get variable name
% -----------------
key = ncv_keys{i};
% display waitbar
% ---------------
if wbool
waitbar( i/numel(ncv_keys), wb, ['writing ' key ' variable']);
end
% uncomment for debug only, display variable
% ------------------------------------------
% key
% get structure
% -------------
s = get(get(self.dynaload, 'VARIABLES'), key);
% get dimension(s) dimids from ncetcdf file, s.dimension is cell
% --------------------------------------------------------------
%dimids = [];
% utiliser numel(s.dimension__) et dimids(i) pour creer le tableau des
% dimids
if ~isfield(s, 'dimension__')
s %#ok<NOPRT>
error('field dimension__ not defined in variables structure ...');
end
try
% preallocate dimids
% ------------------
dimids = zeros(size(s.dimension__));
% fill dimids array from dim name
% -------------------------------
for ind=1:length(dimids)
dimid = netcdf.inqDimID(self.nc_id, s.dimension__{ind});
dimids(ind) = dimid;
end
% find index of unlimited dimension
% ---------------------------------
%ind = find(dimids == unlimDimId);
% reshape dimids array with unlimited value at the start
% -------------------------------------------------------
% if ~isempty(ind)
% dimids = [ dimids(1:ind-1), circshift(dimids(ind+1:end),[0 -1])];
% dimids = [circshift(dimids(1:ind),[0 1]), dimids(ind+1:end)];
% end
% leave comment these lines, it's right case
% ------------------------------------------
catch ME
% fprintf('\nNotice: netcdf.%s, dimension %s don''t exist or is empty',...
% ME.stack(2).name, s.dimension__{ind});
% Leave define mode and go to next variable (key__)
% -------------------------------------------------
netcdf.endDef(self.nc_id);
continue;
end
% We need to flip the dimensions
% ------------------------------
dimids = fliplr(dimids);
%netcdf.reDef(self.nc_id);
% create variable and get it's varid
% ----------------------------------
varid = netcdf.defVar(self.nc_id, key, s.type__, dimids);
% dynamically reate variable attributes
% get structure fieldnames from hashtable
% ---------------------------------------
ncv_fieldNames = fieldnames(s);
% loop over fieldname (variable attributes), first is key (code)
% --------------------------------------------------------------
for j=1:numel(ncv_fieldNames)
% get fielname and value
% ----------------------
fieldName = ncv_fieldNames{j};
value = s.(fieldName);
% jump each internal fieldname (eg key__, data__, type__, dimension__)
% or empty fieldname
% -------------------------------------------------------------
if ~isempty(regexp(fieldName, '__$','ONCE')) || isempty(value)
continue;
end
% change struct fieldname FillValue_ to attribute _FillValue
% ----------------------------------------------------------
if strcmp( fieldName, 'FillValue_')
fieldName = '_FillValue';
end
% BE CARREFULL: it's an very important notice
% value assign to attribute _FillValue should have same type
% as variable, true for all numeric atribute variable
% ------------------------------------------------------
if isnumeric(value)
switch s.type__
case 'double'
value = double(value);
case 'float'
value = single(value);
case 'int'
value = int32(value);
case 'short'
value = int16(value);
case 'byte'
value = int8(value);
case 'char'
value = char(value);
end
end
% Write variable netCDF attribute
% -------------------------------
netcdf.putAtt(self.nc_id, varid, fieldName, value);
end
% Leave define mode and enter data mode to write data.
% -----------------------------------------------------
netcdf.endDef(self.nc_id);
% if there is not data for variable or data__ empty
% ------------------------------------------------
if ~isfield(s, 'data__') || isempty(s.data__)
% and it's missing_value attribute is set, fill data with missing_value
% -------------------------------------------------------------------
if isfield(s, 'missing_value') && ~isempty(s.missing_value)
% get dimension id from name
% --------------------------
dimsize = numel(s.dimension__);
% rajouter un test iscell
% set dimids size array
% ----------------------
dimids = zeros(dimsize, 1);
% fill dimids array with dimension(s) Id
% --------------------------------------
try
for dim = 1: dimsize
dimids(dim) = netcdf.inqDimID(self.nc_id, s.dimension__{dim});
end
catch ME
msg = sprintf('dimension: %s don''t exist', s.dimension__{dim});
fprintf('\nWarning: netcdf.%s (line %d)\n\tin function call: %s',...
ME.stack(2).name, ME.stack(2).line, msg);
continue;
end
% get size of pre-allocate dimsize
% -------------------------------
dimlen = zeros(dimsize, 1);
% get dimension name and length from it's dimid
% ---------------------------------------------
for dim = 1: dimsize
[dimname, dimlen(dim)] = netcdf.inqDim(self.nc_id, dimids(dim));
end
% fill data with missing_value
% could use repmat to do that: s.data__ = repmat(1, dimlen, 1));
% --------------------------------------------------------------
if dimsize == 1
s.data__ = ones(dimlen,1) * s.missing_value;
else
s.data__ = ones(dimlen) * s.missing_value;
end
else
% if variable don't have attribute missing_value, exit loop and go to
% next variable
% -------------------------------------------------------------------
continue;
end
end
% BE CAREFULL:
% cast variable with the right netcdf nctype
% ------------------------------------------
switch s.type__
case 'double'
value = double(s.data__);
case 'float'
value = single(s.data__);
case 'int'
value = int32(s.data__);
case 'short'
value = int16(s.data__);
case 'byte'
value = int8(s.data__);
case 'char'
value = char(s.data__);
end
% matlab use FORTRAN indexing (k,j,i) and lib netcdf come from C style
% indexing (i,j,k)
% Matlab documentation is not very clear about this very important tips
% see:
% http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/helpdesk/help/techdoc/matlab_prog/brrbr9v-1.html&http://www.mathworks.fr/cgi-bin/texis/webinator/search/
% -------------------------------------------
value = permute(value, fliplr(1:ndims(value)));
% If a NetCDF variable has valid scale_factor and add_offset
% attributes, then the data is scaled accordingly.
% ----------------------------------------------------------
if self.autoscale
if isfield(s, 'scale_factor') && isfield(s, 'add_offset')
value = (value - s.add_offset) / s.scale_factor;
end
end
% If a NetCDF variable has valid _FillValue attributes, then
% the data is filled accordingly.
% ----------------------------------------------------------
if self.autonan && isfield(s, 'FillValue_') && ~isempty(s.FillValue_)
value(isnan(value)) = s.FillValue_;
end
% Write data to variable.
% -----------------------
try
% don't create empty variable
% ---------------------------
if ~isempty(value)
netcdf.putVar(self.nc_id, varid, value);
end
catch exception
fprintf('write variable error: %s', s.key__');
s %#ok<NOPRT>
fprintf('check your dynaload csv or xls file !!!\n');
error('Matla:netcdf.write:netcdf.putVar',...
'Cannot write netcdf file\n%s.', exception.message); %#ok<CTPCT>
end
% synchronize netcdf file to disk
% -------------------------------
netcdf.sync(self.nc_id);
end % end for ncv variables loop
% Close waitbar
% -------------
if wbool
close(wb)
end
% Display time to write file on console
% -------------------------------------
t = toc; fprintf('...done (%6.2f sec).\n\n',t);
% close netcdf file
% -----------------
netcdf.close(self.nc_id)
end % end of write function