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