savenc

PURPOSE ^

SAVENC Interface to low level functions to write data to a NetCDF file.

SYNOPSIS ^

function savenc(var_data, var_meta, global_meta, filename)

DESCRIPTION ^

SAVENC  Interface to low level functions to write data to a NetCDF file.

  Syntax:
    SAVENC(VAR_DATA, VAR_META, GLOBAL_META)
    SAVENC(VAR_DATA, VAR_META, GLOBAL_META, FILENAME)

  Description:
    SAVENC(VAR_DATA, VAR_META, GLOBAL_META) creates a NetCDF file according to
    global properties given in struct GLOBAL_META with the variables defined by
    the structs VAR_META and VAR_DATA.
    GLOBAL_META is struct with the following fields:
      DIMENSIONS: struct array describing the dimensions with fields:
        NAME: string with the name of the dimension.
        LENGTH: number with the length of the dimension, or 0 to indicate
          a record dimension.
      ATTRIBUTES: struct array with global attributes with fields:
        NAME: string with the name of the attribute.
        VALUE: arbitrary typed value with the value of the attribute.
      NAME: string with the name of the NetCDF file to be written.
    For every field in struct VAR_DATA a variable is created with the values in
    the field value. VAR_META should have a field with the same name containing
    the metadata for that variable in a struct with fields:
      DIMENSIONS: (mandatory) string cell array with the name of the dimensions
        of the variable.
      ATTRIBUTES: (optional) struct array with fields 'NAME' and 'VALUE' 
        specifying the attributes of the variable.
      DATATYPE: (optional) string with the NetCDF data type of the variable.
        Allowed types are 'double', 'float', 'int', 'short', 'byte', or 'char'.
        If this field is missing, the type is derived from the class of the 
        data, and if it is not valid the default data type 'double' is used.
      NAME: (optional) string with the variable name as it should appear in the
        NetCDF file. If this field is missing the variable is named after the
        field name. This is useful when the desired variable name can not be
        used as field name.

    SAVENC(VAR_DATA, VAR_META, GLOBAL_META, FILENAME) will create a NetCDF file 
    named FILENAME, overriding the 'NAME' field in GLOBAL_META.

  Notes:
    Fill value and scale conversions are always performed.

    Only variables present in both VAR_DATA and VAR_META are written in to the
    NetCDF file. Any field in VAR_DATA not present in VAR_META and viceversa is
    silently omitted.

    It would be more convenient to specify attributes and dimensions in structs
    with attribute and dimension names as field names, and attribute values and
    dimension lengths as field values. But due to a MATLAB limitation, it will 
    cause trouble with attributes like '_FillValue' (because it is not a valid
    field name).

  Examples:
    global_meta = struct()
    global_meta.name = 'random.nc'
    global_meta.dimensions = ...
      struct('name', {'dim1' 'dim2' 'dim3'}, 'length', {0 5 10})
    var_meta = struct()
    var_meta.rand_num = struct('dimensions', {{}})
    var_meta.rand_vec = struct('dimensions', {{'dim1'}})
    var_meta.rand_mat = struct('dimensions', {{'dim2' 'dim3'}}, ...
                               'datatype', {'int'})
    var_data = struct()
    var_data.rand_num = int8(round(12 * rand([1 1])))
    var_data.rand_vec = randn([25 1])
    var_data.rand_mat = round(12 * rand([5 10]))
    var_data.rand_mat(var_data.rand_mat == 1) = nan
    savenc(var_data, var_meta, global_meta)
    filename = 'random_with_atts.nc'
    var_meta.rand_num.attributes = ...
      struct('name', {'comment'}, ...
             'value', {'This is a random signed 8 bit integer'})
    var_meta.rand_vec.attributes = ...
      struct('name', {'comment', 'add_offset', 'scale_factor'}, ...
             'value', {'This is a random vector', 10, 2.5})
    var_meta.rand_mat.attributes = ...
      struct('name', {'comment', '_FillValue'}, ...
             'value', {'This is a random matrix', intmax()})
    global_meta.attributes = ...
      struct('name', {'creation_date'}, 'value', {datestr(now)})
    savenc(var_data, var_meta, global_meta, filename)

  See also:
    LOADNC

  Authors:
    Joan Pau Beltran  <joanpau.beltran@socib.cat>

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

DOWNLOAD ^

savenc.m

SOURCE CODE ^

0001 function savenc(var_data, var_meta, global_meta, filename)
0002 %SAVENC  Interface to low level functions to write data to a NetCDF file.
0003 %
0004 %  Syntax:
0005 %    SAVENC(VAR_DATA, VAR_META, GLOBAL_META)
0006 %    SAVENC(VAR_DATA, VAR_META, GLOBAL_META, FILENAME)
0007 %
0008 %  Description:
0009 %    SAVENC(VAR_DATA, VAR_META, GLOBAL_META) creates a NetCDF file according to
0010 %    global properties given in struct GLOBAL_META with the variables defined by
0011 %    the structs VAR_META and VAR_DATA.
0012 %    GLOBAL_META is struct with the following fields:
0013 %      DIMENSIONS: struct array describing the dimensions with fields:
0014 %        NAME: string with the name of the dimension.
0015 %        LENGTH: number with the length of the dimension, or 0 to indicate
0016 %          a record dimension.
0017 %      ATTRIBUTES: struct array with global attributes with fields:
0018 %        NAME: string with the name of the attribute.
0019 %        VALUE: arbitrary typed value with the value of the attribute.
0020 %      NAME: string with the name of the NetCDF file to be written.
0021 %    For every field in struct VAR_DATA a variable is created with the values in
0022 %    the field value. VAR_META should have a field with the same name containing
0023 %    the metadata for that variable in a struct with fields:
0024 %      DIMENSIONS: (mandatory) string cell array with the name of the dimensions
0025 %        of the variable.
0026 %      ATTRIBUTES: (optional) struct array with fields 'NAME' and 'VALUE'
0027 %        specifying the attributes of the variable.
0028 %      DATATYPE: (optional) string with the NetCDF data type of the variable.
0029 %        Allowed types are 'double', 'float', 'int', 'short', 'byte', or 'char'.
0030 %        If this field is missing, the type is derived from the class of the
0031 %        data, and if it is not valid the default data type 'double' is used.
0032 %      NAME: (optional) string with the variable name as it should appear in the
0033 %        NetCDF file. If this field is missing the variable is named after the
0034 %        field name. This is useful when the desired variable name can not be
0035 %        used as field name.
0036 %
0037 %    SAVENC(VAR_DATA, VAR_META, GLOBAL_META, FILENAME) will create a NetCDF file
0038 %    named FILENAME, overriding the 'NAME' field in GLOBAL_META.
0039 %
0040 %  Notes:
0041 %    Fill value and scale conversions are always performed.
0042 %
0043 %    Only variables present in both VAR_DATA and VAR_META are written in to the
0044 %    NetCDF file. Any field in VAR_DATA not present in VAR_META and viceversa is
0045 %    silently omitted.
0046 %
0047 %    It would be more convenient to specify attributes and dimensions in structs
0048 %    with attribute and dimension names as field names, and attribute values and
0049 %    dimension lengths as field values. But due to a MATLAB limitation, it will
0050 %    cause trouble with attributes like '_FillValue' (because it is not a valid
0051 %    field name).
0052 %
0053 %  Examples:
0054 %    global_meta = struct()
0055 %    global_meta.name = 'random.nc'
0056 %    global_meta.dimensions = ...
0057 %      struct('name', {'dim1' 'dim2' 'dim3'}, 'length', {0 5 10})
0058 %    var_meta = struct()
0059 %    var_meta.rand_num = struct('dimensions', {{}})
0060 %    var_meta.rand_vec = struct('dimensions', {{'dim1'}})
0061 %    var_meta.rand_mat = struct('dimensions', {{'dim2' 'dim3'}}, ...
0062 %                               'datatype', {'int'})
0063 %    var_data = struct()
0064 %    var_data.rand_num = int8(round(12 * rand([1 1])))
0065 %    var_data.rand_vec = randn([25 1])
0066 %    var_data.rand_mat = round(12 * rand([5 10]))
0067 %    var_data.rand_mat(var_data.rand_mat == 1) = nan
0068 %    savenc(var_data, var_meta, global_meta)
0069 %    filename = 'random_with_atts.nc'
0070 %    var_meta.rand_num.attributes = ...
0071 %      struct('name', {'comment'}, ...
0072 %             'value', {'This is a random signed 8 bit integer'})
0073 %    var_meta.rand_vec.attributes = ...
0074 %      struct('name', {'comment', 'add_offset', 'scale_factor'}, ...
0075 %             'value', {'This is a random vector', 10, 2.5})
0076 %    var_meta.rand_mat.attributes = ...
0077 %      struct('name', {'comment', '_FillValue'}, ...
0078 %             'value', {'This is a random matrix', intmax()})
0079 %    global_meta.attributes = ...
0080 %      struct('name', {'creation_date'}, 'value', {datestr(now)})
0081 %    savenc(var_data, var_meta, global_meta, filename)
0082 %
0083 %  See also:
0084 %    LOADNC
0085 %
0086 %  Authors:
0087 %    Joan Pau Beltran  <joanpau.beltran@socib.cat>
0088 
0089 %  Copyright (C) 2013-2016
0090 %  ICTS SOCIB - Servei d'observacio i prediccio costaner de les Illes Balears
0091 %  <http://www.socib.es>
0092 %
0093 %  This program is free software: you can redistribute it and/or modify
0094 %  it under the terms of the GNU General Public License as published by
0095 %  the Free Software Foundation, either version 3 of the License, or
0096 %  (at your option) any later version.
0097 %
0098 %  This program is distributed in the hope that it will be useful,
0099 %  but WITHOUT ANY WARRANTY; without even the implied warranty of
0100 %  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0101 %  GNU General Public License for more details.
0102 %
0103 %  You should have received a copy of the GNU General Public License
0104 %  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0105 
0106   % Consider make this variable persistent.
0107   ISOCTAVE = exist('OCTAVE_VERSION','builtin');
0108   NETCDF_TYPES = {'double' 'float'  'int'   'short' 'byte' 'char'};
0109   NATIVE_TYPES = {'double' 'single' 'int32' 'int16' 'int8' 'char'};
0110 
0111   error(nargchk(3, 4, nargin, 'struct'));
0112 
0113   if nargin < 4
0114     filename = global_meta.name;
0115   end
0116   
0117   if ISOCTAVE
0118     % Create the resource.
0119     nc = netcdf(filename, 'c');
0120     try
0121       % Set global attributes.
0122       if isfield(global_meta, 'attributes')
0123         for global_att = global_meta.attributes(:)'
0124           nc.(global_att.name) = global_att.value;
0125         end
0126       end
0127       % Set dimensions.
0128       if isfield(global_meta, 'dimensions')
0129         for global_dim = global_meta.dimensions(:)'
0130           if isfield(global_dim, 'unlimited') && (global_dim.unlimited)
0131             nc(global_dim.name) = 0;
0132           else
0133             nc(global_dim.name) = global_dim.length;
0134           end
0135         end
0136       end
0137       % Set variable dimensions and attributes, and variable data.
0138       field_name_list = intersect(fieldnames(var_data), fieldnames(var_meta));
0139       for var_idx = 1:numel(field_name_list)
0140         field_name = field_name_list{var_idx};
0141         if isfield(var_meta.(field_name), 'name')
0142           var_name = var_meta.(field_name).name;
0143         else
0144           var_name = field_name;
0145         end
0146         if isfield(var_meta.(field_name), 'datatype')
0147           var_type = var_meta.(field_name).datatype;
0148         else
0149           data_type = class(var_data.(field_name));
0150           data_type_select = strcmp(data_type, NATIVE_TYPES);
0151           if any(data_type_select)
0152             var_type = NETCDF_TYPES{data_type_select};
0153           else
0154             var_type = 'double';
0155           end
0156         end
0157         nc_var_type_func = str2func(['nc' var_type]);
0158         nc{var_name} = nc_var_type_func(var_meta.(field_name).dimensions{:});
0159         if isfield(var_meta.(var_name), 'attributes')
0160           for var_att = var_meta.(var_name).attributes(:)'
0161             nc{var_name}.(var_att.name) = var_att.value;
0162           end
0163         end
0164       end
0165       for var_idx = 1:numel(field_name_list)
0166         field_name = field_name_list{var_idx};
0167         if isfield(var_meta.(field_name), 'name')
0168           var_name = var_meta.(field_name).name;
0169         else
0170           var_name = field_name;
0171         end
0172         % Set the variable data with fill value and scale handling enabled.
0173         % Give the range for record dimensions.
0174         nc_var = nc{var_name};
0175         nc_var = ncautonan(nc_var, 1);
0176         nc_var = ncautoscale(nc_var, 1);
0177         nc_var_ranges = arrayfun(@(s)(1:s), size(var_data.(field_name)), ...
0178                                  'UniformOutput', false);
0179         nc_var(nc_var_ranges{:}) = var_data.(field_name);
0180       end
0181     catch
0182       close(nc);
0183       delete(filename);
0184       rethrow(lasterror());
0185     end
0186     % Close the resource.
0187     close(nc);
0188   else
0189     % Create empty NetCDF file.
0190     nc_create_empty(filename);
0191     try
0192       % Set global attributes.
0193       if isfield(global_meta, 'attributes')
0194         for global_att = global_meta.attributes(:)'
0195           nc_attput(filename, nc_global, global_att.name, global_att.value);
0196         end
0197       end
0198       % Set dimensions.
0199       if isfield(global_meta, 'dimensions')
0200         for global_dim = global_meta.dimensions(:)'
0201           if isfield(global_dim, 'unlimited') && (global_dim.unlimited)
0202             nc_adddim(filename, global_dim.name, 0);
0203           else
0204             nc_adddim(filename, global_dim.name, global_dim.length);
0205           end
0206         end
0207       end
0208       % Set variable dimensions and attributes, and variable data.
0209       field_name_list = intersect(fieldnames(var_data), fieldnames(var_meta));
0210       for var_idx = 1:numel(field_name_list)
0211         field_name = field_name_list{var_idx};
0212         if isfield(var_meta.(field_name), 'name')
0213           var_name = var_meta.(field_name).name;
0214         else
0215           var_name = field_name;
0216         end
0217         if isfield(var_meta.(field_name), 'datatype')
0218           var_type = var_meta.(field_name).datatype;
0219         else
0220           data_type = class(var_data.(field_name));
0221           data_type_select = strcmp(data_type, NATIVE_TYPES);
0222           if any(data_type_select)
0223             var_type = NETCDF_TYPES{data_type_select};
0224           else
0225             var_type = 'double';
0226           end
0227         end
0228         nc_var = struct('Name', {var_name}, ...
0229                         'Dimension', {var_meta.(field_name).dimensions}, ...
0230                         'Datatype', var_type);
0231         if isfield(var_meta.(field_name), 'attributes')
0232           % Rename fields as required by low level library.
0233           nc_var.Attribute = ...
0234             struct('Name', {var_meta.(field_name).attributes.name}, ...
0235                    'Value', {var_meta.(field_name).attributes.value});
0236         end
0237         nc_addvar(filename, nc_var);
0238       end
0239       for var_idx = 1:numel(field_name_list)
0240         field_name = field_name_list{var_idx};
0241         if isfield(var_meta.(field_name), 'name')
0242           var_name = var_meta.(field_name).name;
0243         else
0244           var_name = field_name;
0245         end
0246         nc_varput(filename, var_name, var_data.(field_name))
0247       end
0248     catch exception
0249       delete(filename);
0250       rethrow(exception);
0251     end
0252   end
0253 
0254 end

Generated on Fri 06-Oct-2017 10:47:42 by m2html © 2005