% ------------------------------------------------------------------------------
% Convert DM NetCDF mono-profie files from format version V2.2, V2.3 or V3.0
% into format version V3.1. The NetCDF schema is given by associated RT V3.1
% file generated by the Matlab decoder.
% All the needed information is also added to the output file so that it is
% compliant to V3.1 decoder output files.
%
% SYNTAX :
%   nc_update_dm_mono_profile_prv_to_V3_1 or nc_update_dm_mono_profile_prv_to_V3_13(6900189, 7900118)
%
% INPUT PARAMETERS :
%   varargin : WMO number of floats to process
%
% OUTPUT PARAMETERS :
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   07/29/2014 - RNU - creation
%   05/12/2015 - RNU - V 2.1:
%      since the Arvor ARN float version the Argos float configuration
%      management has been modified and the get_cutoff_pres function of this
%      tool has been updated accordingly
%   05/12/2015 - RNU - V 2.2:
%      if the DM output file has no primary profile, we create a 'default' one
%      (from secondary profile information) - the GDAC checker rejects files
%      with all profile variables set to fillValue (for a given profile)
%   05/21/2015 - RNU - V 2.3:
%      - 1 bug while computing PROFILE_PARAM_QC
%      - 2 'on the fly' corrections of input DM data:
%         #1- from Argo Quality Control Manual V2.9.1: Please note that whenever
%             PARAM_ADJUSTED_QC = ‘4’, both PARAM_ADJUSTED and
%             PARAM_ADJUSTED_ERROR should be set to FillValue
%         #2- if PRES_QC = '0' set PRES_QC = '1'
%   06/08/2015 - RNU - V 2.4:
%      - 1 bug in number of input DM parameters => the SCIENTIFIC_CALIB_* are
%        not copied for some parameters (the last one of the DM input file)
%      - 2 'on the fly' corrections of input DM data:
%         #3- if TEMP_QC = '0' and TEMP parameter has been adjusted then
%             duplicate TEMP_ADJUSTED_QC in TEMP_QC
%         #4- if <PARAM>_ADJUSTED ~= fillValue and
%             <PARAM>_ADJUSTED_ERROR == fillValue then
%             <PARAM>_ADJUSTED_ERROR == error value (retrieve from existing
%             error values (should be unique))
%   06/10/2015 - RNU - V 2.5:
%      - 1 bug when corrections #1 and #4 are done on the same profile (the data
%        were corrected in the output file but the modifications were not
%        reported in memory)
%      - 2 'on the fly' corrections of input DM data:
%         #5- if <PARAM> = fillValue and <PARAM>_QC ~= ' ' and <PARAM>_QC ~= '9'
%             then <PARAM>_QC = '9'
%         #6- if <PARAM>_ADJUSTED = fillValue and <PARAM>_QC ~= ' ' and
%             <PARAM>_QC ~= '9' and <PARAM>_QC ~= '4' then
%             <PARAM>_ADJUSTED_QC = '9'
%         #7- if <PARAM>_ADJUSTED = fillValue then
%             <PARAM>_ADJUSTED_ERROR = fillValue
%   06/15/2015 - RNU - V 2.6:
%      For Argos floats, the profile cut-off pressure can be computed from the
%      CTD pump cut-off pressure (configuration parameter stored in the JSON
%      meta-data file of the float).
%      For Iridium floats, the profile cut-off pressure is transmitted by the
%      float and stored in the TECH nc file (with the label
%      'PRES_LastAscentPumpedRawSample_dbar').
%      The get_cutoff_pres function has been modified accordingly.
%   09/07/2015 - RNU - V 2.7:
%      Correction #8: 'on the fly' correction of output DM data.
%      For each PARAMETER of the output file:
%      - if empty, set SCIENTIFIC_CALIB_DATE to the DATE_UPDATE of the input DM
%        file.
%      - if empty, set SCIENTIFIC_CALIB_COMMENT to 'none'.
%   10/21/2015 - RNU - V 2.8:
%      In the 'history' global attribute "last update (coriolis float real time
%      data processing)" replaced by "last update (coriolis COFC software)".
%      Correction #9: 'on the fly' correction of output DM data.
%      - if JULD > DATE_CREATION set DATE_CREATION = JULD
%   10/04/2015 - RNU - V 2.9:
%      Correction #10: 'on the fly' correction of output DM data.
%      - if PSAL ~= fillValue and PSAL_ADJUSTED == fillValue
%        then PSAL_ADJUSTED_QC = '4'
%   11/20/2018 - RNU - V 3.0:
%      Correction #12: 'on the fly' correction of output DM data.
%      - correct HISTORY_DATE and SCIENTIFIC_CALIB_DATE (or
%        CALIBRATION_DATE) (format YYYYMMDDHHMISS) when SS = 60
% ------------------------------------------------------------------------------
% Version 2.2 (AUM 2.2 08/21/2009
%  - FIRMWARE_VERSION is missing in Coriolis files
%
% Version 2.3 (AUM 2.3 07/13/2010)
% (similar to V 2.3 AUM 2.31 07/13/2010 for variables and dimensions)
%  - V 3.0 global attributes are in Coriolis files
%  - V 3.0 VERTICAL_SAMPLING_SCHEME is in Coriolis files
%  - V 3.0 SCIENTIFIC_CALIB_DATE as already replaced CALIBRATION_DATE in Coriolis files
%
% Version 3.0 (AUM 3.0 05/03/2013)
%  - Global attributes appear
%  - VERTICAL_SAMPLING_SCHEME appears
%  - CALIBRATION_DATE replaced by SCIENTIFIC_CALIB_DATE
%
% Version 3.0 (AUM 3.01 06/28/2013)
% (similar to V 3.0 AUM 3.02 06/28/2013 for variables and dimensions)
% (similar to V 3.0 AUM 3.03 08/28/2013 for variables and dimensions)
%  - INST_REFERENCE disappears
%  - PLATFORM_TYPE appears
%  - FLOAT_SERIAL_NO appears
%  - CONFIG_MISSION_NUMBER appears
%
% At Coriolis, in V 3.0 AUM 3.03 08/28/2013 FLOAT_SERIAL_NO string length has
% been enlarged (to store data base contents):
% FLOAT_SERIAL_NO(N_PROF, STRING32) instead of FLOAT_SERIAL_NO(N_PROF, STRING16)
% ------------------------------------------------------------------------------
function nc_update_dm_mono_profile_prv_to_V3_1(varargin)

% top directory of input DM NetCDF mono-profile files to update
% DIR_INPUT_DM_NC_FILES = 'C:\users\RNU\Argo\work\DM_data_to_update\';
% DIR_INPUT_DM_NC_FILES = 'E:\HDD\_liv_bascule\Lpo\Actions_4_et_5_DM_co_2_DM_3.1\DM_data_to_update_20140728\';
% DIR_INPUT_DM_NC_FILES = 'E:\DM_3.1\DM_data_to_update_20150202\';
% DIR_INPUT_DM_NC_FILES = 'C:\Users\jprannou\_DATA\IN\DM_data_to_update_20150202\';
% DIR_INPUT_DM_NC_FILES = 'C:\Users\jprannou\_DATA\IN\tmp_20151021\dm\';
DIR_INPUT_DM_NC_FILES = 'E:\archive_201505\coriolis\selected\';

% top directory of input RT NetCDF mono-profile files
% DIR_INPUT_RT_NC_FILES = 'C:\users\RNU\Argo\work\nc_output_decPrv_argos\';
% DIR_INPUT_RT_NC_FILES = 'E:\nc_output_decPrv_argos_20150129\';
% DIR_INPUT_RT_NC_FILES = 'C:\Users\jprannou\_DATA\OUT\nc_output_decPrv\';
% DIR_INPUT_RT_NC_FILES = 'C:\Users\jprannou\_DATA\IN\tmp_20151021\rt\';
DIR_INPUT_RT_NC_FILES = 'E:\archive_201510\201510-ArgoData\DATA\coriolis\selected\';

% top directory of output NetCDF mono-profile files
% DIR_OUTPUT_NC_FILES = 'C:\users\RNU\Argo\work\nc_output_updated_tmp2\';
% DIR_OUTPUT_NC_FILES = 'E:\DM_3.1\DM_updated_data_20150202\';
% DIR_OUTPUT_NC_FILES = 'C:\Users\jprannou\_DATA\OUT\DM_updated_data\';
% DIR_OUTPUT_NC_FILES = 'C:\Users\jprannou\_DATA\IN\tmp_20151021\out\';
DIR_OUTPUT_NC_FILES = 'C:\Users\jprannou\_DATA\OUT\DM_updated_data_bis_20151003\';

% directory to store the log file
DIR_LOG_FILE = 'C:\Users\jprannou\_RNU\DecArgo_soft\work\log\';

% default list of floats to process
% FLOAT_LIST_FILE_NAME = 'C:/users/RNU/Argo/Aco/12833_update_decPrv_pour_RT_TRAJ3/lists/nke_all_with_DM_b_file.txt';
% FLOAT_LIST_FILE_NAME = 'C:/users/RNU/Argo/Aco/12833_update_decPrv_pour_RT_TRAJ3/lists/nke_all_with_DM.txt';
FLOAT_LIST_FILE_NAME = 'C:\Users\jprannou\_RNU\DecArgo_soft\lists\nke_all_with_DM_bis_20151003.txt';

% list to link DM and RT cycle numbers
% DM_2_RT_FILE_NAME = 'C:\Users\jprannou\_RNU\DecArgo_soft\work\DM_2_RT_link.txt';
% DM_2_RT_FILE_NAME = 'C:\Users\jprannou\_RNU\DecArgo_soft\work\DM_2_RT_link_for_Arvor_Ir.txt';
DM_2_RT_FILE_NAME = 'C:\Users\jprannou\_RNU\DecArgo_soft\work\DM_2_RT_link_bis_20151003.txt';

% directory of JSON float info files
DIR_JSON_FLOAT_INFO = 'C:\Users\jprannou\_RNU\DecArgo_soft\work/json_float_info/';

% directory of JSON float meta-data
DIR_JSON_FLOAT_META = 'C:\Users\jprannou\_RNU\DecArgo_soft\work/json_float_meta_argos/';

% program version
global g_cofc_ncConvertMonoProfileVersion;
g_cofc_ncConvertMonoProfileVersion = '3.0';

% default values initialization
init_default_values;


% input parameters management
if (nargin == 0)
   % floats to process come from FLOAT_LIST_FILE_NAME
   floatListFileName = FLOAT_LIST_FILE_NAME;
   if ~(exist(floatListFileName, 'file') == 2)
      fprintf('ERROR: File not found: %s\n', floatListFileName);
      return
   end
   
   fprintf('Floats from list: %s\n', floatListFileName);
   floatList = textread(floatListFileName, '%d');
else
   % floats to process come from input parameters
   floatList = cell2mat(varargin);
end

% create and start log file recording
if (nargin == 0)
   [pathstr, name, ext] = fileparts(floatListFileName);
   name = ['_' name];
else
   name = sprintf('_%d', floatList);
end

logFile = [DIR_LOG_FILE '/' 'nc_update_dm_mono_profile_prv_to_V3_1' name '_' datestr(now, 'yyyymmddTHHMMSS') '.log'];
diary(logFile);
tic;

fprintf('PARAMETERS:\n');
fprintf('   Input DM files directory: %s\n', DIR_INPUT_DM_NC_FILES);
fprintf('   Input RT files directory: %s\n', DIR_INPUT_RT_NC_FILES);
fprintf('   Output files directory: %s\n', DIR_OUTPUT_NC_FILES);
fprintf('   File to link DM and RT data: %s\n', DM_2_RT_FILE_NAME);
fprintf('   Log file directory: %s\n', DIR_LOG_FILE);
if (nargin == 0)
   fprintf('   List of floats to process: %s\n', FLOAT_LIST_FILE_NAME);
else
   fprintf('   Floats to process:');
   fprintf(' %d', floatList);
   fprintf('\n');
end
fprintf('   JSON float information files directory: %s\n', DIR_JSON_FLOAT_INFO);
fprintf('   JSON float meta-data files directory: %s\n', DIR_JSON_FLOAT_META);

% read link information
link = load(DM_2_RT_FILE_NAME);
floatWmoList = link(:, 1);
profDirList = link(:, 2);
dmCyNumList = link(:, 3);
rtCyNumList = link(:, 4);

% create the output directory
if ~(exist(DIR_OUTPUT_NC_FILES, 'dir') == 7)
   mkdir(DIR_OUTPUT_NC_FILES);
end

% process the floats
nbFloats = length(floatList);
for idFloat = 1:nbFloats
   
   floatNum = floatList(idFloat);
   fprintf('%03d/%03d %d\n', idFloat, nbFloats, floatNum);
   
   % retrieve the cut off pressure of the CTD profile
   [cutOffPresVal, cutOffPresCy] = get_cutoff_pres(floatNum, ...
      DIR_JSON_FLOAT_INFO, DIR_JSON_FLOAT_META, ...
      DIR_INPUT_RT_NC_FILES);
   if (isempty(cutOffPresVal))
      fprintf('ERROR: Unable to compute PCutOff, DM files not converted for float #%d\n', floatNum);
      continue
   end
   
   dmInFloatPath = [DIR_INPUT_DM_NC_FILES '/' sprintf('/%d/profiles/', floatNum)];
   rtInFloatPath = [DIR_INPUT_RT_NC_FILES '/' sprintf('/%d/profiles/', floatNum)];
   dmOutFloatPath = [DIR_OUTPUT_NC_FILES '/' sprintf('/%d/profiles/', floatNum)];
   
   % create the float output directory
   if ~(exist(dmOutFloatPath, 'dir') == 7)
      mkdir(dmOutFloatPath);
   end
   
   % process the files for this float
   idForWmo = find(floatWmoList == floatNum);
   %    for idFile = 1:min(3, length(idForWmo))
   for idFile = 1:length(idForWmo)
      direct = '';
      if (profDirList(idForWmo(idFile)) == 2)
         direct = 'D';
      end
      
      dmInFilePathName = [dmInFloatPath sprintf('D%d_%03d%s.nc', floatNum, dmCyNumList(idForWmo(idFile)), direct)];
      rtInCFilePathName = [rtInFloatPath sprintf('R%d_%03d%s.nc', floatNum, rtCyNumList(idForWmo(idFile)), direct)];
      rtInBFilePathName = [rtInFloatPath sprintf('BR%d_%03d%s.nc', floatNum, rtCyNumList(idForWmo(idFile)), direct)];
      dmOutCFilePathName = [dmOutFloatPath sprintf('D%d_%03d%s.nc', floatNum, rtCyNumList(idForWmo(idFile)), direct)];
      dmOutBFilePathName = [dmOutFloatPath sprintf('BD%d_%03d%s.nc', floatNum, rtCyNumList(idForWmo(idFile)), direct)];
      
      if ((exist(dmInFilePathName, 'file') == 2) && ...
            (exist(rtInCFilePathName, 'file') == 2))
         
         bFileFlag = 0;
         if (exist(rtInBFilePathName, 'file') == 2)
            bFileFlag = 1;
            %             fprintf('INFO: B file => exit\n');
            %             continue
         end
         
         % update the file
         [ok] = update_dm_file(dmInFilePathName, ...
            rtInCFilePathName, rtInBFilePathName, ...
            dmOutCFilePathName, dmOutBFilePathName, ...
            profDirList(idForWmo(idFile)), ...
            cutOffPresVal, cutOffPresCy, rtCyNumList(idForWmo(idFile)), ...
            bFileFlag, ...
            floatNum, DIR_JSON_FLOAT_INFO, DIR_JSON_FLOAT_META);
         
      else
         fprintf('ERROR: Some input file is missing\n');
      end
   end
end

ellapsedTime = toc;
fprintf('done (Elapsed time is %.1f seconds)\n', ellapsedTime);

diary off;

return

% ------------------------------------------------------------------------------
% Convert a given DM NetCDF mono-profie files from format version V2.2, V2.3 or V3.0
% into format version V3.1. The NetCDF schema is given by associated RT V3.1
% file generated by the Matlab decoder.
%
% SYNTAX :
%  [o_ok] = update_dm_file(a_inputDmFileName, ...
%    a_inputRtCFileName, a_inputRtBFileName, ...
%    a_outputCFileName, a_outputBFileName, ...
%    a_direction, a_cutOffPresVal, a_cutOffPresCy, a_rtCyNum, a_bFileFlag, ...
%    a_floatNum, a_jsonFloatInfoDirName, a_jsonFloatMetaDirName)
%
% INPUT PARAMETERS :
%   a_inputDmFileName      : mono-profile NetCDF input DM file name
%   a_inputRtCFileName     : mono-profile NetCDF input RT c file name
%   a_inputRtBFileName     : mono-profile NetCDF input RT b file name
%   a_outputCFileName      : mono-profile NetCDF output DM c file name
%   a_outputBFileName      : mono-profile NetCDF output DM b file name
%   a_direction            : profile direction (1 for ascending, 2 for
%                            descending)
%   a_cutOffPresVal        : profile cut-off pressures
%   a_cutOffPresCy         : cycles associated to profile cut-off pressures
%   a_rtCyNum              : RT cycle number
%   a_bFileFlag            : b file flag (1 if a b file has to be created, 0
%                            otherwise)
%   a_floatNum             : float WMO number
%   a_jsonFloatInfoDirName : directory name of float JSON information files
%   a_jsonFloatMetaDirName : directory name of float JSON meta-data files
%
% OUTPUT PARAMETERS :
%   o_ok : success flag (1 if Ok, 0 otherwise)
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   07/29/2014 - RNU - creation
% ------------------------------------------------------------------------------
function [o_ok] = update_dm_file(a_inputDmFileName, ...
   a_inputRtCFileName, a_inputRtBFileName, ...
   a_outputCFileName, a_outputBFileName, ...
   a_direction, a_cutOffPresVal, a_cutOffPresCy, a_rtCyNum, a_bFileFlag, ...
   a_floatNum, a_jsonFloatInfoDirName, a_jsonFloatMetaDirName)

% output parameters initialization
o_ok = 0;

% program version
global g_cofc_ncConvertMonoProfileVersion;

% default values
global g_decArgo_janFirst1950InMatlab;

% QC flag values (char)
global g_decArgo_qcStrDef;

% QC flag values (char)
global g_decArgo_qcStrNoQc;
global g_decArgo_qcStrGood;
global g_decArgo_qcStrBad;
global g_decArgo_qcStrMissing;


% retrieve information from input DM file
wantedInputVars = [ ...
   {'FORMAT_VERSION'} ...
   {'STATION_PARAMETERS'} ...
   {'PRES'} ...
   {'PARAMETER'} ...
   {'HISTORY_INSTITUTION'} ...
   ];
[inputDmData] = get_data_from_nc_file(a_inputDmFileName, wantedInputVars);

idVal = find(strcmp('FORMAT_VERSION', inputDmData(1:2:end)) == 1, 1);
inputFileFormatVersionStr = strtrim(inputDmData{2*idVal}');

% fprintf(' (format version %s)\n', inputFileFormatVersionStr);

% check the format version of the input file
if ((strcmp(inputFileFormatVersionStr, '3.0') == 0) && ...
      (strcmp(inputFileFormatVersionStr, '2.3') == 0) && ...
      (strcmp(inputFileFormatVersionStr, '2.2') == 0))
   [~, fileName, fileExt] = fileparts(a_inputDmFileName);
   fprintf('ERROR: Input DM file (%s) is expected to be of 2.2 or 2.3 or 3.0 format version (but FORMAT_VERSION = %s)', ...
      [fileName fileExt], inputFileFormatVersionStr);
   return
end
inputFileFormatVersion = str2num(inputFileFormatVersionStr);

% create the list of parameters
idVal = find(strcmp('STATION_PARAMETERS', inputDmData(1:2:end)) == 1, 1);
stationParameters = inputDmData{2*idVal};
[~, inputNParam, inputNProf] = size(stationParameters);
inputDmParamList = [];
for idProf = 1:inputNProf
   for idParam = 1:inputNParam
      param = deblank(stationParameters(:, idParam, idProf)');
      if (~isempty(param))
         inputDmParamList{end+1} = param;
      end
   end
end
inputDmParamList = sort(unique(inputDmParamList));
nParamDimInput = length(inputDmParamList);

% retrieve information from input RT file
wantedInputVars = [ ...
   {'STATION_PARAMETERS'} ...
   ];
[inputRtData] = get_data_from_nc_file(a_inputRtCFileName, wantedInputVars);

% create the list of parameters
idVal = find(strcmp('STATION_PARAMETERS', inputRtData(1:2:end)) == 1, 1);
stationParameters = inputRtData{2*idVal};
[~, inputNParam, inputNProf] = size(stationParameters);
inputRtParamList = [];
for idProf = 1:inputNProf
   for idParam = 1:inputNParam
      param = deblank(stationParameters(:, idParam, idProf)');
      if (~isempty(param))
         inputRtParamList{end+1} = param;
      end
   end
end
inputRtParamList = sort(unique(inputRtParamList));

if (a_bFileFlag == 1)
   
   wantedInputVars = [ ...
      {'STATION_PARAMETERS'} ...
      ];
   [inputRtData] = get_data_from_nc_file(a_inputRtBFileName, wantedInputVars);
   
   % create the list of parameters
   idVal = find(strcmp('STATION_PARAMETERS', inputRtData(1:2:end)) == 1, 1);
   stationParameters = inputRtData{2*idVal};
   [~, inputNParam, inputNProf] = size(stationParameters);
   for idProf = 1:inputNProf
      for idParam = 1:inputNParam
         param = deblank(stationParameters(:, idParam, idProf)');
         if (~isempty(param))
            inputRtParamList{end+1} = param;
         end
      end
   end
   inputRtParamList = sort(unique(inputRtParamList));
end

inputDmMissingParamList = [];
rtParamInDm = zeros(length(inputRtParamList), 1);
for idP = 1:length(inputDmParamList)
   idF = find(strcmp(inputDmParamList{idP}, inputRtParamList) == 1);
   if (~isempty(idF))
      rtParamInDm(idF) = 1;
   else
      [~, dmFileName, dmFileExt] = fileparts(a_inputDmFileName);
      [~, rtFileName, rtFileExt] = fileparts(a_inputRtCFileName);
      fprintf('ERROR: Parameter %s is in input DM file but missing in input RT file. [DM file: %s] [RT file: (B)%s]\n', ...
         inputDmParamList{idP}, ...
         [dmFileName dmFileExt], [rtFileName rtFileExt]);
   end
end
idF = find(rtParamInDm == 0);
for idP = 1:length(idF)
   [~, dmFileName, dmFileExt] = fileparts(a_inputDmFileName);
   [~, rtFileName, rtFileExt] = fileparts(a_inputRtCFileName);
   fprintf('ERROR: Parameter %s is in input RT file but missing in input DM file. [DM file: %s] [RT file: (B)%s]\n', ...
      inputRtParamList{idF(idP)}, ...
      [dmFileName dmFileExt], [rtFileName rtFileExt]);
   
   % add it into the list to create empty variable in output file
   inputDmParamList{end+1} = inputRtParamList{idF(idP)};
   inputDmParamList = sort(unique(inputDmParamList));
   inputDmMissingParamList{end+1} = inputRtParamList{idF(idP)};
end

% find the dimensions N_PROF, N_PARAM, N_LEVELS, N_HISTORY and N_CALIB of the
% output file

% N_PROF and N_LEVELS dimensions

% retrieve PRES measurements from Input DM file
nLevelsSecondary = 0;
primaryProfInOutput = 1;
idVal = find(strcmp('PRES', inputDmData(1:2:end)) == 1, 1);
inputFilePres = inputDmData{2*idVal};
if (a_direction == 2)
   % descending profile
   nProfDimOutput = 1;
   nLevDimOutput = length(inputFilePres);
   nLevelsPrimary = length(inputFilePres);
else
   % ascending profile
   if (isempty(a_cutOffPresCy))
      % the profile cut-off pressure doesn't depend on cycle numbers (Argos
      % floats)
      cutOffPres = a_cutOffPresVal;
   else
      % the profile cut-off pressure depends on cycle numbers (Iridium floats)
      idF = find(a_cutOffPresCy == a_rtCyNum);
      if (length(idF) == 1)
         cutOffPres = a_cutOffPresVal(idF);
      else
         fprintf('WARNING: Float #%d: Unable to find the profile cut-off pressure for cycle #%d - profile not cut\n', ...
            a_floatNum, a_rtCyNum);
         cutOffPres = -9999;
      end
   end
   
   % ascending profile
   nLevelsPrimary = length(find(inputFilePres > cutOffPres));
   nLevelsSecondary = length(find(inputFilePres <= cutOffPres));
   if (nLevelsSecondary > 0)
      % there is a near-surface profile
      nProfDimOutput = 2;
      nLevDimOutput = max(nLevelsPrimary, nLevelsSecondary);
      if (nLevelsPrimary == 0)
         primaryProfInOutput = 0;
      end
   else
      nProfDimOutput = 1;
      nLevDimOutput = length(inputFilePres);
   end
end

% N_PARAM dimension
if (a_bFileFlag == 0)
   nParamDimCOutput = length(inputDmParamList);
else
   nParamDimCOutput = 0;
   nParamDimBOutput = 1;
   for idP = 1:length(inputDmParamList)
      param = get_netcdf_param_attributes_3_1(inputDmParamList{idP});
      if ((param.paramType == 'c') || (param.paramType == 'j'))
         nParamDimCOutput = nParamDimCOutput + 1;
      else
         nParamDimBOutput = nParamDimBOutput + 1;
      end
   end
end

% N_HISTORY dimension

% retrieve N_HISTORY dimension from input DM file
idVal = find(strcmp('HISTORY_INSTITUTION', inputDmData(1:2:end)) == 1, 1);
inputHistoInstitution = inputDmData{2*idVal};
[~, ~, nHistoryDimOutput] = size(inputHistoInstitution);

% N_CALIB dimension

% retrieve N_CALIB dimension from input DM file
idVal = find(strcmp('PARAMETER', inputDmData(1:2:end)) == 1, 1);
inputParameter = inputDmData{2*idVal};
[~, ~, nCalibDimOutput, ~] = size(inputParameter);

% retrieve file schema from input RT file
outputCFileSchema = ncinfo(a_inputRtCFileName);
if (a_bFileFlag == 1)
   outputBFileSchema = ncinfo(a_inputRtBFileName);
end

% update output file schema with the correct dimensions (no need for N_HISTORY
% which is the unlimited dimension)
[outputCFileSchema] = update_dim_in_nc_schema(outputCFileSchema, ...
   'N_PROF', nProfDimOutput);
[outputCFileSchema] = update_dim_in_nc_schema(outputCFileSchema, ...
   'N_LEVELS', nLevDimOutput);
[outputCFileSchema] = update_dim_in_nc_schema(outputCFileSchema, ...
   'N_PARAM', nParamDimCOutput);
[outputCFileSchema] = update_dim_in_nc_schema(outputCFileSchema, ...
   'N_CALIB', nCalibDimOutput);
if (a_bFileFlag == 1)
   [outputBFileSchema] = update_dim_in_nc_schema(outputBFileSchema, ...
      'N_PROF', nProfDimOutput);
   [outputBFileSchema] = update_dim_in_nc_schema(outputBFileSchema, ...
      'N_LEVELS', nLevDimOutput);
   [outputBFileSchema] = update_dim_in_nc_schema(outputBFileSchema, ...
      'N_PARAM', nParamDimBOutput);
   [outputBFileSchema] = update_dim_in_nc_schema(outputBFileSchema, ...
      'N_CALIB', nCalibDimOutput);
end

% create output files
ncwriteschema(a_outputCFileName, outputCFileSchema);
if (a_bFileFlag == 1)
   ncwriteschema(a_outputBFileName, outputBFileSchema);
end

% retrieve information from input DM file
wantedInputVars = [ ...
   {'DATE_CREATION'} ...
   {'DATE_UPDATE'} ...
   {'DATA_CENTRE'} ...
   {'DC_REFERENCE'} ...
   {'DATA_STATE_INDICATOR'} ...
   {'DATA_MODE'} ...
   {'PARAMETER'} ...
   {'SCIENTIFIC_CALIB_EQUATION'} ...
   {'SCIENTIFIC_CALIB_COEFFICIENT'} ...
   {'SCIENTIFIC_CALIB_COMMENT'} ...
   {'HISTORY_INSTITUTION'} ...
   {'HISTORY_STEP'} ...
   {'HISTORY_SOFTWARE'} ...
   {'HISTORY_SOFTWARE_RELEASE'} ...
   {'HISTORY_REFERENCE'} ...
   {'HISTORY_DATE'} ...
   {'HISTORY_ACTION'} ...
   {'HISTORY_PARAMETER'} ...
   {'HISTORY_START_PRES'} ...
   {'HISTORY_STOP_PRES'} ...
   {'HISTORY_PREVIOUS_VALUE'} ...
   {'HISTORY_QCTEST'} ...
   ];
if (inputFileFormatVersion == 2.2)
   wantedInputVars = [ ...
      wantedInputVars ...
      {'CALIBRATION_DATE'} ...
      ];
elseif (inputFileFormatVersion == 2.3)
   wantedInputVars = [ ...
      wantedInputVars ...
      {'FIRMWARE_VERSION'} ... % missing in 2.2 for Coriolis floats
      {'SCIENTIFIC_CALIB_DATE'} ... % for Coriolis floats
      ];
elseif (inputFileFormatVersion == 3.0)
   wantedInputVars = [ ...
      wantedInputVars ...
      {'FIRMWARE_VERSION'} ... % missing in 2.2 for Coriolis floats
      {'SCIENTIFIC_CALIB_DATE'} ...
      ];
end
for idParam = 1:length(inputDmParamList)
   paramName = inputDmParamList{idParam};
   profParamQcName = ['PROFILE_' paramName '_QC'];
   paramNameQc = [paramName '_QC'];
   paramNameAdj = [paramName '_ADJUSTED'];
   paramNameAdjQc = [paramName '_ADJUSTED_QC'];
   paramNameAdjErr = [paramName '_ADJUSTED_ERROR'];
   wantedInputVars = [ ...
      wantedInputVars ...
      {paramName} ...
      {profParamQcName} ...
      {paramNameQc} ...
      {paramNameAdj} ...
      {paramNameAdjQc} ...
      {paramNameAdjErr} ...
      ];
end
[inputDmData] = get_data_from_nc_file(a_inputDmFileName, wantedInputVars);

% correction #12: correct HISTORY_DATE and SCIENTIFIC_CALIB_DATE (or
% CALIBRATION_DATE) (format YYYYMMDDHHMISS) when SS = 60
idVal = find(strcmp('HISTORY_DATE', inputDmData(1:2:end)) == 1, 1);
if (~isempty(idVal))
   updated = 0;
   inputDmDate = inputDmData{2*idVal};
   % HISTORY_DATE(N_HISTORY, N_PROF, DATE_TIME)
   for idNHistory = 1:size(inputDmDate, 3)
      for idNProf = 1:size(inputDmDate, 2)
         curDate = inputDmDate(:, idNProf, idNHistory)';
         if (~isempty(deblank(curDate)))
            if ((length(deblank(curDate)) == 14) && strcmp(curDate(end-1:end), '60'))
               curDateNum = datenum(curDate, 'yyyymmddHHMMSS');
               newDate = datestr(curDateNum, 'yyyymmddHHMMSS');
               inputDmDate(:, idNProf, idNHistory) = newDate';
               updated = 1;
               
               fprintf('INFO: input ''HISTORY_DATE'' value (%s) updated to (%s) from input DM file %s\n', ...
                  curDate, newDate, a_inputDmFileName);
            end
         end
      end
   end
   if (updated == 1)
      inputDmData{2*idVal} = inputDmDate;
   end
end
inputDmDate = [];
idVal = find(strcmp('SCIENTIFIC_CALIB_DATE', inputDmData(1:2:end)) == 1, 1);
if (~isempty(idVal))
   inputDmDate = inputDmData{2*idVal};
else
   idVal = find(strcmp('CALIBRATION_DATE', inputDmData(1:2:end)) == 1, 1);
   if (~isempty(idVal))
      inputDmDate = inputDmData{2*idVal};
   end
end
if (~isempty(inputDmDate))
   updated = 0;
   inputDmDate = inputDmData{2*idVal};
   % SCIENTIFIC_CALIB_DATE (N_PROF, N_CALIB, N_PARAM, DATE_TIME)
   for idNProf = 1:size(inputDmDate, 4)
      for idNCalib = 1:size(inputDmDate, 3)
         for idNParam = 1:size(inputDmDate, 2)
            curDate = inputDmDate(:, idNParam, idNCalib, idNProf)';
            if (~isempty(deblank(curDate)))
               if ((length(deblank(curDate)) == 14) && strcmp(curDate(end-1:end), '60'))
                  curDateNum = datenum(curDate, 'yyyymmddHHMMSS');
                  newDate = datestr(curDateNum, 'yyyymmddHHMMSS');
                  inputDmDate(:, idNParam, idNCalib, idNProf) = newDate';
                  updated = 1;
                  
                  fprintf('INFO: input ''SCIENTIFIC_CALIB_DATE'' value (%s) updated to (%s) from input DM file %s\n', ...
                     curDate, newDate, a_inputDmFileName);
               end
            end
         end
      end
   end
   if (updated == 1)
      inputDmData{2*idVal} = inputDmDate;
   end
end

% retrieve information from input RT C file
wantedInputVars = [ ...
   {'DATA_TYPE'} ...
   {'FORMAT_VERSION'} ...
   {'HANDBOOK_VERSION'} ...
   {'REFERENCE_DATE_TIME'} ...
   {'PLATFORM_NUMBER'} ...
   {'PROJECT_NAME'} ...
   {'PI_NAME'} ...
   {'STATION_PARAMETERS'} ...
   {'CYCLE_NUMBER'} ...
   {'DIRECTION'} ...
   {'PLATFORM_TYPE'} ...
   {'FLOAT_SERIAL_NO'} ...
   {'FIRMWARE_VERSION'} ...
   {'WMO_INST_TYPE'} ...
   {'JULD'} ...
   {'JULD_QC'} ...
   {'JULD_LOCATION'} ...
   {'LATITUDE'} ...
   {'LONGITUDE'} ...
   {'POSITION_QC'} ...
   {'POSITIONING_SYSTEM'} ...
   {'PARAMETER'} ...
   {'VERTICAL_SAMPLING_SCHEME'} ...
   {'CONFIG_MISSION_NUMBER'} ...
   ];
[inputRtCData] = get_data_from_nc_file(a_inputRtCFileName, wantedInputVars);

if (a_bFileFlag == 1)
   
   % retrieve information from input RT B file
   wantedInputVars = [ ...
      {'DATA_TYPE'} ...
      {'FORMAT_VERSION'} ...
      {'HANDBOOK_VERSION'} ...
      {'REFERENCE_DATE_TIME'} ...
      {'PLATFORM_NUMBER'} ...
      {'PROJECT_NAME'} ...
      {'PI_NAME'} ...
      {'STATION_PARAMETERS'} ...
      {'CYCLE_NUMBER'} ...
      {'DIRECTION'} ...
      {'PLATFORM_TYPE'} ...
      {'FLOAT_SERIAL_NO'} ...
      {'FIRMWARE_VERSION'} ...
      {'WMO_INST_TYPE'} ...
      {'JULD'} ...
      {'JULD_QC'} ...
      {'JULD_LOCATION'} ...
      {'LATITUDE'} ...
      {'LONGITUDE'} ...
      {'POSITION_QC'} ...
      {'POSITIONING_SYSTEM'} ...
      {'PARAMETER'} ...
      {'VERTICAL_SAMPLING_SCHEME'} ...
      {'CONFIG_MISSION_NUMBER'} ...
      ];
   [inputRtBData] = get_data_from_nc_file(a_inputRtBFileName, wantedInputVars);
end

% update date for all new files
outputDateUpdate = datestr(now_utc, 'yyyymmddHHMMSS');

nbOutputFiles = 1;
if (a_bFileFlag == 1)
   nbOutputFiles = 2;
end
for idFile = 1:nbOutputFiles
   
   if (idFile == 1)
      outputFileName = a_outputCFileName;
      inputRtData = inputRtCData;
      nParamDimOutput = nParamDimCOutput;
   else
      outputFileName = a_outputBFileName;
      inputRtData = inputRtBData;
      nParamDimOutput = nParamDimBOutput;
   end
   
   % open the output file to update it
   fCdf = netcdf.open(outputFileName, 'NC_WRITE');
   if (isempty(fCdf))
      fprintf('ERROR: Unable to open NetCDF output c file: %s\n', outputFileName);
      return
   end
   
   netcdf.reDef(fCdf);
   
   % retrieve the creation date of the input DM file
   idVal = find(strcmp('DATE_CREATION', inputDmData(1:2:end)) == 1, 1);
   inputDmDateCreation = inputDmData{2*idVal}';
   if (isempty(deblank(inputDmDateCreation)))
      inputDmDateCreation = outputDateUpdate;
   end
   
   % update the 'history' global attribute
   globalVarId = netcdf.getConstant('NC_GLOBAL');
   globalHistoryText = [datestr(datenum(inputDmDateCreation, 'yyyymmddHHMMSS'), 'yyyy-mm-ddTHH:MM:SSZ') ' creation; '];
   globalHistoryText = [globalHistoryText ...
      datestr(datenum(outputDateUpdate, 'yyyymmddHHMMSS'), 'yyyy-mm-ddTHH:MM:SSZ') ' last update (coriolis COFC software)'];
   netcdf.putAtt(fCdf, globalVarId, 'history', globalHistoryText);
   
   netcdf.endDef(fCdf);
   
   % list of RT variables without N_PROF dimension
   list1InputRtVars = [ ...
      {'DATA_TYPE'} ...
      {'FORMAT_VERSION'} ...
      {'HANDBOOK_VERSION'} ...
      {'REFERENCE_DATE_TIME'} ...
      ];
   
   % copy of the list1 input RT file variables into the output file
   for idVar = 1:length(list1InputRtVars)
      
      varNameIn = list1InputRtVars{idVar};
      varNameOut = varNameIn;
      
      if (var_is_present(fCdf, varNameOut))
         idVal = find(strcmp(varNameIn, inputRtData(1:2:end)) == 1, 1);
         varValue = inputRtData{2*idVal};
         if (isempty(varValue))
            continue
         end
         netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), varValue);
      else
         fprintf('INFO: Variable %s not present in output format - not copied in output file\n', ...
            varNameOut);
      end
   end
   
   % list of DM variables without N_PROF dimension
   list1InputDmVars = [ ...
      {'DATE_CREATION'} ...
      ];
   
   % copy of the list1 input DM file variables into the output file
   for idVar = 1:length(list1InputDmVars)
      
      varNameIn = list1InputDmVars{idVar};
      varNameOut = varNameIn;
      
      if (var_is_present(fCdf, varNameOut))
         idVal = find(strcmp(varNameIn, inputDmData(1:2:end)) == 1, 1);
         varValue = inputDmData{2*idVal};
         if (isempty(varValue))
            continue
         end
         netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), varValue);
      else
         fprintf('INFO: Variable %s not present in output format - not copied in output file\n', ...
            varNameOut);
      end
   end
   
   % update the update date of the Output file
   netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'DATE_UPDATE'), outputDateUpdate);
   
   % list of RT variables with N_PROF dimension
   list2InputRtVars = [ ...
      {'PLATFORM_NUMBER'} ...
      {'PROJECT_NAME'} ...
      {'PI_NAME'} ...
      {'STATION_PARAMETERS'} ...
      {'CYCLE_NUMBER'} ...
      {'DIRECTION'} ...
      {'PLATFORM_TYPE'} ...
      {'FLOAT_SERIAL_NO'} ...
      {'FIRMWARE_VERSION'} ...
      {'WMO_INST_TYPE'} ...
      {'JULD'} ...
      {'JULD_QC'} ...
      {'JULD_LOCATION'} ...
      {'LATITUDE'} ...
      {'LONGITUDE'} ...
      {'POSITION_QC'} ...
      {'POSITIONING_SYSTEM'} ...
      {'PARAMETER'} ...
      {'VERTICAL_SAMPLING_SCHEME'} ...
      {'CONFIG_MISSION_NUMBER'} ...
      ];
   
   primaryProfInRtInput = 1;
   if (a_direction == 2)
      % descending profile
      nProfDimRtInput = 1;
   else
      % ascending profile
      idVal = find(strcmp('CYCLE_NUMBER', inputRtData(1:2:end)) == 1, 1);
      varValue = inputRtData{2*idVal};
      nProfDimRtInput = length(varValue);
      if (varValue(1) == netcdf.getAtt(fCdf, netcdf.inqVarID(fCdf, 'CYCLE_NUMBER'), '_FillValue'))
         primaryProfInRtInput = 0;
      end
   end
   
   if (nProfDimRtInput ~= nProfDimOutput)
      [~, fileName, fileExt] = fileparts(a_inputDmFileName);
      fprintf('INFO: File %s N_PROF = %d in RT input and N_PROF = %d in DM output\n', ...
         [fileName fileExt], nProfDimRtInput, nProfDimOutput);
   end
   if (primaryProfInRtInput ~= primaryProfInOutput)
      [~, fileName, fileExt] = fileparts(a_inputDmFileName);
      if ((primaryProfInRtInput == 0) && (primaryProfInOutput == 1))
         fprintf('ERROR: File %s no primary in RT input but exists in DM output - exit. We must create a new VSS for output primary profile\n', ...
            [fileName fileExt]);
         return
      else
         fprintf('INFO: File %s no primary in DM output but exists in RT input - RT data are ignored\n', ...
            [fileName fileExt]);
      end
   end
   
   if (primaryProfInOutput == 0)
      fprintf('INFO: File %s no primary in DM output - a default primary profile is created (from secondary profile information)\n', ...
         [fileName fileExt]);
   end
   
   % copy of the list2 RT input file variables into the output file
   parameterOutputList = [];
   for idVar = 1:length(list2InputRtVars)
      
      varNameIn = list2InputRtVars{idVar};
      varNameOut = varNameIn;
      
      if (var_is_present(fCdf, varNameOut))
         idVal = find(strcmp(varNameIn, inputRtData(1:2:end)) == 1, 1);
         varValue = inputRtData{2*idVal};
         if (isempty(varValue))
            continue
         end
         
         for idProf = 1:nProfDimOutput
            
            if ((primaryProfInOutput == 0) && (idProf == 1))
               
               % no primary profile in output file, we will create a default one
               % (for the checker) by duplicating some variable of the secondary
               % profile
               if (strcmp(varNameOut, 'STATION_PARAMETERS'))
                  
                  % variables with a (N_PROF, N_PARAM, STRING) dimension
                  for idParam = 1:nParamDimOutput
                     % use the data of the secondary profile
                     data = varValue(:, idParam, 2)';
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 idParam-1 0]), ...
                        fliplr([1 1 length(data)]), data');
                  end
                  
               elseif (strcmp(varNameOut, 'PARAMETER'))
                  
                  % variables with a (N_PROF, N_CALIB, N_PARAM, STRING) dimension
                  for idCalib = 1:nCalibDimOutput
                     for idParam = 1:nParamDimOutput
                        % use the data of the secondary profile
                        data = varValue(:, idParam, idCalib, 2)';
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                           fliplr([idProf-1 idCalib-1 idParam-1 0]), ...
                           fliplr([1 1 1 length(data)]), data');
                        parameterOutputList{idProf, idCalib, idParam} = deblank(data);
                     end
                  end
                  
               elseif (strcmp(varNameOut, 'VERTICAL_SAMPLING_SCHEME'))
                  
                  % (N_PROF, STRING) dimension variables
                  data = 'Primary sampling: averaged []';
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                     fliplr([idProf-1 0]), ...
                     fliplr([1 length(data)]), data');
                  
               else
                  
                  % variables with a (N_PROF, STRING) or (N_PROF) dimension
                  % be careful that:
                  %   - char(N_PROF, STRING16) is stored with size 16, N_PROF
                  %   - char(N_PROF) is stored with size N_PROF, 1
                  if (ischar(varValue) && ...
                        (((nProfDimRtInput == 1) && (size(varValue, 1) > 1)) || ...
                        ((nProfDimRtInput > 1) && (size(varValue, 2) > 1))))
                     % (N_PROF, STRING) dimension variables
                     % use the data of the secondary profile
                     data = varValue(:, 2)';
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 0]), ...
                        fliplr([1 length(data)]), data');
                  else
                     % (N_PROF) dimension variables
                     % use the data of the secondary profile
                     data = varValue(2);
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1]), ...
                        fliplr([1]), data);
                  end
                  
               end
               
            else
               
               % nominal case (the primary profile exists in output file)
               
               if (strcmp(varNameOut, 'STATION_PARAMETERS'))
                  
                  % variables with a (N_PROF, N_PARAM, STRING) dimension
                  for idParam = 1:nParamDimOutput
                     if (primaryProfInRtInput == 1)
                        data = varValue(:, idParam, 1)';
                     else
                        data = varValue(:, idParam, 2)';
                     end
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 idParam-1 0]), ...
                        fliplr([1 1 length(data)]), data');
                  end
                  
               elseif (strcmp(varNameOut, 'PARAMETER'))
                  
                  % variables with a (N_PROF, N_CALIB, N_PARAM, STRING) dimension
                  for idCalib = 1:nCalibDimOutput
                     for idParam = 1:nParamDimOutput
                        if (primaryProfInRtInput == 1)
                           data = varValue(:, idParam, idCalib, 1)';
                        else
                           data = varValue(:, idParam, idCalib, 2)';
                        end
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                           fliplr([idProf-1 idCalib-1 idParam-1 0]), ...
                           fliplr([1 1 1 length(data)]), data');
                        parameterOutputList{idProf, idCalib, idParam} = deblank(data);
                     end
                  end
                  
               elseif (strcmp(varNameOut, 'VERTICAL_SAMPLING_SCHEME'))
                  
                  % (N_PROF, STRING) dimension variables
                  data = varValue(:, idProf)';
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                     fliplr([idProf-1 0]), ...
                     fliplr([1 length(data)]), data');
                  
               else
                  
                  % variables with a (N_PROF, STRING) or (N_PROF) dimension
                  % be careful that:
                  %   - char(N_PROF, STRING16) is stored with size 16, N_PROF
                  %   - char(N_PROF) is stored with size N_PROF, 1
                  if (ischar(varValue) && ...
                        (((nProfDimRtInput == 1) && (size(varValue, 1) > 1)) || ...
                        ((nProfDimRtInput > 1) && (size(varValue, 2) > 1))))
                     % (N_PROF, STRING) dimension variables
                     if (primaryProfInRtInput == 1)
                        data = varValue(:, 1)';
                     else
                        data = varValue(:, 2)';
                     end
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 0]), ...
                        fliplr([1 length(data)]), data');
                  else
                     % (N_PROF) dimension variables
                     if (primaryProfInRtInput == 1)
                        data = varValue(1);
                     else
                        data = varValue(2);
                     end
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1]), ...
                        fliplr([1]), data);
                  end
                  
               end
            end
         end
      else
         fprintf('INFO: Variable %s not present in output format - not copied in output file\n', ...
            varNameOut);
      end
   end
   
   % list of DM variables with N_PROF dimension
   list2InputDmVars = [ ...
      {'DATA_CENTRE'} ...
      {'DC_REFERENCE'} ...
      {'DATA_STATE_INDICATOR'} ...
      {'DATA_MODE'} ...
      {'PARAMETER'} ...
      {'SCIENTIFIC_CALIB_EQUATION'} ...
      {'SCIENTIFIC_CALIB_COEFFICIENT'} ...
      {'SCIENTIFIC_CALIB_COMMENT'} ...
      {'HISTORY_INSTITUTION'} ...
      {'HISTORY_STEP'} ...
      {'HISTORY_SOFTWARE'} ...
      {'HISTORY_SOFTWARE_RELEASE'} ...
      {'HISTORY_REFERENCE'} ...
      {'HISTORY_DATE'} ...
      {'HISTORY_ACTION'} ...
      {'HISTORY_PARAMETER'} ...
      {'HISTORY_START_PRES'} ...
      {'HISTORY_STOP_PRES'} ...
      {'HISTORY_PREVIOUS_VALUE'} ...
      {'HISTORY_QCTEST'} ...
      ];
   if (inputFileFormatVersion == 2.2)
      list2InputDmVars = [ ...
         list2InputDmVars ...
         {'CALIBRATION_DATE'} ...
         ];
   elseif (inputFileFormatVersion == 2.3)
      list2InputDmVars = [ ...
         list2InputDmVars ...
         {'SCIENTIFIC_CALIB_DATE'} ... % for Coriolis floats
         ];
   elseif (inputFileFormatVersion == 3.0)
      list2InputDmVars = [ ...
         list2InputDmVars ...
         {'SCIENTIFIC_CALIB_DATE'} ...
         ];
   end
   
   idVal = find(strcmp('PARAMETER', inputDmData(1:2:end)) == 1, 1);
   parameterValue = inputDmData{2*idVal};
   
   % copy of the list2 DM input file variables into the output file
   for idVar = 1:length(list2InputDmVars)
      
      varNameIn = list2InputDmVars{idVar};
      varNameOut = varNameIn;
      
      if (strcmp(varNameOut, 'PARAMETER'))
         continue
      end
      
      if ((inputFileFormatVersion == 2.2) || ...
            (inputFileFormatVersion == 2.3))
         if (strcmp(varNameIn, 'CALIBRATION_DATE') == 1)
            varNameOut = 'SCIENTIFIC_CALIB_DATE';
         end
      end
      
      if (var_is_present(fCdf, varNameOut))
         idVal = find(strcmp(varNameIn, inputDmData(1:2:end)) == 1, 1);
         varValue = inputDmData{2*idVal};
         if (isempty(varValue))
            continue
         end
         
         for idProf = 1:nProfDimOutput
            
            if ((primaryProfInOutput == 0) && (idProf == 1))
               
               % no primary profile in output file, we will create a default one
               % (for the checker) by duplicating some variable of the secondary
               % profile
               
               if ((strncmp(varNameOut, 'DATA_CENTRE', length('DATA_CENTRE'))) || ...
                     (strncmp(varNameOut, 'DC_REFERENCE', length('DC_REFERENCE'))) || ...
                     (strncmp(varNameOut, 'DATA_STATE_INDICATOR', length('DATA_STATE_INDICATOR'))) || ...
                     (strncmp(varNameOut, 'DATA_MODE', length('DATA_MODE'))))
                  
                  % variables with a (N_PROF, STRING) or (N_PROF) dimension
                  % be careful that:
                  %   - char(N_PROF, STRING16) is stored with size 16, N_PROF
                  %   - char(N_PROF) is stored with size N_PROF, 1
                  if (ischar(varValue) && (size(varValue, 1) > 1))
                     % (N_PROF, STRING) dimension variables
                     data = varValue(:, 1)';
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 0]), ...
                        fliplr([1 length(data)]), data');
                  else
                     % (N_PROF) dimension variables
                     data = varValue(1);
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1]), ...
                        fliplr([1]), data);
                  end
               end
               
            else
               
               % nominal case (the primary profile exists in output file)
               
               if (strncmp(varNameOut, 'SCIENTIFIC_CALIB_', length('SCIENTIFIC_CALIB_')))
                  
                  % variables with a (N_PROF, N_CALIB, N_PARAM, STRING) dimension
                  for idCalib = 1:nCalibDimOutput
                     for idParam = 1:nParamDimInput
                        param = deblank(parameterValue(:, idParam, idCalib, 1)');
                        if (~strcmp(param, 'PRES'))
                           paramStruct = get_netcdf_param_attributes_3_1(param);
                           if (idFile == 1)
                              if ((paramStruct.paramType ~= 'c') && (paramStruct.paramType ~= 'j'))
                                 continue
                              end
                           else
                              if ((paramStruct.paramType == 'c') || (paramStruct.paramType == 'j'))
                                 continue
                              end
                           end
                        end
                        
                        data = varValue(:, idParam, idCalib, 1)';
                        
                        % the position of the parameters can differ
                        idF = find(strcmp(param, parameterOutputList(idProf, idCalib, :)) == 1, 1);
                        
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                           fliplr([idProf-1 idCalib-1 idF-1 0]), ...
                           fliplr([1 1 1 length(data)]), data');
                     end
                  end
                  
               elseif (strncmp(varNameOut, 'HISTORY_', length('HISTORY_')))
                  
                  % variables with a (N_HISTORY, N_PROF, STRING) or (N_HISTORY, N_PROF) dimension
                  for idHisto = 1:nHistoryDimOutput
                     if (ischar(varValue) && (size(varValue, 1) > 1))
                        data = varValue(:, 1, idHisto)';
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                           fliplr([idHisto-1 idProf-1 0]), ...
                           fliplr([1 1 length(data)]), data');
                     else
                        data = varValue(1, idHisto);
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                           fliplr([idHisto-1 idProf-1]), ...
                           fliplr([1 1]), data);
                     end
                  end
                  
               else
                  
                  % variables with a (N_PROF, STRING) or (N_PROF) dimension
                  % be careful that:
                  %   - char(N_PROF, STRING16) is stored with size 16, N_PROF
                  %   - char(N_PROF) is stored with size N_PROF, 1
                  if (ischar(varValue) && (size(varValue, 1) > 1))
                     % (N_PROF, STRING) dimension variables
                     data = varValue(:, 1)';
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1 0]), ...
                        fliplr([1 length(data)]), data');
                  else
                     % (N_PROF) dimension variables
                     data = varValue(1);
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                        fliplr([idProf-1]), ...
                        fliplr([1]), data);
                  end
                  
               end
            end
         end
         
      else
         fprintf('INFO: Variable %s not present in output format - not copied in output file\n', ...
            varNameOut);
      end
   end
   
   % correction #8:
   % for each PARAMETER of the output file:
   % - if empty, set SCIENTIFIC_CALIB_DATE to the DATE_UPDATE of the input DM file
   % - if empty, set SCIENTIFIC_CALIB_COMMENT to 'none'
   
   if (var_is_present(fCdf, 'PARAMETER') && ...
         var_is_present(fCdf, 'SCIENTIFIC_CALIB_DATE') && ...
         var_is_present(fCdf, 'SCIENTIFIC_CALIB_COMMENT'))
      calibParam = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'PARAMETER'));
      calibDate = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'SCIENTIFIC_CALIB_DATE'));
      calibComment = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'SCIENTIFIC_CALIB_COMMENT'));
      [~, nParamDimInput2, nCalibDimOutput2, nProfDimOutput2] = size(calibParam);
      for idProf = 1:nProfDimOutput2
         for idCalib = 1:nCalibDimOutput2
            for idParam = 1:nParamDimInput2
               param = deblank(calibParam(:, idParam, idCalib, idProf)');
               if (~isempty(param))
                  date = deblank(calibDate(:, idParam, idCalib, idProf)');
                  if (isempty(date))
                     % retrieve the update date of the input DM file
                     idVal = find(strcmp('DATE_UPDATE', inputDmData(1:2:end)) == 1, 1);
                     inputDmDateUpdate = inputDmData{2*idVal}';
                     if (~isempty(deblank(inputDmDateUpdate)))
                        netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'SCIENTIFIC_CALIB_DATE'), ...
                           fliplr([idProf-1 idCalib-1 idParam-1 0]), ...
                           fliplr([1 1 1 length(inputDmDateUpdate)]), inputDmDateUpdate');
                        fprintf('INFO: ''SCIENTIFIC_CALIB_DATE'' is empty for %s parameter - set to ''DATE_UPDATE'' of input DM file (= %s) (file %s)\n', ...
                           param, inputDmDateUpdate, outputFileName);
                     else
                        fprintf('WARNING: ''SCIENTIFIC_CALIB_DATE'' is empty for %s parameter - nothing done since ''DATE_UPDATE'' of input DM file is empty (file %s)\n', ...
                           param, outputFileName);
                     end
                  end
                  comment = deblank(calibComment(:, idParam, idCalib, idProf)');
                  if (isempty(comment))
                     defaultComment = 'none';
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'SCIENTIFIC_CALIB_COMMENT'), ...
                        fliplr([idProf-1 idCalib-1 idParam-1 0]), ...
                        fliplr([1 1 1 length(defaultComment)]), defaultComment');
                     fprintf('INFO: ''SCIENTIFIC_CALIB_COMMENT'' is empty for %s parameter - set to ''%s'' (file %s)\n', ...
                        param, defaultComment,outputFileName);
                  end
               end
            end
         end
      end
   end
   
   % correction #9:
   % if JULD > DATE_CREATION set DATE_CREATION = JULD
   if (var_is_present(fCdf, 'DATE_CREATION') && ...
         var_is_present(fCdf, 'JULD'))
      dateCreation = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'DATE_CREATION'));
      julDateCreation = datenum(dateCreation', 'yyyymmddHHMMSS') - g_decArgo_janFirst1950InMatlab;
      
      julD = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'JULD'));
      paramStruct = get_netcdf_param_attributes_3_1('JULD');
      julD = julD(find(julD ~= paramStruct.fillValue));
      if (any(julD > julDateCreation))
         julDateCreationNew = max(julD);
         dateCreationNew = datestr(julDateCreationNew + g_decArgo_janFirst1950InMatlab, 'yyyymmddHHMMSS');
         netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'DATE_CREATION'), dateCreationNew);
         fprintf('INFO: ''DATE_CREATION'' (%s) is before ''JULD'' (%s) - ''DATE_CREATION'' set to ''JULD'' (file %s)\n', ...
            dateCreation, julian_2_gregorian_dec_argo(julDateCreationNew), outputFileName);
      end
   end
   
   if (idFile == 2)
      
      % retrieve parameter of RT input file (same as DM output file) used to
      % update PARAMETER_DATA_MODE
      
      wantedInputVars = [ ...
         {'STATION_PARAMETERS'} ...
         ];
      [inputRtData] = get_data_from_nc_file(a_inputRtBFileName, wantedInputVars);
      
      % create the list of parameters
      idVal = find(strcmp('STATION_PARAMETERS', inputRtData(1:2:end)) == 1, 1);
      stationParameters = inputRtData{2*idVal};
      [~, inputNParam, inputNProf] = size(stationParameters);
      outputStationParameters = [];
      for idProf = 1:inputNProf
         for idParam = 1:inputNParam
            outputStationParameters{idProf, idParam} = deblank(stationParameters(:, idParam, idProf)');
         end
      end
   end
   
   % copy of the DM input measurements into the DM output file
   sufixList = [{''} {'_QC'} {'_ADJUSTED'} {'_ADJUSTED_QC'} {'_ADJUSTED_ERROR'}];
   for idParam = 1:length(inputRtParamList)
      paramNamePrefix = inputRtParamList{idParam};
      
      if (~strcmp(paramNamePrefix, 'PRES'))
         paramStruct = get_netcdf_param_attributes_3_1(paramNamePrefix);
         if (idFile == 1)
            if ((paramStruct.paramType ~= 'c') && (paramStruct.paramType ~= 'j'))
               continue
            end
         else
            if ((paramStruct.paramType == 'c') || (paramStruct.paramType == 'j'))
               continue
            end
         end
      end
      
      if (~isempty(find(strcmp(paramNamePrefix, inputDmMissingParamList) ==1, 1)))
         % this parameter desn't exist in DM input file
         continue
      end
      
      for idS = 1:length(sufixList)
         varNameIn = [paramNamePrefix sufixList{idS}];
         varNameOut = varNameIn;
         
         if (idFile == 2)
            if (strcmp(paramNamePrefix, 'PRES')  && (idS > 1))
               continue
            end
         end
         
         paramStruct = get_netcdf_param_attributes_3_1(paramNamePrefix);
         if (~isempty(paramStruct) && (paramStruct.adjAllowed == 0) && (idS > 2))
            continue
         end
         
         if (var_is_present(fCdf, varNameOut))
            idVal = find(strcmp(varNameIn, inputDmData(1:2:end)) == 1, 1);
            if (~isempty(idVal))
               varValue = inputDmData{2*idVal};
               if (isempty(varValue))
                  continue
               end
            else
               fprintf('WARNING: Variable %s not present in DM input file\n', ...
                  varNameOut);
               continue
            end
            
            % input DM data correction #1
            % from Argo Quality Control Manual V2.9.1
            % Please note that whenever PARAM_ADJUSTED_QC = ‘4’, both
            % PARAM_ADJUSTED and PARAM_ADJUSTED_ERROR should be set to FillValue.
            if ((idS == 3) || (idS == 5))
               
               % retrieve <PARAM>_ADJUSTED_QC values
               varAdjQcValue = [];
               varAdjQcName = [paramNamePrefix sufixList{4}];
               idValTmp = find(strcmp(varAdjQcName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varAdjQcValue = inputDmData{2*idValTmp};
               end
               if (~isempty(varAdjQcValue))
                  idFQc4 = find(varAdjQcValue == g_decArgo_qcStrBad);
                  if (any(varValue(idFQc4) ~= paramStruct.fillValue))
                     fprintf('INFO: %d %s values set to FillValue (because %s = ''4'') (file %s)\n', ...
                        length(idFQc4), varNameIn, varAdjQcName, outputFileName);
                     varValue(idFQc4) = paramStruct.fillValue;
                     inputDmData{2*idVal} = varValue;
                  end
               end
            end
            
            % input DM data correction #2
            % if PRES_QC = '0' set PRES_QC = '1'
            if (strcmp(paramNamePrefix, 'PRES') && (idS == 2))
               idFQc0 = find(varValue == g_decArgo_qcStrNoQc);
               if (~isempty(idFQc0))
                  varValue(idFQc0) = g_decArgo_qcStrGood;
                  fprintf('INFO: %d %s values set to ''1'' (because %s = ''0'') (file %s)\n', ...
                     length(idFQc0), varNameIn, varNameIn, outputFileName);
                  inputDmData{2*idVal} = varValue;
               end
            end
            
            % input DM data correction #3
            % if TEMP_QC = '0' duplicate TEMP_ADJUSTED_QC in TEMP_QC
            if (strcmp(paramNamePrefix, 'TEMP') && (idS == 2))
               idFQc0 = find(varValue == g_decArgo_qcStrNoQc);
               if (~isempty(idFQc0))
                  
                  % retrieve <PARAM>_ADJUSTED_QC values
                  varAdjQcValue = [];
                  varAdjQcName = [paramNamePrefix sufixList{4}];
                  idValTmp = find(strcmp(varAdjQcName, inputDmData(1:2:end)) == 1, 1);
                  if (~isempty(idValTmp))
                     varAdjQcValue = inputDmData{2*idValTmp};
                  end
                  if (~isempty(varAdjQcValue))
                     if (any((varAdjQcValue ~= g_decArgo_qcStrDef) & (varAdjQcValue ~= g_decArgo_qcStrNoQc)))
                        % TEMP parameter has been adjusted
                        fprintf('INFO: %d TEMP_ADJUSTED_QC values duplicated to TEMP_QC (because TEMP_QC = ''0'' or '' '') (file %s)\n', ...
                           length(idFQc0), outputFileName);
                        varValue(idFQc0) = varAdjQcValue(idFQc0);
                        inputDmData{2*idVal} = varValue;
                     end
                  end
               end
            end
            % print a warning if same pb occurs with PSAL
            if (strcmp(paramNamePrefix, 'PSAL') && (idS == 2))
               idFQc0 = find(varValue == g_decArgo_qcStrNoQc);
               if (~isempty(idFQc0))
                  fprintf('WARNING: %d PSAL_QC values equal to ''0'' (file %s)\n', ...
                     length(idFQc0), outputFileName);
               end
            end
            
            % input DM data correction #4
            % if <PARAM>_ADJUSTED ~= fillValue and <PARAM>_ADJUSTED_ERROR =
            % fillValue then <PARAM>_ADJUSTED_ERROR = error value (retrieve
            % from existing error values (should be unique))
            if (idS == 5)
               
               % retrieve <PARAM>_ADJUSTED values
               varAdjValue = [];
               varAdjName = [paramNamePrefix sufixList{3}];
               idValTmp = find(strcmp(varAdjName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varAdjValue = inputDmData{2*idValTmp};
               end
               if (~isempty(varAdjValue))
                  idFAdjNotFillval = find(varAdjValue ~= paramStruct.fillValue);
                  if (any(varValue(idFAdjNotFillval) == paramStruct.fillValue))
                     idFAdjErrorToSet = find(varValue(idFAdjNotFillval) == paramStruct.fillValue);
                     adjErrorVal = unique(varValue(find(varValue ~= paramStruct.fillValue)));
                     if (length(adjErrorVal) == 1)
                        fprintf('INFO: %d %s values set to %f (because %s = FillValue) (file %s)\n', ...
                           length(idFAdjErrorToSet), varNameIn, adjErrorVal, varNameIn, outputFileName);
                        varValue(idFAdjNotFillval(idFAdjErrorToSet)) = adjErrorVal;
                        inputDmData{2*idVal} = varValue;
                     else
                        fprintf('ERROR: %s values are not unique (file %s)\n', ...
                           varNameIn, outputFileName);
                     end
                  end
               end
            end
            
            % input DM data correction #5
            % if <PARAM> = fillValue and <PARAM>_QC ~= ' ' and <PARAM>_QC ~= '9'
            % then <PARAM>_QC = '9'
            if (idS == 2)
               
               % retrieve <PARAM> values
               varParamValue = [];
               varParamName = [paramNamePrefix sufixList{1}];
               idValTmp = find(strcmp(varParamName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varParamValue = inputDmData{2*idValTmp};
               end
               if (~isempty(varParamValue))
                  idFParamFillval = find(varParamValue == paramStruct.fillValue);
                  if (any(~((varValue(idFParamFillval) == g_decArgo_qcStrDef) | ...
                        (varValue(idFParamFillval) == g_decArgo_qcStrMissing))))
                     idFQcToSet = find(~((varValue(idFParamFillval) == g_decArgo_qcStrDef) | ...
                        (varValue(idFParamFillval) == g_decArgo_qcStrMissing)));
                     fprintf('INFO: %d %s values set to ''9'' (because %s = FillValue) (file %s)\n', ...
                        length(idFQcToSet), varNameIn, varParamName, outputFileName);
                     varValue(idFParamFillval(idFQcToSet)) = g_decArgo_qcStrMissing;
                     inputDmData{2*idVal} = varValue;
                  end
               end
            end
            
            % input DM data correction #6
            % if <PARAM>_ADJUSTED = fillValue and <PARAM>_QC ~= ' ' and
            % <PARAM>_QC ~= '9' and <PARAM>_QC ~= '4'
            % then <PARAM>_ADJUSTED_QC = '9'
            if (idS == 4)
               
               % retrieve <PARAM>_ADJUSTED values
               varAdjValue = [];
               varAdjName = [paramNamePrefix sufixList{3}];
               idValTmp = find(strcmp(varAdjName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varAdjValue = inputDmData{2*idValTmp};
               end
               if (~isempty(varAdjValue))
                  idFAdjFillval = find(varAdjValue == paramStruct.fillValue);
                  if (any(~((varValue(idFAdjFillval) == g_decArgo_qcStrDef) | ...
                        (varValue(idFAdjFillval) == g_decArgo_qcStrMissing) | ...
                        (varValue(idFAdjFillval) == g_decArgo_qcStrBad))))
                     idFQcToSet = find(~((varValue(idFParamFillval) == g_decArgo_qcStrDef) | ...
                        (varValue(idFParamFillval) == g_decArgo_qcStrMissing) | ...
                        (varValue(idFParamFillval) == g_decArgo_qcStrBad)));
                     fprintf('INFO: %d %s values set to ''9'' (because %s = FillValue) (file %s)\n', ...
                        length(idFQcToSet), varNameIn, varParamName, outputFileName);
                     varValue(idFAdjFillval(idFQcToSet)) = g_decArgo_qcStrMissing;
                     inputDmData{2*idVal} = varValue;
                  end
               end
            end
            
            % input DM data correction #7
            % if <PARAM>_ADJUSTED = fillValue
            % then <PARAM>_ADJUSTED_ERROR = fillValue
            if (idS == 5)
               
               % retrieve <PARAM>_ADJUSTED values
               varAdjValue = [];
               varAdjName = [paramNamePrefix sufixList{3}];
               idValTmp = find(strcmp(varAdjName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varAdjValue = inputDmData{2*idValTmp};
               end
               if (~isempty(varAdjValue))
                  idFAdjFillval = find(varAdjValue == paramStruct.fillValue);
                  if (any(varValue(idFAdjFillval) ~= paramStruct.fillValue))
                     idFFillValToSet = find(varValue(idFAdjFillval) ~= paramStruct.fillValue);
                     fprintf('INFO: %d %s values set to FillValue (because %s = fillvalue) (file %s)\n', ...
                        length(idFFillValToSet), varNameIn, varAdjName, outputFileName);
                     varValue(idFAdjFillval(idFFillValToSet)) = paramStruct.fillValue;
                     inputDmData{2*idVal} = varValue;
                  end
               end
            end
            
            % input DM data correction #10
            % if PSAL ~= fillValue and PSAL_ADJUSTED == fillValue
            % then PSAL_ADJUSTED_QC = '4'
            if (strcmp(paramNamePrefix, 'PSAL') && (idS == 4))
               
               % retrieve PSAL values
               varParamValue = [];
               varName = [paramNamePrefix sufixList{1}];
               idValTmp = find(strcmp(varName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varParamValue = inputDmData{2*idValTmp};
               end
               
               % retrieve PSAL_ADJUSTED values
               varParamAdjValue = [];
               varAdjName = [paramNamePrefix sufixList{3}];
               idValTmp = find(strcmp(varAdjName, inputDmData(1:2:end)) == 1, 1);
               if (~isempty(idValTmp))
                  varParamAdjValue = inputDmData{2*idValTmp};
               end
               
               if (any((varParamValue ~= paramStruct.fillValue) & ...
                     (varParamAdjValue == paramStruct.fillValue) & ...
                     (varValue ~= g_decArgo_qcStrBad)))
                  idFQcToSet = find((varParamValue ~= paramStruct.fillValue) & ...
                     (varAdjValue == paramStruct.fillValue) & ...
                     (varValue ~= g_decArgo_qcStrBad));
                  fprintf('INFO: %d %s values set to ''4'' (because %s ~= fillvalue and %s_ADJUSTED = fillvalue) (file %s)\n', ...
                     length(idFQcToSet), varNameIn, varParamName, varParamName, outputFileName);
                  varValue(idFQcToSet) = g_decArgo_qcStrBad;
                  inputDmData{2*idVal} = varValue;
               end
            end
            
            if (nLevelsPrimary > 0)
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                  fliplr([0 0]), ...
                  fliplr([1 nLevelsPrimary]), varValue(end-(nLevelsPrimary-1):end));
               
               if (idS == 4)
                  
                  % update the profile quality flags
                  profParamQcName = ['PROFILE_' paramNamePrefix '_QC'];
                  profQualityFlag = compute_profile_quality_flag(varValue(end-(nLevelsPrimary-1):end));
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, profParamQcName), 0, 1, profQualityFlag);
                  
                  if (idFile == 2)
                     
                     % find the place of the current parameter in the DM output
                     % b file
                     idF = find(strcmp(paramNamePrefix, outputStationParameters(1, :)) == 1, 1);
                     
                     % update PARAMETER_DATA_MODE
                     qcData = varValue(end-(nLevelsPrimary-1):end);
                     if (length(find((qcData == g_decArgo_qcStrDef) | (qcData == g_decArgo_qcStrNoQc) | (qcData == g_decArgo_qcStrMissing))) ~= length(qcData))
                        % QC performed
                        dataMode = 'D';
                     else
                        % no QC performed
                        dataMode = 'R';
                     end
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'PARAMETER_DATA_MODE'), ...
                        fliplr([0 idF-1]), dataMode);
                  end
               end
            end
            if (nLevelsSecondary > 0)
               if ~(strcmp(paramNamePrefix, 'PSAL')  && (idS == 2))
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                     fliplr([1 0]), ...
                     fliplr([1 nLevelsSecondary]), varValue(1:nLevelsSecondary));
               else
                  % the Qc of the unpumped PSAL is set to '4' (V. Thierry
                  % 01/09/2014)
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, varNameOut), ...
                     fliplr([1 0]), ...
                     fliplr([1 nLevelsSecondary]), repmat('4', nLevelsSecondary, 1));
               end
               
               % update the profile quality flags
               if (idS == 4)
                  
                  % update the profile quality flags
                  profParamQcName = ['PROFILE_' paramNamePrefix '_QC'];
                  profQualityFlag = compute_profile_quality_flag(varValue(1:nLevelsSecondary));
                  netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, profParamQcName), 1, 1, profQualityFlag);
                  
                  if (idFile == 2)
                     
                     % find the place of the current parameter in the DM output
                     % b file
                     idF = find(strcmp(paramNamePrefix, outputStationParameters(2, :)) == 1, 1);
                     
                     % update PARAMETER_DATA_MODE
                     qcData = varValue(1:nLevelsSecondary);
                     if (length(find((qcData == g_decArgo_qcStrDef) | (qcData == g_decArgo_qcStrNoQc) | (qcData == g_decArgo_qcStrMissing))) ~= length(qcData))
                        % QC performed
                        dataMode = 'D';
                     else
                        % no QC performed
                        dataMode = 'R';
                     end
                     netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'PARAMETER_DATA_MODE'), ...
                        fliplr([1 idF-1]), dataMode);
                  end
               end
            end
         else
            fprintf('INFO: Variable %s not present in output format - not copied in output file\n', ...
               varNameOut);
         end
      end
   end
   
   if (idFile == 2)
      % when MOLAR_DOXY is missing, we try to recover it from RT input file (the
      % corresponding levels is recognized using PRES TEMP and PSAL values)
      molarDoxyAdded = 0;
      if (~isempty(find(strcmp('MOLAR_DOXY', inputDmMissingParamList) ==1, 1)))
         
         % retrieve measurements from input RT C file
         wantedInputVars = [ ...
            {'PRES'} ...
            {'TEMP'} ...
            {'PSAL'} ...
            ];
         [inputRtCMeas] = get_data_from_nc_file(a_inputRtCFileName, wantedInputVars);
         
         idVal = find(strcmp('PRES', inputRtCMeas(1:2:end)) == 1, 1);
         presInputCMeas = inputRtCMeas{2*idVal};
         idVal = find(strcmp('TEMP', inputRtCMeas(1:2:end)) == 1, 1);
         tempInputCMeas = inputRtCMeas{2*idVal};
         idVal = find(strcmp('PSAL', inputRtCMeas(1:2:end)) == 1, 1);
         psalInputCMeas = inputRtCMeas{2*idVal};
         
         % retrieve measurements from input RT B file
         wantedInputVars = [ ...
            {'MOLAR_DOXY'} ...
            ];
         [inputRtBMeas] = get_data_from_nc_file(a_inputRtBFileName, wantedInputVars);
         
         idVal = find(strcmp('MOLAR_DOXY', inputRtBMeas(1:2:end)) == 1, 1);
         molarDoxyInputBMeas = inputRtBMeas{2*idVal};
         
         % retrieve measurements from output DM C file
         wantedInputVars = [ ...
            {'PRES'} ...
            {'TEMP'} ...
            {'PSAL'} ...
            ];
         [ouputDmCMeas] = get_data_from_nc_file(a_outputCFileName, wantedInputVars);
         
         idVal = find(strcmp('PRES', ouputDmCMeas(1:2:end)) == 1, 1);
         presOutputCMeas = ouputDmCMeas{2*idVal};
         idVal = find(strcmp('TEMP', ouputDmCMeas(1:2:end)) == 1, 1);
         tempOutputCMeas = ouputDmCMeas{2*idVal};
         idVal = find(strcmp('PSAL', ouputDmCMeas(1:2:end)) == 1, 1);
         psalOutputCMeas = ouputDmCMeas{2*idVal};
         
         presParam = get_netcdf_param_attributes_3_1('PRES');
         tempParam = get_netcdf_param_attributes_3_1('TEMP');
         psalParam = get_netcdf_param_attributes_3_1('PSAL');
         molarDoxyParam = get_netcdf_param_attributes_3_1('MOLAR_DOXY');
         
         for idProf = 1:size(presOutputCMeas, 2)
            ok = 1;
            molarDoxy = ones(size(presOutputCMeas, 1), 1)*molarDoxyParam.fillValue;
            for idLev = 1:size(presOutputCMeas, 1)
               if((presOutputCMeas(idLev, idProf) ~= presParam.fillValue) && ...
                     (tempOutputCMeas(idLev, idProf) ~= tempParam.fillValue) && ...
                     (psalOutputCMeas(idLev, idProf) ~= psalParam.fillValue))
                  
                  idF = find((presInputCMeas(:, idProf) == presOutputCMeas(idLev, idProf)) & ...
                     (tempInputCMeas(:, idProf) == tempOutputCMeas(idLev, idProf)) & ...
                     (psalInputCMeas(:, idProf) == psalOutputCMeas(idLev, idProf)));
                  if (length(idF) == 1)
                     molarDoxy(idLev) = molarDoxyInputBMeas(idF, idProf);
                  else
                     ok = 0;
                     break
                  end
               end
            end
            if (ok == 1)
               
               % add MOLAR_DOXY in DM output file
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'MOLAR_DOXY'), ...
                  fliplr([idProf-1 0]), ...
                  fliplr([1 size(molarDoxy, 1)]), molarDoxy);
               
               % add MOLAR_DOXY_QC in DM output file
               molarDoxyQcStr = repmat(g_decArgo_qcStrDef, size(molarDoxy, 1), 1);
               molarDoxyQcStr(find(molarDoxy ~= molarDoxyParam.fillValue)) = g_decArgo_qcStrNoQc;
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'MOLAR_DOXY_QC'), ...
                  fliplr([idProf-1 0]), ...
                  fliplr([1 size(molarDoxy, 1)]), molarDoxyQcStr);
               
               % update PARAMETER_DATA_MODE
               
               % find the place of the current parameter in the DM output
               % b file
               idF = find(strcmp('MOLAR_DOXY', outputStationParameters(idProf, :)) == 1, 1);
               
               % update PARAMETER_DATA_MODE
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'PARAMETER_DATA_MODE'), ...
                  fliplr([idProf-1 idF-1]), 'R');
               
               fprintf('INFO: MOLAR_DOXY data added in DM output file for profile #%d\n', ...
                  idProf);
               molarDoxyAdded = 1;
            else
               fprintf('WARNING: cannot add MOLAR_DOXY data in DM output file for profile #%d\n', ...
                  idProf);
            end
         end
      end
      
      % when DOXY is missing, we compute it from DM output c and b files current
      % contents
      doxyAdded = 0;
      if (~isempty(find(strcmp('DOXY', inputDmMissingParamList) ==1, 1)))
         
         % retrieve measurements from output DM C file
         wantedInputVars = [ ...
            {'PRES'} ...
            {'TEMP'} ...
            {'PSAL'} ...
            ];
         [ouputDmCMeas] = get_data_from_nc_file(a_outputCFileName, wantedInputVars);
         
         idVal = find(strcmp('PRES', ouputDmCMeas(1:2:end)) == 1, 1);
         presOutputCMeas = ouputDmCMeas{2*idVal};
         idVal = find(strcmp('TEMP', ouputDmCMeas(1:2:end)) == 1, 1);
         tempOutputCMeas = ouputDmCMeas{2*idVal};
         idVal = find(strcmp('PSAL', ouputDmCMeas(1:2:end)) == 1, 1);
         psalOutputCMeas = ouputDmCMeas{2*idVal};
         
         molarDoxyOutputBMeas = netcdf.getVar(fCdf, netcdf.inqVarID(fCdf, 'MOLAR_DOXY'));
         
         presParam = get_netcdf_param_attributes_3_1('PRES');
         tempParam = get_netcdf_param_attributes_3_1('TEMP');
         psalParam = get_netcdf_param_attributes_3_1('PSAL');
         molarDoxyParam = get_netcdf_param_attributes_3_1('MOLAR_DOXY');
         doxyParam = get_netcdf_param_attributes_3_1('DOXY');
         
         for idProf = 1:size(presOutputCMeas, 2)
            
            idDef = find((presOutputCMeas(:, idProf) ~= presParam.fillValue) & ...
               (tempOutputCMeas(:, idProf) ~= tempParam.fillValue) & ...
               (psalOutputCMeas(:, idProf) ~= psalParam.fillValue) & ...
               (molarDoxyOutputBMeas(:, idProf) ~= molarDoxyParam.fillValue));
            
            if (~isempty(idDef))
               
               % compute DOXY
               [doxyValues] = compute_DOXY(a_floatNum, ...
                  a_jsonFloatInfoDirName, a_jsonFloatMetaDirName, ...
                  molarDoxyOutputBMeas(idDef, idProf), presOutputCMeas(idDef, idProf), ...
                  tempOutputCMeas(idDef, idProf), psalOutputCMeas(idDef, idProf));
               doxy = ones(size(presOutputCMeas, 1), 1)*doxyParam.fillValue;
               doxy(idDef) = doxyValues;
               
               % add DOXY in DM output file
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'DOXY'), ...
                  fliplr([idProf-1 0]), ...
                  fliplr([1 size(doxy, 1)]), doxy);
               
               % add DOXY_QC in DM output file
               doxyQcStr = repmat(g_decArgo_qcStrDef, size(doxy, 1), 1);
               doxyQcStr(find(doxy ~= doxyParam.fillValue)) = g_decArgo_qcStrNoQc;
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'DOXY_QC'), ...
                  fliplr([idProf-1 0]), ...
                  fliplr([1 size(doxy, 1)]), doxyQcStr);
               
               % update PARAMETER_DATA_MODE
               
               % find the place of the current parameter in the DM output
               % b file
               idF = find(strcmp('DOXY', outputStationParameters(idProf, :)) == 1, 1);
               
               % update PARAMETER_DATA_MODE
               netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'PARAMETER_DATA_MODE'), ...
                  fliplr([idProf-1 idF-1]), 'R');
               
               fprintf('INFO: DOXY data computed and added in DM output file for profile #%d\n', ...
                  idProf);
               doxyAdded = 1;
            end
         end
      end
      
      if ((molarDoxyAdded == 1) || (doxyAdded == 1))
         [~, fileName, ~] = fileparts(outputFileName);
         if ((molarDoxyAdded == 1) && (doxyAdded == 1))
            fprintf('@#@%d@%s@MOLAR_DOXY added@DOXY added\n', ...
               a_floatNum, fileName);
         elseif (molarDoxyAdded == 1)
            fprintf('@#@%d@%s@MOLAR_DOXY added\n', ...
               a_floatNum, fileName);
         else
            fprintf('@#@%d@%s@ @DOXY added\n', ...
               a_floatNum, fileName);
         end
      end
   end
   
   % add history information that concerns the current program
   currentHistoId = nHistoryDimOutput;
   for idProf = 1:nProfDimOutput
      
      value = 'IF';
      netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'HISTORY_INSTITUTION'), ...
         fliplr([currentHistoId idProf-1 0]), ...
         fliplr([1 1 length(value)]), value');
      value = 'COFC';
      netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'HISTORY_SOFTWARE'), ...
         fliplr([currentHistoId idProf-1 0]), ...
         fliplr([1 1 length(value)]), value');
      value = g_cofc_ncConvertMonoProfileVersion;
      netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'HISTORY_SOFTWARE_RELEASE'), ...
         fliplr([currentHistoId idProf-1 0]), ...
         fliplr([1 1 length(value)]), value');
      value = outputDateUpdate;
      netcdf.putVar(fCdf, netcdf.inqVarID(fCdf, 'HISTORY_DATE'), ...
         fliplr([currentHistoId idProf-1 0]), ...
         fliplr([1 1 length(value)]), value');
   end
   
   netcdf.close(fCdf);
end

o_ok = 1;

return

% ------------------------------------------------------------------------------
% Compute DOXY values.
%
% SYNTAX :
%  [o_doxyValues] = compute_DOXY(a_floatNum, ...
%    a_jsonFloatInfoDirName, a_jsonFloatMetaDirName, ...
%    a_molarDoxyValues, a_presValues, a_tempValues, a_salValues)
%
% INPUT PARAMETERS :
%   a_floatNum             : float WMO number
%   a_jsonFloatInfoDirName : directory name of float JSON information files
%   a_jsonFloatMetaDirName : directory name of float JSON meta-data files
%   a_molarDoxyValues      : oxygen sensor measurements
%   a_presValues           : pressure measurement values
%   a_tempValues           : temperature measurement values
%   a_salValues            : salinity measurement values
%
% OUTPUT PARAMETERS :
%   o_doxyValues : dissolved oxygen values
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   29/07/2014 - RNU - creation
% ------------------------------------------------------------------------------
function [o_doxyValues] = compute_DOXY(a_floatNum, ...
   a_jsonFloatInfoDirName, a_jsonFloatMetaDirName, ...
   a_molarDoxyValues, a_presValues, a_tempValues, a_salValues)

% output parameters initialization
o_doxyValues = [];

% arrays to store calibration information
global g_decArgo_calibInfo;
g_decArgo_calibInfo = [];


% retrieve the name of the JSON float information file
floatInfoFileNames = dir([a_jsonFloatInfoDirName '/' sprintf('%d_*_info.json', a_floatNum)]);
if (length(floatInfoFileNames) == 1)
   floatInfoFileName = [a_jsonFloatInfoDirName '/' floatInfoFileNames(1).name];
elseif (isempty(floatInfoFileNames))
   fprintf('ERROR: Float information file not found for float #%d\n', a_floatNum);
   return
else
   fprintf('ERROR: Multiple float information files for float #%d\n', a_floatNum);
   return
end

% read information file
fileContents = loadjson(floatInfoFileName);

% float decoder Id
floatDecId = str2num(getfield(fileContents, 'DECODER_ID'));
if (floatDecId == -1)
   
   floatType = getfield(fileContents, 'FLOAT_TYPE');
   floatDecVersion = getfield(fileContents, 'DECODER_VERSION');
   
   fprintf('WARNING: Float #%d (FLOAT_TYPE:%s, Coriolis version: %s not enough information to compute DOXY\n', ...
      a_floatNum, floatType, floatDecVersion);
   return
end

% retrieve the name of the JSON float meta-data file
floatMetaDataFileName = [a_jsonFloatMetaDirName '/' sprintf('%d_meta.json', a_floatNum)];
if ~(exist(floatMetaDataFileName, 'file') == 2)
   fprintf('ERROR: Json meta-data file not found: %s\n', floatMetaDataFileName);
   return
end

% read meta-data file
metaData = loadjson(floatMetaDataFileName);

% store DO calibration information
if ((floatDecId == 4) || (floatDecId == 19))
   
   % read the calibration coefficients in the json meta-data file
   
   % fill the calibration coefficients
   if (isfield(metaData, 'CALIBRATION_COEFFICIENT'))
      if (~isempty(metaData.CALIBRATION_COEFFICIENT))
         fieldNames = fields(metaData.CALIBRATION_COEFFICIENT);
         for idF = 1:length(fieldNames)
            g_decArgo_calibInfo.(fieldNames{idF}) = metaData.CALIBRATION_COEFFICIENT.(fieldNames{idF});
         end
      end
   end
   
   if (isempty(g_decArgo_calibInfo))
      fprintf('WARNING: Float #%d: DOXY calibration coefficients are missing in the Json meta-data file: %s\n', ...
         a_floatNum, ...
         a_jsonFloatMetaDirName);
      return
   end
   
   % current float WMO number
   global g_decArgo_floatNum;
   g_decArgo_floatNum = a_floatNum;
   
   % current cycle number
   global g_decArgo_cycleNum;
   g_decArgo_cycleNum = -1;
   
   % default values initialization
   init_default_values;
   
   % compute DOXY
   [o_doxyValues] = compute_DOXY_4_19_25(a_molarDoxyValues, ...
      a_presValues, a_tempValues, a_salValues);
   
else
   
   fprintf('WARNING: Float #%d: DOXY processing not implemented yet for decId #%d\n', ...
      a_floatNum, floatDecId);
end

return

% ------------------------------------------------------------------------------
% Compute the profile cut-off pressure of an Argos float and retrieve the
% cut-off pressures of an Iridium float.
%
% SYNTAX :
%  [o_cutOffPresVal, o_cutOffPresCy] = get_cutoff_pres(a_floatNum, ...
%    a_jsonFloatInfoDirName, a_jsonFloatMetaDirName, a_rtNcDirName)
%
% INPUT PARAMETERS :
%   a_floatNum             : float WMO number
%   a_jsonFloatInfoDirName : directory name of float JSON information files
%   a_jsonFloatMetaDirName : directory name of float JSON meta-data files
%   a_rtNcDirName          : name of the top directory of the RT nc files
%
% OUTPUT PARAMETERS :
%   o_cutOffPresVal : profile cut-off pressures
%   o_cutOffPresCy  : cycles associated to profile cut-off pressures
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   04/09/2014 - RNU - creation
% ------------------------------------------------------------------------------
function [o_cutOffPresVal, o_cutOffPresCy] = get_cutoff_pres(a_floatNum, ...
   a_jsonFloatInfoDirName, a_jsonFloatMetaDirName, a_rtNcDirName)

% output parameters initialization
o_cutOffPresVal = [];
o_cutOffPresCy = [];


% retrieve the name of the JSON float information file
floatInfoFileNames = dir([a_jsonFloatInfoDirName '/' sprintf('%d_*_info.json', a_floatNum)]);
if (length(floatInfoFileNames) == 1)
   floatInfoFileName = [a_jsonFloatInfoDirName '/' floatInfoFileNames(1).name];
elseif (isempty(floatInfoFileNames))
   fprintf('ERROR: Float information file not found for float #%d\n', a_floatNum);
   o_cutOffPresVal = -1;
   return
else
   fprintf('ERROR: Multiple float information files for float #%d\n', a_floatNum);
   return
end

% read information file
fileContents = loadjson(floatInfoFileName);

% check if this float should have a JSON meta-data file
floatDecId = str2num(getfield(fileContents, 'DECODER_ID'));
if (floatDecId == -1)
   
   floatType = getfield(fileContents, 'FLOAT_TYPE');
   floatDecVersion = getfield(fileContents, 'DECODER_VERSION');
   
   if (strcmp(floatType, 'PROVOR'))
      fprintf('WARNING: Float #%d (FLOAT_TYPE:%s, Coriolis version: %s) not enough information to compute the cut-off pressure of the CTD\n', ...
         a_floatNum, floatType, floatDecVersion);
   else
      fprintf('INFO: Float #%d (FLOAT_TYPE:%s, Coriolis version: %s) no cut-off pressure of the CTD\n', ...
         a_floatNum, floatType, floatDecVersion);
   end
   
   o_cutOffPresVal = -1;
else
   
   if (floatDecId < 100)
      
      % for Argos floats, the cut-off pressure of the CTD pump is stored in the
      % json meta-data file (as a configuration parameter)
      
      % retrieve the name of the JSON float meta-data file
      floatMetaDataFileName = [a_jsonFloatMetaDirName '/' sprintf('%d_meta.json', a_floatNum)];
      if ~(exist(floatMetaDataFileName, 'file') == 2)
         fprintf('ERROR: Json meta-data file not found: %s\n', floatMetaDataFileName);
         return
      end
      
      % read meta-data file
      metaData = loadjson(floatMetaDataFileName);
      
      % retrieve the configuration
      configNames = [];
      configValues = [];
      if ((isfield(metaData, 'CONFIG_PARAMETER_NAME')) && ...
            (isfield(metaData, 'CONFIG_PARAMETER_VALUE')))
         
         configNames = struct2cell(metaData.CONFIG_PARAMETER_NAME);
         cellConfigValues = metaData.CONFIG_PARAMETER_VALUE;
         configValues = nan(size(configNames, 1), size(cellConfigValues, 2));
         if (size(configValues, 2) > 1)
            for idConf = 1:length(cellConfigValues)
               cellConfigVals = struct2cell(cellConfigValues{idConf});
               for idVal = 1:length(cellConfigVals)
                  if (~isempty(cellConfigVals{idVal}))
                     configValues(idVal, idConf) = str2num(cellConfigVals{idVal});
                  end
               end
            end
         else
            cellConfigValues = struct2cell(metaData.CONFIG_PARAMETER_VALUE);
            for idVal = 1:length(cellConfigValues)
               if (~isempty(cellConfigValues{idVal}))
                  configValues(idVal, 1) = str2num(cellConfigValues{idVal});
               end
            end
         end
      end
      
      if (~isempty(configNames))
         
         switch (floatDecId)
            
            case {1, 11, 12, 4, 19, 3}
               
               % retrieve surface slice thickness
               if (floatDecId ~= 3)
                  thickSurf = get_config_value('CONFIG_PM12_', configNames, configValues);
               else
                  thickSurf = get_config_value('CONFIG_PM11_', configNames, configValues);
               end
               
               if (~isempty(thickSurf))
                  o_cutOffPresVal = 5 + thickSurf/2;
               else
                  fprintf('WARNING: Float #%d: Surface slice thickness configuration parameter is missing in the Json meta-data file\n', ...
                     a_floatNum);
               end
               
            case {24, 27, 25, 28, 29, 17}
               
               % retrieve surface slice thickness
               if ((floatDecId == 27) || (floatDecId == 28) || (floatDecId == 29))
                  ctdPumpSwitchOffPres = get_config_value('CONFIG_PT20_', configNames, configValues);
                  
                  if (isempty(ctdPumpSwitchOffPres))
                     ctdPumpSwitchOffPres = 5;
                     fprintf('INFO: Float #%d: CTD switch off pressure parameter is missing in the Json meta-data file - using default value (5 dbars)\n', ...
                        a_floatNum);
                  end
               else
                  ctdPumpSwitchOffPres = 5;
               end
               
               o_cutOffPresVal = ctdPumpSwitchOffPres + 0.5;
               
            otherwise
               o_cutOffPresVal = '';
               fprintf('WARNING: Float #%d: No rules to compute cutoff pressure for decoderId #%d\n', ...
                  a_floatNum, ...
                  floatDecId);
         end
      end
   else
      
      % for Iridium floats, the cut-off pressure of the profile is stored in the
      % TECH NetCDF file (as the pressure of the 'sub-surface point'))
      
      techFileName = sprintf('%d_tech.nc', a_floatNum);
      techFilePathName = [a_rtNcDirName '/' num2str(a_floatNum) '/' techFileName];
      
      if (exist(techFilePathName, 'file') == 2)
         
         % retrieve information from TECH file
         wantedTechVars = [ ...
            {'CYCLE_NUMBER'} ...
            {'TECHNICAL_PARAMETER_NAME'} ...
            {'TECHNICAL_PARAMETER_VALUE'} ...
            ];
         
         % retrieve information from TECH netCDF file
         [techData] = get_data_from_nc_file(techFilePathName, wantedTechVars);
         
         idVal = find(strcmp('CYCLE_NUMBER', techData) == 1);
         if (~isempty(idVal))
            cycleNumber = techData{idVal+1};
         end
         idVal = find(strcmp('TECHNICAL_PARAMETER_NAME', techData) == 1);
         if (~isempty(idVal))
            techParamName = techData{idVal+1}';
         end
         idVal = find(strcmp('TECHNICAL_PARAMETER_VALUE', techData) == 1);
         if (~isempty(idVal))
            techParamValue = techData{idVal+1}';
         end
         
         for idCycle = min(cycleNumber):max(cycleNumber)
            idForCy = find(cycleNumber == idCycle);
            if (~isempty(idForCy))
               for id = 1:length(idForCy)
                  if (strcmp(strtrim(techParamName(idForCy(id), :)), 'PRES_LastAscentPumpedRawSample_dbar'))
                     o_cutOffPresVal(end+1) = str2num(techParamValue(idForCy(id), :));
                     o_cutOffPresCy(end+1) = idCycle;
                     continue
                  end
               end
            end
         end
      else
         fprintf('WARNING: Float #%d: Unable to find the nc TECH file of this float\n', ...
            a_floatNum);
      end
   end
end

return

% ------------------------------------------------------------------------------
% Modify the value of a dimension in a NetCDF schema.
%
% SYNTAX :
%  [o_outputSchema] = update_dim_in_nc_schema(a_inputSchema, ...
%    a_dimName, a_dimVal)
%
% INPUT PARAMETERS :
%   a_inputSchema  : input NetCDF schema
%   a_dimName      : dimension name
%   a_dimVal       : dimension value
%
% OUTPUT PARAMETERS :
%   o_outputSchema  : output NetCDF schema
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   04/09/2014 - RNU - creation
% ------------------------------------------------------------------------------
function [o_outputSchema] = update_dim_in_nc_schema(a_inputSchema, ...
   a_dimName, a_dimVal)

% output parameters initialization
o_outputSchema = [];

% update the dimension
idDim = find(strcmp(a_dimName, {a_inputSchema.Dimensions.Name}) == 1, 1);

if (~isempty(idDim))
   a_inputSchema.Dimensions(idDim).Length = a_dimVal;
   
   % update the dimensions of the variables
   for idVar = 1:length(a_inputSchema.Variables)
      var = a_inputSchema.Variables(idVar);
      idDims = find(strcmp(a_dimName, {var.Dimensions.Name}) == 1);
      a_inputSchema.Variables(idVar).Size(idDims) = a_dimVal;
      for idDim = 1:length(idDims)
         a_inputSchema.Variables(idVar).Dimensions(idDims(idDim)).Length = a_dimVal;
      end
   end
end

o_outputSchema = a_inputSchema;

return

% ------------------------------------------------------------------------------
% Check if a variable (defined by its name) is present in a NetCDF file.
%
% SYNTAX :
%  [o_present] = var_is_present(a_ncId, a_varName)
%
% INPUT PARAMETERS :
%   a_ncId    : NetCDF file Id
%   a_varName : variable name
%
% OUTPUT PARAMETERS :
%   o_present : exist flag (1 if exists, 0 otherwise)
%
% EXAMPLES :
%
% SEE ALSO :
% AUTHORS  : Jean-Philippe Rannou (Altran)(jean-philippe.rannou@altran.com)
% ------------------------------------------------------------------------------
% RELEASES :
%   03/26/2014 - RNU - creation
% ------------------------------------------------------------------------------
function [o_present] = var_is_present(a_ncId, a_varName)

o_present = 0;

[nbDims, nbVars, nbGAtts, unlimId] = netcdf.inq(a_ncId);

for idVar = 0:nbVars-1
   [varName, varType, varDims, nbAtts] = netcdf.inqVar(a_ncId, idVar);
   if (strcmp(varName, a_varName))
      o_present = 1;
      break
   end
end

return
