Changeset 4482 for LMDZ6/branches/LMDZ_ECRad/libf/misc
- Timestamp:
- Mar 29, 2023, 3:14:27 PM (15 months ago)
- Location:
- LMDZ6/branches/LMDZ_ECRad
- Files:
-
- 1 deleted
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
LMDZ6/branches/LMDZ_ECRad
- Property svn:mergeinfo changed
-
LMDZ6/branches/LMDZ_ECRad/libf/misc/readTracFiles_mod.f90
r4203 r4482 1 1 MODULE readTracFiles_mod 2 2 3 USE strings_mod, ONLY: msg, testFile, strFind, strStack, strReduce, strHead, strCount, find, fmsg, reduceExpr, & 4 removeComment, cat, checkList, str2int, strParse, strReplace, strTail, strIdx, maxlen, test, dispTable, get_in 5 USE trac_types_mod, ONLY: trac_type, isot_type, keys_type 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 6 5 7 6 IMPLICIT NONE … … 9 8 PRIVATE 10 9 11 PUBLIC :: initIsotopes, maxlen, trac_type, isot_type, keys_type 12 PUBLIC :: readTracersFiles, indexUpdate, setGeneration !--- TOOLS ASSOCIATED TO TRACERS DESCRIPTORS 13 PUBLIC :: readIsotopesFile !--- TOOLS ASSOCIATED TO ISOTOPES DESCRIPTORS 14 PUBLIC :: getKey_init, getKey, fGetKey, setDirectKeys !--- GET/SET KEYS FROM/TO tracers & isotopes 15 16 PUBLIC :: addPhase, new2oldName, getPhase, & !--- FUNCTIONS RELATED TO THE PHASES 17 delPhase, old2newName, getiPhase, & !--- + ASSOCIATED VARIABLES 18 known_phases, old_phases, phases_sep, phases_names, nphases 19 20 PUBLIC :: oldH2OIso, newH2OIso !--- NEEDED FOR BACKWARD COMPATIBILITY (OLD traceur.def) 21 22 PUBLIC :: tran0, idxAncestor, ancestor !--- GENERATION 0 TRACER + TOOLS FOR GENERATIONS 10 PUBLIC :: maxlen !--- PARAMETER FOR CASUAL STRING LENGTH 11 PUBLIC :: tracers !--- TRACERS DESCRIPTION DATABASE 12 PUBLIC :: trac_type, setGeneration, indexUpdate !--- TRACERS DESCRIPTION ASSOCIATED TOOLS 13 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 19 20 PUBLIC :: oldH2OIso, newH2OIso, old2newH2O, new2oldH2O !--- H2O ISOTOPES BACKWARD COMPATIBILITY (OLD traceur.def) 21 PUBLIC :: oldHNO3, newHNO3 !--- HNO3 REPRO BACKWARD COMPATIBILITY (OLD start.nc) 22 23 PUBLIC :: tran0, idxAncestor, ancestor !--- GENERATION 0 TRACER + TOOLS FOR GENERATIONS 24 25 !=== 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 28 29 !=== FOR ISOTOPES: H2O FAMILY ONLY 30 PUBLIC :: iH2O 31 32 !=== FOR ISOTOPES: DEPENDING ON THE SELECTED ISOTOPES CLASS 33 PUBLIC :: isotope, isoKeys !--- SELECTED ISOTOPES DATABASE + ASSOCIATED KEYS 34 PUBLIC :: isoName, isoZone, isoPhas !--- ISOTOPES AND TAGGING ZONES NAMES AND PHASES 35 PUBLIC :: niso, nzone, nphas, ntiso !--- " " NUMBERS + ISOTOPES AND TAGGING TRACERS NUMBERS 36 PUBLIC :: itZonIso !--- Idx IN isoName(1:niso) = f(tagging idx, isotope idx) 37 PUBLIC :: iqIsoPha !--- Idx IN qx(1:nqtot) = f(isotope idx, phase idx) 38 PUBLIC :: isoCheck !--- FLAG TO RUN ISOTOPES CHECKING ROUTINES 39 23 40 PUBLIC :: maxTableWidth 24 41 !------------------------------------------------------------------------------------------------------------------------------ 25 TYPE :: dataBase_type !=== TYPE FOR TRACERS SECTION 26 CHARACTER(LEN=maxlen) :: name !--- Section name 27 TYPE(trac_type), ALLOCATABLE :: trac(:) !--- Tracers descriptors 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 46 END TYPE keys_type 47 !------------------------------------------------------------------------------------------------------------------------------ 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 69 END TYPE trac_type 70 !------------------------------------------------------------------------------------------------------------------------------ 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 87 !------------------------------------------------------------------------------------------------------------------------------ 88 TYPE :: dataBase_type !=== TYPE FOR TRACERS SECTION 89 CHARACTER(LEN=maxlen) :: name !--- Section name 90 TYPE(trac_type), ALLOCATABLE :: trac(:) !--- Tracers descriptors 28 91 END TYPE dataBase_type 29 92 !------------------------------------------------------------------------------------------------------------------------------ 30 93 INTERFACE getKey 31 MODULE PROCEDURE getKeyByName_s1, getKeyByName_i1, getKeyByName_r1, getKeyByName_sm, getKeyByName_im, getKeyByName_rm 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 32 98 END INTERFACE getKey 33 99 !------------------------------------------------------------------------------------------------------------------------------ 34 INTERFACE fGetKey; MODULE PROCEDURE fgetKeyByIndex_s1, fgetKeyByName_s1; END INTERFACE fGetKey 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 35 104 INTERFACE tracersSubset; MODULE PROCEDURE trSubset_Indx, trSubset_Name, trSubset_gen0Name; END INTERFACE tracersSubset 36 INTERFACE idxAncestor; MODULE PROCEDURE idxAncestor_1, idxAncestor_m; END INTERFACE idxAncestor 37 INTERFACE ancestor; MODULE PROCEDURE ancestor_1, ancestor_m; END INTERFACE ancestor 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 38 108 INTERFACE addPhase; MODULE PROCEDURE addPhase_s1, addPhase_sm, addPhase_i1, addPhase_im; END INTERFACE addPhase 39 INTERFACE old2newName; MODULE PROCEDURE old2newName_1, old2newName_m; END INTERFACE old2newName40 INTERFACE new2oldName; MODULE PROCEDURE new2oldName_1, new2oldName_m; END INTERFACE new2oldName41 109 !------------------------------------------------------------------------------------------------------------------------------ 42 110 … … 45 113 46 114 !--- SOME PARAMETERS THAT ARE NOT LIKELY TO CHANGE OFTEN 47 CHARACTER(LEN=maxlen), SAVE :: tran0 = 'air' !--- Default transporting fluid 48 CHARACTER(LEN=maxlen), PARAMETER :: old_phases = 'vlir' !--- Old phases for water (no separator) 49 CHARACTER(LEN=maxlen), PARAMETER :: known_phases = 'glsr' !--- Known phases initials 50 INTEGER, PARAMETER :: nphases=LEN_TRIM(known_phases) !--- Number of phases 51 CHARACTER(LEN=maxlen), SAVE :: phases_names(nphases) & !--- Known phases names 52 = ['gaseous', 'liquid ', 'solid ', 'cloud '] 53 CHARACTER(LEN=1), SAVE :: phases_sep = '_' !--- Phase separator 54 LOGICAL, SAVE :: tracs_merge = .TRUE. !--- Merge/stack tracers lists 55 LOGICAL, SAVE :: lSortByGen = .TRUE. !--- Sort by growing generation 56 57 !--- KEPT JUST TO MANAGE OLD WATER ISOTOPES NAMES 58 !--- Apart from that context, on limitaion on isotopes names (as long as they have a corresponding line in isotopes_params.def) 59 CHARACTER(LEN=maxlen), SAVE :: oldH2OIso(5) = ['eau', 'HDO', 'O18', 'O17', 'HTO' ] 60 CHARACTER(LEN=maxlen), SAVE :: newH2OIso(5) = ['H2[16]O', 'H[2]HO ', 'H2[18]O', 'H2[17]O', 'H[3]HO '] 61 62 !=== LOCAL COPIES OF THE TRACERS AND ISOTOPES DESCRIPTORS, USED BY getKey (INITIALIZED IN getKey_init) 115 CHARACTER(LEN=maxlen), SAVE :: tran0 = 'air' !--- Default transporting fluid 116 CHARACTER(LEN=maxlen), PARAMETER :: old_phases = 'vlir' !--- Old phases for water (no separator) 117 CHARACTER(LEN=maxlen), PARAMETER :: known_phases = 'glsr' !--- Known phases initials 118 INTEGER, PARAMETER :: nphases = LEN_TRIM(known_phases) !--- Number of phases 119 CHARACTER(LEN=maxlen), SAVE :: phases_names(nphases) & !--- Known phases names 120 = ['gaseous', 'liquid ', 'solid ', 'cloud '] 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 124 CHARACTER(LEN=maxlen), SAVE :: isoFile = 'isotopes_params.def'!--- Name of the isotopes parameters file 125 126 !--- CORRESPONDANCE BETWEEN OLD AND NEW WATER NAMES 127 CHARACTER(LEN=maxlen), SAVE :: oldH2OIso(5) = ['eau', 'HDO', 'O18', 'O17', 'HTO' ] 128 CHARACTER(LEN=maxlen), SAVE :: newH2OIso(5) = ['H216O', 'HDO ', 'H218O', 'H217O', 'HTO '] 129 130 !--- CORRESPONDANCE BETWEEN OLD AND NEW HNO3 RELATED SPECIES NAMES 131 CHARACTER(LEN=maxlen), SAVE :: oldHNO3(2) = ['HNO3_g ', 'HNO3 '] 132 CHARACTER(LEN=maxlen), SAVE :: newHNO3(2) = ['HNO3 ', 'HNO3tot'] 133 134 !=== TRACERS AND ISOTOPES DESCRIPTORS, USED BY getKey 63 135 TYPE(trac_type), ALLOCATABLE, TARGET, SAVE :: tracers(:) 64 136 TYPE(isot_type), ALLOCATABLE, TARGET, SAVE :: isotopes(:) 65 137 66 INTEGER, PARAMETER :: maxTableWidth = 192 !--- Maximum width of a table displayed with "dispTable" 138 !=== ALIASES OF VARIABLES FROM SELECTED ISOTOPES FAMILY EMBEDDED IN "isotope" (isotopes(ixIso)) 139 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 141 INTEGER, SAVE :: nbIso !--- Number of isotopes classes 142 LOGICAL, SAVE :: isoCheck !--- Flag to trigger the checking routines 143 TYPE(keys_type), SAVE, POINTER :: isoKeys(:) !--- ONE SET OF KEYS FOR EACH ISOTOPE (LISTED IN isoName) 144 CHARACTER(LEN=maxlen), SAVE, POINTER :: isoName(:), & !--- ISOTOPES NAMES FOR THE CURRENTLY SELECTED FAMILY 145 isoZone(:), & !--- TAGGING ZONES FOR THE CURRENTLY SELECTED FAMILY 146 isoPhas !--- USED PHASES FOR THE CURRENTLY SELECTED FAMILY 147 INTEGER, SAVE :: niso, nzone, & !--- NUMBER OF ISOTOPES, TAGGING ZONES AND PHASES 148 nphas, ntiso !--- NUMBER OF PHASES AND ISOTOPES + ISOTOPIC TAGGING TRACERS 149 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) 151 152 INTEGER, PARAMETER :: maxTableWidth = 192 !--- Maximum width of a table displayed with "dispTable" 67 153 CHARACTER(LEN=maxlen) :: modname 68 154 … … 72 158 !============================================================================================================================== 73 159 !=== READ ONE OR SEVERAL TRACER FILES AND FILL A "tr" TRACERS DESCRIPTOR DERIVED TYPE. 74 !=== THE RETURN VALUE fType DEPENDS ON WHAT IS FOUND:160 !=== THE RETURNED VALUE fType DEPENDS ON WHAT IS FOUND: 75 161 !=== 0: NO ADEQUATE FILE FOUND ; DEFAULT VALUES MUST BE USED 76 162 !=== 1: AN "OLD STYLE" TRACERS FILE "traceur.def": … … 93 179 ! * If you need to convert a %key/%val pair into a direct-access key, add the corresponding line in "setDirectKeys". 94 180 !============================================================================================================================== 95 LOGICAL FUNCTION readTracersFiles(type_trac, fType, tracs) RESULT(lerr) 96 !------------------------------------------------------------------------------------------------------------------------------ 97 CHARACTER(LEN=*), INTENT(IN) :: type_trac !--- List of components used 98 INTEGER, INTENT(OUT) :: fType !--- Type of input file found 99 TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: tracs(:) 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 100 185 CHARACTER(LEN=maxlen), ALLOCATABLE :: s(:), sections(:), trac_files(:) 101 CHARACTER(LEN=maxlen) :: str, fname, mesg 102 INTEGER :: is, nsec, ierr, it, ntrac, ns, ip, ix 103 LOGICAL, ALLOCATABLE :: ll(:), lGen3(:) 186 CHARACTER(LEN=maxlen) :: str, fname, tname, pname, cname 187 INTEGER :: nsec, ierr, it, ntrac, ns, ip, ix, fType 188 LOGICAL :: lRep 189 TYPE(keys_type), POINTER :: k 104 190 !------------------------------------------------------------------------------------------------------------------------------ 105 191 lerr = .FALSE. 106 192 modname = 'readTracersFiles' 107 193 IF(.NOT.ALLOCATED(dBase)) ALLOCATE(dBase(0)) 108 109 !--- Required sections + corresponding files names (new style single section case) 110 IF(test(strParse(type_trac, '|', sections), lerr)) RETURN !--- Parse "type_trac" list 111 112 nsec = SIZE(sections, DIM=1) 113 ALLOCATE(trac_files(nsec)); DO is=1, nsec; trac_files(is) = 'tracer_'//TRIM(sections(is))//'.def'; END DO 114 115 !--- LOOK AT AVAILABLE FILES 116 ll = .NOT.testFile(trac_files) 117 fType = 0 118 IF(.NOT.testFile('traceur.def') .AND. nsec==1) fType = 1 !--- OLD STYLE FILE 119 IF(.NOT.testFile('tracer.def')) fType = 2 !--- NEW STYLE ; SINGLE FILE, SEVERAL SECTIONS 120 IF(ALL(ll)) fType = 3 !--- NEW STYLE ; SEVERAL FILES, SINGLE SECTION USED 121 IF(ANY(ll) .AND. fType/=3) THEN !--- MISSING FILES 122 IF(test(checkList(trac_files, .NOT.ll, 'Failed reading tracers description', 'files', 'missing'), lerr)) RETURN 123 END IF 124 125 !--- CHECK WHETHER type_trac AND FILE TYPE ARE COMPATIBLE 126 IF(test(fmsg('No multiple sections for the old format "traceur.def"', ll = SIZE(sections)>1 .AND. fType==1), lerr)) RETURN 127 128 !--- TELLS WHAT WAS IS ABOUT TO BE USED 129 IF (fmsg('No adequate tracers description file(s) found ; default values will be used', modname, fType==0)) RETURN 130 CALL msg('Trying to read old-style tracers description file "traceur.def"', modname, fType==1) 131 CALL msg('Trying to read the new style multi-sections tracers description file "tracer.def"', modname, fType==2) 132 CALL msg('Trying to read the new style single section tracers description files "tracer_*.def"', modname, fType==3) 194 lRep=.FALSE.; IF(PRESENT(lRepr)) lRep = lRepr 195 196 !--- 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 198 nsec = SIZE(sections) 133 199 134 200 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 135 201 SELECT CASE(fType) !--- Set %name, %genOName, %parent, %type, %phase, %component, %iGeneration, %keys 136 202 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 137 CASE(1) 203 CASE(1) !=== OLD FORMAT "traceur.def" 138 204 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 139 205 !--- OPEN THE "traceur.def" FILE … … 145 211 146 212 !--- READ THE REMAINING LINES: <hadv> <vadv> <tracer> [<transporting fluid>] 147 ALLOCATE(tracs(ntrac)) 213 IF(ALLOCATED(tracers)) DEALLOCATE(tracers) 214 ALLOCATE(tracers(ntrac)) 148 215 DO it=1,ntrac !=== READ RAW DATA: loop on the line/tracer number 149 216 READ(90,'(a)',IOSTAT=ierr) str 150 217 IF(test(fmsg('Invalid format for "' //TRIM(fname)//'"', modname, ierr>0), lerr)) RETURN 151 218 IF(test(fmsg('Not enough lines in "'//TRIM(fname)//'"', modname, ierr<0), lerr)) RETURN 152 l l = strParse(str, ' ', s, n=ns)219 lerr = strParse(str, ' ', s, ns) 153 220 CALL msg('This file is for air tracers only', modname, ns == 3 .AND. it == 1) 154 221 CALL msg('This files specifies the transporting fluid', modname, ns == 4 .AND. it == 1) 155 tracs(it)%name = old2newName(s(3), ip) !--- Set %name: name of the tracer 156 tracs(it)%parent = tran0 !--- Default transporting fluid name 157 IF(ns == 4) tracs(it)%parent = old2newName(s(4)) !--- Set %parent: parent of the tracer 158 tracs(it)%phase = known_phases(ip:ip) !--- Set %phase: tracer phase (default: "g"azeous) 159 tracs(it)%component = TRIM(type_trac) !--- Set %component: model component name 160 tracs(it)%keys%key = ['hadv', 'vadv'] !--- Set %keys%key 161 tracs(it)%keys%val = s(1:2) !--- Set %keys%val 222 k => tracers(it)%keys 223 224 !=== NAME OF THE TRACER 225 tname = old2newH2O(s(3), ip) 226 ix = strIdx(oldHNO3, s(3)) 227 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 230 tracers(it)%keys%name = tname !--- Copy tracers names in keys components 231 232 !=== NAME OF THE COMPONENT 233 cname = type_trac !--- Name of the model component 234 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 237 238 !=== NAME OF THE PARENT 239 pname = tran0 !--- Default name: default transporting fluid (air) 240 IF(ns == 4) THEN 241 pname = old2newH2O(s(4)) 242 ix = strIdx(oldHNO3, s(4)) 243 IF(ix /= 0 .AND. lRep) pname = newHNO3(ix) !--- Exception for HNO3 (REPROBUS ONLY) 244 END IF 245 tracers(it)%parent = pname !--- Set %parent 246 CALL addKey_1('parent', pname, k) 247 248 !=== 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 162 253 END DO 163 254 CLOSE(90) 164 CALL setGeneration(tracs) !--- Set %iGeneration and %gen0Name 165 WHERE(tracs%iGeneration == 2) tracs%type = 'tag' !--- Set %type: 'tracer' or 'tag' 166 IF(test(checkTracers(tracs, fname, fname), lerr)) RETURN !--- Detect orphans and check phases 167 IF(test(checkUnique (tracs, fname, fname), lerr)) RETURN !--- Detect repeated tracers 168 CALL sortTracers (tracs) !--- Sort the tracers 169 tracs(:)%keys%name = tracs(:)%name !--- Copy tracers names in keys components 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 259 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 170 263 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 171 264 CASE(2); IF(test(feedDBase(["tracer.def"], [type_trac], modname), lerr)) RETURN !=== SINGLE FILE, MULTIPLE SECTIONS … … 175 268 END SELECT 176 269 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 177 178 270 IF(ALL([2,3] /= fType)) RETURN 179 271 180 272 IF(nsec == 1) THEN; 181 trac s = dBase(1)%trac273 tracers = dBase(1)%trac 182 274 ELSE IF(tracs_merge) THEN 183 275 CALL msg('The multiple required sections will be MERGED.', modname) 184 IF(test(mergeTracers(dBase, trac s), lerr)) RETURN276 IF(test(mergeTracers(dBase, tracers), lerr)) RETURN 185 277 ELSE 186 278 CALL msg('The multiple required sections will be CUMULATED.', modname) 187 IF(test(cumulTracers(dBase, trac s), lerr)) RETURN279 IF(test(cumulTracers(dBase, tracers), lerr)) RETURN 188 280 END IF 189 WHERE(tracs%gen0Name(1:3) /= 'H2O') tracs%isInPhysics=.TRUE. !--- Set %isInPhysics: passed to physics 190 CALL setDirectKeys(tracs) !--- Set %iqParent, %iqDescen, %nqDescen, %nqChilds 281 CALL setDirectKeys(tracers) !--- Set %iqParent, %iqDescen, %nqDescen, %nqChildren 191 282 END FUNCTION readTracersFiles 283 !============================================================================================================================== 284 285 286 !============================================================================================================================== 287 LOGICAL FUNCTION testTracersFiles(modname, type_trac, fType, lDisp, tracf, sects) RESULT(lerr) 288 CHARACTER(LEN=*), INTENT(IN) :: modname, type_trac 289 INTEGER, INTENT(OUT) :: fType 290 LOGICAL, OPTIONAL, INTENT(IN) :: lDisp 291 CHARACTER(LEN=maxlen), ALLOCATABLE, OPTIONAL, INTENT(OUT) :: tracf(:), sects(:) 292 CHARACTER(LEN=maxlen), ALLOCATABLE :: trac_files(:), sections(:) 293 LOGICAL, ALLOCATABLE :: ll(:) 294 LOGICAL :: lD, lFound 295 INTEGER :: is, nsec 296 lD = .FALSE.; IF(PRESENT(lDisp)) lD = lDisp 297 lerr = .FALSE. 298 299 !--- PARSE "type_trac" LIST AND DETERMINE THE TRACERS FILES NAMES (FOR CASE 3: MULTIPLE FILES, SINGLE SECTION PER FILE) 300 !--- 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 302 IF(PRESENT(sects)) sects = sections 303 ALLOCATE(trac_files(nsec), ll(nsec)) 304 DO is=1, nsec 305 trac_files(is) = 'tracer_'//TRIM(sections(is))//'.def' 306 INQUIRE(FILE=TRIM(trac_files(is)), EXIST=ll(is)) 307 END DO 308 IF(PRESENT(tracf)) tracf = trac_files 309 fType = 0 310 INQUIRE(FILE='traceur.def', EXIST=lFound); IF(lFound) fType = 1 !--- OLD STYLE FILE 311 INQUIRE(FILE='tracer.def', EXIST=lFound); IF(lFound) fType = 2 !--- NEW STYLE ; SINGLE FILE, SEVERAL SECTIONS 312 IF(ALL(ll)) fType = 3 !--- NEW STYLE ; SEVERAL FILES, SINGLE SECTION USED 313 IF(.NOT.lD) RETURN !--- NO CHECKING/DISPLAY NEEDED: JUST GET type_trac,fType 314 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 316 END IF 317 318 !--- TELLS WHAT WAS IS ABOUT TO BE USED 319 CALL msg('Trying to read old-style tracers description file "traceur.def"', modname, fType==1) 320 CALL msg('Trying to read the new style multi-sections tracers description file "tracer.def"', modname, fType==2) 321 CALL msg('Trying to read the new style single section tracers description files "tracer_*.def"', modname, fType==3) 322 END FUNCTION testTracersFiles 192 323 !============================================================================================================================== 193 324 … … 206 337 INTEGER, ALLOCATABLE :: ndb(:) !--- Number of sections for each file 207 338 INTEGER, ALLOCATABLE :: ixf(:) !--- File index for each section of the expanded list 208 LOGICAL, ALLOCATABLE :: lTg(:) !--- Tagging tracers mask209 339 CHARACTER(LEN=maxlen) :: fnm, snm 210 340 INTEGER :: idb, i … … 224 354 lerr = ANY([(dispTraSection('RAW CONTENT OF SECTION "'//TRIM(snm)//'"', snm, modname), idb=1, SIZE(dBase))]) 225 355 IF(test(expandSection(dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- EXPAND NAMES ; set %parent, %type, %component 226 CALL setGeneration (dBase(idb)%trac)!--- set %iGeneration, %genOName356 IF(test(setGeneration(dBase(idb)%trac), lerr)) RETURN !--- set %iGeneration, %genOName 227 357 IF(test(checkTracers (dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- CHECK ORPHANS AND PHASES 228 358 IF(test(checkUnique (dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- CHECK TRACERS UNIQUENESS … … 246 376 CHARACTER(LEN=maxlen), ALLOCATABLE :: sec(:) 247 377 INTEGER, ALLOCATABLE :: ix(:) 248 INTEGER :: n0, idb, ndb , i, j378 INTEGER :: n0, idb, ndb 249 379 LOGICAL :: ll 250 380 !------------------------------------------------------------------------------------------------------------------------------ … … 299 429 CALL MOVE_ALLOC(FROM=tdb, TO=dBase) 300 430 ELSE !=== TRACER LINE 301 ll = strParse(str,' ', keys = s, vals = v, n = n)!--- Parse <key>=<val> pairs431 ll = strParse(str,' ', s, n, v) !--- Parse <key>=<val> pairs 302 432 tt = dBase(ndb)%trac(:) 303 433 tmp%name = s(1); tmp%keys = keys_type(s(1), s(2:n), v(2:n)) !--- Set %name and %keys … … 330 460 ky => t(jd)%keys 331 461 DO k = 1, SIZE(ky%key) !--- Loop on the keys of the tracer named "defName" 332 ! CALL addKey_m(ky%key(k), ky%val(k), t(:)%keys )!--- Add key to all the tracers (no overwriting)333 DO it = 1, SIZE(t); CALL addKey_1(ky%key(k), ky%val(k), t(it)%keys ); END DO462 ! 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 334 464 END DO 335 465 tt = [t(1:jd-1),t(jd+1:SIZE(t))]; CALL MOVE_ALLOC(FROM=tt, TO=t) !--- Remove the virtual tracer named "defName" … … 381 511 CHARACTER(LEN=maxlen), ALLOCATABLE :: ta(:), pa(:) 382 512 CHARACTER(LEN=maxlen) :: msg1, modname 383 INTEGER :: it, nt, iq, nq, itr, ntr, ipr, npr , i513 INTEGER :: it, nt, iq, nq, itr, ntr, ipr, npr 384 514 LOGICAL :: ll 385 515 modname = 'expandSection' … … 394 524 tr(it)%type = fgetKey(it, 'type' , tr(:)%keys, 'tracer') 395 525 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 396 528 397 529 !--- Determine the number of tracers and parents ; coherence checking … … 409 541 END DO 410 542 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 411 CALL delKey(['parent','type '], tr)412 543 413 544 ALLOCATE(ttr(nq)) … … 416 547 DO it = 1, nt !=== EXPAND TRACERS AND PARENTS NAMES LISTS 417 548 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 418 ll = strParse(tr(it)%name, ',', ta, n =ntr)!--- Number of tracers419 ll = strParse(tr(it)%parent, ',', pa, n =npr)!--- Number of parents549 ll = strParse(tr(it)%name, ',', ta, ntr) !--- Number of tracers 550 ll = strParse(tr(it)%parent, ',', pa, npr) !--- Number of parents 420 551 DO ipr=1,npr !--- Loop on parents list elts 421 552 DO itr=1,ntr !--- Loop on tracers list elts 422 i = iq+itr-1+(ipr-1)*ntr 423 ttr(i)%name = TRIM(ta(itr)) 424 ttr(i)%parent = TRIM(pa(ipr)) 425 ttr(i)%keys%name = ta(itr) 426 ttr(i)%keys%key = tr(it)%keys%key 427 ttr(i)%keys%val = tr(it)%keys%val 428 ! ttr(i)%keys = keys_type(ta(itr), tr(it)%keys%key, tr(it)%keys%val) 553 ttr(iq)%keys%key = tr(it)%keys%key 554 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 429 561 END DO 430 562 END DO 431 ttr(iq:iq+ntr*npr-1)%type = tr(it)%type !--- Duplicating type432 ttr(iq:iq+ntr*npr-1)%component = tr(it)%component !--- Duplicating type433 iq = iq + ntr*npr434 563 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 435 564 END DO … … 441 570 !============================================================================================================================== 442 571 443 !============================================================================================================================== 444 SUBROUTINE setGeneration(tr) 572 573 !============================================================================================================================== 574 LOGICAL FUNCTION setGeneration(tr) RESULT(lerr) 445 575 !------------------------------------------------------------------------------------------------------------------------------ 446 576 ! Purpose: Determine, for each tracer of "tr(:)": 447 577 ! * %iGeneration: the generation number 448 578 ! * %gen0Name: the generation 0 ancestor name 579 ! Check also for orphan tracers (tracers not descending on "tran0"). 449 580 !------------------------------------------------------------------------------------------------------------------------------ 450 581 TYPE(trac_type), INTENT(INOUT) :: tr(:) !--- Tracer derived type vector 451 INTEGER :: iq, nq, ig 452 LOGICAL, ALLOCATABLE :: lg(:) 453 CHARACTER(LEN=maxlen), ALLOCATABLE :: prn(:) 454 !------------------------------------------------------------------------------------------------------------------------------ 455 tr(:)%iGeneration = -1 !--- error if -1 456 nq = SIZE(tr, DIM=1) !--- Number of tracers lines 457 lg = tr(:)%parent == tran0 !--- Flag for generation 0 tracers 458 WHERE(lg) tr(:)%iGeneration = 0 !--- Generation 0 tracers 459 460 !=== Determine generation for each tracer 461 ig=-1; prn = [tran0] 462 DO !--- Update current generation flag 463 IF(ig/=-1) prn = PACK( tr(:)%name, MASK=tr(:)%iGeneration == ig) 464 lg(:) = [(ANY(prn(:) == tr(iq)%parent), iq=1, nq)] !--- Current generation tracers flag 465 IF( ALL( .NOT. lg ) ) EXIT !--- Empty current generation 466 ig = ig+1; WHERE(lg) tr(:)%iGeneration = ig 467 END DO 468 tr(:)%gen0Name = ancestor(tr) !--- First generation ancestor name 469 470 END SUBROUTINE setGeneration 471 !============================================================================================================================== 582 INTEGER :: iq, jq, ig 583 CHARACTER(LEN=maxlen), ALLOCATABLE :: parent(:) 584 !------------------------------------------------------------------------------------------------------------------------------ 585 CHARACTER(LEN=maxlen) :: modname 586 modname = 'setGeneration' 587 IF(test(fmsg('missing "parent" attribute', modname, getKey('parent', parent, ky=tr(:)%keys)), lerr)) RETURN 588 DO iq = 1, SIZE(tr) 589 jq = iq; ig = 0 590 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 593 ig = ig + 1 594 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) 597 END DO 598 END FUNCTION setGeneration 599 !============================================================================================================================== 600 472 601 473 602 !============================================================================================================================== … … 503 632 END FUNCTION checkTracers 504 633 !============================================================================================================================== 634 505 635 506 636 !============================================================================================================================== … … 543 673 !============================================================================================================================== 544 674 675 545 676 !============================================================================================================================== 546 677 SUBROUTINE expandPhases(tr) … … 552 683 TYPE(trac_type), ALLOCATABLE :: ttr(:) 553 684 INTEGER, ALLOCATABLE :: i0(:) 554 CHARACTER(LEN=maxlen) :: nam, pha, t rn685 CHARACTER(LEN=maxlen) :: nam, pha, tname 555 686 CHARACTER(LEN=1) :: p 556 687 INTEGER :: ip, np, iq, jq, nq, it, nt, nc, i, n 557 LOGICAL :: lT g, lEx688 LOGICAL :: lTag, lExt 558 689 !------------------------------------------------------------------------------------------------------------------------------ 559 690 nq = SIZE(tr, DIM=1) … … 561 692 DO iq = 1, nq !--- GET THE NUMBER OF TRACERS 562 693 IF(tr(iq)%iGeneration /= 0) CYCLE !--- Only deal with generation 0 tracers 563 nc = COUNT(tr(:)%gen0Name==tr(iq)%name .AND. tr%iGeneration/=0) !--- Number of child sof tr(iq)564 tr(iq)%phase = fgetKey(iq, 'phases', tr(:)%keys) !--- Phases list of tr(iq)565 np = LEN_TRIM(tr(iq)%phase) !--- Number of phases of tr(iq)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) 566 697 nt = nt + (1+nc) * np !--- Number of tracers after expansion 567 698 END DO … … 569 700 it = 1 !--- Current "ttr(:)" index 570 701 DO iq = 1, nq !--- Loop on "tr(:)" indexes 571 lT g = tr(iq)%type=='tag'!--- Current tracer is a tag702 lTag = tr(iq)%type=='tag' !--- Current tracer is a tag 572 703 i0 = strFind(tr(:)%name, TRIM(tr(iq)%gen0Name), n) !--- Indexes of first generation ancestor copies 573 704 np = SUM([( LEN_TRIM(tr(i0(i))%phase),i=1,n )], 1) !--- Number of phases for current tracer tr(iq) 574 lEx = np>1!--- Phase suffix only required if phases number is > 1575 IF(lT g) lEx = lEx .AND. tr(iq)%iGeneration>0!--- No phase suffix for generation 0 tags705 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 576 707 DO i=1,n !=== LOOP ON GENERATION 0 ANCESTORS 577 708 jq = i0(i) !--- tr(jq): ith tracer with same gen 0 ancestor as tr(iq) … … 580 711 DO ip = 1, LEN_TRIM(pha) !=== LOOP ON PHASES LISTS 581 712 p = pha(ip:ip) 582 t rn = TRIM(tr(iq)%name); nam = trn!--- Tracer name (regular case)583 IF(lT g) nam = TRIM(tr(iq)%parent)!--- Parent name (tagging case)584 IF(lEx ) nam = addPhase(nam, p )!--- Phase extension needed585 IF(lT g) nam = TRIM(nam)//'_'//TRIM(trn)!--- <parent>_<name> for tags713 tname = TRIM(tr(iq)%name); nam = tname !--- Tracer name (regular case) 714 IF(lTag) nam = TRIM(tr(iq)%parent) !--- Parent name (tagging case) 715 IF(lExt) nam = addPhase(nam, p ) !--- Phase extension needed 716 IF(lTag) nam = TRIM(nam)//'_'//TRIM(tname) !--- <parent>_<name> for tags 586 717 ttr(it) = tr(iq) !--- Same <key>=<val> pairs 587 718 ttr(it)%name = TRIM(nam) !--- Name with possibly phase suffix 588 719 ttr(it)%keys%name = TRIM(nam) !--- Name inside the keys decriptor 589 720 ttr(it)%phase = p !--- Single phase entry 590 IF(lEx .AND. tr(iq)%iGeneration>0) THEN 591 ttr(it)%parent = addPhase(ttr(it)%parent, p) 592 ttr(it)%gen0Name = addPhase(ttr(it)%gen0Name, p) 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) 593 728 END IF 594 729 it = it+1 … … 603 738 !============================================================================================================================== 604 739 740 605 741 !============================================================================================================================== 606 742 SUBROUTINE sortTracers(tr) … … 609 745 ! * Put water at the beginning of the vector, in the "known_phases" order. 610 746 ! * lGrowGen == T: in ascending generations numbers. 611 ! * lGrowGen == F: tracer + its child ssorted by growing generation, one after the other.747 ! * lGrowGen == F: tracer + its children sorted by growing generation, one after the other. 612 748 ! TO BE ADDED IF NECESSARY: HIGHER MOMENTS AT THE END 613 749 !------------------------------------------------------------------------------------------------------------------------------ 614 750 TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:) !--- Tracer derived type vector 615 INTEGER, ALLOCATABLE :: iy(:), iz(:) 616 INTEGER :: ig, ng, iq, jq, ip, nq, n, ix(SIZE(tr)), k 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 755 ! tr2 is introduced in order to cope with a bug in gfortran 4.8.5 compiler 617 756 !------------------------------------------------------------------------------------------------------------------------------ 618 757 nq = SIZE(tr) … … 620 759 iq = strIdx(tr(:)%name, addPhase('H2O', ip)) 621 760 IF(iq == 0) CYCLE 622 tr = [tr(iq), tr(1:iq-1), tr(iq+1:nq)] 761 tr2 = tr(:) 762 tr = [tr2(iq), tr2(1:iq-1), tr2(iq+1:nq)] 623 763 END DO 624 764 IF(lSortByGen) THEN … … 637 777 ix(iq) = jq !--- Generation 0 ancestor index first 638 778 iq = iq + 1 !--- Next "iq" for next generations tracers 639 iy = strFind(tr(:)%gen0Name, TRIM(tr(jq)%name)) !--- Indexes of "tr(jq)" child sin "tr(:)"779 iy = strFind(tr(:)%gen0Name, TRIM(tr(jq)%name)) !--- Indexes of "tr(jq)" children in "tr(:)" 640 780 ng = MAXVAL(tr(iy)%iGeneration, MASK=.TRUE., DIM=1) !--- Number of generations of the "tr(jq)" family 641 781 DO ig = 1, ng !--- Loop on generations of the "tr(jq)" family … … 649 789 END SUBROUTINE sortTracers 650 790 !============================================================================================================================== 791 651 792 652 793 !============================================================================================================================== … … 724 865 TYPE(dataBase_type), TARGET, INTENT(IN) :: sections(:) 725 866 TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: tr(:) 726 TYPE(trac_type), POINTER :: t 1(:), t2(:)867 TYPE(trac_type), POINTER :: t(:) 727 868 INTEGER, ALLOCATABLE :: nt(:) 728 869 CHARACTER(LEN=maxlen) :: tnam, tnam_new … … 735 876 DO is=1, nsec !=== LOOP ON SECTIONS 736 877 !---------------------------------------------------------------------------------------------------------------------------- 737 t 1=> sections(is)%trac(:)878 t => sections(is)%trac(:) 738 879 !-------------------------------------------------------------------------------------------------------------------------- 739 880 DO iq=1, nt(is) !=== LOOP ON TRACERS 740 881 !-------------------------------------------------------------------------------------------------------------------------- 741 tnam = TRIM(t 1(iq)%name)!--- Original name742 IF(COUNT(t 1%name == tnam) == 1) CYCLE!--- Current tracer is not duplicated: finished882 tnam = TRIM(t(iq)%name) !--- Original name 883 IF(COUNT(t%name == tnam) == 1) CYCLE !--- Current tracer is not duplicated: finished 743 884 tnam_new = TRIM(tnam)//'_'//TRIM(sections(is)%name) !--- Same with section extension 744 885 nq = SUM(nt(1:is-1)) !--- Number of tracers in previous sections … … 759 900 TYPE(trac_type), INTENT(INOUT) :: tr(:) 760 901 761 !--- Update %iqParent, %iqDescen, %nqDescen, %nqChild s902 !--- Update %iqParent, %iqDescen, %nqDescen, %nqChildren 762 903 CALL indexUpdate(tr) 763 904 … … 774 915 INTEGER :: idb, iq, nq 775 916 INTEGER, ALLOCATABLE :: hadv(:), vadv(:) 776 CHARACTER(LEN=maxlen), ALLOCATABLE :: phas(:) 917 CHARACTER(LEN=maxlen), ALLOCATABLE :: phas(:), prnt(:) 777 918 TYPE(trac_type), POINTER :: tm(:) 778 919 lerr = .FALSE. … … 782 923 !--- BEWARE ! Can't use the "getKeyByName" functions yet. 783 924 ! Names must first include the phases for tracers defined on multiple lines. 784 hadv = str2int([(fgetKey(iq, 'hadv', tm(:)%keys, '10'), iq=1, nq)]) 785 vadv = str2int([(fgetKey(iq, 'vadv', tm(:)%keys, '10'), iq=1, nq)]) 786 phas = [(fgetKey(iq, 'phases',tm(:)%keys, 'g' ), iq=1, nq)] 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') 787 929 CALL msg(TRIM(message)//':', modname) 788 IF(ALL(tm(:)%parent == '')) THEN 789 IF(test(dispTable('iiiss', ['iq ','hadv ','vadv ','name ','phase '], cat(tm%name, phas), & 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), & 790 935 cat([(iq, iq=1, nq)], hadv, vadv), nColMax=maxTableWidth, nHead=2, sub=modname), lerr)) RETURN 791 936 ELSE 792 IF(test(dispTable('iiissis', ['iq ','hadv ','vadv ','name ','parent','igen ','phase '], cat(tm%name, tm%parent,&793 tm%phase),cat([(iq, iq=1, nq)], hadv, vadv, tm%iGeneration), nColMax=maxTableWidth, nHead=2, sub=modname), lerr)) RETURN937 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 794 939 END IF 795 940 END FUNCTION dispTraSection 796 !==============================================================================================================================797 941 !============================================================================================================================== 798 942 … … 809 953 out => NULL(); IF(it /= 0) out => t(it) 810 954 END FUNCTION aliasTracer 811 ! ------------------------------------------------------------------------------------------------------------------------------955 !============================================================================================================================== 812 956 813 957 … … 830 974 CALL indexUpdate(out) 831 975 END FUNCTION trSubset_Name 832 ! ------------------------------------------------------------------------------------------------------------------------------976 !============================================================================================================================== 833 977 834 978 … … 843 987 CALL indexUpdate(out) 844 988 END FUNCTION trSubset_gen0Name 845 ! ------------------------------------------------------------------------------------------------------------------------------989 !============================================================================================================================== 846 990 847 991 … … 851 995 SUBROUTINE indexUpdate(tr) 852 996 TYPE(trac_type), INTENT(INOUT) :: tr(:) 853 INTEGER :: iq, ig, ng, igen, ngen 854 INTEGER, ALLOCATABLE :: ix(:) 997 INTEGER :: iq, ig, igen, ngen, ix(SIZE(tr)) 855 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 856 1000 ngen = MAXVAL(tr(:)%iGeneration, MASK=.TRUE.) 857 1001 DO iq = 1, SIZE(tr) … … 859 1003 IF(ALLOCATED(tr(iq)%iqDescen)) DEALLOCATE(tr(iq)%iqDescen) 860 1004 ALLOCATE(tr(iq)%iqDescen(0)) 861 ix = idxAncestor(tr, igen=ig)!--- Ancestor of generation "ng" for each tr1005 CALL idxAncestor(tr, ix, ig) !--- Ancestor of generation "ng" for each tr 862 1006 DO igen = ig+1, ngen 863 1007 tr(iq)%iqDescen = [tr(iq)%iqDescen, find(ix==iq .AND. tr%iGeneration==igen)] 864 1008 tr(iq)%nqDescen = SIZE(tr(iq)%iqDescen) 865 IF(igen == ig+1) tr(iq)%nqChilds=tr(iq)%nqDescen 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 866 1013 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) 867 1016 END DO 868 1017 END SUBROUTINE indexUpdate 869 ! ------------------------------------------------------------------------------------------------------------------------------1018 !============================================================================================================================== 870 1019 871 1020 … … 875 1024 !=== * For each isotopes class, the <key>=<val> vector of each tracer is moved into the isotopes descriptor "isot" ==== 876 1025 !=== NOTES: ==== 877 !=== * Most of the "isot" components have been defined in the calling routine ( initIsotopes): ====1026 !=== * Most of the "isot" components have been defined in the calling routine (readIsotopes): ==== 878 1027 !=== parent, nzone, zone(:), niso, keys(:)%name, ntiso, trac(:), nphas, phas, iqIsoPha(:,:), itZonPhi(:,:) ==== 879 1028 !=== * Same syntax for isotopes file and "tracer.def": a tracers section contains one line for each of its isotopes ==== … … 883 1032 !=== * The routine gives an error if a required isotope is not available in the database stored in "fnam" ==== 884 1033 !============================================================================================================================== 885 LOGICAL FUNCTION readIsotopesFile (fnam, isot) RESULT(lerr)1034 LOGICAL FUNCTION readIsotopesFile_prv(fnam, isot) RESULT(lerr) 886 1035 CHARACTER(LEN=*), INTENT(IN) :: fnam !--- Input file name 887 TYPE(isot_type), TARGET, INTENT(INOUT) :: isot(:) !--- Isotopes descriptors (field "prnt" must be defined !) 888 INTEGER :: ik, is, it, idb, nk0, i, iis 889 INTEGER :: nk, ns, nt, ndb, nb0, i0 890 CHARACTER(LEN=maxlen), POINTER :: k(:), v(:), k0(:), v0(:) 1036 TYPE(isot_type), TARGET, INTENT(INOUT) :: isot(:) !--- Isotopes descriptors (field %parent must be defined!) 1037 LOGICAL :: lFound 1038 INTEGER :: is, iis, it, idb, ndb, nb0 891 1039 CHARACTER(LEN=maxlen), ALLOCATABLE :: vals(:) 892 CHARACTER(LEN=maxlen) :: val, modname 893 TYPE(keys_type), POINTER :: ky(:) 1040 CHARACTER(LEN=maxlen) :: modname 894 1041 TYPE(trac_type), POINTER :: tt(:), t 895 1042 TYPE(dataBase_type), ALLOCATABLE :: tdb(:) 896 LOGICAL, ALLOCATABLE :: liso(:)897 1043 modname = 'readIsotopesFile' 898 1044 899 1045 !--- THE INPUT FILE MUST BE PRESENT 900 IF(test(fmsg('Missing isotopes parameters file "'//TRIM(fnam)//'"', modname, testFile(fnam)),lerr)) RETURN 1046 INQUIRE(FILE=TRIM(fnam), EXIST=lFound); lerr = .NOT.lFound 1047 IF(fmsg('Missing isotopes parameters file "'//TRIM(fnam)//'"', modname, lerr)) RETURN 901 1048 902 1049 !--- READ THE FILE SECTIONS, ONE EACH PARENT TRACER … … 905 1052 ndb = SIZE(dBase, DIM=1) !--- Current database size 906 1053 DO idb = nb0, ndb 907 iis = idb-nb0+11054 iis = idb-nb0+1 908 1055 909 1056 !--- GET FEW GLOBAL KEYS FROM "def" FILES AND ADD THEM TO THE 'params' SECTION … … 920 1067 is = strIdx(isot(iis)%keys(:)%name, t%name) !--- Index in "isot(iis)%keys(:)%name" of isotope "t%name" 921 1068 IF(is == 0) CYCLE 922 liso = reduceExpr(t%keys%val, vals) !--- Reduce expressions (for substituted variables) 923 IF(test(ANY(liso), lerr)) RETURN !--- Some non-numerical elements were found 924 isot(iis)%keys(is)%key = PACK(t%keys%key, MASK=.NOT.liso) 925 isot(iis)%keys(is)%val = PACK( vals, MASK=.NOT.liso) 1069 IF(test(ANY(reduceExpr(t%keys%val, vals)), lerr)) RETURN !--- Reduce expressions ; detect non-numerical elements 1070 isot(iis)%keys(is)%key = t%keys%key 1071 isot(iis)%keys(is)%val = vals 926 1072 END DO 927 1073 928 1074 !--- CHECK FOR MISSING ISOTOPES (NO KEYS ALLOCATED) 929 liso = [( ALLOCATED(isot(iis)%keys(is)%key), is=1, SIZE(isot(iis)%keys) )] 930 IF(test(checkList(isot(iis)%keys(:)%name, .NOT.liso, & 931 'Check file "'//TRIM(fnam)//'" in section "'//TRIM(dBase(idb)%name)//'"', 'isotopes', 'missing'),lerr)) RETURN 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 932 1077 END DO 933 1078 … … 942 1087 CALL get_in('ok_iso_verif', isot(strIdx(isot%parent, 'H2O'))%check, .FALSE.) 943 1088 944 lerr = dispIsotopes(isot, 'Isotopes parameters read from file "'//TRIM(fnam)//'"', modname) 945 946 END FUNCTION readIsotopesFile 947 !============================================================================================================================== 1089 lerr = dispIsotopes() 1090 1091 CONTAINS 1092 1093 !------------------------------------------------------------------------------------------------------------------------------ 1094 LOGICAL FUNCTION dispIsotopes() RESULT(lerr) 1095 INTEGER :: ik, nk, ip, it, nt 1096 CHARACTER(LEN=maxlen) :: prf 1097 CHARACTER(LEN=maxlen), ALLOCATABLE :: ttl(:), val(:,:) 1098 CALL msg('Isotopes parameters read from file "'//TRIM(fnam)//'":', modname) 1099 DO ip = 1, SIZE(isot) !--- Loop on parents tracers 1100 nk = SIZE(isot(ip)%keys(1)%key) !--- Same keys for each isotope 1101 nt = SIZE(isot(ip)%keys) !--- Number of isotopes 1102 prf = 'i'//REPEAT('s',nk+1) !--- Profile for table printing 1103 ALLOCATE(ttl(nk+2), val(nt,nk+1)) 1104 ttl(1:2) = ['it ','name']; ttl(3:nk+2) = isot(ip)%keys(1)%key(:)!--- Titles line with keys names 1105 val(:,1) = isot(ip)%keys(:)%name !--- Values table 1st column: isotopes names 1106 DO ik = 1, nk 1107 DO it = 1, nt 1108 val(it,ik+1) = isot(ip)%keys(it)%val(ik) !--- Other columns: keys values 1109 END DO 1110 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 1113 DEALLOCATE(ttl, val) 1114 END DO 1115 END FUNCTION dispIsotopes 1116 !------------------------------------------------------------------------------------------------------------------------------ 1117 1118 END FUNCTION readIsotopesFile_prv 1119 !============================================================================================================================== 1120 948 1121 949 1122 !============================================================================================================================== … … 951 1124 !=== * COMPUTE MOST OF THE RELATED QUANTITIES ("isot" COMPONENTS). === 952 1125 !=== * COMPUTE FEW ISOTOPES-DEDICATED "trac" COMPONENTS === 953 !=== * CALL readIsotopesFile TO GET PHYSICAL QUANTITIES (<key>=<val> PAIRS)===1126 !=== * CALL readIsotopesFile_prv TO GET PHYSICAL QUANTITIES (<key>=<val> PAIRS) === 954 1127 !=== NOTE: THIS IS DONE HERE (IN A ROUTINE CALLED BY THE DYNAMIC), BECAUSE THE DYNAMIC NEEDS FEW PHYSICAL PARAMETERS. === 955 1128 !============================================================================================================================== 956 LOGICAL FUNCTION initIsotopes(trac, isot) RESULT(lerr) 957 TYPE(trac_type), ALLOCATABLE, TARGET, INTENT(INOUT) :: trac(:) 958 TYPE(isot_type), ALLOCATABLE, TARGET, INTENT(INOUT) :: isot(:) 1129 LOGICAL FUNCTION readIsotopesFile(iNames) RESULT(lerr) 1130 CHARACTER(LEN=maxlen), TARGET, OPTIONAL, INTENT(IN) :: iNames(:) 959 1131 CHARACTER(LEN=maxlen), ALLOCATABLE :: p(:), str(:) !--- Temporary storage 960 CHARACTER(LEN=maxlen) :: i name1132 CHARACTER(LEN=maxlen) :: iName, modname 961 1133 CHARACTER(LEN=1) :: ph !--- Phase 962 INTEGER :: nbIso,ic, ip, iq, it, iz1134 INTEGER :: ic, ip, iq, it, iz 963 1135 LOGICAL, ALLOCATABLE :: ll(:) !--- Mask 964 1136 TYPE(trac_type), POINTER :: t(:), t1 965 1137 TYPE(isot_type), POINTER :: i 966 1138 lerr = .FALSE. 967 968 t => trac 969 970 p = PACK(delPhase(t%parent), MASK = t%type=='tracer' .AND. t%iGeneration==1) !--- Parents of generation 1 isotopes 1139 modname = 'readIsotopesFile' 1140 1141 t => tracers 1142 1143 !--- GET FROM "tracers" THE FULL LIST OF AVAILABLE ISOTOPES CLASSES 1144 p = PACK(delPhase(t%parent), MASK = t%type=='tracer' .AND. t%iGeneration==1) 971 1145 CALL strReduce(p, nbIso) 972 ALLOCATE(isot(nbIso)) 1146 1147 !--- CHECK WHETHER NEEDED ISOTOPES CLASSES "iNames" ARE AVAILABLE OR NOT 1148 IF(PRESENT(iNames)) THEN 1149 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 1151 END DO 1152 p = iNames; nbIso = SIZE(p) 1153 END IF 1154 IF(ALLOCATED(isotopes)) DEALLOCATE(isotopes) 1155 ALLOCATE(isotopes(nbIso)) 973 1156 974 1157 IF(nbIso==0) RETURN !=== NO ISOTOPES: FINISHED 975 1158 976 1159 !--- ISOTOPES RELATED VARIABLES ; NULL OR EMPTY IF NO ISOTOPES 977 isot (:)%parent = p1160 isotopes(:)%parent = p 978 1161 DO ic = 1, SIZE(p) !--- Loop on isotopes classes 979 i => isot (ic)1162 i => isotopes(ic) 980 1163 iname = i%parent !--- Current isotopes class name (parent tracer name) 981 1164 982 !=== Isotopes child sof tracer "iname": mask, names, number (same for each phase of "iname")1165 !=== Isotopes children of tracer "iname": mask, names, number (same for each phase of "iname") 983 1166 ll = t(:)%type=='tracer' .AND. delPhase(t(:)%parent) == iname .AND. t(:)%phase == 'g' 984 1167 str = PACK(delPhase(t(:)%name), MASK = ll) !--- Effectively found isotopes of "iname" … … 989 1172 !=== Geographic tagging tracers descending on tracer "iname": mask, names, number 990 1173 ll = t(:)%type=='tag' .AND. delPhase(t(:)%gen0Name) == iname .AND. t(:)%iGeneration == 2 991 i%zone = PACK(strTail(t(:)%name,'_' ), MASK = ll)!--- Tagging zones names for isotopes category "iname"1174 i%zone = PACK(strTail(t(:)%name,'_',.TRUE.), MASK = ll) !--- Tagging zones names for isotopes category "iname" 992 1175 CALL strReduce(i%zone) 993 1176 i%nzone = SIZE(i%zone) !--- Tagging zones number for isotopes category "iname" 994 1177 995 !=== Geographic tracers of the isotopes child sof tracer "iname" (same for each phase of "iname")1178 !=== Geographic tracers of the isotopes children of tracer "iname" (same for each phase of "iname") 996 1179 ! NOTE: One might like to create a similar variable for 2nd generation tagging tracers (tagging the gen1 tracers) 997 1180 str = PACK(delPhase(t(:)%name), MASK=ll) … … 1009 1192 !=== Tables giving the index in a table of effectively found items for each dynamical tracer (1<=iq<=nqtot) 1010 1193 DO iq = 1, SIZE(t) 1011 t1 => trac (iq)1194 t1 => tracers(iq) 1012 1195 IF(delPhase(t1%gen0Name)/=iname .OR. t1%iGeneration==0) CYCLE !--- Only deal with tracers descending on "iname" 1013 1196 t1%iso_iGroup = ic !--- Isotopes family idx in list "isotopes(:)%parent" 1014 t1%iso_iName = strIdx(i%trac, delPhase(strHead(t1%name,'_'))) !--- Current isotope idx in effective isotopes list1015 t1%iso_iZone = strIdx(i%zone, strTail(t1%name, '_')) !--- Current isotope zone idx in effective zones list1197 t1%iso_iName = strIdx(i%trac, strHead(delPhase(t1%name),'_',.TRUE.)) !--- Current isotope idx in effective isotopes list 1198 t1%iso_iZone = strIdx(i%zone, strTail(t1%name, '_',.TRUE.)) !--- Current isotope zone idx in effective zones list 1016 1199 t1%iso_iPhase = INDEX(i%phase,TRIM(t1%phase)) !--- Current isotope phase idx in effective phases list 1017 1200 IF(t1%iGeneration /= 2) t1%iso_iZone = 0 !--- Skip possible generation 1 tagging tracers … … 1020 1203 !=== Table used to get iq (index in dyn array, size nqtot) from the isotope and phase indexes ; the full isotopes list 1021 1204 ! (including tagging tracers) is sorted this way: iso1, iso2, ..., iso1_zone1, iso2_zone1, ..., iso1_zoneN, iso2_zoneN 1022 i%iqIsoPha = RESHAPE( [( (strIdx(t%name, addPhase(i%trac(it),i%phase(ip:ip))), it=1, i%ntiso), ip=1, i%nphas)], &1205 i%iqIsoPha = RESHAPE( [( (strIdx(t%name, addPhase(i%trac(it),i%phase(ip:ip))), it=1, i%ntiso), ip=1, i%nphas)], & 1023 1206 [i%ntiso, i%nphas] ) 1024 1207 !=== Table used to get ix (index in tagging tracers isotopes list, size ntiso) from the zone and isotope indexes … … 1027 1210 END DO 1028 1211 1029 !=== READ PHYSICAL PARAMETERS FROM "isotopes_params.def" FILE 1030 ! DONE HERE, AND NOT ONLY IN "infotrac_phy", BECAUSE SOME PHYSICAL PARAMS ARE NEEDED FOR RESTARTS (tnat AND alpha_ideal) 1031 lerr = readIsotopesFile('isotopes_params.def',isot) 1032 1033 END FUNCTION initIsotopes 1034 !============================================================================================================================== 1035 1036 1037 !============================================================================================================================== 1038 LOGICAL FUNCTION dispIsotopes(ides, message, modname) RESULT(lerr) 1039 TYPE(isot_type), INTENT(IN) :: ides(:) !--- Isotopes descriptor vector 1040 CHARACTER(LEN=*), INTENT(IN) :: message !--- Message to display 1041 CHARACTER(LEN=*), INTENT(IN) :: modname !--- Calling subroutine name 1042 INTEGER :: ik, nk, ip, it, nt 1043 CHARACTER(LEN=maxlen) :: prf 1044 CHARACTER(LEN=maxlen), ALLOCATABLE :: ttl(:), val(:,:) 1045 CALL msg(TRIM(message)//':', modname) 1046 DO ip = 1, SIZE(ides) !--- Loop on parents tracers 1047 nk = SIZE(ides(ip)%keys(1)%key) !--- Same keys for each isotope 1048 nt = SIZE(ides(ip)%keys) !--- Number of isotopes 1049 prf = 'i'//REPEAT('s',nk+1) !--- Profile for table printing 1050 ALLOCATE(ttl(nk+2), val(nt,nk+1)) 1051 ttl(1:2) = ['iq ','name']; ttl(3:nk+2) = ides(ip)%keys(1)%key(:)!--- Titles line with keys names 1052 val(:,1) = ides(ip)%keys(:)%name !--- Values table 1st column: isotopes names 1053 DO ik = 1, nk 1054 DO it = 1, nt 1055 val(it,ik+1) = ides(ip)%keys(it)%val(ik) !--- Other columns: keys values 1056 END DO 1212 !=== READ PHYSICAL PARAMETERS FROM isoFile FILE 1213 IF(test(readIsotopesFile_prv(isoFile, isotopes), lerr)) RETURN 1214 1215 !=== 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 1220 1221 CONTAINS 1222 1223 !------------------------------------------------------------------------------------------------------------------------------ 1224 LOGICAL FUNCTION testIsotopes() RESULT(lerr) !--- MAKE SURE MEMBERS OF AN ISOTOPES FAMILY ARE PRESENT IN THE SAME PHASES 1225 !------------------------------------------------------------------------------------------------------------------------------ 1226 INTEGER :: ix, it, ip, np, iz, nz 1227 TYPE(isot_type), POINTER :: i 1228 DO ix = 1, nbIso 1229 i => isotopes(ix) 1230 !--- 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 1057 1235 END DO 1058 IF(test(fmsg('Problem with the table content', modname, dispTable(prf, ttl, val, & 1059 cat([(it,it=1,nt)]), rFmt='(EN8.4)', nColMax=maxTableWidth, nHead=2, sub=modname)), lerr)) RETURN 1060 DEALLOCATE(ttl, val) 1061 END DO 1062 END FUNCTION dispIsotopes 1063 !============================================================================================================================== 1064 1065 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 1240 END DO 1241 END DO 1242 END FUNCTION testIsotopes 1243 !------------------------------------------------------------------------------------------------------------------------------ 1244 1245 END FUNCTION readIsotopesFile 1246 !============================================================================================================================== 1247 1248 1249 !============================================================================================================================== 1250 !=== THE ROUTINE isoSelect IS USED TO SWITCH FROM AN ISOTOPE FAMILY TO ANOTHER: ISOTOPES DEPENDENT PARAMETERS ARE UPDATED 1251 ! Single generic "isoSelect" routine, using the predefined index of the parent (fast version) or its name (first call). 1252 !============================================================================================================================== 1253 LOGICAL FUNCTION isoSelectByName(iName, lVerbose) RESULT(lerr) 1254 IMPLICIT NONE 1255 CHARACTER(LEN=*), INTENT(IN) :: iName 1256 LOGICAL, OPTIONAL, INTENT(IN) :: lVerbose 1257 INTEGER :: iIso 1258 LOGICAL :: lV 1259 lV = .FALSE.; IF(PRESENT(lVerbose)) lV = lVerbose 1260 iIso = strIdx(isotopes(:)%parent, iName) 1261 IF(test(iIso == 0, lerr)) THEN 1262 niso = 0; ntiso = 0; nzone = 0; nphas = 0; isoCheck=.FALSE. 1263 CALL msg('no isotope family named "'//TRIM(iName)//'"', ll=lV) 1264 RETURN 1265 END IF 1266 lerr = isoSelectByIndex(iIso, lV) 1267 END FUNCTION isoSelectByName 1268 !============================================================================================================================== 1269 LOGICAL FUNCTION isoSelectByIndex(iIso, lVerbose) RESULT(lerr) 1270 IMPLICIT NONE 1271 INTEGER, INTENT(IN) :: iIso 1272 LOGICAL, OPTIONAL, INTENT(IN) :: lVerbose 1273 LOGICAL :: lV 1274 lv = .FALSE.; IF(PRESENT(lVerbose)) lv = lVerbose 1275 lerr = .FALSE. 1276 IF(iIso == ixIso) RETURN !--- Nothing to do if the index is already OK 1277 lerr = iIso<=0 .OR. iIso>SIZE(isotopes) 1278 CALL msg('Inconsistent isotopes family index '//TRIM(int2str(iIso))//': should be > 0 and <= '& 1279 //TRIM(int2str(SIZE(isotopes)))//'"', ll = lerr .AND. lV) 1280 IF(lerr) RETURN 1281 ixIso = iIso !--- Update currently selected family index 1282 isotope => isotopes(ixIso) !--- Select corresponding component 1283 isoKeys => isotope%keys; niso = isotope%niso 1284 isoName => isotope%trac; ntiso = isotope%ntiso 1285 isoZone => isotope%zone; nzone = isotope%nzone 1286 isoPhas => isotope%phase; nphas = isotope%nphas 1287 itZonIso => isotope%itZonIso; isoCheck = isotope%check 1288 iqIsoPha => isotope%iqIsoPha 1289 END FUNCTION isoSelectByIndex 1290 !============================================================================================================================== 1291 1292 1293 !============================================================================================================================== 1294 !=== ADD THE <key>=<val> PAIR TO THE "ky[(:)]" KEY[S] DESCRIPTOR[S] OR THE <key>=<val(:)> PAIRS TO THE "ky(:)" KEYS DESCRIPTORS 1066 1295 !============================================================================================================================== 1067 1296 SUBROUTINE addKey_1(key, val, ky, lOverWrite) 1068 !------------------------------------------------------------------------------------------------------------------------------1069 ! Purpose: Add the <key>=<val> pair in the "ky" keys descriptor.1070 !------------------------------------------------------------------------------------------------------------------------------1071 1297 CHARACTER(LEN=*), INTENT(IN) :: key, val 1072 1298 TYPE(keys_type), INTENT(INOUT) :: ky 1073 1299 LOGICAL, OPTIONAL, INTENT(IN) :: lOverWrite 1300 !------------------------------------------------------------------------------------------------------------------------------ 1074 1301 CHARACTER(LEN=maxlen), ALLOCATABLE :: k(:), v(:) 1075 1302 INTEGER :: iky, nky 1076 1303 LOGICAL :: lo 1077 !------------------------------------------------------------------------------------------------------------------------------ 1078 lo=.FALSE.; IF(PRESENT(lOverWrite)) lo=lOverWrite 1304 lo=.TRUE.; IF(PRESENT(lOverWrite)) lo=lOverWrite 1305 IF(.NOT.ALLOCATED(ky%key)) THEN 1306 ALLOCATE(ky%key(1)); ky%key(1)=key 1307 ALLOCATE(ky%val(1)); ky%val(1)=val 1308 RETURN 1309 END IF 1079 1310 iky = strIdx(ky%key,key) 1080 1311 IF(iky == 0) THEN 1081 1312 nky = SIZE(ky%key) 1082 IF(nky == 0) THEN; ky%key = [key]; ky%val = [val]; ELSE; ky%key = [ky%key, key]; ky%val = [ky%val, val]; END IF 1083 ELSE IF(lo) THEN !--- Overwriting 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 1315 ELSE IF(lo) THEN 1084 1316 ky%key(iky) = key; ky%val(iky) = val 1085 1317 END IF … … 1087 1319 !============================================================================================================================== 1088 1320 SUBROUTINE addKey_m(key, val, ky, lOverWrite) 1089 !------------------------------------------------------------------------------------------------------------------------------1090 ! Purpose: Add the <key>=<val> pair in all the components of the "ky" keys descriptor.1091 !------------------------------------------------------------------------------------------------------------------------------1092 1321 CHARACTER(LEN=*), INTENT(IN) :: key, val 1093 1322 TYPE(keys_type), INTENT(INOUT) :: ky(:) 1094 1323 LOGICAL, OPTIONAL, INTENT(IN) :: lOverWrite 1324 !------------------------------------------------------------------------------------------------------------------------------ 1095 1325 INTEGER :: itr 1096 LOGICAL :: lo 1097 !------------------------------------------------------------------------------------------------------------------------------ 1098 lo=.FALSE.; IF(PRESENT(lOverWrite)) lo=lOverWrite 1099 DO itr = 1, SIZE(ky); CALL addKey_1(key, val, ky(itr), lo); END DO 1326 DO itr = 1, SIZE(ky) 1327 CALL addKey_1(key, val, ky(itr), lOverWrite) 1328 END DO 1100 1329 END SUBROUTINE addKey_m 1101 1330 !============================================================================================================================== 1331 SUBROUTINE addKey_mm(key, val, ky, lOverWrite) 1332 CHARACTER(LEN=*), INTENT(IN) :: key, val(:) 1333 TYPE(keys_type), INTENT(INOUT) :: ky(:) 1334 LOGICAL, OPTIONAL, INTENT(IN) :: lOverWrite 1335 !------------------------------------------------------------------------------------------------------------------------------ 1336 INTEGER :: itr 1337 DO itr = 1, SIZE(ky); CALL addKey_1(key, val(itr), ky(itr), lOverWrite); END DO 1338 END SUBROUTINE addKey_mm 1339 !============================================================================================================================== 1340 1341 1342 !============================================================================================================================== 1343 !=== OVERWRITE THE KEYS OF THE TRACER NAMED "tr0" WITH THE VALUES FOUND IN THE *.def FILES, IF ANY. =========================== 1344 !============================================================================================================================== 1102 1345 SUBROUTINE addKeysFromDef(t, tr0) 1103 !------------------------------------------------------------------------------------------------------------------------------1104 ! Purpose: The values of the keys of the tracer named "tr0" are overwritten by the values found in the *.def files, if any.1105 !------------------------------------------------------------------------------------------------------------------------------1106 1346 TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: t(:) 1107 1347 CHARACTER(LEN=*), INTENT(IN) :: tr0 1348 !------------------------------------------------------------------------------------------------------------------------------ 1108 1349 CHARACTER(LEN=maxlen) :: val 1109 1350 INTEGER :: ik, jd … … 1116 1357 END SUBROUTINE addKeysFromDef 1117 1358 !============================================================================================================================== 1359 1360 1361 !============================================================================================================================== 1362 !=== REMOVE THE KEYS NAMED "keyn(:)" FROM EITHER THE "itr"th OR ALL THE KEYS DESCRIPTORS OF "ky(:)" =========================== 1363 !============================================================================================================================== 1118 1364 SUBROUTINE delKey_1(itr, keyn, ky) 1119 !------------------------------------------------------------------------------------------------------------------------------1120 ! Purpose: Internal routine.1121 ! Remove <key>=<val> pairs in the "itr"th component of the "ky" keys descriptor.1122 !------------------------------------------------------------------------------------------------------------------------------1123 1365 INTEGER, INTENT(IN) :: itr 1124 1366 CHARACTER(LEN=*), INTENT(IN) :: keyn(:) 1125 1367 TYPE(trac_type), INTENT(INOUT) :: ky(:) 1368 !------------------------------------------------------------------------------------------------------------------------------ 1126 1369 CHARACTER(LEN=maxlen), ALLOCATABLE :: k(:), v(:) 1127 1370 LOGICAL, ALLOCATABLE :: ll(:) 1128 1371 INTEGER :: iky 1129 !------------------------------------------------------------------------------------------------------------------------------1130 1372 IF(itr<=0 .OR. itr>SIZE(ky, DIM=1)) RETURN !--- Index is out of range 1131 1373 ll = [( ALL(keyn/=ky(itr)%keys%key(iky)), iky=1, SIZE(ky(itr)%keys%key) )] … … 1135 1377 !============================================================================================================================== 1136 1378 SUBROUTINE delKey(keyn, ky) 1137 !------------------------------------------------------------------------------------------------------------------------------1138 ! Purpose: Internal routine.1139 ! Remove <key>=<val> pairs in all the components of the "t" tracers descriptor.1140 !------------------------------------------------------------------------------------------------------------------------------1141 1379 CHARACTER(LEN=*), INTENT(IN) :: keyn(:) 1142 1380 TYPE(trac_type), INTENT(INOUT) :: ky(:) 1381 !------------------------------------------------------------------------------------------------------------------------------ 1143 1382 INTEGER :: iky 1144 !------------------------------------------------------------------------------------------------------------------------------1145 1383 DO iky = 1, SIZE(ky); CALL delKey_1(iky, keyn, ky); END DO 1146 1384 END SUBROUTINE delKey … … 1149 1387 1150 1388 !============================================================================================================================== 1151 !=== PUBLIC ROUTINES: GET A KEY FROM A <key>=<val> LIST ; VECTORS, TRACER AND DATABASE VERSIONS =============================== 1152 !=== BEWARE !!! IF THE "ky" ARGUMENT IS NOT PRESENT, THEN THE VARIABLES "tracers" AND "isotopes" ARE USED. ==================== 1153 !=== THEY ARE LOCAL TO THIS MODULE, SO MUST MUST BE INITIALIZED FIRST USING the "getKey_init" ROUTINE ==================== 1154 !============================================================================================================================== 1155 SUBROUTINE getKey_init(tracers_, isotopes_) 1156 TYPE(trac_type), OPTIONAL, INTENT(IN) :: tracers_(:) 1157 TYPE(isot_type), OPTIONAL, INTENT(IN) :: isotopes_(:) 1158 IF(PRESENT( tracers_)) tracers = tracers_ 1159 IF(PRESENT(isotopes_)) isotopes = isotopes_ 1160 END SUBROUTINE getKey_init 1161 !============================================================================================================================== 1162 CHARACTER(LEN=maxlen) FUNCTION fgetKeyByIndex_s1(itr, keyn, ky, def_val) RESULT(val) 1163 !------------------------------------------------------------------------------------------------------------------------------ 1164 ! Purpose: Internal function ; get a string formatted key value (returned argument) from its name and the tracer index. 1165 !------------------------------------------------------------------------------------------------------------------------------ 1166 INTEGER, INTENT(IN) :: itr 1167 CHARACTER(LEN=*), INTENT(IN) :: keyn 1168 TYPE(keys_type), INTENT(IN) :: ky(:) 1169 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: def_val 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) 1392 INTEGER, INTENT(IN) :: itr 1393 CHARACTER(LEN=*), INTENT(IN) :: keyn 1394 TYPE(keys_type), INTENT(IN) :: ky(:) 1395 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: def_val 1396 LOGICAL, OPTIONAL, INTENT(OUT) :: lerr 1170 1397 !------------------------------------------------------------------------------------------------------------------------------ 1171 1398 INTEGER :: iky 1172 iky = 0; IF(itr > 0 .AND. itr <= SIZE(ky)) iky = strIdx(ky(itr)%key(:), keyn) 1173 val = ''; IF(iky /= 0) val = ky(itr)%val(iky) !--- Key was found 1174 IF(PRESENT(def_val) .AND. iky == 0) val = def_val !--- Default value from arguments 1175 END FUNCTION fgetKeyByIndex_s1 1176 !============================================================================================================================== 1177 CHARACTER(LEN=maxlen) FUNCTION fgetKeyByName_s1(tname, keyn, ky, def_val, lerr) RESULT(val) 1178 !------------------------------------------------------------------------------------------------------------------------------ 1179 ! Purpose: Internal function ; get a string formatted key value (returned argument) from its name and the tracer name. 1180 !------------------------------------------------------------------------------------------------------------------------------ 1399 LOGICAL :: ler 1400 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) 1181 1410 CHARACTER(LEN=*), INTENT(IN) :: tname, keyn 1182 1411 TYPE(keys_type), INTENT(IN) :: ky(:) … … 1184 1413 LOGICAL, OPTIONAL, INTENT(OUT) :: lerr 1185 1414 !------------------------------------------------------------------------------------------------------------------------------ 1186 INTEGER :: iky, itr 1187 val = ''; iky = 0 1188 itr = strIdx(ky(:)%name, tname) !--- Get the index of the wanted tracer 1189 IF(PRESENT(lerr)) lerr = itr==0; IF(itr == 0) RETURN 1190 IF(itr > 0 .AND. itr <= SIZE(ky)) iky = strIdx(ky(itr)%key(:), keyn) 1191 IF(iky /= 0) val = ky(itr)%val(iky) !--- Key was found 1192 IF(PRESENT(def_val) .AND. iky == 0) val = def_val !--- Default value from arguments 1193 END FUNCTION fgetKeyByName_s1 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 ============== 1194 1440 !============================================================================================================================== 1195 1441 LOGICAL FUNCTION getKeyByName_s1(keyn, val, tname, ky) RESULT(lerr) 1196 !--- Purpose: Get the value of the key named "keyn" for the tracer named "tnam".1197 ! * "ky" unspecified: try in "tracers" for "tnam" with phase and tagging suffixes, then in "isotopes" without.1198 ! * "ky" specified: try in "ky" for "tnam" with phase and tagging suffixes, then without.1199 ! The returned error code is always .FALSE.: an empty string is returned when the key hasn't been found.1200 1442 CHARACTER(LEN=*), INTENT(IN) :: keyn 1201 1443 CHARACTER(LEN=maxlen), INTENT(OUT) :: val 1202 1444 CHARACTER(LEN=*), INTENT(IN) :: tname 1203 1445 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1446 !------------------------------------------------------------------------------------------------------------------------------ 1204 1447 CHARACTER(LEN=maxlen) :: tnam 1205 INTEGER, ALLOCATABLE :: is(:) 1206 INTEGER :: i, itr 1207 tnam = delPhase(strHead(tname,'_',.FALSE.)) !--- Remove tag and phase 1208 IF(PRESENT(ky)) THEN 1209 val = fgetKeyByName_s1(tname, keyn, ky, lerr=lerr) !--- "ky" and "tname" 1210 IF(val /= '' .OR. lerr) RETURN 1211 val = fgetKeyByName_s1(tnam, keyn, ky, lerr=lerr) !--- "ky" and "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" 1212 1452 ELSE 1213 IF(.NOT.ALLOCATED(tracers)) RETURN 1214 val = fgetKeyByName_s1(tname, keyn, tracers(:)%keys, lerr=lerr) !--- "tracers" and "tname" 1215 IF(val /= ''.AND..NOT.lerr) RETURN 1216 IF(.NOT.ALLOCATED(isotopes)) RETURN 1217 IF(SIZE(isotopes) == 0) RETURN 1218 !--- Search the "is" isotopes class index of the isotope named "tnam" 1219 is = find([(ANY(isotopes(i)%keys(:)%name == tnam), i=1, SIZE(isotopes))]) 1220 IF(test(SIZE(is) == 0,lerr)) RETURN 1221 val = fgetKeyByName_s1(tname, keyn, isotopes(is(1))%keys(:),lerr=lerr)!--- "isotopes" and "tnam" 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 1222 1463 END IF 1223 1464 END FUNCTION getKeyByName_s1 1224 1465 !============================================================================================================================== 1225 LOGICAL FUNCTION getKeyByName_s m(keyn, val, tname, ky) RESULT(lerr)1466 LOGICAL FUNCTION getKeyByName_s1m(keyn, val, tname, ky) RESULT(lerr) 1226 1467 CHARACTER(LEN=*), INTENT(IN) :: keyn 1227 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1228 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: tname(:) 1229 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1230 TYPE(keys_type), POINTER :: k(:) 1231 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 1468 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1469 CHARACTER(LEN=*), INTENT(IN) :: tname 1470 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1471 !------------------------------------------------------------------------------------------------------------------------------ 1472 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 1475 lerr = strParse(sval, ',', val) 1476 END FUNCTION getKeyByName_s1m 1477 !============================================================================================================================== 1478 LOGICAL FUNCTION getKeyByName_sm(keyn, val, tname, ky, nam) RESULT(lerr) 1479 CHARACTER(LEN=*), INTENT(IN) :: keyn 1480 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1481 CHARACTER(LEN=*), INTENT(IN) :: tname(:) 1482 TYPE(keys_type), OPTIONAL, TARGET, INTENT(IN) :: ky(:) 1483 CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:) 1484 !------------------------------------------------------------------------------------------------------------------------------ 1485 TYPE(keys_type), POINTER :: keys(:) 1486 LOGICAL :: lk, lt, li 1232 1487 INTEGER :: iq, nq 1233 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1234 IF(PRESENT(ky )) nq = SIZE(ky%name) 1235 IF(PRESENT(tname)) nq = SIZE( tname) 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) 1236 1502 ALLOCATE(val(nq)) 1237 IF(PRESENT(tname)) THEN 1238 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1239 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1240 ELSE; lerr = ANY([(getKeyByName_s1(keyn, val(iq), ky(iq)%name, ky), iq=1, 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) 1509 CHARACTER(LEN=*), INTENT(IN) :: keyn 1510 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1511 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1512 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 1241 1525 END IF 1242 END FUNCTION getKey ByName_sm1526 END FUNCTION getKey_sm 1243 1527 !============================================================================================================================== 1244 1528 LOGICAL FUNCTION getKeyByName_i1(keyn, val, tname, ky) RESULT(lerr) … … 1247 1531 CHARACTER(LEN=*), INTENT(IN) :: tname 1248 1532 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1533 !------------------------------------------------------------------------------------------------------------------------------ 1249 1534 CHARACTER(LEN=maxlen) :: sval 1250 1535 INTEGER :: ierr 1251 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname, ky) 1252 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname) 1253 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN 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 1254 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 1255 1553 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not an integer', modname, lerr), lerr)) RETURN 1256 END FUNCTION getKeyByName_i1 1257 !============================================================================================================================== 1258 LOGICAL FUNCTION getKeyByName_im(keyn, val, tname, ky) RESULT(lerr) 1259 CHARACTER(LEN=*), INTENT(IN) :: keyn 1260 INTEGER, ALLOCATABLE, INTENT(OUT) :: val(:) 1261 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: tname(:) 1262 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1263 TYPE(keys_type), POINTER :: k(:) 1264 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 1265 INTEGER :: iq, nq 1266 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1267 IF(PRESENT(ky )) nq = SIZE(ky%name) 1268 IF(PRESENT(tname)) nq = SIZE( tname) 1269 ALLOCATE(val(nq)) 1270 IF(PRESENT(tname)) THEN 1271 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1272 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1273 ELSE; lerr = ANY([(getKeyByName_i1(keyn, val(iq), ky(iq)%name, ky), iq=1, nq)]) 1274 END IF 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(:) 1275 1572 END FUNCTION getKeyByName_im 1573 !============================================================================================================================== 1574 LOGICAL FUNCTION getKey_im(keyn, val, ky, nam) RESULT(lerr) 1575 CHARACTER(LEN=*), INTENT(IN) :: keyn 1576 INTEGER, ALLOCATABLE, INTENT(OUT) :: val(:) 1577 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1578 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 1276 1590 !============================================================================================================================== 1277 1591 LOGICAL FUNCTION getKeyByName_r1(keyn, val, tname, ky) RESULT(lerr) … … 1280 1594 CHARACTER(LEN=*), INTENT(IN) :: tname 1281 1595 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1596 !------------------------------------------------------------------------------------------------------------------------------ 1282 1597 CHARACTER(LEN=maxlen) :: sval 1283 1598 INTEGER :: ierr 1284 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname, ky) 1285 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname) 1599 lerr = getKeyByName_s1(keyn, sval, tname, ky) 1286 1600 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN 1287 1601 READ(sval, *, IOSTAT=ierr) val 1288 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not a real', modname, lerr), lerr)) RETURN1602 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not a real', modname, ierr/=0), lerr)) RETURN 1289 1603 END FUNCTION getKeyByName_r1 1290 1604 !============================================================================================================================== 1291 LOGICAL FUNCTION getKeyByName_r m(keyn, val, tname, ky) RESULT(lerr)1605 LOGICAL FUNCTION getKeyByName_r1m(keyn, val, tname, ky) RESULT(lerr) 1292 1606 CHARACTER(LEN=*), INTENT(IN) :: keyn 1293 REAL, ALLOCATABLE, INTENT(OUT) :: val(:) 1294 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: tname(:) 1295 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1296 TYPE(keys_type), POINTER :: k(:) 1297 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 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 1639 REAL, ALLOCATABLE, INTENT(OUT) :: val(:) 1640 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1641 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(:) 1298 1675 INTEGER :: iq, nq 1299 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1300 IF(PRESENT(ky )) nq = SIZE(ky%name) 1301 IF(PRESENT(tname)) nq = SIZE( tname) 1302 ALLOCATE(val(nq)) 1303 IF(PRESENT(tname)) THEN 1304 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1305 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1306 ELSE; lerr = ANY([(getKeyByName_r1(keyn, val(iq), ky(iq)%name, ky), iq=1, 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 1699 LOGICAL, ALLOCATABLE, INTENT(OUT) :: val(:) 1700 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1701 CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: nam(:) 1702 !------------------------------------------------------------------------------------------------------------------------------ 1703 CHARACTER(LEN=maxlen), ALLOCATABLE :: sval(:) 1704 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 1709 !============================================================================================================================== 1710 1711 1712 !============================================================================================================================== 1713 !=== ROUTINES TO GET OR PUT TRACERS AND ISOTOPES DATABASES, SINCE tracers AND isotopes ARE PRIVATE VARIABLES ================== 1714 !============================================================================================================================== 1715 SUBROUTINE setKeysDBase(tracers_, isotopes_, isotope_) 1716 TYPE(trac_type), OPTIONAL, INTENT(IN) :: tracers_(:) 1717 TYPE(isot_type), OPTIONAL, INTENT(IN) :: isotopes_(:) 1718 TYPE(isot_type), OPTIONAL, INTENT(IN) :: isotope_ 1719 !------------------------------------------------------------------------------------------------------------------------------ 1720 TYPE(isot_type), ALLOCATABLE :: iso(:) 1721 INTEGER :: ix, nbIso 1722 IF(PRESENT( tracers_)) THEN; tracers = tracers_; ELSE; ALLOCATE( tracers(0)); END IF 1723 IF(PRESENT(isotopes_)) THEN; isotopes = isotopes_; ELSE; ALLOCATE(isotopes(0)); END IF 1724 IF(PRESENT(isotope_ )) THEN 1725 ix = strIdx(isotopes(:)%parent, isotope_%parent) 1726 IF(ix /= 0) THEN 1727 isotopes(ix) = isotope_ 1728 ELSE 1729 nbIso = SIZE(isotopes); ALLOCATE(iso(nbIso+1)); iso(1:nbIso) = isotopes; iso(nbIso+1) = isotope_ 1730 CALL MOVE_ALLOC(FROM=iso, TO=isotopes) 1731 END IF 1307 1732 END IF 1308 END FUNCTION getKeyByName_rm 1733 END SUBROUTINE setKeysDBase 1734 !============================================================================================================================== 1735 SUBROUTINE getKeysDBase(tracers_, isotopes_, isotope_) 1736 TYPE(trac_type), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: tracers_(:) 1737 TYPE(isot_type), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: isotopes_(:) 1738 TYPE(isot_type), OPTIONAL, INTENT(OUT) :: isotope_ 1739 !------------------------------------------------------------------------------------------------------------------------------ 1740 INTEGER :: ix 1741 IF(PRESENT( tracers_)) THEN; tracers_ = tracers; ELSE; ALLOCATE( tracers_(0)); END IF 1742 IF(PRESENT(isotopes_)) THEN; isotopes_ = isotopes; ELSE; ALLOCATE(isotopes_(0)); END IF 1743 IF(PRESENT(isotope_ )) THEN; ix = strIdx(isotopes(:)%parent, isotope%parent); IF(ix /= 0) isotope_=isotopes(ix); END IF 1744 END SUBROUTINE getKeysDBase 1309 1745 !============================================================================================================================== 1310 1746 … … 1315 1751 ELEMENTAL CHARACTER(LEN=maxlen) FUNCTION delPhase(s) RESULT(out) 1316 1752 CHARACTER(LEN=*), INTENT(IN) :: s 1317 INTEGER :: l, i, ix 1318 CHARACTER(LEN=maxlen) :: sh, st 1319 out = s 1320 IF(s == '') RETURN !--- Empty string: nothing to do 1321 1322 !--- Special case: old phases for water, no phases separator 1323 i = INDEX(s,'_'); sh = s; IF(i/=0) sh=s(1:i-1); st='H2O'; IF(i/=0) st='H2O_'//s(i+1:LEN_TRIM(s)) 1324 IF(ANY([('H2O'//old_phases(ix:ix), ix=1, nphases)] == sh)) THEN; out=st; RETURN; END IF 1325 1326 !--- Index of found phase in "known_phases" 1327 ix = MAXLOC( [(i, i=1,nphases)], MASK=[( INDEX(s, phases_sep//known_phases(i:i))/=0, i=1, nphases)], DIM=1 ) 1328 IF(ix == 0) RETURN !--- No phase pattern found 1329 i = INDEX(s, phases_sep//known_phases(ix:ix)) !--- Index of <sep><pha> pattern in "str" 1330 l = LEN_TRIM(s) 1331 IF(i == l-1) THEN !--- <var><sep><pha> => return <var> 1332 out = s(1:l-2) 1333 ELSE IF(s(i+2:i+2) == '_') THEN !--- <var><sep><pha>_<tag> => return <var>_<tag> 1334 out = s(1:i-1)//s(i+2:l) 1753 !------------------------------------------------------------------------------------------------------------------------------ 1754 INTEGER :: ix, ip, ns 1755 out = s; ns = LEN_TRIM(s) 1756 IF(s == '' .OR. ns<=2) RETURN !--- Empty string or LEN(name)<=2: nothing to do 1757 IF(s(1:3)=='H2O' .AND. INDEX(old_phases,s(4:4))/=0 .AND. (ns==4 .OR. s(5:5)=='_')) THEN 1758 out='H2O'//s(5:ns) !--- H2O<phase>[_<iso>][_<tag>] 1759 ELSE IF(s(ns-1:ns-1)==phases_sep .AND. INDEX(known_phases,s(ns:ns))/=0) THEN 1760 out = s(1:ns-2); RETURN !--- <var><phase_sep><phase> 1761 ELSE; DO ip = 1, nphases; ix = INDEX(s, phases_sep//known_phases(ip:ip)//'_'); IF(ix /= 0) EXIT; END DO 1762 IF(ip /= nphases+1) out = s(1:ix-1)//s(ix+2:ns) !--- <var><phase_sep><phase>_<tag> 1335 1763 END IF 1336 1764 END FUNCTION delPhase 1337 ! ------------------------------------------------------------------------------------------------------------------------------1765 !============================================================================================================================== 1338 1766 CHARACTER(LEN=maxlen) FUNCTION addPhase_s1(s,pha) RESULT(out) 1339 1767 CHARACTER(LEN=*), INTENT(IN) :: s 1340 1768 CHARACTER(LEN=1), INTENT(IN) :: pha 1769 !------------------------------------------------------------------------------------------------------------------------------ 1341 1770 INTEGER :: l, i 1342 1771 out = s … … 1347 1776 IF(i /= 0) out = s(1:i-1)//phases_sep//pha//'_'//s(i+1:l) !--- <var>_<tag> => return <var><sep><pha>_<tag> 1348 1777 END FUNCTION addPhase_s1 1349 ! ------------------------------------------------------------------------------------------------------------------------------1778 !============================================================================================================================== 1350 1779 FUNCTION addPhase_sm(s,pha) RESULT(out) 1351 1780 CHARACTER(LEN=*), INTENT(IN) :: s(:) 1352 1781 CHARACTER(LEN=1), INTENT(IN) :: pha 1353 1782 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 1783 !------------------------------------------------------------------------------------------------------------------------------ 1354 1784 INTEGER :: k 1355 1785 out = [( addPhase_s1(s(k), pha), k=1, SIZE(s) )] 1356 1786 END FUNCTION addPhase_sm 1357 ! ------------------------------------------------------------------------------------------------------------------------------1787 !============================================================================================================================== 1358 1788 CHARACTER(LEN=maxlen) FUNCTION addPhase_i1(s,ipha,phases) RESULT(out) 1359 1789 CHARACTER(LEN=*), INTENT(IN) :: s 1360 1790 INTEGER, INTENT(IN) :: ipha 1361 1791 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1792 !------------------------------------------------------------------------------------------------------------------------------ 1362 1793 out = s 1363 1794 IF(s == '') RETURN !--- Empty string: nothing to do 1364 IF(ipha ==0) RETURN !--- Nullindex: no phase to add1795 IF(ipha == 0 .OR. ipha > nphases) RETURN !--- Absurd index: no phase to add 1365 1796 IF( PRESENT(phases)) out = addPhase_s1(s, phases(ipha:ipha)) 1366 1797 IF(.NOT.PRESENT(phases)) out = addPhase_s1(s, known_phases(ipha:ipha)) 1367 1798 END FUNCTION addPhase_i1 1368 ! ------------------------------------------------------------------------------------------------------------------------------1799 !============================================================================================================================== 1369 1800 FUNCTION addPhase_im(s,ipha,phases) RESULT(out) 1370 1801 CHARACTER(LEN=*), INTENT(IN) :: s(:) … … 1372 1803 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1373 1804 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 1805 !------------------------------------------------------------------------------------------------------------------------------ 1374 1806 INTEGER :: k 1375 1807 IF( PRESENT(phases)) out = [( addPhase_i1(s(k), ipha, phases), k=1, SIZE(s) )] 1376 1808 IF(.NOT.PRESENT(phases)) out = [( addPhase_i1(s(k), ipha, known_phases), k=1, SIZE(s) )] 1377 1809 END FUNCTION addPhase_im 1378 ! ------------------------------------------------------------------------------------------------------------------------------1810 !============================================================================================================================== 1379 1811 1380 1812 … … 1385 1817 CHARACTER(LEN=*), INTENT(IN) :: tname 1386 1818 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1819 !------------------------------------------------------------------------------------------------------------------------------ 1387 1820 CHARACTER(LEN=maxlen) :: phase 1388 1821 IF( PRESENT(phases)) phase = getPhase(tname, phases, iPhase) 1389 1822 IF(.NOT.PRESENT(phases)) phase = getPhase(tname, known_phases, iPhase) 1390 1823 END FUNCTION getiPhase 1391 ! ------------------------------------------------------------------------------------------------------------------------------1824 !============================================================================================================================== 1392 1825 CHARACTER(LEN=1) FUNCTION getPhase(tname, phases, iPhase) RESULT(phase) 1393 1826 CHARACTER(LEN=*), INTENT(IN) :: tname 1394 1827 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1395 1828 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1829 !------------------------------------------------------------------------------------------------------------------------------ 1396 1830 INTEGER :: ip 1397 phase = TRIM(strHead(strTail(tname, phases_sep , .TRUE.), '_', .TRUE.))1831 phase = TRIM(strHead(strTail(tname, phases_sep), '_', .TRUE.)) !--- <nam><sep><pha>[_<tag>] -> <pha>[_<tag>] -> <pha> 1398 1832 IF( PRESENT(phases)) ip = INDEX( phases, phase) 1399 1833 IF(.NOT.PRESENT(phases)) ip = INDEX(known_phases, phase) … … 1401 1835 IF(PRESENT(iPhase)) iPhase = ip 1402 1836 END FUNCTION getPhase 1403 !------------------------------------------------------------------------------------------------------------------------------ 1404 1405 1406 !------------------------------------------------------------------------------------------------------------------------------ 1407 CHARACTER(LEN=maxlen) FUNCTION old2newName_1(oldName, iPhase) RESULT(newName) 1408 !--- Convert an old style name into a new one. 1409 ! Only usable with old style "traceur.def" files, in which only water isotopes are allowed. 1410 ! In these files, H2O descendants names are: H2O<phase>[_<isotope>][_<tag>], with: 1411 ! phase = v, l or i ; isotope = eau, HDO, O18, O17 or HTO. 1837 !============================================================================================================================== 1838 1839 1840 !============================================================================================================================== 1841 !============ CONVERT WATER-DERIVED NAMES FROM FORMER TO CURRENT CONVENTION ; OTHER NAMES ARE LEFT UNTOUCHED ================== 1842 !======= NAMES STRUCTURE: H2O[<phase>][_<isotope>][_<tag>] (<phase> from "old_phases", <isotope> from "oldH2OIso") ============ 1843 !============================================================================================================================== 1844 CHARACTER(LEN=maxlen) FUNCTION old2newH2O_1(oldName, iPhase) RESULT(newName) 1412 1845 CHARACTER(LEN=*), INTENT(IN) :: oldName 1413 1846 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1847 !------------------------------------------------------------------------------------------------------------------------------ 1414 1848 CHARACTER(LEN=maxlen), ALLOCATABLE :: tmp(:) 1415 INTEGER :: ix, ip, it,nt1416 LOGICAL :: lerr , lH2O1849 INTEGER :: ix, ip, nt 1850 LOGICAL :: lerr 1417 1851 newName = oldName 1418 1852 IF(PRESENT(iPhase)) iPhase = 1 !--- Default: gaseous phase 1419 lH2O=.FALSE. 1420 IF(LEN_TRIM(oldName) > 3) THEN 1421 lH2O = oldName(1:3)=='H2O' .AND. INDEX(old_phases,oldName(4:4))/=0 !--- H2O<phase>*, with phase=="v", "l", "i" or "r" 1422 IF(LEN_TRIM(oldName) > 4) lH2O = lH2O .AND. oldName(5:5) == '_' !--- H2O<phase>_*, with phase=="v", "l", "i" or "r" 1853 lerr = strParse(oldName, '_', tmp, nt) !--- Parsing: 1 up to 3 elements. 1854 ip = strIdx( [('H2O'//old_phases(ix:ix), ix=1, nphases)], tmp(1) ) !--- Phase index 1855 IF(ip /= 0 .AND. PRESENT(iPhase)) iPhase = ip !--- Returning phase index 1856 IF(ip == 0 .AND. tmp(1) /= 'H2O') RETURN !--- Not an old-style water-related species 1857 IF(nt == 1) THEN 1858 newName = addPhase('H2O',ip) !=== WATER WITH OR WITHOUT PHASE 1859 ELSE 1860 ix = strIdx(oldH2OIso, tmp(2)) !--- Index in the known isotopes list 1861 IF(ix /= 0) newName = newH2OIso(ix) !--- Move to new isotope name 1862 IF(ip /= 0) newName = addPhase(newName, ip) !--- Add phase to isotope name 1863 IF(nt == 3) newName = TRIM(newName)//'_'//TRIM(tmp(3)) !=== WATER ISOTOPE OR TAGGING TRACER 1423 1864 END IF 1424 IF(.NOT.lH2O) RETURN 1425 IF(LEN_TRIM(oldName)>3) THEN; IF(INDEX(old_Phases,oldName(4:4))==0) RETURN; END IF 1426 lerr = strParse(oldName, '_', tmp, n=nt) 1427 ip = strIdx([('H2O'//old_phases(ip:ip), ip=1, nphases)], tmp(1)) !--- Phase index (/=0 if any) 1428 IF(PRESENT(iPhase)) iPhase = ip 1429 newName = addPhase('H2O', ip) !--- Water 1430 IF(nt == 1) RETURN !--- Water: finished 1431 ix = strIdx(oldH2OIso, tmp(2)) !--- Index in the known isotopes list 1432 IF(ix == 0) newName = addPhase(tmp(2), ip) !--- Not an isotope 1433 IF(ix /= 0) newName = addPhase(newH2OIso(ix), ip) !--- Isotope 1434 IF(nt == 3) newName = TRIM(newName)//'_'//TRIM(tmp(3)) !--- Tagging tracer 1435 END FUNCTION old2newName_1 1436 !------------------------------------------------------------------------------------------------------------------------------ 1437 FUNCTION old2newName_m(oldName, iPhase) RESULT(newName) 1438 CHARACTER(LEN=*), INTENT(IN) :: oldName(:) 1865 END FUNCTION old2newH2O_1 1866 !============================================================================================================================== 1867 FUNCTION old2newH2O_m(oldName) RESULT(newName) 1868 CHARACTER(LEN=*), INTENT(IN) :: oldName(:) 1869 CHARACTER(LEN=maxlen) :: newName(SIZE(oldName)) 1870 !------------------------------------------------------------------------------------------------------------------------------ 1871 INTEGER :: i 1872 newName = [(old2newH2O_1(oldName(i)), i=1, SIZE(oldName))] 1873 END FUNCTION old2newH2O_m 1874 !============================================================================================================================== 1875 1876 1877 !============================================================================================================================== 1878 !============ CONVERT WATER-DERIVED NAMES FROM CURRENT TO FORMER CONVENTION ; OTHER NAMES ARE LEFT UNTOUCHED ================== 1879 !==== NAMES STRUCTURE: <var>[<phase_sep><phase>][_<tag>] (<phase> from "known_phases", <var> = 'H2O' or from "newH2OIso") ===== 1880 !============================================================================================================================== 1881 CHARACTER(LEN=maxlen) FUNCTION new2oldH2O_1(newName, iPhase) RESULT(oldName) 1882 CHARACTER(LEN=*), INTENT(IN) :: newName 1439 1883 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1440 CHARACTER(LEN=maxlen) :: newName(SIZE(oldName)) 1884 !------------------------------------------------------------------------------------------------------------------------------ 1885 INTEGER :: ix, ip 1886 CHARACTER(LEN=maxlen) :: var 1887 oldName = newName 1888 ip = getiPhase(newName) !--- Phase index 1889 IF(PRESENT(iPhase)) iPhase = MAX(ip, 1) !--- Return phase index ; default: 1 (gazeous) 1890 var = TRIM(strHead(newName, phases_sep, .TRUE.)) !--- Variable without phase and tag 1891 ix = strIdx(newH2OIso, var) !--- Index in the known H2O isotopes list 1892 IF(ix == 0 .AND. var /= 'H2O') RETURN !--- Neither H2O nor an H2O isotope => finished 1893 oldName = 'H2O' 1894 IF(ip /= 0) oldName = TRIM(oldName)//old_phases(ip:ip) !--- Add phase if needed 1895 IF(ix /= 0) oldName = TRIM(oldName)//'_'//oldH2OIso(ix) !--- H2O isotope name 1896 IF(newName /= addPhase(var, ip)) & 1897 oldName = TRIM(oldName)//strTail(newName, '_', .TRUE.) !--- Add the tag suffix 1898 IF(ip == 0 .AND. ix /= 0) oldName = strTail(oldName, '_') !--- Isotope with no phase: remove 'H2O_' prefix 1899 END FUNCTION new2oldH2O_1 1900 !============================================================================================================================== 1901 FUNCTION new2oldH2O_m(newName) RESULT(oldName) 1902 CHARACTER(LEN=*), INTENT(IN) :: newName(:) 1903 CHARACTER(LEN=maxlen) :: oldName(SIZE(newName)) 1904 !------------------------------------------------------------------------------------------------------------------------------ 1441 1905 INTEGER :: i 1442 newName = [(old2newName_1(oldName(i), iPhase), i=1, SIZE(oldName))] 1443 END FUNCTION old2newName_m 1444 !------------------------------------------------------------------------------------------------------------------------------ 1445 1446 !------------------------------------------------------------------------------------------------------------------------------ 1447 CHARACTER(LEN=maxlen) FUNCTION new2oldName_1(newName, iPhase) RESULT(oldName) 1448 !--- Convert a new style name into an old one. 1449 ! Only convertable names are water descendants names H2O_<phase>, <isotope>_<phase>, <isotope>_<phase>_<tag>, with: 1450 ! phase = g, l or s ; isotope = H2[16]O, H[2]O, H2<[18]O, H2[17]O or H[3]O. 1451 CHARACTER(LEN=*), INTENT(IN) :: newName 1452 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1453 INTEGER :: ix, ip, it, nt 1454 LOGICAL :: lH2O 1455 CHARACTER(LEN=maxlen) :: tag 1456 ix = strIdx([(addPhase('H2O',ip), ip=1, nphases)], newName) !--- Phase index for H2O_<phase> 1457 IF(ix /= 0) THEN; oldName = 'H2O'//old_phases(ix:ix); RETURN; END IF !--- H2O_<phase> case 1458 ix = strIdx(newH2OIso, strHead(newName, phases_sep, .TRUE.)) !--- Isotope index 1459 IF(ix == 0) THEN; oldName = newName; RETURN; END IF !--- Not a water descendant 1460 ip = getiPhase(newName) !--- Phase index 1461 oldName = TRIM(oldH2OIso(ix))//old_phases(ip:ip) !--- <isotope>_<phase> 1462 tag = strTail(delPhase(newName), TRIM(newH2OIso(ix))) !--- Get "_<tag>" if any 1463 IF(tag /= delPhase(newName) .AND. tag /= '') oldName = TRIM(oldName)//tag !--- Tagging tracer 1464 END FUNCTION new2oldName_1 1465 !------------------------------------------------------------------------------------------------------------------------------ 1466 FUNCTION new2oldName_m(newName, iPhase) RESULT(oldName) 1467 CHARACTER(LEN=*), INTENT(IN) :: newName(:) 1468 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1469 CHARACTER(LEN=maxlen) :: oldName(SIZE(newName)) 1470 INTEGER :: i 1471 oldName = [(new2oldName_1(newName(i), iPhase), i=1, SIZE(newName))] 1472 END FUNCTION new2oldName_m 1473 !------------------------------------------------------------------------------------------------------------------------------ 1906 oldName = [(new2oldH2O_1(newName(i)), i=1, SIZE(newName))] 1907 END FUNCTION new2oldH2O_m 1908 !============================================================================================================================== 1474 1909 1475 1910 … … 1477 1912 !=== GET THE NAME(S) OF THE ANCESTOR(S) OF TRACER(S) "tname" AT GENERATION "igen" IN THE TRACERS DESCRIPTORS LIST "tr" ======= 1478 1913 !============================================================================================================================== 1479 CHARACTER(LEN=maxlen) FUNCTION ancestor_1(t, tname, igen) RESULT(out) 1480 TYPE(trac_type), INTENT(IN) :: t(:) 1481 CHARACTER(LEN=*), INTENT(IN) :: tname 1482 INTEGER, OPTIONAL, INTENT(IN) :: igen 1483 INTEGER :: ig, ix 1484 ig = 0; IF(PRESENT(igen)) ig = igen 1485 ix = idxAncestor_1(t, tname, ig) 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) 1486 1922 out = ''; IF(ix /= 0) out = t(ix)%name 1487 END FUNCTION ancestor_1 1488 !------------------------------------------------------------------------------------------------------------------------------ 1489 FUNCTION ancestor_m(t, tname, igen) RESULT(out) 1490 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 1491 TYPE(trac_type), INTENT(IN) :: t(:) 1492 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: tname(:) 1493 INTEGER, OPTIONAL, INTENT(IN) :: igen 1494 INTEGER, ALLOCATABLE :: ix(:) 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 1495 1956 INTEGER :: ig 1496 1957 ig = 0; IF(PRESENT(igen)) ig = igen 1497 IF( PRESENT(tname)) ix = idxAncestor_m(t, tname, ig) 1498 IF(.NOT.PRESENT(tname)) ix = idxAncestor_m(t, t(:)%name, ig) 1499 ALLOCATE(out(SIZE(ix))); out(:) = '' 1500 WHERE(ix /= 0) out = t(ix)%name 1501 END FUNCTION ancestor_m 1502 !============================================================================================================================== 1503 1504 1505 !============================================================================================================================== 1506 !=== GET THE INDEX(ES) OF THE ANCESTOR(S) OF TRACER(S) "tname" AT GENERATION "igen" IN THE TRACERS DESCRIPTORS LIST "tr" ===== 1507 !============================================================================================================================== 1508 INTEGER FUNCTION idxAncestor_1(t, tname, igen) RESULT(out) 1509 ! Return the name of the generation "igen" (>=0) ancestor of "tname" 1510 TYPE(trac_type), INTENT(IN) :: t(:) 1511 CHARACTER(LEN=*), INTENT(IN) :: tname 1512 INTEGER, OPTIONAL, INTENT(IN) :: igen 1513 INTEGER :: ig 1514 ig = 0; IF(PRESENT(igen)) ig = igen 1515 out = strIdx(t(:)%name, tname) 1516 IF(out == 0) RETURN !--- Tracer not found 1517 IF(t(out)%iGeneration <= ig) RETURN !--- Tracer has a lower generation number than asked generation 'igen" 1518 DO WHILE(t(out)%iGeneration > ig); out = strIdx(t(:)%name, t(out)%parent); END DO 1519 END FUNCTION idxAncestor_1 1520 !------------------------------------------------------------------------------------------------------------------------------ 1521 FUNCTION idxAncestor_m(t, tname, igen) RESULT(out) 1522 INTEGER, ALLOCATABLE :: out(:) 1523 TYPE(trac_type), INTENT(IN) :: t(:) 1524 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: tname(:) 1525 INTEGER, OPTIONAL, INTENT(IN) :: igen 1526 INTEGER :: ig, ix 1527 ig = 0; IF(PRESENT(igen)) ig = igen 1528 IF( PRESENT(tname)) out = [(idxAncestor_1(t, tname(ix), ig), ix=1, SIZE(tname))] 1529 IF(.NOT.PRESENT(tname)) out = [(idxAncestor_1(t, t(ix)%name, ig), ix=1, SIZE(t))] 1530 END FUNCTION idxAncestor_m 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 1531 1980 !============================================================================================================================== 1532 1981 -
LMDZ6/branches/LMDZ_ECRad/libf/misc/strings_mod.F90
r4203 r4482 10 10 PUBLIC :: is_numeric, bool2str, int2str, real2str, dble2str 11 11 PUBLIC :: reduceExpr, str2bool, str2int, str2real, str2dble 12 PUBLIC :: addQuotes, testFile,checkList, removeComment, test12 PUBLIC :: addQuotes, checkList, removeComment, test 13 13 14 14 INTERFACE get_in; MODULE PROCEDURE getin_s, getin_i, getin_r, getin_l; END INTERFACE get_in … … 21 21 INTERFACE strIdx; MODULE PROCEDURE strIdx_1, strIdx_m; END INTERFACE strIdx 22 22 INTERFACE strCount; MODULE PROCEDURE strCount_m1, strCount_11, strCount_1m; END INTERFACE strCount 23 INTERFACE strParse; MODULE PROCEDURE strParse_1, strParse_m; END INTERFACE strParse24 23 INTERFACE strReplace; MODULE PROCEDURE strReplace_1, strReplace_m; END INTERFACE strReplace 25 24 INTERFACE cat; MODULE PROCEDURE horzcat_s1, horzcat_i1, horzcat_r1, & … … 30 29 INTERFACE reduceExpr; MODULE PROCEDURE reduceExpr_1, reduceExpr_m; END INTERFACE reduceExpr 31 30 INTERFACE addQuotes; MODULE PROCEDURE addQuotes_1, addQuotes_m; END INTERFACE addQuotes 32 INTERFACE testFile; MODULE PROCEDURE testFile_1, testFile_m; END INTERFACE testFile33 31 34 32 INTEGER, PARAMETER :: maxlen = 256 !--- Standard maximum length for strings … … 38 36 CONTAINS 39 37 38 !============================================================================================================================== 40 39 LOGICAL FUNCTION test(lcond, lout) RESULT(lerr) 41 40 LOGICAL, INTENT(IN) :: lcond … … 43 42 lerr = lcond; lout = lcond 44 43 END FUNCTION test 44 !============================================================================================================================== 45 45 46 46 47 !============================================================================================================================== 47 48 SUBROUTINE init_printout(lunout_, prt_level_) 48 49 INTEGER, INTENT(IN) :: lunout_, prt_level_ 49 lunout = lunout_ 50 lunout = lunout_ 51 prt_level = prt_level_ 50 52 END SUBROUTINE init_printout 51 53 !============================================================================================================================== … … 105 107 LOGICAL, OPTIONAL, INTENT(IN) :: ll 106 108 INTEGER, OPTIONAL, INTENT(IN) :: unit 109 !------------------------------------------------------------------------------------------------------------------------------ 107 110 CHARACTER(LEN=maxlen) :: subn 108 111 INTEGER :: unt … … 121 124 INTEGER, OPTIONAL, INTENT(IN) :: unit 122 125 INTEGER, OPTIONAL, INTENT(IN) :: nmax 126 !------------------------------------------------------------------------------------------------------------------------------ 123 127 CHARACTER(LEN=maxlen), ALLOCATABLE :: s(:) 124 128 CHARACTER(LEN=maxlen) :: subn … … 138 142 LOGICAL, OPTIONAL, INTENT(IN) :: ll 139 143 INTEGER, OPTIONAL, INTENT(IN) :: unit 144 !------------------------------------------------------------------------------------------------------------------------------ 140 145 CHARACTER(LEN=maxlen) :: subn 141 146 INTEGER :: unt … … 152 157 INTEGER, OPTIONAL, INTENT(IN) :: unit 153 158 INTEGER, OPTIONAL, INTENT(IN) :: nmax 159 !------------------------------------------------------------------------------------------------------------------------------ 154 160 CHARACTER(LEN=maxlen) :: subn 155 161 INTEGER :: unt, nmx … … 187 193 188 194 !============================================================================================================================== 189 !=== Extract the substring in front of the last (first if lFirst==TRUE) occurrence of separator "sep" in "str"================195 !=== Extract the substring in front of the first (last if lBackward==TRUE) occurrence of "sep" in "str" ================ 190 196 !=== Examples for str='a_b_c' and sep='_' and the bash command with the same effect: ================ 191 197 !=== * strHead(..,.FALSE.) = 'a' ${str%%$sep*} ================ 192 198 !=== * strHead(..,.TRUE.) = 'a_b' ${str%$sep*} ================ 193 199 !============================================================================================================================== 194 CHARACTER(LEN=maxlen) FUNCTION strHead_1(str, sep,lFirst) RESULT(out)200 CHARACTER(LEN=maxlen) FUNCTION strHead_1(str, sep, lBackward) RESULT(out) 195 201 CHARACTER(LEN=*), INTENT(IN) :: str 196 202 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 197 LOGICAL, OPTIONAL, INTENT(IN) :: lFirst 198 LOGICAL :: lf 199 lf = .FALSE.; IF(PRESENT(lFirst)) lf=lFirst 203 LOGICAL, OPTIONAL, INTENT(IN) :: lBackward 204 !------------------------------------------------------------------------------------------------------------------------------ 200 205 IF(PRESENT(sep)) THEN 201 out = str(1:INDEX(str,sep,.NOT.lf)-1) 206 IF( PRESENT(lBackWard)) out = str(1:INDEX(str,sep,lBackWard)-1) 207 IF(.NOT.PRESENT(lBackWard)) out = str(1:INDEX(str,sep)-1) 202 208 ELSE 203 out = str(1:INDEX(str,'/',.NOT.lf)-1) 209 IF( PRESENT(lBackWard)) out = str(1:INDEX(str,'/',lBackWard)-1) 210 IF(.NOT.PRESENT(lBackWard)) out = str(1:INDEX(str,'/')-1) 204 211 END IF 205 212 IF(out == '') out = str 206 213 END FUNCTION strHead_1 207 214 !============================================================================================================================== 208 FUNCTION strHead_m(str, sep,lFirst) RESULT(out)215 FUNCTION strHead_m(str, sep, lBackward) RESULT(out) 209 216 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 210 217 CHARACTER(LEN=*), INTENT(IN) :: str(:) 211 218 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 212 LOGICAL, OPTIONAL, INTENT(IN) :: l First213 LOGICAL :: lf 219 LOGICAL, OPTIONAL, INTENT(IN) :: lBackward 220 !------------------------------------------------------------------------------------------------------------------------------ 214 221 INTEGER :: k 215 lf = .FALSE.; IF(PRESENT(lFirst)) lf=lFirst216 222 IF(PRESENT(sep)) THEN 217 out = [(strHead_1(str(k), sep, lf), k=1, SIZE(str))] 223 IF( PRESENT(lBackWard)) out = [(strHead_1(str(k), sep, lBackWard), k=1, SIZE(str))] 224 IF(.NOT.PRESENT(lBackWard)) out = [(strHead_1(str(k), sep), k=1, SIZE(str))] 218 225 ELSE 219 out = [(strHead_1(str(k), lFirst=lf), k=1, SIZE(str))] 226 IF( PRESENT(lBackWard)) out = [(strHead_1(str(k), '/', lBackWard), k=1, SIZE(str))] 227 IF(.NOT.PRESENT(lBackWard)) out = [(strHead_1(str(k), '/'), k=1, SIZE(str))] 220 228 END IF 221 229 END FUNCTION strHead_m 222 230 !============================================================================================================================== 223 !=== Extract the substring following the last (first if lFirst==TRUE) occurrence of separator "sep" in "str"================231 !=== Extract the substring following the first (last if lBackward==TRUE) occurrence of "sep" in "str" ================ 224 232 !=== Examples for str='a_b_c' and sep='_' and the bash command with the same effect: ================ 225 !=== * strTail( ..,.FALSE.) = 'c' ${str#*$sep}================226 !=== * strTail( ..,.TRUE.) = 'b_c' ${str##*$sep}================227 !============================================================================================================================== 228 CHARACTER(LEN=maxlen) FUNCTION strTail_1(str, sep,lFirst) RESULT(out)233 !=== * strTail(str, '_', .FALSE.) = 'b_c' ${str#*$sep} ================ 234 !=== * strTail(str, '_', .TRUE.) = 'c' ${str##*$sep} ================ 235 !============================================================================================================================== 236 CHARACTER(LEN=maxlen) FUNCTION strTail_1(str, sep, lBackWard) RESULT(out) 229 237 CHARACTER(LEN=*), INTENT(IN) :: str 230 238 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 231 LOGICAL, OPTIONAL, INTENT(IN) :: lFirst 232 LOGICAL :: lf 233 lf = .FALSE.; IF(PRESENT(lFirst)) lf=lFirst 239 LOGICAL, OPTIONAL, INTENT(IN) :: lBackWard 240 !------------------------------------------------------------------------------------------------------------------------------ 234 241 IF(PRESENT(sep)) THEN 235 out = str(INDEX(str,sep,.NOT.lf)+LEN(sep):LEN_TRIM(str)) 242 IF( PRESENT(lBackWard)) out = str(INDEX(str,sep,lBackWard)+LEN(sep):LEN_TRIM(str)) 243 IF(.NOT.PRESENT(lBackWard)) out = str(INDEX(str,sep) +LEN(sep):LEN_TRIM(str)) 236 244 ELSE 237 out = str(INDEX(str,'/',.NOT.lf)+1:LEN_TRIM(str)) 245 IF( PRESENT(lBackWard)) out = str(INDEX(str,'/',lBackWard)+1:LEN_TRIM(str)) 246 IF(.NOT.PRESENT(lBackWard)) out = str(INDEX(str,'/') +1:LEN_TRIM(str)) 238 247 END IF 239 248 IF(out == '') out = str 240 249 END FUNCTION strTail_1 241 250 !============================================================================================================================== 242 FUNCTION strTail_m(str, sep,lFirst) RESULT(out)251 FUNCTION strTail_m(str, sep, lBackWard) RESULT(out) 243 252 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 244 253 CHARACTER(LEN=*), INTENT(IN) :: str(:) 245 254 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 246 LOGICAL, OPTIONAL, INTENT(IN) :: l First247 LOGICAL :: lf 255 LOGICAL, OPTIONAL, INTENT(IN) :: lBackWard 256 !------------------------------------------------------------------------------------------------------------------------------ 248 257 INTEGER :: k 249 lf = .FALSE.; IF(PRESENT(lFirst)) lf=lFirst250 258 IF(PRESENT(sep)) THEN 251 out = [(strTail_1(str(k), sep, lf), k=1, SIZE(str))] 259 IF( PRESENT(lBackWard)) out = [(strTail_1(str(k), sep, lBackWard), k=1, SIZE(str))] 260 IF(.NOT.PRESENT(lBackWard)) out = [(strTail_1(str(k), sep), k=1, SIZE(str))] 252 261 ELSE 253 out = [(strTail_1(str(k), lFirst=lf), k=1, SIZE(str))] 262 IF( PRESENT(lBackWard)) out = [(strTail_1(str(k), '/', lBackWard), k=1, SIZE(str))] 263 IF(.NOT.PRESENT(lBackWard)) out = [(strTail_1(str(k), '/'), k=1, SIZE(str))] 254 264 END IF 255 265 END FUNCTION strTail_m … … 265 275 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 266 276 LOGICAL, OPTIONAL, INTENT(IN) :: mask(:) 277 !------------------------------------------------------------------------------------------------------------------------------ 267 278 CHARACTER(LEN=:), ALLOCATABLE :: s 268 279 INTEGER :: is, i0 … … 285 296 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sep 286 297 INTEGER, OPTIONAL, INTENT(IN) :: nmax 298 !------------------------------------------------------------------------------------------------------------------------------ 287 299 CHARACTER(LEN=maxlen), ALLOCATABLE :: t(:) 288 300 CHARACTER(LEN=maxlen) :: sp … … 339 351 CHARACTER(LEN=*), ALLOCATABLE, INTENT(INOUT) :: str(:) 340 352 INTEGER, OPTIONAL, INTENT(OUT) :: nb 353 !------------------------------------------------------------------------------------------------------------------------------ 341 354 CHARACTER(LEN=maxlen), ALLOCATABLE :: s1(:) 342 355 INTEGER :: k, n, n1 … … 355 368 CHARACTER(LEN=*), ALLOCATABLE, INTENT(INOUT) :: str1(:) 356 369 CHARACTER(LEN=*), INTENT(IN) :: str2(:) 370 !------------------------------------------------------------------------------------------------------------------------------ 357 371 CHARACTER(LEN=maxlen), ALLOCATABLE :: s1(:), s2(:) 358 372 INTEGER :: k … … 374 388 375 389 !============================================================================================================================== 376 !=== GET THE INDEX OF THE FIRST APPEARANCE IN THE STRING VECTOR "str(:)" OF THE STRING(s) "s" ================================= 390 !=== GET THE INDEX OF THE FIRST APPEARANCE IN THE STRING VECTOR "str(:)" OF THE STRING(s) "s[(:)]" ============================ 391 !=== OPTIONALY: GET THE NUMBER OF FOUND ELEMENTS "n". NB: UNFOUND => INDEX=0 ============================ 377 392 !============================================================================================================================== 378 393 INTEGER FUNCTION strIdx_1(str, s) RESULT(out) … … 386 401 INTEGER, OPTIONAL, INTENT(OUT) :: n 387 402 INTEGER, ALLOCATABLE :: out(:) 403 !------------------------------------------------------------------------------------------------------------------------------ 388 404 INTEGER :: k 389 405 out = [(strIdx_1(str(:), s(k)), k=1, SIZE(s))] … … 400 416 INTEGER, OPTIONAL, INTENT(OUT) :: n 401 417 INTEGER, ALLOCATABLE :: out(:) 418 !------------------------------------------------------------------------------------------------------------------------------ 402 419 INTEGER :: k 403 420 out = PACK( [(k, k=1, SIZE(str(:), DIM=1))], MASK = str(:) == s ) … … 409 426 INTEGER, OPTIONAL, INTENT(OUT) :: n 410 427 INTEGER, ALLOCATABLE :: out(:) 428 !------------------------------------------------------------------------------------------------------------------------------ 411 429 INTEGER :: k 412 430 out = PACK( [(k, k=1, SIZE(i(:), DIM=1))], MASK = i(:) == j ) … … 418 436 INTEGER, OPTIONAL, INTENT(OUT) :: n 419 437 INTEGER, ALLOCATABLE :: out(:) 438 !------------------------------------------------------------------------------------------------------------------------------ 420 439 INTEGER :: k 421 440 out = PACK( [(k, k=1, SIZE(l(:), DIM=1))], MASK = l(:) ) 422 441 IF(PRESENT(n)) n = SIZE(out(:), DIM=1) 423 442 END FUNCTION find_boo 424 !==============================================================================================================================425 426 427 428 !==============================================================================================================================429 !=== GET 1ST APPEARANCE INDEX OF EACH ELEMENT OF "t(:)" IN "s(:)" (UNFOUND: INDEX=0) ==========================================430 !=== OPTIONALY: GET THE NUMBER OF FOUND ELEMENTS "n" ==========================================431 443 !============================================================================================================================== 432 444 … … 444 456 INTEGER, INTENT(OUT) :: idel !--- Index of the identified delimiter (0 if idx==0) 445 457 LOGICAL, OPTIONAL, INTENT(IN) :: lSc !--- Care about nbs with front sign or in scient. notation 446 447 INTEGER :: idx0 !--- Used to display an identified non-numeric string 448 INTEGER, ALLOCATABLE :: ii(:) 449 LOGICAL :: ll, ls 450 CHARACTER(LEN=maxlen) :: d 451 ! modname = 'strIdx' 458 !------------------------------------------------------------------------------------------------------------------------------ 459 INTEGER :: idx0 !--- Used to display an identified non-numeric string 452 460 lerr = .FALSE. 453 idx = strIdx1(rawList, del, ibeg, idel) !--- del(idel) appears in "rawList" at position idx461 idx = strIdx1(rawList, del, ibeg, idel) !--- idx/=0: del(idel) is at position "idx" in "rawList" 454 462 IF(.NOT.PRESENT(lSc)) RETURN !--- No need to check exceptions for numbers => finished 455 463 IF(.NOT. lSc ) RETURN !--- No need to check exceptions for numbers => finished 456 IF(idx == 0) THEN !--- No element of "del" in "rawList": 457 lerr = .NOT.is_numeric(rawList(ibeg:)) !--- String must be a number 458 IF(lerr) idx = LEN_TRIM(rawList); RETURN !--- Update idx => rawList(ibeg:idx-1) is the whole string 459 END IF 460 idx0 = idx 461 IF(test(idx==1.AND.INDEX('+-',del(idel))/=0, lerr)) RETURN !--- Front separator different from +/-: error 462 IF(idx/=1.AND.is_numeric(rawList(ibeg:idx-1))) RETURN !--- The input string tail is a valid number 463 idx = strIdx1(rawList, del, idx+1, idel) !--- => TO THE NEXT DELIMITER 464 465 !=== No delimiter found: the whole string must be a valid number 466 IF(idx == 0) THEN !--- No element of "del" in "rawList" 467 lerr = .NOT.is_numeric(rawList(ibeg:LEN_TRIM(rawList))) !--- String must be a number 468 IF(lerr) idx = LEN_TRIM(rawList); RETURN !--- Set idx so that rawList(ibeg:idx-1) = whole string 469 END IF 470 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 473 474 !=== The string part in front of the 1st delimiter is not a valid number: search for next delimiter index "idx" 475 idx0 = idx ; idx = strIdx1(rawList, del, idx+1, idel) !--- Keep start index because idx is recycled 464 476 IF(idx == 0) THEN 465 lerr = .NOT.is_numeric(rawList(ibeg: )) !--- No delimiter detected: string must be a number477 lerr = .NOT.is_numeric(rawList(ibeg:LEN_TRIM(rawList))) !--- No other delimiter: whole string must be a valid numb 466 478 IF(lerr) idx = idx0; RETURN 467 479 END IF 468 idx0 = idx469 IF(is_numeric(rawList(ibeg:idx-1))) RETURN !--- The input string tail is a valid number470 IF(test( INDEX('eE',rawList(idx-1:idx-1)) /= 0 & !--- Sole possible exception: scientific notation: E+/-471 .OR. INDEX('+-',del(idel)) /=0, lerr)) RETURN472 idx = strIdx1(rawList, del, idx+1, idel) !--- => TO THE NEXT DELIMITER473 IF(idx == 0) THEN474 lerr = .NOT.is_numeric(rawList(ibeg:)) !--- No separator detected: string must be a number475 IF(lerr) idx = idx0; RETURN476 END IF477 480 lerr = .NOT.is_numeric(rawList(ibeg:idx-1)) 481 478 482 CONTAINS 479 483 480 INTEGER FUNCTION strIdx1(str, del, ib, id) RESULT(idx) 481 CHARACTER(LEN=*), INTENT(IN) :: str 482 CHARACTER(LEN=*), INTENT(IN) :: del(:) 484 !------------------------------------------------------------------------------------------------------------------------------ 485 INTEGER FUNCTION strIdx1(str, del, ib, id) RESULT(i) 486 !--- Get the index of the first appereance of one of the delimiters "del(:)" in "str" starting from position "ib". 487 !--- "id" is the index in "del(:)" of the first delimiter found. 488 IMPLICIT NONE 489 CHARACTER(LEN=*), INTENT(IN) :: str, del(:) 483 490 INTEGER, INTENT(IN) :: ib 484 491 INTEGER, INTENT(OUT) :: id 485 486 INTEGER :: nd, ns, i 487 INTEGER, ALLOCATABLE :: ii(:) 488 489 nd = SIZE(del) !--- Number of separators 490 ns = LEN_TRIM(str) !--- Length of the raw chain 491 ii = [(INDEX( str(ib:ns), del(i) ), i = 1, nd)] !--- Determine the next separator start index 492 id = MINLOC( ii, MASK = ii /= 0, DIM = 1 ) !--- Current delimiter index in the "delimiter(:)" list 493 idx = 0 494 IF(ANY(ii /= 0)) idx = MINVAL( ii, MASK = ii /= 0 ) + ib - 1 !--- Index in "str(1:ns)" of the delimiter first character 495 IF(idx == 0) id = 0 492 !------------------------------------------------------------------------------------------------------------------------------ 493 DO i = ib, LEN_TRIM(str); id = strIdx(del, str(i:i)); IF(id /= 0) EXIT; END DO 494 IF(i > LEN_TRIM(str)) THEN; i = 0; id = 0; END IF 496 495 END FUNCTION strIdx1 497 496 … … 501 500 502 501 !============================================================================================================================== 503 !=== Return the index of first appearance of "del" in "str" starting from index "ib"504 !==============================================================================================================================505 INTEGER FUNCTION strIndex(str, del, ib) RESULT(idx)506 CHARACTER(LEN=*), INTENT(IN) :: str507 CHARACTER(LEN=*), INTENT(IN) :: del508 INTEGER, INTENT(IN) :: ib509 idx = INDEX( str(ib:LEN_TRIM(str)), del ) + ib -1510 END FUNCTION strIndex511 !==============================================================================================================================512 513 514 !==============================================================================================================================515 502 !=== Count the number of elements separated by "delimiter" in list "rawList". ================================================= 516 503 !============================================================================================================================== 517 LOGICAL FUNCTION strCount_11(rawList, delimiter, nb, lSc) RESULT( out)504 LOGICAL FUNCTION strCount_11(rawList, delimiter, nb, lSc) RESULT(lerr) 518 505 CHARACTER(LEN=*), INTENT(IN) :: rawList 519 506 CHARACTER(LEN=*), INTENT(IN) :: delimiter 520 507 INTEGER, INTENT(OUT) :: nb 521 508 LOGICAL, OPTIONAL, INTENT(IN) :: lSc 509 !------------------------------------------------------------------------------------------------------------------------------ 522 510 LOGICAL :: ll 523 511 ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc 524 out= strCount_1m(rawList, [delimiter], nb, ll)512 lerr = strCount_1m(rawList, [delimiter], nb, ll) 525 513 END FUNCTION strCount_11 526 514 !============================================================================================================================== 527 LOGICAL FUNCTION strCount_m1(rawList, delimiter, nb, lSc) RESULT( out)515 LOGICAL FUNCTION strCount_m1(rawList, delimiter, nb, lSc) RESULT(lerr) 528 516 CHARACTER(LEN=*), INTENT(IN) :: rawList(:) 529 517 CHARACTER(LEN=*), INTENT(IN) :: delimiter 530 518 INTEGER, ALLOCATABLE, INTENT(OUT) :: nb(:) 531 519 LOGICAL, OPTIONAL, INTENT(IN) :: lSc 532 520 !------------------------------------------------------------------------------------------------------------------------------ 533 521 LOGICAL :: ll 534 522 INTEGER :: id 535 536 523 ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc .AND. INDEX('+-', delimiter) /= 0 537 out= .TRUE.524 lerr = .TRUE. 538 525 ALLOCATE(nb(SIZE(rawList))) 539 526 DO id = 1, SIZE(rawList) 540 out = out.AND. strCount_1m(rawList(id), [delimiter], nb(id), ll)527 lerr = lerr .AND. strCount_1m(rawList(id), [delimiter], nb(id), ll) 541 528 END DO 542 529 END FUNCTION strCount_m1 … … 547 534 INTEGER, INTENT(OUT) :: nb 548 535 LOGICAL, OPTIONAL, INTENT(IN) :: lSc 536 !------------------------------------------------------------------------------------------------------------------------------ 549 537 INTEGER :: ib, ie, jd, nr 550 538 LOGICAL :: ll 551 539 CHARACTER(LEN=1024) :: r 552 ! modname = 'strCount'553 540 lerr = .FALSE. 554 541 ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc … … 559 546 lerr = strIdx_prv(r, delimiter, ib, ie, jd, ll) 560 547 IF(fmsg('"'//TRIM(r(ib:ie-1))//'" is not numeric', ll=lerr)) RETURN 561 IF( jd == 0) EXIT548 IF(ie == 0 .OR. jd == 0) EXIT 562 549 ib = ie + LEN(delimiter(jd)) 563 550 DO WHILE(r(ib:ib) == ' ' .AND. ib < nr); ib = ib + 1; END DO !--- Skip spaces before next chain … … 572 559 !=== Corresponding "vals" remains empty if the element does not contain "=" sign. ==================================== 573 560 !============================================================================================================================== 574 LOGICAL FUNCTION strParse _1(rawList, delimiter, keys, lSc, vals, n) RESULT(lerr)561 LOGICAL FUNCTION strParse(rawList, delimiter, keys, n, vals) RESULT(lerr) 575 562 CHARACTER(LEN=*), INTENT(IN) :: rawList, delimiter 576 563 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: keys(:) 577 LOGICAL, OPTIONAL, INTENT(IN) :: lSc !--- Take care about numbers in scientific notation564 INTEGER, OPTIONAL, INTENT(OUT) :: n 578 565 CHARACTER(LEN=maxlen), ALLOCATABLE, OPTIONAL, INTENT(OUT) :: vals(:) 579 INTEGER, OPTIONAL, INTENT(OUT) :: n 580 LOGICAL :: ll 581 ! modname = 'strParse' 582 ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc 583 IF(.NOT.PRESENT(vals)) lerr = strParse_m(rawList, [delimiter], keys, ll) 584 IF( PRESENT(vals)) lerr = strParse_m(rawList, [delimiter], keys, ll, vals) 585 IF(PRESENT(n)) n = SIZE(keys) 586 END FUNCTION strParse_1 587 !============================================================================================================================== 588 LOGICAL FUNCTION strParse_m(rawList, delimiter, keys, lSc, vals, n, id) RESULT(lerr) 566 !------------------------------------------------------------------------------------------------------------------------------ 567 CHARACTER(LEN=1024) :: r 568 INTEGER :: nr, nk 569 lerr = .FALSE. 570 r = TRIM(ADJUSTL(rawList)) 571 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 580 581 CONTAINS 582 583 !------------------------------------------------------------------------------------------------------------------------------ 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 594 DO 595 ie = INDEX(rawList(ib:nr), delimiter)+ib-1 !--- Determine the next separator start index 596 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 599 ib = ie + LEN(delimiter) 600 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 617 618 END FUNCTION strParse 619 !============================================================================================================================== 620 LOGICAL FUNCTION strParse_m(rawList, delimiter, keys, n, vals, lSc, id) RESULT(lerr) 589 621 CHARACTER(LEN=*), INTENT(IN) :: rawList, delimiter(:) 590 622 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: keys(:) !--- Parsed keys vector 623 INTEGER, OPTIONAL, INTENT(OUT) :: n !--- Length of the parsed vector 624 CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: vals(:) !--- Values for <name>=<value> keys 591 625 LOGICAL, OPTIONAL, INTENT(IN) :: lSc !--- Take care about numbers in scientific notation 592 CHARACTER(LEN=maxlen), OPTIONAL, ALLOCATABLE, INTENT(OUT) :: vals(:) !--- Values for <name>=<value> keys593 INTEGER, OPTIONAL, INTENT(OUT) :: n !--- Length of the parsed vector594 626 INTEGER, OPTIONAL, ALLOCATABLE, INTENT(OUT) :: id(:) !--- Indexes of the separators in "delimiter(:)" vector 595 627 !------------------------------------------------------------------------------------------------------------------------------ 596 628 CHARACTER(LEN=1024) :: r 597 629 INTEGER :: nr, ik, nk, ib, ie, jd 598 630 LOGICAL :: ll 599 600 ! modname = 'strParse'601 631 ll = .FALSE.; IF(PRESENT(lSc)) ll = lSc 602 632 IF(test(fmsg("Couldn't parse list: non-numerical strings were found", ll=strCount_1m(rawList, delimiter, nk, ll)),lerr)) RETURN … … 625 655 CONTAINS 626 656 657 !------------------------------------------------------------------------------------------------------------------------------ 627 658 SUBROUTINE parseKeys(key, val) 628 659 CHARACTER(LEN=*), INTENT(INOUT) :: key 629 660 CHARACTER(LEN=*), INTENT(OUT) :: val 661 !------------------------------------------------------------------------------------------------------------------------------ 630 662 INTEGER :: ix 631 663 ix = INDEX(key, '='); IF(ix == 0) RETURN !--- First "=" index in "key" … … 645 677 CHARACTER(LEN=*), INTENT(IN) :: key, val !--- "key" will be replaced by "val" 646 678 LOGICAL, OPTIONAL, INTENT(IN) :: lsurr !--- TRUE => key must be surrounded by special characters to be substituted 647 648 CHARACTER(LEN=1024) :: s, t 679 !------------------------------------------------------------------------------------------------------------------------------ 649 680 INTEGER :: i0, ix, nk, ns 650 681 LOGICAL :: lsur, lb, le 651 652 682 lsur = .FALSE.; IF(PRESENT(lsurr)) lsur = lsurr 653 683 nk = LEN_TRIM(key) … … 688 718 CHARACTER(LEN=*), OPTIONAL, TARGET, INTENT(IN) :: s1, s2, s3, s4, s5, s6, s7, s8, s9 689 719 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 720 !------------------------------------------------------------------------------------------------------------------------------ 690 721 CHARACTER(LEN=maxlen), POINTER :: s 691 722 LOGICAL :: lv(10) … … 707 738 CHARACTER(LEN=*), OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: s1, s2, s3, s4, s5, s6, s7, s8, s9 708 739 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:,:) 740 !------------------------------------------------------------------------------------------------------------------------------ 709 741 CHARACTER(LEN=maxlen), POINTER :: s(:) 710 742 LOGICAL :: lv(10) … … 729 761 INTEGER, OPTIONAL, TARGET, INTENT(IN) :: i1, i2, i3, i4, i5, i6, i7, i8, i9 730 762 INTEGER, ALLOCATABLE :: out(:) 763 !------------------------------------------------------------------------------------------------------------------------------ 731 764 INTEGER, POINTER :: i 732 765 LOGICAL :: lv(10) … … 748 781 INTEGER, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: i1, i2, i3, i4, i5, i6, i7, i8, i9 749 782 INTEGER, ALLOCATABLE :: out(:,:) 783 !------------------------------------------------------------------------------------------------------------------------------ 750 784 INTEGER, POINTER :: i(:) 751 785 LOGICAL :: lv(10) … … 770 804 REAL, OPTIONAL, TARGET, INTENT(IN) :: r1, r2, r3, r4, r5, r6, r7, r8, r9 771 805 REAL, ALLOCATABLE :: out(:) 806 !------------------------------------------------------------------------------------------------------------------------------ 772 807 REAL, POINTER :: r 773 808 LOGICAL :: lv(10) … … 789 824 REAL, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: r1, r2, r3, r4, r5, r6, r7, r8, r9 790 825 REAL, ALLOCATABLE :: out(:,:) 826 !------------------------------------------------------------------------------------------------------------------------------ 791 827 REAL, POINTER :: r(:) 792 828 LOGICAL :: lv(10) … … 811 847 DOUBLE PRECISION, OPTIONAL, TARGET, INTENT(IN) :: d1, d2, d3, d4, d5, d6, d7, d8, d9 812 848 DOUBLE PRECISION, ALLOCATABLE :: out(:) 849 !------------------------------------------------------------------------------------------------------------------------------ 813 850 DOUBLE PRECISION, POINTER :: d 814 851 LOGICAL :: lv(10) … … 830 867 DOUBLE PRECISION, OPTIONAL, TARGET, DIMENSION(:), INTENT(IN) :: d1, d2, d3, d4, d5, d6, d7, d8, d9 831 868 DOUBLE PRECISION, ALLOCATABLE :: out(:,:) 869 !------------------------------------------------------------------------------------------------------------------------------ 832 870 DOUBLE PRECISION, POINTER :: d(:) 833 871 LOGICAL :: lv(10) … … 869 907 INTEGER, OPTIONAL, INTENT(IN) :: unit !--- Output unit (default: screen) 870 908 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: sub !--- Subroutine name 871 909 !------------------------------------------------------------------------------------------------------------------------------ 872 910 CHARACTER(LEN=2048) :: row 873 911 CHARACTER(LEN=maxlen) :: rFm, el, subn … … 879 917 INTEGER, PARAMETER :: nm=1 !--- Space between values & columns 880 918 LOGICAL :: ls, li, lr 881 882 919 subn = ''; IF(PRESENT(sub)) subn = sub 883 920 rFm = '*'; IF(PRESENT(rFmt)) rFm = rFmt !--- Specified format for reals … … 954 991 nr = LEN_TRIM(row)-1 !--- Final separator removed 955 992 CALL msg(row(1:nr), subn, unit=unt) 956 IF(ir /= 1) CYCLE !--- Titles are underlined993 IF(ir /= 1) CYCLE !--- Titles only are underlined 957 994 row=''; DO ic=1,nHd; row=TRIM(row)//REPEAT('-',n(ic))//'+'; END DO 958 995 DO ic = ib,ncmx(it); row=TRIM(row)//REPEAT('-',n(ic))//'+'; END DO … … 975 1012 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: rFmt !--- Format for reals 976 1013 LOGICAL, OPTIONAL, INTENT(IN) :: llast !--- Last variable: no final ',' 977 1014 !------------------------------------------------------------------------------------------------------------------------------ 978 1015 CHARACTER(LEN=maxlen) :: rFm, el 979 1016 CHARACTER(LEN=maxlen), ALLOCATABLE :: d(:,:) … … 983 1020 INTEGER, ALLOCATABLE :: n(:) 984 1021 LOGICAL :: ls, li, lr, la 985 986 ! modname = 'dispNamelist'987 1022 rFm = '*'; IF(PRESENT(rFmt)) rFm = rFmt !--- Specified format for reals 988 1023 ls = PRESENT(s); li = PRESENT(i); lr = PRESENT(r) … … 1056 1091 REAL, INTENT(IN) :: a(:) !--- Linearized array of values 1057 1092 INTEGER, INTENT(IN) :: n(:) !--- Profile before linearization 1058 1059 1093 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: err_msg, nam(:), subn !--- Error message, variables and calling subroutine names 1060 1094 INTEGER, OPTIONAL, INTENT(IN) :: nRowMax !--- Maximum number of lines to display (default: all) … … 1062 1096 INTEGER, OPTIONAL, INTENT(IN) :: nHead !--- Number of front columns to duplicate (default: 1) 1063 1097 INTEGER, OPTIONAL, INTENT(IN) :: unit !--- Output unit (def: lunout) 1098 !------------------------------------------------------------------------------------------------------------------------------ 1064 1099 CHARACTER(LEN=maxlen), ALLOCATABLE :: ttl(:) 1065 1100 LOGICAL, ALLOCATABLE :: m(:) … … 1139 1174 INTEGER, OPTIONAL, INTENT(IN) :: nHead !--- Number of front columns to duplicate (default: 1) 1140 1175 INTEGER, OPTIONAL, INTENT(IN) :: unit !--- Output unit (def: lunout) 1141 1176 !------------------------------------------------------------------------------------------------------------------------------ 1142 1177 CHARACTER(LEN=maxlen) :: mes, sub, fm='(f12.9)', prf 1143 1178 CHARACTER(LEN=maxlen), ALLOCATABLE :: ttl(:), vnm(:) 1144 LOGICAL, ALLOCATABLE :: m(:)1145 1179 INTEGER, ALLOCATABLE :: ki(:), kj(:), kl(:) 1146 INTEGER :: i, j, k, rk, ib, ie, itr, nm, nv, unt, nRmx, nCmx, nHd, rk11180 INTEGER :: i, j, k, rk, nv, unt, nRmx, nCmx, nHd 1147 1181 REAL, ALLOCATABLE :: val(:,:) 1148 1182 … … 1160 1194 lerr= SIZE(a,1) /= PRODUCT(n); IF(fmsg('profile "n" does not match "a" and "ll"', sub, lerr, unt)) RETURN 1161 1195 1162 SELECT CASE(rk 1) !--- Indices list1196 SELECT CASE(rk) !--- Indices list 1163 1197 CASE(0); IF(ll(1)) THEN; WRITE(unt,'(a,", ",a," = ",2f12.9)')TRIM(vnm(1)),TRIM(vnm(2)),a(1,1),a(1,2); RETURN; END IF 1164 1198 CASE(1); ki = [ (i,i=1,n(1)) ] … … 1189 1223 CHARACTER(LEN=*), INTENT(IN) :: str 1190 1224 CHARACTER(LEN=maxlen), INTENT(OUT) :: val 1191 1225 !------------------------------------------------------------------------------------------------------------------------------ 1192 1226 CHARACTER(LEN=maxlen) :: v 1193 1227 CHARACTER(LEN=1024) :: s, vv … … 1196 1230 INTEGER :: nl, nn, i, j, im, ix 1197 1231 LOGICAL :: ll 1198 ! modname = 'reduceExpr_1'1199 1232 s = str 1200 1233 … … 1243 1276 CHARACTER(LEN=maxlen), ALLOCATABLE :: ky(:) 1244 1277 CHARACTER(LEN=1), ALLOCATABLE :: op(:) 1245 1278 !------------------------------------------------------------------------------------------------------------------------------ 1246 1279 CHARACTER(LEN=1024) :: s 1247 1280 DOUBLE PRECISION :: v, vm, vp 1248 1281 INTEGER :: i, ni, io 1249 1250 ! modname = 'reduceExpr_basic'1251 1282 lerr = .FALSE. 1252 1283 IF(is_numeric(str)) THEN; val=TRIM(str); RETURN; END IF 1253 1284 op = ['^','/','*','+','-'] !--- List of recognized operations 1254 1285 s = str 1255 IF(test(strParse_m(s, op, ky, .TRUE., id = id), lerr)) RETURN!--- Parse the values1286 IF(test(strParse_m(s, op, ky, lSc=.TRUE., id = id), lerr)) RETURN !--- Parse the values 1256 1287 vl = str2dble(ky) !--- Conversion to doubles 1257 1288 lerr = ANY(vl >= HUGE(1.d0)) … … 1262 1293 IF(id(i) /= io) CYCLE !--- Current found operator is not op(io) 1263 1294 vm = vl(i); vp = vl(i+1) !--- Couple of values used for current operation 1264 SELECT CASE( io) !--- Perform operation on the two values1265 CASE( 1); v = vm**vp !--- ^1266 CASE( 2); v = vm/vp !--- /1267 CASE( 3); v = vm*vp !--- *1268 CASE( 4); v = vm+vp !--- +1269 CASE( 5); v = vm-vp !--- +1295 SELECT CASE(op(io)) !--- Perform operation on the two values 1296 CASE('^'); v = vm**vp 1297 CASE('/'); v = vm/vp 1298 CASE('*'); v = vm*vp 1299 CASE('+'); v = vm+vp 1300 CASE('-'); v = vm-vp 1270 1301 END SELECT 1271 1302 IF(i == ni) THEN; vl = [vl(1:ni-1), v]; ELSE; vl = [vl(1:i-1), v, vl(i+2:ni+1)]; END IF … … 1283 1314 CHARACTER(LEN=*), INTENT(IN) :: str(:) 1284 1315 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1316 !------------------------------------------------------------------------------------------------------------------------------ 1285 1317 INTEGER :: i 1286 1318 ALLOCATE(lerr(SIZE(str)),val(SIZE(str))) … … 1302 1334 READ(str,fmt,IOSTAT=e) x 1303 1335 out = e==0 .AND. INDEX('Ee',str(LEN_TRIM(str):LEN_TRIM(str)))==0 1304 IF(str == '') out = .FALSE.1305 1336 END FUNCTION is_numeric 1306 1337 !============================================================================================================================== … … 1348 1379 INTEGER, INTENT(IN) :: i 1349 1380 INTEGER, OPTIONAL, INTENT(IN) :: nDigits 1381 !------------------------------------------------------------------------------------------------------------------------------ 1350 1382 WRITE(out,*)i 1351 1383 out = ADJUSTL(out) … … 1357 1389 REAL, INTENT(IN) :: r 1358 1390 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt 1391 !------------------------------------------------------------------------------------------------------------------------------ 1359 1392 IF( PRESENT(fmt)) WRITE(out,fmt)r 1360 1393 IF(.NOT.PRESENT(fmt)) WRITE(out, * )r … … 1365 1398 DOUBLE PRECISION, INTENT(IN) :: d 1366 1399 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: fmt 1400 !------------------------------------------------------------------------------------------------------------------------------ 1367 1401 IF( PRESENT(fmt)) WRITE(out,fmt)d 1368 1402 IF(.NOT.PRESENT(fmt)) WRITE(out, * )d … … 1385 1419 !============================================================================================================================== 1386 1420 1421 1387 1422 !============================================================================================================================== 1388 1423 FUNCTION addQuotes_1(s) RESULT(out) … … 1395 1430 CHARACTER(LEN=*), INTENT(IN) :: s(:) 1396 1431 CHARACTER(LEN=:), ALLOCATABLE :: out(:) 1432 !------------------------------------------------------------------------------------------------------------------------------ 1397 1433 INTEGER :: k, n 1398 1434 n = MAXVAL(LEN_TRIM(s), MASK=.TRUE.) … … 1406 1442 CHARACTER(LEN=*), INTENT(IN) :: s 1407 1443 CHARACTER(LEN=1) :: b, e 1444 !------------------------------------------------------------------------------------------------------------------------------ 1408 1445 out = .TRUE.; IF(TRIM(s) == '') RETURN 1409 1446 b = s(1:1); e = s(MAX(1,LEN_TRIM(s)):MAX(1,LEN_TRIM(s))) 1410 1447 out = .NOT.is_numeric(s) .AND. (b /= "'" .OR. e /= "'") .AND. ( b /= '"' .OR. e /= '"') 1411 1448 END FUNCTION needQuotes 1412 !==============================================================================================================================1413 1414 1415 !==============================================================================================================================1416 !=== TEST WHETHER A FILE IS PRESENT OR NOT ====================================================================================1417 !==============================================================================================================================1418 LOGICAL FUNCTION testFile_1(fname) RESULT(out)1419 CHARACTER(LEN=*), INTENT(IN) :: fname1420 INTEGER :: ierr1421 OPEN(90, FILE=fname, FORM='formatted', STATUS='old', IOSTAT=ierr); CLOSE(99)1422 out = ierr/=01423 END FUNCTION testFile_11424 !==============================================================================================================================1425 FUNCTION testFile_m(fname) RESULT(out)1426 LOGICAL, ALLOCATABLE :: out(:)1427 CHARACTER(LEN=*), INTENT(IN) :: fname(:)1428 INTEGER :: k1429 out = [(testFile_1(fname(k)), k=1, SIZE(fname))]1430 END FUNCTION testFile_m1431 1449 !============================================================================================================================== 1432 1450 … … 1442 1460 CHARACTER(LEN=*), INTENT(IN) :: message, items, reason 1443 1461 INTEGER, OPTIONAL, INTENT(IN) :: nmax 1462 !------------------------------------------------------------------------------------------------------------------------------ 1444 1463 CHARACTER(LEN=maxlen), ALLOCATABLE :: s(:) 1445 1464 INTEGER :: i, nmx … … 1464 1483 1465 1484 1466 1467 1485 END MODULE strings_mod -
LMDZ6/branches/LMDZ_ECRad/libf/misc/wxios.F90
r4146 r4482 308 308 IF (xios_is_valid_axis("axis_lat")) THEN 309 309 CALL xios_set_axis_attr( "axis_lat", n_glo=nbp_lat, n=jj_nb, begin=jj_begin-1, value=io_lat(jj_begin:jj_end)) 310 ENDIF 311 IF (xios_is_valid_axis("axis_lat_greordered")) THEN 312 CALL xios_set_axis_attr( "axis_lat_greordered", n_glo=nbp_lat, n=jj_nb, begin=jj_begin-1, & 313 value=io_lat(jj_begin:jj_end)*(-1.)) 310 314 ENDIF 311 315
Note: See TracChangeset
for help on using the changeset viewer.