Changeset 3083 for trunk/LMDZ.TITAN/libf/muphytitan
- Timestamp:
- Oct 12, 2023, 10:30:22 AM (15 months ago)
- Location:
- trunk/LMDZ.TITAN/libf/muphytitan
- Files:
-
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LMDZ.TITAN/libf/muphytitan/argparse.F90
r1897 r3083 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 ! file and command line arguments parsing features to Fortran programs. 7 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 ! 3 ! This file is part of SWIFT 4 ! 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 11 ! 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 14 ! 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: argparse.F90 35 23 !! summary: Command-line parser source file. 36 24 !! author: J. Burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 39 27 #include "defined.h" … … 45 33 !! For your own sanity, private methods that call Ancient Gods powers through 46 34 !! evil black magic rituals are not described here. 47 !! 35 !! 48 36 !! If you only wish to have an overview of argparse usage, you'd better go 49 37 !! [here](|url|/page/swift/p01_argparse.html). … … 52 40 USE ERRORS 53 41 USE FSYSTEM, ONLY : fs_termsize 54 USE STRING_OP, getpar => format_paragraph, splitstr => format_string 42 USE STRING_OP, getpar => format_paragraph, splitstr => format_string 55 43 IMPLICIT NONE 56 44 … … 68 56 argparser_add_option, & 69 57 argparser_add_positionals, & 70 argparser_throw_error, & 58 argparser_throw_error, & 71 59 argparser_parse, & 72 60 argparser_help, & … … 85 73 ! =========================== 86 74 87 INTEGER, PARAMETER, PUBLIC :: ap_string = st_string 75 INTEGER, PARAMETER, PUBLIC :: ap_string = st_string 88 76 !! String value type identifier. 89 77 INTEGER, PARAMETER, PUBLIC :: ap_complex = st_complex … … 98 86 !> List of all available actions 99 87 100 INTEGER, PARAMETER, PUBLIC :: ap_store = 188 INTEGER, PARAMETER, PUBLIC :: ap_store = 1 101 89 !! store action ID : Each time the option is seen, values are replaced. 102 INTEGER, PARAMETER, PUBLIC :: ap_append = 2103 !! append action ID : Each time the option is seen, values are appended. 104 INTEGER, PARAMETER, PUBLIC :: ap_count = 390 INTEGER, PARAMETER, PUBLIC :: ap_append = 2 91 !! append action ID : Each time the option is seen, values are appended. 92 INTEGER, PARAMETER, PUBLIC :: ap_count = 3 105 93 !! count action ID : increase a counter each time the option is seen. 106 INTEGER, PARAMETER, PUBLIC :: ap_help = 494 INTEGER, PARAMETER, PUBLIC :: ap_help = 4 107 95 !! help action ID : help is requested ! 96 INTEGER, PARAMETER, PUBLIC :: ap_version = 5 97 !! version action ID : version is requested ! 108 98 109 99 !> List of all available actions 110 INTEGER, DIMENSION( 4), PARAMETER, PRIVATE :: ap_actions = (/ap_store, &100 INTEGER, DIMENSION(5), PARAMETER, PRIVATE :: ap_actions = (/ap_store, & 111 101 ap_append, & 112 102 ap_count, & 113 ap_help/) 103 ap_help, & 104 ap_version/) 114 105 !> List of all recognized types by the parser 115 INTEGER, DIMENSION(5), PARAMETER, PRIVATE :: ap_types = (/ap_string, & 106 INTEGER, DIMENSION(5), PARAMETER, PRIVATE :: ap_types = (/ap_string, & 116 107 ap_logical, & 117 108 ap_complex, & 118 109 ap_integer, & 119 ap_real/) 110 ap_real/) 120 111 !> The unknown flag 121 112 !! 122 !! This flag is only intended to initialize flags. It is set by default during initialization 113 !! This flag is only intended to initialize flags. It is set by default during initialization 123 114 !! and quielty replaced by default flags, if user does not provide the relevant feature. 124 115 INTEGER, PARAMETER :: ap_undef = -1 125 116 126 117 !> Add an option to the parser 127 118 !! … … 131 122 !! ``` 132 123 !! 133 !! The function defines a new argument based on input parameters, checks it and finally sets it 134 !! in the parser. 135 !! 124 !! The function defines a new argument based on input parameters, checks it and finally sets it 125 !! in the parser. 126 !! 136 127 !! In its first version both short (`sflag`) and long (`lflag`) options flags are mandatory. In its second 137 128 !! form, a single flag (`flag`) is expected: the method will automatically deduce if it belongs to short or 138 129 !! a long option flag based on the number of hyphens given. 139 !! 130 !! 140 131 !! `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]): 141 132 !! … … 145 136 !! - `ap_integer` ([[string_op(module):st_integer(variable)]]) 146 137 !! - `ap_real` ([[string_op(module):st_real(variable)]]) 147 !! 138 !! 148 139 !! `action` value should be one of the following module constants: 149 140 !! … … 162 153 !! "X" | Exactly X values. Where X is the string representation of an integer (0 is accepted). 163 154 !! 164 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 155 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 165 156 !! produced by misuse of the function arguments. In such case, the program should be 166 157 !! stopped: note that such error should not occur in _released_ programs. … … 168 159 MODULE PROCEDURE ap_add_option_1, ap_add_option_2 169 160 END INTERFACE 170 161 171 162 !> Get positional argument value(s) 172 163 INTERFACE argparser_get_positional 173 164 MODULE PROCEDURE ap_get_positional_sc, ap_get_positional_ve 174 END INTERFACE 165 END INTERFACE 175 166 176 167 !> Get optional argument value(s) … … 179 170 !! FUNCTION argparser_get_value(this,name,output) RESULT(err) 180 171 !! ``` 181 !! 172 !! 182 173 !! This is the generic method that can be used to retrieve any kind of argument value(s) from the parser for a given 183 174 !! argument name (as defined by the `dest` argument of [[argparse(module):argparser_add_option(interface)]]. 184 175 !! All the methods have the same dummy arguments only `output` dummy argument differs in type and shape. 185 !! 176 !! 186 177 !! @note 187 178 !! For string vector, `output` is expected to be an allocatable vector of **assumed length** 188 179 !! strings (thus string length is left to user responsability). 189 !! A good compromise for strings length is to use the [[string_op(module):st_slen(variable)]] 180 !! A good compromise for strings length is to use the [[string_op(module):st_slen(variable)]] 190 181 !! parameter. 191 182 INTERFACE argparser_get_value … … 197 188 !> Interface to [[argparse(module):argc(type)]] getters 198 189 !! 199 !! All the functions have the same prototype, only kind and type of arguments changed 190 !! All the functions have the same prototype, only kind and type of arguments changed 200 191 !! from a function to the other. 201 INTERFACE argc_get_value 192 INTERFACE argc_get_value 202 193 MODULE PROCEDURE ac_get_dv_sc, ac_get_rv_sc, ac_get_iv_sc, ac_get_lv_sc, & 203 194 ac_get_cv_sc, ac_get_sv_sc, ac_get_dv_ve, ac_get_rv_ve, & … … 230 221 !! Defines a command-line argument. 231 222 !! 232 !! An [[argparse(module):argc(type)]] object stores all information about a command-line 223 !! An [[argparse(module):argc(type)]] object stores all information about a command-line 233 224 !! argument, that is: 234 225 !! 235 226 !! - its name 236 !! - its optional flags 227 !! - its optional flags 237 228 !! - its type 238 229 !! - its action … … 253 244 TYPE(words) :: meta 254 245 !! Meta variable name(s) of the argument 255 #if HAVE_FTNDTSTR 246 #if HAVE_FTNDTSTR 256 247 CHARACTER(len=:), ALLOCATABLE :: default 257 !! Default flag 248 !! Default flag 258 249 CHARACTER(len=:), ALLOCATABLE :: name 259 250 !! Name of the argument (needed to check and retrieve its value(s)) 260 CHARACTER(len=:), ALLOCATABLE :: lflag 251 CHARACTER(len=:), ALLOCATABLE :: lflag 261 252 !! Long flag option (st_short_len max chars !) 262 253 CHARACTER(len=:), ALLOCATABLE :: help … … 264 255 #else 265 256 CHARACTER(len=st_slen) :: default = "" 266 !! Default flag 257 !! Default flag 267 258 CHARACTER(len=st_slen) :: name 268 259 !! Name of the argument (needed to check and retrieve its value(s)) … … 278 269 !! Command-line parser 279 270 !! 280 !! This is the main object of the module. It stores definitions of CLI arguments and 271 !! This is the main object of the module. It stores definitions of CLI arguments and 281 272 !! their value(s) once the command-line have been parsed. 282 273 TYPE(argc), PRIVATE, ALLOCATABLE, DIMENSION(:) :: args … … 298 289 #if HAVE_FTNDTSTR 299 290 CHARACTER(len=:), PRIVATE, ALLOCATABLE :: usg 300 !! Program command usage 291 !! Program command usage 301 292 CHARACTER(len=:), PRIVATE, ALLOCATABLE :: descr 302 293 !! Program help description 303 CHARACTER(len=:), PRIVATE, ALLOCATABLE :: eplg 294 CHARACTER(len=:), PRIVATE, ALLOCATABLE :: eplg 304 295 !! Program help epilog 296 CHARACTER(len=:), PRIVATE, ALLOCATABLE :: vers 297 !! Application version string 305 298 #else 306 299 CHARACTER(len=st_llen), PRIVATE :: usg 307 !! Program command usage 300 !! Program command usage 308 301 CHARACTER(len=st_llen), PRIVATE :: descr 309 302 !! Program help description 310 CHARACTER(len=st_llen), PRIVATE :: eplg 303 CHARACTER(len=st_llen), PRIVATE :: eplg 311 304 !! Program help epilog 305 CHARACTER(len=st_llen), PRIVATE :: vers 306 !! Application version string 312 307 #endif 313 INTEGER, PRIVATE :: mxhlpos = 20 308 INTEGER, PRIVATE :: mxhlpos = 20 314 309 !! Position of the short help for options 315 310 INTEGER, PRIVATE :: width = 0 316 !! Maximum width of the help 311 !! Maximum width of the help 317 312 LOGICAL, PRIVATE :: init = .false. 318 313 !! Initialization control flag 319 #if HAVE_FTNPROC 314 #if HAVE_FTNPROC 320 315 321 316 CONTAINS … … 341 336 PROCEDURE, PUBLIC :: parse => argparser_parse 342 337 !! Parse the command-line (or the given input string). 343 PROCEDURE, PUBLIC :: help => argparser_help 338 PROCEDURE, PUBLIC :: help => argparser_help 344 339 !! Compute and print help 340 PROCEDURE, PUBLIC :: version => argparser_version 341 !! print version string 345 342 PROCEDURE, PUBLIC :: found => argparser_found 346 343 !! Check if an optional argument has been found on the command-line … … 356 353 GENERIC, PUBLIC :: add_option => ap_add_option_1, & 357 354 ap_add_option_2 358 !> Get the values of the positionals stored in the parser. 355 !> Get the values of the positionals stored in the parser. 359 356 GENERIC, PUBLIC :: get_positional => ap_get_positional_sc, & 360 357 ap_get_positional_ve … … 372 369 ap_get_cv_ve, & 373 370 ap_get_sv_ve 374 #endif 371 #endif 375 372 END TYPE argparser 376 373 … … 380 377 ! ------------------------------- 381 378 382 FUNCTION new_argparser(usg, dsc, epg, add_help, width, max_help_pos) RESULT(this)379 FUNCTION new_argparser(usg, dsc, epg, add_help, add_version, version_string,width, max_help_pos) RESULT(this) 383 380 !! Initialize an argparser object. 384 !! 381 !! 385 382 !! The method initializes (properly) an [[argparse(module):argparser(type)]] object. 386 !! Even if all the arguments are optional, it is mandatory to **call** the method 383 !! Even if all the arguments are optional, it is mandatory to **call** the method 387 384 !! before using an argparser object. 388 385 CHARACTER(len=*), INTENT(in), OPTIONAL :: usg … … 394 391 !! An optional string with the epilog of the program's help 395 392 LOGICAL, INTENT(in), OPTIONAL :: add_help 396 !! An optional boolean flag with `.true.` to automatically set an option for program's help. 393 !! An optional boolean flag with `.true.` to automatically set an option for program's help. 397 394 !! Note that, the option flags `-h` and `--help` are no more available in that case. 395 LOGICAL, INTENT(in), OPTIONAL :: add_version 396 !! An optional boolean flag with `.true.` to automatically set an option for program's help. 397 !! Note that, the option flags `-V` and `--version` are no more available in that case. 398 CHARACTER(len=*), INTENT(in), OPTIONAL :: version_string 399 !! An optional string with the text to display if the *version* option is found on the 400 !! command line. The text is displayed without any format. 398 401 INTEGER, INTENT(in), OPTIONAL :: width 399 402 !! An optional integer with the maximum width the help text. 400 403 INTEGER, INTENT(in), OPTIONAL :: max_help_pos 401 !! An optional integer with the maximum position of the help string for each option of 402 !! the program when help is requested. Note that this value is just an indicator. The 403 !! helper computes the minimum position between this value and the maximum length of the 404 !! An optional integer with the maximum position of the help string for each option of 405 !! the program when help is requested. Note that this value is just an indicator. The 406 !! helper computes the minimum position between this value and the maximum length of the 404 407 !! options flags. 405 TYPE(argparser) :: this 408 TYPE(argparser) :: this 406 409 !! An initialized argparse object. 407 410 INTEGER :: zh … … 413 416 IF (PRESENT(dsc)) THEN ; this%descr=dsc ; ELSE ; this%descr='' ; ENDIF 414 417 IF (PRESENT(epg)) THEN ; this%eplg=epg ; ELSE ; this%eplg='' ; ENDIF 415 CALL fs_termsize(zh,this%width) 418 CALL fs_termsize(zh,this%width) 416 419 IF (PRESENT(width)) this%width = MAX(width,50) 417 420 IF(PRESENT(max_help_pos)) this%mxhlpos = MAX(5,max_help_pos) … … 422 425 action=ap_help, help="Print this help and quit") 423 426 ENDIF 427 IF (PRESENT(add_version)) THEN 428 IF (add_version) & 429 err = argparser_add_option(this,'version',sflag='-V',lflag='--version', & 430 action=ap_version, help="Print the application version and quit") 431 this%vers = '' 432 if (PRESENT(version_string)) this%vers = TRIM(version_string) 433 ENDIF 424 434 RETURN 425 435 END FUNCTION new_argparser … … 432 442 !! @note If **fccp** has not been built with support for finalization subroutine, 433 443 !! it should be called whenever the argparser object is no more used. 434 TYPE(argparser), INTENT(inout) :: this 444 TYPE(argparser), INTENT(inout) :: this 435 445 !! An argparser object 436 446 IF (ALLOCATED(this%args)) THEN … … 466 476 !! 467 477 !! The method initializes the entry for positional arguments in the parser. 468 !! Positional arguments are always seen by the parser as strings and the 478 !! Positional arguments are always seen by the parser as strings and the 469 479 !! default associated action is 'store'. 470 480 OBJECT(argparser), INTENT(inout) :: this … … 475 485 !! A vector of strings with the the displayed value name(s) of the positionals in the help command 476 486 CHARACTER(len=*), INTENT(in), OPTIONAL :: help 477 !! An optional string with a short description of the positional argument(s) 487 !! An optional string with a short description of the positional argument(s) 478 488 TYPE(error) :: err 479 489 !! Error object with the first error encountered in the process. … … 481 491 CHARACTER(len=:), ALLOCATABLE :: sf,lf,de 482 492 err = noerror 483 IF (.NOT.this%init) THEN 484 err = error("argparse: parser not initialized yet",-1) 493 IF (.NOT.this%init) THEN 494 err = error("argparse: parser not initialized yet",-1) 485 495 RETURN 486 496 ENDIF … … 504 514 RETURN 505 515 ENDIF 506 this%have_posal = this%posals%nrec /= 0 516 this%have_posal = this%posals%nrec /= 0 507 517 ENDIF 508 518 RETURN … … 514 524 !! given as optional argument and fills the parser's arguments. 515 525 !! @note 516 !! If `cmd_line` is provided it should not contains the name of the program or 517 !! the parsing process will certainly failed: program name will be seen as the 518 !! first positional argument and all tokens of the string will then be seen as 526 !! If `cmd_line` is provided it should not contains the name of the program or 527 !! the parsing process will certainly failed: program name will be seen as the 528 !! first positional argument and all tokens of the string will then be seen as 519 529 !! positional. 520 530 OBJECT(argparser), INTENT(inout) :: this … … 523 533 !! An optional string to parse that substitute for the actual command-line. 524 534 LOGICAL, INTENT(in), OPTIONAL :: auto 525 !! An optional boolean flag with `.true.` to instruct the parser wether to perform 535 !! An optional boolean flag with `.true.` to instruct the parser wether to perform 526 536 !! automatic actions or not when error occur during parsing. If `auto` is enabled, 527 537 !! then the parser dumps program's usage and stops the program on error. … … 530 540 CHARACTER(len=:), ALLOCATABLE :: cline,z 531 541 LOGICAL :: zauto 532 LOGICAL :: rhelp 533 INTEGER :: l 542 LOGICAL :: rhelp 543 LOGICAL :: rvers 544 INTEGER :: l 534 545 TYPE(words) :: cmd_tokens 535 546 err = noerror … … 537 548 err = error("parser not initialized yet",-1) ; RETURN 538 549 ENDIF 539 rhelp = .false. 550 rhelp = .false. ; rvers = .false. 540 551 zauto = .false. ; IF (PRESENT(auto)) zauto = auto 541 552 IF (PRESENT(cmd_line)) THEN 542 553 ALLOCATE(cline,source=cmd_line) 543 554 ELSE 544 CALL GET_COMMAND(length=l) 555 CALL GET_COMMAND(length=l) 545 556 ALLOCATE(CHARACTER(len=l) :: z) ; CALL GET_COMMAND(z) 546 557 CALL GET_COMMAND_ARGUMENT(0,length=l) … … 557 568 EXIT ! ... No :) 558 569 ELSE 559 err = ap_split_cmd(this,cline,cmd_tokens,rhelp) 570 err = ap_split_cmd(this,cline,cmd_tokens,rhelp) 560 571 ! we only stops processing if : 561 572 ! - the internal error (string length) is raised … … 565 576 CALL words_reset(cmd_tokens) ! not mandatory... at least theoretically 566 577 ! Parses the options 567 err = ap_parse_options(this,cmd_tokens,rhelp )578 err = ap_parse_options(this,cmd_tokens,rhelp,rvers) 568 579 IF (err /= noerror) EXIT 569 ! exit loop if help is requested. Parser is not completely filled but we570 ! expect someone to use the help action..571 IF (rhelp ) EXIT580 ! exit loop if help or version is requested. Parser is not completely filled but we 581 ! expect someone to use the help or version actions... 582 IF (rhelp.OR.rvers) EXIT 572 583 ! Parses positionals 573 err = ap_parse_positionals(this,cmd_tokens) 584 err = ap_parse_positionals(this,cmd_tokens) 574 585 EXIT ! A one iterated loop :) 575 586 ENDDO … … 581 592 IF (zauto) THEN 582 593 IF (rhelp) CALL argparser_help(this) 594 IF (rvers) CALL argparser_version(this) 583 595 IF (err /= 0) CALL argparser_throw_error(this,err,2) 584 596 ENDIF 585 RETURN 597 RETURN 586 598 END FUNCTION argparser_parse 599 600 SUBROUTINE argparser_version(this) 601 !! Print version string and exit program 602 OBJECT(argparser), INTENT(inout) :: this 603 !! An argparser object reference 604 WRITE(stdout,'(a)') TRIM(this%vers) 605 CALL argparser_clear(this) 606 CALL EXIT(0) 607 END SUBROUTINE argparser_version 587 608 588 609 SUBROUTINE argparser_help(this) … … 606 627 !! 607 628 !! The method performs the following actions: 608 !! 629 !! 609 630 !! - Print the usage command of the program 610 631 !! - Dump the provided @p error message … … 614 635 !! 615 636 !! The error message is always printed in standard error output. 616 !! @note 637 !! @note 617 638 !! If errors::error::id is 0 the method does nothing. 618 639 OBJECT(argparser), INTENT(inout) :: this … … 638 659 FUNCTION argparser_found(this,argname) RESULT(found) 639 660 !! Check wether an argument has been found in the command-line. 640 !! @note 661 !! @note 641 662 !! Keep in mind that arguments in the parser always have a default 642 663 !! value. This method is not intended to check if an argument has a value but … … 663 684 CHARACTER(len=*), INTENT(in) :: argname 664 685 !! Name of the argument to check. 665 INTEGER :: num 686 INTEGER :: num 666 687 !! The number of actual values stored in the argument 667 688 INTEGER :: idx … … 693 714 INTEGER :: ret 694 715 !! The number of actual positionals arguments 695 ret = 0 716 ret = 0 696 717 IF (this%have_posal) THEN 697 718 ret = words_length(this%posals%values) 698 719 ENDIF 699 END FUNCTION argparser_get_num_positional 720 END FUNCTION argparser_get_num_positional 700 721 701 722 ! argparser private methods … … 703 724 704 725 FUNCTION ap_check_state(this) RESULT(err) 705 !! Check current parser state 726 !! Check current parser state 706 727 !! The method returns an error based on the current parser's state: 707 728 !! - Parser is ready (0) … … 712 733 !! An argparser object reference 713 734 TYPE(error) :: err 714 !! Error object with the *status* of the parser 735 !! Error object with the *status* of the parser 715 736 err = noerror 716 737 IF (this%parsed == -1) THEN … … 719 740 err = error("argparse: command-line parsing failed",-20) 720 741 ELSE IF (.NOT.this%init) THEN 721 err = error("argparse: parser not initialized yet",-1) 742 err = error("argparse: parser not initialized yet",-1) 722 743 ENDIF 723 744 RETURN … … 732 753 INTEGER :: i 733 754 TYPE(argc), ALLOCATABLE, DIMENSION(:) :: tmp 734 TYPE(error) :: err 755 TYPE(error) :: err 735 756 IF (.NOT.this%init) THEN 736 757 err = error("parser not initialized yet",-1) ; RETURN … … 739 760 IF (this%nargs == 0) THEN 740 761 ALLOCATE(this%args(1)) 741 this%args(1) = arg 742 this%nargs = 1 762 this%args(1) = arg 763 this%nargs = 1 743 764 RETURN 744 765 ENDIF … … 749 770 ALLOCATE(tmp(this%nargs)) 750 771 DO i=1,this%nargs ; tmp(i) = this%args(i) ; ENDDO 751 CALL clear_argc(this%args) 752 DEALLOCATE(this%args) 772 CALL clear_argc(this%args) 773 DEALLOCATE(this%args) 753 774 this%nargs = this%nargs+1 ; ALLOCATE(this%args(this%nargs)) 754 775 DO i=1,this%nargs-1 ; this%args(i) = tmp(i) ; ENDDO … … 782 803 ! empty parser 783 804 IF (this%nargs == 0) RETURN 784 DO i=1, this%nargs 805 DO i=1, this%nargs 785 806 IF ((nn /= 0 .AND. TRIM(this%args(i)%name) == TRIM(lna)) .OR. & 786 807 (ns /= 0 .AND. TRIM(this%args(i)%sflag) == TRIM(lsf)) .OR. & … … 796 817 !! Add an argument to the parser (interface #1) 797 818 !! 798 !! The function defines a new argument based on input parameters, checks it and finally sets it 819 !! The function defines a new argument based on input parameters, checks it and finally sets it 799 820 !! in the parser. Both **short and long options flags** are mandatory input arguments of the function. 800 !! 821 !! 801 822 !! `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]): 802 823 !! - ap_string ([[string_op(module):st_string(variable)]]) … … 805 826 !! - ap_integer ([[string_op(module):st_integer(variable)]]) 806 827 !! - ap_real ([[string_op(module):st_real(variable)]]) 807 !! 828 !! 808 829 !! `action` value should be one of the following module constants: 809 830 !! - [[argparse(module):ap_store(variable)]] … … 830 851 !! A string (3 characters minimum) with the long option flag of the argument 831 852 INTEGER, INTENT(in), OPTIONAL :: type 832 !! An integer with the type of the argument 853 !! An integer with the type of the argument 833 854 INTEGER, INTENT(in), OPTIONAL :: action 834 !! An integer with the action of the argument 855 !! An integer with the action of the argument 835 856 CHARACTER(len=*), INTENT(in), OPTIONAL :: default 836 857 !! A string with the default value of the argument if not provided in the CLI 837 858 CHARACTER(len=*), INTENT(in), OPTIONAL :: nrec 838 !! A string with the expected number of specified values for the argument in the CLI. 859 !! A string with the expected number of specified values for the argument in the CLI. 839 860 CHARACTER(len=*), INTENT(in), OPTIONAL :: help 840 861 !! A string with a short description of the argument … … 853 874 de ='' ; IF (PRESENT(default)) de = TRIM(default) 854 875 IF (.NOT.this%init) THEN 855 err = error("argparse: parser not initialized yet",-1) 876 err = error("argparse: parser not initialized yet",-1) 856 877 RETURN 857 878 ENDIF … … 876 897 !! Add an argument to the parser (interface #2) 877 898 !! 878 !! The function is a wrapper to ap_add_option_1. In this version, 899 !! The function is a wrapper to ap_add_option_1. In this version, 879 900 !! only one option flag is required. The method only checks for the (trimmed) length of **flag** in 880 !! order to choose wether it is a **short** or **long** option flag. Then the function simply calls 901 !! order to choose wether it is a **short** or **long** option flag. Then the function simply calls 881 902 !! ap_add_option_1 to set the argument. 882 !! 903 !! 883 904 !! Other dummy arguments have the same meaning as in ap_add_option_1. 884 905 OBJECT(argparser), INTENT(inout) :: this … … 891 912 !! A string with the type of the argument 892 913 INTEGER, INTENT(in), OPTIONAL :: action 893 !! A string with the action of the argument 914 !! A string with the action of the argument 894 915 CHARACTER(len=*), INTENT(in), OPTIONAL :: default 895 916 !! A string with the default value of the argument if not provided in the CLI 896 917 CHARACTER(len=*), INTENT(in), OPTIONAL :: nrec 897 !! A string with the expected number of specified values for the argument in the CLI. 918 !! A string with the expected number of specified values for the argument in the CLI. 898 919 CHARACTER(len=*), INTENT(in), OPTIONAL :: help 899 920 !! A string with a short description of the argument … … 956 977 END FUNCTION ap_check_in_parser 957 978 958 FUNCTION ap_parse_options(this,cmd,help_req ) RESULT(err)979 FUNCTION ap_parse_options(this,cmd,help_req,vers_req) RESULT(err) 959 980 !! Parse options of the internal command line 960 !! This (internal) function manages the parsing of the command line options. 981 !! This (internal) function manages the parsing of the command line options. 961 982 OBJECT(argparser), INTENT(inout), TARGET :: this 962 983 !! An argparser object reference … … 965 986 LOGICAL, INTENT(out) :: help_req 966 987 !! An output logical flag with `.true.` if help option has been found, `.false.` otherwise 988 LOGICAL, INTENT(out) :: vers_req 989 !! An output logical flag with `.true.` if version option has been found, `.false.` otherwise 967 990 TYPE(error) :: err 968 991 !! Error object with the first error encountered in the process … … 976 999 ! get current element 977 1000 elt = words_current(cmd) 978 ! check element kind: is it an option flag (-1/0) or a value (1)?1001 ! check element kind: is it an option flag (-1/0) or a value (1)? 979 1002 ic = ap_check_string(this,elt,arg_idx) 980 1003 IF (ic <= 0) THEN 981 1004 IF (arg_idx /= -1) THEN 982 1005 err = ap_fill_argument(this,cmd,this%args(arg_idx)) 983 IF (err == 0 .AND. this%args(arg_idx)%paction == ap_help) THEN 984 this%parsed = 1 985 err = argparser_get_value(this,'help',help_req) 986 EXIT 1006 IF (err == 0) THEN 1007 IF (this%args(arg_idx)%paction == ap_help) THEN 1008 this%parsed = 1 1009 err = argparser_get_value(this,'help',help_req) 1010 EXIT 1011 ELSE IF (this%args(arg_idx)%paction == ap_version) THEN 1012 this%parsed = 1 1013 err = argparser_get_value(this,'version',vers_req) 1014 EXIT 1015 ENDIF 987 1016 ENDIF 988 1017 IF (err /= 0) EXIT … … 998 1027 ! iterates to next value 999 1028 CALL words_next(cmd) 1000 ENDDO 1029 ENDDO 1001 1030 1002 1031 ! Do we need to check for error here ? … … 1020 1049 IF (this%args(i)%nrec < nv) THEN 1021 1050 err = ac_fmt_val_err(this%args(i),-18) ! extra values 1022 ELSE 1051 ELSE 1023 1052 err = ac_fmt_val_err(this%args(i),-17) ! missing values 1024 1053 ENDIF 1025 ENDIF 1054 ENDIF 1026 1055 ENDDO 1027 1056 IF (err /= 0) this%parsed = 0 1028 1057 RETURN 1029 END FUNCTION ap_parse_options 1058 END FUNCTION ap_parse_options 1030 1059 1031 1060 FUNCTION ap_parse_positionals(this,cmd) RESULT(err) 1032 1061 !! Parse positional arguments of the internal command line 1033 !! This (internal) function manages the parsing of the command line positional arguments. 1062 !! This (internal) function manages the parsing of the command line positional arguments. 1034 1063 OBJECT(argparser), INTENT(inout) :: this 1035 1064 !! An argparser object reference … … 1044 1073 1045 1074 ! no positional required but current word is valid 1046 ! Either : no positional required but valid element is present 1075 ! Either : no positional required but valid element is present 1047 1076 ! Or : positional required but no valid element is present 1048 1077 IF ((this%have_posal.AND..NOT.words_valid(cmd)) .OR. & … … 1054 1083 CALL words_clear(this%posals%values) 1055 1084 this%posals%fnd = .true. 1056 DO 1085 DO 1057 1086 na = words_length(this%posals%values) 1058 1087 IF (words_valid(cmd)) THEN … … 1090 1119 !! Fill an argument with values 1091 1120 !! 1092 !! The function parses remaining parts of the command line from the position of 1093 !! the given argument and attempts to retrieve its value(s) (if any). 1121 !! The function parses remaining parts of the command line from the position of 1122 !! the given argument and attempts to retrieve its value(s) (if any). 1094 1123 !! Several tests are performed and may raise errors. The function always stops 1095 1124 !! at the first error encountered which can be one of the following : … … 1103 1132 !! The command line 1104 1133 TYPE(argc), INTENT(inout), TARGET :: arg 1105 !! An argc object reference with the argument currently processed. 1134 !! An argc object reference with the argument currently processed. 1106 1135 TYPE(error) :: err 1107 1136 !! Error object with the first error encountered in the process 1108 INTEGER :: ca, isopt, itmp 1137 INTEGER :: ca, isopt, itmp 1109 1138 LOGICAL :: ltmp 1110 1139 CHARACTER(len=:), ALLOCATABLE :: elt … … 1126 1155 IF (arg%paction == ap_count) THEN 1127 1156 elt = words_pop(arg%values) 1128 READ(elt,*) itmp ; itmp = itmp + 1 1157 READ(elt,*) itmp ; itmp = itmp + 1 1129 1158 CALL words_append(arg%values,TO_STRING(itmp)) 1130 ELSE IF (arg%ptype == ap_logical) THEN 1159 ELSE IF (arg%ptype == ap_logical) THEN 1131 1160 elt = words_pop(arg%values) 1132 READ(elt,*) ltmp 1161 READ(elt,*) ltmp 1133 1162 CALL words_append(arg%values,TO_STRING(.NOT.ltmp)) 1134 1163 ENDIF 1135 1164 ELSE 1136 1165 ! For any other case, the algorithm is quite simple : 1137 ! We consume tokens of the command-line until either the end or 1166 ! We consume tokens of the command-line until either the end or 1138 1167 ! the next option (or '--' separator) 1139 1168 ! When the exit condition is met we perform some tests based on the … … 1155 1184 ! 1) we have consumed all argument of command line 1156 1185 ! 2) current argument is not a value ! 1157 ! 3) current argument the separator '--' 1186 ! 3) current argument the separator '--' 1158 1187 IF (isopt <= 0 .OR. TRIM(elt)=='--') CALL words_previous(cmd) 1159 IF (arg%nrec == -2 .AND. words_length(arg%values) == 0) & 1188 IF (arg%nrec == -2 .AND. words_length(arg%values) == 0) & 1160 1189 err = ac_fmt_val_err(arg,-17) 1161 1190 IF (arg%paction /= ap_append .AND. arg%nrec > 0 .AND. ca /= arg%nrec) & … … 1178 1207 END FUNCTION ap_fill_argument 1179 1208 1180 FUNCTION ap_split_cmd(this,string,new_cmd,rhelp) RESULT(err) 1209 FUNCTION ap_split_cmd(this,string,new_cmd,rhelp) RESULT(err) 1181 1210 !! Preprocess the command line 1182 !! The function reads and splits the given string so merged options/values 1211 !! The function reads and splits the given string so merged options/values 1183 1212 !! are splitted and saves the resulting string elements in a list of words. 1184 1213 !! @warning 1185 1214 !! For compilers that does not support allocatable strings in derived types, 1186 1215 !! computation are highly dependent of [[string_op(module):st_slen(variable): 1187 !! tokens length are limited by this parameter. 1216 !! tokens length are limited by this parameter. 1188 1217 IMPLICIT NONE 1189 1218 OBJECT(argparser), INTENT(in) :: this … … 1193 1222 TYPE(words), INTENT(out) :: new_cmd 1194 1223 !! An output [[string_op(module):words(type)]] object with the processed command line 1195 LOGICAL, INTENT(out) :: rhelp 1224 LOGICAL, INTENT(out) :: rhelp 1196 1225 !! An output boolean flag with `.true.` if help is requested, `.false.` otherwise 1197 1226 TYPE(error) :: err … … 1199 1228 INTEGER :: isopt,j,tl,res 1200 1229 CHARACTER(len=:), ALLOCATABLE :: elt 1201 TYPE(words) :: splitted 1230 TYPE(words) :: splitted 1202 1231 INTEGER :: arg_idx 1203 1232 err = noerror ; rhelp = .false. 1204 1233 IF (LEN_TRIM(string) == 0) THEN 1205 err = error('internal error (empty string)',-255) 1234 err = error('internal error (empty string)',-255) 1206 1235 RETURN 1207 1236 ENDIF … … 1218 1247 res = ap_check_string(this,"-"//elt(j:j),arg_idx) 1219 1248 ! great we have another short option flag 1220 IF (res == -1 .AND. arg_idx /= -1) THEN ! another short option ! 1249 IF (res == -1 .AND. arg_idx /= -1) THEN ! another short option ! 1221 1250 rhelp = (this%args(arg_idx)%paction == ap_help.OR.rhelp) 1222 1251 ! we must not set some argument's values here for help argument 1223 ! if auto is not set the parse method will disable the option 1252 ! if auto is not set the parse method will disable the option 1224 1253 ! during next! parsing process 1225 1254 CALL words_append(new_cmd,"-"//elt(j:j)) … … 1237 1266 rhelp = (this%args(arg_idx)%paction == ap_help.OR.rhelp) 1238 1267 ! we must not set some argument's values here for help argument 1239 ! if auto is not set the parse method will disable the option during 1268 ! if auto is not set the parse method will disable the option during 1240 1269 ! next parsing process 1241 1270 CALL words_append(new_cmd,TRIM(elt)) … … 1247 1276 RETURN 1248 1277 END FUNCTION ap_split_cmd 1249 1278 1250 1279 FUNCTION ap_check_string(this,string,idx) RESULT(ret) 1251 1280 !! Check if a string is an option flag … … 1259 1288 INTEGER, INTENT(out), OPTIONAL :: idx 1260 1289 !! An optional output intger with the index of the afferent argument in the parser (-1 if not found) 1261 INTEGER :: ret 1290 INTEGER :: ret 1262 1291 !! Return code with the following possible values: 1263 1292 !! - -1 if the string is a SHORT option flag … … 1272 1301 ! The combination of the (optional) output index and the return code 1273 1302 ! allows to check if an option is known or not 1274 ret = 1 1303 ret = 1 1275 1304 ! '--' is special : it is a separator that is seen as a value. 1276 1305 IF (TRIM(string) == '--') RETURN … … 1303 1332 CHARACTER(len=:), ALLOCATABLE :: copt,spc,opts,text 1304 1333 INTEGER :: i,j,ia,optmw,i1,io,n,zw,zh 1305 IF (this%width == 0) CALL fs_termsize(zh,this%width) 1334 IF (this%width == 0) CALL fs_termsize(zh,this%width) 1306 1335 zw = this%width 1307 1336 ! Sets usage … … 1312 1341 hlp = TRIM(this%usg)//NEW_LINE('A')//NEW_LINE('A') 1313 1342 ! Sets description 1314 IF (LEN_TRIM(this%descr) /= 0) & 1343 IF (LEN_TRIM(this%descr) /= 0) & 1315 1344 hlp=hlp//getpar(this%descr,zw,2)//NEW_LINE('A')//NEW_LINE('A') 1316 1345 ! Sets positionals … … 1380 1409 !! Format command line usage. 1381 1410 !! 1382 !! The subroutine creates and formats the command line usage of the 1383 !! given argparser object. If [[argparser(type):usg(variable)]] is already set (i.e. not empty) 1384 !! then the method only computes the maximum width of the option part of the usage command 1385 !! (see `optmw` argument description) if needed. In the other case, the method builds the usage 1411 !! The subroutine creates and formats the command line usage of the 1412 !! given argparser object. If [[argparser(type):usg(variable)]] is already set (i.e. not empty) 1413 !! then the method only computes the maximum width of the option part of the usage command 1414 !! (see `optmw` argument description) if needed. In the other case, the method builds the usage 1386 1415 !! line based on the arguments stored in the parser. 1387 1416 OBJECT(argparser), INTENT(inout) :: this 1388 1417 !! An argparser object reference 1389 1418 INTEGER, INTENT(out), OPTIONAL :: optmw 1390 !! An optional integer with the maximum length of the option part of the usage command. 1419 !! An optional integer with the maximum length of the option part of the usage command. 1391 1420 !! This variable is intended to set a fancy indentation while printing option in the helper. 1392 1421 CHARACTER(len=:), ALLOCATABLE :: usage, idts, copt,pgn … … 1428 1457 usage = usage(:)//TRIM(copt) 1429 1458 ENDIF 1430 ENDIF 1459 ENDIF 1431 1460 this%usg = usage 1432 1461 ELSE … … 1439 1468 optmw = omw 1440 1469 ENDIF 1441 ENDIF 1470 ENDIF 1442 1471 END SUBROUTINE ap_format_usage 1443 1472 … … 1462 1491 IF (ALLOCATED(other%descr)) this%descr = other%descr 1463 1492 IF (ALLOCATED(other%eplg)) this%eplg = other%eplg 1493 IF (ALLOCATED(other%vers)) this%vers = other%vers 1464 1494 #else 1465 1495 this%usg = other%usg 1466 1496 this%descr = other%descr 1467 1497 this%eplg = other%eplg 1498 this%vers = other%vers 1468 1499 #endif 1469 1500 this%mxhlpos = other%mxhlpos … … 1507 1538 FUNCTION ac_equals_arg(this,other) RESULT(ret) 1508 1539 !! Check if two arguments are identical 1509 !! The method checks if two arguments are equal based on their name, short option flag and long 1510 !! option flag.Two arguments are considered equals if at least one of these three members is equal 1540 !! The method checks if two arguments are equal based on their name, short option flag and long 1541 !! option flag.Two arguments are considered equals if at least one of these three members is equal 1511 1542 !! and not empty. 1512 1543 TYPE(argc), INTENT(in) :: this … … 1529 1560 tlf=TRIM(this%lflag) ; olf=TRIM(other%lflag) 1530 1561 #endif 1531 tn=LEN_TRIM(tna) ; on=LEN_TRIM(ona) 1562 tn=LEN_TRIM(tna) ; on=LEN_TRIM(ona) 1532 1563 tl=LEN_TRIM(tlf) ; ol=LEN_TRIM(olf) 1533 ts=LEN_TRIM(tsf) ; os=LEN_TRIM(osf) 1564 ts=LEN_TRIM(tsf) ; os=LEN_TRIM(osf) 1534 1565 ! check on name : 1535 1566 ! Returns True if at least of name, sflag and lflag is set to non-empty … … 1537 1568 ret = ((tn/=0 .AND. on==tn) .AND. tna == ona) .OR. & 1538 1569 ((tl/=0 .AND. ol==tl) .AND. tlf == olf) .OR. & 1539 ((ts/=0 .AND. os==ol) .AND. tsf == osf) 1570 ((ts/=0 .AND. os==ol) .AND. tsf == osf) 1540 1571 DEALLOCATE(tna,ona,tsf,osf,tlf,olf) 1541 1572 END FUNCTION ac_equals_arg … … 1543 1574 FUNCTION ac_differs_arg(this,other) RESULT(ret) 1544 1575 !! Check if two arguments are different 1545 !! The method checks if two arguments are different based on their names, short option flag 1576 !! The method checks if two arguments are different based on their names, short option flag 1546 1577 !! and long option flag. 1547 !! @note 1578 !! @note 1548 1579 !! This function is the extact contrary of [[argparse(module):ac_equals_arg(function)]] ! 1549 1580 TYPE(argc), INTENT(in) :: this … … 1558 1589 SUBROUTINE ac_clear_arg_sc(arg) 1559 1590 !! argc destructor (scalar) 1560 !! The subroutine frees all memory used by an argc object and resets its member to 1591 !! The subroutine frees all memory used by an argc object and resets its member to 1561 1592 !! default values. 1562 1593 TYPE(argc), INTENT(inout) :: arg … … 1606 1637 args(i)%lflag = "" 1607 1638 #endif 1608 ENDDO 1639 ENDDO 1609 1640 END SUBROUTINE ac_clear_arg_ve 1610 1641 … … 1622 1653 TYPE(argc), INTENT(in) :: this 1623 1654 !! An argc object 1624 INTEGER :: num 1655 INTEGER :: num 1625 1656 !! The number of values stored in the argument 1626 1657 num = words_length(this%values) … … 1629 1660 FUNCTION ac_get_usg_opt_str(arg) RESULT(line) 1630 1661 !! Build and format the option string for the usage part of the help message 1631 !! The function is private part of the help builder. It creates the 1662 !! The function is private part of the help builder. It creates the 1632 1663 !! option string part of a given argument. 1633 1664 TYPE(argc), INTENT(in), TARGET :: arg … … 1661 1692 FUNCTION ac_get_opt_str(arg) RESULT(line) 1662 1693 !! Build and format the option flag string for the option part of the help message 1663 !! The function is private part of the help builder. It creates the 1694 !! The function is private part of the help builder. It creates the 1664 1695 !! option string part of a given argument for the options part of the help. 1665 1696 TYPE(argc), INTENT(in), TARGET :: arg … … 1701 1732 !! The function formats argparse specific errors when extra (missing) values 1702 1733 !! are (not) set or when given values are not consistent with argument's type. 1703 !! For each of these errors, the basic error is updated with a more precise 1704 !! message. 1734 !! For each of these errors, the basic error is updated with a more precise 1735 !! message. 1705 1736 TYPE(argc), INTENT(in) :: arg 1706 1737 !! An argc object … … 1723 1754 IF (arg%nrec == -2) THEN 1724 1755 msg = msg//' takes at least '//nv//' value(s))' 1725 ELSE 1756 ELSE 1726 1757 msg = msg//' takes exactly '//nv//' value(s))' 1727 1758 ENDIF 1728 1759 CASE (-18) ! extra values -> -18 1729 IF (arg%nrec == -3) THEN 1760 IF (arg%nrec == -3) THEN 1730 1761 msg = msg//' takes at most '//nv//' value(s))' 1731 1762 ELSE … … 1740 1771 FUNCTION ac_check_and_set(this,sf,lf,ty,ac,de,na,meta,check_flag) RESULT(ret) 1741 1772 !! Interface to all argc's member tests 1742 !! The function calls all the tests to perform on argc members. Some of these tests can 1743 !! alter argc's member values to fit argparser's requirements. 1773 !! The function calls all the tests to perform on argc members. Some of these tests can 1774 !! alter argc's member values to fit argparser's requirements. 1744 1775 !! 1745 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1776 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1746 1777 !! produced by misuse of the function arguments. In such case, the program should be 1747 1778 !! stopped: note that such ezrror should not occur in _released_ programs. … … 1763 1794 !! An optional vector of strings with the Meta-name of the values 1764 1795 LOGICAL, INTENT(in), OPTIONAL :: check_flag 1765 !! An optional boolean flag hat instructs the method wether to check for option flag 1766 !! or not. By default this test is enabled but it should be disabled if one wants to 1796 !! An optional boolean flag hat instructs the method wether to check for option flag 1797 !! or not. By default this test is enabled but it should be disabled if one wants to 1767 1798 !! check for POSITIONAL arguments as they do not have option flags. 1768 1799 TYPE(error) :: ret … … 1789 1820 FUNCTION ac_check_ac_ty_de_na(this,ac,ty,de,na) RESULT(ret) 1790 1821 !! Check and set argc's action, type and default value 1791 !! The method checks if input argument's options are valid and update the argc object 1792 !! consequently. 1822 !! The method checks if input argument's options are valid and update the argc object 1823 !! consequently. 1793 1824 !! 1794 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1825 !! On success, `noerror` is returned. Otherwise -9 error code is returned. Errors are only 1795 1826 !! produced by misuse of the function arguments. 1796 1827 TYPE(argc), INTENT(inout) :: this 1797 1828 !! An argc object to update 1798 1829 INTEGER, INTENT(in) :: ac 1799 !! An integer with the action to set and check 1830 !! An integer with the action to set and check 1800 1831 INTEGER, INTENT(in) :: ty 1801 1832 !! An integer with the type to set and check 1802 1833 CHARACTER(len=*), INTENT(in) :: de 1803 1834 !! A string with the default value to set and check 1804 CHARACTER(len=*), INTENT(in) :: na 1835 CHARACTER(len=*), INTENT(in) :: na 1805 1836 !! A string with the expected number of value to set and check 1806 1837 TYPE(error) :: ret … … 1810 1841 ret = noerror 1811 1842 eprf = 'argparse: '//"Invalid argument `"//TRIM(this%name)//"'" 1812 uty = error(eprf//" (type)",-9) 1843 uty = error(eprf//" (type)",-9) 1813 1844 ina = error(eprf//" (inconsistent nargs)",-9) 1814 1845 zna = TRIM(na) 1815 1846 ! Checks action 1816 1847 IF(ANY(ap_actions == ac).OR.ac == ap_undef) THEN 1817 this%paction = ac 1848 this%paction = ac 1818 1849 ELSE 1819 ret = error(eprf//" (action)",-9) ; RETURN 1850 ret = error(eprf//" (action)",-9) ; RETURN 1820 1851 ENDIF 1821 1852 ! Checks and sets type and default as a function of the action 1822 1853 SELECT CASE(this%paction) 1823 ! HELP: fixed in any case: 1854 ! HELP: fixed in any case: 1824 1855 CASE(ap_help) 1825 1856 this%default = 'F' 1826 1857 this%ptype = ap_logical 1827 1858 this%nrec = 0 1859 ! VERSION: fixed in any case: 1860 CASE(ap_version) 1861 this%default = 'F' 1862 this%ptype = ap_logical 1863 this%nrec = 0 1828 1864 ! COUNT: 1829 ! we always use "hard-coded" stuff and do not warn if dev has made 1830 ! mistakes... 1865 ! we always use "hard-coded" stuff and do not warn if dev has made mistakes... 1831 1866 CASE(ap_count) 1832 1867 ! default settings of the count action … … 1835 1870 ret = set_def_val() 1836 1871 ! STORE, APPEND actions 1837 CASE (ap_store, ap_append) 1838 ! set type 1872 CASE (ap_store, ap_append) 1873 ! set type 1839 1874 IF (ty == ap_undef) THEN 1840 this%ptype= ap_integer 1875 this%ptype= ap_integer 1841 1876 ELSEIF (ANY(ap_types == ty)) THEN 1842 1877 this%ptype = ty … … 1847 1882 ret = set_def_val() ; IF (ret /= 0) RETURN 1848 1883 ! check for nargs (if na is empty then we set "*") 1849 ret = set_nrec("*") 1884 ret = set_nrec("*") 1850 1885 ! UNDEFINED: 1851 1886 ! -> 1) set to action to store … … 1855 1890 CASE (ap_undef) 1856 1891 ! 1) always define store action 1857 this%paction = ap_store 1892 this%paction = ap_store 1858 1893 ! 2) set type and nrec: 1859 1894 ! 2.1) If type is undef: 1860 1895 ! - to default value type if default is given 1861 ! - ap_logical otherwiset type 1896 ! - ap_logical otherwiset type 1862 1897 ! 2.2) set nrec 1863 1898 ! - if final type is ap_logical set nrec to 0 … … 1865 1900 If (ty == ap_undef) THEN 1866 1901 ! no explicit type : define logical trigger first 1867 this%ptype = ap_logical ; this%nrec = 0 1902 this%ptype = ap_logical ; this%nrec = 0 1868 1903 ! icheck the default value given 1869 1904 IF (LEN_TRIM(de) > 0) THEN … … 1873 1908 ENDIF 1874 1909 IF (this%ptype == ap_logical) THEN 1875 ret = set_nrec("0") 1910 ret = set_nrec("0") 1876 1911 ELSE 1877 ret = set_nrec("1") 1912 ret = set_nrec("1") 1878 1913 ENDIF 1879 ret = set_def_val() 1914 ret = set_def_val() 1880 1915 IF (ret /= 0) RETURN 1881 1916 ! type is given … … 1883 1918 ! known type given : 1884 1919 ! check default value and nrec: -> if na not given set "*" 1885 this%ptype = ty 1920 this%ptype = ty 1886 1921 ret = set_def_val() ; IF (ret /= 0) RETURN 1887 1922 IF (this%ptype == ap_logical) THEN 1888 ret = set_nrec("0") 1923 ret = set_nrec("0") 1889 1924 ELSE 1890 1925 ret = set_nrec("1") … … 1892 1927 ELSE 1893 1928 ! unknown type => bad end ! 1894 ret = uty ; RETURN 1929 ret = uty ; RETURN 1895 1930 ENDIF 1896 END SELECT 1931 END SELECT 1897 1932 ! set default value as first value if ret is noerror .... 1898 1933 IF (ret == 0) CALL words_append(this%values,this%default) … … 1904 1939 !! Check and set argument's expected number of records 1905 1940 !! The method compares `na` value with the expected and known flags and decides 1906 !! wether to raise an error or defines nrec member of the argument object. If `na` 1941 !! wether to raise an error or defines nrec member of the argument object. If `na` 1907 1942 !! is empty then `base` is used. 1908 1943 CHARACTER(len=1),INTENT(in) :: base … … 1921 1956 ! check numeric characters 1922 1957 IF (VERIFY(zna,"0123456789")==0) READ(zna,*) this%nrec 1923 IF (this%nrec == 0) terr = ina 1958 IF (this%nrec == 0) terr = ina 1924 1959 END SELECT 1925 1960 END FUNCTION set_nrec … … 1927 1962 FUNCTION set_def_val() RESULT(terr) 1928 1963 !! Check and set argument's default value 1929 !! The method compares `de` value with the type already stored in the argument and 1964 !! The method compares `de` value with the type already stored in the argument and 1930 1965 !! decides wether to raise an error or to save `de` as argument's default value. 1931 1966 !! If `de` is empty then it sets a default value according to argument's type. … … 1935 1970 terr = noerror 1936 1971 IF (LEN_TRIM(de) /= 0) THEN 1937 this%default = de ; t = string_is(de) 1972 this%default = de ; t = string_is(de) 1938 1973 IF (t /= this%ptype) THEN 1939 1974 terr = error(eprf//" (inconsistent default value: expected '"// & … … 1952 1987 ENDIF 1953 1988 RETURN 1954 END FUNCTION set_def_val 1989 END FUNCTION set_def_val 1955 1990 END FUNCTION ac_check_ac_ty_de_na 1956 1991 … … 1969 2004 CHARACTER(len=2), INTENT(in) :: sflag 1970 2005 !! A 2-characters wide string with the short option flag 1971 CHARACTER(len=*), INTENT(in) :: lflag 2006 CHARACTER(len=*), INTENT(in) :: lflag 1972 2007 !! A string (at least 3 characters wide) with the long option flag 1973 2008 TYPE(error) :: ret … … 2017 2052 !! Set meta-variable of the given argc object 2018 2053 !! The method set meta-variable in the argc object. If no `meta` are given, the method 2019 !! uses argument's name to set the values. 2054 !! uses argument's name to set the values. 2020 2055 !! @warning 2021 2056 !! To be effective, this subroutine must be called after argparse::chk_opt_nargs … … 2042 2077 j=j+1 ; IF (j>ms) j=1 2043 2078 zmeta = to_upper(meta(j)) 2044 blk=INDEX(TRIM(zmeta),CHAR(32))-1 2079 blk=INDEX(TRIM(zmeta),CHAR(32))-1 2045 2080 IF (blk <= 0) blk=LEN_TRIM(zmeta) 2046 2081 CALL words_append(this%meta,zmeta(1:blk)) … … 2063 2098 FUNCTION ac_check_value(this,str) RESULT(err) 2064 2099 !! Check if given string is a valid value for the argument 2065 TYPE(argc), INTENT(in) :: this 2100 TYPE(argc), INTENT(in) :: this 2066 2101 !! An argc object reference 2067 2102 CHARACTER(len=*), INTENT(in) :: str … … 2093 2128 FUNCTION ap_get_positional_sc(this,idx,value) RESULT(ret) 2094 2129 !! Get positional arguments value at given index 2095 !! @warning 2130 !! @warning 2096 2131 !! On error, the status of `value` is undefined. 2097 2132 OBJECT(argparser), INTENT(in) :: this … … 2100 2135 !! Subscript of the positional argument value to get 2101 2136 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: value 2102 !! Output raw value of the positional. If `idx` is out of range, `value` is set to an 2137 !! Output raw value of the positional. If `idx` is out of range, `value` is set to an 2103 2138 !! empty string. 2104 2139 TYPE(error) :: ret … … 2117 2152 FUNCTION ap_get_positional_ve(this,values) RESULT(ret) 2118 2153 !! Get all positional arguments value 2119 !! @warning 2154 !! @warning 2120 2155 !! On error, the status of `values` is undefined. 2121 2156 OBJECT(argparser), INTENT(in) :: this 2122 2157 !! An argparser object reference 2123 2158 CHARACTER(len=st_slen), INTENT(out), ALLOCATABLE, DIMENSION(:) :: values 2124 !! An allocatable vector of **assumed length** strings with the value(s) of all 2125 !! positionals arguments found. 2159 !! An allocatable vector of **assumed length** strings with the value(s) of all 2160 !! positionals arguments found. 2126 2161 TYPE(error) :: ret 2127 2162 !! Error object with the first error encountered in the process … … 2532 2567 2533 2568 !> Gets a scalar @p REAL(kind=8) value from given argument 2534 !! @param[in,out] this An argc object 2569 !! @param[in,out] this An argc object 2535 2570 !! @param[out] output A scalar with the first value of the argument 2536 2571 !! @return An errors::error object with -21 if the destination variable's type … … 2538 2573 FUNCTION ac_get_dv_sc(this, output) RESULT(ret) 2539 2574 !! Get a scalar `REAL(kind=8)` value from given argument 2540 !! If no error occured, the function always returns at least a value (whatever the parser's 2575 !! If no error occured, the function always returns at least a value (whatever the parser's 2541 2576 !! state is) which is the default value if no specific values are set in the argument. 2542 2577 !! Otherwise, `output` value is undefined. … … 2563 2598 FUNCTION ac_get_rv_sc(this, output) RESULT(ret) 2564 2599 !! Get a scalar `REAL(kind=4)` value from given argument 2565 !! If no error occured, the function always returns at least a value (whatever the parser's 2600 !! If no error occured, the function always returns at least a value (whatever the parser's 2566 2601 !! state is) which is the default value if no specific values are set in the argument. 2567 2602 !! Otherwise, `output` value is undefined. … … 2588 2623 FUNCTION ac_get_iv_sc(this, output) RESULT(ret) 2589 2624 !! Get a scalar `INTEGER` value from given argument 2590 !! If no error occured, the function always returns at least a value (whatever the parser's 2625 !! If no error occured, the function always returns at least a value (whatever the parser's 2591 2626 !! state is) which is the default value if no specific values are set in the argument. 2592 2627 !! Otherwise, `output` value is undefined. … … 2613 2648 FUNCTION ac_get_lv_sc(this, output) RESULT(ret) 2614 2649 !! Get a scalar `INTEGER` value from given argument 2615 !! If no error occured, the function always returns at least a value (whatever the parser's 2650 !! If no error occured, the function always returns at least a value (whatever the parser's 2616 2651 !! state is) which is the default value if no specific values are set in the argument. 2617 2652 !! Otherwise, `output` value is undefined. … … 2638 2673 FUNCTION ac_get_cv_sc(this, output) RESULT(ret) 2639 2674 !! Get a scalar `COMPLEX` value from given argument 2640 !! If no error occured, the function always returns at least a value (whatever the parser's 2675 !! If no error occured, the function always returns at least a value (whatever the parser's 2641 2676 !! state is) which is the default value if no specific values are set in the argument. 2642 2677 !! Otherwise, `output` value is undefined. … … 2663 2698 FUNCTION ac_get_sv_sc(this, output) RESULT(ret) 2664 2699 !! Get a scalar `STRING` value from given argument 2665 !! If no error occured, the function always returns at least a value (whatever the parser's 2700 !! If no error occured, the function always returns at least a value (whatever the parser's 2666 2701 !! state is) which is the default value if no specific values are set in the argument. 2667 2702 !! Otherwise, `output` status is undefined. … … 2685 2720 FUNCTION ac_get_dv_ve(this, output) RESULT(ret) 2686 2721 !! Get a vector of `REAL(kind=8)` values from given argument 2687 !! If no error occured, the function always returns at least a value (whatever the parser's 2722 !! If no error occured, the function always returns at least a value (whatever the parser's 2688 2723 !! state is) which is the default value if no specific values are set in the argument. 2689 2724 !! Otherwise, `output` status is undefined. … … 2714 2749 FUNCTION ac_get_rv_ve(this, output) RESULT(ret) 2715 2750 !! Get a vector of `REAL(kind=4)` values from given argument 2716 !! If no error occured, the function always returns at least a value (whatever the parser's 2751 !! If no error occured, the function always returns at least a value (whatever the parser's 2717 2752 !! state is) which is the default value if no specific values are set in the argument. 2718 2753 !! Otherwise, `output` status is undefined. … … 2743 2778 FUNCTION ac_get_iv_ve(this, output) RESULT(ret) 2744 2779 !! Get a vector of `INTEGER` values from given argument 2745 !! If no error occured, the function always returns at least a value (whatever the parser's 2780 !! If no error occured, the function always returns at least a value (whatever the parser's 2746 2781 !! state is) which is the default value if no specific values are set in the argument. 2747 2782 !! Otherwise, `output` status is undefined. … … 2772 2807 FUNCTION ac_get_lv_ve(this, output) RESULT(ret) 2773 2808 !! Get a vector of `LOGICAL` values from given argument 2774 !! If no error occured, the function always returns at least a value (whatever the parser's 2809 !! If no error occured, the function always returns at least a value (whatever the parser's 2775 2810 !! state is) which is the default value if no specific values are set in the argument. 2776 2811 !! Otherwise, `output` status is undefined. … … 2801 2836 FUNCTION ac_get_cv_ve(this, output) RESULT(ret) 2802 2837 !! Get a vector of `COMPLEX` values from given argument 2803 !! If no error occured, the function always returns at least a value (whatever the parser's 2838 !! If no error occured, the function always returns at least a value (whatever the parser's 2804 2839 !! state is) which is the default value if no specific values are set in the argument. 2805 2840 !! Otherwise, `output` status is undefined. … … 2830 2865 FUNCTION ac_get_sv_ve(this, output) RESULT(ret) 2831 2866 !! Get a vector of `STRING` values from given argument 2832 !! If no error occured, the function always returns at least a value (whatever the parser's 2867 !! If no error occured, the function always returns at least a value (whatever the parser's 2833 2868 !! state is) which is the default value if no specific values are set in the argument. 2834 2869 !! Otherwise, `output` status is undefined. … … 2872 2907 2873 2908 FUNCTION apa2str(ap_a) RESULT(str) 2874 !! Get the string representation of argparse actions constants 2909 !! Get the string representation of argparse actions constants 2875 2910 INTEGER, INTENT(in) :: ap_a 2876 2911 !! One of ap_store, ap_append,cap_count or ap_help module constants … … 2882 2917 CASE(ap_count) ; str = 'count' 2883 2918 CASE(ap_help) ; str = 'help' 2919 CASE(ap_version); str = 'version' 2884 2920 CASE DEFAULT ; str = 'unknown' 2885 2921 END SELECT -
trunk/LMDZ.TITAN/libf/muphytitan/asciiread.f90
r1897 r3083 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 ! file and command line arguments parsing features to Fortran programs. 7 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 ! 3 ! This file is part of SWIFT 4 ! 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 11 ! 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 14 ! 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: asciiread.f90 35 23 !! summary: ASCII data file reader source file 36 24 !! author: burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 MODULE ASCIIREAD 39 27 !! ASCII data file reader module … … 42 30 !! data array from ASCII file. 43 31 !! 44 !! ``` 32 !! ``` 45 33 !! FUNCTION read_data(path,data) RESULT(err) 46 34 !! ``` … … 56 44 !! - must use blank space(s) as value delimiter. 57 45 !! - must have a regular number of columns, that is each data line must 58 !! have the same number of columns. 46 !! have the same number of columns. 59 47 !! - can contains any number of empty lines and/or comment line (i.e. line 60 48 !! where first non-blank character is "#"). All other lines are assumed 61 49 !! to be data. 62 !! Moreover, in the case of 3D data, it must use a SINGLE empty line for "depth" block separator. 50 !! Moreover, in the case of 3D data, it must use a SINGLE empty line for "depth" block separator. 63 51 !! 64 52 !! Error occured when: … … 76 64 !! of _R_ lines with _C_ columns. Each block must be separated by a single empty line 77 65 !! and each columns must separated by one or more blank spaces (no tabulation ALLOWED). 78 !! 66 !! 79 67 !! On success, the shape of the 3D output array will be _data(R,C,D)_. 80 68 USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: IOSTAT_END, IOSTAT_EOR … … 93 81 END INTERFACE 94 82 95 CONTAINS 83 CONTAINS 96 84 97 85 … … 100 88 !! 101 89 !! The function reads an ASCII file and saves its values in a real(kind=8) 3D-array. 102 !! 90 !! 103 91 !! The input file: 104 92 !! 105 93 !! - must have a regular number of columns, that is each data line must have the same number 106 !! of columns (according to the delimiter used). 94 !! of columns (according to the delimiter used). 107 95 !! - must use a SINGLE empty line for "depth" block separator. 108 96 !! - can contains any number of comment lines (i.e. line where first non-blank character is "#"). 109 97 !! All other lines (except empty lines) are assumed to be data. 110 !! 98 !! 111 99 !! Error occured when: 112 100 !! - Path does not refer to a existing file (-11) … … 118 106 !! with _C_ columns. Each block must be separated by a single empty line and 119 107 !! each columns must separated by one or more blank spaces (no tabulation ALLOWED). 120 !! 108 !! 121 109 !! On success, the shape of the 3D output array will be _output(R,C,D)_. 122 110 !! On error, the 3D output array is __not allocated__. 123 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 111 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 124 112 REAL(kind=8), INTENT(out), DIMENSION(:,:,:), ALLOCATABLE :: data3d !! 3D-array with the output values (double precision) 125 113 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter !! Optional column delimiter(s) … … 142 130 err = error(trim(path)//": no such file",-1) ; RETURN 143 131 ENDIF 144 lu = free_lun() 132 lu = free_lun() 145 133 IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF 146 134 ! Open file 147 135 OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ') 148 136 149 ! First pass : 137 ! First pass : 150 138 ! ------------ 151 ! - get size (rows, columns, depth) 139 ! - get size (rows, columns, depth) 152 140 ! - check size consistendcy 153 141 ! - check value type 154 lc = 0 ; tlc = 0 155 ndr = -1 ; ndc = -1 ; ndd = 1 156 DO WHILE(readline(lu,line)) 142 lc = 0 ; tlc = 0 143 ndr = -1 ; ndc = -1 ; ndd = 1 144 DO WHILE(readline(lu,line)) 157 145 lm1 = line 158 146 ! Read the line … … 160 148 ! skip comment line 161 149 IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1) CYCLE 162 ! An empty line: new 2D block 150 ! An empty line: new 2D block 163 151 IF (LEN_TRIM(line) == 0) THEN 164 152 ndd = ndd + 1 … … 175 163 tlc = tlc + 1 176 164 ! Splits line in words 177 IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 165 IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 178 166 ! cannot tokenize 179 167 err = error(trim(path)//": Cannot parse line "//TRIM(slc),-5) … … 183 171 err = error(trim(path)//": Cannot cast values at line "//TRIM(slc),-5) 184 172 RETURN 185 ELSEIF (ndc > 0 .AND. ndc /= SIZE(wrds)) THEN 173 ELSEIF (ndc > 0 .AND. ndc /= SIZE(wrds)) THEN 186 174 ! current number of columns not equal to last one 187 175 err = error(trim(path)//": Invalid number of columns (line "//TRIM(slc)//")",-5) … … 204 192 ! Allocate memory 205 193 ALLOCATE(data3d(ndr,ndc,ndd)) 206 ir = 0 ; kd = 1 ; 207 DO WHILE(readline(lu,line)) 194 ir = 0 ; kd = 1 ; 195 DO WHILE(readline(lu,line)) 208 196 IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1) CYCLE 209 197 ir = ir + 1 210 ! empty line update block subscripts 198 ! empty line update block subscripts 211 199 IF (LEN_TRIM(line) == 0) THEN 212 200 kd = kd + 1 ; ir = 0 ; CYCLE … … 223 211 !! 224 212 !! The function reads an ASCII file and saves its values in a real(kind=8) 2D-array. 225 !! 213 !! 226 214 !! The input file: 227 215 !! 228 !! - can contains any number of empty lines and/or comment line (i.e. line where first 216 !! - can contains any number of empty lines and/or comment line (i.e. line where first 229 217 !! non-blank character is "#"). All other lines are assumed to be data. 230 !! - must have a regular number of columns, that is each data line must have the same 231 !! number of columns. 218 !! - must have a regular number of columns, that is each data line must have the same 219 !! number of columns. 232 220 !! - must use blank space(s) as value delimiter. 233 !! 221 !! 234 222 !! Error occured when: 235 223 !! … … 241 229 !! On error, the 2D output array is __not allocated__. 242 230 USE FSYSTEM 243 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 231 CHARACTER(len=*), INTENT(in) :: path !! Path of the input data file 244 232 REAL(kind=8), INTENT(out), DIMENSION(:,:), ALLOCATABLE :: data2d !! 2D-array with the output values (double precision) 245 233 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter !! Optional column delimiter(s) … … 258 246 err = error(trim(path)//": no such file",-1) ; RETURN 259 247 ENDIF 260 lu = free_lun() 248 lu = free_lun() 261 249 IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF 262 250 OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ') … … 265 253 lc=0 ; vc = 0 ; nc=-1 266 254 ! First pass : get number of row values and checks everything ! 267 DO 255 DO 268 256 ! Read the line 269 257 IF (.NOT.readline(lu,line)) EXIT … … 273 261 ! update row counter 274 262 vc = vc + 1 275 IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 263 IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 276 264 ! cannot tokenize 277 265 err = error(trim(path)//": Cannot parse line "//TRIM(slc),-5) … … 281 269 err = error(trim(path)//": Cannot cast values at line "//TRIM(slc),-5) 282 270 RETURN 283 ELSEIF (nc > 0 .AND. nc /= SIZE(tmp)) THEN 271 ELSEIF (nc > 0 .AND. nc /= SIZE(tmp)) THEN 284 272 ! current number of columns not equal to last one 285 273 err = error(trim(path)//": Invalid number of columns (line "//TRIM(slc)//")",-5) … … 296 284 ALLOCATE(data2d(nl,nc)) 297 285 ! Second pass : saves values :) 298 vc = 0 286 vc = 0 299 287 DO WHILE(vc <= nl) 300 288 ! Reads the line … … 315 303 FUNCTION readline(lun,line) RESULT(not_eof) 316 304 !! Read a complete line 317 !! 318 !! Each time, it is called, the function reads a complete of the file opened in __lun__ 305 !! 306 !! Each time, it is called, the function reads a complete of the file opened in __lun__ 319 307 !! logical unit and returns .false. if EOF has been reached, .true. otherwise. 320 308 !! … … 331 319 !! CLOSE(1) 332 320 !! ``` 333 INTEGER, INTENT(in) :: lun !! Logical unit with the opened file to read. 334 CHARACTER(len=:), ALLOCATABLE, INTENT(out) :: line !! Processed line 321 INTEGER, INTENT(in) :: lun !! Logical unit with the opened file to read. 322 CHARACTER(len=:), ALLOCATABLE, INTENT(out) :: line !! Processed line 335 323 LOGICAL :: not_eof !! .true. if EOF has NOT been reached yet, .false. otherwise 336 324 CHARACTER(len=50) :: buf -
trunk/LMDZ.TITAN/libf/muphytitan/cfgparse.F90
r1897 r3083 1 ! Copyright Jérémie Burgalat (2010-2015,2017)1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 2 ! 3 ! jeremie.burgalat@univ-reims.fr3 ! This file is part of SWIFT 4 4 ! 5 ! This software is a computer program whose purpose is to provide configuration 6 ! file and command line arguments parsing features to Fortran programs. 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 7 11 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 11 ! license as circulated by CEA, CNRS and INRIA at the following URL 12 ! "http://www.cecill.info". 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 13 14 ! 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-B license and that you accept its terms. 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: cfgparse.F90 35 23 !! summary: Configuration file parser source file. 36 24 !! author: J. Burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 39 27 #include "defined.h" … … 330 318 oname = zsname//"/"//zpname 331 319 IF (PRESENT(sname)) sname = zsname 332 IF (PRESENT(pname)) pname = zpname 320 IF (PRESENT(pname)) pname = zpname 333 321 END FUNCTION op_format 334 322 … … 418 406 !! 419 407 !! Otherwise it is assumed to be the basename of the option. 420 !! 408 !! 421 409 !! A valid option (base) name is an alphanumeric sequence in lower-case that always begin by 422 410 !! a letter. … … 479 467 IF(.NOT.ALLOCATED(this%options)) RETURN 480 468 IF (.NOT.PRESENT(section)) THEN 481 num = SIZE(this%options) 469 num = SIZE(this%options) 482 470 ELSE 483 471 DO i=1, SIZE(this%options) -
trunk/LMDZ.TITAN/libf/muphytitan/csystem.c
r1897 r3083 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 * file and command line arguments parsing features to Fortran programs. 7 * 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, 10 * modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 /* 2 * Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 3 * 4 * This file is part of SWIFT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 * this software and associated documentation files (the "Software"), to deal in 8 * the Software without restriction, including without limitation the rights to 9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 * the Software, and to permit persons to whom the Software is furnished to do so, 11 * subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 22 */ 34 23 … … 71 60 free(tmp); 72 61 tmp = NULL; 73 } 62 } 74 63 return tmp; 75 64 } 76 65 77 66 78 /* Get the realpath of input path and saves it in output path */ 67 /* Get the realpath of input path and saves it in output path */ 79 68 char* c_realpath(const char *input){ 80 69 if (!strlen(input)) { … … 148 137 continue; 149 138 } 150 len = path_len + strlen(p->d_name) + 2; 139 len = path_len + strlen(p->d_name) + 2; 151 140 buf = malloc(len); 152 141 if (buf) { … … 168 157 if (!r) { 169 158 r = rmdir(path); 170 159 return r?errno:0; 171 160 } 172 161 return r; … … 174 163 175 164 /* Get some file informations */ 176 int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi, 165 int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi, 177 166 long *si, char a[20], char m[20], char c[20]){ 178 167 struct stat stb; … … 189 178 else *ty = 4; 190 179 *ui = (int)stb.st_uid ; *gi = (int)stb.st_gid ; *si = (long)stb.st_size ; 191 t = localtime(&stb.st_atime) ; ret = strftime(tmp, 20, "%F,%T", t); 180 t = localtime(&stb.st_atime) ; ret = strftime(tmp, 20, "%F,%T", t); 192 181 if(ret != 0) {strncpy(a,tmp,20); a[19] = '\0';}else{a[0] = '\0';} 193 182 t = localtime(&stb.st_mtime) ; ret = strftime(tmp, 20, "%F,%T", t); … … 212 201 if (forced){ 213 202 p = strdup(path) ; if(p == NULL) {return errno;} 214 d = dirname(p) ; free(p) ; 203 d = dirname(p) ; free(p) ; 215 204 if(d == NULL) {return -9;} 216 205 // we attempts to create parent directory first … … 218 207 perm =((S_IRWXU | S_IRWXG | S_IRWXO) & ~(cmask & ~(S_IWUSR | S_IXUSR))); 219 208 (void)umask(cmask) ; 220 eval = c_mkdirp(d,perm); 209 eval = c_mkdirp(d,perm); 221 210 if(eval){return eval;} 222 211 } 223 212 eval = open(path,O_CREAT|O_EXCL,mode); 224 213 if (eval == -1) {eval=errno;}else{close(eval);eval=0;} 225 } 214 } 226 215 return eval ; 227 216 } … … 355 344 * Copyright (c) 1983, 1992, 1993 356 345 * The Regents of the University of California. All rights reserved. 357 * 346 * 358 347 * Redistribution and use in source and binary forms, with or without 359 348 * modification, are permitted provided that the following conditions … … 371 360 * may be used to endorse or promote products derived from this software 372 361 * without specific prior written permission. 373 * 362 * 374 363 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 375 364 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE … … 416 405 retval = 1; break; 417 406 } 418 } 407 } 419 408 if (!last) *p = '/'; 420 409 } … … 433 422 * 434 423 * @APPLE_LICENSE_HEADER_START@ 435 * 424 * 436 425 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 437 426 * Reserved. This file contains Original Code and/or Modifications of … … 441 430 * License at http://www.apple.com/publicsource and read it before using 442 431 * this file. 443 * 432 * 444 433 * The Original Code and all software distributed under the License are 445 434 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER … … 449 438 * License for the specific language governing rights and limitations 450 439 * under the License." 451 * 440 * 452 441 * @APPLE_LICENSE_HEADER_END@ 453 442 * … … 467 456 buf = NULL; 468 457 469 if (realpath(reldir,start_path) == NULL) 458 if (realpath(reldir,start_path) == NULL) 470 459 return buf; 471 472 if (realpath(path,end_path) == NULL) 460 461 if (realpath(path,end_path) == NULL) 473 462 return buf; 474 463 475 464 // stat the starting path 476 if (stat(start_path, &st) < 0) 465 if (stat(start_path, &st) < 0) 477 466 return buf; 478 467 479 468 if ((st.st_mode & S_IFMT) != S_IFDIR) { 480 469 errno = ENOTDIR; 481 470 return buf; 482 } 471 } 483 472 if (start_path[strlen(start_path) - 1] != '/') 484 473 strcat(start_path, "/"); 485 474 486 475 // stat the ending path path 487 if (stat(end_path, &st) < 0) 476 if (stat(end_path, &st) < 0) 488 477 return buf; 489 478 490 479 if ((st.st_mode & S_IFMT) == S_IFDIR 491 480 && end_path[strlen(end_path) - 1] != '/') … … 624 613 #elif defined(__APPLE__) && defined(__MACH__) 625 614 /* 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)615 struct task_basic_info info; 616 mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT; 617 if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &infoCount) != KERN_SUCCESS) 629 618 return (size_t)0L; /* Can't access? */ 630 619 return (size_t)info.resident_size; … … 650 639 651 640 652 641 653 642 /* Get some informatiosn about the OS memory usage (from /proc/meminfo) */ 654 643 int c_getSystemMemory(long long int *m_total,long long int *m_available,long long int *m_free){ … … 661 650 if (m_available) (*m_free) = mem2; 662 651 if (m_free) (*m_free) = mem3; 663 if ((fp = fopen("/proc/meminfo", "r")) == NULL) 652 if ((fp = fopen("/proc/meminfo", "r")) == NULL) 664 653 return 1; 665 654 while (fgets(buf, sizeof(buf), fp) != NULL){ 666 ts = strlen(buf) - 1; buf[ts] = '\0'; 667 tmp = strndup(&buf[0],ts); 655 ts = strlen(buf) - 1; buf[ts] = '\0'; 656 tmp = strdup(&buf[0]); 657 //tmp = strndup(&buf[0],ts); // GNU extension 668 658 // check our 3 cases 669 659 if (ts >= 9 && !strncmp(tmp,"MemTotal:",9)){ … … 674 664 } 675 665 if (ts >= 13 && !strncmp(tmp,"MemAvailable:",13)){ 676 p=strtok(tmp, " "); p=strtok(NULL, " "); 666 p=strtok(tmp, " "); p=strtok(NULL, " "); 677 667 mem2 = strtoll(p,NULL,10); 678 } 668 } 679 669 if (ts >= 8 && !strncmp(tmp,"MemFree:",8)){ 680 p=strtok(tmp, " "); p=strtok(NULL, " "); 670 p=strtok(tmp, " "); p=strtok(NULL, " "); 681 671 mem3 = strtoll(p,NULL,10); 682 672 } -
trunk/LMDZ.TITAN/libf/muphytitan/csystem.h
r1897 r3083 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 * file and command line arguments parsing features to Fortran programs. 7 * 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, 10 * modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 /* 2 * Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 3 * 4 * This file is part of SWIFT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 * this software and associated documentation files (the "Software"), to deal in 8 * the Software without restriction, including without limitation the rights to 9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 * the Software, and to permit persons to whom the Software is furnished to do so, 11 * subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 22 */ 34 23 … … 43 32 int c_umask(); 44 33 45 /** 46 * Get directory name of input path 34 /** 35 * Get directory name of input path 47 36 * @param[in] in A C string with the input path 48 37 * @return A pointer to a char array with the directory name of @bti{input} path. 49 38 * @note On error, a NULL pointer is returned. 50 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 39 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 51 40 * (using fsystem::free_c). 52 41 */ 53 42 char * c_dirname(const char *in); 54 43 55 /** 56 * Get base name of input path 44 /** 45 * Get base name of input path 57 46 * @param[in] in A C string with the input path 58 47 * @return A pointer to a char array with the base name of @bti{input} path. 59 48 * @note On error, a NULL pointer is returned. 60 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 49 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 61 50 * (using fsystem::free_c). 62 51 */ 63 52 char* c_basename(const char *in); 64 53 65 /** 54 /** 66 55 * Get the current working directory. 67 56 * @return A pointer to a char array with the current workind directory. 68 57 * @note On error, a NULL pointer is returned. 69 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 58 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 70 59 * (using fsystem::free_c). 71 60 */ … … 73 62 74 63 75 /** 64 /** 76 65 * Get the realpath of input path. 77 66 * @param[in] input A C string with the input path 78 67 * @return A pointer to a char array with the realpath of @bti{input} path. 79 68 * @note On error, a NULL pointer is returned. 80 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 69 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 81 70 * (using fsystem::free_c). 82 71 */ … … 91 80 * @return A pointer to a char array with the relative path. 92 81 * @note On error, a NULL pointer is returned. 93 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 82 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 94 83 * (using fsystem::free_c). 95 84 */ … … 101 90 * @return A pointer to a char array with the user name. 102 91 * @note On error, a NULL pointer is returned. 103 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 92 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 104 93 * (using fsystem::free_c). 105 94 */ … … 111 100 * @return A pointer to a char array with the group name. 112 101 * @note On error, a NULL pointer is returned. 113 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 102 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 114 103 * (using fsystem::free_c). 115 104 */ … … 122 111 int c_get_errno(); 123 112 124 /** 113 /** 125 114 * Get the error message of the given error id 126 115 * @param err An integer with the error id 127 116 * @return A pointer to a char array with the group name. 128 117 * @note On error, the hard-coded message "Unknown error" is returned. 129 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 118 * @warning In any case, the returned pointer must be freed in the Fortran counterpart 130 119 * (using fsystem::free_c). 131 120 */ … … 139 128 * @return An integer with 0 on success, last errno on failure 140 129 */ 141 int c_mkdirp(const char *path, mode_t mode); 130 int c_mkdirp(const char *path, mode_t mode); 142 131 143 132 /** … … 151 140 /** 152 141 * Change path permissions 153 * @param path A string with the path 142 * @param path A string with the path 154 143 * @param mode A integer with the new permissions to set 155 144 * @return An integer with 0 on success, last errno on failure … … 170 159 * (as well as all the parent directorie created, if any). 171 160 * @return An integer with 0 on success, last errno on failure 172 */ 161 */ 173 162 int c_mkdir(const char *path, mode_t mode); 174 163 … … 200 189 * Remove a directory and its contents recursively 201 190 * 202 * This method mimics 'rm -rf' command. 191 * This method mimics 'rm -rf' command. 203 192 * @param path A C string with the path of the directory to remove. 204 193 * @return An integer with 0 on success, last errno on failure … … 208 197 /** 209 198 * Get some file informations 210 * @note If the path cannot be "stat", most of the output parameters are set 199 * @note If the path cannot be "stat", most of the output parameters are set 211 200 * to -1. 212 201 * @param[in] p A C string with the path of a file (or directory) 213 * @param[out] pe An int with the permissions of the path 202 * @param[out] pe An int with the permissions of the path 214 203 * @param[out] nl An int with the inumber of links 215 204 * @param[out] ty An int with the type of the file : … … 219 208 * - 3 -> link to a directory 220 209 * - 4 -> Other (fifo, socket, block special, char special ...) 221 * @param[out] ui An int with the user id of the path 222 * @param[out] gi An int with the group id of the path 223 * @param[out] si An int with the size of the path 210 * @param[out] ui An int with the user id of the path 211 * @param[out] gi An int with the group id of the path 212 * @param[out] si An int with the size of the path 224 213 * @param[out] a A C string (20 chars wide, including NULL character) with the 225 214 * last access date 226 215 * @param[out] m A C string (20 chars wide, including NULL character) with the 227 216 * last modification date 228 * @param[out] c A C string (20 chars wide, including NULL character) with the 217 * @param[out] c A C string (20 chars wide, including NULL character) with the 229 218 * creation date 230 * @return An integer with 0 on success, last errno on failure 231 */ 232 int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi, 219 * @return An integer with 0 on success, last errno on failure 220 */ 221 int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi, 233 222 long *si, char a[20], char m[20], char c[20]); 234 223 … … 238 227 * @param[in] perm An integer with the user's permission to check : 239 228 * - 0 do not check for permissions 240 * - 1 check for execute permission 229 * - 1 check for execute permission 241 230 * - 2 check for write permission 242 231 * - 4 check for read permission … … 259 248 * @param[out] rows Number of rows of the current terminal window 260 249 * @param[out] cols Number of columns of the current terminal window 261 * @return An int with 0 on success, errno on failure. On failure, rows is set 250 * @return An int with 0 on success, errno on failure. On failure, rows is set 262 251 * to 80 and cols to 20. 263 252 */ -
trunk/LMDZ.TITAN/libf/muphytitan/defined.h
r1897 r3083 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 * file and command line arguments parsing features to Fortran programs. 7 * 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, 10 * modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 /* 2 * Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 3 * 4 * This file is part of SWIFT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 * this software and associated documentation files (the "Software"), to deal in 8 * the Software without restriction, including without limitation the rights to 9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 * the Software, and to permit persons to whom the Software is furnished to do so, 11 * subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 22 */ 34 23 35 /** 24 /** 36 25 * @file defined.h 37 26 * @brief CPP macro definitions files 38 * @details This header defines few CPP symbols and macros that are used 27 * @details This header defines few CPP symbols and macros that are used 39 28 * in the library source code. 40 29 */ … … 63 52 * 64 53 * This macro definition depends on compiler's support for Bounded procedures 65 * in derived type (more precisely, Fortran 2003 PROCEDURE keyword support): 54 * in derived type (more precisely, Fortran 2003 PROCEDURE keyword support): 66 55 * - If it actually supports this feature, the macro defines derived type 67 56 * declaration as dummy argument of subroutine/function using CLASS keyword. -
trunk/LMDZ.TITAN/libf/muphytitan/errors.F90
r1897 r3083 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 ! file and command line arguments parsing features to Fortran programs. 7 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 ! 3 ! This file is part of SWIFT 4 ! 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 11 ! 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 14 ! 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: errors.F90 35 23 !! summary: Errors handling source file. 36 24 !! author: J. Burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 39 27 #include "defined.h" … … 60 48 !! Define an error 61 49 !! 62 !! The following derived type represents in the simplest way (I believe) an error which 50 !! The following derived type represents in the simplest way (I believe) an error which 63 51 !! stores: 64 52 !! 65 53 !! - An integer to numerically identify the error 66 54 !! - A string (250 chars max) with an appropriate error message 67 !! - A bounded procedure to get a string representation of the error (if bounded 55 !! - A bounded procedure to get a string representation of the error (if bounded 68 56 !! procedures are supported by the library). 69 !! - internal subroutines for derived type IO WRITE statement (if Derived IO 57 !! - internal subroutines for derived type IO WRITE statement (if Derived IO 70 58 !! subroutines are supported by the library). 71 59 !! … … 79 67 INTEGER :: id = 0 80 68 !! Numerical identifier of the error 81 !! @note 82 !! The error identifier is used to test the equality/inequality of two error objects. 69 !! @note 70 !! The error identifier is used to test the equality/inequality of two error objects. 83 71 #if HAVE_FTNPROC 84 72 CONTAINS … … 88 76 END TYPE error 89 77 90 INTERFACE 78 INTERFACE 91 79 !! Clean subroutine interface 92 80 SUBROUTINE clean_callback(err) … … 95 83 IMPLICIT NONE 96 84 TYPE(error), INTENT(in) :: err 97 !! An error object with the input error 85 !! An error object with the input error 98 86 END SUBROUTINE clean_callback 99 87 END INTERFACE 100 88 101 INTERFACE 89 INTERFACE 102 90 subroutine abort_() bind(C, name="abort") 103 91 end subroutine … … 111 99 END INTERFACE assert 112 100 113 !> error equality operator 101 !> error equality operator 114 102 INTERFACE OPERATOR(==) 115 103 MODULE PROCEDURE error_equals, error_equals_int 116 104 END INTERFACE 117 105 118 !> error inequality operator 106 !> error inequality operator 119 107 INTERFACE OPERATOR(/=) 120 108 MODULE PROCEDURE error_differs, error_differs_int … … 132 120 FUNCTION error_equals(this, other) RESULT(res) 133 121 !! Check if two error objects are equivalent 134 TYPE(error), INTENT(in) :: this, & !! The first error object to compare 135 other !! The second error object to compare 122 TYPE(error), INTENT(in) :: this, & !! The first error object to compare 123 other !! The second error object to compare 136 124 LOGICAL :: res !! .true. if __this__ and __other__ identifiers are the same, .false. otherwise 137 125 res = (this%id == other%id) … … 150 138 FUNCTION error_differs(this, other) RESULT(res) 151 139 !! Check if two error objects are different 152 TYPE(error), INTENT(in) :: this, & !! The first error object to compare 153 other !! The second error object to compare 140 TYPE(error), INTENT(in) :: this, & !! The first error object to compare 141 other !! The second error object to compare 154 142 LOGICAL :: res !! .false. if __this__ and __other__ identifiers are the same, .true. otherwise 155 143 res = (this%id /= other%id) … … 174 162 CHARACTER(len=*), INTENT(in), OPTIONAL :: progname 175 163 !! An optional string with the name of the program 176 LOGICAL, INTENT(in), OPTIONAL :: as_warning 164 LOGICAL, INTENT(in), OPTIONAL :: as_warning 177 165 !! An optional boolean flag to print the message as warning rather than as error (default to .false.). 178 166 CHARACTER(len=:), ALLOCATABLE :: str 179 167 !! An allocatable string with the string representation of the error 180 CHARACTER(len=:), ALLOCATABLE :: pref 168 CHARACTER(len=:), ALLOCATABLE :: pref 181 169 pref = "error: " 182 170 IF (PRESENT(as_warning)) THEN ; IF (as_warning) pref = "warning: " ; ENDIF … … 190 178 str = pref//TRIM(this%msg) 191 179 ENDIF 192 RETURN 180 RETURN 193 181 END FUNCTION error_to_string 194 182 … … 208 196 SUBROUTINE assert_r(test,reason) 209 197 !! _Raise_ an assertion. 210 !! 198 !! 211 199 !! The method raises an assertion and stops the execution if __test__ is .false. 212 !! 200 !! 213 201 !! @note 214 202 !! If ISO_C_BINDING module is available, the method calls the method abort from the C standard library. Doing so, 215 203 !! developer is able to debug the source code by getting the backtrace of the execution. 216 !! In other situation, the method simply uses the Fortran STOP statement which makes its usage... useless. 204 !! In other situation, the method simply uses the Fortran STOP statement which makes its usage... useless. 217 205 LOGICAL, INTENT(in) :: test 218 206 !! Expression to test. … … 227 215 SUBROUTINE assert_w(test,where,reason) 228 216 !! _Raise_ an assertion. 229 !! 217 !! 230 218 !! The method raises an assertion and stops the execution if __test__ is .false. 231 !! 219 !! 232 220 !! See [[errors(module):assert_r(subroutine)]] remark. 233 221 LOGICAL, INTENT(in) :: test … … 249 237 !! @note 250 238 !! 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 239 !! dependent. I just assume that [7,9999] is a valid range and I believe that 252 240 !! 9992 files to be opened is far enough for any program ! 253 241 !! @note … … 255 243 !! mind that loggers open files with the first free logical unit. Consequently 256 244 !! 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 ! 245 !! free lun instead of just randomly set a lun ! 258 246 INTEGER :: lu 259 247 !! First free logical unit in the range [7,9999] or -1 if no lun is available -
trunk/LMDZ.TITAN/libf/muphytitan/fsystem.F90
r1897 r3083 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 ! file and command line arguments parsing features to Fortran programs. 7 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 ! 3 ! This file is part of SWIFT 4 ! 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 11 ! 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 14 ! 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: fsystem.F90 35 23 !! summary: File system methods source file. 36 24 !! author: J. Burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 39 27 … … 46 34 IMPLICIT NONE 47 35 48 PUBLIC 36 PUBLIC 49 37 50 38 PRIVATE :: get_umask … … 57 45 !! 58 46 !! 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 47 REAL(kind=8), PRIVATE :: cpu_start = 0d0 60 48 !! Starting CPU time 61 INTEGER(kind=8), PRIVATE :: clock_start = 0d0 49 INTEGER(kind=8), PRIVATE :: clock_start = 0d0 62 50 !! Starting clock time 63 51 LOGICAL, PRIVATE :: on_run = .false. 64 52 !! Chrono running state. 65 53 #if HAVE_FTNPROC 66 CONTAINS 67 PROCEDURE :: is_running => chrono_is_running 54 CONTAINS 55 PROCEDURE :: is_running => chrono_is_running 68 56 PROCEDURE :: start => chrono_start 69 57 PROCEDURE :: stop => chrono_stop … … 95 83 END FUNCTION errno_c 96 84 97 FUNCTION usleep_c(usec) BIND(C,name="usleep") 85 FUNCTION usleep_c(usec) BIND(C,name="usleep") 98 86 !! (attemps to) Sleep for a given number of microseconds 99 87 IMPORT C_INT … … 127 115 128 116 FUNCTION access_c(path,perm) BIND(C,name="c_access") 129 !! Check if path is accessible for current user 117 !! Check if path is accessible for current user 130 118 IMPORT c_char, C_INT 131 119 CHARACTER(len=c_char), INTENT(in) :: path(*) !! Path to check … … 134 122 END FUNCTION access_c 135 123 136 FUNCTION create_c(path,mode,asfile,forced) BIND(C,name="c_create") 124 FUNCTION create_c(path,mode,asfile,forced) BIND(C,name="c_create") 137 125 !! Create a directory or a file in given path 138 126 IMPORT c_char, C_INT … … 149 137 INTEGER(kind=C_INT), INTENT(in), VALUE :: uid !! User id 150 138 TYPE(C_PTR) :: uname_c !! C_PTR to the underlying char* pointer storing user name 151 END FUNCTION uname_c 139 END FUNCTION uname_c 152 140 153 141 FUNCTION gname_c(gid) BIND(C, name="c_gname") … … 156 144 INTEGER(kind=C_INT), INTENT(in), VALUE :: gid !! Group id 157 145 TYPE(C_PTR) :: gname_c !! C_PTR to the underlying char* pointer storing group name 158 END FUNCTION gname_c 159 160 FUNCTION dirname_c(path) BIND(C,name="c_dirname") 146 END FUNCTION gname_c 147 148 FUNCTION dirname_c(path) BIND(C,name="c_dirname") 161 149 !! Get the directory name of the path 162 150 IMPORT c_char, c_ptr … … 172 160 END FUNCTION basename_c 173 161 174 FUNCTION getcwd_c() BIND(C,name="c_getcwd") 162 FUNCTION getcwd_c() BIND(C,name="c_getcwd") 175 163 !! Get the current working directory 176 164 IMPORT c_ptr … … 198 186 CHARACTER(kind=c_char), INTENT(in) :: input(*) !! Path to rename 199 187 CHARACTER(kind=c_char), INTENT(in) :: output(*) !! New name of the path 200 INTEGER(kind=C_INT) :: rename_c !! 0 on success, last errno on failure 188 INTEGER(kind=C_INT) :: rename_c !! 0 on success, last errno on failure 201 189 END FUNCTION rename_c 202 190 … … 206 194 CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Path to modify 207 195 INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! New decimal permissions of the path to set 208 INTEGER(kind=C_INT) :: chmod_c !! 0 on success, last errno on failure 196 INTEGER(kind=C_INT) :: chmod_c !! 0 on success, last errno on failure 209 197 END FUNCTION chmod_c 210 198 … … 213 201 IMPORT c_char, C_INT 214 202 CHARACTER(kind=c_char), INTENT(in) :: new(*) !! Path of the new working directory 215 INTEGER(kind=C_INT) :: chdir_c !! 0 on success, last errno on failure 203 INTEGER(kind=C_INT) :: chdir_c !! 0 on success, last errno on failure 216 204 END FUNCTION chdir_c 217 205 … … 220 208 IMPORT c_char, C_INT 221 209 CHARACTER(kind=c_char), INTENT(in) :: dirname(*) !! Path of the directory to create 222 INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set 223 INTEGER(kind=C_INT) :: mkdir_c !! 0 on success, last errno on failure 210 INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set 211 INTEGER(kind=C_INT) :: mkdir_c !! 0 on success, last errno on failure 224 212 END FUNCTION mkdir_c 225 213 … … 228 216 IMPORT c_char, C_INT 229 217 CHARACTER(kind=c_char), INTENT(in) :: dirname(*) !! Path of the directory to create 230 INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set 231 INTEGER(kind=C_INT) :: mkdirp_c !! 0 on success, last errno on failure 218 INTEGER(kind=C_INT), INTENT(in), VALUE :: mode !! Decimal permission to set 219 INTEGER(kind=C_INT) :: mkdirp_c !! 0 on success, last errno on failure 232 220 END FUNCTION mkdirp_c 233 221 234 FUNCTION copy_c(to,from) BIND(C,name="c_copy") 222 FUNCTION copy_c(to,from) BIND(C,name="c_copy") 235 223 !! Copy a file. 236 224 IMPORT c_char, C_INT … … 240 228 END FUNCTION copy_c 241 229 242 FUNCTION remove_c(path) BIND(C,name="c_remove") 230 FUNCTION remove_c(path) BIND(C,name="c_remove") 243 231 !! Remove a file (or a directory) from the filesystem 244 232 IMPORT c_char, C_INT 245 233 CHARACTER(kind=c_char), INTENT(in) :: path(*) !! Path to delete 246 INTEGER(kind=C_INT) :: remove_c !! 0 on success, last errno on failure 234 INTEGER(kind=C_INT) :: remove_c !! 0 on success, last errno on failure 247 235 END FUNCTION remove_c 248 236 … … 251 239 IMPORT c_char, C_INT 252 240 CHARACTER(kind=c_char), INTENT(in) :: dirpath(*) !! Directory to delete 253 INTEGER(kind=C_INT) :: rmdir_c !! 0 on success, last errno on failure 241 INTEGER(kind=C_INT) :: rmdir_c !! 0 on success, last errno on failure 254 242 END FUNCTION rmdir_c 255 243 … … 258 246 IMPORT c_char, C_INT 259 247 CHARACTER(kind=c_char), INTENT(in) :: dirpath(*) !! Directory to delete 260 INTEGER(kind=C_INT) :: rmdirf_c !! 0 on success, last errno on failure 248 INTEGER(kind=C_INT) :: rmdirf_c !! 0 on success, last errno on failure 261 249 END FUNCTION rmdirf_c 262 250 … … 282 270 INTEGER(kind=C_INT), INTENT(out) :: r, & !! Number of rows 283 271 c !! Number of columns 284 INTEGER(kind=C_INT) :: termsize_c !! 0 on success, last errno on failure 272 INTEGER(kind=C_INT) :: termsize_c !! 0 on success, last errno on failure 285 273 END FUNCTION termsize_c 286 274 … … 289 277 IMPORT C_SIZE_T 290 278 INTEGER(kind=C_SIZE_T) :: getCurrentRSS_c !! Current resident set size in bytes (0 if not available). 291 END FUNCTION getCurrentRSS_c 279 END FUNCTION getCurrentRSS_c 292 280 293 281 FUNCTION getPeakRSS_c() BIND(C, name="c_getPeakRSS") … … 295 283 IMPORT C_SIZE_T 296 284 INTEGER(kind=C_SIZE_T) :: getPeakRSS_c !! Peak resident set size in bytes (0 if not available). 297 END FUNCTION getPeakRSS_c 285 END FUNCTION getPeakRSS_c 298 286 299 287 FUNCTION getSystemMemory_c(total,avail,free) BIND(C, name='c_getSystemMemory') … … 303 291 INTEGER(kind=C_LONG_LONG), INTENT(out) :: avail !! Current available memory. 304 292 INTEGER(kind=C_LONG_LONG), INTENT(out) :: free !! Current free memory. 305 INTEGER(kind=C_INT) :: getSystemMemory_c !! status, 0 on success, 1 otherwise. 293 INTEGER(kind=C_INT) :: getSystemMemory_c !! status, 0 on success, 1 otherwise. 306 294 END FUNCTION getSystemMemory_c 307 295 END INTERFACE … … 311 299 312 300 FUNCTION fstring(string) RESULT(str) 313 !! Convert C string to Fortran string 301 !! Convert C string to Fortran string 314 302 !! 315 303 !! The method copies the input C string up to the last C_NULL_CHAR found (not including it), 316 304 !! and returns the converted Fortran string. 317 305 !! All other C_NULL_CHAR found in the C string are removed. 318 CHARACTER(len=*), INTENT(in) :: string !! A string from C 306 CHARACTER(len=*), INTENT(in) :: string !! A string from C 319 307 CHARACTER(len=:), ALLOCATABLE :: str !! Converted fortran string 320 INTEGER :: i,idx 308 INTEGER :: i,idx 321 309 str = "" 322 310 idx = INDEX(string,C_NULL_CHAR,.true.) … … 335 323 !! 336 324 !! The method build the fortran string from a TYPE(C_PTR) object that represent a 337 !! C char\* pointer string. 325 !! C char\* pointer string. 338 326 !! @note 339 327 !! If __cstr__ is not allocated (i.e. the C_PTR is not associated) or if it is set 340 328 !! to a C empty string (i.e. '\0') then the method returns an empty string. 341 329 !! @attention 342 !! The method does not free the underlying C string and it should be free using 330 !! The method does not free the underlying C string and it should be free using 343 331 !! the subroutine free_c(_cstr_). 344 332 TYPE(C_PTR), INTENT(in) :: cstr … … 366 354 367 355 FUNCTION cstring(string) RESULT(str) 368 !> convert Fortran string to cstring 356 !> convert Fortran string to cstring 369 357 !! 370 358 !! The method returns a copy of the input string suitable for C functions argument. 371 !! @note 359 !! @note 372 360 !! Input string is trimmed during computations 373 361 CHARACTER(len=*), INTENT(in) :: string … … 385 373 !=============================================================================== 386 374 387 FUNCTION fs_getgid() RESULT(ret) 375 FUNCTION fs_getgid() RESULT(ret) 388 376 !! Get Group ID 389 377 INTEGER(kind=4) :: ret !! An integer with the group identifier 390 ret = INT(getgid_c(),kind=4) 378 ret = INT(getgid_c(),kind=4) 391 379 RETURN 392 380 END FUNCTION fs_getgid … … 399 387 END FUNCTION fs_getpid 400 388 401 FUNCTION fs_getuid() RESULT(ret) 389 FUNCTION fs_getuid() RESULT(ret) 402 390 !! Get User ID 403 391 INTEGER(kind=4) :: ret !! An integer with the user identifier … … 413 401 zname = gname_c(gid) 414 402 IF (.NOT.C_ASSOCIATED(zname)) THEN 415 gname = "" 403 gname = "" 416 404 ELSE 417 405 gname = cstr2fstr(zname) … … 427 415 zname = gname_c(uid) 428 416 IF (.NOT.C_ASSOCIATED(zname)) THEN 429 uname = "" 417 uname = "" 430 418 ELSE 431 419 uname = cstr2fstr(zname) … … 438 426 CHARACTER(len=*), INTENT(in) :: path 439 427 !! A string with a (valid) path 440 CHARACTER(len=:), ALLOCATABLE :: opath 428 CHARACTER(len=:), ALLOCATABLE :: opath 441 429 !! A Fortran allocated string with the parent directory path or an empty string if method fails 442 430 TYPE(C_PTR) :: zpath … … 458 446 CHARACTER(len=*), INTENT(in) :: path 459 447 !! A string with a (valid) path 460 CHARACTER(len=:), ALLOCATABLE :: opath 448 CHARACTER(len=:), ALLOCATABLE :: opath 461 449 !! The basename of the path or an empty string if method fails 462 450 TYPE(C_PTR) :: zpath … … 478 466 !! 479 467 !! The method computes the absolute path of the given path using C realpath function. 480 !! @note 468 !! @note 481 469 !! If the input path is empty then current working directory is returned. 482 470 CHARACTER(len=*), INTENT(in) :: path 483 471 !! A string with a (valid) path 484 CHARACTER(len=:), ALLOCATABLE :: opath 472 CHARACTER(len=:), ALLOCATABLE :: opath 485 473 !! The absolute of the path or an empty string if method fails 486 474 TYPE(C_PTR) :: zpath … … 497 485 !! Get the relative representation of two paths 498 486 !! 499 !! The method computes the relative representation of __path__ from __reldir__ if possible. 487 !! The method computes the relative representation of __path__ from __reldir__ if possible. 500 488 !! If no common prefix is found, the method returns __path__. 501 489 CHARACTER(len=*), INTENT(in) :: path, & !! Path to be computed relative to reldir … … 508 496 ELSE 509 497 res = cstr2fstr(zpath) 510 ENDIF 498 ENDIF 511 499 CALL free_c(zpath) 512 500 END FUNCTION fs_relpath 513 501 514 FUNCTION fs_getcwd() RESULT(path) 502 FUNCTION fs_getcwd() RESULT(path) 515 503 !! Get the current working directory 516 504 CHARACTER(len=:), ALLOCATABLE :: path … … 558 546 LOGICAL :: ret !! True on success, false otherwise. 559 547 IF (LEN_TRIM(old) == 0.OR.LEN_TRIM(new) == 0) THEN 560 ret = .false. 548 ret = .false. 561 549 ELSE 562 550 ret = INT(rename_c(cstring(ADJUSTL(old)),cstring(ADJUSTL(new)))) == 0 … … 572 560 INTEGER(kind=C_INT) :: zmode 573 561 IF (LEN_TRIM(path) == 0) THEN 574 ret = .false. 562 ret = .false. 575 563 ELSE 576 564 zmode = INT(oct_2_dec(mode),kind=C_INT) … … 585 573 LOGICAL :: ret !! True on success, false otherwise. 586 574 IF (LEN_TRIM(path) == 0) THEN 587 ret = .false. 575 ret = .false. 588 576 ELSE 589 577 ret = INT(chdir_c(cstring(ADJUSTL(path)))) == 0 … … 597 585 !! The method attempts to create a new directory pointed by __path__ with the permission 598 586 !! given by mode. 599 CHARACTER(len=*), INTENT(in) :: path 587 CHARACTER(len=*), INTENT(in) :: path 600 588 !! The path to modify 601 589 INTEGER, INTENT(in), OPTIONAL :: mode … … 608 596 LOGICAL :: zperm 609 597 IF (LEN_TRIM(path) == 0) THEN 610 ret = .false. 611 ELSE 612 zmode = oct_2_dec(744) 598 ret = .false. 599 ELSE 600 zmode = oct_2_dec(744) 613 601 IF (PRESENT(mode)) THEN 614 IF (.NOT.chk_pm(mode)) THEN 602 IF (.NOT.chk_pm(mode)) THEN 615 603 ret = .false. ; RETURN 616 604 ENDIF 617 605 zmode = oct_2_dec(mode) 618 606 ENDIF 619 zperm = .false. ; IF (PRESENT(permissive)) zperm = permissive 607 zperm = .false. ; IF (PRESENT(permissive)) zperm = permissive 620 608 IF (zperm) THEN 621 609 ret = INT(mkdirp_c(cstring(ADJUSTL(path)),INT(zmode,kind=C_INT))) == 0 … … 630 618 !! Remove directory 631 619 !! 632 !! By default, the function removes an __empty__ directory. If __forced__ is given and set 620 !! By default, the function removes an __empty__ directory. If __forced__ is given and set 633 621 !! to .true. then the function recursively deletes the directory and __ALL__ its content. 634 622 CHARACTER(len=*), INTENT(in) :: path … … 638 626 LOGICAL :: ret 639 627 !! True on success, false otherwise. 640 LOGICAL :: zforce 628 LOGICAL :: zforce 641 629 IF (LEN_TRIM(path) == 0) THEN 642 ret = .false. 630 ret = .false. 643 631 ELSE 644 632 zforce = .false. ; IF (PRESENT(forced)) zforce = forced … … 655 643 !! Get some informations about a path 656 644 !! 657 !! The method retrieves various informations about the input path using fstat C function. 645 !! The method retrieves various informations about the input path using fstat C function. 658 646 !! The type of path as returned in __type__ argument is can take the following values: 659 647 !! … … 666 654 INTEGER, INTENT(out), OPTIONAL :: type, & !! Optional type of path (see function documentation). 667 655 perm, & !! Optional permission of the path 668 nlnks, & !! Optional number of links to the path 656 nlnks, & !! Optional number of links to the path 669 657 uid, & !! Optional user id 670 658 gid !! Optional group id … … 674 662 ctime !! Optional creation time 675 663 LOGICAL :: ret !! True on success, false otherwise. 676 INTEGER :: ty,pe,ln,ud,gd 664 INTEGER :: ty,pe,ln,ud,gd 677 665 INTEGER(kind=8) :: fs 678 666 CHARACTER(len=:), ALLOCATABLE :: at,mt,ct … … 691 679 ret = INT(fstat_c(cstring(ADJUSTL(path)),p,l,t,u,g,f,ta,tm,tc)) == 0 692 680 IF (ret) THEN 693 pe=INT(p) ; ln=INT(l) ; ty=INT(t) ; ud=INT(u) ; gd=INT(g) 694 fs=INT(f,kind=8) 681 pe=INT(p) ; ln=INT(l) ; ty=INT(t) ; ud=INT(u) ; gd=INT(g) 682 fs=INT(f,kind=8) 695 683 at = fstring(ta) 696 684 mt = fstring(tm) 697 685 ct = fstring(tc) 698 686 ENDIF 699 IF (PRESENT(type)) type = ty 687 IF (PRESENT(type)) type = ty 700 688 IF (PRESENT(perm)) perm = pe 701 689 IF (PRESENT(nlnks)) nlnks = ln … … 713 701 !! Check if a path is a directory 714 702 !! 715 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 703 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 716 704 !! information about __path__ type. 717 705 CHARACTER(len=*), INTENT(in) :: path !! The path to check 718 LOGICAL :: ret !! .true. if the path is a directory, .false. otherwise. 706 LOGICAL :: ret !! .true. if the path is a directory, .false. otherwise. 719 707 INTEGER :: ty 720 708 ret = fs_stat(path,type=ty) 721 ret = ret.AND.(ty==2.or.ty==3) 709 ret = ret.AND.(ty==2.or.ty==3) 722 710 RETURN 723 711 END FUNCTION fs_isdir 724 712 725 713 FUNCTION fs_isfile(path) RESULT (ret) 726 !! Check if a path is a file 727 !! 728 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 714 !! Check if a path is a file 715 !! 716 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 729 717 !! information about __path__ type. 730 718 CHARACTER(len=*), INTENT(in) :: path !! The path to check 731 LOGICAL :: ret !! .true. if the path is a file, .false. otherwise. 719 LOGICAL :: ret !! .true. if the path is a file, .false. otherwise. 732 720 INTEGER :: ty 733 721 ret=fs_stat(path,type=ty) … … 737 725 738 726 FUNCTION fs_islink(path) RESULT (ret) 739 !! Check if a path is a link 740 !! 741 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 727 !! Check if a path is a link 728 !! 729 !! The method is just a wrapper of [[fsystem(module):fs_stat(function)]] to get only specific 742 730 !! information about __path__ type. 743 731 CHARACTER(len=*), INTENT(in) :: path !! The path to check 744 LOGICAL :: ret !! .true. if the path is a link, .false. otherwise. 745 INTEGER :: ty 732 LOGICAL :: ret !! .true. if the path is a link, .false. otherwise. 733 INTEGER :: ty 746 734 ret=fs_stat(path,type=ty) 747 735 ret = ret.and.(ty==1.or.ty==3) … … 759 747 !! - 1 : Checks for EXECUTE permission 760 748 !! - 2 : Checks for WRITE permission 761 !! - 4 : Checks for READ permission 749 !! - 4 : Checks for READ permission 762 750 CHARACTER(len=*), INTENT(in) :: path !! Path to check 763 751 INTEGER, INTENT(in), OPTIONAL :: permission !! Optional permission to check … … 765 753 INTEGER(kind=C_INT) :: zp 766 754 IF (LEN_TRIM(path) == 0) THEN 767 ret = .false. 755 ret = .false. 768 756 ELSE 769 757 zp = 0 ; IF (PRESENT(permission)) zp = INT(permission,kind=C_INT) … … 777 765 !! Split given path into base,extension 778 766 !! 779 !! The __base__ of a path is conventionnally defined as all characters before the last dot of the path. 780 !! The extension (__ext__) of the path gathers consequently all characters from the last dot to the end 767 !! The __base__ of a path is conventionnally defined as all characters before the last dot of the path. 768 !! The extension (__ext__) of the path gathers consequently all characters from the last dot to the end 781 769 !! of the string. 782 770 !! @note 783 !! If the basename of the path begins by a dot then the path is assumed to be an hidden file (directory). 771 !! If the basename of the path begins by a dot then the path is assumed to be an hidden file (directory). 784 772 !! __ext__ will then be empty. 785 CHARACTER(len=*), INTENT(in) :: path !! Path to split 773 CHARACTER(len=*), INTENT(in) :: path !! Path to split 786 774 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: base, & !! Output base of the path 787 775 ext !! Output extension of the path 788 LOGICAL, INTENT(in), OPTIONAL :: absolute !! .true. to return absolute path 789 LOGICAL :: ret !! .true. on success, .false. otherwise. 776 LOGICAL, INTENT(in), OPTIONAL :: absolute !! .true. to return absolute path 777 LOGICAL :: ret !! .true. on success, .false. otherwise. 790 778 LOGICAL :: zabs 791 779 INTEGER :: p 792 780 CHARACTER(len=:), ALLOCATABLE :: d,b,apath 793 base = "" ; ext = "" 781 base = "" ; ext = "" 794 782 ret = .false. 795 783 IF (LEN_TRIM(path) == 0) THEN … … 800 788 IF (zabs) THEN 801 789 apath = fs_realpath(path) ; IF (LEN_TRIM(apath) == 0) RETURN 802 ENDIF 790 ENDIF 803 791 d = fs_dirname(apath) ; IF (LEN_TRIM(d) == 0) RETURN 804 792 b = fs_basename(apath) ; IF (LEN_TRIM(b) == 0) RETURN … … 806 794 ! If dot is set as first char of basename : it's an hidden file 807 795 IF (p > 1) THEN 808 ext = b(p:) ; base = TRIM(d)//"/"//b(:p-1) 809 ELSE 810 base = TRIM(apath) 796 ext = b(p:) ; base = TRIM(d)//"/"//b(:p-1) 797 ELSE 798 base = TRIM(apath) 811 799 ENDIF 812 800 ret = .true. … … 815 803 816 804 FUNCTION fs_create(path, mode, type, permissive) RESULT(ret) 817 !! Create a directory/file 805 !! Create a directory/file 818 806 !! 819 807 !! The method creates the file/directory pointed by given __path__. … … 827 815 !! Unless __permissive__ is set to .true., the method will fails if intermediate 828 816 !! directories in the path do not exist. 829 CHARACTER(len=*), INTENT(in) :: path !! Path to create 817 CHARACTER(len=*), INTENT(in) :: path !! Path to create 830 818 INTEGER, INTENT(in), OPTIONAL :: mode !! Optional octal permisions to set 831 819 CHARACTER(len=1), INTENT(in), OPTIONAL :: type !! Optional type of path to create … … 833 821 LOGICAL :: ret !! True on success, false otherwise. 834 822 INTEGER :: zmd,zt,zp 835 CHARACTER(len=:), ALLOCATABLE :: b,e 823 CHARACTER(len=:), ALLOCATABLE :: b,e 836 824 ret = .false. 837 825 ! Checking for existence … … 839 827 RETURN 840 828 ELSE IF (fs_access(path)) THEN 841 RETURN 829 RETURN 842 830 ENDIF 843 831 ! Set type of path 844 832 IF (PRESENT(type)) THEN 845 833 IF (.NOT.(type(1:1)=="f".OR.type(1:1)=="d")) THEN 846 RETURN 834 RETURN 847 835 ELSE 848 836 zt=0 ; IF (type(1:1)=="f") zt = 1 … … 854 842 ! set permissions according to type 855 843 IF (zt == 0) THEN 856 zmd = oct_2_dec(777)-get_umask() 844 zmd = oct_2_dec(777)-get_umask() 857 845 ELSE 858 846 zmd = oct_2_dec(666) -get_umask() … … 874 862 FUNCTION fs_get_parent(path, n) RESULT(opath) 875 863 !! Get the nth parent of the given path 876 !! 877 !! The method first resolves the given path using [[fsystem(module):fs_realpath(function)]] 864 !! 865 !! The method first resolves the given path using [[fsystem(module):fs_realpath(function)]] 878 866 !! to get an absolute path. 879 !! @note 867 !! @note 880 868 !! If __n__ is greater than the maximum parent level of the path, "/" is returned. 881 869 CHARACTER(len=*), INTENT(in) :: path 882 870 !! Input path 883 INTEGER, INTENT(in), OPTIONAL :: n 871 INTEGER, INTENT(in), OPTIONAL :: n 884 872 !! The level of the parent to get 885 873 CHARACTER(len=:), ALLOCATABLE :: opath 886 !! The nth parent of the given path, or an empty string if the parent can not be computed 874 !! The nth parent of the given path, or an empty string if the parent can not be computed 887 875 CHARACTER(len=:), ALLOCATABLE :: zp 888 876 INTEGER :: i,mx,zl,mzl 889 opath = "" 877 opath = "" 890 878 zl = 1 ; IF (PRESENT(n)) zl = MAX(n,1) 891 879 IF (LEN_TRIM(path) == 0) THEN … … 900 888 mzl = 1 ; DO i=1,mx ; IF(zp(i:i) == '/') mzl=mzl+1 ; ENDDO 901 889 i=0 902 DO 890 DO 903 891 mx = INDEX(zp(1:mx),'/',.true.) ; i=i+1 904 IF (mx==0.OR.i>=zl.OR.i>=mzl) EXIT 892 IF (mx==0.OR.i>=zl.OR.i>=mzl) EXIT 905 893 mx = mx - 1 906 894 ENDDO 907 895 IF (mx >= 1) THEN 908 896 opath = zp(1:MAX(1,mx-1)) 909 ELSE 910 opath = "/" 897 ELSE 898 opath = "/" 911 899 ENDIF 912 900 RETURN … … 929 917 SUBROUTINE fs_usleep(usec) 930 918 !! Sleep for a given number of microseconds 931 !! @note 932 !! Currently if C usleep function failed, the system... does not sleep ! 919 !! @note 920 !! Currently if C usleep function failed, the system... does not sleep ! 933 921 INTEGER, INTENT(in) :: usec !! The number of microseconds to sleep for 934 INTEGER(kind=C_INT) :: ret 922 INTEGER(kind=C_INT) :: ret 935 923 ! usleep expects useconds_t (unsigned int) which is given here as a 4-bytes int 936 924 ret = usleep_c(INT(usec,kind=C_INT)) … … 979 967 LOGICAL :: zpeak 980 968 CHARACTER(len=2) :: zunits 981 INTEGER(kind=8) :: ztot,zava,zfre 969 INTEGER(kind=8) :: ztot,zava,zfre 982 970 983 971 zunits = 'B ' ; IF (PRESENT(units)) zunits = units 984 972 IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B ' 985 973 ret = INT(getSystemMemory_c(ztot,zava,zfre),kind=4) == 0 986 ztot = ztot * 1024 ; zava = zava * 1024 ; zfre = zfre * 1024 974 ztot = ztot * 1024 ; zava = zava * 1024 ; zfre = zfre * 1024 987 975 988 976 IF (PRESENT(total)) total = ztot … … 1014 1002 FUNCTION oct_2_dec(octal) RESULT(res) 1015 1003 !> Octal to decimal conversion 1016 !! 1004 !! 1017 1005 !! The method converts the octal number ranging from 0 to 777 in the decimal system. 1018 1006 !! @attention … … 1029 1017 ENDDO 1030 1018 res=d 1031 RETURN 1019 RETURN 1032 1020 END FUNCTION oct_2_dec 1033 1021 … … 1059 1047 !! Get octal number of string representation's permission 1060 1048 CHARACTER(len=3),INTENT(in) :: str !! The permission to convert 1061 INTEGER :: oct !! Octal value of the string permission on succes, -1 otherwise. 1049 INTEGER :: oct !! Octal value of the string permission on succes, -1 otherwise. 1062 1050 oct = -1 1063 1051 IF (LEN_TRIM(str) /= 3) RETURN 1064 1052 SELECT CASE(str) 1065 CASE("---") ; oct = 0 1053 CASE("---") ; oct = 0 1066 1054 CASE("--x") ; oct = 1 1067 1055 CASE("-w-") ; oct = 2 … … 1071 1059 CASE("rw-") ; oct = 6 1072 1060 CASE("rwx") ; oct = 7 1073 CASE DEFAULT 1061 CASE DEFAULT 1074 1062 oct = -1 ; RETURN 1075 END SELECT 1063 END SELECT 1076 1064 RETURN 1077 1065 END FUNCTION sp_2_op … … 1090 1078 CASE(6) ; str="rw-" 1091 1079 CASE(7) ; str="rwx" 1092 CASE DEFAULT 1080 CASE DEFAULT 1093 1081 str='ukn' ; RETURN 1094 END SELECT 1082 END SELECT 1095 1083 RETURN 1096 1084 END FUNCTION op_2_sp … … 1098 1086 FUNCTION str_perm(oct_perm) RESULT(ret) 1099 1087 !! Get the string representation of the given permission mask 1100 INTEGER, INTENT(in) :: oct_perm !! The octal representation of the permission 1088 INTEGER, INTENT(in) :: oct_perm !! The octal representation of the permission 1101 1089 CHARACTER(len=9) :: ret !! String representation of the octal number on succes, 'ukn' otherwise 1102 1090 INTEGER :: u,g,o 1103 IF (.NOT.chk_pm(oct_perm)) THEN 1091 IF (.NOT.chk_pm(oct_perm)) THEN 1104 1092 ret = "ukn" ; RETURN 1105 1093 ENDIF … … 1169 1157 1170 1158 SUBROUTINE chrono_start(this) 1171 !! Start the chrono. 1159 !! Start the chrono. 1172 1160 !! 1173 1161 !! @note … … 1180 1168 ENDIF 1181 1169 this%on_run = .true. 1182 END SUBROUTINE chrono_start 1170 END SUBROUTINE chrono_start 1183 1171 1184 1172 SUBROUTINE chrono_stop(this) … … 1197 1185 END SUBROUTINE chrono_reset 1198 1186 1199 SUBROUTINE chrono_get(this,cpu,clock,units) 1187 SUBROUTINE chrono_get(this,cpu,clock,units) 1200 1188 !! Get elapsed time since last call of start or reset methods. 1201 !! 1189 !! 1202 1190 !! The method computes the time elapsed in two ways : 1203 1191 !! 1204 1192 !! - If the [[fsystem(module):chrono(type)]] is not running, the method retruns 0. 1205 !! - Otherwise, elapsed time since the last call of 1193 !! - Otherwise, elapsed time since the last call of 1206 1194 !! [[chrono(type):start(bound)]] (or [[chrono(type):reset(bound)]]). 1207 1195 OBJECT(chrono), INTENT(in) :: this … … 1209 1197 REAL(kind=8), INTENT(out), OPTIONAL :: cpu 1210 1198 !! Elapsed cpu time in seconds by default (see units argument). 1211 REAL(kind=8), INTENT(out), OPTIONAL :: clock 1199 REAL(kind=8), INTENT(out), OPTIONAL :: clock 1212 1200 !! Elapsed system clock time in seconds by default (see units argument). 1213 1201 CHARACTER(len=2), INTENT(in), OPTIONAL :: units 1214 1202 !! 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'. 1203 !! be one of the following : 'ms', 's' (default), 'm', 'h' or 'd'. 1216 1204 CHARACTER(len=2) :: zu 1217 1205 REAL(kind=8) :: cu, fact … … 1223 1211 ENDIF 1224 1212 IF (PRESENT(clock)) THEN 1225 CALL SYSTEM_CLOCK(ck,r,m) 1213 CALL SYSTEM_CLOCK(ck,r,m) 1226 1214 clock = c2t(ck,this%clock_start,r,m) 1227 1215 ENDIF … … 1231 1219 ENDIF 1232 1220 fact = 1d0 1233 zu = 's' 1221 zu = 's' 1234 1222 IF (PRESENT(units)) THEN 1235 1223 zu = units … … 1242 1230 END SELECT 1243 1231 ENDIF 1244 IF (PRESENT(cpu)) cpu = cpu / fact 1232 IF (PRESENT(cpu)) cpu = cpu / fact 1245 1233 IF (PRESENT(clock)) clock = clock / fact 1246 1234 END SUBROUTINE chrono_get … … 1249 1237 !! Get the real-time between two clock counts from system_clock. 1250 1238 INTEGER(kind=8), INTENT(in) :: e !! Final clock count 1251 INTEGER(kind=8), INTENT(in) :: i !! Initial clock count 1239 INTEGER(kind=8), INTENT(in) :: i !! Initial clock count 1252 1240 INTEGER(kind=8), INTENT(in) :: r !! Clock count rate 1253 1241 INTEGER(kind=8), INTENT(in) :: m !! Maximum Clock count value -
trunk/LMDZ.TITAN/libf/muphytitan/mm_clouds.f90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne2 ! Contributor : J. Burgalat(GSMA, URCA)1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 ! Contributors: J. Burgalat (GSMA, URCA), B. de Batz de Trenquelléon (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Clouds microphysics module 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 !! corrections: B. de Batz de Trenquelléon (2023) 38 39 39 40 MODULE MM_CLOUDS 40 41 !! Clouds microphysics module. 41 42 !! 42 !! The module contains all definitions of the microphysics processes related to clouds: 43 !! The module contains all definitions of the microphysics processes related to clouds: 43 44 !! 44 45 !! - [nucleation](page/clouds.html#nucleation) … … 46 47 !! - [sedimentation](page/clouds.html#sedimentation) 47 48 !! 48 !! 49 !! The interface methods always use the global variables defined in [[mm_globals(module)]] when values 50 !! ( any kind,temperature, pressure, moments...) over the vertical grid are required.51 !! Consequently, all these functions only deal s with output argument which are most of the time the49 !! 50 !! The interface methods always use the global variables defined in [[mm_globals(module)]] when values 51 !! (temperature, pressure, moments...) over the vertical grid are required. 52 !! Consequently, all these functions only deal with output arguments which are most of the time the 52 53 !! tendencies of relevant variables on the atmospheric column. 53 54 !! 54 !! @note 55 !! Tendencies returned by public methods are always defined from __TOP__ of the atmosphere to the 55 !! @note 56 !! Tendencies returned by public methods are always defined from __TOP__ of the atmosphere to the 56 57 !! __GROUND__. 57 58 USE MM_MPREC … … 62 63 PRIVATE 63 64 64 PUBLIC :: mm_cloud_microphysics, mm_cloud_sedimentation, mm_cloud_nucond 65 66 65 PUBLIC :: mm_cloud_microphysics, mm_cloud_sedimentation, mm_cloud_nucond 66 67 CONTAINS 67 68 68 69 !============================================================================ … … 73 74 !! Get the evolution of moments tracers through clouds microphysics processes. 74 75 !! 75 !! The subroutine is a wrapper to the clouds microphysics methods. It computes the tendencies of moments 76 !! The subroutine is a wrapper to the clouds microphysics methods. It computes the tendencies of moments 76 77 !! tracers for nucleation, condensation and sedimentation processes for the atmospheric column. 77 78 !! 78 !! @note 79 !! Both __dm3i__ and __dgazs__ are 2D-array with the vertical layers in first dimension and the number 80 !! of ice components in the second. 79 !! @note 80 !! Both __dm3i__ and __dgazs__ are 2D-array with the vertical layers in first dimension and the number 81 !! of ice components in the second. 81 82 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm0a 82 !! Tendency of the 0th order moment of the aerosols (fractal mode) (\(m^{-3}\)).83 !! Tendency of the 0th order moment of the aerosols (fractal mode) (\(m^{-3}\)). 83 84 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm3a 84 85 !! Tendency of the 3rd order moment of the aerosols distribution (fractal mode) (\(m^{3}.m^{-3}\)) . 85 86 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm0n 86 !! Tendency of the 0th order moment of the aerosols distribution (fractal mode)(\(m^{-3}\)).87 !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)). 87 88 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm3n 88 89 !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)). 89 90 REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dm3i 90 !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-3}\)).91 !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-3}\)). 91 92 REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dgazs 92 !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)).93 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm0n,zdm3n 93 !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)). 94 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm0n,zdm3n 94 95 REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: zdm3i 95 96 INTEGER :: i 96 dm0a = 0._mm_wp ; dm3a = 0._mm_wp 97 dm0n = 0._mm_wp ; dm3n = 0._mm_wp 97 dm0a = 0._mm_wp ; dm3a = 0._mm_wp 98 dm0n = 0._mm_wp ; dm3n = 0._mm_wp 98 99 dm3i = 0._mm_wp ; dgazs = 0._mm_wp 99 100 … … 108 109 call mm_cloud_sedimentation(zdm0n,zdm3n,zdm3i) 109 110 110 ! computes precipitation s / ice fluxes111 ! computes precipitation, settling velocity and flux of ices 111 112 mm_ccn_prec = SUM(zdm3n*mm_dzlev) 112 mm_ccn_flux(:) = get_mass_flux(mm_rhoaer,mm_m3ccn(:)) 113 114 DO i=1, mm_nesp 113 mm_ccn_w(:) = wsettle(mm_play,mm_temp,mm_zlay,mm_drho,mm_drad) 114 mm_ccn_flux(:) = get_mass_flux(mm_rhoaer,mm_m3ccn(:)) 115 116 DO i=1, mm_nesp 115 117 mm_ice_prec(i) = SUM(zdm3i(:,i)*mm_dzlev) 116 mm_ice_fluxes(:,i) = get_mass_flux(mm_xESPS(i)%rho,mm_m3ice(:,i)) 117 ENDDO 118 mm_ice_fluxes(:,i) = get_mass_flux(mm_xESPS(i)%rho,mm_m3ice(:,i)) 119 ENDDO 118 120 ! updates tendencies 119 121 dm0n = dm0n + zdm0n … … 131 133 !! Get moments tendencies through nucleation/condensation/evaporation. 132 134 !! 133 !! The method is a wrapper of [[mm_clouds(module):nc_esp(subroutine)]] which computes the 135 !! The method is a wrapper of [[mm_clouds(module):nc_esp(subroutine)]] which computes the 134 136 !! tendencies of tracers for all the condensible species given in the vector __xESPS__. 135 137 !! 138 !! Aerosols and CCN distribution evolution depends on the ice components: 139 !! - For nucleation only creation of CCN can occur. 140 !! - For condensation only loss of CCN can occur. 141 !! 142 !! We use the simple following rule to compute the variation of CCN and aerosols: 143 !! The global variation of CCN (and thus aerosols) is determined from the most intense activity 144 !! of the ice components. 145 !! 136 146 !! @warning 137 !! __xESPS__, __m3i__ and __gazes__ must share the same indexing. For example if __xESPS(IDX)__ 138 !! corresponds to \(CH_{4}\) properties then __m3i(IDX)__ must be the total volume of solid 147 !! __xESPS__, __m3i__ and __gazes__ must share the same indexing. For example if __xESPS(IDX)__ 148 !! corresponds to \(CH_{4}\) properties then __m3i(IDX)__ must be the total volume of solid 139 149 !! \(CH_{4}\) (ice) and __gazs(IDX)__ its vapor mole fraction. 140 150 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm0a 141 151 !! Tendency of the 0th order moment of the aerosols (fractal mode) (\(m^{-3}\)). 142 152 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm3a 143 !! Tendency of the 3rd order moment of the aerosols distribution (fractal mode) (\(m^{3}.m^{-3}\)).153 !! Tendency of the 3rd order moment of the aerosols distribution (fractal mode) (\(m^{3}.m^{-3}\)). 144 154 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm0n 145 155 !! Tendency of the 0th order moment of the aerosols distribution (fractal mode) (\(m^{-3}\)). 146 156 REAL(kind=mm_wp), DIMENSION(:), INTENT(out) :: dm3n 147 157 !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)). 148 158 REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dm3i 149 159 !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-3}\)). 150 160 REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dgazs 151 161 !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)) . 152 162 REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: gazsat 153 !! Saturation ratio of each condensible specie. 154 INTEGER :: i,idx,ng 155 TYPE(mm_esp) :: xESP 163 !! Saturation ratio of each condensible specie. 164 INTEGER :: i,idx 156 165 REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: zdm0a,zdm3a,zdm0n,zdm3n 166 157 167 ALLOCATE(zdm0a(mm_nla,mm_nesp),zdm3a(mm_nla,mm_nesp), & 158 168 zdm0n(mm_nla,mm_nesp),zdm3n(mm_nla,mm_nesp)) … … 164 174 ENDDO 165 175 166 ! Computes balance :167 ! Each ice components has been treated independently from the others, and168 ! their tendencies are returned as is (just converted in input units).169 !170 ! Aerosols and CCN distribution evolution depends on the ice components:171 ! - For nucleation only creation of CCN can occur.172 ! - For condensation only loss of CCN can occur.173 ! We use the simple following rule :174 ! The global variation of CCN (and thus aerosols) is determined from the175 ! most intense activity of the ice components.176 ! that is the maximum value of the CCN tendencies regardless of its sign.177 176 DO i=1, mm_nla 178 idx = MAXLOC(zdm0n(i,:),DIM=1) ! WARNING this is not the definition above (should be in ABS() func) 179 dm0n(i) = zdm0n(i,idx) 180 dm3n(i) = zdm3n(i,idx) 181 dm0a(i) = zdm0a(i,idx) 182 dm3a(i) = zdm3a(i,idx) 183 ! all ice are returned but we must convert their units 184 dm3i(i,:) = dm3i(i,:) 177 ! retrieve the index of the maximum tendency of CCN where ice variation is not null. 178 idx = MAXLOC(zdm0n(i,:),DIM=1,MASK=(dm3i(i,:) /= 0._mm_wp .OR. mm_m3ice(i,:)+dm3i(i,:) >= 0._mm_wp)) 179 IF (idx == 0) THEN 180 dm0n(i) = 0._mm_wp 181 dm3n(i) = 0._mm_wp 182 dm0a(i) = 0._mm_wp 183 dm3a(i) = 0._mm_wp 184 ELSE 185 IF (mm_debug .AND. ABS(zdm0n(i,idx)) > 1e3) THEN 186 WRITE(*,'((a),I2.2,(a),ES10.3,(a))') "Z(",i,") = ",mm_play(i)*1e2, & 187 " mbar: Max aer/ccn exchange variation due to specie: "//TRIM(mm_xESPS(idx)%name) 188 ENDIF 189 dm0n(i) = zdm0n(i,idx) 190 dm3n(i) = zdm3n(i,idx) 191 dm0a(i) = zdm0a(i,idx) 192 dm3a(i) = zdm3a(i,idx) 193 ENDIF 185 194 ENDDO 195 186 196 END SUBROUTINE mm_cloud_nucond 187 197 … … 189 199 !! Get moments tendencies through nucleation/condensation/evaporation of a given condensible specie. 190 200 !! 191 !! The method computes the global tendencies of the aerosols, ccn and "ice" moments through cloud 201 !! The method computes the global tendencies of the aerosols, ccn and "ice" moments through cloud 192 202 !! microphysics processes (nucleation & condensation). 193 203 !! 194 204 !! @warning 195 !! Input quantities __m3iX__,__m3iO__, __m0aer__,__m3aer__, __m0ccn__,__m3ccn__ are assumed to be in 196 !! \(X. kg^{-1}\) (where X is the unit of the moment that is, a number for M0 and a volume - \(m^3\)205 !! Input quantities __m3iX__,__m3iO__, __m0aer__,__m3aer__, __m0ccn__,__m3ccn__ are assumed to be in 206 !! \(X.m^{-3}\) (where X is the unit of the moment that is, a number for M0 and a volume - \(m^3\) 197 207 !! for M3) ; __vapX__ must be expressed in term of molar fraction. 198 208 TYPE(mm_esp), INTENT(in) :: xESP 199 209 !! Condensate specie properties. 200 210 REAL(kind=mm_wp),INTENT(in), DIMENSION(:) :: vapX 201 211 !! Gas specie molar fraction on the vertical grid from __TOP__ to __GROUND__ (\(mol.mol^{-1}\)). 202 212 REAL(kind=mm_wp),INTENT(in), DIMENSION(:) :: m3iX 203 213 !! 3rd order moment of the ice component (\(m^{3}.m^{-3}\)). 204 214 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dvapX 205 215 !! Tendency of gas specie (\(mol.mol^{-1}\)). 206 216 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3iX 207 217 !! Tendency of the 3rd order moment of the ice component (\(m^{3}.m^{-3}\)). 208 218 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm0aer 209 219 !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)). 210 220 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3aer 211 221 !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)). 212 222 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm0ccn 213 223 !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)). 214 224 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3ccn 215 225 !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)). 216 226 REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: Xsat 217 227 !! Saturation ratio values on the vertical grid (--). 218 228 INTEGER :: i 219 229 REAL(kind=mm_wp) :: bef,aft 220 230 REAL(kind=mm_wp), DIMENSION(SIZE(vapX)) :: sm0a,sm3a,sm0n,sm3n,sm3iX 221 231 REAL(kind=mm_wp), DIMENSION(SIZE(vapX)) :: zm0a,zm3a,zm0n,zm3n,zm3iX,zvapX 222 REAL(kind=mm_wp), DIMENSION(SIZE(vapX)) :: pX,sig,qsat,lheat,seq,up,down, & 223 ctot,newvap,nucr,grate,cm0,cm3 224 ! Initialization : 225 ! Copy input argument and convert units X.m-3 -> X.kg-1) 232 REAL(kind=mm_wp), DIMENSION(SIZE(vapX)) :: pX,sig,qsat,seq,up,down,ctot,newvap,nucr,grate,cm0,cm3,drad 233 234 ! get a copy of drop radius. 235 drad(:) = mm_drad(:) 236 237 ! Initialization : 238 ! Copy input argument and convert units X.m-3 -> X.kg-1 226 239 ! sXXX is the initial converted value saved 227 sm3iX = m3iX/mm_rhoair 240 sm3iX = m3iX/mm_rhoair 228 241 sm0a = mm_m0aer_f/mm_rhoair ; sm3a = mm_m3aer_f/mm_rhoair 229 242 sm0n = mm_m0ccn/mm_rhoair ; sm3n = mm_m3ccn/mm_rhoair 230 243 ! zXXX is our working copy 231 zm3i x = sm3ix; zm0a = sm0a ; zm3a = sm3a ; zm0n = sm0n ; zm3n = sm3n232 233 ! Molar fraction of X specie is set in mass mixing ratio 244 zm3iX = sm3iX ; zm0a = sm0a ; zm3a = sm3a ; zm0n = sm0n ; zm3n = sm3n 245 246 ! Molar fraction of X specie is set in mass mixing ratio [kg.kg-1] 234 247 zvapX = vapX * xESP%fmol2fmas 235 ! Surface tension 248 ! Surface tension [N.m-1] 236 249 sig = mm_sigX(mm_temp,xESP) 237 ! X specie mass mixing ratio at saturation 238 qsat = mm_ qsatX(mm_temp,mm_play,xESP)250 ! X specie mass mixing ratio at saturation [kg.kg-1] 251 qsat = mm_ysatX(mm_temp,mm_play,xESP) * xESP%fmol2fmas 239 252 ! partial pressure of X specie 240 253 pX = vapX * mm_play 241 254 ! Saturation ratio 242 255 Xsat = zvapX / qsat 243 ! Equilibrium saturation near the drop 244 seq = dexp(2._mm_wp*sig*xESP%masmol/(xESP%rho*mm_rgas*mm_temp*mm_drad)) 245 ! Latent heat released 246 lheat = mm_lheatX(mm_temp,xESP) 256 247 257 ! Gets nucleation rate (ccn radius is the monomer !) 248 258 call nuc_rate((/(mm_rm, i=1,mm_nla)/),mm_temp,xESP,pX,Xsat,nucr) 259 ! IMPORTANT: update CCN and aerosols moment from nucleation NOW ! 260 ! Doing so should prevent a nasty bug that occurs if we want to generate clouds from scratch (i.e. a "dry" atmosphere without any clouds tracers already present). 261 ! 262 ! In such case, we do not produce ice variation on the first call of the method, at most only CCN are produced (i.e. dm3i == 0, dm3n != 0) 263 ! But the rules for computing the global tendencies in mm_cloud_nucond state that the global variation for CCN is due to the most active specie exchange. 264 ! 265 ! for nucleation we have the following equations: 266 ! dMa(k)/dt = - dMn(k)/dt (conservation of aerosols+ccn) (1) 267 ! dMa(k)/dt = - 4*PI*nucr/rm * Ma(k+3) (2) 268 ! = - 4*PI*nucr/rm * alpha(k+3)/alpha(k) * rc**3 * Ma(k) 269 ! With: 270 ! - Ma(k): k-th order moment of aerosol 271 ! - Mn(k): k-th order moment of ccn 272 ! - nucr : the nucleation rate. 273 ! We solve (implicit scheme) : 274 ! CST_M(k) = 4*PI*nucr/rm * alpha(k+3)/alpha(k)*rc**3 * dt 275 ! Ma(k)[t+dt] = 1/(1+CST_M(k)) * Ma(k)[t] (3) 276 ! Then, from eq. 2: 277 ! Mn(k)[t+dt] = Mn(k)[t] + CST_M(k)/(1+CST_M(k))*Ma(k)[t] (4) 278 cm0 = 4._mm_wp*mm_pi*nucr/mm_rm*mm_alpha_f(3._mm_wp)*mm_rcf**3*mm_dt 279 cm3 = 4._mm_wp*mm_pi*nucr/mm_rm*mm_alpha_f(6._mm_wp)/mm_alpha_f(3._mm_wp)*mm_rcf**3*mm_dt 280 zm0a = 1._mm_wp/(1._mm_wp+cm0) * zm0a 281 zm3a = 1._mm_wp/(1._mm_wp+cm3) * zm3a 282 WHERE (zm0a <= 0._mm_wp .OR. zm3a <= 0._mm_wp) 283 zm0a = 0._mm_wp 284 zm3a = 0._mm_wp 285 zm0n = zm0n + sm0a 286 zm3n = zm3n + sm3a 287 ELSEWHERE 288 zm0n = zm0n + cm0*zm0a 289 zm3n = zm3n + cm3*zm3a 290 ENDWHERE 291 292 ! update the drop radius (we probably should recompute totally the radius to be in better agreement with the other moments) 293 ! We must manage the case where there is no ices and no ccn ==> drop radius is ZERO, 294 ! but conditions are met to spawn nucleation process: creation of ccn. 295 ! Then we set the drop radius to the monomer radius. 296 ! 297 ! Doing so will prevent a nasty bug to occur later when ice volume is updated ! 298 WHERE (nucr > 0._mm_wp .AND. drad <= mm_drad_min) 299 drad = mm_rm 300 ENDWHERE 301 302 ! Equilibrium saturation near the drop 303 seq = exp(min(30._mm_wp,2._mm_wp*sig*xESP%masmol/(xESP%rho*mm_rgas*mm_temp*drad))) 249 304 ! Gets growth rate 250 call growth_rate(mm_temp,mm_play,pX/Xsat,xESP,seq, mm_drad,grate)251 ctot = zvapx + xESP%rho * m3iX252 up = vapx + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * mm_drad * seq * zm0n253 down = 1._mm_wp + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * mm_drad / qsat * zm0n305 call growth_rate(mm_temp,mm_play,pX/Xsat,xESP,seq,drad,grate) 306 ctot = zvapx + xESP%rho * zm3iX 307 up = zvapx + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * drad * seq * zm0n 308 down = 1._mm_wp + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * drad / qsat * zm0n 254 309 ! gets new vapor X specie mass mixing ratio : cannot be greater than the 255 310 ! total gas + ice and lower than nothing :) … … 257 312 ! gets "true" growth rate 258 313 grate = grate * (newvap/qsat - seq) 259 314 260 315 ! computes tendencies through condensation 261 ! 1) check for the specific case : NO ICE and SUBLIMATION 262 WHERE (zm3iX <= 0._mm_wp .AND. grate <= 0._mm_wp) 263 ! no ice and sublimation : reset ice to 0 264 zm3iX = 0._mm_wp 265 ELSEWHERE 266 ! update ice volume ... 267 zm3iX = zm3iX + mm_dt*grate*4._mm_wp*mm_pi*mm_drad*zm0n 268 ! ... and check if there ice left in the ccn 269 WHERE (zm3ix <= 0._mm_wp) 270 zm3ix = 0._mm_wp 271 zm0a = zm0a + zm0n ; zm0n = 0._mm_wp 272 zm3a = zm3a + zm3n ; zm3n = 0._mm_wp 273 ENDWHERE 274 ENDWHERE 275 276 ! computes tendencies 277 ! all of these tendencies are in X.kg-1 278 dm0aer = zm0a - sm0a 279 dm3aer = zm3a - sm3a 280 dm0ccn = zm0n - sm0n 281 dm3ccn = zm3n - sm3n 282 dm3ix = zm3ix - sm3ix 283 ! and this one is in mol.mol-1 284 dvapx = -xESP%rho * dm3ix / xESP%fmol2fmas 285 286 ! reset temporary arrays to initial values 287 zm3ix = sm3ix ; zm0a = sm0a ; zm3a = sm3a ; zm0n = sm0n ; zm3n = sm3n 288 289 ! Computes global tendencies (nucleation && condensation) 290 ! 291 ! for nucleation we have the following equations: 292 ! dMaer_(k)/dt = - dMccn_(k)/dt (conservation of aerosols+ccn) (1) 293 ! dMaer_(k)/dt = - 4*PI*nucr/rm * Maer_(k+3) (2) 294 ! = - 4*PI*nucr/rm * alpha(k+3)/alpha(k) * Maer_(k) 295 ! where alpha(k+3) = Maer_(k+3)/Maer_(0) / rc**(k+3) 296 ! We solve (implicit scheme) : 297 ! CONST_M(k) = 4*PI*nucr/rm * alpha(k+3)/alpha(k)*rc**3 * dt 298 ! Maer_(k)[t+dt] = 1/(1+CONST_M(k)) * Maer_(k)[t] (3) 299 ! Then, from eq. 2: 300 ! Mccn_(k)[t+dt] = Mccn_(k)[t] + CONST_M(k)/(1+CONST_M(k))*Maer_(k)[t] (4) 301 ! 302 cm0 = 4._mm_wp*mm_pi*nucr/mm_rm*mm_alpha_f(3._mm_wp)*mm_rcf**3*mm_dt 303 cm3 = 4._mm_wp*mm_pi*nucr/mm_rm*mm_alpha_f(6._mm_wp)/mm_alpha_f(3._mm_wp)*mm_rcf**3*mm_dt 304 zm0a = 1._mm_wp/(1._mm_wp+cm0) * zm0a 305 zm3a = 1._mm_wp/(1._mm_wp+cm0) * zm3a 306 WHERE (zm0a <= 0._mm_wp .OR. zm3a <= 0._mm_wp) 307 zm0a=0._mm_wp 308 zm3a=0._mm_wp 309 zm0n = zm0n + sm0a 310 zm3n = zm3n + sm3a 311 ELSEWHERE 312 zm0n = zm0n + cm0/(1.+cm0)*zm0a 313 zm3n = zm3n + cm3/(1.+cm3)*zm3a 314 ENDWHERE 315 316 ! Adds condensation tendencies 317 zm0a = zm0a + dm0aer 318 zm3a = zm3a + dm3aer 319 zm0n = zm0n + dm0ccn 320 zm3n = zm3n + dm3ccn 316 DO i=1,mm_nla 317 ! check for the specific case : NO ICE and SUBLIMATION 318 IF (zm3iX(i) <= 0._mm_wp .AND. grate(i) <= 0._mm_wp) THEN 319 zm3iX(i) = 0._mm_wp 320 ELSE 321 ! update ice volume ... 322 zm3iX(i) = zm3iX(i) + mm_dt*grate(i)*4._mm_wp*mm_pi*drad(i)*zm0n(i) 323 ! ... and check if there is ice left in the ccn 324 IF (zm3iX(i) <= 0._mm_wp) THEN 325 zm3iX(i) = 0._mm_wp 326 zm0a(i) = zm0a(i) + zm0n(i) ; zm0n(i) = 0._mm_wp 327 zm3a(i) = zm3a(i) + zm3n(i) ; zm3n(i) = 0._mm_wp 328 ENDIF 329 ENDIF 330 ENDDO 321 331 322 332 ! Computes balance 323 333 IF (mm_debug) THEN 324 WRITE(*,'(a)') "Condensation/nucleation balance :"325 334 DO i=1,mm_nla 326 335 bef = sm0a(i) + sm0n(i) 327 336 aft = zm0a(i) + zm0n(i) 328 IF (ABS(bef-aft)/bef > 1e-10_mm_wp) WRITE(*,'((a),I2.2,(a))') & 329 "[WARNING] nc_esp speaking: Total number not conserved (z=",i,")" 337 IF (ABS(bef-aft)/bef > 1e-10_mm_wp) THEN 338 WRITE(*,'((a),I2.2,(a),ES20.12,(a),ES20.12)') & 339 "[DEBUG] nc_esp("//TRIM(xESP%name)//"): M0 not conserved (z=",i,")",bef," <-> ",aft 340 ENDIF 330 341 bef = sm3a(i) + sm3n(i) 331 342 aft = zm3a(i) + zm3n(i) 332 IF (ABS(bef-aft)/bef > 1e-10_mm_wp) WRITE(*,'((a),I2.2,(a))') & 333 "[WARNING] nc_esp speaking: Total volume not conserved (z=",i,")" 343 IF (ABS(bef-aft)/bef > 1e-10_mm_wp) THEN 344 WRITE(*,'((a),I2.2,(a),ES20.12,(a),ES20.12)') & 345 "[DEBUG] nc_esp("//TRIM(xESP%name)//"): M3 not conserved (z=",i,")",bef," <-> ",aft 346 ENDIF 334 347 ENDDO 335 348 ENDIF 336 349 337 ! Now updates tendencies 338 dm0aer = (zm0a-sm0a)*mm_rhoair 339 dm3aer = (zm3a-sm3a)*mm_rhoair 340 dm0ccn = (zm0n-sm0n)*mm_rhoair 341 dm3ccn = (zm3n-sm3n)*mm_rhoair 350 ! compute tendencies: 351 ! all of these tendencies are in X.m-3 ! 352 dm0aer = (zm0a - sm0a)*mm_rhoair 353 dm3aer = (zm3a - sm3a)*mm_rhoair 354 dm0ccn = (zm0n - sm0n)*mm_rhoair 355 dm3ccn = (zm3n - sm3n)*mm_rhoair 356 357 dm3iX = (zm3iX - sm3iX) ! this one in X.kg-1 (temporary) ! 358 dvapX = -xESP%rho * dm3iX / xESP%fmol2fmas ! in order to compute this one in mol.mol-1 359 dm3iX = dm3iX*mm_rhoair ! update ice tendencies in X.m-3 ! 342 360 343 361 END SUBROUTINE nc_esp 344 362 345 363 SUBROUTINE nuc_rate(rccn,temp,xESP,pvp,sat,rate) 346 364 !! Get nucleation rate. 347 365 !! 348 !! The method computes the heterogeneous nucleation rate for the given specie on a fractal particle 366 !! The method computes the heterogeneous nucleation rate for the given specie on a fractal particle 349 367 !! of size __rccn__. 350 368 !! Except __xESP__, all arguments are vectors of the same size (vertical grid). … … 355 373 TYPE(mm_esp), INTENT(in) :: xESP !! X specie properties (--). 356 374 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: rate !! The nucleation rate (\(m^-{2}.s^{-1}\)). 357 INTEGER :: nv 358 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: nX,rstar,gstar,x,zeldov,deltaf, & 359 fsh,fstar,sig 360 nv = SIZE(rccn) 361 ALLOCATE(nX(nv), rstar(nv), gstar(nv), x(nv), zeldov(nv), & 362 deltaf(nv), fsh(nv), fstar(nv)) 375 INTEGER :: i 376 REAL(kind=mm_wp) :: r,t,s,sig,nX,rstar,gstar,x,zeldov,deltaf,fsh,fstar 377 378 rate(:) = 0._mm_wp 363 379 ! Activation condition 364 WHERE (sat > 1._mm_wp) 365 sig = mm_sigX(temp,xESP) 366 nX = pvp/mm_kboltz/temp 367 rstar = 2._mm_wp*sig*xESP%vol/(mm_kboltz*temp*dlog(sat)) 368 ! curvature radius 369 x = rccn/rstar 370 fsh = mm_fshape(xESP%mteta,x) 371 fstar = (4._mm_wp/3._mm_wp*mm_pi)*sig*(rstar**2.)*fsh 372 deltaf=MIN(MAX((2.*mm_fdes-mm_fdif-fstar)/(mm_kboltz*temp),-100._mm_wp),100._mm_wp) 373 WHERE (deltaf == -100._mm_wp) 374 rate = 0._mm_wp 375 ELSEWHERE 376 gstar = 4._mm_wp*mm_pi*(rstar**3)/(3._mm_wp*xESP%vol) 377 zeldov = dsqrt(fstar/(3._mm_wp*mm_pi*mm_kboltz*temp*(gstar**2))) 378 rate = zeldov*mm_kboltz*temp*(nX*rstar)**2._mm_wp*dexp(deltaf)/ & 379 (fsh*mm_nus*xESP%mas) 380 ENDWHERE 381 ELSEWHERE 382 rate = 0._mm_wp 383 ENDWHERE 384 DEALLOCATE(nX,rstar,gstar,x,zeldov,deltaf,fsh,fstar) 380 DO i=1, SIZE(rccn) 381 s = sat(i) 382 IF (s > 1._mm_wp) THEN 383 t = temp(i) ; r = rccn(i) 384 sig = mm_sigX(t,xESP) 385 nX = pvp(i)/mm_kboltz/t 386 rstar = 2._mm_wp*sig*xESP%vol/(mm_kboltz*t*dlog(s)) 387 ! curvature radius 388 x = r/rstar 389 fsh = mm_fshape(xESP%mteta,x) 390 fstar = (4._mm_wp*mm_pi/3._mm_wp)*sig*(rstar**2.)*fsh 391 deltaf=MIN(MAX((2.*mm_fdes-mm_fdif-fstar)/(mm_kboltz*t),-100._mm_wp),100._mm_wp) 392 IF (deltaf > -100._mm_wp) THEN 393 gstar = 4._mm_wp*mm_pi*(rstar**3)/(3._mm_wp*xESP%vol) 394 zeldov = dsqrt(fstar/(3._mm_wp*mm_pi*mm_kboltz*t*(gstar**2))) 395 rate(i)= zeldov*mm_kboltz*t*(nX*rstar)**2._mm_wp*dexp(deltaf)/(fsh*mm_nus*xESP%mas) 396 ENDIF 397 ENDIF 398 ENDDO 399 385 400 RETURN 386 401 END SUBROUTINE nuc_rate … … 390 405 !! 391 406 !! The method computes the growth rate a drop through condensation/evaporation processes: 392 !! 407 !! 393 408 !! $$ r \times \frac{dr}{dt} = g_{rate} \times (S - S_{eq}) $$ 394 409 !! … … 396 411 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperature (K). 397 412 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pres !! Pressure level (Pa). 398 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: seq!! Saturation vapor pressure of specie (Pa).399 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: drad!! Specie properties.400 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pXsat!! Equilibrium saturation near the drop.401 TYPE(mm_esp), INTENT(in) :: xESP!! Drop radius (m).413 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pXsat !! Saturation vapor pressure of specie (Pa). 414 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 415 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: seq !! Equilibrium saturation near the drop. 416 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: drad !! Drop radius (m). 402 417 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: rate !! Growth rate (\(m^{2}.s^{-1}\)). 403 418 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: k,knu,slf,rkc,rdc,l,dv … … 412 427 ! Diffusion coefficient of X gas 413 428 Dv(:) = 1._mm_wp/3._mm_wp*dsqrt(8._mm_wp*mm_rgas*temp(:)/(mm_pi*xESP%masmol))*mm_kboltz*temp(:) / & 414 429 (mm_pi*pres(:)*(mm_air_rad+xESP%ray)**2* dsqrt(1._mm_wp+xESP%fmol2fmas)) 415 430 knu(:) = l(:)/drad(:) ! The knudsen number of the drop 416 431 slf(:) = (1.333_mm_wp+0.71_mm_wp/knu(:))/(1._mm_wp+1._mm_wp/knu(:)) ! Slip flow correction … … 424 439 RETURN 425 440 END SUBROUTINE growth_rate 426 441 427 442 428 443 !----------------------------------------------------------------------------- … … 433 448 !! Compute the tendency of _clouds_ related moments through sedimentation process. 434 449 !! 435 !! The method computes the tendencies of moments related to cloud microphysics through 436 !! sedimentation process. The algorithm used here differs from 437 !! [[mm_haze(module):mm_haze_sedimentation(subroutine)]] as all moments settle with the same 438 !! terminal velocity which is computed with the average drop radius of the size distribution. 439 !! We simply compute an _exchange matrix_ that stores the new positions of each cells through 450 !! The method computes the tendencies of moments related to cloud microphysics through 451 !! sedimentation process. The algorithm used here differs from 452 !! [[mm_haze(module):mm_haze_sedimentation(subroutine)]] as all moments settle with the same 453 !! terminal velocity which is computed with the average drop radius of the size distribution. 454 !! We simply compute an _exchange matrix_ that stores the new positions of each cells through 440 455 !! sedimentation process and then computes the matrix 441 456 !! product with input moments values to get final tendencies. 442 457 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0n 443 !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)).458 !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)). 444 459 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3n 445 !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).460 !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)). 446 461 REAL(kind=mm_wp), INTENT(out), DIMENSION(:,:) :: dm3i 447 !! Tendencies of the 3rd order moment of each ice component of the cloud (\(m^{3}m^{-3}\)).462 !! Tendencies of the 3rd order moment of each ice component of the cloud (\(m^{3}m^{-3}\)). 448 463 INTEGER :: im,nm 449 464 REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: moms, momsf,chg_matrix 465 450 466 nm = 2 + mm_nesp 451 467 ALLOCATE(moms(mm_nla,nm),momsf(mm_nla,nm),chg_matrix(mm_nla,mm_nla)) 452 ! Initializes moms 468 ! Initializes moms 453 469 moms(:,1) = mm_m0ccn * mm_dzlev 454 470 moms(:,2) = mm_m3ccn * mm_dzlev 455 DO im=1,mm_nesp 456 moms(:,2+im) = mm_m3ice(:,im) * mm_dzlev 457 ENDDO 471 DO im=1,mm_nesp ; moms(:,2+im) = mm_m3ice(:,im) * mm_dzlev ; ENDDO 458 472 ! Computes exchange matrix 459 473 CALL exchange(mm_drad,mm_drho,mm_dt,chg_matrix) … … 463 477 dm0n = (momsf(:,1)-moms(:,1))/mm_dzlev 464 478 dm3n = (momsf(:,2)-moms(:,2))/mm_dzlev 465 DO im=1,mm_nesp 466 dm3i(:,im) = (momsf(:,2+im)-moms(:,2+im))/mm_dzlev 467 ENDDO 479 DO im=1,mm_nesp ; dm3i(:,im) = (momsf(:,2+im)-moms(:,2+im))/mm_dzlev ; ENDDO 468 480 RETURN 469 481 END SUBROUTINE mm_cloud_sedimentation … … 472 484 !! Compute the exchange matrix. 473 485 !! 474 !! The subroutine computes the matrix exchange used by 475 !! [[mm_clouds(module):mm_cloud_sedimentation(subroutine)]] to compute moments tendencies 476 !! through sedimentation process. Both __rad__ and __rhog__ must be vector with relevant 486 !! The subroutine computes the matrix exchange used by 487 !! [[mm_clouds(module):mm_cloud_sedimentation(subroutine)]] to compute moments tendencies 488 !! through sedimentation process. Both __rad__ and __rhog__ must be vector with relevant 477 489 !! values over the atmospheric vertical structure. __matrix__ is square 2D-array with same 478 490 !! dimension size than __rad__. 479 491 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rad 480 492 !! Cloud drop radius over the atmospheric vertical structure (m). 481 493 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rhog 482 494 !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)). 483 495 REAL(kind=mm_wp), INTENT(in) :: dt 484 496 !! Timestep (s). 485 497 REAL(kind=mm_wp), INTENT(out) :: matrix(:,:) 486 487 INTEGER :: nz,i,j,jj,jinf,jsup498 !! The output _exchange matrix_. 499 INTEGER :: nz,i,j,jj,jinf,jsup 488 500 REAL(kind=mm_wp) :: zni,znip1,xf,xft,xcnt 489 501 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: puit 490 502 REAL(kind=mm_wp) :: cpte,cpte2 491 INTEGER, PARAMETER :: ichx = 1 503 REAL(kind=mm_wp) :: zsurf 504 INTEGER, PARAMETER :: ichx = 1 492 505 matrix = 0._mm_wp ; nz = SIZE(rad) ; ALLOCATE(puit(nz)) 493 ! compute exchange matrix 506 zsurf = mm_zlev(nz) 507 508 ! compute exchange matrix 494 509 DO i=1,nz 495 510 puit(i) = 0._mm_wp 496 511 xcnt = 0._mm_wp 497 ! computes drop move (i.e. its new positions) 498 CALL getnzs(ichx,i,rad,rhog,dt,zni,znip1) 499 500 ! Peculiar case : Ground level precipitation [znip1 <0 && (zni<0 || zni>0)]501 ! Complete precipitation [ znip1 <= 0 && zni <= 0 ] :502 IF(zni <=0._mm_wp.and.znip1<=0._mm_wp) THEN512 ! computes drop move (i.e. its new positions) 513 CALL getnzs(ichx,i,rad,rhog,dt,zni,znip1) 514 515 ! Peculiar case : Ground level precipitation [znip1 < zsurf && (zni < zsurf || zni > zsurf)] 516 ! - complete precipitation [ znip1 <= 0 && zni <= 0 ] : 517 IF(zni <= zsurf .and. znip1 <= zsurf) THEN 503 518 xft=0._mm_wp 504 519 xf=1._mm_wp … … 506 521 puit(i)=puit(i)+xf 507 522 ENDIF 508 ! partial precipitation [ znip1 <= 0 && zni > 0] :509 IF (zni >0._mm_wp .and. znip1 <= 0._mm_wp) THEN510 xft= zni/(zni-znip1)523 ! - partial precipitation [ znip1 <= zsurf && zni > zsurf ] : 524 IF (zni > zsurf .and. znip1 <= zsurf) THEN 525 xft=(zni-zsurf)/(zni-znip1) 511 526 xf=(1.-xft) 512 527 xcnt=xcnt+xf 513 528 puit(i)=puit(i)+xf 514 529 ENDIF 515 ! General case : no ground precipitation [ znip1 > 0 && zni > 0]516 IF (zni >0._mm_wp.and.znip1>0._mm_wp) THEN517 xft = 1._mm_wp 530 ! General case : no ground precipitation [ znip1 > zsurf && zni > zsurf ] 531 IF (zni > zsurf .and. znip1 > zsurf) THEN 532 xft = 1._mm_wp ! on a la totalite de la case 518 533 xf = 0._mm_wp 519 534 xcnt=xcnt+xf 520 535 puit(i)=puit(i)+xf 521 536 ENDIF 522 ! Fix minimum level to the ground 523 znip1 = MAX(znip1,0.) 524 zni = MAX(zni,0.) 537 IF (zni < znip1) THEN 538 WRITE(*,'("[EXCHANGES] WARNING, missing this case :",2(2X,ES10.3))') zni, znip1 539 ENDIF 540 541 ! Fix minimum level to the ground 542 znip1 = MAX(znip1,zsurf) 543 zni = MAX(zni,zsurf) 525 544 ! Locate new "drop" position in the verical grid 526 545 jsup=nz+1 … … 531 550 ENDDO 532 551 ! Volume is out of range: (all drops have touched the ground!) 533 ! Note: can happen here,it has been treated previously :)534 IF (jsup>=nz+1.and.jinf==jsup) THEN 552 ! Note: cannot happen here, it has been treated previously :) 553 IF (jsup>=nz+1.and.jinf==jsup) THEN 535 554 WRITE(*,'(a)') "[EXCHANGE] speaking: The impossible happened !" 536 555 call EXIT(666) 537 556 ENDIF 538 557 ! Volume inside a single level 539 IF (jsup==jinf.and.jsup<=nz) THEN 558 IF (jsup==jinf.and.jsup<=nz) THEN 540 559 xf=1._mm_wp 541 560 xcnt=xcnt+xft*xf 542 561 matrix(jinf,i)=matrix(jinf,i)+xft*xf 543 ENDIF 544 545 ! Volume over 2 levels 546 IF (jinf==jsup+1) THEN 562 ENDIF 563 564 ! Volume over 2 levels 565 IF (jinf==jsup+1) THEN 547 566 xf=(zni-mm_zlev(jinf))/(zni-znip1) 548 567 xcnt=xcnt+xf*xft … … 556 575 ENDIF 557 576 ENDIF 558 577 559 578 ! Volume over 3 or more levels 560 579 IF (jinf > jsup+1) THEN … … 573 592 matrix(jj,i)=matrix(jj,i)+xft*xf 574 593 ENDDO 575 ENDIF 576 ENDDO 577 ! checking if everything is alright if debug enabled... 594 ENDIF 595 ENDDO 596 597 ! checking if everything is alright if debug enabled... 578 598 IF (mm_debug) THEN 579 599 cpte=0._mm_wp ; cpte2=0._mm_wp … … 582 602 cpte=cpte+matrix(jj,j) 583 603 ENDDO 584 cpte2=cpte+puit(j)585 604 ENDDO 605 cpte2=cpte+sum(puit) 586 606 IF (abs(cpte2-nz)>1.e-4_mm_wp) THEN 587 WRITE(*,'(a)')"[EXCHANGE] speaking :" 588 WRITE(*,'("tx expl (/nz):",2(2X,ES10.3))') cpte,cpte2 607 WRITE(*,'("[EXCHANGE] speaking: tx expl (/nz):",2(2X,ES10.3))') cpte,cpte2 589 608 ENDIF 590 609 ENDIF 591 RETURN 610 611 RETURN 592 612 END SUBROUTINE exchange 593 613 … … 595 615 !! Compute displacement of a cell under sedimentation process. 596 616 !! 597 !! The method computes the new position of a _drop cell_ through sedimentation process as 617 !! The method computes the new position of a _drop cell_ through sedimentation process as 598 618 !! descibed in the following scheme: 599 619 !! … … 604 624 !! @note 605 625 !! The method uses directly [[mm_globals(module):mm_play(variable)]], [[mm_globals(module):mm_plev(variable)]], 606 !! [[mm_globals(module):mm_temp(variable)]],[[mm_globals(module):mm_btemp(variable)]], 626 !! [[mm_globals(module):mm_temp(variable)]],[[mm_globals(module):mm_btemp(variable)]], 607 627 !! [[mm_globals(module):mm_zlay(variable)]] and [[mm_globals(module):mm_zlev(variable)]] and uses __idx__ to 608 628 !! get the relevant value to use on the vertical grid. 609 629 INTEGER, INTENT(in) :: ichx 610 630 !! Velocity extrapolation control flag (0 for linear, 1 for exponential -preferred -). 611 631 INTEGER, INTENT(in) :: idx 612 632 !! Initial position of the drop (subscript of vertical layers vectors). 613 633 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rad 614 634 !! Cloud drop radius over the atmospheric vertical structure (m). 615 635 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rho 616 636 !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)). 617 637 REAL(kind=mm_wp), INTENT(in) :: dt 618 638 !! Timestep (s). 619 639 REAL(kind=mm_wp), INTENT(out) :: zni 620 !! Final layer centerposition (m).640 !! Final layer upper boundary position (m). 621 641 REAL(kind=mm_wp), INTENT(out) :: zns 622 !! Final layer upper boundary position (m).623 REAL(kind=mm_wp) :: ws,wi,w,zi,zs 642 !! Final layer lower boundary position (m). 643 REAL(kind=mm_wp) :: ws,wi,w,zi,zs 624 644 REAL(kind=mm_wp) :: alpha,argexp,v0,arg1,arg2 625 645 INTEGER :: i,nz 626 646 REAL(kind=mm_wp), PARAMETER :: es = 30._mm_wp 647 627 648 nz = SIZE(rad) 628 649 ! Linear extrapolation of velocity … … 636 657 ! velocity lower interface 637 658 wi = wsettle(mm_plev(idx+1),mm_btemp(idx+1),mm_zlev(idx+1), & 638 639 ELSE 640 WRITE(*,'(a)') "[getnzs] speaking:" 659 rho(idx+1),rad(idx+1)) 660 ELSE 661 WRITE(*,'(a)') "[getnzs] speaking:" 641 662 WRITE(*,'(a)') "This is the fatal error..." 642 663 WRITE(*,'(a)') "index is higher than number of levels" … … 647 668 zns = mm_zlev(idx)-mm_dzlev(idx)-w*dt 648 669 RETURN 649 ! Exponential extrapolation of velocity 670 ! Exponential extrapolation of velocity 671 650 672 ELSEIF(ichx==1) THEN 651 ws = wsettle(mm_plev(idx),mm_btemp(idx),mm_zlev(idx),rho(idx),rad(idx))652 673 zs = mm_zlev(idx) 653 w i = wsettle(mm_play(idx),mm_temp(idx),mm_zlay(idx),rho(idx),rad(idx))674 ws = wsettle(mm_plev(idx),mm_btemp(idx),zs,rho(idx),rad(idx)) 654 675 zi=mm_zlay(idx) 676 wi = wsettle(mm_play(idx),mm_temp(idx),zi,rho(idx),rad(idx)) 655 677 ! ws & wi must be different ! 656 678 IF(dabs(wi-ws)/wi <= 1.e-3_mm_wp) wi=ws/1.001_mm_wp 657 679 IF (wi /= 0._mm_wp) alpha = dlog(ws/wi)/(zs-zi) ! alpha < 0 if wi > ws 658 ! -es < argexp < es 659 argexp=MAX(MIN(alpha*zs,es),-es) 680 ! -es < argexp < es 681 argexp=MAX(MIN(alpha*zs,es),-es) 660 682 v0 = ws/dexp(argexp) 661 683 arg1=1._mm_wp+v0*alpha*dexp(argexp)*dt 662 684 argexp=MAX(MIN(alpha*(mm_zlev(idx)-mm_dzlev(idx)),es),-es) 663 685 arg2=1._mm_wp+v0*alpha*dexp(argexp)*dt 664 IF (arg1<=0._mm_wp.OR.arg2<=0._mm_wp) THEN 686 IF (arg1<=0._mm_wp.OR.arg2<=0._mm_wp) THEN 665 687 ! correct velocity 666 688 ! divides the velocity argument in arg1 and arg2 : … … 669 691 DO i=1,25 670 692 IF (arg1<=0._mm_wp.OR.arg2<=0._mm_wp) THEN 671 IF (mm_debug) & 672 WRITE(*,'((a),I2.2,(a))') "[getnzs] must adjust velocity (",i,"/25)"693 IF (mm_debug) & 694 WRITE(*,'((a),I2.2,(a))') "[getnzs] must adjust velocity (iter:",i,"/25)" 673 695 arg1=(arg1+1._mm_wp)/2._mm_wp ; arg2=(arg2+1._mm_wp)/2._mm_wp 674 696 ELSE 675 EXIT 697 EXIT 676 698 ENDIF 677 699 ENDDO … … 683 705 ENDIF 684 706 ENDIF 707 685 708 zni = mm_zlev(idx)-dlog(arg1)/alpha 686 709 zns = mm_zlev(idx)-mm_dzlev(idx)-dlog(arg2)/alpha 710 687 711 RETURN 688 ENDIF 712 ENDIF 689 713 END SUBROUTINE getnzs 690 714 691 715 ELEMENTAL FUNCTION wsettle(p,t,z,rho,rad) RESULT(w) 692 !! Compute the settling velocity of a spherical particle. 693 !! 694 !! The method computes the effective settling velocity of spherical particle of 716 !! Compute the settling velocity of a spherical particle. 717 !! 718 !! The method computes the effective settling velocity of spherical particle of 695 719 !! radius __rad__. It accounts for the slip-flow transition (no approximation). 696 720 REAL(kind=mm_wp), INTENT(in) :: p !! The pressure level (Pa). … … 700 724 REAL(kind=mm_wp), INTENT(in) :: rad !! Radius of the particle (m). 701 725 REAL(kind=mm_wp) :: w !! Settling velocity (\(m.s^{-1}\)). 702 REAL(kind=mm_wp) :: g,a,kn,nu703 REAL(kind=mm_wp), PARAMETER :: ra = 1.75e-10_mm_wp, nu0 = 1.74e-4_mm_wp, c = 109._mm_wp704 ! Computes corrected gravity705 g = mm_effg(z)706 ! Knudsen number707 kn = mm_kboltz*t/(p*4._mm_wp*sqrt(2._mm_wp)*mm_pi*ra**2)/rad708 ! Air viscosity709 nu=nu0*sqrt(t/293._mm_wp)*(1._mm_wp+c/293._mm_wp)/(1._mm_wp+c/t) 726 REAL(kind=mm_wp) :: Us, Fc 727 728 ! Computes Stokes settling velocity 729 Us = (2._mm_wp * rad**2 * rho * mm_effg(z)) / (9._mm_wp * mm_eta_g(t)) 730 731 ! Apply slip-flow correction 732 Fc = 1 + (mm_akn * mm_lambda_g(t,p) / rad) 733 710 734 ! Computes settling velocity 711 w = 2._mm_wp/9._mm_wp * rad**2*g*rho/nu 712 ! apply slip-flow correction 713 w = w*(1._mm_wp+1.2517_mm_wp*kn+0.4_mm_wp*kn*dexp(-1.1_mm_wp/kn)) 735 w = Us * Fc 736 !>>> [TEMPO : BBT] 737 !w = Us * Fc * 5. 738 !<<< [TEMPO : BBT] 714 739 END FUNCTION wsettle 715 740 … … 723 748 !! 724 749 !! @note 725 !! The computed flux is always positive. 750 !! The computed flux is always positive. 726 751 REAL(kind=mm_wp), INTENT(in) :: rho 727 752 !! Tracer density (\(kg.m^{-3}\)). 728 753 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: m3 729 754 !! Vertical profile of the total volume of tracer (i.e. M3) from __TOP__ to __GROUND__ (\(m^{3}.m^{-3}\)). 730 755 REAL(kind=mm_wp), DIMENSION(SIZE(m3)) :: flx 731 756 !! Mass sedimentation fluxes at each layer from __TOP__ to __GROUND__ (\(kg.m^{-2}.s^{-1}\)). 732 757 REAL(kind=mm_wp), SAVE :: fac = 4._mm_wp/3._mm_wp * mm_pi 733 758 flx = fac * rho * m3 * wsettle(mm_play,mm_temp,mm_zlay,mm_drho,mm_drad) -
trunk/LMDZ.TITAN/libf/muphytitan/mm_globals.f90
r2242 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Parameters and global variables module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 39 39 MODULE MM_GLOBALS 40 40 !! Parameters and global variables module. 41 !! 41 !! 42 42 !! # Module overview 43 43 !! 44 44 !! The module defines all the parameters and global variables that are common 45 45 !! to all other modules of the library. 46 !! 46 !! 47 47 !! It is separated in two parts : 48 48 !! … … 52 52 !! method. 53 53 !! - The second part defines a set of vectors that defines the vertical structure of the atmosphere. 54 !! Each time a new atmospheric column has to be computed (either on a new timestep or on a new couple 55 !! of longitude/latitude), these vectors should be intialized with new values by calling 56 !! [[mm_globals(module):mm_column_init(function)]] method. 57 !! This part is separated in two sets : 58 !! 59 !! - The atmospheric structure with temperature, pressure levels and altitude definitions. 60 !! - The vertical profiles of tracers with the moments of the two aerosols modes (both \(M_{0}\) 61 !! and \(M_{3}\) for a total of 4 vectors), the _clouds_ microphysics moments tracers (i.e. 54 !! Each time a new atmospheric column has to be computed (either on a new timestep or on a new couple 55 !! of longitude/latitude), these vectors should be intialized with new values by calling 56 !! [[mm_globals(module):mm_column_init(function)]] method. 57 !! This part is separated in two sets : 58 !! 59 !! - The atmospheric structure with temperature, pressure levels and altitude definitions. 60 !! - The vertical profiles of tracers with the moments of the two aerosols modes (both \(M_{0}\) 61 !! and \(M_{3}\) for a total of 4 vectors), the _clouds_ microphysics moments tracers (i.e. 62 62 !! \(M_{0}\) and \(M_{3}\) for the ccn and \(M_{3}\) for the ice components). 63 !! Additionally, the module also stores intermediates variables of interest such as the 64 !! characteristic radii of the aerosols modes, the mean drop radius and the drop density, 63 !! Additionally, the module also stores intermediates variables of interest such as the 64 !! characteristic radii of the aerosols modes, the mean drop radius and the drop density, 65 65 !! the molar fraction of each condensible species (related to ice components) and some 66 66 !! scalar variables that holds arrays sizes. 67 67 !! 68 68 !! @note 69 !! All the vectors that represent the vertical structure of the atmosphere (altitude, pressure and 69 !! All the vectors that represent the vertical structure of the atmosphere (altitude, pressure and 70 70 !! temperature...) are oriented from the __TOP__ of the atmosphere to the __GROUND__. 71 71 !! 72 !! @note 73 !! The module also imports errors module from __ FCCP__ library to get definitions of the error object72 !! @note 73 !! The module also imports errors module from __SWIFT__ library to get definitions of the error object 74 74 !! everywhere in the library ([[mm_globals(module)]] is always imported, except in [[mm_mprec(module)]]). 75 75 !! 76 !! # Global variables 76 !! # Global variables 77 77 !! 78 78 !! [[mm_globals(module)]] module contains the declaration of all global/common variable that are shared … … 82 82 !! the following sections list all the global variables by category. 83 83 !! 84 !! ## Control flags 85 !! 84 !! ## Control flags 85 !! 86 86 !! | Name | Description 87 87 !! | :----------------- | :----------------- … … 93 93 !! | mm_w_clouds_sed | Enable/Disable clouds microphysics sedimentation 94 94 !! | mm_w_clouds_nucond | Enable/Disable clouds microphysics nucleation/condensation 95 !! | mm_wsed_m0 | Force all aerosols moments to fall at M0 settling velocity 95 !! | mm_wsed_m0 | Force all aerosols moments to fall at M0 settling velocity 96 96 !! | mm_wsed_m3 | Force all aerosols moments to fall at M3 settling velocity 97 97 !! | mm_no_fiadero_w | Enable/Disable __Fiadero__ correction … … 101 101 !! | Name | Description 102 102 !! | :-------------- | :----------------- 103 !! | mm_fiadero_min | Minimum ratio for __Fiadero__'s correction 103 !! | mm_fiadero_min | Minimum ratio for __Fiadero__'s correction 104 104 !! | mm_fiadero_max | Maximum ratio for __Fiadero__'s correction 105 !! | mm_coag_choice | Coagulation interaction activation flag. It should be a combination of [[mm_globals(module):mm_coag_no(variable)]], [[mm_globals(module):mm_coag_ss(variable)]], [[mm_globals(module):mm_coag_sf(variable)]] and [[mm_globals(module):mm_coag_ff(variable)]]. 106 !! 107 !! ## Physical constants 105 !! | mm_coag_choice | Coagulation interaction activation flag. It should be a combination of [[mm_globals(module):mm_coag_no(variable)]], [[mm_globals(module):mm_coag_ss(variable)]], [[mm_globals(module):mm_coag_sf(variable)]] and [[mm_globals(module):mm_coag_ff(variable)]]. 106 !! 107 !! ## Physical constants 108 108 !! 109 109 !! | Name | Description … … 131 131 !! | mm_w_prod | Angular frequency of the time-dependent production rate. 132 132 !! | mm_ne | Electric charging of aerosols (\(e^{-}.m^{-1}\)) (unused) 133 !! | mm_rb2ra | Bulk to apparent radius conversion pre-factor (\(m^X\)) 133 !! | mm_rb2ra | Bulk to apparent radius conversion pre-factor (\(m^X\)) 134 134 !! | mm_rpla | Planet radius (m) 135 135 !! | mm_g0 | Planet acceleration due to gravity constant (ground) (\(m.s^{-2}\)) … … 152 152 ! the following variables are read-only outside this module. 153 153 ! One must call the afferent subroutine to update them. 154 154 155 155 ! initialization control flags (cannot be updated) 156 156 PROTECTED :: mm_ini,mm_ini_col,mm_ini_aer,mm_ini_cld … … 165 165 ! Moments parameters (derived, are updated with moments parameters) 166 166 PROTECTED :: mm_rcs, mm_rcf, mm_drad, mm_drho 167 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). 167 ! Thresholds parameters 168 PROTECTED :: mm_m0as_min, mm_m3as_min, mm_rcs_min, mm_m0af_min, mm_m3af_min, mm_rcf_min, mm_m0n_min, mm_m3cld_min 169 170 LOGICAL, SAVE :: mm_debug = .false. !! Enable QnD debug mode (can be used for devel). 171 LOGICAL, SAVE :: mm_log = .false. !! Enable log mode (for configuration only). 170 172 171 173 LOGICAL, SAVE :: mm_w_haze_prod = .true. !! Enable/Disable haze production. … … 182 184 !> Enable/Disable __Fiadero__'s correction. 183 185 !! 184 !! This flag enables/disables the __Fiadero__ correction alogrithm for fractal mode settling velocity 185 !! computation. 186 !! This flag enables/disables the __Fiadero__ correction alogrithm for fractal mode settling velocity 187 !! computation. 186 188 !! 187 189 !! @bug 188 !! Currently, the Fiadero correction creates instatibilities on the vertical structure. It seems to be 190 !! Currently, the Fiadero correction creates instatibilities on the vertical structure. It seems to be 189 191 !! related to the coupling between the two moments. In order to reduce the instabilities, settling 190 192 !! velocity of moments are forced to be the same, see [[mm_globals(module):mm_wsed_m0(variable)]] and 191 193 !! [[mm_globals(module):mm_wsed_m3(variable)]]). 192 LOGICAL, SAVE :: mm_no_fiadero_w = .false. 194 LOGICAL, SAVE :: mm_no_fiadero_w = .false. 193 195 194 196 !> Minimum ratio for __Fiadero__ correction. 195 197 !! 196 !! When [[mm_globals(module):mm_no_fiadero_w(variable)]] is disabled, this variable defines the minimum 198 !! When [[mm_globals(module):mm_no_fiadero_w(variable)]] is disabled, this variable defines the minimum 197 199 !! value of the moment's ratio between two adjacents vertical cells to be used within the correction. 198 200 REAL(kind=mm_wp), SAVE :: mm_fiadero_min = 0.1_mm_wp … … 200 202 !> Maximum ratio for __Fiadero__ correction. 201 203 !! 202 !! When [[mm_globals(module):mm_no_fiadero_w(variable)]] is disabled, this variable defines the maximum 204 !! When [[mm_globals(module):mm_no_fiadero_w(variable)]] is disabled, this variable defines the maximum 203 205 !! value of the moment's ratio between two adjacents vertical cells to be used within the correction. 204 206 REAL(kind=mm_wp), SAVE :: mm_fiadero_max = 10._mm_wp … … 213 215 INTEGER, PARAMETER :: mm_coag_ff = 4 !! FF mode interaction for coagulation. 214 216 !> Default interactions to activate (all by default). 215 INTEGER, SAVE :: mm_coag_choice = mm_coag_ss+mm_coag_sf+mm_coag_ff 217 INTEGER, SAVE :: mm_coag_choice = mm_coag_ss+mm_coag_sf+mm_coag_ff 216 218 217 219 !> Pi number. 218 220 REAL(kind=mm_wp), PARAMETER :: mm_pi = 4._mm_wp*atan(1._mm_wp) 219 221 !> Avogadro number. 220 REAL(kind=mm_wp), PARAMETER :: mm_navo = 6.0221367e23_mm_wp 222 REAL(kind=mm_wp), PARAMETER :: mm_navo = 6.0221367e23_mm_wp 221 223 !> Boltzmann constant (\(J.K^{-1}\)). 222 224 REAL(kind=mm_wp), PARAMETER :: mm_kboltz = 1.3806488e-23_mm_wp … … 261 263 262 264 !> Bulk to apparent radius conversion pre-factor (\(m^{X}\)). 263 !! 264 !! It is initialized using [[mm_globals(module):mm_rm(variable)]] in 265 !! 266 !! It is initialized using [[mm_globals(module):mm_rm(variable)]] in 265 267 !! [[mm_globals(module):mm_global_init(interface)]] from the following equation: 266 268 !! 267 269 !! $$ r_{a} = r_{b}^{3/D_{f}}\times r_{m}^{\frac{D_{f}-3}{D_{f}}} $$ 268 270 !! 269 !! Where \(r_{a}\) is the apparent radius, \(r_{b}\) the bulk radius and 271 !! Where \(r_{a}\) is the apparent radius, \(r_{b}\) the bulk radius and 270 272 !! \(rb2ra = r_{m}^{\frac{D_{f}-3}{D_{f}}}\) is the returned pre-factor 271 REAL(kind=mm_wp), SAVE :: mm_rb2ra = 1._mm_wp 273 REAL(kind=mm_wp), SAVE :: mm_rb2ra = 1._mm_wp 274 275 ! Thresholds ! 276 277 !> (min.) Total number of aerosols minimum threshold for the spherical mode. 278 REAL(kind=mm_wp), SAVE :: mm_m0as_min = 1.e-10_mm_wp 279 280 !> (min.) Total volume of aerosols minimum threshold for the spherical mode. 281 REAL(kind=mm_wp), SAVE :: mm_m3as_min = 1.e-40_mm_wp 282 283 !> Characteristic radius minimum threshold for the spherical mode. 284 REAL(kind=mm_wp), SAVE :: mm_rcs_min = 1.e-9_mm_wp 285 286 !> (min.) Total number of aerosols minimum threshold for the fractal mode. 287 REAL(kind=mm_wp), SAVE :: mm_m0af_min = 1.e-10_mm_wp 288 289 !> (min.) Total volume of aerosols minimum threshold for the fractal mode. 290 REAL(kind=mm_wp), SAVE :: mm_m3af_min = 1.e-40_mm_wp 291 292 !> Characteristic radius minimum threshold for the fractal mode. 293 REAL(kind=mm_wp), SAVE :: mm_rcf_min = 1.e-9_mm_wp 294 295 !> (min.) Total number of cloud drop minimum threshold. 296 REAL(kind=mm_wp), SAVE :: mm_m0n_min = 1.e-10_mm_wp 297 298 !> (min.) Total volume of cloud drop minimum threshold. 299 REAL(kind=mm_wp), SAVE :: mm_m3cld_min = 1.e-40_mm_wp 272 300 273 301 !> Characteristic radius threshold. 274 302 REAL(kind=mm_wp), SAVE :: mm_rc_min = 1.e-200_mm_wp 303 304 !> Minimum cloud drop radius 305 REAL(kind=mm_wp), SAVE :: mm_drad_min = 1.e-9_mm_wp 306 307 !> Maximum cloud drop radius 308 REAL(kind=mm_wp), SAVE :: mm_drad_max = 1.e-3_mm_wp 275 309 276 310 !> Name of condensible species. … … 339 373 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_temp 340 374 !> Air density vertical profile (\(kg.m^{-3}\)). 341 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_rhoair 375 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_rhoair 342 376 !> Temperature vertical profil at interfaces (K). 343 377 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_btemp 344 378 345 379 !> Atmospheric levels thickness (m). 346 !! 347 !! Atmospheric thickness between two adjacent levels (\(m\)) from the 380 !! 381 !! Atmospheric thickness between two adjacent levels (\(m\)) from the 348 382 !! __TOP__ to the __GROUND__. 349 383 !! @note __mm_dzlev__ is defined on the total number of layers and actually … … 352 386 353 387 !> Atmospheric layers "thickness" (m). 354 !! 388 !! 355 389 !! Atmospheric thickness between the center of two adjacent layers (\(m\)) 356 390 !! from the __TOP__ to the __GROUND__. 357 !! @note 358 !! __mm_dzlay__ is defined on the total number of layers. The last 391 !! @note 392 !! __mm_dzlay__ is defined on the total number of layers. The last 359 393 !! value of __mm_dzlay__ is set to twice the altitude of the ground layer. 360 !! @note This value corresponds to the thickness between the center of the 394 !! @note This value corresponds to the thickness between the center of the 361 395 !! __GROUND__ layer and below the surface. It is arbitrary and not used. 362 396 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_dzlay … … 377 411 !> Ice components 3rd order moments (\(m^{3}.m^{-3}\)). 378 412 !! 379 !! It is a 2D array with the vertical layers in first dimension, and the number of ice 413 !! It is a 2D array with the vertical layers in first dimension, and the number of ice 380 414 !! components in the second. 381 !! @note 415 !! @note 382 416 !! Both [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]] 383 417 !! share the same indexing (related to species order). … … 387 421 !! 388 422 !! It is a 2D array with the vertical layers in first dimension, and 389 !! the number of condensible species in the second. 390 !! @note 423 !! the number of condensible species in the second. 424 !! @note 391 425 !! Both [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]] 392 426 !! share the same indexing (related to species order). … … 410 444 !> Spherical mode \(M_{0}\) settling velocity (\(m.s^{-1}\)). 411 445 !! 412 !! It is a vector with the vertical layers that contains the settling velocity for 446 !! It is a vector with the vertical layers that contains the settling velocity for 413 447 !! the \(0^{th}\) order moment of the spherical mode. 414 448 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 415 !! @note 449 !! @note 416 450 !! This variable is always negative. 417 451 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m0as_vsed … … 419 453 !> Spherical mode \(M_{3}\) settling velocity (\(m.s^{-1}\)). 420 454 !! 421 !! It is a vector with the vertical layers that contains the settling velocity for the 455 !! It is a vector with the vertical layers that contains the settling velocity for the 422 456 !! \(3^{rd}\) order moment of the spherical mode. 423 457 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 424 !! @note 458 !! @note 425 459 !! This variable is always negative. 426 460 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m3as_vsed … … 428 462 !> Fractal mode \(M_{0}\) settling velocity (\(m.s^{-1}\)). 429 463 !! 430 !! It is a vector with the vertical layers that contains the settling velocity for the 464 !! It is a vector with the vertical layers that contains the settling velocity for the 431 465 !! \(0^{th}\) order moment of the fractal mode. 432 466 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 433 !! @note 467 !! @note 434 468 !! This variable is always negative. 435 469 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m0af_vsed … … 437 471 !> Fractal mode \(M_{3}\) settling velocity (\(m.s^{-1}\)). 438 472 !! 439 !! It is a vector with the vertical layers that contains the settling velocity for the 473 !! It is a vector with the vertical layers that contains the settling velocity for the 440 474 !! \(3^{rd}\) order moment of the fractal mode. 441 475 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 442 !! @note 476 !! @note 443 477 !! This variable is always negative. 444 478 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m3af_vsed … … 448 482 !! It is a vector with the vertical layers that contains the mass fluxes for spherical aerosols. 449 483 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 450 !! @note 484 !! @note 451 485 !! This variable is always negative. 452 486 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_aer_s_flux … … 456 490 !! It is a vector with the vertical layers that contains the mass fluxes for fractal aerosols 457 491 !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]]. 458 !! @note 492 !! @note 459 493 !! This variable is always negative. 460 494 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_aer_f_flux … … 464 498 REAL(kind=mm_wp), SAVE :: mm_ccn_prec = 0._mm_wp 465 499 466 !> CCN mass fluxes (\(kg.m^{-2}.s^{-1}\)).467 !! 468 !! It is a vector with the vertical layers that contains the 469 !! mass fluxes for CCN.500 !> CCN settling velocity (\(m.s^{-1}\)). 501 !! 502 !! It is a vector with the vertical layers that contains the 503 !! settling velocity for CCN (and ices). 470 504 !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]]. 471 505 !! @note 472 !! This variable is always negative. 506 !! This variable is always positive. 507 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_ccn_w 508 509 !> CCN mass fluxes (\(kg.m^{-2}.s^{-1}\)). 510 !! 511 !! It is a vector with the vertical layers that contains the 512 !! mass fluxes for CCN. 513 !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]]. 514 !! @note 515 !! This variable is always positive. 473 516 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_ccn_flux 474 517 475 518 !> Ice components precipitations (m). 476 519 !! 477 !! It is a vector of [[mm_globals(module):mm_nesp(variable)]] values which share the same indexing 520 !! It is a vector of [[mm_globals(module):mm_nesp(variable)]] values which share the same indexing 478 521 !! than [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]]. 479 522 !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]]. … … 484 527 !> Ice components sedimentation fluxes (\(kg.m^{-2}.s-1\)). 485 528 !! 486 !! It is a 2D-array with the vertical layers in first dimension and the number of ice components 529 !! It is a 2D-array with the vertical layers in first dimension and the number of ice components 487 530 !! in the second. It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]]. 488 531 !! @note … … 492 535 !> Condensible species saturation ratio (--). 493 536 !! 494 !! It is a 2D-array with the vertical layers in first dimension and the number of condensible 537 !! It is a 2D-array with the vertical layers in first dimension and the number of condensible 495 538 !! species in the second. 496 539 !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]]. … … 516 559 INTERFACE mm_cloud_properties 517 560 MODULE PROCEDURE cldprop_sc,cldprop_ve 518 END INTERFACE 561 END INTERFACE mm_cloud_properties 519 562 520 563 !> Interface to global initialization. … … 522 565 !! The method performs the global initialization of the model. 523 566 !! @warning 524 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 567 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 525 568 !! initializes global variable that are not thread private. 526 569 !! 527 !! ''' 528 !! !$OMP SINGLE 529 !! call mm_global_init(...) 530 !! !$OMP END SINGLE 570 !! !$OMP SINGLE 571 !! call mm_global_init(...) 572 !! !$OMP END SINGLE 531 573 INTERFACE mm_global_init 532 574 MODULE PROCEDURE mm_global_init_0,mm_global_init_1 533 END INTERFACE 575 END INTERFACE mm_global_init 534 576 535 577 !> Check an option from the configuration system. … … 538 580 !! set a default value if the option is not found. This is an overloaded method 539 581 !! that can take in input either a floating point, integer, logical or string 540 !! option value. 582 !! option value. 541 583 INTERFACE mm_check_opt 542 584 MODULE PROCEDURE check_r1,check_i1,check_l1,check_s1 543 END INTERFACE 585 END INTERFACE mm_check_opt 544 586 545 587 ! --- OPENMP --------------- 546 ! All variable related to column computations should be private to each thread588 ! All variables related to column computations should be private to each thread 547 589 ! 548 590 !$OMP THREADPRIVATE(mm_ini_col,mm_ini_aer,mm_ini_cld) … … 551 593 !$OMP THREADPRIVATE(mm_m0ccn,mm_m3ccn,mm_m3ice,mm_gazs) 552 594 !$OMP THREADPRIVATE(mm_rcs,mm_rcf,mm_drad,mm_drho) 553 !$OMP THREADPRIVATE(mm_aer_s_flux,mm_aer_f_flux,mm_ccn_ flux,mm_ice_prec,mm_ice_fluxes,mm_gazs_sat)595 !$OMP THREADPRIVATE(mm_aer_s_flux,mm_aer_f_flux,mm_ccn_w,mm_ccn_flux,mm_ice_prec,mm_ice_fluxes,mm_gazs_sat) 554 596 !$OMP THREADPRIVATE(mm_m0as_vsed,mm_m3as_vsed,mm_m0af_vsed,mm_m3af_vsed) 555 597 !$OMP THREADPRIVATE(mm_m0as_min,mm_m3as_min,mm_rcs_min,mm_m0af_min,mm_m3af_min,mm_rcf_min,mm_m0n_min,mm_m3cld_min) 556 598 !$OMP THREADPRIVATE(mm_nla,mm_nle) 557 599 … … 559 601 560 602 561 CONTAINS 603 CONTAINS 562 604 563 605 FUNCTION mm_global_init_0(dt,df,rm,rho_aer,p_prod,tx_prod,rc_prod,rplanet,g0, & 564 air_rad,air_mmol,coag_interactions,clouds,spcfile, & 565 w_haze_prod,w_haze_sed,w_haze_coag,w_cloud_nucond, & 566 w_cloud_sed,force_wsed_to_m0,force_wsed_to_m3, & 567 no_fiadero,fiadero_min,fiadero_max) RESULT(err) 606 air_rad,air_mmol,coag_interactions,clouds,spcfile, & 607 w_haze_prod,w_haze_sed,w_haze_coag,w_cloud_nucond, & 608 w_cloud_sed,force_wsed_to_m0,force_wsed_to_m3, & 609 no_fiadero,fiadero_min,fiadero_max, & 610 m0as_min,rcs_min,m0af_min,rcf_min,m0n_min,debug) RESULT(err) 568 611 !! Initialize global parameters of the model. 569 !! 612 !! 570 613 !! The function initializes all the global parameters of the model from direct input. 571 !! Boolean (and Fiadero) parameters are optional as they are rather testing parameters. Their572 !! default values are suitable for production runs.614 !! Boolean, Fiadero and thresholds parameters are optional as they are rather testing parameters. 615 !! Their default values are suitable for production runs. 573 616 !! @note 574 617 !! If the method fails to initialize parameters (i.e. returned error is not 0). Then the model 575 618 !! should probably be aborted as the global variables of the model will not be correctly setup. 576 619 !! @warning 577 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 578 !! initializes global variable that are not thread private. 579 !! 580 !! ''' 581 !! !$OMP SINGLE 582 !! call mm_global_init_0(...) 583 !! !$OMP END SINGLE 620 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 621 !! initializes (only) global variables that are not thread private. 622 !! 623 !! !$OMP SINGLE 624 !! call mm_global_init_0(...) 625 !! !$OMP END SINGLE 584 626 REAL(kind=mm_wp), INTENT(in) :: dt 585 627 !! Microphysics timestep in seconds. 586 628 REAL(kind=mm_wp), INTENT(in) :: df 587 629 !! Fractal dimension of fractal aerosol. 588 630 REAL(kind=mm_wp), INTENT(in) :: rm 589 631 !! Monomer radius in meter. 590 632 REAL(kind=mm_wp), INTENT(in) :: rho_aer 591 633 !! Aerosol density in \(kg.m^{-3}\). 592 634 REAL(kind=mm_wp), INTENT(in) :: p_prod 593 635 !! Aerosol production pressure level in Pa. 594 636 REAL(kind=mm_wp), INTENT(in) :: tx_prod 595 637 !! Spherical aerosol mode production rate in \(kg.m^{-2}.s^{-1}\). 596 638 REAL(kind=mm_wp), INTENT(in) :: rc_prod 597 639 !! Spherical mode characteristic radius for production in meter. 598 640 REAL(kind=mm_wp), INTENT(in) :: rplanet 599 641 !! Planet radius in meter 600 642 REAL(kind=mm_wp), INTENT(in) :: g0 601 643 !! Planet gravity acceleration at ground level in \(m.s^{-2}\). 602 644 REAL(kind=mm_wp), INTENT(in) :: air_rad 603 645 !! Air molecules mean radius in meter. 604 646 REAL(kind=mm_wp), INTENT(in) :: air_mmol 605 647 !! Air molecules mean molar mass in \(kg.mol^{-1}\). 606 648 INTEGER, INTENT(in) :: coag_interactions 607 649 !! Coagulation interactions process control flag. 608 650 LOGICAL, INTENT(in) :: clouds 609 651 !! Clouds microphysics control flag. 610 652 CHARACTER(len=*), INTENT(in) :: spcfile 611 653 !! Clouds microphysics condensible species properties file. 612 654 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: fiadero_max 613 655 !! Maximum moment ratio threshold for Fiadero correction (default: 10.) . 614 656 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: fiadero_min 615 657 !! Minimum moment ratio threshold for Fiadero correction (default: 0.1). 616 658 LOGICAL, INTENT(in), OPTIONAL :: w_haze_prod 617 659 !! Haze microphysics production process control flag (default: T). 618 660 LOGICAL, INTENT(in), OPTIONAL :: w_haze_sed 619 661 !! Haze microphysics sedimentation process control flag (default: T). 620 662 LOGICAL, INTENT(in), OPTIONAL :: w_haze_coag 621 663 !! Haze microphysics coagulation process control flag (default: T). 622 664 LOGICAL, INTENT(in), OPTIONAL :: w_cloud_sed 623 665 !! Cloud microphysics nucleation/conensation process control flag (default: __clouds__ value). 624 666 LOGICAL, INTENT(in), OPTIONAL :: w_cloud_nucond 625 667 !! Cloud microphysics production process control flag (default: __clouds__ value). 626 668 LOGICAL, INTENT(in), OPTIONAL :: no_fiadero 627 669 !! Disable Fiadero correction for haze sedimentation process (default: F). 628 670 LOGICAL, INTENT(in), OPTIONAL :: force_wsed_to_m0 629 !! force __all__ aerosols moments to fall at M0 settling velocity (default: T). 630 LOGICAL, INTENT(in), OPTIONAL :: force_wsed_to_m3 631 !! Force __all__ aerosols moments to fall at M3 settling velocity (default: F). 671 !! force __all__ aerosols moments to fall at M0 settling velocity (default: T). 672 LOGICAL, INTENT(in), OPTIONAL :: force_wsed_to_m3 673 !! Force __all__ aerosols moments to fall at M3 settling velocity (default: F). 674 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: m0as_min 675 !! Minimum threshold for M0 of the spherical mode (default: 1e-10). 676 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: rcs_min 677 !! Minimum threshold for the characteristic radius of the spherical mode in meter (default: 1e-9). 678 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: m0af_min 679 !! Minimum threshold for M0 of the factal mode (default: 1e-10). 680 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: rcf_min 681 !! Minimum threshold for the characteristic radius of the fractal mode in meter (default: _monomer radius_). 682 REAL(kind=mm_wp), INTENT(in), OPTIONAL :: m0n_min 683 !! Minimum threshold for M0 of cloud drop (default: 1e-10). 684 LOGICAL, INTENT(in), OPTIONAL :: debug 685 !! Debug mode control flag (may print lot of stuff if enabled) 632 686 TYPE(error) :: err 633 687 !! Error status of the function. 634 688 INTEGER :: i 635 689 TYPE(cfgparser) :: cp 636 CHARACTER(len=st_slen) :: spcpath637 CHARACTER(len=:), ALLOCATABLE :: defmsg638 690 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species 639 691 REAL(kind=mm_wp) :: zfiamin,zfiamax 640 692 LOGICAL :: zwhp,zwhs,zwhc,zwcs,zwcn,znofia, & 641 693 zwstom0,zwstom3 642 643 694 zwhp = .true. ; zwhs = .true. ; zwhc = .true. 644 zwcs = clouds ; zwcn = clouds 695 zwcs = clouds ; zwcn = clouds 645 696 znofia = .false. ; zfiamin = 0.1_mm_wp ; zfiamax = 10._mm_wp 646 697 zwstom0 = .true. ; zwstom3 = .false. … … 652 703 653 704 ! Store options values in global variables... 654 mm_df = df 655 mm_rm = rm 705 mm_df = df 706 mm_rm = rm 656 707 mm_rb2ra = mm_rm**((mm_df-3._mm_wp)/mm_df) ! conversion factor for bulk -> fractal radius 657 mm_rhoaer = rho_aer 708 mm_rhoaer = rho_aer 658 709 mm_p_prod = p_prod 659 710 mm_tx_prod = tx_prod … … 662 713 mm_g0 = g0 663 714 mm_dt = dt 664 mm_air_rad = mm_air_rad715 mm_air_rad = air_rad 665 716 mm_air_mmol = air_mmol 666 717 mm_coag_choice = coag_interactions … … 670 721 RETURN 671 722 ENDIF 723 724 ! force fractal radius minimum threshold to monomer radius ^^ 725 mm_rcf_min = mm_rm 672 726 673 727 mm_w_clouds = clouds … … 680 734 RETURN 681 735 ENDIF 682 ! Reads species properties configuration file 736 ! Reads species properties configuration file 683 737 err = cfg_read_config(cp,TRIM(spcfile)) ; IF (err /= 0) RETURN 684 err = cfg_get_value(cp,"used_species",species) 738 err = cfg_get_value(cp,"used_species",species) 685 739 IF (err /= 0) THEN 686 740 err = error("mm_global_init: cannot retrieve 'used_species' values",-1) … … 691 745 ALLOCATE(mm_spcname(mm_nesp),mm_xESPS(mm_nesp)) 692 746 DO i=1,mm_nesp 693 mm_spcname(i) = to_lower(species(i))747 mm_spcname(i) = TRIM(species(i)) 694 748 IF(.NOT.cfg_has_section(cp,TRIM(mm_spcname(i)))) THEN 695 749 err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1) … … 708 762 709 763 ! optional flags 764 ! debug mode 765 IF (PRESENT(debug)) THEN 766 mm_debug = debug 767 ELSE 768 mm_debug = .false. 769 call printw("mm_debug",to_string(mm_debug)) 770 ENDIF 710 771 ! haze control flags 711 IF (PRESENT(w_haze_prod)) THEN 772 IF (PRESENT(w_haze_prod)) THEN 712 773 mm_w_haze_prod = w_haze_prod 713 ELSE 714 mm_w_haze_prod = zwhp 774 ELSE 775 mm_w_haze_prod = zwhp 715 776 call printw("mm_haze_production",to_string(mm_w_haze_prod)) 716 777 ENDIF 717 IF (PRESENT(w_haze_sed)) THEN 778 IF (PRESENT(w_haze_sed)) THEN 718 779 mm_w_haze_sed = w_haze_sed 719 ELSE 720 mm_w_haze_sed = zwhs 780 ELSE 781 mm_w_haze_sed = zwhs 721 782 call printw("mm_haze_sedimentation",to_string(mm_w_haze_sed)) 722 783 ENDIF 723 IF (PRESENT(w_haze_coag)) THEN 784 IF (PRESENT(w_haze_coag)) THEN 724 785 mm_w_haze_coag = w_haze_coag 725 ELSE 786 ELSE 726 787 mm_w_haze_coag = zwhc 727 788 call printw("mm_haze_coagulation",to_string(mm_w_haze_coag)) 728 789 ENDIF 729 IF (PRESENT(force_wsed_to_m0)) THEN 790 IF (PRESENT(force_wsed_to_m0)) THEN 730 791 mm_wsed_m0 = force_wsed_to_m0 731 ELSE 792 ELSE 732 793 mm_wsed_m0 = zwstom0 733 794 call printw("mm_wsed_m0",to_string(mm_wsed_m0)) 734 795 ENDIF 735 IF (PRESENT(force_wsed_to_m3)) THEN 796 IF (PRESENT(force_wsed_to_m3)) THEN 736 797 mm_wsed_m3 = force_wsed_to_m3 737 ELSE 798 ELSE 738 799 mm_wsed_m3 = zwstom3 739 800 call printw("mm_wsed_m3",to_string(mm_wsed_m3)) 740 801 ENDIF 741 IF (PRESENT(no_fiadero)) THEN 802 IF (PRESENT(no_fiadero)) THEN 742 803 mm_no_fiadero_w = no_fiadero 743 ELSE 744 mm_no_fiadero_w = znofia 804 ELSE 805 mm_no_fiadero_w = znofia 745 806 call printw("mm_no_fiadero",to_string(mm_no_fiadero_w)) 746 807 ENDIF 747 IF (PRESENT(fiadero_min)) THEN 808 IF (PRESENT(fiadero_min)) THEN 748 809 mm_fiadero_min = fiadero_min 749 ELSE 810 ELSE 750 811 mm_fiadero_min = zfiamin 751 812 call printw("mm_fiadero_min",to_string(mm_fiadero_min)) 752 813 ENDIF 753 IF (PRESENT(fiadero_max)) THEN 814 IF (PRESENT(fiadero_max)) THEN 754 815 mm_fiadero_max = fiadero_max 755 ELSE 816 ELSE 756 817 mm_fiadero_max = zfiamax 757 818 call printw("mm_fiadero_max",to_string(mm_fiadero_max)) 758 819 ENDIF 820 821 ! moments threshold flags 822 IF (PRESENT(m0as_min)) THEN 823 mm_m0as_min = MAX(0._mm_wp,m0as_min) 824 ELSE 825 call printw("mm_m0as_min",to_string(mm_m0as_min)) 826 ENDIF 827 IF (PRESENT(rcs_min)) THEN 828 mm_rcs_min = MAX(1.e-9_mm_wp,rcs_min) 829 ELSE 830 call printw("mm_rcs_min",to_string(mm_rcs_min)) 831 ENDIF 832 IF (PRESENT(m0af_min)) THEN 833 mm_m0af_min = MAX(0._mm_wp,m0af_min) 834 ELSE 835 call printw("mm_m0af_min",to_string(mm_m0af_min)) 836 ENDIF 837 IF (PRESENT(rcf_min)) THEN 838 mm_rcf_min = MAX(rcf_min,mm_rm) 839 ELSE 840 mm_rcf_min = mm_rm 841 call printw("mm_rcf_min",to_string(mm_rcf_min)) 842 ENDIF 843 IF (PRESENT(m0n_min)) THEN 844 mm_m0n_min = MAX(0._mm_wp,m0n_min) 845 ELSE 846 call printw("mm_m0n_min",to_string(mm_m0n_min)) 847 ENDIF 848 849 ! compute m3 thresholds from user-defined thresholds. 850 mm_m3as_min = mm_m0as_min*mm_alpha_s(3._mm_wp) * mm_rcs_min**3._mm_wp 851 mm_m3af_min = mm_m0af_min*mm_alpha_f(3._mm_wp) * mm_rcf_min**3._mm_wp 852 mm_m3cld_min = mm_m0n_min * (4._mm_wp * mm_pi / 3._mm_wp) * mm_drad_min**3._mm_wp 853 759 854 ! clouds control flags 760 855 IF (mm_w_clouds) THEN 761 IF (PRESENT(w_cloud_sed)) THEN 856 IF (PRESENT(w_cloud_sed)) THEN 762 857 mm_w_cloud_sed = w_cloud_sed 763 ELSE 764 mm_w_cloud_sed = zwcs 765 call printw("mm_cloud_sed",to_string(mm_w_cloud_sed)) 858 ELSE 859 mm_w_cloud_sed = zwcs 860 call printw("mm_cloud_sed",to_string(mm_w_cloud_sed)) 766 861 ENDIF 767 IF (PRESENT(w_cloud_nucond)) THEN 862 IF (PRESENT(w_cloud_nucond)) THEN 768 863 mm_w_cloud_nucond = w_cloud_nucond 769 ELSE 864 ELSE 770 865 mm_w_cloud_nucond = zwcs 771 call printw("mm_cloud_nucond",to_string(mm_w_cloud_nucond)) 866 call printw("mm_cloud_nucond",to_string(mm_w_cloud_nucond)) 772 867 ENDIF 773 868 ENDIF … … 781 876 mm_ini = err == noerror 782 877 783 878 CONTAINS 784 879 785 880 SUBROUTINE printw(string,value) … … 788 883 CHARACTER(len=*), INTENT(in) :: value !! (string) Value of the option. 789 884 IF (mm_log) & 790 WRITE(*,'(a,a,a)') "warning: Parameter "//string//"not given... Using default value: "//value791 END SUBROUTINE printw 885 WRITE(*,'(a,a,a)') "warning: Parameter "//string//"not given... Using default value: "//value 886 END SUBROUTINE printw 792 887 END FUNCTION mm_global_init_0 793 888 … … 796 891 !! 797 892 !! See [[mm_globals(module):mm_global_init_0(function)]]. 798 TYPE(cfgparser), INTENT(in) :: cfg !! Configuration file path. 799 TYPE(error) :: err !! Error status of the function. 893 TYPE(cfgparser), INTENT(in) :: cfg 894 !! Configuration file path. 895 TYPE(error) :: err 896 !! Error status of the function. 800 897 INTEGER :: i 801 898 TYPE(cfgparser) :: spccfg 802 899 CHARACTER(len=st_slen) :: spcpath 803 CHARACTER(len=:), ALLOCATABLE :: defmsg804 900 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species 805 901 REAL(kind=mm_wp) :: zfiamin,zfiamax 806 902 LOGICAL :: zwhp,zwhs,zwhc,zwcs,zwcn,znofia, & 807 903 zwstom0,zwstom3 808 904 809 905 err = noerror … … 856 952 ! Gets species property file path 857 953 err = cfg_get_value(cfg,'specie_cfg',spcpath) ; IF (err /= 0) RETURN 858 ! Reads species properties configuration file 954 ! Reads species properties configuration file 859 955 err = cfg_read_config(spccfg,trim(spcpath)) ; IF (err /= 0) RETURN 860 err = cfg_get_value(spccfg,"used_species",species) 956 err = cfg_get_value(spccfg,"used_species",species) 861 957 IF (err /= 0) THEN 862 958 err = error("mm_global_init: cannot retrieve 'used_species' values",-1) … … 868 964 !mm_spcname(1:mm_nesp) = species(:) 869 965 DO i=1,mm_nesp 870 mm_spcname(i) = to_lower(species(i))966 mm_spcname(i) = TRIM(species(i)) 871 967 IF (.NOT.cfg_has_section(spccfg,TRIM(mm_spcname(i)))) THEN 872 968 err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1) … … 890 986 891 987 ! MP2M Optional parameters 988 err = mm_check_opt(cfg_get_value(cfg,"debug",mm_debug),mm_debug,.false.,wlog=mm_log) 892 989 err = mm_check_opt(cfg_get_value(cfg,"haze_production",mm_w_haze_prod),mm_w_haze_prod,zwhp,wlog=mm_log) 893 990 err = mm_check_opt(cfg_get_value(cfg,"haze_sedimentation",mm_w_haze_sed),mm_w_haze_sed,zwhs,wlog=mm_log) … … 901 998 err = mm_check_opt(cfg_get_value(cfg,"fiadero_max_ratio",mm_fiadero_max),mm_fiadero_max,zfiamax,wlog=mm_log) 902 999 1000 err = mm_check_opt(cfg_get_value(cfg,"m0as_min",mm_m0as_min),mm_m0as_min,1e-10_mm_wp,wlog=mm_log) 1001 err = mm_check_opt(cfg_get_value(cfg,"rcs_min",mm_rcs_min),mm_rcs_min,1e-9_mm_wp,wlog=mm_log) 1002 err = mm_check_opt(cfg_get_value(cfg,"m0af_min",mm_m0af_min),mm_m0af_min,1e-10_mm_wp,wlog=mm_log) 1003 err = mm_check_opt(cfg_get_value(cfg,"rcf_min",mm_rcf_min),mm_rcf_min,mm_rm,wlog=mm_log) 1004 err = mm_check_opt(cfg_get_value(cfg,"m0n_min",mm_m0n_min),mm_m0n_min,1e-10_mm_wp,wlog=mm_log) 1005 1006 1007 ! force fractal radius minimum threshold to monomer radius ^^ 1008 mm_rcf_min = MAX(mm_rm,mm_rcf_min) 1009 1010 ! compute m3 thresholds from user-defined thresholds. 1011 mm_m3as_min = mm_m0as_min*mm_alpha_s(3._mm_wp) * mm_rcs_min**3._mm_wp 1012 mm_m3af_min = mm_m0af_min*mm_alpha_f(3._mm_wp) * mm_rcf_min**3._mm_wp 1013 mm_m3cld_min = mm_m0n_min * (4._mm_wp * mm_pi / 3._mm_wp) * mm_drad_min**3._mm_wp 1014 903 1015 err = noerror 904 1016 ! special check for settling velocity … … 911 1023 FUNCTION mm_column_init(plev,zlev,play,zlay,temp) RESULT(err) 912 1024 !! Initialize vertical atmospheric fields. 913 !! 1025 !! 914 1026 !! This subroutine initializes vertical fields needed by the microphysics: 915 1027 !! 916 !! 1. Save reversed input field into "local" array 1028 !! 1. Save reversed input field into "local" array 917 1029 !! 2. Compute thicknesses layers and levels 918 1030 !! 3. Interpolate temperature at levels … … 922 1034 !! @attention 923 1035 !! All the input vectors should be defined from __GROUND__ to __TOP__ of the atmosphere, 924 !! otherwise nasty things will occur in computations. 1036 !! otherwise nasty things will occur in computations. 925 1037 REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: plev !! Pressure levels (Pa). 926 1038 REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: zlev !! Altitude levels (m). … … 930 1042 TYPE(error) :: err !! Error status of the function. 931 1043 INTEGER :: i 932 mm_ini_col = .false. 1044 mm_ini_col = .false. 933 1045 err = noerror 934 1046 IF (.NOT.mm_ini) THEN … … 980 1092 ! Hydrostatic equilibrium 981 1093 mm_rhoair(1:mm_nla) = (mm_plev(2:mm_nle)-mm_plev(1:mm_nla)) / & 982 983 mm_ini_col = .true. 1094 (mm_effg(mm_zlay)*mm_dzlev) 1095 mm_ini_col = .true. 984 1096 ! write out profiles (only if BOTH debug and log are enabled). 985 1097 IF (mm_log.AND.mm_debug) THEN … … 1003 1115 FUNCTION mm_aerosols_init(m0aer_s,m3aer_s,m0aer_f,m3aer_f) RESULT(err) 1004 1116 !! Initialize clouds tracers vertical grid. 1005 !! 1006 !! The subroutine initializes aerosols microphysics tracers columns. It allocates variables if 1007 !! required and stores input vectors in reversed order. It also computes the characteristic radii 1008 !! of each mode. 1117 !! 1118 !! The subroutine initializes aerosols microphysics tracers columns. It allocates variables if 1119 !! required and stores input vectors in reversed order. It also computes the characteristic radii 1120 !! of each mode. 1009 1121 !! @note 1010 !! All the input arguments should be defined from ground to top. 1122 !! All the input arguments should be defined from ground to top. 1011 1123 !! 1012 1124 !! @attention 1013 1125 !! [[mm_globals(module):mm_global_init(interface)]] and [[mm_globals(module):mm_column_init(function)]] 1014 1126 !! must have been called at least once before this method is called. Moreover, this method should be 1015 !! after each call of [[mm_globals(module):mm_column_init(function)]] to reflect changes in the 1127 !! after each call of [[mm_globals(module):mm_column_init(function)]] to reflect changes in the 1016 1128 !! vertical atmospheric structure. 1017 1129 REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: m0aer_s !! \(0^{th}\) order moment of the spherical mode (\(m^{-2}\)). … … 1063 1175 mm_m0aer_f = m0aer_f(mm_nla:1:-1)/mm_dzlev(:) 1064 1176 mm_m3aer_f = m3aer_f(mm_nla:1:-1)/mm_dzlev(:) 1177 1178 ! Setup threshold: 1179 call mm_set_moments_thresholds() 1180 1065 1181 ! aerosols characteristic radii 1066 ! il faudrait peut etre revoir la gestion des zeros ici et la1067 ! remplacer par une valeur seuil des moments.1068 !1069 !-> JVO 19 : Done. Zero threshold set at espilon from dynamics on the1070 ! input moments in calmufi (safer than here). Might still be some unphysical1071 ! values after the dynamics near the threshold. Could be a could idea to add1072 ! a sanity check filtering too high values of radii.1073 !1074 ! TBD : Add a sanity check for high radii ????1075 1182 WHERE(mm_m3aer_s > 0._mm_wp .AND. mm_m0aer_s > 0._mm_wp) 1076 1183 mm_rcs = mm_get_rcs(mm_m0aer_s,mm_m3aer_s) … … 1088 1195 FUNCTION mm_clouds_init(m0ccn,m3ccn,m3ice,gazs) RESULT(err) 1089 1196 !! Initialize clouds tracers vertical grid. 1090 !! 1091 !! The subroutine initializes cloud microphysics tracers columns. It allocates variables if 1092 !! required and stores input vectors in reversed order. It also computes the mean drop radius 1197 !! 1198 !! The subroutine initializes cloud microphysics tracers columns. It allocates variables if 1199 !! required and stores input vectors in reversed order. It also computes the mean drop radius 1093 1200 !! and density and allocates diagnostic vectors. 1094 1201 !! @note 1095 !! All the input arguments should be defined from ground to top. 1202 !! All the input arguments should be defined from ground to top. 1096 1203 !! 1097 1204 !! @attention 1098 1205 !! [[mm_globals(module):mm_global_init(interface)]] and [[mm_globals(module):mm_column_init(function)]] 1099 1206 !! must have been called at least once before this method is called. Moreover, this method should be 1100 !! after each call of [[mm_globals(module):mm_column_init(function)]] to reflect changes in the 1207 !! after each call of [[mm_globals(module):mm_column_init(function)]] to reflect changes in the 1101 1208 !! vertical atmospheric structure. 1102 1209 REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: m0ccn !! 0th order moment of the CCN distribution (\(m^{-2}\)). … … 1121 1228 ! Actually, mm_nla should always initialized the first time mm_column_init is called, NOT HERE. 1122 1229 IF (mm_nla < 0) mm_nla = SIZE(gazs,DIM=1) 1123 ! Note: 1230 ! Note: 1124 1231 ! here we could check that mm_nesp is the same size of gazs(DIM=2) 1125 1232 ! Actually, mm_nesp should be always initialized in mm_global_init, NOT HERE. … … 1134 1241 IF (.NOT.ALLOCATED(mm_drho)) ALLOCATE(mm_drho(mm_nla)) 1135 1242 ! Allocate memory for diagnostics 1243 IF (.NOT.ALLOCATED(mm_ccn_w)) THEN 1244 ALLOCATE(mm_ccn_w(mm_nla)) ; mm_ccn_w(:) = 0._mm_wp 1245 ENDIF 1136 1246 IF (.NOT.ALLOCATED(mm_ccn_flux)) THEN 1137 1247 ALLOCATE(mm_ccn_flux(mm_nla)) ; mm_ccn_flux(:) = 0._mm_wp … … 1154 1264 mm_gazs(:,i) = gazs(mm_nla:1:-1,i) 1155 1265 ENDDO 1266 1267 ! Setup threshold : 1268 call mm_set_moments_cld_thresholds() 1269 1156 1270 ! drop mean radius 1157 1271 call mm_cloud_properties(mm_m0ccn,mm_m3ccn,mm_m3ice,mm_drad,mm_drho) … … 1162 1276 !! Dump model global parameters on stdout. 1163 1277 WRITE(*,'(a)') "========= YAMMS PARAMETERS ============" 1278 WRITE(*,'(a,a)') "mm_fp_precision : ", mm_wp_s 1279 WRITE(*,'(a,L2)') "mm_debug : ", mm_debug 1164 1280 WRITE(*,'(a,L2)') "mm_w_haze_prod : ", mm_w_haze_prod 1165 1281 WRITE(*,'(a,ES14.7)') " mm_p_prod : ", mm_p_prod … … 1168 1284 WRITE(*,'(a,L2)') "mm_w_haze_coag : ", mm_w_haze_coag 1169 1285 WRITE(*,'(a,I2.2)') " mm_coag_interactions: ", mm_coag_choice 1170 WRITE(*,'(a,L2)') "mm_w_haze_sed : ", mm_w_haze_sed 1286 WRITE(*,'(a,L2)') "mm_w_haze_sed : ", mm_w_haze_sed 1171 1287 WRITE(*,'(a,L2)') " mm_wsed_m0 : ", mm_wsed_m0 1172 1288 WRITE(*,'(a,L2)') " mm_wsed_m3 : ", mm_wsed_m3 … … 1178 1294 WRITE(*,'(a,L2)') " mm_w_cloud_nucond : ", mm_w_cloud_nucond 1179 1295 WRITE(*,'(a)') "---------------------------------------" 1296 WRITE(*,'(a)') "Thresholds spherical mode" 1297 WRITE(*,'(a,ES14.7)') " mm_m0as_min : ", mm_m0as_min 1298 WRITE(*,'(a,ES14.7)') " mm_rcs_min : ", mm_rcs_min 1299 WRITE(*,'(a)') "Thresholds fractal mode" 1300 WRITE(*,'(a,ES14.7)') " mm_m0af_min : ", mm_m0af_min 1301 WRITE(*,'(a,ES14.7)') " mm_rcf_min : ", mm_rcf_min 1302 WRITE(*,'(a)') "Thresholds clouds drop" 1303 WRITE(*,'(a,ES14.7)') " mm_m0n_min : ", mm_m0n_min 1304 WRITE(*,'(a,ES14.7)') " mm_drad_min : ", mm_drad_min 1305 WRITE(*,'(a,ES14.7)') " mm_drad_max : ", mm_drad_max 1306 WRITE(*,'(a)') "---------------------------------------" 1180 1307 WRITE(*,'(a,ES14.7)') "mm_dt : ", mm_dt 1181 1308 IF (mm_nla > -1) THEN … … 1191 1318 END SUBROUTINE mm_dump_parameters 1192 1319 1320 SUBROUTINE mm_set_moments_thresholds() 1321 !! Apply minimum threshold for the aerosols moments. 1322 !! 1323 !! The method resets moments (for both modes and orders, 0 and 3) values to zero if 1324 !! their current value is below the minimum threholds. 1325 !! 1326 !! See also [[mm_globals(module):mm_m0as_min(variable)]], [[mm_globals(module):mm_rcs_min(variable)]], 1327 !! [[mm_globals(module):mm_rcf_min(variable)]] and [[mm_globals(module):mm_m0as_min(variable)]]. 1328 INTEGER :: i 1329 DO i=1,mm_nla 1330 IF ((mm_m0aer_s(i) < mm_m0as_min) .OR. (mm_m3aer_s(i) < mm_m3as_min)) THEN 1331 mm_m0aer_s(i) = 0._mm_wp ! mm_m0as_min 1332 mm_m3aer_s(i) = 0._mm_wp ! mm_m0as_min * mm_rcs_min**3._mm_wp * mm_alpha_s(3._mm_wp) 1333 ENDIF 1334 IF ((mm_m0aer_f(i) < mm_m0af_min) .OR. (mm_m3aer_f(i) < mm_m3af_min)) THEN 1335 mm_m0aer_f(i) = 0._mm_wp ! mm_m0af_min 1336 mm_m3aer_f(i) = 0._mm_wp ! mm_m0af_min * mm_rcf_min**3._mm_wp * mm_alpha_f(3._mm_wp) 1337 ENDIF 1338 ENDDO 1339 END SUBROUTINE mm_set_moments_thresholds 1340 1341 SUBROUTINE mm_set_moments_cld_thresholds() 1342 !! Apply minimum threshold for the cloud drop moments. 1343 !! 1344 !! The method resets moments (for both modes and orders, 0 and 3) values to zero if 1345 !! their current value is below the minimum threholds. 1346 INTEGER :: i, j 1347 REAL(kind=mm_wp) :: m3cld 1348 1349 DO i = 1, mm_nla 1350 m3cld = mm_m3ccn(i) 1351 DO j = 1, mm_nesp 1352 m3cld = m3cld + mm_m3ice(i,j) 1353 ENDDO 1354 1355 IF ((mm_m0ccn(i) < mm_m0n_min) .OR. (m3cld < mm_m3cld_min)) THEN 1356 mm_m0ccn(i) = 0._mm_wp 1357 mm_m3ccn(i) = 0._mm_wp 1358 DO j = 1, mm_nesp 1359 mm_m3ice(i,j) = 0._mm_wp 1360 ENDDO 1361 ENDIF 1362 ENDDO 1363 END SUBROUTINE mm_set_moments_cld_thresholds 1364 1365 ELEMENTAL SUBROUTINE mm_check_tendencies(v,dv) 1366 !! Check that tendencies is not greater than value. 1367 !! 1368 !! the purpose of the subroutine is to update dvalue so that v+dv is not negative. 1369 REAL(kind=mm_wp), INTENT(in) :: v !! Value to check. 1370 REAL(kind=mm_wp), INTENT(inout) :: dv !! Value tendencies to check and update consequently. 1371 REAL(kind=mm_wp), PARAMETER :: a = (epsilon(1._mm_wp)-1._mm_wp) 1372 IF (v+dv < 0._mm_wp) THEN 1373 dv = a*v 1374 ENDIF 1375 END SUBROUTINE mm_check_tendencies 1376 1193 1377 ELEMENTAL FUNCTION mm_get_rcs(m0,m3) RESULT(res) 1194 1378 !! Get the characteristic radius for the spherical aerosols size distribution. 1195 !! 1379 !! 1196 1380 !! The method computes the characteristic radius of the size distribution law 1197 1381 !! of the spherical aerosols mode according to its moments and its inter-moments 1198 1382 !! relation. 1199 REAL(kind=mm_wp), INTENT(in) :: m0 !! \(0^{th}\) order moment 1383 REAL(kind=mm_wp), INTENT(in) :: m0 !! \(0^{th}\) order moment 1200 1384 REAL(kind=mm_wp), INTENT(in) :: m3 !! \(3^{rd}\) order moment 1201 1385 REAL(kind=mm_wp) :: res !! Radius 1202 ! arbitrary: if there is no way to compute radius1203 IF (m3 <= 0._mm_wp .OR. m0 <= 0._mm_wp) res = 1._mm_wp1204 1386 res = (m3/m0/mm_alpha_s(3._mm_wp))**(1._mm_wp/3._mm_wp) 1205 1387 END FUNCTION mm_get_rcs … … 1207 1389 ELEMENTAL FUNCTION mm_get_rcf(m0,m3) RESULT(res) 1208 1390 !! Get the characteristic radius for the fractal aerosols size distribution. 1209 !! 1391 !! 1210 1392 !! The method computes the characteristic radius of the size distribution law 1211 1393 !! of the fractal aerosols mode according to its moments and its inter-moments 1212 1394 !! relation. 1213 REAL(kind=mm_wp), INTENT(in) :: m0 !! \(0^{th}\) order moment 1395 REAL(kind=mm_wp), INTENT(in) :: m0 !! \(0^{th}\) order moment 1214 1396 REAL(kind=mm_wp), INTENT(in) :: m3 !! \(3^{rd}\) order moment 1215 1397 REAL(kind=mm_wp) :: res !! Radius 1216 ! arbitrary: if there is no way to compute radius1217 IF (m3 <= 0._mm_wp .OR. m0 <= 0._mm_wp) res = 1._mm_wp1218 1398 res = (m3/m0/mm_alpha_f(3._mm_wp))**(1._mm_wp/3._mm_wp) 1219 1399 END FUNCTION mm_get_rcf 1220 1400 1221 ELEMENTAL FUNCTION mm_effg(z) RESULT(effg) 1401 ELEMENTAL FUNCTION mm_effg(z) RESULT(effg) 1222 1402 !! Compute effective gravitational acceleration. 1223 1403 REAL(kind=mm_wp), INTENT(in) :: z !! Altitude in meters … … 1226 1406 IF (mm_use_effg) effg = effg * (mm_rpla/(mm_rpla+z))**2 1227 1407 RETURN 1228 END FUNCTION mm_effg 1408 END FUNCTION mm_effg 1229 1409 1230 1410 !================================== … … 1237 1417 !! The method computes the mean radius and mean density of cloud drops. 1238 1418 !! 1239 !! @bug 1240 !! A possible bug can happen because of threshold snippet. If __drad__ is greater than 1241 !! __drmax__ (== 1 00 microns) it is automatically set to __drmax__, but computation of1419 !! @bug 1420 !! A possible bug can happen because of threshold snippet. If __drad__ is greater than 1421 !! __drmax__ (== 1e3 microns) it is automatically set to __drmax__, but computation of 1242 1422 !! __drho__ remains unmodified. So __drho__ is not correct in that case. 1243 1423 !! 1244 !! @todo 1245 !! Fix the bug of the subroutine, but it is rather minor, since theoretically we do not 1424 !! @todo 1425 !! Fix the bug of the subroutine, but it is rather minor, since theoretically we do not 1246 1426 !! need the density of the drop. 1247 1427 !! 1248 !! @todo 1249 !! Think about a better implementation of thresholds, and get sure of their consequences in 1250 !! the other parts of the model. 1251 REAL(kind=mm_wp), INTENT(in) :: m0ccn !! \(0^{th}\) order moment of the ccn 1252 REAL(kind=mm_wp), INTENT(in) :: m3ccn !! \(3^{rd}\) order moment of the ccn 1428 !! @todo 1429 !! Think about a better implementation of thresholds, and get sure of their consequences in 1430 !! the other parts of the model. 1431 REAL(kind=mm_wp), INTENT(in) :: m0ccn !! \(0^{th}\) order moment of the ccn 1432 REAL(kind=mm_wp), INTENT(in) :: m3ccn !! \(3^{rd}\) order moment of the ccn 1253 1433 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: m3ice !! \(3^{rd}\) order moments of each ice component 1254 REAL(kind=mm_wp), INTENT(out) :: drad !! Output mean drop radius 1434 REAL(kind=mm_wp), INTENT(out) :: drad !! Output mean drop radius 1255 1435 REAL(kind=mm_wp), INTENT(out), OPTIONAL :: drho !! Optional output mean drop density 1256 REAL(kind=mm_wp) :: vtot, wtot, ntot 1257 REAL(kind=mm_wp), PARAMETER :: threshold = 1.e-25_mm_wp, & 1258 drmin = 1.e-10_mm_wp, & 1259 drmax = 1.e-4_mm_wp, & 1260 athird = 1._mm_wp/3._mm_wp, & 1261 pifac = 4._mm_wp/3._mm_wp*mm_pi 1436 REAL(kind=mm_wp) :: Ntot, Vtot, Wtot 1437 REAL(kind=mm_wp), PARAMETER :: athird = 1._mm_wp / 3._mm_wp 1438 REAL(kind=mm_wp), PARAMETER :: pifac = (4._mm_wp * mm_pi) / 3._mm_wp 1439 1440 ! Set to zero : 1262 1441 drad = 0._mm_wp 1263 ntot = m0ccn 1264 vtot = pifac*m3ccn+SUM(m3ice) 1265 wtot = pifac*m3ccn*mm_rhoaer+SUM(m3ice*mm_xESPS(:)%rho) 1266 IF (ntot <= threshold .OR. vtot <= 0._mm_wp) THEN 1267 drad = drmin 1268 IF (PRESENT(drho)) drho = mm_rhoaer 1269 ELSE 1270 drad = (vtot/ntot/pifac)**athird 1271 drad = MAX(MIN(drad,drmax),drmin) 1272 IF (PRESENT(drho)) drho = wtot/vtot 1273 ENDIF 1442 IF (PRESENT(drho)) drho = 0._mm_wp 1443 1444 ! Initialization : 1445 Ntot = m0ccn 1446 Vtot = pifac * m3ccn + SUM(m3ice) 1447 Wtot = pifac * ((m3ccn*mm_rhoaer) + SUM(m3ice*mm_xESPS(:)%rho)) 1448 1449 IF (Ntot <= mm_m0n_min .OR. Vtot <= mm_m3cld_min) THEN 1450 drad = mm_drad_min 1451 IF (PRESENT(drho)) drho = mm_rhoaer 1452 ELSE 1453 drad = (Vtot / (pifac*Ntot))**athird 1454 drad = MAX(MIN(drad,mm_drad_max),mm_drad_min) 1455 IF (PRESENT(drho)) drho = Wtot / Vtot 1456 ENDIF 1457 1274 1458 RETURN 1275 1459 END SUBROUTINE cldprop_sc … … 1286 1470 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: drad !! Output mean drop radius. 1287 1471 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: drho !! Optional output mean drop density. 1288 INTEGER :: i,ns 1289 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: vtot,wtot,ntot,rho 1290 REAL(kind=mm_wp), PARAMETER :: threshold = 1.e-25_mm_wp, & 1291 drmin = 1.e-10_mm_wp, & 1292 drmax = 1.e-4_mm_wp, & 1293 athird = 1._mm_wp/3._mm_wp, & 1294 pifac = 4._mm_wp/3._mm_wp*mm_pi 1295 1296 ns = SIZE(m0ccn) ; ALLOCATE(vtot(ns),wtot(ns),ntot(ns),rho(ns)) 1297 drad = 0._mm_wp 1298 ntot = m0ccn 1299 vtot = pifac*m3ccn+SUM(m3ice,DIM=2) 1300 wtot = pifac*m3ccn*mm_rhoaer 1301 DO i=1,SIZE(m3ice,DIM=2) 1302 wtot = wtot+m3ice(:,i)*mm_xESPS(i)%rho 1303 ENDDO 1304 WHERE(ntot <= threshold .OR. vtot <= 0._mm_wp) 1305 drad = drmin 1306 rho = mm_rhoaer 1307 ELSEWHERE 1308 drad = (vtot/ntot/pifac)**athird 1309 drad = MAX(MIN(drad,drmax),drmin) 1310 rho = wtot/vtot 1311 END WHERE 1312 IF (PRESENT(drho)) drho = rho 1472 INTEGER :: i 1473 IF (PRESENT(drho)) THEN 1474 DO i = 1, SIZE(m0ccn) ; call cldprop_sc(m0ccn(i),m3ccn(i),m3ice(i,:),drad(i),drho(i)) ; ENDDO 1475 ELSE 1476 DO i = 1, SIZE(m0ccn) ; call cldprop_sc(m0ccn(i),m3ccn(i),m3ice(i,:),drad(i)) ; ENDDO 1477 ENDIF 1313 1478 RETURN 1314 1479 END SUBROUTINE cldprop_ve 1315 1480 1316 ! For configuration file (requires fccplibrary).1481 ! For configuration file (requires swift library). 1317 1482 1318 1483 FUNCTION read_esp(parser,sec,pp) RESULT (err) … … 1322 1487 TYPE(mm_esp), INTENT(out) :: pp !! [[mm_globals(module):mm_esp(type)]] object that stores the parameters. 1323 1488 TYPE(error) :: err !! Error status of the function. 1324 err = cfg_get_value(parser,TRIM(sec)//' name',pp%name) ; IF (err /= 0) RETURN1325 err = cfg_get_value(parser,TRIM(sec)//' mas',pp%mas) ; IF (err /= 0) RETURN1326 err = cfg_get_value(parser,TRIM(sec)//' vol',pp%vol) ; IF (err /= 0) RETURN1327 err = cfg_get_value(parser,TRIM(sec)//' ray',pp%ray) ; IF (err /= 0) RETURN1328 err = cfg_get_value(parser,TRIM(sec)//' mas',pp%mas) ; IF (err /= 0) RETURN1329 err = cfg_get_value(parser,TRIM(sec)//' vol',pp%vol) ; IF (err /= 0) RETURN1330 err = cfg_get_value(parser,TRIM(sec)//' ray',pp%ray) ; IF (err /= 0) RETURN1331 err = cfg_get_value(parser,TRIM(sec)//' masmol',pp%masmol) ; IF (err /= 0) RETURN1332 err = cfg_get_value(parser,TRIM(sec)//' rho',pp%rho) ; IF (err /= 0) RETURN1333 err = cfg_get_value(parser,TRIM(sec)//' tc',pp%tc) ; IF (err /= 0) RETURN1334 err = cfg_get_value(parser,TRIM(sec)//' pc',pp%pc) ; IF (err /= 0) RETURN1335 err = cfg_get_value(parser,TRIM(sec)//' tb',pp%tb) ; IF (err /= 0) RETURN1336 err = cfg_get_value(parser,TRIM(sec)//' w',pp%w) ; IF (err /= 0) RETURN1337 err = cfg_get_value(parser,TRIM(sec)//' a_sat',pp%a_sat) ; IF (err /= 0) RETURN1338 err = cfg_get_value(parser,TRIM(sec)//' b_sat',pp%b_sat) ; IF (err /= 0) RETURN1339 err = cfg_get_value(parser,TRIM(sec)//' c_sat',pp%c_sat) ; IF (err /= 0) RETURN1340 err = cfg_get_value(parser,TRIM(sec)//' d_sat',pp%d_sat) ; IF (err /= 0) RETURN1341 err = cfg_get_value(parser,TRIM(sec)//' mteta',pp%mteta) ; IF (err /= 0) RETURN1342 err = cfg_get_value(parser,TRIM(sec)//' tx_prod',pp%tx_prod) ; IF (err /= 0) RETURN1489 err = cfg_get_value(parser,TRIM(sec)//'/name',pp%name) ; IF (err /= 0) RETURN 1490 err = cfg_get_value(parser,TRIM(sec)//'/mas',pp%mas) ; IF (err /= 0) RETURN 1491 err = cfg_get_value(parser,TRIM(sec)//'/vol',pp%vol) ; IF (err /= 0) RETURN 1492 err = cfg_get_value(parser,TRIM(sec)//'/ray',pp%ray) ; IF (err /= 0) RETURN 1493 err = cfg_get_value(parser,TRIM(sec)//'/mas',pp%mas) ; IF (err /= 0) RETURN 1494 err = cfg_get_value(parser,TRIM(sec)//'/vol',pp%vol) ; IF (err /= 0) RETURN 1495 err = cfg_get_value(parser,TRIM(sec)//'/ray',pp%ray) ; IF (err /= 0) RETURN 1496 err = cfg_get_value(parser,TRIM(sec)//'/masmol',pp%masmol) ; IF (err /= 0) RETURN 1497 err = cfg_get_value(parser,TRIM(sec)//'/rho',pp%rho) ; IF (err /= 0) RETURN 1498 err = cfg_get_value(parser,TRIM(sec)//'/tc',pp%tc) ; IF (err /= 0) RETURN 1499 err = cfg_get_value(parser,TRIM(sec)//'/pc',pp%pc) ; IF (err /= 0) RETURN 1500 err = cfg_get_value(parser,TRIM(sec)//'/tb',pp%tb) ; IF (err /= 0) RETURN 1501 err = cfg_get_value(parser,TRIM(sec)//'/w',pp%w) ; IF (err /= 0) RETURN 1502 err = cfg_get_value(parser,TRIM(sec)//'/a_sat',pp%a_sat) ; IF (err /= 0) RETURN 1503 err = cfg_get_value(parser,TRIM(sec)//'/b_sat',pp%b_sat) ; IF (err /= 0) RETURN 1504 err = cfg_get_value(parser,TRIM(sec)//'/c_sat',pp%c_sat) ; IF (err /= 0) RETURN 1505 err = cfg_get_value(parser,TRIM(sec)//'/d_sat',pp%d_sat) ; IF (err /= 0) RETURN 1506 err = cfg_get_value(parser,TRIM(sec)//'/mteta',pp%mteta) ; IF (err /= 0) RETURN 1507 err = cfg_get_value(parser,TRIM(sec)//'/tx_prod',pp%tx_prod) ; IF (err /= 0) RETURN 1343 1508 RETURN 1344 1509 END FUNCTION read_esp … … 1346 1511 ! ========================================================================= 1347 1512 ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1348 ! CONFIGURATION PARSER checking methods 1513 ! CONFIGURATION PARSER checking methods 1349 1514 ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1350 1515 ! ========================================================================= … … 1352 1517 FUNCTION check_r1(err,var,def,wlog) RESULT(ret) 1353 1518 !! Check an option value (float). 1354 !! 1355 !! The method checks an option value and optionally set a default value, __def__ to initialize 1519 !! 1520 !! The method checks an option value and optionally set a default value, __def__ to initialize 1356 1521 !! __var__ on error if given. 1357 1522 TYPE(error), INTENT(in) :: err !! Error object from value getter. … … 1360 1525 LOGICAL, INTENT(in), OPTIONAL :: wlog !! .true. to print warning/error message. 1361 1526 TYPE(error) :: ret !! Input error. 1362 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1527 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1363 1528 LOGICAL :: zlog 1364 1529 ret = err … … 1376 1541 FUNCTION check_l1(err,var,def,wlog) RESULT(ret) 1377 1542 !! Check an option value (logical). 1378 !! 1379 !! The method checks an option value and optionally set a default value, __def__ to initialize 1543 !! 1544 !! The method checks an option value and optionally set a default value, __def__ to initialize 1380 1545 !! __var__ on error if given. 1381 1546 TYPE(error), INTENT(in) :: err !! Error object from value getter. … … 1384 1549 LOGICAL, INTENT(in), OPTIONAL :: wlog !! .true. to print warning/error message. 1385 1550 TYPE(error) :: ret !! Input error. 1386 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1551 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1387 1552 LOGICAL :: zlog 1388 1553 ret = err 1389 1554 zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog 1390 1555 IF (err == 0) RETURN 1391 1556 IF (PRESENT(def)) THEN … … 1400 1565 FUNCTION check_i1(err,var,def,wlog) RESULT(ret) 1401 1566 !! Check an option value (integer). 1402 !! 1403 !! The method checks an option value and optionally set a default value, __def__ to initialize 1567 !! 1568 !! The method checks an option value and optionally set a default value, __def__ to initialize 1404 1569 !! __var__ on error if given. 1405 1570 TYPE(error), INTENT(in) :: err !! Error object from value getter. … … 1411 1576 LOGICAL :: zlog 1412 1577 ret = err 1413 1578 zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog 1414 1579 IF (err == 0) RETURN 1415 1580 IF (PRESENT(def)) THEN … … 1424 1589 FUNCTION check_s1(err,var,def,wlog) RESULT(ret) 1425 1590 !! Check an option value (string). 1426 !! 1427 !! The method checks an option value and optionally set a default value, __def__ to initialize 1591 !! 1592 !! The method checks an option value and optionally set a default value, __def__ to initialize 1428 1593 !! __var__ on error if given. 1429 1594 TYPE(error), INTENT(in) :: err !! Error object from value getter. … … 1432 1597 LOGICAL, INTENT(in), OPTIONAL :: wlog !! .true. to print warning/error message. 1433 1598 TYPE(error) :: ret !! Input error. 1434 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1599 CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 1435 1600 LOGICAL :: zlog 1436 ret = err 1601 ret = err 1437 1602 zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog 1438 1603 IF (err == 0) RETURN -
trunk/LMDZ.TITAN/libf/muphytitan/mm_haze.f90
r2109 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Haze microphysics module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 MODULE MM_HAZE 39 39 !! Haze microphysics module. … … 46 46 !! 47 47 !! @note 48 !! The production function is specific to Titan, where aerosols are created above the detached 49 !! haze layer. No other source is taken into account. This process is controled by two parameters, 50 !! the pressure level of production and the production rate. Then both M0 and M3 of the aerosols 48 !! The production function is specific to Titan, where aerosols are created above the detached 49 !! haze layer. No other source is taken into account. This process is controled by two parameters, 50 !! the pressure level of production and the production rate. Then both M0 and M3 of the aerosols 51 51 !! distribution are updated in the production zone by addition of the production rate along a 52 52 !! gaussian shape. 53 53 !! 54 54 !! @note 55 !! The interface methods always uses the global variables defined in [[mm_globals(module)]] when 55 !! The interface methods always uses the global variables defined in [[mm_globals(module)]] when 56 56 !! values (any kind, temperature, pressure, moments...) over the vertical grid are required. 57 57 !! 58 58 !! @warning 59 !! The tendencies returned by the method are always defined over the vertical grid from __TOP__ 59 !! The tendencies returned by the method are always defined over the vertical grid from __TOP__ 60 60 !! to __GROUND__. 61 61 !! 62 !! @todo 62 !! @todo 63 63 !! Modify tests on tendencies vectors to get sure that allocation is done: 64 64 !! Currently, we assume the compiler handles automatic allocation of arrays. … … 72 72 73 73 PUBLIC :: mm_haze_microphysics, mm_haze_coagulation, mm_haze_sedimentation, & 74 75 76 74 mm_haze_production 75 76 CONTAINS 77 77 78 78 !============================================================================ … … 83 83 !! Get the evolution of moments tracers through haze microphysics processes. 84 84 !! 85 !! The subroutine is a wrapper to the haze microphysics methods. It computes the tendencies 86 !! of moments tracers for coagulation, sedimentation and production processes for the 85 !! The subroutine is a wrapper to the haze microphysics methods. It computes the tendencies 86 !! of moments tracers for coagulation, sedimentation and production processes for the 87 87 !! atmospheric column. 88 88 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_s 89 89 !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-3}\)). 90 90 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_s 91 91 !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-3}\)). 92 92 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_f 93 93 !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)). 94 94 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_f 95 95 !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)). 96 96 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm0as 97 97 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm3as … … 107 107 zdm3af(1:mm_nla) = 0._mm_wp 108 108 109 IF (mm_w_haze_coag) THEN 109 IF (mm_w_haze_coag) THEN 110 110 ! Calls coagulation 111 111 call mm_haze_coagulation(dm0a_s,dm3a_s,dm0a_f,dm3a_f) … … 120 120 121 121 ! Updates tendencies 122 dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as 122 dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as 123 123 dm0a_f=dm0a_f+zdm0af ; dm3a_f=dm3a_f+zdm3af 124 124 ENDIF … … 127 127 call mm_haze_production(zdm0as,zdm3as) 128 128 ! We only produce spherical aerosols 129 dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as 129 dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as 130 130 ENDIF 131 131 … … 137 137 ! COAGULATION PROCESS RELATED METHODS 138 138 !============================================================================ 139 139 140 140 SUBROUTINE mm_haze_coagulation(dM0s,dM3s,dM0f,dM3f) 141 141 !! Get the evolution of the aerosols moments vertical column due to coagulation process. 142 !! 142 !! 143 143 !! This is main method of the coagulation process: 144 144 !! … … 149 149 !! 5. Finally computes the tendencies of the moments. 150 150 !! 151 !! All arguments are assumed vectors of __N__ elements where __N__ is the total number of 151 !! All arguments are assumed vectors of __N__ elements where __N__ is the total number of 152 152 !! vertical __layers__. 153 153 !! 154 154 !! @note 155 !! The method uses directly the global variables related to the vertical atmospheric structure 156 !! stored in [[mm_globals(module)]]. Consequently they must be updated before calling the subroutine. 155 !! The method uses directly the global variables related to the vertical atmospheric structure 156 !! stored in [[mm_globals(module)]]. Consequently they must be updated before calling the subroutine. 157 157 !! 158 158 !! @bug 159 !! If the transfert probabilities are set to 1 for the two flow regimes (pco and pfm), 159 !! If the transfert probabilities are set to 1 for the two flow regimes (pco and pfm), 160 160 !! a floating point exception occured (i.e. a NaN) as we perform a division by zero 161 161 !! … … 163 163 !! Get rid of the fu\*\*\*\* STOP statement... 164 164 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM0s 165 165 !! Tendency of the 0th order moment of the spherical size-distribution over a time step (\(m^{-3}\)). 166 166 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM3s 167 167 !! Tendency of the 3rd order moment of the spherical size-distribution (\(m^{3}.m^{-3}\)). 168 168 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM0f 169 169 !! Tendency of the 0th order moment of the fractal size-distribution over a time step (\(m^{-3}\)). 170 170 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM3f 171 171 !! Tendency of the 3rd order moment of the fractal size-distribution over a time step (\(m^{3}.m^{-3}\)). 172 172 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: c_kco,c_kfm,c_slf,tmp, & 173 173 kco,kfm,pco,pfm,mq 174 174 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a_ss,a_sf,b_ss,b_ff,c_ss,c_sf 175 175 INTEGER :: i … … 180 180 ! Alloctes local arrays 181 181 ALLOCATE(kco(mm_nla),kfm(mm_nla),c_slf(mm_nla), & 182 183 182 c_kco(mm_nla),c_kfm(mm_nla),mq(mm_nla), & 183 pco(mm_nla),pfm(mm_nla)) 184 184 ALLOCATE(a_ss(mm_nla),a_sf(mm_nla), & 185 186 187 185 b_ss(mm_nla),b_ff(mm_nla), & 186 c_ss(mm_nla),c_sf(mm_nla)) 187 188 188 a_ss(:) = 0._mm_wp ; a_sf(:) = 0._mm_wp 189 b_ss(:) = 0._mm_wp ; b_ff(:) = 0._mm_wp 189 b_ss(:) = 0._mm_wp ; b_ff(:) = 0._mm_wp 190 190 c_ss(:) = 0._mm_wp ; c_sf(:) = 0._mm_wp 191 191 … … 193 193 c_kco(:) = mm_get_kco(mm_temp) ; c_kfm(:) = mm_get_kfm(mm_temp) 194 194 ! get slf (slip-flow factor) 195 c_slf(:) = mm_akn * mm_lambda_g(mm_temp,mm_play) 195 c_slf(:) = mm_akn * mm_lambda_g(mm_temp,mm_play) 196 196 197 197 DO i=1,mm_nla … … 202 202 pfm(i) = mm_ps2s(mm_rcs(i),0,1,mm_temp(i),mm_play(i)) 203 203 ! (A_SS_CO x A_SS_FM) / (A_SS_CO + A_SS_FM) 204 kco(i) = g0ssco(mm_rcs(i),c_slf(i),c_kco(i)) 205 kfm(i) = g0ssfm(mm_rcs(i),c_kfm(i)) 204 kco(i) = g0ssco(mm_rcs(i),c_slf(i),c_kco(i)) 205 kfm(i) = g0ssfm(mm_rcs(i),c_kfm(i)) 206 206 IF (kco(i)*(pco(i)-2._mm_wp)+kfm(i)*(pfm(i)-2._mm_wp) /=0) THEN 207 207 a_ss(i) = (kco(i)*(pco(i)-2._mm_wp)*kfm(i)*(pfm(i)-2._mm_wp))/(kco(i)*(pco(i)-2._mm_wp)+kfm(i)*(pfm(i)-2._mm_wp)) … … 267 267 ENDIF 268 268 ENDDO 269 269 270 270 DEALLOCATE(kco,kfm,c_kco,c_kfm,pco,pfm,c_slf) 271 271 … … 302 302 !! Get γ pre-factor for the 0th order moment with SS interactions in the continuous flow regime. 303 303 !! 304 !! @note 304 !! @note 305 305 !! If __rcs__ is 0, the function returns 0. 306 306 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 320 320 !! Get γ pre-factor for the 0th order moment with SF interactions in the continuous flow regime. 321 321 !! 322 !! @note 322 !! @note 323 323 !! If __rcs__ or __rcf__ is 0, the function returns 0. 324 324 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 329 329 REAL(kind=mm_wp) :: a1, a2, a3, a4, a5, a6, e, rcff 330 330 res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN 331 e=3._mm_wp/mm_df ; rcff = rcf**e*mm_rb2ra 332 ! computes mm_alpha coefficients 333 a1=mm_alpha_s(1._mm_wp) ; a2=mm_alpha_f(-e) ; a3=mm_alpha_f(e) 331 e=3._mm_wp/mm_df ; rcff = rcf**e*mm_rb2ra 332 ! computes mm_alpha coefficients 333 a1=mm_alpha_s(1._mm_wp) ; a2=mm_alpha_f(-e) ; a3=mm_alpha_f(e) 334 334 a4=mm_alpha_s(-1._mm_wp) ; a5=mm_alpha_s(-2._mm_wp) ; a6=mm_alpha_f(-2._mm_wp*e) 335 335 ! Computes gamma pre-factor 336 336 res = c_kco*( 2._mm_wp + a1*a2*rcs/rcff + a4*a3*rcff/rcs + c_slf*( a4/rcs + & 337 337 a2/rcff + a5*a3*rcff/rcs**2 + a1*a6*rcs/rcff**2)) 338 338 RETURN 339 339 END FUNCTION g0sfco … … 342 342 !! Get γ pre-factor for the 0th order moment with FF interactions in the continuous flow regime. 343 343 !! 344 !! @note 344 !! @note 345 345 !! If __rcf__ is 0, the function returns 0. 346 346 REAL(kind=mm_wp), INTENT(in) :: rcf !! Characteristic radius of the fractal size-distribution. … … 361 361 !! Get γ pre-factor for the 3rd order moment with SS interactions in the continuous flow regime. 362 362 !! 363 !! @note 363 !! @note 364 364 !! If __rcs__ is 0, the function returns 0. 365 365 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 370 370 res = 0._mm_wp ; IF (rcs <= 0._mm_wp) RETURN 371 371 ! computes mm_alpha coefficients 372 a1=mm_alpha_s(3._mm_wp) ; a2=mm_alpha_s(2._mm_wp) ; a3=mm_alpha_s(1._mm_wp) 372 a1=mm_alpha_s(3._mm_wp) ; a2=mm_alpha_s(2._mm_wp) ; a3=mm_alpha_s(1._mm_wp) 373 373 a4=mm_alpha_s(4._mm_wp) ; a5=mm_alpha_s(-1._mm_wp) ; a6=mm_alpha_s(-2._mm_wp) 374 374 375 375 ! Computes gamma pre-factor 376 res = (2._mm_wp*a1 + a2*a3 + a4*a5 + c_slf/rcs*(a3**2 + a4*a6 + a1*a5 + a2))* & 377 376 res = (2._mm_wp*a1 + a2*a3 + a4*a5 + c_slf/rcs*(a3**2 + a4*a6 + a1*a5 + a2))* & 377 c_kco/(a1**2*rcs**3) 378 378 RETURN 379 379 END FUNCTION g3ssco … … 382 382 !! Get γ pre-factor for the 3rd order moment with SF interactions in the continuous flow regime. 383 383 !! 384 !! @note 384 !! @note 385 385 !! If __rcs__ or __rcf__ is 0, the function returns 0. 386 386 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 392 392 res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN 393 393 ! computes mm_alpha coefficients 394 e=3._mm_wp/mm_df ; rcff = rcf**e*mm_rb2ra 395 a1=mm_alpha_s(3._mm_wp) ; a2=mm_alpha_s(4._mm_wp) ; a3=mm_alpha_f(-e) 394 e=3._mm_wp/mm_df ; rcff = rcf**e*mm_rb2ra 395 a1=mm_alpha_s(3._mm_wp) ; a2=mm_alpha_s(4._mm_wp) ; a3=mm_alpha_f(-e) 396 396 a4=mm_alpha_s(2._mm_wp) ; a5=mm_alpha_f(e) ; a6=mm_alpha_s(1._mm_wp) 397 397 a7=mm_alpha_f(-2._mm_wp*e) ; a8=mm_alpha_f(3._mm_wp) 398 398 ! Computes gamma pre-factor 399 399 res = (2._mm_wp*a1*rcs**3 + a2*rcs**4*a3/rcff + a4*rcs**2*a5*rcff + & 400 401 400 c_slf *( a4*rcs**2 + a1*rcs**3*a3/rcff + a6*rcs*a5*rcff + & 401 a2*rcs**4*a7/rcff**2))* c_kco/(a1*a8*(rcs*rcf)**3) 402 402 RETURN 403 403 END FUNCTION g3sfco … … 406 406 !! Get γ pre-factor for the 0th order moment with SS interactions in the Free Molecular flow regime. 407 407 !! 408 !! @note 408 !! @note 409 409 !! If __rcs__ is 0, the function returns 0. 410 410 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 422 422 423 423 ELEMENTAL FUNCTION g0sffm(rcs, rcf, c_kfm) RESULT(res) 424 !> Get γ pre-factor for the 0th order moment with SF interactions in the Free Molecular flow regime. 425 !! 426 !! @note 424 !> Get γ pre-factor for the 0th order moment with SF interactions in the Free Molecular flow regime. 425 !! 426 !! @note 427 427 !! If __rcs__ or __rcf__ is 0, the function returns 0. 428 428 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 435 435 res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN 436 436 ! computes mm_alpha coefficients 437 e1 = 3._mm_wp/mm_df 438 e2 = 6._mm_wp/mm_df 437 e1 = 3._mm_wp/mm_df 438 e2 = 6._mm_wp/mm_df 439 439 e3 = (6._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 440 440 e4 = (12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 441 441 442 rcff1 = mm_rb2ra * rcf**e1 442 rcff1 = mm_rb2ra * rcf**e1 443 443 rcff2 = rcff1**2 444 rcff3 = mm_rb2ra * rcf**e3 444 rcff3 = mm_rb2ra * rcf**e3 445 445 rcff4 = mm_rb2ra**2 * rcf**e4 446 446 447 a1=mm_alpha_s(0.5_mm_wp) ; a2=mm_alpha_s(-0.5_mm_wp) ; a3=mm_alpha_f(e1) 447 a1=mm_alpha_s(0.5_mm_wp) ; a2=mm_alpha_s(-0.5_mm_wp) ; a3=mm_alpha_f(e1) 448 448 a4=mm_alpha_s(-1.5_mm_wp) ; a5=mm_alpha_f(e2) ; a6=mm_alpha_s(2._mm_wp) 449 a7=mm_alpha_f(-1.5_mm_wp) ; a8=mm_alpha_s(1._mm_wp) ; a9=mm_alpha_f(e3) 449 a7=mm_alpha_f(-1.5_mm_wp) ; a8=mm_alpha_s(1._mm_wp) ; a9=mm_alpha_f(e3) 450 450 a10=mm_alpha_f(e4) 451 451 452 452 ! Computes gamma pre-factor 453 453 res = (a1*rcs**0.5_mm_wp + 2._mm_wp*rcff1*a2*a3/rcs**0.5_mm_wp + a4*a5*rcff2/rcs**1.5_mm_wp + & 454 455 454 a6*a7*rcs**2/rcf**1.5_mm_wp + 2._mm_wp*a8*a9*rcs*rcff3 + a10*rcff4 & 455 )*mm_get_btk(4,0)*c_kfm 456 456 RETURN 457 457 END FUNCTION g0sffm 458 458 459 459 ELEMENTAL FUNCTION g0fffm(rcf, c_kfm) RESULT(res) 460 !! Get γ pre-factor for the 0th order moment with FF interactions in the Free Molecular flow regime. 461 !! 462 !! @note 460 !! Get γ pre-factor for the 0th order moment with FF interactions in the Free Molecular flow regime. 461 !! 462 !! @note 463 463 !! If __rcf__ is 0, the function returns 0. 464 464 REAL(kind=mm_wp), INTENT(in) :: rcf !! Characteristic radius of the fractal size-distribution. 465 465 REAL(kind=mm_wp), INTENT(in) :: c_kfm !! Thermodynamic free molecular flow regime pre-factor. 466 REAL(kind=mm_wp) :: res !! γ coagulation kernel pre-factor. 466 REAL(kind=mm_wp) :: res !! γ coagulation kernel pre-factor. 467 467 REAL(kind=mm_wp) :: a1, a2, a3, a4, a5, e1, e2, e3, rcff 468 468 res = 0._mm_wp ; IF (rcf <= 0._mm_wp) RETURN 469 469 ! computes mm_alpha coefficients 470 e1=3._mm_wp/mm_df ; e2=(6_mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 470 e1=3._mm_wp/mm_df ; e2=(6_mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 471 471 e3=(12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 472 472 rcff=mm_rb2ra**2*rcf**e3 … … 489 489 res = 0._mm_wp ; IF (rcs <= 0._mm_wp) RETURN 490 490 ! computes mm_alpha coefficients 491 a1=mm_alpha_s(3.5_mm_wp) ; a2=mm_alpha_s(1._mm_wp) ; a3=mm_alpha_s(2.5_mm_wp) 491 a1=mm_alpha_s(3.5_mm_wp) ; a2=mm_alpha_s(1._mm_wp) ; a3=mm_alpha_s(2.5_mm_wp) 492 492 a4=mm_alpha_s(2._mm_wp) ; a5=mm_alpha_s(1.5_mm_wp) ; a6=mm_alpha_s(5._mm_wp) 493 a7=mm_alpha_s(-1.5_mm_wp) ; a8=mm_alpha_s(4._mm_wp) ; a9=mm_alpha_s(-0.5_mm_wp) 493 a7=mm_alpha_s(-1.5_mm_wp) ; a8=mm_alpha_s(4._mm_wp) ; a9=mm_alpha_s(-0.5_mm_wp) 494 494 a10=mm_alpha_s(3._mm_wp) ; a11=mm_alpha_s(0.5_mm_wp) 495 495 ! Computes gamma pre-factor 496 496 res = (a1 + 2._mm_wp*a2*a3 + a4*a5 + a6*a7 + 2._mm_wp*a8*a9 + a10*a11) & 497 497 *mm_get_btk(1,3)*c_kfm/(a10**2*rcs**2.5_mm_wp) 498 498 RETURN 499 499 END FUNCTION g3ssfm … … 502 502 !! Get γ pre-factor for the 3rd order moment with SF interactions in the Free Molecular flow regime. 503 503 !! 504 !! @note 504 !! @note 505 505 !! If __rcs__ or __rcf__ is 0, the function returns 0. 506 506 REAL(kind=mm_wp), INTENT(in) :: rcs !! Characteristic radius of the spherical size-distribution. … … 512 512 res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN 513 513 ! computes mm_alpha coefficients 514 e1=3._mm_wp/mm_df 515 e2=(6._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 514 e1=3._mm_wp/mm_df 515 e2=(6._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 516 516 e3=(12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df) 517 517 rcff1=mm_rb2ra*rcf**e1 ; rcff2=mm_rb2ra*rcf**e2 ; rcff3=mm_rb2ra**2*rcf**e3 518 a1=mm_alpha_s(3.5_mm_wp) ; a2=mm_alpha_s(2.5_mm_wp) ; a3=mm_alpha_f(e1) 519 a4=mm_alpha_s(1.5_mm_wp) ; a5=mm_alpha_f(2._mm_wp*e1) ; a6=mm_alpha_s(5._mm_wp) 520 a7=mm_alpha_f(-1.5_mm_wp) ; a8=mm_alpha_s(4._mm_wp) ; a9=mm_alpha_f(e2) 518 a1=mm_alpha_s(3.5_mm_wp) ; a2=mm_alpha_s(2.5_mm_wp) ; a3=mm_alpha_f(e1) 519 a4=mm_alpha_s(1.5_mm_wp) ; a5=mm_alpha_f(2._mm_wp*e1) ; a6=mm_alpha_s(5._mm_wp) 520 a7=mm_alpha_f(-1.5_mm_wp) ; a8=mm_alpha_s(4._mm_wp) ; a9=mm_alpha_f(e2) 521 521 a10=mm_alpha_s(3._mm_wp) ; a11=mm_alpha_f(e3) ; a12=mm_alpha_f(3._mm_wp) 522 522 ! Computes gamma pre-factor 523 523 res = (a1*rcs**3.5_mm_wp + 2._mm_wp*a2*a3*rcs**2.5_mm_wp*rcff1 + a4*a5*rcs**1.5_mm_wp*rcff1**2 + & 524 a6*a7*rcs**5/rcf**1.5_mm_wp + 2._mm_wp*a8*a9*rcs**4*rcff2 + &525 524 a6*a7*rcs**5/rcf**1.5_mm_wp + 2._mm_wp*a8*a9*rcs**4*rcff2 + & 525 a10*a11*rcs**3*rcff3)*mm_get_btk(4,3)*c_kfm/(a10*a12*(rcs*rcf)**3) 526 526 RETURN 527 527 END FUNCTION g3sffm … … 530 530 ! SEDIMENTATION PROCESS RELATED METHODS 531 531 !============================================================================ 532 532 533 533 SUBROUTINE mm_haze_sedimentation(dm0s,dm3s,dm0f,dm3f) 534 534 !! Interface to sedimentation algorithm. 535 535 !! 536 536 !! The subroutine computes the evolution of each moment of the aerosols tracers 537 !! through sedimentation process and returns their tendencies for a timestep. 537 !! through sedimentation process and returns their tendencies for a timestep. 538 538 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0s 539 539 !! Tendency of the 0th order moment of the spherical mode (\(m^{-3}\)). 540 540 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3s 541 541 !! Tendency of the 3rd order moment of the spherical mode (\(m^{3}.m^{-3}\)). 542 542 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0f 543 543 !! Tendency of the 0th order moment of the fractal mode (\(m^{-3}\)). 544 544 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3f 545 545 !! Tendency of the 3rd order moment of the fractal mode (\(m^{3}.m^{-3}\)). 546 546 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: ft,fdcor,wth 547 REAL(kind=mm_wp) :: m,n,p 548 REAL(kind=mm_wp), PARAMETER :: fac = 4._mm_wp/3._mm_wp * mm_pi 547 REAL(kind=mm_wp), PARAMETER :: fac = 4._mm_wp/3._mm_wp * mm_pi 549 548 550 549 ALLOCATE(ft(mm_nle),wth(mm_nle),fdcor(mm_nle)) … … 624 623 !! Compute the tendency of the moment through sedimentation process. 625 624 !! 626 !! 625 !! 627 626 !! The method computes the time evolution of the \(k^{th}\) order moment through sedimentation: 628 627 !! … … 630 629 !! 631 630 !! The equation is resolved using a [Crank-Nicolson algorithm](http://en.wikipedia.org/wiki/Crank-Nicolson_method). 632 !! 633 !! Sedimentation algorithm is quite messy. It appeals to the dark side of the Force and uses evil black magic spells 631 !! 632 !! Sedimentation algorithm is quite messy. It appeals to the dark side of the Force and uses evil black magic spells 634 633 !! from ancient times. It is based on \cite{toon1988b,fiadeiro1977,turco1979} and is an update of the algorithm 635 634 !! originally implemented in the LMDZ-Titan 2D GCM. … … 638 637 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: ft !! Downward sedimentation flux (effective velocity of the moment). 639 638 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dmk !! Tendency of \(k^{th}\) order moment (in \(m^{k}.m^{-3}\)). 640 INTEGER :: i 639 INTEGER :: i 641 640 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: as,bs,cs,mko 642 641 ALLOCATE(as(mm_nla), bs(mm_nla), cs(mm_nla), mko(mm_nla)) … … 648 647 bs(1:mm_nla) = -(ft(2:mm_nle)+mm_dzlay(1:mm_nla)/dt) 649 648 cs(1:mm_nla) = -mm_dzlay(1:mm_nla)/dt*mk(1:mm_nla) 650 ! (Tri)diagonal matrix inversion 649 ! (Tri)diagonal matrix inversion 651 650 mko(1) = cs(1)/bs(1) 652 651 DO i=2,mm_nla ; mko(i) = (cs(i)-mko(i-1)*as(i))/bs(i) ; ENDDO … … 660 659 ! interior 661 660 mko(2:mm_nla-1)=(bs(2:mm_nla-1)*mk(1:mm_nla-2) + & 662 663 661 cs(2:mm_nla-1)*mk(2:mm_nla-1) & 662 )/as(2:mm_nla-1) 664 663 ENDIF 665 664 dmk = mko - mk … … 670 669 SUBROUTINE get_weff(mk,k,df,rc,dt,afun,wth,corf) 671 670 !! Get the effective settling velocity for aerosols moments. 672 !! 673 !! This method computes the effective settling velocity of the \(k^{th}\) order moment of aerosol 674 !! tracers. The basic settling velocity (\(v^{eff}_{M_{k}}\)) is computed using the following 671 !! 672 !! This method computes the effective settling velocity of the \(k^{th}\) order moment of aerosol 673 !! tracers. The basic settling velocity (\(v^{eff}_{M_{k}}\)) is computed using the following 675 674 !! equation: 676 !! 677 !! $$ 675 !! 676 !! $$ 678 677 !! \begin{eqnarray*} 679 !! \Phi^{sed}_{M_{k}} &=& \int_{0}^{\infty} n(r) r^{k} \times w(r) dr 678 !! \Phi^{sed}_{M_{k}} &=& \int_{0}^{\infty} n(r) r^{k} \times w(r) dr 680 679 !! == M_{k} \times v^{eff}_{M_{k}} \\ 681 680 !! v^{eff}_{M_{k} &=& \dfrac{2 \rho g r_{c}^{\dfrac{3D_{f}-3}{D_{f}}}} … … 686 685 !! $$ 687 686 !! 688 !! \(v^{eff}_{M_{k}\) is then corrected to reduce numerical diffusion of the sedimentation algorithm 687 !! \(v^{eff}_{M_{k}\) is then corrected to reduce numerical diffusion of the sedimentation algorithm 689 688 !! as defined in \cite{toon1988b}. 690 689 !! 691 690 !! @warning 692 !! Both __df__, __rc__ and __afun__ must be consistent with each other otherwise wrong values will 691 !! Both __df__, __rc__ and __afun__ must be consistent with each other otherwise wrong values will 693 692 !! be computed. 694 693 REAL(kind=mm_wp), INTENT(in), DIMENSION(mm_nla) :: mk 695 694 !! Moment of order __k__ (\(m^{k}.m^{-3}\)) at each layer. 696 695 REAL(kind=mm_wp), INTENT(in), DIMENSION(mm_nla) :: rc 697 696 !! Characteristic radius associated to the moment at each layer. 698 697 REAL(kind=mm_wp), INTENT(in) :: k 699 698 !! The order of the moment. 700 699 REAL(kind=mm_wp), INTENT(in) :: df 701 700 !! Fractal dimension of the aersols. 702 701 REAL(kind=mm_wp), INTENT(in) :: dt 703 702 !! Time step (s). 704 703 REAL(kind=mm_wp), INTENT(out), DIMENSION(mm_nle) :: wth 705 706 REAL(kind=mm_wp), INTENT(out), DIMENSION(mm_nle), OPTIONAL :: corf 707 704 !! Theoretical Settling velocity at each vertical __levels__ (\( wth \times corf = weff\)). 705 REAL(kind=mm_wp), INTENT(out), DIMENSION(mm_nle), OPTIONAL :: corf 706 !! _Fiadero_ correction factor applied to the theoretical settling velocity at each vertical __levels__. 708 707 INTERFACE 709 708 FUNCTION afun(order) … … 713 712 REAL(kind=mm_wp) :: afun !! Alpha value. 714 713 END FUNCTION afun 715 END INTERFACE 714 END INTERFACE 716 715 INTEGER :: i 717 716 REAL(kind=mm_wp) :: af1,af2,ar1,ar2 … … 720 719 REAL(kind=mm_wp), DIMENSION(mm_nle) :: zcorf 721 720 ! ------------------ 722 721 723 722 wth(:) = 0._mm_wp ; zcorf(:) = 1._mm_wp 724 723 725 724 ar1 = (3._mm_wp*df -3._mm_wp)/df ; ar2 = (3._mm_wp*df -6._mm_wp)/df 726 af1 = (df*(k+3._mm_wp)-3._mm_wp)/df ; af2 = (df*(k+3._mm_wp)-6._mm_wp)/df 725 af1 = (df*(k+3._mm_wp)-3._mm_wp)/df ; af2 = (df*(k+3._mm_wp)-6._mm_wp)/df 727 726 rb2ra = mm_rm**((df-3._mm_wp)/df) 728 727 DO i=2,mm_nla 729 IF (rc(i-1) <= 0._mm_wp) CYCLE 728 IF (rc(i-1) <= 0._mm_wp) CYCLE 730 729 dzb = (mm_dzlay(i)+mm_dzlay(i-1))/2._mm_wp 731 730 csto = 2._mm_wp*mm_rhoaer*mm_effg(mm_zlev(i))/(9._mm_wp*mm_eta_g(mm_btemp(i))) 732 731 cslf = mm_akn * mm_lambda_g(mm_btemp(i),mm_plev(i)) 733 wth(i) = - csto/(rb2ra*afun(k)) * (rc(i-1)**ar1 * afun(af1) + cslf/rb2ra * rc(i-1)**ar2 * afun(af2)) 732 wth(i) = - csto/(rb2ra*afun(k)) * (rc(i-1)**ar1 * afun(af1) + cslf/rb2ra * rc(i-1)**ar2 * afun(af2)) 733 734 ! >>> [TEMPO : BBT] 735 !wth(i) = wth(i) * (2574e3 / (2574e3+mm_zlev(i)))**4 736 ! <<< [TEMPO : BBT] 737 734 738 ! now correct velocity to reduce numerical diffusion 735 739 IF (.NOT.mm_no_fiadero_w) THEN 736 740 IF (mk(i) <= 0._mm_wp) THEN 737 ratio = mm_fiadero_max 741 ratio = mm_fiadero_max 738 742 ELSE 739 ratio = MAX(MIN(mk(i-1)/mk(i),mm_fiadero_max),mm_fiadero_min) 743 ratio = MAX(MIN(mk(i-1)/mk(i),mm_fiadero_max),mm_fiadero_min) 740 744 ENDIF 741 745 ! apply correction … … 760 764 SUBROUTINE mm_haze_production(dm0s,dm3s) 761 765 !! Compute the production of aerosols moments. 762 !! 763 !! The method computes the tendencies of M0 and M3 for the spherical mode through production process. 764 !! Production values are distributed along a normal law in altitude, centered at 766 !! 767 !! The method computes the tendencies of M0 and M3 for the spherical mode through production process. 768 !! Production values are distributed along a normal law in altitude, centered at 765 769 !! [[mm_globals(module):mm_p_prod(variable)]] pressure level with a fixed sigma of 20km. 766 770 !! 767 !! First M3 tendency is computed and M0 is retrieved using the inter-moments relation a spherical 771 !! First M3 tendency is computed and M0 is retrieved using the inter-moments relation a spherical 768 772 !! characteristic radius set to [[mm_globals(module):mm_rc_prod(variable)]]. 769 773 !! … … 773 777 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3s !! Tendency of M3 (\(m^{3}.m^{-3}\)). 774 778 INTEGER :: i 775 REAL(kind=mm_wp) :: zprod,cprod,timefact 779 REAL(kind=mm_wp) :: zprod,cprod,timefact 776 780 REAL(kind=mm_wp), PARAMETER :: sigz = 20e3_mm_wp, & 777 781 fnorm = 1._mm_wp/(dsqrt(2._mm_wp*mm_pi)*sigz), & … … 793 797 dm3s(:)= mm_tx_prod *0.75_mm_wp/mm_pi *mm_dt / mm_rhoaer / 2._mm_wp / mm_dzlev(1:mm_nla) * & 794 798 (erf((mm_zlev(1:mm_nla)-zprod)/znorm) - & 795 erf((mm_zlev(2:mm_nla+1)-zprod)/znorm)) 799 erf((mm_zlev(2:mm_nla+1)-zprod)/znorm)) 796 800 dm0s(:) = dm3s(:)/(mm_rc_prod**3*mm_alpha_s(3._mm_wp)) 797 801 … … 803 807 ENDIF 804 808 805 806 809 END SUBROUTINE mm_haze_production 807 810 -
trunk/LMDZ.TITAN/libf/muphytitan/mm_interfaces.f90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Interfaces module for external functions 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 39 39 MODULE MM_INTERFACES 40 40 !! Interfaces to external functions. 41 !!42 !! The module contains the definitions of all "external" functions used by moments model which are43 !! left to the developer's responsibility.44 41 !! 45 !! # Functions 42 !! The module contains the definitions of all "external" functions used by moments model which are 43 !! left to the developer's responsibility. 46 44 !! 47 !! - [[mm_interfaces(module):mm_alpha_s(interface)]] should compute the inter-moments relation coefficient 45 !! # Functions 46 !! 47 !! - [[mm_interfaces(module):mm_alpha_s(interface)]] should compute the inter-moments relation coefficient 48 48 !! as a function of the moment's order for the spherical mode. 49 !! - [[mm_interfaces(module):mm_alpha_f(interface)]] should perform the same computations as 49 !! - [[mm_interfaces(module):mm_alpha_f(interface)]] should perform the same computations as 50 50 !! [[mm_interfaces(module):mm_alpha_s(interface)]] but for the fractal mode. 51 !! - [[mm_interfaces(module):mm_ps2s(interface)]] should compute the probability for particles of the 51 !! - [[mm_interfaces(module):mm_ps2s(interface)]] should compute the probability for particles of the 52 52 !! spherical mode to remain in that mode during coagulation process. 53 !! - [[mm_interfaces(module):mm_qmean(interface)]] should compute the mean eletric charge correction to be 53 !! - [[mm_interfaces(module):mm_qmean(interface)]] should compute the mean eletric charge correction to be 54 54 !! applied on each coagulation sub-kernels computed in mm_haze module. 55 55 !! - [[mm_interfaces(module):mm_get_btk(interface)]] should compute the \(b_{k}^{T}\) coefficient of the … … 60 60 PUBLIC 61 61 62 INTERFACE 62 INTERFACE 63 63 64 64 PURE FUNCTION mm_alpha_s(k) RESULT (res) … … 70 70 REAL(kind=mm_wp), INTENT(in) :: k !! Order of the moment. 71 71 REAL(kind=mm_wp) :: res !! Alpha value. 72 END FUNCTION mm_alpha_s 72 END FUNCTION mm_alpha_s 73 73 74 74 PURE FUNCTION mm_alpha_f(k) RESULT (res) … … 99 99 !! kernel as a function of the temperature, pressure and the characteristic radius of 100 100 !! the mode involved in the coagulation. 101 !! 101 !! 102 102 !! Modes are referred by a two letters uppercase string with the combination of: 103 103 !! 104 104 !! - S : spherical mode 105 105 !! - F : fractal mode 106 !! 106 !! 107 107 !! For example, SS means intra-modal coagulation for spherical particles. 108 108 IMPORT mm_wp … … 118 118 PURE FUNCTION mm_get_btk(t,k) RESULT(res) 119 119 !! Get the \(b_{k}^{T}\) coefficient of the Free Molecular regime. 120 !! 120 !! 121 121 !! The method computes and returns the value of the pre-factor \(b_{k}^{T}\) used to 122 122 !! approximate free-molecular regime coagulation kernels. 123 !! @note 124 !! For more details about \(b_{k}^{T}\) coefficient, please read the 123 !! @note 124 !! For more details about \(b_{k}^{T}\) coefficient, please read the 125 125 !! [scientific documentation](page/haze.html#free-molecular). 126 126 !! -
trunk/LMDZ.TITAN/libf/muphytitan/mm_lib.f90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: MP2M library interface module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 39 39 MODULE MM_LIB 40 40 !! MP2M library interface module. 41 41 !! 42 !! This module is only intended to get a overall acces to all library module. It contains no 42 !! This module is only intended to get a overall acces to all library module. It contains no 43 43 !! definitions and just __uses__ all others modules of the library. 44 44 USE MM_MPREC -
trunk/LMDZ.TITAN/libf/muphytitan/mm_methods.f90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne2 ! Contributor : J. Burgalat(GSMA, URCA)1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 ! Contributors: J. Burgalat (GSMA, URCA), B. de Batz de Trenquelléon (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Model miscellaneous methods module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 !! corrections: B. de Batz de Trenquelléon (2023) 38 39 39 40 MODULE MM_METHODS … … 43 44 !! 44 45 !! All thermodynamic functions related to cloud microphysics (i.e. [[mm_methods(module):mm_lHeatX(interface)]], 45 !! [[mm_methods(module):mm_sigX(interface)]] and [[mm_methods(module):mm_psatX(interface)]]) compute related equations 46 !! [[mm_methods(module):mm_sigX(interface)]] and [[mm_methods(module):mm_psatX(interface)]]) compute related equations 46 47 !! from \cite{reid1986}. A version of the book is freely available [here](http://f3.tiera.ru/3/Chemistry/References/Poling%20B.E.,%20Prausnitz%20J.M.,%20O'Connell%20J.P.%20The%20Properties%20of%20Gases%20and%20Liquids%20(5ed.,%20MGH,%202000)(ISBN%200070116822)(803s).pdf). 47 48 !! 48 49 !! The module defines the following functions/subroutines/interfaces: 49 50 !! 50 !! | name | description 51 !! | name | description 51 52 !! | :---------: | :------------------------------------------------------------------------------------- 52 53 !! | mm_lheatx | Compute latent heat released … … 64 65 IMPLICIT NONE 65 66 66 PRIVATE 67 68 PUBLIC :: mm_sigX, mm_LheatX, mm_psatX, mm_qsatx, mm_ fshape, &69 67 PRIVATE 68 69 PUBLIC :: mm_sigX, mm_LheatX, mm_psatX, mm_qsatx, mm_ysatX, mm_fshape, & 70 mm_get_kco, mm_get_kfm, mm_eta_g, mm_lambda_g 70 71 71 72 ! ---- INTERFACES … … 78 79 !! FUNCTION mm_sigX(temp,xESP) 79 80 !! ``` 80 !! 81 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 81 !! 82 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 82 83 !! computes the result for all the temperatures and returns a vector of same size than __temp__. 83 84 INTERFACE mm_sigX 84 85 MODULE PROCEDURE sigx_sc,sigx_ve 85 END INTERFACE 86 END INTERFACE mm_sigX 86 87 87 88 !> Interface to Latent heat computation functions. 88 !! 89 !! 89 90 !! The method computes the latent heat released of a given specie at given temperature(s). 90 91 !! … … 93 94 !! ``` 94 95 !! 95 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 96 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 96 97 !! computes the result for all the temperatures and returns a vector of same size than __temp__. 97 98 INTERFACE mm_LheatX 98 99 MODULE PROCEDURE lheatx_sc,lheatx_ve 99 END INTERFACE 100 END INTERFACE mm_LheatX 100 101 101 102 !> Interface to saturation vapor pressure computation functions. … … 104 105 !! FUNCTION mm_psatX(temp,xESP) 105 106 !! ``` 106 !! 107 !! 107 108 !! The method computes the saturation vapor pressure of a given specie at given temperature(s). 108 109 !! 109 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 110 !! __xESP__ must always be given as a scalar. If __temp__ is given as a vector, then the method 110 111 !! computes the result for all the temperatures and returns a vector of same size than __temp__. 111 112 INTERFACE mm_psatX 112 113 MODULE PROCEDURE psatx_sc,psatx_ve 113 END INTERFACE 114 115 ! ! Interface to saturation mass mixing ratio computaiton functions.116 !! 117 !! The method computes the mass mixing ratio at saturation of a given specie at given temperature(s) 114 END INTERFACE mm_psatX 115 116 !> Interface to saturation mass mixing ratio computation functions. 117 !! 118 !! The method computes the mass mixing ratio at saturation of a given specie at given temperature(s) 118 119 !! and pressure level(s). 119 120 !! 120 121 !! ```fortran 121 !! FUNCTION mm_qsatX(temp,pres,xESP) 122 !! ``` 123 !! 124 !! __xESP__ must always be given as a scalar. If __temp__ and __pres__ are given as a vector (of same 122 !! FUNCTION mm_qsatX(temp,pres,xESP) 123 !! ``` 124 !! 125 !! __xESP__ must always be given as a scalar. If __temp__ and __pres__ are given as a vector (of same 125 126 !! size !), then the method computes the result for each couple of (temperature, pressure) and returns 126 127 !! a vector of same size than __temp__. 127 128 INTERFACE mm_qsatx 128 129 MODULE PROCEDURE qsatx_sc,qsatx_ve 129 END INTERFACE 130 END INTERFACE mm_qsatx 131 132 !> Interface to saturation molar mixing ratio computation functions. 133 !! 134 !! The method computes the molar mixing ratio at saturation of a given specie at given temperature(s) 135 !! and pressure level(s) [Fray and Schmidt (2009)]. 136 !! 137 !! ```fortran 138 !! FUNCTION mm_ysatX(temp,pres,xESP) 139 !! ``` 140 !! 141 !! __xESP__ must always be given as a scalar. If __temp__ and __pres__ are given as a vector (of same 142 !! size !), then the method computes the result for each couple of (temperature, pressure) and returns 143 !! a vector of same size than __temp__. 144 INTERFACE mm_ysatX 145 MODULE PROCEDURE ysatX_sc,ysatX_ve 146 END INTERFACE mm_ysatX 130 147 131 148 !> Interface to shape factor computation functions. … … 137 154 !! ``` 138 155 !! 139 !! Where __m__ is cosine of the contact angle and __x__ the curvature radius. __m__ must always be 140 !! given as a scalar. If __x__ is given as a vector, then the method compute the result for each 156 !! Where __m__ is cosine of the contact angle and __x__ the curvature radius. __m__ must always be 157 !! given as a scalar. If __x__ is given as a vector, then the method compute the result for each 141 158 !! value of __x__ and and returns a vector of same size than __x__. 142 159 INTERFACE mm_fshape 143 160 MODULE PROCEDURE fshape_sc,fshape_ve 144 END INTERFACE 145 146 161 END INTERFACE mm_fshape 162 163 CONTAINS 147 164 148 165 FUNCTION fshape_sc(cost,rap) RESULT(res) 149 166 !! Get the shape factor of a ccn (scalar). 150 167 !! 151 !! The method computes the shape factor for the heterogeneous nucleation on a fractal particle. 168 !! The method computes the shape factor for the heterogeneous nucleation on a fractal particle. 152 169 !! Details about the shape factor can be found in \cite{prup1978}. 153 170 REAL(kind=mm_wp), INTENT(in) :: cost !! Cosine of the contact angle. … … 160 177 phi = dsqrt(1._mm_wp-2._mm_wp*cost*rap+rap**2) 161 178 a = 1._mm_wp + ( (1._mm_wp-cost*rap)/phi )**3 162 b = (rap**3) * (2._mm_wp -3._mm_wp*(rap-cost)/phi+((rap-cost)/phi)**3)179 b = (rap**3) * (2._mm_wp - 3._mm_wp*(rap-cost)/phi + ((rap-cost)/phi)**3) 163 180 c = 3._mm_wp * cost * (rap**2) * ((rap-cost)/phi-1._mm_wp) 164 181 res = 0.5_mm_wp*(a+b+c) … … 177 194 WHERE(rap > 3000._mm_wp) 178 195 res = ((2._mm_wp+cost)*(1._mm_wp-cost)**2)/4._mm_wp 179 ELSEWHERE 196 ELSEWHERE 180 197 phi = dsqrt(1._mm_wp-2._mm_wp*cost*rap+rap**2) 181 198 a = 1._mm_wp + ((1._mm_wp-cost*rap)/phi )**3 … … 192 209 !! The method computes the latent heat equation as given in \cite{reid1986} p. 220 (eq. 7-9.4). 193 210 IMPLICIT NONE 194 ! - DUMMY 211 ! - DUMMY 195 212 REAL(kind=mm_wp), INTENT(in) :: temp !! temperature (K). 196 213 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 197 214 REAL(kind=mm_wp) :: res !! Latent heat of given specie at given temperature (\(J.kg^{-1}\)). 198 215 REAL(kind=mm_wp) :: ftm 199 ftm=M IN(1._mm_wp-temp/xESP%tc,1.e-3_mm_wp)216 ftm=MAX(1._mm_wp-temp/xESP%tc,1.e-3_mm_wp) 200 217 res = mm_rgas*xESP%tc*(7.08_mm_wp*ftm**0.354_mm_wp+10.95_mm_wp*xESP%w*ftm**0.456_mm_wp)/xESP%masmol 201 218 END FUNCTION LHeatX_sc 202 219 203 220 FUNCTION LHeatX_ve(temp,xESP) RESULT(res) 204 221 !! Compute latent heat of a given specie at given temperature (vector). … … 208 225 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 209 226 REAL(kind=mm_wp), DIMENSION(SIZE(temp)) :: res !! Latent heat of given specie at given temperatures (\(J.kg^{-1}\)). 210 REAL(kind=mm_wp) :: ftm 227 REAL(kind=mm_wp) :: ftm 211 228 INTEGER :: i 212 229 DO i=1,SIZE(temp) 213 ftm=M IN(1._mm_wp-temp(i)/xESP%tc,1.e-3_mm_wp)230 ftm=MAX(1._mm_wp-temp(i)/xESP%tc,1.e-3_mm_wp) 214 231 res(i) = mm_rgas*xESP%tc*(7.08_mm_wp*ftm**0.354_mm_wp+10.95_mm_wp*xESP%w*ftm**0.456_mm_wp) / & 215 xESP%masmol232 xESP%masmol 216 233 ENDDO 217 234 END FUNCTION LHeatX_ve … … 219 236 FUNCTION sigX_sc(temp,xESP) RESULT(res) 220 237 !! Get the surface tension between a given specie and the air (scalar). 221 !! 238 !! 222 239 !! The method computes the surface tension equation as given in \cite{reid1986} p. 637 (eq. 12-3.6). 223 240 REAL(kind=mm_wp), INTENT(in) :: temp !! temperature (K). … … 229 246 sig = 0.1196_mm_wp*(1._mm_wp+(tbr*dlog(xESP%pc/1.01325_mm_wp))/(1._mm_wp-tbr))-0.279_mm_wp 230 247 sig = xESP%pc**(2._mm_wp/3._mm_wp)*xESP%tc**(1._mm_wp/3._mm_wp)*sig*(1._mm_wp-tr)**(11._mm_wp/9._mm_wp) 231 res = sig*1e 3_mm_wp ! dyn/cm2-> N/m248 res = sig*1e-3_mm_wp ! dyn/cm -> N/m 232 249 END FUNCTION sigX_sc 233 250 234 251 FUNCTION sigX_ve(temp,xESP) RESULT(res) 235 252 !! Get the surface tension between a given specie and the air (vector). … … 240 257 REAL(kind=mm_wp), DIMENSION(SIZE(temp)) :: res !! Surface tensions (\(N.m^{-1}\)). 241 258 INTEGER :: i 242 REAL(kind=mm_wp) :: tr,tbr,sig 259 REAL(kind=mm_wp) :: tr,tbr,sig0,sig 243 260 tbr = xESP%tb/xESP%tc 244 sig = 0.1196_mm_wp*(1._mm_wp+(tbr*dlog(xESP%pc/1.01325_mm_wp))/(1._mm_wp-tbr))-0.279_mm_wp261 sig0 = 0.1196_mm_wp*(1._mm_wp+(tbr*dlog(xESP%pc/1.01325_mm_wp))/(1._mm_wp-tbr))-0.279_mm_wp 245 262 DO i=1,SIZE(temp) 246 263 tr = MIN(temp(i)/xESP%tc,0.99_mm_wp) 247 sig = xESP%pc**(2._mm_wp/3._mm_wp)*xESP%tc**(1._mm_wp/3._mm_wp)*sig *(1._mm_wp-tr)**(11._mm_wp/9._mm_wp)248 res(i) = sig*1e 3_mm_wp ! dyn/cm2-> N/m264 sig = xESP%pc**(2._mm_wp/3._mm_wp)*xESP%tc**(1._mm_wp/3._mm_wp)*sig0*(1._mm_wp-tr)**(11._mm_wp/9._mm_wp) 265 res(i) = sig*1e-3_mm_wp ! dyn/cm -> N/m 249 266 ENDDO 250 267 END FUNCTION sigX_ve … … 252 269 FUNCTION psatX_sc(temp,xESP) RESULT(res) 253 270 !! Get saturation vapor pressure for a given specie at given temperature (scalar). 254 !! 271 !! 255 272 !! The method computes the saturation vapor pressure equation given in \cite{reid1986} p. 657 (eq. 1). 256 !!257 !! @warning258 !! This subroutine accounts for a specific Titan feature:259 !! If __xESP__ corresponds to \(CH_{4}\), the saturation vapor presure is multiplied by 0.85260 !! to take into account its dissolution in \(N_{2}\).261 273 REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K). 262 274 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. … … 266 278 IF (x > 0._mm_wp) THEN 267 279 qsat = (1._mm_wp-x)**(-1) * & 268 (xESP%a_sat*x + xESP%b_sat*x**1.5_mm_wp + xESP%c_sat*x**3 + xESP%d_sat*x**6)280 (xESP%a_sat*x + xESP%b_sat*x**1.5_mm_wp + xESP%c_sat*x**2.5_mm_wp + xESP%d_sat*x**5_mm_wp) 269 281 ELSE 270 qsat = XESP%a_sat*x/abs(1._mm_wp-x) ! approx for t > tc 271 ENDIF 272 ! Special case : ch4 : x0.85 (dissolution in N2) 273 IF (xESP%name == "ch4") THEN 274 res = xESP%pc*dexp(qsat)*0.85_mm_wp 275 ELSE 276 res = xESP%pc*dexp(qsat) 277 ENDIF 282 qsat = XESP%a_sat*x/abs(1._mm_wp-x) ! approx for t > tc 283 ENDIF 284 res = xESP%pc*exp(qsat) 278 285 ! now convert bar to Pa 279 286 res = res * 1e5_mm_wp … … 282 289 FUNCTION psatX_ve(temp,xESP) RESULT(res) 283 290 !! Get saturation vapor pressure for a given specie at given temperature (vector). 284 !! 291 !! 285 292 !! See [[mm_methods(module):psatX_sc(function)]]. 286 293 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperatures (K). … … 292 299 x = 1._mm_wp-temp(i)/xESP%tc 293 300 IF (x > 0._mm_wp) THEN 294 qsat = (1._mm_wp-x)**(-1) * & 295 (xESP%a_sat*x + xESP%b_sat*x**1.5_mm_wp + xESP%c_sat*x**3 + xESP%d_sat*x**6)301 qsat = (1._mm_wp-x)**(-1) * & 302 (xESP%a_sat*x + xESP%b_sat*x**1.5_mm_wp + xESP%c_sat*x**2.5_mm_wp + xESP%d_sat*x**5_mm_wp) 296 303 ELSE 297 qsat = XESP%a_sat*x/abs(1._mm_wp-x) ! approx fort > tc304 qsat = XESP%a_sat*x/abs(1._mm_wp-x) ! approx for t > tc 298 305 ENDIF 299 res(i) = xESP%pc*dexp(qsat) 300 ! Peculiar case : ch4 : x0.85 (dissolution in N2) 301 IF (xESP%name == "ch4") res(i) = res(i)* 0.85_mm_wp 306 res(i) = xESP%pc*exp(qsat) 302 307 ENDDO 303 res = res * 1e5_mm_wp ! bar -> Pa 308 ! now convert bar to Pa 309 res = res * 1e5_mm_wp 304 310 END FUNCTION psatX_ve 305 311 306 312 FUNCTION qsatX_sc(temp,pres,xESP) RESULT(res) 307 313 !! Get the mass mixing ratio of a given specie at saturation (scalar). 314 !! 315 !! @warning 316 !! The method applies a multiplicative factor of 0.85 if the specie is CH4 : 317 !! this is done to account for dissolution in N2 and is somehow specific to Titan atmosphere. 308 318 REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K). 309 319 REAL(kind=mm_wp), INTENT(in) :: pres !! Pressure level (Pa). 310 320 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 311 321 REAL(kind=mm_wp) :: res !! Mass mixing ratio of the specie. 312 REAL(kind=mm_wp) :: x,psat322 REAL(kind=mm_wp) :: psat 313 323 psat = mm_psatX(temp,xESP) 314 324 res = (psat / pres) * xESP%fmol2fmas 325 ! Peculiar case : CH4 : x0.85 (dissolution in N2) 326 IF (xESP%name == "CH4") THEN 327 res = res * 0.85_mm_wp 328 IF (mm_debug) WRITE(*,'(a)') "[DEBUG] mm_qsat: applying .85 factor to qsat for CH4 specie (N2 dissolution)" 329 ENDIF 315 330 END FUNCTION qsatX_sc 316 331 317 332 FUNCTION qsatX_ve(temp,pres,xESP) RESULT(res) 318 333 !! Get the mass mixing ratio of a given specie at saturation (vector). 334 !! 335 !! @warning 336 !! The method applies a multiplicative factor of 0.85 if the specie is CH4 : 337 !! this is done to account for dissolution in N2 and is somehow specific to Titan atmosphere. 319 338 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperatures (K). 320 339 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pres !! Pressure levels (Pa). … … 324 343 psat = mm_psatX(temp,xESP) 325 344 res = (psat / pres) * xESP%fmol2fmas 345 ! Peculiar case : CH4 : x0.85 (dissolution in N2) 346 IF (xESP%name == "CH4") THEN 347 res = res * 0.85_mm_wp 348 IF (mm_debug) WRITE(*,'(a)') "[DEBUG] mm_qsat: applying .85 factor to qsat for CH4 specie (N2 dissolution)" 349 ENDIF 326 350 END FUNCTION qsatX_ve 351 352 FUNCTION ysatX_sc(temp,pres,xESP) RESULT(res) 353 !! Get the molar mixing ratio of a given specie at saturation (scalar). 354 !! 355 !! @warning 356 !! The method applies a multiplicative factor of 0.85 if the specie is CH4 : 357 !! this is done to account for dissolution in N2 and is somehow specific to Titan atmosphere. 358 REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K). 359 REAL(kind=mm_wp), INTENT(in) :: pres !! Pressure level (Pa). 360 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 361 REAL(kind=mm_wp) :: res !! Molar mixing ratio of the specie. 362 363 ! Fray and Schmidt (2009) 364 IF(xESP%name == "C2H2") THEN 365 res = (1.0e5 / pres) * exp(1.340e1 - 2.536e3/temp) 366 367 ELSE IF(xESP%name == "C2H6") THEN 368 res = (1.0e5 / pres) * exp(1.511e1 - 2.207e3/temp - 2.411e4/temp**2 + 7.744e5/temp**3 - 1.161e7/temp**4 + 6.763e7/temp**5) 369 370 ELSE IF(xESP%name == "HCN") THEN 371 res = (1.0e5 / pres) * exp(1.393e1 - 3.624e3/temp - 1.325e5/temp**2 + 6.314e6/temp**3 - 1.128e8/temp**4) 372 373 ELSE IF (xESP%name == "CH4") THEN 374 res = (1.0e5 / pres) * exp(1.051e1 - 1.110e3/temp - 4.341e3/temp**2 + 1.035e5/temp**3 - 7.910e5/temp**4) 375 res = res * 0.85_mm_wp 376 !IF (res < 0.014) THEN 377 ! res = 0.014 378 !ENDIF 379 ENDIF 380 END FUNCTION ysatX_sc 381 382 FUNCTION ysatX_ve(temp,pres,xESP) RESULT(res) 383 !! Get the molar mixing ratio of a given specie at saturation (vector). 384 !! 385 !! @warning 386 !! The method applies a multiplicative factor of 0.85 if the specie is CH4 : 387 !! this is done to account for dissolution in N2 and is somehow specific to Titan atmosphere. 388 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperatures (K). 389 REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pres !! Pressure levels (Pa). 390 TYPE(mm_esp), INTENT(in) :: xESP !! Specie properties. 391 REAL(kind=mm_wp), DIMENSION(SIZE(temp)) :: res !! Molar mixing ratios of the specie. 392 393 ! Fray and Schmidt (2009) 394 IF(xESP%name == "C2H2") THEN 395 res = (1.0e5 / pres) * exp(1.340e1 - 2.536e3/temp) 396 397 ELSE IF(xESP%name == "C2H6") THEN 398 res = (1.0e5 / pres) * exp(1.511e1 - 2.207e3/temp - 2.411e4/temp**2 + 7.744e5/temp**3 - 1.161e7/temp**4 + 6.763e7/temp**5) 399 400 ELSE IF(xESP%name == "HCN") THEN 401 res = (1.0e5 / pres) * exp(1.393e1 - 3.624e3/temp - 1.325e5/temp**2 + 6.314e6/temp**3 - 1.128e8/temp**4) 402 403 ! Peculiar case : CH4 : x0.85 (dissolution in N2) 404 ELSE IF (xESP%name == "CH4") THEN 405 res = (1.0e5 / pres) * exp(1.051e1 - 1.110e3/temp - 4.341e3/temp**2 + 1.035e5/temp**3 - 7.910e5/temp**4) 406 res = res * 0.85_mm_wp 407 !WHERE (res(:) < 0.014) res(:) = 0.014 408 ENDIF 409 END FUNCTION ysatX_ve 327 410 328 411 ELEMENTAL FUNCTION mm_get_kco(t) RESULT(res) -
trunk/LMDZ.TITAN/libf/muphytitan/mm_microphysic.f90
r2109 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! brief: Microphysic processes interface module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 39 39 MODULE MM_MICROPHYSIC … … 51 51 52 52 !! Interface to main microphysics subroutine. 53 !! 54 !! The interface computes calls either all the microphysics processes ([[mm_microphysic(module):muphys_all(function)]] 53 !! 54 !! The interface computes calls either all the microphysics processes ([[mm_microphysic(module):muphys_all(function)]] 55 55 !! or only aerosols microphysics ([[mm_microphysic(module):muphys_nocld(function)]]) in a single call. 56 56 INTERFACE mm_muphys 57 57 MODULE PROCEDURE muphys_all, muphys_nocld 58 END INTERFACE 59 60 61 62 63 58 END INTERFACE mm_muphys 59 60 CONTAINS 61 62 63 64 64 FUNCTION muphys_all(dm0a_s,dm3a_s,dm0a_f,dm3a_f,dm0n,dm3n,dm3i,dgazs) RESULT(ret) 65 65 !! Compute the evolution of moments tracers through haze and clouds microphysics processes. 66 !! 67 !! This method computes the evolution of all the microphysics tracers, given under the form of moments 66 !! 67 !! This method computes the evolution of all the microphysics tracers, given under the form of moments 68 68 !! (and molar fraction for cloud condensible species) during a time step. 69 !! 70 !! The method requires that global variables of the model (i.e. variables declared in [[mm_globals(module)]] 69 !! 70 !! The method requires that global variables of the model (i.e. variables declared in [[mm_globals(module)]] 71 71 !! module) are initialized/updated correctly (see [[mm_globals(module):mm_global_init(interface)]], 72 72 !! [[mm_globals(module):mm_column_init(function)]],[[mm_globals(module):mm_aerosols_init(function)]] and 73 73 !! [[mm_globals(module):mm_clouds_init(function)]]). 74 !! 75 !! The tendencies returned by the method are defined on the vertical __layers__ of the model from the __GROUND__ to 76 !! the __TOP__ of the atmosphere. They should be added to the input variables used in the initialization methods 74 !! 75 !! The tendencies returned by the method are defined on the vertical __layers__ of the model from the __GROUND__ to 76 !! the __TOP__ of the atmosphere. They should be added to the input variables used in the initialization methods 77 77 !! before the latter are called to initialize a new step. 78 78 !! @note 79 79 !! __dm3i__ and __dgazs__ are 2D-arrays with vertical __layers__ in the 1st dimension and the number of 80 !! ice components in the 2nd. They share the same _species_ indexing. 80 !! ice components in the 2nd. They share the same _species_ indexing. 81 81 !! 82 82 !! It should be a 2D-array with the vertical layers in first dimension and the number of ice components in the second. 83 83 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_s 84 84 !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)). 85 85 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_s 86 !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-2}\)).86 !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-2}\)). 87 87 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_f 88 88 !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)). 89 89 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_f 90 90 !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)). 91 91 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0n 92 92 !! Tendency of the 0th order moment of the _CCN_ distribution (\(m^{-2}\)). 93 93 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3n 94 94 !! Tendency of the 3rd order moment of the _CCN_ distribution (\(m^{3}.m^{-2}\)). 95 95 REAL(kind=mm_wp), INTENT(out), DIMENSION(:,:) :: dm3i 96 !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-2}\)).96 !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-2}\)). 97 97 REAL(kind=mm_wp), INTENT(out), DIMENSION(:,:) :: dgazs 98 !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)).98 !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)). 99 99 LOGICAL :: ret 100 !! .true. on success (i.e. model has been initialized at least once previously), .false. otherwise.100 !! .true. on success (i.e. model has been initialized at least once previously), .false. otherwise. 101 101 REAL(kind=mm_wp), DIMENSION(SIZE(dm0a_s)) :: zdm0a_f,zdm3a_f 102 102 INTEGER :: i … … 111 111 ! add temporary aerosols tendencies (-> m-3) 112 112 dm0a_f = dm0a_f + zdm0a_f ; dm3a_f = dm3a_f + zdm3a_f 113 ! reverse clouds tendencies (-> m-2)113 ! reverse directly clouds tendencies (-> m-2) 114 114 dm0n = dm0n(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 115 115 dm3n = dm3n(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 116 ! sanity check for clouds tendencies : call mm_check_tendencies(mm_m0ccn,dm0n) 117 ! sanity check for clouds tendencies : call mm_check_tendencies(mm_m3ccn,dm3n) 116 118 DO i=1,mm_nesp 117 dm3i(:,i) = dm3i(mm_nla:1:-1,i) * mm_dzlev(mm_nla:1:-1) 118 dgazs(:,i) = dgazs(mm_nla:1:-1,i) 119 dm3i(:,i) = dm3i(mm_nla:1:-1,i) * mm_dzlev(mm_nla:1:-1) 120 ! sanity check for clouds tendencies : call mm_check_tendencies(mm_m3ice,dm3i) 121 dgazs(:,i) = dgazs(mm_nla:1:-1,i) 122 ! no sanity check for gazs, let's prey. 119 123 ENDDO 120 124 ELSE … … 126 130 dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 127 131 dm3a_f = dm3a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 128 132 ! sanity check 133 ! sanity check : call mm_check_tendencies(mm_m0aer_s,dm0a_s) 134 ! sanity check : call mm_check_tendencies(mm_m3aer_s,dm3a_s) 135 ! sanity check : call mm_check_tendencies(mm_m0aer_f,dm0a_f) 136 ! sanity check : call mm_check_tendencies(mm_m3aer_f,dm3a_f) 129 137 RETURN 130 138 END FUNCTION muphys_all … … 132 140 FUNCTION muphys_nocld(dm0a_s,dm3a_s,dm0a_f,dm3a_f) RESULT(ret) 133 141 !! Compute the evolution of moments tracers through haze microphysics only. 134 !! 135 !! This method is a __light__ version of [[mm_microphysic(module):muphys_all(function)]] where 142 !! 143 !! This method is a __light__ version of [[mm_microphysic(module):muphys_all(function)]] where 136 144 !! only haze microphysics is computed and its tendencies returned. 137 145 !! 138 !! The method has the same requirements and remarks than [[mm_microphysic(module):muphys_all(function)]]. 146 !! The method has the same requirements and remarks than [[mm_microphysic(module):muphys_all(function)]]. 139 147 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_s 140 148 !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)). 141 149 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_s 142 !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-2}\)).150 !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-2}\)). 143 151 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_f 144 152 !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)). 145 153 REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_f 146 154 !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)). 147 155 LOGICAL :: ret 148 !! .true. on succes (i.e. model has been initialized at least once previously), .false. otherwise.156 !! .true. on succes (i.e. model has been initialized at least once previously), .false. otherwise. 149 157 ret = (mm_ini_col.AND.mm_ini_aer) 150 158 IF (.NOT.ret) RETURN 151 159 IF (mm_w_clouds.AND.mm_debug) THEN 152 160 WRITE(*,'(a)') "WARNING: clouds microphysics enabled but will not be & 153 161 &computed... (wrong interface)" 154 162 ENDIF 155 163 ! Calls haze microphysics 156 164 call mm_haze_microphysics(dm0a_s,dm3a_s,dm0a_f,dm3a_f) 157 165 ! reverse vectors so they go from ground to top :) 158 dm0a_s = dm0a_s(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 166 dm0a_s = dm0a_s(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 159 167 dm3a_s = dm3a_s(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 160 dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 168 dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 161 169 dm3a_f = dm3a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1) 170 ! sanity check 171 ! sanity check : call mm_check_tendencies(mm_m0aer_s,dm0a_s) 172 ! sanity check : call mm_check_tendencies(mm_m3aer_s,dm3a_s) 173 ! sanity check : call mm_check_tendencies(mm_m0aer_f,dm0a_f) 174 ! sanity check : call mm_check_tendencies(mm_m3aer_f,dm3a_f) 162 175 RETURN 163 176 END FUNCTION muphys_nocld 164 177 165 SUBROUTINE mm_diagnostics(aer_prec,aer_s_flux,aer_f_flux, & 166 ccn_prec,ccn_flux, ice_prec,ice_fluxes, & 167 gazs_sat) 178 SUBROUTINE mm_diagnostics(aer_prec,aer_s_w,aer_f_w,aer_s_flux,aer_f_flux,ccn_prec,ccn_w,ccn_flux,ice_prec,ice_fluxes,gazs_sat) 168 179 !! Get various diagnostic fields of the microphysics. 169 180 !! … … 171 182 !! 172 183 !! - Mass fluxes (aerosols -both mode-, CCN and ices) 184 !! - Settling velocity (aerosols -total-, CCN and ices) 173 185 !! - Precipitations (aerosols -total-, CCN and ices) 174 186 !! - condensible gazes saturation ratio 175 187 !! 176 !! @note 177 !! Fluxes values are always negative as they account for sedimentation fluxes. They are set as 188 !! @note 189 !! Fluxes values are always negative as they account for sedimentation fluxes. They are set as 178 190 !! vector (for aerosols and CCN) or 2D-array (with the vertical structure in the first dimension 179 191 !! and number of species in the second, for ice) and are ordered from __GROUND__ to __TOP__. 180 192 !! 181 193 !! @note 182 !! Precipitations are always positive and defined in meters. For ice, it is set as a vector with 194 !! Precipitations are always positive and defined in meters. For ice, it is set as a vector with 183 195 !! the precipitations of each cloud ice components. 184 196 !! 185 197 !! @note 186 !! __ccnprec__, __iceprec__, __icefluxes__ and __gazsat__ are always set to 0 if clouds 198 !! __ccnprec__, __iceprec__, __icefluxes__ and __gazsat__ are always set to 0 if clouds 187 199 !! microphysics is disabled (see [[mm_globals(module):mm_w_clouds(variable)]] documentation). 188 200 REAL(kind=mm_wp), INTENT(out), OPTIONAL :: aer_prec !! Aerosols precipitations (both modes) (m). 201 REAL(kind=mm_wp), INTENT(out), OPTIONAL :: ccn_prec !! CCN precipitations (m). 202 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: aer_s_w !! Spherical aerosol settling velocity (\(m.s^{-1}\)). 203 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: aer_f_w !! Fractal aerosol settling velocity (\(m.s^{-1}\)). 204 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: ccn_w !! CCN settling velocity (\(m.s^{-1}\)). 189 205 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: aer_s_flux !! Spherical aerosol mass flux (\(kg.m^{-2}.s^{-1}\)). 190 206 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: aer_f_flux !! Fractal aerosol mass flux (\(kg.m^{-2}.s^{-1}\)). 191 REAL(kind=mm_wp), INTENT(out), OPTIONAL :: ccn_prec !! CCN precipitations (m).192 207 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: ccn_flux !! CCN mass flux (\(kg.m^{-2}.s^{-1}\)). 193 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: ice_prec !! Ice precipitations (m).194 208 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:,:) :: ice_fluxes !! Ice sedimentation fluxes (\(kg.m^{-2}.s^{-1}\)). 195 209 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:,:) :: gazs_sat !! Condensible gaz saturation ratios (--). 196 197 IF (PRESENT(aer_prec)) aer_prec = ABS(mm_aer_prec) 210 REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:) :: ice_prec !! Ice precipitations (m). 211 212 IF (PRESENT(aer_prec)) aer_prec = ABS(mm_aer_prec) 213 IF (PRESENT(aer_s_w)) aer_s_w = -mm_m3as_vsed(mm_nla:1:-1) 214 IF (PRESENT(aer_f_w)) aer_f_w = -mm_m3af_vsed(mm_nla:1:-1) 198 215 IF (PRESENT(aer_s_flux)) aer_s_flux = -mm_aer_s_flux(mm_nla:1:-1) 199 216 IF (PRESENT(aer_f_flux)) aer_f_flux = -mm_aer_f_flux(mm_nla:1:-1) … … 202 219 IF (PRESENT(ccn_prec)) ccn_prec = ABS(mm_ccn_prec) 203 220 IF (PRESENT(ice_prec)) ice_prec = ABS(mm_ice_prec) 221 IF (PRESENT(ccn_w)) ccn_w = mm_ccn_w(mm_nla:1:-1) 204 222 IF (PRESENT(ccn_flux)) ccn_flux = -mm_ccn_flux(mm_nla:1:-1) 205 IF (PRESENT(ice_fluxes)) ice_fluxes = -mm_ice_fluxes(mm_nla:1:-1,:)223 IF (PRESENT(ice_fluxes)) ice_fluxes = mm_ice_fluxes(mm_nla:1:-1,:) 206 224 IF (PRESENT(gazs_sat)) gazs_sat = mm_gazs_sat(mm_nla:1:-1,:) 207 ELSE 225 ELSE 208 226 IF (PRESENT(ccn_prec)) ccn_prec = 0._mm_wp 209 227 IF (PRESENT(ice_prec)) ice_prec = 0._mm_wp 228 IF (PRESENT(ccn_w)) ccn_w = 0._mm_wp 210 229 IF (PRESENT(ccn_flux)) ccn_flux = 0._mm_wp 211 230 IF (PRESENT(ice_fluxes)) ice_fluxes = 0._mm_wp … … 216 235 SUBROUTINE mm_get_radii(rcsph,rcfra,rccld) 217 236 !! Get characteristic radii of microphysical tracers on the vertical grid. 218 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rcsph !! Spherical mode characteristic radius 219 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rcfra !! Fractal mode characteristic radius 237 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rcsph !! Spherical mode characteristic radius 238 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rcfra !! Fractal mode characteristic radius 220 239 REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rccld !! Cloud drops mean radius 221 240 IF (mm_ini_aer) THEN 222 IF (PRESENT(rcsph)) rcsph = mm_rcs(mm_nla:1:-1) 223 IF (PRESENT(rcfra)) rcfra = mm_rcf(mm_nla:1:-1) 241 IF (PRESENT(rcsph)) rcsph = mm_rcs(mm_nla:1:-1) 242 IF (PRESENT(rcfra)) rcfra = mm_rcf(mm_nla:1:-1) 224 243 ELSE 225 IF (PRESENT(rcsph)) rcsph = 0._mm_wp 226 IF (PRESENT(rcfra)) rcfra = 0._mm_wp 244 IF (PRESENT(rcsph)) rcsph = 0._mm_wp 245 IF (PRESENT(rcfra)) rcfra = 0._mm_wp 227 246 ENDIF 228 247 IF (PRESENT(rccld)) THEN -
trunk/LMDZ.TITAN/libf/muphytitan/mm_mprec.F90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 8 ! This library 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. … … 35 35 !! summary: Library floating point precision module. 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 39 39 #ifdef HAVE_CONFIG_H … … 42 42 43 43 #ifndef PREC 44 #define PREC 64 44 #define PREC 64 45 45 #elif (PREC != 32 && PREC != 64 && PREC != 80) 46 46 #undef PREC … … 52 52 !! 53 53 !! This module only defines a single variable [[mm_mprec(module):mm_wp(variable)]] which sets 54 !! the kind of floating point value used in all other part of the library (REAL(kind=mm_wp) 54 !! the kind of floating point value used in all other part of the library (REAL(kind=mm_wp) 55 55 !! declaration statement). 56 56 IMPLICIT NONE … … 58 58 #if (PREC == 32) 59 59 !> Size of floating point variables in the library (single). 60 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=6) ! 32 bits 60 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=6) ! 32 bits 61 CHARACTER(len=è), PUBLIC, PARAMETER :: mm_wp_s = "32 bits" 61 62 #elif (PREC == 64) 62 63 !> Size of floating point variables in the library (double). 63 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=15) ! 64 bits 64 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=15) ! 64 bits 65 CHARACTER(len=7), PUBLIC, PARAMETER :: mm_wp_s = "64 bits" 64 66 #elif (PREC == 80) 65 67 !> Size of floating point variables in the library (extended-double). 66 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=18) ! 80 bits 68 INTEGER, PUBLIC, PARAMETER :: mm_wp = SELECTED_REAL_KIND(p=18) ! 80 bits 69 CHARACTER(len=7), PUBLIC, PARAMETER :: mm_wp_s = "80 bits" 67 70 #endif 68 71 END MODULE MM_MPREC -
trunk/LMDZ.TITAN/libf/muphytitan/mmp_gcm.f90
r1926 r3083 1 ! Copyright 2017 Université de Reims Champagne-Ardenne 1 ! Copyright 2017 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 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, 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 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 license and that you accept its terms. … … 44 44 IMPLICIT NONE 45 45 46 CONTAINS 47 46 CONTAINS 47 48 48 SUBROUTINE mmp_initialize(dt,p_prod,tx_prod,rc_prod,rplanet,g0, air_rad,air_mmol,clouds,cfgpath) 49 49 !! Initialize global parameters of the model. 50 !! 50 !! 51 51 !! The function initializes all the global parameters of the model from direct input. 52 !! Boolean (and Fiadero) parameters are optional as they are rather testing parameters. Their 53 !! default values are suitable for production runs. 52 !! Boolean (and Fiadero) parameters are optional as they are rather testing parameters. Their 53 !! default values are suitable for production runs. 54 54 !! @note 55 55 !! If the subroutine fails to initialize parameters, the run is aborted. 56 56 !! 57 57 !! @warning 58 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 58 !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it 59 59 !! initializes global variable that are not thread private. 60 60 !! … … 87 87 88 88 INTEGER :: coag_choice 89 REAL(kind=mm_wp) :: fiad_max, 90 LOGICAL :: w_h_prod, w_h_sed, w_h_coag, w_c_sed,w_c_nucond, &91 no_fiadero, fwsed_m0,fwsed_m389 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 92 TYPE(error) :: err 93 93 INTEGER :: i … … 96 96 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species 97 97 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: tmp 98 REAL(kind=mm_wp) :: m0as_min,rcs_min,m0af_min,rcf_min,m0n_min 99 LOGICAL :: wdebug 98 100 99 101 w_h_prod = .true. … … 104 106 fwsed_m0 = .true. 105 107 fwsed_m3 = .false. 106 no_fiadero = . false.108 no_fiadero = .true. 107 109 fiad_min = 0.1_mm_wp 108 110 fiad_max = 10._mm_wp 109 111 coag_choice = 7 112 wdebug = .false. 113 m0as_min = 1e-10_mm_wp 114 rcs_min = 1e-9_mm_wp 115 m0af_min = 1e-10_mm_wp 116 rcf_min = 1e-9_mm_wp 117 m0n_min = 1e-10_mm_wp 110 118 111 119 WRITE(*,'(a)') "##### MMP_GCM SPEAKING #####" 112 WRITE(*,'(a)') "I will initialize ze microphysics model in moments YAMMS"120 WRITE(*,'(a)') "I will initialize the microphysics model in moments YAMMS" 113 121 WRITE(*,'(a)') "On error I will simply abort the program. Stay near your computer !" 114 122 WRITE(*,*) 115 123 WRITE(*,'(a)') "Reading muphys configuration file ("//trim(cfgpath)//")..." 116 err = cfg_read_config(cparser,TRIM(cfgpath),.true.) 124 err = cfg_read_config(cparser,TRIM(cfgpath),.true.) 117 125 IF (err /= 0) THEN 118 126 ! RETURN AN ERROR !! 119 127 call abort_program(err) 120 128 ENDIF 121 129 122 130 ! YAMMS internal parameters: 123 131 err = mm_check_opt(cfg_get_value(cparser,"rm",rm),rm,50e-9_mm_wp,mm_log) … … 126 134 ! the following parameters are primarily used to test and debug YAMMS. 127 135 ! They are set in an optional configuration file and default to suitable values for production runs. 128 err = mm_check_opt(cfg_get_value(cparser,"haze_production",w_h_prod) ,w_h_prod ,.true. ,mm_log) 129 err = mm_check_opt(cfg_get_value(cparser,"haze_sedimentation",w_h_sed) ,w_h_sed ,.true. ,mm_log) 130 err = mm_check_opt(cfg_get_value(cparser,"haze_coagulation",w_h_coag) ,w_h_coag ,.true. ,mm_log) 131 err = mm_check_opt(cfg_get_value(cparser,"clouds_sedimentation",w_c_sed),w_c_sed ,clouds ,mm_log) 132 err = mm_check_opt(cfg_get_value(cparser,"clouds_nucl_cond",w_c_nucond) ,w_c_nucond ,clouds ,mm_log) 133 err = mm_check_opt(cfg_get_value(cparser,"wsed_m0",fwsed_m0) ,fwsed_m0 ,.true. ,mm_log) 134 err = mm_check_opt(cfg_get_value(cparser,"wsed_m3",fwsed_m3) ,fwsed_m3 ,.false. ,mm_log) 135 err = mm_check_opt(cfg_get_value(cparser,"no_fiadero",no_fiadero) ,no_fiadero ,.false. ,mm_log) 136 err = mm_check_opt(cfg_get_value(cparser,"fiadero_min_ratio",fiad_min) ,fiad_min ,0.1_mm_wp,mm_log) 137 err = mm_check_opt(cfg_get_value(cparser,"fiadero_max_ratio",fiad_max) ,fiad_max ,10._mm_wp,mm_log) 138 err = mm_check_opt(cfg_get_value(cparser,"haze_coag_interactions",coag_choice),coag_choice,7,mm_log) 139 140 ! optic look-up table file path. 141 mmp_optic_file = '' 142 opt_file = '' 143 err = mm_check_opt(cfg_get_value(cparser,"optics/optic_file",opt_file),opt_file,'',mm_log) 144 IF (err /= 0) THEN 145 WRITE(*,'(a)') "Warning: I was unable to retrieve the path of the optic look-up table file:" 146 WRITE(*,'(a)') " The GCM may abort if it uses YAMMS optical properties calculation module !" 147 ELSE 148 mmp_optic_file = TRIM(opt_file) 149 ENDIF 136 err = mm_check_opt(cfg_get_value(cparser,"haze_production",w_h_prod) ,w_h_prod ,.true. ,mm_log) 137 err = mm_check_opt(cfg_get_value(cparser,"haze_sedimentation",w_h_sed) ,w_h_sed ,.true. ,mm_log) 138 err = mm_check_opt(cfg_get_value(cparser,"haze_coagulation",w_h_coag) ,w_h_coag ,.true. ,mm_log) 139 err = mm_check_opt(cfg_get_value(cparser,"clouds_sedimentation",w_c_sed) ,w_c_sed ,clouds ,mm_log) 140 err = mm_check_opt(cfg_get_value(cparser,"clouds_nucl_cond",w_c_nucond) ,w_c_nucond ,clouds ,mm_log) 141 err = mm_check_opt(cfg_get_value(cparser,"wsed_m0",fwsed_m0) ,fwsed_m0 ,.true. ,mm_log) 142 err = mm_check_opt(cfg_get_value(cparser,"wsed_m3",fwsed_m3) ,fwsed_m3 ,.false. ,mm_log) 143 err = mm_check_opt(cfg_get_value(cparser,"no_fiadero",no_fiadero) ,no_fiadero ,.true. ,mm_log) 144 err = mm_check_opt(cfg_get_value(cparser,"fiadero_min_ratio",fiad_min) ,fiad_min ,0.1_mm_wp ,mm_log) 145 err = mm_check_opt(cfg_get_value(cparser,"fiadero_max_ratio",fiad_max) ,fiad_max ,10._mm_wp ,mm_log) 146 err = mm_check_opt(cfg_get_value(cparser,"haze_coag_interactions",coag_choice),coag_choice,7 ,mm_log) 147 err = mm_check_opt(cfg_get_value(cparser,"m0as_min",m0as_min) ,m0as_min ,1e-10_mm_wp,mm_log) 148 err = mm_check_opt(cfg_get_value(cparser,"rcs_min",rcs_min) ,rcs_min ,1e-9_mm_wp ,mm_log) 149 err = mm_check_opt(cfg_get_value(cparser,"m0af_min",m0af_min) ,m0af_min ,1e-10_mm_wp,mm_log) 150 err = mm_check_opt(cfg_get_value(cparser,"rcf_min",rcf_min) ,rcf_min ,rm ,mm_log) 151 err = mm_check_opt(cfg_get_value(cparser,"m0n_min",m0n_min) ,m0n_min ,1e-10_mm_wp,mm_log) 152 err = mm_check_opt(cfg_get_value(cparser,"debug",wdebug) ,wdebug ,.false. ,mm_log) 150 153 151 154 ! Retrieve clouds species configuration file … … 156 159 ENDIF 157 160 158 ! YAMMS initialization. 159 err = mm_global_init_0(dt,df,rm,rho_aer,p_prod,tx_prod,rc_prod,rplanet,g0, & 160 air_rad,air_mmol,coag_choice,clouds,spcpath, & 161 w_h_prod,w_h_sed,w_h_coag,w_c_nucond, & 162 w_c_sed,fwsed_m0,fwsed_m3, & 163 no_fiadero,fiad_min,fiad_max) 164 IF (err /= 0) call abort_program(err) 165 166 ! Extra initialization (needed for YAMMS method interfaces) 167 err = mm_check_opt(cfg_get_value(cparser, "transfert_probability", mmp_w_ps2s), mmp_w_ps2s, wlog=mm_log) 168 IF (err/=0) call abort_program(err) 169 err = mm_check_opt(cfg_get_value(cparser, "electric_charging" , mmp_w_qe ), mmp_w_qe, wlog=mm_log) 170 IF (err/=0) call abort_program(err) 171 172 ! initialize transfert probabilities look-up tables 173 IF (mm_w_haze_coag .AND. mmp_w_ps2s) THEN 174 err = mm_check_opt(cfg_get_value(cparser, "ps2s_file", pssfile), pssfile) 175 IF (err /= 0) call abort_program(err) 176 177 IF (.NOT.read_dset(pssfile,'p_m0_co',mmp_pco0p)) THEN 178 call abort_program(error("Cannot get 'p_m0_co' from "//pssfile,-1)) 179 ENDIF 180 IF (.NOT.read_dset(pssfile,'p_m3_co',mmp_pco3p)) THEN 181 call abort_program(error("Cannot get 'p_m3_co' from "//pssfile,-1)) 182 ENDIF 183 IF (.NOT.read_dset(pssfile,'p_m0_fm',mmp_pfm0p)) THEN 184 call abort_program(error("Cannot get 'p_m0_fm' from "//pssfile,-1)) 185 ENDIF 186 IF (.NOT.read_dset(pssfile,'p_m3_fm',mmp_pfm3p)) THEN 187 call abort_program(error("Cannot get 'p_m3_fm' from "//pssfile,-1)) 188 ENDIF 189 ENDIF 190 ! initialize mean electric correction look-up tables 191 IF (mm_w_haze_coag .AND. mmp_w_qe) THEN 192 err = mm_check_opt(cfg_get_value(cparser, "mq_file", mqfile), mqfile) 193 IF (err /= 0) call abort_program(err) 194 195 IF (.NOT.read_dset(mqfile,'qbsf0',mmp_qbsf0)) THEN 196 call abort_program(error("Cannot get 'qbsf0' from "//mqfile,-1)) 197 ELSE 198 mmp_qbsf0_e(1,1) = MINVAL(mmp_qbsf0%x) 199 mmp_qbsf0_e(1,2) = MAXVAL(mmp_qbsf0%x) 200 mmp_qbsf0_e(2,1) = MINVAL(mmp_qbsf0%y) 201 mmp_qbsf0_e(2,2) = MAXVAL(mmp_qbsf0%y) 202 ENDIF 203 IF (.NOT.read_dset(mqfile,'qbsf3',mmp_qbsf3)) THEN 204 call abort_program(error("Cannot get 'qbsf3' from "//mqfile,-1)) 205 ELSE 206 mmp_qbsf3_e(1,1) = MINVAL(mmp_qbsf3%x) 207 mmp_qbsf3_e(1,2) = MAXVAL(mmp_qbsf3%x) 208 mmp_qbsf3_e(2,1) = MINVAL(mmp_qbsf3%y) 209 mmp_qbsf3_e(2,2) = MAXVAL(mmp_qbsf3%y) 210 ENDIF 211 IF (.NOT.read_dset(mqfile,'qbff0',mmp_qbff0)) THEN 212 call abort_program(error("Cannot get 'qbff0' from "//mqfile,-1)) 213 ELSE 214 mmp_qbff0_e(1,1) = MINVAL(mmp_qbff0%x) 215 mmp_qbff0_e(1,2) = MAXVAL(mmp_qbff0%x) 216 mmp_qbff0_e(2,1) = MINVAL(mmp_qbff0%y) 217 mmp_qbff0_e(2,2) = MAXVAL(mmp_qbff0%y) 218 ENDIF 219 ENDIF 161 ! Setup alpha function: THEY ARE REQUIRED IN YAMMS global initialization ! 220 162 ! spherical mode inter-moments function parameters 221 163 IF (.NOT.cfg_has_section(cparser,'alpha_s')) call abort_program(error("Cannot find [alpha_s] section",-1)) … … 227 169 IF (err /= 0) call abort_program(error("alpha_s: "//TRIM(err%msg),-1)) 228 170 229 ! get size-distribution laws parameters 230 IF (.NOT.cfg_has_section(cparser,'dndr_s')) call abort_program(error("Cannot find [dndr_s] section",-2)) 231 err = read_nprm(cparser,'dndr_s',mmp_pns) 232 IF (err /= 0) call abort_program(error("dndr_s: "//TRIM(err%msg),-2)) 233 IF (.NOT.cfg_has_section(cparser,'dndr_f')) call abort_program(error("Cannot find [dndr_f] section",-2)) 234 err = read_nprm(cparser,'dndr_f',mmp_pnf) 235 IF (err /= 0) call abort_program(error("dndr_f: "//TRIM(err%msg),-2)) 171 ! YAMMS initialization. 172 err = mm_global_init_0(dt,df,rm,rho_aer,p_prod,tx_prod,rc_prod,rplanet,g0, & 173 air_rad,air_mmol,coag_choice,clouds,spcpath, & 174 w_h_prod,w_h_sed,w_h_coag,w_c_nucond, & 175 w_c_sed,fwsed_m0,fwsed_m3, & 176 no_fiadero,fiad_min,fiad_max, & 177 m0as_min,rcs_min,m0af_min,rcf_min,m0n_min,wdebug) 178 IF (err /= 0) call abort_program(err) 179 180 ! Extra initialization (needed for YAMMS method interfaces) 181 err = mm_check_opt(cfg_get_value(cparser, "transfert_probability", mmp_w_ps2s), mmp_w_ps2s, wlog=mm_log) 182 IF (err/=0) call abort_program(err) 183 err = mm_check_opt(cfg_get_value(cparser, "electric_charging" , mmp_w_qe ), mmp_w_qe, wlog=mm_log) 184 IF (err/=0) call abort_program(err) 185 186 ! initialize transfert probabilities look-up tables 187 IF (mm_w_haze_coag .AND. mmp_w_ps2s) THEN 188 err = mm_check_opt(cfg_get_value(cparser, "ps2s_file", pssfile), pssfile) 189 IF (err /= 0) call abort_program(err) 190 191 IF (.NOT.read_dset(pssfile,'p_m0_co',mmp_pco0p)) THEN 192 call abort_program(error("Cannot get 'p_m0_co' from "//pssfile,-1)) 193 ENDIF 194 IF (.NOT.read_dset(pssfile,'p_m3_co',mmp_pco3p)) THEN 195 call abort_program(error("Cannot get 'p_m3_co' from "//pssfile,-1)) 196 ENDIF 197 IF (.NOT.read_dset(pssfile,'p_m0_fm',mmp_pfm0p)) THEN 198 call abort_program(error("Cannot get 'p_m0_fm' from "//pssfile,-1)) 199 ENDIF 200 IF (.NOT.read_dset(pssfile,'p_m3_fm',mmp_pfm3p)) THEN 201 call abort_program(error("Cannot get 'p_m3_fm' from "//pssfile,-1)) 202 ENDIF 203 ENDIF 204 ! initialize mean electric correction look-up tables 205 IF (mm_w_haze_coag .AND. mmp_w_qe) THEN 206 err = mm_check_opt(cfg_get_value(cparser, "mq_file", mqfile), mqfile) 207 IF (err /= 0) call abort_program(err) 208 209 IF (.NOT.read_dset(mqfile,'qbsf0',mmp_qbsf0)) THEN 210 call abort_program(error("Cannot get 'qbsf0' from "//mqfile,-1)) 211 ELSE 212 mmp_qbsf0_e(1,1) = MINVAL(mmp_qbsf0%x) 213 mmp_qbsf0_e(1,2) = MAXVAL(mmp_qbsf0%x) 214 mmp_qbsf0_e(2,1) = MINVAL(mmp_qbsf0%y) 215 mmp_qbsf0_e(2,2) = MAXVAL(mmp_qbsf0%y) 216 ENDIF 217 IF (.NOT.read_dset(mqfile,'qbsf3',mmp_qbsf3)) THEN 218 call abort_program(error("Cannot get 'qbsf3' from "//mqfile,-1)) 219 ELSE 220 mmp_qbsf3_e(1,1) = MINVAL(mmp_qbsf3%x) 221 mmp_qbsf3_e(1,2) = MAXVAL(mmp_qbsf3%x) 222 mmp_qbsf3_e(2,1) = MINVAL(mmp_qbsf3%y) 223 mmp_qbsf3_e(2,2) = MAXVAL(mmp_qbsf3%y) 224 ENDIF 225 IF (.NOT.read_dset(mqfile,'qbff0',mmp_qbff0)) THEN 226 call abort_program(error("Cannot get 'qbff0' from "//mqfile,-1)) 227 ELSE 228 mmp_qbff0_e(1,1) = MINVAL(mmp_qbff0%x) 229 mmp_qbff0_e(1,2) = MAXVAL(mmp_qbff0%x) 230 mmp_qbff0_e(2,1) = MINVAL(mmp_qbff0%y) 231 mmp_qbff0_e(2,2) = MAXVAL(mmp_qbff0%y) 232 ENDIF 233 ENDIF 236 234 237 235 ! btk coefficients … … 249 247 WRITE(*,'(a,L2)') "electric_charging : ", mmp_w_qe 250 248 call mm_dump_parameters() 251 249 250 IF (clouds) THEN 251 DO i=1, size(mm_xESPS) 252 print*, TRIM(mm_xESPS(i)%name), " fmol2fmas = ", mm_xESPS(i)%fmol2fmas 253 ENDDO 254 ENDIF 255 252 256 END SUBROUTINE mmp_initialize 253 257 254 258 FUNCTION read_aprm(parser,sec,pp) RESULT(err) 255 !! Read and store [[mmp_gcm(module):aprm(type)]] parameters. 256 TYPE(cfgparser), INTENT(in) :: parser !! Configuration parser 259 !! Read and store [[mmp_gcm(module):aprm(type)]] parameters. 260 TYPE(cfgparser), INTENT(in) :: parser !! Configuration parser 257 261 CHARACTER(len=*), INTENT(in) :: sec !! Name of the section that contains the parameters. 258 262 TYPE(aprm), INTENT(out) :: pp !! [[mmp_gcm(module):aprm(type)]] object that stores the parameters values. … … 266 270 END FUNCTION read_aprm 267 271 268 FUNCTION read_nprm(parser,sec,pp) RESULT(err)269 !! Read and store [[mmp_gcm(module):nprm(type)]] parameters.270 TYPE(cfgparser), INTENT(in) :: parser !! Configuration parser271 CHARACTER(len=*), INTENT(in) :: sec !! Name of the section that contains the parameters.272 TYPE(nprm), INTENT(out) :: pp !! [[mmp_gcm(module):nprm(type)]] object that stores the parameters values.273 TYPE(error) :: err !! Error status of the function.274 err = cfg_get_value(parser,TRIM(sec)//'/rc',pp%rc) ; IF (err /= 0) RETURN275 err = cfg_get_value(parser,TRIM(sec)//'/a0',pp%a0) ; IF (err /= 0) RETURN276 err = cfg_get_value(parser,TRIM(sec)//'/c',pp%c) ; IF (err /= 0) RETURN277 err = cfg_get_value(parser,TRIM(sec)//'/a',pp%a) ; IF (err /= 0) RETURN278 err = cfg_get_value(parser,TRIM(sec)//'/b',pp%b) ; IF (err /= 0) RETURN279 IF (SIZE(pp%a) /= SIZE(pp%b)) &280 err = error("Inconsistent number of coefficients (a and b must have the same size)",3)281 RETURN282 END FUNCTION read_nprm283 284 272 END MODULE MMP_GCM 285 273 -
trunk/LMDZ.TITAN/libf/muphytitan/mmp_globals.f90
r1926 r3083 27 27 END TYPE 28 28 29 !> Size distribution parameters derived type.30 !!31 !! It stores the parameters of the size distribution law for Titan.32 !!33 !! The size distribution law is represented by the minimization of a sum of34 !! power law functions:35 !!36 !! $$37 !! \displaystyle n\left(r\right) = \frac{A_{0}}{C+\sum_{i=1}^{n} A_{i}\times38 !! \left(\frac{r}{r_{c}}\right)^{-b_{i}}}39 !! $$40 TYPE, PUBLIC :: nprm41 !> Scaling factor.42 REAL(kind=mm_wp) :: a043 !> Characterisitic radius.44 REAL(kind=mm_wp) :: rc45 !> Additional constant to the sum of power law.46 REAL(kind=mm_wp) :: c47 !> Scaling factor of each power law.48 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a49 !> Power of each power law.50 REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: b51 END TYPE52 53 29 !> Inter-moment relation set of parameters for the spherical mode. 54 30 TYPE(aprm), PUBLIC, SAVE :: mmp_asp 55 31 !> Inter-moment relation set of parameters for the fractal mode. 56 32 TYPE(aprm), PUBLIC, SAVE :: mmp_afp 57 58 !> Size-distribution law parameters of the spherical mode.59 TYPE(nprm), PUBLIC, SAVE :: mmp_pns60 !> Size-distribution law parameters of the fractal mode.61 TYPE(nprm), PUBLIC, SAVE :: mmp_pnf62 33 63 34 !> Data set for @f$<Q>_{SF}^{M0}@f$. … … 92 63 !> Aerosol electric charge correction control flag. 93 64 LOGICAL, SAVE :: mmp_w_qe = .true. 94 !> Optic look-up table file path.95 CHARACTER(len=:), ALLOCATABLE, SAVE :: mmp_optic_file96 65 97 66 CONTAINS -
trunk/LMDZ.TITAN/libf/muphytitan/mmp_moments.f90
r1897 r3083 1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne1 ! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne 2 2 ! Contributor: J. Burgalat (GSMA, URCA) 3 3 ! email of the author : jeremie.burgalat@univ-reims.fr 4 ! 4 ! 5 5 ! This software is a computer program whose purpose is to compute 6 6 ! microphysics processes using a two-moments scheme. 7 ! 7 ! 8 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, 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 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 license and that you accept its terms. … … 35 35 !! summary: YAMMS/MP2M model external methods 36 36 !! author: J. Burgalat 37 !! date: 2013-2015,2017 37 !! date: 2013-2015,2017,2022 38 38 !! 39 39 !! This file contains the definitions of all external methods that should be defined 40 !! for mp2m library. 41 !! 42 !! All the methods defined here satisify the interfaces defined in __m_interfaces__ module 40 !! for mp2m library. 41 !! 42 !! All the methods defined here satisify the interfaces defined in __m_interfaces__ module 43 43 !! of YAMMS library. 44 44 45 45 PURE FUNCTION mm_alpha_s(k) RESULT (res) 46 46 !! Inter-moment relation for spherical aerosols size distribution law. 47 !! 48 !! The method computes the relation between the kth order moment and the 0th 47 !! 48 !! The method computes the relation between the kth order moment and the 0th 49 49 !! order moment of the size-distribution law: 50 50 !! … … 58 58 res = SUM(dexp(mmp_asp%a*k**2+mmp_asp%b*k+mmp_asp%c)) 59 59 RETURN 60 END FUNCTION mm_alpha_s 60 END FUNCTION mm_alpha_s 61 61 62 62 PURE FUNCTION mm_alpha_f(k) RESULT (res) … … 81 81 !! 82 82 !! @warning 83 !! Here, the method assumes the datasets define the probability for __spherical__ particles to 83 !! Here, the method assumes the datasets define the probability for __spherical__ particles to 84 84 !! be transferred in the __fractal__ mode, but returns the proportion of particles that remains 85 85 !! in the mode (which is expected by mp2m model). 86 86 !! 87 87 !! @attention 88 !! If value cannot be interpolated, the method aborts the program. Normally, it cannot happen 88 !! If value cannot be interpolated, the method aborts the program. Normally, it cannot happen 89 89 !! since we extrapolate the probability for characteristic radius value out of range. 90 90 !! 91 91 !! @attention 92 !! Consequently, as the probability can only range from 0 to 1, it is wise to ensure that the 93 !! look-up table limits this range: To do so, one can just add two values at the start and end 92 !! Consequently, as the probability can only range from 0 to 1, it is wise to ensure that the 93 !! look-up table limits this range: To do so, one can just add two values at the start and end 94 94 !! of the table with probabilities respectively set to 0 and 1. 95 95 USE LINTDSET … … 111 111 TYPE(dset1d), POINTER :: pp 112 112 res = 1._mm_wp 113 IF (rcs <= 0.0_mm_wp .OR. .NOT.mmp_w_ps2s) RETURN 113 IF (rcs <= 0.0_mm_wp .OR. .NOT.mmp_w_ps2s) RETURN 114 114 SELECT CASE(k+flow) 115 115 CASE(0) ; pp => mmp_pco0p ! 0 = 0 + 0 -> M0 / CO … … 119 119 CASE DEFAULT ; RETURN 120 120 END SELECT 121 IF (.NOT.hdcd_lint_dset(rcs,pp,locate_reg_ext,res)) THEN 121 IF (.NOT.hdcd_lint_dset(rcs,pp,locate_reg_ext,res)) THEN 122 122 WRITE(*,'(a)') "mm_moments:ps2s_sc: Cannot interpolate transfert probability" 123 123 call EXIT(10) 124 124 ELSE 125 ! 05102017: do not care anymore for bad extrapolation: 125 ! 05102017: do not care anymore for bad extrapolation: 126 126 ! Bound probability value between 0 and 1 127 127 ! note: The input look-up table still must have strict monotic variation or … … 139 139 !! kernel as a function of the temperature, pressure and the characteristic radius of 140 140 !! the mode involved in the coagulation. 141 !! 141 !! 142 142 !! Modes are referred by a two letters uppercase string with the combination of: 143 143 !! 144 144 !! - S : spherical mode 145 145 !! - F : fractal mode 146 !! 146 !! 147 147 !! For example, SS means intra-modal coagulation for spherical particles. 148 148 !! … … 159 159 CHARACTER(len=2), INTENT(in) :: modes !! Interaction mode (a combination of [S,F]). 160 160 REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K). 161 REAL(kind=mm_wp), INTENT(in) :: pres !! Pressure level (Pa). 161 REAL(kind=mm_wp), INTENT(in) :: pres !! Pressure level (Pa). 162 162 REAL(kind=mm_wp) :: res !! Electric charging correction. 163 163 INTEGER :: chx,np 164 164 REAL(kind=mm_wp) :: vmin,vmax 165 165 REAL(kind=mm_wp) :: r_tmp, t_tmp 166 chx = 0 166 chx = 0 167 167 IF (.NOT.mmp_w_qe) THEN 168 168 res = 1._mm_wp … … 177 177 SELECT CASE(chx) 178 178 CASE(2) ! M0/SS 179 res = 1._mm_wp 179 res = 1._mm_wp 180 180 CASE(4) ! M0/SF 181 181 ! Fix max values of input parameters … … 211 211 PURE FUNCTION mm_get_btk(t,k) RESULT(res) 212 212 !! Get the \(b_{k}^{T}\) coefficient of the Free Molecular regime. 213 !! 213 !! 214 214 !! The method get the value of the Free-molecular regime coagulation pre-factor \(b_{k}^{T}\). 215 !! For more details about this coefficient, please read [Coagulation](page/haze.html#coagulation) 215 !! For more details about this coefficient, please read [Coagulation](page/haze.html#coagulation) 216 216 !! documentation page. 217 217 !! … … 244 244 tsut = 109._mm_wp, & 245 245 tref = 293._mm_wp 246 res = eta0 * dsqrt(t/tref)*(1._mm_wp+tsut/tref)/(1._mm_wp+tsut/t)246 res = eta0 * dsqrt(t/tref) * (1._mm_wp + tsut/tref) / (1._mm_wp + tsut/t) 247 247 RETURN 248 248 END FUNCTION mm_eta_g -
trunk/LMDZ.TITAN/libf/muphytitan/string_op.F90
r1897 r3083 1 ! Copyright Jérémie Burgalat (2013-2015,2017) 2 ! 3 ! jeremie.burgalat@univ-reims.fr 4 ! 5 ! This software is a computer program whose purpose is to provide configuration 6 ! file and command line arguments parsing features to Fortran programs. 7 ! 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, 10 ! modify and/ or redistribute the software under the terms of the CeCILL-B 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-B license and that you accept its terms. 1 ! Copyright (c) (2013-2015,2017) Jeremie Burgalat (jeremie.burgalat@univ-reims.fr). 2 ! 3 ! This file is part of SWIFT 4 ! 5 ! Permission is hereby granted, free of charge, to any person obtaining a copy of 6 ! this software and associated documentation files (the "Software"), to deal in 7 ! the Software without restriction, including without limitation the rights to 8 ! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 ! the Software, and to permit persons to whom the Software is furnished to do so, 10 ! subject to the following conditions: 11 ! 12 ! The above copyright notice and this permission notice shall be included in all 13 ! copies or substantial portions of the Software. 14 ! 15 ! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 ! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 ! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 ! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 ! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 ! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 21 34 22 !! file: strings.F90 35 23 !! summary: Strings manipulation source file 36 24 !! author: J. Burgalat 37 !! date: 2013-2015,2017 25 !! date: 2013-2015,2017,2022 38 26 39 27 #include "defined.h" … … 41 29 MODULE STRING_OP 42 30 !! Fortran strings manipulation module 43 !! 31 !! 44 32 !! This module provides methods and objects to manipulate Fortran (allocatable) strings. It defines 45 33 !! a doubly linked-list of strings, [[string_op(module):words(type)]] and several methods to format 46 !! strings or convert them in other intrinsic types. 34 !! strings or convert them in other intrinsic types. 47 35 USE ERRORS 48 36 IMPLICIT NONE 49 37 50 38 PRIVATE 51 39 … … 55 43 ! errors module (not used but propagated) 56 44 PUBLIC :: stdout,stderr,noerror,error, error_to_string,aborting 57 45 58 46 ! misc module methods 59 47 PUBLIC :: to_string, from_string, string_is, remove_quotes, format_string, & … … 86 74 INTEGER, PUBLIC, PARAMETER :: st_integer = 4 !! Integer type ID 87 75 INTEGER, PUBLIC, PARAMETER :: st_real = 5 !! Real type ID 88 76 89 77 !> List of types names 90 78 CHARACTER(len=*), DIMENSION(5), PARAMETER, PUBLIC :: st_type_names = & … … 95 83 96 84 97 85 98 86 INTEGER, PUBLIC, PARAMETER :: FC_BLACK = 30 !! Black foreground csi code 99 87 INTEGER, PUBLIC, PARAMETER :: FC_RED = 31 !! Red foreground csi code … … 120 108 INTEGER, PUBLIC, PARAMETER, DIMENSION(21) :: attributes = [FC_BLACK, & 121 109 FC_RED, & 122 FC_GREEN, & 110 FC_GREEN, & 123 111 FC_YELLOW, & 124 112 FC_BLUE, & … … 133 121 BG_MAGENTA, & 134 122 BG_CYAN, & 135 BG_WHITE, & 123 BG_WHITE, & 136 124 ST_NORMAL, & 137 125 ST_BOLD, & … … 139 127 ST_UNDERLINE, & 140 128 ST_BLINK & 141 ] 142 129 ] 130 143 131 !> Aliases for CSI codes. 144 132 CHARACTER(len=2), DIMENSION(21), PARAMETER, PUBLIC :: csis =(/ & … … 151 139 MODULE PROCEDURE ws_affect 152 140 END INTERFACE 153 141 154 142 !> Clear either a scalar or a vector of list of [[words(type)]] 155 143 !! 156 !! The interface encapsulates words _destructors_, that deallocate memory used 157 !! by the given list(s) of words. This method should be called anytime words 144 !! The interface encapsulates words _destructors_, that deallocate memory used 145 !! by the given list(s) of words. This method should be called anytime words 158 146 !! object(s) is no longer used to avoid memory leaks. 159 147 !! @note … … 168 156 !! The interface encapsulates two subroutines: 169 157 !! 170 !! - [[ws_extend_ws(subroutine)]](this,other) which extends __this__ by __other__ 158 !! - [[ws_extend_ws(subroutine)]](this,other) which extends __this__ by __other__ 171 159 !! (both are words objects). 172 160 !! - [[ws_extend_str(subroutine)]](this,str,delimiter,merge) which splits __str__ 173 !! according to __delimiter__ (and optionally __merge__) and then extends 161 !! according to __delimiter__ (and optionally __merge__) and then extends 174 162 !! __this__ with the resulting tokens. 175 163 INTERFACE words_extend … … 192 180 !! parenthesis can be omitted. 193 181 !! - __str__ is an allocatable string with the converted value in output, or an empty 194 !! string if the conversion failed. 182 !! string if the conversion failed. 195 183 INTERFACE to_string 196 184 MODULE PROCEDURE int2str_as,int2str_fs … … 201 189 MODULE PROCEDURE dcplx2str_as,dcplx2str_fs 202 190 END INTERFACE 203 191 204 192 !> Convert a string into an intrisinc type 205 193 !! 206 194 !! All methods defined in the interface are functions which take in arguments, 207 !! a string (input) and an output variable with the relevant type (or vectors of both). 195 !! a string (input) and an output variable with the relevant type (or vectors of both). 208 196 !! They always return an error object which is set to -5 error code (i.e. cannot cast value) 209 197 !! on error, otherwise [[errors(module):noerror(variable)]]. … … 217 205 !! The generic interface adds CSI codes to the given value and returns a fortran intrinsic string. 218 206 !! 219 !! This is convinient wrapper to [[string_op(module):to_string(interface)]] and 207 !! This is convinient wrapper to [[string_op(module):to_string(interface)]] and 220 208 !! [[string_op(module):add_csi(function)]]. 221 209 !! … … 251 239 !! It's part of the doubly linked list words. 252 240 TYPE, PUBLIC :: word 253 #if HAVE_FTNDTSTR 241 #if HAVE_FTNDTSTR 254 242 CHARACTER(len=:), ALLOCATABLE :: value !! Value of the word 255 #else 243 #else 256 244 !> Value of the word 257 245 !! 258 !! @warning 246 !! @warning 259 247 !! It is always limited to [[string_op(module):st_slen(variable)]] characters. 260 248 CHARACTER(len=st_slen) :: value = '' … … 263 251 TYPE(word), PRIVATE, POINTER :: prev => null() !! Previous word in the list of words 264 252 END TYPE word 265 253 266 254 !> Define a list of words 267 255 TYPE, PUBLIC :: words … … 270 258 TYPE(word), PRIVATE, POINTER :: tail => null() !! Last word in the list 271 259 TYPE(word), PRIVATE, POINTER :: iter => null() !! Current word (iterator) 272 #if HAVE_FTNPROC 260 #if HAVE_FTNPROC 273 261 CONTAINS 274 262 PROCEDURE, PRIVATE :: ws_extend_ws … … 279 267 !! Insert a word at given index 280 268 PROCEDURE, PUBLIC :: append => words_append 281 !! Append a word at the end of the list 269 !! Append a word at the end of the list 282 270 PROCEDURE, PUBLIC :: prepend => words_prepend 283 !! Prepend a word at the beginning of the list 271 !! Prepend a word at the beginning of the list 284 272 PROCEDURE, PUBLIC :: get => words_get 285 273 !! Get the word at given index … … 293 281 !! Reverse the list in place 294 282 PROCEDURE, PUBLIC :: reversed => words_reversed 295 !! Get a reversed copy of the list 283 !! Get a reversed copy of the list 296 284 PROCEDURE, PUBLIC :: dump => words_dump 297 285 !! Dump words of the list (on per line) … … 301 289 !! Convert the list in a vector 302 290 PROCEDURE, PUBLIC :: pop => words_pop 303 !! Pop a word from the list and returns it 291 !! Pop a word from the list and returns it 304 292 PROCEDURE, PUBLIC :: remove => words_remove 305 293 !! Remove a word from the list … … 318 306 #endif 319 307 END TYPE words 320 308 321 309 CONTAINS 322 310 323 311 FUNCTION word_length(this) RESULT(lgth) 324 312 !! Get the trimmed length of the word object … … 327 315 INTEGER :: lgth 328 316 !! The length of the word's value (without trailing spaces) 329 #if HAVE_FTNDTSTR 317 #if HAVE_FTNDTSTR 330 318 IF (.NOT.ALLOCATED(this%value)) THEN 331 319 lgth = 0 ; RETURN 332 320 ENDIF 333 #endif 321 #endif 334 322 lgth = LEN_TRIM(this%value) 335 323 RETURN 336 324 END FUNCTION word_length 337 325 338 326 SUBROUTINE disconnect_word(this) 339 327 !! Disconnect a word object 340 328 !! 341 329 !! The object is no more connected to its neighbours which are connected together. 342 !! @note 343 !! After this method is called the object is no longer connected to its parent words 330 !! @note 331 !! After this method is called the object is no longer connected to its parent words 344 332 !! object and should be deallocated in order to avoid memory leaks. 345 333 TYPE(word), INTENT(inout) :: this … … 351 339 RETURN 352 340 END SUBROUTINE disconnect_word 353 341 354 342 SUBROUTINE ws_affect(this,other) 355 343 !! words object assignment operator subroutine … … 365 353 cur => other%head 366 354 DO WHILE(associated(cur)) 367 #if HAVE_FTNDTSTR 355 #if HAVE_FTNDTSTR 368 356 IF (.NOT.ALLOCATED(cur%value)) THEN 369 357 CALL words_append(this,"") … … 380 368 RETURN 381 369 END SUBROUTINE ws_affect 382 370 383 371 SUBROUTINE ini_word(this,value) 384 372 !! Initialize the first word of a list of words 385 373 !! 386 !! This subroutine is not a constructor. It is only intended to set the first word 374 !! This subroutine is not a constructor. It is only intended to set the first word 387 375 !! object in a words object. 388 376 TYPE(words), INTENT(inout) :: this 389 377 !! A words object reference 390 378 CHARACTER(len=*), INTENT(in) :: value 391 !! A string with the word used to initialize the list 379 !! A string with the word used to initialize the list 392 380 ALLOCATE(this%head) 393 381 this%tail => this%head … … 401 389 !! 402 390 !! This subroutine deallocates all memory used by the given words object. 403 !! @warning 404 !! The subroutine should be called whenever a words is no more used (e.g. at 391 !! @warning 392 !! The subroutine should be called whenever a words is no more used (e.g. at 405 393 !! the end of the current scope), otherwise memory leaks could occur. 406 394 TYPE(words),INTENT(inout), TARGET :: obj … … 408 396 TYPE(word), POINTER :: cur,next 409 397 IF (obj%nw == 0) RETURN 410 cur => obj%head 398 cur => obj%head 411 399 DO WHILE(ASSOCIATED(cur)) 412 400 next => cur%next … … 426 414 !! 427 415 !! This subroutine deallocates all memory used by the given vector of words objects. 428 !! @warning 429 !! The subroutine should be called whenever a words is no more used (e.g. at the end 416 !! @warning 417 !! The subroutine should be called whenever a words is no more used (e.g. at the end 430 418 !! of the current scope), otherwise memory leaks could occur. 431 419 TYPE(words),INTENT(inout), DIMENSION(:) :: objs … … 453 441 END SUBROUTINE ws_extend_ws 454 442 455 SUBROUTINE ws_extend_str(this,str,delimiter,merge,protect) 443 SUBROUTINE ws_extend_str(this,str,delimiter,merge,protect) 456 444 !> Extend a list of word with a given string 457 !! @details The method adds a new list of words to the current list by 445 !! @details The method adds a new list of words to the current list by 458 446 !! splitting a string using a set of delimiters. 459 !! 447 !! 460 448 !! - If __delimiter__ is not given, THEN blank space is used. 461 !! - __delimiter__ can be a string of any length, but each character of 462 !! the sequence is seen as a single delimiter. Each time one of these 449 !! - __delimiter__ can be a string of any length, but each character of 450 !! the sequence is seen as a single delimiter. Each time one of these 463 451 !! special character is seen on the string, it is splitted. 464 452 !! - If __protect__ is set to .true. THEN delimiter enclosed by … … 466 454 !! - The optional argument __merge__ instructs the method wether to merge 467 455 !! or not successive delimiters in the string. 468 !! 456 !! 469 457 !! For example, considering the following string: 470 458 !! <center>@verbatim "I like coffee and bananas." @endverbatim</center> … … 484 472 !! A string to split in words 485 473 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter 486 !! An optional string with the words delimiters (default to blank space). 474 !! An optional string with the words delimiters (default to blank space). 487 475 LOGICAL, INTENT(in), OPTIONAL :: merge 488 476 !! An optional boolean control flag that instructs the method 489 477 !! wether to merge or not successive delimiters (default to .false.) 490 478 LOGICAL, INTENT(in), OPTIONAL :: protect 491 !! An optional boolean flag with .true. to indicate that 479 !! An optional boolean flag with .true. to indicate that 492 480 !! delimiter characters between quotes are protected 493 481 ! - LOCAL … … 498 486 CHARACTER(len=1), PARAMETER :: sq = CHAR(39) ! single quote ascii code 499 487 CHARACTER(len=1), PARAMETER :: dq = CHAR(34) ! double quotes ascii code 500 stat=0 ; p=1 ; indq = .false. ; insq = .false. 488 stat=0 ; p=1 ; indq = .false. ; insq = .false. 501 489 seps = ' ' 502 490 zmerge = .false. ; IF (PRESENT(merge)) zmerge = merge … … 506 494 ENDIF 507 495 sl = LEN(str) ; IF (sl == 0) RETURN 508 outer = (INDEX(str,sq) == 1 .AND. INDEX(str,sq,.true.) == LEN(str)) & 496 outer = (INDEX(str,sq) == 1 .AND. INDEX(str,sq,.true.) == LEN(str)) & 509 497 .OR.(INDEX(str,dq) == 1 .AND. INDEX(str,dq,.true.) == LEN(str)) 510 498 ! no delimiter found or (have outer quotes and should protect) 511 499 IF (SCAN(str,seps) == 0.OR.(outer.AND.zprotect)) THEN 512 CALL words_append(this,remove_quotes(str)) 500 CALL words_append(this,remove_quotes(str)) 513 501 RETURN 514 502 ENDIF 515 ! We have to loop... 503 ! We have to loop... 516 504 i = 1 ; curw='' 517 505 DO … … 564 552 !! Get the pointer of the word object at given index 565 553 !! 566 !! The method returns the pointer of the word object at the given index. 554 !! The method returns the pointer of the word object at the given index. 567 555 !! If index is out of range a null poitner is returned. 568 556 OBJECT(words), INTENT(in) :: this 569 !! A words object 557 !! A words object 570 558 INTEGER, INTENT(in) :: idx 571 559 !! An integer with the index of the desired object in __this__ … … 629 617 ELSE 630 618 IF (idx > (this%nw+1)/2) THEN 631 nx => this%tail 619 nx => this%tail 632 620 DO i=1, this%nw - idx ; nx => nx%prev ; ENDDO 633 621 ELSE 634 nx => this%head 622 nx => this%head 635 623 DO i=1, idx-1 ; nx => nx%next ; ENDDO 636 624 ENDIF … … 647 635 SUBROUTINE words_append(this,value) 648 636 !! Append a word to the list of word 649 !! 650 !! The method appends a word to the list of word. This is a convinient wrapper to 637 !! 638 !! The method appends a word to the list of word. This is a convinient wrapper to 651 639 !! [[string_op(module)::words_insert(subroutine)]] to add a new word at the beginning of the list. 652 OBJECT(words), INTENT(inout) :: this !! A words object 640 OBJECT(words), INTENT(inout) :: this !! A words object 653 641 CHARACTER(len=*), INTENT(in) :: value !! A string to append 654 642 !CALL words_insert(this,this%nw+1,value) … … 668 656 !this%tail%value = TRIM(value) 669 657 !this%tail%prev => np 670 !this%tail%prev%next => this%tail 658 !this%tail%prev%next => this%tail 671 659 RETURN 672 660 END SUBROUTINE words_append … … 677 665 !! The method prepends a word to the list of word. This is a convinient wrapper to 678 666 !! [[string_op(module)::words_insert(subroutine)]] to add a new word at the end of the list. 679 OBJECT(words), INTENT(inout) :: this !! A words object 667 OBJECT(words), INTENT(inout) :: this !! A words object 680 668 CHARACTER(len=*), INTENT(in) :: value !! A string to prepend 681 669 CALL words_insert(this,0,value) … … 685 673 FUNCTION words_get(this,idx,case) RESULT (res) 686 674 !! Get the word's value at given index 687 !! 675 !! 688 676 !! The method attempts to get the word's value at the given index. If index is out of range 689 677 !! an empty string is returned. 690 !! @note 678 !! @note 691 679 !! The returned string is always trimmed. 692 680 OBJECT(words), INTENT(in) :: this … … 694 682 INTEGER, INTENT(in) :: idx 695 683 !! An integer with the index of a word in the list 696 CHARACTER(len=5), INTENT(in), OPTIONAL :: case 684 CHARACTER(len=5), INTENT(in), OPTIONAL :: case 697 685 !! An optional string with either 'upper' or 'lower' to get the value converted in the relevant case 698 686 CHARACTER(len=:), ALLOCATABLE :: res … … 704 692 ENDIF 705 693 IF (PRESENT(case)) THEN 706 IF (case == "upper") res = to_upper(cur%value) 694 IF (case == "upper") res = to_upper(cur%value) 707 695 IF (case == "lower") res = to_lower(cur%value) 708 696 ELSE … … 729 717 !! 730 718 !! The method computes and returns the longest (trimmed) word's width in the words object. 731 OBJECT(words), INTENT(in) :: this !! A words object 719 OBJECT(words), INTENT(in) :: this !! A words object 732 720 INTEGER :: res !! An integer with the maximum width (0 if the list is empty) 733 721 TYPE(word), POINTER :: cur … … 744 732 FUNCTION words_get_total_width(this) RESULT(width) 745 733 !! Get the total width of all words stored in the list of words 746 !! 747 !! The method computes and returns the total width of all words stored in 734 !! 735 !! The method computes and returns the total width of all words stored in 748 736 !! the list of words. 749 !! @note 737 !! @note 750 738 !! Total width is computed using strings::word_length so it only takes 751 739 !! into account trimmed words (without trailing blanks) 752 !! @note 740 !! @note 753 741 !! If csi codes have been added to words elements they are counted in the width. 754 742 OBJECT(words), INTENT(in) :: this !! A words object … … 795 783 DO WHILE(ASSOCIATED(cur)) 796 784 CALL words_append(res,cur%value) 797 IF (ASSOCIATED(cur,this%iter)) res%iter => res%tail 785 IF (ASSOCIATED(cur,this%iter)) res%iter => res%tail 798 786 cur => cur%prev 799 787 ENDDO … … 804 792 SUBROUTINE words_dump(this,lun) 805 793 !! Dump the list of words 806 !! 794 !! 807 795 !! The method dumps on the given logical unit the elements of the list one by line. 808 796 OBJECT(words), INTENT(in) :: this 809 797 !! A words object to dump 810 798 INTEGER, INTENT(in), OPTIONAL :: lun 811 !! An optional integer with the printing logical unit. If not given, the list is dumped on 799 !! An optional integer with the printing logical unit. If not given, the list is dumped on 812 800 !! standard output stream. 813 801 TYPE(word), POINTER :: cur … … 834 822 !! setting it back as values of the list of words. 835 823 OBJECT(words), INTENT(in) :: this 836 !! A words object 824 !! A words object 837 825 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter 838 826 !! An optional string used as delimiter between each words … … 867 855 !! .false., otherwise it returns .true. 868 856 !! @note 869 !! If elements in __this__ words object are wider than [[string_op(module):st_slen(variable)]], output 857 !! If elements in __this__ words object are wider than [[string_op(module):st_slen(variable)]], output 870 858 !! values will be truncated. 871 859 OBJECT(words), INTENT(in) :: this … … 895 883 !! Pop a word in the list of words 896 884 !! 897 !! The method removes the word of the list at given index and returns it. If no index is given, 885 !! The method removes the word of the list at given index and returns it. If no index is given, 898 886 !! last word of the list is removed. 899 887 !! … … 906 894 INTEGER, INTENT(in), OPTIONAL :: idx 907 895 !! Optional index of the word to delete 908 LOGICAL, INTENT(in), OPTIONAL :: move_forward 909 !! Move the iterator forward if needed. By default the iterator is moved backward. 896 LOGICAL, INTENT(in), OPTIONAL :: move_forward 897 !! Move the iterator forward if needed. By default the iterator is moved backward. 910 898 CHARACTER(len=:), ALLOCATABLE :: value 911 !! The word's value at given index 899 !! The word's value at given index 912 900 LOGICAL :: zforward 913 901 INTEGER :: zidx … … 935 923 !! Remove the word of the list at given index 936 924 !! 937 !! The method removes the word of the list at given index. If no index is given, last word 925 !! The method removes the word of the list at given index. If no index is given, last word 938 926 !! of the list is removed. 939 927 !! … … 947 935 !! Index of the word to delete 948 936 LOGICAL, INTENT(in), OPTIONAL :: move_forward 949 !! Move the iterator forward if needed. By default the iterator is moved backward. 950 LOGICAL :: zforward 937 !! Move the iterator forward if needed. By default the iterator is moved backward. 938 LOGICAL :: zforward 951 939 INTEGER :: zidx 952 940 TYPE(word), POINTER :: cur … … 982 970 983 971 FUNCTION words_valid(this) RESULT(ret) 984 !! Check if the current iterated word is valid 972 !! Check if the current iterated word is valid 985 973 OBJECT(words), INTENT(in) :: this !! A words object 986 974 LOGICAL :: ret !! A logical flag with .true. if the current iterated word is valid … … 993 981 !! A words object 994 982 CHARACTER(len=:), ALLOCATABLE :: wrd 995 !! A string with the value of the current word or __an unallocated string__ if current word 983 !! A string with the value of the current word or __an unallocated string__ if current word 996 984 !! is not valid (see [[string_op(module):words_valid(function)]]). 997 985 IF (ASSOCIATED(this%iter)) THEN … … 1001 989 1002 990 SUBROUTINE words_reset(this,to_end) 1003 !! Reset the iterator 1004 !! 1005 !! The method resets the iterator either at the beginning or at the end of the list of words 991 !! Reset the iterator 992 !! 993 !! The method resets the iterator either at the beginning or at the end of the list of words 1006 994 !! (if __to_end__ is set to .true.). 1007 OBJECT(words), INTENT(inout) :: this !! A words object 995 OBJECT(words), INTENT(inout) :: this !! A words object 1008 996 LOGICAL, INTENT(in), OPTIONAL :: to_end !! An optional logical flag with .true. to reset the iterator at the end of the list 1009 997 this%iter => this%head … … 1018 1006 FUNCTION tokenize(str,vector,delimiter,merge,protect) RESULT(ok) 1019 1007 !! Tokenize a string. 1020 CHARACTER(len=*), INTENT(in) :: str1008 CHARACTER(len=*), INTENT(in) :: str 1021 1009 !! A string to tokenize 1022 CHARACTER(len= *), INTENT(out), DIMENSION(:), ALLOCATABLE :: vector1023 !! An allocatable vector of strings with the tokens found. If string cannot be tokenized, 1010 CHARACTER(len=st_slen), INTENT(out), DIMENSION(:), ALLOCATABLE :: vector 1011 !! An allocatable vector of strings with the tokens found. If string cannot be tokenized, 1024 1012 !! the vector is __allocated to 0 elements__ and the method returns .false.. 1025 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter1026 !! An optional string with the words delimiters. It is set to blank space by default. 1013 CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter 1014 !! An optional string with the words delimiters. It is set to blank space by default. 1027 1015 !! Note that each character is seen as a single delimiter. 1028 LOGICAL, INTENT(in), OPTIONAL :: merge1029 !! An optional boolean control flag with .true. that instructs the method whether to 1016 LOGICAL, INTENT(in), OPTIONAL :: merge 1017 !! An optional boolean control flag with .true. that instructs the method whether to 1030 1018 !! merge or not successive delimiters. Default to .false. 1031 LOGICAL, INTENT(in), OPTIONAL :: protect1032 !! An optional boolean flag with .true. to indicate that delimiter characters between 1019 LOGICAL, INTENT(in), OPTIONAL :: protect 1020 !! An optional boolean flag with .true. to indicate that delimiter characters between 1033 1021 !! quotes are protected. Default to .true. 1034 1022 LOGICAL :: ok … … 1040 1028 integer :: i,nw 1041 1029 ok = .true. 1042 zmerge = .false. ; zprotect = .true. ; seps = ' ' 1030 zmerge = .false. ; zprotect = .true. ; seps = ' ' 1043 1031 IF (PRESENT(merge)) zmerge = merge 1044 1032 IF (PRESENT(protect)) zprotect = protect … … 1073 1061 !! The output string is trimmed from leading and trailing blank spaces (after quotes removal !) 1074 1062 CHARACTER(len=*), INTENT(in) :: str !! A string to check 1075 CHARACTER(len=:), ALLOCATABLE :: ostr !! A string without external quotes (if any). 1063 CHARACTER(len=:), ALLOCATABLE :: ostr !! A string without external quotes (if any). 1076 1064 CHARACTER(len=1), PARAMETER :: sq=CHAR(39), dq=CHAR(34) 1077 1065 CHARACTER(len=2), PARAMETER :: dsq=CHAR(39)//CHAR(34) … … 1090 1078 !! Check if string represents an intrinsic type 1091 1079 !! 1092 !! The method checks if the given string represents an intrinsic type. Both logical and complex type 1080 !! The method checks if the given string represents an intrinsic type. Both logical and complex type 1093 1081 !! are checked in a strict way : 1094 1082 !! 1095 1083 !! - A string is a logical if it is one of the following value: __.false.__, __.true.__, __F__, __T__. 1096 !! - A string is potentially a complex if it has the following format: __(\*\*\*,\*\*\*)__ where 1084 !! - A string is potentially a complex if it has the following format: __(\*\*\*,\*\*\*)__ where 1097 1085 !! __\*\*\*__ is checked to see wether it is numerical or not. 1098 1086 !! … … 1102 1090 !! [0-9]*.?[0-9]*?([ed][+-]?[0-9]+)? 1103 1091 !! ``` 1104 !! Obviously if returned value is greater than 3, the string can be converted in 1092 !! Obviously if returned value is greater than 3, the string can be converted in 1105 1093 !! floating point value. 1106 1094 !! 1107 !! Empty input string is simply considered to be of string type ! 1095 !! Empty input string is simply considered to be of string type ! 1108 1096 CHARACTER(len=*), INTENT(in) :: str 1109 1097 !! A string to check … … 1213 1201 ALLOCATE(output,source='') ; RETURN 1214 1202 ENDIF 1215 i=0 ; IF (PRESENT(idt1)) i = MAX(i,idt1) 1216 ALLOCATE(CHARACTER(len=i) :: output) 1217 IF (i > 0) output(1:i) = CHAR(32) 1203 i=0 ; IF (PRESENT(idt1)) i = MAX(i,idt1) 1204 ALLOCATE(CHARACTER(len=i) :: output) 1205 IF (i > 0) output(1:i) = CHAR(32) 1218 1206 ! i0 is relative to i1 and must be >= 0 1219 1207 IF (PRESENT(idto)) i = MAX(i+idto,0) 1220 1208 ALLOCATE(CHARACTER(len=i+1) :: idts) 1221 idts(1:1) = NEW_LINE('A') ; IF (i>1) idts(2:) = CHAR(32) 1222 ! Builds output string 1209 idts(1:1) = NEW_LINE('A') ; IF (i>1) idts(2:) = CHAR(32) 1210 ! Builds output string 1223 1211 c=1 ; mx = LEN_TRIM(str) 1224 1212 i = INDEX(str(c:),'\n') ; ti = c+i-1 1225 1213 IF (i == 0) THEN 1226 output=output//TRIM(str(ti+1:mx)) 1214 output=output//TRIM(str(ti+1:mx)) 1227 1215 ELSE 1228 output=output//TRIM(str(c:ti-1)) ; c=ti+2 1216 output=output//TRIM(str(c:ti-1)) ; c=ti+2 1229 1217 DO 1230 1218 i = INDEX(str(c:),"\n") ; ti = c+i-1 1231 1219 IF (i == 0) THEN 1232 output=output//TRIM(str(ti+1:mx)) ; c = mx+1 1220 output=output//TRIM(str(ti+1:mx)) ; c = mx+1 1233 1221 ELSE 1234 1222 output=output//idts//str(c:ti-1) ; c = ti+2 … … 1243 1231 1244 1232 FUNCTION format_paragraph(str,width,idt1,idto) RESULT(output) 1245 !! Split and format a string over several lines 1246 !! 1247 !! The function splits an input string in words so output lines fit (almost) in __width__ characters. 1248 !! The method handles indentation level (defined as leading blank spaces). It also accounts for known 1233 !! Split and format a string over several lines 1234 !! 1235 !! The function splits an input string in words so output lines fit (almost) in __width__ characters. 1236 !! The method handles indentation level (defined as leading blank spaces). It also accounts for known 1249 1237 !! csi (see [[string_op(module):attributes(variable)]]). 1250 1238 !! @note 1251 !! Words are considered indivisible and thus output lines can sometimes exceed the maximum width if 1239 !! Words are considered indivisible and thus output lines can sometimes exceed the maximum width if 1252 1240 !! there is not enough space to put a word (with the associated indentation if given). The default 1253 1241 !! behavior in that case is to print the word in a new line (with the correct leading blank spaces). … … 1256 1244 !! method still computes the paragraph, but each words will be set on a new line with the appropriate 1257 1245 !! indentation. 1258 CHARACTER(len=*), INTENT(in) :: str !! string with the content to split 1246 CHARACTER(len=*), INTENT(in) :: str !! string with the content to split 1259 1247 INTEGER, INTENT(in) :: width !! An positive integer with the maximum width of a line 1260 1248 INTEGER, INTENT(in), OPTIONAL :: idt1 !! An optional integer with the indentation level of the first output line … … 1278 1266 output = str ; RETURN 1279 1267 ENDIF 1280 ! check if can just return the string as is 1268 ! check if can just return the string as is 1281 1269 IF (zmx + l1 <= zw) THEN 1282 1270 output=output//TRIM(zs) ; RETURN 1283 1271 ENDIF 1284 j=1 ; jj=1+l1 1285 DO 1272 j=1 ; jj=1+l1 1273 DO 1286 1274 ! Gets next blank in input string 1287 1275 cc = INDEX(TRIM(zs(j:)),CHAR(32)) … … 1290 1278 ! this value will be substracted to each length test 1291 1279 IF (cc == 0) THEN 1292 l = csis_length(zs(j:)) 1280 l = csis_length(zs(j:)) 1293 1281 IF (jj-1+LEN_TRIM(zs(j:))-l > zw) THEN 1294 1282 output = output//idts … … 1297 1285 EXIT ! we are at the last word : we must exit the infinite loop ! 1298 1286 ELSE 1299 l = csis_length(zs(j:j+cc-1)) 1287 l = csis_length(zs(j:j+cc-1)) 1300 1288 IF (cc+jj-1-l > zw) THEN 1301 1289 output=output//idts//zs(j:j+cc-1) ; jj = lo+1+cc+1 - l … … 1315 1303 INTEGER :: jc,iesc,im 1316 1304 LOGICAL :: tcsi 1317 value = 0 1305 value = 0 1318 1306 jc=1 1319 DO 1307 DO 1320 1308 IF (jc>LEN(str)) EXIT 1321 1309 ! search for escape 1322 1310 iesc = INDEX(str(jc:),CHAR(27)) 1323 IF (iesc == 0) EXIT 1311 IF (iesc == 0) EXIT 1324 1312 ! search for m 1325 1313 im = INDEX(str(jc+iesc:),"m") … … 1328 1316 ! check if this is really a csi and updates length 1329 1317 tcsi = is_csi(str(jc+iesc-1:jc+iesc+im-1)) 1330 jc = jc + iesc 1318 jc = jc + iesc 1331 1319 IF (tcsi) THEN 1332 1320 value=value+im+1 … … 1340 1328 !! Replace newline escape sequences by spaces 1341 1329 !! 1342 !! The function replaces newline (both '\\n' escape sequence and Fortran NEW_LINE() character) in the 1330 !! The function replaces newline (both '\\n' escape sequence and Fortran NEW_LINE() character) in the 1343 1331 !! given string and returns the resulting string. 1344 1332 CHARACTER(len=*), INTENT(in) :: str !! A string to process 1345 1333 CHARACTER(len=1), INTENT(in), OPTIONAL :: rpl !! A optional single character used as substitution of escape sequences (blank space by default) 1346 CHARACTER(len=:), ALLOCATABLE :: stripped !! An allocatable string with all newline sequences replaced by blank space or __rpl__ if given 1334 CHARACTER(len=:), ALLOCATABLE :: stripped !! An allocatable string with all newline sequences replaced by blank space or __rpl__ if given 1347 1335 CHARACTER(len=1) :: zrp 1348 INTEGER :: i, j, ns 1336 INTEGER :: i, j, ns 1349 1337 zrp = CHAR(32) ; IF(PRESENT(rpl)) zrp = rpl 1350 1338 IF (str == NEW_LINE('A')) THEN 1351 stripped = zrp ; RETURN 1339 stripped = zrp ; RETURN 1352 1340 ENDIF 1353 1341 ns = LEN_TRIM(str) … … 1357 1345 ALLOCATE(CHARACTER(len=ns) :: stripped) ; stripped(1:ns) = CHAR(32) 1358 1346 i=1 ; j=1 1359 DO 1347 DO 1360 1348 IF (str(i:i) == NEW_LINE('A')) THEN 1361 stripped(j:j) = zrp 1349 stripped(j:j) = zrp 1362 1350 ELSE IF (i < ns) THEN 1363 1351 IF (str(i:i+1) == "\n") THEN 1364 1352 stripped(j:j) = zrp ; i=i+1 1365 1353 ELSE 1366 stripped(j:j) = str(i:i) 1354 stripped(j:j) = str(i:i) 1367 1355 ENDIF 1368 1356 ELSE 1369 stripped(j:j) = str(i:i) 1357 stripped(j:j) = str(i:i) 1370 1358 ENDIF 1371 1359 j=j+1 ; i=i+1 … … 1378 1366 FUNCTION str_length(str) RESULT(res) 1379 1367 !! Get the length of the string object 1380 !! 1368 !! 1381 1369 !! The method computes the length of the string. It differs from LEN intrinsic function as 1382 1370 !! it does not account for extra-characters of csi codes. … … 1384 1372 INTEGER :: res !! The actual length of string (i.e. does not account for csi codes) 1385 1373 CHARACTER(len=:), ALLOCATABLE :: tmp 1386 res = 0 1374 res = 0 1387 1375 IF (LEN(str) /= 0) THEN 1388 1376 tmp = reset_csi(str) … … 1421 1409 INTEGER :: j,i,ic,icsi,lcsi 1422 1410 IF (LEN(str1) > 0) THEN 1423 str = str1 1411 str = str1 1424 1412 i = 1 1425 1413 DO … … 1442 1430 IF (ic >= 97 .AND. ic < 122) str(j:j) = char(ic-32) 1443 1431 ENDDO 1444 i = i + icsi + lcsi-1 1432 i = i + icsi + lcsi-1 1445 1433 ENDIF 1446 1434 ENDDO … … 1451 1439 1452 1440 FUNCTION str_remove(string,substring,back,all) RESULT(str) 1453 !! Remove substring from current string 1454 !! 1455 !! The function removes the first occurence of __substring__ in __string__ or all 1441 !! Remove substring from current string 1442 !! 1443 !! The function removes the first occurence of __substring__ in __string__ or all 1456 1444 !! its occurences if __all__ is explicitly set to .true.. 1457 1445 CHARACTER(len=*), INTENT(in) :: string !! A string to search in … … 1469 1457 zboff = 0 ; IF (zb) zboff = 1 1470 1458 IF (LEN(string) == 0) RETURN 1471 j=1 1472 DO 1459 j=1 1460 DO 1473 1461 IF (j>LEN(string)) EXIT 1474 1462 ! search for substring … … 1476 1464 IF (is == 0) THEN 1477 1465 ! substring is not found : we get the last part of the string and return 1478 str = str//string(j:) ; RETURN 1466 str = str//string(j:) ; RETURN 1479 1467 ELSE IF (is == 1) THEN 1480 1468 j = j + LEN(substring) … … 1486 1474 ! if we only want to str_remove ONE occurence we exit if substring 1487 1475 ! has been found 1488 IF (.NOT.(is==0.OR.za)) EXIT 1476 IF (.NOT.(is==0.OR.za)) EXIT 1489 1477 ENDDO 1490 1478 IF (j <= LEN(string).AND..NOT.zb) str=str//string(j:) 1491 RETURN 1479 RETURN 1492 1480 END FUNCTION str_remove 1493 1481 1494 1482 FUNCTION str_replace(string,old,new,back,all) RESULT(str) 1495 !! Replace substring from current string 1496 !! 1497 !! The function replaces the first occurence of __old__ in __string__ by 1483 !! Replace substring from current string 1484 !! 1485 !! The function replaces the first occurence of __old__ in __string__ by 1498 1486 !! __new__ or all its occurence(s) if __all__ is explicitly set to .true.. 1499 1487 CHARACTER(len=*), INTENT(in) :: string !! A string to search in … … 1510 1498 IF (PRESENT(all)) za = all 1511 1499 IF (za) zb = .NOT.za 1512 IF (LEN(string) == 0) RETURN 1513 j=1 1514 DO 1500 IF (LEN(string) == 0) RETURN 1501 j=1 1502 DO 1515 1503 IF (j>LEN(string)) EXIT 1516 1504 ! search for "old" … … 1518 1506 IF (is == 0) THEN 1519 1507 ! "old" is not found : we get the last part of the string and return 1520 str = str//string(j:) ; RETURN 1508 str = str//string(j:) ; RETURN 1521 1509 ELSE IF (is == 1) THEN 1522 1510 str = str//new … … 1525 1513 ! "old" is not at the begin of the string : saves the string 1526 1514 str = str//string(j:j+is-2)//new 1527 j = j + is + LEN(old) - 1 1515 j = j + is + LEN(old) - 1 1528 1516 ENDIF 1529 IF (.NOT.(is==0.OR.za)) EXIT 1517 IF (.NOT.(is==0.OR.za)) EXIT 1530 1518 ENDDO 1531 1519 IF (j <= LEN(str)) str=str//string(j:) 1532 RETURN 1520 RETURN 1533 1521 END FUNCTION str_replace 1534 1522 1535 1523 FUNCTION endswith(string,substring,icase) RESULT(ret) 1536 !! Check if string ends by substring 1524 !! Check if string ends by substring 1537 1525 CHARACTER(len=*), INTENT(in) :: string 1538 1526 !! @param[in] string A string to check 1539 1527 CHARACTER(len=*), INTENT(in) :: substring 1540 1528 !! A string to search in __string__ 1541 LOGICAL, INTENT(in), OPTIONAL :: icase 1529 LOGICAL, INTENT(in), OPTIONAL :: icase 1542 1530 !! An optional boolean flag with .true. to perform insensitive case search 1543 1531 LOGICAL :: ret 1544 1532 !! .true. if __string__ ends by __substring__, .false. otherwise. 1545 1533 CHARACTER(len=:), ALLOCATABLE :: zthis,zstr 1546 INTEGER :: idx 1547 LOGICAL :: noc 1534 INTEGER :: idx 1535 LOGICAL :: noc 1548 1536 ret = .false. 1549 1537 noc = .false. ; IF (PRESENT(icase)) noc = icase … … 1560 1548 1561 1549 FUNCTION startswith(string,substring,icase) RESULT(ret) 1562 !! Check if string starts by substring 1550 !! Check if string starts by substring 1563 1551 CHARACTER(len=*), INTENT(in) :: string 1564 1552 !! A string to check 1565 1553 CHARACTER(len=*), INTENT(in) :: substring 1566 1554 !! A string to search in __string__ 1567 LOGICAL, INTENT(in), OPTIONAL :: icase 1555 LOGICAL, INTENT(in), OPTIONAL :: icase 1568 1556 !! An optional boolean flag with .true. to perform insensitive case search 1569 1557 LOGICAL :: ret 1570 1558 !! .true. if __string__ starts by __substring__, .false. otherwise. 1571 1559 CHARACTER(len=:), ALLOCATABLE :: zthis,zstr 1572 INTEGER :: idx 1573 LOGICAL :: noc 1560 INTEGER :: idx 1561 LOGICAL :: noc 1574 1562 ret = .false. 1575 1563 noc = .false. ; IF (PRESENT(icase)) noc = icase … … 1585 1573 END FUNCTION startswith 1586 1574 1587 ! CSI related functions 1575 ! CSI related functions 1588 1576 ! --------------------- 1589 1577 … … 1594 1582 !! returns a copy of it. 1595 1583 CHARACTER(len=*), INTENT(in) :: string 1596 !! @param[in] string A string object reference 1584 !! @param[in] string A string object reference 1597 1585 INTEGER, INTENT(in), DIMENSION(:) :: attrs 1598 1586 !! A vector of integers with the code to add. Each __attrs__ value should refers to one i … … 1613 1601 tmp = string 1614 1602 ENDIF 1615 ! 3) Add all the given csi preceded by <ESC>[0m at the beginning of the string 1603 ! 3) Add all the given csi preceded by <ESC>[0m at the beginning of the string 1616 1604 ! if it does not start by an ANSI sequence 1617 1605 IF (INDEX(tmp,CHAR(27)//"[") /= 1) & 1618 1606 tmp = str_add_to_csi(rcsi,attrs)//tmp 1619 1607 ! Loops on new string and updates csi codes 1620 j=1 1621 DO 1608 j=1 1609 DO 1622 1610 IF (j>LEN(tmp)) EXIT 1623 1611 ! search for escape … … 1646 1634 ENDDO 1647 1635 IF (INDEX(str,rcsi,.true.) /= LEN(str)-3) str = str//rcsi 1648 RETURN 1636 RETURN 1649 1637 END FUNCTION add_csi 1650 1638 … … 1652 1640 !! Remove attributes to the given string 1653 1641 !! 1654 !! The function removes list of csi (ANSI escape sequences) from the given 1642 !! The function removes list of csi (ANSI escape sequences) from the given 1655 1643 !! string and returns a copy of it. 1656 1644 CHARACTER(len=*), INTENT(in) :: string 1657 !! Input string 1658 INTEGER, INTENT(in), DIMENSION(:) :: attrs 1659 !! A vector of integers with the code to remove. Each __attrs__ value should 1645 !! Input string 1646 INTEGER, INTENT(in), DIMENSION(:) :: attrs 1647 !! A vector of integers with the code to remove. Each __attrs__ value should 1660 1648 !! refers to one of [[string_op(module):attributes(variable)]] values. 1661 1649 CHARACTER(len=:), ALLOCATABLE :: str … … 1676 1664 ! Loops on new string and updates csi codes 1677 1665 j=1 ; csis="" 1678 DO 1666 DO 1679 1667 IF (j>LEN(tmp)) EXIT 1680 1668 ! search for escape … … 1705 1693 ! Add <ESC>[0m at the end of string if not found 1706 1694 IF (INDEX(str,rcsi,.true.) /= LEN(str)-3) str = str//rcsi 1707 ! resets all attributes if we only have <ESC>[0m in final list 1708 ok = tokenize(csis(1:LEN(csis)-1),tks,"|") 1695 ! resets all attributes if we only have <ESC>[0m in final list 1696 ok = tokenize(csis(1:LEN(csis)-1),tks,"|") 1709 1697 IF (ALL(tks == rcsi)) str = reset_csi(str) 1710 1698 DEALLOCATE(tks) 1711 RETURN 1699 RETURN 1712 1700 END FUNCTION del_csi 1713 1701 1714 1702 FUNCTION reset_csi(string) RESULT(str) 1715 1703 !! Reset all csi codes of the string 1716 !! 1704 !! 1717 1705 !! The method removes __all__ the known escape sequences from the input string. 1718 1706 CHARACTER(len=*), INTENT(in) :: string 1719 1707 !! Input string 1720 CHARACTER(len=:), ALLOCATABLE :: str 1708 CHARACTER(len=:), ALLOCATABLE :: str 1721 1709 !! An allocatable string with the copy of input string stripped off csi codes. 1722 1710 INTEGER :: j,iesc,im 1723 1711 LOGICAL :: tcsi 1724 1712 str = "" 1725 IF (LEN(string) == 0) RETURN 1726 j=1 1727 DO 1713 IF (LEN(string) == 0) RETURN 1714 j=1 1715 DO 1728 1716 IF (j>LEN(string)) EXIT 1729 1717 ! search for escape … … 1748 1736 j = j + iesc ; IF (tcsi) j=j+im 1749 1737 ENDDO 1750 RETURN 1738 RETURN 1751 1739 END FUNCTION reset_csi 1752 1740 1753 1741 FUNCTION is_csi(value) RESULT(yes) 1754 1742 !! Check if string is a known csi 1755 !! 1743 !! 1756 1744 !! The function only check for known csi code which are defined in [[string_op(module):attributes(variable)]]. 1757 1745 CHARACTER(len=*), INTENT(in) :: value … … 1760 1748 !! .true. if it is a known csi, .false. otherwise 1761 1749 LOGICAL :: ok 1762 CHARACTER(len=:), ALLOCATABLE :: tmp 1750 CHARACTER(len=:), ALLOCATABLE :: tmp 1763 1751 TYPE(words) :: wtks 1764 1752 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: stks … … 1783 1771 FUNCTION str_add_to_csi(csi,list) RESULT(ncsi) 1784 1772 !! Add a new list of codes to the input csi string 1785 !! 1773 !! 1786 1774 !! The method adds all the csi codes given in __list__ that are known by the module and not 1787 1775 !! already present in the input csi. … … 1789 1777 !! A string with the input csi. It __must__ begin with "<ESC>[" and ends with "m". 1790 1778 INTEGER, INTENT(in), DIMENSION(:) :: list 1791 !! A vector of integers with the csi code to add. Each value of __list__ should be one of 1792 !! [[string_op(module):attributes(variable)]] values. All unknown values are filtered out as well 1779 !! A vector of integers with the csi code to add. Each value of __list__ should be one of 1780 !! [[string_op(module):attributes(variable)]] values. All unknown values are filtered out as well 1793 1781 !! as csi code already present in input __csi__. 1794 CHARACTER(len=:), ALLOCATABLE :: ncsi 1795 !! A new csi string or the input __csi__ if some "errors" occured (the input csi could not 1782 CHARACTER(len=:), ALLOCATABLE :: ncsi 1783 !! A new csi string or the input __csi__ if some "errors" occured (the input csi could not 1796 1784 !! be tokenized or none of __list__ values are left after filtering). 1797 LOGICAL :: ok 1785 LOGICAL :: ok 1798 1786 CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: tks 1799 1787 CHARACTER(len=:), ALLOCATABLE :: tmp … … 1801 1789 INTEGER :: i,j,ni,no 1802 1790 ! 1) Filter input list : 1803 ! 1.1) Gets the list of current csi codes 1804 ncsi = csi(3:len(csi)-1) 1791 ! 1.1) Gets the list of current csi codes 1792 ncsi = csi(3:len(csi)-1) 1805 1793 ok = tokenize(ncsi,tks,"; ",merge=.true.) 1806 1794 IF (.NOT.from_string(tks,nums)) THEN … … 1809 1797 ENDIF 1810 1798 DEALLOCATE(tks) 1811 ! 1.2) Filter input list of new flags to add 1799 ! 1.2) Filter input list of new flags to add 1812 1800 ! counts number of valid flags 1813 j=0 1814 DO i=1,SIZE(list) 1801 j=0 1802 DO i=1,SIZE(list) 1815 1803 ! new flags must be in attributes but NOT in nums 1816 1804 IF (ANY(attributes==list(i).AND..NOT.ANY(nums == list(i)))) j=j+1 … … 1820 1808 ni = SIZE(nums) ; no = j + ni 1821 1809 ALLOCATE(zlist(no)) ; zlist(1:ni) = nums(:) ; j = ni 1822 DO i=1,SIZE(list) 1810 DO i=1,SIZE(list) 1823 1811 ! new flags must be in attributes but NOT in nums 1824 1812 IF (ANY(attributes==list(i).AND..NOT.ANY(nums == list(i)))) THEN 1825 1813 j=j+1 ; zlist(j) = list(i) 1826 ENDIF 1814 ENDIF 1827 1815 ENDDO 1828 1816 DEALLOCATE(nums) … … 1831 1819 ncsi = CHAR(27)//"[0;" 1832 1820 DO i=1,no 1833 ! ... So we get rid of all "0" flag in the list 1821 ! ... So we get rid of all "0" flag in the list 1834 1822 IF (zlist(i) /= 0) THEN 1835 1823 tmp = to_string(zlist(i)) … … 1841 1829 ENDIF 1842 1830 ENDDO 1843 ncsi = ncsi//"m" 1831 ncsi = ncsi//"m" 1844 1832 END FUNCTION str_add_to_csi 1845 1833 … … 1852 1840 !! An intrinsic Fortran string with the input csi. It __must__ begin with "<ESC>[" and ends with "m". 1853 1841 INTEGER, INTENT(in), DIMENSION(:) :: list 1854 !! A vector of integers with the csi code to remove. Each value of __list__ should be one of 1842 !! A vector of integers with the csi code to remove. Each value of __list__ should be one of 1855 1843 !! [[string_op(module):attributes(variable)]] values. All unknown values are filtered out. 1856 CHARACTER(len=:), ALLOCATABLE :: ncsi 1857 !! A new csi string or the input __csi__ if some "errors" occured (the input csi could not 1844 CHARACTER(len=:), ALLOCATABLE :: ncsi 1845 !! A new csi string or the input __csi__ if some "errors" occured (the input csi could not 1858 1846 !! be tokenized or none of __list__ values are left after filtering). 1859 1847 LOGICAL :: ok … … 1862 1850 INTEGER, DIMENSION(:), ALLOCATABLE :: nums 1863 1851 INTEGER :: i 1864 ncsi = csi(3:len(csi)-1) 1865 ok = tokenize(ncsi,tks,"; ",merge=.true.) 1866 IF (.NOT.from_string(tks,nums)) THEN 1867 ncsi = csi 1868 RETURN 1852 ncsi = csi(3:len(csi)-1) 1853 ok = tokenize(ncsi,tks,"; ",merge=.true.) 1854 IF (.NOT.from_string(tks,nums)) THEN 1855 ncsi = csi 1856 RETURN 1869 1857 ENDIF 1870 1858 DEALLOCATE(tks) … … 1886 1874 !! Get the position of the first known csi in string 1887 1875 !! 1888 !! The method searches for the first known csi in string. The csi must contain known codes 1876 !! The method searches for the first known csi in string. The csi must contain known codes 1889 1877 !! (i.e. values of [[string_op(module):attributes(variable)]]). 1890 1878 CHARACTER(len=*), INTENT(in) :: str !! A string to search in … … 1894 1882 pos = 0 ; length = 0 1895 1883 ! we need at least 4 chars to create a csi 1896 IF (LEN_TRIM(str) < 4) RETURN 1884 IF (LEN_TRIM(str) < 4) RETURN 1897 1885 iesc = INDEX(str,CHAR(27)) 1898 1886 IF (iesc == 0) RETURN … … 1975 1963 COMPLEX(kind=4), INTENT(out) :: value !! Output value 1976 1964 LOGICAL :: ret !! Return status (.true. on success) 1977 ! - LOCAL 1965 ! - LOCAL 1978 1966 CHARACTER(len=:), ALLOCATABLE :: zs 1979 1967 ret = .true. ; zs = remove_quotes(str) … … 2028 2016 CHARACTER(len=*), INTENT(in), DIMENSION(:) :: str !! Vector of strings to convert 2029 2017 REAL(kind=4), INTENT(out), DIMENSION(:), ALLOCATABLE :: value !! Vector of output values 2030 LOGICAL :: ret !! Return status (.true. on success) 2018 LOGICAL :: ret !! Return status (.true. on success) 2031 2019 INTEGER :: i,ns 2032 2020 CHARACTER(len=:), ALLOCATABLE :: zs … … 2081 2069 2082 2070 FUNCTION int2str_as(value) RESULT(str) 2083 !! Convert an integer value to string (auto format / string result) 2071 !! Convert an integer value to string (auto format / string result) 2084 2072 INTEGER, INTENT(in) :: value !! Value to convert 2085 2073 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2088 2076 WRITE(str,*,iostat=err) value 2089 2077 str = TRIM(ADJUSTL(str)) 2090 IF (err /= 0) str = '' 2078 IF (err /= 0) str = '' 2091 2079 RETURN 2092 2080 END FUNCTION int2str_as 2093 2081 2094 2082 FUNCTION log2str_as(value) RESULT(str) 2095 !! Convert a logical value to string (auto format / string result) 2083 !! Convert a logical value to string (auto format / string result) 2096 2084 LOGICAL, INTENT(in) :: value !! Value to convert 2097 2085 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2105 2093 2106 2094 FUNCTION real2str_as(value) RESULT(str) 2107 !! Convert a simple precision floating point value to string (auto format / string result) 2095 !! Convert a simple precision floating point value to string (auto format / string result) 2108 2096 REAL(kind=4), INTENT(in) :: value !! Value to convert 2109 2097 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2112 2100 WRITE(str,*, IOSTAT = err) value 2113 2101 str=TRIM(ADJUSTL(str)) 2114 IF (err /= 0) str = '' 2102 IF (err /= 0) str = '' 2115 2103 RETURN 2116 2104 END FUNCTION real2str_as 2117 2105 2118 2106 FUNCTION dble2str_as(value) RESULT(str) 2119 !! Convert a double precision floating point value to string (auto format / string result) 2107 !! Convert a double precision floating point value to string (auto format / string result) 2120 2108 REAL(kind=8), INTENT(in) :: value !! Value to convert 2121 2109 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2124 2112 WRITE(str,*, IOSTAT = err) value 2125 2113 str=TRIM(ADJUSTL(str)) 2126 IF (err /= 0) str = '' 2114 IF (err /= 0) str = '' 2127 2115 RETURN 2128 2116 END FUNCTION dble2str_as 2129 2117 2130 2118 FUNCTION cplx2str_as(value) RESULT(str) 2131 !! Convert a complex value to string (auto format / string result) 2119 !! Convert a complex value to string (auto format / string result) 2132 2120 COMPLEX(kind=4), INTENT(in) :: value !! Value to convert 2133 2121 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2137 2125 WRITE(str, *, IOSTAT = err) value 2138 2126 str = TRIM(ADJUSTL(str)) 2139 IF (err /= 0) str = '' 2127 IF (err /= 0) str = '' 2140 2128 RETURN 2141 2129 END FUNCTION cplx2str_as 2142 2130 2143 2131 FUNCTION dcplx2str_as(value) RESULT(str) 2144 !! Convert a complex value to string (auto format / string result) 2132 !! Convert a complex value to string (auto format / string result) 2145 2133 COMPLEX(kind=8), INTENT(in) :: value !! Value to convert 2146 2134 CHARACTER(len=:), ALLOCATABLE :: str !! String with the converted value in output … … 2150 2138 WRITE(str, *, IOSTAT = err) value 2151 2139 str = TRIM(ADJUSTL(str)) 2152 IF (err /= 0) str = '' 2140 IF (err /= 0) str = '' 2153 2141 RETURN 2154 2142 END FUNCTION dcplx2str_as 2155 2143 2156 2144 FUNCTION int2str_fs(value, fmt) RESULT(str) 2157 !! Convert an integer value to string (user format / string result) 2145 !! Convert an integer value to string (user format / string result) 2158 2146 INTEGER, INTENT(in) :: value !! Value to convert 2159 2147 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2163 2151 WRITE(str, '('//fmt//')', IOSTAT = err) value 2164 2152 str = TRIM(ADJUSTL(str)) 2165 IF (err /= 0) str = '' 2153 IF (err /= 0) str = '' 2166 2154 RETURN 2167 2155 END FUNCTION int2str_fs 2168 2156 2169 2157 FUNCTION log2str_fs(value, fmt) RESULT(str) 2170 !! Convert a logical value to string (user format / string result) 2158 !! Convert a logical value to string (user format / string result) 2171 2159 LOGICAL, INTENT(in) :: value !! Value to convert 2172 2160 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2176 2164 WRITE(str, '('//fmt//')', IOSTAT = err) value 2177 2165 str=TRIM(ADJUSTL(str)) 2178 IF (err /= 0) str = '' 2166 IF (err /= 0) str = '' 2179 2167 RETURN 2180 2168 END FUNCTION log2str_fs 2181 2169 2182 2170 FUNCTION real2str_fs(value, fmt) RESULT(str) 2183 !! Convert a simple precision floating point value to string (user format / string result) 2171 !! Convert a simple precision floating point value to string (user format / string result) 2184 2172 REAL(kind=4), INTENT(in) :: value !! Value to convert 2185 2173 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2189 2177 WRITE(str, '('//fmt//')', IOSTAT = err) value 2190 2178 str = TRIM(ADJUSTL(str)) 2191 IF (err /= 0) str = '' 2179 IF (err /= 0) str = '' 2192 2180 RETURN 2193 2181 END FUNCTION real2str_fs 2194 2182 2195 2183 FUNCTION dble2str_fs(value, fmt) RESULT(str) 2196 !! Convert a double precision floating point value to string (user format / string result) 2184 !! Convert a double precision floating point value to string (user format / string result) 2197 2185 REAL(kind=8), INTENT(in) :: value !! Value to convert 2198 2186 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2202 2190 WRITE(str, '('//fmt//')', IOSTAT = err) value 2203 2191 str = TRIM(ADJUSTL(str)) 2204 IF (err /= 0) str = '' 2192 IF (err /= 0) str = '' 2205 2193 RETURN 2206 2194 END FUNCTION dble2str_fs 2207 2195 2208 2196 FUNCTION cplx2str_fs(value, fmt) RESULT(str) 2209 !! Convert a complex value to string (user format / string result) 2197 !! Convert a complex value to string (user format / string result) 2210 2198 COMPLEX(kind=4), INTENT(in) :: value !! Value to convert 2211 2199 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2215 2203 WRITE(str, '('//fmt//')', IOSTAT = err) value 2216 2204 str = TRIM(ADJUSTL(str)) 2217 IF (err /= 0) str = '' 2205 IF (err /= 0) str = '' 2218 2206 RETURN 2219 2207 END FUNCTION cplx2str_fs 2220 2208 2221 2209 FUNCTION dcplx2str_fs(value, fmt) RESULT(str) 2222 !! Convert a complex value to string (user format / string result) 2210 !! Convert a complex value to string (user format / string result) 2223 2211 COMPLEX(kind=8), INTENT(in) :: value !! Value to convert 2224 2212 CHARACTER(len=*), INTENT(in) :: fmt !! String format … … 2228 2216 WRITE(str, '('//fmt//')', IOSTAT = err) value 2229 2217 str = TRIM(ADJUSTL(str)) 2230 IF (err /= 0) str = '' 2218 IF (err /= 0) str = '' 2231 2219 RETURN 2232 2220 END FUNCTION dcplx2str_fs … … 2240 2228 INTEGER, INTENT(in) :: int2 !! Integer to concatenate 2241 2229 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2242 ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 2230 ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 2243 2231 WRITE(str,*) int2 ; str = TRIM(ADJUSTL(str)) 2244 2232 IF (LEN(str1) /= 0) str = str1//str … … 2251 2239 FUNCTION fis_cat_int_inv(int2,str1) RESULT(str) 2252 2240 !! Concatenate a fortran intrinsic string with a integer (reversed). 2253 INTEGER, INTENT(in) :: int2 !! Integer to concatenate 2241 INTEGER, INTENT(in) :: int2 !! Integer to concatenate 2254 2242 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2255 2243 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2256 ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 2244 ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 2257 2245 WRITE(str,*) int2 ; str = TRIM(ADJUSTL(str)) 2258 2246 IF (LEN(str1) /= 0) str = str//str1 … … 2266 2254 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2267 2255 CHARACTER(len=2) ::tmp 2268 WRITE(tmp,*) bool2 2256 WRITE(tmp,*) bool2 2269 2257 str=TRIM(ADJUSTL(tmp)) 2270 2258 IF (LEN(str1) /= 0) str = str1//str … … 2277 2265 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2278 2266 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2279 CHARACTER(len=2) ::tmp 2280 WRITE(tmp,*) bool2 2267 CHARACTER(len=2) ::tmp 2268 WRITE(tmp,*) bool2 2281 2269 str = TRIM(ADJUSTL(tmp)) 2282 2270 IF (LEN(str1) /= 0) str = str//str1 … … 2289 2277 REAL(kind=4), INTENT(in) :: real2 !! Simple precision real to concatenate 2290 2278 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2291 ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 2279 ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 2292 2280 WRITE(str,*) real2 ; str = TRIM(ADJUSTL(str)) 2293 IF (LEN(str1) /= 0) str=str1//str 2281 IF (LEN(str1) /= 0) str=str1//str 2294 2282 RETURN 2295 2283 END FUNCTION fis_cat_real … … 2300 2288 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2301 2289 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2302 ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 2290 ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 2303 2291 WRITE(str,*) real2 ; str = TRIM(ADJUSTL(str)) 2304 2292 IF (LEN(str1) /= 0) str = str//str1 … … 2311 2299 REAL(kind=8), INTENT(in) :: double2 !! Double precision real to concatenate 2312 2300 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2313 ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 2301 ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 2314 2302 WRITE(str,*) double2 ; str = TRIM(ADJUSTL(str)) 2315 IF (LEN(str1) /= 0) str=str1//str 2303 IF (LEN(str1) /= 0) str=str1//str 2316 2304 RETURN 2317 2305 END FUNCTION fis_cat_double … … 2322 2310 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2323 2311 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2324 ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 2312 ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 2325 2313 WRITE(str,*) double2 ; str = TRIM(ADJUSTL(str)) 2326 2314 IF (LEN(str1) /= 0) str = str//str1 … … 2329 2317 2330 2318 FUNCTION fis_cat_cplx(str1,cplx2) RESULT(str) 2331 !! Concatenate a string with a complex 2332 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2333 COMPLEX(kind=4), INTENT(in) :: cplx2 !! Complex value to concatenate 2319 !! Concatenate a string with a complex 2320 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2321 COMPLEX(kind=4), INTENT(in) :: cplx2 !! Complex value to concatenate 2334 2322 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2335 2323 INTEGER :: sl … … 2343 2331 FUNCTION fis_cat_cplx_inv(cplx2,str1) RESULT(str) 2344 2332 !! Concatenate a string with a complex (reversed) 2345 COMPLEX(kind=4), INTENT(in) :: cplx2 !! Complex value to concatenate 2346 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2333 COMPLEX(kind=4), INTENT(in) :: cplx2 !! Complex value to concatenate 2334 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2347 2335 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2348 2336 INTEGER :: sl … … 2356 2344 2357 2345 FUNCTION fis_cat_dcplx(str1,dcplx2) RESULT(str) 2358 !! Concatenate a string with a double precision complex 2346 !! Concatenate a string with a double precision complex 2359 2347 CHARACTER(len=*), INTENT(in) :: str1 !! String to concatenate 2360 COMPLEX(kind=8), INTENT(in) :: dcplx2 !! Complex value to concatenate 2348 COMPLEX(kind=8), INTENT(in) :: dcplx2 !! Complex value to concatenate 2361 2349 CHARACTER(len=:), ALLOCATABLE :: str !! Output string 2362 2350 INTEGER :: sl … … 2370 2358 FUNCTION fis_cat_dcplx_inv(dcplx2,str1) RESULT(str) 2371 2359 !! Concatenate a string with a double precision complex (reversed) 2372 COMPLEX(kind=8), INTENT(in) :: dcplx2 !! Complex value to concatenate 2360 COMPLEX(kind=8), INTENT(in) :: dcplx2 !! Complex value to concatenate 2373 2361 CHARACTER(len=*), INTENT(in) :: str1 !! string to concatenate 2374 2362 CHARACTER(len=:), ALLOCATABLE :: str !! Output string … … 2383 2371 2384 2372 SUBROUTINE fis_affect_int(str,int) 2385 !! Assignment subroutine (using intrinsic integer) 2373 !! Assignment subroutine (using intrinsic integer) 2386 2374 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2387 INTEGER, INTENT(in) :: int !! Input value to assign 2375 INTEGER, INTENT(in) :: int !! Input value to assign 2388 2376 str = fis_cat_int('',int) 2389 2377 END SUBROUTINE fis_affect_int 2390 2378 2391 2379 SUBROUTINE fis_affect_bool(str,bool) 2392 !! Assignment subroutine (using intrinsic logical) 2380 !! Assignment subroutine (using intrinsic logical) 2393 2381 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2394 2382 LOGICAL, INTENT(in) :: bool !! Input value to assign … … 2397 2385 2398 2386 SUBROUTINE fis_affect_real(str,float) 2399 !! Assignment subroutine (using intrinsic real) 2387 !! Assignment subroutine (using intrinsic real) 2400 2388 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2401 2389 REAL(kind=4), INTENT(in) :: float !! Input value to assign … … 2404 2392 2405 2393 SUBROUTINE fis_affect_double(str,double) 2406 !! Assignment subroutine (using intrinsic real(kind=8)) 2394 !! Assignment subroutine (using intrinsic real(kind=8)) 2407 2395 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2408 REAL(kind=8), INTENT(in) :: double !! Input value to assign 2396 REAL(kind=8), INTENT(in) :: double !! Input value to assign 2409 2397 str = fis_cat_double('',double) 2410 2398 END SUBROUTINE fis_affect_double 2411 2399 2412 2400 SUBROUTINE fis_affect_cplx(str,cplx) 2413 !! Assignment subroutine (using intrinsic complex) 2401 !! Assignment subroutine (using intrinsic complex) 2414 2402 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2415 2403 COMPLEX(kind=4), INTENT(in) :: cplx !! Input value to assign … … 2418 2406 2419 2407 SUBROUTINE fis_affect_dcplx(str,dcplx) 2420 !! Assignment subroutine (using intrinsic complex(kind=8)) 2408 !! Assignment subroutine (using intrinsic complex(kind=8)) 2421 2409 CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str !! Output string to be assigned 2422 2410 COMPLEX(kind=8), INTENT(in) :: dcplx !! Input value to assign … … 2429 2417 !! Only know CSI codes are returned. If no known CSI are found the outputput vector is 2430 2418 !! allocated with 0 elements. 2431 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2419 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2432 2420 INTEGER, DIMENSION(:), ALLOCATABLE :: codes !! CSI codes. 2433 2421 INTEGER :: i,j,n … … 2454 2442 FUNCTION fancy_fstr(value,flags,fmt) RESULT(output) 2455 2443 !! Compute a fancy string from the given (fortran intrinsic) string. 2456 CHARACTER(len=*), INTENT(in) :: value !! String object reference 2444 CHARACTER(len=*), INTENT(in) :: value !! String object reference 2457 2445 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2458 2446 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format (unused for this overload) 2459 2447 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2460 2448 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2461 codes = get_attrs_indexes(flags) 2449 codes = get_attrs_indexes(flags) 2462 2450 IF (SIZE(codes) == 0) THEN 2463 2451 output = value ; RETURN … … 2469 2457 FUNCTION fancy_int(value,flags,fmt) RESULT(output) 2470 2458 !! Compute a fancy string from the given integer value. 2471 INTEGER, INTENT(in) :: value !! String object reference 2459 INTEGER, INTENT(in) :: value !! String object reference 2472 2460 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2473 2461 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2474 2462 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2475 2463 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2476 CHARACTER(len=:), ALLOCATABLE :: tmp 2477 codes = get_attrs_indexes(flags) 2464 CHARACTER(len=:), ALLOCATABLE :: tmp 2465 codes = get_attrs_indexes(flags) 2478 2466 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2479 2467 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF … … 2482 2470 FUNCTION fancy_bool(value,flags,fmt) RESULT(output) 2483 2471 !! Compute a fancy string from the given logical value. 2484 LOGICAL, INTENT(in) :: value !! String object reference 2472 LOGICAL, INTENT(in) :: value !! String object reference 2485 2473 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2486 2474 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2487 2475 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2488 2476 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2489 CHARACTER(len=:), ALLOCATABLE :: tmp 2490 codes = get_attrs_indexes(flags) 2477 CHARACTER(len=:), ALLOCATABLE :: tmp 2478 codes = get_attrs_indexes(flags) 2491 2479 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2492 2480 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF … … 2495 2483 FUNCTION fancy_real(value,flags,fmt) RESULT(output) 2496 2484 !! Compute a fancy string from the given real value (simple precision). 2497 REAL(kind=4), INTENT(in) :: value !! String object reference 2485 REAL(kind=4), INTENT(in) :: value !! String object reference 2498 2486 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2499 2487 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2500 2488 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2501 2489 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2502 CHARACTER(len=:), ALLOCATABLE :: tmp 2503 codes = get_attrs_indexes(flags) 2490 CHARACTER(len=:), ALLOCATABLE :: tmp 2491 codes = get_attrs_indexes(flags) 2504 2492 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2505 2493 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF 2506 END FUNCTION fancy_real 2494 END FUNCTION fancy_real 2507 2495 2508 2496 FUNCTION fancy_double(value,flags,fmt) RESULT(output) 2509 2497 !! Compute a fancy string from the given real value (double precision). 2510 REAL(kind=8), INTENT(in) :: value !! String object reference 2498 REAL(kind=8), INTENT(in) :: value !! String object reference 2511 2499 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2512 2500 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2513 2501 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2514 2502 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2515 CHARACTER(len=:), ALLOCATABLE :: tmp 2516 codes = get_attrs_indexes(flags) 2503 CHARACTER(len=:), ALLOCATABLE :: tmp 2504 codes = get_attrs_indexes(flags) 2517 2505 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2518 2506 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF … … 2521 2509 FUNCTION fancy_cplx(value,flags,fmt) RESULT(output) 2522 2510 !! Compute a fancy string from the given complex value (simple precision). 2523 COMPLEX(kind=4), INTENT(in) :: value !! String object reference 2511 COMPLEX(kind=4), INTENT(in) :: value !! String object reference 2524 2512 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2525 2513 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2526 2514 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2527 2515 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2528 CHARACTER(len=:), ALLOCATABLE :: tmp 2529 codes = get_attrs_indexes(flags) 2516 CHARACTER(len=:), ALLOCATABLE :: tmp 2517 codes = get_attrs_indexes(flags) 2530 2518 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2531 2519 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF 2532 2520 END FUNCTION fancy_cplx 2533 2521 2534 2522 FUNCTION fancy_dcplx(value,flags,fmt) RESULT(output) 2535 2523 !! Compute a fancy string from the given complex value (double precision). 2536 COMPLEX(kind=8), INTENT(in) :: value !! String object reference 2524 COMPLEX(kind=8), INTENT(in) :: value !! String object reference 2537 2525 CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags !! CSI attributes flags 2538 2526 CHARACTER(len=*), INTENT(in), OPTIONAL :: fmt !! Optional format. If given it must be a valid Fortran format. 2539 2527 CHARACTER(len=:), ALLOCATABLE :: output !! Output fortran instrinsic string 2540 2528 INTEGER, DIMENSION(:), ALLOCATABLE :: codes 2541 CHARACTER(len=:), ALLOCATABLE :: tmp 2542 codes = get_attrs_indexes(flags) 2529 CHARACTER(len=:), ALLOCATABLE :: tmp 2530 codes = get_attrs_indexes(flags) 2543 2531 IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF 2544 2532 IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
Note: See TracChangeset
for help on using the changeset viewer.