Changeset 1897
- Timestamp:
- Jan 24, 2018, 10:24:24 PM (7 years ago)
- Location:
- trunk/LMDZ.TITAN
- Files:
-
- 5 added
- 2 deleted
- 28 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LMDZ.TITAN/README
r1896 r1897 1401 1401 Added a bash script ( utilities/prepare_startkim.bash ) to create startfi files 1402 1402 with upper_chemistry_layers dimension and fill fields from old comp_xx files 1403 1404 == 24/01/18 == JVO 1405 Major updates in YAMMS and it's coupling from J.Burgalat, including 1406 + Added the microphysics optical routines and coupling of YAMMS haze with the radiative transfer 1407 + ... yet you shouldn't activate it yet ( flag uncoupl_optic_haze has to be true ) ! 1408 + Some supplementary safety checks to keep microphysics spitting negative tendencies 1409 + Other upkeep changes deeper in the library -
trunk/LMDZ.TITAN/libf/muphytitan/argparse.F90
r1814 r1897 1 ! Copyright Jérémie Burgalat (2010-2015 )1 ! Copyright Jérémie Burgalat (2010-2015,2017) 2 2 ! 3 ! burgalat.jeremie@gmail.com3 ! jeremie.burgalat@univ-reims.fr 4 4 ! 5 5 ! This software is a computer program whose purpose is to provide configuration … … 33 33 34 34 !! file: argparse.F90 35 !! summary: Command-line parser source file 36 !! author: burgalat37 !! date: 2013-2015 35 !! summary: Command-line parser source file. 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 38 38 39 39 #include "defined.h" … … 47 47 !! 48 48 !! If you only wish to have an overview of argparse usage, you'd better go 49 !! [p_argparse](here). 49 !! [here](|url|/page/swift/p01_argparse.html). 50 50 51 USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY : stdout=>OUTPUT_UNIT, stderr=>ERROR_UNIT 51 52 USE ERRORS 52 53 USE FSYSTEM, ONLY : fs_termsize 53 USE STRINGS, getpar => format_paragraph, & 54 splitstr => format_string, & 55 ap_string => st_string, & !! String value type ID 56 ap_complex => st_complex, & !! Complex value type ID 57 ap_logical => st_logical, & !! Logical value type ID 58 ap_integer => st_integer, & !! Integer value type ID 59 ap_real => st_real !! Floating point value type ID 54 USE STRING_OP, getpar => format_paragraph, splitstr => format_string 60 55 IMPLICIT NONE 61 56 … … 66 61 PUBLIC :: noerror,error, error_to_string,aborting 67 62 ! from strings 68 #if ! HAVE_FTNDTSTR69 63 PUBLIC :: st_slen, st_llen 70 #endif71 PUBLIC :: ap_string, ap_complex, ap_logical, ap_integer, ap_real72 64 PUBLIC :: stderr, stdout 73 65 ! argparse module … … 92 84 ! PARAMETERS (INTRISIC TYPES) 93 85 ! =========================== 86 87 INTEGER, PARAMETER, PUBLIC :: ap_string = st_string 88 !! String value type identifier. 89 INTEGER, PARAMETER, PUBLIC :: ap_complex = st_complex 90 !! Complex value type identifier. 91 INTEGER, PARAMETER, PUBLIC :: ap_logical = st_logical 92 !! Logical value type identifier. 93 INTEGER, PARAMETER, PUBLIC :: ap_integer = st_integer 94 !! Integer value type identifier. 95 INTEGER, PARAMETER, PUBLIC :: ap_real = st_real 96 !! Real value type identifier. 97 98 !> List of all available actions 94 99 95 100 INTEGER, PARAMETER, PUBLIC :: ap_store = 1 … … 120 125 121 126 !> Add an option to the parser 127 !! 128 !! ``` 129 !! FUNCTION argparser_add_option(this,dest,sflag,lflag,type,action,default,nrec,help,meta) RESULT(err) 130 !! argparser_add_option(this,dest,flag,type,action,default,nrec,help,meta) RESULT(err) 131 !! ``` 132 !! 133 !! The function defines a new argument based on input parameters, checks it and finally sets it 134 !! in the parser. 135 !! 136 !! In its first version both short (`sflag`) and long (`lflag`) options flags are mandatory. In its second 137 !! form, a single flag (`flag`) is expected: the method will automatically deduce if it belongs to short or 138 !! a long option flag based on the number of hyphens given. 139 !! 140 !! `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]): 141 !! 142 !! - `ap_string` ([[string_op(module):st_string(variable)]]) 143 !! - `ap_complex` ([[string_op(module):st_complex(variable)]]) 144 !! - `ap_logical` ([[string_op(module):st_logical(variable)]]) 145 !! - `ap_integer` ([[string_op(module):st_integer(variable)]]) 146 !! - `ap_real` ([[string_op(module):st_real(variable)]]) 147 !! 148 !! `action` value should be one of the following module constants: 149 !! 150 !! - [[argparse(module):ap_store(variable)]] 151 !! - [[argparse(module):ap_append(variable)]] 152 !! - [[argparse(module):ap_count(variable)]] 153 !! - [[argparse(module):ap_help(variable)]] 154 !! 155 !! `nrec` string can take the following forms: 156 !! 157 !! tag | description 158 !! :---: | : ------------- 159 !! "?" | zero or one argument's value 160 !! "*" | any number of arguments 161 !! "+" | one or more argument's value(s) 162 !! "X" | Exactly X values. Where X is the string representation of an integer (0 is accepted). 163 !! 164 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 165 !! produced by misuse of the function arguments. In such case, the program should be 166 !! stopped: note that such error should not occur in _released_ programs. 122 167 INTERFACE argparser_add_option 123 168 MODULE PROCEDURE ap_add_option_1, ap_add_option_2 … … 131 176 !> Get optional argument value(s) 132 177 !! 133 !! This is the generic method that can be used to retrieve any kind of argument value(s) from the parser. 178 !! ``` 179 !! FUNCTION argparser_get_value(this,name,output) RESULT(err) 180 !! ``` 181 !! 182 !! This is the generic method that can be used to retrieve any kind of argument value(s) from the parser for a given 183 !! argument name (as defined by the `dest` argument of [[argparse(module):argparser_add_option(interface)]]. 134 184 !! All the methods have the same dummy arguments only `output` dummy argument differs in type and shape. 135 185 !! … … 137 187 !! For string vector, `output` is expected to be an allocatable vector of **assumed length** 138 188 !! strings (thus string length is left to user responsability). 139 !! A good compromise for strings length is to use the [[string s(module):st_slen(variable)]]189 !! A good compromise for strings length is to use the [[string_op(module):st_slen(variable)]] 140 190 !! parameter. 141 191 INTERFACE argparser_get_value … … 287 337 PROCEDURE, PRIVATE :: ap_get_sv_ve 288 338 PROCEDURE, PRIVATE :: ap_check_state 289 !PROCEDURE, PUBLIC :: reset_values => argparser_reset_values290 ! !! Resets values stored in the parser291 339 PROCEDURE, PUBLIC :: throw_error => argparser_throw_error 292 340 !! Throw an error and exit the program … … 415 463 416 464 FUNCTION argparser_add_positionals(this,nargs,meta,help) RESULT(err) 417 !! Add positional arguments definition to the parser 465 !! Add positional arguments definition to the parser. 466 !! 418 467 !! The method initializes the entry for positional arguments in the parser. 419 468 !! Positional arguments are always seen by the parser as strings and the 420 469 !! default associated action is 'store'. 421 422 470 OBJECT(argparser), INTENT(inout) :: this 423 471 !! An argparser object reference … … 533 581 IF (zauto) THEN 534 582 IF (rhelp) CALL argparser_help(this) 535 IF (err /= 0 .AND. err /= 255) CALL argparser_throw_error(this,err,2)583 IF (err /= 0) CALL argparser_throw_error(this,err,2) 536 584 ENDIF 537 585 RETURN … … 751 799 !! in the parser. Both **short and long options flags** are mandatory input arguments of the function. 752 800 !! 753 !! `type` value should be one of the following module constants (which are aliases from [[string s(module)]]):754 !! - ap_string ([[string s(module):st_string(variable)]])755 !! - ap_complex ([[string s(module):st_complex(variable)]])756 !! - ap_logical ([[string s(module):st_logical(variable)]])757 !! - ap_integer ([[string s(module):st_integer(variable)]])758 !! - ap_real ([[string s(module):st_real(variable)]])801 !! `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]): 802 !! - ap_string ([[string_op(module):st_string(variable)]]) 803 !! - ap_complex ([[string_op(module):st_complex(variable)]]) 804 !! - ap_logical ([[string_op(module):st_logical(variable)]]) 805 !! - ap_integer ([[string_op(module):st_integer(variable)]]) 806 !! - ap_real ([[string_op(module):st_real(variable)]]) 759 807 !! 760 808 !! `action` value should be one of the following module constants: … … 772 820 !! X | Exactly X values. Where X is the string representation of an integer (0 is accepted). 773 821 !! 774 !! See also [[argparse(module):ap_add_option_2(function)]]documentation.822 !! See also ap_add_option_2 documentation. 775 823 OBJECT(argparser), INTENT(inout) :: this 776 824 !! An argparser object reference … … 828 876 !! Add an argument to the parser (interface #2) 829 877 !! 830 !! The function is a wrapper to [[argparse(module):ap_add_option_1(function)]]. In this version,878 !! The function is a wrapper to ap_add_option_1. In this version, 831 879 !! only one option flag is required. The method only checks for the (trimmed) length of **flag** in 832 880 !! order to choose wether it is a **short** or **long** option flag. Then the function simply calls 833 !! [[argparse(module):ap_add_option_1(function)]]to set the argument.881 !! ap_add_option_1 to set the argument. 834 882 !! 835 !! Other dummy arguments have the same meaning as in [[argparse(module):ap_add_option_1(function)]].883 !! Other dummy arguments have the same meaning as in ap_add_option_1. 836 884 OBJECT(argparser), INTENT(inout) :: this 837 885 !! An argparser object reference … … 886 934 !! An argc object to check 887 935 TYPE(error) :: err 888 !! Error object with - 15id if object is already set, no error otherwise.936 !! Error object with -8 id if object is already set, no error otherwise. 889 937 INTEGER :: i 890 938 err = noerror … … 914 962 !! An argparser object reference 915 963 TYPE(words), INTENT(inout) :: cmd 916 !! A [[string s(module):words(type)]] object with the command-line to parse964 !! A [[string_op(module):words(type)]] object with the command-line to parse 917 965 LOGICAL, INTENT(out) :: help_req 918 966 !! An output logical flag with `.true.` if help option has been found, `.false.` otherwise … … 987 1035 !! An argparser object reference 988 1036 TYPE(words), INTENT(inout) :: cmd 989 !! A [[string s(module):words(type)]] object with the command-line to parse1037 !! A [[string_op(module):words(type)]] object with the command-line to parse 990 1038 TYPE(error) :: err 991 1039 !! Error object with the first error encountered in the process … … 1068 1116 ! Gets values as a function of the expected number of records 1069 1117 IF (arg%nrec == 0) THEN 1070 ! parse_args(main parsing method) reset all values: for 0 nrec1118 ! argparser_parse (main parsing method) reset all values: for 0 nrec 1071 1119 ! we should have at least one value saved which is the default. 1072 1120 ! if it is not the case we set default as values of the argument … … 1136 1184 !! @warning 1137 1185 !! For compilers that does not support allocatable strings in derived types, 1138 !! computation are highly dependent of [[string s(module):st_slen(variable):1186 !! computation are highly dependent of [[string_op(module):st_slen(variable): 1139 1187 !! tokens length are limited by this parameter. 1140 1188 IMPLICIT NONE … … 1144 1192 !! A string to process 1145 1193 TYPE(words), INTENT(out) :: new_cmd 1146 !! An output [[string s(module):words(type)]] object with the processed command line1194 !! An output [[string_op(module):words(type)]] object with the processed command line 1147 1195 LOGICAL, INTENT(out) :: rhelp 1148 1196 !! An output boolean flag with `.true.` if help is requested, `.false.` otherwise … … 1155 1203 err = noerror ; rhelp = .false. 1156 1204 IF (LEN_TRIM(string) == 0) THEN 1157 err = error('internal error (empty string)',-2 )1205 err = error('internal error (empty string)',-255) 1158 1206 RETURN 1159 1207 ENDIF 1160 1208 ! split input command line in words ! 1161 splitted = new_words(string," ",.true.) ! tokens may be truncated :(1209 call words_extend(splitted,string," ",.true.) 1162 1210 ! reset iterator 1163 1211 CALL words_reset(splitted) … … 1330 1378 1331 1379 SUBROUTINE ap_format_usage(this,optmw) 1332 !! Format command line usage 1380 !! Format command line usage. 1381 !! 1333 1382 !! The subroutine creates and formats the command line usage of the 1334 1383 !! given argparser object. If [[argparser(type):usg(variable)]] is already set (i.e. not empty) … … 1693 1742 !! The function calls all the tests to perform on argc members. Some of these tests can 1694 1743 !! alter argc's member values to fit argparser's requirements. 1695 !! @note 1696 !! Normally, program should be stopped if returned error is not 0 ! 1744 !! 1745 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1746 !! produced by misuse of the function arguments. In such case, the program should be 1747 !! stopped: note that such ezrror should not occur in _released_ programs. 1697 1748 TYPE(argc), INTENT(inout) :: this 1698 1749 !! An argc object … … 1740 1791 !! The method checks if input argument's options are valid and update the argc object 1741 1792 !! consequently. 1793 !! 1794 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1795 !! produced by misuse of the function arguments. 1742 1796 TYPE(argc), INTENT(inout) :: this 1743 1797 !! An argc object to update … … 1756 1810 ret = noerror 1757 1811 eprf = 'argparse: '//"Invalid argument `"//TRIM(this%name)//"'" 1758 uty = error(eprf//" (type)",- 2)1759 ina = error(eprf//" (inconsistent nargs)",- 2)1812 uty = error(eprf//" (type)",-9) 1813 ina = error(eprf//" (inconsistent nargs)",-9) 1760 1814 zna = TRIM(na) 1761 1815 ! Checks action … … 1763 1817 this%paction = ac 1764 1818 ELSE 1765 ret = error(eprf//" (action)",- 2) ; RETURN1819 ret = error(eprf//" (action)",-9) ; RETURN 1766 1820 ENDIF 1767 1821 ! Checks and sets type and default as a function of the action … … 1885 1939 terr = error(eprf//" (inconsistent default value: expected '"// & 1886 1940 TRIM(st_type_names(this%ptype))//"', found '"// & 1887 TRIM(st_type_names(t))//"')",- 2)1941 TRIM(st_type_names(t))//"')",-9) 1888 1942 RETURN 1889 1943 ENDIF … … 1977 2031 SELECT CASE(this%nrec) 1978 2032 CASE(-3,-2,-1) 1979 zmeta = str_to_upper(meta(1))2033 zmeta = to_upper(meta(1)) 1980 2034 blk = INDEX(TRIM(zmeta),CHAR(32)) - 1 1981 2035 IF (blk <= 0) blk=LEN_TRIM(zmeta) … … 1987 2041 DO i=1,this%nrec 1988 2042 j=j+1 ; IF (j>ms) j=1 1989 zmeta = str_to_upper(meta(j))2043 zmeta = to_upper(meta(j)) 1990 2044 blk=INDEX(TRIM(zmeta),CHAR(32))-1 1991 2045 IF (blk <= 0) blk=LEN_TRIM(zmeta) … … 1994 2048 END SELECT 1995 2049 ELSE 1996 zmeta = str_to_upper(TRIM(this%name))2050 zmeta = to_upper(TRIM(this%name)) 1997 2051 SELECT CASE(this%nrec) 1998 2052 CASE(-3,-2,-1) … … 2223 2277 !! - -7 : argument not found (i.e. does not set in the parser) 2224 2278 !! - -19 : parsing not done yet 2225 !! - -20 : (previous)parsing failed2279 !! - -20 : parsing failed 2226 2280 !! - -21 : inconsistent destination type 2227 2281 !! @note … … 2480 2534 !! @param[in,out] this An argc object 2481 2535 !! @param[out] output A scalar with the first value of the argument 2482 !! @return An errors::error object with - 12if the destination variable's type2536 !! @return An errors::error object with -21 if the destination variable's type 2483 2537 !! is inconsistent, 0 otherwise. 2484 2538 FUNCTION ac_get_dv_sc(this, output) RESULT(ret) … … 2492 2546 !! Output value 2493 2547 TYPE(error) :: ret 2494 !! Error object with the - 12if the destination variable's type is inconsistent, 0 otherwise2548 !! Error object with the -21 if the destination variable's type is inconsistent, 0 otherwise 2495 2549 ret = noerror 2496 2550 IF (this%ptype /= ap_real) THEN -
trunk/LMDZ.TITAN/libf/muphytitan/asciiread.f90
r1793 r1897 1 ! Copyright Jérémie Burgalat (2010-2015 )2 ! 3 ! burgalat.jeremie@gmail.com1 ! Copyright Jérémie Burgalat (2010-2015,2017) 2 ! 3 ! jeremie.burgalat@univ-reims.fr 4 4 ! 5 5 ! This software is a computer program whose purpose is to provide configuration … … 32 32 ! knowledge of the CeCILL-B license and that you accept its terms. 33 33 34 !! file: asciiread. F9034 !! file: asciiread.f90 35 35 !! summary: ASCII data file reader source file 36 36 !! author: burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 MODULE ASCIIREAD 39 39 !! ASCII data file reader module … … 42 42 !! data array from ASCII file. 43 43 !! 44 !! ``` fortran44 !! ``` 45 45 !! FUNCTION read_data(path,data) RESULT(err) 46 46 !! ``` … … 65 65 !! 66 66 !! - path does not refer to a existing file (1) 67 !! - Logical unit 666 is not free (1)67 !! - No free logical unit available (1) 68 68 !! - the file does not have regular data-columns number (5) 69 69 !! - at least a value cannot be cast in double precision (5) … … 79 79 !! On success, the shape of the 3D output array will be _data(R,C,D)_. 80 80 USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: IOSTAT_END, IOSTAT_EOR 81 USE STRINGS, ONLY: tokenize,from_string, st_slen 81 !USE STRING_OP, ONLY: tokenize,from_string, st_slen 82 USE STRING_OP 82 83 USE ERRORS 83 84 IMPLICIT NONE … … 85 86 PRIVATE 86 87 PUBLIC :: noerror,error, error_to_string,aborting 87 PUBLIC :: read _data, OPERATOR(/=), OPERATOR(==)88 PUBLIC :: readline,read_data, OPERATOR(/=), OPERATOR(==) 88 89 89 90 !! Global interface to reading methods … … 110 111 !! Error occured when: 111 112 !! - Path does not refer to a existing file (-11) 112 !! - No free logical unit available (-1 2)113 !! - No free logical unit available (-1) 113 114 !! - The file does not have regular data-columns number (-5) 114 115 !! - At least a value cannot be cast in double precision (-10) … … 120 121 !! On success, the shape of the 3D output array will be _output(R,C,D)_. 121 122 !! On error, the 3D output array is __not allocated__. 122 !!123 !! @note124 !! The function uses the logical unit 666 !125 123 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 126 124 REAL(kind=8), INTENT(out), DIMENSION(:,:,:), ALLOCATABLE :: data3d !! 3D-array with the output values (double precision) … … 130 128 INTEGER :: i,lc,tlc 131 129 INTEGER :: ndr,ndc,ndd 132 INTEGER :: ir,jc,kd 130 INTEGER :: ir,jc,kd,lu 133 131 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tmp 134 132 CHARACTER(len=5) :: slc … … 144 142 err = error(trim(path)//": no such file",-1) ; RETURN 145 143 ENDIF 146 INQUIRE(unit=666,OPENED=ok) 147 IF (ok) THEN 148 err = error("lun 666 is already used",-1) ; RETURN 149 ENDIF 144 lu = free_lun() 145 IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF 150 146 ! Open file 151 OPEN( 666,FILE=TRIM(path),STATUS='OLD',ACTION='READ')147 OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ') 152 148 153 149 ! First pass : … … 158 154 lc = 0 ; tlc = 0 159 155 ndr = -1 ; ndc = -1 ; ndd = 1 160 DO WHILE(readline( 666,line))156 DO WHILE(readline(lu,line)) 161 157 lm1 = line 162 158 ! Read the line … … 193 189 ENDIF 194 190 IF (ndc == -1) ndc = SIZE(wrds) 191 IF (ALLOCATED(wrds)) DEALLOCATE(wrds) 192 IF (ALLOCATED(tmp)) DEALLOCATE(tmp) 195 193 ENDDO 196 194 … … 203 201 204 202 ! Rewind input data file 205 REWIND( 666)203 REWIND(lu) 206 204 ! Allocate memory 207 205 ALLOCATE(data3d(ndr,ndc,ndd)) 208 206 ir = 0 ; kd = 1 ; 209 DO WHILE(readline( 666,line))207 DO WHILE(readline(lu,line)) 210 208 IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1) CYCLE 211 209 ir = ir + 1 … … 216 214 ok = tokenize(line,wrds,zdelim,.true.) 217 215 DO jc = 1,ndc ; ok = from_string(wrds(jc),data3d(ir,jc,kd)) ; ENDDO 218 ENDDO 219 CLOSE(666) 216 IF (ALLOCATED(wrds)) DEALLOCATE(wrds) 217 ENDDO 218 CLOSE(lu) 220 219 END FUNCTION read_data_3d 221 220 … … 236 235 !! 237 236 !! - Path does not refer to a existing file (-1) 238 !! - Logical unit 666 is not free (-1)237 !! - No free logical unit available (-1) 239 238 !! - The file does not have regular data-columns number (-5) 240 239 !! - At least a value cannot be cast in double precision (-5) 241 240 !! 242 241 !! On error, the 2D output array is __not allocated__. 243 !! @note 244 !! The function uses the logical unit 666 ! 242 USE FSYSTEM 245 243 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 246 244 REAL(kind=8), INTENT(out), DIMENSION(:,:), ALLOCATABLE :: data2d !! 2D-array with the output values (double precision) … … 249 247 LOGICAL :: ok 250 248 INTEGER :: i,e,vc,lc 251 INTEGER :: nl,nc 249 INTEGER :: nl,nc,lu 252 250 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tmp 253 251 CHARACTER(len=5) :: slc 254 252 CHARACTER(len=:), ALLOCATABLE :: line,zdelim 255 253 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: wrds 256 257 254 zdelim = CHAR(9)//CHAR(32) 258 255 IF (PRESENT(delimiter)) zdelim = delimiter 259 ! Gets array size260 256 INQUIRE(FILE=TRIM(path),EXIST=ok) 261 257 IF (.NOT.ok) THEN 262 258 err = error(trim(path)//": no such file",-1) ; RETURN 263 259 ENDIF 264 INQUIRE(unit=666,OPENED=ok) 265 IF (ok) THEN 266 err = error("lun 666 is already used",-1) ; RETURN 267 ENDIF 268 OPEN(666,FILE=TRIM(path),STATUS='OLD',ACTION='READ') 260 lu = free_lun() 261 IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF 262 OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ') 269 263 vc = 0 ; lc=0 ; ok = .true. 270 264 ! Read the file twice :) … … 273 267 DO 274 268 ! Read the line 275 IF (.NOT.readline( 666,line)) EXIT269 IF (.NOT.readline(lu,line)) EXIT 276 270 lc = lc + 1 ; WRITE(slc,'(I5)') lc ; slc = ADJUSTL(slc) 277 271 ! skip empty/comment line … … 279 273 ! update row counter 280 274 vc = vc + 1 281 ! Splits line in words282 275 IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 283 276 ! cannot tokenize … … 286 279 ELSEIF (.NOT.from_string(wrds,tmp)) THEN 287 280 ! cannot cast values 288 do i=1,size(wrds) ; write(*,*) trim(wrds(i)) ; enddo289 write(1111,'(a)') line290 281 err = error(trim(path)//": Cannot cast values at line "//TRIM(slc),-5) 291 282 RETURN 292 ELSEIF (nc > 0 .AND. nc /= SIZE( wrds)) THEN283 ELSEIF (nc > 0 .AND. nc /= SIZE(tmp)) THEN 293 284 ! current number of columns not equal to last one 294 285 err = error(trim(path)//": Invalid number of columns (line "//TRIM(slc)//")",-5) … … 296 287 ENDIF 297 288 IF (nc == -1) nc = SIZE(wrds) 289 IF (ALLOCATED(wrds)) DEALLOCATE(wrds) 290 IF (ALLOCATED(tmp)) DEALLOCATE(tmp) 298 291 ENDDO 299 292 ! Rewind input data file 300 REWIND( 666)293 REWIND(lu) 301 294 nl = vc 302 295 ! allocate memory … … 306 299 DO WHILE(vc <= nl) 307 300 ! Reads the line 308 IF (.NOT.readline( 666,line)) EXIT301 IF (.NOT.readline(lu,line)) EXIT 309 302 ! Check if we have comment or null string 310 303 IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1.OR.LEN_TRIM(line) == 0) CYCLE … … 314 307 ok = from_string(wrds(i),data2d(vc,i)) 315 308 ENDDO 316 ENDDO 317 CLOSE(666) 309 IF (ALLOCATED(wrds)) DEALLOCATE(wrds) 310 ENDDO 311 CLOSE(lu) 318 312 RETURN 319 313 END FUNCTION read_data_2d … … 327 321 !! The function is intended to read a file line by line: 328 322 !! 329 !! ``` fortran323 !! ``` 330 324 !! lu = 1 331 325 !! open(lu,file="path/to/the/file/to/read") … … 358 352 END FUNCTION readline 359 353 360 END MODULE 354 END MODULE ASCIIREAD -
trunk/LMDZ.TITAN/libf/muphytitan/cfgparse.F90
r1814 r1897 1 ! Copyright Jérémie Burgalat (2010-2015 )2 ! 3 ! burgalat.jeremie@gmail.com4 ! 5 ! This software is a computer program whose purpose is to provide configuration 1 ! Copyright Jérémie Burgalat (2010-2015,2017) 2 ! 3 ! jeremie.burgalat@univ-reims.fr 4 ! 5 ! This software is a computer program whose purpose is to provide configuration 6 6 ! file and command line arguments parsing features to Fortran programs. 7 ! 7 ! 8 8 ! This software is governed by the CeCILL-B license under French law and 9 ! abiding by the rules of distribution of free software. You can use, 9 ! abiding by the rules of distribution of free software. You can use, 10 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 11 11 ! license as circulated by CEA, CNRS and INRIA at the following URL 12 ! "http://www.cecill.info". 13 ! 12 ! "http://www.cecill.info". 13 ! 14 14 ! As a counterpart to the access to the source code and rights to copy, 15 15 ! modify and redistribute granted by the license, users are provided only 16 16 ! with a limited warranty and the software's author, the holder of the 17 17 ! economic rights, and the successive licensors have only limited 18 ! liability. 19 ! 18 ! liability. 19 ! 20 20 ! In this respect, the user's attention is drawn to the risks associated 21 21 ! with loading, using, modifying and/or developing or reproducing the … … 25 25 ! professionals having in-depth computer knowledge. Users are therefore 26 26 ! encouraged to load and test the software's suitability as regards their 27 ! requirements in conditions enabling the security of their systems and/or 28 ! data to be ensured and, more generally, to use and operate it in the 29 ! same conditions as regards security. 30 ! 27 ! requirements in conditions enabling the security of their systems and/or 28 ! data to be ensured and, more generally, to use and operate it in the 29 ! same conditions as regards security. 30 ! 31 31 ! The fact that you are presently reading this means that you have had 32 32 ! knowledge of the CeCILL-B license and that you accept its terms. 33 33 34 34 !! file: cfgparse.F90 35 !! summary: Configuration file parser source file 36 !! author: burgalat37 !! date: 2013-2015, 35 !! summary: Configuration file parser source file. 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 38 38 39 39 #include "defined.h" … … 41 41 MODULE CFGPARSE 42 42 !! Configuration file parsing module 43 !! 44 !! This module defines a set of derived types as well as methods to parse configuration files. 43 !! 44 !! This module defines a set of derived types as well as methods to parse configuration files. 45 !! 46 !! If you only wish to have an overview of cfgparse usage, you'd better go 47 !! [here](|url|/page/swift/p02_cfgparse.html). 45 48 !! @todo 46 !! Add interpolation from environment and/or parser options 49 !! Add interpolation from environment and/or parser options. 47 50 USE, INTRINSIC :: ISO_FORTRAN_ENV 48 51 USE ERRORS 49 USE STRING S52 USE STRING_OP 50 53 USE FSYSTEM 51 54 IMPLICIT NONE … … 56 59 cfg_get_value, cfg_set_value, cfg_count, cfg_check_name, & 57 60 cfg_has_option, cfg_has_section, & 61 cfg_option_names,cfg_section_names, & 58 62 cfg_remove_option, cfg_remove_section, & 59 63 cfg_sort_options … … 63 67 ! some public definitions from other modules 64 68 ! from strings 65 PUBLIC :: str_to_lower,st_slen, st_llen69 PUBLIC :: to_lower,st_slen, st_llen 66 70 67 71 PUBLIC :: OPERATOR(==), OPERATOR(/=), ASSIGNMENT(=) … … 76 80 TYPE, PUBLIC :: cfgparser 77 81 !! Define a parser of options 78 !! 79 !! A [[cfgparser(type)]] stores [[option(type)]] objects. 82 !! 83 !! A [[cfgparser(type)]] stores [[option(type)]] objects. 80 84 TYPE(option), DIMENSION(:), ALLOCATABLE :: options !! list of options. 81 85 #if HAVE_FTNPROC … … 124 128 PROCEDURE, PUBLIC :: remove_option => cfg_remove_option 125 129 !> Remove a section (and all the associated options) from the parser. 126 PROCEDURE, PUBLIC :: remove_section => cfg_remove_section 127 !> Get value(s) of an option in the parser by name 128 !! 130 PROCEDURE, PUBLIC :: remove_section => cfg_remove_section 131 !> Get value(s) of an option in the parser by name 132 !! 129 133 !! ``` 130 134 !! FUNCTION cfg_get_value(this,name,output) RESULT(error) … … 135 139 !! On error, __output__ argument is undefined (that is, left unchanged 136 140 !! for scalar versions, **unallocated** for vector version). 137 !! 141 !! 138 142 !! Errors occur in the following situations: 139 143 !! - The option has no value (-6) 140 !! - The option does not exist (-7) 144 !! - The option does not exist (-7) 141 145 !! - The option's value cannot be cast in the desired type (-10) 142 146 GENERIC, PUBLIC :: get_value => cp_get_rv_sc,cp_get_dv_sc,cp_get_iv_sc, & … … 144 148 cp_get_rv_ve,cp_get_dv_ve,cp_get_iv_ve, & 145 149 cp_get_lv_ve,cp_get_cv_ve,cp_get_sv_ve 146 !> Set value(s) of an option in the parser by name 147 !! 150 !> Set value(s) of an option in the parser by name 151 !! 148 152 !! ``` 149 153 !! FUNCTION cfg_set_value(this,name,input,create) RESULT(error) … … 167 171 END TYPE cfgparser 168 172 169 !> Get value(s) of an option in the parser by name. 170 !! 173 !> Get value(s) of an option in the parser by name. 174 !! 171 175 !! ``` 172 176 !! FUNCTION cfg_get_value(parser,name,output) RESULT(error) … … 177 181 !! On error, __output__ argument is undefined (that is, left unchanged 178 182 !! for scalar versions, **unallocated** for vector version). 179 !! 183 !! 180 184 !! Errors occur in the following situations: 181 185 !! - The option has no value (-6) 182 !! - The option does not exist (-7) 186 !! - The option does not exist (-7) 183 187 !! - The option's value cannot be cast in the desired type (-10) 184 188 INTERFACE cfg_get_value … … 189 193 END INTERFACE 190 194 191 !> Set value(s) of an option in the parser by name 192 !! 195 !> Set value(s) of an option in the parser by name 196 !! 193 197 !! ``` 194 198 !! FUNCTION set_value(this,name,input,create) RESULT(error) … … 201 205 !! exist in _this_ parser. 202 206 !! @warning 203 !! In such case, if the given is not valid, an assertionis raised !207 !! In such case, if the given __name__ is not valid, an error is raised ! 204 208 !! 205 209 !! On error (i.e. no option matches the given _name_), no values are set. 206 INTERFACE cfg_set_value 210 INTERFACE cfg_set_value 207 211 MODULE PROCEDURE :: cp_set_rv_sc,cp_set_dv_sc,cp_set_iv_sc, & 208 212 cp_set_lv_sc,cp_set_cv_sc,cp_set_sv_sc, & 209 213 cp_set_rv_ve,cp_set_dv_ve,cp_set_iv_ve, & 210 214 cp_set_lv_ve,cp_set_cv_ve,cp_set_sv_ve 211 END INTERFACE 215 END INTERFACE 212 216 213 217 !> Derived type assignment operator … … 230 234 this%section = other%section 231 235 this%values = other%values 232 END SUBROUTINE op_affect_sc 233 236 END SUBROUTINE op_affect_sc 237 234 238 FUNCTION op_valid(opt) RESULT(ok) 235 239 !! Check whether or not the option is valid (i.e. has name) 236 TYPE(option), INTENT(in) :: opt !! An option object 240 TYPE(option), INTENT(in) :: opt !! An option object 237 241 LOGICAL :: ok !! True if the option is valid, false otherwise. 238 242 ok = LEN_TRIM(opt%name) > 0 239 243 END FUNCTION op_valid 240 244 241 SUBROUTINE op_clear(opt) 245 SUBROUTINE op_clear(opt) 242 246 !! Clear and invalid the given option. 243 TYPE(option), INTENT(inout) :: opt !! An option object 247 TYPE(option), INTENT(inout) :: opt !! An option object 244 248 opt%name = '' 245 249 opt%section = '' … … 261 265 ENDIF 262 266 END FUNCTION op_full_name 263 267 264 268 FUNCTION op_split_name(fname,sname,pname) RESULT(err) 265 269 !> Split a full name in section and option names 266 !! 267 !! The method splits a full name into (section,option) names. Output names (if any) are always 268 !! set to lower case. 270 !! 271 !! The method splits a full name into (section,option) names: 272 !! 273 !! - Option basename is always set in lower-case. 274 !! - If any, section name case is left unmodified. 269 275 !! 270 276 !! A full name simply consists in a section name and an option name separated by a single "/". 271 277 !! 272 !! The method never checks the validity of the output names. Consider using [[cfg_check_name(function)]] 273 !! to do so. 274 !! @note 275 !! If _fname_ does not contains any "/", the method set the special name "\_\_default\_\_" for the output 276 !! section name. 278 !! The method never checks the validity of the output names. Consider using [[cfg_check_name(function)]] 279 !! to do so. 277 280 !! @note 278 !! On success, option and section names are set to lower case. Otherwise they are set to empty strings. 281 !! If _fname_ does not contains any "/", the method sets the special name "\_\_default\_\_" for the output 282 !! section name. 283 !! @note 284 !! On failure, output arguments are set to empty strings. 279 285 !! @warning 280 !! If _fname_ ends with a "/", an error (- 6, invalid name) is raised: the method always assumes it can286 !! If _fname_ ends with a "/", an error (-9, invalid name) is raised: the method always assumes it can 281 287 !! find an option part in the name. 282 288 CHARACTER(len=*), INTENT(in) :: fname !! A name to split 283 289 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: sname, & !! Section part of the name 284 290 pname !! Option part of the name 285 TYPE(error) :: err !! Error status of the method 286 INTEGER :: idx 291 TYPE(error) :: err !! Error status of the method 292 INTEGER :: idx 293 CHARACTER(len=:), ALLOCATABLE :: tfname 287 294 err = noerror ; pname = "" ; sname = "" 295 tfname = op_format(fname,sname,pname) 296 IF (LEN_TRIM(tfname) == 0) err = error("Invalid option name ("//TRIM(fname)//")",-9) 297 END FUNCTION op_split_name 298 299 FUNCTION op_format(name,sname,pname) RESULT(oname) 300 !! Format the input name to be consistent with character case requirements. 301 !! 302 !! Given a **name**, the method tries to split in section/option names. 303 !! Then it converts the option part in lower-case. 304 !! 305 !! If no section part is found (not '/' or set as first character of **name**), the 306 !! special section name `__default__` is set. 307 !! 308 !! If **name** ends with a '/', it is an error and the method returns an empty string. 309 CHARACTER(len=*), INTENT(in) :: name !! Name to format. 310 CHARACTER(len=:), ALLOCATABLE, INTENT(out), OPTIONAL :: sname !! Section part of the name (optional output) 311 CHARACTER(len=:), ALLOCATABLE, INTENT(out), OPTIONAL :: pname !! Option part of the name (optional output) 312 CHARACTER(len=:), ALLOCATABLE :: oname !! Formatted full option name. 313 INTEGER :: idx 314 CHARACTER(len=:), ALLOCATABLE :: zsname,zpname 315 zpname = "" ; zsname = "" 288 316 ! splits input name in sname, pname 289 idx = INDEX(fname,'/') 290 IF (idx == LEN_TRIM(fname)) THEN 291 err = error("Invalid option name ("//TRIM(fname)//")",-9) 317 idx = INDEX(name,'/') 318 IF (idx == LEN_TRIM(name)) THEN 319 oname = '' 320 IF (PRESENT(sname)) sname = '' 321 IF (PRESENT(pname)) pname = '' 292 322 RETURN 293 323 ELSE IF (idx <= 1) THEN 294 sname = "__default__" ; pname = TRIM(fname)295 IF (idx == 1) pname=pname(2:)296 ELSE 297 sname = fname(:idx-1)298 pname = fname(idx+1:LEN_TRIM(fname))299 ENDIF 300 ! 17/12/2014: set option name to lower301 pname = str_to_lower(pname)302 sname = str_to_lower(sname)303 END FUNCTION op_ split_name324 zsname = "__default__" ; zpname = to_lower(TRIM(name)) 325 IF (idx == 1) zpname=zpname(2:) 326 ELSE 327 zsname = name(:idx-1) 328 zpname = to_lower(name(idx+1:LEN_TRIM(name))) 329 ENDIF 330 oname = zsname//"/"//zpname 331 IF (PRESENT(sname)) sname = zsname 332 IF (PRESENT(pname)) pname = zpname 333 END FUNCTION op_format 304 334 305 335 FUNCTION op_greater_than(left,right) RESULT(ret) … … 309 339 TYPE(option), INTENT(in) :: left !! LHS option. 310 340 TYPE(option), INTENT(in) :: right !! RHS option. 311 LOGICAL :: ret 341 LOGICAL :: ret 312 342 !! .true. if LHS is _greater_ than RHS (based on section and option name) 313 343 ret = LGT(op_full_name(left),op_full_name(right)) … … 320 350 TYPE(option), INTENT(in) :: left !! LHS option. 321 351 TYPE(option), INTENT(in) :: right !! RHS option. 322 LOGICAL :: ret 352 LOGICAL :: ret 323 353 !! .true. if LHS is _less_ than RHS (based on section and option name) 324 354 ret = LLT(op_full_name(left),op_full_name(right)) … … 327 357 FUNCTION op_to_str(opt,num_values) RESULT(str) 328 358 !! Get the string representation of a option object 329 !! @note 359 !! @note 330 360 !! If the object is not valid an empty string is returned. 331 TYPE(option), INTENT(in) :: opt 361 TYPE(option), INTENT(in) :: opt 332 362 !! A option object 333 363 INTEGER, INTENT(in), OPTIONAL :: num_values … … 343 373 str = TRIM(opt%name)//" = " ; np = LEN(str) 344 374 ALLOCATE(CHARACTER(len=np) :: nspcs) ; nspcs(1:) = " " 345 ! stores the error but do not check... 375 ! stores the error but do not check... 346 376 ret = words_to_vector(opt%values,vec) 347 377 IF (.NOT.ALLOCATED(vec)) RETURN … … 382 412 383 413 FUNCTION cfg_check_name(name) RESULT(valid) 384 !! Check if a name is valid 385 !! 386 !! A valid option/section name begins with a letter and is followed by any 387 !! number of alphanumeric characters and underscore (`[A-Za-z][A-Za-z0-9\_]\*`). 414 !! Check if a name is valid. 415 !! 416 !! If **name** contains a '/' it is assumed to be a full option name. In such case 417 !! both parts of the name are checked against section/option names requirements (see below). 418 !! 419 !! Otherwise it is assumed to be the basename of the option. 420 !! 421 !! A valid option (base) name is an alphanumeric sequence in lower-case that always begin by 422 !! a letter. 423 !! 424 !! A valid section name is and alphanumeric sequence (in any case) that always begins by 425 !! by a letter. 388 426 CHARACTER(len=*), INTENT(in) :: name !! A string with the name to check. 389 427 LOGICAL :: valid !! .true. if the name is valid, .false. otherwise 390 428 INTEGER :: i 391 CHARACTER(len=26), PARAMETER :: alpha = "abcdefghijklmnopqrstuvwxyz" 392 CHARACTER(len=12), PARAMETER :: num = "0123456789_" 429 CHARACTER(len=26), PARAMETER :: alpha = "abcdefghijklmnopqrstuvwxyz" 430 CHARACTER(len=26), PARAMETER :: ualpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 431 CHARACTER(len=12), PARAMETER :: num = "0123456789_" 393 432 CHARACTER(len=:), ALLOCATABLE :: pname,sname 394 433 TYPE(error) :: err … … 401 440 ENDIF 402 441 ELSE 403 pname = str_to_lower(TRIM(name))442 pname = to_lower(TRIM(name)) 404 443 sname = "__default__" 405 444 ENDIF … … 416 455 i = INDEX(sname,CHAR(32)) 417 456 IF (i /= 0.OR.LEN_TRIM(sname) <= 0) RETURN 418 valid = (VERIFY(sname(1:1), alpha) == 0 .AND.VERIFY(TRIM(sname),alpha//"/"//num) == 0)457 valid = (VERIFY(sname(1:1),ualpha//alpha) == 0 .AND.VERIFY(TRIM(sname),ualpha//alpha//num) == 0) 419 458 ENDIF 420 459 END FUNCTION cfg_check_name 421 460 422 FUNCTION cfg_count(this ) RESULT(num)461 FUNCTION cfg_count(this,section) RESULT(num) 423 462 !! Get the total number of option in the parser. 424 463 !! 464 !! If a section name is given in argument, the method returns the count for the given section only. 465 !! 466 !! To get the number of top-level options (i.e. that belongs to the default section) the keyword \_\_default\_\_ 467 !! should be set for the section argument. 468 !! 469 !! If __section__ is not defined in the parser, the method returns 0. 470 !! 425 471 !! @internal 426 !! If no options are defined, then it implies that the internal vector of options is 472 !! If no options are defined, then it implies that the internal vector of options is 427 473 !! not allocated. 428 OBJECT(cfgparser), INTENT(in) :: this !! A cfgparser object to search in 429 INTEGER :: num !! Number of current options registered in the parser. 474 OBJECT(cfgparser), INTENT(in) :: this !! A cfgparser object to search in 475 CHARACTER(len=*), INTENT(in), OPTIONAL :: section !! Optional section name to search in. 476 INTEGER :: num !! Number of current options registered in the parser. 477 INTEGER :: i 430 478 num = 0 431 479 IF(.NOT.ALLOCATED(this%options)) RETURN 432 num = SIZE(this%options) 480 IF (.NOT.PRESENT(section)) THEN 481 num = SIZE(this%options) 482 ELSE 483 DO i=1, SIZE(this%options) 484 IF (this%options(i)%section == section) num = num+1 485 ENDDO 486 ENDIF 433 487 END FUNCTION cfg_count 434 488 … … 469 523 ! Found a match so start looking again 470 524 found = (tmp(j) == this%options(i)%section .OR. & 471 this%options(i)%section == "__default__") 525 this%options(i)%section == "__default__") 472 526 IF (found) EXIT 473 527 ENDDO … … 482 536 END FUNCTION cfg_section_names 483 537 484 FUNCTION cfg_option_names(this ) RESULT(list)538 FUNCTION cfg_option_names(this,secname) RESULT(list) 485 539 !! Get the list of option names. 486 540 !! 487 541 !! @note 488 542 !! If the parser does not have options, the vector is still allocated but with 0 elements. 489 OBJECT(cfgparser), INTENT(in) :: this !! A cfgparser object to process. 490 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: list !! List of option names. 491 INTEGER :: i,no 543 OBJECT(cfgparser), INTENT(in) :: this !! A cfgparser object to process. 544 CHARACTER(len=*), INTENT(in), OPTIONAL :: secname !! Optional section name to search in. 545 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: list !! List of option names. 546 INTEGER :: j,i,no,nso 492 547 no = cfg_count(this) 493 ALLOCATE(list(no)) 494 IF (no == 0) RETURN 495 DO i=1,no 496 IF (this%options(i)%section == "__default__") THEN 497 list(i) = TRIM(this%options(i)%name) 498 ELSE 499 list(i) = TRIM(this%options(i)%section)//"/"//TRIM(this%options(i)%name) 500 ENDIF 501 ENDDO 548 IF (no == 0) THEN 549 ALLOCATE(list(no)) ; RETURN 550 ENDIF 551 IF (PRESENT(secname)) THEN 552 IF (.NOT.cfg_has_section(this,TRIM(secname))) THEN 553 ALLOCATE(list(no)) ; RETURN 554 ELSE 555 nso = 0 556 DO i=1,no ; IF (this%options(i)%section == TRIM(secname)) nso = nso + 1 ; ENDDO 557 ALLOCATE(list(nso)) 558 IF (nso == 0) RETURN 559 j = 1 560 DO i=1,no 561 IF (this%options(i)%section == TRIM(secname)) THEN 562 list(j) = TRIM(this%options(i)%section)//"/"//TRIM(this%options(i)%name) ; j=j+1 563 ENDIF 564 ENDDO 565 ENDIF 566 ELSE 567 ALLOCATE(list(no)) 568 DO i=1,no 569 IF (this%options(i)%section == "__default__") THEN 570 list(i) = TRIM(this%options(i)%name) 571 ELSE 572 list(i) = TRIM(this%options(i)%section)//"/"//TRIM(this%options(i)%name) 573 ENDIF 574 ENDDO 575 ENDIF 502 576 END FUNCTION cfg_option_names 503 577 504 578 FUNCTION cfg_has_section(this,name) RESULT(yes) 505 579 !! Check if parser has section by name 580 !! 581 !! @note 582 !! Keep in mind that section name in the configuration are case-sensitive. 506 583 OBJECT(cfgparser), INTENT(in) :: this !! cfgparser object 507 584 CHARACTER(len=*), INTENT(in) :: name !! Name of the section to search 508 585 LOGICAL :: yes !! .true. if the section exists, .false. otherwise 509 CHARACTER(len=:), ALLOCATABLE :: zname510 586 INTEGER :: i,no 511 587 yes = .false. 512 588 no = cfg_count(this) 513 589 IF (no == 0) RETURN 514 zname = str_to_lower(name)515 590 DO i = 1,no 516 IF (this%options(i)%section == zname) THEN591 IF (this%options(i)%section == name) THEN 517 592 yes = .true. 518 593 RETURN … … 527 602 LOGICAL :: yes !! .true. if the option is found, .false. otherwise 528 603 CHARACTER(len=:), ALLOCATABLE :: pname,zname 529 INTEGER :: i,no 604 INTEGER :: i,no,iscan 530 605 yes = .false. 531 606 no = cfg_count(this) 532 607 IF (no == 0) RETURN 533 IF (SCAN(name,"/") <= 0) THEN 534 zname = "__default__"//"/"//str_to_lower(TRIM(name)) 535 ELSE 536 zname = str_to_lower(TRIM(name)) 537 ENDIF 608 zname = op_format(name) 609 IF (LEN_TRIM(zname) == 0) RETURN 538 610 DO i = 1,no 539 pname = op_full_name(this%options(i)) 611 pname = op_full_name(this%options(i)) 540 612 IF (pname == zname) THEN 541 613 yes = .true. … … 545 617 END FUNCTION cfg_has_option 546 618 547 SUBROUTINE cfg_sort_options(this) 619 SUBROUTINE cfg_sort_options(this) 548 620 !! Sort the options in the parser (alphabetiCALLy). 549 621 OBJECT(cfgparser), INTENT(inout) :: this !! A cfgparser object … … 552 624 IF (no == 0) RETURN 553 625 CALL insertionSort(this%options) 554 END SUBROUTINE cfg_sort_options 626 END SUBROUTINE cfg_sort_options 555 627 556 628 SUBROUTINE cfg_remove_option(this,name) 557 629 !! Remove an option from parser by name. 558 OBJECT(cfgparser), INTENT(inout) :: this !! A cfgparser object to search in 630 OBJECT(cfgparser), INTENT(inout) :: this !! A cfgparser object to search in 559 631 CHARACTER(len=*), INTENT(in) :: name !! The name of the option to remove 560 CHARACTER(len=:), ALLOCATABLE :: zname,pname561 632 INTEGER :: no,idx,i,j 562 633 TYPE(option), DIMENSION(:), ALLOCATABLE :: tmp 563 IF (SCAN(name,"/") <= 0) THEN 564 zname = "__default__"//"/"//str_to_lower(TRIM(name)) 565 ELSE 566 zname = str_to_lower(TRIM(name)) 567 ENDIF 568 idx = cp_get_opt_idx(this,zname) 634 idx = cp_get_opt_idx(this,name) 635 IF (idx == -1) RETURN 569 636 no = cfg_count(this) 570 IF (idx == -1) RETURN571 637 ! only one opt 572 638 IF (no == 1) THEN … … 589 655 this%options(i) = tmp(i) 590 656 CALL op_clear(tmp(i)) 591 ENDDO 657 ENDDO 592 658 DEALLOCATE(tmp) 593 659 END SUBROUTINE cfg_remove_option … … 597 663 !! 598 664 !! The method removes all the options that belong to the given section name. 599 OBJECT(cfgparser), INTENT(inout) :: this 600 !! A cfgparser object to search in 665 OBJECT(cfgparser), INTENT(inout) :: this 666 !! A cfgparser object to search in 601 667 CHARACTER(len=*), INTENT(in) :: name 602 668 !! The name of the section to remove 603 CHARACTER(len=:), ALLOCATABLE :: zname604 669 INTEGER :: no,i,j,icount 605 670 INTEGER, DIMENSION(:), ALLOCATABLE :: idxs,itmp 606 671 TYPE(option), DIMENSION(:), ALLOCATABLE :: tmp 607 608 672 no = cfg_count(this) 609 673 IF (no == 0) RETURN 610 zname = str_to_lower(TRIM(name))611 674 ALLOCATE(itmp(no)) 612 675 itmp(:) = -1 613 676 icount = 0 614 677 DO i=1,no 615 IF (TRIM(this%options(i)%section) == zname) THEN678 IF (TRIM(this%options(i)%section) == TRIM(name)) THEN 616 679 itmp(icount+1) = i 617 680 icount = icount + 1 … … 627 690 DEALLOCATE(this%options) 628 691 RETURN 629 ENDIF 692 ENDIF 630 693 ALLOCATE(tmp(icount)) 631 694 j = 1 … … 650 713 !! Read configuration file 651 714 !! 652 !! @note 715 !! @note 653 716 !! If the library support C bindings, the method can read included files which are defined 654 717 !! by the __#include <...>__ directive (see [p_cfgparse](here) from more details). … … 662 725 !! An error with the first error encountered 663 726 INTEGER :: i 664 LOGICAL :: zoverride,ok 665 TYPE(words) :: incfiles 727 LOGICAL :: zoverride,ok 728 TYPE(words) :: incfiles 666 729 CHARACTER(len=:), ALLOCATABLE :: name 667 730 CHARACTER(len=st_slen) :: isec 668 err = noerror 731 err = noerror 669 732 zoverride = .false. ; IF (PRESENT(override)) zoverride = override 670 733 isec = "__default__" 671 734 name = TRIM(path) 672 i = INDEX(name,'/',.true.) ; IF (i /= 0) name = name(i+1:) 735 i = INDEX(name,'/',.true.) ; IF (i /= 0) name = name(i+1:) 673 736 IF (i == 0) THEN 674 737 name = fs_realpath("./"//path) … … 710 773 no = cfg_count(this) 711 774 IF (no == 0) THEN 712 err = error("No options to write",-7) 775 err = error("No options to write",-7) 713 776 RETURN 714 777 ENDIF … … 728 791 WRITE(lu,'(a)') op_to_str(this%options(i),nv) 729 792 ENDDO 730 END FUNCTION cfg_write_config 793 END FUNCTION cfg_write_config 731 794 732 795 ! internal (private methods) … … 751 814 FUNCTION cp_get_opt_idx(this,name) RESULT(idx) 752 815 !! Get the index of an option by name in the parser. 753 !! 816 !! 754 817 !! The method searches in the parser for the option with the given (full) __name__. 755 818 !! If found, it returns the index of the option in the internal vector of options. Otherwise … … 763 826 no = cfg_count(this) 764 827 IF (no == 0) RETURN 765 IF (SCAN(name,"/") <= 0) THEN 766 zname = "__default__"//"/"//str_to_lower(TRIM(name)) 767 ELSE 768 zname = str_to_lower(TRIM(name)) 769 ENDIF 828 zname = op_format(name) ! prepare the name to search. 829 IF (LEN_TRIM(zname) == 0) RETURN 770 830 DO i=1,no 771 831 pname = op_full_name(this%options(i)) … … 780 840 !! Update an option in the parser. 781 841 !! 782 !! The attempts to update the option in the parser that matches __opt__ name. 783 !! 784 !! If __name__ is given it is used instead of __opt__ name. 785 !! 786 !! If no option is found, __opt__ is appended in the parser. Otherwise the matched 787 !! option is updated (i.e. its values are set to __opt__ values). 788 !! 789 !! If the option is not valid, the method does nothing and -X error status is returned. 842 !! The method attempts to update the option in the parser. 843 !! 844 !! If __sname__ is set to empty string, the method searches for the option 845 !! in the default section. 846 !! 847 !! If no option is found, The the option is appended in the parser. Otherwise it is updated 848 !! with the content of __values__. 849 !! 850 !! If the option name is not valid, the method does nothing and -9 error status is returned. 790 851 !! 791 852 !! @internal 792 853 !! The method performs the same kind of operations than the setters except that it 793 !! expects raw data ([[string s(module):words(type)]]).854 !! expects raw data ([[string_op(module):words(type)]]). 794 855 OBJECT(cfgparser), INTENT(inout) :: this !! cfgparser object to process. 795 856 CHARACTER(len=*), INTENT(in) :: sname !! Name of the section. 796 CHARACTER(len=*), INTENT(in) :: pname !! Name of the option.857 CHARACTER(len=*), INTENT(in) :: pname !! Basename of the option. 797 858 TYPE(words), INTENT(in) :: values !! Raw values. 798 TYPE(error) :: err!! Error status.859 TYPE(error) :: err !! Error status. 799 860 CHARACTER(len=:), ALLOCATABLE :: zsname,fname 800 861 INTEGER :: i 801 862 err = noerror 802 zsname = str_to_lower(TRIM(sname))803 IF (LEN_TRIM( zsname) == 0) zsname = "__default__"804 fname = zsname//"/"// str_to_lower(TRIM(pname))863 zsname = TRIM(sname) 864 IF (LEN_TRIM(sname) == 0) zsname = "__default__" 865 fname = zsname//"/"//to_lower(TRIM(pname)) 805 866 IF (.NOT.cfg_check_name(fname)) THEN 806 867 err = error("Invalid option (no name)",-9) … … 816 877 END FUNCTION cp_update_opt 817 878 818 819 FUNCTION cp_add_opt(this,sname,pname,values) RESULT(err) 879 FUNCTION cp_add_opt(this,sname,pname,values) RESULT(err) 820 880 !! Add an option to the parser. 821 881 !! 822 882 !! In order to add an option to the default section, _sname_ should be left empty or set to "\_\_default\_\_". 823 !!824 !! If given, _opt_ points to the new option on output. If an error occured the pointer is null.825 883 !! 826 884 !! The following error code can be returned: … … 828 886 !! - -8, the option already exists. 829 887 !! - -9, option name is not valid. 830 OBJECT(cfgparser), INTENT(inout) :: this 888 OBJECT(cfgparser), INTENT(inout) :: this 831 889 !! A cfgparser object to process. 832 890 CHARACTER(len=*), INTENT(in) :: sname 833 891 !! Section name. 834 892 CHARACTER(len=*), INTENT(in) :: pname 835 !! Option name.893 !! Option basename. 836 894 TYPE(words), INTENT(in) :: values 837 895 !! Values to set. … … 839 897 !! Return error status. 840 898 CHARACTER(len=:), ALLOCATABLE :: zsname,fname 841 TYPE(option), DIMENSION(:), ALLOCATABLE :: tmp 899 TYPE(option), DIMENSION(:), ALLOCATABLE :: tmp 842 900 INTEGER :: no,i 843 844 TYPE(option) :: sca 901 TYPE(option) :: sca 845 902 846 903 err = noerror … … 848 905 no = cfg_count(this) 849 906 IF (LEN_TRIM(zsname) == 0) zsname = "__default__" 850 fname = TRIM(zsname)//"/"// TRIM(pname)907 fname = TRIM(zsname)//"/"//to_lower(TRIM(pname)) 851 908 ! check name 852 909 IF (.NOT.cfg_check_name(fname)) THEN … … 864 921 ! build option 865 922 CALL op_clear(sca) 866 sca%name = pname923 sca%name = to_lower(TRIM(pname)) 867 924 sca%section = zsname 868 925 sca%values = values … … 874 931 ! parser has options: increase this%options size (ugly copy). 875 932 ALLOCATE(tmp(no)) 876 DO i =1,no 877 tmp(i) = this%options(i) 933 DO i =1,no 934 tmp(i) = this%options(i) 878 935 CALL op_clear(this%options(i)) 879 936 ENDDO 880 937 DEALLOCATE(this%options) 881 938 ALLOCATE(this%options(no+1)) 882 DO i =1,no 883 this%options(i) = tmp(i) 939 DO i =1,no 940 this%options(i) = tmp(i) 884 941 CALL op_clear(tmp(i)) 885 942 ENDDO … … 898 955 !! - -6, the option does not have value(s). 899 956 !! - -10, the value cannot be converted in the output type. 900 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 957 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 901 958 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 902 959 REAL(kind=4), INTENT(out) :: output !! Output value 903 TYPE(error) :: err 960 TYPE(error) :: err 904 961 !! Error status 905 INTEGER :: idx 962 INTEGER :: idx 906 963 CHARACTER(len=:), ALLOCATABLE :: tmp 907 964 err = noerror … … 918 975 err = error("Option "//TRIM(name)//" has no value",-6) 919 976 ELSE 920 IF(.NOT.from_string(tmp,output)) & 977 IF(.NOT.from_string(tmp,output)) & 921 978 err = error(TRIM(name)//": Cannot convert "//tmp//" to real.",-10) 922 979 ENDIF … … 931 988 !! - -6, the option does not have value(s). 932 989 !! - -10, the value cannot be converted in the output type. 933 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 990 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 934 991 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 935 992 REAL(kind=8), INTENT(out) :: output !! Output value 936 TYPE(error) :: err 993 TYPE(error) :: err 937 994 !! Error status 938 INTEGER :: idx 995 INTEGER :: idx 939 996 CHARACTER(len=:), ALLOCATABLE :: tmp 940 997 err = noerror … … 951 1008 err = error("Option "//TRIM(name)//" has no value",-6) 952 1009 ELSE 953 IF(.NOT.from_string(tmp,output)) & 1010 IF(.NOT.from_string(tmp,output)) & 954 1011 err = error(TRIM(name)//": Cannot convert "//tmp//" to double.",-10) 955 1012 ENDIF … … 964 1021 !! - -6, the option does not have value(s). 965 1022 !! - -10, the value cannot be converted in the output type. 966 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1023 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 967 1024 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 968 1025 INTEGER, INTENT(out) :: output !! Output value 969 TYPE(error) :: err 1026 TYPE(error) :: err 970 1027 !! Error status 971 INTEGER :: idx 1028 INTEGER :: idx 972 1029 CHARACTER(len=:), ALLOCATABLE :: tmp 973 1030 err = noerror … … 984 1041 err = error("Option "//TRIM(name)//" has no value",-6) 985 1042 ELSE 986 IF(.NOT.from_string(tmp,output)) & 1043 IF(.NOT.from_string(tmp,output)) & 987 1044 err = error(TRIM(name)//": Cannot convert "//tmp//" to integer.",-10) 988 1045 ENDIF … … 997 1054 !! - -6, the option does not have value(s). 998 1055 !! - -10, the value cannot be converted in the output type. 999 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1056 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1000 1057 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1001 1058 LOGICAL, INTENT(out) :: output !! Output value 1002 TYPE(error) :: err 1059 TYPE(error) :: err 1003 1060 !! Error status 1004 INTEGER :: idx 1061 INTEGER :: idx 1005 1062 CHARACTER(len=:), ALLOCATABLE :: tmp 1006 1063 err = noerror … … 1017 1074 err = error("Option "//TRIM(name)//" has no value",-6) 1018 1075 ELSE 1019 IF(.NOT.from_string(tmp,output)) & 1076 IF(.NOT.from_string(tmp,output)) & 1020 1077 err = error(TRIM(name)//": Cannot convert "//tmp//" to logical.",-10) 1021 1078 ENDIF … … 1030 1087 !! - -6, the option does not have value(s). 1031 1088 !! - -10, the value cannot be converted in the output type. 1032 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1089 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1033 1090 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1034 1091 COMPLEX, INTENT(out) :: output !! Output value 1035 TYPE(error) :: err 1092 TYPE(error) :: err 1036 1093 !! Error status 1037 INTEGER :: idx 1094 INTEGER :: idx 1038 1095 CHARACTER(len=:), ALLOCATABLE :: tmp 1039 1096 err = noerror … … 1050 1107 err = error("Option "//TRIM(name)//" has no value",-6) 1051 1108 ELSE 1052 IF(.NOT.from_string(tmp,output)) & 1109 IF(.NOT.from_string(tmp,output)) & 1053 1110 err = error(TRIM(name)//": Cannot convert "//tmp//" to complex.",-10) 1054 1111 ENDIF … … 1062 1119 !! - -7, no option matches the given name. 1063 1120 !! - -6, the option does not have value(s). 1064 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1121 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1065 1122 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1066 1123 CHARACTER(len=*), INTENT(out) :: output !! Output value 1067 TYPE(error) :: err 1124 TYPE(error) :: err 1068 1125 !! Error status 1069 INTEGER :: idx 1126 INTEGER :: idx 1070 1127 !CHARACTER(len=:), ALLOCATABLE :: tmp 1071 1128 err = noerror … … 1087 1144 !! 1088 1145 !! On error, the output vector is not allocated. 1089 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1146 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1090 1147 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1091 1148 REAL(kind=4), INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1092 TYPE(error) :: err 1149 TYPE(error) :: err 1093 1150 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1094 1151 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tmp … … 1114 1171 ELSE IF (.NOT.from_string(tmp(i), output(i))) THEN 1115 1172 err = error("Cannot convert value #"//TRIM(i2s)//" from option "//TRIM(name),-10) 1116 DEALLOCATE(output) ; EXIT 1173 DEALLOCATE(output) ; EXIT 1117 1174 ENDIF 1118 1175 ENDDO 1119 1176 ENDIF 1120 1177 DEALLOCATE(tmp) 1121 RETURN 1178 RETURN 1122 1179 END FUNCTION cp_get_rv_ve 1123 1180 … … 1126 1183 !! 1127 1184 !! On error, the output vector is not allocated. 1128 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1185 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1129 1186 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1130 1187 REAL(kind=8), INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1131 TYPE(error) :: err 1188 TYPE(error) :: err 1132 1189 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1133 1190 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tmp … … 1153 1210 ELSE IF (.NOT.from_string(tmp(i), output(i))) THEN 1154 1211 err = error("Cannot convert value #"//TRIM(i2s)//" from option "//TRIM(name),-10) 1155 DEALLOCATE(output) ; EXIT 1212 DEALLOCATE(output) ; EXIT 1156 1213 ENDIF 1157 1214 ENDDO 1158 1215 ENDIF 1159 1216 DEALLOCATE(tmp) 1160 RETURN 1217 RETURN 1161 1218 END FUNCTION cp_get_dv_ve 1162 1219 … … 1165 1222 !! 1166 1223 !! On error, the output vector is not allocated. 1167 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1224 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1168 1225 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1169 1226 INTEGER, INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1170 TYPE(error) :: err 1227 TYPE(error) :: err 1171 1228 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1172 1229 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tmp … … 1192 1249 ELSE IF (.NOT.from_string(tmp(i), output(i))) THEN 1193 1250 err = error("Cannot convert value #"//TRIM(i2s)//" from option "//TRIM(name),-10) 1194 DEALLOCATE(output) ; EXIT 1251 DEALLOCATE(output) ; EXIT 1195 1252 ENDIF 1196 1253 ENDDO 1197 1254 ENDIF 1198 1255 DEALLOCATE(tmp) 1199 RETURN 1256 RETURN 1200 1257 END FUNCTION cp_get_iv_ve 1201 1258 … … 1204 1261 !! 1205 1262 !! On error, the output vector is not allocated. 1206 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1263 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1207 1264 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1208 1265 LOGICAL, INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1209 TYPE(error) :: err 1266 TYPE(error) :: err 1210 1267 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1211 1268 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tmp … … 1231 1288 ELSE IF (.NOT.from_string(tmp(i), output(i))) THEN 1232 1289 err = error("Cannot convert value #"//TRIM(i2s)//" from option "//TRIM(name),-10) 1233 DEALLOCATE(output) ; EXIT 1290 DEALLOCATE(output) ; EXIT 1234 1291 ENDIF 1235 1292 ENDDO 1236 1293 ENDIF 1237 1294 DEALLOCATE(tmp) 1238 RETURN 1295 RETURN 1239 1296 END FUNCTION cp_get_lv_ve 1240 1297 … … 1243 1300 !! 1244 1301 !! On error, the output vector is not allocated. 1245 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1302 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1246 1303 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1247 1304 COMPLEX, INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1248 TYPE(error) :: err 1305 TYPE(error) :: err 1249 1306 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1250 1307 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tmp … … 1270 1327 ELSE IF (.NOT.from_string(tmp(i), output(i))) THEN 1271 1328 err = error("Cannot convert value #"//TRIM(i2s)//" from option "//TRIM(name),-10) 1272 DEALLOCATE(output) ; EXIT 1329 DEALLOCATE(output) ; EXIT 1273 1330 ENDIF 1274 1331 ENDDO 1275 1332 ENDIF 1276 1333 DEALLOCATE(tmp) 1277 RETURN 1334 RETURN 1278 1335 END FUNCTION cp_get_cv_ve 1279 1336 … … 1282 1339 !! 1283 1340 !! On error, the output vector is not allocated. 1284 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1341 OBJECT(cfgparser), INTENT(in) :: this !! Cfgparser object 1285 1342 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1286 1343 CHARACTER(len=*), INTENT(out), DIMENSION(:), ALLOCATABLE :: output !! Output values 1287 TYPE(error) :: err 1288 !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1344 TYPE(error) :: err !! Error status of the method (see [[cfgparser(type):get_value(bound)]] documentation) 1289 1345 LOGICAL :: ok 1290 1346 INTEGER :: idx … … 1307 1363 !! 1308 1364 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1309 !! the parser. 1310 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1365 !! the parser. 1366 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1311 1367 !! 1312 1368 !! In other case, if the option is not defined in the parser the error status is set to -7. 1313 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1369 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1314 1370 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1315 1371 REAL(kind=4), INTENT(in) :: input !! Input value 1316 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1372 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1317 1373 TYPE(error) :: err !! Error status 1318 1374 LOGICAL :: zcreate 1319 INTEGER :: idx 1375 INTEGER :: idx 1320 1376 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1321 1377 TYPE(words) :: values … … 1332 1388 ENDIF 1333 1389 ELSE 1334 this%options(idx)%values = values 1390 this%options(idx)%values = values 1335 1391 ENDIF 1336 1392 CALL words_clear(values) … … 1341 1397 !! 1342 1398 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1343 !! the parser. 1344 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1399 !! the parser. 1400 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1345 1401 !! 1346 1402 !! In other case, if the option is not defined in the parser the error status is set to -7. 1347 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1403 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1348 1404 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1349 1405 REAL(kind=8), INTENT(in) :: input !! Input value 1350 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1406 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1351 1407 TYPE(error) :: err !! Error status 1352 1408 LOGICAL :: zcreate 1353 INTEGER :: idx 1409 INTEGER :: idx 1354 1410 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1355 1411 TYPE(words) :: values … … 1366 1422 ENDIF 1367 1423 ELSE 1368 this%options(idx)%values = values 1424 this%options(idx)%values = values 1369 1425 ENDIF 1370 1426 CALL words_clear(values) … … 1376 1432 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1377 1433 !! the parser. 1378 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1434 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1379 1435 !! 1380 1436 !! In other case, if the option is not defined in the parser the error status is set to -7. 1381 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1437 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1382 1438 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1383 1439 INTEGER, INTENT(in) :: input !! Input value 1384 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1440 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1385 1441 TYPE(error) :: err !! Error status 1386 1442 LOGICAL :: zcreate 1387 INTEGER :: idx 1443 INTEGER :: idx 1388 1444 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1389 1445 TYPE(words) :: values … … 1395 1451 IF (zcreate) THEN 1396 1452 err = op_split_name(name,sname,pname) 1397 !IF (err == 0) err = cp_add_opt(this,sname,pname,values) 1398 err = cp_add_opt(this,sname,pname,values) 1453 IF (err == 0) err = cp_add_opt(this,sname,pname,values) 1399 1454 ELSE 1400 1455 err = error("Option "//TRIM(name)//" does not exist",-7) 1401 1456 ENDIF 1402 1457 ELSE 1403 this%options(idx)%values = values 1458 this%options(idx)%values = values 1404 1459 ENDIF 1405 1460 CALL words_clear(values) … … 1411 1466 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1412 1467 !! the parser. 1413 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1468 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1414 1469 !! 1415 1470 !! In other case, if the option is not defined in the parser the error status is set to -7. 1416 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1471 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1417 1472 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1418 1473 LOGICAL, INTENT(in) :: input !! Input value 1419 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1474 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1420 1475 TYPE(error) :: err !! Error status 1421 1476 LOGICAL :: zcreate 1422 INTEGER :: idx 1477 INTEGER :: idx 1423 1478 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1424 1479 TYPE(words) :: values … … 1435 1490 ENDIF 1436 1491 ELSE 1437 this%options(idx)%values = values 1492 this%options(idx)%values = values 1438 1493 ENDIF 1439 1494 CALL words_clear(values) … … 1445 1500 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1446 1501 !! the parser. 1447 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1502 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1448 1503 !! 1449 1504 !! In other case, if the option is not defined in the parser the error status is set to -7. 1450 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1505 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1451 1506 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1452 1507 COMPLEX, INTENT(in) :: input !! Input value 1453 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1508 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1454 1509 TYPE(error) :: err !! Error status 1455 1510 LOGICAL :: zcreate 1456 INTEGER :: idx 1511 INTEGER :: idx 1457 1512 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1458 1513 TYPE(words) :: values … … 1469 1524 ENDIF 1470 1525 ELSE 1471 this%options(idx)%values = values 1526 this%options(idx)%values = values 1472 1527 ENDIF 1473 1528 CALL words_clear(values) … … 1479 1534 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1480 1535 !! the parser. 1481 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1536 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1482 1537 !! 1483 1538 !! In other case, if the option is not defined in the parser the error status is set to -7. 1484 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1539 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1485 1540 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to set 1486 1541 CHARACTER(len=*), INTENT(in) :: input !! Input value 1487 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1542 LOGICAL, INTENT(in), OPTIONAL :: create !! .true. to create option if it does not exist (default to false). 1488 1543 TYPE(error) :: err !! Error status 1489 1544 LOGICAL :: zcreate 1490 INTEGER :: idx 1545 INTEGER :: idx 1491 1546 CHARACTER(len=:), ALLOCATABLE :: sname,pname 1492 1547 TYPE(words) :: values … … 1503 1558 ENDIF 1504 1559 ELSE 1505 this%options(idx)%values = values 1560 this%options(idx)%values = values 1506 1561 ENDIF 1507 1562 CALL words_clear(values) … … 1512 1567 !! 1513 1568 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1514 !! the parser. 1515 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1569 !! the parser. 1570 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1516 1571 !! 1517 1572 !! In other case, if the option is not defined in the parser the error status is set to -7. 1518 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1573 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1519 1574 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1520 1575 REAL(kind=4), INTENT(in), DIMENSION(:) :: input !! Input values … … 1537 1592 ENDIF 1538 1593 ELSE 1539 this%options(idx)%values = values 1594 this%options(idx)%values = values 1540 1595 ENDIF 1541 1596 CALL words_clear(values) … … 1547 1602 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1548 1603 !! the parser. 1549 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1604 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1550 1605 !! 1551 1606 !! In other case, if the option is not defined in the parser the error status is set to -7. 1552 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1607 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1553 1608 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1554 1609 REAL(kind=8), INTENT(in), DIMENSION(:) :: input !! Input values … … 1571 1626 ENDIF 1572 1627 ELSE 1573 this%options(idx)%values = values 1628 this%options(idx)%values = values 1574 1629 ENDIF 1575 1630 CALL words_clear(values) … … 1580 1635 !! 1581 1636 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1582 !! the parser. 1583 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1637 !! the parser. 1638 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1584 1639 !! 1585 1640 !! In other case, if the option is not defined in the parser the error status is set to -7. 1586 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1641 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1587 1642 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1588 1643 INTEGER, INTENT(in), DIMENSION(:) :: input !! Input values … … 1605 1660 ENDIF 1606 1661 ELSE 1607 this%options(idx)%values = values 1662 this%options(idx)%values = values 1608 1663 ENDIF 1609 1664 CALL words_clear(values) … … 1615 1670 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1616 1671 !! the parser. 1617 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1672 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1618 1673 !! 1619 1674 !! In other case, if the option is not defined in the parser the error status is set to -7. 1620 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1675 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1621 1676 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1622 1677 LOGICAL, INTENT(in), DIMENSION(:) :: input !! Input values … … 1639 1694 ENDIF 1640 1695 ELSE 1641 this%options(idx)%values = values 1696 this%options(idx)%values = values 1642 1697 ENDIF 1643 1698 CALL words_clear(values) … … 1648 1703 !! 1649 1704 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1650 !! the parser. 1651 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1705 !! the parser. 1706 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1652 1707 !! 1653 1708 !! In other case, if the option is not defined in the parser the error status is set to -7. 1654 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1709 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1655 1710 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1656 1711 COMPLEX, INTENT(in), DIMENSION(:) :: input !! Input values … … 1673 1728 ENDIF 1674 1729 ELSE 1675 this%options(idx)%values = values 1730 this%options(idx)%values = values 1676 1731 ENDIF 1677 1732 CALL words_clear(values) … … 1683 1738 !! If _create_ is given to .true., the method will add a new option if it does not exist in 1684 1739 !! the parser. 1685 !! In such case, an error ( -6, invalid name) is raised if the option name is not valid.1740 !! In such case, an error ((-9, invalid name)) is raised if the option name is not valid. 1686 1741 !! 1687 1742 !! In other case, if the option is not defined in the parser the error status is set to -7. 1688 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1743 OBJECT(cfgparser), INTENT(inout) :: this !! Cfgparser object 1689 1744 CHARACTER(len=*), INTENT(in) :: name !! (Full) Name of the option to get 1690 1745 CHARACTER(len=*), INTENT(in), DIMENSION(:) :: input !! Input values … … 1707 1762 ENDIF 1708 1763 ELSE 1709 this%options(idx)%values = values 1764 this%options(idx)%values = values 1710 1765 ENDIF 1711 1766 CALL words_clear(values) … … 1734 1789 LOGICAL :: zoverride,ok,has_opt 1735 1790 INTEGER :: lineno,lu,i 1736 CHARACTER(len=2), PARAMETER :: space = CHAR(32)//"," ! check if , is really wanted.. 1791 CHARACTER(len=2), PARAMETER :: space = CHAR(32)//"," ! check if , is really wanted... A: YES space are the delimiter of the words internal object ! 1737 1792 CHARACTER(len=2), PARAMETER :: blanks = CHAR(9)//CHAR(32) ! currently not used because blanks truncate. 1738 1793 CHARACTER(len=15) :: sln … … 1746 1801 zoverride = .false. ; IF (PRESENT(override)) zoverride = override 1747 1802 ! initialize local variables 1748 curval = '' ; line = '' ; name = '' ; value = '' 1749 lineno = 0 ; lu = free_lun() 1803 curval = '' ; line = '' ; name = '' ; value = '' 1804 lineno = 0 ; lu = free_lun() 1750 1805 IF (LEN_TRIM(isec) == 0) isec = "__default__" 1751 1806 i = INDEX(TRIM(path),"/",.true.) 1752 IF (i == 0) THEN 1807 IF (i == 0) THEN 1753 1808 fulp = fs_realpath("./"//TRIM(ADJUSTL(path))) 1754 1809 ELSE … … 1763 1818 RETURN 1764 1819 ENDIF 1765 ! check for lun 1820 ! check for lun 1766 1821 IF (lu == -1) THEN ; err = error("No available logical unit",-12) ; RETURN ; ENDIF 1767 1822 OPEN(lu,FILE=TRIM(path),STATUS='old',ACTION='READ') … … 1775 1830 ! 1) get relative path 1776 1831 ipath = fs_relpath(ipath,dirp) 1777 ! 2) compute asbolute path )1832 ! 2) compute asbolute path 1778 1833 ipath = TRIM(dirp)//"/"//TRIM(ipath) 1779 1834 ipath = fs_realpath(ipath) … … 1793 1848 CALL op_clear(curopt); curval = '' 1794 1849 ENDIF 1795 err = read_include(parser,ipath,isec,ipaths,zoverride) 1850 err = read_include(parser,ipath,isec,ipaths,zoverride) 1796 1851 IF (err /= 0) EXIT 1797 1852 ENDIF … … 1799 1854 ENDIF 1800 1855 ! continuation line ? 1801 IF (SCAN(line(1:1),blanks) /= 0 .AND. op_valid(curopt)) THEN 1856 IF (SCAN(line(1:1),blanks) /= 0 .AND. op_valid(curopt)) THEN 1802 1857 IF (LEN(curval) == 0) THEN 1803 1858 curval = strip_comment(line) … … 1806 1861 ENDIF 1807 1862 ELSE 1808 ! 1. Remove comment part and left adjust line 1863 ! 1. Remove comment part and left adjust line 1809 1864 line = strip_comment(line) 1810 1865 ! a section header or option header? … … 1837 1892 ! 3. curval is set to value 1838 1893 ! 4. update curval 1839 IF (op_valid(curopt)) THEN 1894 IF (op_valid(curopt)) THEN 1840 1895 IF (LEN(curval) > 0) & 1841 1896 CALL words_extend(curopt%values,TRIM(ADJUSTL(curval)),space,.true.,.true.) … … 1847 1902 ENDIF 1848 1903 CALL op_clear(curopt) ; curval = '' 1849 has_opt = cfg_has_option(parser,TRIM(isec)//"/"//TRIM(name)) 1904 has_opt = cfg_has_option(parser,TRIM(isec)//"/"//TRIM(name)) 1850 1905 1851 1906 IF (has_opt.AND..NOT.zoverride) THEN 1852 ! it is an error: no duplicate allowed 1907 ! it is an error: no duplicate allowed 1853 1908 err = error(basp//'(L'//TRIM(sln)//"): Duplicate option '"//TRIM(name)//"' in "//isec,-8) 1854 1909 EXIT … … 1859 1914 curval = value 1860 1915 CASE(cfg_UNKNOWN) 1861 ! unknown handles also invalid name: it is a critical error 1916 ! unknown handles also invalid name: it is a critical error 1862 1917 IF (err == -9) EXIT 1863 END SELECT 1918 END SELECT 1864 1919 ENDIF 1865 1920 ENDDO 1866 IF (op_valid(curopt)) THEN 1921 IF (op_valid(curopt)) THEN 1867 1922 IF (LEN(curval) > 0) & 1868 1923 CALL words_extend(curopt%values,TRIM(ADJUSTL(curval)),space,.true.,.true.) … … 1886 1941 !! it is a section header. 1887 1942 !! - Otherwise, if line has '=', without '#' before '=', it is an option. 1888 !! 1889 !! Then the method returns an integer with the kind flag of the statement which is one of 1943 !! 1944 !! Then the method returns an integer with the kind flag of the statement which is one of 1890 1945 !! -1 (cfg_UNKNOWN), 0 (cfg_SECTION) or 1 (cfg_OPTION). 1891 1946 CHARACTER(len=*), INTENT(in) :: string !! Input string to process … … 1898 1953 kind = cfg_UNKNOWN 1899 1954 ! get a trimmed (and left adjusted) copy 1900 copy = TRIM(string) 1955 copy = TRIM(string) 1901 1956 ! Is it a section ? 1902 1957 ! ---> search for subscripts of '[' and ']' 1903 1958 ! ---> check that '[' is 1st char and ']' is last char 1904 bi = INDEX(copy,'[') ; ei = INDEX(copy,']') 1959 bi = INDEX(copy,'[') ; ei = INDEX(copy,']') 1905 1960 IF (bi == 1 .AND. ei == LEN(copy) .AND. bi < ei) THEN 1906 1961 ! it is a section header 1907 1962 kind = cfg_SECTION 1908 1963 ! get section name: adjust and trim to remove extra blank spaces 1909 name = str_to_lower(TRIM(ADJUSTL(copy(bi+1:ei-1)))) 1910 IF (TRIM(name) /= "__default__" .AND. .NOT.cfg_check_name(name)) THEN 1964 name = TRIM(ADJUSTL(copy(bi+1:ei-1))) 1965 ! hack cfg_check_name: append '/a' to get a valid option part to test 1966 IF (TRIM(name) /= "__default__" .AND. .NOT.cfg_check_name(name//"/a")) THEN 1911 1967 kind = cfg_UNKNOWN 1912 1968 err = error("Invalid section name ("//name//")",-9) … … 1916 1972 ELSE 1917 1973 ! Is it an option ? 1918 ! --> search for '=' and check if it is set before 1974 ! --> search for '=' and check if it is set before 1919 1975 ! 1st quote (if any) 1920 bi = INDEX(copy,"=") 1976 bi = INDEX(copy,"=") 1921 1977 ! search for quotes 1922 1978 ei = SCAN(copy,quotes) ; IF (ei==0) ei = LEN(copy)+1 1923 1979 IF (bi /= 0 .AND. bi < ei) THEN 1924 1980 kind = cfg_OPTION 1925 name = str_to_lower(TRIM(copy(1:bi-1)))1926 IF (.NOT.cfg_check_name(name)) THEN 1981 name = to_lower(TRIM(copy(1:bi-1))) 1982 IF (.NOT.cfg_check_name(name)) THEN 1927 1983 kind = cfg_UNKNOWN 1928 1984 err = error("Invalid option name ("//TRIM(name)//")",-9) … … 1944 2000 FUNCTION strip_comment(line) RESULT(stripped) 1945 2001 !! Replace comments part of a string by blank spaces 1946 !! The method replaces every characters after '#' (included) by spaces. 1947 !! @note 2002 !! The method replaces every characters after '#' (included) by spaces. 2003 !! @note 1948 2004 !! Output string is also left adjusted, thus only trailing blank can be present. 1949 2005 CHARACTER(len=*), INTENT(in) :: line !! A string to process 1950 2006 CHARACTER(len=LEN(line)) :: stripped !! A string of same length than 'line' but without comment(s) 1951 2007 1952 2008 INTEGER :: idx 1953 2009 stripped = ADJUSTL(line) … … 1960 2016 !! Read a complete line 1961 2017 !! 1962 !! Each time it is CALLed, the function reads a complete of the file opened in 'lun' logical 2018 !! Each time it is CALLed, the function reads a complete of the file opened in 'lun' logical 1963 2019 !! unit and returns .false. if EOF has been reached, .true. otherwise. 1964 2020 !! 1965 2021 !! The function is intended to read a file line by line: 1966 !! 1967 !! ``` fortran2022 !! 2023 !! ``` 1968 2024 !! lu = 1 1969 2025 !! open(lu,file="path/to/the/file/to/read") … … 1975 2031 !! CLOSE(1) 1976 2032 !! ``` 1977 INTEGER, INTENT(in) :: lun !! Logical unit with the opened file to read. 1978 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: string !! Output processed line 2033 INTEGER, INTENT(in) :: lun !! Logical unit with the opened file to read. 2034 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: string !! Output processed line 1979 2035 LOGICAL :: not_eof !! .true. if EOF has NOT been reached yet, .false. otherwise 1980 2036 CHARACTER(len=50) :: buf 1981 2037 INTEGER :: e,sz 1982 not_eof = .true. ; string = '' 2038 not_eof = .true. ; string = '' 1983 2039 DO 1984 2040 READ(lun,'(a)',ADVANCE="no",SIZE=sz,IOSTAT=e) buf … … 2006 2062 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: incpath 2007 2063 !! A string with the filepath to be included if '#include' statement is found, empty string otherwise 2008 LOGICAL :: res 2064 LOGICAL :: res 2009 2065 !! .true. if line is a comment or an empty string, .false. otherwise 2010 2066 CHARACTER(len=:), ALLOCATABLE :: copy … … 2017 2073 ! search for include statement 2018 2074 ! IMPORTANT: assume that there is only a path after include statement 2019 IF (INDEX(copy,"#include ") == 1) incpath = TRIM(ADJUSTL(copy(10:)))2075 IF (INDEX(copy,"#include ") == 1) incpath = remove_quotes(TRIM(ADJUSTL(copy(10:)))) 2020 2076 ENDIF 2021 2077 RETURN … … 2046 2102 SUBROUTINE insertionSort(opts) 2047 2103 !! Sort an array of Options using insertion sort algorithm 2048 TYPE(option), INTENT(inout), DIMENSION(:) :: opts !! Array to sort. 2104 TYPE(option), INTENT(inout), DIMENSION(:) :: opts !! Array to sort. 2049 2105 TYPE(option) :: temp 2050 2106 INTEGER :: i, j … … 2058 2114 ELSE 2059 2115 EXIT 2060 ENDIF 2116 ENDIF 2061 2117 ENDDO 2062 2118 opts(j+1) = temp … … 2065 2121 END SUBROUTINE insertionSort 2066 2122 2067 FUNCTION free_lun() RESULT(lu)2068 !> Get the first free logical unit2069 !!2070 !! The function loops from 7 to 9999 and returns the first free logical unit.2071 !! @note2072 !! According to Fortran standard, the maximum value for a lun is processor2073 !! dependent. I just assume that [7,9999] is a valid range and I believe that2074 !! 9992 files to be opened is far enough for any program !2075 !! @note2076 !! If you intend to use loggers object from this library, you should keep in2077 !! mind that loggers open files with the first free logical unit. Consequently2078 !! if you need to perform I/O operations you should use this function to get a2079 !! free lun instead of just randomly set a lun !2080 INTEGER :: lu2081 !! First free logical unit in the range [7,999] or -1 if no lun is available2082 INTEGER, PARAMETER :: mxlu = 99992083 LOGICAL :: notfree2084 lu = 6 ; notfree = .true.2085 DO WHILE(notfree.AND.lu<=mxlu)2086 lu=lu+1 ; INQUIRE(unit=lu,OPENED=notfree)2087 ENDDO2088 IF (lu >= mxlu) lu = -12089 END FUNCTION free_lun2090 2091 2123 END MODULE CFGPARSE 2092 2124 -
trunk/LMDZ.TITAN/libf/muphytitan/csystem.c
r1793 r1897 1 /* Copyright Jérémie Burgalat (2010-2015 )2 * 3 * burgalat.jeremie@gmail.com1 /* Copyright Jérémie Burgalat (2010-2015,2017) 2 * 3 * jeremie.burgalat@univ-reims.fr 4 4 * 5 5 * This software is a computer program whose purpose is to provide configuration … … 38 38 #include <stdio.h> 39 39 #include <limits.h> 40 #include <string.h> 40 41 #include <libgen.h> 41 42 #include <sys/param.h> // MAXPATHLEN … … 49 50 #include <time.h> 50 51 #include <unistd.h> 51 52 52 #include "csystem.h" 53 53 … … 270 270 } 271 271 272 273 int c_copy(const char *to, const char *from) { 274 int fd_to, fd_from; 275 char buf[4096]; 276 ssize_t nread; 277 int saved_errno; 278 279 fd_from = open(from, O_RDONLY); 280 if (fd_from < 0) 281 return -1; 282 283 fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666); 284 if (fd_to < 0) 285 goto out_error; 286 287 while (nread = read(fd_from, buf, sizeof buf), nread > 0) { 288 char *out_ptr = buf; 289 ssize_t nwritten; 290 291 do { 292 nwritten = write(fd_to, out_ptr, nread); 293 294 if (nwritten >= 0) { 295 nread -= nwritten; 296 out_ptr += nwritten; 297 } else if (errno != EINTR) { 298 goto out_error; 299 } 300 } while (nread > 0); 301 } 302 303 if (nread == 0) { 304 if (close(fd_to) < 0) { 305 fd_to = -1; 306 goto out_error; 307 } 308 close(fd_from); 309 /* Success! */ 310 return 0; 311 } 312 313 out_error: 314 saved_errno = errno; 315 316 close(fd_from); 317 if (fd_to >= 0) 318 close(fd_to); 319 320 errno = saved_errno; 321 return 1; 322 } 323 272 324 /* Remove file from filesytem */ 273 325 int c_remove(const char *path){ … … 490 542 } 491 543 492 /* This verison of realpath was a dumb attempt to get a resolved path 493 * that may not exist. As a matter of fact, it cannot cover all range 494 * of possibilities. 495 * Thus it has been removed. The current verison of c_realpath simply 496 * uses POSIX realpath and returns CWD if no path is given... 544 /* 545 * Author: David Robert Nadeau 546 * Site: http://NadeauSoftware.com/ 547 * License: Creative Commons Attribution 3.0 Unported License 548 * http://creativecommons.org/licenses/by/3.0/deed.en_US 549 * 550 * Cross-plateform way to get memory usage at a given time in fucking bytes !! 551 * 552 * Usage: 553 * 554 * size_t currentSize = getCurrentRSS( ); 555 * size_t peakSize = getPeakRSS( ); 497 556 */ 498 557 499 /* Get the realpath of input path and saves it in output path */ 500 /* 501 char* c_realpath(const char *input){ 502 char *in,*output, *cur,*tmp,*res,*cwd ; 503 int c,om,rm,im; 504 output = NULL; 505 cwd = c_getcwd(); 506 if(!strlen(input)) 507 return cwd; 508 // check (ugly) if path is absolute 509 if (input[0] == '/') { 510 in = strdup(input); 511 }else{ 512 fprintf(stderr,"+++ C( in): %s\n",input); 513 in = malloc((strlen(input)+strlen(cwd)+2)*sizeof(char)); 514 strncpy(in, cwd, strlen(cwd)); 515 strncpy(&in[strlen(cwd)+1], input, strlen(input)); 516 in[strlen(cwd)] = '/'; 517 in[strlen(input)+strlen(cwd)+1] = '\0'; 518 } 519 fprintf(stderr,"C( in): %s\n",in); 520 c = om = im = strlen(in); 521 tmp = malloc((c+1)*sizeof(char)); 522 tmp[c] ='\0'; 523 // search for the deepest existing directory in "input" path 524 while(c != 0 && (res = realpath(tmp,NULL)) == NULL){ 525 // search for the next / from the right (i.e. parent directory) 526 for (cur=tmp+strlen(tmp) ; *cur != '/' && cur != tmp ; cur--, c--); 527 free(tmp) ; tmp = malloc((c+1)*sizeof(char)); 528 strncpy(tmp, in, c); tmp[c] ='\0'; 529 } 530 free(tmp); 531 // On error: null string 532 if (c == 0 || (res==NULL)) { 533 output = (char *)malloc(sizeof(char)); 534 output[0]='\0'; 535 return output; 536 } 537 // no error: allocate output string 538 rm = strlen(res); 539 om += rm-c; 540 output = (char *)malloc(om*sizeof(char)); 541 strncpy(output,res,rm); 542 // Here we could have a bug: 543 // If the path does not exist and contains .. or . references after the deepest 544 // existing directory, it will simply be appended ! 545 // Thus we can never resolve the path. 546 if (c != im) 547 strncpy(output+rm,in+c,im-c); 548 //strncpy(output+rm,in+c,im-c-1); 549 output[om] = '\0'; 550 fprintf(stderr,"C(tmp): %s\n",res); 551 fprintf(stderr,"C(out): %s\n",output); 552 free(res) ; 553 return output; 554 } 555 */ 558 #if defined(_WIN32) 559 #include <windows.h> 560 #include <psapi.h> 561 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) 562 #include <sys/resource.h> 563 #if defined(__APPLE__) && defined(__MACH__) 564 #include <mach/mach.h> 565 #elif(defined(_AIX) || defined(__TOS__AIX__)) || \ 566 (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) 567 #include <procfs.h> 568 #endif 569 #endif 570 571 /** 572 * Returns the peak (maximum so far) resident set size (physical 573 * memory use) measured in bytes, or zero if the value cannot be 574 * determined on this OS. 575 */ 576 size_t c_getPeakRSS() { 577 #if defined(_WIN32) 578 /* Windows -------------------------------------------------- */ 579 PROCESS_MEMORY_COUNTERS info; 580 GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 581 return (size_t)info.PeakWorkingSetSize; 582 583 #elif(defined(_AIX) || defined(__TOS__AIX__)) || \ 584 (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) 585 /* AIX and Solaris ------------------------------------------ */ 586 struct psinfo psinfo; 587 int fd = -1; 588 if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1) 589 return (size_t)0L; /* Can't open? */ 590 if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { 591 close(fd); 592 return (size_t)0L; /* Can't read? */ 593 } 594 close(fd); 595 return (size_t)(psinfo.pr_rssize * 1024L); 596 597 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) 598 /* BSD, Linux, and OSX -------------------------------------- */ 599 struct rusage rusage; 600 getrusage(RUSAGE_SELF, &rusage); 601 #if defined(__APPLE__) && defined(__MACH__) 602 return (size_t)rusage.ru_maxrss; 603 #else 604 return (size_t)(rusage.ru_maxrss * 1024L); 605 #endif 606 607 #else 608 /* Unknown OS ----------------------------------------------- */ 609 return (size_t)0L; /* Unsupported. */ 610 #endif 611 } 612 613 /** 614 * Returns the current resident set size (physical memory use) measured 615 * in bytes, or zero if the value cannot be determined on this OS. 616 */ 617 size_t c_getCurrentRSS() { 618 #if defined(_WIN32) 619 /* Windows -------------------------------------------------- */ 620 PROCESS_MEMORY_COUNTERS info; 621 GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 622 return (size_t)info.WorkingSetSize; 623 624 #elif defined(__APPLE__) && defined(__MACH__) 625 /* OSX ------------------------------------------------------ */ 626 struct mach_task_basic_info info; 627 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; 628 if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) != KERN_SUCCESS) 629 return (size_t)0L; /* Can't access? */ 630 return (size_t)info.resident_size; 631 632 #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) 633 /* Linux ---------------------------------------------------- */ 634 long rss = 0L; 635 FILE *fp = NULL; 636 if ((fp = fopen("/proc/self/statm", "r")) == NULL) 637 return (size_t)0L; /* Can't open? */ 638 if (fscanf(fp, "%*s%ld", &rss) != 1) { 639 fclose(fp); 640 return (size_t)0L; /* Can't read? */ 641 } 642 fclose(fp); 643 return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE); 644 645 #else 646 /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ 647 return (size_t)0L; /* Unsupported. */ 648 #endif 649 } 650 651 652 653 /* Get some informatiosn about the OS memory usage (from /proc/meminfo) */ 654 int c_getSystemMemory(long long int *m_total,long long int *m_available,long long int *m_free){ 655 FILE* fp; 656 char buf[1024]; 657 char *tmp,*p; 658 int ts; 659 long long int mem1 = 0L,mem2 = 0L,mem3 = 0L; 660 if (m_total) (*m_total) = mem1; 661 if (m_available) (*m_free) = mem2; 662 if (m_free) (*m_free) = mem3; 663 if ((fp = fopen("/proc/meminfo", "r")) == NULL) 664 return 1; 665 while (fgets(buf, sizeof(buf), fp) != NULL){ 666 ts = strlen(buf) - 1; buf[ts] = '\0'; 667 tmp = strndup(&buf[0],ts); 668 // check our 3 cases 669 if (ts >= 9 && !strncmp(tmp,"MemTotal:",9)){ 670 // extract the two first tokens. 671 p=strtok(tmp, " "); p=strtok(NULL, " "); 672 // convert the value. 673 mem1 = strtoll(p,NULL,10); 674 } 675 if (ts >= 13 && !strncmp(tmp,"MemAvailable:",13)){ 676 p=strtok(tmp, " "); p=strtok(NULL, " "); 677 mem2 = strtoll(p,NULL,10); 678 } 679 if (ts >= 8 && !strncmp(tmp,"MemFree:",8)){ 680 p=strtok(tmp, " "); p=strtok(NULL, " "); 681 mem3 = strtoll(p,NULL,10); 682 } 683 free(tmp); 684 } 685 fclose(fp); 686 if (m_total) (*m_total) = mem1; 687 if (m_available) (*m_available) = mem2; 688 if (m_free) (*m_free) = mem3; 689 return 0; 690 } -
trunk/LMDZ.TITAN/libf/muphytitan/csystem.h
r1793 r1897 1 /* Copyright Jérémie Burgalat (2010-2015 )2 * 3 * burgalat.jeremie@gmail.com1 /* Copyright Jérémie Burgalat (2010-2015,2017) 2 * 3 * jeremie.burgalat@univ-reims.fr 4 4 * 5 5 * This software is a computer program whose purpose is to provide configuration … … 31 31 * The fact that you are presently reading this means that you have had 32 32 * knowledge of the CeCILL-B license and that you accept its terms. 33 */ /* csystem.h */33 */ 34 34 35 35 … … 172 172 */ 173 173 int c_mkdir(const char *path, mode_t mode); 174 175 176 /** 177 * Copy file to another. 178 * @param to A C string with the new filepath 179 * @param from A C string with the filepath to copy 180 * @return An integer with 0 on success, 1 on failure. 181 */ 182 int c_copy(const char *to, const char *from); 174 183 175 184 /** … … 255 264 int c_termsize(int *rows,int *cols); 256 265 266 /** 267 * Get the current resident set size memory used by the program. 268 */ 269 size_t c_getCurrentRSS(); 270 271 /** 272 * Get the peak resident set size memory used by the program. 273 */ 274 size_t c_getPeakRSS(); 275 276 /** 277 * Get global memory usage informations. 278 * 279 * Note: The method attempts to read /proc/meminfo. If the file does not exists, all the given output arguments are 280 * set to zero. 281 */ 282 int c_getSystemMemory(long long int *m_total,long long int *m_available,long long int *m_free); -
trunk/LMDZ.TITAN/libf/muphytitan/datasets.F90
r1793 r1897 36 36 !! summary: Dataset module definition file 37 37 !! author: J. Burgalat 38 !! date: 2014 39 40 #if HAVE_CONFIG_H 41 #include "config.h" 42 #endif 38 !! date: 2014,2017 43 39 44 40 MODULE DATASETS … … 65 61 !! Note that for ASCII file, data must be ordered so first dimensions vary first. Same requirement 66 62 !! is needed for NetCDF file but in most cases, it is implicitly done (if dimensions are ordered). 67 USE LINT_PREC68 #if HAVE_NC_FTN69 63 USE NETCDF 70 #endif71 64 IMPLICIT NONE 72 65 73 66 PRIVATE 74 67 75 PUBLIC :: read_dset, clear_dset, is_in, debug68 PUBLIC :: read_dset, write_dset, clear_dset, is_in, has_data, debug 76 69 77 70 LOGICAL :: debug = .false. !! A control flag to enable verbose mode 78 79 #if HAVE_NC_FTN80 LOGICAL, PUBLIC, PARAMETER ::nc_supported = .true. !! NetCDF input files are supported81 #else82 LOGICAL, PUBLIC, PARAMETER ::nc_supported = .false. !! NetCDF input files are not supported83 #endif84 71 85 72 !> Initialize a data set from either an ASCII or a NetCDF file … … 91 78 !! Netcdf reader interface is available only if the library has been compiled with NetCDF support. 92 79 INTERFACE read_dset 93 #if HAVE_NC_FTN94 80 MODULE PROCEDURE ncdf_rd_1d,ncdf_rd_2d,ncdf_rd_3d,ncdf_rd_4d,ncdf_rd_5d 95 81 #if HAVE_NC4_FTN 96 82 MODULE PROCEDURE ncdf4_rd_1d,ncdf4_rd_2d,ncdf4_rd_3d,ncdf4_rd_4d,ncdf4_rd_5d 97 83 #endif 98 #endif99 84 MODULE PROCEDURE ascii_rd_1d,ascii_rd_2d,ascii_rd_3d,ascii_rd_4d,ascii_rd_5d 85 END INTERFACE 86 87 !> Write a dataset in a netcdf (classic) file. 88 INTERFACE write_dset 89 MODULE PROCEDURE nc_wr_1d,nc_wr_2d,nc_wr_3d,nc_wr_4d,nc_wr_5d 100 90 END INTERFACE 101 91 … … 111 101 112 102 !> Private interface to netcdf informations getters 113 #if HAVE_NC_FTN114 103 INTERFACE get_nc_info 115 104 MODULE PROCEDURE get_nc3_info … … 118 107 #endif 119 108 END INTERFACE 120 #endif 109 110 INTERFACE has_data 111 MODULE PROCEDURE has_d_1d,has_d_2d,has_d_3d,has_d_4d,has_d_5d 112 END INTERFACE 113 121 114 122 115 TYPE, PUBLIC :: DSET1D 123 116 !! A 1D data set 124 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 125 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 117 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 118 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 119 CHARACTER(len=NF90_MAX_NAME) :: xname = "X" !! Name of the X coordinate 120 CHARACTER(len=NF90_MAX_NAME) :: dname = "data" !! Name of the data block 126 121 END TYPE DSET1D 127 122 128 123 TYPE, PUBLIC :: DSET2D 129 124 !! A 2D data set 130 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 131 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 132 REAL(kind=wp), DIMENSION(:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 125 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 126 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 127 REAL(kind=8), DIMENSION(:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 128 CHARACTER(len=NF90_MAX_NAME) :: xname = "X" !! Name of the X coordinate 129 CHARACTER(len=NF90_MAX_NAME) :: yname = "Y" !! Name of the Y coordinate 130 CHARACTER(len=NF90_MAX_NAME) :: dname = "data" !! Name of the data block 133 131 END TYPE DSET2D 134 132 135 133 TYPE, PUBLIC :: DSET3D 136 134 !! A 3D data set 137 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 138 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 139 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 140 REAL(kind=wp), DIMENSION(:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 135 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 136 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 137 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 138 REAL(kind=8), DIMENSION(:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 139 CHARACTER(len=NF90_MAX_NAME) :: xname = "X" !! Name of the X coordinate 140 CHARACTER(len=NF90_MAX_NAME) :: yname = "Y" !! Name of the Y coordinate 141 CHARACTER(len=NF90_MAX_NAME) :: zname = "Z" !! Name of the Z coordinate 142 CHARACTER(len=NF90_MAX_NAME) :: dname = "data" !! Name of the data block 141 143 END TYPE DSET3D 142 144 143 145 TYPE, PUBLIC :: DSET4D 144 146 !! A 4D data set 145 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 146 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 147 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 148 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: t !! T coordinate tabulated values 149 REAL(kind=wp), DIMENSION(:,:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 147 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 148 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 149 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 150 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: t !! T coordinate tabulated values 151 REAL(kind=8), DIMENSION(:,:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 152 CHARACTER(len=NF90_MAX_NAME) :: xname = "X" !! Name of the X coordinate 153 CHARACTER(len=NF90_MAX_NAME) :: yname = "Y" !! Name of the Y coordinate 154 CHARACTER(len=NF90_MAX_NAME) :: zname = "Z" !! Name of the Z coordinate 155 CHARACTER(len=NF90_MAX_NAME) :: tname = "T" !! Name of the T coordinate 156 CHARACTER(len=NF90_MAX_NAME) :: dname = "data" !! Name of the data block 150 157 END TYPE DSET4D 151 158 152 159 TYPE, PUBLIC :: DSET5D 153 160 !! A 5D data set 154 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 155 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 156 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 157 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: t !! T coordinate tabulated values 158 REAL(kind=wp), DIMENSION(:), ALLOCATABLE :: w !! W coordinate tabulated values 159 REAL(kind=wp), DIMENSION(:,:,:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 161 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: x !! X coordinate tabulated values 162 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: y !! Y coordinate tabulated values 163 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: z !! Z coordinate tabulated values 164 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: t !! T coordinate tabulated values 165 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: w !! W coordinate tabulated values 166 REAL(kind=8), DIMENSION(:,:,:,:,:), ALLOCATABLE :: data !! Tabulated function's value at each coordinate 167 CHARACTER(len=NF90_MAX_NAME) :: xname = "X" !! Name of the X coordinate 168 CHARACTER(len=NF90_MAX_NAME) :: yname = "Y" !! Name of the Y coordinate 169 CHARACTER(len=NF90_MAX_NAME) :: zname = "Z" !! Name of the Z coordinate 170 CHARACTER(len=NF90_MAX_NAME) :: tname = "T" !! Name of the T coordinate 171 CHARACTER(len=NF90_MAX_NAME) :: wname = "W" !! Name of the W coordinate 172 CHARACTER(len=NF90_MAX_NAME) :: dname = "data" !! Name of the data block 160 173 END TYPE DSET5D 161 174 … … 165 178 FUNCTION is_in_1d(set,x) RESULT(ret) 166 179 !! Check if point is in the 1D data set 167 TYPE(DSET1D), INTENT(in) 168 REAL(kind= wp), INTENT(in) :: x !! coordinate of the point to check180 TYPE(DSET1D), INTENT(in) :: set !! Dataset object to search in 181 REAL(kind=8), INTENT(in) :: x !! coordinate of the point to check 169 182 LOGICAL :: ret !! .true. if the point is in the data set, .false. otherwise 170 REAL(kind= wp) :: l,u183 REAL(kind=8) :: l,u 171 184 ret=.true. 172 185 l = set%x(1) ; u= set%x(size(set%x)) … … 177 190 FUNCTION is_in_2d(set,x,y) RESULT(ret) 178 191 !! Check if point is in the 2D data set 179 TYPE(DSET2D), INTENT(in) 180 REAL(kind= wp), INTENT(in) :: x !! X coordinate of the point to check181 REAL(kind= wp), INTENT(in) :: y !! Y coordinate of the point to check192 TYPE(DSET2D), INTENT(in) :: set !! Dataset object to search in 193 REAL(kind=8), INTENT(in) :: x !! X coordinate of the point to check 194 REAL(kind=8), INTENT(in) :: y !! Y coordinate of the point to check 182 195 LOGICAL :: ret !! .true. if the point is in the data set, .false. otherwise 183 REAL(kind= wp) :: l,u196 REAL(kind=8) :: l,u 184 197 ret=.false. 185 198 l = set%x(1) ; u= set%x(size(set%x)) … … 194 207 FUNCTION is_in_3d(set,x,y,z) RESULT(ret) 195 208 !! Check if point is in the 3D data set 196 TYPE(DSET3D), INTENT(in) 197 REAL(kind= wp), INTENT(in) :: x !! X coordinate of the point to check198 REAL(kind= wp), INTENT(in) :: y !! Y coordinate of the point to check199 REAL(kind= wp), INTENT(in) :: z !! Z coordinate of the point to check209 TYPE(DSET3D), INTENT(in) :: set !! Dataset object to search in 210 REAL(kind=8), INTENT(in) :: x !! X coordinate of the point to check 211 REAL(kind=8), INTENT(in) :: y !! Y coordinate of the point to check 212 REAL(kind=8), INTENT(in) :: z !! Z coordinate of the point to check 200 213 LOGICAL :: ret !! .true. if the point is in the data set, .false. otherwise 201 REAL(kind= wp) :: l,u214 REAL(kind=8) :: l,u 202 215 ret=.false. 203 216 l = set%x(1) ; u= set%x(size(set%x)) … … 213 226 FUNCTION is_in_4d(set,x,y,z,t) RESULT(ret) 214 227 !! Check if point is in the 4D data set 215 TYPE(DSET4D), INTENT(in) 216 REAL(kind= wp), INTENT(in) :: x !! X coordinate of the point to check217 REAL(kind= wp), INTENT(in) :: y !! Y coordinate of the point to check218 REAL(kind= wp), INTENT(in) :: z !! Z coordinate of the point to check219 REAL(kind= wp), INTENT(in) :: t !! T coordinate of the point to check228 TYPE(DSET4D), INTENT(in) :: set !! Dataset object to search in 229 REAL(kind=8), INTENT(in) :: x !! X coordinate of the point to check 230 REAL(kind=8), INTENT(in) :: y !! Y coordinate of the point to check 231 REAL(kind=8), INTENT(in) :: z !! Z coordinate of the point to check 232 REAL(kind=8), INTENT(in) :: t !! T coordinate of the point to check 220 233 LOGICAL :: ret !! .true. if the point is in the data set, .false. otherwise 221 REAL(kind= wp) :: l,u234 REAL(kind=8) :: l,u 222 235 ret=.false. 223 236 l = set%x(1) ; u= set%x(size(set%x)) … … 235 248 FUNCTION is_in_5d(set,x,y,z,t,w) RESULT(ret) 236 249 !! Check if point is in the 4D data set 237 TYPE(DSET5D), INTENT(in) 238 REAL(kind= wp), INTENT(in) :: x !! X coordinate of the point to check239 REAL(kind= wp), INTENT(in) :: y !! Y coordinate of the point to check240 REAL(kind= wp), INTENT(in) :: z !! Z coordinate of the point to check241 REAL(kind= wp), INTENT(in) :: t !! T coordinate of the point to check242 REAL(kind= wp), INTENT(in) :: w !! W coordinate of the point to check250 TYPE(DSET5D), INTENT(in) :: set !! Dataset object to search in 251 REAL(kind=8), INTENT(in) :: x !! X coordinate of the point to check 252 REAL(kind=8), INTENT(in) :: y !! Y coordinate of the point to check 253 REAL(kind=8), INTENT(in) :: z !! Z coordinate of the point to check 254 REAL(kind=8), INTENT(in) :: t !! T coordinate of the point to check 255 REAL(kind=8), INTENT(in) :: w !! W coordinate of the point to check 243 256 LOGICAL :: ret !! .true. if the point is in the data set, .false. otherwise 244 REAL(kind= wp) :: l,u257 REAL(kind=8) :: l,u 245 258 ret=.false. 246 259 l = set%x(1) ; u= set%x(size(set%x)) … … 300 313 END FUNCTION ascii_header 301 314 302 #if HAVE_NC_FTN 303 FUNCTION nc_get_dim(fid,did,var,values,ds) RESULT(ret) 304 !! Get dimensions information of a NetCDF variable 315 FUNCTION nc_get_dim_by_name(fid,dn,values,ds,did) RESULT(ret) 316 !! Get informations about a dimension. 305 317 !! 306 318 !! The method gets the values and size of a given dimension. 307 INTEGER, INTENT(in) :: fid 319 !! 320 !! Errors occur if: 321 !! 322 !! - the given name is not a dimension name. 323 !! - the size of the dimension is less than 2 (the method assumes dimension has an afferent variable with values). 324 !! - the method can not retrieve the values of the afferent variable. 325 INTEGER, INTENT(in) :: fid 308 326 !! Id of the NetCDF file 309 INTEGER, INTENT(in) :: did 327 CHARACTER(len=NF90_MAX_NAME), INTENT(in) :: dn 328 !! Name of the dimension. 329 REAL(kind=8), INTENT(out), DIMENSION(:), ALLOCATABLE :: values 330 !! Values of the dimension 331 INTEGER, INTENT(out) :: ds 332 !! Size of __values__ 333 INTEGER, INTENT(out) :: did 310 334 !! Id of the NetCDF dimension 311 CHARACTER(len=*), INTENT(in) :: var312 !! Name of the related NetCDF variable313 REAL(kind=wp), INTENT(out), DIMENSION(:), ALLOCATABLE :: values314 !! Values of the dimension315 INTEGER, INTENT(out) :: ds316 !! Size of __values__317 335 LOGICAL :: ret 318 336 !! .true. if no error(s) occured, .false. otherwise 319 337 INTEGER :: vid,err 320 CHARACTER(len=NF90_MAX_NAME) :: dn321 338 CHARACTER(len=15) :: i2s 322 339 ret = .false. 323 340 ! --- Get dimension informations 324 IF (NF90_INQUIRE_DIMENSION(fid,did,dn,ds) /= NF90_NOERR) THEN 325 IF (debug) THEN 326 WRITE(i2s,*) did ; i2s=TRIM(i2s) 327 WRITE(*,'(a)') "ERROR:"//TRIM(var)//": Cannot find "// & 328 "dimension #"//TRIM(i2s)//" name" 329 ENDIF 330 err = NF90_CLOSE(fid) ; RETURN 331 ENDIF 332 IF (ds < 2) THEN 333 IF (debug) WRITE(*,'(a)') "ERROR:"//TRIM(dn)//": Invalid dimension "// & 334 "size (<2)" 335 err = NF90_CLOSE(fid) ; RETURN 336 ENDIF 337 IF (NF90_INQ_VARID(fid,TRIM(dn),vid) /= NF90_NOERR) THEN 338 IF (debug) WRITE(*,'(a)') "ERROR:"//TRIM(dn)//": Cannot get ID" 339 err = NF90_CLOSE(fid) ; RETURN 340 ENDIF 341 err = NF90_INQ_DIMID(fid,dn,did) 342 IF (err /= NF90_NOERR) RETURN 343 err = NF90_INQUIRE_DIMENSION(fid,did,len=ds) 344 IF (err /= NF90_NOERR) RETURN 345 IF (ds < 2) RETURN 346 err = NF90_INQ_VARID(fid,TRIM(dn),vid) 347 IF (err /= NF90_NOERR) RETURN 341 348 ALLOCATE(values(ds)) 342 IF (NF90_GET_VAR(fid,vid,values) /= NF90_NOERR) THEN 343 IF (debug) WRITE(*,'(a)') "ERROR:"//TRIM(dn)//": Cannot get values" 344 err = NF90_CLOSE(fid) ; RETURN 345 ENDIF 346 ret = .true. 347 END FUNCTION nc_get_dim 348 349 FUNCTION get_nc3_info(path,variable,ncid,vid,dimids) RESULT(ret) 349 err = NF90_GET_VAR(fid,vid,values) 350 IF (err /= NF90_NOERR) RETURN 351 ret = .true. 352 END FUNCTION nc_get_dim_by_name 353 354 FUNCTION nc_get_dim_by_id(fid,did,values,ds,dn) RESULT(ret) 355 !! Get informations about a dimension. 356 !! 357 !! The method gets the values and size of a given dimension. 358 !! 359 !! Errors occur if: 360 !! 361 !! - the given id is not a dimension identifier. 362 !! - the size of the dimension is less than 2 (the method assumes dimension has an afferent variable with values). 363 !! - the method can not retrieve the values of the afferent variable. 364 INTEGER, INTENT(in) :: fid 365 !! Id of the NetCDF file 366 INTEGER, INTENT(in) :: did 367 !! Id of the NetCDF dimension 368 REAL(kind=8), INTENT(out), DIMENSION(:), ALLOCATABLE :: values 369 !! Values of the dimension 370 INTEGER, INTENT(out) :: ds 371 !! Size of __values__ 372 CHARACTER(len=NF90_MAX_NAME), INTENT(out) :: dn 373 !! Name of the dimension. 374 LOGICAL :: ret 375 !! .true. if no error(s) occured, .false. otherwise 376 INTEGER :: vid,err 377 CHARACTER(len=15) :: i2s 378 ret = .false. 379 ! --- Get dimension informations 380 IF (NF90_INQUIRE_DIMENSION(fid,did,dn,ds) /= NF90_NOERR) RETURN 381 IF (ds < 2) RETURN 382 IF (NF90_INQ_VARID(fid,TRIM(dn),vid) /= NF90_NOERR) RETURN 383 ALLOCATE(values(ds)) 384 IF (NF90_GET_VAR(fid,vid,values) /= NF90_NOERR) RETURN 385 ret = .true. 386 END FUNCTION nc_get_dim_by_id 387 388 FUNCTION get_nc3_info(path,variable,ncid,vid,dimids,verbose) RESULT(ret) 350 389 !! Get variable informations from NetCDF file 351 390 !! … … 358 397 !! - variable's dimensions sizes 359 398 !! 360 !! If no error occured (i.e. the function has returned .true.) then the361 !! NetCDF file remains open. In other case, the file is closed.399 !! The method always opens and closes the file. If the file cannot be opened, 400 !! __ncid__ is set to -1. 362 401 CHARACTER(len=*), INTENT(in) :: path 363 402 !! Path of the NetCDF file … … 370 409 INTEGER, INTENT(out), DIMENSION(:), ALLOCATABLE :: dimids 371 410 !! Id of the variable's dimensions. __dimids__ is not allocated on error. 411 LOGICAL, INTENT(in), OPTIONAL :: verbose 412 !! True to print out message on error (default to False). 372 413 LOGICAL :: ret 373 414 !! .true. if no errors occured, .false. otherwise 374 415 INTEGER :: fid,ty,nc,err 375 ret = .false. 416 LOGICAL :: zlog 417 zlog = .false. ; IF (PRESENT(verbose)) zlog = verbose 418 ret = .false. 419 ncid = -1 376 420 ! Opens file 377 421 IF (NF90_OPEN(TRIM(path),NF90_NOWRITE,fid) /= NF90_NOERR) THEN 378 WRITE(*,'(a)') 'ERROR: Cannot open '//trim(path)422 IF (zlog) WRITE(*,'(a)') 'ERROR: Cannot open '//trim(path) 379 423 RETURN 380 424 ENDIF … … 382 426 ! Searches for variable 383 427 IF (NF90_INQ_VARID(ncid,TRIM(variable),vid) /= NF90_NOERR) THEN 384 WRITE(*,'(a)') 'Cannot find '//TRIM(variable)//' in '//trim(path)428 IF (zlog) WRITE(*,'(a)') 'Cannot find '//TRIM(variable)//' in '//trim(path) 385 429 nc = NF90_CLOSE(fid) 386 430 RETURN … … 389 433 ! 1st call to get type and number of dimensions) 390 434 IF (NF90_INQUIRE_VARIABLE(ncid,vid,xtype=ty,ndims=nc) /= NF90_NOERR) THEN 391 WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations'435 IF (zlog) WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations' 392 436 nc = NF90_CLOSE(fid) 393 437 RETURN … … 395 439 ! Checks type 396 440 IF (ty == NF90_CHAR) THEN 397 WRITE(*,'(a)') 'Inconsistent variable type (should be numeric)'441 IF (zlog) WRITE(*,'(a)') 'Inconsistent variable type (should be numeric)' 398 442 nc = NF90_CLOSE(fid) 399 443 RETURN … … 404 448 ! first get dimensions id 405 449 IF (NF90_INQUIRE_VARIABLE(ncid,vid,dimids=dimids) /= NF90_NOERR) THEN 406 WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations'450 IF (zlog) WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations' 407 451 nc = NF90_CLOSE(fid) 408 452 DEALLOCATE(dimids) 409 453 RETURN 410 454 ENDIF 455 nc = NF90_CLOSE(fid) 411 456 ret = .true. 412 457 END FUNCTION get_nc3_info 413 458 414 459 #if HAVE_NC4_FTN 415 FUNCTION get_nc4_info(path,variable,group,ncid,vid,dimids ) RESULT(ret)460 FUNCTION get_nc4_info(path,variable,group,ncid,vid,dimids,verbose) RESULT(ret) 416 461 !! Get variable informations from NetCDF4 file 417 462 !! … … 424 469 !! - variable's dimensions sizes 425 470 !! 426 !! If no error occured (i.e. the function has returned .true.) then the427 !! NetCDF file remains open. In other case, the file is closed.471 !! The method always opens and closes the file. If the file cannot be opened, 472 !! __ncid__ is set to -1. 428 473 CHARACTER(len=*), INTENT(in) :: path 429 474 !! Path of the NetCDF file … … 438 483 INTEGER, INTENT(out), DIMENSION(:), ALLOCATABLE :: dimids 439 484 !! Id of the variable's dimensions. On error, __dimids__ is not allocated. 485 LOGICAL, INTENT(in), OPTIONAL :: verbose 486 !! True to print out message on error (default to False). 440 487 LOGICAL :: ret 441 488 !! .true. if no errors occured, .false. otherwise 442 489 INTEGER :: fid,ty,nc,err 443 ret = .false. 490 LOGICAL :: zlog 491 zlog = .false. ; IF (PRESENT(verbose)) zlog = verbose 492 ret = .false. 493 ncid = -1 444 494 ! Opens file 445 495 IF (NF90_OPEN(TRIM(path),NF90_NOWRITE,fid) /= NF90_NOERR) THEN 446 WRITE(*,'(a)') 'ERROR: Cannot open '//trim(path)496 IF (zlog) WRITE(*,'(a)') 'ERROR: Cannot open '//trim(path) 447 497 RETURN 448 498 ENDIF … … 456 506 ! NF90_ENOGRP is missing from Netcdf-Fortran4.2 : its value=-125 457 507 CASE(-125) 458 WRITE(*,'(a)') TRIM(group)//' does not exist in '//TRIM(path)508 IF (zlog) WRITE(*,'(a)') TRIM(group)//' does not exist in '//TRIM(path) 459 509 nc = NF90_CLOSE(fid) ; RETURN 460 510 CASE(NF90_ENOTNC4,NF90_ESTRICTNC3) 461 WRITE(*,'(a)') TRIM(path)//' is not a NetCDF-4 file with "group" feature'511 IF (zlog) WRITE(*,'(a)') TRIM(path)//' is not a NetCDF-4 file with "group" feature' 462 512 nc = NF90_CLOSE(fid) ; RETURN 463 513 CASE(NF90_EHDFERR) 464 WRITE(*,'(a)') "Too bad, an HDF5 error has been reported..."514 IF (zlog) WRITE(*,'(a)') "Too bad, an HDF5 error has been reported..." 465 515 nc = NF90_CLOSE(fid) ; RETURN 466 516 END SELECT 467 517 ! Searches for variable 468 518 IF (NF90_INQ_VARID(ncid,TRIM(variable),vid) /= NF90_NOERR) THEN 469 WRITE(*,'(a)') 'Cannot find '//TRIM(variable)//' in '//trim(path)519 IF (zlog) WRITE(*,'(a)') 'Cannot find '//TRIM(variable)//' in '//trim(path) 470 520 nc = NF90_CLOSE(fid) 471 521 RETURN … … 474 524 ! 1st call to get type and number of dimensions) 475 525 IF (NF90_INQUIRE_VARIABLE(ncid,vid,xtype=ty,ndims=nc) /= NF90_NOERR) THEN 476 WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations'526 IF (zlog) WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations' 477 527 nc = NF90_CLOSE(fid) 478 528 RETURN … … 480 530 ! Checks type 481 531 IF (ty == NF90_CHAR) THEN 482 WRITE(*,'(a)') 'Inconsistent variable type (should be numeric)'532 IF (zlog) WRITE(*,'(a)') 'Inconsistent variable type (should be numeric)' 483 533 nc = NF90_CLOSE(fid) 484 534 RETURN … … 489 539 ! first get dimensions id 490 540 IF (NF90_INQUIRE_VARIABLE(ncid,vid,dimids=dimids) /= NF90_NOERR) THEN 491 WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations'541 IF (zlog) WRITE(*,'(a)') 'Cannot access to '//TRIM(variable)//' informations' 492 542 nc = NF90_CLOSE(fid) 493 543 DEALLOCATE(dimids) 494 544 RETURN 495 545 ENDIF 546 nc = NF90_CLOSE(fid) 496 547 ret = .true. 497 548 END FUNCTION get_nc4_info 498 549 #endif 499 #endif500 550 501 551 !------------------------- 502 552 ! NetCDF data file readers 503 553 !------------------------- 504 505 #if HAVE_NC_FTN506 507 554 508 555 FUNCTION ncdf_rd_1d(path,variable,set) RESULT(ret) … … 512 559 TYPE(DSET1D), INTENT(out) :: set !! Output dataset object 513 560 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 514 INTEGER :: fi,vi,nd 561 INTEGER :: fi,vi,nd,iret 515 562 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 516 563 CHARACTER(len=NF90_MAX_NAME) :: dn … … 521 568 ! --- Check NetCDF file info 522 569 IF (.NOT.get_nc_info(path,variable,fi,vi,di)) RETURN 570 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 523 571 ! --- Check dimension size 524 572 nd = SIZE(di) … … 533 581 ALLOCATE(ds(nd)) 534 582 ! ------ X coordinate 535 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN536 CALL clear_dset(set) ; RETURN583 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 584 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 537 585 ENDIF 538 586 ! --- Read data … … 543 591 ENDIF 544 592 nd = NF90_CLOSE(fi) 593 set%dname = variable 545 594 ret = .true. 546 595 RETURN … … 553 602 TYPE(DSET2D), INTENT(out) :: set !! Output dataset object 554 603 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 555 INTEGER :: fi,vi,nd 604 INTEGER :: fi,vi,nd,iret 556 605 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 557 606 CHARACTER(len=15) :: i2s … … 561 610 ! --- Check NetCDF file info 562 611 IF (.NOT.get_nc_info(path,variable,fi,vi,di)) RETURN 612 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 563 613 ! --- Check dimension size 564 614 nd = SIZE(di) … … 573 623 ALLOCATE(ds(nd)) 574 624 ! ------ X coordinate 575 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN576 CALL clear_dset(set) ; RETURN625 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 626 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 577 627 ENDIF 578 628 ! ------ Y coordinate 579 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN580 CALL clear_dset(set) ; RETURN629 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 630 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 581 631 ENDIF 582 632 ! --- Read data … … 587 637 ENDIF 588 638 nd = NF90_CLOSE(fi) 639 set%dname = variable 589 640 ret = .true. 590 641 RETURN … … 597 648 TYPE(DSET3D), INTENT(out) :: set !! Output dataset object 598 649 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 599 INTEGER :: fi,vi,nd 650 INTEGER :: fi,vi,nd,iret 600 651 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 601 652 CHARACTER(len=15) :: i2s … … 605 656 ! --- Check NetCDF file info 606 657 IF (.NOT.get_nc_info(path,variable,fi,vi,di)) RETURN 658 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 607 659 ! --- Check dimension size 608 660 nd = SIZE(di) … … 617 669 ALLOCATE(ds(nd)) 618 670 ! ------ X coordinate 619 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN620 CALL clear_dset(set) ; RETURN671 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 672 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 621 673 ENDIF 622 674 ! ------ Y coordinate 623 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN624 CALL clear_dset(set) ; RETURN675 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 676 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 625 677 ENDIF 626 678 ! ------ Z coordinate 627 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN628 CALL clear_dset(set) ; RETURN679 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 680 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 629 681 ENDIF 630 682 ! --- Read data … … 635 687 ENDIF 636 688 nd = NF90_CLOSE(fi) 689 set%dname = variable 637 690 ret = .true. 638 691 RETURN … … 645 698 TYPE(DSET4D), INTENT(out) :: set !! Output dataset object 646 699 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 647 INTEGER :: fi,vi,nd 700 INTEGER :: fi,vi,nd,iret 648 701 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 649 702 CHARACTER(len=15) :: i2s … … 653 706 ! --- Check NetCDF file info 654 707 IF (.NOT.get_nc_info(path,variable,fi,vi,di)) RETURN 708 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 655 709 ! --- Check dimension size 656 710 nd = SIZE(di) … … 665 719 ALLOCATE(ds(nd)) 666 720 ! ------ X coordinate 667 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN668 CALL clear_dset(set) ; RETURN721 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 722 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 669 723 ENDIF 670 724 ! ------ Y coordinate 671 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN672 CALL clear_dset(set) ; RETURN725 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 726 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 673 727 ENDIF 674 728 ! ------ Z coordinate 675 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN676 CALL clear_dset(set) ; RETURN729 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 730 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 677 731 ENDIF 678 732 ! ------ T coordinate 679 IF (.NOT.nc_get_dim (fi,di(4),variable,set%t,ds(4))) THEN680 CALL clear_dset(set) ; RETURN733 IF (.NOT.nc_get_dim_by_id(fi,di(4),set%t,ds(4),set%tname)) THEN 734 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 681 735 ENDIF 682 736 ! --- Read data … … 687 741 ENDIF 688 742 nd = NF90_CLOSE(fi) 743 set%dname = variable 689 744 ret = .true. 690 745 RETURN … … 697 752 TYPE(DSET5D), INTENT(out) :: set !! Output dataset object 698 753 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 699 INTEGER :: fi,vi,nd 754 INTEGER :: fi,vi,nd,iret 700 755 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 701 756 CHARACTER(len=15) :: i2s … … 705 760 ! --- Check NetCDF file info 706 761 IF (.NOT.get_nc_info(path,variable,fi,vi,di)) RETURN 762 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 707 763 ! --- Check dimension size 708 764 nd = SIZE(di) … … 717 773 ALLOCATE(ds(nd)) 718 774 ! ------ X coordinate 719 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN720 CALL clear_dset(set) ; RETURN775 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 776 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 721 777 ENDIF 722 778 ! ------ Y coordinate 723 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN724 CALL clear_dset(set) ; RETURN779 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 780 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 725 781 ENDIF 726 782 ! ------ Z coordinate 727 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN728 CALL clear_dset(set) ; RETURN783 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 784 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 729 785 ENDIF 730 786 ! ------ T coordinate 731 IF (.NOT.nc_get_dim (fi,di(4),variable,set%t,ds(4))) THEN732 CALL clear_dset(set) ; RETURN787 IF (.NOT.nc_get_dim_by_id(fi,di(4),set%t,ds(4),set%tname)) THEN 788 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 733 789 ENDIF 734 790 ! ------ W coordinate 735 IF (.NOT.nc_get_dim (fi,di(5),variable,set%w,ds(5))) THEN736 CALL clear_dset(set) ; RETURN791 IF (.NOT.nc_get_dim_by_id(fi,di(5),set%w,ds(5),set%wname)) THEN 792 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 737 793 ENDIF 738 794 ! --- Read data … … 743 799 ENDIF 744 800 nd = NF90_CLOSE(fi) 801 set%dname = variable 745 802 ret = .true. 746 803 RETURN … … 757 814 TYPE(DSET1D), INTENT(out) :: set !! Output dataset 758 815 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 759 INTEGER :: fi,vi,nd 816 INTEGER :: fi,vi,nd,iret 760 817 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 761 818 CHARACTER(len=NF90_MAX_NAME) :: dn … … 766 823 ! --- Check NetCDF file info 767 824 IF (.NOT.get_nc_info(path,group,variable,fi,vi,di)) RETURN 825 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 768 826 ! --- Check dimension size 769 827 nd = SIZE(di) … … 778 836 ALLOCATE(ds(nd)) 779 837 ! ------ X coordinate 780 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN781 CALL clear_dset(set) ; RETURN838 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 839 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 782 840 ENDIF 783 841 ! --- Read data … … 788 846 ENDIF 789 847 nd = NF90_CLOSE(fi) 848 set%dname = variable 790 849 ret = .true. 791 850 RETURN … … 799 858 TYPE(DSET2D), INTENT(out) :: set !! Output dataset 800 859 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 801 INTEGER :: fi,vi,nd 860 INTEGER :: fi,vi,nd,iret 802 861 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 803 862 CHARACTER(len=15) :: i2s … … 807 866 ! --- Check NetCDF file info 808 867 IF (.NOT.get_nc_info(path,group,variable,fi,vi,di)) rETURN 868 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 809 869 ! --- Check dimension size 810 870 nd = SIZE(di) … … 819 879 ALLOCATE(ds(nd)) 820 880 ! ------ X coordinate 821 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN822 CALL clear_dset(set) ; RETURN881 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 882 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 823 883 ENDIF 824 884 ! ------ Y coordinate 825 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN826 CALL clear_dset(set) ; RETURN885 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 886 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 827 887 ENDIF 828 888 ! --- Read data … … 833 893 ENDIF 834 894 nd = NF90_CLOSE(fi) 895 set%dname = variable 835 896 ret = .true. 836 897 RETURN … … 844 905 TYPE(DSET3D), INTENT(out) :: set !! Output dataset 845 906 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 846 INTEGER :: fi,vi,nd 907 INTEGER :: fi,vi,nd,iret 847 908 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 848 909 CHARACTER(len=15) :: i2s … … 852 913 ! --- Check NetCDF file info 853 914 IF (.NOT.get_nc_info(path,group,variable,fi,vi,di)) RETURN 915 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 854 916 ! --- Check dimension size 855 917 nd = SIZE(di) … … 864 926 ALLOCATE(ds(nd)) 865 927 ! ------ X coordinate 866 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN867 CALL clear_dset(set) ; RETURN928 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 929 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 868 930 ENDIF 869 931 ! ------ Y coordinate 870 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN871 CALL clear_dset(set) ; RETURN932 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 933 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 872 934 ENDIF 873 935 ! ------ Z coordinate 874 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN875 CALL clear_dset(set) ; RETURN936 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 937 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 876 938 ENDIF 877 939 ! --- Read data … … 882 944 ENDIF 883 945 nd = NF90_CLOSE(fi) 946 set%dname = variable 884 947 ret = .true. 885 948 RETURN … … 893 956 TYPE(DSET4D), INTENT(out) :: set !! Output dataset 894 957 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 895 INTEGER :: fi,vi,nd 958 INTEGER :: fi,vi,nd,iret 896 959 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 897 960 CHARACTER(len=15) :: i2s … … 901 964 ! --- Check NetCDF file info 902 965 IF (.NOT.get_nc_info(path,group,variable,fi,vi,di)) RETURN 966 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 903 967 ! --- Check dimension size 904 968 nd = SIZE(di) … … 913 977 ALLOCATE(ds(nd)) 914 978 ! ------ X coordinate 915 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN916 CALL clear_dset(set) ; RETURN979 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 980 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 917 981 ENDIF 918 982 ! ------ Y coordinate 919 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN920 CALL clear_dset(set) ; RETURN983 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 984 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 921 985 ENDIF 922 986 ! ------ Z coordinate 923 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN924 CALL clear_dset(set) ; RETURN987 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 988 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 925 989 ENDIF 926 990 ! ------ T coordinate 927 IF (.NOT.nc_get_dim (fi,di(4),variable,set%t,ds(4))) THEN928 CALL clear_dset(set) ; RETURN991 IF (.NOT.nc_get_dim_by_id(fi,di(4),set%t,ds(4),set%tname)) THEN 992 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 929 993 ENDIF 930 994 ! --- Read data … … 935 999 ENDIF 936 1000 nd = NF90_CLOSE(fi) 1001 set%dname = variable 937 1002 ret = .true. 938 1003 RETURN … … 946 1011 TYPE(DSET5D), INTENT(out) :: set !! Output dataset 947 1012 LOGICAL :: ret !! .true. if no errors occured, .false. otherwise 948 INTEGER :: fi,vi,nd 1013 INTEGER :: fi,vi,nd,iret 949 1014 INTEGER, DIMENSION(:), ALLOCATABLE :: di,ds 950 1015 CHARACTER(len=15) :: i2s … … 954 1019 ! --- Check NetCDF file info 955 1020 IF (.NOT.get_nc_info(path,group,variable,fi,vi,di)) RETURN 1021 iret = NF90_OPEN(path,NF90_NOWRITE,fi) 956 1022 ! --- Check dimension size 957 1023 nd = SIZE(di) … … 966 1032 ALLOCATE(ds(nd)) 967 1033 ! ------ X coordinate 968 IF (.NOT.nc_get_dim (fi,di(1),variable,set%x,ds(1))) THEN969 CALL clear_dset(set) ; RETURN1034 IF (.NOT.nc_get_dim_by_id(fi,di(1),set%x,ds(1),set%xname)) THEN 1035 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 970 1036 ENDIF 971 1037 ! ------ Y coordinate 972 IF (.NOT.nc_get_dim (fi,di(2),variable,set%y,ds(2))) THEN973 CALL clear_dset(set) ; RETURN1038 IF (.NOT.nc_get_dim_by_id(fi,di(2),set%y,ds(2),set%yname)) THEN 1039 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 974 1040 ENDIF 975 1041 ! ------ Z coordinate 976 IF (.NOT.nc_get_dim (fi,di(3),variable,set%z,ds(3))) THEN977 CALL clear_dset(set) ; RETURN1042 IF (.NOT.nc_get_dim_by_id(fi,di(3),set%z,ds(3),set%zname)) THEN 1043 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 978 1044 ENDIF 979 1045 ! ------ T coordinate 980 IF (.NOT.nc_get_dim (fi,di(4),variable,set%t,ds(4))) THEN981 CALL clear_dset(set) ; RETURN1046 IF (.NOT.nc_get_dim_by_id(fi,di(4),set%t,ds(4),set%tname)) THEN 1047 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 982 1048 ENDIF 983 1049 ! ------ W coordinate 984 IF (.NOT.nc_get_dim(fi,di(5),variable,set%w,ds(5))) THEN 1050 IF (.NOT.nc_get_dim_by_id(fi,di(5),set%w,ds(5),set%wname)) THEN 1051 nd = NF90_CLOSE(fi) ; CALL clear_dset(set) ; RETURN 985 1052 CALL clear_dset(set) ; RETURN 986 1053 ENDIF … … 992 1059 ENDIF 993 1060 nd = NF90_CLOSE(fi) 1061 set%dname = variable 994 1062 ret = .true. 995 1063 RETURN 996 1064 END FUNCTION ncdf4_rd_5d 997 #endif998 1065 #endif 999 1066 … … 1007 1074 TYPE(dset1d), INTENT(out) :: set !! output 1D dataset 1008 1075 LOGICAL :: ret !! .true. if no error occured, .false. otherwise 1009 INTEGER 1010 REAL(kind= wp), DIMENSION(2) :: vl1011 INTEGER, DIMENSION(1) 1076 INTEGER :: i,e 1077 REAL(kind=8), DIMENSION(2) :: vl 1078 INTEGER, DIMENSION(1) :: cc,ds,dp 1012 1079 ret = .false. 1013 1080 CALL clear_dset(set) … … 1037 1104 TYPE(dset2d), INTENT(out) :: set !! output 2D dataset 1038 1105 LOGICAL :: ret !! .true. if no error occured, .false. otherwise 1039 INTEGER 1040 REAL(kind= wp), DIMENSION(3) :: vl1041 INTEGER, DIMENSION(2) 1106 INTEGER :: i,e 1107 REAL(kind=8), DIMENSION(3) :: vl 1108 INTEGER, DIMENSION(2) :: cc,ds,dp 1042 1109 ret = .false. 1043 1110 CALL clear_dset(set) … … 1077 1144 TYPE(dset3d), INTENT(out) :: set !! output 3D dataset 1078 1145 LOGICAL :: ret !! .true. if no error occured, .false. otherwise 1079 INTEGER 1080 REAL(kind= wp), DIMENSION(4) :: vl1081 INTEGER, DIMENSION(3) 1146 INTEGER :: i,e 1147 REAL(kind=8), DIMENSION(4) :: vl 1148 INTEGER, DIMENSION(3) :: cc,ds,dp 1082 1149 ret = .false. 1083 1150 CALL clear_dset(set) … … 1120 1187 TYPE(dset4d), INTENT(out) :: set !! output 4D dataset 1121 1188 LOGICAL :: ret !! .true. if no error occured, .false. otherwise 1122 INTEGER 1123 REAL(kind= wp), DIMENSION(5) :: vl1124 INTEGER, DIMENSION(4) 1189 INTEGER :: i,e 1190 REAL(kind=8), DIMENSION(5) :: vl 1191 INTEGER, DIMENSION(4) :: cc,ds,dp 1125 1192 ret = .false. 1126 1193 CALL clear_dset(set) … … 1166 1233 TYPE(dset5d), INTENT(out) :: set !! output 5D dataset 1167 1234 LOGICAL :: ret !! .true. if no error occured, .false. otherwise 1168 INTEGER 1169 REAL(kind= wp), DIMENSION(6) :: vl1170 INTEGER, DIMENSION(5) 1235 INTEGER :: i,e 1236 REAL(kind=8), DIMENSION(6) :: vl 1237 INTEGER, DIMENSION(5) :: cc,ds,dp 1171 1238 ret = .false. 1172 1239 CALL clear_dset(set) … … 1260 1327 END SUBROUTINE clr_5d_set 1261 1328 1329 FUNCTION has_d_1d(dset) RESULT(yes) 1330 !! Check whether or not the dataset has data. 1331 TYPE(DSET1D), INTENT(in) :: dset !! Dataset to check 1332 LOGICAL :: yes !! return status 1333 yes = (ALLOCATED(dset%data).AND. & 1334 ALLOCATED(dset%x)) 1335 END FUNCTION has_d_1d 1336 1337 FUNCTION has_d_2d(dset) RESULT(yes) 1338 !! Check whether or not the dataset has data. 1339 TYPE(DSET2D), INTENT(in) :: dset !! Dataset to check 1340 LOGICAL :: yes !! return status 1341 yes = (ALLOCATED(dset%data).AND. & 1342 ALLOCATED(dset%x) .AND. & 1343 ALLOCATED(dset%y)) 1344 END FUNCTION has_d_2d 1345 1346 FUNCTION has_d_3d(dset) RESULT(yes) 1347 !! Check whether or not the dataset has data. 1348 TYPE(DSET3D), INTENT(in) :: dset !! Dataset to check 1349 LOGICAL :: yes !! return status 1350 yes = (ALLOCATED(dset%data).AND. & 1351 ALLOCATED(dset%x) .AND. & 1352 ALLOCATED(dset%y) .AND. & 1353 ALLOCATED(dset%z)) 1354 END FUNCTION has_d_3d 1355 1356 FUNCTION has_d_4d(dset) RESULT(yes) 1357 !! Check whether or not the dataset has data. 1358 TYPE(DSET4D), INTENT(in) :: dset !! Dataset to check 1359 LOGICAL :: yes !! return status 1360 yes = (ALLOCATED(dset%data).AND. & 1361 ALLOCATED(dset%x) .AND. & 1362 ALLOCATED(dset%y) .AND. & 1363 ALLOCATED(dset%z) .AND. & 1364 ALLOCATED(dset%t)) 1365 END FUNCTION has_d_4d 1366 1367 FUNCTION has_d_5d(dset) RESULt(yes) 1368 !! Check whether or not the dataset has data. 1369 TYPE(DSET5D), INTENT(in) :: dset !! Dataset to check 1370 LOGICAL :: yes !! return status 1371 yes = (ALLOCATED(dset%data).AND. & 1372 ALLOCATED(dset%x) .AND. & 1373 ALLOCATED(dset%y) .AND. & 1374 ALLOCATED(dset%z) .AND. & 1375 ALLOCATED(dset%t) .AND. & 1376 ALLOCATED(dset%w)) 1377 END FUNCTION has_d_5d 1378 1379 FUNCTION nc_wr_1d(path,dset) RESULT(ret) 1380 CHARACTER(len=*), INTENT(in) :: path !! Path of the netcdf file. 1381 TYPE(DSET1D), INTENT(in) :: dset !! Dataset to write 1382 LOGICAL :: ret !! Return status 1383 INTEGER :: fi,vi,nd,ds,iret 1384 INTEGER, DIMENSION(:), ALLOCATABLE :: di 1385 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tv 1386 CHARACTER(len=15) :: i2s 1387 LOGICAL :: hxd,ok 1388 INTEGER :: xid,vid 1389 ret = has_data(dset) 1390 IF (.NOT.ret) RETURN 1391 ret = .false. 1392 INQUIRE(FILE=TRIM(path),EXIST=ok) 1393 IF (ok) THEN 1394 IF (NF90_OPEN(TRIM(path), NF90_WRITE, fi) /= NF90_NOERR) RETURN 1395 ELSE 1396 IF (NF90_CREATE(TRIM(path), NF90_NOCLOBBER, fi) /= NF90_NOERR) RETURN 1397 ENDIF 1398 iret = NF90_CLOSE(fi) 1399 ! if variable already exist: get out of here ! 1400 IF (get_nc_info(path,dset%dname,fi,vi,di)) RETURN 1401 1402 iret = NF90_OPEN(path,NF90_WRITE,fi) 1403 1404 hxd = nc_get_dim_by_name(fi,dset%xname,tv,ds,xid) 1405 IF (hxd) THEN 1406 IF(.NOT.compare(dset%x,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1407 ENDIF 1408 1409 IF (.NOT.hxd) THEN 1410 ret = nc_set_dim(fi,dset%xname,dset%x,xid) 1411 IF (.NOT.ret) THEN ; iret= NF90_CLOSE(fi) ; RETURN ; ENDIF 1412 ENDIF 1413 ret = .false. 1414 iret = nf90_redef(fi) 1415 iret = nf90_def_var(fi, TRIM(dset%dname), nf90_double,(/xid/),vid) 1416 IF (iret /= 0) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1417 iret = nf90_enddef(fi) 1418 iret = nf90_put_var(fi,vid,dset%data) 1419 ret = (iret == 0) 1420 iret=NF90_CLOSE(fi) 1421 ret = .true. 1422 RETURN 1423 END FUNCTION nc_wr_1d 1424 1425 FUNCTION nc_wr_2d(path,dset) RESULT(ret) 1426 CHARACTER(len=*), INTENT(in) :: path !! Path of the netcdf file. 1427 TYPE(DSET2D), INTENT(in) :: dset !! Dataset to write 1428 LOGICAL :: ret !! Return status 1429 INTEGER :: fi,vi,nd,ds,iret,nferr 1430 INTEGER, DIMENSION(:), ALLOCATABLE :: di 1431 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tv 1432 CHARACTER(len=15) :: i2s 1433 LOGICAL :: hxd,hyd,ok 1434 INTEGER :: xid,yid,vid 1435 ret = has_data(dset) 1436 IF (.NOT.ret) RETURN 1437 ret = .false. 1438 INQUIRE(FILE=TRIM(path),EXIST=ok) 1439 IF (ok) THEN 1440 IF (NF90_OPEN(TRIM(path), NF90_WRITE, fi) /= NF90_NOERR) RETURN 1441 ELSE 1442 IF (NF90_CREATE(TRIM(path), NF90_NOCLOBBER, fi) /= NF90_NOERR) RETURN 1443 ENDIF 1444 iret = NF90_CLOSE(fi) 1445 1446 ! if variable already exist: get out of here ! 1447 IF (get_nc_info(path,dset%dname,fi,vi,di)) RETURN 1448 1449 iret = NF90_OPEN(path,NF90_WRITE,fi) 1450 1451 hxd = nc_get_dim_by_name(fi,dset%xname,tv,ds,xid) 1452 IF (hxd) THEN 1453 IF(.NOT.compare(dset%x,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1454 ENDIF 1455 hyd = nc_get_dim_by_name(fi,dset%yname,tv,ds,yid) 1456 IF (hyd) THEN 1457 IF(.NOT.compare(dset%y,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1458 ENDIF 1459 1460 IF (.NOT.hxd) THEN 1461 ret = nc_set_dim(fi,dset%xname,dset%x,xid) 1462 IF (.NOT.ret) THEN ; iret= NF90_CLOSE(fi) ; RETURN ; ENDIF 1463 ENDIF 1464 IF (.NOT.hyd) THEN 1465 ret = nc_set_dim(fi,dset%yname,dset%y,yid) 1466 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1467 ENDIF 1468 ret = .false. 1469 iret = nf90_redef(fi) 1470 iret = nf90_def_var(fi, TRIM(dset%dname), nf90_double,(/xid,yid/),vid) 1471 IF (iret /= 0) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1472 iret = nf90_enddef(fi) 1473 iret = nf90_put_var(fi,vid,dset%data) 1474 ret = (iret == 0) 1475 iret=NF90_CLOSE(fi) 1476 ret = .true. 1477 RETURN 1478 END FUNCTION nc_wr_2d 1479 1480 FUNCTION nc_wr_3d(path,dset) RESULT(ret) 1481 CHARACTER(len=*), INTENT(in) :: path !! Path of the netcdf file. 1482 TYPE(DSET3D), INTENT(in) :: dset !! Dataset to write 1483 LOGICAL :: ret !! Return status 1484 INTEGER :: fi,vi,nd,ds,iret 1485 INTEGER, DIMENSION(:), ALLOCATABLE :: di 1486 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tv 1487 CHARACTER(len=15) :: i2s 1488 LOGICAL :: hxd,hyd,hzd,ok 1489 INTEGER :: xid,yid,zid,vid 1490 ret = has_data(dset) 1491 IF (.NOT.ret) RETURN 1492 ret = .false. 1493 INQUIRE(FILE=TRIM(path),EXIST=ok) 1494 IF (ok) THEN 1495 IF (NF90_OPEN(TRIM(path), NF90_WRITE, fi) /= NF90_NOERR) RETURN 1496 ELSE 1497 IF (NF90_CREATE(TRIM(path), NF90_NOCLOBBER, fi) /= NF90_NOERR) RETURN 1498 ENDIF 1499 iret = NF90_CLOSE(fi) 1500 1501 ! if variable already exist: get out of here ! 1502 IF (get_nc_info(path,dset%dname,fi,vi,di)) RETURN 1503 1504 iret = NF90_OPEN(path,NF90_WRITE,fi) 1505 1506 hxd = nc_get_dim_by_name(fi,dset%xname,tv,ds,xid) 1507 IF (hxd) THEN 1508 IF(.NOT.compare(dset%x,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1509 ENDIF 1510 hyd = nc_get_dim_by_name(fi,dset%yname,tv,ds,yid) 1511 IF (hyd) THEN 1512 IF(.NOT.compare(dset%y,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1513 ENDIF 1514 hzd = nc_get_dim_by_name(fi,dset%zname,tv,ds,zid) 1515 IF (hzd) THEN 1516 IF(.NOT.compare(dset%z,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1517 ENDIF 1518 1519 IF (.NOT.hxd) THEN 1520 ret = nc_set_dim(fi,dset%xname,dset%x,xid) 1521 IF (.NOT.ret) THEN ; iret= NF90_CLOSE(fi) ; RETURN ; ENDIF 1522 ENDIF 1523 IF (.NOT.hyd) THEN 1524 ret = nc_set_dim(fi,dset%yname,dset%y,yid) 1525 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1526 ENDIF 1527 IF (.NOT.hzd) THEN 1528 ret = nc_set_dim(fi,dset%zname,dset%z,zid) 1529 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1530 ENDIF 1531 ret = .false. 1532 iret = nf90_redef(fi) 1533 iret = nf90_def_var(fi, TRIM(dset%dname), nf90_double,(/xid,yid,zid/),vid) 1534 IF (iret /= 0) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1535 iret = nf90_enddef(fi) 1536 iret = nf90_put_var(fi,vid,dset%data) 1537 ret = (iret == 0) 1538 iret=NF90_CLOSE(fi) 1539 ret = .true. 1540 RETURN 1541 END FUNCTION nc_wr_3d 1542 1543 FUNCTION nc_wr_4d(path,dset) RESULT(ret) 1544 CHARACTER(len=*), INTENT(in) :: path !! Path of the netcdf file. 1545 TYPE(DSET4D), INTENT(in) :: dset !! Dataset to write 1546 LOGICAL :: ret !! Return status 1547 INTEGER :: fi,vi,nd,ds,iret 1548 INTEGER, DIMENSION(:), ALLOCATABLE :: di 1549 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tv 1550 CHARACTER(len=15) :: i2s 1551 LOGICAL :: hxd,hyd,hzd,htd,ok 1552 INTEGER :: xid,yid,zid,tid,vid 1553 ret = has_data(dset) 1554 IF (.NOT.ret) RETURN 1555 ret = .false. 1556 INQUIRE(FILE=TRIM(path),EXIST=ok) 1557 IF (ok) THEN 1558 IF (NF90_OPEN(TRIM(path), NF90_WRITE, fi) /= NF90_NOERR) RETURN 1559 ELSE 1560 IF (NF90_CREATE(TRIM(path), NF90_NOCLOBBER, fi) /= NF90_NOERR) RETURN 1561 ENDIF 1562 iret = NF90_CLOSE(fi) 1563 1564 ! if variable already exist: get out of here ! 1565 IF (get_nc_info(path,dset%dname,fi,vi,di)) RETURN 1566 1567 iret = NF90_OPEN(path,NF90_WRITE,fi) 1568 1569 hxd = nc_get_dim_by_name(fi,dset%xname,tv,ds,xid) 1570 IF (hxd) THEN 1571 IF(.NOT.compare(dset%x,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1572 ENDIF 1573 hyd = nc_get_dim_by_name(fi,dset%yname,tv,ds,yid) 1574 IF (hyd) THEN 1575 IF(.NOT.compare(dset%y,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1576 ENDIF 1577 hzd = nc_get_dim_by_name(fi,dset%zname,tv,ds,zid) 1578 IF (hzd) THEN 1579 IF(.NOT.compare(dset%z,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1580 ENDIF 1581 htd = nc_get_dim_by_name(fi,dset%tname,tv,ds,tid) 1582 IF (htd) THEN 1583 IF(.NOT.compare(dset%t,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1584 ENDIF 1585 1586 IF (.NOT.hxd) THEN 1587 ret = nc_set_dim(fi,dset%xname,dset%x,xid) 1588 IF (.NOT.ret) THEN ; iret= NF90_CLOSE(fi) ; RETURN ; ENDIF 1589 ENDIF 1590 IF (.NOT.hyd) THEN 1591 ret = nc_set_dim(fi,dset%yname,dset%y,yid) 1592 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1593 ENDIF 1594 IF (.NOT.hzd) THEN 1595 ret = nc_set_dim(fi,dset%zname,dset%z,zid) 1596 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1597 ENDIF 1598 IF (.NOT.htd) THEN 1599 ret = nc_set_dim(fi,dset%tname,dset%t,tid) 1600 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1601 ENDIF 1602 ret = .false. 1603 iret = nf90_redef(fi) 1604 iret = nf90_def_var(fi, TRIM(dset%dname), nf90_double,(/xid,yid,zid,tid/),vid) 1605 IF (iret /= 0) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1606 iret = nf90_enddef(fi) 1607 iret = nf90_put_var(fi,vid,dset%data) 1608 ret = (iret == 0) 1609 iret=NF90_CLOSE(fi) 1610 ret = .true. 1611 RETURN 1612 END FUNCTION nc_wr_4d 1613 1614 FUNCTION nc_wr_5d(path,dset) RESULT(ret) 1615 CHARACTER(len=*), INTENT(in) :: path !! Path of the netcdf file. 1616 TYPE(DSET5D), INTENT(in) :: dset !! Dataset to write 1617 LOGICAL :: ret !! Return status 1618 INTEGER :: fi,vi,nd,ds,iret 1619 INTEGER, DIMENSION(:), ALLOCATABLE :: di 1620 REAL(kind=8), DIMENSION(:), ALLOCATABLE :: tv 1621 CHARACTER(len=15) :: i2s 1622 LOGICAL :: hxd,hyd,hzd,htd,hwd,ok 1623 INTEGER :: xid,yid,zid,tid,wid,vid 1624 ret = has_data(dset) 1625 IF (.NOT.ret) RETURN 1626 ret = .false. 1627 INQUIRE(FILE=TRIM(path),EXIST=ok) 1628 IF (ok) THEN 1629 IF (NF90_OPEN(TRIM(path), NF90_WRITE, fi) /= NF90_NOERR) RETURN 1630 ELSE 1631 IF (NF90_CREATE(TRIM(path), NF90_NOCLOBBER, fi) /= NF90_NOERR) RETURN 1632 ENDIF 1633 iret = NF90_CLOSE(fi) 1634 1635 ! if variable already exist: get out of here ! 1636 IF (get_nc_info(path,dset%dname,fi,vi,di)) RETURN 1637 1638 iret = NF90_OPEN(path,NF90_WRITE,fi) 1639 1640 hxd = nc_get_dim_by_name(fi,dset%xname,tv,ds,xid) 1641 IF (hxd) THEN 1642 IF(.NOT.compare(dset%x,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1643 ENDIF 1644 hyd = nc_get_dim_by_name(fi,dset%yname,tv,ds,yid) 1645 IF (hyd) THEN 1646 IF(.NOT.compare(dset%y,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1647 ENDIF 1648 hzd = nc_get_dim_by_name(fi,dset%zname,tv,ds,zid) 1649 IF (hzd) THEN 1650 IF(.NOT.compare(dset%z,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1651 ENDIF 1652 htd = nc_get_dim_by_name(fi,dset%tname,tv,ds,tid) 1653 IF (htd) THEN 1654 IF(.NOT.compare(dset%t,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1655 ENDIF 1656 hwd = nc_get_dim_by_name(fi,dset%wname,tv,ds,wid) 1657 IF (hwd) THEN 1658 IF (.NOT.compare(dset%w,tv)) THEN ; ret = .false. ; RETURN ; ENDIF 1659 ENDIF 1660 1661 IF (.NOT.hxd) THEN 1662 ret = nc_set_dim(fi,dset%xname,dset%x,xid) 1663 IF (.NOT.ret) THEN ; iret= NF90_CLOSE(fi) ; RETURN ; ENDIF 1664 ENDIF 1665 IF (.NOT.hyd) THEN 1666 ret = nc_set_dim(fi,dset%yname,dset%y,yid) 1667 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1668 ENDIF 1669 IF (.NOT.hzd) THEN 1670 ret = nc_set_dim(fi,dset%zname,dset%z,zid) 1671 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1672 ENDIF 1673 IF (.NOT.htd) THEN 1674 ret = nc_set_dim(fi,dset%tname,dset%t,tid) 1675 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1676 ENDIF 1677 IF (.NOT.hwd) THEN 1678 ret = nc_set_dim(fi,dset%wname,dset%w,wid) 1679 IF (.NOT.ret) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1680 ENDIF 1681 ret = .false. 1682 iret = nf90_redef(fi) 1683 iret = nf90_def_var(fi, TRIM(dset%dname), nf90_double,(/xid,yid,zid,tid,wid/),vid) 1684 IF (iret /= 0) THEN ; iret = NF90_CLOSE(fi) ; RETURN ; ENDIF 1685 iret = nf90_enddef(fi) 1686 iret = nf90_put_var(fi,vid,dset%data) 1687 ret = (iret == 0) 1688 iret=NF90_CLOSE(fi) 1689 ret = .true. 1690 RETURN 1691 END FUNCTION nc_wr_5d 1692 1693 FUNCTION nc_set_dim(fid,name,values,dimid) RESULT(ret) 1694 !! Set a new dimension (and its associated values) in a NetCDF file. 1695 INTEGER, INTENT(in) :: fid !! Netcdf file id. 1696 CHARACTER(len=*), INTENT(in) :: name !! Name of the dimension to set. 1697 REAL(kind=8), DIMENSION(:), INTENT(in) :: values !! Associated values. 1698 INTEGER, INTENT(out) :: dimid !! Output dimension id. 1699 LOGICAL :: ret !! Return status 1700 INTEGER :: iret,vid 1701 ret = .false. 1702 iret = nf90_redef(fid) 1703 iret = nf90_def_dim(fid, TRIM(name), size(values), dimid) 1704 WRITE(*,'(a)') "nc_set_dim: "//TRIM(name)//" --> "//TRIM(nf90_strerror(iret)) 1705 IF (iret /=0) RETURN 1706 iret = nf90_def_var(fid, TRIM(name), nf90_double,(/dimid/),vid) 1707 IF (iret /=0) RETURN 1708 iret = nf90_enddef(fid) 1709 iret = nf90_put_var(fid, vid,values) 1710 ret = .true. 1711 END FUNCTION nc_set_dim 1712 1713 FUNCTION compare(vec1,vec2,tol) RESULT(ret) 1714 !! Compare two vector of double. 1715 !! 1716 !! The test is checked against the difference (element wise) of the two vector compared to 1717 !! to a given tolerance. 1718 REAL(kind=8), DIMENSION(:), INTENT(in) :: vec1 !! First vector to compare 1719 REAL(kind=8), DIMENSION(:), INTENT(in) :: vec2 !! Second vector to compare 1720 REAL(kind=8), INTENT(in), OPTIONAL :: tol !! Tolerance to apply for the comparison 1721 LOGICAL :: ret !! .true. if both vectors are equal, .false. otherwise. 1722 REAL(kind=8) :: ztol 1723 INTEGER :: i 1724 ztol = 1d-10 ; IF (PRESENT(tol)) ztol = abs(tol) 1725 ret = .false. 1726 IF (size(vec1) /= size(vec2)) RETURN 1727 1728 DO i=1,size(vec1) ; IF (abs(vec1(i)-vec2(i)) > ztol) RETURN ; ENDDO 1729 ret = .true. 1730 END FUNCTION compare 1731 1732 1733 1262 1734 END MODULE DATASETS -
trunk/LMDZ.TITAN/libf/muphytitan/defined.h
r1793 r1897 1 /* Copyright Jérémie Burgalat (2010-2015 )1 /* Copyright Jérémie Burgalat (2010-2015,2017) 2 2 * 3 * burgalat.jeremie@gmail.com3 * jeremie.burgalat@univ-reims.fr 4 4 * 5 5 * This software is a computer program whose purpose is to provide configuration … … 76 76 /* Defines SSLEN if needed */ 77 77 #ifndef SSLEN 78 #define SSLEN 2 0078 #define SSLEN 250 79 79 #endif 80 80 81 81 /* Defines SLLEN if needed */ 82 82 #ifndef SLLEN 83 #define SLLEN 2 00083 #define SLLEN 2500 84 84 #endif -
trunk/LMDZ.TITAN/libf/muphytitan/errors.F90
r1814 r1897 1 ! Copyright Jérémie Burgalat (2010-2015 )2 ! 3 ! burgalat.jeremie@gmail.com1 ! Copyright Jérémie Burgalat (2010-2015,2017) 2 ! 3 ! jeremie.burgalat@univ-reims.fr 4 4 ! 5 5 ! This software is a computer program whose purpose is to provide configuration … … 33 33 34 34 !! file: errors.F90 35 !! summary: Errors handling source file 36 !! author: Burgalat37 !! date: 2013-2015 35 !! summary: Errors handling source file. 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 38 38 39 39 #include "defined.h" … … 84 84 CONTAINS 85 85 PROCEDURE, PUBLIC :: to_string => error_to_string 86 !! Get a string representation of the error 86 87 #endif 87 88 END TYPE error … … 201 202 IF (err /= 0) THEN 202 203 WRITE(*,'(a)') error_to_string(err) 203 CALL EXIT( abs(err%id))204 CALL EXIT(err%id) 204 205 ENDIF 205 206 END SUBROUTINE aborting … … 229 230 !! The method raises an assertion and stops the execution if __test__ is .false. 230 231 !! 231 !! See [[errors(module):assert_r(subroutine)] remark.232 !! See [[errors(module):assert_r(subroutine)]] remark. 232 233 LOGICAL, INTENT(in) :: test 233 234 !! Expression to test. … … 242 243 END SUBROUTINE assert_w 243 244 245 FUNCTION free_lun() RESULT(lu) 246 !> Get the first free logical unit 247 !! 248 !! The function loops from 7 to 9999 and returns the first free logical unit. 249 !! @note 250 !! According to Fortran standard, the maximum value for a lun is processor 251 !! dependent. I just assume that [7,9999] is a valid range and I believe that 252 !! 9992 files to be opened is far enough for any program ! 253 !! @note 254 !! If you intend to use loggers object from this library, you should keep in 255 !! mind that loggers open files with the first free logical unit. Consequently 256 !! if you need to perform I/O operations you should use this function to get a 257 !! free lun instead of just randomly set a lun ! 258 INTEGER :: lu 259 !! First free logical unit in the range [7,9999] or -1 if no lun is available 260 INTEGER, PARAMETER :: mxlu = 9999 261 LOGICAL :: notfree 262 lu = 6 ; notfree = .true. 263 DO WHILE(notfree.AND.lu<=mxlu) 264 lu=lu+1 ; INQUIRE(unit=lu,OPENED=notfree) 265 ENDDO 266 IF (lu >= mxlu) lu = -1 267 END FUNCTION free_lun 268 269 244 270 245 271 END MODULE ERRORS -
trunk/LMDZ.TITAN/libf/muphytitan/fsystem.F90
r1793 r1897 1 ! Copyright Jérémie Burgalat (2010-2015 )1 ! Copyright Jérémie Burgalat (2010-2015,2017) 2 2 ! 3 ! burgalat.jeremie@gmail.com3 ! jeremie.burgalat@univ-reims.fr 4 4 ! 5 5 ! This software is a computer program whose purpose is to provide configuration … … 33 33 34 34 !! file: fsystem.F90 35 !! summary: File system methods source file 36 !! date: 2013-2015 37 !! author: Burgalat 35 !! summary: File system methods source file. 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 38 38 39 39 40 #include "defined.h" … … 48 49 49 50 PRIVATE :: get_umask 51 PRIVATE :: c2t 50 52 51 53 INTEGER, PARAMETER :: MAX_PATH = 512 !! Maximum length of a path 52 54 53 55 TYPE, PUBLIC :: chrono 56 !! Define a simple chronometer 57 !! 58 !! This object can be used to get an approximation of the execution of some piece of code. 59 REAL(kind=8), PRIVATE :: cpu_start = 0d0 60 !! Starting CPU time 61 INTEGER(kind=8), PRIVATE :: clock_start = 0d0 62 !! Starting clock time 63 LOGICAL, PRIVATE :: on_run = .false. 64 !! Chrono running state. 65 #if HAVE_FTNPROC 66 CONTAINS 67 PROCEDURE :: is_running => chrono_is_running 68 PROCEDURE :: start => chrono_start 69 PROCEDURE :: stop => chrono_stop 70 PROCEDURE :: reset => chrono_reset 71 PROCEDURE :: get => chrono_get 72 #endif 73 END TYPE chrono 74 75 #ifndef FORD_DOC 76 ! C interfaces 54 77 INTERFACE 55 56 78 FUNCTION strlen_c(s) RESULT(length) bind(C,name="strlen") 57 79 !! Get length of C-string up to (but not including) the terminator … … 68 90 69 91 FUNCTION errno_c() BIND(C,name="c_get_errno") 70 !! Get last error num bero92 !! Get last error numero 71 93 IMPORT C_INT 72 94 INTEGER(kind=C_INT) :: errno_c !! Last errno … … 209 231 INTEGER(kind=C_INT) :: mkdirp_c !! 0 on success, last errno on failure 210 232 END FUNCTION mkdirp_c 233 234 FUNCTION copy_c(to,from) BIND(C,name="c_copy") 235 !! Copy a file. 236 IMPORT c_char, C_INT 237 CHARACTER(kind=c_char), INTENT(in) :: to(*) !! Destination path. 238 CHARACTER(kind=c_char), INTENT(in) :: from(*) !! Input file path to copy. 239 INTEGER(kind=C_INT) :: copy_c !! 0 on success, 1 on failure. 240 END FUNCTION copy_c 211 241 212 242 FUNCTION remove_c(path) BIND(C,name="c_remove") … … 255 285 END FUNCTION termsize_c 256 286 287 FUNCTION getCurrentRSS_c() BIND(C, name="c_getCurrentRSS") 288 !! Get the current resident set size memory in bytes. 289 IMPORT C_SIZE_T 290 INTEGER(kind=C_SIZE_T) :: getCurrentRSS_c !! Current resident set size in bytes (0 if not available). 291 END FUNCTION getCurrentRSS_c 292 293 FUNCTION getPeakRSS_c() BIND(C, name="c_getPeakRSS") 294 !! Get the peak resident set size memory in bytes. 295 IMPORT C_SIZE_T 296 INTEGER(kind=C_SIZE_T) :: getPeakRSS_c !! Peak resident set size in bytes (0 if not available). 297 END FUNCTION getPeakRSS_c 298 299 FUNCTION getSystemMemory_c(total,avail,free) BIND(C, name='c_getSystemMemory') 300 !! Get global memory informations. 301 IMPORT C_LONG_LONG,C_INT 302 INTEGER(kind=C_LONG_LONG), INTENT(out) :: total !! Total available memory. 303 INTEGER(kind=C_LONG_LONG), INTENT(out) :: avail !! Current available memory. 304 INTEGER(kind=C_LONG_LONG), INTENT(out) :: free !! Current free memory. 305 INTEGER(kind=C_INT) :: getSystemMemory_c !! status, 0 on success, 1 otherwise. 306 END FUNCTION getSystemMemory_c 257 307 END INTERFACE 258 308 #endif 259 309 260 310 CONTAINS … … 291 341 !! @attention 292 342 !! The method does not free the underlying C string and it should be free using 293 !! [[fsystem(module):free_c(interface)]] method.343 !! the subroutine free_c(_cstr_). 294 344 TYPE(C_PTR), INTENT(in) :: cstr 295 345 !! A TYPE(C_PTR) that represent the pointer to the C char array. … … 476 526 RETURN 477 527 END FUNCTION fs_getcwd 528 529 FUNCTION fs_copy(input,output) RESULT(ret) 530 !! Copy input file into output file. 531 CHARACTER(len=*), INTENT(in) :: input !! Input file path to copy. 532 CHARACTER(len=*), INTENT(in) :: output !! Output file path destination. 533 LOGICAL :: ret !! True on success, false otherwise. 534 IF (LEN_TRIM(input) == 0 .OR. LEN_TRIM(output) == 0 .OR. input == output) THEN 535 ret = .false. 536 ELSE 537 ret = INT(copy_c(cstring(ADJUSTL(output)),cstring(ADJUSTL(input)))) == 0 538 ENDIF 539 RETURN 540 END FUNCTION fs_copy 478 541 479 542 FUNCTION fs_remove(path) RESULT(ret) … … 880 943 END SUBROUTINE fs_msleep 881 944 945 FUNCTION fs_get_memory(peak,units) RESULT(mem) 946 !! Get the memory usage of the current process. 947 LOGICAL, INTENT(in), OPTIONAL :: peak !! True to retrieve the peak RSS memory, otherwise retrieve the current RSS memory. Default to False. 948 CHARACTER(len=*), INTENT(in), OPTIONAL :: units !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'. 949 REAL(kind=8) :: mem !! Memory usage. 950 LOGICAL :: zpeak 951 CHARACTER(len=2) :: zunits 952 zpeak = .false. ; IF (PRESENT(peak)) zpeak = peak 953 zunits = 'B ' ; IF (PRESENT(units)) zunits = units 954 IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B ' 955 IF (zpeak) THEN 956 mem = REAL(getPeakRSS_c(),kind=8) 957 ELSE 958 mem = REAL(getCurrentRSS_c(),kind=8) 959 ENDIF 960 IF (zunits == 'KB') THEN 961 mem = mem / 1024d0 962 ELSE IF (zunits == 'MB') THEN 963 mem = mem / 1048576d0 964 ELSE IF (zunits == 'GB') THEN 965 mem = mem / 1073741824d0 966 ENDIF 967 RETURN 968 END FUNCTION fs_get_memory 969 970 FUNCTION fs_get_system_memory(total,available,free,units) RESULT(ret) 971 !! Get informations about system memory. 972 !! 973 !! If no informations is available, output arguments are set to 0 and the method returns false. 974 REAL(kind=8), INTENT(out), OPTIONAL :: total !! Total available memory. 975 REAL(kind=8), INTENT(out), OPTIONAL :: available !! Current available memory. 976 REAL(kind=8), INTENT(out), OPTIONAL :: free !! Current free memory. 977 CHARACTER(len=*), INTENT(in), OPTIONAL :: units !! Output units: either 'B' (Bytes),'KB' (Kilo-),'MB' (Mega-),'GB' (Giga-). Default to 'B'. 978 LOGICAL :: ret !! True on success, false otherwise. 979 LOGICAL :: zpeak 980 CHARACTER(len=2) :: zunits 981 INTEGER(kind=8) :: ztot,zava,zfre 982 983 zunits = 'B ' ; IF (PRESENT(units)) zunits = units 984 IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B ' 985 ret = INT(getSystemMemory_c(ztot,zava,zfre),kind=4) == 0 986 ztot = ztot * 1024 ; zava = zava * 1024 ; zfre = zfre * 1024 987 988 IF (PRESENT(total)) total = ztot 989 IF (PRESENT(available)) available = zava 990 IF (PRESENT(free)) free = zfre 991 IF (.NOT.ret) RETURN 992 993 IF (zunits == 'KB') THEN 994 IF (PRESENT(total)) total = ztot / 1024d0 995 IF (PRESENT(available)) available = zava / 1024d0 996 IF (PRESENT(free)) free = zfre / 1024d0 997 ELSE IF (zunits == 'MB') THEN 998 IF (PRESENT(total)) total = ztot / 1048576d0 999 IF (PRESENT(available)) available = zava / 1048576d0 1000 IF (PRESENT(free)) free = zfre / 1048576d0 1001 ELSE IF (zunits == 'GB') THEN 1002 IF (PRESENT(total)) total = ztot / 1073741824d0 1003 IF (PRESENT(available)) available = zava / 1073741824d0 1004 IF (PRESENT(free)) free = zfre / 1073741824d0 1005 ENDIF 1006 RETURN 1007 END FUNCTION fs_get_system_memory 1008 1009 882 1010 !=============================================================================== 883 1011 ! MODULE MISCELLANEOUS METHODS … … 1032 1160 END FUNCTION sz2str 1033 1161 1162 FUNCTION chrono_is_running(this) RESULT (ret) 1163 !! Get chrono's state. 1164 OBJECT(chrono), INTENT(in) :: this !! Chrono object reference. 1165 LOGICAL :: ret !! Running state. 1166 ret = this%on_run 1167 RETURN 1168 END FUNCTION chrono_is_running 1169 1170 SUBROUTINE chrono_start(this) 1171 !! Start the chrono. 1172 !! 1173 !! @note 1174 !! Calling the method multiple times without explicitly stopping the chrono 1175 !! [[chrono(type):stop(bound)]] does nothing (except for the first called). 1176 OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. 1177 IF (.NOT.this%on_run) THEN 1178 CALL CPU_TIME(this%cpu_start) 1179 CALL SYSTEM_CLOCK(this%clock_start) 1180 ENDIF 1181 this%on_run = .true. 1182 END SUBROUTINE chrono_start 1183 1184 SUBROUTINE chrono_stop(this) 1185 !! Stop the chrono. 1186 OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. 1187 REAL(kind=8) :: ecpu 1188 INTEGER(kind=8) :: eclk,nbm,nbr 1189 this%on_run = .false. 1190 END SUBROUTINE chrono_stop 1191 1192 SUBROUTINE chrono_reset(this) 1193 !! Reset the chrono's internal elapsed times. 1194 OBJECT(chrono), INTENT(inout) :: this !! Chrono object reference. 1195 CALL CPU_TIME(this%cpu_start) 1196 CALL SYSTEM_CLOCK(this%clock_start) 1197 END SUBROUTINE chrono_reset 1198 1199 SUBROUTINE chrono_get(this,cpu,clock,units) 1200 !! Get elapsed time since last call of start or reset methods. 1201 !! 1202 !! The method computes the time elapsed in two ways : 1203 !! 1204 !! - If the [[fsystem(module):chrono(type)]] is not running, the method retruns 0. 1205 !! - Otherwise, elapsed time since the last call of 1206 !! [[chrono(type):start(bound)]] (or [[chrono(type):reset(bound)]]). 1207 OBJECT(chrono), INTENT(in) :: this 1208 !! Chrono object reference. 1209 REAL(kind=8), INTENT(out), OPTIONAL :: cpu 1210 !! Elapsed cpu time in seconds by default (see units argument). 1211 REAL(kind=8), INTENT(out), OPTIONAL :: clock 1212 !! Elapsed system clock time in seconds by default (see units argument). 1213 CHARACTER(len=2), INTENT(in), OPTIONAL :: units 1214 !! A two characters wide string with the units to convert in. Units should 1215 !! be one of the following : 'ms', 's' (default), 'm', 'h' or 'd'. 1216 CHARACTER(len=2) :: zu 1217 REAL(kind=8) :: cu, fact 1218 INTEGER(kind=8) :: ck, r, m 1219 IF (this%on_run) THEN 1220 IF (PRESENT(cpu)) THEN 1221 CALL CPU_TIME(cu) 1222 cpu = (cu - this%cpu_start) 1223 ENDIF 1224 IF (PRESENT(clock)) THEN 1225 CALL SYSTEM_CLOCK(ck,r,m) 1226 clock = c2t(ck,this%clock_start,r,m) 1227 ENDIF 1228 ELSE 1229 IF (PRESENT(cpu)) cpu = 0d0 1230 IF (PRESENT(clock)) clock = 0d0 1231 ENDIF 1232 fact = 1d0 1233 zu = 's' 1234 IF (PRESENT(units)) THEN 1235 zu = units 1236 SELECT CASE(zu) 1237 CASE ('d') ; fact = 3600d0*24. 1238 CASE ('h') ; fact = 3600d0 1239 CASE ('m') ; fact = 60d0 1240 CASE ('ms') ; fact = 1d-3 1241 CASE DEFAULT ; fact = 1d0 1242 END SELECT 1243 ENDIF 1244 IF (PRESENT(cpu)) cpu = cpu / fact 1245 IF (PRESENT(clock)) clock = clock / fact 1246 END SUBROUTINE chrono_get 1247 1248 FUNCTION c2t(e,i,r,m) RESULT(time) 1249 !! Get the real-time between two clock counts from system_clock. 1250 INTEGER(kind=8), INTENT(in) :: e !! Final clock count 1251 INTEGER(kind=8), INTENT(in) :: i !! Initial clock count 1252 INTEGER(kind=8), INTENT(in) :: r !! Clock count rate 1253 INTEGER(kind=8), INTENT(in) :: m !! Maximum Clock count value 1254 REAL(kind=8) :: time !! Time in seconds 1255 INTEGER(kind=8) :: nc 1256 nc = e-i ; IF (e < i) nc = nc+m 1257 time = REAL(nc,kind=8)/r 1258 RETURN 1259 END FUNCTION c2t 1034 1260 END MODULE FSYSTEM 1261 -
trunk/LMDZ.TITAN/libf/muphytitan/mm_clouds.f90
r1793 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Clouds microphysics module 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_CLOUDS -
trunk/LMDZ.TITAN/libf/muphytitan/mm_globals.f90
r1814 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Parameters and global variables module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_GLOBALS … … 141 141 ! from swift 142 142 USE CFGPARSE 143 USE STRING S143 USE STRING_OP 144 144 USE ERRORS 145 145 IMPLICIT NONE … … 166 166 PROTECTED :: mm_rcs, mm_rcf, mm_drad, mm_drho 167 167 168 LOGICAL, SAVE :: mm_debug = .true. !! Enable QnD debug mode .169 LOGICAL, SAVE :: mm_log = .false. !! Enable log mode .168 LOGICAL, SAVE :: mm_debug = .true. !! Enable QnD debug mode (can be used for devel). 169 LOGICAL, SAVE :: mm_log = .false. !! Enable log mode (for configuration only). 170 170 171 171 LOGICAL, SAVE :: mm_w_haze_prod = .true. !! Enable/Disable haze production. … … 177 177 178 178 LOGICAL, SAVE :: mm_var_prod = .false. !! Time variation of production rate control flag. 179 180 LOGICAL, SAVE :: mm_use_effg = .true. !! Enable/Disable effective G for computations. 179 181 180 182 !> Enable/Disable __Fiadero__'s correction. … … 689 691 ALLOCATE(mm_spcname(mm_nesp),mm_xESPS(mm_nesp)) 690 692 DO i=1,mm_nesp 691 mm_spcname(i) = str_to_lower(species(i))693 mm_spcname(i) = to_lower(species(i)) 692 694 IF(.NOT.cfg_has_section(cp,TRIM(mm_spcname(i)))) THEN 693 695 err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1) … … 866 868 !mm_spcname(1:mm_nesp) = species(:) 867 869 DO i=1,mm_nesp 868 mm_spcname(i) = str_to_lower(species(i))870 mm_spcname(i) = to_lower(species(i)) 869 871 IF (.NOT.cfg_has_section(spccfg,TRIM(mm_spcname(i)))) THEN 870 872 err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1) … … 1214 1216 REAL(kind=mm_wp), INTENT(in) :: z !! Altitude in meters 1215 1217 REAL(kind=mm_wp) :: effg !! Effective gravitational acceleration in \(m.s^{-2}\) 1216 effg = mm_g0 * (mm_rpla/(mm_rpla+z))**2 1218 effg = mm_g0 1219 IF (mm_use_effg) effg = effg * (mm_rpla/(mm_rpla+z))**2 1217 1220 RETURN 1218 1221 END FUNCTION mm_effg -
trunk/LMDZ.TITAN/libf/muphytitan/mm_haze.f90
r1819 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Haze microphysics module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 38 37 !! date: 2013-2015,2017 39 38 MODULE MM_HAZE 40 39 !! Haze microphysics module. -
trunk/LMDZ.TITAN/libf/muphytitan/mm_interfaces.f90
r1793 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Interfaces module for external functions 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_INTERFACES -
trunk/LMDZ.TITAN/libf/muphytitan/mm_lib.f90
r1793 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: MP2M library interface module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_LIB -
trunk/LMDZ.TITAN/libf/muphytitan/mm_methods.f90
r1793 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Model miscellaneous methods module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_METHODS -
trunk/LMDZ.TITAN/libf/muphytitan/mm_microphysic.f90
r1819 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! brief: Microphysic processes interface module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 MODULE MM_MICROPHYSIC … … 111 111 ! add temporary aerosols tendencies (-> m-3) 112 112 dm0a_f = dm0a_f + zdm0a_f ; dm3a_f = dm3a_f + zdm3a_f 113 ! sanity check for clouds tendencies114 WHERE (mm_m0ccn+dm0n*mm_dzlev < 0) ; dm0n = -mm_m0ccn/mm_dzlev ; END WHERE115 WHERE (mm_m3ccn+dm3n*mm_dzlev < 0) ; dm3n = -mm_m3ccn/mm_dzlev ; END WHERE116 117 113 ! reverse directly clouds tendencies (-> m-2) 118 114 dm0n = dm0n(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 119 115 dm3n = dm3n(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 116 ! sanity check for clouds tendencies 117 WHERE (mm_m0ccn+dm0n < 0) ; dm0n = -mm_m0ccn ; END WHERE 118 WHERE (mm_m3ccn+dm3n < 0) ; dm3n = -mm_m3ccn ; END WHERE 120 119 DO i=1,mm_nesp 121 120 dm3i(:,i) = dm3i(mm_nla:1:-1,i) * mm_dzlev(mm_nla:1:-1) 122 WHERE (mm_m3 ccn+dm3n*mm_dzlev < 0) ; dm3n = -mm_m3ccn/mm_dzlev; END WHERE121 WHERE (mm_m3ice+dm3i < 0) ; dm3i = -mm_m3ice ; END WHERE 123 122 dgazs(:,i) = dgazs(mm_nla:1:-1,i) 124 123 ! no sanity check for gazs, let's prey. … … 127 126 dm0n = 0._mm_wp ; dm3n = 0._mm_wp ; dm3i = 0._mm_wp ; dgazs = 0._mm_wp 128 127 ENDIF 129 ! sanity check130 WHERE (mm_m0aer_s+dm0a_s*mm_dzlev < 0) ; dm0a_s = -mm_m0aer_s/mm_dzlev ; END WHERE131 WHERE (mm_m3aer_s+dm3a_f*mm_dzlev < 0) ; dm3a_s = -mm_m3aer_s/mm_dzlev ; END WHERE132 WHERE (mm_m0aer_f+dm0a_f*mm_dzlev < 0) ; dm0a_f = -mm_m0aer_f/mm_dzlev ; END WHERE133 WHERE (mm_m3aer_f+dm3a_f*mm_dzlev < 0) ; dm3a_f = -mm_m3aer_f/mm_dzlev ; END WHERE134 135 128 ! multiply by altitude thickness and reverse vectors so they go from ground to top :) 136 129 dm0a_s = dm0a_s(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) … … 138 131 dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 139 132 dm3a_f = dm3a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 133 ! sanity check 134 WHERE (mm_m0aer_s+dm0a_s < 0) ; dm0a_s = -mm_m0aer_s ; END WHERE 135 WHERE (mm_m3aer_s+dm3a_f < 0) ; dm3a_s = -mm_m3aer_s ; END WHERE 136 WHERE (mm_m0aer_f+dm0a_f < 0) ; dm0a_f = -mm_m0aer_f ; END WHERE 137 WHERE (mm_m3aer_f+dm3a_f < 0) ; dm3a_f = -mm_m3aer_f ; END WHERE 140 138 141 139 RETURN … … 167 165 ! Calls haze microphysics 168 166 call mm_haze_microphysics(dm0a_s,dm3a_s,dm0a_f,dm3a_f) 169 ! sanity check170 WHERE (mm_m0aer_s+dm0a_s*mm_dzlev < 0) ; dm0a_s = -mm_m0aer_s/mm_dzlev ; END WHERE171 WHERE (mm_m3aer_s+dm3a_f*mm_dzlev < 0) ; dm3a_s = -mm_m3aer_s/mm_dzlev ; END WHERE172 WHERE (mm_m0aer_f+dm0a_f*mm_dzlev < 0) ; dm0a_f = -mm_m0aer_f/mm_dzlev ; END WHERE173 WHERE (mm_m3aer_f+dm3a_f*mm_dzlev < 0) ; dm3a_f = -mm_m3aer_f/mm_dzlev ; END WHERE174 167 ! reverse vectors so they go from ground to top :) 175 168 dm0a_s = dm0a_s(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) … … 177 170 dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 178 171 dm3a_f = dm3a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 172 ! sanity check 173 WHERE (mm_m0aer_s+dm0a_s < 0) ; dm0a_s = -mm_m0aer_s ; END WHERE 174 WHERE (mm_m3aer_s+dm3a_f < 0) ; dm3a_s = -mm_m3aer_s ; END WHERE 175 WHERE (mm_m0aer_f+dm0a_f < 0) ; dm0a_f = -mm_m0aer_f ; END WHERE 176 WHERE (mm_m3aer_f+dm3a_f < 0) ; dm3a_f = -mm_m3aer_f ; END WHERE 179 177 RETURN 180 178 END FUNCTION muphys_nocld -
trunk/LMDZ.TITAN/libf/muphytitan/mm_mprec.F90
r1793 r1897 1 ! Copyright 2013-2015 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr … … 35 35 !! summary: Library floating point precision module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015 37 !! date: 2013-2015,2017 38 38 39 39 #ifdef HAVE_CONFIG_H -
trunk/LMDZ.TITAN/libf/muphytitan/mmp_gcm.f90
r1819 r1897 1 ! Copyright 2017 Université de Reims Champagne-Ardenne 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 5 ! This software is a computer program whose purpose is to compute 6 ! microphysics processes using a two-moments scheme. 7 ! 8 ! This library is governed by the CeCILL license under French law and 9 ! abiding by the rules of distribution of free software. You can use, 10 ! modify and/ or redistribute the software under the terms of the CeCILL 11 ! license as circulated by CEA, CNRS and INRIA at the following URL 12 ! "http://www.cecill.info". 13 ! 14 ! As a counterpart to the access to the source code and rights to copy, 15 ! modify and redistribute granted by the license, users are provided only 16 ! with a limited warranty and the software's author, the holder of the 17 ! economic rights, and the successive licensors have only limited 18 ! liability. 19 ! 20 ! In this respect, the user's attention is drawn to the risks associated 21 ! with loading, using, modifying and/or developing or reproducing the 22 ! software by the user in light of its specific status of free software, 23 ! that may mean that it is complicated to manipulate, and that also 24 ! therefore means that it is reserved for developers and experienced 25 ! professionals having in-depth computer knowledge. Users are therefore 26 ! encouraged to load and test the software's suitability as regards their 27 ! requirements in conditions enabling the security of their systems and/or 28 ! data to be ensured and, more generally, to use and operate it in the 29 ! same conditions as regards security. 30 ! 31 ! The fact that you are presently reading this means that you have had 32 ! knowledge of the CeCILL license and that you accept its terms. 33 34 !! file: mmp_gcm.f90 35 !! summary: YAMMS interfaces for the LMDZ GCM. 36 !! author: J. Burgalat 37 !! date: 2017 1 38 MODULE MMP_GCM 2 39 !! Interface to YAMMS for the LMDZ GCM. 40 USE MMP_GLOBALS 3 41 USE MM_LIB 4 42 USE CFGPARSE … … 6 44 IMPLICIT NONE 7 45 8 PUBLIC9 10 !> Alpha function parameters.11 !!12 !! It stores the parameters of the inter-moments relation functions.13 !!14 !! The inter-moments relation function is represented by the sum of exponential15 !! quadratic expressions:16 !!17 !! $$18 !! \displaystyle \alpha(k) = \sum_{i=1}^{n} \exp\left( a_{i}\times k^{2} +19 !! b_{i}\times k^{2} +c_{i}\right)20 !! $$21 TYPE, PUBLIC :: aprm22 !> Quadratic coefficients of the quadratic expressions.23 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a24 !> Linear coefficients of the quadratic expressions.25 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: b26 !> Free term of the quadratic expressions.27 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: c28 END TYPE29 30 !> Size distribution parameters derived type.31 !!32 !! It stores the parameters of the size distribution law for Titan.33 !!34 !! The size distribution law is represented by the minimization of a sum of35 !! power law functions:36 !!37 !! $$38 !! \displaystyle n\left(r\right) = \frac{A_{0}}{C+\sum_{i=1}^{n} A_{i}\times39 !! \left(\frac{r}{r_{c}}\right)^{-b_{i}}}40 !! $$41 TYPE, PUBLIC :: nprm42 !> Scaling factor.43 REAL(kind=mm_wp) :: a044 !> Characterisitic radius.45 REAL(kind=mm_wp) :: rc46 !> Additional constant to the sum of power law.47 REAL(kind=mm_wp) :: c48 !> Scaling factor of each power law.49 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a50 !> Power of each power law.51 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: b52 END TYPE53 54 !> Inter-moment relation set of parameters for the spherical mode.55 TYPE(aprm), PUBLIC, SAVE :: mmp_asp56 !> Inter-moment relation set of parameters for the fractal mode.57 TYPE(aprm), PUBLIC, SAVE :: mmp_afp58 59 !> Size-distribution law parameters of the spherical mode.60 TYPE(nprm), PUBLIC, SAVE :: mmp_pns61 !> Size-distribution law parameters of the fractal mode.62 TYPE(nprm), PUBLIC, SAVE :: mmp_pnf63 64 !> Data set for @f$<Q>_{SF}^{M0}@f$.65 TYPE(dset2d), PUBLIC, SAVE, TARGET :: mmp_qbsf066 !> Extended values of [[mmp_gcm(module):mmp_qbsf0(variable)]] dataset.67 REAL(kind=mm_wp), PUBLIC, SAVE, DIMENSION(2,2) :: mmp_qbsf0_e68 !> Data set for @f$<Q>_{SF}^{M3}@f$.69 TYPE(dset2d), PUBLIC, SAVE, TARGET :: mmp_qbsf370 !> Extended values of [[mmp_gcm(module):mmp_qbsf3(variable)]] dataset.71 REAL(kind=mm_wp), PUBLIC, SAVE, DIMENSION(2,2) :: mmp_qbsf3_e72 !> Data set for @f$<Q>_{FF}^{M0}@f$.73 TYPE(dset2d), PUBLIC, SAVE, TARGET :: mmp_qbff074 !> Extended values of [[mmp_gcm(module):mmp_qbff0(variable)]] dataset.75 REAL(kind=mm_wp), PUBLIC, SAVE, DIMENSION(2,2) :: mmp_qbff0_e76 77 !> Data set for linear interpolation of transfert probability (M0/CO).78 TYPE(dset1d), PUBLIC, SAVE, TARGET :: mmp_pco0p79 !> Data set for linear interpolation of transfert probability (M3/CO).80 TYPE(dset1d), PUBLIC, SAVE, TARGET :: mmp_pco3p81 !> Data set for linear interpolation of transfert probability (M0/FM).82 TYPE(dset1d), PUBLIC, SAVE, TARGET :: mmp_pfm0p83 !> Data set for linear interpolation of transfert probability (M3/FM).84 TYPE(dset1d), PUBLIC, SAVE, TARGET :: mmp_pfm3p85 86 !> \(b_{0}^{t}\) coefficients for Free-molecular regime kernel approximation.87 REAL(kind=mm_wp), PUBLIC, SAVE, DIMENSION(5) :: mmp_bt0 = (/1._mm_wp,1._mm_wp,1._mm_wp,1._mm_wp,1._mm_wp/)88 !> \(b_{3}^{t}\) coefficients for Free-molecular regime kernel approximation.89 REAL(kind=mm_wp), PUBLIC, SAVE, DIMENSION(5) :: mmp_bt3 = (/1._mm_wp,1._mm_wp,1._mm_wp,1._mm_wp,1._mm_wp/)90 91 !> Spherical probability transfert control flag.92 LOGICAL, SAVE :: mmp_w_ps2s = .true.93 !> Aerosol electric charge correction control flag.94 LOGICAL, SAVE :: mmp_w_qe = .true.95 96 97 46 CONTAINS 98 47 99 SUBROUTINE abort_program(err) 100 !! Dump error message and abort the program. 101 TYPE(error), INTENT(in) :: err !! Error object. 102 WRITE(stderr,'(a)') "ERROR: "//TRIM(err%msg) 103 CALL EXIT(err%id) 104 END SUBROUTINE abort_program 105 106 107 SUBROUTINE mmp_initialize(dt,df,rm,rho_aer,p_prod,tx_prod,rc_prod,rplanet,g0, air_rad,air_mmol,clouds,cfgpath) 48 SUBROUTINE mmp_initialize(dt,p_prod,tx_prod,rc_prod,rplanet,g0, air_rad,air_mmol,clouds,cfgpath) 108 49 !! Initialize global parameters of the model. 109 50 !! … … 112 53 !! default values are suitable for production runs. 113 54 !! @note 114 !! If the method fails to initialize parameters (i.e. returned error is not 0). Then the model 115 !! should probably be aborted as the global variables of the model will not be correctly setup. 55 !! If the subroutine fails to initialize parameters, the run is aborted. 116 56 !! 117 57 !! @warning … … 119 59 !! initializes global variable that are not thread private. 120 60 !! 121 !! '''61 !! ``` 122 62 !! !$OMP SINGLE 123 63 !! call mmp_initialize(...) 124 64 !! !$OMP END SINGLE 65 !! ``` 125 66 !! 126 67 REAL(kind=mm_wp), INTENT(in) :: dt 127 68 !! Microphysics timestep in seconds. 128 REAL(kind=mm_wp), INTENT(in) :: df129 !! Fractal dimension of fractal aerosol.130 REAL(kind=mm_wp), INTENT(in) :: rm131 !! Monomer radius in meter.132 REAL(kind=mm_wp), INTENT(in) :: rho_aer133 !! Aerosol density in \(kg.m^{-3}\).134 69 REAL(kind=mm_wp), INTENT(in) :: p_prod 135 70 !! Aerosol production pressure level in Pa. … … 151 86 !! Internal microphysic configuration file. 152 87 153 INTEGER :: coag_choice154 REAL(kind=mm_wp) :: fiad_max, fiad_min155 LOGICAL :: w_h_prod, w_h_sed, w_h_coag, w_c_sed, w_c_nucond, &156 no_fiadero, fwsed_m0, fwsed_m3157 TYPE(error) :: err88 INTEGER :: coag_choice 89 REAL(kind=mm_wp) :: fiad_max, fiad_min,df,rm,rho_aer 90 LOGICAL :: w_h_prod, w_h_sed, w_h_coag, w_c_sed, w_c_nucond, & 91 no_fiadero, fwsed_m0, fwsed_m3 92 TYPE(error) :: err 158 93 INTEGER :: i 159 94 TYPE(cfgparser) :: cparser … … 186 121 187 122 ! YAMMS internal parameters: 123 err = mm_check_opt(cfg_get_value(cparser,"rm",rm),rm,50e-9_mm_wp,mm_log) 124 err = mm_check_opt(cfg_get_value(cparser,"df",df),df,2._mm_wp,mm_log) 125 err = mm_check_opt(cfg_get_value(cparser,"rho_aer",rho_aer),rho_aer,1000._mm_wp,mm_log) 188 126 ! the following parameters are primarily used to test and debug YAMMS. 189 127 ! They are set in an optional configuration file and default to suitable values for production runs. -
trunk/LMDZ.TITAN/libf/phytitan/callcorrk.F90
r1822 r1897 45 45 INTEGER,INTENT(IN) :: ngrid ! Number of atmospheric columns. 46 46 INTEGER,INTENT(IN) :: nlayer ! Number of atmospheric layers. 47 REAL,INTENT(IN) :: pq(ngrid,nlayer,nq) ! Tracers ( kg/kg_of_air).47 REAL,INTENT(IN) :: pq(ngrid,nlayer,nq) ! Tracers (X/m2). 48 48 INTEGER,INTENT(IN) :: nq ! Number of tracers. 49 49 REAL,INTENT(IN) :: qsurf(ngrid,nq) ! Tracers on surface (kg.m-2). … … 298 298 endif 299 299 300 call optcv(pq ,plevrad,tmid,pmid,&300 call optcv(pq(ig,:,1:nmicro),nlayer,plevrad,tmid,pmid, & 301 301 dtauv,tauv,taucumv,wbarv,cosbv,tauray,taugsurf) 302 302 … … 340 340 !----------------------------------------------------------------------- 341 341 342 call optci(pq ,plevrad,tlevrad,tmid,pmid,&342 call optci(pq(ig,:,1:nmicro),nlayer,plevrad,tlevrad,tmid,pmid, & 343 343 dtaui,taucumi,cosbi,wbari,taugsurfi) 344 344 -
trunk/LMDZ.TITAN/libf/phytitan/callkeys_mod.F90
r1822 r1897 12 12 logical,save :: callgasvis,continuum,graybody 13 13 !$OMP THREADPRIVATE(callgasvis,continuum,graybody) 14 logical,save :: strictboundcorrk 14 logical,save :: strictboundcorrk 15 15 !$OMP THREADPRIVATE(strictboundcorrk) 16 logical,save :: uncoupl_optic_haze 17 !$OMP THREADPRIVATE(uncoupl_optic_haze) 18 16 19 logical,save :: callchim, callmufi, callclouds 17 20 !$OMP THREADPRIVATE(callchim,callmufi,callclouds) … … 45 48 !$OMP THREADPRIVATE(iddist,iradia,startype) 46 49 47 real,save :: df_mufi, rm_mufi, rho_aer_mufi48 50 real,save :: p_prod, tx_prod, rc_prod 49 51 real,save :: air_rad 50 !$OMP THREADPRIVATE( df_mufi, rm_mufi, rho_aer_mufi,p_prod,tx_prod,rc_prod,air_rad)51 52 !$OMP THREADPRIVATE(p_prod,tx_prod,rc_prod,air_rad) 53 52 54 real,save :: szangle 53 55 !$OMP THREADPRIVATE(szangle) -
trunk/LMDZ.TITAN/libf/phytitan/calmufi.F90
r1819 r1897 1 2 1 3 SUBROUTINE calmufi(plev, zlev, play, zlay, temp, pq, zdq) 2 4 !! Interface subroutine to YAMMS model for Titan LMDZ GCM. 3 5 !! 4 !! The subroutine computes the microphysics processes for a si ngle vertical column.6 !! The subroutine computes the microphysics processes for a si:le vertical column. 5 7 !! 6 8 !! - All input vectors are assumed to be defined from GROUND to TOP of the atmosphere. … … 52 54 53 55 INTEGER :: ilon, i,nices 54 55 56 INTEGER :: nlon,nlay 56 57 … … 89 90 ! Convert tracers to extensive ( except for gazs where we work with molar mass ratio ) 90 91 ! We suppose a given order of tracers ! 91 int2ext(:) = ( plev(ilon,1:nlay) - plev(ilon,2:nlay+1) ) / g 92 92 int2ext(:) = ( plev(ilon,1:nlay)-plev(ilon,2:nlay+1) ) / g 93 93 m0as(:) = pq(ilon,:,1) * int2ext(:) 94 94 m3as(:) = pq(ilon,:,2) * int2ext(:) … … 97 97 98 98 if (callclouds) then ! if call clouds 99 dm0n(:) = pq(ilon,:,5) * int2ext(:)100 dm3n(:) = pq(ilon,:,6) * int2ext(:)99 m0n(:) = pq(ilon,:,5) * int2ext(:) 100 m3n(:) = pq(ilon,:,6) * int2ext(:) 101 101 do i=1,nices 102 dm3i(:,nices) = pq(ilon,:,6+i) * int2ext(:)103 dgazs(:,i) = pq(ilon,:,ices_indx(i)) * rat_mmol(ices_indx(i)) ! For gazs we work on the full tracer array !!102 m3i(:,nices) = pq(ilon,:,6+i) * int2ext(:) 103 gazs(:,i) = pq(ilon,:,ices_indx(i)) * rat_mmol(ices_indx(i)) ! For gazs we work on the full tracer array !! 104 104 ! We use the molar mass ratio from GCM in case there is discrepancy with the mm one 105 105 enddo 106 106 endif 107 108 107 109 108 ! Initialize YAMMS atmospheric column … … 135 134 ! Convert tracers back to intensives ( except for gazs where we work with molar mass ratio ) 136 135 ! We suppose a given order of tracers ! 137 136 138 137 zdq(ilon,:,1) = dm0as(:) / int2ext(:) 139 138 zdq(ilon,:,2) = dm3as(:) / int2ext(:) … … 150 149 enddo 151 150 endif 152 153 151 END DO ! loop on ilon 154 152 -
trunk/LMDZ.TITAN/libf/phytitan/inifis_mod.F90
r1896 r1897 377 377 endif 378 378 379 write(*,*) "Fractal dimension ?" 380 df_mufi=2.0 ! default value 381 call getin_p("df_mufi",df_mufi) 382 write(*,*)" df_mufi = ",df_mufi 383 384 write(*,*) "Monomer radius (m) ?" 385 rm_mufi=6.66e-08 ! default value 386 call getin_p("rm_mufi",rm_mufi) 387 write(*,*)" rm_mufi = ",rm_mufi 388 389 write(*,*) "Aerosol density (kg.m-3)?" 390 rho_aer_mufi=1.e3 ! default value 391 call getin_p("rho_aer_mufi",rho_aer_mufi) 392 write(*,*)" rho_aer_mufi = ",rho_aer_mufi 379 write(*,*) "Disable the coupling of microphysics within rad. transf. ?" 380 write(*,*) "If disabled we will assume a planetwide vert. profile of extinction ..." 381 uncoupl_optic_haze=.true. ! default value - true as long as the microphysics is bugged 382 call getin_p("uncoupl_optic_haze",uncoupl_optic_haze) 383 write(*,*)" uncoupl_optic_haze = ",uncoupl_optic_haze 393 384 394 385 write(*,*) "Pressure level of aer. production (Pa) ?" -
trunk/LMDZ.TITAN/libf/phytitan/inimufi.F90
r1795 r1897 2 2 3 3 use mmp_gcm 4 use callkeys_mod, only : callclouds, df_mufi, & 5 rm_mufi, rho_aer_mufi, p_prod, tx_prod, rc_prod, air_rad 4 use callkeys_mod, only : callclouds, p_prod, tx_prod, rc_prod, air_rad 6 5 use tracer_h 7 6 use comcstfi_mod, only : g, rad, mugaz … … 42 41 logical :: err 43 42 43 ! PATCH : YAMMS now allows to enable/disable effective g computations: 44 ! In the library it defaults to .true., in the GCM we do not want it ! 45 mm_use_effg = .false. 44 46 45 47 !---------------------------------------------------- … … 47 49 ! --------------------------------------------------- 48 50 49 call mmp_initialize(ptimestep, df_mufi,rm_mufi,rho_aer_mufi,p_prod,tx_prod,rc_prod, &51 call mmp_initialize(ptimestep,p_prod,tx_prod,rc_prod, & 50 52 rad,g,air_rad,mugaz,callclouds,config_mufi) 51 53 -
trunk/LMDZ.TITAN/libf/phytitan/optci.F90
r1822 r1897 1 subroutine optci(PQ ,PLEV,TLEV,TMID,PMID, &1 subroutine optci(PQO,NLAY,PLEV,TLEV,TMID,PMID, & 2 2 DTAUI,TAUCUMI,COSBI,WBARI,TAUGSURF) 3 3 … … 6 6 use gases_h 7 7 use comcstfi_mod, only: g, r 8 use callkeys_mod, only: continuum,graybody 8 use callkeys_mod, only: continuum,graybody,callclouds,callmufi, uncoupl_optic_haze 9 use tracer_h, only : nmicro,nice 10 use MMP_OPTICS 11 9 12 implicit none 10 13 … … 34 37 ! Input/Output 35 38 !========================================================== 36 REAL*8, INTENT(IN) :: PQ ! Tracers (kg/kg_of_air). 39 REAL*8, INTENT(IN) :: PQO(nlay,nmicro) ! Tracers (X/m2). 40 INTEGER, INTENT(IN) :: NLAY ! Number of pressure layers (for pqo) 37 41 REAL*8, INTENT(IN) :: PLEV(L_LEVELS), TLEV(L_LEVELS) 38 42 REAL*8, INTENT(IN) :: TMID(L_LEVELS), PMID(L_LEVELS) … … 86 90 integer interm 87 91 92 real*8 m0as,m3as,m0af,m3af 93 real*8 ext_s,sca_s,ssa_s,asf_s 94 real*8 ext_f,sca_f,ssa_f,asf_f 95 logical,save :: firstcall=.true. 96 !$OMP THREADPRIVATE(firstcall) 97 88 98 !! AS: to save time in computing continuum (see bilinearbig) 89 99 IF (.not.ALLOCATED(indi)) THEN … … 127 137 ilay = k / 2 ! int. arithmetic => gives the gcm layer index 128 138 129 !================= Titan customisation ======================================== 130 call disr_haze(dz(k),plev(k),wnoi(nw),dhaze_T(k,nw),SSA_T(k,nw),ASF_T(k,nw)) 131 ! ============================================================================= 139 ! Optical coupling of YAMMS is plugged but inactivated for now 140 ! as long as the microphysics only isn't fully debugged -- JVO 01/18 141 IF (callmufi .AND. (.NOT. uncoupl_optic_haze)) THEN 142 m0as = pqo(ilay,1) 143 m3as = pqo(ilay,2) 144 m0af = pqo(ilay,3) 145 m3af = pqo(ilay,4) 146 147 IF (.NOT.mmp_sph_optics_ir(m0as,m3as,nw,ext_s,sca_s,ssa_s,asf_s)) & 148 CALL abort_gcm("optcv", "Fatal error in mmp_sph_optics_ir", 12) 149 IF (.NOT.mmp_fra_optics_ir(m0af,m3af,nw,ext_f,sca_f,ssa_f,asf_f)) & 150 CALL abort_gcm("optcv", "Fatal error in mmp_fra_optics_ir", 12) 151 dhaze_T(k,nw) = ext_s+ext_f 152 SSA_T(k,nw) = (sca_s+sca_f)/dhaze_T(k,nw) 153 ASF_T(k,nw) = (asf_s*sca_s + asf_f*sca_f) /(sca_s+sca_f) 154 IF (callclouds.and.firstcall) & 155 WRITE(*,*) 'WARNING: In optci, optical properties & 156 &calculations are not implemented yet' 157 ELSE 158 ! Call fixed vertical haze profile of extinction - same for all columns 159 call disr_haze(dz(k),plev(k),wnoi(nw),dhaze_T(k,nw),SSA_T(k,nw),ASF_T(k,nw)) 160 ENDIF 132 161 133 162 DCONT = 0.0d0 ! continuum absorption … … 401 430 ! ============================================================================== 402 431 432 if(firstcall) firstcall = .false. 433 403 434 return 404 435 -
trunk/LMDZ.TITAN/libf/phytitan/optcv.F90
r1826 r1897 1 SUBROUTINE OPTCV(PQ ,PLEV,TMID,PMID, &1 SUBROUTINE OPTCV(PQO,NLAY,PLEV,TMID,PMID, & 2 2 DTAUV,TAUV,TAUCUMV,WBARV,COSBV,TAURAY,TAUGSURF) 3 3 … … 6 6 use gases_h 7 7 use comcstfi_mod, only: g, r 8 use callkeys_mod, only: continuum,graybody,callgasvis 8 use callkeys_mod, only: continuum,graybody,callgasvis,callclouds,callmufi,uncoupl_optic_haze 9 use tracer_h, only: nmicro,nice 10 use MMP_OPTICS 9 11 10 12 implicit none … … 41 43 ! Input/Output 42 44 !========================================================== 43 REAL*8, INTENT(IN) :: PQ ! Tracers (kg/kg_of_air). 45 REAL*8, INTENT(IN) :: PQO(nlay,nmicro) ! Tracers (X/m2). 46 INTEGER, INTENT(IN) :: NLAY ! Number of pressure layers (for pqo) 44 47 REAL*8, INTENT(IN) :: PLEV(L_LEVELS) 45 48 REAL*8, INTENT(IN) :: TMID(L_LEVELS), PMID(L_LEVELS) … … 97 100 integer interm 98 101 102 real*8 m0as,m3as,m0af,m3af 103 real*8 ext_s,sca_s,ssa_s,asf_s 104 real*8 ext_f,sca_f,ssa_f,asf_f 105 logical,save :: firstcall=.true. 106 !$OMP THREADPRIVATE(firstcall) 107 108 99 109 !! AS: to save time in computing continuum (see bilinearbig) 100 110 IF (.not.ALLOCATED(indv)) THEN … … 149 159 150 160 do NW=1,L_NSPECTV 151 152 !================= Titan customisation ======================================== 153 call disr_haze(dz(k),plev(k),wnov(nw),dhaze_T(k,nw),SSA_T(k,nw),ASF_T(k,nw)) 154 ! ============================================================================= 161 162 ! Optical coupling of YAMMS is plugged but inactivated (if false) for now 163 ! as long as the microphysics only isn't fully debugged -- JVO 01/18 164 IF (callmufi .AND. (.NOT. uncoupl_optic_haze)) THEN 165 m0as = pqo(ilay,1) 166 m3as = pqo(ilay,2) 167 m0af = pqo(ilay,3) 168 m3af = pqo(ilay,4) 169 170 IF (.NOT.mmp_sph_optics_vis(m0as,m3as,nw,ext_s,sca_s,ssa_s,asf_s)) & 171 CALL abort_gcm("optcv", "Fatal error in mmp_sph_optics_vis", 12) 172 IF (.NOT.mmp_fra_optics_vis(m0af,m3af,nw,ext_f,sca_f,ssa_f,asf_f)) & 173 CALL abort_gcm("optcv", "Fatal error in mmp_fra_optics_vis", 12) 174 dhaze_T(k,nw) = ext_s+ext_f 175 SSA_T(k,nw) = (sca_s+sca_f)/dhaze_T(k,nw) 176 ASF_T(k,nw) = (asf_s*sca_s + asf_f*sca_f) /(sca_s+sca_f) 177 IF (callclouds.and.firstcall) & 178 WRITE(*,*) 'WARNING: In optcv, optical properties & 179 &calculations are not implemented yet' 180 ELSE 181 ! Call fixed vertical haze profile of extinction - same for all columns 182 call disr_haze(dz(k),plev(k),wnov(nw),dhaze_T(k,nw),SSA_T(k,nw),ASF_T(k,nw)) 183 ENDIF 155 184 156 185 DRAYAER = TRAY(K,NW) … … 355 384 ! ============================================================================== 356 385 386 if(firstcall) firstcall = .false. 357 387 358 388 return -
trunk/LMDZ.TITAN/libf/phytitan/physiq_mod.F90
r1896 r1897 1 #define USE_QTEST 2 1 3 module physiq_mod 2 4 … … 46 48 use wxios, only: wxios_context_init, xios_context_finalize 47 49 #endif 50 use MMP_OPTICS 48 51 implicit none 49 52 … … 150 153 ! + clean of all too-generic (ocean, water, co2 ...) routines 151 154 ! + Titan's chemistry 155 ! Microphysical moment model - J.Burgalat / J.Vatant d'Ollone (2017-2018) 152 156 !============================================================================================ 153 157 … … 383 387 !$OMP THREADPRIVATE(tankCH4) 384 388 389 ! -----******----- FOR MUPHYS OPTICS -----******----- 390 integer :: i,j 391 real :: pqo(ngrid,nlayer,nq) ! Tracers for the optics (X/m2). 392 real :: i2e(nlayer) ! int 2 ext factor 393 ! -----******----- END FOR MUPHYS OPTICS -----******----- 394 395 real,save,dimension(:,:,:), allocatable :: tpq ! Tracers for decoupled microphysical tests ( temporary in 01/18 ) 396 !$OMP THREADPRIVATE(tpq) 397 398 385 399 !----------------------------------------------------------------------------- 386 400 ! Interface to calmufi 387 401 ! --> needed in order to pass assumed-shape arrays. Otherwise we must put calmufi in a module 388 ! (to have an explicit generated by the compiler).402 ! (to have an explicit interface generated by the compiler). 389 403 ! Or one can put calmufi in MMP_GCM module (in muphytitan). 390 404 INTERFACE … … 410 424 ! -------------------------------- 411 425 if (firstcall) then 426 allocate(tpq(ngrid,nlayer,nq)) 427 tpq(:,:,:) = pq(:,:,:) 412 428 413 429 ! Initialisation of nmicro as well as tracers names, indexes ... … … 518 534 519 535 call inimufi(nq,ptimestep) 536 537 ! Optical coupling of YAMMS is plugged but inactivated for now 538 ! as long as the microphysics only isn't fully debugged -- JVO 01/18 539 IF (.NOT.uncoupl_optic_haze) call mmp_initialize_optics("/path/to/mmp_optic_table.nc") 520 540 521 541 ENDIF … … 820 840 call call_profilgases(nlayer) 821 841 842 ! Convert (microphysical) tracers for optics: X.kg-1 --> X.m-2_ 843 ! NOTE: it should be moved somewhere else: calmufi performs the same kind of 844 ! computations... waste of time... 845 DO i = 1, ngrid 846 i2e(:) = ( pplev(i,1:nlayer)-pplev(i,2:nlayer+1) ) / g 847 pqo(i,:,:) = 0.0 848 DO j=1,nmicro-nice 849 pqo(i,:,j) = pq(i,:,j)*i2e(:) 850 ENDDO 851 ENDDO 852 853 822 854 ! standard callcorrk 823 call callcorrk(ngrid,nlayer,pq ,nq,qsurf,&855 call callcorrk(ngrid,nlayer,pqo,nq,qsurf, & 824 856 albedo,albedo_equivalent,emis,mu0,pplev,pplay,pt, & 825 857 tsurf,fract,dist_star, & … … 1108 1140 1109 1141 if (callmufi) then 1110 1142 #ifdef USE_QTEST 1143 if (ngrid.eq.1) then ! We obviously don't have access to (and don't need) zonal means in 1D 1144 call calmufi(pplev,zzlev,pplay,zzlay,pt,tpq,zdqmufi) 1145 else 1146 call calmufi(zplevbar,zzlevbar,zplaybar,zzlaybar,ztfibar,tpq,zdqmufi) 1147 endif 1148 tpq(:,:,:) = tpq(:,:,:) + zdqmufi(1:ngrid,1:nlayer,1:nq)*ptimestep 1149 #else 1111 1150 ! Inside this routine we will split 2D->1D, intensive->extensive and separate different types of tracers 1112 1151 ! Should be put in phytrac … … 1119 1158 1120 1159 pdq(1:ngrid,1:nlayer,1:nq) = pdq(1:ngrid,1:nlayer,1:nq) + zdqmufi(1:ngrid,1:nlayer,1:nq) 1121 1160 #endif 1122 1161 endif ! end of 'callmufi' 1123 1162 … … 1340 1379 1341 1380 1342 !-----------------------------------1343 ! Saving statistics :1344 !-----------------------------------1345 1346 ! Note :("stats" stores and accumulates 8 key variables in file "stats.nc"1347 ! which can later be used to make the statistic files of the run:1348 ! "stats") only possible in 3D runs !!!1349 1350 1351 if (callstats) then1352 1353 call wstats(ngrid,"ps","Surface pressure","Pa",2,ps)1354 call wstats(ngrid,"tsurf","Surface temperature","K",2,tsurf)1355 call wstats(ngrid,"fluxsurf_lw", &1356 "Thermal IR radiative flux to surface","W.m-2",2, &1357 fluxsurf_lw)1358 call wstats(ngrid,"fluxtop_lw", &1359 "Thermal IR radiative flux to space","W.m-2",2, &1360 fluxtop_lw)1361 1362 ! call wstats(ngrid,"fluxsurf_sw", &1363 ! "Solar radiative flux to surface","W.m-2",2, &1364 ! fluxsurf_sw_tot)1365 ! call wstats(ngrid,"fluxtop_sw", &1366 ! "Solar radiative flux to space","W.m-2",2, &1367 ! fluxtop_sw_tot)1368 1369 1370 call wstats(ngrid,"ISR","incoming stellar rad.","W m-2",2,fluxtop_dn)1371 call wstats(ngrid,"ASR","absorbed stellar rad.","W m-2",2,fluxabs_sw)1372 call wstats(ngrid,"OLR","outgoing longwave rad.","W m-2",2,fluxtop_lw)1373 !call wstats(ngrid,"ALB","Surface albedo"," ",2,albedo_equivalent)1374 !call wstats(ngrid,"ALB_1st","First Band Surface albedo"," ",2,albedo(:,1))1375 call wstats(ngrid,"p","Pressure","Pa",3,pplay)1376 call wstats(ngrid,"temp","Atmospheric temperature","K",3,zt)1377 call wstats(ngrid,"u","Zonal (East-West) wind","m.s-1",3,zu)1378 call wstats(ngrid,"v","Meridional (North-South) wind","m.s-1",3,zv)1379 call wstats(ngrid,"w","Vertical (down-up) wind","m.s-1",3,pw)1380 call wstats(ngrid,"q2","Boundary layer eddy kinetic energy","m2.s-2",3,q2)1381 1382 if (tracer) then1383 do iq=1,nq1384 call wstats(ngrid,noms(iq),noms(iq),'kg/kg',3,zq(1,1,iq))1385 call wstats(ngrid,trim(noms(iq))//'_surf',trim(noms(iq))//'_surf', &1386 'kg m^-2',2,qsurf(1,iq) )1387 1388 ! call wstats(ngrid,trim(noms(iq))//'_reff', &1389 ! trim(noms(iq))//'_reff', &1390 ! 'm',3,reffrad(1,1,iq))1391 1392 end do1393 1394 endif ! end of 'tracer'1395 1396 if(lastcall) then1397 write (*,*) "Writing stats..."1398 call mkstats(ierr)1399 endif1400 1401 endif ! end of 'callstats'1402 1403 1404 1381 !----------------------------------------------------------------------------------------------------- 1405 1382 ! OUTPUT in netcdf file "DIAGFI.NC", containing any variable for diagnostic … … 1475 1452 ! Temporary inclusions for winds diagnostics. 1476 1453 call writediagfi(ngrid,"zdudif","Turbdiff tend. zon. wind","m s-2",3,zdudif) 1477 1454 call writediagfi(ngrid,"zdudyn","Dyn. tend. zon. wind","m s-2",3,zdudyn) 1478 1455 1479 1456 ! Temporary inclusions for heating diagnostics. … … 1491 1468 1492 1469 if (callmufi) then ! For now we assume an given order for tracers ! 1470 #ifdef USE_QTEST 1471 ! Microphysical tracers passed through dyn+phys(except mufi) 1472 call writediagfi(ngrid,"mu_m0as_dp","Dynphys only spherical mode 0th order moment",'kg/kg',3,zq(:,:,1)) 1473 call writediagfi(ngrid,"mu_m3as_dp","Dynphys only spherical mode 3rd order moment",'kg/kg',3,zq(:,:,2)) 1474 call writediagfi(ngrid,"mu_m0af_dp","Dynphys only fractal mode 0th order moment",'kg/kg',3,zq(:,:,3)) 1475 call writediagfi(ngrid,"mu_m3af_dp","Dynphys only fractal mode 3rd order moment",'kg/kg',3,zq(:,:,4)) 1476 ! Microphysical tracers passed through mufi only 1477 call writediagfi(ngrid,"mu_m0as_mo","Mufi only spherical mode 0th order moment",'kg/kg',3,tpq(:,:,1)) 1478 call writediagfi(ngrid,"mu_m3as_mo","Mufi only spherical mode 3rd order moment",'kg/kg',3,tpq(:,:,2)) 1479 call writediagfi(ngrid,"mu_m0af_mo","Mufi only fractal mode 0th order moment",'kg/kg',3,tpq(:,:,3)) 1480 call writediagfi(ngrid,"mu_m3af_mo","Mufi only fractal mode 3rd order moment",'kg/kg',3,tpq(:,:,4)) 1481 #else 1493 1482 call writediagfi(ngrid,"mu_m0as","Spherical mode 0th order moment",'kg/kg',3,zq(:,:,1)) 1494 1483 call writediagfi(ngrid,"mu_m3as","Spherical mode 3rd order moment",'kg/kg',3,zq(:,:,2)) 1495 1484 call writediagfi(ngrid,"mu_m0af","Fractal mode 0th order moment",'kg/kg',3,zq(:,:,3)) 1496 1485 call writediagfi(ngrid,"mu_m3af","Fractal mode 3rd order moment",'kg/kg',3,zq(:,:,4)) 1486 #endif 1497 1487 endif ! end of 'callmufi' 1498 1488 -
trunk/LMDZ.TITAN/libf/phytitan/setspi.F90
r1822 r1897 138 138 end do 139 139 ! note M=L_NSPECTI+1 after loop due to Fortran bizarreness 140 ! --> No fortran bizarreness here... incrementation is performed at the end of the loop... 141 ! --> then when M reached L_NSPECTI, we initialiaze the last element of each array and 142 ! ... increment one last time M... tadaaaa, mystery solved ! 143 ! The same logic is applied on for loop in C ! 140 144 141 145 !=======================================================================
Note: See TracChangeset
for help on using the changeset viewer.