diff --git a/AutomaticQC/imosSalinityFromPTQC.m b/AutomaticQC/imosSalinityFromPTQC.m index feb2e83f5..bda37dad0 100644 --- a/AutomaticQC/imosSalinityFromPTQC.m +++ b/AutomaticQC/imosSalinityFromPTQC.m @@ -58,7 +58,7 @@ if ~strcmp(type, 'variables'), return; end -param = {'PSAL'}; +salinityName = {'PSAL'}; % let's handle the case we have multiple same param distinguished by "_1", % "_2", etc... @@ -73,7 +73,7 @@ end end -iParam = strcmpi(paramName, param); +iParam = strcmpi(paramName, salinityName); if any(iParam) % get the flag values with which we flag good and out of range data @@ -93,11 +93,16 @@ % initialise all flags to non QC'd flags = ones(lenData, 1, 'int8')*rawFlag; + depthFlags = ones(lenData, 1, 'int8')*rawFlag; + pressureFlags = ones(lenData, 1, 'int8')*rawFlag; % we look for flags from pressure, conductivity and temperature data to give them % to salinity as well - paramNames = {'DEPTH', 'PRES_REL', 'PRES', 'TEMP', 'CNDC'}; + paramNames = {'TEMP', 'CNDC'}; + depthName = {'DEPTH'}; + pressureNames = {'PRES_REL', 'PRES'}; + isDepth = false; for i=1:length(sample_data.(type)) % let's handle the case we have multiple same param distinguished by "_1", % "_2", etc... @@ -111,12 +116,30 @@ end end end - iParam = strcmpi(paramName, paramNames); - if any(iParam) + + if any(strcmpi(paramName, paramNames)) flags = max(flags, sample_data.(type){i}.flags(:)); end + + if any(strcmpi(paramName, pressureNames)) + pressureFlags = max(pressureFlags, sample_data.(type){i}.flags(:)); + end + + if any(strcmpi(paramName, depthName)) + isDepth = true; + depthFlags = max(depthFlags, sample_data.(type){i}.flags(:)); + end end + % in case DEPTH has been inferred from a neighbouring sensor when PRES + % or PRES_REL failed, we only consider DEPTH flags + if isDepth + flags = max(flags, depthFlags); + else + flags = max(flags, pressureFlags); + end + + if isMatrix % we fold the vector back into a matrix data = reshape(data, [len1, len2, len3]); diff --git a/Graph/checkMooringPresDiffs.m b/Graph/checkMooringPresDiffs.m index efb605ccc..4a36bf913 100644 --- a/Graph/checkMooringPresDiffs.m +++ b/Graph/checkMooringPresDiffs.m @@ -289,12 +289,14 @@ function checkMooringPresDiffs(sample_data, iSampleMenu, isQC, saveToFile, expor 'Layer', 'top'); if isPlottable + iOthersLogical = false(max(iOthers), 1); + iOthersLogical(iOthers) = true; iNan = isnan(hLineVar); if any(iNan) hLineVar(iNan) = []; instrumentDesc(iNan) = []; + iOthersLogical(iNan) = []; end - iOthers = iOthers - (min(iOthers)-1); datetick(hAxPressDiff, 'x', 'dd-mm-yy HH:MM:SS', 'keepticks'); datetick(hAxPress, 'x', 'dd-mm-yy HH:MM:SS', 'keepticks'); @@ -313,7 +315,7 @@ function checkMooringPresDiffs(sample_data, iSampleMenu, isQC, saveToFile, expor xscale = 0.75; end hYBuffer = 1.1 * (2*(fontSizeAx + fontSizeLb)); - hLegend = legendflex(hAxPress, instrumentDesc(iOthers),... + hLegend = legendflex(hAxPress, instrumentDesc(iOthersLogical),... 'anchor', [6 2], ... 'buffer', [0 -hYBuffer], ... 'ncol', nCols,... diff --git a/Graph/lineMooring1DVar.m b/Graph/lineMooring1DVar.m index 2815c0e38..3834eef52 100644 --- a/Graph/lineMooring1DVar.m +++ b/Graph/lineMooring1DVar.m @@ -261,7 +261,11 @@ function lineMooring1DVar(sample_data, varName, isQC, saveToFile, exportDir) qcParam = get(mWh, 'UserData'); yLim = get(hAxMooringVar, 'YLim'); for i=1:lenSampleData - if isfield(qcParam, 'inWater') + iVar = getVar(sample_data{iSort(i)}.(typeVar), varName); + + if iVar && isfield(qcParam, 'inWater') + dataVar = sample_data{iSort(i)}.(typeVar){iVar}.data; + line([qcParam(iSort(i)).inWater, qcParam(iSort(i)).inWater, NaN, qcParam(iSort(i)).outWater, qcParam(iSort(i)).outWater], ... [yLim, NaN, yLim], ... 'Parent', hAxMooringVar, ... @@ -271,9 +275,6 @@ function lineMooring1DVar(sample_data, varName, isQC, saveToFile, exportDir) iTime = getVar(sample_data{i}.dimensions, 'TIME'); xLine = sample_data{iSort(i)}.dimensions{iTime}.data; - iVar = getVar(sample_data{iSort(i)}.(typeVar), varName); - dataVar = sample_data{iSort(i)}.(typeVar){iVar}.data; - if strcmpi(varName, 'TIME') xLine(1) = []; dataVar = diff(dataVar)*24*3600; diff --git a/Preprocessing/depthPP.m b/Preprocessing/depthPP.m index ce3f84c7c..c6b51817a 100644 --- a/Preprocessing/depthPP.m +++ b/Preprocessing/depthPP.m @@ -568,10 +568,14 @@ iSecond = secondNearestInst(iCurSam); if iSecond == 0 && iFirst ~= 0 - tidalAmplitudeComment = ' Tidal amplitude is not accurate.'; + if sample_data{nearestInsts{iCurSam}(iFirst)}.meta.depth < sample_data{iCurSam}.meta.depth + warningDepthComment = ' Tidal amplitude is not accurate.'; + else + warningDepthComment = ' Mooring knock downs performed by strong current events are either not detected or inaccurate.'; + end fprintf('%s\n', ['Warning : ' descSam{iCurSam} ... ' has its actual depth inferred from only one neighbouring pressure sensor ' ... - 'on mooring.' tidalAmplitudeComment]); + 'on mooring.' warningDepthComment]); % we found only one sensor presIdxOther = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES'); presRelIdxOther = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES_REL'); @@ -595,43 +599,7 @@ 'precision at a deployed depth)']; end - % compute pressure at current sensor using trigonometry and - % assuming sensors repartition on a line between the - % nearest pressure sensor and the mooring's anchor - % - % the only drawback is that tidal amplitude is - % flattenned by static value of siteDepth - if isfield(sample_data{iCurSam}, 'site_nominal_depth') - if ~isempty(sample_data{iCurSam}.site_nominal_depth) - siteDepth = sample_data{iCurSam}.site_nominal_depth; - end - end - - if isfield(sample_data{iCurSam}, 'site_depth_at_deployment') - if ~isempty(sample_data{iCurSam}.site_depth_at_deployment) - siteDepth = sample_data{iCurSam}.site_depth_at_deployment; - end - end - - if isSensorTargetDepth - nominalHeightOther = siteDepth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; - nominalHeightCurSensor = siteDepth - sample_data{iCurSam}.instrument_nominal_depth; - else - nominalHeightOther = sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_height; - nominalHeightCurSensor = sample_data{iCurSam}.instrument_nominal_height; - end - - % theta is the angle between the vertical and line - % formed by the sensors - % - % cos(theta) = heightOther/nominalHeightOther - % and - % cos(theta) = heightCurSensor/nominalHeightCurSensor - % - % computedDepth = nominalSiteDepth - nominalHeightCurSensor * (nominalSiteDepth - zOther) / nominalHeightOther - % - % pressure = density*gravity*depth - % + % compute depth of the nearest sensor from its pressure 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) @@ -639,20 +607,20 @@ 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.06 from latitude and ' presComment '.' tidalAmplitudeComment]; + '(TEOS-10) v3.06 from latitude and ' presComment '.' warningDepthComment]; else 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); computedDepthComment = ['depthPP: Depth inferred from only one neighbouring pressure sensor ' ... descOtherSam{iCurSam}{iFirst + 1} ', using the Gibbs-SeaWater toolbox ' ... - '(TEOS-10) v3.06 from mean latitude and ' presComment '.' tidalAmplitudeComment]; + '(TEOS-10) v3.06 from mean latitude and ' presComment '.' warningDepthComment]; end else % without latitude information, we assume 1dbar ~= 1m zOther = relPresOther; computedDepthComment = ['depthPP: Depth inferred from only one neighbouring pressure sensor ' ... - descOtherSam{iCurSam}{iFirst + 1} ' with ' presComment ', assuming 1dbar ~= 1m.' tidalAmplitudeComment]; + descOtherSam{iCurSam}{iFirst + 1} ' with ' presComment ', assuming 1dbar ~= 1m.' warningDepthComment]; end clear relPresOther; @@ -664,8 +632,76 @@ zOther = interp1(tOther, zOther, tCur); clear tOther tCur; - computedDepth = siteDepth - nominalHeightCurSensor * (siteDepth - zOther) / nominalHeightOther; + if sample_data{nearestInsts{iCurSam}(iFirst)}.meta.depth < sample_data{iCurSam}.meta.depth + % compute pressure at current sensor using trigonometry and + % assuming sensors repartition on a line between the + % nearest pressure sensor and the mooring's anchor + % + % the only drawback is that tidal amplitude is + % flattenned by static value of siteDepth + if isfield(sample_data{iCurSam}, 'site_nominal_depth') + if ~isempty(sample_data{iCurSam}.site_nominal_depth) + siteDepth = sample_data{iCurSam}.site_nominal_depth; + end + end + + if isfield(sample_data{iCurSam}, 'site_depth_at_deployment') + if ~isempty(sample_data{iCurSam}.site_depth_at_deployment) + siteDepth = sample_data{iCurSam}.site_depth_at_deployment; + end + end + + if isSensorTargetDepth + nominalHeightOther = siteDepth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; + nominalHeightCurSensor = siteDepth - sample_data{iCurSam}.instrument_nominal_depth; + else + nominalHeightOther = sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_height; + nominalHeightCurSensor = sample_data{iCurSam}.instrument_nominal_height; + end + + % theta is the angle between the vertical and line + % formed by the sensors + % + % cos(theta) = heightOther/nominalHeightOther + % and + % cos(theta) = heightCurSensor/nominalHeightCurSensor + % + % computedDepth = nominalSiteDepth - nominalHeightCurSensor * (nominalSiteDepth - zOther) / nominalHeightOther + % + % pressure = density*gravity*depth + % + computedDepth = siteDepth - nominalHeightCurSensor * (siteDepth - zOther) / nominalHeightOther; + else + % compute pressure at current sensor assuming sensors + % repartition on a vertical line between current sensor + % and the nearest. This is the best we can do as we can't + % have any idea of the angle of the mooring with one + % pressure sensor. + % + % computedDepth = depthOther + distOtherCurSensor + % computedHeight = heightOther - distOtherCurSensor + % + % vertical axis is positive down when talking about + % depth + if isSensorTargetDepth + distOtherCurSensor = sample_data{iCurSam}.instrument_nominal_depth - sample_data{nearestInsts{iCurSam}(iFirst)}.instrument_nominal_depth; + signOtherCurSensor = sign(distOtherCurSensor); + + distOtherCurSensor = abs(distOtherCurSensor); + else + 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 + % -1 => current sensor is lower than other sensor + + distOtherCurSensor = abs(distOtherCurSensor); + end + + computedDepth = zOther + signOtherCurSensor*distOtherCurSensor; + end clear zOther; + elseif iSecond ~= 0 && iFirst ~= 0 presIdxFirst = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES'); presRelIdxFirst = getVar(sample_data{nearestInsts{iCurSam}(iFirst)}.variables, 'PRES_REL'); diff --git a/Preprocessing/rinkoDoPP.m b/Preprocessing/rinkoDoPP.m index dad6747de..58439f7c6 100644 --- a/Preprocessing/rinkoDoPP.m +++ b/Preprocessing/rinkoDoPP.m @@ -95,6 +95,11 @@ else if depthIdx > 0 depth = sam.(depthType){depthIdx}.data; + + % any depth values <= -5 are discarded (reminder, depth is + % positive down), this allow use of gsw_p_from_z without error. + depth(depth <= -5) = NaN; + if ~isempty(sam.geospatial_lat_min) && ~isempty(sam.geospatial_lat_max) % compute depth with Gibbs-SeaWater toolbox % relative_pressure ~= gsw_p_from_z(-depth, latitude) diff --git a/imosToolbox.m b/imosToolbox.m index c3091c8c5..48467b6ad 100644 --- a/imosToolbox.m +++ b/imosToolbox.m @@ -37,7 +37,7 @@ function imosToolbox(auto, varargin) % % Set current toolbox version -toolboxVersion = ['2.5.34 - ' computer]; +toolboxVersion = ['2.5.35 - ' computer]; if nargin == 0, auto = 'manual'; end diff --git a/imosToolbox_Linux64.bin b/imosToolbox_Linux64.bin index 02cc016e1..8ddc50716 100755 Binary files a/imosToolbox_Linux64.bin and b/imosToolbox_Linux64.bin differ diff --git a/imosToolbox_Win32.exe b/imosToolbox_Win32.exe index ef3ec6db0..2173b8ce7 100644 Binary files a/imosToolbox_Win32.exe and b/imosToolbox_Win32.exe differ diff --git a/imosToolbox_Win64.exe b/imosToolbox_Win64.exe index 080adf87a..69a2c7a35 100644 Binary files a/imosToolbox_Win64.exe and b/imosToolbox_Win64.exe differ