generateOutputNetCDF

PURPOSE ^

GENERATEOUTPUTNETCDF Generate NetCDF output for glider deployment data.

SYNOPSIS ^

function nc = generateOutputNetCDF(filename, data, meta, deployment, vars, dims, atts, varargin)

DESCRIPTION ^

GENERATEOUTPUTNETCDF  Generate NetCDF output for glider deployment data.

  Syntax:
    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS)
    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS, OPTIONS)
    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS, OPT1, VAL1, ...)

  Description:
    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS)
    calls SAVENC to generate a NetCDF file named FILENAME from deployment data
    in struct DATA, according to the template defined by variable metadata in
    VARS, dimension definitions in struct DIMS and global attributes in struct
    array ATTS, and returns the absolute name of the generated file in string
    NC.

    DATA and VARS should be structs with one field per variable with the
    variable data and the variable metadata respectively, as needed by SAVENC.
    To allow runtime defined variable metadata, META might be a struct with 
    variable names as field names and runtime defined variable attributes as 
    values. Each field should be a struct with the vattribute names as field
    names and the attribute values as field values. If the value of a variable
    attribute in a field of VARS is left undefined (empty) and its name matches
    a field name of the corresponding variable field in META, the value is
    overwritten.

    DIMS should be a struct as needed by SAVENC. To allow runtime defined 
    dimensions and predefined dimensions (useful for the case of string
    variables), variables may specifye dimensions in VARS which are not defined 
    in DIMS or with undefined length (empty LENGTH field value), and they are 
    inferred from the size of the data values.

    ATTS should be a struct array as needed by SAVENC, too. To allow runtime 
    defined global attributes, attributes in ATTS whose name matches a field
    name in struct DEPLOYMENT are overwritten with the field value.
    In addition, if the following global attributes are present in struct ATTS, 
    they are updated with values computed from data (see options below):
      DATE_MODIFIED: modification time given by POSIXTIME ('yyyy-mm-ddTHH:MM:SS+00:00').
      GEOSPATIAL_LAT_MAX: maximum latitude value inferred from data.
      GEOSPATIAL_LAT_MIN: minimum latitude value inferred from data.
      GEOSPATIAL_LAT_UNITS: latitude units given by variable attributes.
      GEOSPATIAL_LON_MAX: maximum longitude value inferred from data.
      GEOSPATIAL_LON_MIN: minimum longitude value inferred from data.
      GEOSPATIAL_LON_UNITS: longitude units given by variable attributes.
      GEOSPATIAL_VERTICAL_MAX: maximum vertical value inferred from data.
      GEOSPATIAL_VERTICAL_MIN: minimum vertical value inferred from data.
      GEOSPATIAL_VERTICAL_UNITS: vertical units given by variable attributes.
      GEOSPATIAL_VERTICAL_POSITIVE: vertical positive direction given by variable attributes.
      TIME_COVERAGE_END: maximum time value inferred from data.
      TIME_COVERAGE_START: minimum time value inferred from data.
      TIME_COVERAGE_UNITS: time units given by value variable attributes.

    NC = GENERATEOUTPUTNETCDF(..., OPTIONS) and
    NC = GENERATEOUTPUTNETCDF(..., OPT1, VAL1, ...) accept the following
    options given in key-value pairs OPT1, VAL1... or in a struct OPTIONS 
    with field names as option keys and field values as option values, 
    to control the generation of coverage metadata:
      MODIFIED: modification time stamp.
        String with the timestamp for the 'date_modified' attribute.
        Default value: 
          datestr(posixtime2utc(posixtime()), 'yyyy-mm-ddTHH:MM:SS+00:00');
      TIME: variable choices for time coverage information.
        Char array or string cell array with the names of the variables from
        which to extract the time coverage information, in order of preference.
        Default value: 'time'
      TIME_CONVERSION: conversion to POSIX time for time coverage.
        String cell array of function names or cell array of function handles 
        with the functions to convert time variables in option TIME to POSIX
        time format (seconds since 1970-01-01 00:00:00 UTC). If a single value
        is provided, the same conversion is used for all variable choices.
        If empty, no conversion is applied.
      TIME_FORMAT: format for time coverage timestamps.
        String cell array of function names or cell array of function handles 
        with the functions to convert each time variable choice in option TIME
        to the desired timestamp format (instead of using the numeric values).
        If a single value is provided, the same format is used for all choices.
        If empty, no format is applied and the numeric values are used.
        Default value: @(t)(datestr(posixtime2utc(t), 'yyyy-mm-ddTHH:MM:SS+00:00'))
      POSITION: variable choice for position coverage information.
        Two column string cell array with the names of the variables from which 
        to extract the position coverage information (latitude and longitude).
        Columns correspond to the x and y coordinates respectively.
        Default value: {'longitude' 'latitude'}
      POSITION_CONVERSION: conversion to decimal degrees for position coverage.
        String cell array of function names or cell array of function handles 
        with the functions to convert each choice of position variables in 
        option POSITION to longitude and latitude in decimal degrees
        (in that order). If a single value is provided, the same conversion 
        is used for all variable choices. If empty, no conversion is applied.
        Default value: [] (no conversion applied)
      VERTICAL: variable choice for latitude coverage information.
        Char array or string cell array with the names of the variables from
        which to extract the vertical coverage information, in order of 
        preference.
        Default value: 'depth'
      VERTICAL_CONVERSION: conversion to meters for vertical coverage.
        String cell array of function names or cell array of function handles 
        with the functions to convert each choice of vertical coordinate 
        variable in option VERTICAL to meters. If a single value is provided,
        the same conversion is used for all variable choices. If empty, 
        no conversion is applied.
        Default value: [] (no conversion applied)
      VERTICAL_POSITIVE: vertical positive direction.
        Char array or string cell array with the positive direction of each
        choice of vertical coordinate variable in option VERTICAL ('up' or 
        'down'). If a single string is provided, the same direction is assumed
        for all vertical coordinate variables.
        Default value: 'down'

  Notes:
    Usually input data is the output of LOADSLOCUMDATA or LOADSEAGLIDERDATA, 
    PROCESSGLIDERDATA or GRIDGLIDERDATA.
    
    Be aware that only variables present in both structs DATA and VARS are 
    added to the NetCDF file. Any field in DATA not present in VARS is omited.

  Examples:
    nc = generateOutputNetCDF(filename, data, deployment, vars, dims, atts)
    nc = ...
      generateOutputNetCDF( ...
       filename, data, deployment, vars, dims, atts, ...
       'time', {'m_present_time' 'sci_m_present_time'}, ...
       'vertical', {'m_depth' 'sci_water_pressure' 'm_pressure'}, ...
       'vertical_positive', 'down', ...
       'vertical_conversion', {false, @(z)(z*10), @(z)(z*10)}, ...
       'position', {'m_gps_lon' 'm_gps_lat'; 'm_lon' 'm_lat'}, ...
       'position_conversion', ...
          @(x,y)(subsref({nmea2deg(x) nmea2deg(y)}, substruct('{}', {':'}))))

  See also:
    SAVENC
    POSIXTIME2UTC
    POSIXTIME
    NMEA2DEG
    LOADSLOCUMDATA
    LOADSEAGLIDERDATA
    PREPROCESSGLIDERDATA
    PROCESSGLIDERDATA
    GRIDGLIDERDATA

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

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

DOWNLOAD ^

generateOutputNetCDF.m

SOURCE CODE ^

0001 function nc = generateOutputNetCDF(filename, data, meta, deployment, vars, dims, atts, varargin)
0002 %GENERATEOUTPUTNETCDF  Generate NetCDF output for glider deployment data.
0003 %
0004 %  Syntax:
0005 %    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS)
0006 %    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS, OPTIONS)
0007 %    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS, OPT1, VAL1, ...)
0008 %
0009 %  Description:
0010 %    NC = GENERATEOUTPUTNETCDF(FILENAME, DATA, META, DEPLOYMENT, VARS, DIMS, ATTS)
0011 %    calls SAVENC to generate a NetCDF file named FILENAME from deployment data
0012 %    in struct DATA, according to the template defined by variable metadata in
0013 %    VARS, dimension definitions in struct DIMS and global attributes in struct
0014 %    array ATTS, and returns the absolute name of the generated file in string
0015 %    NC.
0016 %
0017 %    DATA and VARS should be structs with one field per variable with the
0018 %    variable data and the variable metadata respectively, as needed by SAVENC.
0019 %    To allow runtime defined variable metadata, META might be a struct with
0020 %    variable names as field names and runtime defined variable attributes as
0021 %    values. Each field should be a struct with the vattribute names as field
0022 %    names and the attribute values as field values. If the value of a variable
0023 %    attribute in a field of VARS is left undefined (empty) and its name matches
0024 %    a field name of the corresponding variable field in META, the value is
0025 %    overwritten.
0026 %
0027 %    DIMS should be a struct as needed by SAVENC. To allow runtime defined
0028 %    dimensions and predefined dimensions (useful for the case of string
0029 %    variables), variables may specifye dimensions in VARS which are not defined
0030 %    in DIMS or with undefined length (empty LENGTH field value), and they are
0031 %    inferred from the size of the data values.
0032 %
0033 %    ATTS should be a struct array as needed by SAVENC, too. To allow runtime
0034 %    defined global attributes, attributes in ATTS whose name matches a field
0035 %    name in struct DEPLOYMENT are overwritten with the field value.
0036 %    In addition, if the following global attributes are present in struct ATTS,
0037 %    they are updated with values computed from data (see options below):
0038 %      DATE_MODIFIED: modification time given by POSIXTIME ('yyyy-mm-ddTHH:MM:SS+00:00').
0039 %      GEOSPATIAL_LAT_MAX: maximum latitude value inferred from data.
0040 %      GEOSPATIAL_LAT_MIN: minimum latitude value inferred from data.
0041 %      GEOSPATIAL_LAT_UNITS: latitude units given by variable attributes.
0042 %      GEOSPATIAL_LON_MAX: maximum longitude value inferred from data.
0043 %      GEOSPATIAL_LON_MIN: minimum longitude value inferred from data.
0044 %      GEOSPATIAL_LON_UNITS: longitude units given by variable attributes.
0045 %      GEOSPATIAL_VERTICAL_MAX: maximum vertical value inferred from data.
0046 %      GEOSPATIAL_VERTICAL_MIN: minimum vertical value inferred from data.
0047 %      GEOSPATIAL_VERTICAL_UNITS: vertical units given by variable attributes.
0048 %      GEOSPATIAL_VERTICAL_POSITIVE: vertical positive direction given by variable attributes.
0049 %      TIME_COVERAGE_END: maximum time value inferred from data.
0050 %      TIME_COVERAGE_START: minimum time value inferred from data.
0051 %      TIME_COVERAGE_UNITS: time units given by value variable attributes.
0052 %
0053 %    NC = GENERATEOUTPUTNETCDF(..., OPTIONS) and
0054 %    NC = GENERATEOUTPUTNETCDF(..., OPT1, VAL1, ...) accept the following
0055 %    options given in key-value pairs OPT1, VAL1... or in a struct OPTIONS
0056 %    with field names as option keys and field values as option values,
0057 %    to control the generation of coverage metadata:
0058 %      MODIFIED: modification time stamp.
0059 %        String with the timestamp for the 'date_modified' attribute.
0060 %        Default value:
0061 %          datestr(posixtime2utc(posixtime()), 'yyyy-mm-ddTHH:MM:SS+00:00');
0062 %      TIME: variable choices for time coverage information.
0063 %        Char array or string cell array with the names of the variables from
0064 %        which to extract the time coverage information, in order of preference.
0065 %        Default value: 'time'
0066 %      TIME_CONVERSION: conversion to POSIX time for time coverage.
0067 %        String cell array of function names or cell array of function handles
0068 %        with the functions to convert time variables in option TIME to POSIX
0069 %        time format (seconds since 1970-01-01 00:00:00 UTC). If a single value
0070 %        is provided, the same conversion is used for all variable choices.
0071 %        If empty, no conversion is applied.
0072 %      TIME_FORMAT: format for time coverage timestamps.
0073 %        String cell array of function names or cell array of function handles
0074 %        with the functions to convert each time variable choice in option TIME
0075 %        to the desired timestamp format (instead of using the numeric values).
0076 %        If a single value is provided, the same format is used for all choices.
0077 %        If empty, no format is applied and the numeric values are used.
0078 %        Default value: @(t)(datestr(posixtime2utc(t), 'yyyy-mm-ddTHH:MM:SS+00:00'))
0079 %      POSITION: variable choice for position coverage information.
0080 %        Two column string cell array with the names of the variables from which
0081 %        to extract the position coverage information (latitude and longitude).
0082 %        Columns correspond to the x and y coordinates respectively.
0083 %        Default value: {'longitude' 'latitude'}
0084 %      POSITION_CONVERSION: conversion to decimal degrees for position coverage.
0085 %        String cell array of function names or cell array of function handles
0086 %        with the functions to convert each choice of position variables in
0087 %        option POSITION to longitude and latitude in decimal degrees
0088 %        (in that order). If a single value is provided, the same conversion
0089 %        is used for all variable choices. If empty, no conversion is applied.
0090 %        Default value: [] (no conversion applied)
0091 %      VERTICAL: variable choice for latitude coverage information.
0092 %        Char array or string cell array with the names of the variables from
0093 %        which to extract the vertical coverage information, in order of
0094 %        preference.
0095 %        Default value: 'depth'
0096 %      VERTICAL_CONVERSION: conversion to meters for vertical coverage.
0097 %        String cell array of function names or cell array of function handles
0098 %        with the functions to convert each choice of vertical coordinate
0099 %        variable in option VERTICAL to meters. If a single value is provided,
0100 %        the same conversion is used for all variable choices. If empty,
0101 %        no conversion is applied.
0102 %        Default value: [] (no conversion applied)
0103 %      VERTICAL_POSITIVE: vertical positive direction.
0104 %        Char array or string cell array with the positive direction of each
0105 %        choice of vertical coordinate variable in option VERTICAL ('up' or
0106 %        'down'). If a single string is provided, the same direction is assumed
0107 %        for all vertical coordinate variables.
0108 %        Default value: 'down'
0109 %
0110 %  Notes:
0111 %    Usually input data is the output of LOADSLOCUMDATA or LOADSEAGLIDERDATA,
0112 %    PROCESSGLIDERDATA or GRIDGLIDERDATA.
0113 %
0114 %    Be aware that only variables present in both structs DATA and VARS are
0115 %    added to the NetCDF file. Any field in DATA not present in VARS is omited.
0116 %
0117 %  Examples:
0118 %    nc = generateOutputNetCDF(filename, data, deployment, vars, dims, atts)
0119 %    nc = ...
0120 %      generateOutputNetCDF( ...
0121 %       filename, data, deployment, vars, dims, atts, ...
0122 %       'time', {'m_present_time' 'sci_m_present_time'}, ...
0123 %       'vertical', {'m_depth' 'sci_water_pressure' 'm_pressure'}, ...
0124 %       'vertical_positive', 'down', ...
0125 %       'vertical_conversion', {false, @(z)(z*10), @(z)(z*10)}, ...
0126 %       'position', {'m_gps_lon' 'm_gps_lat'; 'm_lon' 'm_lat'}, ...
0127 %       'position_conversion', ...
0128 %          @(x,y)(subsref({nmea2deg(x) nmea2deg(y)}, substruct('{}', {':'}))))
0129 %
0130 %  See also:
0131 %    SAVENC
0132 %    POSIXTIME2UTC
0133 %    POSIXTIME
0134 %    NMEA2DEG
0135 %    LOADSLOCUMDATA
0136 %    LOADSEAGLIDERDATA
0137 %    PREPROCESSGLIDERDATA
0138 %    PROCESSGLIDERDATA
0139 %    GRIDGLIDERDATA
0140 %
0141 %  Authors:
0142 %    Joan Pau Beltran  <joanpau.beltran@socib.cat>
0143 
0144 %  Copyright (C) 2013-2016
0145 %  ICTS SOCIB - Servei d'observacio i prediccio costaner de les Illes Balears
0146 %  <http://www.socib.es>
0147 %
0148 %  This program is free software: you can redistribute it and/or modify
0149 %  it under the terms of the GNU General Public License as published by
0150 %  the Free Software Foundation, either version 3 of the License, or
0151 %  (at your option) any later version.
0152 %
0153 %  This program is distributed in the hope that it will be useful,
0154 %  but WITHOUT ANY WARRANTY; without even the implied warranty of
0155 %  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0156 %  GNU General Public License for more details.
0157 %
0158 %  You should have received a copy of the GNU General Public License
0159 %  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0160 
0161   error(nargchk(6, 26, nargin, 'struct'));
0162   
0163   %% Set options and default values.
0164   options.modified = ...
0165     datestr(posixtime2utc(posixtime()), 'yyyy-mm-ddTHH:MM:SS+00:00');
0166   options.time = 'time';
0167   options.time_conversion = [];
0168   options.time_format = ...
0169     @(t)(datestr(posixtime2utc(t), 'yyyy-mm-ddTHH:MM:SS+00:00'));
0170   options.position = {'longitude' 'latitude'};
0171   options.position_conversion = [];
0172   options.vertical = 'depth';
0173   options.vertical_conversion = [];
0174   options.vertical_positive = 'down';
0175  
0176   
0177   %% Parse optional arguments.
0178   % Get option key-value pairs in any accepted call signature.
0179   argopts = varargin;
0180   if isscalar(argopts) && isstruct(argopts{1})
0181     % Options passed as a single option struct argument:
0182     % field names are option keys and field values are option values.
0183     opt_key_list = fieldnames(argopts{1});
0184     opt_val_list = struct2cell(argopts{1});
0185   elseif mod(numel(argopts), 2) == 0
0186     % Options passed as key-value argument pairs.
0187     opt_key_list = argopts(1:2:end);
0188     opt_val_list = argopts(2:2:end);
0189   else
0190     error('glider_toolbox:generateOutputNetCDF:InvalidOptions', ...
0191           'Invalid optional arguments (neither key-value pairs nor struct).');
0192   end
0193   % Overwrite default options with values given in extra arguments.
0194   for opt_idx = 1:numel(opt_key_list)
0195     opt = lower(opt_key_list{opt_idx});
0196     val = opt_val_list{opt_idx};
0197     if isfield(options, opt)
0198       options.(opt) = val;
0199     else
0200       error('glider_toolbox:generateOutputNetCDF:InvalidOption', ...
0201             'Invalid option: %s.', opt);
0202     end
0203   end
0204   
0205 
0206   %% Get dynamic global attribute values.
0207   dyn_atts = struct();
0208   % Modification date:
0209   dyn_atts.date_modified = options.modified;
0210   % Time coverage:
0211   time_field_list = cellstr(options.time);
0212   time_field_present = ...
0213     isfield(data, time_field_list) & isfield(vars, time_field_list);
0214   if any(time_field_present)
0215     time_field_index = find(time_field_present, 1);
0216     time_field = time_field_list{time_field_index};
0217     time_units = [];
0218     if iscell(options.time_conversion)
0219       time_func = options.time_conversion{time_field_index};
0220     else
0221       time_func = options.time_conversion;
0222     end
0223     if isempty(time_func)
0224       time_data = data.(time_field);
0225       if isfield(vars.(time_field), 'attributes')
0226         time_atts = vars.(time_field).attributes;
0227         time_units_select = strcmp('units', {time_atts.name});
0228         if any(time_units_select)
0229           time_units = time_atts(time_units_select).value;
0230         end
0231       end
0232     else
0233       if ischar(time_func)
0234         time_func = str2func(time_func);
0235       end
0236       time_data = time_func(data.(time_field));
0237     end
0238     if numel(options.time_format) > 1
0239       time_format_func = options.time_format{time_field_index};
0240     else
0241       time_format_func = options.time_format;
0242     end
0243     if isempty(time_format_func)
0244       dyn_atts.time_coverage_start = min(time_data);
0245       dyn_atts.time_coverage_end = max(time_data);
0246       if time_units
0247         dyn_atts.time_coverage_units = time_units;
0248       end
0249     else
0250       dyn_atts.time_coverage_start = time_format_func(min(time_data));
0251       dyn_atts.time_coverage_end = time_format_func(max(time_data));
0252     end
0253   end
0254   % Geospatial coverage:
0255   position_field_list  = cellstr(options.position);
0256   position_field_present = all(isfield(data, position_field_list) ...
0257                              & isfield(vars, position_field_list), 2);
0258   if any(position_field_present)
0259     position_field_index = find(position_field_present, 1);
0260     [position_x_field, position_y_field] = ...
0261       position_field_list{position_field_index, :};
0262     if iscell(options.position_conversion)
0263       position_func = options.position_conversion{position_field_index};
0264     else
0265       position_func = options.position_conversion;
0266     end
0267     if isempty(position_func)
0268       longitude_data = data.(position_x_field);
0269       latitude_data = data.(position_y_field);
0270       longitude_units = [];
0271       latitude_units = [];
0272       if isfield(vars.(position_x_field), 'attributes')
0273         longitude_atts = vars.(position_x_field).attributes;
0274         longitude_units_select = strcmp('units', {longitude_atts.name});
0275         if any(longitude_units_select)
0276           longitude_units = longitude_atts(longitude_units_select).value;
0277         end
0278       end
0279       if isfield(vars.(position_y_field), 'attributes')
0280         latitude_atts = vars.(position_y_field).attributes;
0281         latitude_units_select = strcmp('units', {latitude_atts.name});
0282         if any(latitude_units_select)
0283           latitude_units = latitude_atts(latitude_units_select).value;
0284         end
0285       end
0286     else
0287       if ischar(position_func)
0288         position_func = str2func(position_func);
0289       end
0290       [longitude_data, latitude_data] = ...
0291         position_func(data.(position_x_field), data.(position_y_field));
0292       longitude_units = 'degree_east';
0293       latitude_units = 'degree_north';
0294     end
0295     dyn_atts.geospatial_lon_min = min(longitude_data);
0296     dyn_atts.geospatial_lon_max = max(longitude_data);
0297     dyn_atts.geospatial_lat_min = min(latitude_data);
0298     dyn_atts.geospatial_lat_max = max(latitude_data);
0299     if longitude_units
0300       dyn_atts.geospatial_lon_units = longitude_units;
0301     end
0302     if latitude_units
0303       dyn_atts.geospatial_lat_units = latitude_units;
0304     end
0305   end
0306   % Vertical coverage:
0307   vertical_field_list  = cellstr(options.vertical);
0308   vertical_field_present = ...
0309     isfield(data, vertical_field_list) & isfield(vars, vertical_field_list);
0310   if any(vertical_field_present)
0311     vertical_field_index = find(vertical_field_present, 1);
0312     vertical_field = vertical_field_list{vertical_field_index};
0313     if iscell(options.vertical_conversion)
0314       vertical_func = options.vertical_conversion{vertical_field_index};
0315     else
0316       vertical_func = options.vertical_conversion;
0317     end
0318     if isempty(vertical_func)
0319       vertical_data = data.(vertical_field);
0320       vertical_units = [];
0321       vertical_positive = [];
0322       if isfield(vars.(vertical_field), 'attributes')
0323         vertical_atts = vars.(vertical_field).attributes;
0324         vertical_units_select = strcmp('units', {vertical_atts.name});
0325         vertical_positive_select = strcmp('positive', {vertical_atts.name});
0326         if any(vertical_units_select)
0327           vertical_units = vertical_atts(vertical_units_select).value;
0328         end
0329         if any(vertical_positive_select)
0330           vertical_positive = vertical_atts(vertical_positive_select).value;
0331         end
0332       end
0333     else
0334       if ischar(vertical_func)
0335         vertical_func = str2func(vertical_func);
0336       end
0337       vertical_data = vertical_func(data.(vertical_field));
0338       vertical_units = 'meters';
0339       vertical_positive_list = cellstr(options.vertical_positive);
0340       if numel(vertical_positive_list) > 1
0341         vertical_positive = vertical_positive_list{position_field_index};
0342       else
0343         vertical_positive = vertical_positive_list{1};
0344       end
0345     end
0346     dyn_atts.geospatial_vertical_min = min(vertical_data);
0347     dyn_atts.geospatial_vertical_max = max(vertical_data);
0348     if vertical_units
0349       dyn_atts.geospatial_vertical_units = vertical_units;
0350     end
0351     if vertical_positive
0352       dyn_atts.geospatial_vertical_positive = vertical_positive;
0353     end
0354   end
0355   
0356 
0357   %% Aggregate global metadata (global attributes and dimension definitions).
0358   global_meta = struct();
0359   % Set global attributes.
0360   global_meta.attributes = atts;
0361   % Overwrite default attributes with deployment fields or dynamic values.
0362   for att_idx = 1:numel(global_meta.attributes)
0363     if isfield(deployment, global_meta.attributes(att_idx).name)
0364       global_meta.attributes(att_idx).value = ...
0365         deployment.(global_meta.attributes(att_idx).name);
0366     elseif isfield(dyn_atts, global_meta.attributes(att_idx).name)
0367       global_meta.attributes(att_idx).value = ...
0368         dyn_atts.(global_meta.attributes(att_idx).name);
0369     end
0370   end
0371   % Set dimension lengths.
0372   global_meta.dimensions = dims;
0373   % Overwrite lengths of dimensions not defined by input arguments.
0374   var_name_list = fieldnames(vars);
0375   for var_idx = 1:numel(var_name_list);
0376     var_name = var_name_list{var_idx};
0377     if isfield(data, var_name)
0378       dim_name_list = vars.(var_name).dimensions;
0379       dim_size_list = size(data.(var_name));
0380       for dim_idx = 1:numel(dim_name_list)
0381         dim_name = dim_name_list{dim_idx};
0382         dim_size = dim_size_list(dim_idx);
0383         dim_comp = strcmp(dim_name, {global_meta.dimensions.name});
0384         if ~any(dim_comp)
0385           global_meta.dimensions(end+1) = ...
0386             struct('name', {dim_name}, 'length', {dim_size});
0387         elseif isempty(global_meta.dimensions(dim_comp).length)
0388           global_meta.dimensions(dim_comp).length = dim_size;
0389         end
0390       end
0391     end
0392   end
0393   
0394   
0395   %% Aggregate variable metadata and overwrite runtime defined metadata.
0396   variable_meta = struct();
0397   var_name_list = fieldnames(vars);
0398   for var_name_idx = 1:numel(var_name_list)
0399     var_name = var_name_list{var_name_idx};
0400     if isfield(data, var_name)
0401       variable_meta.(var_name) = vars.(var_name);
0402       % Loop in reverse order to allow for deletion of indexed attributes.
0403       for att_idx = numel(variable_meta.(var_name).attributes):-1:1
0404         att_name = variable_meta.(var_name).attributes(att_idx).name;
0405         att_value = variable_meta.(var_name).attributes(att_idx).value;
0406         if isempty(att_value)
0407           if isfield(meta, var_name) && isfield(meta.(var_name), att_name)
0408             if iscellstr(meta.(var_name).(att_name))
0409               variable_meta.(var_name).attributes(att_idx).value = ...
0410                 strtrim(sprintf('%s ', meta.(var_name).(att_name){:}));
0411             elseif islogical(meta.(var_name).(att_name))
0412               variable_meta.(var_name).attributes(att_idx).value = ...
0413                 uint8(meta.(var_name).(att_name));
0414             else
0415               variable_meta.(var_name).attributes(att_idx).value = ...
0416                 meta.(var_name).(att_name);
0417             end
0418           else
0419             variable_meta.(var_name).attributes(att_idx) = [];
0420           end
0421         end
0422       end
0423     end
0424   end
0425   
0426   
0427   %% Aggregate required variable data and apply required conversions.
0428   variable_data = struct();
0429   data_field_list = fieldnames(data);
0430   for data_field_idx = 1:numel(data_field_list)
0431     data_field = data_field_list{data_field_idx};
0432     if isfield(vars, data_field)
0433       % Convert text data from string cell array to C style strings.
0434       if iscellstr(data.(data_field))
0435         variable_data.(data_field) = strc(data.(data_field));
0436       else
0437         variable_data.(data_field) = data.(data_field);
0438       end
0439     end
0440   end
0441   
0442   
0443   %% Create base directory of target file if needed.
0444   % This seems to be the best way to check if a relative path points to
0445   % an existing directory (EXIST checks for existance in the whole load path).
0446   [file_dir, ~, ~] = fileparts(filename);
0447   [status, attrout] = fileattrib(file_dir);
0448   if ~status
0449     [success, message] = mkdir(file_dir);
0450     if ~success
0451       error('glider_toolbox:generateOutputNetCDF:NetCDFDirectoryError', ...
0452             'Could not create directory %s: %s.', file_dir, message);
0453     end
0454   elseif ~attrout.directory
0455     error('glider_toolbox:generateOutputNetCDF:NetCDFDirectoryError', ...
0456           'Not a directory: %s.', attrout.Name);
0457   end
0458   
0459   
0460   %% Generate the file.
0461   savenc(variable_data, variable_meta, global_meta, filename);
0462   
0463   
0464   %% Return the absolute name of the generated file.
0465   [status, attrout, ~] = fileattrib(filename);
0466   if status==0
0467     % We should never get here (if NetCDF creation succeed, file must exist).
0468     error('glider_toolbox:generateOutputNetCDF:NetCDFFileError', ...
0469           'NetCDF generation succeed but problems with output file %s: %s.', ...
0470           filename, attrout);
0471   end
0472   nc = attrout.Name;
0473 
0474 end

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