gridGliderData

PURPOSE ^

GRIDGLIDERDATA Grid glider trajectory data over instantaneous homogeneous regular profiles.

SYNOPSIS ^

function [data_grid, meta_grid] = gridGliderData(data_proc, meta_proc, varargin)

DESCRIPTION ^

GRIDGLIDERDATA  Grid glider trajectory data over instantaneous homogeneous regular profiles.

  Syntax:
    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC)
    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC, OPTIONS)
    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC, OPT1, VAL1, ...)

  Description:
    DATA_GRID = GRIDGLIDERDATA(DATA_PROC, META_PROC) converts glider trajectory 
    data in struct DATA_PROC to vertical instantaneous profiles defined at 
    regular intervals of depth in DATA_GRID using default option values.
    See options description below.

    DATA_PROC should be a struct in the format returned by PROCESSGLIDERDATA,
    where each field is a vector of readings of the variable with the same 
    name along the glider trajectory. At least it should have a sequence for
    each reference coordinate: time, latitude and longitude, and depth.
    It also should have a sequence of profile indices that flags each reading
    with the number of the cast it belongs to.

    META_PROC is also a struct as returned by PROCESSGLIDERDATA, and gridding
    information is added to any existing metadata of each reference coordinate
    variable or data variable in returned struct META_GRID.

    DATA_GRID is a struct with two kind of fields: bidimensional arrays with 
    profiles of gridded variables as rows, and one dimensional reference 
    coordinate sequences: LATITUDE, LONTGITUDE, DEPTH, TIME and PROFILE_INDEX.
    Coordinate sequences are selected according to preferred choices in 
    options (see below). Only variables selected in options and also present 
    in DATA_PROC are gridded. Selected variables not present in DATA_PROC are
    silently omited.

    Each cast identified in DATA_PROC is converted to an instantaneous 
    vertical profile. The position and time coordinates of the new profile are
    the mean values of the respective coordinates in the cast. All profiles 
    are defined at the same depth coordinates, computed as the depth range of
    the whole trajectory divided into regular intervals of given resolution. 
    The cast data is interpolated over the new depth grid binning the readings 
    that lay in the corresponding depth intervals.

    Options may be given in key-value pairs OPT1, VAL1... or in a struct 
    OPTIONS with field names as option keys and field values as option values.
    Recognized options are:
      PROFILE_LIST: profile index sequence choices.
        String cell array with the names of the sequence to be used as profile 
        index, in order of preference.
        Default value: {'profile_index'}
      TIME_LIST: timestamp sequence choices.
        String cell array with the names of the sequence to be used as time 
        coordinates, in order of preference.
        Default value: {'time'}
      POSITION_LIST: latitude and longitude sequence choices.
        Struct array with the names of the sequence the to be used as 
        latitude and longitude coordinates, in order of preference.
        It should have the following fields:
          LATITUDE: latitude sequence name.
          LONGITUDE: longitude sequence name.
        Default value: struct('latitude',  {'latitude'}, 
                              'longitude', {'longitude'})
      DEPTH_LIST: depth sequence choices.
        String cell array with the names of the sequence to be use as depth
        coordinate, in order of preference.
        Default value: {'depth'}
      DEPTH_STEP: depth resolution.
        Positive number setting the depth resolution for output profiles.
        Default value: 1
      VARIABLE_LIST: list of variables to be included in output profiles.
        String cell array with the names of the variables to be interpolated
        over the output profiles.
        Default value: {} (do nothing except compute profile coordinates)

  Notes:
    This function is an improved version of a previous function by Tomeu Garau
    with the same name. He is the true glider man. Main changes are:
      - Support for reference coordinate sequence selection, variables to
        interpolate, gridding options.
      - Use the mean value of readings lying in the depth interval centered at
        each new depth level with the diameter of the depth resolution
        (instead of interpolation).

  Examples:
    [data_grid, meta_grid] = gridGliderData(data_proc, meta_proc, options)

  See also:
    PROCESSGLIDERDATA

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

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

DOWNLOAD ^

gridGliderData.m

SOURCE CODE ^

0001 function [data_grid, meta_grid] = gridGliderData(data_proc, meta_proc, varargin)
0002 %GRIDGLIDERDATA  Grid glider trajectory data over instantaneous homogeneous regular profiles.
0003 %
0004 %  Syntax:
0005 %    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC)
0006 %    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC, OPTIONS)
0007 %    [DATA_GRID, META_GRID] = GRIDGLIDERDATA(DATA_PROC, META_PROC, OPT1, VAL1, ...)
0008 %
0009 %  Description:
0010 %    DATA_GRID = GRIDGLIDERDATA(DATA_PROC, META_PROC) converts glider trajectory
0011 %    data in struct DATA_PROC to vertical instantaneous profiles defined at
0012 %    regular intervals of depth in DATA_GRID using default option values.
0013 %    See options description below.
0014 %
0015 %    DATA_PROC should be a struct in the format returned by PROCESSGLIDERDATA,
0016 %    where each field is a vector of readings of the variable with the same
0017 %    name along the glider trajectory. At least it should have a sequence for
0018 %    each reference coordinate: time, latitude and longitude, and depth.
0019 %    It also should have a sequence of profile indices that flags each reading
0020 %    with the number of the cast it belongs to.
0021 %
0022 %    META_PROC is also a struct as returned by PROCESSGLIDERDATA, and gridding
0023 %    information is added to any existing metadata of each reference coordinate
0024 %    variable or data variable in returned struct META_GRID.
0025 %
0026 %    DATA_GRID is a struct with two kind of fields: bidimensional arrays with
0027 %    profiles of gridded variables as rows, and one dimensional reference
0028 %    coordinate sequences: LATITUDE, LONTGITUDE, DEPTH, TIME and PROFILE_INDEX.
0029 %    Coordinate sequences are selected according to preferred choices in
0030 %    options (see below). Only variables selected in options and also present
0031 %    in DATA_PROC are gridded. Selected variables not present in DATA_PROC are
0032 %    silently omited.
0033 %
0034 %    Each cast identified in DATA_PROC is converted to an instantaneous
0035 %    vertical profile. The position and time coordinates of the new profile are
0036 %    the mean values of the respective coordinates in the cast. All profiles
0037 %    are defined at the same depth coordinates, computed as the depth range of
0038 %    the whole trajectory divided into regular intervals of given resolution.
0039 %    The cast data is interpolated over the new depth grid binning the readings
0040 %    that lay in the corresponding depth intervals.
0041 %
0042 %    Options may be given in key-value pairs OPT1, VAL1... or in a struct
0043 %    OPTIONS with field names as option keys and field values as option values.
0044 %    Recognized options are:
0045 %      PROFILE_LIST: profile index sequence choices.
0046 %        String cell array with the names of the sequence to be used as profile
0047 %        index, in order of preference.
0048 %        Default value: {'profile_index'}
0049 %      TIME_LIST: timestamp sequence choices.
0050 %        String cell array with the names of the sequence to be used as time
0051 %        coordinates, in order of preference.
0052 %        Default value: {'time'}
0053 %      POSITION_LIST: latitude and longitude sequence choices.
0054 %        Struct array with the names of the sequence the to be used as
0055 %        latitude and longitude coordinates, in order of preference.
0056 %        It should have the following fields:
0057 %          LATITUDE: latitude sequence name.
0058 %          LONGITUDE: longitude sequence name.
0059 %        Default value: struct('latitude',  {'latitude'},
0060 %                              'longitude', {'longitude'})
0061 %      DEPTH_LIST: depth sequence choices.
0062 %        String cell array with the names of the sequence to be use as depth
0063 %        coordinate, in order of preference.
0064 %        Default value: {'depth'}
0065 %      DEPTH_STEP: depth resolution.
0066 %        Positive number setting the depth resolution for output profiles.
0067 %        Default value: 1
0068 %      VARIABLE_LIST: list of variables to be included in output profiles.
0069 %        String cell array with the names of the variables to be interpolated
0070 %        over the output profiles.
0071 %        Default value: {} (do nothing except compute profile coordinates)
0072 %
0073 %  Notes:
0074 %    This function is an improved version of a previous function by Tomeu Garau
0075 %    with the same name. He is the true glider man. Main changes are:
0076 %      - Support for reference coordinate sequence selection, variables to
0077 %        interpolate, gridding options.
0078 %      - Use the mean value of readings lying in the depth interval centered at
0079 %        each new depth level with the diameter of the depth resolution
0080 %        (instead of interpolation).
0081 %
0082 %  Examples:
0083 %    [data_grid, meta_grid] = gridGliderData(data_proc, meta_proc, options)
0084 %
0085 %  See also:
0086 %    PROCESSGLIDERDATA
0087 %
0088 %  Authors:
0089 %    Joan Pau Beltran  <joanpau.beltran@socib.cat>
0090 
0091 %  Copyright (C) 2013-2016
0092 %  ICTS SOCIB - Servei d'observacio i prediccio costaner de les Illes Balears
0093 %  <http://www.socib.es>
0094 %
0095 %  This program is free software: you can redistribute it and/or modify
0096 %  it under the terms of the GNU General Public License as published by
0097 %  the Free Software Foundation, either version 3 of the License, or
0098 %  (at your option) any later version.
0099 %
0100 %  This program is distributed in the hope that it will be useful,
0101 %  but WITHOUT ANY WARRANTY; without even the implied warranty of
0102 %  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0103 %  GNU General Public License for more details.
0104 %
0105 %  You should have received a copy of the GNU General Public License
0106 %  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0107 
0108   error(nargchk(2, 16, nargin, 'struct'));  
0109   
0110   
0111   %% Set gridding options from default values and extra arguments.
0112   % Set default option values.
0113   options = struct();
0114   options.profile_list = {'profile_index'};
0115   options.time_list = {'time'};
0116   options.position_list.latitude = 'latitude';
0117   options.position_list.longitude = 'longitude';
0118   options.depth_list = {'depth'};
0119   options.depth_step = 1;
0120   options.variable_list = {};
0121   % Parse option key-value pairs in any accepted call signature.
0122   if isscalar(varargin) && isstruct(varargin{1})
0123     % Options passed as a single option struct argument:
0124     % field names are option keys and field values are option values.
0125     option_key_list = fieldnames(varargin{1});
0126     option_val_list = struct2cell(varargin{1});
0127   elseif mod(numel(varargin), 2) == 0
0128     % Options passed as key-value argument pairs.
0129     option_key_list = varargin(1:2:end);
0130     option_val_list = varargin(2:2:end);
0131   else
0132     error('glider_toolbox:processGliderData:InvalidOptions', ...
0133           'Invalid optional arguments (neither key-value pairs nor struct).');
0134   end
0135   % Overwrite default options with values given in extra arguments.
0136   for opt_idx = 1:numel(option_key_list)
0137     opt = lower(option_key_list{opt_idx});
0138     val = option_val_list{opt_idx};
0139     if isfield(options, opt)
0140       options.(opt) = val;
0141     else
0142       error('glider_toolbox:gridGliderData:InvalidOption', ...
0143             'Invalid option: %s.', opt);
0144     end
0145   end
0146 
0147   
0148   %% Get list of sequences in trajectory data.
0149   sequence_list = fieldnames(data_proc);
0150   
0151   
0152   %% Select profile index sequence and coordinate sequences.
0153   % Profile index and coordinate variables (latitude, longitude, depth and time)
0154   % are mandatory.
0155   profile_available = false;
0156   time_available = false;
0157   position_available = false;
0158   depth_available = false;
0159   % Select profile index sequence.
0160   profile_choice_list = cellstr(options.profile_list);
0161   for profile_choice_idx = 1:numel(profile_choice_list)
0162     profile_sequence = profile_choice_list{profile_choice_idx};
0163     if ismember(profile_sequence, sequence_list) ...
0164         && ~all(isnan(data_proc.(profile_sequence)))
0165       fprintf('Selected profile index coordinate sequence:\n');
0166       fprintf('  profile: %s\n', profile_sequence);
0167       profile_available = true;
0168       break
0169     end
0170   end
0171   % Select time coordinate sequence.
0172   time_choice_list = cellstr(options.time_list);
0173   for time_choice_idx = 1:numel(time_choice_list)
0174     time_sequence = time_choice_list{time_choice_idx};
0175     if ismember(time_sequence, sequence_list) ...
0176         && any(data_proc.(time_sequence) > 0)
0177       fprintf('Selected time coordinate sequence:\n');
0178       fprintf('  time: %s\n', time_sequence);
0179       time_available = true;
0180       break
0181     end
0182   end
0183   % Select position coordinate sequences.
0184   position_choice_list = options.position_list;
0185   for position_choice_idx = 1:numel(position_choice_list)
0186     latitude_sequence = position_choice_list(position_choice_idx).latitude;
0187     longitude_sequence = position_choice_list(position_choice_idx).longitude;
0188     if all(ismember({latitude_sequence longitude_sequence}, sequence_list)) ...
0189         && ~all(isnan(data_proc.(latitude_sequence))) ...
0190         && ~all(isnan(data_proc.(longitude_sequence))) 
0191       fprintf('Selected position coordinate sequences:\n');
0192       fprintf('  longitude: %s\n', latitude_sequence);
0193       fprintf('  latitude : %s\n', longitude_sequence);
0194       position_available = true;
0195       break
0196     end
0197   end
0198   % Select depth sequence.
0199   depth_choice_list = cellstr(options.depth_list);
0200   for depth_choice_idx = 1:numel(depth_choice_list)
0201     depth_sequence = depth_choice_list{depth_choice_idx};
0202     if ismember(depth_sequence, sequence_list) ...
0203         && ~all(isnan(data_proc.(depth_sequence)))
0204       fprintf('Selected depth coordinate sequence:\n');
0205       fprintf('  depth: %s\n', depth_sequence);
0206       depth_available = true;
0207       break
0208     end
0209   end
0210   % Check all required inputs are present.
0211   coordinate_sequence_available = ...
0212     [profile_available time_available position_available depth_available];
0213   if ~all(coordinate_sequence_available)
0214     coordinate_sequences = {'profile' 'time' 'position' 'depth'};
0215     miss_coords = coordinate_sequences(~coordinate_sequence_available);
0216     miss_coords_str = [sprintf('%s, ', miss_coords{1:end-1}) miss_coords{end}];
0217     error('glider_toolbox:processGliderData:MissingCoordinateSequence', ...
0218           'Missing coordinate sequences in data set: %s.', miss_coords_str);
0219   end
0220 
0221 
0222   %% Select variables to grid.
0223   variable_list_choice = cellstr(options.variable_list);
0224   variable_name_list = intersect(sequence_list, variable_list_choice);
0225   fprintf('Selected variables to interpolate:\n');
0226   fprintf('  %s\n', variable_name_list{:});
0227 
0228   
0229   %% Store variables as columns in a single array to accelerate binning below.
0230   profile = data_proc.(profile_sequence);
0231   time = data_proc.(time_sequence);
0232   latitude = data_proc.(latitude_sequence);
0233   longitude = data_proc.(longitude_sequence);
0234   depth = data_proc.(depth_sequence);
0235   num_variables = numel(variable_name_list);
0236   num_instants = numel(time);
0237   variables = nan(num_instants, num_variables);
0238   for variable_name_idx = 1:num_variables
0239     variable_name = variable_name_list{variable_name_idx};
0240     variables(:, variable_name_idx) = data_proc.(variable_name)(:);
0241   end
0242 
0243   
0244   %% Compute number of casts.
0245   num_casts = fix(max(profile));
0246   profile_range = (1:num_casts);
0247 
0248 
0249   %% Compute depth intervals.
0250   depth_resolution = options.depth_step;
0251   depth_min = round(min(depth) / depth_resolution) * depth_resolution;
0252   depth_max = round(max(depth) / depth_resolution) * depth_resolution;
0253   depth_range = depth_min : depth_resolution : depth_max;
0254   num_levels = numel(depth_range);
0255   
0256   
0257   %% Initialize output.
0258   data_grid.depth = depth_range(:);
0259   data_grid.profile_index = profile_range(:);
0260   data_grid.time = nan(num_casts, 1);
0261   data_grid.longitude = nan(num_casts, 1);
0262   data_grid.latitude = nan(num_casts, 1);
0263   for variable_name_idx = 1:numel(variable_name_list)
0264     variable_name = variable_name_list{variable_name_idx};
0265     data_grid.(variable_name) = nan(num_casts, num_levels);
0266   end
0267   
0268 
0269   %% Compute profile coordinates and profile data.
0270   % Spatial and temporal coordinates are the mean values among cast readings.
0271   % Selected variable data is interpolated at selected depth levels.
0272   %{
0273   for cast_idx = 1:num_casts
0274     cast_select = (profile == cast_idx);
0275     cast_lat = latitude(cast_select);
0276     cast_lon = longitude(cast_select);
0277     cast_depth = depth(cast_select);
0278     cast_time = time(cast_select);
0279     data_grid.time(cast_idx) = nanmean(cast_time);
0280     data_grid.latitude(cast_idx) = nanmean(cast_lat);
0281     data_grid.longitude(cast_idx) = nanmean(cast_lon);
0282     for variable_name_idx = 1:numel(variable_name_list)
0283       variable_name = variable_name_list{variable_name_idx};
0284       cast_variable = data_proc.(variable_name)(cast_select);
0285       cast_valid = ~(isnan(cast_depth(:)) | isnan(cast_variable(:)));
0286       if sum(cast_valid) > 2
0287         data_grid.(variable_name)(cast_idx, :) = ...
0288           interp1(cast_depth(cast_valid), cast_variable(cast_valid), ...
0289           depth_range(:));
0290       end
0291     end
0292   end
0293   %}
0294   %%{
0295   % Spatial and temporal coordinates are the mean values among cast readings.
0296   % Selected variable data is binned taking the mean values of readings in depth
0297   % intervals centered at selected depth levels.
0298   % For better performance, compute variable data in single array and move it to
0299   % output struct at the end.
0300   fprintf('Gridding variables with settings:\n');
0301   fprintf('  depth level min : %d\n', depth_min);
0302   fprintf('  depth level max : %d\n', depth_max);
0303   fprintf('  depth level step: %d\n', depth_resolution);
0304   fprintf('  number of depth levels: %d\n', num_levels);
0305   fprintf('  number of profiles    : %d\n', num_casts);
0306   fprintf('  number of variables   : %d\n', num_variables);
0307   data_grid_variables = nan(num_casts, num_levels, num_variables);
0308   for cast_idx = 1:num_casts
0309     cast_select = (profile == cast_idx);
0310     cast_lat = latitude(cast_select);
0311     cast_lon = longitude(cast_select);
0312     cast_depth = depth(cast_select);
0313     cast_time = time(cast_select);
0314     cast_variables = variables(cast_select, :);
0315     data_grid.time(cast_idx) = nanmean(cast_time);
0316     data_grid.latitude(cast_idx) = nanmean(cast_lat);
0317     data_grid.longitude(cast_idx) = nanmean(cast_lon);
0318     if ~isempty(cast_variables) % Speed up when there are no variables.
0319       data_grid_variables(cast_idx, :, :) = ...
0320         cell2mat(arrayfun(@(d) nanmean(cast_variables(abs(cast_depth-d)<=0.5*depth_resolution, :), 1), ...
0321                           depth_range(:), 'UniformOutput', false));
0322     end
0323   end
0324   % Move binned variable data to output struct.
0325   for variable_name_idx = 1:num_variables
0326     variable_name = variable_name_list{variable_name_idx};
0327     data_grid.(variable_name) = data_grid_variables(:, :, variable_name_idx);
0328   end
0329   %%}
0330 
0331   
0332   %% Add gridding metadata:
0333   meta_grid.profile_index = meta_proc.(profile_sequence);
0334   meta_grid.profile_index.grid_sources = profile_sequence;
0335   meta_grid.profile_index.grid_resolution = 1;
0336   meta_grid.profile_index.grid_min = min(profile_range);
0337   meta_grid.profile_index.grid_max = max(profile_range);
0338   meta_grid.depth = meta_proc.(depth_sequence);
0339   meta_grid.depth.grid_sources = depth_sequence;
0340   meta_grid.depth.grid_resolution = depth_resolution;
0341   meta_grid.depth.grid_min = depth_min;
0342   meta_grid.depth.grid_max = depth_max;
0343   meta_grid.time = meta_proc.(time_sequence);
0344   meta_grid.time.grid_sources = time_sequence;
0345   meta_grid.time.grid_coordinates = {'profile_index'};
0346   meta_grid.time.grid_method = {'mean'};
0347   meta_grid.longitude = meta_proc.(longitude_sequence);
0348   meta_grid.longitude.grid_sources = longitude_sequence;
0349   meta_grid.longitude.grid_coordinates = {'profile_index'};
0350   meta_grid.longitude.grid_method = {'mean'};
0351   meta_grid.latitude = meta_proc.(latitude_sequence);
0352   meta_grid.latitude.grid_sources = latitude_sequence;
0353   meta_grid.latitude.grid_coordinates = {'profile_index'};
0354   meta_grid.latitude.grid_method = {'mean'};
0355   for variable_name_idx = 1:numel(variable_name_list)
0356     variable_name = variable_name_list{variable_name_idx};
0357     meta_grid.(variable_name) = meta_proc.(variable_name);
0358     meta_grid.(variable_name).grid_sources = variable_name;
0359     meta_grid.(variable_name).grid_coordinates = {'profile_index' 'depth'};
0360     meta_grid.(variable_name).grid_method = {'index' 'mean'};
0361   end
0362   
0363 end

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