0001 function [meta, data] = sglogcat(meta_list, data_list, varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 error(nargchk(2, 8, nargin, 'struct'));
0116
0117
0118
0119 options.format = 'array';
0120 options.params = 'all';
0121 options.period = 'all';
0122
0123
0124
0125
0126 argopts = varargin;
0127 if isscalar(argopts) && isstruct(argopts{1})
0128
0129
0130 opt_key_list = fieldnames(argopts{1});
0131 opt_val_list = struct2cell(argopts{1});
0132 elseif mod(numel(argopts), 2) == 0
0133
0134 opt_key_list = argopts(1:2:end);
0135 opt_val_list = argopts(2:2:end);
0136 else
0137 error('glider_toolbox:sglogcat:InvalidOptions', ...
0138 'Invalid optional arguments (neither key-value pairs nor struct).');
0139 end
0140
0141 for opt_idx = 1:numel(opt_key_list)
0142 opt = lower(opt_key_list{opt_idx});
0143 val = opt_val_list{opt_idx};
0144 if isfield(options, opt)
0145 options.(opt) = val;
0146 else
0147 error('glider_toolbox:sglogcat:InvalidOption', ...
0148 'Invalid option: %s.', opt);
0149 end
0150 end
0151
0152
0153
0154 output_format = lower(options.format);
0155 param_filter = true;
0156 param_list = cellstr(options.params);
0157 start_filter = true;
0158 start_range = options.period;
0159 if ischar(options.params) && strcmp(options.params, 'all')
0160 param_filter = false;
0161 end
0162 if ischar(options.period) && strcmp(options.period, 'all')
0163 start_filter = false;
0164 end
0165
0166
0167
0168
0169
0170 if isempty(meta_list)
0171 meta_list = struct();
0172 meta_list.sources = {};
0173 meta_list.headers = struct('version', {}, 'glider', {}, ...
0174 'mission', {}, 'dive', {}, 'start', {});
0175 meta_list.params = struct();
0176 meta_list.start_secs = [];
0177 meta_list.GCHEAD = {};
0178 meta_list.DEVICES = {};
0179 meta_list.SENSORS = {};
0180 elseif iscell(meta_list)
0181 meta_list = vertcat(meta_list{:});
0182 end
0183 if isstruct(data_list)
0184 data_list = num2cell(data_list(:));
0185 else
0186 data_list = data_list(:);
0187 end
0188
0189
0190
0191
0192
0193 all_sources = vertcat(meta_list.sources);
0194 all_gcheads = {meta_list.GCHEAD}';
0195 all_devices = {meta_list.DEVICES}';
0196 all_sensors = {meta_list.SENSORS}';
0197 all_start_secs = vertcat(meta_list.start_secs);
0198 all_params = {meta_list.params}';
0199 all_headers = vertcat(meta_list.headers);
0200
0201 all_dive_nums = vertcat(all_headers.dive);
0202 all_miss_nums = vertcat(all_headers.mission);
0203 [~, miss_dive_sorting] = ...
0204 sort( (all_dive_nums - min(all_dive_nums)) ...
0205 + (all_miss_nums - min(all_miss_nums)) ...
0206 * (max(all_dive_nums) - min(all_dive_nums) + 1));
0207
0208 time_filtering = true(size(meta_list));
0209 if start_filter
0210 time_filtering = ...
0211 start_range(1) <= all_start_secs & all_start_secs <= start_range(2);
0212 end
0213
0214 time_filtering_and_miss_dive_sorting = ...
0215 miss_dive_sorting(time_filtering(miss_dive_sorting));
0216 header_list = all_headers(time_filtering_and_miss_dive_sorting, :);
0217 source_list = all_sources(time_filtering_and_miss_dive_sorting, :);
0218 gchead_list = all_gcheads(time_filtering_and_miss_dive_sorting, :);
0219 device_list = all_devices(time_filtering_and_miss_dive_sorting, :);
0220 sensor_list = all_sensors(time_filtering_and_miss_dive_sorting, :);
0221 column_list = all_params(time_filtering_and_miss_dive_sorting, :);
0222 starts_list = all_start_secs(time_filtering_and_miss_dive_sorting, :);
0223 values_list = data_list(time_filtering_and_miss_dive_sorting, :);
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 field_list = cellfun(@fieldnames, column_list, 'UniformOutput', false);
0238 field_list = unique(vertcat(field_list{:}));
0239 field_present_list = ...
0240 cellfun(@(c)(isfield(c, field_list)), column_list, 'UniformOutput', false);
0241 field_present_list = horzcat(field_present_list{:})';
0242 field_nested_list = ...
0243 cellfun(@(d)(isfield(d, field_list)), values_list, 'UniformOutput', false);
0244 field_nested_list = horzcat(field_nested_list{:})';
0245 field_struct_list = false(size(field_nested_list));
0246 field_member_list = struct();
0247 field_member_present_list = struct();
0248 field_member_indices_list = struct();
0249 field_filtering = true(size(field_list));
0250 if param_filter
0251 field_filtering = ismember(field_list, param_list);
0252 end
0253 for field_idx = 1:numel(field_list);
0254 field = field_list{field_idx};
0255 field_present = field_present_list(:,field_idx);
0256 field_nested = field_nested_list(:,field_idx);
0257 field_struct = cellfun(@(d)(isstruct(d.(field))), ...
0258 values_list(field_nested), 'UniformOutput', false);
0259 field_struct_list(field_nested, field_idx) = horzcat(field_struct{:})';
0260 member_list = cellfun(@(c)(c.(field)), ...
0261 column_list(field_present), 'UniformOutput', false);
0262 member_list = unique(vertcat(member_list{:}));
0263 if ~field_filtering(field_idx)
0264 member_filtering = ...
0265 ismember(strcat(field, '_', member_list), param_list);
0266 member_list = member_list(member_filtering);
0267 field_filtering(field_idx) = any(member_filtering);
0268 end
0269 if field_filtering(field_idx)
0270 field_member_list.(field) = member_list;
0271 field_member_present_list.(field) = ...
0272 false(numel(column_list), numel(member_list));
0273 field_member_indices_list.(field) = ...
0274 zeros(numel(column_list), numel(member_list));
0275 if ~isempty(member_list)
0276 [member_present_list, member_indices_list] = ...
0277 cellfun(@(c)(ismember(member_list, c.(field))), ...
0278 column_list(field_present), 'UniformOutput', false);
0279 field_member_present_list.(field)(field_present, :) = ...
0280 horzcat(member_present_list{:})';
0281 field_member_indices_list.(field)(field_present, :) = ...
0282 horzcat(member_indices_list{:})';
0283 end
0284 end
0285 end
0286 if param_filter
0287 field_list = field_list(field_filtering);
0288 field_present_list = field_present_list(:, field_filtering);
0289 field_nested_list = field_nested_list(:, field_filtering);
0290 field_struct_list = field_struct_list(:, field_filtering);
0291 end
0292
0293
0294
0295 meta = struct();
0296 meta.sources = source_list;
0297 meta.headers = header_list;
0298 meta.GCHEAD = gchead_list;
0299 meta.DEVICES = device_list;
0300 meta.SENSORS = sensor_list;
0301 meta.start_secs = min(starts_list);
0302 meta.params = field_member_list;
0303
0304
0305
0306 data = struct();
0307 spe_field_list = {'GC' 'STATE' 'SM_CCo'}';
0308 gps_field_list = {'GPSFIX'};
0309 bad_field_list = {'RECOV_CODE' 'RESTART_TIME'}';
0310 [~, field_index_list] = ...
0311 setdiff(field_list, vertcat(spe_field_list, gps_field_list, bad_field_list));
0312 for field_idx = field_index_list(:)'
0313 field = field_list{field_idx};
0314 field_present = field_present_list(:, field_idx);
0315 member_list = field_member_list.(field);
0316 if isempty(member_list)
0317
0318
0319 field_value_list = ...
0320 cellfun(@(d)(d.(field)), values_list(field_present), ...
0321 'UniformOutput', false);
0322 field_value = vertcat(field_value_list{:});
0323 data.(field)(field_present, 1) = field_value;
0324 if isnumeric(field_value)
0325 data.(field)(~field_present, 1) = nan;
0326 else
0327 data.(field)(~field_present, 1) = {''};
0328 end
0329 else
0330 field_nested = field_nested_list(:, field_idx);
0331 field_struct = field_struct_list(:, field_idx);
0332 member_list = field_member_list.(field);
0333 member_present_list = field_member_present_list.(field);
0334 member_indices_list = field_member_indices_list.(field);
0335 for member_idx = 1:numel(member_list)
0336 member = member_list{member_idx};
0337 field_member = [field '_' member];
0338 member_present = member_present_list(:, member_idx);
0339 member_indices = member_indices_list(:, member_idx);
0340 member_struct = member_present & field_struct;
0341 member_nested = member_present & field_nested & ~field_struct;
0342 member_merged = member_present & ~field_nested;
0343 member_value_list = cell(size(values_list));
0344 if any(member_struct)
0345 member_value_list(member_struct) = ...
0346 cellfun(@(d)(d.(field).(member)), values_list(member_struct), ...
0347 'UniformOutput', false);
0348 end
0349 if any(member_nested)
0350 member_value_list(member_nested) = ...
0351 cellfun(@(d,c)(d.(field)(:,c)), values_list(member_nested), ...
0352 num2cell(member_indices(member_nested)), ...
0353 'UniformOutput', false);
0354 end
0355 if any(member_merged)
0356 member_value_list(member_merged) = ...
0357 cellfun(@(d)(d.(field_member)), values_list(member_merged), ...
0358 'UniformOutput', false);
0359 end
0360 member_value = vertcat(member_value_list{member_present});
0361 data.(field)(member_present, member_idx) = member_value;
0362 if isnumeric(member_value)
0363 data.(field)(~member_present, member_idx) = nan;
0364 else
0365 data.(field)(~member_present, member_idx) = {''};
0366 end
0367 end
0368 end
0369 end
0370
0371
0372
0373 dive_start_offset_list = starts_list - min(starts_list);
0374 [~, spe_field_index_list] = ...
0375 intersect(field_list, ...
0376 vertcat(spe_field_list, gps_field_list, bad_field_list));
0377 spe_field_numeric_list = {'GC' 'SM_CCo'}';
0378 for spe_field_index = spe_field_index_list(:)'
0379 spe_field = field_list{spe_field_index};
0380 spe_field_numeric = any(strcmp(spe_field, spe_field_numeric_list));
0381 spe_member_list = field_member_list.(spe_field);
0382 spe_member_secs = strcmp('st_secs', spe_member_list);
0383 spe_data_list = cell(size(values_list));
0384 for data_idx = 1:numel(values_list)
0385 spe_member_present = field_member_present_list.(spe_field)(data_idx, :);
0386 spe_member_indices = field_member_indices_list.(spe_field)(data_idx, :);
0387 if field_struct_list(data_idx, spe_field_index)
0388 spe_data = struct2cell(values_list{data_idx}.(spe_field))';
0389 if spe_field_numeric
0390 spe_data = cell2mat(spe_data);
0391 end
0392 elseif field_nested_list(data_idx, spe_field_index)
0393 spe_data = values_list{data_idx}.(spe_field);
0394 else
0395 if spe_field_numeric
0396 spe_data = zeros(0,sum(spe_member_present));
0397 else
0398 spe_data = cell(0,sum(spe_member_present));
0399 end
0400 for spe_member_idx = find(spe_member_present(:)');
0401 spe_member = [spe_field '_' spe_member_list{spe_member_idx}];
0402 spe_member_index = spe_member_indices(spe_member_idx);
0403 spe_member_values = values_list{data_idx}.(spe_member);
0404 if spe_field_numeric || iscell(spe_member_values)
0405 spe_data(1:numel(spe_member_values), spe_member_index) = ...
0406 spe_member_values;
0407 else
0408 spe_data(1:numel(spe_member_values), spe_member_index) = ...
0409 num2cell(spe_member_values);
0410 end
0411 end
0412 end
0413 spe_data_list{data_idx}(:, spe_member_present) = ...
0414 spe_data(:, spe_member_indices(spe_member_present));
0415 if spe_field_numeric
0416 spe_data_list{data_idx}(1:end, ~spe_member_present) = nan;
0417 if size(spe_data_list{data_idx}, 1) > 0 && any(spe_member_secs)
0418 spe_data_list{data_idx}(:, spe_member_secs) = ...
0419 spe_data_list{data_idx}(:, spe_member_secs) ...
0420 + dive_start_offset_list(data_idx);
0421 end
0422 else
0423 spe_data_list{data_idx}(1:end, ~spe_member_present) = {''};
0424 if size(spe_data_list{data_idx}, 1) > 0 && any(spe_member_secs)
0425 spe_data_list{data_idx}(:, spe_member_secs) = ...
0426 num2cell(vertcat(spe_data_list{data_idx}{:, spe_member_secs}) ...
0427 + dive_start_offset_list(data_idx));
0428 end
0429 end
0430 end
0431 data.(spe_field) = vertcat(spe_data_list{:});
0432 if iscell(data.(spe_field))
0433 for spe_member_idx = 1:numel(spe_member_list)
0434 if ~iscellstr(data.(spe_field)(:,spe_member_idx))
0435 data_field_member_undef = ...
0436 cellfun(@isempty, data.(spe_field)(:,spe_member_idx));
0437 data.(spe_field)(data_field_member_undef, spe_member_idx) = {nan};
0438 end
0439 end
0440 end
0441 end
0442
0443
0444
0445 switch output_format
0446 case 'array'
0447 case 'merged'
0448 field_list = fieldnames(data);
0449 for field_idx = 1:numel(field_list)
0450 field = field_list{field_idx};
0451 member_list = meta.params.(field);
0452 value_list = data.(field);
0453 if ~isempty(member_list)
0454 for member_idx = 1:numel(member_list)
0455 member = member_list{member_idx};
0456 field_member = [field '_' member];
0457 value = value_list(:, member_idx);
0458 if iscell(value) && ~iscellstr(value)
0459 value = vertcat(value{:});
0460 end
0461 data.(field_member) = value;
0462 end
0463 data = rmfield(data, field);
0464 end
0465 end
0466 case 'struct'
0467 field_list = fieldnames(data);
0468 for field_idx = 1:numel(field_list)
0469 field = field_list{field_idx};
0470 member_list = meta.params.(field);
0471 value_list = data.(field);
0472 if ~isempty(member_list)
0473 if isnumeric(value_list)
0474 value_list = num2cell(value_list);
0475 end
0476 data.(field) = cell2struct(value_list, member_list, 2);
0477 end
0478 end
0479 otherwise
0480 error('glider_toolbox:sglog2cat:InvalidFormat', ...
0481 'Invalid output format: %s.', output_format)
0482 end
0483
0484 end