Ignore:
Timestamp:
Sep 20, 2024, 12:32:04 PM (4 months ago)
Author:
Laurent Fairhead
Message:

Updating cirrus branch to trunk revision 5171

Location:
LMDZ6/branches/cirrus
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • LMDZ6/branches/cirrus

  • LMDZ6/branches/cirrus/libf/misc/readTracFiles_mod.f90

    r4951 r5202  
    11MODULE readTracFiles_mod
    22
    3   USE strings_mod,    ONLY: msg, find, get_in, str2int, dispTable, strHead,  strReduce,  strFind, strStack, strIdx, &
    4        test, removeComment, cat, fmsg, maxlen, int2str, checkList, strParse, strReplace, strTail, strCount, reduceExpr
     3  USE strings_mod,    ONLY: msg, find, get_in, dispTable, strHead,  strReduce,  strFind, strStack, strIdx, &
     4             removeComment, cat, fmsg, maxlen, checkList, strParse, strReplace, strTail, strCount, reduceExpr, &
     5             int2str, str2int, real2str, str2real, bool2str, str2bool
    56
    67  IMPLICIT NONE
     
    910
    1011  PUBLIC :: maxlen                                              !--- PARAMETER FOR CASUAL STRING LENGTH
    11   PUBLIC :: tracers                                             !--- TRACERS  DESCRIPTION DATABASE
    12   PUBLIC :: trac_type, setGeneration, indexUpdate               !--- TRACERS  DESCRIPTION ASSOCIATED TOOLS
     12  PUBLIC :: trac_type, tracers, setGeneration, indexUpdate      !--- TRACERS  DESCRIPTION DATABASE + ASSOCIATED TOOLS
    1313  PUBLIC :: testTracersFiles, readTracersFiles                  !--- TRACERS FILES READING ROUTINES
    14   PUBLIC :: getKey, fGetKey, fGetKeys, addKey, setDirectKeys    !--- TOOLS TO GET/SET KEYS FROM/TO  tracers & isotopes
    15   PUBLIC :: getKeysDBase,    setKeysDBase                       !--- TOOLS TO GET/SET THE DATABASE (tracers & isotopes)
    16 
    17   PUBLIC :: addPhase, getiPhase,  old_phases, phases_sep, &     !--- FUNCTIONS RELATED TO THE PHASES
    18    nphases, delPhase, getPhase, known_phases, phases_names      !--- + ASSOCIATED VARIABLES
     14  PUBLIC :: getKeysDBase, setKeysDBase                          !--- TOOLS TO GET/SET THE DATABASE (tracers & isotopes)
     15  PUBLIC :: addTracer, delTracer                                !--- ADD/REMOVE A TRACER FROM
     16  PUBLIC :: addKey,    delKey,    getKey,    keys_type          !--- TOOLS TO SET/DEL/GET KEYS FROM/TO  tracers & isotopes
     17  PUBLIC :: addPhase,  delPhase,  getPhase,  getiPhase,  &      !--- FUNCTIONS RELATED TO THE PHASES
     18   nphases, old_phases, phases_sep, known_phases, phases_names  !--- + ASSOCIATED VARIABLES
    1919
    2020  PUBLIC :: oldH2OIso, newH2OIso, old2newH2O, new2oldH2O        !--- H2O ISOTOPES BACKWARD COMPATIBILITY (OLD traceur.def)
    2121  PUBLIC :: oldHNO3,   newHNO3                                  !--- HNO3 REPRO   BACKWARD COMPATIBILITY (OLD start.nc)
    2222
    23   PUBLIC :: tran0, idxAncestor, ancestor                        !--- GENERATION 0 TRACER + TOOLS FOR GENERATIONS
     23  PUBLIC :: tran0                                               !--- TRANSPORTING FLUID (USUALLY air)
    2424
    2525  !=== FOR ISOTOPES: GENERAL
    26   PUBLIC :: isot_type, readIsotopesFile, isoSelect              !--- ISOTOPES DESCRIPTION TYPE + READING ROUTINE
    27   PUBLIC :: ixIso, nbIso                                        !--- INDEX OF SELECTED ISOTOPES CLASS + NUMBER OF CLASSES
     26  PUBLIC :: isot_type, processIsotopes, isoSelect, ixIso, nbIso !--- PROCESS [AND READ] & SELECT ISOTOPES + CLASS IDX & NUMBER
    2827
    2928  !=== FOR ISOTOPES: H2O FAMILY ONLY
     
    3635  PUBLIC :: itZonIso                                            !--- Idx IN isoName(1:niso) = f(tagging idx, isotope idx)
    3736  PUBLIC :: iqIsoPha                                            !--- Idx IN qx(1:nqtot)     = f(isotope idx,   phase idx)
     37  PUBLIC :: iqWIsoPha                                           !--- Idx IN qx(1:nqtot)     = f(isotope idx,   phase idx) but with normal water first
    3838  PUBLIC :: isoCheck                                            !--- FLAG TO RUN ISOTOPES CHECKING ROUTINES
    3939
    4040  PUBLIC :: maxTableWidth
    4141!------------------------------------------------------------------------------------------------------------------------------
    42   TYPE :: keys_type                                        !=== TYPE FOR A SET OF KEYS ASSOCIATED TO AN ELEMENT
    43     CHARACTER(LEN=maxlen)              :: name             !--- Tracer name
    44     CHARACTER(LEN=maxlen), ALLOCATABLE :: key(:)           !--- Keys string list
    45     CHARACTER(LEN=maxlen), ALLOCATABLE :: val(:)           !--- Corresponding values string list
     42  TYPE :: keys_type                                             !=== TYPE FOR A SET OF KEYS ASSOCIATED TO AN ELEMENT
     43    CHARACTER(LEN=maxlen)              :: name                  !--- Tracer name
     44    CHARACTER(LEN=maxlen), ALLOCATABLE :: key(:)                !--- Keys string list
     45    CHARACTER(LEN=maxlen), ALLOCATABLE :: val(:)                !--- Corresponding values string list
    4646  END TYPE keys_type
    4747!------------------------------------------------------------------------------------------------------------------------------
    48   TYPE :: trac_type                                        !=== TYPE FOR A SINGLE TRACER NAMED "name"
    49     CHARACTER(LEN=maxlen) :: name        = ''              !--- Name of the tracer
    50     CHARACTER(LEN=maxlen) :: gen0Name    = ''              !--- First generation ancestor name
    51     CHARACTER(LEN=maxlen) :: parent      = ''              !--- Parent name
    52     CHARACTER(LEN=maxlen) :: longName    = ''              !--- Long name (with advection scheme suffix)
    53     CHARACTER(LEN=maxlen) :: type        = 'tracer'        !--- Type  (so far: 'tracer' / 'tag')
    54     CHARACTER(LEN=maxlen) :: phase       = 'g'             !--- Phase ('g'as / 'l'iquid / 's'olid)
    55     CHARACTER(LEN=maxlen) :: component   = ''              !--- Coma-separated list of components (Ex: lmdz,inca)
    56     INTEGER               :: iGeneration = -1              !--- Generation number (>=0)
    57     INTEGER               :: iqParent    = 0               !--- Parent index
    58     INTEGER,  ALLOCATABLE :: iqDescen(:)                   !--- Descendants index (in growing generation order)
    59     INTEGER               :: nqDescen    = 0               !--- Number of descendants (all generations)
    60     INTEGER               :: nqChildren  = 0               !--- Number of children  (first generation)
    61     TYPE(keys_type)       :: keys                          !--- <key>=<val> pairs vector
    62     INTEGER               :: iadv        = 10              !--- Advection scheme used
    63     LOGICAL               :: isAdvected  = .FALSE.         !--- "true" tracers: iadv > 0.   COUNT(isAdvected )=nqtrue
    64     LOGICAL               :: isInPhysics = .TRUE.          !--- "true" tracers: in tr_seri. COUNT(isInPhysics)=nqtottr
    65     INTEGER               :: iso_iGroup  = 0               !--- Isotopes group index in isotopes(:)
    66     INTEGER               :: iso_iName   = 0               !--- Isotope  name  index in isotopes(iso_iGroup)%trac(:)
    67     INTEGER               :: iso_iZone   = 0               !--- Isotope  zone  index in isotopes(iso_iGroup)%zone(:)
    68     INTEGER               :: iso_iPhase  = 0               !--- Isotope  phase index in isotopes(iso_iGroup)%phase
     48  TYPE :: trac_type                                             !=== TYPE FOR A SINGLE TRACER NAMED "name"
     49    CHARACTER(LEN=maxlen) :: name        = ''                   !--- Name of the tracer
     50    TYPE(keys_type)       :: keys                               !--- <key>=<val> pairs vector
     51    CHARACTER(LEN=maxlen) :: gen0Name    = ''                   !--- First generation ancestor name
     52    CHARACTER(LEN=maxlen) :: parent      = ''                   !--- Parent name
     53    CHARACTER(LEN=maxlen) :: longName    = ''                   !--- Long name (with advection scheme suffix)
     54    CHARACTER(LEN=maxlen) :: type        = 'tracer'             !--- Type  (so far: 'tracer' / 'tag')
     55    CHARACTER(LEN=maxlen) :: phase       = 'g'                  !--- Phase ('g'as / 'l'iquid / 's'olid)
     56    CHARACTER(LEN=maxlen) :: component   = ''                   !--- Coma-separated list of components (Ex: lmdz,inca)
     57    INTEGER               :: iGeneration = -1                   !--- Generation number (>=0)
     58    INTEGER               :: iqParent    = 0                    !--- Parent index
     59    INTEGER,  ALLOCATABLE :: iqDescen(:)                        !--- Descendants index (in growing generation order)
     60    INTEGER               :: nqDescen    = 0                    !--- Number of descendants (all generations)
     61    INTEGER               :: nqChildren  = 0                    !--- Number of children  (first generation)
     62    INTEGER               :: iadv        = 10                   !--- Advection scheme used
     63    LOGICAL               :: isAdvected  = .FALSE.              !--- "true" tracers: iadv > 0.   COUNT(isAdvected )=nqtrue
     64    LOGICAL               :: isInPhysics = .TRUE.               !--- "true" tracers: in tr_seri. COUNT(isInPhysics)=nqtottr
     65    INTEGER               :: iso_iGroup  = 0                    !--- Isotopes group index in isotopes(:)
     66    INTEGER               :: iso_iName   = 0                    !--- Isotope  name  index in isotopes(iso_iGroup)%trac(:)
     67    INTEGER               :: iso_iZone   = 0                    !--- Isotope  zone  index in isotopes(iso_iGroup)%zone(:)
     68    INTEGER               :: iso_iPhase  = 0                    !--- Isotope  phase index in isotopes(iso_iGroup)%phase
    6969  END TYPE trac_type
    7070!------------------------------------------------------------------------------------------------------------------------------
    71   TYPE :: isot_type                                        !=== TYPE FOR AN ISOTOPES FAMILY DESCENDING ON TRACER "parent"
    72     CHARACTER(LEN=maxlen)              :: parent           !--- Isotopes family name (parent tracer name ; ex: H2O)
    73     LOGICAL                            :: check=.FALSE.    !--- Triggering of the checking routines
    74     TYPE(keys_type),       ALLOCATABLE :: keys(:)          !--- Isotopes keys/values pairs list     (length: niso)
    75     CHARACTER(LEN=maxlen), ALLOCATABLE :: trac(:)          !--- Isotopes + tagging tracers list     (length: ntiso)
    76     CHARACTER(LEN=maxlen), ALLOCATABLE :: zone(:)          !--- Geographic tagging zones names list (length: nzone)
    77     CHARACTER(LEN=maxlen)              :: phase = 'g'      !--- Phases list: [g][l][s]              (length: nphas)
    78     INTEGER                            :: niso  = 0        !--- Number of isotopes, excluding tagging tracers
    79     INTEGER                            :: nzone = 0        !--- Number of geographic tagging zones
    80     INTEGER                            :: ntiso = 0        !--- Number of isotopes, including tagging tracers
    81     INTEGER                            :: nphas = 0        !--- Number phases
    82     INTEGER,               ALLOCATABLE :: iqIsoPha(:,:)    !--- Idx in "tracers(1:nqtot)" = f(name(1:ntiso)),phas)
    83                                                            !---        "iqIsoPha" former name: "iqiso"
    84     INTEGER,               ALLOCATABLE :: itZonIso(:,:)    !--- Idx in "trac(1:ntiso)" = f(zone, name(1:niso))
    85                                                            !---        "itZonIso" former name: "index_trac"
    86   END TYPE isot_type
     71  TYPE :: isot_type                                             !=== TYPE FOR AN ISOTOPES FAMILY DESCENDING ON TRACER "parent"
     72    CHARACTER(LEN=maxlen)              :: parent                !--- Isotopes family name (parent tracer name ; ex: H2O)
     73    TYPE(keys_type),       ALLOCATABLE :: keys(:)               !--- Isotopes keys/values pairs list     (length: niso)
     74    LOGICAL                            :: check=.FALSE.         !--- Flag for checking routines triggering
     75    CHARACTER(LEN=maxlen), ALLOCATABLE :: trac(:)               !--- Isotopes + tagging tracers list     (length: ntiso)
     76    CHARACTER(LEN=maxlen), ALLOCATABLE :: zone(:)               !--- Geographic tagging zones names list (length: nzone)
     77    CHARACTER(LEN=maxlen)              :: phase = 'g'           !--- Phases list: [g][l][s]              (length: nphas)
     78    INTEGER                            :: niso  = 0             !--- Number of isotopes, excluding tagging tracers
     79    INTEGER                            :: ntiso = 0             !--- Number of isotopes, including tagging tracers
     80    INTEGER                            :: nzone = 0             !--- Number of geographic tagging zones
     81    INTEGER                            :: nphas = 0             !--- Number of phases
     82    INTEGER,               ALLOCATABLE :: iqIsoPha(:,:)         !--- Idx in "tracers(1:nqtot)" = f(name(1:ntiso),phas)
     83                                                                !---        (former name: "iqiso"
     84    INTEGER,               ALLOCATABLE :: iqWIsoPha(:,:)        !--- Idx in "tracers(1:nqtot)" = f([H2O,name(1:ntiso)],phas)
     85    INTEGER,               ALLOCATABLE :: itZonIso(:,:)         !--- Idx in "trac(1:ntiso)" = f(zone, name(1:niso))
     86  END TYPE isot_type                                            !---        (former name: "index_trac")
    8787!------------------------------------------------------------------------------------------------------------------------------
    8888  TYPE :: dataBase_type                                         !=== TYPE FOR TRACERS SECTION
    89     CHARACTER(LEN=maxlen)  :: name                              !--- Section name
     89    CHARACTER(LEN=maxlen) :: name                               !--- Section name
    9090    TYPE(trac_type), ALLOCATABLE :: trac(:)                     !--- Tracers descriptors
    9191  END TYPE dataBase_type
    9292!------------------------------------------------------------------------------------------------------------------------------
    9393  INTERFACE getKey
    94     MODULE PROCEDURE getKeyByName_s1, getKeyByName_s1m, getKeyByName_sm, getKey_sm, &
    95                      getKeyByName_i1, getKeyByName_i1m, getKeyByName_im, getKey_im, &
    96                      getKeyByName_r1, getKeyByName_r1m, getKeyByName_rm, getKey_rm, &
    97                      getKeyByName_l1, getKeyByName_l1m, getKeyByName_lm, getKey_lm
     94    MODULE PROCEDURE &
     95       getKeyByIndex_s111, getKeyByIndex_sm11, getKeyByIndex_s1m1, getKeyByIndex_smm1, getKeyByIndex_s1mm, getKeyByIndex_smmm, &
     96       getKeyByIndex_i111, getKeyByIndex_im11, getKeyByIndex_i1m1, getKeyByIndex_imm1, getKeyByIndex_i1mm, getKeyByIndex_immm, &
     97       getKeyByIndex_r111, getKeyByIndex_rm11, getKeyByIndex_r1m1, getKeyByIndex_rmm1, getKeyByIndex_r1mm, getKeyByIndex_rmmm, &
     98       getKeyByIndex_l111, getKeyByIndex_lm11, getKeyByIndex_l1m1, getKeyByIndex_lmm1, getKeyByIndex_l1mm, getKeyByIndex_lmmm, &
     99        getKeyByName_s111,  getKeyByName_sm11,  getKeyByName_s1m1,  getKeyByName_smm1,  getKeyByName_s1mm,  getKeyByName_smmm, &
     100        getKeyByName_i111,  getKeyByName_im11,  getKeyByName_i1m1,  getKeyByName_imm1,  getKeyByName_i1mm,  getKeyByName_immm, &
     101        getKeyByName_r111,  getKeyByName_rm11,  getKeyByName_r1m1,  getKeyByName_rmm1,  getKeyByName_r1mm,  getKeyByName_rmmm, &
     102        getKeyByName_l111,  getKeyByName_lm11,  getKeyByName_l1m1,  getKeyByName_lmm1,  getKeyByName_l1mm,  getKeyByName_lmmm
    98103  END INTERFACE getKey
    99104!------------------------------------------------------------------------------------------------------------------------------
    100   INTERFACE    isoSelect;  MODULE PROCEDURE  isoSelectByIndex,  isoSelectByName; END INTERFACE isoSelect
    101   INTERFACE  old2newH2O;   MODULE PROCEDURE  old2newH2O_1,  old2newH2O_m;        END INTERFACE old2newH2O
    102   INTERFACE  new2oldH2O;   MODULE PROCEDURE  new2oldH2O_1,  new2oldH2O_m;        END INTERFACE new2oldH2O
    103   INTERFACE fGetKey;       MODULE PROCEDURE fgetKeyIdx_s1, fgetKeyNam_s1;        END INTERFACE fGetKey
    104   INTERFACE tracersSubset; MODULE PROCEDURE trSubset_Indx, trSubset_Name, trSubset_gen0Name; END INTERFACE tracersSubset
    105   INTERFACE idxAncestor;   MODULE PROCEDURE idxAncestor_1, idxAncestor_m, idxAncestor_mt;    END INTERFACE idxAncestor
    106   INTERFACE    ancestor;   MODULE PROCEDURE    ancestor_1,    ancestor_m,    ancestor_mt;    END INTERFACE    ancestor
    107   INTERFACE      addKey;   MODULE PROCEDURE      addKey_1; END INTERFACE addKey!,      addKey_m,     addKey_mm;     END INTERFACE addKey
    108   INTERFACE    addPhase;   MODULE PROCEDURE   addPhase_s1,   addPhase_sm,   addPhase_i1,   addPhase_im; END INTERFACE addPhase
     105  INTERFACE addKey
     106    MODULE PROCEDURE addKey_s11, addKey_s1m, addKey_smm, addKey_i11, addKey_i1m, addKey_imm, &
     107                     addKey_r11, addKey_r1m, addKey_rmm, addKey_l11, addKey_l1m, addKey_lmm
     108  END INTERFACE addKey
     109!------------------------------------------------------------------------------------------------------------------------------
     110  INTERFACE     isoSelect; MODULE PROCEDURE  isoSelectByIndex,  isoSelectByName; END INTERFACE isoSelect
     111  INTERFACE    old2newH2O; MODULE PROCEDURE  old2newH2O_1,  old2newH2O_m;        END INTERFACE old2newH2O
     112  INTERFACE    new2oldH2O; MODULE PROCEDURE  new2oldH2O_1,  new2oldH2O_m;        END INTERFACE new2oldH2O
     113  INTERFACE     addTracer; MODULE PROCEDURE   addTracer_1, addTracer_1def;       END INTERFACE addTracer
     114  INTERFACE     delTracer; MODULE PROCEDURE   delTracer_1, delTracer_1def;       END INTERFACE delTracer
     115  INTERFACE      addPhase; MODULE PROCEDURE   addPhase_s1,  addPhase_sm,  addPhase_i1,  addPhase_im; END INTERFACE addPhase
     116  INTERFACE tracersSubset; MODULE PROCEDURE trSubset_Indx,     trSubset_Name,     trSubset_gen0Name; END INTERFACE tracersSubset
    109117!------------------------------------------------------------------------------------------------------------------------------
    110118
     
    114122  !--- SOME PARAMETERS THAT ARE NOT LIKELY TO CHANGE OFTEN
    115123  CHARACTER(LEN=maxlen), SAVE      :: tran0        = 'air'      !--- Default transporting fluid
    116   CHARACTER(LEN=maxlen), PARAMETER :: old_phases   = 'vlifbc'     !--- Old phases for water (no separator)
    117   CHARACTER(LEN=maxlen), PARAMETER :: known_phases = 'glsfbc'     !--- Known phases initials
     124  CHARACTER(LEN=maxlen), PARAMETER :: old_phases   = 'vlirb'    !--- Old phases for water (no separator)
     125  CHARACTER(LEN=maxlen), PARAMETER :: known_phases = 'glsrb'    !--- Known phases initials
    118126  INTEGER, PARAMETER :: nphases = LEN_TRIM(known_phases)        !--- Number of phases
    119127  CHARACTER(LEN=maxlen), SAVE      :: phases_names(nphases) &   !--- Known phases names
    120                                 = ['gaseous', 'liquid ', 'solid  ', 'fracld ', 'blosnow', 'cldvapr']
    121   CHARACTER(LEN=1), SAVE :: phases_sep  =  '_'                  !--- Phase separator
    122   LOGICAL,          SAVE :: tracs_merge = .TRUE.                !--- Merge/stack tracers lists
    123   LOGICAL,          SAVE :: lSortByGen  = .TRUE.                !--- Sort by growing generation
     128                                = ['gaseous  ', 'liquid   ', 'solid    ', 'cloud    ','blownSnow']
     129  CHARACTER(LEN=1),      SAVE :: phases_sep  =  '_'             !--- Phase separator
    124130  CHARACTER(LEN=maxlen), SAVE :: isoFile = 'isotopes_params.def'!--- Name of the isotopes parameters file
    125131
     
    128134  CHARACTER(LEN=maxlen), SAVE :: newH2OIso(5) = ['H216O', 'HDO  ', 'H218O', 'H217O', 'HTO  ']
    129135
    130   !--- CORRESPONDANCE BETWEEN OLD AND NEW HNO3 RELATED SPECIES NAMES
     136  !--- CORRESPONDANCE BETWEEN OLD AND NEW HNO3 RELATED SPECIES NAMES (FOR REPROBUS)
    131137  CHARACTER(LEN=maxlen), SAVE ::   oldHNO3(2) = ['HNO3_g ', 'HNO3   ']
    132138  CHARACTER(LEN=maxlen), SAVE ::   newHNO3(2) = ['HNO3   ', 'HNO3tot']
     
    138144  !=== ALIASES OF VARIABLES FROM SELECTED ISOTOPES FAMILY EMBEDDED IN "isotope" (isotopes(ixIso))
    139145  TYPE(isot_type),         SAVE, POINTER :: isotope             !--- CURRENTLY SELECTED ISOTOPES FAMILY DESCRIPTOR
    140   INTEGER,                 SAVE          :: ixIso, iH2O         !--- Index of the selected isotopes family and H2O family
     146  INTEGER,                 SAVE          :: ixIso, iH2O=0       !--- Index of the selected isotopes family and H2O family
    141147  INTEGER,                 SAVE          :: nbIso               !--- Number of isotopes classes
    142148  LOGICAL,                 SAVE          :: isoCheck            !--- Flag to trigger the checking routines
     
    148154                                            nphas, ntiso        !--- NUMBER OF PHASES AND ISOTOPES + ISOTOPIC TAGGING TRACERS
    149155  INTEGER,                 SAVE, POINTER ::itZonIso(:,:), &     !--- INDEX IN "isoTrac" AS f(tagging zone idx,  isotope idx)
    150                                            iqIsoPha(:,:)        !--- INDEX IN "qx"      AS f(isotopic tracer idx, phase idx)
     156                                           iqIsoPha(:,:), &     !--- INDEX IN "qx" AS f(isotopic tracer idx, phase idx)
     157                                           iqWIsoPha(:,:)       !--- INDEX IN "qx" AS f(H2O + isotopic tracer idx, phase idx)
     158
     159  !=== PARAMETERS FOR DEFAULT BEHAVIOUR
     160  LOGICAL, PARAMETER :: lTracsMerge = .FALSE.                   !--- Merge/stack tracers lists
     161  LOGICAL, PARAMETER :: lSortByGen  = .TRUE.                    !--- Sort by growing generation
    151162
    152163  INTEGER,    PARAMETER :: maxTableWidth = 192                  !--- Maximum width of a table displayed with "dispTable"
     
    179190!     * If you need to convert a %key/%val pair into a direct-access key, add the corresponding line in "setDirectKeys".
    180191!==============================================================================================================================
    181 LOGICAL FUNCTION readTracersFiles(type_trac, lRepr) RESULT(lerr)
    182 !------------------------------------------------------------------------------------------------------------------------------
    183   CHARACTER(LEN=*),  INTENT(IN)  :: type_trac                        !--- List of components used
    184   LOGICAL, OPTIONAL, INTENT(IN)  :: lRepr                            !--- Activate the HNNO3 exceptions for REPROBUS
     192LOGICAL FUNCTION readTracersFiles(type_trac, tracs, lRepr) RESULT(lerr)
     193!------------------------------------------------------------------------------------------------------------------------------
     194  CHARACTER(LEN=*),                               INTENT(IN)  :: type_trac     !--- List of components used
     195  TYPE(trac_type), ALLOCATABLE, TARGET, OPTIONAL, INTENT(OUT) :: tracs(:)      !--- Tracers descriptor for external storage
     196  LOGICAL,                              OPTIONAL, INTENT(IN)  :: lRepr         !--- Activate the HNO3 exceptions for REPROBUS
    185197  CHARACTER(LEN=maxlen),  ALLOCATABLE :: s(:), sections(:), trac_files(:)
    186198  CHARACTER(LEN=maxlen) :: str, fname, tname, pname, cname
    187199  INTEGER               :: nsec, ierr, it, ntrac, ns, ip, ix, fType
     200  INTEGER, ALLOCATABLE  :: iGen(:)
    188201  LOGICAL :: lRep
    189202  TYPE(keys_type), POINTER :: k
     
    195208
    196209  !--- Required sections + corresponding files names (new style single section case) for tests
    197   IF(test(testTracersFiles(modname, type_trac, fType, .FALSE., trac_files, sections), lerr)) RETURN
     210  lerr = testTracersFiles(modname, type_trac, fType, .FALSE., trac_files, sections); IF(lerr) RETURN
    198211  nsec = SIZE(sections)
    199212
    200213  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    201   SELECT CASE(fType)                         !--- Set %name, %genOName, %parent, %type, %phase, %component, %iGeneration, %keys
     214  SELECT CASE(fType)                         !--- Set name, component, parent, phase, iGeneration, gen0Name, type
    202215  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    203216    CASE(1)                                                          !=== OLD FORMAT "traceur.def"
    204217    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    205218      !--- OPEN THE "traceur.def" FILE
    206       OPEN(90, FILE="traceur.def", FORM='formatted', STATUS='old', IOSTAT=ierr)
     219      OPEN(90, FILE="traceur.def", FORM='formatted', STATUS='old', POSITION='REWIND', IOSTAT=ierr)
    207220
    208221      !--- GET THE TRACERS NUMBER
    209222      READ(90,'(i3)',IOSTAT=ierr)ntrac                               !--- Number of lines/tracers
    210       IF(test(fmsg('Invalid format for "'//TRIM(fname)//'"', modname, ierr /= 0), lerr)) RETURN
     223      lerr = ierr/=0; IF(fmsg('Invalid format for "'//TRIM(fname)//'"', modname, lerr)) RETURN
    211224
    212225      !--- READ THE REMAINING LINES: <hadv> <vadv> <tracer> [<transporting fluid>]
    213       IF(ALLOCATED(tracers)) DEALLOCATE(tracers)
    214226      ALLOCATE(tracers(ntrac))
    215       DO it=1,ntrac                                                  !=== READ RAW DATA: loop on the line/tracer number
     227      DO it = 1, ntrac                                               !=== READ RAW DATA: loop on the line/tracer number
    216228        READ(90,'(a)',IOSTAT=ierr) str
    217         IF(test(fmsg('Invalid format for "' //TRIM(fname)//'"', modname, ierr>0), lerr)) RETURN
    218         IF(test(fmsg('Not enough lines in "'//TRIM(fname)//'"', modname, ierr<0), lerr)) RETURN
     229        lerr = ierr>0; IF(fmsg('Invalid format for "' //TRIM(fname)//'"', modname, lerr)) RETURN
     230        lerr = ierr<0; IF(fmsg('Not enough lines in "'//TRIM(fname)//'"', modname, lerr)) RETURN
    219231        lerr = strParse(str, ' ', s, ns)
    220232        CALL msg('This file is for air tracers only',           modname, ns == 3 .AND. it == 1)
     
    226238        ix = strIdx(oldHNO3, s(3))
    227239        IF(ix /= 0 .AND. lRep) tname = newHNO3(ix)                   !--- Exception for HNO3 (REPROBUS ONLY)
    228         tracers(it)%name = tname                                     !--- Set %name
    229         CALL addKey_1('name', tname, k)                              !--- Set the name of the tracer
     240        tracers(it)%name = tname                                     !--- Set the name of the tracer
     241        CALL addKey('name', tname, k)                                !--- Set the name of the tracer
    230242        tracers(it)%keys%name = tname                                !--- Copy tracers names in keys components
    231243
     
    233245        cname = type_trac                                            !--- Name of the model component
    234246        IF(ANY([(addPhase('H2O', ip), ip = 1, nphases)] == tname)) cname = 'lmdz'
    235         tracers(it)%component = cname                                !--- Set %component
    236         CALL addKey_1('component', cname, k)                         !--- Set the name of the model component
     247        tracers(it)%component = cname                                !--- Set component
     248        CALL addKey('component', cname, k)                           !--- Set the name of the model component
    237249
    238250        !=== NAME OF THE PARENT
     
    243255          IF(ix /= 0 .AND. lRep) pname = newHNO3(ix)                 !--- Exception for HNO3 (REPROBUS ONLY)
    244256        END IF
    245         tracers(it)%parent = pname                                   !--- Set %parent
    246         CALL addKey_1('parent', pname, k)
     257        tracers(it)%parent = pname                                   !--- Set the parent name
     258        CALL addKey('parent', pname, k)
    247259
    248260        !=== PHASE AND ADVECTION SCHEMES NUMBERS
    249         tracers(it)%phase = known_phases(ip:ip)                      !--- Set %phase:  tracer phase (default: "g"azeous)
    250         CALL addKey_1('phase', known_phases(ip:ip), k)               !--- Set the phase of the tracer (default: "g"azeous)
    251         CALL addKey_1('hadv', s(1),  k)                              !--- Set the horizontal advection schemes number
    252         CALL addKey_1('vadv', s(2),  k)                              !--- Set the vertical   advection schemes number
     261        tracers(it)%phase = known_phases(ip:ip)                      !--- Set the phase of the tracer (default: "g"azeous)
     262        CALL addKey('phase', known_phases(ip:ip), k)                 !--- Set the phase of the tracer (default: "g"azeous)
     263        CALL addKey('hadv', s(1),  k)                                !--- Set the horizontal advection schemes number
     264        CALL addKey('vadv', s(2),  k)                                !--- Set the vertical   advection schemes number
    253265      END DO
    254266      CLOSE(90)
    255       IF(test(setGeneration(tracers), lerr)) RETURN                  !--- Set %iGeneration and %gen0Name
    256       WHERE(tracers%iGeneration == 2) tracers(:)%type = 'tag'        !--- Set %type:        'tracer' or 'tag'
    257       DO it=1,ntrac
    258         CALL addKey_1('type', tracers(it)%type, tracers(it)%keys)    !--- Set the type of tracer
     267      lerr = setGeneration(tracers); IF(lerr) RETURN                 !--- Set iGeneration and gen0Name
     268      lerr = getKey('iGeneration', iGen, tracers(:)%keys)            !--- Generation number
     269      WHERE(iGen == 2) tracers(:)%type = 'tag'                       !--- Set type:      'tracer' or 'tag'
     270      DO it = 1, ntrac
     271        CALL addKey('type', tracers(it)%type, tracers(it)%keys)      !--- Set the type of tracer
    259272      END DO
    260       IF(test(checkTracers(tracers, fname, fname), lerr)) RETURN     !--- Detect orphans and check phases
    261       IF(test(checkUnique (tracers, fname, fname), lerr)) RETURN     !--- Detect repeated tracers
    262       CALL sortTracers    (tracers)                                  !--- Sort the tracers
     273      lerr = checkTracers(tracers, fname, fname); IF(lerr) RETURN    !--- Detect orphans and check phases
     274      lerr = checkUnique (tracers, fname, fname); IF(lerr) RETURN    !--- Detect repeated tracers
     275      CALL sortTracers   (tracers)                                   !--- Sort the tracers
    263276    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    264     CASE(2); IF(test(feedDBase(["tracer.def"], [type_trac], modname), lerr)) RETURN !=== SINGLE   FILE, MULTIPLE SECTIONS
     277    CASE(2); lerr=feedDBase(["tracer.def"], [type_trac], modname); IF(lerr) RETURN !=== SINGLE   FILE, MULTIPLE SECTIONS
    265278    !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    266     CASE(3); IF(test(feedDBase(  trac_files  ,  sections,   modname), lerr)) RETURN !=== MULTIPLE FILES, SINGLE  SECTION
     279    CASE(3); lerr=feedDBase(  trac_files  ,  sections,   modname); IF(lerr) RETURN !=== MULTIPLE FILES, SINGLE  SECTION
    267280  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    268281  END SELECT
    269282  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    270283  IF(ALL([2,3] /= fType)) RETURN
    271 
    272   IF(nsec  == 1) THEN;
    273     tracers = dBase(1)%trac
    274   ELSE IF(tracs_merge) THEN
    275     CALL msg('The multiple required sections will be MERGED.',    modname)
    276     IF(test(mergeTracers(dBase, tracers), lerr)) RETURN
    277   ELSE
    278     CALL msg('The multiple required sections will be CUMULATED.', modname)
    279     IF(test(cumulTracers(dBase, tracers), lerr)) RETURN
     284  IF(nsec == 1) tracers = dBase(1)%trac
     285  IF(nsec /= 1) THEN
     286    CALL msg('Multiple sections are MERGED',    modname,      lTracsMerge)
     287    CALL msg('Multiple sections are CUMULATED', modname, .NOT.lTracsMerge)
     288    IF(     lTracsMerge) lerr = cumulTracers(dBase, tracers)
     289    IF(.NOT.lTracsMerge) lerr = cumulTracers(dBase, tracers)
     290    IF(lerr) RETURN
    280291  END IF
    281   CALL setDirectKeys(tracers)                                        !--- Set %iqParent, %iqDescen, %nqDescen, %nqChildren
     292  lerr = indexUpdate(tracers); IF(lerr) RETURN                       !--- Set iqParent, iqDescen, nqDescen, nqChildren
     293  IF(PRESENT(tracs)) CALL MOVE_ALLOC(FROM=tracers, TO=tracs)
    282294END FUNCTION readTracersFiles
    283295!==============================================================================================================================
     
    299311  !--- PARSE "type_trac" LIST AND DETERMINE THE TRACERS FILES NAMES (FOR CASE 3: MULTIPLE FILES, SINGLE SECTION PER FILE)
    300312  !--- If type_trac is a scalar (case 1), "sections" and "trac_files" are not usable, but are meaningless for case 1 anyway.
    301   IF(test(strParse(type_trac, '|', sections,  n=nsec), lerr)) RETURN !--- Parse "type_trac" list
     313  lerr = strParse(type_trac, '|', sections, n=nsec); IF(lerr) RETURN !--- Parse "type_trac" list
    302314  IF(PRESENT(sects)) sects = sections
    303315  ALLOCATE(trac_files(nsec), ll(nsec))
     
    313325  IF(.NOT.lD) RETURN                                                 !--- NO CHECKING/DISPLAY NEEDED: JUST GET type_trac,fType
    314326  IF(ANY(ll) .AND. fType/=3) THEN                                    !--- MISSING FILES
    315     IF(test(checkList(trac_files, .NOT.ll, 'Failed reading tracers description', 'files', 'missing'), lerr)) RETURN
     327    lerr = checkList(trac_files, .NOT.ll, 'Failed reading tracers description', 'files', 'missing'); IF(lerr) RETURN
    316328  END IF
    317329
     
    344356  ll = strCount(snames, '|', ndb)                                    !--- Number of sections for each file
    345357  ALLOCATE(ixf(SUM(ndb)))
    346   DO i=1, SIZE(fnames)                                               !--- Set %name, %keys
    347     IF(test(readSections(fnames(i), snames(i), 'default'), lerr)) RETURN
     358  DO i=1, SIZE(fnames)                                               !--- Set name, keys
     359    lerr = readSections(fnames(i), snames(i), 'default'); IF(lerr) RETURN
    348360    ixf(1+SUM(ndb(1:i-1)):SUM(ndb(1:i))) = i                         !--- File index for each section of the expanded list
    349361  END DO
     
    353365    fnm = fnames(ixf(idb)); snm = dBase(idb)%name                    !--- FILE AND SECTION NAMES
    354366    lerr = ANY([(dispTraSection('RAW CONTENT OF SECTION "'//TRIM(snm)//'"', snm, modname), idb=1, SIZE(dBase))])
    355     IF(test(expandSection(dBase(idb)%trac, snm, fnm), lerr)) RETURN  !--- EXPAND NAMES ;  set %parent, %type, %component
    356     IF(test(setGeneration(dBase(idb)%trac),           lerr)) RETURN  !---                 set %iGeneration,   %genOName
    357     IF(test(checkTracers (dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- CHECK ORPHANS AND PHASES
    358     IF(test(checkUnique  (dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- CHECK TRACERS UNIQUENESS
    359     CALL expandPhases    (dBase(idb)%trac)                           !--- EXPAND PHASES ; set %phase
    360     CALL sortTracers     (dBase(idb)%trac)                           !--- SORT TRACERS
     367    lerr = expandSection(dBase(idb)%trac, snm, fnm); IF(lerr) RETURN !--- EXPAND NAMES ;  SET parent, type, component
     368    lerr = setGeneration(dBase(idb)%trac);           IF(lerr) RETURN !---                 SET iGeneration,  genOName
     369    lerr = checkTracers (dBase(idb)%trac, snm, fnm); IF(lerr) RETURN !--- CHECK ORPHANS AND PHASES
     370    lerr = checkUnique  (dBase(idb)%trac, snm, fnm); IF(lerr) RETURN !--- CHECK TRACERS UNIQUENESS
     371    lerr = expandPhases (dBase(idb)%trac);           IF(lerr) RETURN !--- EXPAND PHASES ; set phase
     372    CALL sortTracers    (dBase(idb)%trac)                            !--- SORT TRACERS
    361373    lerr = ANY([(dispTraSection('EXPANDED CONTENT OF SECTION "'//TRIM(snm)//'"', snm, modname), idb=1, SIZE(dBase))])
    362374  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     
    387399  ll = strParse(snam, '|', keys = sec)                               !--- Requested sections names
    388400  ix = strIdx(dBase(:)%name, sec(:))                                 !--- Indexes of requested sections in database
    389   IF(test(checkList(sec, ix == 0, 'In file "'//TRIM(fnam)//'"','section(s)', 'missing'), lerr)) RETURN
     401  lerr = checkList(sec, ix == 0, 'In file "'//TRIM(fnam)//'"','section(s)', 'missing'); IF(lerr) RETURN
    390402  tdb = dBase(:); dBase = [tdb(1:n0-1),tdb(PACK(ix, MASK=ix/=0))]    !--- Keep requested sections only
    391403
     
    403415!------------------------------------------------------------------------------------------------------------------------------
    404416  IF(.NOT.ALLOCATED(dBase)) ALLOCATE(dBase(0))
    405   OPEN(90, FILE=fnam, FORM='formatted', STATUS='old')
     417  OPEN(90, FILE=fnam, FORM='formatted', POSITION='REWIND', STATUS='old')
    406418  DO; str=''
    407419    DO
     
    416428    IF(str(1:1)=='#') CYCLE                                          !--- Skip comments lines
    417429    CALL removeComment(str)                                          !--- Skip comments at the end of a line
     430    IF(LEN_TRIM(str) == 0) CYCLE                                     !--- Empty line (probably end of file)
    418431    IF(str     == '') CYCLE                                          !--- Skip empty line (probably at the end of the file)
    419432    IF(str(1:1)=='&') THEN                                           !=== SECTION HEADER LINE
     
    431444      ll = strParse(str,' ', s, n, v)                                !--- Parse <key>=<val> pairs
    432445      tt = dBase(ndb)%trac(:)
    433       tmp%name = s(1); tmp%keys = keys_type(s(1), s(2:n), v(2:n))    !--- Set %name and %keys
     446      v(1) = s(1); s(1) = 'name'                                     !--- Convert "name" into a regular key
     447      tmp%name = v(1); tmp%keys = keys_type(v(1), s(:), v(:))        !--- Set %name and %keys
    434448      dBase(ndb)%trac = [tt(:), tmp]
    435       DEALLOCATE(tt)
    436 !      dBase(ndb)%trac = [dBase(ndb)%trac(:), tra(name=s(1), keys=keys_type(s(1), s(2:n), v(2:n)))]
     449      DEALLOCATE(tt, tmp%keys%key, tmp%keys%val)
    437450    END IF
    438451  END DO
     
    460473  ky => t(jd)%keys
    461474  DO k = 1, SIZE(ky%key)                                             !--- Loop on the keys of the tracer named "defName"
    462 !   CALL addKey_m(ky%key(k), ky%val(k), t(:)%keys, .FALSE.)           !--- Add key to all the tracers (no overwriting)
    463     DO it = 1, SIZE(t); CALL addKey_1(ky%key(k), ky%val(k), t(it)%keys, .FALSE.); END DO
     475!   CALL addKey(ky%key(k), ky%val(k), t(:)%keys, .FALSE.)            !--- Add key to all the tracers (no overwriting)
     476    DO it = 1, SIZE(t); CALL addKey(ky%key(k), ky%val(k), t(it)%keys, .FALSE.); END DO
    464477  END DO
    465478  tt = [t(1:jd-1),t(jd+1:SIZE(t))]; CALL MOVE_ALLOC(FROM=tt, TO=t)   !--- Remove the virtual tracer named "defName"
     
    506519!------------------------------------------------------------------------------------------------------------------------------
    507520  TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:)                 !--- Tracer derived type vector
    508   CHARACTER(LEN=*),             INTENT(IN)    :: sname
    509   CHARACTER(LEN=*), OPTIONAL,   INTENT(IN)    :: fname
     521  CHARACTER(LEN=*),             INTENT(IN)    :: sname                 !--- Current section name
     522  CHARACTER(LEN=*), OPTIONAL,   INTENT(IN)    :: fname                 !--- Tracers description file name
    510523  TYPE(trac_type),       ALLOCATABLE :: ttr(:)
    511   CHARACTER(LEN=maxlen), ALLOCATABLE :: ta(:), pa(:)
     524  CHARACTER(LEN=maxlen), ALLOCATABLE :: ta(:), pa(:), tname(:), parent(:), dType(:)
    512525  CHARACTER(LEN=maxlen) :: msg1, modname
    513526  INTEGER :: it, nt, iq, nq, itr, ntr, ipr, npr
     
    516529  lerr = .FALSE.
    517530  nt = SIZE(tr)
     531  lerr = getKey('name',   tname,  tr(:)%keys);                 IF(lerr) RETURN
     532  lerr = getKey('parent', parent, tr(:)%keys, def = tran0);    IF(lerr) RETURN
     533  lerr = getKey('type',   dType,  tr(:)%keys, def = 'tracer'); IF(lerr) RETURN
    518534  nq = 0
    519535  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     
    521537  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    522538    !--- Extract useful keys: parent name, type, component name
    523     tr(it)%parent    = fgetKey(it, 'parent', tr(:)%keys,  tran0  )
    524     tr(it)%type      = fgetKey(it, 'type'  , tr(:)%keys, 'tracer')
    525539    tr(it)%component = sname
    526 !   CALL addKey_m('component', sname, tr(:)%keys)
    527     DO iq=1,SIZE(tr); CALL addKey_1('component', sname, tr(iq)%keys); END DO
     540    CALL addKey('component', sname,  tr(it)%keys)
    528541
    529542    !--- Determine the number of tracers and parents ; coherence checking
    530     ll = strCount(tr(it)%name,  ',', ntr)
    531     ll = strCount(tr(it)%parent, ',', npr)
     543    ll = strCount( tname(it), ',', ntr)
     544    ll = strCount(parent(it), ',', npr)
    532545
    533546    !--- Tagging tracers only can have multiple parents
    534     IF(test(npr/=1 .AND. TRIM(tr(it)%type)/='tag', lerr)) THEN
     547    lerr = npr /=1 .AND. TRIM(dType(it)) /= 'tag'
     548    IF(lerr) THEN
    535549      msg1 = 'Check section "'//TRIM(sname)//'"'
    536       IF(PRESENT(fname)) msg1=TRIM(msg1)//' in file "'//TRIM(fname)//'"'
    537       CALL msg(TRIM(msg1)//': "'//TRIM(tr(it)%name)//'" has several parents but is not a tag', modname); RETURN
     550      IF(PRESENT(fname)) msg1 = TRIM(msg1)//' in file "'//TRIM(fname)//'"'
     551      CALL msg(TRIM(msg1)//': "'//TRIM(tname(it))//'" has several parents but is not a tag', modname); RETURN
    538552    END IF
    539553    nq = nq + ntr*npr                 
     
    547561  DO it = 1, nt                                                      !=== EXPAND TRACERS AND PARENTS NAMES LISTS
    548562  !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    549     ll = strParse(tr(it)%name,   ',', ta, ntr)                       !--- Number of tracers
    550     ll = strParse(tr(it)%parent, ',', pa, npr)                       !--- Number of parents
    551     DO ipr=1,npr                                                     !--- Loop on parents list elts
    552       DO itr=1,ntr                                                   !--- Loop on tracers list elts
     563    ll = strParse( tname(it), ',', ta, ntr)                          !--- Number of tracers
     564    ll = strParse(parent(it), ',', pa, npr)                          !--- Number of parents
     565    DO ipr = 1, npr                                                  !--- Loop on parents list elts
     566      DO itr = 1, ntr                                                !--- Loop on tracers list elts
     567        ttr(iq)%keys%name = TRIM(ta(itr))
    553568        ttr(iq)%keys%key  = tr(it)%keys%key
    554569        ttr(iq)%keys%val  = tr(it)%keys%val
    555         ttr(iq)%keys%name = ta(itr)
    556         ttr(iq)%name      = TRIM(ta(itr));    CALL addKey_1('name',      ta(itr),          ttr(iq)%keys)
    557         ttr(iq)%parent    = TRIM(pa(ipr));    CALL addKey_1('parent',    pa(ipr),          ttr(iq)%keys)
    558         ttr(iq)%type      = tr(it)%type;      CALL addKey_1('type',      tr(it)%type,      ttr(iq)%keys)
    559         ttr(iq)%component = tr(it)%component; CALL addKey_1('component', tr(it)%component, ttr(iq)%keys)
    560         iq = iq+1
     570        ttr(iq)%name      = TRIM(ta(itr))
     571        ttr(iq)%parent    = TRIM(pa(ipr))
     572        ttr(iq)%type      = dType(it)
     573        ttr(iq)%component = sname
     574        CALL addKey('name',      ta(itr),   ttr(iq)%keys)
     575        CALL addKey('parent',    pa(ipr),   ttr(iq)%keys)
     576        CALL addKey('type',      dType(it), ttr(iq)%keys)
     577        CALL addKey('component', sname,     ttr(iq)%keys)
     578        iq = iq + 1
    561579      END DO
    562580    END DO
     
    575593!------------------------------------------------------------------------------------------------------------------------------
    576594! Purpose: Determine, for each tracer of "tr(:)":
    577 !   * %iGeneration: the generation number
    578 !   * %gen0Name:    the generation 0 ancestor name
    579 !          Check also for orphan tracers (tracers not descending on "tran0").
     595!   * iGeneration: the generation number
     596!   * gen0Name:    the generation 0 ancestor name
     597!          Check also for orphan tracers (tracers without parent).
    580598!------------------------------------------------------------------------------------------------------------------------------
    581599  TYPE(trac_type),     INTENT(INOUT) :: tr(:)                        !--- Tracer derived type vector
    582600  INTEGER                            :: iq, jq, ig
    583   CHARACTER(LEN=maxlen), ALLOCATABLE :: parent(:)
     601  CHARACTER(LEN=maxlen), ALLOCATABLE :: parent(:), tname(:)
    584602!------------------------------------------------------------------------------------------------------------------------------
    585603  CHARACTER(LEN=maxlen) :: modname
    586604  modname = 'setGeneration'
    587   IF(test(fmsg('missing "parent" attribute', modname, getKey('parent', parent, ky=tr(:)%keys)), lerr)) RETURN
     605  lerr = getKey('name',   tname,  ky=tr(:)%keys); IF(lerr) RETURN
     606  lerr = getKey('parent', parent, ky=tr(:)%keys); IF(lerr) RETURN
    588607  DO iq = 1, SIZE(tr)
    589608    jq = iq; ig = 0
    590609    DO WHILE(parent(jq) /= tran0)
    591       jq = strIdx(tr(:)%name, parent(jq))
    592       IF(test(fmsg('Orphan tracer "'//TRIM(tr(iq)%name)//'"', modname, jq == 0), lerr)) RETURN
     610      jq = strIdx(tname(:), parent(jq))
     611      lerr = jq == 0
     612      IF(fmsg('Orphan tracer "'//TRIM(tname(iq))//'"', modname, lerr)) RETURN
    593613      ig = ig + 1
    594614    END DO
    595     tr(iq)%gen0Name = tr(jq)%name; CALL addKey_1('gen0Name',    tr(iq)%gen0Name,   tr(iq)%keys)
    596     tr(iq)%iGeneration = ig;       CALL addKey_1('iGeneration', TRIM(int2str(ig)), tr(iq)%keys)
     615    tr(iq)%gen0Name = tname(jq)
     616    tr(iq)%iGeneration = ig
     617    CALL addKey('iGeneration',   ig,  tr(iq)%keys)
     618    CALL addKey('gen0Name', tname(jq), tr(iq)%keys)
    597619  END DO
    598620END FUNCTION setGeneration
     
    604626!------------------------------------------------------------------------------------------------------------------------------
    605627! Purpose:
    606 !   * check for orphan tracers (without known parent)
    607 !   * check wether the phases are known or not ("g"aseous, "l"iquid or "s"olid so far)
     628!   * check for orphan tracers (without parent)
     629!   * check wether the phases are known or not (elements of "known_phases")
    608630!------------------------------------------------------------------------------------------------------------------------------
    609631  TYPE(trac_type),            INTENT(IN) :: tr(:)                    !--- Tracer derived type vector
    610632  CHARACTER(LEN=*),           INTENT(IN) :: sname                    !--- Section name
    611633  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fname                    !--- File name
     634  CHARACTER(LEN=1) :: p
    612635  CHARACTER(LEN=maxlen) :: mesg
    613636  CHARACTER(LEN=maxlen) :: bp(SIZE(tr, DIM=1)), pha                  !--- Bad phases list, phases of current tracer
    614   CHARACTER(LEN=1) :: p
     637  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:)
     638  INTEGER,               ALLOCATABLE ::  iGen(:)
    615639  INTEGER :: ip, np, iq, nq
    616640!------------------------------------------------------------------------------------------------------------------------------
     641  CHARACTER(LEN=maxlen) :: modname
     642  modname = 'checkTracers'
    617643  nq = SIZE(tr,DIM=1)                                                !--- Number of tracers lines
    618644  mesg = 'Check section "'//TRIM(sname)//'"'
    619645  IF(PRESENT(fname)) mesg=TRIM(mesg)//' in file "'//TRIM(fname)//'"'
     646  lerr = getKey('iGeneration', iGen, tr(:)%keys);               IF(lerr) RETURN
     647  lerr = getKey('name',       tname, tr(:)%keys);               IF(lerr) RETURN
    620648
    621649  !=== CHECK FOR ORPHAN TRACERS
    622   IF(test(checkList(tr%name, tr%iGeneration==-1, mesg, 'tracers', 'orphan'), lerr)) RETURN
     650  lerr = checkList(tname, iGen==-1, mesg, 'tracers', 'orphan'); IF(lerr) RETURN
    623651
    624652  !=== CHECK PHASES
    625   DO iq=1,nq; IF(tr(iq)%iGeneration/=0) CYCLE                        !--- Generation O only is checked
    626     pha = fgetKey(iq, 'phases', tr(:)%keys, 'g')                     !--- Phases
     653  DO iq = 1, nq; IF(iGen(iq) /= 0) CYCLE                             !--- Generation O only is checked
     654    IF(getKey(['phases','phase '], pha, iq, tr(:)%keys, lDisp=.FALSE.)) pha = 'g'   !--- Phase
    627655    np = LEN_TRIM(pha); bp(iq)=' '
    628     DO ip=1,np; p = pha(ip:ip); IF(INDEX(known_phases,p)==0) bp(iq) = TRIM(bp(iq))//p; END DO
    629     IF(TRIM(bp(iq)) /= '') bp(iq) = TRIM(tr(iq)%name)//': '//TRIM(bp(iq))
     656    DO ip = 1, np; p = pha(ip:ip); IF(INDEX(known_phases, p) == 0) bp(iq) = TRIM(bp(iq))//p; END DO
     657    IF(TRIM(bp(iq)) /= '') bp(iq) = TRIM(tname(iq))//': '//TRIM(bp(iq))
    630658  END DO
    631   lerr = checkList(bp, tr%iGeneration==0 .AND. bp/='', mesg, 'tracers phases', 'unknown')
     659  lerr = checkList(bp, iGen == 0 .AND. bp /= '', mesg, 'tracers phases', 'unknown')
    632660END FUNCTION checkTracers
    633661!==============================================================================================================================
     
    645673  INTEGER :: ip, np, iq, nq, k
    646674  LOGICAL, ALLOCATABLE  :: ll(:)
    647   CHARACTER(LEN=maxlen) :: mesg, tnam, tdup(SIZE(tr,DIM=1))
    648   CHARACTER(LEN=1)      :: p
    649 !------------------------------------------------------------------------------------------------------------------------------
     675  CHARACTER(LEN=maxlen) :: mesg, phase, tdup(SIZE(tr,DIM=1))
     676  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:), dType(:)
     677  INTEGER,               ALLOCATABLE :: iGen(:)
     678  CHARACTER(LEN=1) :: p
     679!------------------------------------------------------------------------------------------------------------------------------
     680  CHARACTER(LEN=maxlen) :: modname
     681  modname = 'checkUnique'
    650682  mesg = 'Check section "'//TRIM(sname)//'"'
    651683  IF(PRESENT(fname)) mesg=TRIM(mesg)//' in file "'//TRIM(fname)//'"'
    652684  nq=SIZE(tr,DIM=1); lerr=.FALSE.                                    !--- Number of lines ; error flag
    653685  tdup(:) = ''
    654   DO iq=1,nq; IF(tr(iq)%type == 'tag') CYCLE                         !--- Tags can be repeated
    655     tnam = TRIM(tr(iq)%name)
    656     ll = tr(:)%name==TRIM(tnam)                                      !--- Mask for current tracer name
    657     IF(COUNT(ll)==1 ) CYCLE                                          !--- Tracer is not repeated
    658     IF(tr(iq)%iGeneration>0) THEN
    659       tdup(iq) = tnam                                                !--- gen>0: MUST be unique
     686  lerr = getKey('name',       tname, tr%keys); IF(lerr) RETURN
     687  lerr = getKey('type',       dType, tr%keys); IF(lerr) RETURN
     688  lerr = getKey('iGeneration', iGen, tr%keys); IF(lerr) RETURN
     689  DO iq = 1, nq
     690    IF(dType(iq) == 'tag') CYCLE                                     !--- Tags can be repeated
     691    ll = tname==TRIM(tname(iq))                                      !--- Mask for current tracer name
     692    IF(COUNT(ll) == 1) CYCLE                                         !--- Tracer is not repeated
     693    IF(iGen(iq) > 0) THEN
     694      tdup(iq) = tname(iq)                                           !--- gen>0: MUST be unique
    660695    ELSE
    661       DO ip=1,nphases; p=known_phases(ip:ip)                         !--- Loop on known phases
    662         !--- Number of appearances of the current tracer with known phase "p"
    663         np = COUNT( PACK( [(INDEX(fgetKey(k, 'phases', tr(:)%keys, 'g'),p), k=1, nq)] /=0 , MASK=ll ) )
    664         IF(np <=1) CYCLE
    665         tdup(iq) = TRIM(tdup(iq))//TRIM(phases_names(ip))
     696      DO ip = 1, nphases; p = known_phases(ip:ip)                    !--- Loop on known phases
     697        np = 0
     698        DO k = 1, nq
     699          IF(.NOT.ll(k)) CYCLE                                       !--- Skip tracers different from current one
     700          IF(getKey(['phases','phase '], phase, k, tr%keys, lDisp=.FALSE.)) phase='g'!--- Get current phases
     701          IF(INDEX(phase, p) /= 0) np = np + 1                       !--- One more appearance of current tracer with phase "p"
     702        END DO
     703        IF(np <= 1) CYCLE                                            !--- Regular case: no or a single appearance
     704        tdup(iq) = TRIM(tdup(iq))//TRIM(phases_names(ip))            !--- Repeated phase
    666705        IF(ANY(tdup(1:iq-1) == tdup(iq))) tdup(iq)=''                !--- Avoid repeating same messages
    667706      END DO
    668707    END IF
    669     IF(tdup(iq) /= '') tdup(iq)=TRIM(tnam)//' in '//TRIM(tdup(iq))//' phase(s)'
     708    IF(tdup(iq) /= '') tdup(iq)=TRIM(tname(iq))//' in '//TRIM(tdup(iq))//' phase(s)'
    670709  END DO
    671710  lerr = checkList(tdup, tdup/='', mesg, 'tracers', 'duplicated')
     
    675714
    676715!==============================================================================================================================
    677 SUBROUTINE expandPhases(tr)
     716LOGICAL FUNCTION expandPhases(tr) RESULT(lerr)
    678717!------------------------------------------------------------------------------------------------------------------------------
    679718! Purpose: Expand the phases in the tracers descriptor "tr". Phases are not repeated for a tracer, thanks to "checkUnique".
     
    681720  TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:)               !--- Tracer derived type vector
    682721!------------------------------------------------------------------------------------------------------------------------------
    683   TYPE(trac_type), ALLOCATABLE :: ttr(:)
    684   INTEGER,   ALLOCATABLE ::  i0(:)
    685   CHARACTER(LEN=maxlen)  :: nam, pha, tname
     722  TYPE(trac_type),       ALLOCATABLE :: ttr(:)
     723  INTEGER,               ALLOCATABLE ::  i0(:), iGen(:)
     724  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:), gen0N(:), phase(:), parents(:), dType(:)
     725  CHARACTER(LEN=maxlen)              ::  nam,     gen0Nm,   pha,      parent
    686726  CHARACTER(LEN=1) :: p
    687727  INTEGER :: ip, np, iq, jq, nq, it, nt, nc, i, n
    688728  LOGICAL :: lTag, lExt
    689729!------------------------------------------------------------------------------------------------------------------------------
     730  CHARACTER(LEN=maxlen) :: modname
     731  modname = 'expandPhases'
    690732  nq = SIZE(tr, DIM=1)
    691733  nt = 0
     734  lerr = getKey('name',       tname, tr%keys); IF(lerr) RETURN       !--- Names of the tracers
     735  lerr = getKey('gen0Name',   gen0N, tr%keys); IF(lerr) RETURN       !--- Names of the tracers of first generation
     736  lerr = getKey('iGeneration', iGen, tr%keys); IF(lerr) RETURN       !--- Generation number
     737  lerr = getKey('phases',     phase, tr%keys); IF(lerr) RETURN       !--- Phases names
     738  lerr = getKey('parent',   parents, tr%keys); IF(lerr) RETURN       !--- Parents names
     739  lerr = getKey('type',       dType, tr%keys); IF(lerr) RETURN       !--- Tracers types ('tracer' or 'tag')
    692740  DO iq = 1, nq                                                      !--- GET THE NUMBER OF TRACERS
    693     IF(tr(iq)%iGeneration /= 0) CYCLE                                !--- Only deal with generation 0 tracers
    694     nc = COUNT(tr(:)%gen0Name==tr(iq)%name .AND. tr%iGeneration/=0)  !--- Number of children of tr(iq)
    695     tr(iq)%phase = fgetKey(iq, 'phases', tr(:)%keys)                 !--- Phases list        of tr(iq)
    696     np = LEN_TRIM(tr(iq)%phase)                                      !--- Number of phases   of tr(iq)
     741    IF(iGen(iq) /= 0) CYCLE                                          !--- Only deal with generation 0 tracers
     742    nc = COUNT(gen0N == tname(iq) .AND. iGen /= 0)                   !--- Number of children of tr(iq)
     743    np = LEN_TRIM(phase(iq))                                         !--- Number of phases   of tr(iq)
    697744    nt = nt + (1+nc) * np                                            !--- Number of tracers after expansion
    698745  END DO
     
    700747  it = 1                                                             !--- Current "ttr(:)" index
    701748  DO iq = 1, nq                                                      !--- Loop on "tr(:)" indexes
    702     lTag = tr(iq)%type=='tag'                                        !--- Current tracer is a tag
    703     i0 = strFind(tr(:)%name, TRIM(tr(iq)%gen0Name), n)               !--- Indexes of first generation ancestor copies
    704     np = SUM([( LEN_TRIM(tr(i0(i))%phase),i=1,n )], 1)               !--- Number of phases for current tracer tr(iq)
    705     lExt = np>1                                                      !--- Phase suffix only required if phases number is > 1
    706     IF(lTag) lExt = lExt .AND. tr(iq)%iGeneration>0                  !--- No phase suffix for generation 0 tags
    707     DO i=1,n                                                         !=== LOOP ON GENERATION 0 ANCESTORS
     749    lTag = dType(iq)=='tag'                                          !--- Current tracer is a tag
     750    i0 = strFind(tname, TRIM(gen0N(iq)), n)                          !--- Indexes of first generation ancestor copies
     751    np = SUM([( LEN_TRIM(phase(i0(i))), i = 1, n )], 1)              !--- Number of phases for current tracer tr(iq)
     752    lExt = np > 1                                                    !--- Phase suffix only required if phases number is > 1
     753    IF(lTag) lExt = lExt .AND. iGen(iq) > 0                          !--- No phase suffix for generation 0 tags
     754    DO i = 1, n                                                      !=== LOOP ON GENERATION 0 ANCESTORS
    708755      jq = i0(i)                                                     !--- tr(jq): ith tracer with same gen 0 ancestor as tr(iq)
    709       IF(tr(iq)%iGeneration==0) jq=iq                                !--- Generation 0: count the current tracer phases only
    710       pha = tr(jq)%phase                                             !--- Phases list for tr(jq)
     756      IF(iGen(iq) == 0) jq = iq                                      !--- Generation 0: count the current tracer phases only
     757      pha = phase(jq)                                                !--- Phases list for tr(jq)
    711758      DO ip = 1, LEN_TRIM(pha)                                       !=== LOOP ON PHASES LISTS
    712759        p = pha(ip:ip)
    713         tname = TRIM(tr(iq)%name); nam = tname                       !--- Tracer name (regular case)
    714         IF(lTag) nam = TRIM(tr(iq)%parent)                           !--- Parent name (tagging case)
     760        nam = tname(iq)                                              !--- Tracer name (regular case)
     761        IF(lTag) nam = TRIM(parents(iq))                             !--- Parent name (tagging case)
    715762        IF(lExt) nam = addPhase(nam, p )                             !--- Phase extension needed
    716         IF(lTag) nam = TRIM(nam)//'_'//TRIM(tname)                   !--- <parent>_<name> for tags
     763        IF(lTag) nam = TRIM(nam)//'_'//TRIM(tname(iq))               !--- <parent>_<name> for tags
    717764        ttr(it) = tr(iq)                                             !--- Same <key>=<val> pairs
    718765        ttr(it)%name      = TRIM(nam)                                !--- Name with possibly phase suffix
    719766        ttr(it)%keys%name = TRIM(nam)                                !--- Name inside the keys decriptor
    720767        ttr(it)%phase     = p                                        !--- Single phase entry
    721         CALL addKey_1('name', nam, ttr(it)%keys)
    722         CALL addKey_1('phase', p,  ttr(it)%keys)
    723         IF(lExt .AND. tr(iq)%iGeneration>0) THEN
    724           ttr(it)%parent   = addPhase(tr(iq)%parent,   p)
    725           ttr(it)%gen0Name = addPhase(tr(iq)%gen0Name, p)
    726           CALL addKey_1('parent',   ttr(it)%parent,   ttr(it)%keys)
    727           CALL addKey_1('gen0Name', ttr(it)%gen0Name, ttr(it)%keys)
     768        CALL addKey('name', nam, ttr(it)%keys)
     769        CALL addKey('phase', p,  ttr(it)%keys)
     770        IF(lExt) THEN
     771          parent = parents(iq); IF(iGen(iq) > 0) parent = addPhase(parent, p)
     772          gen0Nm =   gen0N(iq); IF(iGen(iq) > 0) gen0Nm = addPhase(gen0Nm, p)
     773          ttr(it)%parent   = parent
     774          ttr(it)%gen0Name = gen0Nm
     775          CALL addKey('parent',   parent, ttr(it)%keys)
     776          CALL addKey('gen0Name', gen0Nm, ttr(it)%keys)
    728777        END IF
    729778        it = it+1
    730779      END DO
    731       IF(tr(iq)%iGeneration==0) EXIT                                 !--- Break phase loop for gen 0
     780      IF(iGen(iq) == 0) EXIT                                         !--- Break phase loop for gen 0
    732781    END DO
    733782  END DO
     
    735784  CALL delKey(['phases'],tr)                                         !--- Remove few keys entries
    736785
    737 END SUBROUTINE expandPhases
     786END FUNCTION expandPhases
    738787!==============================================================================================================================
    739788
     
    748797!   TO BE ADDED IF NECESSARY: HIGHER MOMENTS AT THE END
    749798!------------------------------------------------------------------------------------------------------------------------------
    750   TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:)         !--- Tracer derived type vector
    751 !------------------------------------------------------------------------------------------------------------------------------
    752   TYPE(trac_type), ALLOCATABLE        :: tr2(:)
    753   INTEGER,         ALLOCATABLE        :: iy(:), iz(:)
    754   INTEGER                             :: ig, ng, iq, jq, ip, nq, n, ix(SIZE(tr)), k
     799  TYPE(trac_type), INTENT(INOUT) :: tr(:)                            !--- Tracer derived type vector
     800!------------------------------------------------------------------------------------------------------------------------------
     801  TYPE(trac_type),       ALLOCATABLE :: tr2(:)
     802  INTEGER,               ALLOCATABLE :: iy(:), iz(:)
     803  INTEGER,               ALLOCATABLE ::  iGen(:)
     804  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:), gen0N(:)
     805  INTEGER :: ig, ng, iq, jq, ip, nq, n, ix(SIZE(tr)), k
     806  LOGICAL :: lerr
    755807!  tr2 is introduced in order to cope with a bug in gfortran 4.8.5 compiler
    756808!------------------------------------------------------------------------------------------------------------------------------
     809  lerr = getKey('iGeneration', iGen, tr%keys); IF(lerr) RETURN       !--- Generation number
    757810  nq = SIZE(tr)
    758811  DO ip = nphases, 1, -1
    759     iq = strIdx(tr(:)%name, addPhase('H2O', ip))
     812    lerr = getKey('name',     tname, tr%keys); IF(lerr) RETURN       !--- Names of the tracers of first generation
     813    iq = strIdx(tname, addPhase('H2O', ip))
    760814    IF(iq == 0) CYCLE
    761815    tr2 = tr(:)
     
    764818  IF(lSortByGen) THEN
    765819    iq = 1
    766     ng = MAXVAL(tr(:)%iGeneration, MASK=.TRUE., DIM=1)               !--- Number of generations
     820    ng = MAXVAL(iGen, MASK=.TRUE., DIM=1)                            !--- Number of generations
    767821    DO ig = 0, ng                                                    !--- Loop on generations
    768       iy = PACK([(k, k=1, nq)], MASK=tr(:)%iGeneration==ig)          !--- Generation ig tracers indexes
     822      iy = PACK([(k, k=1, nq)], MASK=iGen(:) == ig)                  !--- Generation ig tracers indexes
    769823      n = SIZE(iy)
    770824      ix(iq:iq+n-1) = iy                                             !--- Stack growing generations idxs
     
    772826    END DO
    773827  ELSE
    774     iq = 1
     828    lerr = getKey('gen0Name',   gen0N, tr%keys); IF(lerr) RETURN     !--- Names of the tracers    iq = 1
    775829    DO jq = 1, nq                                                    !--- Loop on generation 0 tracers
    776       IF(tr(jq)%iGeneration /= 0) CYCLE                              !--- Skip generations /= 0
     830      IF(iGen(jq) /= 0) CYCLE                                        !--- Skip generations /= 0
    777831      ix(iq) = jq                                                    !--- Generation 0 ancestor index first
    778832      iq = iq + 1                                                    !--- Next "iq" for next generations tracers
    779       iy = strFind(tr(:)%gen0Name, TRIM(tr(jq)%name))                !--- Indexes of "tr(jq)" children in "tr(:)"
    780       ng = MAXVAL(tr(iy)%iGeneration, MASK=.TRUE., DIM=1)            !--- Number of generations of the "tr(jq)" family
     833      iy = strFind(gen0N(:), TRIM(tname(jq)))                        !--- Indices of "tr(jq)" children in "tr(:)"
     834      ng = MAXVAL(iGen(iy), MASK=.TRUE., DIM=1)                      !--- Number of generations of the "tr(jq)" family
    781835      DO ig = 1, ng                                                  !--- Loop   on generations of the "tr(jq)" family
    782         iz = find(tr(iy)%iGeneration, ig, n)                         !--- Indexes of the tracers "tr(iy(:))" of generation "ig"
     836        iz = find(iGen(iy), ig, n)                                   !--- Indices of the tracers "tr(iy(:))" of generation "ig"
    783837        ix(iq:iq+n-1) = iy(iz)                                       !--- Same indexes in "tr(:)"
    784838        iq = iq + n
     
    796850  TYPE(trac_type), ALLOCATABLE, INTENT(OUT) ::       tr(:)
    797851  TYPE(trac_type), POINTER ::   t1(:),   t2(:)
     852  TYPE(keys_type), POINTER ::   k1(:),   k2(:)
    798853  INTEGER,     ALLOCATABLE :: ixct(:), ixck(:)
    799   INTEGER :: is, k1, k2, nk2, i1, i2, nt2
     854  INTEGER :: is, ik, ik1, ik2, nk2, i1, i2, nt2
    800855  CHARACTER(LEN=maxlen) :: s1, v1, v2, tnam, knam, modname
     856  CHARACTER(LEN=maxlen), ALLOCATABLE :: keys(:), n1(:), n2(:)
    801857  modname = 'mergeTracers'
    802858  lerr = .FALSE.
    803   t1 => sections(1)%trac(:)                                          !--- Alias: first tracers section
     859  keys = ['parent     ', 'type       ', 'iGeneration']               !--- Mandatory keys
     860  t1 => sections(1)%trac(:); k1 => t1(:)%keys                        !--- Alias: first tracers section, corresponding keys
     861  lerr = getKey('name', n1, k1); IF(lerr) RETURN                     !--- Names of the tracers
    804862  tr = t1
    805863  !----------------------------------------------------------------------------------------------------------------------------
     
    807865  !----------------------------------------------------------------------------------------------------------------------------
    808866    t2  => sections(is)%trac(:)                                      !--- Alias: current tracers section
     867    k2  => t2(:)%keys
     868    lerr = getKey('name', n2, k2); IF(lerr) RETURN                   !--- Names of the tracers
    809869    nt2  = SIZE(t2(:), DIM=1)                                        !--- Number of tracers in section
    810     ixct = strIdx(t1(:)%name, t2(:)%name)                            !--- Indexes of common tracers
     870    ixct = strIdx(n1(:), n2(:))                                      !--- Indexes of common tracers
    811871    tr = [tr, PACK(t2, MASK= ixct==0)]                               !--- Append with new tracers
    812872    IF( ALL(ixct == 0) ) CYCLE                                       !--- No common tracers => done
    813873    CALL msg('Tracers defined in previous sections and duplicated in "'//TRIM(sections(is)%name)//'":', modname)
    814     CALL msg(t1(PACK(ixct, MASK = ixct/=0))%name, modname, nmax=128) !--- Display duplicates (the 128 first at most)
     874    CALL msg(n1(PACK(ixct, MASK = ixct/=0)), modname, nmax=128)      !--- Display duplicates (the 128 first at most)
    815875    !--------------------------------------------------------------------------------------------------------------------------
    816876    DO i2=1,nt2; tnam = TRIM(t2(i2)%name)                            !=== LOOP ON COMMON TRACERS
     
    820880      !=== CHECK WETHER ESSENTIAL KEYS ARE IDENTICAL OR NOT
    821881      s1=' of "'//TRIM(tnam)//'" in "'//TRIM(sections(is)%name)//'" not matching previous value'
    822      
    823       IF(test(fmsg('Parent name'//TRIM(s1), modname, t1(i1)%parent      /= t2(i2)%parent),      lerr)) RETURN
    824       IF(test(fmsg('Type'       //TRIM(s1), modname, t1(i1)%type        /= t2(i2)%type),        lerr)) RETURN
    825       IF(test(fmsg('Generation' //TRIM(s1), modname, t1(i1)%iGeneration /= t2(i2)%iGeneration), lerr)) RETURN
    826 
    827       !=== APPEND <key>=<val> PAIRS NOT PREVIOULSLY DEFINED
    828       nk2  = SIZE(t2(i2)%keys%key(:))                                !--- Keys number in current section
    829       ixck = strIdx(t1(i1)%keys%key(:), t2(i2)%keys%key(:))          !--- Common keys indexes
    830 
    831       !=== APPEND NEW KEYS
     882      DO ik = 1, SIZE(keys)
     883        lerr = getKey(keys(ik), v1, i1, k1)
     884        lerr = getKey(keys(ik), v2, i2, k2)
     885        lerr = v1 /= v2; IF(fmsg(TRIM(keys(ik))//TRIM(s1), modname, lerr)) RETURN
     886      END DO
     887
     888      !=== GET THE INDICES IN tr(i2)%keys%key(:) OF THE KEYS ALSO PRESENT IN tr(i1)%keys%key(:)
     889      nk2  =   SIZE(k2(i2)%key(:))                                   !--- Keys number in current section
     890      ixck = strIdx(k1(i1)%key(:), k2(i2)%key(:))                    !--- Common keys indexes
     891      !--- APPEND THE NEW KEYS PAIRS IN tr(i1)%keys%key(:)
    832892      tr(i1)%keys%key = [ tr(i1)%keys%key, PACK(tr(i2)%keys%key, MASK = ixck==0)]
    833893      tr(i1)%keys%val = [ tr(i1)%keys%val, PACK(tr(i2)%keys%val, MASK = ixck==0)]
    834894
    835       !--- KEEP TRACK OF THE COMPONENTS NAMES
    836       tr(i1)%component = TRIM(tr(i1)%component)//','//TRIM(tr(i2)%component)
    837 
    838       !--- SELECT COMMON TRACERS WITH DIFFERING KEYS VALUES (PREVIOUS VALUE IS KEPT)
    839       DO k2=1,nk2
    840         k1 = ixck(k2); IF(k1 == 0) CYCLE
    841         IF(t1(i1)%keys%val(k1) == t2(i2)%keys%val(k2)) ixck(k2)=0
     895      !=== KEEP TRACK OF THE COMPONENTS NAMES: COMA-SEPARATED LIST
     896      lerr = getKey('component', v1, i1, k1)
     897      lerr = getKey('component', v2, i2, k2)
     898      tr(i1)%component = TRIM(v1)//','//TRIM(v2)
     899      CALL addKey('component', TRIM(v1)//','//TRIM(v2), tr(i1)%keys)
     900
     901      !=== FOR TRACERS COMMON TO PREVIOUS AND CURRENT SECTIONS: CHECK WETHER SOME KEYS HAVE DIFFERENT VALUES ; KEEP OLD ONE
     902      DO ik2 = 1, nk2                                                !--- Collect the corresponding indices
     903        ik1 = ixck(ik2); IF(ik1 == 0) CYCLE
     904        IF(k1(i1)%val(ik1) == k2(i2)%val(ik2)) ixck(ik2)=0
    842905      END DO
    843       IF(ALL(ixck==0)) CYCLE                                         !--- No identical keys with /=values
    844 
    845       !--- DISPLAY INFORMATION: OLD VALUES ARE KEPT FOR THE KEYS FOUND IN PREVIOUS AND CURRENT SECTIONS
    846       CALL msg('Key(s)'//TRIM(s1), modname)
    847       DO k2 = 1, nk2                                                 !--- Loop on keys found in both t1(:) and t2(:)
    848         knam = t2(i2)%keys%key(k2)                                   !--- Name of the current key
    849         k1 = ixck(k2)                                                !--- Corresponding index in t1(:)
    850         IF(k1 == 0) CYCLE                                            !--- New keys are skipped
    851         v1 = t1(i1)%keys%val(k1); v2 = t2(i2)%keys%val(k2)           !--- Key values in t1(:) and t2(:)
     906      IF(ALL(ixck==0)) CYCLE                                         !--- No identical keys with /=values => nothing to display
     907      CALL msg('Key(s)'//TRIM(s1), modname)                          !--- Display the  keys with /=values (names list)
     908      DO ik2 = 1, nk2                                                !--- Loop on keys found in both t1(:) and t2(:)
     909        knam = k2(i2)%key(ik2)                                       !--- Name of the current key
     910        ik1 = ixck(ik2)                                              !--- Corresponding index in t1(:)
     911        IF(ik1 == 0) CYCLE                                           !--- New keys are skipped
     912        v1 = k1(i1)%val(ik1); v2 = k2(i2)%val(ik2)                   !--- Key values in t1(:) and t2(:)
    852913        CALL msg(' * '//TRIM(knam)//'='//TRIM(v2)//' ; previous value kept:'//TRIM(v1), modname)
    853914      END DO
     
    862923
    863924!==============================================================================================================================
    864 LOGICAL FUNCTION cumulTracers(sections, tr) RESULT(lerr)
     925LOGICAL FUNCTION cumulTracers(sections, tr, lRename) RESULT(lerr)
    865926  TYPE(dataBase_type),  TARGET, INTENT(IN)  :: sections(:)
    866927  TYPE(trac_type), ALLOCATABLE, INTENT(OUT) ::       tr(:)
    867   TYPE(trac_type), POINTER     :: t(:)
    868   INTEGER,   ALLOCATABLE :: nt(:)
    869   CHARACTER(LEN=maxlen)  :: tnam, tnam_new
    870   INTEGER :: iq, nq, is, ns, nsec
    871   lerr = .FALSE.                                                     !--- Can't fail ; kept to match "mergeTracer" interface.
    872   nsec =  SIZE(sections)
    873   tr = [(      sections(is)%trac(:) , is=1, nsec )]                  !--- Concatenated tracers vector
    874   nt = [( SIZE(sections(is)%trac(:)), is=1, nsec )]                  !--- Number of tracers in each section
     928  LOGICAL,            OPTIONAL, INTENT(IN)  :: lRename               !--- .TRUE.: add a section suffix to identical names
     929  CHARACTER(LEN=maxlen)  :: tnam_new, modname
     930  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:), parent(:), comp(:)
     931  INTEGER :: iq, jq, is
     932  modname = 'cumulTracers'
     933  lerr = .FALSE.
     934  tr = [( sections(is)%trac(:), is = 1, SIZE(sections) )]            !--- Concatenated tracers vector
     935  IF(PRESENT(lRename)) THEN; IF(lRename) RETURN; END IF              !--- No renaming: finished
     936  lerr = getKey('name',     tname, tr%keys); IF(lerr) RETURN         !--- Names
     937  lerr = getKey('parent',  parent, tr%keys); IF(lerr) RETURN         !--- Parents
     938  lerr = getKey('component', comp, tr%keys); IF(lerr) RETURN         !--- Component name
    875939  !----------------------------------------------------------------------------------------------------------------------------
    876   DO is=1, nsec                                                      !=== LOOP ON SECTIONS
     940  DO iq = 1, SIZE(tr); IF(COUNT(tname == tname(iq)) == 1) CYCLE      !=== LOOP ON TRACERS
    877941  !----------------------------------------------------------------------------------------------------------------------------
    878     t => sections(is)%trac(:)
     942    tnam_new = TRIM(tname(iq))//'_'//TRIM(comp(iq))                  !--- Same with section extension
     943    CALL addKey('name', tnam_new, tr(iq)%keys)                       !--- Modify tracer name
     944    tr(iq)%name = TRIM(tnam_new)                                     !--- Modify tracer name
    879945    !--------------------------------------------------------------------------------------------------------------------------
    880     DO iq=1, nt(is)                                                  !=== LOOP ON TRACERS
     946    DO jq = 1, SIZE(tr); IF(parent(jq) /= tname(iq)) CYCLE           !=== LOOP ON TRACERS PARENTS
    881947    !--------------------------------------------------------------------------------------------------------------------------
    882       tnam = TRIM(t(iq)%name)                                        !--- Original name
    883       IF(COUNT(t%name == tnam) == 1) CYCLE                           !--- Current tracer is not duplicated: finished
    884       tnam_new = TRIM(tnam)//'_'//TRIM(sections(is)%name)            !--- Same with section extension
    885       nq = SUM(nt(1:is-1))                                           !--- Number of tracers in previous sections
    886       ns = nt(is)                                                    !--- Number of tracers in the current section
    887       tr(iq + nq)%name = TRIM(tnam_new)                              !--- Modify tracer name
    888       WHERE(tr(1+nq:ns+nq)%parent==tnam) tr(1+nq:ns+nq)%parent=tnam_new  !--- Modify parent name
     948      CALL addKey('parent', tnam_new, tr(jq)%keys)                   !--- Modify tracer name
     949      tr(jq)%parent = TRIM(tnam_new)                                 !--- Modify tracer name
    889950    !--------------------------------------------------------------------------------------------------------------------------
    890951    END DO
     
    896957!==============================================================================================================================
    897958
    898 !==============================================================================================================================
    899 SUBROUTINE setDirectKeys(tr)
     959
     960!==============================================================================================================================
     961LOGICAL  FUNCTION  dispTraSection(message, sname, modname) RESULT(lerr)
     962  CHARACTER(LEN=*), INTENT(IN) :: message, sname, modname
     963  CHARACTER(LEN=maxlen), ALLOCATABLE :: s(:,:), n(:), tmp(:)
     964  CHARACTER(LEN=maxlen) :: p
     965  INTEGER :: idb, iq, nq
     966  idb = strIdx(dBase(:)%name, sname); IF(idb == 0) RETURN
     967  nq = SIZE(dBase(idb)%trac)
     968  p = ''
     969  CALL append(['iq'],     .TRUE. ); IF(lerr) RETURN
     970  CALL append(['name'],   .TRUE. ); IF(lerr) RETURN
     971  CALL append(['phases','phase '], .FALSE., 'pha'); IF(lerr) RETURN
     972  CALL append(['hadv'],   .TRUE. ); IF(lerr) RETURN
     973  CALL append(['vadv'],   .TRUE. ); IF(lerr) RETURN
     974  CALL append(['parent'], .FALSE.); IF(lerr) RETURN
     975  CALL append(['iGen'],   .FALSE.); IF(lerr) RETURN
     976  CALL msg(TRIM(message)//':', modname)
     977  lerr = dispTable(p, n, s, nColMax=maxTableWidth, nHead=2, sub=modname); IF(lerr) RETURN
     978
     979CONTAINS
     980
     981SUBROUTINE append(nam, lMandatory, snam)
     982! Test whether key named "nam(:)" is available.
     983!  * yes: - get its value for all species in "tmp(:)" and append table "s(:,:)" with it
     984!         - append titles list with "nam(1)" (or, if specified, "snam", usually a short name).
     985!  * no:  return to calling routine with an error flag if the required key is mandatory
     986  CHARACTER(LEN=*),           INTENT(IN) :: nam(:)
     987  LOGICAL,                    INTENT(IN) :: lMandatory
     988  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: snam
     989  INTEGER :: m
     990  CHARACTER(LEN=maxlen), ALLOCATABLE :: n0(:)
     991  CHARACTER(LEN=maxlen) :: nm
     992  lerr = .FALSE.
     993  IF(nam(1) == 'iq') THEN
     994    tmp = int2str([(iq, iq=1, nq)])
     995  ELSE
     996    lerr = getKey(nam, tmp, dBase(idb)%trac(:)%keys, lDisp=lMandatory)
     997  END IF
     998  IF(lerr) THEN; lerr = lMandatory; RETURN; END IF
     999  nm = nam(1); IF(PRESENT(snam)) nm = snam
     1000  p = TRIM(p)//'s'
     1001  IF(ALLOCATED(s)) THEN; s = cat(s, tmp); ELSE; ALLOCATE(s(nq,1)); s(:,1) = tmp; END IF
     1002  IF(ALLOCATED(n)) THEN; m = SIZE(n); ALLOCATE(n0(m+1)); n0(1:m)=n; n0(m+1)=nm; CALL MOVE_ALLOC(FROM=n0, TO=n)
     1003  ELSE; n=nam(1:1); END IF
     1004END SUBROUTINE append
     1005
     1006END FUNCTION dispTraSection
     1007!==============================================================================================================================
     1008
     1009
     1010!==============================================================================================================================
     1011!=== CREATE TRACER(S) ALIAS: SCALAR/VECTOR FROM NAME(S) OR INDICE(S) ==========================================================
     1012!==============================================================================================================================
     1013LOGICAL FUNCTION aliasTracer(tname, trac, alias) RESULT(lerr)                  !=== TRACER NAMED "tname" - SCALAR
     1014  CHARACTER(LEN=*),         INTENT(IN)  :: tname
     1015  TYPE(trac_type), TARGET,  INTENT(IN)  :: trac(:)
     1016  TYPE(trac_type), POINTER, INTENT(OUT) :: alias
     1017  INTEGER :: it
     1018  CHARACTER(LEN=maxlen), ALLOCATABLE :: tnames(:)
     1019  alias => NULL()
     1020  lerr = getKey('name', tnames, trac(:)%keys)
     1021  it = strIdx(tnames, tname)
     1022  lerr = it /= 0; IF(.NOT.lerr) alias => trac(it)
     1023END FUNCTION aliasTracer
     1024!==============================================================================================================================
     1025LOGICAL FUNCTION trSubset_Indx(trac, idx, alias) RESULT(lerr)                  !=== TRACERS WITH INDICES "idx(:)" - VECTOR
     1026  TYPE(trac_type), ALLOCATABLE, INTENT(IN)  ::  trac(:)
     1027  INTEGER,                      INTENT(IN)  ::   idx(:)
     1028  TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: alias(:)
     1029  alias = trac(idx)
     1030  lerr = indexUpdate(alias)
     1031END FUNCTION trSubset_Indx
     1032!------------------------------------------------------------------------------------------------------------------------------
     1033LOGICAL FUNCTION trSubset_Name(trac, tname, alias) RESULT(lerr)                !=== TRACERS NAMED "tname(:)" - VECTOR
     1034  TYPE(trac_type), ALLOCATABLE, INTENT(IN)  ::  trac(:)
     1035  CHARACTER(LEN=*),             INTENT(IN)  :: tname(:)
     1036  TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: alias(:)
     1037  CHARACTER(LEN=maxlen), ALLOCATABLE :: tnames(:)
     1038  lerr = getKey('name', tnames, trac(:)%keys)
     1039  alias = trac(strIdx(tnames, tname))
     1040  lerr = indexUpdate(alias)
     1041END FUNCTION trSubset_Name
     1042!==============================================================================================================================
     1043LOGICAL FUNCTION trSubset_gen0Name(trac, gen0Nm, alias) RESULT(lerr)           !=== TRACERS OF COMMON 1st GENERATION ANCESTOR
     1044  TYPE(trac_type), ALLOCATABLE, INTENT(IN)  :: trac(:)
     1045  CHARACTER(LEN=*),             INTENT(IN)  :: gen0Nm
     1046  TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: alias(:)
     1047  CHARACTER(LEN=maxlen), ALLOCATABLE :: gen0N(:)
     1048  lerr = getKey('gen0Name', gen0N, trac(:)%keys)
     1049  alias = trac(strFind(delPhase(gen0N), gen0Nm))
     1050  lerr = indexUpdate(alias)
     1051END FUNCTION trSubset_gen0Name
     1052!==============================================================================================================================
     1053
     1054
     1055!==============================================================================================================================
     1056!=== UPDATE THE INDEXES iqParent, iqDescend AND iGeneration IN THE TRACERS DESCRIPTOR LIST "tr" (USEFULL FOR SUBSETS) =========
     1057!==============================================================================================================================
     1058LOGICAL FUNCTION indexUpdate(tr) RESULT(lerr)
    9001059  TYPE(trac_type), INTENT(INOUT) :: tr(:)
    901 
    902   !--- Update %iqParent, %iqDescen, %nqDescen, %nqChildren
    903   CALL indexUpdate(tr)
    904 
    905   !--- Extract some direct-access keys
    906 !  DO iq = 1, SIZE(tr)
    907 !    tr(iq)%keys%<key> = getKey_prv(it, "<key>", tr%keys, <default_value> )
    908 !  END DO
    909 END SUBROUTINE setDirectKeys
    910 !==============================================================================================================================
    911 
    912 !==============================================================================================================================
    913 LOGICAL FUNCTION dispTraSection(message, sname, modname) RESULT(lerr)
    914   CHARACTER(LEN=*), INTENT(IN) :: message, sname, modname
    915   INTEGER :: idb, iq, nq
    916   INTEGER, ALLOCATABLE :: hadv(:), vadv(:)
    917   CHARACTER(LEN=maxlen), ALLOCATABLE :: phas(:), prnt(:)
    918   TYPE(trac_type), POINTER :: tm(:)
    919   lerr = .FALSE.
    920   idb = strIdx(dBase(:)%name, sname); IF(idb == 0) RETURN
    921   tm => dBase(idb)%trac
    922   nq = SIZE(tm)
    923   !--- BEWARE ! Can't use the "getKeyByName" functions yet.
    924   !             Names must first include the phases for tracers defined on multiple lines.
    925   hadv = str2int(fgetKeys('hadv',  tm(:)%keys, '10'))
    926   vadv = str2int(fgetKeys('vadv',  tm(:)%keys, '10'))
    927   prnt =         fgetKeys('parent',tm(:)%keys,  '' )
    928   IF(getKey('phases', phas, ky=tm(:)%keys)) phas = fGetKeys('phase', tm(:)%keys, 'g')
    929   CALL msg(TRIM(message)//':', modname)
    930   IF(ALL(prnt == 'air')) THEN
    931     IF(test(dispTable('iiiss',   ['iq    ','hadv  ','vadv  ','name  ','phase '],                   cat(tm%name,       phas),  &
    932                  cat([(iq, iq=1, nq)], hadv, vadv),                 nColMax=maxTableWidth, nHead=2, sub=modname), lerr)) RETURN
    933   ELSE IF(ALL(tm%iGeneration == -1)) THEN
    934     IF(test(dispTable('iiisss', ['iq    ','hadv  ','vadv  ','name  ','parent','phase '],           cat(tm%name, prnt, phas),  &
    935                  cat([(iq, iq=1, nq)], hadv, vadv),                 nColMax=maxTableWidth, nHead=2, sub=modname), lerr)) RETURN
    936   ELSE
    937     IF(test(dispTable('iiissis', ['iq    ','hadv  ','vadv  ','name  ','parent','igen  ','phase '], cat(tm%name, prnt, phas),  &
    938                  cat([(iq, iq=1, nq)], hadv, vadv, tm%iGeneration), nColMax=maxTableWidth, nHead=2, sub=modname), lerr)) RETURN
    939   END IF
    940 END FUNCTION dispTraSection
    941 !==============================================================================================================================
    942 
    943 
    944 !==============================================================================================================================
    945 !== CREATE A SCALAR ALIAS OF THE COMPONENT OF THE TRACERS DESCRIPTOR "t" NAMED "tname" ========================================
    946 !==============================================================================================================================
    947 FUNCTION aliasTracer(tname, t) RESULT(out)
    948   TYPE(trac_type),         POINTER    :: out
    949   CHARACTER(LEN=*),        INTENT(IN) :: tname
    950   TYPE(trac_type), TARGET, INTENT(IN) :: t(:)
    951   INTEGER :: it
    952   it = strIdx(t(:)%name, tname)
    953   out => NULL(); IF(it /= 0) out => t(it)
    954 END FUNCTION aliasTracer
    955 !==============================================================================================================================
    956 
    957 
    958 !==============================================================================================================================
    959 !=== FROM A LIST OF INDEXES OR NAMES, CREATE A SUBSET OF THE TRACERS DESCRIPTORS LIST "trac" ==================================
    960 !==============================================================================================================================
    961 FUNCTION trSubset_Indx(trac,idx) RESULT(out)
    962   TYPE(trac_type), ALLOCATABLE             ::  out(:)
    963   TYPE(trac_type), ALLOCATABLE, INTENT(IN) :: trac(:)
    964   INTEGER,                      INTENT(IN) ::  idx(:)
    965   out = trac(idx)
    966   CALL indexUpdate(out)
    967 END FUNCTION trSubset_Indx
    968 !------------------------------------------------------------------------------------------------------------------------------
    969 FUNCTION trSubset_Name(trac,nam) RESULT(out)
    970   TYPE(trac_type), ALLOCATABLE             ::  out(:)
    971   TYPE(trac_type), ALLOCATABLE, INTENT(IN) :: trac(:)
    972   CHARACTER(LEN=*),             INTENT(IN) ::  nam(:)
    973   out = trac(strIdx(trac(:)%name, nam))
    974   CALL indexUpdate(out)
    975 END FUNCTION trSubset_Name
    976 !==============================================================================================================================
    977 
    978 
    979 !==============================================================================================================================
    980 !=== CREATE THE SUBSET OF THE TRACERS DESCRIPTORS LIST "trac" HAVING THE FIRST GENERATION ANCESTOR NAMED "nam" ================
    981 !==============================================================================================================================
    982 FUNCTION trSubset_gen0Name(trac,nam) RESULT(out)
    983   TYPE(trac_type), ALLOCATABLE             ::  out(:)
    984   TYPE(trac_type), ALLOCATABLE, INTENT(IN) :: trac(:)
    985   CHARACTER(LEN=*),             INTENT(IN) ::  nam
    986   out = trac(strFind(delPhase(trac(:)%gen0Name), nam))
    987   CALL indexUpdate(out)
    988 END FUNCTION trSubset_gen0Name
    989 !==============================================================================================================================
    990 
    991 
    992 !==============================================================================================================================
    993 !=== UPDATE THE INDEXES iqParent, iqDescend AND iGeneration IN THE TRACERS DESCRIPTOR LIST "tr" (USEFULL FOR SUBSETS) =========
    994 !==============================================================================================================================
    995 SUBROUTINE indexUpdate(tr)
    996   TYPE(trac_type), INTENT(INOUT) :: tr(:)
    997   INTEGER :: iq, ig, igen, ngen, ix(SIZE(tr))
    998   tr(:)%iqParent = strIdx( tr(:)%name, tr(:)%parent )                !--- Parent index
    999   DO iq = 1, SIZE(tr); CALL addKey_1('iqParent', int2str(tr(iq)%iqParent), tr(iq)%keys); END DO
    1000   ngen = MAXVAL(tr(:)%iGeneration, MASK=.TRUE.)
    1001   DO iq = 1, SIZE(tr)
    1002     ig = tr(iq)%iGeneration
    1003     IF(ALLOCATED(tr(iq)%iqDescen)) DEALLOCATE(tr(iq)%iqDescen)
    1004     ALLOCATE(tr(iq)%iqDescen(0))
    1005     CALL idxAncestor(tr, ix, ig)                                     !--- Ancestor of generation "ng" for each tr
    1006     DO igen = ig+1, ngen
    1007       tr(iq)%iqDescen = [tr(iq)%iqDescen, find(ix==iq .AND. tr%iGeneration==igen)]
    1008       tr(iq)%nqDescen = SIZE(tr(iq)%iqDescen)
    1009       IF(igen == ig+1) THEN
    1010         tr(iq)%nqChildren = tr(iq)%nqDescen
    1011         CALL addKey_1('nqChildren', int2str(tr(iq)%nqChildren), tr(iq)%keys)
    1012       END IF
     1060  INTEGER :: iq, jq, nq, ig, nGen
     1061  INTEGER,               ALLOCATABLE :: iqDescen(:), ix(:), iy(:)
     1062  CHARACTER(LEN=maxlen), ALLOCATABLE :: tnames(:), parent(:)
     1063  INTEGER,       DIMENSION(SIZE(tr)) :: iqParent, iGen
     1064  lerr = getKey('name',   tnames, tr%keys); IF(lerr) RETURN          !--- Names
     1065  lerr = getKey('parent', parent, tr%keys); IF(lerr) RETURN          !--- Parents
     1066  nq = SIZE(tr)
     1067
     1068  !=== iqParent, iGeneration
     1069  DO iq = 1, nq; iGen(iq) = 0; jq = iq
     1070    iqParent(iq) = strIdx(tnames, parent(iq))
     1071    DO; jq = strIdx(tnames, parent(jq)); IF(jq == 0) EXIT; iGen(iq) = iGen(iq) + 1; END DO
     1072    CALL addKey('iqParent',   parent(iq), tr(iq)%keys)
     1073    CALL addKey('iqGeneration', iGen(iq), tr(iq)%keys)
     1074  END DO
     1075
     1076  !=== nqChildren, iqDescen, nqDescen
     1077  nGen = MAXVAL(iGen, MASK=.TRUE.)
     1078  DO iq = 1, nq
     1079    ix = [iq]; ALLOCATE(iqDescen(0))
     1080    DO ig = iGen(iq)+1, nGen
     1081      iy = find(iqParent, ix); iqDescen = [iqDescen, iy]; ix = iy
     1082      IF(ig /= iGen(iq)+1) CYCLE
     1083      CALL addKey('nqChildren', SIZE(iqDescen), tr(iq)%keys)
     1084      tr(iq)%nqChildren = SIZE(iqDescen)
    10131085    END DO
    1014     CALL addKey_1('iqDescen', strStack(int2str(tr(iq)%iqDescen)), tr(iq)%keys)
    1015     CALL addKey_1('nqDescen',          int2str(tr(iq)%nqDescen) , tr(iq)%keys)
     1086    CALL addKey('iqDescen', strStack(int2str(iqDescen)), tr(iq)%keys)
     1087    CALL addKey('nqDescen',             SIZE(iqDescen),  tr(iq)%keys)
     1088    tr(iq)%iqDescen =      iqDescen
     1089    tr(iq)%nqDescen = SIZE(iqDescen)
     1090    DEALLOCATE(iqDescen)
    10161091  END DO
    1017 END SUBROUTINE indexUpdate
     1092END FUNCTION indexUpdate
    10181093!==============================================================================================================================
    10191094 
     
    10241099!===  * For each isotopes class, the <key>=<val> vector of each tracer is moved into the isotopes descriptor "isot"        ====
    10251100!=== NOTES:                                                                                                                ====
    1026 !===  * Most of the "isot" components have been defined in the calling routine (readIsotopes):                             ====
     1101!===  * Most of the "isot" components have been defined in the calling routine (processIsotopes):                          ====
    10271102!===      parent,  nzone, zone(:),  niso, keys(:)%name,  ntiso, trac(:),  nphas, phas,  iqIsoPha(:,:),  itZonPhi(:,:)      ====
    10281103!===  * Same syntax for isotopes file and "tracer.def": a tracers section contains one line for each of its isotopes       ====
     
    10321107!===  * The routine gives an error if a required isotope is not available in the database stored in "fnam"                 ====
    10331108!==============================================================================================================================
    1034 LOGICAL FUNCTION readIsotopesFile_prv(fnam, isot) RESULT(lerr)
     1109LOGICAL FUNCTION readIsotopesFile(fnam, isot) RESULT(lerr)
    10351110  CHARACTER(LEN=*),        INTENT(IN)    :: fnam                     !--- Input file name
    10361111  TYPE(isot_type), TARGET, INTENT(INOUT) :: isot(:)                  !--- Isotopes descriptors (field %parent must be defined!)
     
    10491124  !--- READ THE FILE SECTIONS, ONE EACH PARENT TRACER
    10501125  nb0 = SIZE(dBase, DIM=1)+1                                         !--- Next database element index
    1051   IF(test(readSections(fnam,strStack(isot(:)%parent,'|')),lerr)) RETURN !--- Read sections, one each parent tracer
     1126  lerr = readSections(fnam,strStack(isot(:)%parent,'|')); IF(lerr) RETURN !--- Read sections, one each parent tracer
    10521127  ndb = SIZE(dBase, DIM=1)                                           !--- Current database size
    10531128  DO idb = nb0, ndb
     
    10671142      is = strIdx(isot(iis)%keys(:)%name, t%name)                    !--- Index in "isot(iis)%keys(:)%name" of isotope "t%name"
    10681143      IF(is == 0) CYCLE
    1069       IF(test(ANY(reduceExpr(t%keys%val, vals)), lerr)) RETURN       !--- Reduce expressions ; detect non-numerical elements
     1144      lerr = ANY(reduceExpr(t%keys%val, vals)); IF(lerr) RETURN      !--- Reduce expressions ; detect non-numerical elements
    10701145      isot(iis)%keys(is)%key = t%keys%key
    10711146      isot(iis)%keys(is)%val = vals
     
    10731148
    10741149    !--- CHECK FOR MISSING ISOTOPES (NO KEYS ALLOCATED)
    1075     IF(test(checkList(isot(iis)%keys(:)%name, .NOT.[( ALLOCATED(isot(iis)%keys(is)%key), is=1, SIZE(isot(iis)%keys) )], &
    1076       'Check file "'//TRIM(fnam)//'" in section "'//TRIM(dBase(idb)%name)//'"', 'isotopes', 'missing'), lerr)) RETURN
     1150    lerr = checkList(isot(iis)%keys(:)%name, .NOT.[( ALLOCATED(isot(iis)%keys(is)%key), is=1, SIZE(isot(iis)%keys) )], &
     1151                     'Check file "'//TRIM(fnam)//'" in section "'//TRIM(dBase(idb)%name)//'"', 'isotopes', 'missing')
     1152    IF(lerr) RETURN
    10771153  END DO
    10781154
     
    11091185      END DO
    11101186    END DO
    1111     IF(test(fmsg('Problem with the table content', modname, dispTable(prf, ttl, val, &
    1112             cat([(it,it=1,nt)]), rFmt='(EN8.4)', nColMax=maxTableWidth, nHead=2, sub=modname)), lerr)) RETURN
     1187    lerr = dispTable(prf, ttl, val, cat([(it,it=1,nt)]), rFmt='(EN8.4)', nColMax=maxTableWidth, nHead=2, sub=modname)
     1188    IF(fmsg('Problem with the table content', modname, lerr)) RETURN
    11131189    DEALLOCATE(ttl, val)
    11141190  END DO       
     
    11161192!------------------------------------------------------------------------------------------------------------------------------
    11171193
    1118 END FUNCTION readIsotopesFile_prv
     1194END FUNCTION readIsotopesFile
    11191195!==============================================================================================================================
    11201196
     
    11241200!===    * COMPUTE MOST OF THE RELATED QUANTITIES ("isot" COMPONENTS).                                                       ===
    11251201!===    * COMPUTE FEW ISOTOPES-DEDICATED "trac" COMPONENTS                                                                  ===
    1126 !===    * CALL readIsotopesFile_prv TO GET PHYSICAL QUANTITIES (<key>=<val> PAIRS)                                          ===
     1202!===    * CALL readIsotopesFile TO GET PHYSICAL QUANTITIES (<key>=<val> PAIRS)                                              ===
    11271203!===      NOTE: THIS IS DONE HERE (IN A ROUTINE CALLED BY THE DYNAMIC), BECAUSE THE DYNAMIC NEEDS FEW PHYSICAL PARAMETERS.  ===
    11281204!==============================================================================================================================
    1129 LOGICAL FUNCTION readIsotopesFile(iNames) RESULT(lerr)
     1205LOGICAL FUNCTION processIsotopes(iNames) RESULT(lerr)
    11301206  CHARACTER(LEN=maxlen), TARGET, OPTIONAL, INTENT(IN)  :: iNames(:)
    11311207  CHARACTER(LEN=maxlen), ALLOCATABLE :: p(:), str(:)                 !--- Temporary storage
     1208  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:), parent(:), dType(:), phase(:), gen0N(:)
    11321209  CHARACTER(LEN=maxlen) :: iName, modname
    11331210  CHARACTER(LEN=1)   :: ph                                           !--- Phase
     1211  INTEGER, ALLOCATABLE ::  iGen(:)
    11341212  INTEGER :: ic, ip, iq, it, iz
    11351213  LOGICAL, ALLOCATABLE :: ll(:)                                      !--- Mask
    11361214  TYPE(trac_type), POINTER   ::  t(:), t1
    11371215  TYPE(isot_type), POINTER   ::  i
     1216
    11381217  lerr = .FALSE.
    11391218  modname = 'readIsotopesFile'
     
    11411220  t => tracers
    11421221
     1222  lerr = getKey('name',       tname, t%keys); IF(lerr) RETURN       !--- Names
     1223  lerr = getKey('parent',    parent, t%keys); IF(lerr) RETURN       !--- Parents
     1224  lerr = getKey('type',       dType, t%keys); IF(lerr) RETURN       !--- Tracer type
     1225  lerr = getKey('phase',      phase, t%keys); IF(lerr) RETURN       !--- Phase
     1226  lerr = getKey('gen0Name',   gen0N, t%keys); IF(lerr) RETURN       !--- 1st generation ancestor name
     1227  lerr = getKey('iGeneration', iGen, t%keys); IF(lerr) RETURN       !--- Generation number
     1228
    11431229  !--- GET FROM "tracers" THE FULL LIST OF AVAILABLE ISOTOPES CLASSES
    1144   p = PACK(delPhase(t%parent), MASK = t%type=='tracer' .AND. t%iGeneration==1)
     1230  p = PACK(delPhase(parent), MASK = dType=='tracer' .AND. iGen==1)
    11451231  CALL strReduce(p, nbIso)
    11461232
     
    11481234  IF(PRESENT(iNames)) THEN
    11491235    DO it = 1, SIZE(iNames)
    1150       IF(test(fmsg('No isotopes class "'//TRIM(iNames(it))//'" found among tracers', modname, ALL(p /= iNames(it))), lerr)) RETURN
     1236      lerr = ALL(p /= iNames(it))
     1237      IF(fmsg('No isotopes class "'//TRIM(iNames(it))//'" found among tracers', modname, lerr)) RETURN
    11511238    END DO
    11521239    p = iNames; nbIso = SIZE(p)
     
    11641251
    11651252    !=== Isotopes children of tracer "iname": mask, names, number (same for each phase of "iname")
    1166     ll = t(:)%type=='tracer' .AND. delPhase(t(:)%parent) == iname .AND. t(:)%phase == 'g'
    1167     str = PACK(delPhase(t(:)%name), MASK = ll)                       !--- Effectively found isotopes of "iname"
     1253    ll = dType=='tracer' .AND. delPhase(parent) == iname .AND. phase == 'g'
     1254    str = PACK(delPhase(tname), MASK = ll)                           !--- Effectively found isotopes of "iname"
    11681255    i%niso = SIZE(str)                                               !--- Number of "effectively found isotopes of "iname"
    11691256    ALLOCATE(i%keys(i%niso))
     
    11711258
    11721259    !=== Geographic tagging tracers descending on tracer "iname": mask, names, number
    1173     ll = t(:)%type=='tag'    .AND. delPhase(t(:)%gen0Name) == iname .AND. t(:)%iGeneration == 2
    1174     i%zone = PACK(strTail(t(:)%name,'_',.TRUE.), MASK = ll)          !--- Tagging zones names  for isotopes category "iname"
     1260    ll = dType=='tag'    .AND. delPhase(gen0N) == iname .AND. iGen == 2
     1261    i%zone = PACK(strTail(tname,'_',.TRUE.), MASK = ll)              !--- Tagging zones names  for isotopes category "iname"
    11751262    CALL strReduce(i%zone)
    11761263    i%nzone = SIZE(i%zone)                                           !--- Tagging zones number for isotopes category "iname"
     
    11781265    !=== Geographic tracers of the isotopes children of tracer "iname" (same for each phase of "iname")
    11791266    !    NOTE: One might like to create a similar variable for 2nd generation tagging tracers (tagging the gen1 tracers)
    1180     str = PACK(delPhase(t(:)%name), MASK=ll)
     1267    str = PACK(delPhase(tname), MASK=ll)
    11811268    CALL strReduce(str)
    11821269    i%ntiso = i%niso + SIZE(str)                                     !--- Number of isotopes + their geographic tracers [ntiso]
     
    12051292    i%iqIsoPha = RESHAPE( [( (strIdx(t%name,  addPhase(i%trac(it),i%phase(ip:ip))),       it=1, i%ntiso), ip=1, i%nphas)], &
    12061293                         [i%ntiso, i%nphas] )
     1294    !=== Table used to get iq (index in dyn array, size nqtot) from the water and isotope and phase indexes ; the full isotopes list
     1295    !    (including tagging tracers) is sorted this way:  iso1, iso2, ..., iso1_zone1, iso2_zone1, ..., iso1_zoneN, iso2_zoneN
     1296    i%iqWIsoPha = RESHAPE( [( [strIdx(t%name,   addPhase('H2O',i%phase(ip:ip))), i%iqIsoPha(:,ip)], ip=1,i%nphas)], &
     1297                         [1+i%ntiso, i%nphas] )
    12071298    !=== Table used to get ix (index in tagging tracers isotopes list, size ntiso) from the zone and isotope indexes
    12081299    i%itZonIso = RESHAPE( [( (strIdx(i%trac(:), TRIM(i%trac(it))//'_'//TRIM(i%zone(iz))), iz=1, i%nzone), it=1, i%niso )], &
     
    12111302
    12121303  !=== READ PHYSICAL PARAMETERS FROM isoFile FILE
    1213   IF(test(readIsotopesFile_prv(isoFile, isotopes), lerr)) RETURN
     1304!  lerr = readIsotopesFile(isoFile, isotopes); IF(lerr) RETURN! on commente pour ne pas chercher isotopes_params.def
     1305
     1306  !--- GET THE isoCheck ENTRY FROM THE *.DEF FILES (MIGHT BE CHANGED TO A CLASS-DEPENDANT KEYWORD)
     1307  CALL get_in('ok_iso_verif', isoCheck, .TRUE.)
    12141308
    12151309  !=== CHECK CONSISTENCY
    1216   IF(test(testIsotopes(), lerr)) RETURN
    1217 
    1218   !=== SELECT FIRST ISOTOPES CLASS OR, IF POSSIBLE, WATER CLASS
    1219   IF(.NOT.test(isoSelect(1, .TRUE.), lerr)) THEN; IF(isotope%parent == 'H2O') iH2O = ixIso; END IF
     1310  lerr = testIsotopes(); IF(lerr) RETURN
     1311
     1312  !=== SELECT WATER ISOTOPES CLASS OR, IF UNFOUND, THE FIRST ISOTOPES CLASS
     1313  IF(isoSelect('H2O', .TRUE.)) THEN; iH2O = ixIso; ELSE; lerr = isoSelect(1, .TRUE.); END IF
    12201314
    12211315CONTAINS
     
    12241318LOGICAL FUNCTION testIsotopes() RESULT(lerr)     !--- MAKE SURE MEMBERS OF AN ISOTOPES FAMILY ARE PRESENT IN THE SAME PHASES
    12251319!------------------------------------------------------------------------------------------------------------------------------
    1226   INTEGER :: ix, it, ip, np, iz, nz
     1320  INTEGER :: ix, it, ip, np, iz, nz, npha, nzon
    12271321  TYPE(isot_type), POINTER :: i
    12281322  DO ix = 1, nbIso
    12291323    i => isotopes(ix)
    12301324    !--- Check whether each isotope and tagging isotopic tracer is present in the same number of phases
    1231     DO it = 1, i%ntiso
    1232       np = SUM([(COUNT(tracers(:)%name == addPhase(i%trac(it), i%phase(ip:ip))), ip=1, i%nphas)])
    1233       IF(test(fmsg(TRIM(int2str(np))//' phases instead of '//TRIM(int2str(i%nphas))//' for '//TRIM(i%trac(it)), &
    1234         modname, np /= i%nphas), lerr)) RETURN
     1325    DO it = 1, i%ntiso; npha = i%nphas
     1326      np = SUM([(COUNT(tracers(:)%name == addPhase(i%trac(it), i%phase(ip:ip))), ip=1, npha)])
     1327      lerr = np /= npha
     1328      CALL msg(TRIM(int2str(np))//' phases instead of '//TRIM(int2str(npha))//' for '//TRIM(i%trac(it)), modname, lerr)
     1329      IF(lerr) RETURN
    12351330    END DO
    1236     DO it = 1, i%niso
    1237       nz = SUM([(COUNT(i%trac == TRIM(i%trac(it))//'_'//i%zone(iz)), iz=1, i%nzone)])
    1238       IF(test(fmsg(TRIM(int2str(nz))//' tagging zones instead of '//TRIM(int2str(i%nzone))//' for '//TRIM(i%trac(it)), &
    1239         modname, nz /= i%nzone), lerr)) RETURN
     1331    DO it = 1, i%niso; nzon = i%nzone
     1332      nz = SUM([(COUNT(i%trac == TRIM(i%trac(it))//'_'//i%zone(iz)), iz=1, nzon)])
     1333      lerr = nz /= nzon
     1334      CALL msg(TRIM(int2str(nz))//' tagging zones instead of '//TRIM(int2str(nzon))//' for '//TRIM(i%trac(it)), modname, lerr)
     1335      IF(lerr) RETURN
    12401336    END DO
    12411337  END DO
     
    12431339!------------------------------------------------------------------------------------------------------------------------------
    12441340
    1245 END FUNCTION readIsotopesFile
     1341END FUNCTION processIsotopes
    12461342!==============================================================================================================================
    12471343
     
    12591355   lV = .FALSE.; IF(PRESENT(lVerbose)) lV = lVerbose
    12601356   iIso = strIdx(isotopes(:)%parent, iName)
    1261    IF(test(iIso == 0, lerr)) THEN
     1357   lerr = iIso == 0
     1358   IF(lerr) THEN
    12621359      niso = 0; ntiso = 0; nzone = 0; nphas = 0; isoCheck=.FALSE.
    12631360      CALL msg('no isotope family named "'//TRIM(iName)//'"', ll=lV)
     
    12871384   itZonIso => isotope%itZonIso; isoCheck = isotope%check
    12881385   iqIsoPha => isotope%iqIsoPha
     1386   iqWIsoPha => isotope%iqWIsoPha
    12891387END FUNCTION isoSelectByIndex
    12901388!==============================================================================================================================
     
    12941392!=== ADD THE <key>=<val> PAIR TO THE "ky[(:)]" KEY[S] DESCRIPTOR[S] OR THE <key>=<val(:)> PAIRS TO THE "ky(:)" KEYS DESCRIPTORS
    12951393!==============================================================================================================================
    1296 SUBROUTINE addKey_1(key, val, ky, lOverWrite)
    1297   CHARACTER(LEN=*),  INTENT(IN)    :: key, val
     1394SUBROUTINE addKey_s11(key, sval, ky, lOverWrite)
     1395  CHARACTER(LEN=*),  INTENT(IN)    :: key, sval
    12981396  TYPE(keys_type),   INTENT(INOUT) :: ky
    12991397  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     
    13051403  IF(.NOT.ALLOCATED(ky%key)) THEN
    13061404    ALLOCATE(ky%key(1)); ky%key(1)=key
    1307     ALLOCATE(ky%val(1)); ky%val(1)=val
     1405    ALLOCATE(ky%val(1)); ky%val(1)=sval
    13081406    RETURN
    13091407  END IF
     
    13111409  IF(iky == 0) THEN
    13121410    nky = SIZE(ky%key)
    1313     ALLOCATE(k(nky+1)); k(1:nky) = ky%key; k(nky+1) = key; ky%key = k
    1314     ALLOCATE(v(nky+1)); v(1:nky) = ky%val; v(nky+1) = val; ky%val = v
     1411    ALLOCATE(k(nky+1)); k(1:nky) = ky%key; k(nky+1) = key;  ky%key = k
     1412    ALLOCATE(v(nky+1)); v(1:nky) = ky%val; v(nky+1) = sval; ky%val = v
    13151413  ELSE IF(lo) THEN
    1316     ky%key(iky) = key; ky%val(iky) = val
     1414    ky%key(iky) = key; ky%val(iky) = sval
    13171415  END IF
    1318 END SUBROUTINE addKey_1
    1319 !==============================================================================================================================
    1320 SUBROUTINE addKey_m(key, val, ky, lOverWrite)
    1321   CHARACTER(LEN=*),  INTENT(IN)    :: key, val
     1416END SUBROUTINE addKey_s11
     1417!==============================================================================================================================
     1418SUBROUTINE addKey_i11(key, ival, ky, lOverWrite)
     1419  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1420  INTEGER,           INTENT(IN)    :: ival
     1421  TYPE(keys_type),   INTENT(INOUT) :: ky
     1422  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1423!------------------------------------------------------------------------------------------------------------------------------
     1424  CALL addKey_s11(key, int2str(ival), ky, lOverWrite)
     1425END SUBROUTINE addKey_i11
     1426!==============================================================================================================================
     1427SUBROUTINE addKey_r11(key, rval, ky, lOverWrite)
     1428  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1429  REAL,              INTENT(IN)    :: rval
     1430  TYPE(keys_type),   INTENT(INOUT) :: ky
     1431  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1432!------------------------------------------------------------------------------------------------------------------------------
     1433  CALL addKey_s11(key, real2str(rval), ky, lOverWrite)
     1434END SUBROUTINE addKey_r11
     1435!==============================================================================================================================
     1436SUBROUTINE addKey_l11(key, lval, ky, lOverWrite)
     1437  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1438  LOGICAL,           INTENT(IN)    :: lval
     1439  TYPE(keys_type),   INTENT(INOUT) :: ky
     1440  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1441!------------------------------------------------------------------------------------------------------------------------------
     1442  CALL addKey_s11(key, bool2str(lval), ky, lOverWrite)
     1443END SUBROUTINE addKey_l11
     1444!==============================================================================================================================
     1445!==============================================================================================================================
     1446SUBROUTINE addKey_s1m(key, sval, ky, lOverWrite)
     1447  CHARACTER(LEN=*),  INTENT(IN)    :: key, sval
    13221448  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
    13231449  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
    13241450!------------------------------------------------------------------------------------------------------------------------------
    13251451  INTEGER :: itr
    1326   DO itr = 1, SIZE(ky)
    1327     CALL addKey_1(key, val, ky(itr), lOverWrite)
    1328   END DO
    1329 END SUBROUTINE addKey_m
    1330 !==============================================================================================================================
    1331 SUBROUTINE addKey_mm(key, val, ky, lOverWrite)
    1332   CHARACTER(LEN=*),  INTENT(IN)    :: key, val(:)
     1452  DO itr = 1, SIZE(ky); CALL addKey_s11(key, sval, ky(itr), lOverWrite); END DO
     1453END SUBROUTINE addKey_s1m
     1454!==============================================================================================================================
     1455SUBROUTINE addKey_i1m(key, ival, ky, lOverWrite)
     1456  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1457  INTEGER,           INTENT(IN)    :: ival
    13331458  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
    13341459  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
    13351460!------------------------------------------------------------------------------------------------------------------------------
    13361461  INTEGER :: itr
    1337   DO itr = 1, SIZE(ky); CALL addKey_1(key, val(itr), ky(itr), lOverWrite); END DO
    1338 END SUBROUTINE addKey_mm
     1462  DO itr = 1, SIZE(ky); CALL addKey_s11(key, int2str(ival), ky(itr), lOverWrite); END DO
     1463END SUBROUTINE addKey_i1m
     1464!==============================================================================================================================
     1465SUBROUTINE addKey_r1m(key, rval, ky, lOverWrite)
     1466  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1467  REAL,              INTENT(IN)    :: rval
     1468  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1469  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1470!------------------------------------------------------------------------------------------------------------------------------
     1471  INTEGER :: itr
     1472  DO itr = 1, SIZE(ky); CALL addKey_s11(key, real2str(rval), ky(itr), lOverWrite); END DO
     1473END SUBROUTINE addKey_r1m
     1474!==============================================================================================================================
     1475SUBROUTINE addKey_l1m(key, lval, ky, lOverWrite)
     1476  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1477  LOGICAL,           INTENT(IN)    :: lval
     1478  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1479  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1480!------------------------------------------------------------------------------------------------------------------------------
     1481  INTEGER :: itr
     1482  DO itr = 1, SIZE(ky); CALL addKey_s11(key, bool2str(lval), ky(itr), lOverWrite); END DO
     1483END SUBROUTINE addKey_l1m
     1484!==============================================================================================================================
     1485!==============================================================================================================================
     1486SUBROUTINE addKey_smm(key, sval, ky, lOverWrite)
     1487  CHARACTER(LEN=*),  INTENT(IN)    :: key, sval(:)
     1488  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1489  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1490!------------------------------------------------------------------------------------------------------------------------------
     1491  INTEGER :: itr
     1492  DO itr = 1, SIZE(ky); CALL addKey_s11(key, sval(itr), ky(itr), lOverWrite); END DO
     1493END SUBROUTINE addKey_smm
     1494!==============================================================================================================================
     1495SUBROUTINE addKey_imm(key, ival, ky, lOverWrite)
     1496  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1497  INTEGER,           INTENT(IN)    :: ival(:)
     1498  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1499  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1500!------------------------------------------------------------------------------------------------------------------------------
     1501  INTEGER :: itr
     1502  DO itr = 1, SIZE(ky); CALL addKey_s11(key, int2str(ival(itr)), ky(itr), lOverWrite); END DO
     1503END SUBROUTINE addKey_imm
     1504!==============================================================================================================================
     1505SUBROUTINE addKey_rmm(key, rval, ky, lOverWrite)
     1506  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1507  REAL,              INTENT(IN)    :: rval(:)
     1508  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1509  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1510!------------------------------------------------------------------------------------------------------------------------------
     1511  INTEGER :: itr
     1512  DO itr = 1, SIZE(ky); CALL addKey_s11(key, real2str(rval(itr)), ky(itr), lOverWrite); END DO
     1513END SUBROUTINE addKey_rmm
     1514!==============================================================================================================================
     1515SUBROUTINE addKey_lmm(key, lval, ky, lOverWrite)
     1516  CHARACTER(LEN=*),  INTENT(IN)    :: key
     1517  LOGICAL,           INTENT(IN)    :: lval(:)
     1518  TYPE(keys_type),   INTENT(INOUT) :: ky(:)
     1519  LOGICAL, OPTIONAL, INTENT(IN)    :: lOverWrite
     1520!------------------------------------------------------------------------------------------------------------------------------
     1521  INTEGER :: itr
     1522  DO itr = 1, SIZE(ky); CALL addKey_s11(key, bool2str(lval(itr)), ky(itr), lOverWrite); END DO
     1523END SUBROUTINE addKey_lmm
    13391524!==============================================================================================================================
    13401525
     
    13531538  DO ik = 1, SIZE(t(jd)%keys%key)
    13541539    CALL get_in(t(jd)%keys%key(ik), val, '*none*')
    1355     IF(val /= '*none*') CALL addKey_1(t(jd)%keys%key(ik), val, t(jd)%keys, .TRUE.)
     1540    IF(val /= '*none*') CALL addKey(t(jd)%keys%key(ik), val, t(jd)%keys, .TRUE.)
    13561541  END DO
    13571542END SUBROUTINE addKeysFromDef
     
    13871572
    13881573!==============================================================================================================================
    1389 !================ GET THE VALUE OF A KEY FROM A "keys_type" DERIVED TYPE ; THE RESULT IS THE RETURNED VALUE ===================
    1390 !==============================================================================================================================
    1391 CHARACTER(LEN=maxlen) FUNCTION fgetKeyIdx_s1(itr, keyn, ky, def_val, lerr) RESULT(val)
     1574!===   INTERNAL FUNCTION: GET THE VALUE OF A KEY FOR "itr"th TRACER FROM A "keys_type" DERIVED TYPE AND RETURN THE RESULT   ===
     1575!===   IF keyn CONTAINS SEVERAL ELEMENTS, TRY WITH EACH ELEMENT ONE AFTER THE OTHER                                         ===
     1576!==============================================================================================================================
     1577CHARACTER(LEN=maxlen) FUNCTION fgetKeyIdx(itr, keyn, ky, lerr) RESULT(val)
    13921578  INTEGER,                    INTENT(IN)  :: itr
    1393   CHARACTER(LEN=*),           INTENT(IN)  :: keyn
     1579  CHARACTER(LEN=*),           INTENT(IN)  :: keyn(:)
    13941580  TYPE(keys_type),            INTENT(IN)  :: ky(:)
    1395   CHARACTER(LEN=*), OPTIONAL, INTENT(IN)  :: def_val
    13961581  LOGICAL,          OPTIONAL, INTENT(OUT) :: lerr
    13971582!------------------------------------------------------------------------------------------------------------------------------
     1583  INTEGER :: ik
     1584  LOGICAL :: ler
     1585  ler = .TRUE.
     1586  DO ik = 1, SIZE(keyn)
     1587    CALL getKeyIdx(keyn(ik)); IF(.NOT.ler) EXIT
     1588  END DO
     1589  IF(PRESENT(lerr)) lerr = ler
     1590
     1591CONTAINS
     1592
     1593SUBROUTINE getKeyIdx(keyn)
     1594  CHARACTER(LEN=*), INTENT(IN) :: keyn
     1595!------------------------------------------------------------------------------------------------------------------------------
    13981596  INTEGER :: iky
    1399   LOGICAL :: ler
    14001597  iky = 0; val = ''
    1401   IF(.NOT.test(itr <= 0 .OR. itr > SIZE(ky), ler)) iky = strIdx(ky(itr)%key(:), keyn)    !--- Correct index
    1402   IF(.NOT.test(iky == 0, ler))                     val = ky(itr)%val(iky)                !--- Found key
    1403   IF(iky == 0) THEN
    1404     IF(.NOT.test(.NOT.PRESENT(def_val), ler))      val = def_val                         !--- Default value
    1405   END IF
    1406   IF(PRESENT(lerr)) lerr = ler
    1407 END FUNCTION fgetKeyIdx_s1
    1408 !==============================================================================================================================
    1409 CHARACTER(LEN=maxlen) FUNCTION fgetKeyNam_s1(tname, keyn, ky, def_val, lerr) RESULT(val)
    1410   CHARACTER(LEN=*),           INTENT(IN)  :: tname, keyn
    1411   TYPE(keys_type),            INTENT(IN)  :: ky(:)
    1412   CHARACTER(LEN=*), OPTIONAL, INTENT(IN)  :: def_val
    1413   LOGICAL,          OPTIONAL, INTENT(OUT) :: lerr
    1414 !------------------------------------------------------------------------------------------------------------------------------
    1415   val = fgetKeyIdx_s1(strIdx(ky(:)%name, tname), keyn, ky, def_val, lerr)
    1416 END FUNCTION fgetKeyNam_s1
    1417 !==============================================================================================================================
    1418 FUNCTION fgetKeys(keyn, ky, def_val, lerr) RESULT(val)
    1419 CHARACTER(LEN=maxlen),        ALLOCATABLE :: val(:)
    1420   CHARACTER(LEN=*),           INTENT(IN)  :: keyn
    1421   TYPE(keys_type),            INTENT(IN)  :: ky(:)
    1422   CHARACTER(LEN=*), OPTIONAL, INTENT(IN)  :: def_val
    1423   LOGICAL,          OPTIONAL, INTENT(OUT) :: lerr
    1424 !------------------------------------------------------------------------------------------------------------------------------
    1425   LOGICAL :: ler(SIZE(ky))
    1426   INTEGER :: it
    1427   val = [(fgetKeyIdx_s1(it, keyn, ky, def_val, ler(it)), it = 1, SIZE(ky))]
    1428   IF(PRESENT(lerr)) lerr = ANY(ler)
    1429 END FUNCTION fgetKeys
    1430 !==============================================================================================================================
    1431 
    1432 
    1433 !==============================================================================================================================
    1434 !========== GET THE VALUE OF A KEY FROM A "keys_type" DERIVED TYPE ; THE RETURNED VALUE IS THE ERROR CODE        ==============
    1435 !==========  The key "keyn" is searched in: 1)           "ky(:)%name" (if given)                                 ==============
    1436 !==========                                 2)      "tracers(:)%name"                                            ==============
    1437 !==========                                 3) "isotope%keys(:)%name"                                            ==============
    1438 !==========  for the tracer[s] "tname[(:)]" (if given) or all the available tracers from the used set otherwise. ==============
    1439 !==========  The type of the returned value(s) can be string, integer or real, scalar or vector                  ==============
    1440 !==============================================================================================================================
    1441 LOGICAL FUNCTION getKeyByName_s1(keyn, val, tname, ky) RESULT(lerr)
     1598  ler = itr <= 0 .OR. itr > SIZE(ky); IF(ler) RETURN
     1599  iky = strIdx(ky(itr)%key(:), keyn)
     1600  ler = iky == 0;                     IF(ler) RETURN
     1601  val = ky(itr)%val(iky)
     1602END SUBROUTINE getKeyIdx
     1603
     1604END FUNCTION fgetKeyIdx
     1605!==============================================================================================================================
     1606
     1607
     1608!==============================================================================================================================
     1609!===                                          GET KEYS VALUES FROM TRACERS INDICES                                          ===
     1610!==============================================================================================================================
     1611!=== TRY TO GET THE KEY NAMED "key" FOR THE "itr"th TRACER IN:                                                              ===
     1612!===  * ARGUMENT "ky" DATABASE IF SPECIFIED ; OTHERWISE:                                                                    ===
     1613!===  * IN INTERNAL TRACERS DATABASE "tracers(:)%keys" (IF UNFOUND, IN INTERNAL ISOTOPES DATABASE "isotope%keys(:)")        ===
     1614!=== THE RETURNED VALUE (STRING, AN INTEGER, A REAL OR A LOGICAL) CAN BE EITHER:                                            ===
     1615!===  * A SCALAR                                                                                                            ===
     1616!===  * A VECTOR, WHICH IS THE FOUND VALUE PARSED WITH THE SEPARATOR ","                                                    ===
     1617!===                                                                                                                        ===
     1618!=== SYNTAX:       lerr = getKeyByIndex_{sirl}{1m}{1m}1(keyn[(:)], val[(:)], itr[, ky(:)]          [, def][, lDisp])        ===
     1619!==============================================================================================================================
     1620!=== IF "itr" IS NOT PRESENT, VALUES FOR ALL THE TRACERS OF THE SELECTED DATABASE ARE STORED IN THE VECTOR "val(:)"         ===
     1621!=== THE NAME OF THE TRACERS FOUND IN THE EFFECTIVELY USED DATABASE CAN BE RETURNED OPTIONALLY IN "nam(:)"                  ===
     1622!=== SYNTAX        lerr = getKeyByIndex_{sirl}{1m}mm   (keyn[(:)], val (:)      [, ky(:)][, nam(:)][, def][, lDisp])        ===
     1623!==============================================================================================================================
     1624LOGICAL FUNCTION getKeyByIndex_s111(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
    14421625  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
    14431626  CHARACTER(LEN=maxlen),     INTENT(OUT) :: val
    1444   CHARACTER(LEN=*),          INTENT(IN)  :: tname
     1627  INTEGER,                   INTENT(IN)  :: itr
    14451628  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
    1446 !------------------------------------------------------------------------------------------------------------------------------
    1447   CHARACTER(LEN=maxlen) :: tnam
    1448   tnam = strHead(delPhase(tname),'_',.TRUE.)                                             !--- Remove phase and tag
    1449   IF(PRESENT(ky)) THEN                                                                   !=== KEY FROM "ky"
    1450                val = fgetKeyNam_s1(tname, keyn, ky,           lerr=lerr)                 !--- "ky" and "tname"
    1451     IF( lerr ) val = fgetKeyNam_s1(tnam,  keyn, ky,           lerr=lerr)                 !--- "ky" and "tnam"
    1452   ELSE
    1453     IF(         .NOT.test(.NOT.ALLOCATED(tracers ), lerr)) lerr = SIZE(tracers ) == 0    !=== KEY FROM "tracers"
    1454     IF(.NOT.lerr) THEN
    1455                val = fgetKeyNam_s1(tname, keyn, tracers%keys, lerr=lerr)                 !--- "ky" and "tname"
    1456       IF(lerr) val = fgetKeyNam_s1(tnam,  keyn, tracers%keys, lerr=lerr)                 !--- "ky" and "tnam"
    1457     END IF
    1458     IF(lerr.AND..NOT.test(.NOT.ALLOCATED(isotopes), lerr)) lerr = SIZE(isotopes) == 0    !=== KEY FROM "isotope"
    1459     IF(.NOT.lerr) THEN
    1460                val = fgetKeyNam_s1(tname, keyn, isotope%keys, lerr=lerr)                 !--- "ky" and "tname"
    1461       IF(lerr) val = fgetKeyNam_s1(tnam,  keyn, isotope%keys, lerr=lerr)                 !--- "ky" and "tnam"
    1462     END IF
     1629  CHARACTER(LEN=*),OPTIONAL, INTENT(IN)  :: def
     1630  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1631  lerr = getKeyByIndex_sm11([keyn], val, itr, ky, def, lDisp)
     1632END FUNCTION getKeyByIndex_s111
     1633!==============================================================================================================================
     1634LOGICAL FUNCTION getKeyByIndex_i111(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1635  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1636  INTEGER,                   INTENT(OUT) :: val
     1637  INTEGER,                   INTENT(IN)  :: itr
     1638  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1639  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     1640  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1641  lerr = getKeyByIndex_im11([keyn], val, itr, ky, def, lDisp)
     1642END FUNCTION getKeyByIndex_i111
     1643!==============================================================================================================================
     1644LOGICAL FUNCTION getKeyByIndex_r111(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1645  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1646  REAL   ,                   INTENT(OUT) :: val
     1647  INTEGER,                   INTENT(IN)  :: itr
     1648  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1649  REAL,            OPTIONAL, INTENT(IN)  :: def
     1650  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1651  lerr = getKeyByIndex_rm11([keyn], val, itr, ky, def, lDisp)
     1652END FUNCTION getKeyByIndex_r111
     1653!==============================================================================================================================
     1654LOGICAL FUNCTION getKeyByIndex_l111(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1655  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1656  LOGICAL,                   INTENT(OUT) :: val
     1657  INTEGER,                   INTENT(IN)  :: itr
     1658  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1659  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     1660  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1661  lerr = getKeyByIndex_lm11([keyn], val, itr, ky, def, lDisp)
     1662END FUNCTION getKeyByIndex_l111
     1663!==============================================================================================================================
     1664!==============================================================================================================================
     1665LOGICAL FUNCTION getKeyByIndex_sm11(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1666  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1667  CHARACTER(LEN=maxlen),     INTENT(OUT) :: val
     1668  INTEGER,                   INTENT(IN)  :: itr
     1669  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1670  CHARACTER(LEN=*),OPTIONAL, INTENT(IN)  :: def
     1671  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1672!------------------------------------------------------------------------------------------------------------------------------
     1673  CHARACTER(LEN=maxlen) :: s
     1674  LOGICAL :: lD
     1675  lD = .TRUE.; IF(PRESENT(lDisp)) lD = lDisp
     1676  s = 'key "'//TRIM(strStack(keyn, '/'))//'" for tracer nr. '//TRIM(int2str(itr))
     1677  lerr = .TRUE.
     1678  IF(lerr .AND. PRESENT(ky))         val = fgetKey(ky)                                   !--- "ky"
     1679  IF(lerr .AND. ALLOCATED (tracers)) val = fgetKey(tracers(:)%keys)                      !--- "tracers"
     1680  IF(lerr .AND. ASSOCIATED(isotope)) val = fgetKey(isotope%keys(:))                      !--- "isotope"
     1681  IF(lerr .AND. PRESENT(def)) THEN
     1682     val = def; lerr = .NOT.PRESENT(def)
     1683     CALL msg('Using defaut value of '//TRIM(s)//': '//TRIM(def), modname, lD)
    14631684  END IF
    1464 END FUNCTION getKeyByName_s1
    1465 !==============================================================================================================================
    1466 LOGICAL FUNCTION getKeyByName_s1m(keyn, val, tname, ky) RESULT(lerr)
     1685  CALL msg('No '//TRIM(s)//' or out of bounds index', modname, lD .AND. lerr)
     1686
     1687CONTAINS
     1688
     1689CHARACTER(LEN=maxlen) FUNCTION fgetKey(ky) RESULT(val)
     1690  TYPE(keys_type),  INTENT(IN)  :: ky(:)
     1691  lerr = SIZE(ky) == 0; IF(lerr) RETURN
     1692  val = fgetKeyIdx(itr, keyn(:), ky, lerr)
     1693END FUNCTION fgetKey
     1694
     1695END FUNCTION getKeyByIndex_sm11
     1696!==============================================================================================================================
     1697LOGICAL FUNCTION getKeyByIndex_im11(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1698  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1699  INTEGER,                   INTENT(OUT) :: val
     1700  INTEGER,                   INTENT(IN)  :: itr
     1701  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1702  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     1703  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1704!------------------------------------------------------------------------------------------------------------------------------
     1705  CHARACTER(LEN=maxlen) :: sval, s
     1706  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, int2str(def), lDisp)
     1707  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1708  IF(lerr) RETURN
     1709  val = str2int(sval)
     1710  lerr = val == -HUGE(1)
     1711  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1712  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     1713END FUNCTION getKeyByIndex_im11
     1714!==============================================================================================================================
     1715LOGICAL FUNCTION getKeyByIndex_rm11(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1716  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1717  REAL   ,                   INTENT(OUT) :: val
     1718  INTEGER,                   INTENT(IN)  :: itr
     1719  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1720  REAL,            OPTIONAL, INTENT(IN)  :: def
     1721  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1722!------------------------------------------------------------------------------------------------------------------------------
     1723  CHARACTER(LEN=maxlen) :: sval, s
     1724  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, real2str(def), lDisp)
     1725  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1726  IF(lerr) RETURN
     1727  val = str2real(sval)
     1728  lerr = val == -HUGE(1.)
     1729  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1730  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     1731END FUNCTION getKeyByIndex_rm11
     1732!==============================================================================================================================
     1733LOGICAL FUNCTION getKeyByIndex_lm11(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1734  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1735  LOGICAL,                   INTENT(OUT) :: val
     1736  INTEGER,                   INTENT(IN)  :: itr
     1737  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1738  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     1739  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1740!------------------------------------------------------------------------------------------------------------------------------
     1741  CHARACTER(LEN=maxlen) :: sval, s
     1742  INTEGER               :: ival
     1743  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, bool2str(def), lDisp)
     1744  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1745  IF(lerr) RETURN
     1746  ival = str2bool(sval)
     1747  lerr = ival == -1
     1748  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1749  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     1750  IF(.NOT.lerr) val = ival == 1
     1751END FUNCTION getKeyByIndex_lm11
     1752!==============================================================================================================================
     1753!==============================================================================================================================
     1754LOGICAL FUNCTION getKeyByIndex_s1m1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
    14671755  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn
    14681756  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:)
    1469   CHARACTER(LEN=*),                   INTENT(IN)  :: tname
     1757  INTEGER,                            INTENT(IN)  :: itr
    14701758  TYPE(keys_type),          OPTIONAL, INTENT(IN)  :: ky(:)
     1759  CHARACTER(LEN=*),         OPTIONAL, INTENT(IN)  :: def
     1760  LOGICAL,                  OPTIONAL, INTENT(IN)  :: lDisp
     1761!------------------------------------------------------------------------------------------------------------------------------
     1762  CHARACTER(LEN=maxlen)              :: sval
     1763  lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, def, lDisp); IF(lerr) RETURN
     1764  lerr = strParse(sval, ',', val)
     1765  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1766END FUNCTION getKeyByIndex_s1m1
     1767!==============================================================================================================================
     1768LOGICAL FUNCTION getKeyByIndex_i1m1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1769  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1770  INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
     1771  INTEGER,                   INTENT(IN)  :: itr
     1772  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1773  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     1774  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1775!------------------------------------------------------------------------------------------------------------------------------
     1776  CHARACTER(LEN=maxlen)              :: sval, s
     1777  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1778  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, int2str(def), lDisp)
     1779  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, lDisp=lDisp)
     1780  IF(lerr) RETURN
     1781  lerr = strParse(sval, ',', svals)
     1782  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1783  val = str2int(svals)
     1784  lerr = ANY(val == -HUGE(1))
     1785  s = 'key "'//TRIM(keyn)//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1786  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     1787END FUNCTION getKeyByIndex_i1m1
     1788!==============================================================================================================================
     1789LOGICAL FUNCTION getKeyByIndex_r1m1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1790  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1791  REAL,         ALLOCATABLE, INTENT(OUT) :: val(:)
     1792  INTEGER,                   INTENT(IN)  :: itr
     1793  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1794  REAL,            OPTIONAL, INTENT(IN)  :: def
     1795  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1796!------------------------------------------------------------------------------------------------------------------------------
     1797  CHARACTER(LEN=maxlen)              :: sval, s
     1798  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1799  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, real2str(def), lDisp)
     1800  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, lDisp=lDisp)
     1801  lerr = strParse(sval, ',', svals)
     1802  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1803  val = str2real(svals)
     1804  lerr = ANY(val == -HUGE(1.))
     1805  s = 'key "'//TRIM(keyn)//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1806  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     1807END FUNCTION getKeyByIndex_r1m1
     1808!==============================================================================================================================
     1809LOGICAL FUNCTION getKeyByIndex_l1m1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1810  CHARACTER(LEN=*),          INTENT(IN)  :: keyn
     1811  LOGICAL,      ALLOCATABLE, INTENT(OUT) :: val(:)
     1812  INTEGER,                   INTENT(IN)  :: itr
     1813  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1814  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     1815  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1816!------------------------------------------------------------------------------------------------------------------------------
     1817  CHARACTER(LEN=maxlen)              :: sval, s
     1818  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1819  INTEGER,               ALLOCATABLE :: ivals(:)
     1820  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, bool2str(def), lDisp)
     1821  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11([keyn], sval, itr, ky, lDisp=lDisp)
     1822  lerr = strParse(sval, ',', svals)
     1823  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1824  ivals = str2bool(svals)
     1825  lerr = ANY(ivals == -1)
     1826  s = 'key "'//TRIM(keyn)//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1827  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     1828  IF(.NOT.lerr) val = ivals == 1
     1829END FUNCTION getKeyByIndex_l1m1
     1830!==============================================================================================================================
     1831!==============================================================================================================================
     1832LOGICAL FUNCTION getKeyByIndex_smm1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1833  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn(:)
     1834  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:)
     1835  INTEGER,                            INTENT(IN)  :: itr
     1836  TYPE(keys_type),          OPTIONAL, INTENT(IN)  :: ky(:)
     1837  CHARACTER(LEN=*),         OPTIONAL, INTENT(IN)  :: def
     1838  LOGICAL,                  OPTIONAL, INTENT(IN)  :: lDisp
    14711839!------------------------------------------------------------------------------------------------------------------------------
    14721840  CHARACTER(LEN=maxlen) :: sval
    1473   lerr = getKeyByName_s1(keyn, sval, tname, ky)
    1474   IF(test(fmsg('missing key "'//TRIM(keyn)//'" for tracer "'//TRIM(tname)//'"', modname, lerr), lerr)) RETURN
     1841  lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, def, lDisp); IF(lerr) RETURN
    14751842  lerr = strParse(sval, ',', val)
    1476 END FUNCTION getKeyByName_s1m
    1477 !==============================================================================================================================
    1478 LOGICAL FUNCTION getKeyByName_sm(keyn, val, tname, ky, nam) RESULT(lerr)
     1843  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1844END FUNCTION getKeyByIndex_smm1
     1845!==============================================================================================================================
     1846LOGICAL FUNCTION getKeyByIndex_imm1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1847  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1848  INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
     1849  INTEGER,                   INTENT(IN)  :: itr
     1850  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1851  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     1852  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1853!------------------------------------------------------------------------------------------------------------------------------
     1854  CHARACTER(LEN=maxlen)              :: sval, s
     1855  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1856  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, int2str(def), lDisp)
     1857  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1858  IF(lerr) RETURN
     1859  lerr = strParse(sval, ',', svals)
     1860  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1861  val = str2int(svals)
     1862  lerr = ANY(val == -HUGE(1))
     1863  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1864  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     1865END FUNCTION getKeyByIndex_imm1
     1866!==============================================================================================================================
     1867LOGICAL FUNCTION getKeyByIndex_rmm1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1868  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1869  REAL,         ALLOCATABLE, INTENT(OUT) :: val(:)
     1870  INTEGER,                   INTENT(IN)  :: itr
     1871  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1872  REAL,            OPTIONAL, INTENT(IN)  :: def
     1873  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1874!------------------------------------------------------------------------------------------------------------------------------
     1875  CHARACTER(LEN=maxlen)              :: sval, s
     1876  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1877  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, real2str(def), lDisp)
     1878  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1879  IF(lerr) RETURN
     1880  lerr = strParse(sval, ',', svals)
     1881  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1882  val = str2real(svals)
     1883  lerr = ANY(val == -HUGE(1.))
     1884  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1885  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     1886END FUNCTION getKeyByIndex_rmm1
     1887!==============================================================================================================================
     1888LOGICAL FUNCTION getKeyByIndex_lmm1(keyn, val, itr, ky, def, lDisp) RESULT(lerr)
     1889  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:)
     1890  LOGICAL,      ALLOCATABLE, INTENT(OUT) :: val(:)
     1891  INTEGER,                   INTENT(IN)  :: itr
     1892  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     1893  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     1894  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     1895!------------------------------------------------------------------------------------------------------------------------------
     1896  CHARACTER(LEN=maxlen)              :: sval, s
     1897  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     1898  INTEGER,               ALLOCATABLE :: ivals(:)
     1899  IF(     PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, bool2str(def), lDisp)
     1900  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_sm11(keyn, sval, itr, ky, lDisp=lDisp)
     1901  IF(lerr) RETURN
     1902  lerr = strParse(sval, ',', svals)
     1903  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     1904  ivals = str2bool(svals)
     1905  lerr = ANY(ivals == -1)
     1906  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of tracer nr. '//TRIM(int2str(itr))//' is not'
     1907  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     1908  IF(.NOT.lerr) val = ivals == 1
     1909END FUNCTION getKeyByIndex_lmm1
     1910!==============================================================================================================================
     1911!==============================================================================================================================
     1912LOGICAL FUNCTION getKeyByIndex_s1mm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
    14791913  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
    14801914  CHARACTER(LEN=maxlen),           ALLOCATABLE, INTENT(OUT) :: val(:)
    1481   CHARACTER(LEN=*),                             INTENT(IN)  :: tname(:)
    1482   TYPE(keys_type),       OPTIONAL, TARGET,      INTENT(IN)  :: ky(:)
     1915  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::  ky(:)
    14831916  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:)
    1484 !------------------------------------------------------------------------------------------------------------------------------
    1485   TYPE(keys_type), POINTER ::  keys(:)
    1486   LOGICAL :: lk, lt, li
    1487   INTEGER :: iq, nq
    1488 
    1489   !--- DETERMINE THE DATABASE TO BE USED (ky, tracers or isotope)
    1490   lk = PRESENT(ky)
    1491   lt = .NOT.lk .AND. ALLOCATED(tracers);  IF(lt) lt = SIZE(tracers)  /= 0; IF(lt) lt = ANY(tracers(1)%keys%key(:) == keyn)
    1492   li = .NOT.lt .AND. ALLOCATED(isotopes); IF(li) li = SIZE(isotopes) /= 0; IF(li) li = ANY(isotope%keys(1)%key(:) == keyn)
    1493 
    1494   !--- LINK "keys" TO THE RIGHT DATABASE
    1495   IF(test(.NOT.ANY([lk,lt,li]), lerr)) RETURN
    1496   IF(lk) keys => ky(:)
    1497   IF(lt) keys => tracers(:)%keys
    1498   IF(li) keys => isotope%keys(:)
    1499 
    1500   !--- GET THE DATA
    1501   nq = SIZE(tname)
    1502   ALLOCATE(val(nq))
    1503   lerr = ANY([(getKeyByName_s1(keyn, val(iq), tname(iq), keys(:)), iq=1, nq)])
    1504   IF(PRESENT(nam)) nam = tname(:)
    1505 
    1506 END FUNCTION getKeyByName_sm
    1507 !==============================================================================================================================
    1508 LOGICAL FUNCTION getKey_sm(keyn, val, ky, nam) RESULT(lerr)
     1917  CHARACTER(LEN=*),      OPTIONAL,              INTENT(IN)  :: def
     1918  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     1919  lerr = getKeyByIndex_smmm([keyn], val, ky, nam, def, lDisp)
     1920END FUNCTION getKeyByIndex_s1mm
     1921!==============================================================================================================================
     1922LOGICAL FUNCTION getKeyByIndex_i1mm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
    15091923  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
    1510   CHARACTER(LEN=maxlen),           ALLOCATABLE, INTENT(OUT) :: val(:)
    1511   TYPE(keys_type),       OPTIONAL,              INTENT(IN)  :: ky(:)
     1924  INTEGER,                         ALLOCATABLE, INTENT(OUT) :: val(:)
     1925  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::  ky(:)
    15121926  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:)
    1513 !------------------------------------------------------------------------------------------------------------------------------
    1514 ! Note: if names are repeated, getKeyByName_sm can't be used ; this routine, using indexes, must be used instead.
    1515   IF(PRESENT(ky)) THEN                                                                   !=== KEY FROM "ky"
    1516     val = fgetKeys(keyn, ky, lerr=lerr)
    1517     IF(PRESENT(nam)) nam = ky(:)%name
    1518   ELSE
    1519     IF(         .NOT.test(.NOT.ALLOCATED(tracers ), lerr)) lerr = SIZE(tracers ) == 0    !=== KEY FROM "tracers"
    1520     IF(.NOT.lerr) val = fgetKeys(keyn, tracers%keys, lerr=lerr)
    1521     IF(.NOT.lerr.AND.PRESENT(nam)) nam = tracers(:)%keys%name
    1522     IF(lerr.AND..NOT.test(.NOT.ALLOCATED(isotopes), lerr)) lerr = SIZE(isotopes) == 0    !=== KEY FROM "isotope"
    1523     IF(.NOT.lerr) val = fgetKeys(keyn, isotope%keys, lerr=lerr)
    1524     IF(.NOT.lerr.AND.PRESENT(nam)) nam = isotope%keys(:)%name
     1927  INTEGER,               OPTIONAL,              INTENT(IN)  :: def
     1928  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     1929  lerr = getKeyByIndex_immm([keyn], val, ky, nam, def, lDisp)
     1930END FUNCTION getKeyByIndex_i1mm
     1931!==============================================================================================================================
     1932LOGICAL FUNCTION getKeyByIndex_r1mm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     1933  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
     1934  REAL,                            ALLOCATABLE, INTENT(OUT) :: val(:)
     1935  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::  ky(:)
     1936  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:)
     1937  REAL,                  OPTIONAL,              INTENT(IN)  :: def
     1938  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     1939  lerr = getKeyByIndex_rmmm([keyn], val, ky, nam, def, lDisp)
     1940END FUNCTION getKeyByIndex_r1mm
     1941!==============================================================================================================================
     1942LOGICAL FUNCTION getKeyByIndex_l1mm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     1943  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
     1944  LOGICAL,                         ALLOCATABLE, INTENT(OUT) :: val(:)
     1945  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::  ky(:)
     1946  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:)
     1947  LOGICAL,               OPTIONAL,              INTENT(IN)  :: def
     1948  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     1949  lerr = getKeyByIndex_lmmm([keyn], val, ky, nam, def, lDisp)
     1950END FUNCTION getKeyByIndex_l1mm
     1951!==============================================================================================================================
     1952!==============================================================================================================================
     1953LOGICAL FUNCTION getKeyByIndex_smmm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     1954  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn(:)
     1955  CHARACTER(LEN=maxlen),           ALLOCATABLE, INTENT(OUT) ::  val(:)
     1956  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::   ky(:)
     1957  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::  nam(:)
     1958  CHARACTER(LEN=*),      OPTIONAL,              INTENT(IN)  ::  def
     1959  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     1960!------------------------------------------------------------------------------------------------------------------------------
     1961  CHARACTER(LEN=maxlen) :: s
     1962  CHARACTER(LEN=maxlen), ALLOCATABLE :: tname(:)
     1963  INTEGER :: iq, nq(3), k
     1964  LOGICAL :: lD, l(3)
     1965  lD = .TRUE.; IF(PRESENT(lDisp)) lD = lDisp
     1966  s = 'key "'//TRIM(strStack(keyn, '/'))//'"'
     1967  lerr = .TRUE.
     1968  IF(PRESENT(ky)) THEN;                 val = fgetKey(ky)                                !--- "ky"
     1969  ELSE IF(ALLOCATED(tracers)) THEN;     val = fgetKey(tracers(:)%keys)                   !--- "tracers"
     1970     IF(lerr .AND. ASSOCIATED(isotope)) val = fgetKey(isotope%keys(:))                   !--- "isotope"
    15251971  END IF
    1526 END FUNCTION getKey_sm
    1527 !==============================================================================================================================
    1528 LOGICAL FUNCTION getKeyByName_i1(keyn, val, tname, ky) RESULT(lerr)
    1529   CHARACTER(LEN=*),          INTENT(IN)  :: keyn
    1530   INTEGER,                   INTENT(OUT) :: val
    1531   CHARACTER(LEN=*),          INTENT(IN)  :: tname
    1532   TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
    1533 !------------------------------------------------------------------------------------------------------------------------------
    1534   CHARACTER(LEN=maxlen) :: sval
    1535   INTEGER :: ierr
    1536   lerr = getKeyByName_s1(keyn, sval, tname, ky)
    1537   IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN
    1538   READ(sval, *, IOSTAT=ierr) val
    1539   IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not an integer', modname, ierr/=0), lerr)) RETURN
    1540 END FUNCTION getKeyByName_i1
    1541 !==============================================================================================================================
    1542 LOGICAL FUNCTION getKeyByName_i1m(keyn, val, tname, ky) RESULT(lerr)
    1543   CHARACTER(LEN=*),          INTENT(IN)  :: keyn
    1544   INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
    1545   CHARACTER(LEN=*),          INTENT(IN)  :: tname
    1546   TYPE(keys_type), OPTIONAL, INTENT(IN)  ::  ky(:)
    1547 !------------------------------------------------------------------------------------------------------------------------------
    1548   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:)
    1549   INTEGER :: ierr, iq, nq
    1550   IF(test(getKeyByName_s1m(keyn, sval, tname, ky), lerr)) RETURN
    1551   nq = SIZE(sval); ALLOCATE(val(nq))
    1552   lerr = .FALSE.; DO iq=1, nq; READ(sval(iq), *, IOSTAT=ierr) val(iq); lerr = lerr .OR. ierr /= 0; END DO
    1553   IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not an integer', modname, lerr), lerr)) RETURN
    1554 END FUNCTION getKeyByName_i1m
    1555 !==============================================================================================================================
    1556 LOGICAL FUNCTION getKeyByName_im(keyn, val, tname, ky, nam) RESULT(lerr)
    1557   CHARACTER(LEN=*),                             INTENT(IN)  ::  keyn
    1558   INTEGER,                         ALLOCATABLE, INTENT(OUT) ::   val(:)
    1559   CHARACTER(LEN=*),                             INTENT(IN)  :: tname(:)
    1560   TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::    ky(:)
    1561   CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::   nam(:)
    1562 !------------------------------------------------------------------------------------------------------------------------------
    1563   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:), names(:)
    1564   INTEGER :: ierr, iq, nq
    1565   IF(test(getKeyByName_sm(keyn, sval, tname, ky, names), lerr)) RETURN
    1566   nq = SIZE(sval); ALLOCATE(val(nq))
    1567   DO iq = 1, nq                                                      !--- CONVERT THE KEYS TO INTEGERS
    1568     READ(sval(iq), *, IOSTAT=ierr) val(iq)
    1569     IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(names(iq))//'" is not an integer', modname, ierr/=0), lerr)) RETURN
    1570   END DO
    1571   IF(PRESENT(nam)) nam = names(:)
    1572 END FUNCTION getKeyByName_im
    1573 !==============================================================================================================================
    1574 LOGICAL FUNCTION getKey_im(keyn, val, ky, nam) RESULT(lerr)
    1575   CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
     1972  IF(.NOT.lerr) THEN; IF(PRESENT(nam)) nam = tname; RETURN; END IF
     1973  IF(.NOT.PRESENT(def)) THEN; CALL msg('No '//TRIM(s)//' found', modname, lD); RETURN; END IF
     1974
     1975  !--- DEFAULT VALUE
     1976  l = [PRESENT(ky), ALLOCATED(tracers), ASSOCIATED(isotope)]; nq(:) = 0
     1977  IF(l(1)) nq(1) = SIZE(ky)
     1978  IF(l(2)) nq(2) = SIZE(tracers)
     1979  IF(l(3)) nq(3) = SIZE(isotope%keys)
     1980  DO k = 1, 3; IF(l(k) .AND. nq(k) /= 0) THEN; val = [(def, iq = 1, nq(k))]; EXIT; END IF; END DO
     1981  lerr = k == 4
     1982  CALL msg('Using defaut value for '//TRIM(s)//': '//TRIM(def), modname, lD .AND. .NOT.lerr)
     1983  CALL msg('No '//TRIM(s), modname, lD .AND. lerr)
     1984
     1985CONTAINS
     1986
     1987FUNCTION fgetKey(ky) RESULT(val)
     1988  CHARACTER(LEN=maxlen), ALLOCATABLE :: val(:)
     1989  TYPE(keys_type),       INTENT(IN)  :: ky(:)
     1990  LOGICAL :: ler(SIZE(ky))
     1991  INTEGER :: iq
     1992  lerr = SIZE(ky) == 0; IF(lerr) RETURN
     1993  tname = ky%name
     1994  val = [(fgetKeyIdx(iq, keyn(:), ky, ler(iq)), iq = 1, SIZE(ky))]
     1995  lerr = ANY(ler)
     1996END FUNCTION fgetKey
     1997
     1998END FUNCTION getKeyByIndex_smmm
     1999!==============================================================================================================================
     2000LOGICAL FUNCTION getKeyByIndex_immm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     2001  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn(:)
    15762002  INTEGER,                         ALLOCATABLE, INTENT(OUT) ::  val(:)
    15772003  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::   ky(:)
    15782004  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::  nam(:)
    1579 !------------------------------------------------------------------------------------------------------------------------------
    1580   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:), names(:)
    1581   INTEGER :: ierr, iq, nq
    1582   IF(test(getKey_sm(keyn, sval, ky, names), lerr)) RETURN
    1583   nq = SIZE(sval); ALLOCATE(val(nq))
    1584   DO iq = 1, nq
    1585     READ(sval(iq), *, IOSTAT=ierr) val(iq)
    1586     IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(names(iq))//'" is not an integer', modname, ierr/=0), lerr)) RETURN
    1587   END DO
    1588   IF(PRESENT(nam)) nam = names
    1589 END FUNCTION getKey_im
    1590 !==============================================================================================================================
    1591 LOGICAL FUNCTION getKeyByName_r1(keyn, val, tname, ky) RESULT(lerr)
    1592   CHARACTER(LEN=*),          INTENT(IN)  :: keyn
    1593   REAL,                      INTENT(OUT) :: val
    1594   CHARACTER(LEN=*),          INTENT(IN)  :: tname
    1595   TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
    1596 !------------------------------------------------------------------------------------------------------------------------------
    1597   CHARACTER(LEN=maxlen) :: sval
    1598   INTEGER :: ierr
    1599   lerr = getKeyByName_s1(keyn, sval, tname, ky)
    1600   IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing',    modname, lerr), lerr)) RETURN
    1601   READ(sval, *, IOSTAT=ierr) val
    1602   IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not a real', modname, ierr/=0), lerr)) RETURN
    1603 END FUNCTION getKeyByName_r1
    1604 !==============================================================================================================================
    1605 LOGICAL FUNCTION getKeyByName_r1m(keyn, val, tname, ky) RESULT(lerr)
    1606   CHARACTER(LEN=*),           INTENT(IN)  :: keyn
    1607   REAL,          ALLOCATABLE, INTENT(OUT) :: val(:)
    1608   CHARACTER(LEN=*),           INTENT(IN)  :: tname
    1609   TYPE(keys_type),  OPTIONAL, INTENT(IN)  ::  ky(:)
    1610 !------------------------------------------------------------------------------------------------------------------------------
    1611   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:)
    1612   INTEGER :: ierr, iq, nq
    1613   IF(test(getKeyByName_s1m(keyn, sval, tname, ky), lerr)) RETURN
    1614   nq = SIZE(sval); ALLOCATE(val(nq))
    1615   lerr = .FALSE.; DO iq=1, nq; READ(sval(iq), *, IOSTAT=ierr) val(iq); lerr = lerr .OR. ierr /= 0; END DO
    1616   IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not a vector of reals', modname, lerr), lerr)) RETURN
    1617 END FUNCTION getKeyByName_r1m
    1618 !==============================================================================================================================
    1619 LOGICAL FUNCTION getKeyByName_rm(keyn, val, tname, ky, nam) RESULT(lerr)
    1620   CHARACTER(LEN=*),                             INTENT(IN)  ::  keyn
    1621   REAL,                            ALLOCATABLE, INTENT(OUT) ::   val(:)
    1622   CHARACTER(LEN=*),                             INTENT(IN)  :: tname(:)
    1623   TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::    ky(:)
    1624   CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::   nam(:)
    1625 !------------------------------------------------------------------------------------------------------------------------------
    1626   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:), names(:)
    1627   INTEGER :: ierr, iq, nq
    1628   IF(test(getKeyByName_sm(keyn, sval, tname, ky, names), lerr)) RETURN
    1629   nq = SIZE(sval); ALLOCATE(val(nq))
    1630   DO iq = 1, nq                                                      !--- CONVERT THE KEYS TO INTEGERS
    1631     READ(sval(iq), *, IOSTAT=ierr) val(iq)
    1632     IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(names(iq))//'" is not a real', modname, ierr/=0), lerr)) RETURN
    1633   END DO
    1634   IF(PRESENT(nam)) nam = names
    1635 END FUNCTION getKeyByName_rm
    1636 !==============================================================================================================================
    1637 LOGICAL FUNCTION getKey_rm(keyn, val, ky, nam) RESULT(lerr)
    1638   CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
     2005  INTEGER,               OPTIONAL,              INTENT(IN)  ::  def
     2006  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     2007!------------------------------------------------------------------------------------------------------------------------------
     2008  CHARACTER(LEN=maxlen) :: s
     2009  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:), tname(:)
     2010  LOGICAL,               ALLOCATABLE ::    ll(:)
     2011  IF(     PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, int2str(def), lDisp)
     2012  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, lDisp=lDisp)
     2013  IF(lerr) RETURN
     2014  val = str2int(svals)
     2015  ll = val == -HUGE(1)
     2016  lerr = ANY(ll); IF(.NOT.lerr) THEN; IF(PRESENT(nam)) nam = tname; RETURN; END IF
     2017  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(PACK(tname, MASK=ll)))//' is not'
     2018  CALL msg(TRIM(s)//' an integer: '//TRIM(strStack(svals, MASK=ll)), modname, lerr)
     2019  IF(.NOT.lerr .AND. PRESENT(nam)) nam = tname
     2020END FUNCTION getKeyByIndex_immm
     2021!==============================================================================================================================
     2022LOGICAL FUNCTION getKeyByIndex_rmmm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     2023  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn(:)
    16392024  REAL,                            ALLOCATABLE, INTENT(OUT) ::  val(:)
    16402025  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::   ky(:)
    16412026  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::  nam(:)
    1642 !------------------------------------------------------------------------------------------------------------------------------
    1643   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:), names(:)
    1644   INTEGER :: ierr, iq, nq
    1645   IF(test(getKey_sm(keyn, sval, ky, names), lerr)) RETURN
    1646   nq = SIZE(sval); ALLOCATE(val(nq))
    1647   DO iq = 1, nq                                                      !--- CONVERT THE KEYS TO INTEGERS
    1648     READ(sval(iq), *, IOSTAT=ierr) val(iq)
    1649     IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(names(iq))//'" is not a real', modname, ierr/=0), lerr)) RETURN
    1650   END DO
    1651   IF(PRESENT(nam)) nam = names
    1652 END FUNCTION getKey_rm
    1653 !==============================================================================================================================
    1654 LOGICAL FUNCTION getKeyByName_l1(keyn, val, tname, ky) RESULT(lerr)
    1655   USE strings_mod, ONLY: str2bool
    1656   CHARACTER(LEN=*),          INTENT(IN)  :: keyn
    1657   LOGICAL,                   INTENT(OUT) :: val
    1658   CHARACTER(LEN=*),          INTENT(IN)  :: tname
    1659   TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
    1660 !------------------------------------------------------------------------------------------------------------------------------
    1661   CHARACTER(LEN=maxlen) :: sval
    1662   lerr = getKeyByName_s1(keyn, sval, tname, ky)
    1663   IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN
    1664   val = str2bool(sval)
    1665 END FUNCTION getKeyByName_l1
    1666 !==============================================================================================================================
    1667 LOGICAL FUNCTION getKeyByName_l1m(keyn, val, tname, ky) RESULT(lerr)
    1668   USE strings_mod, ONLY: str2bool
    1669   CHARACTER(LEN=*),           INTENT(IN)  :: keyn
    1670   LOGICAL,       ALLOCATABLE, INTENT(OUT) :: val(:)
    1671   CHARACTER(LEN=*),           INTENT(IN)  :: tname
    1672   TYPE(keys_type),  OPTIONAL, INTENT(IN)  ::  ky(:)
    1673 !------------------------------------------------------------------------------------------------------------------------------
    1674   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:)
    1675   INTEGER :: iq, nq
    1676   IF(test(getKeyByName_s1m(keyn, sval, tname, ky), lerr)) RETURN
    1677   nq = SIZE(sval); ALLOCATE(val(nq))
    1678   lerr = .FALSE.; DO iq=1, nq; val(iq)=str2bool(sval(iq)); END DO
    1679 END FUNCTION getKeyByName_l1m
    1680 !==============================================================================================================================
    1681 LOGICAL FUNCTION getKeyByName_lm(keyn, val, tname, ky, nam) RESULT(lerr)
    1682   USE strings_mod, ONLY: str2bool
    1683   CHARACTER(LEN=*),                             INTENT(IN)  ::  keyn
    1684   LOGICAL,                         ALLOCATABLE, INTENT(OUT) ::   val(:)
    1685   CHARACTER(LEN=*),                             INTENT(IN)  :: tname(:)
    1686   TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::    ky(:)
    1687   CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::   nam(:)
    1688 !------------------------------------------------------------------------------------------------------------------------------
    1689   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:)
    1690   INTEGER :: iq, nq
    1691   IF(test(getKeyByName_sm(keyn, sval, tname, ky, nam), lerr)) RETURN
    1692   nq = SIZE(sval); ALLOCATE(val(nq))
    1693   lerr = .FALSE.; DO iq=1, nq; val(iq)=str2bool(sval(iq)); END DO
    1694 END FUNCTION getKeyByName_lm
    1695 !==============================================================================================================================
    1696 LOGICAL FUNCTION getKey_lm(keyn, val, ky, nam) RESULT(lerr)
    1697   USE strings_mod, ONLY: str2bool
    1698   CHARACTER(LEN=*),                             INTENT(IN)  :: keyn
     2027  REAL,                  OPTIONAL,              INTENT(IN)  ::  def
     2028  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     2029!------------------------------------------------------------------------------------------------------------------------------
     2030  CHARACTER(LEN=maxlen) :: s
     2031  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:), tname(:)
     2032  LOGICAL,               ALLOCATABLE ::    ll(:)
     2033  IF(     PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, real2str(def), lDisp)
     2034  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, lDisp=lDisp)
     2035  IF(lerr) RETURN
     2036  val = str2real(svals)
     2037  ll = val == -HUGE(1.)
     2038  lerr = ANY(ll); IF(.NOT.lerr) THEN; IF(PRESENT(nam)) nam = tname; RETURN; END IF
     2039  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(PACK(tname, MASK=ll)))//' is not a'
     2040  CALL msg(TRIM(s)//' a real: '//TRIM(strStack(svals, MASK=ll)), modname)
     2041END FUNCTION getKeyByIndex_rmmm
     2042!==============================================================================================================================
     2043LOGICAL FUNCTION getKeyByIndex_lmmm(keyn, val, ky, nam, def, lDisp) RESULT(lerr)
     2044  CHARACTER(LEN=*),                             INTENT(IN)  :: keyn(:)
    16992045  LOGICAL,                         ALLOCATABLE, INTENT(OUT) ::  val(:)
    17002046  TYPE(keys_type),       OPTIONAL,              INTENT(IN)  ::   ky(:)
    17012047  CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) ::  nam(:)
    1702 !------------------------------------------------------------------------------------------------------------------------------
    1703   CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:)
     2048  LOGICAL,               OPTIONAL,              INTENT(IN)  ::  def
     2049  LOGICAL,               OPTIONAL,              INTENT(IN)  :: lDisp
     2050!------------------------------------------------------------------------------------------------------------------------------
     2051  CHARACTER(LEN=maxlen) :: s
     2052  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:), tname(:)
     2053  LOGICAL,               ALLOCATABLE ::    ll(:)
     2054  INTEGER,               ALLOCATABLE :: ivals(:)
     2055  IF(     PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, bool2str(def), lDisp)
     2056  IF(.NOT.PRESENT(def)) lerr = getKeyByIndex_smmm(keyn, svals, ky, tname, lDisp=lDisp)
     2057  IF(lerr) RETURN
     2058  ivals = str2bool(svals)
     2059  ll = ivals == -1
     2060  lerr = ANY(ll); IF(.NOT.lerr) THEN; val = ivals == 1; IF(PRESENT(nam)) nam = tname; RETURN; END IF
     2061  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(tname, MASK=ll))//' is not'
     2062  CALL msg(TRIM(s)//' a boolean: '//TRIM(strStack(svals, MASK=ll)), modname)
     2063END FUNCTION getKeyByIndex_lmmm
     2064!==============================================================================================================================
     2065
     2066
     2067
     2068!==============================================================================================================================
     2069!===                                           GET KEYS VALUES FROM TRACERS NAMES                                           ===
     2070!==============================================================================================================================
     2071!=== TRY TO GET THE KEY NAMED "key" FOR THE TRACER NAMED "tname" IN:                                                        ===
     2072!===  * ARGUMENT "ky" DATABASE IF SPECIFIED ; OTHERWISE:                                                                    ===
     2073!===  * IN INTERNAL TRACERS DATABASE "tracers(:)%keys" (IF UNFOUND, IN INTERNAL ISOTOPES DATABASE "isotope%keys(:)")        ===
     2074!=== THE RETURNED VALUE (STRING, AN INTEGER, A REAL OR A LOGICAL) CAN BE EITHER:                                            ===
     2075!===  * A SCALAR                                                                                                            ===
     2076!===  * A VECTOR, WHICH IS THE FOUND VALUE PARSED WITH THE SEPARATOR ","                                                    ===
     2077!===                                                                                                                        ===
     2078!=== SYNTAX:       lerr = getKeyByName_{sirl}{1m}{1m}1(keyn[(:)], val[(:)], tname  [, ky(:)][, def][, lDisp])               ===
     2079!==============================================================================================================================
     2080!=== IF "tname(:)" IS A VECTOR, THE RETURNED VALUES (ONE EACH "tname(:)" ELEMENT) ARE STORED IN THE VECTOR "val(:)"         ===
     2081!===                                                                                                                        ===
     2082!=== SYNTAX        lerr = getKeyByName_{sirl}{1m}mm   (keyn[(:)], val (:), tname(:)[, ky(:)][, def][, lDisp])               ===
     2083!==============================================================================================================================
     2084LOGICAL FUNCTION getKeyByName_s111(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2085  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2086  CHARACTER(LEN=maxlen),     INTENT(OUT) :: val
     2087  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2088  CHARACTER(LEN=*),OPTIONAL, INTENT(IN)  :: def
     2089  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2090  lerr = getKeyByName_sm11([keyn], val, tname, ky, def, lDisp)
     2091END FUNCTION getKeyByName_s111
     2092!==============================================================================================================================
     2093LOGICAL FUNCTION getKeyByName_i111(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2094  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2095  INTEGER,                   INTENT(OUT) :: val
     2096  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2097  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     2098  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2099  lerr = getKeyByName_im11([keyn], val, tname, ky, def, lDisp)
     2100END FUNCTION getKeyByName_i111
     2101!==============================================================================================================================
     2102LOGICAL FUNCTION getKeyByName_r111(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2103  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2104  REAL   ,                   INTENT(OUT) :: val
     2105  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2106  REAL,            OPTIONAL, INTENT(IN)  :: def
     2107  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2108  lerr = getKeyByName_rm11([keyn], val, tname, ky, def, lDisp)
     2109END FUNCTION getKeyByName_r111
     2110!==============================================================================================================================
     2111LOGICAL FUNCTION getKeyByName_l111(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2112  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2113  LOGICAL,                   INTENT(OUT) :: val
     2114  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2115  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     2116  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2117  lerr = getKeyByName_lm11([keyn], val, tname, ky, def, lDisp)
     2118END FUNCTION getKeyByName_l111
     2119!==============================================================================================================================
     2120!==============================================================================================================================
     2121LOGICAL FUNCTION getKeyByName_sm11(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2122  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2123  CHARACTER(LEN=maxlen),     INTENT(OUT) :: val
     2124  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2125  CHARACTER(LEN=*),OPTIONAL, INTENT(IN)  :: def
     2126  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2127!------------------------------------------------------------------------------------------------------------------------------
     2128  CHARACTER(LEN=maxlen) :: s, tnam
     2129  LOGICAL :: lD
     2130  lD = .TRUE.; IF(PRESENT(lDisp)) lD = lDisp
     2131  s = 'key "'//TRIM(strStack(keyn, '/'))//'" for "'//TRIM(tname)//'"'
     2132  lerr = .TRUE.
     2133  tnam = strHead(delPhase(tname),'_',.TRUE.)                                             !--- Remove phase and tag
     2134  IF(lerr .AND. PRESENT(ky))         val = fgetKey(ky)                                   !--- "ky"
     2135  IF(lerr .AND. ALLOCATED (tracers)) val = fgetKey(tracers(:)%keys)                      !--- "tracers"
     2136  IF(lerr .AND. ASSOCIATED(isotope)) val = fgetKey(isotope%keys(:))                      !--- "isotope"
     2137  IF(lerr .AND. PRESENT(def)) THEN
     2138     val = def; lerr = .NOT.PRESENT(def)
     2139     CALL msg('Using defaut value of '//TRIM(s)//': '//TRIM(def), modname, lD)
     2140  END IF
     2141  CALL msg('No '//TRIM(s)//' or out of bounds index', modname, lD .AND. lerr)
     2142
     2143CONTAINS
     2144
     2145 CHARACTER(LEN=maxlen) FUNCTION fgetKey(ky) RESULT(val)
     2146  TYPE(keys_type),  INTENT(IN)  :: ky(:)
     2147  lerr = SIZE(ky) == 0
     2148  IF(lerr) RETURN
     2149           val = fgetKeyIdx(strIdx(ky%name, tname), [keyn], ky, lerr)
     2150  IF(lerr) val = fgetKeyIdx(strIdx(ky%name, tnam ), [keyn], ky, lerr)
     2151
     2152END FUNCTION fgetKey
     2153
     2154END FUNCTION getKeyByName_sm11
     2155!==============================================================================================================================
     2156LOGICAL FUNCTION getKeyByName_im11(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2157  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2158  INTEGER,                   INTENT(OUT) :: val
     2159  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2160  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     2161  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2162!------------------------------------------------------------------------------------------------------------------------------
     2163  CHARACTER(LEN=maxlen) :: sval, s
     2164  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, int2str(def), lDisp)
     2165  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2166  IF(lerr) RETURN
     2167  val = str2int(sval)
     2168  lerr = val == -HUGE(1)
     2169  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2170  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     2171END FUNCTION getKeyByName_im11
     2172!==============================================================================================================================
     2173LOGICAL FUNCTION getKeyByName_rm11(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2174  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2175  REAL   ,                   INTENT(OUT) :: val
     2176  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2177  REAL,            OPTIONAL, INTENT(IN)  :: def
     2178  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2179!------------------------------------------------------------------------------------------------------------------------------
     2180  CHARACTER(LEN=maxlen) :: sval, s
     2181  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, real2str(def), lDisp)
     2182  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2183  IF(lerr) RETURN
     2184  val = str2real(sval)
     2185  lerr = val == -HUGE(1.)
     2186  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2187  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     2188END FUNCTION getKeyByName_rm11
     2189!==============================================================================================================================
     2190LOGICAL FUNCTION getKeyByName_lm11(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2191  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2192  LOGICAL,                   INTENT(OUT) :: val
     2193  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2194  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     2195  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2196!------------------------------------------------------------------------------------------------------------------------------
     2197  CHARACTER(LEN=maxlen) :: sval, s
     2198  INTEGER               :: ival
     2199  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, bool2str(def), lDisp)
     2200  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2201  IF(lerr) RETURN
     2202  ival = str2bool(sval)
     2203  lerr = ival == -1
     2204  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2205  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     2206  IF(.NOT.lerr) val = ival == 1
     2207END FUNCTION getKeyByName_lm11
     2208!==============================================================================================================================
     2209!==============================================================================================================================
     2210LOGICAL FUNCTION getKeyByName_s1m1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2211  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn, tname
     2212  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:)
     2213  TYPE(keys_type),          OPTIONAL, INTENT(IN)  :: ky(:)
     2214  CHARACTER(LEN=*),         OPTIONAL, INTENT(IN)  :: def
     2215  LOGICAL,                  OPTIONAL, INTENT(IN)  :: lDisp
     2216!------------------------------------------------------------------------------------------------------------------------------
     2217  CHARACTER(LEN=maxlen)              :: sval
     2218  lerr = getKeyByName_sm11([keyn], sval, tname, ky, def, lDisp); IF(lerr) RETURN
     2219  lerr = strParse(sval, ',', val)
     2220  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2221END FUNCTION getKeyByName_s1m1
     2222!==============================================================================================================================
     2223LOGICAL FUNCTION getKeyByName_i1m1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2224  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2225  INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2226  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2227  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     2228  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2229!------------------------------------------------------------------------------------------------------------------------------
     2230  CHARACTER(LEN=maxlen)              :: sval, s
     2231  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2232  IF(     PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, int2str(def), lDisp)
     2233  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, lDisp=lDisp)
     2234  IF(lerr) RETURN
     2235  lerr = strParse(sval, ',', svals)
     2236  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2237  val = str2int(svals)
     2238  lerr = ANY(val == -HUGE(1))
     2239  s = 'key "'//TRIM(keyn)//'" of '//TRIM(tname)//' is not'
     2240  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     2241END FUNCTION getKeyByName_i1m1
     2242!==============================================================================================================================
     2243LOGICAL FUNCTION getKeyByName_r1m1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2244  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2245  REAL,         ALLOCATABLE, INTENT(OUT) :: val(:)
     2246  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2247  REAL,            OPTIONAL, INTENT(IN)  :: def
     2248  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2249!------------------------------------------------------------------------------------------------------------------------------
     2250  CHARACTER(LEN=maxlen)              :: sval, s
     2251  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2252  IF(     PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, real2str(def), lDisp)
     2253  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, lDisp=lDisp)
     2254  IF(lerr) RETURN
     2255  lerr = strParse(sval, ',', svals)
     2256  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2257  val = str2real(svals)
     2258  lerr = ANY(val == -HUGE(1.))
     2259  s = 'key "'//TRIM(keyn)//'" of '//TRIM(tname)//' is not'
     2260  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     2261END FUNCTION getKeyByName_r1m1
     2262!==============================================================================================================================
     2263LOGICAL FUNCTION getKeyByName_l1m1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2264  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname
     2265  LOGICAL,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2266  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2267  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     2268  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2269!------------------------------------------------------------------------------------------------------------------------------
     2270  CHARACTER(LEN=maxlen)              :: sval, s
     2271  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2272  INTEGER,               ALLOCATABLE :: ivals(:)
     2273  IF(     PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, bool2str(def), lDisp)
     2274  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11([keyn], sval, tname, ky, lDisp=lDisp)
     2275  IF(lerr) RETURN
     2276  lerr = strParse(sval, ',', svals)
     2277  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2278  ivals = str2bool(svals)
     2279  lerr = ANY(ivals == -1)
     2280  s = 'key "'//TRIM(keyn)//'" of '//TRIM(tname)//' is not'
     2281  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     2282  IF(.NOT.lerr) val = ivals == 1
     2283END FUNCTION getKeyByName_l1m1
     2284!==============================================================================================================================
     2285!==============================================================================================================================
     2286LOGICAL FUNCTION getKeyByName_smm1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2287  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn(:), tname
     2288  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:)
     2289  TYPE(keys_type),          OPTIONAL, INTENT(IN)  :: ky(:)
     2290  CHARACTER(LEN=*),         OPTIONAL, INTENT(IN)  :: def
     2291  LOGICAL,                  OPTIONAL, INTENT(IN)  :: lDisp
     2292!------------------------------------------------------------------------------------------------------------------------------
     2293  CHARACTER(LEN=maxlen) :: sval
     2294  lerr = getKeyByName_sm11(keyn, sval, tname, ky, def, lDisp); IF(lerr) RETURN
     2295  lerr = strParse(sval, ',', val)
     2296  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2297END FUNCTION getKeyByName_smm1
     2298!==============================================================================================================================
     2299LOGICAL FUNCTION getKeyByName_imm1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2300  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2301  INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2302  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2303  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     2304  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2305!------------------------------------------------------------------------------------------------------------------------------
     2306  CHARACTER(LEN=maxlen)              :: sval, s
     2307  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2308  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, int2str(def), lDisp)
     2309  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2310  IF(lerr) RETURN
     2311  lerr = strParse(sval, ',', svals)
     2312  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2313  val = str2int(svals)
     2314  lerr = ANY(val == -HUGE(1))
     2315  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2316  CALL msg(TRIM(s)//' an integer: '//TRIM(sval), modname, lerr)
     2317END FUNCTION getKeyByName_imm1
     2318!==============================================================================================================================
     2319LOGICAL FUNCTION getKeyByName_rmm1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2320  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2321  REAL,         ALLOCATABLE, INTENT(OUT) :: val(:)
     2322  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2323  REAL,            OPTIONAL, INTENT(IN)  :: def
     2324  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2325!------------------------------------------------------------------------------------------------------------------------------
     2326  CHARACTER(LEN=maxlen)              :: sval, s
     2327  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2328  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, real2str(def), lDisp)
     2329  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2330  IF(lerr) RETURN
     2331  lerr = strParse(sval, ',', svals)
     2332  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2333  val = str2real(svals)
     2334  lerr = ANY(val == -HUGE(1.))
     2335  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2336  CALL msg(TRIM(s)//' a real: '//TRIM(sval), modname, lerr)
     2337END FUNCTION getKeyByName_rmm1
     2338!==============================================================================================================================
     2339LOGICAL FUNCTION getKeyByName_lmm1(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2340  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname
     2341  LOGICAL,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2342  TYPE(keys_type), OPTIONAL, INTENT(IN)  :: ky(:)
     2343  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     2344  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2345!------------------------------------------------------------------------------------------------------------------------------
     2346  CHARACTER(LEN=maxlen)              :: sval, s
     2347  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2348  INTEGER,               ALLOCATABLE :: ivals(:)
     2349  IF(     PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, bool2str(def), lDisp)
     2350  IF(.NOT.PRESENT(def)) lerr = getKeyByName_sm11(keyn, sval, tname, ky, lDisp=lDisp)
     2351  IF(lerr) RETURN
     2352  lerr = strParse(sval, ',', svals)
     2353  IF(fmsg('can''t parse '//TRIM(sval), modname, lerr)) RETURN
     2354  ivals = str2bool(svals)
     2355  lerr = ANY(ivals == -1)
     2356  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(tname)//' is not'
     2357  CALL msg(TRIM(s)//' a boolean: '//TRIM(sval), modname, lerr)
     2358  IF(.NOT.lerr) val = ivals == 1
     2359END FUNCTION getKeyByName_lmm1
     2360!==============================================================================================================================
     2361!==============================================================================================================================
     2362LOGICAL FUNCTION getKeyByName_s1mm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2363  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn, tname(:)
     2364  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:)
     2365  TYPE(keys_type),       OPTIONAL,    INTENT(IN)  ::  ky(:)
     2366  CHARACTER(LEN=*),      OPTIONAL,    INTENT(IN)  :: def
     2367  LOGICAL,               OPTIONAL,    INTENT(IN)  :: lDisp
     2368  lerr = getKeyByName_smmm([keyn], val, tname, ky, def, lDisp)
     2369END FUNCTION getKeyByName_s1mm
     2370!==============================================================================================================================
     2371LOGICAL FUNCTION getKeyByName_i1mm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2372  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname(:)
     2373  INTEGER,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2374  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::  ky(:)
     2375  INTEGER,         OPTIONAL, INTENT(IN)  :: def
     2376  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2377  lerr = getKeyByName_immm([keyn], val, tname, ky, def, lDisp)
     2378END FUNCTION getKeyByName_i1mm
     2379!==============================================================================================================================
     2380LOGICAL FUNCTION getKeyByName_r1mm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2381  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname(:)
     2382  REAL,         ALLOCATABLE, INTENT(OUT) :: val(:)
     2383  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::  ky(:)
     2384  REAL,            OPTIONAL, INTENT(IN)  :: def
     2385  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2386  lerr = getKeyByName_rmmm([keyn], val, tname, ky, def, lDisp)
     2387END FUNCTION getKeyByName_r1mm
     2388!==============================================================================================================================
     2389LOGICAL FUNCTION getKeyByName_l1mm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2390  CHARACTER(LEN=*),          INTENT(IN)  :: keyn, tname(:)
     2391  LOGICAL,      ALLOCATABLE, INTENT(OUT) :: val(:)
     2392  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::  ky(:)
     2393  LOGICAL,         OPTIONAL, INTENT(IN)  :: def
     2394  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2395  lerr = getKeyByName_lmmm([keyn], val, tname, ky, def, lDisp)
     2396END FUNCTION getKeyByName_l1mm
     2397!==============================================================================================================================
     2398!==============================================================================================================================
     2399LOGICAL FUNCTION getKeyByName_smmm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2400  CHARACTER(LEN=*),                   INTENT(IN)  :: keyn(:), tname(:)
     2401  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) ::  val(:)
     2402  TYPE(keys_type),       OPTIONAL,    INTENT(IN)  ::   ky(:)
     2403  CHARACTER(LEN=*),      OPTIONAL,    INTENT(IN)  ::   def
     2404  LOGICAL,               OPTIONAL,    INTENT(IN)  :: lDisp
     2405!------------------------------------------------------------------------------------------------------------------------------
     2406  CHARACTER(LEN=maxlen) :: s
    17042407  INTEGER :: iq, nq
    1705   IF(test(getKey_sm(keyn, sval, ky, nam), lerr)) RETURN
    1706   nq = SIZE(sval); ALLOCATE(val(nq))
    1707   lerr = .FALSE.; DO iq=1, nq; val(iq)=str2bool(sval(iq)); END DO
    1708 END FUNCTION getKey_lm
     2408  LOGICAL :: lD
     2409  nq = SIZE(tname); ALLOCATE(val(nq))
     2410  lD = .TRUE.; IF(PRESENT(lDisp)) lD = lDisp
     2411  s = 'key "'//TRIM(strStack(keyn, '/'))//'"'
     2412  lerr = .TRUE.
     2413  IF(PRESENT(ky)) THEN;                 val = fgetKey(ky)                                !--- "ky"
     2414  ELSE IF(ALLOCATED(tracers)) THEN;     val = fgetKey(tracers(:)%keys)                   !--- "tracers"
     2415     IF(lerr .AND. ASSOCIATED(isotope)) val = fgetKey(isotope%keys(:))                   !--- "isotope"
     2416  END IF
     2417  IF(.NOT.PRESENT(def)) THEN; CALL msg('No '//TRIM(s)//' found', modname, lD); RETURN; END IF
     2418
     2419  !--- DEFAULT VALUE
     2420  val = [(def, iq = 1, SIZE(tname))]
     2421  CALL msg('Using defaut value for '//TRIM(s)//': '//TRIM(def), modname, lD)
     2422
     2423CONTAINS
     2424
     2425FUNCTION fgetKey(ky) RESULT(val)
     2426  CHARACTER(LEN=maxlen), ALLOCATABLE :: val(:)
     2427  TYPE(keys_type),       INTENT(IN)  :: ky(:)
     2428  LOGICAL,               ALLOCATABLE :: ler(:)
     2429  lerr = SIZE(ky) == 0; IF(lerr) RETURN
     2430  ALLOCATE(ler(SIZE(tname)))
     2431  val = [(fgetKeyIdx(strIdx(ky(:)%name, tname(iq)), keyn, ky, ler(iq)), iq = 1, SIZE(tname))]
     2432  lerr = ANY(ler)
     2433END FUNCTION fgetKey
     2434
     2435END FUNCTION getKeyByName_smmm
     2436!==============================================================================================================================
     2437LOGICAL FUNCTION getKeyByName_immm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2438  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname(:)
     2439  INTEGER,      ALLOCATABLE, INTENT(OUT) ::  val(:)
     2440  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::   ky(:)
     2441  INTEGER,         OPTIONAL, INTENT(IN)  ::  def
     2442  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2443!------------------------------------------------------------------------------------------------------------------------------
     2444  CHARACTER(LEN=maxlen) :: s
     2445  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2446  LOGICAL,               ALLOCATABLE ::    ll(:)
     2447  IF(     PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, int2str(def), lDisp)
     2448  IF(.NOT.PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, lDisp=lDisp)
     2449  IF(lerr) RETURN
     2450  val = str2int(svals)
     2451  ll = val == -HUGE(1)
     2452  lerr = ANY(ll); IF(.NOT.lerr) RETURN
     2453  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(tname, MASK=ll))//' is not'
     2454  CALL msg(TRIM(s)//' an integer: '//TRIM(strStack(svals, MASK=ll)), modname)
     2455END FUNCTION getKeyByName_immm
     2456!==============================================================================================================================
     2457LOGICAL FUNCTION getKeyByName_rmmm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2458  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname(:)
     2459  REAL,         ALLOCATABLE, INTENT(OUT) ::  val(:)
     2460  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::   ky(:)
     2461  REAL,            OPTIONAL, INTENT(IN)  ::  def
     2462  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2463!------------------------------------------------------------------------------------------------------------------------------
     2464  CHARACTER(LEN=maxlen) :: s
     2465  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2466  LOGICAL,               ALLOCATABLE ::    ll(:)
     2467  IF(     PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, real2str(def), lDisp)
     2468  IF(.NOT.PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, lDisp=lDisp)
     2469  IF(lerr) RETURN
     2470  val = str2real(svals)
     2471  ll = val == -HUGE(1.)
     2472  lerr = ANY(ll); IF(.NOT.lerr) RETURN
     2473  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(tname, MASK=ll))//' is not'
     2474  CALL msg(TRIM(s)//' a real: '//TRIM(strStack(svals, MASK=ll)), modname)
     2475END FUNCTION getKeyByName_rmmm
     2476!==============================================================================================================================
     2477LOGICAL FUNCTION getKeyByName_lmmm(keyn, val, tname, ky, def, lDisp) RESULT(lerr)
     2478  CHARACTER(LEN=*),          INTENT(IN)  :: keyn(:), tname(:)
     2479  LOGICAL,      ALLOCATABLE, INTENT(OUT) ::  val(:)
     2480  TYPE(keys_type), OPTIONAL, INTENT(IN)  ::   ky(:)
     2481  LOGICAL,         OPTIONAL, INTENT(IN)  ::  def
     2482  LOGICAL,         OPTIONAL, INTENT(IN)  :: lDisp
     2483!------------------------------------------------------------------------------------------------------------------------------
     2484  CHARACTER(LEN=maxlen) :: s
     2485  CHARACTER(LEN=maxlen), ALLOCATABLE :: svals(:)
     2486  LOGICAL,               ALLOCATABLE ::    ll(:)
     2487  INTEGER,               ALLOCATABLE :: ivals(:)
     2488  IF(     PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, bool2str(def), lDisp)
     2489  IF(.NOT.PRESENT(def)) lerr = getKeyByName_smmm(keyn, svals, tname, ky, lDisp=lDisp)
     2490  IF(lerr) RETURN
     2491  ivals = str2bool(svals)
     2492  ll = ivals == -1
     2493  lerr = ANY(ll); IF(.NOT.lerr) THEN; val = ivals == 1; RETURN; END IF
     2494  s = 'key "'//TRIM(strStack(keyn, '/'))//'" of '//TRIM(strStack(tname, MASK=ll))//' is not'
     2495  CALL msg(TRIM(s)//' a boolean: '//TRIM(strStack(svals, MASK=ll)), modname)
     2496END FUNCTION getKeyByName_lmmm
    17092497!==============================================================================================================================
    17102498
     
    18082596  IF(.NOT.PRESENT(phases)) out = [( addPhase_i1(s(k), ipha, known_phases), k=1, SIZE(s) )]
    18092597END FUNCTION addPhase_im
     2598!==============================================================================================================================
     2599
     2600
     2601!==============================================================================================================================
     2602!=== APPEND TRACERS DATABASE "tracs" WITH TRACERS/KEYS "tname"/"keys" ; SAME FOR INTERNAL DATABASE "tracers" ==================
     2603!==============================================================================================================================
     2604LOGICAL FUNCTION addTracer_1(tname, keys, tracs) RESULT(lerr)
     2605  CHARACTER(LEN=*),             INTENT(IN)    :: tname
     2606  TYPE(keys_type),              INTENT(IN)    ::  keys
     2607  TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tracs(:)
     2608  TYPE(trac_type), ALLOCATABLE :: tr(:)
     2609  CHARACTER(LEN=maxlen), ALLOCATABLE :: tnames(:)
     2610  INTEGER :: nt, ix
     2611  IF(ALLOCATED(tracs)) THEN
     2612     lerr = getKey('name', tnames, ky=tracs(:)%keys); IF(lerr) RETURN
     2613     nt = SIZE(tracs)
     2614     ix = strIdx(tnames, tname)
     2615     CALL msg('Modifying existing tracer "'//TRIM(tname)//'"', modname, ix /= 0)
     2616     CALL msg('Appending with tracer "'    //TRIM(tname)//'"', modname, ix == 0)
     2617     IF(ix == 0) THEN
     2618        ix = nt+1; ALLOCATE(tr(nt+1)); tr(1:nt) = tracs(1:nt); CALL MOVE_ALLOC(FROM=tr, TO=tracs)
     2619     END IF
     2620  ELSE
     2621     CALL msg('Creating a tracer descriptor with tracer "'//TRIM(tname)//'"', modname)
     2622     ix = 1; ALLOCATE(tracs(1))
     2623  END IF
     2624  CALL addKey('name', tname, tracs(ix)%keys)
     2625  tracs(ix)%name = tname
     2626  tracs(ix)%keys = keys
     2627
     2628END FUNCTION addTracer_1
     2629!==============================================================================================================================
     2630LOGICAL FUNCTION addTracer_1def(tname, keys) RESULT(lerr)
     2631  CHARACTER(LEN=*),             INTENT(IN)    :: tname
     2632  TYPE(keys_type),              INTENT(IN)    ::  keys
     2633  lerr = addTracer_1(tname, keys, tracers)
     2634END FUNCTION addTracer_1def
     2635!==============================================================================================================================
     2636
     2637
     2638!==============================================================================================================================
     2639LOGICAL FUNCTION delTracer_1(tname, tracs) RESULT(lerr)
     2640  CHARACTER(LEN=*),                     INTENT(IN)    :: tname
     2641  TYPE(trac_type), ALLOCATABLE, TARGET, INTENT(INOUT) :: tracs(:)
     2642  TYPE(trac_type), ALLOCATABLE :: tr(:)
     2643  CHARACTER(LEN=maxlen), ALLOCATABLE :: tnames(:)
     2644  INTEGER :: nt, ix
     2645  lerr = .NOT.ALLOCATED(tracs)
     2646  IF(fmsg('Can''t remove tracer "'//TRIM(tname)//'" from an empty tracers descriptor', modname, lerr)) RETURN
     2647  nt = SIZE(tracs)
     2648  lerr = getKey('name', tnames, ky=tracs(:)%keys); IF(lerr) RETURN
     2649  ix = strIdx(tnames, tname)
     2650  CALL msg('Removing tracer "'             //TRIM(tname)//'"', modname, ix /= 0)
     2651  CALL msg('Can''t remove unknown tracer "'//TRIM(tname)//'"', modname, ix == 0)
     2652  IF(ix /= 0) THEN
     2653     ALLOCATE(tr(nt-1)); tr(1:ix-1) = tracs(1:ix-1); tr(ix:nt-1) = tracs(ix+1:nt); CALL MOVE_ALLOC(FROM=tr, TO=tracs)
     2654  END IF
     2655END FUNCTION delTracer_1
     2656!==============================================================================================================================
     2657LOGICAL FUNCTION delTracer_1def(tname) RESULT(lerr)
     2658  CHARACTER(LEN=*), INTENT(IN) :: tname
     2659  lerr = delTracer(tname, tracers)
     2660END FUNCTION delTracer_1def
    18102661!==============================================================================================================================
    18112662
     
    19082759!==============================================================================================================================
    19092760
    1910 
    1911 !==============================================================================================================================
    1912 !=== GET THE NAME(S) OF THE ANCESTOR(S) OF TRACER(S) "tname" AT GENERATION "igen"  IN THE TRACERS DESCRIPTORS LIST "tr" =======
    1913 !==============================================================================================================================
    1914 SUBROUTINE ancestor_1(t, out, tname, igen)
    1915   TYPE(trac_type),       INTENT(IN)  :: t(:)
    1916   CHARACTER(LEN=maxlen), INTENT(OUT) :: out
    1917   CHARACTER(LEN=*),      INTENT(IN)  :: tname
    1918   INTEGER,     OPTIONAL, INTENT(IN)  :: igen
    1919 !------------------------------------------------------------------------------------------------------------------------------
    1920   INTEGER :: ix
    1921   CALL idxAncestor_1(t, ix, tname, igen)
    1922   out = ''; IF(ix /= 0) out = t(ix)%name
    1923 END SUBROUTINE ancestor_1
    1924 !==============================================================================================================================
    1925 SUBROUTINE ancestor_mt(t, out, tname, igen)
    1926   TYPE(trac_type),       INTENT(IN)  :: t(:)
    1927   CHARACTER(LEN=*),      INTENT(IN)  :: tname(:)
    1928   CHARACTER(LEN=maxlen), INTENT(OUT) :: out(SIZE(tname))
    1929   INTEGER,     OPTIONAL, INTENT(IN)  :: igen
    1930 !------------------------------------------------------------------------------------------------------------------------------
    1931   INTEGER :: ix(SIZE(tname))
    1932   CALL idxAncestor_mt(t, ix, tname, igen)
    1933   out(:) = ''; WHERE(ix /= 0) out = t(ix)%name
    1934 END SUBROUTINE ancestor_mt
    1935 !==============================================================================================================================
    1936 SUBROUTINE ancestor_m(t, out, igen)
    1937   TYPE(trac_type),       INTENT(IN)  :: t(:)
    1938   CHARACTER(LEN=maxlen), INTENT(OUT) :: out(SIZE(t))
    1939   INTEGER,     OPTIONAL, INTENT(IN)  :: igen
    1940 !------------------------------------------------------------------------------------------------------------------------------
    1941   INTEGER :: ix(SIZE(t))
    1942   CALL idxAncestor_m(t, ix, igen)
    1943   out(:) = ''; WHERE(ix /= 0) out = t(ix)%name
    1944 END SUBROUTINE ancestor_m
    1945 !==============================================================================================================================
    1946 
    1947 
    1948 !==============================================================================================================================
    1949 !=== GET THE INDEX(ES) OF THE GENERATION "igen" ANCESTOR(S) OF "tname" (t%name IF UNSPECIFIED) IN THE "t" LIST ================
    1950 !==============================================================================================================================
    1951 SUBROUTINE idxAncestor_1(t, idx, tname, igen)
    1952   TYPE(trac_type),   INTENT(IN)  :: t(:)
    1953   INTEGER,           INTENT(OUT) :: idx
    1954   CHARACTER(LEN=*),  INTENT(IN)  :: tname
    1955   INTEGER, OPTIONAL, INTENT(IN)  :: igen
    1956   INTEGER :: ig
    1957   ig = 0; IF(PRESENT(igen)) ig = igen
    1958   idx = strIdx(t(:)%name, tname)
    1959   IF(idx == 0)                 RETURN            !--- Tracer not found
    1960   IF(t(idx)%iGeneration <= ig) RETURN            !--- Tracer has a lower generation number than asked generation 'igen"
    1961   DO WHILE(t(idx)%iGeneration > ig); idx = strIdx(t(:)%name, t(idx)%parent); END DO
    1962 END SUBROUTINE idxAncestor_1
    1963 !------------------------------------------------------------------------------------------------------------------------------
    1964 SUBROUTINE idxAncestor_mt(t, idx, tname, igen)
    1965   TYPE(trac_type),   INTENT(IN)  :: t(:)
    1966   CHARACTER(LEN=*),  INTENT(IN)  :: tname(:)
    1967   INTEGER,           INTENT(OUT) :: idx(SIZE(tname))
    1968   INTEGER, OPTIONAL, INTENT(IN)  :: igen
    1969   INTEGER :: ix
    1970   DO ix = 1, SIZE(tname); CALL idxAncestor_1(t, idx(ix), tname(ix), igen); END DO
    1971 END SUBROUTINE idxAncestor_mt
    1972 !------------------------------------------------------------------------------------------------------------------------------
    1973 SUBROUTINE idxAncestor_m(t, idx, igen)
    1974   TYPE(trac_type),   INTENT(IN)  :: t(:)
    1975   INTEGER,           INTENT(OUT) :: idx(SIZE(t))
    1976   INTEGER, OPTIONAL, INTENT(IN)  :: igen
    1977   INTEGER :: ix
    1978   DO ix = 1, SIZE(t); CALL idxAncestor_1(t, idx(ix), t(ix)%name, igen); END DO
    1979 END SUBROUTINE idxAncestor_m
    1980 !==============================================================================================================================
    1981 
    1982 
    19832761END MODULE readTracFiles_mod
  • LMDZ6/branches/cirrus/libf/misc/strings_mod.F90

    r4454 r5202  
    1010  PUBLIC :: is_numeric, bool2str, int2str, real2str, dble2str
    1111  PUBLIC :: reduceExpr, str2bool, str2int, str2real, str2dble
    12   PUBLIC :: addQuotes, checkList, removeComment, test
     12  PUBLIC :: addQuotes, checkList, removeComment
    1313
    1414  INTERFACE get_in;     MODULE PROCEDURE getin_s,  getin_i,  getin_r,  getin_l;  END INTERFACE get_in
     
    2222  INTERFACE strCount;   MODULE PROCEDURE  strCount_m1, strCount_11, strCount_1m; END INTERFACE strCount
    2323  INTERFACE strReplace; MODULE PROCEDURE strReplace_1,             strReplace_m; END INTERFACE strReplace
    24   INTERFACE cat;        MODULE PROCEDURE   horzcat_s1,  horzcat_i1,  horzcat_r1, &
    25 !                 horzcat_d1,  horzcat_dm,
    26                                            horzcat_sm,  horzcat_im,  horzcat_rm; END INTERFACE cat
    27   INTERFACE find;         MODULE PROCEDURE    strFind,    find_int,    find_boo; END INTERFACE find
     24  INTERFACE cat;        MODULE PROCEDURE  horzcat_s00, horzcat_i00, horzcat_r00,  & !horzcat_d00, &
     25                                          horzcat_s10, horzcat_i10, horzcat_r10,  & !horzcat_d10, &
     26                                          horzcat_s11, horzcat_i11, horzcat_r11,  & !horzcat_d11, &
     27                                          horzcat_s21, horzcat_i21, horzcat_r21; END INTERFACE cat !horzcat_d21
     28  INTERFACE strFind;      MODULE PROCEDURE strFind_1, strFind_m;                 END INTERFACE strFind
     29  INTERFACE find;         MODULE PROCEDURE strFind_1, strFind_m, intFind_1, intFind_m, booFind; END INTERFACE find
    2830  INTERFACE dispOutliers; MODULE PROCEDURE dispOutliers_1, dispOutliers_2; END INTERFACE dispOutliers
    2931  INTERFACE reduceExpr;   MODULE PROCEDURE   reduceExpr_1,   reduceExpr_m; END INTERFACE reduceExpr
     
    3638CONTAINS
    3739
    38 !==============================================================================================================================
    39 LOGICAL FUNCTION test(lcond, lout) RESULT(lerr)
    40   LOGICAL, INTENT(IN)  :: lcond
    41   LOGICAL, INTENT(OUT) :: lout
    42   lerr = lcond; lout = lcond
    43 END FUNCTION test
    44 !==============================================================================================================================
    45 
    4640
    4741!==============================================================================================================================
    4842SUBROUTINE init_printout(lunout_, prt_level_)
     43  IMPLICIT NONE
    4944  INTEGER, INTENT(IN) :: lunout_, prt_level_
    5045  lunout    = lunout_
     
    5853!==============================================================================================================================
    5954SUBROUTINE getin_s(nam, val, def)
    60 USE ioipsl_getincom, ONLY: getin
     55  USE ioipsl_getincom, ONLY: getin
     56  IMPLICIT NONE
    6157  CHARACTER(LEN=*), INTENT(IN)    :: nam
    6258  CHARACTER(LEN=*), INTENT(INOUT) :: val
     
    6763!==============================================================================================================================
    6864SUBROUTINE getin_i(nam, val, def)
    69 USE ioipsl_getincom, ONLY: getin
     65  USE ioipsl_getincom, ONLY: getin
     66  IMPLICIT NONE
    7067  CHARACTER(LEN=*), INTENT(IN)    :: nam
    7168  INTEGER,          INTENT(INOUT) :: val
     
    7673!==============================================================================================================================
    7774SUBROUTINE getin_r(nam, val, def)
    78 USE ioipsl_getincom, ONLY: getin
     75  USE ioipsl_getincom, ONLY: getin
     76  IMPLICIT NONE
    7977  CHARACTER(LEN=*), INTENT(IN)    :: nam
    8078  REAL,             INTENT(INOUT) :: val
     
    8583!==============================================================================================================================
    8684SUBROUTINE getin_l(nam, val, def)
    87 USE ioipsl_getincom, ONLY: getin
     85  USE ioipsl_getincom, ONLY: getin
     86  IMPLICIT NONE
    8887  CHARACTER(LEN=*), INTENT(IN)    :: nam
    8988  LOGICAL,          INTENT(INOUT) :: val
     
    9998!==============================================================================================================================
    10099SUBROUTINE msg_1(str, modname, ll, unit)
     100  IMPLICIT NONE
    101101  !--- Display a simple message "str". Optional parameters:
    102102  !    * "modname": module name, displayed in front of the message (with ": " separator) if present.
     
    118118!==============================================================================================================================
    119119SUBROUTINE msg_m(str, modname, ll, unit, nmax)
     120  IMPLICIT NONE
    120121  !--- Same as msg_1 with multiple strings that are stacked (separator: coma) on up to "nmax" full lines.
    121122  CHARACTER(LEN=*),           INTENT(IN) :: str(:)
     
    138139!==============================================================================================================================
    139140LOGICAL FUNCTION fmsg_1(str, modname, ll, unit) RESULT(l)
     141  IMPLICIT NONE
    140142  CHARACTER(LEN=*),           INTENT(IN) :: str
    141143  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: modname
     
    152154!==============================================================================================================================
    153155LOGICAL FUNCTION fmsg_m(str, modname, ll, unit, nmax) RESULT(l)
     156  IMPLICIT NONE
    154157  CHARACTER(LEN=*),           INTENT(IN)  :: str(:)
    155158  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: modname
     
    173176!==============================================================================================================================
    174177ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION strLower(str) RESULT(out)
     178  IMPLICIT NONE
    175179  CHARACTER(LEN=*), INTENT(IN) :: str
    176180  INTEGER :: k
     
    182186!==============================================================================================================================
    183187ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION strUpper(str) RESULT(out)
     188  IMPLICIT NONE
    184189  CHARACTER(LEN=*), INTENT(IN) :: str
    185190  INTEGER :: k
     
    199204!==============================================================================================================================
    200205CHARACTER(LEN=maxlen) FUNCTION strHead_1(str, sep, lBackward) RESULT(out)
     206  IMPLICIT NONE
    201207  CHARACTER(LEN=*),           INTENT(IN) :: str
    202208  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep
     
    214220!==============================================================================================================================
    215221FUNCTION strHead_m(str, sep, lBackward) RESULT(out)
     222  IMPLICIT NONE
    216223  CHARACTER(LEN=maxlen),     ALLOCATABLE :: out(:)
    217224  CHARACTER(LEN=*),           INTENT(IN) :: str(:)
     
    235242!==============================================================================================================================
    236243CHARACTER(LEN=maxlen) FUNCTION strTail_1(str, sep, lBackWard) RESULT(out)
     244  IMPLICIT NONE
    237245  CHARACTER(LEN=*),           INTENT(IN) :: str
    238246  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep
     
    250258!==============================================================================================================================
    251259FUNCTION strTail_m(str, sep, lBackWard) RESULT(out)
     260  IMPLICIT NONE
    252261  CHARACTER(LEN=maxlen),     ALLOCATABLE :: out(:)
    253262  CHARACTER(LEN=*),           INTENT(IN) :: str(:)
     
    271280!==============================================================================================================================
    272281FUNCTION strStack(str, sep, mask) RESULT(out)
     282  IMPLICIT NONE
    273283  CHARACTER(LEN=:),          ALLOCATABLE :: out
    274284  CHARACTER(LEN=*),           INTENT(IN) :: str(:)
     
    292302!==============================================================================================================================
    293303FUNCTION strStackm(str, sep, nmax) RESULT(out)
     304  IMPLICIT NONE
    294305  CHARACTER(LEN=maxlen),     ALLOCATABLE :: out(:)
    295306  CHARACTER(LEN=*),           INTENT(IN) :: str(:)
     
    324335!==============================================================================================================================
    325336SUBROUTINE strClean_1(str)
     337  IMPLICIT NONE
    326338  CHARACTER(LEN=*), INTENT(INOUT) :: str
    327339  INTEGER :: k, n, m
     
    337349!==============================================================================================================================
    338350SUBROUTINE strClean_m(str)
     351  IMPLICIT NONE
    339352  CHARACTER(LEN=*), INTENT(INOUT) :: str(:)
    340353  INTEGER :: k
     
    349362!==============================================================================================================================
    350363SUBROUTINE strReduce_1(str, nb)
     364  IMPLICIT NONE
    351365  CHARACTER(LEN=*), ALLOCATABLE, INTENT(INOUT) :: str(:)
    352366  INTEGER,          OPTIONAL,    INTENT(OUT)   :: nb
     
    366380!==============================================================================================================================
    367381SUBROUTINE strReduce_2(str1, str2)
     382  IMPLICIT NONE
    368383  CHARACTER(LEN=*),   ALLOCATABLE, INTENT(INOUT) :: str1(:)
    369384  CHARACTER(LEN=*),                INTENT(IN)    :: str2(:)
     
    392407!==============================================================================================================================
    393408INTEGER FUNCTION strIdx_1(str, s) RESULT(out)
     409  IMPLICIT NONE
    394410  CHARACTER(LEN=*), INTENT(IN) :: str(:), s
    395411  DO out = 1, SIZE(str); IF(str(out) == s) EXIT; END DO
     
    398414!==============================================================================================================================
    399415FUNCTION strIdx_m(str, s, n) RESULT(out)
     416  IMPLICIT NONE
    400417  CHARACTER(LEN=*),  INTENT(IN)  :: str(:), s(:)
    401418  INTEGER, OPTIONAL, INTENT(OUT) :: n
     
    412429!=== GET THE INDEX LIST OF THE ELEMENTS OF "str(:)" EQUAL TO "s" AND OPTIONALY, ITS LENGTH "n" ================================
    413430!==============================================================================================================================
    414 FUNCTION strFind(str, s, n) RESULT(out)
     431FUNCTION strFind_1(str, s, n) RESULT(out)
     432  IMPLICIT NONE
    415433  CHARACTER(LEN=*),  INTENT(IN)  :: str(:), s
    416434  INTEGER, OPTIONAL, INTENT(OUT) :: n
     
    420438  out = PACK( [(k, k=1, SIZE(str(:), DIM=1))], MASK = str(:) == s )
    421439  IF(PRESENT(n)) n = SIZE(out(:), DIM=1)
    422 END FUNCTION strFind
    423 !==============================================================================================================================
    424 FUNCTION find_int(i,j,n) RESULT(out)
     440END FUNCTION strFind_1
     441!==============================================================================================================================
     442FUNCTION strFind_m(str, s, n) RESULT(out)
     443  IMPLICIT NONE
     444  CHARACTER(LEN=*),  INTENT(IN)  :: str(:), s(:)
     445  INTEGER, OPTIONAL, INTENT(OUT) :: n
     446  INTEGER,           ALLOCATABLE :: out(:)
     447!------------------------------------------------------------------------------------------------------------------------------
     448  INTEGER :: k
     449  out = [(strFind_1(str, s(k)), k=1, SIZE(s))]
     450  IF(PRESENT(n)) n = SIZE(out(:), DIM=1)
     451END FUNCTION strFind_m
     452!==============================================================================================================================
     453FUNCTION intFind_1(i,j,n) RESULT(out)
     454  IMPLICIT NONE
    425455  INTEGER,           INTENT(IN)  :: i(:), j
    426456  INTEGER, OPTIONAL, INTENT(OUT) :: n
     
    430460  out = PACK( [(k, k=1, SIZE(i(:), DIM=1))], MASK = i(:) == j )
    431461  IF(PRESENT(n)) n = SIZE(out(:), DIM=1)
    432 END FUNCTION find_int
    433 !==============================================================================================================================
    434 FUNCTION find_boo(l,n) RESULT(out)
    435   LOGICAL,           INTENT(IN)  :: l(:)
     462END FUNCTION intFind_1
     463!==============================================================================================================================
     464FUNCTION intFind_m(i,j,n) RESULT(out)
     465  IMPLICIT NONE
     466  INTEGER,           INTENT(IN)  :: i(:), j(:)
     467  INTEGER, OPTIONAL, INTENT(OUT) :: n
     468  INTEGER,           ALLOCATABLE :: out(:)
     469!------------------------------------------------------------------------------------------------------------------------------
     470  INTEGER :: k
     471  out = [(intFind_1(i, j(k)), k=1, SIZE(j))]
     472  IF(PRESENT(n)) n = SIZE(out(:), DIM=1)
     473END FUNCTION intFind_m
     474!==============================================================================================================================
     475FUNCTION booFind(l,n) RESULT(out)
     476   IMPLICIT NONE
     477 LOGICAL,           INTENT(IN)  :: l(:)
    436478  INTEGER, OPTIONAL, INTENT(OUT) :: n
    437479  INTEGER,           ALLOCATABLE :: out(:)
     
    440482  out = PACK( [(k, k=1, SIZE(l(:), DIM=1))], MASK = l(:) )
    441483  IF(PRESENT(n)) n = SIZE(out(:), DIM=1)
    442 END FUNCTION find_boo
     484END FUNCTION booFind
    443485!==============================================================================================================================
    444486
     
    450492!==============================================================================================================================
    451493LOGICAL FUNCTION strIdx_prv(rawList, del, ibeg, idx, idel, lSc) RESULT(lerr)
     494  IMPLICIT NONE
    452495  CHARACTER(LEN=*),  INTENT(IN)  :: rawList                          !--- String in which delimiters have to be identified
    453496  CHARACTER(LEN=*),  INTENT(IN)  :: del(:)                           !--- List of delimiters
     
    469512  END IF
    470513
    471   IF(test(idx == 1 .AND. INDEX('+-',del(idel)) /= 0, lerr)) RETURN   !--- The front delimiter is different from +/-: error
    472   IF(     idx /= 1 .AND. is_numeric(rawList(ibeg:idx-1)))   RETURN   !--- The input string head is a valid number
     514  lerr = idx == 1 .AND. INDEX('+-',del(idel)) /= 0; IF(lerr) RETURN  !--- The front delimiter is different from +/-: error
     515  IF(    idx /= 1 .AND. is_numeric(rawList(ibeg:idx-1)))     RETURN  !--- The input string head is a valid number
    473516
    474517  !=== The string part in front of the 1st delimiter is not a valid number: search for next delimiter index "idx"
     
    503546!==============================================================================================================================
    504547LOGICAL FUNCTION strCount_11(rawList, delimiter, nb, lSc) RESULT(lerr)
     548  IMPLICIT NONE
    505549  CHARACTER(LEN=*),  INTENT(IN)  :: rawList
    506550  CHARACTER(LEN=*),  INTENT(IN)  :: delimiter
     
    514558!==============================================================================================================================
    515559LOGICAL FUNCTION strCount_m1(rawList, delimiter, nb, lSc) RESULT(lerr)
     560  IMPLICIT NONE
    516561  CHARACTER(LEN=*),     INTENT(IN)  :: rawList(:)
    517562  CHARACTER(LEN=*),     INTENT(IN)  :: delimiter
     
    530575!==============================================================================================================================
    531576LOGICAL FUNCTION strCount_1m(rawList, delimiter, nb, lSc) RESULT(lerr)
     577  IMPLICIT NONE
    532578  CHARACTER(LEN=*),  INTENT(IN)  :: rawList
    533579  CHARACTER(LEN=*),  INTENT(IN)  :: delimiter(:)
     
    560606!==============================================================================================================================
    561607LOGICAL FUNCTION strParse(rawList, delimiter, keys, n, vals) RESULT(lerr)
     608  IMPLICIT NONE
    562609  CHARACTER(LEN=*),                             INTENT(IN)  :: rawList, delimiter
    563610  CHARACTER(LEN=maxlen), ALLOCATABLE,           INTENT(OUT) :: keys(:)
     
    570617  r  = TRIM(ADJUSTL(rawList))
    571618  nr = LEN_TRIM(r); IF(nr == 0) THEN; keys = ['']; RETURN; END IF
    572   CALL strParse_prv(nk)                                              !--- COUNT THE ELEMENTS
    573   ALLOCATE(keys(nk))
    574   IF(PRESENT(vals)) THEN
    575     ALLOCATE(vals(nk)); CALL strParse_prv(nk, keys, vals)            !--- PARSE THE KEYS
    576   ELSE
    577     CALL strParse_prv(nk, keys)                                      !--- PARSE THE KEYS
    578   END IF
    579   IF(PRESENT(n)) n = nk
     619  nk = countK()                                                      !--- COUNT THE ELEMENTS
     620  CALL parseK(keys)                                                  !--- PARSE THE KEYS
     621  IF(PRESENT(vals)) CALL parseV(vals)                                !--- PARSE <key>=<val> PAIRS
     622  IF(PRESENT(n)) n = nk                                              !--- RETURN THE NUMBER OF KEYS
    580623
    581624CONTAINS
    582625
    583626!------------------------------------------------------------------------------------------------------------------------------
    584 SUBROUTINE strParse_prv(nkeys, keys, vals)
    585 !--- * Get the number of elements after parsing ("nkeys" only is present)
    586 !--- * Parse the <key>=<val> pairs and store result in "keys" and "vals" (already allocated)
    587   IMPLICIT NONE
    588   INTEGER,                         INTENT(OUT) :: nkeys
    589   CHARACTER(LEN=maxlen), OPTIONAL, INTENT(OUT) :: keys(:)
    590   CHARACTER(LEN=maxlen), OPTIONAL, INTENT(OUT) :: vals(:)
    591 !------------------------------------------------------------------------------------------------------------------------------
    592   INTEGER :: ib, ie
    593   nkeys = 1; ib = 1
     627INTEGER FUNCTION countK() RESULT(nkeys)
     628!--- Get the number of elements after parsing.
     629  IMPLICIT NONE
     630!------------------------------------------------------------------------------------------------------------------------------
     631  INTEGER :: ib, ie, nl
     632  nkeys = 1; ib = 1; nl = LEN(delimiter)
    594633  DO
    595634    ie = INDEX(rawList(ib:nr), delimiter)+ib-1                       !--- Determine the next separator start index
    596635    IF(ie == ib-1) EXIT
    597     IF(PRESENT(keys)) keys(nkeys) = r(ib:ie-1)                       !--- Get the ikth key
    598     IF(PRESENT(vals)) CALL parseKeys(keys(nkeys), vals(nkeys))       !--- Parse the ikth <key>=<val> pair
     636    ib = ie + nl
     637    DO WHILE(ANY([0, 9, 32] == IACHAR(r(ib:ib))) .AND. ib < nr)      !--- Skip blanks (ascii): NULL (0), TAB (9), SPACE (32)
     638      ib = ib + 1
     639    END DO     !--- Skip spaces before next chain
     640    nkeys = nkeys+1
     641  END DO
     642END FUNCTION countK
     643
     644!------------------------------------------------------------------------------------------------------------------------------
     645SUBROUTINE parseK(keys)
     646!--- Parse the string separated by "delimiter" from "rawList" into "keys(:)"
     647  IMPLICIT NONE
     648  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: keys(:)
     649!------------------------------------------------------------------------------------------------------------------------------
     650  INTEGER :: ib, ie, ik
     651  ALLOCATE(keys(nk))
     652  ib = 1
     653  DO ik = 1, nk
     654    ie = INDEX(rawList(ib:nr), delimiter)+ib-1                       !--- Determine the next separator start index
     655    IF(ie == ib-1) EXIT
     656    keys(ik) = r(ib:ie-1)                                            !--- Get the ikth key
    599657    ib = ie + LEN(delimiter)
    600658    DO WHILE(r(ib:ib) == ' ' .AND. ib < nr); ib = ib + 1; END DO     !--- Skip spaces before next chain
    601     nkeys = nkeys+1
    602   END DO
    603   IF(PRESENT(keys)) keys(nkeys) = r(ib:nr)                           !--- Get the last key
    604   IF(PRESENT(vals)) CALL parseKeys(keys(nkeys), vals(nkeys))         !--- Parse the last <key>=<val> pair
    605 END SUBROUTINE strParse_prv
    606 
    607 !------------------------------------------------------------------------------------------------------------------------------
    608 SUBROUTINE parseKeys(key, val)
    609   CHARACTER(LEN=*), INTENT(INOUT) :: key
    610   CHARACTER(LEN=*), INTENT(OUT)   :: val
    611 !------------------------------------------------------------------------------------------------------------------------------
    612   INTEGER :: ix
    613   ix = INDEX(key, '='); IF(ix == 0) RETURN                           !--- First "=" index in "key"
    614   val = ADJUSTL(key(ix+1:LEN_TRIM(key)))
    615   key = ADJUSTL(key(1:ix-1))
    616 END SUBROUTINE parseKeys
     659  END DO
     660  keys(ik) = r(ib:nr)                                                !--- Get the last key
     661END SUBROUTINE parseK
     662
     663!------------------------------------------------------------------------------------------------------------------------------
     664SUBROUTINE parseV(vals)
     665!--- Parse the <key>=<val> pairs in "keys(:)" into "keys" and "vals"
     666  IMPLICIT NONE
     667  CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: vals(:)
     668!------------------------------------------------------------------------------------------------------------------------------
     669  CHARACTER(LEN=maxlen) :: key
     670  INTEGER :: ik, ix
     671  ALLOCATE(vals(nk))
     672  DO ik = 1, nk; key = keys(ik)
     673    vals(ik) = ''
     674    ix = INDEX(key, '='); IF(ix == 0) CYCLE                          !--- First "=" index in "key"
     675    vals(ik) = ADJUSTL(key(ix+1:LEN_TRIM(key)))
     676    keys(ik) = ADJUSTL(key(1:ix-1))
     677  END DO
     678END SUBROUTINE parseV
    617679
    618680END FUNCTION strParse
    619681!==============================================================================================================================
    620682LOGICAL FUNCTION strParse_m(rawList, delimiter, keys, n, vals, lSc, id) RESULT(lerr)
     683  IMPLICIT NONE
    621684  CHARACTER(LEN=*),                             INTENT(IN)  :: rawList, delimiter(:)
    622685  CHARACTER(LEN=maxlen),           ALLOCATABLE, INTENT(OUT) :: keys(:)  !--- Parsed keys vector
     
    630693  LOGICAL :: ll
    631694  ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc
    632   IF(test(fmsg("Couldn't parse list: non-numerical strings were found", ll=strCount_1m(rawList, delimiter, nk, ll)),lerr)) RETURN
     695  lerr = strCount_1m(rawList, delimiter, nk, ll)
     696  CALL msg("Couldn't parse list: non-numerical strings were found", ll=lerr); IF(lerr) RETURN
    633697
    634698  !--- FEW ALLOCATIONS
     
    643707  ib = 1
    644708  DO ik = 1, nk-1
    645     IF(test(fmsg('Non-numeric values found', ll=strIdx_prv(r, delimiter, ib, ie, jd, ll)),lerr)) RETURN
     709    lerr = strIdx_prv(r, delimiter, ib, ie, jd, ll)
     710    CALL msg('Non-numeric values found', ll=lerr); IF(lerr) RETURN
    646711    keys(ik) = r(ib:ie-1)
    647712    IF(PRESENT(vals)) CALL parseKeys(keys(ik), vals(ik))             !--- Parse a <key>=<val> pair
     
    657722!------------------------------------------------------------------------------------------------------------------------------
    658723SUBROUTINE parseKeys(key, val)
     724  IMPLICIT NONE
    659725  CHARACTER(LEN=*), INTENT(INOUT) :: key
    660726  CHARACTER(LEN=*), INTENT(OUT)   :: val
     
    674740!==============================================================================================================================
    675741SUBROUTINE strReplace_1(str, key, val, lsurr)
     742  IMPLICIT NONE
    676743  CHARACTER(LEN=*),  INTENT(INOUT) :: str        !--- Main string
    677744  CHARACTER(LEN=*),  INTENT(IN)    :: key, val   !--- "key" will be replaced by "val"
     
    700767!==============================================================================================================================
    701768SUBROUTINE strReplace_m(str, key, val, lsurr)
     769  IMPLICIT NONE
    702770  CHARACTER(LEN=*),  INTENT(INOUT) :: str(:)     !--- Main strings vector
    703771  CHARACTER(LEN=*),  INTENT(IN)    :: key, val   !--- "key" will be replaced by "val"
     
    714782!=== Contatenate horizontally scalars/vectors of strings/integers/reals into a vector/array ===================================
    715783!==============================================================================================================================
    716 FUNCTION horzcat_s1(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
    717   CHARACTER(LEN=*),           TARGET, INTENT(IN) :: s0
     784FUNCTION horzcat_s00(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
     785  IMPLICIT NONE
     786  CHARACTER(LEN=*),                   INTENT(IN) :: s0
    718787  CHARACTER(LEN=*), OPTIONAL, TARGET, INTENT(IN) :: s1, s2, s3, s4, s5, s6, s7, s8, s9
    719788  CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:)
    720 !------------------------------------------------------------------------------------------------------------------------------
    721789  CHARACTER(LEN=maxlen), POINTER     :: s
    722   LOGICAL :: lv(10)
    723   INTEGER :: iv
    724   lv = [   .TRUE.   , PRESENT(s1), PRESENT(s2), PRESENT(s3), PRESENT(s4) , &
    725          PRESENT(s5), PRESENT(s6), PRESENT(s7), PRESENT(s8), PRESENT(s9) ]
    726   ALLOCATE(out(COUNT(lv)))
    727   DO iv=1, COUNT(lv)
    728     SELECT CASE(iv)
    729       CASE(1); s=> s0; CASE(2); s=> s1; CASE(3); s=> s2; CASE(4); s=> s3; CASE(5); s=> s4
    730       CASE(6); s=> s5; CASE(7); s=> s6; CASE(8); s=> s7; CASE(9); s=> s8; CASE(10);s=> s9
     790  INTEGER                            :: nrow, iv
     791  LOGICAL                            :: pre(9)
     792!------------------------------------------------------------------------------------------------------------------------------
     793  pre(:) = [PRESENT(s1),PRESENT(s2),PRESENT(s3),PRESENT(s4),PRESENT(s5),PRESENT(s6),PRESENT(s7),PRESENT(s8),PRESENT(s9)]
     794  nrow = 1+COUNT(pre)
     795  ALLOCATE(out(nrow))
     796  out(1) = s0
     797  DO iv = 2, nrow; IF(.NOT.pre(iv-1)) CYCLE
     798    SELECT CASE(iv-1)
     799      CASE(1); s=> s1; CASE(2); s=> s2; CASE(3); s=> s3; CASE(4); s=> s4; CASE(5); s=> s5
     800      CASE(6); s=> s6; CASE(7); s=> s7; CASE(8); s=> s8; CASE(9); s=> s9
    731801    END SELECT
    732802    out(iv) = s
    733803  END DO
    734 END FUNCTION horzcat_s1
    735 !==============================================================================================================================
    736 FUNCTION horzcat_sm(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
    737   CHARACTER(LEN=*),           TARGET, DIMENSION(:), INTENT(IN) :: s0
    738   CHARACTER(LEN=*), OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: s1, s2, s3, s4, s5, s6, s7, s8, s9
     804END FUNCTION horzcat_s00
     805!==============================================================================================================================
     806FUNCTION horzcat_s10(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
     807  IMPLICIT NONE
     808  CHARACTER(LEN=*),           INTENT(IN) :: s0(:), s1
     809  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: s2, s3, s4, s5, s6, s7, s8, s9
     810  CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:), tmp(:)
     811  INTEGER :: nc
     812  nc = SIZE(s0)
     813  tmp = horzcat_s00(s0(nc), s1, s2, s3, s4, s5, s6, s7, s8, s9)
     814  IF(nc == 1) out = tmp
     815  IF(nc /= 1) out = [s0(1:nc-1), tmp]
     816END FUNCTION horzcat_s10
     817!==============================================================================================================================
     818FUNCTION horzcat_s11(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
     819  IMPLICIT NONE
     820  CHARACTER(LEN=*),                   INTENT(IN) :: s0(:)
     821  CHARACTER(LEN=*), OPTIONAL, TARGET, INTENT(IN) :: s1(:), s2(:), s3(:), s4(:), s5(:), s6(:), s7(:), s8(:), s9(:)
    739822  CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:,:)
    740 !------------------------------------------------------------------------------------------------------------------------------
    741823  CHARACTER(LEN=maxlen), POINTER     :: s(:)
    742   LOGICAL :: lv(10)
    743   INTEGER :: nrow, ncol, iv, n
    744   lv = [   .TRUE.   , PRESENT(s1), PRESENT(s2), PRESENT(s3), PRESENT(s4) , &
    745          PRESENT(s5), PRESENT(s6), PRESENT(s7), PRESENT(s8), PRESENT(s9) ]
    746   nrow = SIZE(s0); ncol=COUNT(lv)
     824  INTEGER                            :: nrow, ncol, iv, n
     825  LOGICAL                            :: pre(9)
     826!------------------------------------------------------------------------------------------------------------------------------
     827  pre(:) = [PRESENT(s1),PRESENT(s2),PRESENT(s3),PRESENT(s4),PRESENT(s5),PRESENT(s6),PRESENT(s7),PRESENT(s8),PRESENT(s9)]
     828  nrow = SIZE(s0)
     829  ncol = 1+COUNT(pre)
    747830  ALLOCATE(out(nrow, ncol))
    748   DO iv=1, ncol
    749     SELECT CASE(iv)
    750       CASE(1); s=> s0; CASE(2); s=> s1; CASE(3); s=> s2; CASE(4); s=> s3; CASE(5); s=> s4
    751       CASE(6); s=> s5; CASE(7); s=> s6; CASE(8); s=> s7; CASE(9); s=> s8; CASE(10);s=> s9
     831  out(:,1) = s0
     832  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     833    SELECT CASE(iv-1)
     834      CASE(1); s=> s1; CASE(2); s=> s2; CASE(3); s=> s3; CASE(4); s=> s4; CASE(5); s=> s5
     835      CASE(6); s=> s6; CASE(7); s=> s7; CASE(8); s=> s8; CASE(9); s=> s9
    752836    END SELECT
    753837    n = SIZE(s, DIM=1)
    754     IF(n/=nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
     838    IF(n /= nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
    755839    out(:,iv) = s(:)
    756840  END DO
    757 END FUNCTION horzcat_sm
    758 !==============================================================================================================================
    759 FUNCTION horzcat_i1(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
    760   INTEGER,           TARGET, INTENT(IN) :: i0
     841END FUNCTION horzcat_s11
     842!==============================================================================================================================
     843FUNCTION horzcat_s21(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) RESULT(out)
     844  IMPLICIT NONE
     845  CHARACTER(LEN=*),           INTENT(IN) :: s0(:,:), s1(:)
     846  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: s2(:), s3(:), s4(:), s5(:), s6(:), s7(:), s8(:), s9(:)
     847  CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:,:), tmp(:,:)
     848  INTEGER :: nc
     849  nc  = SIZE(s0, 2)
     850  tmp = horzcat_s11(s0(:,nc), s1, s2, s3, s4, s5, s6, s7, s8, s9)
     851  IF(nc == 1) out = tmp
     852  IF(nc /= 1) out = RESHAPE([PACK(s0(:,1:nc-1), .TRUE.), PACK(tmp, .TRUE.)], SHAPE=[SIZE(s0, 1), nc + SIZE(tmp, 2)-1])
     853END FUNCTION horzcat_s21
     854!==============================================================================================================================
     855FUNCTION horzcat_i00(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
     856  IMPLICIT NONE
     857  INTEGER,                   INTENT(IN) :: i0
    761858  INTEGER, OPTIONAL, TARGET, INTENT(IN) :: i1, i2, i3, i4, i5, i6, i7, i8, i9
    762859  INTEGER, ALLOCATABLE :: out(:)
    763 !------------------------------------------------------------------------------------------------------------------------------
    764860  INTEGER, POINTER     :: i
    765   LOGICAL :: lv(10)
    766   INTEGER :: iv
    767   lv = [   .TRUE.   , PRESENT(i1), PRESENT(i2), PRESENT(i3), PRESENT(i4) , &
    768          PRESENT(i5), PRESENT(i6), PRESENT(i7), PRESENT(i8), PRESENT(i9) ]
    769   ALLOCATE(out(COUNT(lv)))
    770   DO iv=1, COUNT(lv)
    771     SELECT CASE(iv)
    772       CASE(1); i=> i0; CASE(2); i=> i1; CASE(3); i=> i2; CASE(4); i=> i3; CASE(5); i=> i4
    773       CASE(6); i=> i5; CASE(7); i=> i6; CASE(8); i=> i7; CASE(9); i=> i8; CASE(10);i=> i9
     861  INTEGER              :: ncol, iv
     862  LOGICAL              :: pre(9)
     863!------------------------------------------------------------------------------------------------------------------------------
     864  pre(:) = [PRESENT(i1),PRESENT(i2),PRESENT(i3),PRESENT(i4),PRESENT(i5),PRESENT(i6),PRESENT(i7),PRESENT(i8),PRESENT(i9)]
     865  ncol = SIZE(pre)
     866  ALLOCATE(out(ncol))
     867  out(1) = i0
     868  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     869    SELECT CASE(iv-1)
     870      CASE(1); i=> i1; CASE(2); i=> i2; CASE(3); i=> i3; CASE(4); i=> i4; CASE(5); i=> i5
     871      CASE(6); i=> i6; CASE(7); i=> i7; CASE(8); i=> i8; CASE(9); i=> i9
    774872    END SELECT
    775873    out(iv) = i
    776874  END DO
    777 END FUNCTION horzcat_i1
    778 !==============================================================================================================================
    779 FUNCTION horzcat_im(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
    780   INTEGER,           TARGET, DIMENSION(:), INTENT(IN) :: i0
    781   INTEGER, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: i1, i2, i3, i4, i5, i6, i7, i8, i9
     875END FUNCTION horzcat_i00
     876!==============================================================================================================================
     877FUNCTION horzcat_i10(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
     878  IMPLICIT NONE
     879  INTEGER,           INTENT(IN) :: i0(:), i1
     880  INTEGER, OPTIONAL, INTENT(IN) :: i2, i3, i4, i5, i6, i7, i8, i9
     881  INTEGER, ALLOCATABLE :: out(:), tmp(:)
     882  INTEGER :: nc
     883  nc = SIZE(i0)
     884  tmp = horzcat_i00(i0(nc), i1, i2, i3, i4, i5, i6, i7, i8, i9)
     885  IF(nc == 1) out = tmp
     886  IF(nc /= 1) out = [i0(1:nc-1), tmp]
     887END FUNCTION horzcat_i10
     888!==============================================================================================================================
     889FUNCTION horzcat_i11(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
     890  IMPLICIT NONE
     891  INTEGER,                   INTENT(IN) :: i0(:)
     892  INTEGER, OPTIONAL, TARGET, INTENT(IN) :: i1(:), i2(:), i3(:), i4(:), i5(:), i6(:), i7(:), i8(:), i9(:)
    782893  INTEGER, ALLOCATABLE :: out(:,:)
    783 !------------------------------------------------------------------------------------------------------------------------------
    784894  INTEGER, POINTER     :: i(:)
    785   LOGICAL :: lv(10)
    786   INTEGER :: nrow, ncol, iv, n
    787   lv = [   .TRUE.   , PRESENT(i1), PRESENT(i2), PRESENT(i3), PRESENT(i4) , &
    788          PRESENT(i5), PRESENT(i6), PRESENT(i7), PRESENT(i8), PRESENT(i9) ]
    789   nrow = SIZE(i0); ncol=COUNT(lv)
     895  INTEGER              :: nrow, ncol, iv, n
     896  LOGICAL              :: pre(9)
     897!------------------------------------------------------------------------------------------------------------------------------
     898  pre(:) = [PRESENT(i1),PRESENT(i2),PRESENT(i3),PRESENT(i4),PRESENT(i5),PRESENT(i6),PRESENT(i7),PRESENT(i8),PRESENT(i9)]
     899  nrow = SIZE(i0)
     900  ncol = 1+COUNT(pre)
    790901  ALLOCATE(out(nrow, ncol))
    791   DO iv=1, ncol
    792     SELECT CASE(iv)
    793       CASE(1); i=> i0; CASE(2); i=> i1; CASE(3); i=> i2; CASE(4); i=> i3; CASE(5); i=> i4
    794       CASE(6); i=> i5; CASE(7); i=> i6; CASE(8); i=> i7; CASE(9); i=> i8; CASE(10);i=> i9
     902  out(:,1) = i0
     903  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     904    SELECT CASE(iv-1)
     905      CASE(1); i=> i1; CASE(2); i=> i2; CASE(3); i=> i3; CASE(4); i=> i4; CASE(5); i=> i5
     906      CASE(6); i=> i6; CASE(7); i=> i7; CASE(8); i=> i8; CASE(9); i=> i9
    795907    END SELECT
    796908    n = SIZE(i, DIM=1)
    797     IF(n/=nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
     909    IF(n /= nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
    798910    out(:,iv) = i(:)
    799911  END DO
    800 END FUNCTION horzcat_im
    801 !==============================================================================================================================
    802 FUNCTION horzcat_r1(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
    803   REAL,           TARGET, INTENT(IN) :: r0
     912END FUNCTION horzcat_i11
     913!==============================================================================================================================
     914FUNCTION horzcat_i21(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9) RESULT(out)
     915  IMPLICIT NONE
     916  INTEGER,           INTENT(IN) :: i0(:,:), i1(:)
     917  INTEGER, OPTIONAL, INTENT(IN) :: i2(:), i3(:), i4(:), i5(:), i6(:), i7(:), i8(:), i9(:)
     918  INTEGER, ALLOCATABLE :: out(:,:), tmp(:,:)
     919  INTEGER :: nc
     920  nc  = SIZE(i0, 2)
     921  tmp = horzcat_i11(i0(:,nc), i1, i2, i3, i4, i5, i6, i7, i8, i9)
     922  IF(nc == 1) out = tmp
     923  IF(nc /= 1) out = RESHAPE([PACK(i0(:,1:nc-1), .TRUE.), PACK(tmp, .TRUE.)], SHAPE=[SIZE(i0, 1), nc + SIZE(tmp, 2)-1])
     924END FUNCTION horzcat_i21
     925!==============================================================================================================================
     926FUNCTION horzcat_r00(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
     927  IMPLICIT NONE
     928  REAL,                   INTENT(IN) :: r0
    804929  REAL, OPTIONAL, TARGET, INTENT(IN) :: r1, r2, r3, r4, r5, r6, r7, r8, r9
    805930  REAL, ALLOCATABLE :: out(:)
    806 !------------------------------------------------------------------------------------------------------------------------------
    807931  REAL, POINTER     :: r
    808   LOGICAL :: lv(10)
    809   INTEGER :: iv
    810   lv = [   .TRUE.   , PRESENT(r1), PRESENT(r2), PRESENT(r3), PRESENT(r4) , &
    811          PRESENT(r5), PRESENT(r6), PRESENT(r7), PRESENT(r8), PRESENT(r9) ]
    812   ALLOCATE(out(COUNT(lv)))
    813   DO iv=1, COUNT(lv)
    814     SELECT CASE(iv)
    815       CASE(1); r=> r0; CASE(2); r=> r1; CASE(3); r=> r2; CASE(4); r=> r3; CASE(5); r=> r4
    816       CASE(6); r=> r5; CASE(7); r=> r6; CASE(8); r=> r7; CASE(9); r=> r8; CASE(10);r=> r9
     932  INTEGER           :: ncol, iv
     933  LOGICAL           :: pre(9)
     934!------------------------------------------------------------------------------------------------------------------------------
     935  pre(:) = [PRESENT(r1),PRESENT(r2),PRESENT(r3),PRESENT(r4),PRESENT(r5),PRESENT(r6),PRESENT(r7),PRESENT(r8),PRESENT(r9)]
     936  ncol = 1+COUNT(pre)
     937  ALLOCATE(out(ncol))
     938  out(1) = r0
     939  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     940    SELECT CASE(iv-1)
     941      CASE(1); r=> r1; CASE(2); r=> r2; CASE(3); r=> r3; CASE(4); r=> r4; CASE(5); r=> r5
     942      CASE(6); r=> r6; CASE(7); r=> r7; CASE(8); r=> r8; CASE(9); r=> r9
    817943    END SELECT
    818944    out(iv) = r
    819945  END DO
    820 END FUNCTION horzcat_r1
    821 !==============================================================================================================================
    822 FUNCTION horzcat_rm(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
    823   REAL,           TARGET, DIMENSION(:), INTENT(IN) :: r0
    824   REAL, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: r1, r2, r3, r4, r5, r6, r7, r8, r9
     946END FUNCTION horzcat_r00
     947!==============================================================================================================================
     948FUNCTION horzcat_r10(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
     949  IMPLICIT NONE
     950  REAL,           INTENT(IN) :: r0(:), r1
     951  REAL, OPTIONAL, INTENT(IN) :: r2, r3, r4, r5, r6, r7, r8, r9
     952  REAL, ALLOCATABLE :: out(:), tmp(:)
     953  INTEGER :: nc
     954  nc  = SIZE(r0)
     955  tmp = horzcat_r00(r0(nc), r1, r2, r3, r4, r5, r6, r7, r8, r9)
     956  IF(nc == 1) out = tmp
     957  IF(nc /= 1) out = [r0(1:nc-1), tmp]
     958END FUNCTION horzcat_r10
     959!==============================================================================================================================
     960FUNCTION horzcat_r11(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
     961  IMPLICIT NONE
     962  REAL,                   INTENT(IN) :: r0(:)
     963  REAL, OPTIONAL, TARGET, INTENT(IN) :: r1(:), r2(:), r3(:), r4(:), r5(:), r6(:), r7(:), r8(:), r9(:)
    825964  REAL, ALLOCATABLE :: out(:,:)
    826 !------------------------------------------------------------------------------------------------------------------------------
    827965  REAL, POINTER     :: r(:)
    828   LOGICAL :: lv(10)
    829   INTEGER :: nrow, ncol, iv, n
    830   lv = [   .TRUE.   , PRESENT(r1), PRESENT(r2), PRESENT(r3), PRESENT(r4) , &
    831          PRESENT(r5), PRESENT(r6), PRESENT(r7), PRESENT(r8), PRESENT(r9) ]
    832   nrow = SIZE(r0); ncol=COUNT(lv)
     966  INTEGER           :: nrow, ncol, iv, n
     967  LOGICAL           :: pre(9)
     968!------------------------------------------------------------------------------------------------------------------------------
     969  pre(:) = [PRESENT(r1),PRESENT(r2),PRESENT(r3),PRESENT(r4),PRESENT(r5),PRESENT(r6),PRESENT(r7),PRESENT(r8),PRESENT(r9)]
     970  nrow = SIZE(r0)
     971  ncol = 1+COUNT(pre)
    833972  ALLOCATE(out(nrow, ncol))
    834   DO iv=1, ncol
    835     SELECT CASE(iv)
    836       CASE(1); r=> r0; CASE(2); r=> r1; CASE(3); r=> r2; CASE(4); r=> r3; CASE(5); r=> r4
    837       CASE(6); r=> r5; CASE(7); r=> r6; CASE(8); r=> r7; CASE(9); r=> r8; CASE(10);r=> r9
     973  out(:,1) = r0
     974  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     975    SELECT CASE(iv-1)
     976      CASE(1); r=> r1; CASE(2); r=> r2; CASE(3); r=> r3; CASE(4); r=> r4; CASE(5); r=> r5
     977      CASE(6); r=> r5; CASE(7); r=> r7; CASE(8); r=> r8; CASE(9); r=> r9
    838978    END SELECT
    839979    n = SIZE(r, DIM=1)
    840     IF(n/=nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
     980    IF(n /= nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
    841981    out(:,iv) = r(:)
    842982  END DO
    843 END FUNCTION horzcat_rm
    844 !==============================================================================================================================
    845 FUNCTION horzcat_d1(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
    846   DOUBLE PRECISION,           TARGET, INTENT(IN) :: d0
     983END FUNCTION horzcat_r11
     984!==============================================================================================================================
     985FUNCTION horzcat_r21(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9) RESULT(out)
     986  IMPLICIT NONE
     987  REAL,           INTENT(IN) :: r0(:,:), r1(:)
     988  REAL, OPTIONAL, INTENT(IN) :: r2(:), r3(:), r4(:), r5(:), r6(:), r7(:), r8(:), r9(:)
     989  REAL, ALLOCATABLE :: out(:,:), tmp(:,:)
     990  INTEGER :: nc
     991  nc  = SIZE(r0, 2)
     992  tmp = horzcat_r11(r0(:,nc), r1, r2, r3, r4, r5, r6, r7, r8, r9)
     993  IF(nc == 1) out = tmp
     994  IF(nc /= 1) out = RESHAPE([PACK(r0(:,1:nc-1), .TRUE.), PACK(tmp, .TRUE.)], SHAPE=[SIZE(r0, 1), nc + SIZE(tmp, 2)-1])
     995END FUNCTION horzcat_r21
     996!==============================================================================================================================
     997FUNCTION horzcat_d00(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
     998  IMPLICIT NONE
     999  DOUBLE PRECISION,                   INTENT(IN) :: d0
    8471000  DOUBLE PRECISION, OPTIONAL, TARGET, INTENT(IN) :: d1, d2, d3, d4, d5, d6, d7, d8, d9
    8481001  DOUBLE PRECISION, ALLOCATABLE :: out(:)
    849 !------------------------------------------------------------------------------------------------------------------------------
    8501002  DOUBLE PRECISION, POINTER     :: d
    851   LOGICAL :: lv(10)
    852   INTEGER :: iv
    853   lv = [   .TRUE.   , PRESENT(d1), PRESENT(d2), PRESENT(d3), PRESENT(d4) , &
    854          PRESENT(d5), PRESENT(d6), PRESENT(d7), PRESENT(d8), PRESENT(d9) ]
    855   ALLOCATE(out(COUNT(lv)))
    856   DO iv=1, COUNT(lv)
    857     SELECT CASE(iv)
    858       CASE(1); d=> d0; CASE(2); d=> d1; CASE(3); d=> d2; CASE(4); d=> d3; CASE(5); d=> d4
    859       CASE(6); d=> d5; CASE(7); d=> d6; CASE(8); d=> d7; CASE(9); d=> d8; CASE(10);d=> d9
     1003  INTEGER                       :: ncol, iv
     1004  LOGICAL                       :: pre(9)
     1005!------------------------------------------------------------------------------------------------------------------------------
     1006  pre(:) = [PRESENT(d1),PRESENT(d2),PRESENT(d3),PRESENT(d4),PRESENT(d5),PRESENT(d6),PRESENT(d7),PRESENT(d8),PRESENT(d9)]
     1007  ncol = 1+COUNT(pre)
     1008  ALLOCATE(out(ncol))
     1009  out(1) = d0
     1010  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     1011    SELECT CASE(iv-1)
     1012      CASE(1); d=> d1; CASE(2); d=> d2; CASE(3); d=> d3; CASE(4); d=> d4; CASE(5); d=> d5
     1013      CASE(6); d=> d6; CASE(7); d=> d7; CASE(8); d=> d8; CASE(9); d=> d9
    8601014    END SELECT
    8611015    out(iv) = d
    8621016  END DO
    863 END FUNCTION horzcat_d1
    864 !==============================================================================================================================
    865 FUNCTION horzcat_dm(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
    866   DOUBLE PRECISION,           TARGET, DIMENSION(:), INTENT(IN) :: d0
    867   DOUBLE PRECISION, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: d1, d2, d3, d4, d5, d6, d7, d8, d9
     1017END FUNCTION horzcat_d00
     1018!==============================================================================================================================
     1019FUNCTION horzcat_d10(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
     1020  IMPLICIT NONE
     1021  DOUBLE PRECISION,           INTENT(IN) :: d0(:), d1
     1022  DOUBLE PRECISION, OPTIONAL, INTENT(IN) :: d2, d3, d4, d5, d6, d7, d8, d9
     1023  DOUBLE PRECISION, ALLOCATABLE :: out(:), tmp(:)
     1024  INTEGER :: nc
     1025  nc = SIZE(d0)
     1026  tmp = horzcat_d00(d0(nc), d1, d2, d3, d4, d5, d6, d7, d8, d9)
     1027  IF(nc == 1) out = tmp
     1028  IF(nc /= 1) out = [d0(1:nc-1), tmp]
     1029END FUNCTION horzcat_d10
     1030!==============================================================================================================================
     1031FUNCTION horzcat_d11(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
     1032  IMPLICIT NONE
     1033  DOUBLE PRECISION,                   INTENT(IN) :: d0(:)
     1034  DOUBLE PRECISION, OPTIONAL, TARGET, INTENT(IN) :: d1(:), d2(:), d3(:), d4(:), d5(:), d6(:), d7(:), d8(:), d9(:)
    8681035  DOUBLE PRECISION, ALLOCATABLE :: out(:,:)
    869 !------------------------------------------------------------------------------------------------------------------------------
    8701036  DOUBLE PRECISION, POINTER     :: d(:)
    871   LOGICAL :: lv(10)
    872   INTEGER :: nrow, ncol, iv, n
    873   lv = [   .TRUE.   , PRESENT(d1), PRESENT(d2), PRESENT(d3), PRESENT(d4) , &
    874          PRESENT(d5), PRESENT(d6), PRESENT(d7), PRESENT(d8), PRESENT(d9) ]
    875   nrow = SIZE(d0); ncol=COUNT(lv)
     1037  INTEGER                       :: nrow, ncol, iv, n
     1038  LOGICAL                       :: pre(9)
     1039!------------------------------------------------------------------------------------------------------------------------------
     1040  nrow = SIZE(d0)
     1041  pre(:) = [PRESENT(d1),PRESENT(d2),PRESENT(d3),PRESENT(d4),PRESENT(d5),PRESENT(d6),PRESENT(d7),PRESENT(d8),PRESENT(d9)]
     1042  ncol = 1+COUNT(pre)
    8761043  ALLOCATE(out(nrow, ncol))
    877   DO iv=1, ncol
    878     SELECT CASE(iv)
    879       CASE(1); d=> d0; CASE(2); d=> d1; CASE(3); d=> d2; CASE(4); d=> d3; CASE(5); d=> d4
    880       CASE(6); d=> d5; CASE(7); d=> d6; CASE(8); d=> d7; CASE(9); d=> d8; CASE(10);d=> d9
     1044  DO iv = 2, ncol; IF(.NOT.pre(iv-1)) CYCLE
     1045    SELECT CASE(iv-1)
     1046      CASE(1); d=> d1; CASE(2); d=> d2; CASE(3); d=> d3; CASE(4); d=> d4; CASE(5); d=> d5
     1047      CASE(6); d=> d6; CASE(7); d=> d7; CASE(8); d=> d8; CASE(9); d=> d9
    8811048    END SELECT
    8821049    n = SIZE(d, DIM=1)
    883     IF(n/=nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
     1050    IF(n /= nrow) THEN; CALL msg("Can't concatenate vectors of differing lengths"); STOP; END IF
    8841051    out(:,iv) = d(:)
    8851052  END DO
    886 END FUNCTION horzcat_dm
     1053END FUNCTION horzcat_d11
     1054!==============================================================================================================================
     1055FUNCTION horzcat_d21(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) RESULT(out)
     1056  IMPLICIT NONE
     1057  DOUBLE PRECISION,           INTENT(IN) :: d0(:,:), d1(:)
     1058  DOUBLE PRECISION, OPTIONAL, INTENT(IN) :: d2(:), d3(:), d4(:), d5(:), d6(:), d7(:), d8(:), d9(:)
     1059  DOUBLE PRECISION, ALLOCATABLE :: out(:,:), tmp(:,:)
     1060  INTEGER :: nc
     1061  nc  = SIZE(d0, 2)
     1062  tmp = horzcat_d11(d0(:,nc), d1, d2, d3, d4, d5, d6, d7, d8, d9)
     1063  IF(nc == 1) out = tmp
     1064  IF(nc /= 1) out = RESHAPE([PACK(d0(:,1:nc-1), .TRUE.), PACK(tmp, .TRUE.)], SHAPE=[SIZE(d0, 1), nc + SIZE(tmp, 2)-1])
     1065END FUNCTION horzcat_d21
    8871066!==============================================================================================================================
    8881067
     
    8961075!==============================================================================================================================
    8971076LOGICAL FUNCTION dispTable(p, titles, s, i, r, rFmt, nRowMax, nColMax, nHead, unit, sub) RESULT(lerr)
     1077  IMPLICIT NONE
    8981078  CHARACTER(LEN=*),           INTENT(IN)  :: p             !--- DISPLAY MAP: s/i/r
    8991079  CHARACTER(LEN=*),           INTENT(IN)  :: titles(:)     !--- TITLES (ONE EACH COLUMN)
     
    10041184!==============================================================================================================================
    10051185LOGICAL FUNCTION dispNamelist(unt, p, titles, s, i, r, rFmt, llast) RESULT(lerr)
     1186  IMPLICIT NONE
    10061187  INTEGER,                    INTENT(IN)  :: unt           !--- Output unit
    10071188  CHARACTER(LEN=*),           INTENT(IN)  :: p             !--- DISPLAY MAP: s/i/r
     
    10861267!==============================================================================================================================
    10871268LOGICAL FUNCTION dispOutliers_1(ll, a, n, err_msg, nam, subn, nRowmax, nColMax, nHead, unit) RESULT(lerr)
     1269  IMPLICIT NONE
    10881270! Display outliers list in tables
    10891271! If "nam" is supplied, it means the last index is for tracers => one table each tracer for rank > 2.
     
    11151297
    11161298  rk = SIZE(n); nv = SIZE(vnm)
    1117   IF(test(fmsg('SIZE(nam) /= 1 and /= last "n" element', sub, nv /= 1 .AND. nv /= n(rk), unt),lerr)) RETURN
    1118   IF(test(fmsg('ll" and "a" sizes mismatch',             sub, SIZE(a) /= SIZE(ll),       unt),lerr)) RETURN
    1119   IF(test(fmsg('profile "n" does not match "a" and "ll', sub, SIZE(a) /= PRODUCT(n),     unt),lerr)) RETURN
     1299  lerr = nv/=1 .AND. nv/=n(rk); CALL msg('SIZE(nam) /= 1 and /= last "n" element', sub, lerr); IF(lerr) RETURN
     1300  lerr = SIZE(a) /=   SIZE(ll); CALL msg('ll" and "a" sizes mismatch',             sub, lerr); IF(lerr) RETURN
     1301  lerr = SIZE(a) /= PRODUCT(n); CALL msg('profile "n" does not match "a" and "ll', sub, lerr); IF(lerr) RETURN
    11201302  CALL msg(mes, sub, unit=unt)
    11211303
     
    11641346!==============================================================================================================================
    11651347LOGICAL FUNCTION dispOutliers_2(ll, a, n, err_msg, nam, subn, nRowMax, nColMax, nHead, unit) RESULT(lerr)
     1348  IMPLICIT NONE
    11661349! Display outliers list in tables
    11671350! If "nam" is supplied and, it means the last index is for tracers => one table each tracer for rank > 2.
     
    12211404!==============================================================================================================================
    12221405LOGICAL FUNCTION reduceExpr_1(str, val) RESULT(lerr)
     1406  IMPLICIT NONE
    12231407  CHARACTER(LEN=*),      INTENT(IN)  :: str
    12241408  CHARACTER(LEN=maxlen), INTENT(OUT) :: val
     
    12541438  DO WHILE(nl > 1)
    12551439    i = 1; DO WHILE(ip(i) /= 1 .OR. ip(i+1) /= 2); i = i + 1; END DO !IF(i > SIZE(ip)+1) EXIT;END DO
    1256     IF(test(reduceExpr_basic(vl(i+1), v), lerr)) RETURN
     1440    lerr = reduceExpr_basic(vl(i+1), v); IF(lerr) RETURN
    12571441    v = TRIM(vl(i))//TRIM(v); IF(i+2<=nl) v=TRIM(v)//TRIM(vl(i+2))
    12581442    vv = v//REPEAT(' ',768)
     
    12701454!==============================================================================================================================
    12711455LOGICAL FUNCTION reduceExpr_basic(str, val) RESULT(lerr)
     1456  IMPLICIT NONE
    12721457  CHARACTER(LEN=*),      INTENT(IN)  :: str
    12731458  CHARACTER(LEN=*),      INTENT(OUT) :: val
     
    12841469  op = ['^','/','*','+','-']                                                   !--- List of recognized operations
    12851470  s = str
    1286   IF(test(strParse_m(s, op, ky, lSc=.TRUE., id = id), lerr)) RETURN            !--- Parse the values
     1471  lerr = strParse_m(s, op, ky, lSc=.TRUE., id = id)                            !--- Parse the values
     1472  IF(lerr) RETURN                                                              !--- Problem with the parsing
    12871473  vl = str2dble(ky)                                                            !--- Conversion to doubles
    12881474  lerr = ANY(vl >= HUGE(1.d0))
    1289   IF(fmsg('Some values are non-numeric in: '//TRIM(s), ll=lerr)) RETURN        !--- Non-numerical values found
     1475  CALL msg('Some values are non-numeric in: '//TRIM(s), ll=lerr)
     1476  IF(lerr) RETURN                                                              !--- Non-numerical values found
    12901477  DO io = 1, SIZE(op)                                                          !--- Loop on known operators (order matters !)
    12911478    DO i = SIZE(id), 1, -1                                                     !--- Loop on found operators
     
    12931480      IF(id(i) /= io) CYCLE                                                    !--- Current found operator is not op(io)
    12941481      vm = vl(i); vp = vl(i+1)                                                 !--- Couple of values used for current operation
    1295       SELECT CASE(op(io))                                                          !--- Perform operation on the two values
     1482      SELECT CASE(op(io))                                                      !--- Perform operation on the two values
    12961483        CASE('^'); v = vm**vp
    12971484        CASE('/'); v = vm/vp
     
    13111498!==============================================================================================================================
    13121499FUNCTION reduceExpr_m(str, val) RESULT(lerr)
     1500  IMPLICIT NONE
    13131501  LOGICAL,               ALLOCATABLE              :: lerr(:)
    13141502  CHARACTER(LEN=*),                   INTENT(IN)  :: str(:)
     
    13261514!==============================================================================================================================
    13271515ELEMENTAL LOGICAL FUNCTION is_numeric(str) RESULT(out)
     1516  IMPLICIT NONE
    13281517  CHARACTER(LEN=*), INTENT(IN) :: str
    13291518  REAL    :: x
     
    13411530!=== Convert a string into a logical/integer integer or an integer/real into a string =========================================
    13421531!==============================================================================================================================
    1343 ELEMENTAL LOGICAL FUNCTION str2bool(str) RESULT(out)
     1532ELEMENTAL INTEGER FUNCTION str2bool(str) RESULT(out)  !--- Result: 0/1 for .FALSE./.TRUE., -1 if not a valid boolean
     1533  IMPLICIT NONE
    13441534  CHARACTER(LEN=*), INTENT(IN) :: str
    13451535  INTEGER :: ierr
    1346   READ(str,*,IOSTAT=ierr) out
    1347   IF(ierr==0) RETURN
    1348   out = ANY(['t     ','true  ','.true.','y     ','yes   ']==strLower(str))
     1536  LOGICAL :: lout
     1537  READ(str,*,IOSTAT=ierr) lout
     1538  out = -HUGE(1)
     1539  IF(ierr /= 0) THEN
     1540    IF(ANY(['.false.', 'false  ', 'no     ', 'f      ', 'n      '] == strLower(str))) out = 0
     1541    IF(ANY(['.true. ', 'true   ', 'yes    ', 't      ', 'y      '] == strLower(str))) out = 1
     1542  ELSE
     1543    out = 0; IF(lout) out = 1
     1544  END IF
    13491545END FUNCTION str2bool
    13501546!==============================================================================================================================
    13511547ELEMENTAL INTEGER FUNCTION str2int(str) RESULT(out)
     1548  IMPLICIT NONE
    13521549  CHARACTER(LEN=*), INTENT(IN) :: str
    13531550  INTEGER :: ierr
     
    13571554!==============================================================================================================================
    13581555ELEMENTAL REAL FUNCTION str2real(str) RESULT(out)
     1556  IMPLICIT NONE
    13591557  CHARACTER(LEN=*), INTENT(IN) :: str
    13601558  INTEGER :: ierr
     
    13641562!==============================================================================================================================
    13651563ELEMENTAL DOUBLE PRECISION FUNCTION str2dble(str) RESULT(out)
     1564  IMPLICIT NONE
    13661565  CHARACTER(LEN=*), INTENT(IN) :: str
    13671566  INTEGER :: ierr
     
    13711570!==============================================================================================================================
    13721571ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION bool2str(b) RESULT(out)
     1572  IMPLICIT NONE
    13731573  LOGICAL, INTENT(IN) :: b
    13741574  WRITE(out,*)b
     
    13771577!==============================================================================================================================
    13781578ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION int2str(i, nDigits) RESULT(out)
     1579  IMPLICIT NONE
    13791580  INTEGER,           INTENT(IN) :: i
    13801581  INTEGER, OPTIONAL, INTENT(IN) :: nDigits
     
    13871588!==============================================================================================================================
    13881589ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION real2str(r,fmt) RESULT(out)
     1590  IMPLICIT NONE
    13891591  REAL,                       INTENT(IN) :: r
    13901592  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt
     
    13961598!==============================================================================================================================
    13971599ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION dble2str(d,fmt) RESULT(out)
     1600  IMPLICIT NONE
    13981601  DOUBLE PRECISION,           INTENT(IN) :: d
    13991602  CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt
     
    14051608!==============================================================================================================================
    14061609ELEMENTAL SUBROUTINE cleanZeros(s)
     1610  IMPLICIT NONE
    14071611  CHARACTER(LEN=*), INTENT(INOUT) :: s
    14081612  INTEGER :: ls, ix, i
     
    14221626!==============================================================================================================================
    14231627FUNCTION addQuotes_1(s) RESULT(out)
     1628  IMPLICIT NONE
    14241629  CHARACTER(LEN=*), INTENT(IN)  :: s
    14251630  CHARACTER(LEN=:), ALLOCATABLE :: out
     
    14281633!==============================================================================================================================
    14291634FUNCTION addQuotes_m(s) RESULT(out)
     1635  IMPLICIT NONE
    14301636  CHARACTER(LEN=*), INTENT(IN)  :: s(:)
    14311637  CHARACTER(LEN=:), ALLOCATABLE :: out(:)
     
    14401646!==============================================================================================================================
    14411647ELEMENTAL LOGICAL FUNCTION needQuotes(s) RESULT(out)
     1648  IMPLICIT NONE
    14421649  CHARACTER(LEN=*), INTENT(IN) :: s
    14431650  CHARACTER(LEN=1) :: b, e
     
    14541661!==============================================================================================================================
    14551662LOGICAL FUNCTION checkList(str, lerr, message, items, reason, nmax) RESULT(out)
     1663  IMPLICIT NONE
    14561664! Purpose: Messages in case a list contains wrong elements (indicated by lerr boolean vector).
    14571665! Note:    Return value "out" is .TRUE. if there are errors (ie at least one element of "lerr" is TRUE).
     
    14761684!==============================================================================================================================
    14771685SUBROUTINE removeComment(str)
     1686  IMPLICIT NONE
    14781687  CHARACTER(LEN=*), INTENT(INOUT) :: str
    14791688  INTEGER :: ix
Note: See TracChangeset for help on using the changeset viewer.