Changeset 4120 for LMDZ6/trunk/libf/misc/readTracFiles_mod.f90
- Timestamp:
- Apr 5, 2022, 3:44:30 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
LMDZ6/trunk/libf/misc/readTracFiles_mod.f90
r4075 r4120 1 1 MODULE readTracFiles_mod 2 2 3 USE strings_mod, ONLY: msg, testFile, strFind, strStack, strReduce, strHead, strCount, find, maxlen, fmsg, &4 removeComment, cat, checkList, str Idx, strParse, strReplace, strTail, reduceExpr, test, get_in, dispTable3 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 5 USE trac_types_mod, ONLY: trac_type, isot_type, keys_type 6 6 … … 12 12 PUBLIC :: readTracersFiles, indexUpdate, setGeneration !--- TOOLS ASSOCIATED TO TRACERS DESCRIPTORS 13 13 PUBLIC :: readIsotopesFile !--- TOOLS ASSOCIATED TO ISOTOPES DESCRIPTORS 14 PUBLIC :: getKey_init, getKey, setDirectKeys !--- GET/SET KEYS FROM/TO tracers & isotopes 15 16 PUBLIC :: known_phases, old_phases, nphases, phases_names, & !--- VARIABLES RELATED TO THE PHASES 17 phases_sep, delPhase, addPhase, & !--- + ROUTINES TO ADD/REMOVE PHASE TO/FROM A NAME 18 old2newPhase, new2oldPhase 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) 19 21 20 22 PUBLIC :: tran0, idxAncestor, ancestor !--- GENERATION 0 TRACER + TOOLS FOR GENERATIONS 21 22 23 !------------------------------------------------------------------------------------------------------------------------------ 23 24 TYPE :: dataBase_type !=== TYPE FOR TRACERS SECTION … … 30 31 END INTERFACE getKey 31 32 !------------------------------------------------------------------------------------------------------------------------------ 33 INTERFACE fGetKey; MODULE PROCEDURE fgetKeyByIndex_s1, fgetKeyByName_s1; END INTERFACE fGetKey 32 34 INTERFACE tracersSubset; MODULE PROCEDURE trSubset_Indx, trSubset_Name, trSubset_gen0Name; END INTERFACE tracersSubset 33 35 INTERFACE idxAncestor; MODULE PROCEDURE idxAncestor_1, idxAncestor_m; END INTERFACE idxAncestor 34 36 INTERFACE ancestor; MODULE PROCEDURE ancestor_1, ancestor_m; END INTERFACE ancestor 35 INTERFACE addPhase; MODULE PROCEDURE addPhase_1, addPhase_m; END INTERFACE addPhase 37 INTERFACE addPhase; MODULE PROCEDURE addPhase_s1, addPhase_sm, addPhase_i1, addPhase_im; END INTERFACE addPhase 38 INTERFACE old2newName; MODULE PROCEDURE old2newName_1, old2newName_m; END INTERFACE old2newName 39 INTERFACE new2oldName; MODULE PROCEDURE new2oldName_1, new2oldName_m; END INTERFACE new2oldName 36 40 !------------------------------------------------------------------------------------------------------------------------------ 37 41 … … 49 53 LOGICAL, SAVE :: tracs_merge = .TRUE. !--- Merge/stack tracers lists 50 54 LOGICAL, SAVE :: lSortByGen = .TRUE. !--- Sort by growing generation 55 56 !--- KEPT JUST TO MANAGE OLD WATER ISOTOPES NAMES 57 !--- Apart from that context, on limitaion on isotopes names (as long as they have a corresponding line in isotopes_params.def) 58 CHARACTER(LEN=maxlen), SAVE :: oldH2OIso(5) = ['eau', 'HDO', 'O18', 'O17', 'HTO' ] 59 CHARACTER(LEN=maxlen), SAVE :: newH2OIso(5) = ['H2[16]O', 'H[2]HO ', 'H2[18]O', 'H2[17]O', 'H[3]HO '] 60 51 61 52 62 !=== LOCAL COPIES OF THE TRACERS AND ISOTOPES DESCRIPTORS, USED BY getKey (INITIALIZED IN getKey_init) … … 87 97 INTEGER, INTENT(OUT) :: fType !--- Type of input file found 88 98 TYPE(trac_type), ALLOCATABLE, INTENT(OUT) :: tracs(:) 89 CHARACTER(LEN=maxlen), ALLOCATABLE :: 90 CHARACTER(LEN=maxlen) :: str, fname, mesg , oldH2O, newH2O99 CHARACTER(LEN=maxlen), ALLOCATABLE :: s(:), sections(:), trac_files(:) 100 CHARACTER(LEN=maxlen) :: str, fname, mesg 91 101 INTEGER :: is, nsec, ierr, it, ntrac, ns, ip, ix 92 102 LOGICAL, ALLOCATABLE :: ll(:), lGen3(:) … … 142 152 CALL msg('This file is for air tracers only', modname, ns == 3 .AND. it == 1) 143 153 CALL msg('This files specifies the transporting fluid', modname, ns == 4 .AND. it == 1) 144 tracs(it)%name = TRIM(s(3)) !--- Set %name: nameof the tracer145 tracs(it)%parent = tran0 !--- Set %parent: transporting fluid146 IF(ns == 4) tracs(it)%parent = s(4) !--- default: 'air' or defined in the file147 tracs(it)%phase = known_phases( 1:1)!--- Set %phase: tracer phase (default: "g"azeous)154 tracs(it)%name = old2newName(s(3), ip) !--- Set %name: name of the tracer 155 tracs(it)%parent = tran0 !--- Default transporting fluid name 156 IF(ns == 4) tracs(it)%parent = old2newName(s(4)) !--- Set %parent: parent of the tracer 157 tracs(it)%phase = known_phases(ip:ip) !--- Set %phase: tracer phase (default: "g"azeous) 148 158 tracs(it)%component = TRIM(type_trac) !--- Set %component: model component name 149 159 tracs(it)%keys%key = ['hadv', 'vadv'] !--- Set %keys%key … … 151 161 END DO 152 162 CLOSE(90) 153 DO ip = 1, nphases !--- Deal with old water names154 oldH2O = 'H2O'//old_phases(ip:ip)155 newH2O = 'H2O'//phases_sep//known_phases(ip:ip)156 ix = strIdx(tracs(:)%name, oldH2O)157 IF(ix == 0) CYCLE158 tracs(ix)%name = newH2O !--- Set %name: name of the tracer159 WHERE(tracs(:)%parent == oldH2O) tracs(:)%parent = newH2O !--- Set %parent: transporting fluid160 tracs(ix)%phase = known_phases(ip:ip) !--- Set %phase: tracer phase161 END DO162 163 CALL setGeneration(tracs) !--- Set %iGeneration and %gen0Name 163 WHERE(tracs%iGeneration == 3) tracs%type = 'tag' !--- Set %type: 'tracer' or 'tag'164 WHERE(tracs%iGeneration == 2) tracs%type = 'tag' !--- Set %type: 'tracer' or 'tag' 164 165 IF(test(checkTracers(tracs, fname, fname), lerr)) RETURN !--- Detect orphans and check phases 165 166 IF(test(checkUnique (tracs, fname, fname), lerr)) RETURN !--- Detect repeated tracers … … 167 168 tracs(:)%keys%name = tracs(:)%name !--- Copy tracers names in keys components 168 169 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 169 CASE(2); IF(test(feedDBase(["tracer.def"], [type_trac]), lerr)) RETURN !=== SINGLE FILE, COMA-SEPARATED SECTIONS LIST170 CASE(2); IF(test(feedDBase(["tracer.def"], [type_trac], modname), lerr)) RETURN !=== SINGLE FILE, MULTIPLE SECTIONS 170 171 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 171 CASE(3); IF(test(feedDBase( trac_files , sections ), lerr)) RETURN !=== MULTIPLE FILES, ONE SECTION EACH FILE172 CASE(3); IF(test(feedDBase( trac_files , sections, modname), lerr)) RETURN !=== MULTIPLE FILES, SINGLE SECTION 172 173 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 173 174 END SELECT 174 175 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 175 176 176 IF(A NY([2,3] == fType) .AND. nsec > 1) THEN177 IF(tracs_merge) THEN 178 CALL msg('The multiple required sections will be MERGED.', modname)179 IF(test(mergeTracers(dBase, tracs), lerr)) RETURN180 ELSE181 CALL msg('The multiple required sections will be CUMULATED.',modname)182 IF(test(cumulTracers(dBase, tracs), lerr)) RETURN183 END IF184 WHERE(tracs%gen0Name(1:3) /= 'H2O') tracs%isInPhysics=.TRUE. !--- Set %isInPhysics: passed to physics185 CALL setDirectKeys(tracs) !--- Set %iqParent, %iqDescen, %nqDescen, %nqChilds177 IF(ALL([2,3] /= fType)) RETURN 178 179 IF(nsec == 1) THEN; 180 tracs = dBase(1)%trac 181 ELSE IF(tracs_merge) THEN 182 CALL msg('The multiple required sections will be MERGED.', modname) 183 IF(test(mergeTracers(dBase, tracs), lerr)) RETURN 184 ELSE 185 CALL msg('The multiple required sections will be CUMULATED.', modname) 186 IF(test(cumulTracers(dBase, tracs), lerr)) RETURN 186 187 END IF 187 188 WHERE(tracs%gen0Name(1:3) /= 'H2O') tracs%isInPhysics=.TRUE. !--- Set %isInPhysics: passed to physics 189 CALL setDirectKeys(tracs) !--- Set %iqParent, %iqDescen, %nqDescen, %nqChilds 188 190 END FUNCTION readTracersFiles 189 191 !============================================================================================================================== 190 192 191 193 !============================================================================================================================== 192 LOGICAL FUNCTION feedDBase(fnames, snames ) RESULT(lerr)194 LOGICAL FUNCTION feedDBase(fnames, snames, modname) RESULT(lerr) 193 195 ! Purpose: Read the sections "snames(is)" (coma-separated list) from each "fnames(is)" 194 196 ! file and create the corresponding tracers set descriptors in the database "dBase": … … 200 202 CHARACTER(LEN=*), INTENT(IN) :: fnames(:) !--- Files names 201 203 CHARACTER(LEN=*), INTENT(IN) :: snames(:) !--- Coma-deparated list of sections (one list each file) 202 INTEGER, ALLOCATABLE :: ndb(:) !--- Nuber of sections for each file 204 CHARACTER(LEN=*), INTENT(IN) :: modname !--- Calling routine name 205 INTEGER, ALLOCATABLE :: ndb(:) !--- Number of sections for each file 203 206 INTEGER, ALLOCATABLE :: ixf(:) !--- File index for each section of the expanded list 204 207 LOGICAL, ALLOCATABLE :: lTg(:) !--- Tagging tracers mask 205 CHARACTER(LEN=maxlen) :: fnm, snm , modname208 CHARACTER(LEN=maxlen) :: fnm, snm 206 209 INTEGER :: idb, i 207 210 LOGICAL :: ll 208 211 !------------------------------------------------------------------------------------------------------------------------------ 209 modname = 'feedDBase'210 212 !=== READ THE REQUIRED SECTIONS 211 213 ll = strCount(snames, ',', ndb) !--- Number of sections for each file … … 219 221 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 220 222 fnm = fnames(ixf(idb)); snm = dBase(idb)%name !--- FILE AND SECTION NAMES 223 lerr = ANY([(dispTraSection('RAW CONTENT OF SECTION "'//TRIM(snm)//'"', snm, modname), idb=1, SIZE(dBase))]) 221 224 IF(test(expandSection(dBase(idb)%trac, snm, fnm), lerr)) RETURN !--- EXPAND NAMES ; set %parent, %type, %component 222 225 CALL setGeneration (dBase(idb)%trac) !--- set %iGeneration, %genOName … … 225 228 CALL expandPhases (dBase(idb)%trac) !--- EXPAND PHASES ; set %phase 226 229 CALL sortTracers (dBase(idb)%trac) !--- SORT TRACERS 230 lerr = ANY([(dispTraSection('EXPANDED CONTENT OF SECTION "'//TRIM(snm)//'"', snm, modname), idb=1, SIZE(dBase))]) 227 231 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 228 232 END DO 229 233 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 230 231 !=== DISPLAY BASIC INFORMATION232 lerr = ANY([( dispTraSection('Expanded list for section "'//TRIM(dBase(idb)%name)//'"', dBase(idb)%name, modname), &233 idb=1, SIZE(dBase) )])234 234 END FUNCTION feedDBase 235 235 !------------------------------------------------------------------------------------------------------------------------------ … … 406 406 DO it = 1, nt !=== EXPAND TRACERS AND PARENTS NAMES LISTS 407 407 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 408 ll = strParse(tr(it)%name, ',', ta, n=ntr)!--- Number of tracers408 ll = strParse(tr(it)%name, ',', ta, n=ntr) !--- Number of tracers 409 409 ll = strParse(tr(it)%parent, ',', pa, n=npr) !--- Number of parents 410 410 DO ipr=1,npr !--- Loop on parents list elts 411 411 DO itr=1,ntr !--- Loop on tracers list elts 412 412 i = iq+itr-1+(ipr-1)*ntr 413 ttr(i)%name = TRIM(ta(itr)); ttr(i)%parent = pa(ipr) 414 ttr(i)%keys = keys_type(ta(itr), tr(it)%keys%key, tr(it)%keys%val) 413 ttr(i)%name = TRIM(ta(itr)) 414 ttr(i)%parent = TRIM(pa(ipr)) 415 ttr(i)%keys = keys_type(ta(itr), tr(it)%keys%key, tr(it)%keys%val) 415 416 END DO 416 417 END DO 417 ttr(iq:iq+ntr*npr-1)%type = tr(it)%type !--- Duplicating type 418 ttr(iq:iq+ntr*npr-1)%type = tr(it)%type !--- Duplicating type 419 ttr(iq:iq+ntr*npr-1)%component = tr(it)%component !--- Duplicating type 418 420 iq = iq + ntr*npr 419 421 !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ … … 440 442 tr(:)%iGeneration = -1 !--- error if -1 441 443 nq = SIZE(tr, DIM=1) !--- Number of tracers lines 442 lg = tr(:)%parent == tran0 !--- F irst generation tracers flag443 WHERE(lg) tr(:)%iGeneration = 0 !--- First generationtracers444 lg = tr(:)%parent == tran0 !--- Flag for generation 0 tracers 445 WHERE(lg) tr(:)%iGeneration = 0 !--- Generation 0 tracers 444 446 445 447 !=== Determine generation for each tracer … … 511 513 ll = tr(:)%name==TRIM(tnam) !--- Mask for current tracer name 512 514 IF(COUNT(ll)==1 ) CYCLE !--- Tracer is not repeated 513 IF(tr(iq)%iGeneration> 1) THEN514 tdup(iq) = tnam !--- gen> 1: MUST be unique515 IF(tr(iq)%iGeneration>0) THEN 516 tdup(iq) = tnam !--- gen>0: MUST be unique 515 517 ELSE 516 518 DO ip=1,nphases; p=known_phases(ip:ip) !--- Loop on known phases … … 531 533 SUBROUTINE expandPhases(tr) 532 534 !------------------------------------------------------------------------------------------------------------------------------ 533 ! Purpose: Expand the phases in the tracers descriptor "tr". 535 ! Purpose: Expand the phases in the tracers descriptor "tr". Phases are not repeated for a tracer, thanks to "checkUnique". 534 536 !------------------------------------------------------------------------------------------------------------------------------ 535 537 TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:) !--- Tracer derived type vector … … 538 540 INTEGER, ALLOCATABLE :: i0(:) 539 541 CHARACTER(LEN=maxlen) :: nam, pha, trn 542 CHARACTER(LEN=1) :: p 540 543 INTEGER :: ip, np, iq, jq, nq, it, nt, nc, i, n 541 544 LOGICAL :: lTg, lEx … … 544 547 nt = 0 545 548 DO iq = 1, nq !--- GET THE NUMBER OF TRACERS 546 IF(tr(iq)%iGeneration /= 1) CYCLE547 nc = COUNT(tr(:)%gen0Name==tr(iq)%name .AND. tr%iGeneration/= 1) !--- Number of childs of tr(iq)549 IF(tr(iq)%iGeneration /= 0) CYCLE !--- Only deal with generation 0 tracers 550 nc = COUNT(tr(:)%gen0Name==tr(iq)%name .AND. tr%iGeneration/=0) !--- Number of childs of tr(iq) 548 551 tr(iq)%phase = fgetKey(iq, 'phases', tr(:)%keys) !--- Phases list of tr(iq) 549 552 np = LEN_TRIM(tr(iq)%phase) !--- Number of phases of tr(iq) 550 553 nt = nt + (1+nc) * np !--- Number of tracers after expansion 551 554 END DO 552 ALLOCATE(ttr(nt)) 555 ALLOCATE(ttr(nt)) !--- Version of "tr" after phases expansion 553 556 it = 1 !--- Current "ttr(:)" index 554 557 DO iq = 1, nq !--- Loop on "tr(:)" indexes 555 558 lTg = tr(iq)%type=='tag' !--- Current tracer is a tag 556 559 i0 = strFind(tr(:)%name, TRIM(tr(iq)%gen0Name), n) !--- Indexes of first generation ancestor copies 557 np = SUM( [( LEN_TRIM(tr(i0(i))%phase),i=1,n )],1) !--- Number of phases for current tracer tr(iq)558 lEx = np>1 !--- Need of a phase suffix559 IF(lTg) lEx =lEx.AND.tr(iq)%iGeneration>1 !--- No phase suffix for first generationtags560 DO i=1,n !=== LOOP ON FIRST GENERATIONANCESTORS561 jq =i0(i) !--- tr(jq): ith copy of 1st gen. ancestor oftr(iq)562 IF(tr(iq)%iGeneration== 1) jq=iq !--- Generation 1:current tracer phases only560 np = SUM([( LEN_TRIM(tr(i0(i))%phase),i=1,n )], 1) !--- Number of phases for current tracer tr(iq) 561 lEx = np>1 !--- Phase suffix only required if phases number is > 1 562 IF(lTg) lEx = lEx .AND. tr(iq)%iGeneration>0 !--- No phase suffix for generation 0 tags 563 DO i=1,n !=== LOOP ON GENERATION 0 ANCESTORS 564 jq = i0(i) !--- tr(jq): ith tracer with same gen 0 ancestor as tr(iq) 565 IF(tr(iq)%iGeneration==0) jq=iq !--- Generation 0: count the current tracer phases only 563 566 pha = tr(jq)%phase !--- Phases list for tr(jq) 564 DO ip=1,LEN_TRIM(pha) !=== LOOP ON PHASES LISTS 565 trn=TRIM(tr(iq)%name); nam=trn !--- Tracer name (regular case) 567 DO ip = 1, LEN_TRIM(pha) !=== LOOP ON PHASES LISTS 568 p = pha(ip:ip) 569 trn = TRIM(tr(iq)%name); nam = trn !--- Tracer name (regular case) 566 570 IF(lTg) nam = TRIM(tr(iq)%parent) !--- Parent name (tagging case) 567 IF(lEx) nam = TRIM(nam)//phases_sep//pha(ip:ip)!--- Phase extension needed571 IF(lEx) nam = addPhase(nam, p ) !--- Phase extension needed 568 572 IF(lTg) nam = TRIM(nam)//'_'//TRIM(trn) !--- <parent>_<name> for tags 569 573 ttr(it) = tr(iq) !--- Same <key>=<val> pairs 570 ttr(it)%name = TRIM(nam)!--- Name with possibly phase suffix574 ttr(it)%name = TRIM(nam) !--- Name with possibly phase suffix 571 575 ttr(it)%keys%name = TRIM(nam) !--- Name inside the keys decriptor 572 ttr(it)%phase = pha(ip:ip)!--- Single phase entry573 IF(lEx .AND.tr(iq)%iGeneration>1) THEN574 ttr(it)%parent = TRIM(ttr(it)%parent)//phases_sep//pha(ip:ip)575 ttr(it)%gen0Name = TRIM(ttr(it)%gen0Name)//phases_sep//pha(ip:ip)576 ttr(it)%phase = p !--- Single phase entry 577 IF(lEx .AND. tr(iq)%iGeneration>0) THEN 578 ttr(it)%parent = addPhase(ttr(it)%parent, p) 579 ttr(it)%gen0Name = addPhase(ttr(it)%gen0Name, p) 576 580 END IF 577 it =it+1581 it = it+1 578 582 END DO 579 IF(tr(iq)%iGeneration== 1) EXIT !--- Break phase loop for gen 1583 IF(tr(iq)%iGeneration==0) EXIT !--- Break phase loop for gen 0 580 584 END DO 581 585 END DO … … 590 594 !------------------------------------------------------------------------------------------------------------------------------ 591 595 ! Purpose: Sort tracers: 592 ! * Put water at first places, in the "known_phases" order.596 ! * Put water at the beginning of the vector, in the "known_phases" order. 593 597 ! * lGrowGen == T: in ascending generations numbers. 594 598 ! * lGrowGen == F: tracer + its childs sorted by growing generation, one after the other. 595 599 ! TO BE ADDED IF NECESSARY: HIGHER MOMENTS AT THE END 596 600 !------------------------------------------------------------------------------------------------------------------------------ 597 TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:) !--- Tracer derived type vector 601 TYPE(trac_type), ALLOCATABLE, INTENT(INOUT) :: tr(:) !--- Tracer derived type vector 602 ! TYPE(trac_type), ALLOCATABLE :: ttr(:) 603 INTEGER, ALLOCATABLE :: iy(:), iz(:) 598 604 INTEGER :: ig, ng, iq, jq, ip, nq, n, ix(SIZE(tr)), k 599 INTEGER, ALLOCATABLE :: iy(:), iz(:)600 605 !------------------------------------------------------------------------------------------------------------------------------ 601 606 nq = SIZE(tr) 602 iy = [(k, k=1, nq)]603 607 DO ip = nphases, 1, -1 604 iq = strIdx(tr acers(:)%name, 'H2O'//phases_sep//known_phases(ip:ip))605 IF(iq /=0) iy = [iq, iy(1:iq-1), iy(iq:nq)]606 END DO607 tr = tr(iy) !--- Water displaces at first positions 608 iq = 1608 iq = strIdx(tr(:)%name, addPhase('H2O', ip)) 609 IF(iq == 0) CYCLE 610 tr = tr([iq, 1:iq-1, iq+1:nq]) 611 ! tr(:)%name = nam 612 END DO 609 613 IF(lSortByGen) THEN 614 iq = 1 610 615 ng = MAXVAL(tr(:)%iGeneration, MASK=.TRUE., DIM=1) !--- Number of generations 611 616 DO ig = 0, ng !--- Loop on generations … … 616 621 END DO 617 622 ELSE 618 DO jq = 1, nq !--- Loop on first generation tracers 619 IF(tr(jq)%iGeneration /= 1) CYCLE !--- Skip generations >= 1 620 ix(iq) = jq !--- First generation ancestor index first 621 iq = iq + 1 623 iq = 1 624 DO jq = 1, nq !--- Loop on generation 0 tracers 625 IF(tr(jq)%iGeneration /= 0) CYCLE !--- Skip generations /= 0 626 ix(iq) = jq !--- Generation 0 ancestor index first 627 iq = iq + 1 !--- Next "iq" for next generations tracers 622 628 iy = strFind(tr(:)%gen0Name, TRIM(tr(jq)%name)) !--- Indexes of "tr(jq)" childs in "tr(:)" 623 ng = MAXVAL(tr(iy)%iGeneration, MASK=.TRUE., DIM=1) !--- Generations numberof the "tr(jq)" family624 DO ig = 2, ng !--- Loop on generations for the tr(jq)family629 ng = MAXVAL(tr(iy)%iGeneration, MASK=.TRUE., DIM=1) !--- Number of generations of the "tr(jq)" family 630 DO ig = 1, ng !--- Loop on generations of the "tr(jq)" family 625 631 iz = find(tr(iy)%iGeneration, ig, n) !--- Indexes of the tracers "tr(iy(:))" of generation "ig" 626 632 ix(iq:iq+n-1) = iy(iz) !--- Same indexes in "tr(:)" … … 724 730 tnam = TRIM(t1(iq)%name) !--- Original name 725 731 IF(COUNT(t1%name == tnam) == 1) CYCLE !--- Current tracer is not duplicated: finished 726 tnam_new = TRIM(tnam)// phases_sep//TRIM(sections(is)%name)!--- Same with section extension732 tnam_new = TRIM(tnam)//'_'//TRIM(sections(is)%name) !--- Same with section extension 727 733 nq = SUM(nt(1:is-1)) !--- Number of tracers in previous sections 728 734 ns = nt(is) !--- Number of tracers in the current section … … 757 763 INTEGER :: idb, iq, nq 758 764 INTEGER, ALLOCATABLE :: hadv(:), vadv(:) 765 CHARACTER(LEN=maxlen), ALLOCATABLE :: phas(:) 759 766 TYPE(trac_type), POINTER :: tm(:) 760 767 lerr = .FALSE. … … 762 769 tm => dBase(idb)%trac 763 770 nq = SIZE(tm) 764 IF(test(getKeyByName_im('hadv', hadv, tm(:)%name, tm(:)%keys),lerr)) RETURN 765 IF(test(getKeyByName_im('vadv', vadv, tm(:)%name, tm(:)%keys),lerr)) RETURN 771 !--- BEWARE ! Can't use the "getKeyByName" functions yet. 772 ! Names must first include the phases for tracers defined on multiple lines. 773 hadv = str2int([(fgetKey(iq, 'hadv', tm(:)%keys, '10'), iq=1, nq)]) 774 vadv = str2int([(fgetKey(iq, 'vadv', tm(:)%keys, '10'), iq=1, nq)]) 775 phas = [(fgetKey(iq, 'phases',tm(:)%keys, 'g' ), iq=1, nq)] 766 776 CALL msg(TRIM(message)//':', modname) 767 IF(test(dispTable('iiissis', ['iq ','hadv ','vadv ','short name','parent ','igen ','phase '], & 768 cat(tm(:)%name, tm(:)%parent, tm(:)%phase), cat([(iq, iq=1, nq)], hadv, vadv, tm(:)%iGeneration)), lerr)) RETURN 777 IF(tm(1)%parent == '') THEN 778 IF(test(dispTable('iiiss', ['iq ','hadv ','vadv ','name ','phase '], cat(tm%name, phas), cat([(iq, iq=1, nq)], & 779 hadv, vadv), sub=modname), lerr)) RETURN 780 ELSE 781 IF(test(dispTable('iiissis', ['iq ','hadv ','vadv ','name ','parent','igen ','phase '], cat(tm%name, tm%parent, & 782 tm%phase), cat([(iq, iq=1, nq)], hadv, vadv, tm%iGeneration), sub=modname), lerr)) RETURN 783 END IF 769 784 END FUNCTION dispTraSection 770 785 !============================================================================================================================== … … 825 840 SUBROUTINE indexUpdate(tr) 826 841 TYPE(trac_type), INTENT(INOUT) :: tr(:) 827 INTEGER :: iq, ig, ng, ngen842 INTEGER :: iq, ig, ng, igen, ngen 828 843 INTEGER, ALLOCATABLE :: ix(:) 829 844 tr(:)%iqParent = strIdx( tr(:)%name, tr(:)%parent ) !--- Parent index 830 845 ngen = MAXVAL(tr(:)%iGeneration, MASK=.TRUE.) 831 846 DO iq = 1, SIZE(tr) 832 ng = tr(iq)%iGeneration !--- Generation of the current tracer 833 ix = idxAncestor(tr, igen = ng); ix = PACK(ix, ix/=0) !--- Indexes of the tracers with ancestor tr(iq) 834 !--- Childs indexes in growing generation order 835 tr(iq)%iqDescen = [( PACK(ix, MASK = tr(ix)%iGeneration == ig), ig = ng+1, ngen)] 836 tr(iq)%nqDescen = SUM( [( COUNT(tr(ix)%iGeneration == ig), ig = ng+1, ngen)] ) 837 tr(iq)%nqChilds = COUNT(tr(ix)%iGeneration == ng+1) 847 ig = tr(iq)%iGeneration 848 IF(ALLOCATED(tr(iq)%iqDescen)) DEALLOCATE(tr(iq)%iqDescen) 849 ALLOCATE(tr(iq)%iqDescen(0)) 850 ix = idxAncestor(tr, igen=ig) !--- Ancestor of generation "ng" for each tr 851 DO igen = ig+1, ngen 852 tr(iq)%iqDescen = [tr(iq)%iqDescen, find(ix==iq .AND. tr%iGeneration==igen)] 853 tr(iq)%nqDescen = SIZE(tr(iq)%iqDescen) 854 IF(igen == ig+1) tr(iq)%nqChilds=tr(iq)%nqDescen 855 END DO 838 856 END DO 839 857 END SUBROUTINE indexUpdate … … 847 865 !=== NOTES: ==== 848 866 !=== * Most of the "isot" components have been defined in the calling routine (initIsotopes): ==== 849 !=== parent, nzone, zone(:), niso, keys(:)%name, ntiso, trac(:), nphas, phas, i TraPha(:,:), iZonPhi(:,:)====867 !=== parent, nzone, zone(:), niso, keys(:)%name, ntiso, trac(:), nphas, phas, iqTraPha(:,:), itZonPhi(:,:) ==== 850 868 !=== * Same syntax for isotopes file and "tracer.def": a tracers section contains one line for each of its isotopes ==== 851 869 !=== * Each tracers section can contain a "params" virtual isotope line of isotopes parameters default values ==== … … 909 927 ALLOCATE(tdb(nb0-1)); tdb(1:nb0-1)=dBase(1:nb0-1); CALL MOVE_ALLOC(FROM=tdb, TO=dBase) 910 928 END IF 929 930 !--- GET THE isoCheck ENTRY FROM THE *.DEF FILES (MIGHT BE CHANGED TO A CLASS-DEPENDANT KEYWORD) 931 CALL get_in('ok_iso_verif', isot(strIdx(isot%parent, 'H2O'))%check, .FALSE.) 932 911 933 lerr = dispIsotopes(isot, 'Isotopes parameters read from file', modname) 912 934 … … 930 952 LOGICAL, ALLOCATABLE :: ll(:) !--- Mask 931 953 TYPE(trac_type), POINTER :: t(:), t1 932 TYPE(isot_type), POINTER :: s954 TYPE(isot_type), POINTER :: i 933 955 934 956 t => trac 935 957 936 p = PACK(delPhase(t%parent), MASK = t%type=='tracer' .AND. t%iGeneration== 2) !--- Parents of 2nd generationisotopes958 p = PACK(delPhase(t%parent), MASK = t%type=='tracer' .AND. t%iGeneration==1) !--- Parents of generation 1 isotopes 937 959 CALL strReduce(p, nbIso) 938 960 ALLOCATE(isot(nbIso)) … … 943 965 isot(:)%parent = p 944 966 DO ic = 1, SIZE(p) !--- Loop on isotopes classes 945 s=> isot(ic)946 iname = s%parent !--- Current isotopes class name (parent tracer name)967 i => isot(ic) 968 iname = i%parent !--- Current isotopes class name (parent tracer name) 947 969 948 970 !=== Isotopes childs of tracer "iname": mask, names, number (same for each phase of "iname") 949 971 ll = t(:)%type=='tracer' .AND. delPhase(t(:)%parent) == iname .AND. t(:)%phase == 'g' 950 972 str = PACK(delPhase(t(:)%name), MASK = ll) !--- Effectively found isotopes of "iname" 951 s%niso = SIZE(str) !--- Number of "effectively found isotopes of "iname"952 ALLOCATE( s%keys(s%niso))953 FORALL(it = 1: s%niso) s%keys(it)%name = str(it)973 i%niso = SIZE(str) !--- Number of "effectively found isotopes of "iname" 974 ALLOCATE(i%keys(i%niso)) 975 FORALL(it = 1:i%niso) i%keys(it)%name = str(it) 954 976 955 977 !=== Geographic tagging tracers descending on tracer "iname": mask, names, number 956 ll = t(:)%type=='tag' .AND. delPhase(t(:)%gen0Name) == iname .AND. t(:)%iGeneration == 3957 s%zone = PACK(strTail(t(:)%name,'_',lFirst=.TRUE.), MASK = ll)!--- Tagging zones names for isotopes category "iname"958 CALL strReduce( s%zone)959 s%nzone = SIZE(s%zone) !--- Tagging zones number for isotopes category "iname"978 ll = t(:)%type=='tag' .AND. delPhase(t(:)%gen0Name) == iname .AND. t(:)%iGeneration == 2 979 i%zone = PACK(strTail(t(:)%name,'_'), MASK = ll) !--- Tagging zones names for isotopes category "iname" 980 CALL strReduce(i%zone) 981 i%nzone = SIZE(i%zone) !--- Tagging zones number for isotopes category "iname" 960 982 961 983 !=== Geographic tracers of the isotopes childs of tracer "iname" (same for each phase of "iname") … … 963 985 str = PACK(delPhase(t(:)%name), MASK=ll) 964 986 CALL strReduce(str) 965 s%ntiso = s%niso + SIZE(str) !--- Number of isotopes + their geographic tracers [ntraciso]966 ALLOCATE( s%trac(s%ntiso))967 FORALL(it = 1: s%niso) s%trac(it) = s%keys(it)%name968 FORALL(it = s%niso+1:s%ntiso) s%trac(it) = str(it-s%niso)987 i%ntiso = i%niso + SIZE(str) !--- Number of isotopes + their geographic tracers [ntraciso] 988 ALLOCATE(i%trac(i%ntiso)) 989 FORALL(it = 1:i%niso) i%trac(it) = i%keys(it)%name 990 FORALL(it = i%niso+1:i%ntiso) i%trac(it) = str(it-i%niso) 969 991 970 992 !=== Phases for tracer "iname" 971 s%phase = ''972 DO ip = 1, nphases; ph = known_phases(ip:ip); IF(strIdx(t%name,addPhase(iname, ph)) /= 0) s%phase = TRIM(s%phase)//ph; END DO973 s%nphas = LEN_TRIM(s%phase) !--- Equal to "nqo" for water993 i%phase = '' 994 DO ip = 1, nphases; ph = known_phases(ip:ip); IF(strIdx(t%name,addPhase(iname, ph)) /= 0) i%phase = TRIM(i%phase)//ph; END DO 995 i%nphas = LEN_TRIM(i%phase) !--- Equal to "nqo" for water 974 996 975 997 !=== Tables giving the index in a table of effectively found items for each dynamical tracer (1<=iq<=nqtot) 976 998 DO iq = 1, SIZE(t) 977 999 t1 => trac(iq) 978 IF(delPhase(t1%gen0Name) /= iname) CYCLE!--- Only deal with tracers descending on "iname"1000 IF(delPhase(t1%gen0Name)/=iname .OR. t1%iGeneration==0) CYCLE !--- Only deal with tracers descending on "iname" 979 1001 t1%iso_iGroup = ic !--- Isotopes family idx in list "isotopes(:)%parent" 980 t1%iso_iName = strIdx( s%trac, delPhase(strHead(t1%name,'_'))) !--- Current isotope idx in effective isotopes list981 t1%iso_iZone = strIdx( s%zone, strTail(t1%name,'_') ) !--- Current isotope zone idx in effective zones list982 t1%iso_iPhase = INDEX( s%phase,TRIM(t1%phase)) !--- Current isotope phase idx in effective phases list983 IF(t1%iGeneration /= 3) t1%iso_iZone = 0 !--- Skip possible generation 2tagging tracers1002 t1%iso_iName = strIdx(i%trac, delPhase(strHead(t1%name,'_'))) !--- Current isotope idx in effective isotopes list 1003 t1%iso_iZone = strIdx(i%zone, strTail(t1%name,'_') ) !--- Current isotope zone idx in effective zones list 1004 t1%iso_iPhase = INDEX(i%phase,TRIM(t1%phase)) !--- Current isotope phase idx in effective phases list 1005 IF(t1%iGeneration /= 2) t1%iso_iZone = 0 !--- Skip possible generation 1 tagging tracers 984 1006 END DO 985 1007 986 1008 !=== Table used to get iq (index in dyn array, size nqtot) from the isotope and phase indexes ; the full isotopes list 987 1009 ! (including tagging tracers) is sorted this way: iso1, iso2, ..., iso1_zone1, iso2_zone1, ..., iso1_zoneN, iso2_zoneN 988 s%iTraPha = RESHAPE( [( (strIdx(t(:)%name, addPhase(s%trac(it),s%phase(ip:ip))), it=1, s%ntiso), ip=1, s%nphas)], & 989 [s%ntiso, s%nphas] ) 990 1010 i%iqTraPha = RESHAPE( [( (strIdx(t%name, addPhase(i%trac(it),i%phase(ip:ip))), it=1, i%ntiso), ip=1, i%nphas)], & 1011 [i%ntiso, i%nphas] ) 991 1012 !=== Table used to get ix (index in tagging tracers isotopes list, size ntiso) from the zone and isotope indexes 992 s%iZonIso = RESHAPE( [( (strIdx(s%trac(:), TRIM(s%trac(it))//'_'//TRIM(s%zone(iz))), iz=1, s%nzone), it=1, s%niso )], &993 [ s%nzone, s%niso] )1013 i%itZonIso = RESHAPE( [( (strIdx(i%trac(:), TRIM(i%trac(it))//'_'//TRIM(i%zone(iz))), iz=1, i%nzone), it=1, i%niso )], & 1014 [i%nzone, i%niso] ) 994 1015 END DO 995 1016 … … 1023 1044 END DO 1024 1045 END DO 1025 IF(test(fmsg('Problem with the table content', modname, dispTable(prf, ttl, val, cat([(it,it=1,nt)]), rFmt='(EN8.4)' )),&1026 lerr)) RETURN1046 IF(test(fmsg('Problem with the table content', modname, dispTable(prf, ttl, val, cat([(it,it=1,nt)]), rFmt='(EN8.4)', & 1047 sub=modname)), lerr)) RETURN 1027 1048 DEALLOCATE(ttl, val) 1028 1049 END DO … … 1078 1099 IF(jd == 0) RETURN 1079 1100 DO ik = 1, SIZE(t(jd)%keys%key) 1080 CALL get_in(t(jd)%keys%key(ik), val, ' zzzz')1081 IF(val /= ' zzzz') CALL addKey_1(t(jd)%keys%key(ik), val, t(jd)%keys, .TRUE.)1101 CALL get_in(t(jd)%keys%key(ik), val, '*none*') 1102 IF(val /= '*none*') CALL addKey_1(t(jd)%keys%key(ik), val, t(jd)%keys, .TRUE.) 1082 1103 END DO 1083 1104 END SUBROUTINE addKeysFromDef … … 1127 1148 END SUBROUTINE getKey_init 1128 1149 !============================================================================================================================== 1129 CHARACTER(LEN=maxlen) FUNCTION fgetKey (itr, keyn, ky, def_val) RESULT(out)1130 !------------------------------------------------------------------------------------------------------------------------------ 1131 ! Purpose: Internal function ; get a key value in string format (this is the returned argument).1150 CHARACTER(LEN=maxlen) FUNCTION fgetKeyByIndex_s1(itr, keyn, ky, def_val) RESULT(val) 1151 !------------------------------------------------------------------------------------------------------------------------------ 1152 ! Purpose: Internal function ; get a string formatted key value (returned argument) from its name and the tracer index. 1132 1153 !------------------------------------------------------------------------------------------------------------------------------ 1133 1154 INTEGER, INTENT(IN) :: itr … … 1136 1157 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: def_val 1137 1158 !------------------------------------------------------------------------------------------------------------------------------ 1138 INTEGER :: ik 1139 ik = 0; IF(itr>0 .AND. itr<=SIZE(ky)) ik = strIdx(ky(itr)%key(:), keyn) 1140 out = ''; IF(ik /= 0) out = ky(itr)%val(ik) !--- Key was found 1141 IF(PRESENT(def_val) .AND. ik == 0) out = def_val !--- Default value from arguments 1142 END FUNCTION fgetKey 1159 INTEGER :: iky 1160 iky = 0; IF(itr > 0 .AND. itr <= SIZE(ky)) iky = strIdx(ky(itr)%key(:), keyn) 1161 val = ''; IF(iky /= 0) val = ky(itr)%val(iky) !--- Key was found 1162 IF(PRESENT(def_val) .AND. iky == 0) val = def_val !--- Default value from arguments 1163 END FUNCTION fgetKeyByIndex_s1 1164 !============================================================================================================================== 1165 CHARACTER(LEN=maxlen) FUNCTION fgetKeyByName_s1(tname, keyn, ky, def_val, lerr) RESULT(val) 1166 !------------------------------------------------------------------------------------------------------------------------------ 1167 ! Purpose: Internal function ; get a string formatted key value (returned argument) from its name and the tracer name. 1168 !------------------------------------------------------------------------------------------------------------------------------ 1169 CHARACTER(LEN=*), INTENT(IN) :: tname, keyn 1170 TYPE(keys_type), INTENT(IN) :: ky(:) 1171 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: def_val 1172 LOGICAL, OPTIONAL, INTENT(OUT) :: lerr 1173 !------------------------------------------------------------------------------------------------------------------------------ 1174 INTEGER :: iky, itr 1175 val = ''; iky = 0 1176 itr = strIdx(ky(:)%name, tname) !--- Get the index of the wanted tracer 1177 IF(PRESENT(lerr)) lerr = itr==0; IF(itr == 0) RETURN 1178 IF(itr > 0 .AND. itr <= SIZE(ky)) iky = strIdx(ky(itr)%key(:), keyn) 1179 IF(iky /= 0) val = ky(itr)%val(iky) !--- Key was found 1180 IF(PRESENT(def_val) .AND. iky == 0) val = def_val !--- Default value from arguments 1181 END FUNCTION fgetKeyByName_s1 1143 1182 !============================================================================================================================== 1144 1183 LOGICAL FUNCTION getKeyByName_s1(keyn, val, tname, ky) RESULT(lerr) … … 1151 1190 CHARACTER(LEN=*), INTENT(IN) :: tname 1152 1191 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1153 INTEGER :: is 1154 lerr = .FALSE. 1192 CHARACTER(LEN=maxlen) :: tnam 1193 INTEGER, ALLOCATABLE :: is(:) 1194 INTEGER :: i, itr 1195 tnam = delPhase(strHead(tname,'_',.FALSE.)) !--- Remove tag and phase 1155 1196 IF(PRESENT(ky)) THEN 1156 val = getKeyByName_prv(keyn, tname , ky); IF(val /= '') RETURN !--- "ky" and "tnam" 1157 val = getKeyByName_prv(keyn, delPhase(strHead(tname,'_')), ky) !--- "ky" and "tnam" without phase 1197 val = fgetKeyByName_s1(tname, keyn, ky, lerr=lerr) !--- "ky" and "tname" 1198 IF(val /= '' .OR. lerr) RETURN 1199 val = fgetKeyByName_s1(tnam, keyn, ky, lerr=lerr) !--- "ky" and "tnam" 1158 1200 ELSE 1159 1201 IF(.NOT.ALLOCATED(tracers)) RETURN 1160 val = getKeyByName_prv(keyn, tname, tracers(:)%keys); IF(val /= '') RETURN !--- "tracers" and "tnam" 1202 val = fgetKeyByName_s1(tname, keyn, tracers(:)%keys, lerr=lerr) !--- "tracers" and "tname" 1203 IF(val /= ''.AND..NOT.lerr) RETURN 1161 1204 IF(.NOT.ALLOCATED(isotopes)) RETURN 1162 1205 IF(SIZE(isotopes) == 0) RETURN 1163 DO is = 1, SIZE(isotopes); IF(strIdx(isotopes(is)%keys(:)%name, delPhase(strHead(tname,'_'))) /= 0) EXIT; END DO 1164 IF(is /= 0) val = getKeyByName_prv(keyn, tname, isotopes(is)%keys(:)) !--- "isotopes" and "tnam" without phase 1206 !--- Search the "is" isotopes class index of the isotope named "tnam" 1207 is = find([(ANY(isotopes(i)%keys(:)%name == tnam), i=1, SIZE(isotopes))]) 1208 IF(test(SIZE(is) == 0,lerr)) RETURN 1209 val = fgetKeyByName_s1(tname, keyn, isotopes(is(1))%keys(:),lerr=lerr)!--- "isotopes" and "tnam" 1165 1210 END IF 1166 1167 CONTAINS1168 1169 FUNCTION getKeyByName_prv(keyn, tname, ky) RESULT(val)1170 CHARACTER(LEN=maxlen) :: val1171 CHARACTER(LEN=*), INTENT(IN) :: keyn1172 CHARACTER(LEN=*), INTENT(IN) :: tname1173 TYPE(keys_type), INTENT(IN) :: ky(:)1174 INTEGER :: itr, iky1175 val = ''; iky = 01176 itr = strIdx(ky(:)%name, tname); IF(itr==0) RETURN !--- Get the index of the wanted tracer1177 IF(itr /= 0) iky = strIdx(ky(itr)%key(:), keyn); IF(iky==0) RETURN !--- Wanted key index1178 val = ky(itr)%val(iky)1179 END FUNCTION getKeyByName_prv1180 1181 1211 END FUNCTION getKeyByName_s1 1182 1212 !============================================================================================================================== 1183 LOGICAL FUNCTION getKeyByName_sm(keyn, val, tnam , ky) RESULT(lerr)1213 LOGICAL FUNCTION getKeyByName_sm(keyn, val, tname, ky) RESULT(lerr) 1184 1214 CHARACTER(LEN=*), INTENT(IN) :: keyn 1185 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1186 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tnam(:) 1187 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1188 CHARACTER(LEN=maxlen), POINTER :: n(:) 1189 INTEGER :: iq 1190 n => tracers(:)%keys%name; IF(PRESENT(tnam)) n => tnam(:) 1191 ALLOCATE(val(SIZE(n))) 1192 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), n(iq), ky), iq=1, SIZE(n))]) 1193 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), n(iq)), iq=1, SIZE(n))]) 1215 CHARACTER(LEN=maxlen), ALLOCATABLE, INTENT(OUT) :: val(:) 1216 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tname(:) 1217 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1218 TYPE(keys_type), POINTER :: k(:) 1219 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 1220 INTEGER :: iq, nq 1221 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1222 IF(PRESENT(ky )) nq = SIZE(ky%name) 1223 IF(PRESENT(tname)) nq = SIZE( tname) 1224 ALLOCATE(val(nq)) 1225 IF(PRESENT(tname)) THEN 1226 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1227 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_s1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1228 ELSE; lerr = ANY([(getKeyByName_s1(keyn, val(iq), ky(iq)%name, ky), iq=1, nq)]) 1229 END IF 1194 1230 END FUNCTION getKeyByName_sm 1195 1231 !============================================================================================================================== 1196 LOGICAL FUNCTION getKeyByName_i1(keyn, val, tnam , ky) RESULT(lerr)1232 LOGICAL FUNCTION getKeyByName_i1(keyn, val, tname, ky) RESULT(lerr) 1197 1233 CHARACTER(LEN=*), INTENT(IN) :: keyn 1198 1234 INTEGER, INTENT(OUT) :: val 1199 CHARACTER(LEN=*), INTENT(IN) :: tnam 1235 CHARACTER(LEN=*), INTENT(IN) :: tname 1200 1236 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1201 1237 CHARACTER(LEN=maxlen) :: sval 1202 1238 INTEGER :: ierr 1203 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tnam , ky)1204 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tnam )1205 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tnam )//'" is missing', modname, lerr), lerr)) RETURN1239 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname, ky) 1240 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname) 1241 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN 1206 1242 READ(sval, *, IOSTAT=ierr) val 1207 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tnam )//'" is not an integer', modname, lerr), lerr)) RETURN1243 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not an integer', modname, lerr), lerr)) RETURN 1208 1244 END FUNCTION getKeyByName_i1 1209 1245 !============================================================================================================================== 1210 LOGICAL FUNCTION getKeyByName_im(keyn, val, tnam , ky) RESULT(lerr)1246 LOGICAL FUNCTION getKeyByName_im(keyn, val, tname, ky) RESULT(lerr) 1211 1247 CHARACTER(LEN=*), INTENT(IN) :: keyn 1212 INTEGER, ALLOCATABLE, INTENT(OUT) :: val(:) 1213 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tnam(:) 1214 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1215 CHARACTER(LEN=maxlen), POINTER :: n(:) 1216 INTEGER :: iq 1217 n => tracers(:)%name; IF(PRESENT(tnam)) n => tnam(:) 1218 ALLOCATE(val(SIZE(n))) 1219 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), n(iq), ky), iq=1, SIZE(n))]) 1220 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), n(iq)), iq=1, SIZE(n))]) 1248 INTEGER, ALLOCATABLE, INTENT(OUT) :: val(:) 1249 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tname(:) 1250 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1251 TYPE(keys_type), POINTER :: k(:) 1252 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 1253 INTEGER :: iq, nq 1254 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1255 IF(PRESENT(ky )) nq = SIZE(ky%name) 1256 IF(PRESENT(tname)) nq = SIZE( tname) 1257 ALLOCATE(val(nq)) 1258 IF(PRESENT(tname)) THEN 1259 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1260 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_i1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1261 ELSE; lerr = ANY([(getKeyByName_i1(keyn, val(iq), ky(iq)%name, ky), iq=1, nq)]) 1262 END IF 1221 1263 END FUNCTION getKeyByName_im 1222 1264 !============================================================================================================================== 1223 LOGICAL FUNCTION getKeyByName_r1(keyn, val, tnam , ky) RESULT(lerr)1265 LOGICAL FUNCTION getKeyByName_r1(keyn, val, tname, ky) RESULT(lerr) 1224 1266 CHARACTER(LEN=*), INTENT(IN) :: keyn 1225 1267 REAL, INTENT(OUT) :: val 1226 CHARACTER(LEN=*), INTENT(IN) :: tnam 1268 CHARACTER(LEN=*), INTENT(IN) :: tname 1227 1269 TYPE(keys_type), OPTIONAL, INTENT(IN) :: ky(:) 1228 1270 CHARACTER(LEN=maxlen) :: sval 1229 1271 INTEGER :: ierr 1230 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tnam , ky)1231 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tnam )1232 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tnam )//'" is missing', modname, lerr), lerr)) RETURN1272 IF( PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname, ky) 1273 IF(.NOT.PRESENT(ky)) lerr = getKeyByName_s1(keyn, sval, tname) 1274 IF(test(fmsg('key "'//TRIM(keyn)//'" or tracer "'//TRIM(tname)//'" is missing', modname, lerr), lerr)) RETURN 1233 1275 READ(sval, *, IOSTAT=ierr) val 1234 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tnam )//'" is not a real', modname, lerr), lerr)) RETURN1276 IF(test(fmsg('key "'//TRIM(keyn)//'" of tracer "'//TRIM(tname)//'" is not a real', modname, lerr), lerr)) RETURN 1235 1277 END FUNCTION getKeyByName_r1 1236 1278 !============================================================================================================================== 1237 LOGICAL FUNCTION getKeyByName_rm(keyn, val, tnam , ky) RESULT(lerr)1279 LOGICAL FUNCTION getKeyByName_rm(keyn, val, tname, ky) RESULT(lerr) 1238 1280 CHARACTER(LEN=*), INTENT(IN) :: keyn 1239 REAL, ALLOCATABLE, INTENT(OUT) :: val(:) 1240 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tnam(:) 1241 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1242 CHARACTER(LEN=maxlen), POINTER :: n(:) 1243 INTEGER :: iq 1244 n => tracers(:)%name; IF(PRESENT(tnam)) n => tnam(:) 1245 ALLOCATE(val(SIZE(n))) 1246 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), n(iq), ky), iq=1, SIZE(n))]) 1247 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), n(iq)), iq=1, SIZE(n))]) 1281 REAL, ALLOCATABLE, INTENT(OUT) :: val(:) 1282 CHARACTER(LEN=*), TARGET, OPTIONAL, INTENT(IN) :: tname(:) 1283 TYPE(keys_type), TARGET, OPTIONAL, INTENT(IN) :: ky(:) 1284 TYPE(keys_type), POINTER :: k(:) 1285 CHARACTER(LEN=maxlen), ALLOCATABLE :: n(:) 1286 INTEGER :: iq, nq 1287 IF(test(.NOT.(PRESENT(tname).OR.PRESENT(ky)), lerr)) RETURN 1288 IF(PRESENT(ky )) nq = SIZE(ky%name) 1289 IF(PRESENT(tname)) nq = SIZE( tname) 1290 ALLOCATE(val(nq)) 1291 IF(PRESENT(tname)) THEN 1292 IF( PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), tname(iq), ky), iq=1, nq)]) 1293 IF(.NOT.PRESENT(ky)) lerr = ANY([(getKeyByName_r1(keyn, val(iq), tname(iq) ), iq=1, nq)]) 1294 ELSE; lerr = ANY([(getKeyByName_r1(keyn, val(iq), ky(iq)%name, ky), iq=1, nq)]) 1295 END IF 1248 1296 END FUNCTION getKeyByName_rm 1249 1297 !============================================================================================================================== … … 1276 1324 END FUNCTION delPhase 1277 1325 !------------------------------------------------------------------------------------------------------------------------------ 1278 CHARACTER(LEN=maxlen) FUNCTION addPhase_ 1(s,pha,ph_sep) RESULT(out)1326 CHARACTER(LEN=maxlen) FUNCTION addPhase_s1(s,pha) RESULT(out) 1279 1327 CHARACTER(LEN=*), INTENT(IN) :: s 1280 1328 CHARACTER(LEN=1), INTENT(IN) :: pha 1281 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: ph_sep1282 CHARACTER(LEN=1) :: psep1283 1329 INTEGER :: l, i 1284 1330 out = s 1285 1331 IF(s == '') RETURN !--- Empty string: nothing to do 1286 psep = phases_sep; IF(PRESENT(ph_sep)) psep = ph_sep1287 1332 i = INDEX(s, '_') !--- /=0 for <var>_<tag> tracers names 1288 1333 l = LEN_TRIM(s) 1289 IF(i == 0) out = TRIM(s)// TRIM(psep)//pha !--- <var> => return <var><sep><pha>1290 IF(i /= 0) out = s(1:i-1)// TRIM(psep)//pha//'_'//s(i+1:l) !--- <var>_<tag> => return <var><sep><pha>_<tag>1291 END FUNCTION addPhase_ 11292 !------------------------------------------------------------------------------------------------------------------------------ 1293 FUNCTION addPhase_ m(s,pha,ph_sep) RESULT(out)1334 IF(i == 0) out = TRIM(s)//phases_sep//pha !--- <var> => return <var><sep><pha> 1335 IF(i /= 0) out = s(1:i-1)//phases_sep//pha//'_'//s(i+1:l) !--- <var>_<tag> => return <var><sep><pha>_<tag> 1336 END FUNCTION addPhase_s1 1337 !------------------------------------------------------------------------------------------------------------------------------ 1338 FUNCTION addPhase_sm(s,pha) RESULT(out) 1294 1339 CHARACTER(LEN=*), INTENT(IN) :: s(:) 1295 1340 CHARACTER(LEN=1), INTENT(IN) :: pha 1296 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: ph_sep1297 1341 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 1298 CHARACTER(LEN=1) :: psep1299 1342 INTEGER :: k 1300 psep = phases_sep; IF(PRESENT(ph_sep)) psep = ph_sep 1301 out = [( addPhase_1(s(k), pha, psep), k=1, SIZE(s) )] 1302 END FUNCTION addPhase_m 1303 !------------------------------------------------------------------------------------------------------------------------------ 1304 1305 CHARACTER(LEN=1) FUNCTION old2newPhase(op) RESULT(np) 1306 CHARACTER(LEN=1), INTENT(IN) :: op 1307 np = known_phases(INDEX(old_phases,op):INDEX(old_phases,op)) 1308 END FUNCTION old2newPhase 1309 1310 CHARACTER(LEN=1) FUNCTION new2oldPhase(np) RESULT(op) 1311 CHARACTER(LEN=1), INTENT(IN) :: np 1312 op = old_phases(INDEX(known_phases,np):INDEX(known_phases,np)) 1313 END FUNCTION new2oldPhase 1343 out = [( addPhase_s1(s(k), pha), k=1, SIZE(s) )] 1344 END FUNCTION addPhase_sm 1345 !------------------------------------------------------------------------------------------------------------------------------ 1346 CHARACTER(LEN=maxlen) FUNCTION addPhase_i1(s,ipha,phases) RESULT(out) 1347 CHARACTER(LEN=*), INTENT(IN) :: s 1348 INTEGER, INTENT(IN) :: ipha 1349 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1350 out = s 1351 IF(s == '') RETURN !--- Empty string: nothing to do 1352 IF(ipha==0) RETURN !--- Null index: no phase to add 1353 IF( PRESENT(phases)) out = addPhase_s1(s, phases(ipha:ipha)) 1354 IF(.NOT.PRESENT(phases)) out = addPhase_s1(s, known_phases(ipha:ipha)) 1355 END FUNCTION addPhase_i1 1356 !------------------------------------------------------------------------------------------------------------------------------ 1357 FUNCTION addPhase_im(s,ipha,phases) RESULT(out) 1358 CHARACTER(LEN=*), INTENT(IN) :: s(:) 1359 INTEGER, INTENT(IN) :: ipha 1360 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1361 CHARACTER(LEN=maxlen), ALLOCATABLE :: out(:) 1362 INTEGER :: k 1363 IF( PRESENT(phases)) out = [( addPhase_i1(s(k), ipha, phases), k=1, SIZE(s) )] 1364 IF(.NOT.PRESENT(phases)) out = [( addPhase_i1(s(k), ipha, known_phases), k=1, SIZE(s) )] 1365 END FUNCTION addPhase_im 1366 !------------------------------------------------------------------------------------------------------------------------------ 1367 1368 1369 !============================================================================================================================== 1370 !=== GET PHASE INDEX IN THE POSSIBLE PHASES LIST OR IN A SPECIFIED LIST ("phases") ============================================ 1371 !============================================================================================================================== 1372 INTEGER FUNCTION getiPhase(tname, phases) RESULT(iPhase) 1373 CHARACTER(LEN=*), INTENT(IN) :: tname 1374 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1375 CHARACTER(LEN=maxlen) :: phase 1376 IF( PRESENT(phases)) phase = getPhase(tname, phases, iPhase) 1377 IF(.NOT.PRESENT(phases)) phase = getPhase(tname, known_phases, iPhase) 1378 END FUNCTION getiPhase 1379 !------------------------------------------------------------------------------------------------------------------------------ 1380 CHARACTER(LEN=1) FUNCTION getPhase(tname, phases, iPhase) RESULT(phase) 1381 CHARACTER(LEN=*), INTENT(IN) :: tname 1382 CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: phases 1383 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1384 INTEGER :: ip 1385 phase = TRIM(strHead(strTail(tname, phases_sep, .TRUE.), '_', .TRUE.)) 1386 IF( PRESENT(phases)) ip = INDEX( phases, phase) 1387 IF(.NOT.PRESENT(phases)) ip = INDEX(known_phases, phase) 1388 IF(ip == 0) phase = 'g' 1389 IF(PRESENT(iPhase)) iPhase = ip 1390 END FUNCTION getPhase 1391 !------------------------------------------------------------------------------------------------------------------------------ 1392 1393 1394 !------------------------------------------------------------------------------------------------------------------------------ 1395 CHARACTER(LEN=maxlen) FUNCTION old2newName_1(oldName, iPhase) RESULT(newName) 1396 !--- Convert an old style name into a new one. 1397 ! Only usable with old style "traceur.def" files, in which only water isotopes are allowed. 1398 ! In these files, H2O descendants names are: H2O<phase>[_<isotope>][_<tag>], with: 1399 ! phase = v, l or i ; isotope = eau, HDO, O18, O17 or HTO. 1400 CHARACTER(LEN=*), INTENT(IN) :: oldName 1401 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1402 CHARACTER(LEN=maxlen), ALLOCATABLE :: tmp(:) 1403 INTEGER :: ix, ip, it, nt 1404 LOGICAL :: lerr 1405 newName = oldName 1406 IF(PRESENT(iPhase)) iPhase = 1 !--- Default: gaseous phase 1407 IF(oldName(1:MIN(3,LEN_TRIM(oldName))) /= 'H2O') RETURN !--- Not a water descendant 1408 lerr = strParse(oldName, '_', tmp, n=nt) 1409 ip = strIdx([('H2O'//old_phases(ip:ip), ip=1, nphases)], tmp(1)) !--- Phase index (/=0 if any) 1410 IF(PRESENT(iPhase)) iPhase = ip 1411 newName = addPhase('H2O', ip) !--- Water 1412 IF(nt == 1) RETURN !--- Water: finished 1413 ix = strIdx(oldH2OIso, tmp(2)) !--- Index in the known isotopes list 1414 IF(ix == 0) newName = addPhase(tmp(2), ip) !--- Not an isotope 1415 IF(ix /= 0) newName = addPhase(newH2OIso(ix), ip) !--- Isotope 1416 IF(nt == 3) newName = TRIM(newName)//'_'//TRIM(tmp(3)) !--- Tagging tracer 1417 END FUNCTION old2newName_1 1418 !------------------------------------------------------------------------------------------------------------------------------ 1419 FUNCTION old2newName_m(oldName, iPhase) RESULT(newName) 1420 CHARACTER(LEN=*), INTENT(IN) :: oldName(:) 1421 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1422 CHARACTER(LEN=maxlen) :: newName(SIZE(oldName)) 1423 INTEGER :: i 1424 newName = [(old2newName_1(oldName(i), iPhase), i=1, SIZE(oldName))] 1425 END FUNCTION old2newName_m 1426 !------------------------------------------------------------------------------------------------------------------------------ 1427 1428 !------------------------------------------------------------------------------------------------------------------------------ 1429 CHARACTER(LEN=maxlen) FUNCTION new2oldName_1(newName, iPhase) RESULT(oldName) 1430 !--- Convert a new style name into an old one. 1431 ! Only convertable names are water descendants names H2O_<phase>, <isotope>_<phase>, <isotope>_<phase>_<tag>, with: 1432 ! phase = g, l or s ; isotope = H2[16]O, H[2]O, H2<[18]O, H2[17]O or H[3]O. 1433 CHARACTER(LEN=*), INTENT(IN) :: newName 1434 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1435 INTEGER :: ix, ip, it, nt 1436 LOGICAL :: lH2O 1437 CHARACTER(LEN=maxlen) :: tag 1438 ix = strIdx([(addPhase('H2O',ip), ip=1, nphases)], newName) !--- Phase index for H2O_<phase> 1439 IF(ix /= 0) THEN; oldName = 'H2O'//old_phases(ix:ix); RETURN; END IF !--- H2O_<phase> case 1440 ix = strIdx(newH2OIso, strHead(newName, phases_sep, .TRUE.)) !--- Isotope index 1441 IF(ix == 0) THEN; oldName = newName; RETURN; END IF !--- Not a water descendant 1442 ip = getiPhase(newName) !--- Phase index 1443 oldName = TRIM(oldH2OIso(ix))//old_phases(ip:ip) !--- <isotope>_<phase> 1444 tag = strTail(delPhase(newName), TRIM(newH2OIso(ix))) !--- Get "_<tag>" if any 1445 IF(tag /= delPhase(newName) .AND. tag /= '') oldName = TRIM(oldName)//tag !--- Tagging tracer 1446 END FUNCTION new2oldName_1 1447 !------------------------------------------------------------------------------------------------------------------------------ 1448 FUNCTION new2oldName_m(newName, iPhase) RESULT(oldName) 1449 CHARACTER(LEN=*), INTENT(IN) :: newName(:) 1450 INTEGER, OPTIONAL, INTENT(OUT) :: iPhase 1451 CHARACTER(LEN=maxlen) :: oldName(SIZE(newName)) 1452 INTEGER :: i 1453 oldName = [(new2oldName_1(newName(i), iPhase), i=1, SIZE(newName))] 1454 END FUNCTION new2oldName_m 1455 !------------------------------------------------------------------------------------------------------------------------------ 1456 1314 1457 1315 1458 !==============================================================================================================================
Note: See TracChangeset
for help on using the changeset viewer.