diff --git a/AutomaticQC/imosCorrMagVelocitySetQC.m b/AutomaticQC/imosCorrMagVelocitySetQC.m index 5883d13b7..f52695edc 100644 --- a/AutomaticQC/imosCorrMagVelocitySetQC.m +++ b/AutomaticQC/imosCorrMagVelocitySetQC.m @@ -111,7 +111,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -cmag = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', cmag); +cmag = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', cmag); paramsLog = ['cmag=' num2str(cmag)]; @@ -158,6 +158,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', cmag); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', cmag); end \ No newline at end of file diff --git a/AutomaticQC/imosEchoIntensityVelocitySetQC.m b/AutomaticQC/imosEchoIntensityVelocitySetQC.m index 92351fded..a5dab5cf9 100644 --- a/AutomaticQC/imosEchoIntensityVelocitySetQC.m +++ b/AutomaticQC/imosEchoIntensityVelocitySetQC.m @@ -116,7 +116,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -ea_thresh = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', ea_thresh); +ea_thresh = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', ea_thresh); paramsLog = ['ea_thresh=' num2str(ea_thresh)]; @@ -189,6 +189,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', ea_thresh); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', ea_thresh); end diff --git a/AutomaticQC/imosErrorVelocitySetQC.m b/AutomaticQC/imosErrorVelocitySetQC.m index 55685baf7..8ec6fed7a 100644 --- a/AutomaticQC/imosErrorVelocitySetQC.m +++ b/AutomaticQC/imosErrorVelocitySetQC.m @@ -97,7 +97,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -err_vel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', err_vel); +err_vel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', err_vel); paramsLog = ['err_vel=' num2str(err_vel)]; @@ -141,6 +141,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', err_vel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', err_vel); end \ No newline at end of file diff --git a/AutomaticQC/imosHorizontalVelocitySetQC.m b/AutomaticQC/imosHorizontalVelocitySetQC.m index 3acd3b6b6..d4745c594 100644 --- a/AutomaticQC/imosHorizontalVelocitySetQC.m +++ b/AutomaticQC/imosHorizontalVelocitySetQC.m @@ -93,7 +93,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -hvel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', hvel); +hvel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', hvel); paramsLog = ['hvel=' num2str(hvel)]; @@ -127,6 +127,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', hvel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', hvel); end diff --git a/AutomaticQC/imosImpossibleDateQC.m b/AutomaticQC/imosImpossibleDateQC.m index c6a74ab87..6dc9d8a42 100644 --- a/AutomaticQC/imosImpossibleDateQC.m +++ b/AutomaticQC/imosImpossibleDateQC.m @@ -101,8 +101,8 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; - dateMin = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'dateMin', dateMin); - dateMax = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'dateMax', dateMax); + dateMin = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'dateMin', dateMin); + dateMax = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'dateMax', dateMax); paramsLog = ['dateMin=' datestr(dateMin, 'dd/mm/yyyy') ... ', dateMax=' datestr(dateMax, 'dd/mm/yyyy')]; @@ -122,6 +122,6 @@ end % write/update dataset QC parameters - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'dateMin', dateMin); - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'dateMax', dateMax); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'dateMin', dateMin); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'dateMax', dateMax); end \ No newline at end of file diff --git a/AutomaticQC/imosImpossibleDepthQC.m b/AutomaticQC/imosImpossibleDepthQC.m index 6d56786d4..b60a54f8a 100644 --- a/AutomaticQC/imosImpossibleDepthQC.m +++ b/AutomaticQC/imosImpossibleDepthQC.m @@ -254,8 +254,8 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; - zNominalMargin = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'zNominalMargin', zNominalMargin); - maxAngle = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'maxAngle', maxAngle); + zNominalMargin = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'zNominalMargin', zNominalMargin); + maxAngle = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'maxAngle', maxAngle); paramsLog = ['zNominalMargin=' num2str(zNominalMargin) ', maxAngle=' num2str(maxAngle)]; @@ -365,8 +365,8 @@ end % write/update dataset QC parameters - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'zNominalMargin', zNominalMargin); - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'maxAngle', maxAngle); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'zNominalMargin', zNominalMargin); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'maxAngle', maxAngle); % update climatologyRange info for display climatologyRange(p).(['range' paramName]) = [instrumentNominalDepth; instrumentNominalDepth]; diff --git a/AutomaticQC/imosPercentGoodVelocitySetQC.m b/AutomaticQC/imosPercentGoodVelocitySetQC.m index fcdb0b0ce..0221b7050 100644 --- a/AutomaticQC/imosPercentGoodVelocitySetQC.m +++ b/AutomaticQC/imosPercentGoodVelocitySetQC.m @@ -109,7 +109,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -pgood = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', pgood); +pgood = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', pgood); paramsLog = ['pgood=' num2str(pgood)]; @@ -148,6 +148,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', pgood); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', pgood); end \ No newline at end of file diff --git a/AutomaticQC/imosRateOfChangeQC.m b/AutomaticQC/imosRateOfChangeQC.m index c6bff10a8..c2dcc315b 100644 --- a/AutomaticQC/imosRateOfChangeQC.m +++ b/AutomaticQC/imosRateOfChangeQC.m @@ -91,7 +91,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -values = readQCparameter(sample_data.toolbox_input_file, currentQCtest, '*', values); +values = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, '*', values); param = strtrim(values{1}); thresholdExpr = strtrim(values{2}); @@ -225,6 +225,6 @@ % write/update dataset QC parameters for i=1:length(param) - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, param{i}, thresholdExpr{i}); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, param{i}, thresholdExpr{i}); end end \ No newline at end of file diff --git a/AutomaticQC/imosSideLobeVelocitySetQC.m b/AutomaticQC/imosSideLobeVelocitySetQC.m index d6898b8ff..58e48ae5a 100644 --- a/AutomaticQC/imosSideLobeVelocitySetQC.m +++ b/AutomaticQC/imosSideLobeVelocitySetQC.m @@ -119,7 +119,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -nBinSize = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'nBinSize', nBinSize); +nBinSize = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'nBinSize', nBinSize); paramsLog = ['nBinSize=' num2str(nBinSize)]; @@ -268,6 +268,6 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'nBinSize', nBinSize); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'nBinSize', nBinSize); end diff --git a/AutomaticQC/imosVerticalSpikeQC.m b/AutomaticQC/imosVerticalSpikeQC.m index aa0162fb0..499c413f7 100644 --- a/AutomaticQC/imosVerticalSpikeQC.m +++ b/AutomaticQC/imosVerticalSpikeQC.m @@ -77,7 +77,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -values = readQCparameter(sample_data.toolbox_input_file, currentQCtest, '*', values); +values = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, '*', values); param = strtrim(values{1}); thresholdExpr = strtrim(values{2}); @@ -197,6 +197,6 @@ % write/update dataset QC parameters for i=1:length(param) - writeQCparameter(sample_data.toolbox_input_file, currentQCtest, param{i}, thresholdExpr{i}); + writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, param{i}, thresholdExpr{i}); end end \ No newline at end of file diff --git a/AutomaticQC/imosVerticalVelocityQC.m b/AutomaticQC/imosVerticalVelocityQC.m index db202f236..31661057c 100644 --- a/AutomaticQC/imosVerticalVelocityQC.m +++ b/AutomaticQC/imosVerticalVelocityQC.m @@ -94,7 +94,7 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -vvel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', vvel); +vvel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', vvel); paramsLog = ['vvel=' num2str(vvel)]; @@ -112,6 +112,6 @@ flags(iPass) = goodFlag; % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', vvel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', vvel); end diff --git a/AutomaticQC/teledyneSetQC.m b/AutomaticQC/teledyneSetQC.m index 0a5f73de4..20949cf77 100644 --- a/AutomaticQC/teledyneSetQC.m +++ b/AutomaticQC/teledyneSetQC.m @@ -145,12 +145,12 @@ % read dataset QC parameters if exist and override previous % parameters file currentQCtest = mfilename; -qcthresh.err_vel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', qcthresh.err_vel); -qcthresh.pgood = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', qcthresh.pgood); -qcthresh.cmag = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', qcthresh.cmag); -qcthresh.vvel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', qcthresh.vvel); -qcthresh.hvel = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', qcthresh.hvel); -qcthresh.ea_thresh = readQCparameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', qcthresh.ea_thresh); +qcthresh.err_vel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', qcthresh.err_vel); +qcthresh.pgood = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', qcthresh.pgood); +qcthresh.cmag = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', qcthresh.cmag); +qcthresh.vvel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', qcthresh.vvel); +qcthresh.hvel = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', qcthresh.hvel); +qcthresh.ea_thresh = readDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh', qcthresh.ea_thresh); paramsLog = ['err_vel=' num2str(qcthresh.err_vel) ', pgood=' num2str(qcthresh.pgood) ... ', cmag=' num2str(qcthresh.cmag) ', vvel=' num2str(qcthresh.vvel) ... @@ -195,12 +195,12 @@ end % write/update dataset QC parameters -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', qcthresh.err_vel); -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', qcthresh.pgood); -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', qcthresh.cmag); -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', qcthresh.vvel); -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', qcthresh.hvel); -writeQCparameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh',qcthresh.ea_thresh); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'err_vel', qcthresh.err_vel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'pgood', qcthresh.pgood); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'cmag', qcthresh.cmag); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'vvel', qcthresh.vvel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'hvel', qcthresh.hvel); +writeDatasetParameter(sample_data.toolbox_input_file, currentQCtest, 'ea_thresh',qcthresh.ea_thresh); end diff --git a/FlowManager/autoIMOSToolbox.m b/FlowManager/autoIMOSToolbox.m index c6df048b9..be21a29fa 100644 --- a/FlowManager/autoIMOSToolbox.m +++ b/FlowManager/autoIMOSToolbox.m @@ -191,7 +191,7 @@ function autoIMOSToolbox(toolboxVersion, fieldTrip, dataDir, ppChain, qcChain, e if isempty(sample_data), continue; end raw_data = preprocessManager(sample_data, 'raw', mode, true); - qc_data = preprocessManager(raw_data, 'qc', mode, true); + qc_data = preprocessManager(sample_data, 'qc', mode, true); clear sample_data; qc_data = autoQCManager(qc_data, true); diff --git a/FlowManager/flowManager.m b/FlowManager/flowManager.m index 33168d33a..ec16e4135 100644 --- a/FlowManager/flowManager.m +++ b/FlowManager/flowManager.m @@ -55,11 +55,11 @@ function flowManager(toolboxVersion) for k = 1:length(nonUTCRawData), nonUTCRawData{k}.meta.index = k; end % preprocess data - [rawData, cancel] = preprocessManager(nonUTCRawData, 'raw', mode, false); % only apply TIME to UTC conversion pre-processing routines + [autoQCData, cancel] = preprocessManager(nonUTCRawData, 'qc', mode, false); if cancel - autoQCData = rawData; + rawData = nonUTCRawData; else - autoQCData = preprocessManager(rawData, 'qc', mode, true); % apply any pp routine except TIME to UTC conversion, auto is true so that GUI only appears once + rawData = preprocessManager(nonUTCRawData, 'raw', mode, true); % only apply TIME to UTC conversion pre-processing routines, auto is true so that GUI only appears once end clear nonUTCRawData; diff --git a/FlowManager/importManager.m b/FlowManager/importManager.m index 324d7299d..9c13746e9 100644 --- a/FlowManager/importManager.m +++ b/FlowManager/importManager.m @@ -85,16 +85,15 @@ rawFiles = {}; if ~isempty(ddb) || (~isempty(driver) && ~isempty(connection)) - [structs rawFiles] = ddbImport(auto, iMooring, ddb, mode); + [structs, rawFiles] = ddbImport(auto, iMooring, ddb, mode); else if auto, error('manual import cannot be automated without deployment database'); end - [structs rawFiles] = manualImport(mode); + [structs, rawFiles] = manualImport(mode); end % user cancelled if isempty(structs), return; end - dateFmt = readProperty('exportNetCDF.dateFormat'); qcSet = str2double(readProperty('toolbox.qc_set')); rawFlag = imosQCFlag('raw', qcSet, 'flag'); @@ -118,7 +117,7 @@ end end -function [sample_data rawFile]= manualImport(mode) +function [sample_data, rawFile]= manualImport(mode) %MANUALIMPORT Imports a data set by manually prompting the user to select a % raw file, and a parser with which to import it. % @@ -140,7 +139,7 @@ while true % prompt the user to select a data file - [rawFile path] = uigetfile('*', 'Select Data File', manualDir); + [rawFile, path] = uigetfile('*', 'Select Data File', manualDir); if rawFile == 0, return; end; @@ -158,7 +157,7 @@ % display progress dialog progress = waitbar(0, rawFile, ... - 'Name', 'Importing file',... + 'Name', 'Importing files',... 'DefaultTextInterpreter','none'); % import the data @@ -193,7 +192,7 @@ end end -function [sample_data rawFiles] = ddbImport(auto, iMooring, ddb, mode) +function [sample_data, rawFiles] = ddbImport(auto, iMooring, ddb, mode) %DDBIMPORT Imports data sets using metadata retrieved from a deployment % database. % @@ -226,9 +225,9 @@ while true switch mode case 'profile' - [fieldTrip deps sits dataDir] = getCTDs(auto, isCSV); % one entry is one CTD profile instrument file + [fieldTrip, deps, sits, dataDir] = getCTDs(auto, isCSV); % one entry is one CTD profile instrument file case 'timeSeries' - [fieldTrip deps sits dataDir] = getDeployments(auto, isCSV); % one entry is one moored instrument file + [fieldTrip, deps, sits, dataDir] = getDeployments(auto, isCSV); % one entry is one moored instrument file end if isempty(fieldTrip), return; end @@ -304,21 +303,14 @@ % find physical files for each deployed instrument allFiles = cell(size(deps)); for k = 1:length(deps) - - switch mode - case 'profile' - id = deps(k).FieldTrip; - case 'timeSeries' - id = deps(k).DeploymentId; - end rawFile = deps(k).FileName; hits = fsearch(rawFile, dataDir, 'files'); - % we remove any potential .pqc or .mqc files found (reserved for use + % we remove any potential .ppp, .pqc or .mqc files found (reserved for use % by the toolbox) - reservedExts = {'.pqc', '.mqc'}; + reservedExts = {'.ppp', '.pqc', '.mqc'}; for l=1:length(hits) [~, ~, ext] = fileparts(hits{l}); if all(~strcmp(ext, reservedExts)) @@ -327,17 +319,36 @@ end end + % Sort data_samples + % + % [B, iX] = sort(A); + % => + % A(iX) == B + % + switch mode + case 'timeSeries' + % for a mooring, sort instruments by depth + % we have to handle the case when InstrumentDepth is not documented + instDepths = {deps.InstrumentDepth}; + instDepths(cellfun(@isempty, instDepths)) = {NaN}; + instDepths = cell2mat(instDepths); + + [~, iSort] = sort(instDepths); + deps = deps(iSort); + allFiles = allFiles(iSort); + end + % display status dialog to highlight any discrepancies (file not found % for a deployment, more than one file found for a deployment) if ~auto - [deps allFiles] = dataFileStatusDialog(deps, allFiles, isCSV); + [deps, allFiles] = dataFileStatusDialog(deps, allFiles, isCSV); % user cancelled file dialog if isempty(deps), continue; end % display progress dialog - progress = waitbar(0, 'Importing file', ... - 'Name', 'Importing file',... + progress = waitbar(0, 'Importing files', ... + 'Name', 'Importing files',... 'DefaultTextInterpreter','none'); end diff --git a/FlowManager/preprocessManager.m b/FlowManager/preprocessManager.m index 6aaec7c14..b58e56926 100644 --- a/FlowManager/preprocessManager.m +++ b/FlowManager/preprocessManager.m @@ -115,7 +115,7 @@ if ~isempty(ppChain) % let user know what is going on in batch mode if auto - if strcmpi(qcLevel, 'raw') + if strcmpi(qcLevel, 'qc') % so that we only display this once ppChainStr = cellfun(@(x)([x ' ']), ppChain, 'UniformOutput', false); fprintf('%s\n', ['Preprocessing using : ' ppChainStr{:}]); end diff --git a/GUI/dataFileStatusDialog.m b/GUI/dataFileStatusDialog.m index 7e211fe5f..c72ed5e85 100644 --- a/GUI/dataFileStatusDialog.m +++ b/GUI/dataFileStatusDialog.m @@ -81,23 +81,11 @@ case 'profile' % for a profile, sort by alphabetical order [deploymentDescs, iSort] = sort(deploymentDescs); - case 'timeSeries' - % for a mooring, sort instruments by depth - - % we have to handle the case when InstrumentDepth is not documented - instDepths = {deployments.InstrumentDepth}; - instDepths(cellfun(@isempty, instDepths)) = {NaN}; - instDepths = cell2mat(instDepths); - - [~, iSort] = sort(instDepths); - deploymentDescs = deploymentDescs(iSort); + deployments = deployments(iSort); + files = files(iSort); + end - - - deployments = deployments(iSort); - files = files(iSort); - nofile = readProperty('dataFileStatusDialog.noFileFormat'); multiple = readProperty('dataFileStatusDialog.multipleFileFormat'); invalid = readProperty('dataFileStatusDialog.invalidFileNameFormat'); diff --git a/Geomag/geomag70.m b/Geomag/geomag70.m index 71e189b78..403b32176 100644 --- a/Geomag/geomag70.m +++ b/Geomag/geomag70.m @@ -94,7 +94,7 @@ fclose(inputId); % we run the geomag program and read its output - geomagCmd = sprintf('%s %s f %s %s %s', geomagExeFull, geomagModelFile, geomagInputFile, geomagOutputFile, stdOutRedirection); + geomagCmd = sprintf('"%s" "%s" f "%s" "%s" %s', geomagExeFull, geomagModelFile, geomagInputFile, geomagOutputFile, stdOutRedirection); system(geomagCmd); geomagFormat = '%s D M%f %f %f %fd %fm %*s %*s %*f %*f %*f %*f %*f %*f %*f %*f %*f %*f %*f %*f'; diff --git a/NetCDF/makeNetCDFCompliant.m b/NetCDF/makeNetCDFCompliant.m index 5a71ca8f8..a662670e5 100644 --- a/NetCDF/makeNetCDFCompliant.m +++ b/NetCDF/makeNetCDFCompliant.m @@ -229,11 +229,13 @@ Sensors = executeQueryFunc('Sensors', 'SensorID', InstrumentSensorConfig(i).SensorID); if ~isempty(Sensors) % check if this sensor is associated to the current IMOS parameter - parameters = textscan(Sensors.Parameter, '%s', 'Delimiter', ','); - if ~isempty(parameters) - parameters = parameters{1}; - if any(strcmpi(IMOSParam, parameters)) - target = Sensors.SerialNumber; + if isfield(Sensors, 'Parameter') + parameters = textscan(Sensors.Parameter, '%s', 'Delimiter', ','); + if ~isempty(parameters) + parameters = parameters{1}; + if any(strcmpi(IMOSParam, parameters)) + target = Sensors.SerialNumber; + end end end end diff --git a/Parser/aquadoppProfilerParse.m b/Parser/aquadoppProfilerParse.m index 3bafdbeb6..946f23646 100644 --- a/Parser/aquadoppProfilerParse.m +++ b/Parser/aquadoppProfilerParse.m @@ -68,51 +68,11 @@ % this is a plain profiler velocity data profilerType = 'Id33'; end -nsamples = length(structures.(profilerType).Id); -ncells = user.NBins; - -% preallocate memory for all sample data -time = nan(nsamples, 1); -distance = nan(ncells, 1); -analn1 = nan(nsamples, 1); -battery = nan(nsamples, 1); -analn2 = nan(nsamples, 1); -heading = nan(nsamples, 1); -pitch = nan(nsamples, 1); -roll = nan(nsamples, 1); -status = zeros(nsamples, 8, 'uint8'); -pressure = nan(nsamples, 1); -temperature = nan(nsamples, 1); -velocity1 = nan(nsamples, ncells); -velocity2 = nan(nsamples, ncells); -velocity3 = nan(nsamples, ncells); -backscatter1 = nan(nsamples, ncells); -backscatter2 = nan(nsamples, ncells); -backscatter3 = nan(nsamples, ncells); velocityProcessed = false; if isfield(structures, 'Id106') % velocity has been processed velocityProcessed = true; - nsamplesProc = length(structures.Id106.Sync); - timeProc = nan(nsamplesProc, 1); - velocity1Proc = nan(nsamples, ncells); - velocity2Proc = nan(nsamples, ncells); - velocity3Proc = nan(nsamples, ncells); - sig2noise1 = nan(nsamples, ncells); - sig2noise2 = nan(nsamples, ncells); - sig2noise3 = nan(nsamples, ncells); - stdDev1 = nan(nsamples, ncells); - stdDev2 = nan(nsamples, ncells); - stdDev3 = nan(nsamples, ncells); - errorCode1 = nan(nsamples, ncells); - errorCode2 = nan(nsamples, ncells); - errorCode3 = nan(nsamples, ncells); - speed = nan(nsamples, ncells); - direction = nan(nsamples, ncells); - verticalDist = nan(nsamples, ncells); - profileErrorCode = nan(nsamples, ncells); - qcFlag = nan(nsamples, ncells); end % @@ -124,6 +84,7 @@ freq = head.Frequency; % this is in KHz blankDist = user.T2; % counts cellSize = user.BinLength; % counts +ncells = user.NBins; factor = 0; % used for conversion switch freq @@ -137,9 +98,9 @@ blankDist = blankDist * 0.0229 * cos(25 * pi / 180) - cellSize; % generate distance values -distance(:) = (blankDist): ... - (cellSize): ... - (blankDist + (ncells-1) * cellSize); +distance = (blankDist: ... + cellSize: ... + blankDist + (ncells-1) * cellSize)'; % Note this is actually the distance between the ADCP's transducers and the % middle of each cell @@ -147,45 +108,45 @@ distance = distance + cellSize; % retrieve sample data -time = structures.(profilerType).Time'; -analn1 = structures.(profilerType).Analn1'; -battery = structures.(profilerType).Battery'; -analn2 = structures.(profilerType).Analn2'; -heading = structures.(profilerType).Heading'; -pitch = structures.(profilerType).Pitch'; -roll = structures.(profilerType).Roll'; -status = structures.(profilerType).Status'; -pressure = structures.(profilerType).PressureMSB'*65536 + structures.(profilerType).PressureLSW'; -temperature = structures.(profilerType).Temperature'; -velocity1 = structures.(profilerType).Vel1'; -velocity2 = structures.(profilerType).Vel2'; -velocity3 = structures.(profilerType).Vel3'; -backscatter1 = structures.(profilerType).Amp1'; -backscatter2 = structures.(profilerType).Amp2'; -backscatter3 = structures.(profilerType).Amp3'; +time = [structures.(profilerType)(:).Time]'; +analn1 = [structures.(profilerType)(:).Analn1]'; +battery = [structures.(profilerType)(:).Battery]'; +analn2 = [structures.(profilerType)(:).Analn2]'; +heading = [structures.(profilerType)(:).Heading]'; +pitch = [structures.(profilerType)(:).Pitch]'; +roll = [structures.(profilerType)(:).Roll]'; +status = [structures.(profilerType)(:).Status]'; +pressure = [structures.(profilerType)(:).PressureMSB]'*65536 + [structures.(profilerType)(:).PressureLSW]'; +temperature = [structures.(profilerType)(:).Temperature]'; +velocity1 = [structures.(profilerType)(:).Vel1]'; +velocity2 = [structures.(profilerType)(:).Vel2]'; +velocity3 = [structures.(profilerType)(:).Vel3]'; +backscatter1 = [structures.(profilerType)(:).Amp1]'; +backscatter2 = [structures.(profilerType)(:).Amp2]'; +backscatter3 = [structures.(profilerType)(:).Amp3]'; if velocityProcessed % velocity has been processed - timeProc = structures.Id106.Time'; + timeProc = [structures.Id106(:).Time]'; iCommonTime = ismember(time, timeProc); % timeProc can be shorter than time - velocity1Proc(iCommonTime, :) = structures.Id106.Vel1'; % tilt effect corrected velocity - velocity2Proc(iCommonTime, :) = structures.Id106.Vel2'; - velocity3Proc(iCommonTime, :) = structures.Id106.Vel3'; - sig2noise1(iCommonTime, :) = structures.Id106.Snr1'; - sig2noise2(iCommonTime, :) = structures.Id106.Snr2'; - sig2noise3(iCommonTime, :) = structures.Id106.Snr3'; - stdDev1(iCommonTime, :) = structures.Id106.Std1'; % currently not used - stdDev2(iCommonTime, :) = structures.Id106.Std2'; - stdDev3(iCommonTime, :) = structures.Id106.Std3'; - errorCode1(iCommonTime, :) = structures.Id106.Erc1'; % error codes for each cell in one beam, values between 0 and 4. - errorCode2(iCommonTime, :) = structures.Id106.Erc2'; - errorCode3(iCommonTime, :) = structures.Id106.Erc3'; - speed(iCommonTime, :) = structures.Id106.speed'; - direction(iCommonTime, :) = structures.Id106.direction'; - verticalDist(iCommonTime, :) = structures.Id106.verticalDistance'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. - profileErrorCode(iCommonTime, :) = structures.Id106.profileErrorCode'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 - qcFlag(iCommonTime, :) = structures.Id106.qcFlag'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. + velocity1Proc(iCommonTime, :) = [structures.Id106(:).Vel1]'; % tilt effect corrected velocity + velocity2Proc(iCommonTime, :) = [structures.Id106(:).Vel2]'; + velocity3Proc(iCommonTime, :) = [structures.Id106(:).Vel3]'; + sig2noise1(iCommonTime, :) = [structures.Id106(:).Snr1]'; + sig2noise2(iCommonTime, :) = [structures.Id106(:).Snr2]'; + sig2noise3(iCommonTime, :) = [structures.Id106(:).Snr3]'; + stdDev1(iCommonTime, :) = [structures.Id106(:).Std1]'; % currently not used + stdDev2(iCommonTime, :) = [structures.Id106(:).Std2]'; + stdDev3(iCommonTime, :) = [structures.Id106(:).Std3]'; + errorCode1(iCommonTime, :) = [structures.Id106(:).Erc1]'; % error codes for each cell in one beam, values between 0 and 4. + errorCode2(iCommonTime, :) = [structures.Id106(:).Erc2]'; + errorCode3(iCommonTime, :) = [structures.Id106(:).Erc3]'; + speed(iCommonTime, :) = [structures.Id106(:).speed]'; + direction(iCommonTime, :) = [structures.Id106(:).direction]'; + verticalDist(iCommonTime, :) = [structures.Id106(:).verticalDistance]'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. + profileErrorCode(iCommonTime, :) = [structures.Id106(:).profileErrorCode]'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 + qcFlag(iCommonTime, :) = [structures.Id106(:).qcFlag]'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. end clear structures; diff --git a/Parser/aquadoppVelocityParse.m b/Parser/aquadoppVelocityParse.m index 54755e414..d5f3b0665 100644 --- a/Parser/aquadoppVelocityParse.m +++ b/Parser/aquadoppVelocityParse.m @@ -60,26 +60,6 @@ % the rest of the sections are aquadopp velocity data, diagnostic header % and diagnostic data. We will only keep the velocity data (Id == 1) . -nsamples = length(structures.Id1); -ncells = user.NBins; - -% preallocate memory for all sample data -time = zeros(nsamples, 1); -distance = zeros(ncells, 1); -analn1 = zeros(nsamples, 1); -battery = zeros(nsamples, 1); -analn2 = zeros(nsamples, 1); -heading = zeros(nsamples, 1); -pitch = zeros(nsamples, 1); -roll = zeros(nsamples, 1); -pressure = zeros(nsamples, 1); -temperature = zeros(nsamples, 1); -velocity1 = zeros(nsamples, ncells); -velocity2 = zeros(nsamples, ncells); -velocity3 = zeros(nsamples, ncells); -backscatter1 = zeros(nsamples, ncells); -backscatter2 = zeros(nsamples, ncells); -backscatter3 = zeros(nsamples, ncells); % % calculate distance values from metadata. See continentalParse.m @@ -90,6 +70,7 @@ freq = head.Frequency; % this is in KHz cellStart = user.T2; % counts cellLength = user.BinLength; % counts +ncells = user.NBins; factor = 0; % used for conversion switch freq @@ -100,9 +81,9 @@ cellStart = cellStart * 0.0229 * cos(25 * pi / 180) - cellLength; % generate distance values -distance(:) = (cellStart): ... - (cellLength): ... - (cellStart + (ncells-1) * cellLength); +distance = (cellStart: ... + cellLength: ... + cellStart + (ncells-1) * cellLength)'; % Note this is actually the distance between the ADCP's transducers and the % middle of each cell @@ -112,21 +93,21 @@ distance = distance + cellLength; % retrieve sample data -time = structures.Id1.Time'; -analn1 = structures.Id1.Analn1'; -battery = structures.Id1.Battery'; -analn2 = structures.Id1.Analn2'; -heading = structures.Id1.Heading'; -pitch = structures.Id1.Pitch'; -roll = structures.Id1.Roll'; -pressure = structures.Id1.PressureMSB'*65536 + structures.Id1.PressureLSW'; -temperature = structures.Id1.Temperature'; -velocity1 = structures.Id1.Vel1'; -velocity2 = structures.Id1.Vel2'; -velocity3 = structures.Id1.Vel3'; -backscatter1 = structures.Id1.Amp1'; -backscatter2 = structures.Id1.Amp2'; -backscatter3 = structures.Id1.Amp3'; +time = [structures.Id1(:).Time]'; +analn1 = [structures.Id1(:).Analn1]'; +battery = [structures.Id1(:).Battery]'; +analn2 = [structures.Id1(:).Analn2]'; +heading = [structures.Id1(:).Heading]'; +pitch = [structures.Id1(:).Pitch]'; +roll = [structures.Id1(:).Roll]'; +pressure = [structures.Id1(:).PressureMSB]'*65536 + [structures.Id1(:).PressureLSW]'; +temperature = [structures.Id1(:).Temperature]'; +velocity1 = [structures.Id1(:).Vel1]'; +velocity2 = [structures.Id1(:).Vel2]'; +velocity3 = [structures.Id1(:).Vel3]'; +backscatter1 = [structures.Id1(:).Amp1]'; +backscatter2 = [structures.Id1(:).Amp2]'; +backscatter3 = [structures.Id1(:).Amp3]'; clear structures; % battery / 10.0 (0.1 V -> V) diff --git a/Parser/awacParse.m b/Parser/awacParse.m index f2ac5ed33..dd46adda6 100644 --- a/Parser/awacParse.m +++ b/Parser/awacParse.m @@ -72,51 +72,11 @@ user = structures.Id0; % the rest of the sections are awac data -nsamples = length(structures.Id32); -ncells = user.NBins; - -% preallocate memory for all sample data -time = nan(nsamples, 1); -distance = nan(ncells, 1); -analn1 = nan(nsamples, 1); -battery = nan(nsamples, 1); -analn2 = nan(nsamples, 1); -heading = nan(nsamples, 1); -pitch = nan(nsamples, 1); -roll = nan(nsamples, 1); -status = zeros(nsamples, 8, 'uint8'); -pressure = nan(nsamples, 1); -temperature = nan(nsamples, 1); -velocity1 = nan(nsamples, ncells); -velocity2 = nan(nsamples, ncells); -velocity3 = nan(nsamples, ncells); -backscatter1 = nan(nsamples, ncells); -backscatter2 = nan(nsamples, ncells); -backscatter3 = nan(nsamples, ncells); velocityProcessed = false; if isfield(structures, 'Id106') % velocity has been processed velocityProcessed = true; - nsamplesProc = length(structures.Id106.Sync); - timeProc = nan(nsamplesProc, 1); - velocity1Proc = nan(nsamples, ncells); - velocity2Proc = nan(nsamples, ncells); - velocity3Proc = nan(nsamples, ncells); - sig2noise1 = nan(nsamples, ncells); - sig2noise2 = nan(nsamples, ncells); - sig2noise3 = nan(nsamples, ncells); - stdDev1 = nan(nsamples, ncells); - stdDev2 = nan(nsamples, ncells); - stdDev3 = nan(nsamples, ncells); - errorCode1 = nan(nsamples, ncells); - errorCode2 = nan(nsamples, ncells); - errorCode3 = nan(nsamples, ncells); - speed = nan(nsamples, ncells); - direction = nan(nsamples, ncells); - verticalDist = nan(nsamples, ncells); - profileErrorCode = nan(nsamples, ncells); - qcFlag = nan(nsamples, ncells); end % @@ -128,6 +88,7 @@ freq = head.Frequency; % this is in KHz blankDist = user.T2; % counts cellSize = user.BinLength; % counts +ncells = user.NBins; factor = 0; % used in conversion switch freq @@ -138,9 +99,9 @@ cellSize = (cellSize / 256) * factor * cos(25 * pi / 180); blankDist = blankDist * 0.0229 * cos(25 * pi / 180) - cellSize; -distance(:) = (blankDist): ... - (cellSize): ... - (blankDist + (ncells-1) * cellSize); +distance = (blankDist: ... + cellSize: ... + blankDist + (ncells-1) * cellSize)'; % Note this is actually the distance between the ADCP's transducers and the % middle of each cell @@ -148,45 +109,45 @@ distance = distance + cellSize; % retrieve sample data -time = structures.Id32.Time'; -analn1 = structures.Id32.Analn1'; -battery = structures.Id32.Battery'; -analn2 = structures.Id32.Analn2'; -heading = structures.Id32.Heading'; -pitch = structures.Id32.Pitch'; -roll = structures.Id32.Roll'; -status = structures.Id32.Status'; -pressure = structures.Id32.PressureMSB'*65536 + structures.Id32.PressureLSW'; -temperature = structures.Id32.Temperature'; -velocity1 = structures.Id32.Vel1'; -velocity2 = structures.Id32.Vel2'; -velocity3 = structures.Id32.Vel3'; -backscatter1 = structures.Id32.Amp1'; -backscatter2 = structures.Id32.Amp2'; -backscatter3 = structures.Id32.Amp3'; +time = [structures.Id32(:).Time]'; +analn1 = [structures.Id32(:).Analn1]'; +battery = [structures.Id32(:).Battery]'; +analn2 = [structures.Id32(:).Analn2]'; +heading = [structures.Id32(:).Heading]'; +pitch = [structures.Id32(:).Pitch]'; +roll = [structures.Id32(:).Roll]'; +status = [structures.Id32(:).Status]'; +pressure = [structures.Id32(:).PressureMSB]'*65536 + [structures.Id32(:).PressureLSW]'; +temperature = [structures.Id32(:).Temperature]'; +velocity1 = [structures.Id32(:).Vel1]'; +velocity2 = [structures.Id32(:).Vel2]'; +velocity3 = [structures.Id32(:).Vel3]'; +backscatter1 = [structures.Id32(:).Amp1]'; +backscatter2 = [structures.Id32(:).Amp2]'; +backscatter3 = [structures.Id32(:).Amp3]'; if velocityProcessed % velocity has been processed - timeProc = structures.Id106.Time'; + timeProc = [structures.Id106(:).Time]'; iCommonTime = ismember(time, timeProc); % timeProc can be shorter than time - velocity1Proc(iCommonTime, :) = structures.Id106.Vel1'; % tilt effect corrected velocity - velocity2Proc(iCommonTime, :) = structures.Id106.Vel2'; - velocity3Proc(iCommonTime, :) = structures.Id106.Vel3'; - sig2noise1(iCommonTime, :) = structures.Id106.Snr1'; - sig2noise2(iCommonTime, :) = structures.Id106.Snr2'; - sig2noise3(iCommonTime, :) = structures.Id106.Snr3'; - stdDev1(iCommonTime, :) = structures.Id106.Std1'; % currently not used - stdDev2(iCommonTime, :) = structures.Id106.Std2'; - stdDev3(iCommonTime, :) = structures.Id106.Std3'; - errorCode1(iCommonTime, :) = structures.Id106.Erc1'; % error codes for each cell in one beam, values between 0 and 4. - errorCode2(iCommonTime, :) = structures.Id106.Erc2'; - errorCode3(iCommonTime, :) = structures.Id106.Erc3'; - speed(iCommonTime, :) = structures.Id106.speed'; - direction(iCommonTime, :) = structures.Id106.direction'; - verticalDist(iCommonTime, :) = structures.Id106.verticalDistance'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. - profileErrorCode(iCommonTime, :) = structures.Id106.profileErrorCode'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 - qcFlag(iCommonTime, :) = structures.Id106.qcFlag'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. + velocity1Proc(iCommonTime, :) = [structures.Id106(:).Vel1]'; % tilt effect corrected velocity + velocity2Proc(iCommonTime, :) = [structures.Id106(:).Vel2]'; + velocity3Proc(iCommonTime, :) = [structures.Id106(:).Vel3]'; + sig2noise1(iCommonTime, :) = [structures.Id106(:).Snr1]'; + sig2noise2(iCommonTime, :) = [structures.Id106(:).Snr2]'; + sig2noise3(iCommonTime, :) = [structures.Id106(:).Snr3]'; + stdDev1(iCommonTime, :) = [structures.Id106(:).Std1]'; % currently not used + stdDev2(iCommonTime, :) = [structures.Id106(:).Std2]'; + stdDev3(iCommonTime, :) = [structures.Id106(:).Std3]'; + errorCode1(iCommonTime, :) = [structures.Id106(:).Erc1]'; % error codes for each cell in one beam, values between 0 and 4. + errorCode2(iCommonTime, :) = [structures.Id106(:).Erc2]'; + errorCode3(iCommonTime, :) = [structures.Id106(:).Erc3]'; + speed(iCommonTime, :) = [structures.Id106(:).speed]'; + direction(iCommonTime, :) = [structures.Id106(:).direction]'; + verticalDist(iCommonTime, :) = [structures.Id106(:).verticalDistance]'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. + profileErrorCode(iCommonTime, :) = [structures.Id106(:).profileErrorCode]'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 + qcFlag(iCommonTime, :) = [structures.Id106(:).qcFlag]'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. end clear structures; diff --git a/Parser/continentalParse.m b/Parser/continentalParse.m index 441719aed..00ac0bb86 100644 --- a/Parser/continentalParse.m +++ b/Parser/continentalParse.m @@ -63,51 +63,10 @@ % the rest of the sections are continental data (which have % the same structure as awac velocity profile data sections). -nsamples = length(structures.Id36.Sync); -ncells = user.NBins; - -% preallocate memory for all sample data -time = nan(nsamples, 1); -distance = nan(ncells, 1); -analn1 = nan(nsamples, 1); -battery = nan(nsamples, 1); -analn2 = nan(nsamples, 1); -heading = nan(nsamples, 1); -pitch = nan(nsamples, 1); -roll = nan(nsamples, 1); -status = zeros(nsamples, 8, 'uint8'); -pressure = nan(nsamples, 1); -temperature = nan(nsamples, 1); -velocity1 = nan(nsamples, ncells); -velocity2 = nan(nsamples, ncells); -velocity3 = nan(nsamples, ncells); -backscatter1 = nan(nsamples, ncells); -backscatter2 = nan(nsamples, ncells); -backscatter3 = nan(nsamples, ncells); - velocityProcessed = false; if isfield(structures, 'Id106') % velocity has been processed velocityProcessed = true; - nsamplesProc = length(structures.Id106.Sync); - timeProc = nan(nsamplesProc, 1); - velocity1Proc = nan(nsamples, ncells); - velocity2Proc = nan(nsamples, ncells); - velocity3Proc = nan(nsamples, ncells); - sig2noise1 = nan(nsamples, ncells); - sig2noise2 = nan(nsamples, ncells); - sig2noise3 = nan(nsamples, ncells); - stdDev1 = nan(nsamples, ncells); - stdDev2 = nan(nsamples, ncells); - stdDev3 = nan(nsamples, ncells); - errorCode1 = nan(nsamples, ncells); - errorCode2 = nan(nsamples, ncells); - errorCode3 = nan(nsamples, ncells); - speed = nan(nsamples, ncells); - direction = nan(nsamples, ncells); - verticalDist = nan(nsamples, ncells); - profileErrorCode = nan(nsamples, ncells); - qcFlag = nan(nsamples, ncells); end % @@ -129,6 +88,7 @@ freq = head.Frequency; % this is in KHz blankDist = user.T2; % counts cellSize = user.BinLength; % counts +ncells = user.NBins; factor = 0; % used for conversion switch freq @@ -140,9 +100,9 @@ blankDist = blankDist * 0.0229 * cos(25 * pi / 180) - cellSize; % generate distance values -distance(:) = (blankDist): ... - (cellSize): ... - (blankDist + (ncells-1) * cellSize); +distance = (blankDist: ... + cellSize: ... + blankDist + (ncells-1) * cellSize)'; % Note this is actually the distance between the ADCP's transducers and the % middle of each cell along the beams axis (no tilt correction applied) @@ -150,45 +110,45 @@ distance = distance + cellSize; % retrieve sample data -time = structures.Id36.Time'; -analn1 = structures.Id36.Analn1'; -battery = structures.Id36.Battery'; -analn2 = structures.Id36.Analn2'; -heading = structures.Id36.Heading'; -pitch = structures.Id36.Pitch'; -roll = structures.Id36.Roll'; -status = structures.Id36.Status'; -pressure = structures.Id36.PressureMSB'*65536 + structures.Id36.PressureLSW'; -temperature = structures.Id36.Temperature'; -velocity1 = structures.Id36.Vel1'; -velocity2 = structures.Id36.Vel2'; -velocity3 = structures.Id36.Vel3'; -backscatter1 = structures.Id36.Amp1'; -backscatter2 = structures.Id36.Amp2'; -backscatter3 = structures.Id36.Amp3'; +time = [structures.Id36(:).Time]'; +analn1 = [structures.Id36(:).Analn1]'; +battery = [structures.Id36(:).Battery]'; +analn2 = [structures.Id36(:).Analn2]'; +heading = [structures.Id36(:).Heading]'; +pitch = [structures.Id36(:).Pitch]'; +roll = [structures.Id36(:).Roll]'; +status = [structures.Id36(:).Status]'; +pressure = [structures.Id36(:).PressureMSB]'*65536 + [structures.Id36(:).PressureLSW]'; +temperature = [structures.Id36(:).Temperature]'; +velocity1 = [structures.Id36(:).Vel1]'; +velocity2 = [structures.Id36(:).Vel2]'; +velocity3 = [structures.Id36(:).Vel3]'; +backscatter1 = [structures.Id36(:).Amp1]'; +backscatter2 = [structures.Id36(:).Amp2]'; +backscatter3 = [structures.Id36(:).Amp3]'; if velocityProcessed % velocity has been processed - timeProc = structures.Id106.Time'; + timeProc = [structures.Id106(:).Time]'; iCommonTime = ismember(time, timeProc); % timeProc can be shorter than time - velocity1Proc(iCommonTime, :) = structures.Id106.Vel1'; % tilt effect corrected velocity - velocity2Proc(iCommonTime, :) = structures.Id106.Vel2'; - velocity3Proc(iCommonTime, :) = structures.Id106.Vel3'; - sig2noise1(iCommonTime, :) = structures.Id106.Snr1'; - sig2noise2(iCommonTime, :) = structures.Id106.Snr2'; - sig2noise3(iCommonTime, :) = structures.Id106.Snr3'; - stdDev1(iCommonTime, :) = structures.Id106.Std1'; % currently not used - stdDev2(iCommonTime, :) = structures.Id106.Std2'; - stdDev3(iCommonTime, :) = structures.Id106.Std3'; - errorCode1(iCommonTime, :) = structures.Id106.Erc1'; % error codes for each cell in one beam, values between 0 and 4. - errorCode2(iCommonTime, :) = structures.Id106.Erc2'; - errorCode3(iCommonTime, :) = structures.Id106.Erc3'; - speed(iCommonTime, :) = structures.Id106.speed'; - direction(iCommonTime, :) = structures.Id106.direction'; - verticalDist(iCommonTime, :) = structures.Id106.verticalDistance'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. - profileErrorCode(iCommonTime, :) = structures.Id106.profileErrorCode'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 - qcFlag(iCommonTime, :) = structures.Id106.qcFlag'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. + velocity1Proc(iCommonTime, :) = [structures.Id106(:).Vel1]'; % tilt effect corrected velocity + velocity2Proc(iCommonTime, :) = [structures.Id106(:).Vel2]'; + velocity3Proc(iCommonTime, :) = [structures.Id106(:).Vel3]'; + sig2noise1(iCommonTime, :) = [structures.Id106(:).Snr1]'; + sig2noise2(iCommonTime, :) = [structures.Id106(:).Snr2]'; + sig2noise3(iCommonTime, :) = [structures.Id106(:).Snr3]'; + stdDev1(iCommonTime, :) = [structures.Id106(:).Std1]'; % currently not used + stdDev2(iCommonTime, :) = [structures.Id106(:).Std2]'; + stdDev3(iCommonTime, :) = [structures.Id106(:).Std3]'; + errorCode1(iCommonTime, :) = [structures.Id106(:).Erc1]'; % error codes for each cell in one beam, values between 0 and 4. + errorCode2(iCommonTime, :) = [structures.Id106(:).Erc2]'; + errorCode3(iCommonTime, :) = [structures.Id106(:).Erc3]'; + speed(iCommonTime, :) = [structures.Id106(:).speed]'; + direction(iCommonTime, :) = [structures.Id106(:).direction]'; + verticalDist(iCommonTime, :) = [structures.Id106(:).verticalDistance]'; % ? no idea what this is, always same values between 6000 and 65534 for each profile. + profileErrorCode(iCommonTime, :) = [structures.Id106(:).profileErrorCode]'; % error codes for each cell of a velocity profile inferred from the 3 beams. 0=good; otherwise error. See http://www.nortek-as.com/en/knowledge-center/forum/waves/20001875?b_start=0#769595815 + qcFlag(iCommonTime, :) = [structures.Id106(:).qcFlag]'; % QUARTOD QC result. 0=not eval; 1=bad; 2=questionable; 3=good. end clear structures; diff --git a/Parser/readAD2CPBinary.m b/Parser/readAD2CPBinary.m index 0dca0599b..0cb9f5009 100644 --- a/Parser/readAD2CPBinary.m +++ b/Parser/readAD2CPBinary.m @@ -76,6 +76,14 @@ structures = struct; [~, ~, cpuEndianness] = computer; +% the while loop below involves poor performances so we display a waitbar +% dialog to make sure the user knows the toolbox is doing something +[~, fName, ext] = fileparts(filename); +lastStepProgress = 0; +hWaitbar = waitbar(lastStepProgress, ' 0 %', ... + 'Name', ['Reading file ' fName ext],... + 'DefaultTextInterpreter', 'none'); + while dIdx < dataLen [sect, len] = readSection(filename, data, dIdx, cpuEndianness); @@ -100,9 +108,22 @@ end end + % we don't want to update the waitbar for every single section (too + % slow) instead we update it every percent of a step + progress = dIdx/dataLen; + percentProgress = floor(progress * 100); + stepProgress = percentProgress/100; + if stepProgress > lastStepProgress + lastStepProgress = stepProgress; + waitbar(stepProgress, hWaitbar, [sprintf('%3u', percentProgress) ' %']); + end + dIdx = dIdx + len; % if len is empty, then dIdx is going to be empty and will fail the while test end +waitbar(1, hWaitbar, '100 %'); +close(hWaitbar); + return; end @@ -141,15 +162,15 @@ id = dec2hex(data(idx+2)); switch id case '15' - [sect, len, off] = readBurstAverage (data, idx, cpuEndianness); % 0x15 + [sect, ~, off] = readBurstAverage (data, idx, cpuEndianness); % 0x15 case '16' - [sect, len, off] = readBurstAverage (data, idx, cpuEndianness); % 0x16 + [sect, ~, off] = readBurstAverage (data, idx, cpuEndianness); % 0x16 case '17' - [sect, len, off] = readBottomTrack (data, idx, cpuEndianness); % 0x17 + [sect, ~, off] = readBottomTrack (data, idx, cpuEndianness); % 0x17 case '18' - [sect, len, off] = readBurstAverage (data, idx, cpuEndianness); % 0x18 + [sect, ~, off] = readBurstAverage (data, idx, cpuEndianness); % 0x18 case 'A0' - [sect, len, off] = readString (data, idx, cpuEndianness); % 0xA0 + [sect, ~, off] = readString (data, idx, cpuEndianness); % 0xA0 otherwise disp('Unknown section type'); disp(['ID : hex ' id ' at offset ' num2str(idx+2)]); @@ -298,7 +319,6 @@ if isCorrelation sect.CorrelationData = reshape(bytecast(data(idx+off+1:idx+off+sect.nBeams*sect.nCells), 'L', 'uint8', cpuEndianness), sect.nCells, sect.nBeams)'; % [0-100] - off = off+sect.nBeams*sect.nCells; end end @@ -367,7 +387,6 @@ if isCorrelation sect.CorrelationData = reshape(bytecast(data(idx+off+1:idx+off+sect.nBeams*sect.nCells), 'L', 'uint8', cpuEndianness), sect.nCells, sect.nBeams)'; % [0-100] - off = off+sect.nBeams*sect.nCells; end end @@ -467,7 +486,6 @@ sect.ASTPressure = bytecast(data(idx+off+1:idx+off+4), 'L', 'single', cpuEndianness); % dbar off = off + 4; sect.ASTSpare = bytecast(data(idx+off+1:idx+off+8), 'L', 'int8', cpuEndianness); % spare - off = off + 8; end end @@ -477,13 +495,10 @@ % Id=0x17, Bottom Track Data Record sect = struct; -[sect.Header, len, off] = readHeader(data, idx, cpuEndianness); +[sect.Header, ~, off] = readHeader(data, idx, cpuEndianness); idx = idx+off; -len = len + sect.Header.DataSize; -off = len; - sect.Data.Version = bytecast(data(idx), 'L', 'uint8', cpuEndianness); sect.Data.OffsetOfData = bytecast(data(idx+1), 'L', 'uint8', cpuEndianness); sect.Data.Configuration = dec2bin(bytecast(data(idx+2:idx+3), 'L', 'uint16', cpuEndianness), 16); @@ -541,7 +556,6 @@ if isFigureOfMerit sect.FigureOfMeritData = bytecast(data(idx+off+1:idx+off+sect.nBeams*2), 'L', 'uint16', cpuEndianness); - off = off+sect.nBeams*2; end end diff --git a/Parser/readParadoppBinary.m b/Parser/readParadoppBinary.m index ca5870d9b..c5ca3c172 100644 --- a/Parser/readParadoppBinary.m +++ b/Parser/readParadoppBinary.m @@ -93,66 +93,46 @@ structures = struct; [~, ~, cpuEndianness] = computer; -% list of Ids that have variables that can vary in size, so cannot just -% concatenate them -specialIds{1}.id = 'Id66'; -specialIds{1}.vars = { 'Amp' }; -specialIds{2}.id = 'Id98'; -specialIds{2}.vars = { 'Energy' }; +% the while loop below involves poor performances so we display a waitbar +% dialog to make sure the user knows the toolbox is doing something +[~, fName, ext] = fileparts(filename); +lastStepProgress = 0; +hWaitbar = waitbar(lastStepProgress, ' 0 %', ... + 'Name', ['Reading file ' fName ext],... + 'DefaultTextInterpreter', 'none'); while dIdx < dataLen [sect, len] = readSection(filename, data, dIdx, cpuEndianness); if ~isempty(sect) curField = ['Id' sprintf('%d', sect.Id)]; - theFieldNames = fieldnames(sect); - nField = length(theFieldNames); - - iSpecialId = cellfun(@(x) strcmp(curField, x.id), specialIds); - notSpecial = false; - if all(~iSpecialId) - notSpecial = true; - else - specialId = specialIds{iSpecialId}; - specialVars = specialId.vars; - iSpecialVars = logical(cell2mat(cellfun(@(x) any(strcmp(x, specialVars)), theFieldNames, 'UniformOutput', false))); - end if ~isfield(structures, curField) % copy first instance of IdX structure - if notSpecial - structures.(curField) = sect; - else - for i=1:nField - if ~iSpecialVars(i) - structures.(curField).(theFieldNames{i}) = sect.(theFieldNames{i}); - else - structures.(curField).(theFieldNames{i}){1} = sect.(theFieldNames{i}); - end - end - end + structures.(curField) = sect; else % append current IdX structure to existing % no pre-allocation is still faster than allocating more than needed and then removing the excess - if notSpecial - for i=1:nField - structures.(curField).(theFieldNames{i})(:, end+1) = sect.(theFieldNames{i}); - end - else - for i=1:nField - if ~iSpecialVars(i) - structures.(curField).(theFieldNames{i})(:, end+1) = sect.(theFieldNames{i}); - else - structures.(curField).(theFieldNames{i}){end+1} = sect.(theFieldNames{i}); - end - end - end + structures.(curField)(end+1) = sect; end end + % we don't want to update the waitbar for every single section (too + % slow) instead we update it every percent of a step + progress = dIdx/dataLen; + percentProgress = floor(progress * 100); + stepProgress = percentProgress/100; + if stepProgress > lastStepProgress + lastStepProgress = stepProgress; + waitbar(stepProgress, hWaitbar, [sprintf('%3u', percentProgress) ' %']); + end + dIdx = dIdx + len; % if len is empty, then dIdx is going to be empty and will fail the while test end +waitbar(1, hWaitbar, '100 %'); +close(hWaitbar); + return; end @@ -1176,13 +1156,12 @@ function [sect, len, off] = readGeneric(data, idx, cpuEndianness) %READGENERIC Skip past an unknown sector type -Sync = data(idx); Id = data(idx+1); Size = bytecast(data(idx+2:idx+3), 'L', 'uint16', cpuEndianness); len = Size * 2; off = len; sect = []; -%warning(['Skipping sector type ' num2str(Id) ' at ' num2str(idx) ' size ' num2str(Size)]); + disp(['Skipping sector type ' num2str(Id) ' at ' num2str(idx) ' size ' num2str(Size)]); end diff --git a/Parser/readWorkhorseEnsembles.m b/Parser/readWorkhorseEnsembles.m index b2442a096..35f2913cc 100644 --- a/Parser/readWorkhorseEnsembles.m +++ b/Parser/readWorkhorseEnsembles.m @@ -218,7 +218,6 @@ igood = (nBytes == nBytes0(1)); idx = idx(igood); - nBytes = nBytes(igood); else error('This file looks corrupted. Try open it with WinADCP and save it again.'); end @@ -344,7 +343,7 @@ end -function [sect len] = parseFixedLeader(data, idx, cpuEndianness) +function [sect, len] = parseFixedLeader(data, idx, cpuEndianness) %PARSEFIXEDLEADER Parses a fixed leader section from an ADCP ensemble. % % Inputs: @@ -451,7 +450,7 @@ end end -function [sect len] = parseVariableLeader( data, idx, cpuEndianness ) +function [sect, len] = parseVariableLeader( data, idx, cpuEndianness ) %PARSEVARIABLELEADER Parses a variable leader section from an ADCP ensemble. % % Inputs: @@ -555,7 +554,7 @@ sect.y2kHundredth = double(data(idx+64)); end -function [sect len] = parseVelocity( data, numCells, idx, cpuEndianness ) +function [sect, len] = parseVelocity( data, numCells, idx, cpuEndianness ) %PARSEVELOCITY Parses a velocity section from an ADCP ensemble. % % Inputs: @@ -588,7 +587,7 @@ end -function [sect len] = parseX( data, numCells, name, idx, cpuEndianness ) +function [sect, len] = parseX( data, numCells, name, idx, cpuEndianness ) %PARSEX Parses one of the correlation magnitude, echo intensity or percent % good sections from an ADCP ensemble. They all have the same format. % @@ -624,7 +623,7 @@ end -function [sect length] = parseBottomTrack( data, idx, cpuEndianness ) +function [sect, length] = parseBottomTrack( data, idx, cpuEndianness ) %PARSEBOTTOMTRACK Parses a bottom track data section from an ADCP % ensemble. % diff --git a/Parser/workhorseParse.m b/Parser/workhorseParse.m index bdc762c05..e5319beb7 100644 --- a/Parser/workhorseParse.m +++ b/Parser/workhorseParse.m @@ -125,9 +125,9 @@ % note this is actually distance between the ADCP's transducers and the % middle of each cell - distance = (cellStart): ... - (cellLength): ... - (cellStart + (numCells-1) * cellLength); + distance = (cellStart: ... + cellLength: ... + cellStart + (numCells-1) * cellLength)'; % rearrange the sample data time = datenum(... @@ -276,8 +276,8 @@ iWellOriented = adcpOrientations == adcpOrientation; % we'll only keep data collected when ADCP is oriented as expected dims = { 'TIME', time(iWellOriented), ['Time stamp corresponds to the start of the measurement which lasts ' num2str(sample_data.meta.instrument_average_interval) ' seconds.']; ... - 'HEIGHT_ABOVE_SENSOR', height(:), 'Data has been vertically bin-mapped using tilt information so that the cells have consistant heights above sensor in time.'; ... - 'DIST_ALONG_BEAMS', distance(:), 'Data is not vertically bin-mapped (no tilt correction applied). Cells are lying parallel to the beams, at heights above sensor that vary with tilt.' + 'HEIGHT_ABOVE_SENSOR', height, 'Data has been vertically bin-mapped using tilt information so that the cells have consistant heights above sensor in time.'; ... + 'DIST_ALONG_BEAMS', distance, 'Data is not vertically bin-mapped (no tilt correction applied). Cells are lying parallel to the beams, at heights above sensor that vary with tilt.' }; clear time height distance; @@ -530,12 +530,4 @@ direction(se) = 180 - direction(se); direction(sw) = 180 + direction(sw); direction(nw) = 360 - direction(nw); -end - -function angle = make0To360(angle) - iLower = angle < 0; - angle(iLower) = 360 + angle(iLower); - - iHigher = angle >= 360; - angle(iHigher) = angle(iHigher) - 360; end \ No newline at end of file diff --git a/Preprocessing/adcpBinMappingPP.m b/Preprocessing/adcpBinMappingPP.m index 20d2fc542..e0ff13676 100644 --- a/Preprocessing/adcpBinMappingPP.m +++ b/Preprocessing/adcpBinMappingPP.m @@ -106,7 +106,7 @@ % while beams 2 and 3 get further away. When roll is positive beam 3 is % closer to the surface while beam 2 gets further away. % - distAlongBeams = sample_data{k}.dimensions{distAlongBeamsIdx}.data; + distAlongBeams = sample_data{k}.dimensions{distAlongBeamsIdx}.data'; pitch = sample_data{k}.variables{pitchIdx}.data*pi/180; roll = sample_data{k}.variables{rollIdx}.data*pi/180; @@ -115,34 +115,34 @@ if isRDI % RDI 4 beams - nonMappedHeightAboveSensorBeam1 = (cos(beamAngle + roll)/cos(beamAngle)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam1 = (cos(beamAngle + roll)/cos(beamAngle)) * distAlongBeams; nonMappedHeightAboveSensorBeam1 = repmat(cos(pitch), 1, nBins) .* nonMappedHeightAboveSensorBeam1; - nonMappedHeightAboveSensorBeam2 = (cos(beamAngle - roll)/cos(beamAngle)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam2 = (cos(beamAngle - roll)/cos(beamAngle)) * distAlongBeams; nonMappedHeightAboveSensorBeam2 = repmat(cos(pitch), 1, nBins) .* nonMappedHeightAboveSensorBeam2; - nonMappedHeightAboveSensorBeam3 = (cos(beamAngle - pitch)/cos(beamAngle)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam3 = (cos(beamAngle - pitch)/cos(beamAngle)) * distAlongBeams; nonMappedHeightAboveSensorBeam3 = repmat(cos(roll), 1, nBins) .* nonMappedHeightAboveSensorBeam3; - nonMappedHeightAboveSensorBeam4 = (cos(beamAngle + pitch)/cos(beamAngle)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam4 = (cos(beamAngle + pitch)/cos(beamAngle)) * distAlongBeams; nonMappedHeightAboveSensorBeam4 = repmat(cos(roll), 1, nBins) .* nonMappedHeightAboveSensorBeam4; else % Nortek 3 beams - nonMappedHeightAboveSensorBeam1 = (cos(beamAngle - pitch)/cos(beamAngle)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam1 = (cos(beamAngle - pitch)/cos(beamAngle)) * distAlongBeams; nonMappedHeightAboveSensorBeam1 = repmat(cos(roll), 1, nBins) .* nonMappedHeightAboveSensorBeam1; beamAngleX = atan(tan(beamAngle) * cos(60*pi/180)); % beams 2 and 3 angle projected on the X axis beamAngleY = atan(tan(beamAngle) * cos(30*pi/180)); % beams 2 and 3 angle projected on the Y axis - nonMappedHeightAboveSensorBeam2 = (cos(beamAngleX + pitch)/cos(beamAngleX)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam2 = (cos(beamAngleX + pitch)/cos(beamAngleX)) * distAlongBeams; nonMappedHeightAboveSensorBeam2 = repmat(cos(beamAngleY + roll)/cos(beamAngleY), 1, nBins) .* nonMappedHeightAboveSensorBeam2; - nonMappedHeightAboveSensorBeam3 = (cos(beamAngleX + pitch)/cos(beamAngleX)) * distAlongBeams'; + nonMappedHeightAboveSensorBeam3 = (cos(beamAngleX + pitch)/cos(beamAngleX)) * distAlongBeams; nonMappedHeightAboveSensorBeam3 = repmat(cos(beamAngleY - roll)/cos(beamAngleY), 1, nBins) .* nonMappedHeightAboveSensorBeam3; end nSamples = length(pitch); - mappedHeightAboveSensor = repmat(distAlongBeams', nSamples, 1); + mappedHeightAboveSensor = repmat(distAlongBeams, nSamples, 1); % we can now interpolate mapped values per bin when needed for each % impacted parameter diff --git a/Preprocessing/depthPP.m b/Preprocessing/depthPP.m index e1b6442d9..f40ff62a7 100644 --- a/Preprocessing/depthPP.m +++ b/Preprocessing/depthPP.m @@ -1,6 +1,6 @@ function sample_data = depthPP( sample_data, qcLevel, auto ) %DEPTHPP Adds a depth variable to the given data sets, if they contain a -% pressure variable. +% pressure variable or if there are neighbouring pressure sensor on their same mooring. % % This function uses the Gibbs-SeaWater toolbox (TEOS-10) to derive depth data % from pressure. It adds the depth data as a new variable in the data sets. @@ -66,6 +66,33 @@ % local time to UTC conversion if strcmpi(qcLevel, 'raw'), return; end +% get the toolbox execution mode +mode = readProperty('toolbox.mode'); +switch mode + case 'profile' + depthVarType = 'dimensions'; + + otherwise + depthVarType = 'variables'; + +end + +% check wether height or target depth information is documented +isSensorHeight = false; +isSensorTargetDepth = false; + +if isfield(sample_data{1}, 'instrument_nominal_height') + if ~isempty(sample_data{1}.instrument_nominal_height) + isSensorHeight = true; + end +end + +if isfield(sample_data{1}, 'instrument_nominal_depth') + if ~isempty(sample_data{1}.instrument_nominal_depth) + isSensorTargetDepth = true; + end +end + % read options from parameter file depthFile = ['Preprocessing' filesep 'depthPP.txt']; same_family = readProperty('same_family', depthFile, ','); @@ -87,213 +114,479 @@ exclude = exclude{1}; end -% check wether height or target depth information is documented -isSensorHeight = false; -isSensorTargetDepth = false; +%% loop on every data sets and find out default choices +nDatasets = length(sample_data); -if isfield(sample_data{1}, 'instrument_nominal_height') - if ~isempty(sample_data{1}.instrument_nominal_height) - isSensorHeight = true; - end -else - -end +depthIdx = zeros(nDatasets, 1); +presIdx = zeros(nDatasets, 1); +presRelIdx = zeros(nDatasets, 1); -if isfield(sample_data{1}, 'instrument_nominal_depth') - if ~isempty(sample_data{1}.instrument_nominal_depth) - isSensorTargetDepth = true; +useItsOwnDepth = false(nDatasets, 1); +useItsOwnPresRel = false(nDatasets, 1); +useItsOwnPres = false(nDatasets, 1); + +nearestInsts = cell(nDatasets, 1); +firstNearestInst = zeros(nDatasets, 1); +secondNearestInst = zeros(nDatasets, 1); + +currentPProutine = mfilename; + +for iCurSam = 1:nDatasets + % read dataset specific PP parameters if exist and override previous entries from + % parameter file depth.txt + same_family = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'same_family', same_family); % although we store / define these for each dataset, they are usually the same for a whole mooring + include = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'include', include); + exclude = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'exclude', exclude); + + % look for already existing DEPTH, PRES or PRES_REL variables + depthIdx(iCurSam) = getVar(sample_data{iCurSam}.(depthVarType), 'DEPTH'); + if depthIdx(iCurSam) + useItsOwnDepth(iCurSam) = true; end -else -end - -% loop on every data sets -for k = 1:length(sample_data) - % current data set - curSam = sample_data{k}; + presIdx(iCurSam) = getVar(sample_data{iCurSam}.variables, 'PRES'); + if presIdx(iCurSam) + useItsOwnPres(iCurSam) = true; + end - % if data set already contains depth data then next sample data - if getVar(curSam.variables, 'DEPTH'), continue; end - if getVar(curSam.dimensions, 'DEPTH'), continue; end + presRelIdx(iCurSam) = getVar(sample_data{iCurSam}.variables, 'PRES_REL'); + if presRelIdx(iCurSam) + useItsOwnPresRel(iCurSam) = true; + end - presIdx = getVar(curSam.variables, 'PRES'); - presRelIdx = getVar(curSam.variables, 'PRES_REL'); + % read dataset specific PP parameters if exist and override previous default entries + useItsOwnDepth(iCurSam) = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnDepth', useItsOwnDepth(iCurSam)); + useItsOwnPres(iCurSam) = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnPres', useItsOwnPres(iCurSam)); + useItsOwnPresRel(iCurSam) = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnPresRel', useItsOwnPresRel(iCurSam)); - % if no pressure data, try to compute it from other sensors in the - % mooring, otherwise go to next sample data - if presIdx == 0 && presRelIdx == 0 - if isSensorHeight || isSensorTargetDepth - % let's see if part of a mooring with pressure data from other - % sensors - m = 0; - otherSam = []; - % loop on every other data sets - for l = 1:length(sample_data) - sam = sample_data{l}; - - presCurIdx = getVar(sam.variables, 'PRES'); - presRelCurIdx = getVar(sam.variables, 'PRES_REL'); - - % samples without pressure information are excluded - if (presCurIdx == 0 && presRelCurIdx == 0), continue; end - - if isSensorTargetDepth - samSensorZ = sam.instrument_nominal_depth; - else - samSensorZ = sam.instrument_nominal_height; - end - - % current sample or samples without vertical nominal - % information are excluded - if l == k || isempty(samSensorZ), continue; end - + % look for nearest instruments with depth or pressure information + if isSensorHeight || isSensorTargetDepth + % let's see if part of a mooring with pressure data from other + % sensors + for iOtherSam = 1:nDatasets + % loop on every data sets to find other compatible ones + presCurIdx = getVar(sample_data{iOtherSam}.variables, 'PRES'); + presRelCurIdx = getVar(sample_data{iOtherSam}.variables, 'PRES_REL'); + + % samples without pressure information are excluded + if (presCurIdx == 0 && presRelCurIdx == 0), continue; end + + if isSensorTargetDepth + samSensorZ = sample_data{iOtherSam}.instrument_nominal_depth; + else + samSensorZ = sample_data{iOtherSam}.instrument_nominal_height; + end + + % current sample or samples without vertical nominal + % information are excluded + if iOtherSam == iCurSam || isempty(samSensorZ), continue; end + + % we look at the instrument family/ brand of the sample + samSource = textscan(sample_data{iOtherSam}.instrument, '%s'); + samSource = samSource{1}; + p = 0; + if same_family % only samples that are from the same instrument % family/brand of the current sample are selected - samSource = textscan(sam.instrument, '%s'); - samSource = samSource{1}; - p = 0; - % is from the same family - if same_family - % loop on every words composing the instrument global - % attribute of current other data set - for n = 1:length(samSource) - if ~isempty(strfind(curSam.instrument, samSource{n})) - p = 1; - end - end - else - p = 1; - end - - % loop on every words that would include current other data set - for n = 1:length(include) - % is included - if ~isempty(strfind(sam.instrument, include{n})) + for n = 1:length(samSource) + % loop on every words composing the 'instrument' global + % attribute of other sample + if ~isempty(strfind(sample_data{iCurSam}.instrument, samSource{n})) p = 1; end end - - % loop on every words that would exclude current other data set - for n = 1:length(exclude) - % is excluded - if ~isempty(strfind(sam.instrument, exclude{n})) - p = 0; - end + else + p = 1; + end + + % we look at the including option + for n = 1:length(include) + % loop on every words that would include other data set + if ~isempty(strfind(sample_data{iOtherSam}.instrument, include{n})) + p = 1; end - - if p > 0 - m = m+1; - otherSam{m} = sam; + end + + % we look at the excluding option + for n = 1:length(exclude) + % loop on every words that would exclude other data set + if ~isempty(strfind(sample_data{iOtherSam}.instrument, exclude{n})) + p = 0; end - clear sam; end - if m == 0 - fprintf('%s\n', ['Warning : ' curSam.toolbox_input_file ... - ' there is no pressure sensor on this mooring from '... - 'which an actual depth can be computed']); - continue; - else - % find the nearests pressure data - diffWithOthers = nan(m,1); - iFirst = []; - iSecond = []; - for l = 1:m - if isSensorTargetDepth - diffWithOthers(l) = curSam.instrument_nominal_depth - otherSam{l}.instrument_nominal_depth; - else - % below is reversed so that sign convention is the - % same - diffWithOthers(l) = otherSam{l}.instrument_nominal_height - curSam.instrument_nominal_height; - end + if p > 0 + nearestInsts{iCurSam}(end+1) = iOtherSam; + end + end + + if isempty(nearestInsts{iCurSam}) + % there is no neighbouring pressure sensor on this mooring from + % which an actual depth can be computed + continue; + else + nOtherSam = length(nearestInsts{iCurSam}); + % find the nearests pressure data + diffWithOthers = nan(nOtherSam, 1); + iFirst = 0; + iSecond = 0; + for iOtherSam = 1:nOtherSam + if isSensorTargetDepth + diffWithOthers(iOtherSam) = sample_data{iCurSam}.instrument_nominal_depth - sample_data{nearestInsts{iCurSam}(iOtherSam)}.instrument_nominal_depth; + else + % below is reversed so that sign convention is the + % same + diffWithOthers(iOtherSam) = sample_data{nearestInsts{iCurSam}(iOtherSam)}.instrument_nominal_height - sample_data{iCurSam}.instrument_nominal_height; end + end + + iAbove = diffWithOthers(diffWithOthers >= 0); + iBelow = diffWithOthers(diffWithOthers < 0); + + if ~isempty(iAbove) + iAbove = find(diffWithOthers == min(iAbove), 1); + end + + if ~isempty(iBelow) + iBelow = find(diffWithOthers == max(iBelow), 1); + end + + if isempty(iAbove) && ~isempty(iBelow) + iFirst = iBelow; - iAbove = diffWithOthers(diffWithOthers >= 0); - iBelow = diffWithOthers(diffWithOthers < 0); + % let's find the second nearest below + newDiffWithOthers = diffWithOthers; + newDiffWithOthers(iFirst) = NaN; + distance = 0; - if ~isempty(iAbove) - iAbove = find(diffWithOthers == min(iAbove), 1); + % if those two sensors are too close to each other then + % the calculated depth could be too far off the truth + distMin = 10; + while distance < distMin && ~all(isnan(newDiffWithOthers)) + iNextBelow = diffWithOthers == max(newDiffWithOthers(newDiffWithOthers < 0)); + iNextBelow(isnan(newDiffWithOthers)) = 0; % deals with the case of same depth instrument previously found + iNextBelow = find(iNextBelow, 1, 'first'); + distance = abs(diffWithOthers(iNextBelow) - diffWithOthers(iBelow)); + if distance >= distMin + iSecond = iNextBelow; + break; + end + newDiffWithOthers(iNextBelow) = NaN; end + elseif isempty(iBelow) && ~isempty(iAbove) + iFirst = iAbove; - if ~isempty(iBelow) - iBelow = find(diffWithOthers == max(iBelow), 1); - end + % extending reseach to further nearest above didn't + % lead to better results - if isempty(iAbove) && ~isempty(iBelow) - iFirst = iBelow; - - % let's find the second nearest below - newDiffWithOthers = diffWithOthers; - newDiffWithOthers(iFirst) = NaN; - distance = 0; - - % if those two sensors are too close to each other then - % the calculated depth could be too far off the truth - distMin = 10; - while distance < distMin && ~all(isnan(newDiffWithOthers)) - iNextBelow = diffWithOthers == max(newDiffWithOthers(newDiffWithOthers < 0)); - iNextBelow(isnan(newDiffWithOthers)) = 0; % deals with the case of same depth instrument previously found - iNextBelow = find(iNextBelow, 1, 'first'); - distance = abs(diffWithOthers(iNextBelow) - diffWithOthers(iBelow)); - if distance >= distMin - iSecond = iNextBelow; - break; - end - newDiffWithOthers(iNextBelow) = NaN; - end - elseif isempty(iBelow) && ~isempty(iAbove) - iFirst = iAbove; - - % extending reseach to further nearest above didn't - % lead to better results - -% % let's find the second nearest above -% newDiffWithOthers = diffWithOthers; -% newDiffWithOthers(iFirst) = NaN; -% distance = 0; -% -% % if those two sensors are too close to each other then -% % the calculated depth could be too far off the truth -% distMin = 10; -% while distance < distMin && ~all(isnan(newDiffWithOthers)) -% iNextAbove = find(diffWithOthers == min(newDiffWithOthers(newDiffWithOthers > 0)), 1); -% distance = abs(diffWithOthers(iNextAbove) - diffWithOthers(iAbove)); -% if distance >= distMin -% iSecond = iNextAbove; -% break; -% end -% newDiffWithOthers(iNextAbove) = NaN; -% end - else - iFirst = iAbove; - iSecond = iBelow; - end + % % let's find the second nearest above + % newDiffWithOthers = diffWithOthers; + % newDiffWithOthers(iFirst) = NaN; + % distance = 0; + % + % % if those two sensors are too close to each other then + % % the calculated depth could be too far off the truth + % distMin = 10; + % while distance < distMin && ~all(isnan(newDiffWithOthers)) + % iNextAbove = find(diffWithOthers == min(newDiffWithOthers(newDiffWithOthers > 0)), 1); + % distance = abs(diffWithOthers(iNextAbove) - diffWithOthers(iAbove)); + % if distance >= distMin + % iSecond = iNextAbove; + % break; + % end + % newDiffWithOthers(iNextAbove) = NaN; + % end + else + iFirst = iAbove; + iSecond = iBelow; + end + + firstNearestInst(iCurSam) = iFirst; + secondNearestInst(iCurSam) = iSecond; + + % read dataset specific PP parameters if exist and override previous default entries + firstNearestInst(iCurSam) = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'firstNearestInst', firstNearestInst(iCurSam)); + secondNearestInst(iCurSam) = readDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'secondNearestInst', secondNearestInst(iCurSam)); + end + else + fprintf('%s\n', ['Warning : ' sample_data{iCurSam}.toolbox_input_file ... + ' please document either instrument_nominal_height or instrument_nominal_depth '... + 'global attributes so that an actual depth can be '... + 'computed from other pressure sensors in the mooring']); + continue; + end +end + +%% create GUI to show default settings +% create descriptions, get methodology and nearest P sensors for each data set +descSam = cell(nDatasets, 1); +descOtherSam = cell(nDatasets, 1); +methodsString = {'from DEPTH measurements', ... + 'from PRES measurements', ... + 'from PRES_REL measurements', ... + 'from nearest pressure sensors'}; +methodsSamString = cell(nDatasets, 1); % cell array of strings of possible methods per dataset +iMethodsSamString = false(nDatasets, 4); % logical array with methodsString of possible methods per dataset +iMethodSam = zeros(nDatasets, 1); % index of selected method within methodsSamString per dataset + +for iCurSam = 1:nDatasets + descSam{iCurSam} = genSampleDataDesc(sample_data{iCurSam}, 'medium'); + + iMethodsSamString(iCurSam, 4) = true; + if useItsOwnPresRel(iCurSam) + iMethodsSamString(iCurSam, 3) = true; + end + if useItsOwnPres(iCurSam) + iMethodsSamString(iCurSam, 2) = true; + end + if useItsOwnDepth(iCurSam) + iMethodsSamString(iCurSam, 1) = true; + end + + % given the order of definition, the first methodology is the default one + iMethodSam(iCurSam) = 1; + + descOtherSam{iCurSam}{1} = ' - '; + nOtherSam = length(nearestInsts{iCurSam}); + for iOtherSam = 1:nOtherSam + descOtherSam{iCurSam}{iOtherSam+1} = genSampleDataDesc(sample_data{nearestInsts{iCurSam}(iOtherSam)}, 'short'); + end +end + +if ~auto + f = figure(... + 'Name', 'Depth Computation',... + 'Visible', 'off',... + 'MenuBar' , 'none',... + 'Resize', 'off',... + 'WindowStyle', 'Modal',... + 'NumberTitle', 'off'); + + cancelButton = uicontrol('Style', 'pushbutton', 'String', 'Cancel'); + resetParamsButton = uicontrol('Style', 'pushbutton', 'String', 'Reset parameters, restart from depthPP.txt'); + resetMappingButton = uicontrol('Style', 'pushbutton', 'String', 'Reset to current default mapping'); + confirmButton = uicontrol('Style', 'pushbutton', 'String', 'Ok'); + + descSamUic = nan(nDatasets, 1); + methodSamUic = nan(nDatasets, 1); + firstNearestInstUic = nan(nDatasets, 1); + andStrUic = nan(nDatasets, 1); + secondNearestInstUic = nan(nDatasets, 1); + for iCurSam = 1:nDatasets + descSamUic(iCurSam) = uicontrol( ... + 'Style', 'text', ... + 'HorizontalAlignment', 'left', ... + 'String', descSam{iCurSam}); + + methodsSamString{iCurSam} = methodsString(iMethodsSamString(iCurSam, :)); + methodSamUic(iCurSam) = uicontrol( ... + 'Style', 'popupmenu', ... + 'String', methodsSamString{iCurSam}, ... + 'Value', iMethodSam(iCurSam), ... + 'Callback', {@methodSamCallback, iCurSam}); + + switch methodsSamString{iCurSam}{iMethodSam(iCurSam)} + case methodsString{end} + nearestInstVisibility = 'on'; - if isempty(iSecond) - fprintf('%s\n', ['Warning : ' curSam.toolbox_input_file ... - ' computing actual depth from only one pressure sensor '... + otherwise + nearestInstVisibility = 'off'; + end + + firstNearestInstUic(iCurSam) = uicontrol( ... + 'Style', 'popupmenu', ... + 'String', descOtherSam{iCurSam}, ... + 'Value', firstNearestInst(iCurSam) + 1, ... + 'Visible', nearestInstVisibility); + + andStrUic(iCurSam) = uicontrol( ... + 'Style', 'text', ... + 'String', 'and', ... + 'Visible', nearestInstVisibility); + + secondNearestInstUic(iCurSam) = uicontrol( ... + 'Style', 'popupmenu', ... + 'String', descOtherSam{iCurSam}, ... + 'Value', secondNearestInst(iCurSam) + 1, ... + 'Visible', nearestInstVisibility); + end + + paramsString = 'Look within same kind of instruments: '; + if same_family + paramsString = [paramsString, 'Yes.']; + else + paramsString = [paramsString, 'No.']; + end + + if ~isempty(include) + includeStr = [include,[repmat({' '},numel(include)-1,1);{[]}]]'; + includeStr = [includeStr{:}]; + paramsString = [paramsString, ' Include: ' includeStr '.']; + end + + if ~isempty(exclude) + excludeStr = [exclude,[repmat({' '},numel(exclude)-1,1);{[]}]]'; + excludeStr = [excludeStr{:}]; + paramsString = [paramsString, ' Exclude: ' excludeStr '.']; + end + paramsStringUic = uicontrol('Style', 'text', 'String', paramsString); + + % set all widgets to normalized for positioning + set(f, 'Units', 'normalized'); + set(cancelButton, 'Units', 'normalized'); + set(resetParamsButton, 'Units', 'normalized'); + set(resetMappingButton, 'Units', 'normalized'); + set(confirmButton, 'Units', 'normalized'); + set(descSamUic, 'Units', 'normalized'); + set(methodSamUic, 'Units', 'normalized'); + set(firstNearestInstUic, 'Units', 'normalized'); + set(andStrUic, 'Units', 'normalized'); + set(secondNearestInstUic, 'Units', 'normalized'); + set(paramsStringUic, 'Units', 'normalized'); + + set(f, 'Position', [0.2 0.35 0.6 0.0222 * (nDatasets + 2 )]); % need to include 2 extra space for the depth.txt parameters and the row of buttons + + rowHeight = 1 / (nDatasets + 2); + + set(cancelButton, 'Position', [0.0 0.0 0.25 rowHeight]); + set(resetParamsButton, 'Position', [0.25 0.0 0.25 rowHeight]); + set(resetMappingButton, 'Position', [0.5 0.0 0.25 rowHeight]); + set(confirmButton, 'Position', [0.75 0.0 0.25 rowHeight]); + + for k = 1:nDatasets + rowStart = 1.0 - (k + 1) * rowHeight; + + set(descSamUic (k), 'Position', [0.0 rowStart 0.4 rowHeight]); + set(methodSamUic(k), 'Position', [0.4 rowStart 0.2 rowHeight]); + set(firstNearestInstUic(k), 'Position', [0.6 rowStart 0.175 rowHeight]); + set(andStrUic(k), 'Position', [0.775 rowStart 0.05 rowHeight]); + set(secondNearestInstUic(k), 'Position', [0.825 rowStart 0.175 rowHeight]); + end + + set(paramsStringUic, 'Position', [0.0 (1.0 - rowHeight) 1 rowHeight]); + + % set widget callbacks + set(f, 'CloseRequestFcn', @cancelCallback); + set(f, 'WindowKeyPressFcn', @keyPressCallback); + + set(cancelButton, 'Callback', @cancelCallback); + set(resetParamsButton, 'Callback', @resetParamsCallback); + set(resetMappingButton, 'Callback', @resetMappingCallback); + set(confirmButton, 'Callback', @confirmCallback); + + cancel = false; + reset = false; + + set(f, 'Visible', 'on'); + + uiwait(f); + + if cancel + return; + end + + if reset + sample_data = depthPP(sample_data, qcLevel, auto); + return; + end +end + +%% loop on every data sets again and apply choices +for iCurSam = 1:nDatasets + % if data set already contains depth data then next sample data + if useItsOwnDepth(iCurSam), continue; end + + if useItsOwnPres(iCurSam) || useItsOwnPresRel(iCurSam) + % we can compute DEPTH straight from the instrument pressure + % measurements + if presRelIdx(iCurSam) + % update from a relative measured pressure + relPres = sample_data{iCurSam}.variables{presRelIdx(iCurSam)}.data; + presComment = ['relative ' ... + 'pressure measurements (calibration offset ' ... + 'usually performed to balance current ' ... + 'atmospheric pressure and acute sensor ' ... + 'precision at a deployed depth)']; + dimensions = sample_data{iCurSam}.variables{presRelIdx(iCurSam)}.dimensions; + coordinates = sample_data{iCurSam}.variables{presRelIdx(iCurSam)}.coordinates; + else + % update from an absolute measured pressure, substracting a + % constant value 10.1325 dbar for nominal atmospheric pressure + % like SeaBird does in its processed files + relPres = sample_data{iCurSam}.variables{presIdx(iCurSam)}.data - gsw_P0/10^4; + presComment = ['absolute ' ... + 'pressure measurements to which a nominal ' ... + 'value for atmospheric pressure (10.1325 dbar) ' ... + 'has been substracted']; + dimensions = sample_data{iCurSam}.variables{presIdx(iCurSam)}.dimensions; + coordinates = sample_data{iCurSam}.variables{presIdx(iCurSam)}.coordinates; + end + + if ~isempty(sample_data{iCurSam}.geospatial_lat_min) && ~isempty(sample_data{iCurSam}.geospatial_lat_max) + % compute depth with Gibbs-SeaWater toolbox + if sample_data{iCurSam}.geospatial_lat_min == sample_data{iCurSam}.geospatial_lat_max + % latitude doesn't change in the dataset + computedDepth = - gsw_z_from_p(relPres, sample_data{iCurSam}.geospatial_lat_min); + clear relPres; + computedDepthComment = ['depthPP: Depth computed using the ' ... + 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from latitude and ' ... + presComment '.']; + else + % latitude does change in the dataset, so we use the mean + % latitude with Gibbs-Seawater toolbox + meanLat = sample_data{iCurSam}.geospatial_lat_min + ... + (sample_data{iCurSam}.geospatial_lat_max - sample_data{iCurSam}.geospatial_lat_min)/2; + + computedDepth = - gsw_z_from_p(relPres, meanLat); + clear relPres; + computedDepthComment = ['depthPP: Depth computed using the ' ... + 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from mean latitude and ' ... + presComment '.']; + end + else + % without latitude information, we assume 1dbar ~= 1m + computedDepth = relPres; + clear relPres; + computedDepthComment = ['depthPP: Depth computed from ' ... + presComment ', assuming 1dbar ~= 1m.']; + end + else + % if no pressure data, try to compute it from other sensors in the + % mooring, otherwise go to next sample data + if isSensorHeight || isSensorTargetDepth + if isempty(nearestInsts{iCurSam}) + fprintf('%s\n', ['Warning : ' descSam{iCurSam} ... + ' has no neighbouring pressure sensor on this mooring from ' ... + 'which an actual depth can be inferred']); + continue; + else + iFirst = firstNearestInst(iCurSam); + iSecond = secondNearestInst(iCurSam); + + if iSecond == 0 + fprintf('%s\n', ['Warning : ' descSam{iCurSam} ... + ' has its actual depth inferred from only one neighbouring pressure sensor ' ... 'on mooring']); % we found only one sensor - otherSam = otherSam{iFirst}; - presIdxOther = getVar(otherSam.variables, 'PRES'); - presRelIdxOther = getVar(otherSam.variables, 'PRES_REL'); + presIdxOther = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES'); + presRelIdxOther = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES_REL'); if presRelIdxOther == 0 % update from an absolute pressure like SeaBird computes % a relative pressure in its processed files, substracting a constant value % 10.1325 dbar for nominal atmospheric pressure - relPresOther = otherSam.variables{presIdxOther}.data - gsw_P0/10^4; - presComment = ['absolute '... - 'pressure measurements to which a nominal '... - 'value for atmospheric pressure (10.1325 dbar) '... + relPresOther = sample_data{nearestInsts{iCurSam}(iFirst)}.variables{presIdxOther}.data - gsw_P0/10^4; + presComment = ['absolute ' ... + 'pressure measurements to which a nominal ' ... + 'value for atmospheric pressure (10.1325 dbar) ' ... 'has been substracted']; else % update from a relative pressure measurement - relPresOther = otherSam.variables{presRelIdxOther}.data; - presComment = ['relative '... - 'pressure measurements (calibration offset '... - 'usually performed to balance current '... - 'atmospheric pressure and acute sensor '... + relPresOther = sample_data{nearestInsts{iCurSam}(iFirst)}.variables{presRelIdxOther}.data; + presComment = ['relative ' ... + 'pressure measurements (calibration offset ' ... + 'usually performed to balance current ' ... + 'atmospheric pressure and acute sensor ' ... 'precision at a deployed depth)']; end @@ -311,12 +604,12 @@ % depth % if isSensorTargetDepth - distOtherCurSensor = curSam.instrument_nominal_depth - otherSam.instrument_nominal_depth; + distOtherCurSensor = sample_data{iCurSam}.instrument_nominal_depth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; signOtherCurSensor = sign(distOtherCurSensor); distOtherCurSensor = abs(distOtherCurSensor); else - distOtherCurSensor = otherSam.instrument_nominal_height - curSam.instrument_nominal_height; + distOtherCurSensor = sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_height - sample_data{iCurSam}.instrument_nominal_height; signOtherCurSensor = -sign(distOtherCurSensor); % 0 => two sensors at the same depth % 1 => current sensor is deeper than other sensor @@ -325,41 +618,32 @@ distOtherCurSensor = abs(distOtherCurSensor); end - if ~isempty(curSam.geospatial_lat_min) && ~isempty(curSam.geospatial_lat_max) + if ~isempty(sample_data{iCurSam}.geospatial_lat_min) && ~isempty(sample_data{iCurSam}.geospatial_lat_max) % compute depth with Gibbs-SeaWater toolbox % depth ~= - gsw_z_from_p(relative_pressure, latitude) - if curSam.geospatial_lat_min == curSam.geospatial_lat_max - zOther = - gsw_z_from_p(relPresOther, curSam.geospatial_lat_min); - clear relPresOther; - - computedDepthComment = ['depthPP: Depth computed from '... - 'the only pressure sensor available, using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from latitude and '... - presComment '.']; + if sample_data{iCurSam}.geospatial_lat_min == sample_data{iCurSam}.geospatial_lat_max + zOther = - gsw_z_from_p(relPresOther, sample_data{iCurSam}.geospatial_lat_min); + computedDepthComment = ['depthPP: Depth inferred from only one neighbouring pressure sensor ' ... + descOtherSam{iCurSam}{iFirst + 1} ', using the Gibbs-SeaWater toolbox ' ... + '(TEOS-10) v3.05 from latitude and ' presComment '.']; else - meanLat = curSam.geospatial_lat_min + ... - (curSam.geospatial_lat_max - curSam.geospatial_lat_min)/2; + meanLat = sample_data{iCurSam}.geospatial_lat_min + ... + (sample_data{iCurSam}.geospatial_lat_max - sample_data{iCurSam}.geospatial_lat_min)/2; zOther = - gsw_z_from_p(relPresOther, meanLat); - clear relPresOther; - - computedDepthComment = ['depthPP: Depth computed from '... - 'the only pressure sensor available, using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from mean latitude and '... - presComment '.']; + computedDepthComment = ['depthPP: Depth inferred from only one neighbouring pressure sensor ' ... + descOtherSam{iCurSam}{iFirst + 1} ', using the Gibbs-SeaWater toolbox ' ... + '(TEOS-10) v3.05 from mean latitude and ' presComment '.']; end else % without latitude information, we assume 1dbar ~= 1m zOther = relPresOther; - clear relPresOther; - - computedDepthComment = ['depthPP: Depth computed from '... - 'the only pressure sensor available with '... - presComment ', assuming 1dbar ~= 1m.']; + computedDepthComment = ['depthPP: Depth inferred from only one neighbouring pressure sensor ' ... + descOtherSam{iCurSam}{iFirst + 1} ' with ' presComment ', assuming 1dbar ~= 1m.']; end + clear relPresOther; - tOther = otherSam.dimensions{getVar(otherSam.dimensions, 'TIME')}.data; - tCur = curSam.dimensions{getVar(curSam.dimensions, 'TIME')}.data; - clear otherSam; + tOther = sample_data{nearestInsts{iCurSam}(iFirst)}.dimensions{getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.dimensions, 'TIME')}.data; + tCur = sample_data{iCurSam}.dimensions{getVar(sample_data{iCurSam}.dimensions, 'TIME')}.data; % let's interpolate the other data set depth values in time % to fit with the current data set time values @@ -369,47 +653,44 @@ computedDepth = zOther + signOtherCurSensor*distOtherCurSensor; clear zOther; else - samFirst = otherSam{iFirst}; - presIdxFirst = getVar(samFirst.variables, 'PRES'); - presRelIdxFirst = getVar(samFirst.variables, 'PRES_REL'); + presIdxFirst = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES'); + presRelIdxFirst = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES_REL'); - samSecond = otherSam{iSecond}; - presIdxSecond = getVar(samSecond.variables, 'PRES'); - presRelIdxSecond = getVar(samSecond.variables, 'PRES_REL'); - clear otherSam; + presIdxSecond = getVar(sample_data{nearestInsts{iCurSam}(iSecond)}.variables, 'PRES'); + presRelIdxSecond = getVar(sample_data{nearestInsts{iCurSam}(iSecond)}.variables, 'PRES_REL'); if presIdxFirst ~= 0 && presIdxSecond ~= 0 % update from an absolute pressure like SeaBird computes % a relative pressure in its processed files, substracting a constant value % 10.1325 dbar for nominal atmospheric pressure - relPresFirst = samFirst.variables{presIdxFirst}.data - gsw_P0/10^4; - relPresSecond = samSecond.variables{presIdxSecond}.data - gsw_P0/10^4; - presComment = ['absolute '... - 'pressure measurements to which a nominal '... - 'value for atmospheric pressure (10.1325 dbar) '... + relPresFirst = sample_data{nearestInsts{iCurSam}(iFirst )}.variables{presIdxFirst }.data - gsw_P0/10^4; + relPresSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.variables{presIdxSecond}.data - gsw_P0/10^4; + presComment = ['absolute ' ... + 'pressure measurements to which a nominal ' ... + 'value for atmospheric pressure (10.1325 dbar) ' ... 'has been substracted']; elseif presIdxFirst ~= 0 && presIdxSecond == 0 - relPresFirst = samFirst.variables{presIdxFirst}.data - gsw_P0/10^4; - relPresSecond = samSecond.variables{presRelIdxSecond}.data; - presComment = ['relative and absolute '... - 'pressure measurements to which a nominal '... - 'value for atmospheric pressure (10.1325 dbar) '... + relPresFirst = sample_data{nearestInsts{iCurSam}(iFirst )}.variables{presIdxFirst }.data - gsw_P0/10^4; + relPresSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.variables{presRelIdxSecond}.data; + presComment = ['relative and absolute ' ... + 'pressure measurements to which a nominal ' ... + 'value for atmospheric pressure (10.1325 dbar) ' ... 'has been substracted']; elseif presIdxFirst == 0 && presIdxSecond ~= 0 - relPresFirst = samFirst.variables{presRelIdxFirst}.data; - relPresSecond = samSecond.variables{presIdxSecond}.data - gsw_P0/10^4; - presComment = ['relative and absolute '... - 'pressure measurements to which a nominal '... - 'value for atmospheric pressure (10.1325 dbar) '... + relPresFirst = sample_data{nearestInsts{iCurSam}(iFirst )}.variables{presRelIdxFirst}.data; + relPresSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.variables{presIdxSecond }.data - gsw_P0/10^4; + presComment = ['relative and absolute ' ... + 'pressure measurements to which a nominal ' ... + 'value for atmospheric pressure (10.1325 dbar) ' ... 'has been substracted']; else % update from a relative measured pressure - relPresFirst = samFirst.variables{presRelIdxFirst}.data; - relPresSecond = samSecond.variables{presRelIdxSecond}.data; - presComment = ['relative '... - 'pressure measurements (calibration offset '... - 'usually performed to balance current '... - 'atmospheric pressure and acute sensor '... + relPresFirst = sample_data{nearestInsts{iCurSam}(iFirst )}.variables{presRelIdxFirst }.data; + relPresSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.variables{presRelIdxSecond}.data; + presComment = ['relative ' ... + 'pressure measurements (calibration offset ' ... + 'usually performed to balance current ' ... + 'atmospheric pressure and acute sensor ' ... 'precision at a deployed depth)']; end @@ -417,11 +698,11 @@ % assuming sensors repartition on a line between the two % nearest pressure sensors if isSensorTargetDepth - distFirstSecond = samSecond.instrument_nominal_depth - samFirst.instrument_nominal_depth; - distFirstCurSensor = curSam.instrument_nominal_depth - samFirst.instrument_nominal_depth; + distFirstSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.instrument_nominal_depth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; + distFirstCurSensor = sample_data{iCurSam}.instrument_nominal_depth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; else - distFirstSecond = samFirst.instrument_nominal_height - samSecond.instrument_nominal_height; - distFirstCurSensor = samFirst.instrument_nominal_height - curSam.instrument_nominal_height; + distFirstSecond = sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_height - sample_data{nearestInsts{iCurSam}(iSecond)}.instrument_nominal_height; + distFirstCurSensor = sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_height - sample_data{iCurSam}.instrument_nominal_height; end % theta is the angle between the vertical and line @@ -436,50 +717,50 @@ % % pressure = density*gravity*depth % - if ~isempty(curSam.geospatial_lat_min) && ~isempty(curSam.geospatial_lat_max) + if ~isempty(sample_data{iCurSam}.geospatial_lat_min) && ~isempty(sample_data{iCurSam}.geospatial_lat_max) % compute depth with Gibbs-SeaWater toolbox % depth ~= - gsw_z_from_p(relative_pressure, latitude) - if curSam.geospatial_lat_min == curSam.geospatial_lat_max - zFirst = - gsw_z_from_p(relPresFirst, curSam.geospatial_lat_min); - zSecond = - gsw_z_from_p(relPresSecond, curSam.geospatial_lat_min); - clear relPresFirst relPresSecond; + if sample_data{iCurSam}.geospatial_lat_min == sample_data{iCurSam}.geospatial_lat_max + zFirst = - gsw_z_from_p(relPresFirst, sample_data{iCurSam}.geospatial_lat_min); + zSecond = - gsw_z_from_p(relPresSecond, sample_data{iCurSam}.geospatial_lat_min); - computedDepthComment = ['depthPP: Depth computed from '... - 'the 2 nearest pressure sensors available, using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from latitude and '... + computedDepthComment = ['depthPP: Depth inferred from ' ... + '2 neighbouring pressure sensors ' descOtherSam{iCurSam}{iFirst + 1} ... + ' and ' descOtherSam{iCurSam}{iSecond + 1} ', using the ' ... + 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from latitude and ' ... presComment '.']; else - meanLat = curSam.geospatial_lat_min + ... - (curSam.geospatial_lat_max - curSam.geospatial_lat_min)/2; + meanLat = sample_data{iCurSam}.geospatial_lat_min + ... + (sample_data{iCurSam}.geospatial_lat_max - sample_data{iCurSam}.geospatial_lat_min)/2; - zFirst = - gsw_z_from_p(relPresFirst, meanLat); + zFirst = - gsw_z_from_p(relPresFirst, meanLat); zSecond = - gsw_z_from_p(relPresSecond, meanLat); - clear relPresFirst relPresSecond; - computedDepthComment = ['depthPP: Depth computed from '... - 'the 2 nearest pressure sensors available, using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from mean latitude and '... + computedDepthComment = ['depthPP: Depth inferred from ' ... + '2 neighbouring pressure sensors ' descOtherSam{iCurSam}{iFirst + 1} ... + ' and ' descOtherSam{iCurSam}{iSecond + 1} ', using the ' ... + 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from mean latitude and ' ... presComment '.']; end else % without latitude information, we assume 1dbar ~= 1m - zFirst = relPresFirst; + zFirst = relPresFirst; zSecond = relPresSecond; - clear relPresFirst relPresSecond; - computedDepthComment = ['depthPP: Depth computed from '... - 'the 2 nearest pressure sensors available with '... + computedDepthComment = ['depthPP: Depth inferred from ' ... + '2 neighbouring pressure sensors ' descOtherSam{iCurSam}{iFirst + 1} ... + ' and ' descOtherSam{iCurSam}{iSecond + 1} ', with ' ... presComment ', assuming 1dbar ~= 1m.']; end + clear relPresFirst relPresSecond; - tFirst = samFirst.dimensions{getVar(samFirst.dimensions, 'TIME')}.data; - tSecond = samSecond.dimensions{getVar(samSecond.dimensions, 'TIME')}.data; - tCur = curSam.dimensions{getVar(curSam.dimensions, 'TIME')}.data; - clear samFirst samSecond; + tCur = sample_data{iCurSam}.dimensions{getVar(sample_data{iCurSam}.dimensions, 'TIME')}.data; + tFirst = sample_data{nearestInsts{iCurSam}(iFirst )}.dimensions{getVar(sample_data{nearestInsts{iCurSam}(iFirst )}.dimensions, 'TIME')}.data; + tSecond = sample_data{nearestInsts{iCurSam}(iSecond)}.dimensions{getVar(sample_data{nearestInsts{iCurSam}(iSecond)}.dimensions, 'TIME')}.data; % let's interpolate data so we have consistent period % sample and time sample over the 3 data sets - zFirst = interp1(tFirst, zFirst, tCur); + zFirst = interp1(tFirst, zFirst, tCur); zSecond = interp1(tSecond, zSecond, tCur); clear tFirst tSecond tCur; @@ -489,114 +770,174 @@ end end else - fprintf('%s\n', ['Warning : ' curSam.toolbox_input_file ... - ' please document either instrument_nominal_height or instrument_nominal_depth '... - 'global attributes so that an actual depth can be '... + fprintf('%s\n', ['Warning : ' sample_data{iCurSam}.toolbox_input_file ... + ' please document either instrument_nominal_height or instrument_nominal_depth ' ... + 'global attributes so that an actual depth can be ' ... 'computed from other pressure sensors in the mooring']); continue; end - % variable Depth will be a function of T - dimensions = getVar(curSam.dimensions, 'TIME'); + % variable DEPTH will be a function of dimension TIME + dimensions = getVar(sample_data{iCurSam}.dimensions, 'TIME'); % hopefully the last variable in the file is a data variable - coordinates = curSam.variables{end}.coordinates; - else - if presRelIdx == 0 - % update from a relative pressure like SeaBird computes - % it in its processed files, substracting a constant value - % 10.1325 dbar for nominal atmospheric pressure - relPres = curSam.variables{presIdx}.data - gsw_P0/10^4; - presComment = ['absolute '... - 'pressure measurements to which a nominal '... - 'value for atmospheric pressure (10.1325 dbar) '... - 'has been substracted']; - else - % update from a relative measured pressure - relPres = curSam.variables{presRelIdx}.data; - presComment = ['relative '... - 'pressure measurements (calibration offset '... - 'usually performed to balance current '... - 'atmospheric pressure and acute sensor '... - 'precision at a deployed depth)']; - end + coordinates = sample_data{iCurSam}.variables{end}.coordinates; + end + + if depthIdx(iCurSam) + % update existing depth data in data set + sample_data{iCurSam}.(depthVarType).data = computedDepth; - if ~isempty(curSam.geospatial_lat_min) && ~isempty(curSam.geospatial_lat_max) - % compute vertical min/max with Gibbs-SeaWater toolbox - if curSam.geospatial_lat_min == curSam.geospatial_lat_max - computedDepth = - gsw_z_from_p(relPres, ... - curSam.geospatial_lat_min); - clear relPres; - computedDepthComment = ['depthPP: Depth computed using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from latitude and '... - presComment '.']; - else - meanLat = curSam.geospatial_lat_min + ... - (curSam.geospatial_lat_max - curSam.geospatial_lat_min)/2; - - computedDepth = - gsw_z_from_p(relPres, meanLat); - clear relPres; - computedDepthComment = ['depthPP: Depth computed using the '... - 'Gibbs-SeaWater toolbox (TEOS-10) v3.05 from mean latitude and '... - presComment '.']; - end + depthComment = sample_data{iCurSam}.(depthVarType).comment; + if isempty(depthComment) + sample_data{iCurSam}.(depthVarType).comment = computedDepthComment; else - % without latitude information, we assume 1dbar ~= 1m - computedDepth = relPres; - clear relPres; - computedDepthComment = ['depthPP: Depth computed from '... - presComment ', assuming 1dbar ~= 1m.']; + sample_data{iCurSam}.(depthVarType).comment = [comment ' ' computedDepthComment]; end - if presRelIdx == 0 - dimensions = curSam.variables{presIdx}.dimensions; - coordinates = curSam.variables{presIdx}.coordinates; - else - dimensions = curSam.variables{presRelIdx}.dimensions; - coordinates = curSam.variables{presRelIdx}.coordinates; - end + else + % add depth data as new variable in data set + sample_data{iCurSam} = addVar( ... + sample_data{iCurSam}, ... + 'DEPTH', ... + computedDepth, ... + dimensions, ... + computedDepthComment, ... + coordinates); end - - % get the toolbox execution mode - mode = readProperty('toolbox.mode'); - - % add depth data as new variable in data set - sample_data{k} = addVar(... - curSam, ... - 'DEPTH', ... - computedDepth, ... - dimensions, ... - computedDepthComment, ... - coordinates); - - % update vertical min/max from new computed DEPTH - sample_data{k}.geospatial_vertical_min = min(computedDepth); - sample_data{k}.geospatial_vertical_max = max(computedDepth); - sample_data{k}.comment = strrep(sample_data{k}.comment, 'NOMINAL_DEPTH', 'DEPTH min and max'); + % update vertical min/max from newly computed DEPTH variable + sample_data{iCurSam}.geospatial_vertical_min = min(computedDepth); + sample_data{iCurSam}.geospatial_vertical_max = max(computedDepth); clear computedDepth; - history = sample_data{k}.history; + sample_data{iCurSam}.comment = strrep(sample_data{iCurSam}.comment, 'NOMINAL_DEPTH', 'DEPTH min and max'); + + history = sample_data{iCurSam}.history; if isempty(history) - sample_data{k}.history = sprintf('%s - %s', datestr(now_utc, readProperty('exportNetCDF.dateFormat')), computedDepthComment); + sample_data{iCurSam}.history = sprintf('%s - %s', ... + datestr(now_utc, readProperty('exportNetCDF.dateFormat')), ... + computedDepthComment); else - sample_data{k}.history = sprintf('%s\n%s - %s', history, datestr(now_utc, readProperty('exportNetCDF.dateFormat')), computedDepthComment); + sample_data{iCurSam}.history = sprintf('%s\n%s - %s', history, ... + datestr(now_utc, readProperty('exportNetCDF.dateFormat')), ... + computedDepthComment); end % update the keywords with variable DEPTH - sample_data{k}.keywords = [sample_data{k}.keywords, ', DEPTH']; - - switch mode - case 'profile' - %let's redefine the coordinates attribute for each variables - nVars = length(sample_data{k}.variables); - for i=1:nVars - if isfield(sample_data{k}.variables{i}, 'coordinates') - sample_data{k}.variables{i}.coordinates = [sample_data{k}.variables{i}.coordinates ' DEPTH']; - end + sample_data{iCurSam}.keywords = [sample_data{iCurSam}.keywords, ', DEPTH']; + + if strcmpi(mode, 'profile') + %let's redefine the coordinates attribute for each variables + nVars = length(sample_data{iCurSam}.variables); + for i=1:nVars + if isfield(sample_data{iCurSam}.variables{i}, 'coordinates') + sample_data{iCurSam}.variables{i}.coordinates = [sample_data{iCurSam}.variables{i}.coordinates ' DEPTH']; end + end + end + + % write/update dataset PP parameters + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'same_family', same_family); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'include', include); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'exclude', exclude); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnDepth', useItsOwnDepth(iCurSam)); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnPres', useItsOwnPres(iCurSam)); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'useItsOwnPresRel', useItsOwnPresRel(iCurSam)); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'firstNearestInst', firstNearestInst(iCurSam)); + writeDatasetParameter(sample_data{iCurSam}.toolbox_input_file, currentPProutine, 'secondNearestInst', secondNearestInst(iCurSam)); +end + +%% Callbacks + function methodSamCallback(source,ev,j) + %RESETCALLBACK Reset to default choices in the GUI. + % + iMethod = get(methodSamUic(j), 'Value'); + switch methodsSamString{j}{iMethod} + case methodsString{end} + nearestInstVisibility = 'on'; + + otherwise + nearestInstVisibility = 'off'; + end + + set([firstNearestInstUic(j), andStrUic(j), secondNearestInstUic(j)], ... + 'Visible', nearestInstVisibility); + end + + function keyPressCallback(source,ev) + %KEYPRESSCALLBACK If the user pushes escape/return while the dialog has + % focus, the dialog is cancelled/confirmed. This is done by delegating + % to the cancelCallback/confirmCallback functions. + % + if strcmp(ev.Key, 'escape'), cancelCallback( source,ev); + elseif strcmp(ev.Key, 'return'), confirmCallback(source,ev); + end + end + + function cancelCallback(source,ev) + %CANCELCALLBACK Cancel button callback. Set cancel to true and closes the + % dialog. + % + cancel = true; + reset = false; + delete(f); + end + + function resetParamsCallback(source,ev) + %RESETPARAMSCALLBACK Reset dataset specific parameters re-start + %from depthPP.txt parameters + % + for j = 1:nDatasets + pppFile = [sample_data{j}.toolbox_input_file '.ppp']; + if exist(pppFile, 'file') + delete(pppFile); + end + end + reset = true; + delete(f); + end + + function resetMappingCallback(source,ev) + %RESETMAPPINGCALLBACK Reset to current default choices in the GUI. + % + for j = 1:nDatasets + set(methodSamUic(j), 'Value', iMethodSam(j)); + methodSamCallback(source,ev,j) + set(firstNearestInstUic(j), 'Value', firstNearestInst(j) + 1); + set(secondNearestInstUic(j), 'Value', secondNearestInst(j) + 1); + end + reset = false; end - clear curSam; -end + function confirmCallback(source,ev) + %CONFIRMCALLBACK Set choices as they appear on the GUI and closes the dialog. + % + for j = 1:nDatasets + useItsOwnDepth(j) = false; + useItsOwnPres(j) = false; + useItsOwnPresRel(j) = false; + + strings = get(methodSamUic(j), 'String'); + value = get(methodSamUic(j), 'Value'); + + switch strings{value} + case methodsString{1} % from DEPTH measurements + useItsOwnDepth(j) = true; + + case methodsString{2} % from PRES measurements + useItsOwnPres(j) = true; + + case methodsString{3} % from PRES_REL measurements + useItsOwnPresRel(j) = true; + + end + + firstNearestInst(j) = get(firstNearestInstUic(j), 'Value') - 1; + secondNearestInst(j) = get(secondNearestInstUic(j), 'Value') - 1; + end + reset = false; + delete(f); + end +end \ No newline at end of file diff --git a/Preprocessing/timeDriftPP.m b/Preprocessing/timeDriftPP.m index 8dded0b03..41339038b 100644 --- a/Preprocessing/timeDriftPP.m +++ b/Preprocessing/timeDriftPP.m @@ -148,11 +148,13 @@ set(startOffsetFields, 'Units', 'normalized'); set(endOffsetFields, 'Units', 'normalized'); -set(f, 'Position', [0.2 0.35 0.6 0.0222*nSample]); -set(cancelButton, 'Position', [0.0 0.0 0.5 0.1]); -set(confirmButton, 'Position', [0.5 0.0 0.5 0.1]); +set(f, 'Position', [0.2 0.35 0.6 0.0222 * (nSample + 1)]); % need to include 1 extra space for the row of buttons + +rowHeight = 1 / (nSample + 1); + +set(cancelButton, 'Position', [0.0 0.0 0.5 rowHeight]); +set(confirmButton, 'Position', [0.5 0.0 0.5 rowHeight]); -rowHeight = 0.9 / nSample; for k = 1:nSample rowStart = 1.0 - k * rowHeight; @@ -277,7 +279,7 @@ function checkboxCallback(source, ev) else val = 'off'; end - set(startOffsetFields(idx), 'Enable', val); + set([startOffsetFields(idx), endOffsetFields(idx)], 'Visible', val); end diff --git a/Preprocessing/timeMetaOffsetPP.m b/Preprocessing/timeMetaOffsetPP.m index 5538e371c..48b0537d1 100644 --- a/Preprocessing/timeMetaOffsetPP.m +++ b/Preprocessing/timeMetaOffsetPP.m @@ -62,20 +62,17 @@ % auto logical in input to enable running under batch processing if nargin<3, auto=false; end - - % time offsets are already performed on raw FV00 dataset which then go through - % this pp to generate the qc'd FV01 dataset. - if strcmpi(qcLevel, 'qc'), return; end offsetFile = ['Preprocessing' filesep 'timeOffsetPP.txt']; + nSample = length(sample_data); descs = {}; timezones = {}; offsets = []; - sets = ones(length(sample_data), 1); + sets = ones(nSample, 1); % create descriptions, and get timezones/offsets for each data set - for k = 1:length(sample_data) + for k = 1:nSample descs{k} = genSampleDataDesc(sample_data{k}); @@ -110,7 +107,7 @@ timezoneLabels = []; offsetFields = []; - for k = 1:length(sample_data) + for k = 1:nSample setCheckboxes(k) = uicontrol(... 'Style', 'checkbox',... @@ -136,12 +133,14 @@ set(timezoneLabels, 'Units', 'normalized'); set(offsetFields, 'Units', 'normalized'); - set(f, 'Position', [0.2 0.35 0.6 0.3]); - set(cancelButton, 'Position', [0.0 0.0 0.5 0.1]); - set(confirmButton, 'Position', [0.5 0.0 0.5 0.1]); + set(f, 'Position', [0.2 0.35 0.6 0.0222 * (nSample +1 )]); % need to include 1 extra space for the row of buttons + + rowHeight = 1 / (nSample + 1); + + set(cancelButton, 'Position', [0.0 0.0 0.5 rowHeight]); + set(confirmButton, 'Position', [0.5 0.0 0.5 rowHeight]); - rowHeight = 0.9 / length(sample_data); - for k = 1:length(sample_data) + for k = 1:nSample rowStart = 1.0 - k * rowHeight; @@ -172,7 +171,7 @@ end % apply the time offset to the selected datasets - for k = 1:length(sample_data) + for k = 1:nSample % this set has been deselected if ~sets(k), continue; end diff --git a/Preprocessing/timeOffsetPP.m b/Preprocessing/timeOffsetPP.m index 340c60717..fd3b8d225 100644 --- a/Preprocessing/timeOffsetPP.m +++ b/Preprocessing/timeOffsetPP.m @@ -64,20 +64,17 @@ % auto logical in input to enable running under batch processing if nargin<3, auto=false; end - - % time offsets are already performed on raw FV00 dataset which then go through - % this pp to generate the qc'd FV01 dataset. - if strcmpi(qcLevel, 'qc'), return; end offsetFile = ['Preprocessing' filesep 'timeOffsetPP.txt']; + nSample = length(sample_data); descs = {}; timezones = {}; offsets = []; - sets = ones(length(sample_data), 1); + sets = ones(nSample, 1); % create descriptions, and get timezones/offsets for each data set - for k = 1:length(sample_data) + for k = 1:nSample descs{k} = genSampleDataDesc(sample_data{k}); @@ -117,7 +114,7 @@ timezoneLabels = []; offsetFields = []; - for k = 1:length(sample_data) + for k = 1:nSample setCheckboxes(k) = uicontrol(... 'Style', 'checkbox',... @@ -143,12 +140,15 @@ set(timezoneLabels, 'Units', 'normalized'); set(offsetFields, 'Units', 'normalized'); - set(f, 'Position', [0.2 0.35 0.6 0.3]); - set(cancelButton, 'Position', [0.0 0.0 0.5 0.1]); - set(confirmButton, 'Position', [0.5 0.0 0.5 0.1]); + set(f, 'Position', [0.2 0.35 0.6 0.0222 * (nSample +1 )]); % need to include 1 extra space for the row of buttons + + rowHeight = 1 / (nSample + 1); + + set(cancelButton, 'Position', [0.0 0.0 0.5 rowHeight]); + set(confirmButton, 'Position', [0.5 0.0 0.5 rowHeight]); + - rowHeight = 0.9 / length(sample_data); - for k = 1:length(sample_data) + for k = 1:nSample rowStart = 1.0 - k * rowHeight; @@ -179,7 +179,7 @@ end % apply the time offset to the selected datasets - for k = 1:length(sample_data) + for k = 1:nSample % this set has been deselected if ~sets(k), continue; end diff --git a/Util/genSampleDataDesc.m b/Util/genSampleDataDesc.m index 7369faf50..c304c0779 100644 --- a/Util/genSampleDataDesc.m +++ b/Util/genSampleDataDesc.m @@ -1,4 +1,4 @@ -function desc = genSampleDataDesc( sam ) +function desc = genSampleDataDesc( sam, detailLevel ) %GENSAMPLEDATADESC Generates a string description of the given sample_data % struct. % @@ -6,7 +6,9 @@ % be used throughout the toolbox. % % Inputs: -% sam - struct containing a data set +% sam - struct containing a data set +% detailLevel - string either 'full', 'medium' or 'short', dictates the level of +% details for output sample description % % Outputs: % desc - a string describing the given data set. @@ -43,23 +45,43 @@ % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % -narginchk(1,1); +narginchk(1,2); if ~isstruct(sam), error('sam must be a struct'); end +if nargin == 1 + detailLevel = 'full'; +end + timeFmt = readProperty('toolbox.timeFormat'); timeRange = ['from ' datestr(sam.time_coverage_start, timeFmt) ' to ' ... datestr(sam.time_coverage_end, timeFmt)]; -[fPath fName fSuffix] = fileparts(sam.toolbox_input_file); +[~, fName, fSuffix] = fileparts(sam.toolbox_input_file); fName = [fName fSuffix]; -desc = [ sam.meta.site_id ... - ' - ' sam.meta.instrument_make ... - ' ' sam.meta.instrument_model ... - ' SN=' sam.meta.instrument_serial_no ... - ' @' num2str(sam.meta.depth) 'm' ... - ' ' timeRange ... - ' (' fName ')']; +switch detailLevel + case 'short' + desc = [ sam.meta.instrument_make ... + ' ' sam.meta.instrument_model ... + ' @' num2str(sam.meta.depth) 'm']; + + case 'medium' + desc = [ sam.meta.instrument_make ... + ' ' sam.meta.instrument_model ... + ' SN=' sam.meta.instrument_serial_no ... + ' @' num2str(sam.meta.depth) 'm' ... + ' (' fName ')']; + + otherwise + % full details + desc = [ sam.meta.site_id ... + ' - ' sam.meta.instrument_make ... + ' ' sam.meta.instrument_model ... + ' SN=' sam.meta.instrument_serial_no ... + ' @' num2str(sam.meta.depth) 'm' ... + ' ' timeRange ... + ' (' fName ')']; +end \ No newline at end of file diff --git a/AutomaticQC/readQCparameter.m b/Util/readDatasetParameter.m similarity index 56% rename from AutomaticQC/readQCparameter.m rename to Util/readDatasetParameter.m index a1c119bce..1c1f9c65f 100644 --- a/AutomaticQC/readQCparameter.m +++ b/Util/readDatasetParameter.m @@ -1,30 +1,30 @@ -function value = readQCparameter(rawDataFile, QCtest, param, value) -%READQCPARAMETER Return the value of the specified parameter from the QC -%parameter file associated to the raw data file. +function value = readDatasetParameter(rawDataFile, routine, param, value) +%READDATASETPARAMETER Returns the value of a specified parameter from the PP or QC +%parameter file associated to a raw data file. % % This function provides a simple interface to retrieve the values of -% parameters stored in a QC parameter file. +% parameters stored in a PP or QC parameter file. % -% A 'QC parameter' file is a 'mat' file which contains a pqc struct which -% fields are the name of a QC test and subfields the name of their parameters +% A 'parameter' file is a 'mat' file which contains a p structure which +% fields are the name of a PP or QC routine and subfields the name of their parameters % which contain this parameter value. % % Inputs: % -% rawDataFile - Name of the raw data file. Is used to build the QC -% property file name (same root but different extension). +% rawDataFile - Name of the raw data file. Is used to build the parameter +% file name (same root but different extension). % -% QCtest - Name of the QC test. If the name does not map to a QC -% test then the default value from (QCtest).txt is returned. +% routine - Name of the PP or QC routine. If the name does not map to any +% existing routine then the default value is returned. % -% param - Name of the QC test parameter to be retrieved. If the -% name does not map to a parameter listed in the QC test of -% the QC parameter file, an error is raised. +% param - Name of the routine parameter to be retrieved. If the +% name does not map to a parameter listed in the routine of +% the parameter file, an error is raised. % -% value - Value of the default QC parameter. +% value - Value of the default parameter. % % Outputs: -% value - Value of the dataset QC parameter. +% value - Value of the dataset parameter. % % Author: Guillaume Galibert % @@ -61,35 +61,54 @@ narginchk(4,4); if ~ischar(rawDataFile), error('rawDataFile must be a string'); end -if ~ischar(QCtest), error('QCtest must be a string'); end +if ~ischar(routine), error('routine must be a string'); end if ~ischar(param), error('param must be a string'); end -pqcFile = [rawDataFile, '.pqc']; +switch lower(routine(end-1:end)) + case 'qc' + pType = 'pqc'; + + case 'pp' + pType = 'ppp'; + + otherwise + return; +end +pFile = [rawDataFile, '.', pType]; % we need to migrate any remnants of the old file naming convention % for .pqc files. -[pqcPath, oldPqcFile, ~] = fileparts(rawDataFile); -oldPqcFile = fullfile(pqcPath, [oldPqcFile, '.pqc']); -if exist(oldPqcFile, 'file') - movefile(oldPqcFile, pqcFile); +[pPath, oldPFile, ~] = fileparts(rawDataFile); +oldPFile = fullfile(pPath, [oldPFile, '.', pType]); +if exist(oldPFile, 'file') + movefile(oldPFile, pFile); end +ppp = struct([]); pqc = struct([]); -if exist(pqcFile, 'file') - load(pqcFile, '-mat', 'pqc'); +if exist(pFile, 'file') + load(pFile, '-mat', pType); + + switch pType + case 'pqc' + p = pqc; + + case 'ppp' + p = ppp; + end - if isfield(pqc, QCtest) + if isfield(p, routine) if strcmpi(param, '*') - value{1} = fieldnames(pqc.(QCtest)); + value{1} = fieldnames(p.(routine)); for i=1:length(value{1}) - value{2}{i} = pqc.(QCtest).(value{1}{i}); + value{2}{i} = p.(routine).(value{1}{i}); end else - if isfield(pqc.(QCtest), param) - value = pqc.(QCtest).(param); + if isfield(p.(routine), param) + value = p.(routine).(param); else - error([param ' is not a parameter of ' QCtest]); + error([param ' is not a parameter of ' routine]); end end end diff --git a/AutomaticQC/writeQCparameter.m b/Util/writeDatasetParameter.m similarity index 58% rename from AutomaticQC/writeQCparameter.m rename to Util/writeDatasetParameter.m index 26922d5c4..4cba87db9 100644 --- a/AutomaticQC/writeQCparameter.m +++ b/Util/writeDatasetParameter.m @@ -1,12 +1,12 @@ -function writeQCparameter(rawDataFile, QCtest, param, value) -%WRITEQCPARAMETER Writes the value of the specified QC parameter to a QC -%parameter file associated to the raw data file. +function writeDatasetParameter(rawDataFile, routine, param, value) +%WRITEDATASETPARAMETER Writes the value of the specified parameter to a PP or QC +%parameter file associated to a raw data file. % % This function provides a simple interface to store the values of -% parameters in a QC parameter file. +% parameters in a PP or QC parameter file. % -% A 'QC parameter' file is a 'mat' file which contains a pqc struct which -% fields are the name of a QC test and subfields the name of their parameters +% A 'parameter' file is a 'mat' file which contains a p structure which +% fields are the name of a PP or QC routine and subfields the name of their parameters % which contain this parameter value. % % Inputs: @@ -14,14 +14,14 @@ function writeQCparameter(rawDataFile, QCtest, param, value) % rawDataFile - Name of the raw data file. Is used to build the QC % property file name (same root but different extension). % -% QCtest - Name of the QC test. If the name does not map to a QC -% test then an empty value is returned. +% routine - Name of the PP or QC routine. If the name does not map to +% any existing routine then an empty value is returned. % -% param - Name of the QC test parameter to be retrieved. If the -% name does not map to a parameter listed in the QC test of -% the QC parameter file, an error is raised. +% param - Name of the routine parameter to be retrieved. If the +% name does not map to a parameter listed in the routine of +% the parameter file, an error is raised. % -% value - Value of the parameter. +% value - Value of the parameter to be stored. % % Author: Guillaume Galibert % @@ -58,27 +58,48 @@ function writeQCparameter(rawDataFile, QCtest, param, value) narginchk(4,4); if ~ischar(rawDataFile), error('rawDataFile must be a string'); end -if ~ischar(QCtest), error('QCtest must be a string'); end +if ~ischar(routine), error('routine must be a string'); end if ~ischar(param), error('param must be a string'); end -pqcFile = [rawDataFile, '.pqc']; +switch lower(routine(end-1:end)) + case 'qc' + pType = 'pqc'; + + case 'pp' + pType = 'ppp'; + + otherwise + return; +end +pFile = [rawDataFile, '.', pType]; % we need to migrate any remnants of the old file naming convention % for .pqc files. -[pqcPath, oldPqcFile, ~] = fileparts(rawDataFile); -oldPqcFile = fullfile(pqcPath, [oldPqcFile, '.pqc']); -if exist(oldPqcFile, 'file') - movefile(oldPqcFile, pqcFile); +[pPath, oldPFile, ~] = fileparts(rawDataFile); +oldPFile = fullfile(pPath, [oldPFile, '.', pType]); +if exist(oldPFile, 'file') + movefile(oldPFile, pFile); end +ppp = struct([]); pqc = struct([]); -if exist(pqcFile, 'file'), load(pqcFile, '-mat', 'pqc'); end +if exist(pFile, 'file'), load(pFile, '-mat', pType); end -if isempty(pqc) - pqc(1).(QCtest).(param) = value; -else - pqc.(QCtest).(param) = value; +switch pType + case 'pqc' + if isempty(pqc) + pqc(1).(routine).(param) = value; + else + pqc.(routine).(param) = value; + end + + case 'ppp' + if isempty(pqc) + ppp(1).(routine).(param) = value; + else + ppp.(routine).(param) = value; + end end -save(pqcFile, 'pqc'); +save(pFile, pType); diff --git a/imosToolbox.m b/imosToolbox.m index 399eb7538..8a37cd47f 100644 --- a/imosToolbox.m +++ b/imosToolbox.m @@ -73,7 +73,7 @@ function imosToolbox(auto, varargin) end % Set current toolbox version -toolboxVersion = ['2.5.23 - ' computer]; +toolboxVersion = ['2.5.24 - ' computer]; switch auto case 'auto', autoIMOSToolbox(toolboxVersion, varargin{:}); diff --git a/imosToolbox_Linux64.bin b/imosToolbox_Linux64.bin index 789c55667..ef3e0fa8c 100755 Binary files a/imosToolbox_Linux64.bin and b/imosToolbox_Linux64.bin differ diff --git a/imosToolbox_Win32.exe b/imosToolbox_Win32.exe index d99fb9faa..c657bb858 100644 Binary files a/imosToolbox_Win32.exe and b/imosToolbox_Win32.exe differ diff --git a/imosToolbox_Win64.exe b/imosToolbox_Win64.exe index 26589abc2..b762808ba 100644 Binary files a/imosToolbox_Win64.exe and b/imosToolbox_Win64.exe differ