Ignore:
Timestamp:
Oct 12, 2023, 10:30:22 AM (15 months ago)
Author:
slebonnois
Message:

BBT : Update for the titan microphysics and cloud model

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.
    3321
    3422!! file: argparse.F90
    3523!! summary: Command-line parser source file.
    3624!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826
    3927#include "defined.h"
     
    4533  !! For your own sanity, private methods that call Ancient Gods powers through
    4634  !! evil black magic rituals are not described here.
    47   !! 
     35  !!
    4836  !! If you only wish to have an overview of argparse usage, you'd better go
    4937  !! [here](|url|/page/swift/p01_argparse.html).
     
    5240  USE ERRORS
    5341  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
    5543  IMPLICIT NONE
    5644
     
    6856            argparser_add_option,       &
    6957            argparser_add_positionals,  &
    70             argparser_throw_error,      & 
     58            argparser_throw_error,      &
    7159            argparser_parse,            &
    7260            argparser_help,             &
     
    8573  ! ===========================
    8674
    87   INTEGER, PARAMETER, PUBLIC :: ap_string  = st_string 
     75  INTEGER, PARAMETER, PUBLIC :: ap_string  = st_string
    8876    !! String value type identifier.
    8977  INTEGER, PARAMETER, PUBLIC :: ap_complex = st_complex
     
    9886  !> List of all available actions
    9987
    100   INTEGER, PARAMETER, PUBLIC :: ap_store  = 1
     88  INTEGER, PARAMETER, PUBLIC :: ap_store   = 1
    10189    !! store action ID : Each time the option is seen, values are replaced.
    102   INTEGER, PARAMETER, PUBLIC :: ap_append = 2
    103     !! append action ID : Each time the option is seen, values are appended. 
    104   INTEGER, PARAMETER, PUBLIC :: ap_count  = 3
     90  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
    10593    !! count action ID : increase a counter each time the option is seen.
    106   INTEGER, PARAMETER, PUBLIC :: ap_help   = 4
     94  INTEGER, PARAMETER, PUBLIC :: ap_help    = 4
    10795    !! help action ID : help is requested !
     96  INTEGER, PARAMETER, PUBLIC :: ap_version = 5
     97    !! version action ID : version is requested !
    10898
    10999  !> 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,  &
    111101                                                              ap_append, &
    112102                                                              ap_count,  &
    113                                                               ap_help/)
     103                                                              ap_help,   &
     104                                                              ap_version/)
    114105  !> 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,  &
    116107                                                            ap_logical, &
    117108                                                            ap_complex, &
    118109                                                            ap_integer, &
    119                                                             ap_real/) 
     110                                                            ap_real/)
    120111  !> The unknown flag
    121112  !!
    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
    123114  !! and quielty replaced by default flags, if user does not provide the relevant feature.
    124115  INTEGER, PARAMETER :: ap_undef = -1
    125    
     116
    126117  !> Add an option to the parser
    127118  !!
     
    131122  !! ```
    132123  !!
    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  !!
    136127  !! In its first version both short (`sflag`) and long (`lflag`) options flags are mandatory. In its second
    137128  !! form, a single flag (`flag`) is expected: the method will automatically deduce if it belongs to short or
    138129  !! a long option flag based on the number of hyphens given.
    139   !! 
     130  !!
    140131  !! `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]):
    141132  !!
     
    145136  !! - `ap_integer` ([[string_op(module):st_integer(variable)]])
    146137  !! - `ap_real` ([[string_op(module):st_real(variable)]])
    147   !! 
     138  !!
    148139  !! `action` value should be one of the following module constants:
    149140  !!
     
    162153  !!  "X"  | Exactly X values. Where X is the string representation of an integer (0 is accepted).
    163154  !!
    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
    165156  !! produced by misuse of the function arguments. In such case, the program should be
    166157  !! stopped: note that such error should not occur in _released_ programs.
     
    168159    MODULE PROCEDURE ap_add_option_1, ap_add_option_2
    169160  END INTERFACE
    170  
     161
    171162  !> Get positional argument value(s)
    172163  INTERFACE argparser_get_positional
    173164    MODULE PROCEDURE ap_get_positional_sc, ap_get_positional_ve
    174   END INTERFACE 
     165  END INTERFACE
    175166
    176167  !> Get optional argument value(s)
     
    179170  !! FUNCTION argparser_get_value(this,name,output) RESULT(err)
    180171  !! ```
    181   !! 
     172  !!
    182173  !! This is the generic method that can be used to retrieve any kind of argument value(s) from the parser for a given
    183174  !! argument name (as defined by the `dest` argument of [[argparse(module):argparser_add_option(interface)]].
    184175  !! All the methods have the same dummy arguments only `output` dummy argument differs in type and shape.
    185   !! 
     176  !!
    186177  !! @note
    187178  !! For string vector, `output` is expected to be an allocatable vector of **assumed length**
    188179  !! 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)]]
    190181  !! parameter.
    191182  INTERFACE argparser_get_value
     
    197188  !> Interface to [[argparse(module):argc(type)]] getters
    198189  !!
    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
    200191  !! from a function to the other.
    201   INTERFACE argc_get_value                   
     192  INTERFACE argc_get_value
    202193    MODULE PROCEDURE ac_get_dv_sc, ac_get_rv_sc, ac_get_iv_sc, ac_get_lv_sc, &
    203194                     ac_get_cv_sc, ac_get_sv_sc, ac_get_dv_ve, ac_get_rv_ve, &
     
    230221    !! Defines a command-line argument.
    231222    !!
    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
    233224    !! argument, that is:
    234225    !!
    235226    !! - its name
    236     !! - its optional flags 
     227    !! - its optional flags
    237228    !! - its type
    238229    !! - its action
     
    253244    TYPE(words)      :: meta
    254245      !! Meta variable name(s) of the argument
    255 #if HAVE_FTNDTSTR 
     246#if HAVE_FTNDTSTR
    256247    CHARACTER(len=:), ALLOCATABLE :: default
    257       !! Default flag 
     248      !! Default flag
    258249    CHARACTER(len=:), ALLOCATABLE :: name
    259250      !! Name of the argument (needed to check and retrieve its value(s))
    260     CHARACTER(len=:), ALLOCATABLE :: lflag 
     251    CHARACTER(len=:), ALLOCATABLE :: lflag
    261252      !! Long flag option (st_short_len max chars !)
    262253    CHARACTER(len=:), ALLOCATABLE :: help
     
    264255#else
    265256    CHARACTER(len=st_slen) :: default = ""
    266       !! Default flag 
     257      !! Default flag
    267258    CHARACTER(len=st_slen) :: name
    268259      !! Name of the argument (needed to check and retrieve its value(s))
     
    278269    !! Command-line parser
    279270    !!
    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
    281272    !! their value(s) once the command-line have been parsed.
    282273    TYPE(argc), PRIVATE, ALLOCATABLE, DIMENSION(:) :: args
     
    298289#if HAVE_FTNDTSTR
    299290    CHARACTER(len=:), PRIVATE, ALLOCATABLE :: usg
    300       !! Program command usage 
     291      !! Program command usage
    301292    CHARACTER(len=:), PRIVATE, ALLOCATABLE :: descr
    302293      !! Program help description
    303     CHARACTER(len=:), PRIVATE, ALLOCATABLE :: eplg 
     294    CHARACTER(len=:), PRIVATE, ALLOCATABLE :: eplg
    304295      !! Program help epilog
     296    CHARACTER(len=:), PRIVATE, ALLOCATABLE :: vers
     297      !! Application version string
    305298#else
    306299    CHARACTER(len=st_llen), PRIVATE :: usg
    307       !! Program command usage 
     300      !! Program command usage
    308301    CHARACTER(len=st_llen), PRIVATE :: descr
    309302      !! Program help description
    310     CHARACTER(len=st_llen), PRIVATE :: eplg 
     303    CHARACTER(len=st_llen), PRIVATE :: eplg
    311304      !! Program help epilog
     305    CHARACTER(len=st_llen), PRIVATE :: vers
     306      !! Application version string
    312307#endif
    313     INTEGER, PRIVATE :: mxhlpos = 20 
     308    INTEGER, PRIVATE :: mxhlpos = 20
    314309      !! Position of the short help for options
    315310    INTEGER, PRIVATE :: width = 0
    316       !! Maximum width of the help 
     311      !! Maximum width of the help
    317312    LOGICAL, PRIVATE :: init = .false.
    318313      !! Initialization control flag
    319 #if HAVE_FTNPROC   
     314#if HAVE_FTNPROC
    320315
    321316    CONTAINS
     
    341336    PROCEDURE, PUBLIC  :: parse              => argparser_parse
    342337      !! Parse the command-line (or the given input string).
    343     PROCEDURE, PUBLIC  :: help               => argparser_help 
     338    PROCEDURE, PUBLIC  :: help               => argparser_help
    344339      !! Compute and print help
     340    PROCEDURE, PUBLIC  :: version            => argparser_version
     341      !! print version string
    345342    PROCEDURE, PUBLIC  :: found              => argparser_found
    346343      !! Check if an optional argument has been found on the command-line
     
    356353    GENERIC, PUBLIC    :: add_option         => ap_add_option_1, &
    357354                                                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.
    359356    GENERIC, PUBLIC    :: get_positional     => ap_get_positional_sc, &
    360357                                                ap_get_positional_ve
     
    372369                                                ap_get_cv_ve, &
    373370                                                ap_get_sv_ve
    374 #endif       
     371#endif
    375372  END TYPE argparser
    376373
     
    380377  ! -------------------------------
    381378
    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)
    383380    !! Initialize an argparser object.
    384     !! 
     381    !!
    385382    !! 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
    387384    !! before using an argparser object.
    388385    CHARACTER(len=*), INTENT(in), OPTIONAL :: usg
     
    394391      !! An optional string with the epilog of the program's help
    395392    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.
    397394      !! 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.
    398401    INTEGER, INTENT(in), OPTIONAL          :: width
    399402      !! An optional integer with the maximum width the help text.
    400403    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
    404407      !! options flags.
    405     TYPE(argparser) :: this 
     408    TYPE(argparser) :: this
    406409      !! An initialized argparse object.
    407410    INTEGER     :: zh
     
    413416    IF (PRESENT(dsc)) THEN ; this%descr=dsc ; ELSE ; this%descr='' ; ENDIF
    414417    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)
    416419    IF (PRESENT(width)) this%width = MAX(width,50)
    417420    IF(PRESENT(max_help_pos)) this%mxhlpos = MAX(5,max_help_pos)
     
    422425                    action=ap_help, help="Print this help and quit")
    423426    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
    424434    RETURN
    425435  END FUNCTION new_argparser
     
    432442    !! @note If **fccp** has not been built with support for finalization subroutine,
    433443    !! it should be called whenever the argparser object is no more used.
    434     TYPE(argparser), INTENT(inout) :: this 
     444    TYPE(argparser), INTENT(inout) :: this
    435445      !! An argparser object
    436446    IF (ALLOCATED(this%args)) THEN
     
    466476    !!
    467477    !! 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
    469479    !! default associated action is 'store'.
    470480    OBJECT(argparser), INTENT(inout)                     :: this
     
    475485      !! A vector of strings with the the displayed value name(s) of the positionals in the help command
    476486    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)
    478488    TYPE(error) :: err
    479489      !! Error object with the first error encountered in the process.
     
    481491    CHARACTER(len=:), ALLOCATABLE :: sf,lf,de
    482492    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)
    485495      RETURN
    486496    ENDIF
     
    504514        RETURN
    505515      ENDIF
    506       this%have_posal = this%posals%nrec /= 0 
     516      this%have_posal = this%posals%nrec /= 0
    507517    ENDIF
    508518    RETURN
     
    514524    !! given as optional argument and fills the parser's arguments.
    515525    !! @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
    519529    !! positional.
    520530    OBJECT(argparser), INTENT(inout)       :: this
     
    523533      !! An optional string to parse that substitute for the actual command-line.
    524534    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
    526536      !! automatic actions or not when error occur during parsing. If `auto` is enabled,
    527537      !! then the parser dumps program's usage and stops the program on error.
     
    530540    CHARACTER(len=:), ALLOCATABLE :: cline,z
    531541    LOGICAL                       :: zauto
    532     LOGICAL                       :: rhelp
    533     INTEGER                       :: l
     542    LOGICAL                       :: rhelp
     543    LOGICAL                       :: rvers
     544    INTEGER                       :: l
    534545    TYPE(words)                   :: cmd_tokens
    535546    err = noerror
     
    537548      err = error("parser not initialized yet",-1) ; RETURN
    538549    ENDIF
    539     rhelp = .false.
     550    rhelp = .false. ; rvers = .false.
    540551    zauto = .false. ; IF (PRESENT(auto)) zauto = auto
    541552    IF (PRESENT(cmd_line)) THEN
    542553      ALLOCATE(cline,source=cmd_line)
    543554    ELSE
    544       CALL GET_COMMAND(length=l) 
     555      CALL GET_COMMAND(length=l)
    545556      ALLOCATE(CHARACTER(len=l) :: z) ; CALL GET_COMMAND(z)
    546557      CALL GET_COMMAND_ARGUMENT(0,length=l)
     
    557568        EXIT ! ... No :)
    558569      ELSE
    559         err = ap_split_cmd(this,cline,cmd_tokens,rhelp) 
     570        err = ap_split_cmd(this,cline,cmd_tokens,rhelp)
    560571        ! we only stops processing if :
    561572        !   - the internal error (string length) is raised
     
    565576      CALL words_reset(cmd_tokens) ! not mandatory... at least theoretically
    566577      ! Parses the options
    567       err = ap_parse_options(this,cmd_tokens,rhelp)
     578      err = ap_parse_options(this,cmd_tokens,rhelp,rvers)
    568579      IF (err /= noerror) EXIT
    569       ! exit loop if help is requested. Parser is not completely filled but we
    570       ! expect someone to use the help action..
    571       IF (rhelp) EXIT
     580      ! 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
    572583      ! Parses positionals
    573       err = ap_parse_positionals(this,cmd_tokens) 
     584      err = ap_parse_positionals(this,cmd_tokens)
    574585      EXIT ! A one iterated loop :)
    575586    ENDDO
     
    581592    IF (zauto) THEN
    582593      IF (rhelp) CALL argparser_help(this)
     594      IF (rvers) CALL argparser_version(this)
    583595      IF (err /= 0) CALL argparser_throw_error(this,err,2)
    584596    ENDIF
    585     RETURN 
     597    RETURN
    586598  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
    587608
    588609  SUBROUTINE argparser_help(this)
     
    606627    !!
    607628    !! The method performs the following actions:
    608     !! 
     629    !!
    609630    !! - Print the usage command of the program
    610631    !! - Dump the provided @p error message
     
    614635    !!
    615636    !! The error message is always printed in standard error output.
    616     !! @note 
     637    !! @note
    617638    !! If errors::error::id is 0 the method does nothing.
    618639    OBJECT(argparser), INTENT(inout) :: this
     
    638659  FUNCTION argparser_found(this,argname) RESULT(found)
    639660    !! Check wether an argument has been found in the command-line.
    640     !! @note 
     661    !! @note
    641662    !! Keep in mind that arguments in the parser always have a default
    642663    !! value. This method is not intended to check if an argument has a value but
     
    663684    CHARACTER(len=*), INTENT(in)  :: argname
    664685      !! Name of the argument to check.
    665     INTEGER :: num 
     686    INTEGER :: num
    666687      !! The number of actual values stored in the argument
    667688    INTEGER  :: idx
     
    693714    INTEGER :: ret
    694715      !! The number of actual positionals arguments
    695     ret = 0 
     716    ret = 0
    696717    IF (this%have_posal) THEN
    697718      ret = words_length(this%posals%values)
    698719    ENDIF
    699   END FUNCTION argparser_get_num_positional 
     720  END FUNCTION argparser_get_num_positional
    700721
    701722  ! argparser private methods
     
    703724
    704725  FUNCTION ap_check_state(this) RESULT(err)
    705     !! Check current parser state 
     726    !! Check current parser state
    706727    !! The method returns an error based on the current parser's state:
    707728    !! - Parser is ready (0)
     
    712733      !! An argparser object reference
    713734    TYPE(error) :: err
    714       !! Error object with the *status* of the parser 
     735      !! Error object with the *status* of the parser
    715736    err = noerror
    716737    IF (this%parsed == -1) THEN
     
    719740      err = error("argparse: command-line parsing failed",-20)
    720741    ELSE IF (.NOT.this%init) THEN
    721       err = error("argparse: parser not initialized yet",-1) 
     742      err = error("argparse: parser not initialized yet",-1)
    722743    ENDIF
    723744    RETURN
     
    732753    INTEGER                               :: i
    733754    TYPE(argc), ALLOCATABLE, DIMENSION(:) :: tmp
    734     TYPE(error) :: err 
     755    TYPE(error) :: err
    735756    IF (.NOT.this%init)  THEN
    736757      err = error("parser not initialized yet",-1) ; RETURN
     
    739760    IF (this%nargs == 0) THEN
    740761      ALLOCATE(this%args(1))
    741       this%args(1) = arg 
    742       this%nargs = 1 
     762      this%args(1) = arg
     763      this%nargs = 1
    743764      RETURN
    744765    ENDIF
     
    749770    ALLOCATE(tmp(this%nargs))
    750771    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)
    753774    this%nargs = this%nargs+1 ; ALLOCATE(this%args(this%nargs))
    754775    DO i=1,this%nargs-1 ; this%args(i) = tmp(i) ; ENDDO
     
    782803    ! empty parser
    783804    IF (this%nargs == 0) RETURN
    784     DO i=1, this%nargs 
     805    DO i=1, this%nargs
    785806      IF ((nn /= 0 .AND. TRIM(this%args(i)%name)  == TRIM(lna)) .OR. &
    786807          (ns /= 0 .AND. TRIM(this%args(i)%sflag) == TRIM(lsf)) .OR. &
     
    796817    !! Add an argument to the parser (interface #1)
    797818    !!
    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
    799820    !! in the parser. Both **short and long options flags** are mandatory input arguments of the function.
    800     !! 
     821    !!
    801822    !!  `type` value should be one of the following module constants (which are aliases from [[string_op(module)]]):
    802823    !!  - ap_string ([[string_op(module):st_string(variable)]])
     
    805826    !!  - ap_integer ([[string_op(module):st_integer(variable)]])
    806827    !!  - ap_real ([[string_op(module):st_real(variable)]])
    807     !! 
     828    !!
    808829    !!  `action` value should be one of the following module constants:
    809830    !!  - [[argparse(module):ap_store(variable)]]
     
    830851      !! A string (3 characters minimum) with the long option flag of the argument
    831852    INTEGER, INTENT(in), OPTIONAL                        :: type
    832       !! An integer with the type of the argument 
     853      !! An integer with the type of the argument
    833854    INTEGER, INTENT(in), OPTIONAL                        :: action
    834       !! An integer with the action of the argument 
     855      !! An integer with the action of the argument
    835856    CHARACTER(len=*), INTENT(in), OPTIONAL               :: default
    836857      !! A string with the default value of the argument if not provided in the CLI
    837858    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.
    839860    CHARACTER(len=*), INTENT(in), OPTIONAL               :: help
    840861      !! A string with a short description of the argument
     
    853874    de =''        ; IF (PRESENT(default)) de = TRIM(default)
    854875    IF (.NOT.this%init)  THEN
    855       err = error("argparse: parser not initialized yet",-1) 
     876      err = error("argparse: parser not initialized yet",-1)
    856877      RETURN
    857878    ENDIF
     
    876897    !! Add an argument to the parser (interface #2)
    877898    !!
    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,
    879900    !! 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
    881902    !! ap_add_option_1 to set the argument.
    882     !! 
     903    !!
    883904    !! Other dummy arguments have the same meaning as in ap_add_option_1.
    884905    OBJECT(argparser), INTENT(inout)                     :: this
     
    891912      !! A string with the type of the argument
    892913    INTEGER, INTENT(in), OPTIONAL                        :: action
    893       !! A string with the action of the argument 
     914      !! A string with the action of the argument
    894915    CHARACTER(len=*), INTENT(in), OPTIONAL               :: default
    895916      !! A string with the default value of the argument if not provided in the CLI
    896917    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.
    898919    CHARACTER(len=*), INTENT(in), OPTIONAL               :: help
    899920      !! A string with a short description of the argument
     
    956977  END FUNCTION ap_check_in_parser
    957978
    958   FUNCTION ap_parse_options(this,cmd,help_req) RESULT(err)
     979  FUNCTION ap_parse_options(this,cmd,help_req,vers_req) RESULT(err)
    959980    !! 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.
    961982    OBJECT(argparser), INTENT(inout), TARGET :: this
    962983      !! An argparser object reference
     
    965986    LOGICAL, INTENT(out)                     :: help_req
    966987      !! 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
    967990    TYPE(error) :: err
    968991      !! Error object with the first error encountered in the process
     
    976999      ! get current element
    9771000      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)?
    9791002      ic = ap_check_string(this,elt,arg_idx)
    9801003      IF (ic <= 0) THEN
    9811004        IF (arg_idx /= -1) THEN
    9821005          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
    9871016          ENDIF
    9881017          IF (err /= 0) EXIT
     
    9981027      ! iterates to next value
    9991028      CALL words_next(cmd)
    1000     ENDDO 
     1029    ENDDO
    10011030
    10021031    ! Do we need to check for error here ?
     
    10201049        IF (this%args(i)%nrec < nv) THEN
    10211050          err = ac_fmt_val_err(this%args(i),-18) ! extra values
    1022         ELSE 
     1051        ELSE
    10231052          err = ac_fmt_val_err(this%args(i),-17) ! missing values
    10241053        ENDIF
    1025       ENDIF 
     1054      ENDIF
    10261055    ENDDO
    10271056    IF (err /= 0) this%parsed = 0
    10281057    RETURN
    1029   END FUNCTION ap_parse_options 
     1058  END FUNCTION ap_parse_options
    10301059
    10311060  FUNCTION ap_parse_positionals(this,cmd) RESULT(err)
    10321061    !! 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.
    10341063    OBJECT(argparser), INTENT(inout) :: this
    10351064      !! An argparser object reference
     
    10441073
    10451074    ! 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
    10471076    !     Or : positional required but no valid element is present
    10481077    IF ((this%have_posal.AND..NOT.words_valid(cmd)) .OR. &
     
    10541083    CALL words_clear(this%posals%values)
    10551084    this%posals%fnd = .true.
    1056     DO 
     1085    DO
    10571086      na = words_length(this%posals%values)
    10581087      IF (words_valid(cmd)) THEN
     
    10901119    !! Fill an argument with values
    10911120    !!
    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).
    10941123    !! Several tests are performed and may raise errors. The function always stops
    10951124    !! at the first error encountered which can be one of the following :
     
    11031132      !! The command line
    11041133    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.
    11061135    TYPE(error) :: err
    11071136      !! Error object with the first error encountered in the process
    1108     INTEGER                       :: ca, isopt, itmp 
     1137    INTEGER                       :: ca, isopt, itmp
    11091138    LOGICAL                       :: ltmp
    11101139    CHARACTER(len=:), ALLOCATABLE :: elt
     
    11261155      IF (arg%paction == ap_count) THEN
    11271156        elt = words_pop(arg%values)
    1128         READ(elt,*) itmp ; itmp = itmp + 1 
     1157        READ(elt,*) itmp ; itmp = itmp + 1
    11291158        CALL words_append(arg%values,TO_STRING(itmp))
    1130       ELSE IF (arg%ptype == ap_logical) THEN 
     1159      ELSE IF (arg%ptype == ap_logical) THEN
    11311160        elt = words_pop(arg%values)
    1132         READ(elt,*) ltmp 
     1161        READ(elt,*) ltmp
    11331162        CALL words_append(arg%values,TO_STRING(.NOT.ltmp))
    11341163      ENDIF
    11351164    ELSE
    11361165      ! 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
    11381167      ! the next option (or '--' separator)
    11391168      ! When the exit condition is met we perform some tests based on the
     
    11551184          !    1) we have consumed all argument of command line
    11561185          !    2) current argument is not a value !
    1157           !    3) current argument the separator '--' 
     1186          !    3) current argument the separator '--'
    11581187          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) &
    11601189            err = ac_fmt_val_err(arg,-17)
    11611190          IF (arg%paction /= ap_append .AND. arg%nrec > 0 .AND. ca /= arg%nrec) &
     
    11781207  END FUNCTION ap_fill_argument
    11791208
    1180   FUNCTION ap_split_cmd(this,string,new_cmd,rhelp) RESULT(err) 
     1209  FUNCTION ap_split_cmd(this,string,new_cmd,rhelp) RESULT(err)
    11811210    !! 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
    11831212    !! are splitted and saves the resulting string elements in a list of words.
    11841213    !! @warning
    11851214    !! For compilers that does not support allocatable strings in derived types,
    11861215    !! 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.
    11881217    IMPLICIT NONE
    11891218    OBJECT(argparser), INTENT(in) :: this
     
    11931222    TYPE(words), INTENT(out)      :: new_cmd
    11941223      !! An output [[string_op(module):words(type)]] object with the processed command line
    1195     LOGICAL, INTENT(out)          :: rhelp   
     1224    LOGICAL, INTENT(out)          :: rhelp
    11961225      !! An output boolean flag with `.true.` if help is requested, `.false.` otherwise
    11971226    TYPE(error) :: err
     
    11991228    INTEGER                       :: isopt,j,tl,res
    12001229    CHARACTER(len=:), ALLOCATABLE :: elt
    1201     TYPE(words)                   :: splitted 
     1230    TYPE(words)                   :: splitted
    12021231    INTEGER                       :: arg_idx
    12031232    err = noerror ; rhelp = .false.
    12041233    IF (LEN_TRIM(string) == 0) THEN
    1205       err = error('internal error (empty string)',-255) 
     1234      err = error('internal error (empty string)',-255)
    12061235      RETURN
    12071236    ENDIF
     
    12181247          res = ap_check_string(this,"-"//elt(j:j),arg_idx)
    12191248          ! 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 !
    12211250            rhelp = (this%args(arg_idx)%paction == ap_help.OR.rhelp)
    12221251            ! 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
    12241253            ! during next! parsing process
    12251254            CALL words_append(new_cmd,"-"//elt(j:j))
     
    12371266        rhelp = (this%args(arg_idx)%paction == ap_help.OR.rhelp)
    12381267        ! 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
    12401269        ! next parsing process
    12411270        CALL words_append(new_cmd,TRIM(elt))
     
    12471276    RETURN
    12481277  END FUNCTION ap_split_cmd
    1249    
     1278
    12501279  FUNCTION ap_check_string(this,string,idx) RESULT(ret)
    12511280    !! Check if a string is an option flag
     
    12591288    INTEGER, INTENT(out), OPTIONAL             :: idx
    12601289      !! An optional output intger with the index of the afferent argument in the parser (-1 if not found)
    1261     INTEGER :: ret 
     1290    INTEGER :: ret
    12621291      !! Return code with the following possible values:
    12631292      !! - -1 if the string is a SHORT option flag
     
    12721301    ! The combination of the (optional) output index and the return code
    12731302    ! allows to check if an option is known or not
    1274     ret = 1 
     1303    ret = 1
    12751304    ! '--' is special : it is a separator that is seen as a value.
    12761305    IF (TRIM(string) == '--') RETURN
     
    13031332    CHARACTER(len=:), ALLOCATABLE :: copt,spc,opts,text
    13041333    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)
    13061335    zw = this%width
    13071336    ! Sets usage
     
    13121341    hlp = TRIM(this%usg)//NEW_LINE('A')//NEW_LINE('A')
    13131342    ! Sets description
    1314     IF (LEN_TRIM(this%descr) /= 0) & 
     1343    IF (LEN_TRIM(this%descr) /= 0) &
    13151344      hlp=hlp//getpar(this%descr,zw,2)//NEW_LINE('A')//NEW_LINE('A')
    13161345    ! Sets positionals
     
    13801409    !! Format command line usage.
    13811410    !!
    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
    13861415    !! line based on the arguments stored in the parser.
    13871416    OBJECT(argparser), INTENT(inout) :: this
    13881417      !! An argparser object reference
    13891418    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.
    13911420      !! This variable is intended to set a fancy indentation while printing option in the helper.
    13921421    CHARACTER(len=:), ALLOCATABLE :: usage, idts, copt,pgn
     
    14281457          usage = usage(:)//TRIM(copt)
    14291458        ENDIF
    1430       ENDIF 
     1459      ENDIF
    14311460      this%usg = usage
    14321461    ELSE
     
    14391468        optmw = omw
    14401469      ENDIF
    1441     ENDIF 
     1470    ENDIF
    14421471  END SUBROUTINE ap_format_usage
    14431472
     
    14621491    IF (ALLOCATED(other%descr)) this%descr = other%descr
    14631492    IF (ALLOCATED(other%eplg))  this%eplg  = other%eplg
     1493    IF (ALLOCATED(other%vers))  this%vers  = other%vers
    14641494#else
    14651495    this%usg   = other%usg
    14661496    this%descr = other%descr
    14671497    this%eplg  = other%eplg
     1498    this%vers  = other%vers
    14681499#endif
    14691500    this%mxhlpos = other%mxhlpos
     
    15071538  FUNCTION ac_equals_arg(this,other) RESULT(ret)
    15081539    !! 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
    15111542    !! and not empty.
    15121543    TYPE(argc), INTENT(in) :: this
     
    15291560    tlf=TRIM(this%lflag) ; olf=TRIM(other%lflag)
    15301561#endif
    1531     tn=LEN_TRIM(tna) ; on=LEN_TRIM(ona) 
     1562    tn=LEN_TRIM(tna) ; on=LEN_TRIM(ona)
    15321563    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)
    15341565    ! check on name :
    15351566    ! Returns True if at least of name, sflag and lflag is set to non-empty
     
    15371568    ret = ((tn/=0 .AND. on==tn) .AND. tna == ona) .OR. &
    15381569          ((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)
    15401571    DEALLOCATE(tna,ona,tsf,osf,tlf,olf)
    15411572  END FUNCTION ac_equals_arg
     
    15431574  FUNCTION ac_differs_arg(this,other) RESULT(ret)
    15441575    !! 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
    15461577    !! and long option flag.
    1547     !! @note 
     1578    !! @note
    15481579    !! This function is the extact contrary of [[argparse(module):ac_equals_arg(function)]] !
    15491580    TYPE(argc), INTENT(in) :: this
     
    15581589  SUBROUTINE ac_clear_arg_sc(arg)
    15591590    !! 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
    15611592    !! default values.
    15621593    TYPE(argc), INTENT(inout) :: arg
     
    16061637      args(i)%lflag   = ""
    16071638#endif
    1608     ENDDO 
     1639    ENDDO
    16091640  END SUBROUTINE ac_clear_arg_ve
    16101641
     
    16221653    TYPE(argc), INTENT(in) :: this
    16231654      !! An argc object
    1624     INTEGER :: num 
     1655    INTEGER :: num
    16251656      !! The number of values stored in the argument
    16261657    num = words_length(this%values)
     
    16291660  FUNCTION ac_get_usg_opt_str(arg) RESULT(line)
    16301661    !! 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
    16321663    !! option string part of a given argument.
    16331664    TYPE(argc), INTENT(in), TARGET :: arg
     
    16611692  FUNCTION ac_get_opt_str(arg) RESULT(line)
    16621693    !! 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
    16641695    !! option string part of a given argument for the options part of the help.
    16651696    TYPE(argc), INTENT(in), TARGET :: arg
     
    17011732    !! The function formats argparse specific errors when extra (missing) values
    17021733    !! 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.
    17051736    TYPE(argc), INTENT(in) :: arg
    17061737      !! An argc object
     
    17231754        IF (arg%nrec == -2) THEN
    17241755          msg = msg//' takes at least '//nv//' value(s))'
    1725         ELSE 
     1756        ELSE
    17261757          msg = msg//' takes exactly '//nv//' value(s))'
    17271758        ENDIF
    17281759      CASE (-18) ! extra values -> -18
    1729         IF (arg%nrec == -3) THEN 
     1760        IF (arg%nrec == -3) THEN
    17301761          msg = msg//' takes at most '//nv//' value(s))'
    17311762        ELSE
     
    17401771  FUNCTION ac_check_and_set(this,sf,lf,ty,ac,de,na,meta,check_flag) RESULT(ret)
    17411772    !! 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.
    17441775    !!
    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
    17461777    !! produced by misuse of the function arguments. In such case, the program should be
    17471778    !! stopped: note that such ezrror should not occur in _released_ programs.
     
    17631794      !! An optional vector of strings with the Meta-name of the values
    17641795    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
    17671798      !! check for POSITIONAL arguments as they do not have option flags.
    17681799    TYPE(error) :: ret
     
    17891820  FUNCTION ac_check_ac_ty_de_na(this,ac,ty,de,na) RESULT(ret)
    17901821    !! 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.
    17931824    !!
    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
    17951826    !! produced by misuse of the function arguments.
    17961827    TYPE(argc), INTENT(inout)  :: this
    17971828      !! An argc object to update
    17981829    INTEGER, INTENT(in)          :: ac
    1799       !! An integer with the action to set and check 
     1830      !! An integer with the action to set and check
    18001831    INTEGER, INTENT(in)          :: ty
    18011832      !! An integer with the type to set and check
    18021833    CHARACTER(len=*), INTENT(in) :: de
    18031834      !! A string with the default value to set and check
    1804     CHARACTER(len=*), INTENT(in) :: na 
     1835    CHARACTER(len=*), INTENT(in) :: na
    18051836      !! A string with the expected number of value to set and check
    18061837    TYPE(error) :: ret
     
    18101841    ret = noerror
    18111842    eprf = 'argparse: '//"Invalid argument `"//TRIM(this%name)//"'"
    1812     uty = error(eprf//" (type)",-9) 
     1843    uty = error(eprf//" (type)",-9)
    18131844    ina = error(eprf//" (inconsistent nargs)",-9)
    18141845    zna = TRIM(na)
    18151846    ! Checks action
    18161847    IF(ANY(ap_actions == ac).OR.ac == ap_undef) THEN
    1817       this%paction = ac 
     1848      this%paction = ac
    18181849    ELSE
    1819       ret = error(eprf//" (action)",-9) ; RETURN 
     1850      ret = error(eprf//" (action)",-9) ; RETURN
    18201851    ENDIF
    18211852    ! Checks and sets type and default as a function of the action
    18221853    SELECT CASE(this%paction)
    1823       ! HELP: fixed in any case: 
     1854      ! HELP: fixed in any case:
    18241855      CASE(ap_help)
    18251856        this%default = 'F'
    18261857        this%ptype = ap_logical
    18271858        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
    18281864      ! 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...
    18311866      CASE(ap_count)
    18321867        ! default settings of the count action
     
    18351870        ret = set_def_val()
    18361871      ! STORE, APPEND actions
    1837       CASE (ap_store, ap_append) 
    1838         ! set type 
     1872      CASE (ap_store, ap_append)
     1873        ! set type
    18391874        IF (ty == ap_undef) THEN
    1840           this%ptype= ap_integer 
     1875          this%ptype= ap_integer
    18411876        ELSEIF (ANY(ap_types == ty)) THEN
    18421877          this%ptype = ty
     
    18471882        ret = set_def_val() ; IF (ret /= 0) RETURN
    18481883        ! check for nargs (if na is empty then we set "*")
    1849         ret = set_nrec("*") 
     1884        ret = set_nrec("*")
    18501885      ! UNDEFINED:
    18511886      !   -> 1) set to action to store
     
    18551890      CASE (ap_undef)
    18561891        ! 1) always define store action
    1857         this%paction = ap_store 
     1892        this%paction = ap_store
    18581893        ! 2) set type and nrec:
    18591894        !    2.1) If type is undef:
    18601895        !         - to default value type if default is given
    1861         !         - ap_logical otherwiset type 
     1896        !         - ap_logical otherwiset type
    18621897        !    2.2) set nrec
    18631898        !        - if final type is ap_logical set nrec to 0
     
    18651900        If (ty == ap_undef) THEN
    18661901          ! no explicit type : define logical trigger first
    1867           this%ptype = ap_logical ; this%nrec = 0 
     1902          this%ptype = ap_logical ; this%nrec = 0
    18681903          ! icheck the default value given
    18691904          IF (LEN_TRIM(de) > 0) THEN
     
    18731908          ENDIF
    18741909          IF (this%ptype == ap_logical) THEN
    1875             ret = set_nrec("0") 
     1910            ret = set_nrec("0")
    18761911          ELSE
    1877             ret = set_nrec("1") 
     1912            ret = set_nrec("1")
    18781913          ENDIF
    1879           ret = set_def_val() 
     1914          ret = set_def_val()
    18801915          IF (ret /= 0) RETURN
    18811916        ! type is given
     
    18831918          ! known type given :
    18841919          !  check default value and nrec: -> if na not given set "*"
    1885           this%ptype = ty 
     1920          this%ptype = ty
    18861921          ret = set_def_val() ; IF (ret /= 0) RETURN
    18871922          IF (this%ptype == ap_logical) THEN
    1888             ret = set_nrec("0") 
     1923            ret = set_nrec("0")
    18891924          ELSE
    18901925            ret = set_nrec("1")
     
    18921927        ELSE
    18931928          ! unknown type => bad end !
    1894           ret = uty ; RETURN 
     1929          ret = uty ; RETURN
    18951930        ENDIF
    1896     END SELECT 
     1931    END SELECT
    18971932    ! set default value as first value if ret is noerror ....
    18981933    IF (ret == 0) CALL words_append(this%values,this%default)
     
    19041939        !! Check and set argument's expected number of records
    19051940        !! 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`
    19071942        !! is empty then `base` is used.
    19081943        CHARACTER(len=1),INTENT(in) :: base
     
    19211956            ! check numeric characters
    19221957            IF (VERIFY(zna,"0123456789")==0) READ(zna,*) this%nrec
    1923             IF (this%nrec == 0) terr = ina 
     1958            IF (this%nrec == 0) terr = ina
    19241959        END SELECT
    19251960      END FUNCTION set_nrec
     
    19271962      FUNCTION set_def_val() RESULT(terr)
    19281963        !! 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
    19301965        !! decides wether to raise an error or to save `de` as argument's default value.
    19311966        !! If `de` is empty then it sets a default value according to argument's type.
     
    19351970        terr = noerror
    19361971        IF (LEN_TRIM(de) /= 0) THEN
    1937           this%default = de ; t = string_is(de) 
     1972          this%default = de ; t = string_is(de)
    19381973          IF (t /= this%ptype) THEN
    19391974            terr = error(eprf//" (inconsistent default value: expected '"// &
     
    19521987        ENDIF
    19531988        RETURN
    1954       END FUNCTION set_def_val 
     1989      END FUNCTION set_def_val
    19551990  END FUNCTION ac_check_ac_ty_de_na
    19561991
     
    19692004    CHARACTER(len=2), INTENT(in) :: sflag
    19702005      !! A 2-characters wide string with the short option flag
    1971     CHARACTER(len=*), INTENT(in) :: lflag 
     2006    CHARACTER(len=*), INTENT(in) :: lflag
    19722007      !! A string (at least 3 characters wide) with the long option flag
    19732008    TYPE(error) :: ret
     
    20172052    !! Set meta-variable of the given argc object
    20182053    !! 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.
    20202055    !! @warning
    20212056    !! To be effective, this subroutine must be called after argparse::chk_opt_nargs
     
    20422077            j=j+1 ; IF (j>ms) j=1
    20432078            zmeta = to_upper(meta(j))
    2044             blk=INDEX(TRIM(zmeta),CHAR(32))-1 
     2079            blk=INDEX(TRIM(zmeta),CHAR(32))-1
    20452080            IF (blk <= 0) blk=LEN_TRIM(zmeta)
    20462081            CALL words_append(this%meta,zmeta(1:blk))
     
    20632098  FUNCTION ac_check_value(this,str) RESULT(err)
    20642099    !! Check if given string is a valid value for the argument
    2065     TYPE(argc), INTENT(in)       :: this 
     2100    TYPE(argc), INTENT(in)       :: this
    20662101      !! An argc object reference
    20672102    CHARACTER(len=*), INTENT(in) :: str
     
    20932128  FUNCTION ap_get_positional_sc(this,idx,value) RESULT(ret)
    20942129    !! Get positional arguments value at given index
    2095     !! @warning 
     2130    !! @warning
    20962131    !! On error, the status of `value` is undefined.
    20972132    OBJECT(argparser), INTENT(in)              :: this
     
    21002135      !! Subscript of the positional argument value to get
    21012136    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
    21032138      !! empty string.
    21042139    TYPE(error) :: ret
     
    21172152  FUNCTION ap_get_positional_ve(this,values) RESULT(ret)
    21182153    !! Get all positional arguments value
    2119     !! @warning 
     2154    !! @warning
    21202155    !! On error, the status of `values` is undefined.
    21212156    OBJECT(argparser), INTENT(in)                                  :: this
    21222157      !! An argparser object reference
    21232158    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.
    21262161    TYPE(error) :: ret
    21272162      !! Error object with the first error encountered in the process
     
    25322567
    25332568  !> 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
    25352570  !! @param[out] output A scalar with the first value of the argument
    25362571  !! @return An errors::error object with -21 if the destination variable's type
     
    25382573  FUNCTION ac_get_dv_sc(this, output) RESULT(ret)
    25392574    !! 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
    25412576    !! state is) which is the default value if no specific values are set in the argument.
    25422577    !! Otherwise, `output` value is undefined.
     
    25632598  FUNCTION ac_get_rv_sc(this, output) RESULT(ret)
    25642599    !! 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
    25662601    !! state is) which is the default value if no specific values are set in the argument.
    25672602    !! Otherwise, `output` value is undefined.
     
    25882623  FUNCTION ac_get_iv_sc(this, output) RESULT(ret)
    25892624    !! 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
    25912626    !! state is) which is the default value if no specific values are set in the argument.
    25922627    !! Otherwise, `output` value is undefined.
     
    26132648  FUNCTION ac_get_lv_sc(this, output) RESULT(ret)
    26142649    !! 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
    26162651    !! state is) which is the default value if no specific values are set in the argument.
    26172652    !! Otherwise, `output` value is undefined.
     
    26382673  FUNCTION ac_get_cv_sc(this, output) RESULT(ret)
    26392674    !! 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
    26412676    !! state is) which is the default value if no specific values are set in the argument.
    26422677    !! Otherwise, `output` value is undefined.
     
    26632698  FUNCTION ac_get_sv_sc(this, output) RESULT(ret)
    26642699    !! 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
    26662701    !! state is) which is the default value if no specific values are set in the argument.
    26672702    !! Otherwise, `output` status is undefined.
     
    26852720  FUNCTION ac_get_dv_ve(this, output) RESULT(ret)
    26862721    !! 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
    26882723    !! state is) which is the default value if no specific values are set in the argument.
    26892724    !! Otherwise, `output` status is undefined.
     
    27142749  FUNCTION ac_get_rv_ve(this, output) RESULT(ret)
    27152750    !! 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
    27172752    !! state is) which is the default value if no specific values are set in the argument.
    27182753    !! Otherwise, `output` status is undefined.
     
    27432778  FUNCTION ac_get_iv_ve(this, output) RESULT(ret)
    27442779    !! 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
    27462781    !! state is) which is the default value if no specific values are set in the argument.
    27472782    !! Otherwise, `output` status is undefined.
     
    27722807  FUNCTION ac_get_lv_ve(this, output) RESULT(ret)
    27732808    !! 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
    27752810    !! state is) which is the default value if no specific values are set in the argument.
    27762811    !! Otherwise, `output` status is undefined.
     
    28012836  FUNCTION ac_get_cv_ve(this, output) RESULT(ret)
    28022837    !! 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
    28042839    !! state is) which is the default value if no specific values are set in the argument.
    28052840    !! Otherwise, `output` status is undefined.
     
    28302865  FUNCTION ac_get_sv_ve(this, output) RESULT(ret)
    28312866    !! 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
    28332868    !! state is) which is the default value if no specific values are set in the argument.
    28342869    !! Otherwise, `output` status is undefined.
     
    28722907
    28732908  FUNCTION apa2str(ap_a) RESULT(str)
    2874     !! Get the string representation of argparse actions constants 
     2909    !! Get the string representation of argparse actions constants
    28752910    INTEGER, INTENT(in) :: ap_a
    28762911     !! One of ap_store, ap_append,cap_count or ap_help module constants
     
    28822917      CASE(ap_count)  ; str = 'count'
    28832918      CASE(ap_help)   ; str = 'help'
     2919      CASE(ap_version); str = 'version'
    28842920      CASE DEFAULT    ; str = 'unknown'
    28852921    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.
    3321
    3422!! file: asciiread.f90
    3523!! summary: ASCII data file reader source file
    3624!! author: burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826MODULE ASCIIREAD
    3927  !! ASCII data file reader module
     
    4230  !! data array from ASCII file.
    4331  !!
    44   !! ``` 
     32  !! ```
    4533  !! FUNCTION read_data(path,data) RESULT(err)
    4634  !! ```
     
    5644  !!   - must use blank space(s) as value delimiter.
    5745  !!   - 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.
    5947  !!   - can contains any number of empty lines and/or comment line (i.e. line
    6048  !!     where first non-blank character is "#"). All other lines are assumed
    6149  !!     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.
    6351  !!
    6452  !! Error occured when:
     
    7664  !! of _R_ lines with _C_ columns. Each block must be separated by a single empty line
    7765  !! and each columns must separated by one or more blank spaces (no tabulation ALLOWED).
    78   !! 
     66  !!
    7967  !! On success, the shape of the 3D output array will be _data(R,C,D)_.
    8068  USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: IOSTAT_END, IOSTAT_EOR
     
    9381  END INTERFACE
    9482
    95   CONTAINS 
     83  CONTAINS
    9684
    9785
     
    10088    !!
    10189    !! The function reads an ASCII file and saves its values in a real(kind=8) 3D-array.
    102     !! 
     90    !!
    10391    !! The input file:
    10492    !!
    10593    !! - 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).
    10795    !! - must use a SINGLE empty line for "depth" block separator.
    10896    !! - can contains any number of comment lines (i.e. line where first non-blank character is "#").
    10997    !!   All other lines (except empty lines) are assumed to be data.
    110     !! 
     98    !!
    11199    !! Error occured when:
    112100    !!    - Path does not refer to a existing file (-11)
     
    118106    !! with _C_ columns. Each block must be separated by a single empty line and
    119107    !! each columns must separated by one or more blank spaces (no tabulation ALLOWED).
    120     !! 
     108    !!
    121109    !! On success, the shape of the 3D output array will be _output(R,C,D)_.
    122110    !! 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
    124112    REAL(kind=8), INTENT(out), DIMENSION(:,:,:), ALLOCATABLE :: data3d    !! 3D-array with the output values (double precision)
    125113    CHARACTER(len=*), INTENT(in), OPTIONAL                   :: delimiter !! Optional column delimiter(s)
     
    142130      err = error(trim(path)//": no such file",-1) ; RETURN
    143131    ENDIF
    144     lu = free_lun() 
     132    lu = free_lun()
    145133    IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF
    146134    ! Open file
    147135    OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ')
    148136
    149     ! First pass : 
     137    ! First pass :
    150138    ! ------------
    151     !   - get size (rows, columns, depth) 
     139    !   - get size (rows, columns, depth)
    152140    !   - check size consistendcy
    153141    !   - 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))
    157145      lm1 = line
    158146      ! Read the line
     
    160148      ! skip comment line
    161149      IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1) CYCLE
    162       ! An empty line: new 2D block 
     150      ! An empty line: new 2D block
    163151      IF (LEN_TRIM(line) == 0) THEN
    164152        ndd = ndd + 1
     
    175163      tlc = tlc + 1
    176164      ! Splits line in words
    177       IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 
     165      IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN
    178166        ! cannot tokenize
    179167        err = error(trim(path)//": Cannot parse line "//TRIM(slc),-5)
     
    183171        err = error(trim(path)//": Cannot cast values at line "//TRIM(slc),-5)
    184172        RETURN
    185       ELSEIF (ndc > 0 .AND. ndc /= SIZE(wrds)) THEN 
     173      ELSEIF (ndc > 0 .AND. ndc /= SIZE(wrds)) THEN
    186174        ! current number of columns not equal to last one
    187175        err = error(trim(path)//": Invalid number of columns (line "//TRIM(slc)//")",-5)
     
    204192    ! Allocate memory
    205193    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))
    208196      IF (INDEX(TRIM(ADJUSTL(line)),"#") == 1) CYCLE
    209197      ir = ir + 1
    210       ! empty line update block subscripts 
     198      ! empty line update block subscripts
    211199      IF (LEN_TRIM(line) == 0) THEN
    212200        kd = kd + 1 ; ir = 0 ; CYCLE
     
    223211    !!
    224212    !! The function reads an ASCII file and saves its values in a real(kind=8) 2D-array.
    225     !! 
     213    !!
    226214    !! The input file:
    227215    !!
    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
    229217    !!   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.
    232220    !! - must use blank space(s) as value delimiter.
    233     !! 
     221    !!
    234222    !! Error occured when:
    235223    !!
     
    241229    !! On error, the 2D output array is __not allocated__.
    242230    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
    244232    REAL(kind=8), INTENT(out), DIMENSION(:,:), ALLOCATABLE :: data2d    !! 2D-array with the output values (double precision)
    245233    CHARACTER(len=*), INTENT(in), OPTIONAL                 :: delimiter !! Optional column delimiter(s)
     
    258246      err = error(trim(path)//": no such file",-1) ; RETURN
    259247    ENDIF
    260     lu = free_lun() 
     248    lu = free_lun()
    261249    IF (lu == -1) THEN ; err = error("Cannot find available logical unit...",-1) ; RETURN ; ENDIF
    262250    OPEN(lu,FILE=TRIM(path),STATUS='OLD',ACTION='READ')
     
    265253    lc=0 ; vc = 0 ; nc=-1
    266254    ! First pass : get number of row values and checks everything !
    267     DO 
     255    DO
    268256      ! Read the line
    269257      IF (.NOT.readline(lu,line)) EXIT
     
    273261      ! update row counter
    274262      vc = vc + 1
    275       IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN 
     263      IF (.NOT.tokenize(line,wrds,zdelim,.true.)) THEN
    276264        ! cannot tokenize
    277265        err = error(trim(path)//": Cannot parse line "//TRIM(slc),-5)
     
    281269        err = error(trim(path)//": Cannot cast values at line "//TRIM(slc),-5)
    282270        RETURN
    283       ELSEIF (nc > 0 .AND. nc /= SIZE(tmp)) THEN 
     271      ELSEIF (nc > 0 .AND. nc /= SIZE(tmp)) THEN
    284272        ! current number of columns not equal to last one
    285273        err = error(trim(path)//": Invalid number of columns (line "//TRIM(slc)//")",-5)
     
    296284    ALLOCATE(data2d(nl,nc))
    297285    ! Second pass : saves values :)
    298     vc = 0 
     286    vc = 0
    299287    DO WHILE(vc <= nl)
    300288      ! Reads the line
     
    315303  FUNCTION readline(lun,line) RESULT(not_eof)
    316304    !! 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__
    319307    !! logical unit and returns .false. if EOF has been reached, .true. otherwise.
    320308    !!
     
    331319    !! CLOSE(1)
    332320    !! ```
    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
    335323    LOGICAL  :: not_eof                                !! .true. if EOF has NOT been reached yet, .false. otherwise
    336324    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).
    22!
    3 ! jeremie.burgalat@univ-reims.fr
     3! This file is part of SWIFT
    44!
    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:
    711!
    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.
    1314!
    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.
    3321
    3422!! file: cfgparse.F90
    3523!! summary: Configuration file parser source file.
    3624!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826
    3927#include "defined.h"
     
    330318    oname = zsname//"/"//zpname
    331319    IF (PRESENT(sname)) sname = zsname
    332     IF (PRESENT(pname)) pname = zpname 
     320    IF (PRESENT(pname)) pname = zpname
    333321  END FUNCTION op_format
    334322
     
    418406    !!
    419407    !! Otherwise it is assumed to be the basename of the option.
    420     !! 
     408    !!
    421409    !! A valid option (base) name is an alphanumeric sequence in lower-case that always begin by
    422410    !! a letter.
     
    479467    IF(.NOT.ALLOCATED(this%options)) RETURN
    480468    IF (.NOT.PRESENT(section)) THEN
    481       num = SIZE(this%options) 
     469      num = SIZE(this%options)
    482470    ELSE
    483471      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.
    3322 */
    3423
     
    7160    free(tmp);
    7261    tmp = NULL;
    73   } 
     62  }
    7463  return tmp;
    7564}
    7665
    7766
    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 */
    7968char* c_realpath(const char *input){
    8069  if (!strlen(input)) {
     
    148137        continue;
    149138      }
    150       len = path_len + strlen(p->d_name) + 2; 
     139      len = path_len + strlen(p->d_name) + 2;
    151140      buf = malloc(len);
    152141      if (buf) {
     
    168157  if (!r) {
    169158    r = rmdir(path);
    170         return r?errno:0;
     159  return r?errno:0;
    171160  }
    172161  return r;
     
    174163
    175164/* Get some file informations */
    176 int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi, 
     165int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi,
    177166            long *si, char a[20], char m[20], char c[20]){
    178167  struct stat stb;
     
    189178    else *ty = 4;
    190179    *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);
    192181    if(ret != 0) {strncpy(a,tmp,20); a[19] = '\0';}else{a[0] = '\0';}
    193182    t = localtime(&stb.st_mtime) ; ret = strftime(tmp, 20, "%F,%T", t);
     
    212201    if (forced){
    213202      p = strdup(path) ; if(p == NULL) {return errno;}
    214       d = dirname(p) ; free(p) ; 
     203      d = dirname(p) ; free(p) ;
    215204      if(d == NULL) {return -9;}
    216205      // we attempts to create parent directory first
     
    218207      perm =((S_IRWXU | S_IRWXG | S_IRWXO) & ~(cmask & ~(S_IWUSR | S_IXUSR)));
    219208      (void)umask(cmask) ;
    220       eval = c_mkdirp(d,perm); 
     209      eval = c_mkdirp(d,perm);
    221210      if(eval){return eval;}
    222211    }
    223212    eval = open(path,O_CREAT|O_EXCL,mode);
    224213    if (eval == -1) {eval=errno;}else{close(eval);eval=0;}
    225   } 
     214  }
    226215  return eval ;
    227216}
     
    355344 *  Copyright (c) 1983, 1992, 1993
    356345 *   The Regents of the University of California.  All rights reserved.
    357  * 
     346 *
    358347 *  Redistribution and use in source and binary forms, with or without
    359348 *  modification, are permitted provided that the following conditions
     
    371360 *     may be used to endorse or promote products derived from this software
    372361 *     without specific prior written permission.
    373  * 
     362 *
    374363 *  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    375364 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    416405        retval = 1; break;
    417406      }
    418     } 
     407    }
    419408    if (!last) *p = '/';
    420409  }
     
    433422 *
    434423 * @APPLE_LICENSE_HEADER_START@
    435  * 
     424 *
    436425 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
    437426 * Reserved.  This file contains Original Code and/or Modifications of
     
    441430 * License at http://www.apple.com/publicsource and read it before using
    442431 * this file.
    443  * 
     432 *
    444433 * The Original Code and all software distributed under the License are
    445434 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
     
    449438 * License for the specific language governing rights and limitations
    450439 * under the License."
    451  * 
     440 *
    452441 * @APPLE_LICENSE_HEADER_END@
    453442 *
     
    467456  buf = NULL;
    468457
    469   if (realpath(reldir,start_path) == NULL) 
     458  if (realpath(reldir,start_path) == NULL)
    470459    return buf;
    471  
    472   if (realpath(path,end_path) == NULL) 
     460
     461  if (realpath(path,end_path) == NULL)
    473462    return buf;
    474463
    475464  // stat the starting path
    476   if (stat(start_path, &st) < 0) 
     465  if (stat(start_path, &st) < 0)
    477466    return buf;
    478  
     467
    479468  if ((st.st_mode & S_IFMT) != S_IFDIR) {
    480469    errno = ENOTDIR;
    481470    return buf;
    482   } 
     471  }
    483472  if (start_path[strlen(start_path) - 1] != '/')
    484473    strcat(start_path, "/");
    485474
    486475  // stat the ending path path
    487   if (stat(end_path, &st) < 0) 
     476  if (stat(end_path, &st) < 0)
    488477    return buf;
    489  
     478
    490479  if ((st.st_mode & S_IFMT) == S_IFDIR
    491480      && end_path[strlen(end_path) - 1] != '/')
     
    624613#elif defined(__APPLE__) && defined(__MACH__)
    625614    /* 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)
    629618        return (size_t)0L; /* Can't access? */
    630619    return (size_t)info.resident_size;
     
    650639
    651640
    652  
     641
    653642/* Get some informatiosn about the OS memory usage (from /proc/meminfo) */
    654643int c_getSystemMemory(long long int *m_total,long long int *m_available,long long int *m_free){
     
    661650    if (m_available) (*m_free) = mem2;
    662651    if (m_free) (*m_free) = mem3;
    663     if ((fp = fopen("/proc/meminfo", "r")) == NULL) 
     652    if ((fp = fopen("/proc/meminfo", "r")) == NULL)
    664653        return 1;
    665654    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
    668658        // check our 3 cases
    669659        if (ts >= 9 && !strncmp(tmp,"MemTotal:",9)){
     
    674664        }
    675665        if (ts >= 13 && !strncmp(tmp,"MemAvailable:",13)){
    676             p=strtok(tmp, " "); p=strtok(NULL, " "); 
     666            p=strtok(tmp, " "); p=strtok(NULL, " ");
    677667            mem2 = strtoll(p,NULL,10);
    678         }   
     668        }
    679669        if (ts >= 8 && !strncmp(tmp,"MemFree:",8)){
    680             p=strtok(tmp, " "); p=strtok(NULL, " "); 
     670            p=strtok(tmp, " "); p=strtok(NULL, " ");
    681671            mem3 = strtoll(p,NULL,10);
    682672        }
  • 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.
    3322 */
    3423
     
    4332int c_umask();
    4433
    45 /** 
    46  * Get directory name of input path 
     34/**
     35 * Get directory name of input path
    4736 * @param[in] in A C string with the input path
    4837 * @return A pointer to a char array with the directory name of @bti{input} path.
    4938 * @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
    5140 * (using fsystem::free_c).
    5241 */
    5342char * c_dirname(const char *in);
    5443
    55 /** 
    56  * Get base name of input path 
     44/**
     45 * Get base name of input path
    5746 * @param[in] in A C string with the input path
    5847 * @return A pointer to a char array with the base name of @bti{input} path.
    5948 * @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
    6150 * (using fsystem::free_c).
    6251 */
    6352char* c_basename(const char *in);
    6453
    65 /** 
     54/**
    6655 * Get the current working directory.
    6756 * @return A pointer to a char array with the current workind directory.
    6857 * @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
    7059 * (using fsystem::free_c).
    7160 */
     
    7362
    7463
    75 /** 
     64/**
    7665 * Get the realpath of input path.
    7766 * @param[in] input A C string with the input path
    7867 * @return A pointer to a char array with the realpath of @bti{input} path.
    7968 * @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
    8170 * (using fsystem::free_c).
    8271 */
     
    9180 * @return A pointer to a char array with the relative path.
    9281 * @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
    9483 * (using fsystem::free_c).
    9584 */
     
    10190 * @return A pointer to a char array with the user name.
    10291 * @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
    10493 * (using fsystem::free_c).
    10594 */
     
    111100 * @return A pointer to a char array with the group name.
    112101 * @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
    114103 * (using fsystem::free_c).
    115104 */
     
    122111int c_get_errno();
    123112
    124 /** 
     113/**
    125114 * Get the error message of the given error id
    126115 * @param err An integer with the error id
    127116 * @return A pointer to a char array with the group name.
    128117 * @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
    130119 * (using fsystem::free_c).
    131120 */
     
    139128 * @return An integer with 0 on success, last errno on failure
    140129 */
    141 int c_mkdirp(const char *path, mode_t mode); 
     130int c_mkdirp(const char *path, mode_t mode);
    142131
    143132/**
     
    151140/**
    152141 * Change path permissions
    153  * @param path A string with the path 
     142 * @param path A string with the path
    154143 * @param mode A integer with the new permissions to set
    155144 * @return An integer with 0 on success, last errno on failure
     
    170159 *                 (as well as all the parent directorie created, if any).
    171160 * @return An integer with 0 on success, last errno on failure
    172  */ 
     161 */
    173162int c_mkdir(const char *path, mode_t mode);
    174163
     
    200189 * Remove a directory and its contents recursively
    201190 *
    202  * This method mimics 'rm -rf' command. 
     191 * This method mimics 'rm -rf' command.
    203192 * @param path A C string with the path of the directory to remove.
    204193 * @return An integer with 0 on success, last errno on failure
     
    208197/**
    209198 * 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
    211200 * to -1.
    212201 * @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
    214203 * @param[out] nl An int with the inumber of links
    215204 * @param[out] ty An int with the type of the file :
     
    219208 *    - 3 -> link to a directory
    220209 *    - 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
    224213 * @param[out] a A C string (20 chars wide, including NULL character) with the
    225214 * last access date
    226215 * @param[out] m A C string (20 chars wide, including NULL character) with the
    227216 * 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
    229218 * 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 */
     221int c_fstat(const char *p, int *pe, int *nl, int *ty, int *ui, int *gi,
    233222            long *si, char a[20], char m[20], char c[20]);
    234223
     
    238227 * @param[in] perm An integer with the user's permission to check :
    239228 *   - 0 do not check for permissions
    240  *   - 1 check for execute permission 
     229 *   - 1 check for execute permission
    241230 *   - 2 check for write permission
    242231 *   - 4 check for read permission
     
    259248 * @param[out] rows Number of rows of the current terminal window
    260249 * @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
    262251 * to 80 and cols to 20.
    263252 */
  • 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.
    3322 */
    3423
    35  /** 
     24 /**
    3625  * @file defined.h
    3726  * @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
    3928  * in the library source code.
    4029  */
     
    6352 *
    6453 *  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):
    6655 *    - If it actually supports this feature, the macro defines derived type
    6756 *      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.
    3321
    3422!! file: errors.F90
    3523!! summary: Errors handling source file.
    3624!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826
    3927#include "defined.h"
     
    6048    !! Define an error
    6149    !!
    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
    6351    !! stores:
    6452    !!
    6553    !! - An integer to numerically identify the error
    6654    !! - 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
    6856    !!   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
    7058    !!   subroutines are supported by the library).
    7159    !!
     
    7967    INTEGER :: id = 0
    8068      !! 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.
    8371#if HAVE_FTNPROC
    8472    CONTAINS
     
    8876  END TYPE error
    8977
    90   INTERFACE 
     78  INTERFACE
    9179    !! Clean subroutine interface
    9280    SUBROUTINE clean_callback(err)
     
    9583      IMPLICIT NONE
    9684      TYPE(error), INTENT(in) :: err
    97         !! An error object with the input error 
     85        !! An error object with the input error
    9886    END SUBROUTINE clean_callback
    9987  END INTERFACE
    10088
    101   INTERFACE 
     89  INTERFACE
    10290    subroutine abort_() bind(C, name="abort")
    10391    end subroutine
     
    11199  END INTERFACE assert
    112100
    113   !> error equality operator 
     101  !> error equality operator
    114102  INTERFACE OPERATOR(==)
    115103    MODULE PROCEDURE error_equals, error_equals_int
    116104  END INTERFACE
    117105
    118   !> error inequality operator 
     106  !> error inequality operator
    119107  INTERFACE OPERATOR(/=)
    120108    MODULE PROCEDURE error_differs, error_differs_int
     
    132120  FUNCTION error_equals(this, other) RESULT(res)
    133121    !! 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
    136124    LOGICAL :: res                     !! .true. if __this__ and __other__ identifiers are the same, .false. otherwise
    137125    res = (this%id == other%id)
     
    150138  FUNCTION error_differs(this, other) RESULT(res)
    151139    !! 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
    154142    LOGICAL :: res                     !! .false. if __this__ and __other__ identifiers are the same, .true. otherwise
    155143    res = (this%id /= other%id)
     
    174162    CHARACTER(len=*), INTENT(in), OPTIONAL :: progname
    175163      !! An optional string with the name of the program
    176     LOGICAL, INTENT(in), OPTIONAL          :: as_warning 
     164    LOGICAL, INTENT(in), OPTIONAL          :: as_warning
    177165      !! An optional boolean flag to print the message as warning rather than as error (default to .false.).
    178166    CHARACTER(len=:), ALLOCATABLE :: str
    179167      !! An allocatable string with the string representation of the error
    180     CHARACTER(len=:), ALLOCATABLE :: pref 
     168    CHARACTER(len=:), ALLOCATABLE :: pref
    181169    pref = "error: "
    182170    IF (PRESENT(as_warning)) THEN ; IF (as_warning) pref = "warning: " ; ENDIF
     
    190178      str = pref//TRIM(this%msg)
    191179    ENDIF
    192     RETURN 
     180    RETURN
    193181  END FUNCTION error_to_string
    194182
     
    208196  SUBROUTINE assert_r(test,reason)
    209197    !! _Raise_ an assertion.
    210     !! 
     198    !!
    211199    !! The method raises an assertion and stops the execution if __test__ is .false.
    212     !! 
     200    !!
    213201    !! @note
    214202    !! If ISO_C_BINDING module is available, the method calls the method abort from the C standard library. Doing so,
    215203    !! 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.
    217205   LOGICAL, INTENT(in)          :: test
    218206     !! Expression to test.
     
    227215  SUBROUTINE assert_w(test,where,reason)
    228216    !! _Raise_ an assertion.
    229     !! 
     217    !!
    230218    !! The method raises an assertion and stops the execution if __test__ is .false.
    231     !! 
     219    !!
    232220    !! See [[errors(module):assert_r(subroutine)]] remark.
    233221    LOGICAL, INTENT(in)         :: test
     
    249237    !! @note
    250238    !! 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
    252240    !! 9992 files to be opened is far enough for any program !
    253241    !! @note
     
    255243    !! mind that loggers open files with the first free logical unit. Consequently
    256244    !! 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 !
    258246    INTEGER :: lu
    259247      !! 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.
    3321
    3422!! file: fsystem.F90
    3523!! summary: File system methods source file.
    3624!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826
    3927
     
    4634  IMPLICIT NONE
    4735
    48   PUBLIC 
     36  PUBLIC
    4937
    5038  PRIVATE :: get_umask
     
    5745    !!
    5846    !! 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
    6048      !! Starting CPU time
    61     INTEGER(kind=8), PRIVATE :: clock_start = 0d0 
     49    INTEGER(kind=8), PRIVATE :: clock_start = 0d0
    6250      !! Starting clock time
    6351    LOGICAL, PRIVATE         :: on_run = .false.
    6452      !! Chrono running state.
    6553#if HAVE_FTNPROC
    66     CONTAINS 
    67       PROCEDURE :: is_running => chrono_is_running 
     54    CONTAINS
     55      PROCEDURE :: is_running => chrono_is_running
    6856      PROCEDURE :: start      => chrono_start
    6957      PROCEDURE :: stop       => chrono_stop
     
    9583    END FUNCTION errno_c
    9684
    97     FUNCTION usleep_c(usec) BIND(C,name="usleep") 
     85    FUNCTION usleep_c(usec) BIND(C,name="usleep")
    9886      !! (attemps to) Sleep for a given number of microseconds
    9987      IMPORT C_INT
     
    127115
    128116    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
    130118      IMPORT c_char, C_INT
    131119      CHARACTER(len=c_char), INTENT(in)      :: path(*)  !! Path to check
     
    134122    END FUNCTION access_c
    135123
    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")
    137125      !! Create a directory or a file in given path
    138126      IMPORT c_char, C_INT
     
    149137      INTEGER(kind=C_INT), INTENT(in), VALUE :: uid     !! User id
    150138      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
    152140
    153141    FUNCTION gname_c(gid) BIND(C, name="c_gname")
     
    156144      INTEGER(kind=C_INT), INTENT(in), VALUE :: gid     !! Group id
    157145      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")
    161149      !! Get the directory name of the path
    162150      IMPORT c_char, c_ptr
     
    172160    END FUNCTION basename_c
    173161
    174     FUNCTION getcwd_c() BIND(C,name="c_getcwd") 
     162    FUNCTION getcwd_c() BIND(C,name="c_getcwd")
    175163      !! Get the current working directory
    176164      IMPORT c_ptr
     
    198186      CHARACTER(kind=c_char), INTENT(in) :: input(*)  !! Path to rename
    199187      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
    201189    END FUNCTION rename_c
    202190
     
    206194      CHARACTER(kind=c_char), INTENT(in)     :: path(*) !! Path to modify
    207195      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
    209197    END FUNCTION chmod_c
    210198
     
    213201      IMPORT c_char, C_INT
    214202      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
    216204    END FUNCTION chdir_c
    217205
     
    220208      IMPORT c_char, C_INT
    221209      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
    224212    END FUNCTION mkdir_c
    225213
     
    228216      IMPORT c_char, C_INT
    229217      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
    232220    END FUNCTION mkdirp_c
    233221
    234     FUNCTION copy_c(to,from) BIND(C,name="c_copy") 
     222    FUNCTION copy_c(to,from) BIND(C,name="c_copy")
    235223      !! Copy a file.
    236224      IMPORT c_char, C_INT
     
    240228    END FUNCTION copy_c
    241229
    242     FUNCTION remove_c(path) BIND(C,name="c_remove") 
     230    FUNCTION remove_c(path) BIND(C,name="c_remove")
    243231      !! Remove a file (or a directory) from the filesystem
    244232      IMPORT c_char, C_INT
    245233      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
    247235    END FUNCTION remove_c
    248236
     
    251239      IMPORT c_char, C_INT
    252240      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
    254242    END FUNCTION rmdir_c
    255243
     
    258246      IMPORT c_char, C_INT
    259247      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
    261249    END FUNCTION rmdirf_c
    262250
     
    282270      INTEGER(kind=C_INT), INTENT(out) :: r, &       !! Number of rows
    283271                                          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
    285273    END FUNCTION termsize_c
    286274
     
    289277      IMPORT  C_SIZE_T
    290278      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
    292280
    293281    FUNCTION getPeakRSS_c() BIND(C, name="c_getPeakRSS")
     
    295283      IMPORT  C_SIZE_T
    296284      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
    298286
    299287    FUNCTION getSystemMemory_c(total,avail,free) BIND(C, name='c_getSystemMemory')
     
    303291      INTEGER(kind=C_LONG_LONG), INTENT(out) :: avail             !! Current available memory.
    304292      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.
    306294    END FUNCTION getSystemMemory_c
    307295  END INTERFACE
     
    311299
    312300  FUNCTION fstring(string) RESULT(str)
    313     !! Convert C string to  Fortran string 
     301    !! Convert C string to  Fortran string
    314302    !!
    315303    !! The method copies the input C string up to the last C_NULL_CHAR found (not including it),
    316304    !! and returns the converted Fortran string.
    317305    !! 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
    319307    CHARACTER(len=:), ALLOCATABLE :: str   !! Converted fortran string
    320     INTEGER :: i,idx 
     308    INTEGER :: i,idx
    321309    str = ""
    322310    idx = INDEX(string,C_NULL_CHAR,.true.)
     
    335323    !!
    336324    !! 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.
    338326    !! @note
    339327    !! If __cstr__ is not allocated (i.e. the C_PTR is not associated) or if it is set
    340328    !! to a C empty string (i.e. '\0') then the method returns an empty string.
    341329    !! @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
    343331    !! the subroutine free_c(_cstr_).
    344332    TYPE(C_PTR), INTENT(in) :: cstr
     
    366354
    367355  FUNCTION cstring(string) RESULT(str)
    368     !> convert Fortran string to cstring 
     356    !> convert Fortran string to cstring
    369357    !!
    370358    !! The method returns a copy of the input string suitable for C functions argument.
    371     !! @note 
     359    !! @note
    372360    !! Input string is trimmed during computations
    373361    CHARACTER(len=*), INTENT(in) :: string
     
    385373!===============================================================================
    386374
    387   FUNCTION fs_getgid() RESULT(ret) 
     375  FUNCTION fs_getgid() RESULT(ret)
    388376    !! Get Group ID
    389377    INTEGER(kind=4) :: ret !! An integer with the group identifier
    390     ret = INT(getgid_c(),kind=4) 
     378    ret = INT(getgid_c(),kind=4)
    391379    RETURN
    392380  END FUNCTION fs_getgid
     
    399387  END FUNCTION fs_getpid
    400388
    401   FUNCTION fs_getuid() RESULT(ret) 
     389  FUNCTION fs_getuid() RESULT(ret)
    402390    !! Get User ID
    403391    INTEGER(kind=4) :: ret !! An integer with the user identifier
     
    413401    zname = gname_c(gid)
    414402    IF (.NOT.C_ASSOCIATED(zname)) THEN
    415       gname = "" 
     403      gname = ""
    416404    ELSE
    417405      gname = cstr2fstr(zname)
     
    427415    zname = gname_c(uid)
    428416    IF (.NOT.C_ASSOCIATED(zname)) THEN
    429       uname = "" 
     417      uname = ""
    430418    ELSE
    431419      uname = cstr2fstr(zname)
     
    438426    CHARACTER(len=*), INTENT(in)  :: path
    439427      !! A string with a (valid) path
    440     CHARACTER(len=:), ALLOCATABLE :: opath 
     428    CHARACTER(len=:), ALLOCATABLE :: opath
    441429      !! A Fortran allocated string with the parent directory path or an empty string if method fails
    442430    TYPE(C_PTR) :: zpath
     
    458446    CHARACTER(len=*), INTENT(in)  :: path
    459447      !! A string with a (valid) path
    460     CHARACTER(len=:), ALLOCATABLE :: opath 
     448    CHARACTER(len=:), ALLOCATABLE :: opath
    461449      !! The basename of the path or an empty string if method fails
    462450    TYPE(C_PTR) :: zpath
     
    478466    !!
    479467    !! The method computes the absolute path of the given path using C realpath function.
    480     !! @note 
     468    !! @note
    481469    !! If the input path is empty then current working directory is returned.
    482470    CHARACTER(len=*), INTENT(in)  :: path
    483471      !! A string with a (valid) path
    484     CHARACTER(len=:), ALLOCATABLE :: opath 
     472    CHARACTER(len=:), ALLOCATABLE :: opath
    485473      !! The absolute of the path or an empty string if method fails
    486474    TYPE(C_PTR) :: zpath
     
    497485    !! Get the relative representation of two paths
    498486    !!
    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.
    500488    !! If no common prefix is found, the method returns __path__.
    501489    CHARACTER(len=*), INTENT(in) :: path, & !! Path to be computed relative to reldir
     
    508496    ELSE
    509497      res = cstr2fstr(zpath)
    510     ENDIF 
     498    ENDIF
    511499    CALL free_c(zpath)
    512500  END FUNCTION fs_relpath
    513501
    514   FUNCTION fs_getcwd() RESULT(path) 
     502  FUNCTION fs_getcwd() RESULT(path)
    515503    !! Get the current working directory
    516504    CHARACTER(len=:), ALLOCATABLE :: path
     
    558546    LOGICAL :: ret                         !! True on success, false otherwise.
    559547    IF (LEN_TRIM(old) == 0.OR.LEN_TRIM(new) == 0) THEN
    560       ret = .false. 
     548      ret = .false.
    561549    ELSE
    562550      ret = INT(rename_c(cstring(ADJUSTL(old)),cstring(ADJUSTL(new)))) == 0
     
    572560    INTEGER(kind=C_INT) :: zmode
    573561    IF (LEN_TRIM(path) == 0) THEN
    574       ret = .false. 
     562      ret = .false.
    575563    ELSE
    576564      zmode = INT(oct_2_dec(mode),kind=C_INT)
     
    585573    LOGICAL :: ret                       !! True on success, false otherwise.
    586574    IF (LEN_TRIM(path) == 0) THEN
    587       ret = .false. 
     575      ret = .false.
    588576    ELSE
    589577      ret = INT(chdir_c(cstring(ADJUSTL(path)))) == 0
     
    597585    !! The method attempts to create a new directory pointed by __path__ with the permission
    598586    !! given by mode.
    599     CHARACTER(len=*), INTENT(in)  :: path 
     587    CHARACTER(len=*), INTENT(in)  :: path
    600588      !! The path to modify
    601589    INTEGER, INTENT(in), OPTIONAL :: mode
     
    608596    LOGICAL :: zperm
    609597    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)
    613601      IF (PRESENT(mode)) THEN
    614         IF (.NOT.chk_pm(mode)) THEN 
     602        IF (.NOT.chk_pm(mode)) THEN
    615603          ret = .false. ; RETURN
    616604        ENDIF
    617605        zmode = oct_2_dec(mode)
    618606      ENDIF
    619       zperm = .false. ; IF (PRESENT(permissive)) zperm = permissive 
     607      zperm = .false. ; IF (PRESENT(permissive)) zperm = permissive
    620608      IF (zperm) THEN
    621609        ret = INT(mkdirp_c(cstring(ADJUSTL(path)),INT(zmode,kind=C_INT))) == 0
     
    630618    !! Remove directory
    631619    !!
    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
    633621    !! to .true. then the function recursively deletes the directory and __ALL__ its content.
    634622    CHARACTER(len=*), INTENT(in)  :: path
     
    638626    LOGICAL :: ret
    639627      !! True on success, false otherwise.
    640     LOGICAL :: zforce 
     628    LOGICAL :: zforce
    641629    IF (LEN_TRIM(path) == 0) THEN
    642       ret = .false. 
     630      ret = .false.
    643631    ELSE
    644632      zforce = .false. ; IF (PRESENT(forced)) zforce = forced
     
    655643    !! Get some informations about a path
    656644    !!
    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.
    658646    !! The type of path as returned in __type__ argument is can take the following values:
    659647    !!
     
    666654    INTEGER, INTENT(out), OPTIONAL           :: type,  & !! Optional type of path (see function documentation).
    667655                                                perm,  & !! Optional permission of the path
    668                                                 nlnks, & !! Optional number of links to the path 
     656                                                nlnks, & !! Optional number of links to the path
    669657                                                uid,   & !! Optional user id
    670658                                                gid      !! Optional group id
     
    674662                                                ctime    !! Optional creation time
    675663    LOGICAL :: ret                                       !! True on success, false otherwise.
    676     INTEGER                       :: ty,pe,ln,ud,gd 
     664    INTEGER                       :: ty,pe,ln,ud,gd
    677665    INTEGER(kind=8)               :: fs
    678666    CHARACTER(len=:), ALLOCATABLE :: at,mt,ct
     
    691679      ret = INT(fstat_c(cstring(ADJUSTL(path)),p,l,t,u,g,f,ta,tm,tc)) == 0
    692680      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)
    695683        at = fstring(ta)
    696684        mt = fstring(tm)
    697685        ct = fstring(tc)
    698686      ENDIF
    699       IF (PRESENT(type))  type  = ty 
     687      IF (PRESENT(type))  type  = ty
    700688      IF (PRESENT(perm))  perm  = pe
    701689      IF (PRESENT(nlnks)) nlnks = ln
     
    713701    !! Check if a path is a directory
    714702    !!
    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
    716704    !! information about __path__ type.
    717705    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.
    719707    INTEGER :: ty
    720708    ret = fs_stat(path,type=ty)
    721     ret = ret.AND.(ty==2.or.ty==3) 
     709    ret = ret.AND.(ty==2.or.ty==3)
    722710    RETURN
    723711  END FUNCTION fs_isdir
    724712
    725713  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
    729717    !! information about __path__ type.
    730718    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.
    732720    INTEGER :: ty
    733721    ret=fs_stat(path,type=ty)
     
    737725
    738726  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
    742730    !! information about __path__ type.
    743731    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
    746734    ret=fs_stat(path,type=ty)
    747735    ret = ret.and.(ty==1.or.ty==3)
     
    759747    !! - 1 : Checks for EXECUTE permission
    760748    !! - 2 : Checks for WRITE permission
    761     !! - 4 : Checks for READ permission 
     749    !! - 4 : Checks for READ permission
    762750    CHARACTER(len=*), INTENT(in)  :: path       !! Path to check
    763751    INTEGER, INTENT(in), OPTIONAL :: permission !! Optional permission to check
     
    765753    INTEGER(kind=C_INT) :: zp
    766754    IF (LEN_TRIM(path) == 0) THEN
    767       ret = .false. 
     755      ret = .false.
    768756    ELSE
    769757      zp = 0 ; IF (PRESENT(permission)) zp = INT(permission,kind=C_INT)
     
    777765    !! Split given path into base,extension
    778766    !!
    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
    781769    !! of the string.
    782770    !! @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).
    784772    !! __ext__ will then be empty.
    785     CHARACTER(len=*), INTENT(in)               :: path     !! Path to split 
     773    CHARACTER(len=*), INTENT(in)               :: path     !! Path to split
    786774    CHARACTER(len=:), INTENT(out), ALLOCATABLE :: base, &  !! Output base of the path
    787775                                                  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.
    790778    LOGICAL                       :: zabs
    791779    INTEGER                       :: p
    792780    CHARACTER(len=:), ALLOCATABLE :: d,b,apath
    793     base = "" ; ext = "" 
     781    base = "" ; ext = ""
    794782    ret = .false.
    795783    IF (LEN_TRIM(path) == 0) THEN
     
    800788    IF (zabs) THEN
    801789      apath = fs_realpath(path) ; IF (LEN_TRIM(apath) == 0) RETURN
    802     ENDIF 
     790    ENDIF
    803791    d = fs_dirname(apath) ; IF (LEN_TRIM(d) == 0) RETURN
    804792    b = fs_basename(apath) ; IF (LEN_TRIM(b) == 0) RETURN
     
    806794    ! If dot is set as first char of basename : it's an hidden file
    807795    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)
    811799    ENDIF
    812800    ret = .true.
     
    815803
    816804  FUNCTION fs_create(path, mode, type, permissive) RESULT(ret)
    817     !! Create a directory/file 
     805    !! Create a directory/file
    818806    !!
    819807    !! The method creates the file/directory pointed by given __path__.
     
    827815    !! Unless __permissive__ is set to .true., the method will fails if intermediate
    828816    !! 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
    830818    INTEGER, INTENT(in), OPTIONAL          :: mode        !! Optional octal permisions to set
    831819    CHARACTER(len=1), INTENT(in), OPTIONAL :: type        !! Optional type of path to create
     
    833821    LOGICAL :: ret                                        !! True on success, false otherwise.
    834822    INTEGER                       :: zmd,zt,zp
    835     CHARACTER(len=:), ALLOCATABLE :: b,e 
     823    CHARACTER(len=:), ALLOCATABLE :: b,e
    836824    ret = .false.
    837825    ! Checking for existence
     
    839827      RETURN
    840828    ELSE IF (fs_access(path)) THEN
    841       RETURN 
     829      RETURN
    842830    ENDIF
    843831    ! Set type of path
    844832    IF (PRESENT(type)) THEN
    845833      IF (.NOT.(type(1:1)=="f".OR.type(1:1)=="d")) THEN
    846         RETURN 
     834        RETURN
    847835      ELSE
    848836        zt=0 ; IF (type(1:1)=="f") zt = 1
     
    854842    ! set permissions according to type
    855843    IF (zt == 0) THEN
    856       zmd = oct_2_dec(777)-get_umask() 
     844      zmd = oct_2_dec(777)-get_umask()
    857845    ELSE
    858846      zmd = oct_2_dec(666) -get_umask()
     
    874862  FUNCTION fs_get_parent(path, n) RESULT(opath)
    875863    !! 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)]]
    878866    !! to get an absolute path.
    879     !! @note 
     867    !! @note
    880868    !! If __n__ is greater than the maximum parent level of the path, "/" is returned.
    881869    CHARACTER(len=*), INTENT(in)  :: path
    882870      !! Input path
    883     INTEGER, INTENT(in), OPTIONAL :: n 
     871    INTEGER, INTENT(in), OPTIONAL :: n
    884872      !! The level of the parent to get
    885873    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
    887875    CHARACTER(len=:), ALLOCATABLE :: zp
    888876    INTEGER                       :: i,mx,zl,mzl
    889     opath = "" 
     877    opath = ""
    890878    zl = 1 ; IF (PRESENT(n)) zl = MAX(n,1)
    891879    IF (LEN_TRIM(path) == 0) THEN
     
    900888    mzl = 1 ; DO i=1,mx ; IF(zp(i:i) == '/') mzl=mzl+1 ; ENDDO
    901889    i=0
    902     DO 
     890    DO
    903891      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
    905893      mx = mx - 1
    906894    ENDDO
    907895    IF (mx >= 1) THEN
    908896      opath = zp(1:MAX(1,mx-1))
    909     ELSE 
    910       opath = "/" 
     897    ELSE
     898      opath = "/"
    911899    ENDIF
    912900    RETURN
     
    929917  SUBROUTINE fs_usleep(usec)
    930918    !! 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 !
    933921    INTEGER, INTENT(in) :: usec !! The number of microseconds to sleep for
    934     INTEGER(kind=C_INT) :: ret 
     922    INTEGER(kind=C_INT) :: ret
    935923    ! usleep expects useconds_t (unsigned int) which is given here as a 4-bytes int
    936924    ret = usleep_c(INT(usec,kind=C_INT))
     
    979967    LOGICAL          :: zpeak
    980968    CHARACTER(len=2) :: zunits
    981     INTEGER(kind=8)  :: ztot,zava,zfre   
     969    INTEGER(kind=8)  :: ztot,zava,zfre
    982970
    983971    zunits = 'B '   ; IF (PRESENT(units)) zunits = units
    984972    IF (zunits /= 'B' .AND. zunits /= 'KB' .AND. zunits /= 'MB' .AND. zunits /= 'GB') zunits = 'B '
    985973    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
    987975
    988976    IF (PRESENT(total))     total     = ztot
     
    10141002  FUNCTION oct_2_dec(octal) RESULT(res)
    10151003    !> Octal to decimal conversion
    1016     !! 
     1004    !!
    10171005    !! The method converts the octal number ranging from 0 to 777 in the decimal system.
    10181006    !! @attention
     
    10291017    ENDDO
    10301018    res=d
    1031     RETURN 
     1019    RETURN
    10321020  END FUNCTION oct_2_dec
    10331021
     
    10591047    !! Get octal number of string representation's permission
    10601048    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.
    10621050    oct = -1
    10631051    IF (LEN_TRIM(str) /= 3) RETURN
    10641052    SELECT CASE(str)
    1065       CASE("---")  ; oct = 0 
     1053      CASE("---")  ; oct = 0
    10661054      CASE("--x")  ; oct = 1
    10671055      CASE("-w-")  ; oct = 2
     
    10711059      CASE("rw-")  ; oct = 6
    10721060      CASE("rwx")  ; oct = 7
    1073       CASE DEFAULT 
     1061      CASE DEFAULT
    10741062        oct = -1 ; RETURN
    1075     END SELECT 
     1063    END SELECT
    10761064    RETURN
    10771065  END FUNCTION sp_2_op
     
    10901078      CASE(6) ; str="rw-"
    10911079      CASE(7) ; str="rwx"
    1092       CASE DEFAULT 
     1080      CASE DEFAULT
    10931081        str='ukn' ; RETURN
    1094     END SELECT 
     1082    END SELECT
    10951083    RETURN
    10961084  END FUNCTION op_2_sp
     
    10981086  FUNCTION str_perm(oct_perm) RESULT(ret)
    10991087    !! 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
    11011089    CHARACTER(len=9) :: ret      !! String representation of the octal number on succes, 'ukn' otherwise
    11021090    INTEGER :: u,g,o
    1103     IF (.NOT.chk_pm(oct_perm)) THEN 
     1091    IF (.NOT.chk_pm(oct_perm)) THEN
    11041092      ret = "ukn" ; RETURN
    11051093    ENDIF
     
    11691157
    11701158  SUBROUTINE chrono_start(this)
    1171     !! Start the chrono. 
     1159    !! Start the chrono.
    11721160    !!
    11731161    !! @note
     
    11801168    ENDIF
    11811169    this%on_run = .true.
    1182   END SUBROUTINE chrono_start 
     1170  END SUBROUTINE chrono_start
    11831171
    11841172  SUBROUTINE chrono_stop(this)
     
    11971185  END SUBROUTINE chrono_reset
    11981186
    1199   SUBROUTINE chrono_get(this,cpu,clock,units) 
     1187  SUBROUTINE chrono_get(this,cpu,clock,units)
    12001188    !! Get elapsed time since last call of start or reset methods.
    1201     !! 
     1189    !!
    12021190    !! The method computes the time elapsed in two ways :
    12031191    !!
    12041192    !! - 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
    12061194    !!   [[chrono(type):start(bound)]] (or [[chrono(type):reset(bound)]]).
    12071195    OBJECT(chrono), INTENT(in)             :: this
     
    12091197    REAL(kind=8), INTENT(out), OPTIONAL    :: cpu
    12101198      !! 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
    12121200      !! Elapsed system clock time in seconds by default (see units argument).
    12131201    CHARACTER(len=2), INTENT(in), OPTIONAL :: units
    12141202      !! 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'.
    12161204    CHARACTER(len=2) :: zu
    12171205    REAL(kind=8)     :: cu, fact
     
    12231211      ENDIF
    12241212      IF (PRESENT(clock)) THEN
    1225         CALL SYSTEM_CLOCK(ck,r,m) 
     1213        CALL SYSTEM_CLOCK(ck,r,m)
    12261214        clock = c2t(ck,this%clock_start,r,m)
    12271215      ENDIF
     
    12311219    ENDIF
    12321220    fact = 1d0
    1233     zu = 's' 
     1221    zu = 's'
    12341222    IF (PRESENT(units))  THEN
    12351223      zu = units
     
    12421230      END SELECT
    12431231    ENDIF
    1244     IF (PRESENT(cpu)) cpu = cpu / fact 
     1232    IF (PRESENT(cpu)) cpu = cpu / fact
    12451233    IF (PRESENT(clock)) clock = clock / fact
    12461234  END SUBROUTINE chrono_get
     
    12491237    !! Get the real-time between two clock counts from system_clock.
    12501238    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
    12521240    INTEGER(kind=8), INTENT(in) :: r !! Clock count rate
    12531241    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-Ardenne
    2 ! 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)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Clouds microphysics module
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
     38!! corrections: B. de Batz de Trenquelléon (2023)
    3839
    3940MODULE MM_CLOUDS
    4041  !! Clouds microphysics module.
    4142  !!
    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:
    4344  !!
    4445  !! - [nucleation](page/clouds.html#nucleation)
     
    4647  !! - [sedimentation](page/clouds.html#sedimentation)
    4748  !!
    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 deals with output argument which are most of the time the
     49  !!
     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
    5253  !! tendencies of relevant variables on the atmospheric column.
    5354  !!
    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
    5657  !! __GROUND__.
    5758  USE MM_MPREC
     
    6263  PRIVATE
    6364
    64   PUBLIC :: mm_cloud_microphysics, mm_cloud_sedimentation, mm_cloud_nucond 
    65 
    66   CONTAINS
     65  PUBLIC :: mm_cloud_microphysics, mm_cloud_sedimentation, mm_cloud_nucond
     66
     67CONTAINS
    6768
    6869  !============================================================================
     
    7374    !! Get the evolution of moments tracers through clouds microphysics processes.
    7475    !!
    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
    7677    !! tracers for nucleation, condensation and sedimentation processes for the atmospheric column.
    7778    !!
    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.
    8182    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}\)).
    8384    REAL(kind=mm_wp), DIMENSION(:), INTENT(out)   :: dm3a
    84       !! Tendency of the 3rd order moment of the aerosols distribution (fractal mode) (\(m^{3}.m^{-3}\)) .
     85    !! Tendency of the 3rd order moment of the aerosols distribution (fractal mode) (\(m^{3}.m^{-3}\)) .
    8586    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}\)).
    8788    REAL(kind=mm_wp), DIMENSION(:), INTENT(out)   :: dm3n
    88       !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
     89    !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
    8990    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}\)).
    9192    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
    9495    REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: zdm3i
    9596    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
    9899    dm3i = 0._mm_wp ; dgazs = 0._mm_wp
    99100
     
    108109      call mm_cloud_sedimentation(zdm0n,zdm3n,zdm3i)
    109110
    110       ! computes precipitations / ice fluxes
     111      ! computes precipitation, settling velocity and flux of ices
    111112      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
    115117        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
    118120      ! updates tendencies
    119121      dm0n = dm0n + zdm0n
     
    131133    !! Get moments tendencies through nucleation/condensation/evaporation.
    132134    !!
    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
    134136    !! tendencies of tracers for all the condensible species given in the vector __xESPS__.
    135137    !!
     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    !!
    136146    !! @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
    139149    !! \(CH_{4}\) (ice) and  __gazs(IDX)__ its vapor mole fraction.
    140150    REAL(kind=mm_wp), DIMENSION(:), INTENT(out)   :: dm0a
    141       !! Tendency of the 0th order moment of the aerosols (fractal mode) (\(m^{-3}\)).
     151    !! Tendency of the 0th order moment of the aerosols (fractal mode) (\(m^{-3}\)).
    142152    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}\)).
    144154    REAL(kind=mm_wp), DIMENSION(:), INTENT(out)   :: dm0n
    145       !! Tendency of the 0th order moment of the aerosols distribution (fractal mode) (\(m^{-3}\)).
     155    !! Tendency of the 0th order moment of the aerosols distribution (fractal mode) (\(m^{-3}\)).
    146156    REAL(kind=mm_wp), DIMENSION(:), INTENT(out)   :: dm3n
    147       !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
     157    !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
    148158    REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dm3i
    149       !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-3}\)).
     159    !! Tendencies of the 3rd order moments of each ice components (\(m^{3}.m^{-3}\)).
    150160    REAL(kind=mm_wp), DIMENSION(:,:), INTENT(out) :: dgazs
    151       !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)) .
     161    !! Tendencies of each condensible gaz species (\(mol.mol^{-1}\)) .
    152162    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
    156165    REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: zdm0a,zdm3a,zdm0n,zdm3n
     166
    157167    ALLOCATE(zdm0a(mm_nla,mm_nesp),zdm3a(mm_nla,mm_nesp), &
    158168             zdm0n(mm_nla,mm_nesp),zdm3n(mm_nla,mm_nesp))
     
    164174    ENDDO
    165175
    166     ! Computes balance :
    167     ! Each ice components has been treated independently from the others, and
    168     ! 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 the
    175     !   most intense activity of the ice components.
    176     !   that is the maximum value of the CCN tendencies regardless of its sign.
    177176    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
    185194    ENDDO
     195
    186196  END SUBROUTINE mm_cloud_nucond
    187197
     
    189199    !! Get moments tendencies through nucleation/condensation/evaporation of a given condensible specie.
    190200    !!
    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
    192202    !! microphysics processes (nucleation & condensation).
    193203    !!
    194204    !! @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\)
    197207    !! for M3) ; __vapX__ must be expressed in term of molar fraction.
    198208    TYPE(mm_esp), INTENT(in)                   :: xESP
    199       !! Condensate specie properties.
     209    !! Condensate specie properties.
    200210    REAL(kind=mm_wp),INTENT(in), DIMENSION(:)  :: vapX
    201       !! Gas specie molar fraction on the vertical grid from __TOP__ to __GROUND__ (\(mol.mol^{-1}\)).
     211    !! Gas specie molar fraction on the vertical grid from __TOP__ to __GROUND__ (\(mol.mol^{-1}\)).
    202212    REAL(kind=mm_wp),INTENT(in), DIMENSION(:)  :: m3iX
    203       !! 3rd order moment of the ice component (\(m^{3}.m^{-3}\)).
     213    !! 3rd order moment of the ice component (\(m^{3}.m^{-3}\)).
    204214    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dvapX
    205       !! Tendency of gas specie (\(mol.mol^{-1}\)).
     215    !! Tendency of gas specie (\(mol.mol^{-1}\)).
    206216    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3iX
    207       !! Tendency of the 3rd order moment of the ice component (\(m^{3}.m^{-3}\)).
     217    !! Tendency of the 3rd order moment of the ice component (\(m^{3}.m^{-3}\)).
    208218    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm0aer
    209       !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)).
     219    !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)).
    210220    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3aer
    211       !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)).
     221    !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)).
    212222    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm0ccn
    213       !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)).
     223    !! Tendency of the 0th order moment of the ccn distribution (\(m^{-3}\)).
    214224    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: dm3ccn
    215       !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
     225    !! Tendency of the 3rd order moment of the ccn distribution (\(m^{3}.m^{-3}\)).
    216226    REAL(kind=mm_wp),INTENT(out), DIMENSION(:) :: Xsat
    217       !! Saturation ratio values on the vertical grid (--).
     227    !! Saturation ratio values on the vertical grid (--).
    218228    INTEGER                                 :: i
    219229    REAL(kind=mm_wp)                        :: bef,aft
    220230    REAL(kind=mm_wp), DIMENSION(SIZE(vapX)) :: sm0a,sm3a,sm0n,sm3n,sm3iX
    221231    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
    226239    ! sXXX is the initial converted value saved
    227     sm3iX = m3iX/mm_rhoair 
     240    sm3iX = m3iX/mm_rhoair
    228241    sm0a = mm_m0aer_f/mm_rhoair ; sm3a = mm_m3aer_f/mm_rhoair
    229242    sm0n = mm_m0ccn/mm_rhoair ; sm3n = mm_m3ccn/mm_rhoair
    230243    ! zXXX is our working copy
    231     zm3ix = sm3ix ; zm0a = sm0a ; zm3a = sm3a ; zm0n = sm0n ; zm3n = sm3n
    232 
    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]
    234247    zvapX  = vapX  * xESP%fmol2fmas
    235     ! Surface tension
     248    ! Surface tension [N.m-1]
    236249    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
    239252    ! partial pressure of X specie
    240253    pX = vapX * mm_play
    241254    ! Saturation ratio
    242255    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   
    247257    ! Gets nucleation rate (ccn radius is the monomer !)
    248258    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)))
    249304    ! Gets growth rate
    250     call growth_rate(mm_temp,mm_play,pX/Xsat,xESP,seq,mm_drad,grate)
    251     ctot = zvapx + xESP%rho * m3iX
    252     up = vapx + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * mm_drad * seq * zm0n
    253     down = 1._mm_wp + mm_dt * grate * 4._mm_wp * mm_pi * xESP%rho * mm_drad / qsat * zm0n
     305    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
    254309    ! gets new vapor X specie mass mixing ratio : cannot be greater than the
    255310    ! total gas + ice and lower than nothing :)
     
    257312    ! gets "true" growth rate
    258313    grate = grate * (newvap/qsat - seq)
    259    
     314
    260315    ! 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
    321331
    322332    ! Computes balance
    323333    IF (mm_debug) THEN
    324       WRITE(*,'(a)') "Condensation/nucleation balance :"
    325334      DO i=1,mm_nla
    326335        bef = sm0a(i) + sm0n(i)
    327336        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
    330341        bef = sm3a(i) + sm3n(i)
    331342        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
    334347      ENDDO
    335348    ENDIF
    336349
    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 !
    342360
    343361  END SUBROUTINE nc_esp
    344  
     362
    345363  SUBROUTINE nuc_rate(rccn,temp,xESP,pvp,sat,rate)
    346364    !! Get nucleation rate.
    347365    !!
    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
    349367    !! of size __rccn__.
    350368    !! Except __xESP__, all arguments are vectors of the same size (vertical grid).
     
    355373    TYPE(mm_esp), INTENT(in)                    :: xESP !! X specie properties (--).
    356374    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
    363379    ! 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
    385400    RETURN
    386401  END SUBROUTINE nuc_rate
     
    390405    !!
    391406    !! The method computes the growth rate a drop through condensation/evaporation processes:
    392     !! 
     407    !!
    393408    !! $$ r \times \frac{dr}{dt} = g_{rate} \times (S - S_{eq}) $$
    394409    !!
     
    396411    REAL(kind=mm_wp), INTENT(in), DIMENSION(:)  :: temp  !! Temperature (K).
    397412    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).
    402417    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: rate  !! Growth rate (\(m^{2}.s^{-1}\)).
    403418    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: k,knu,slf,rkc,rdc,l,dv
     
    412427    ! Diffusion coefficient of X gas
    413428    Dv(:) = 1._mm_wp/3._mm_wp*dsqrt(8._mm_wp*mm_rgas*temp(:)/(mm_pi*xESP%masmol))*mm_kboltz*temp(:) / &
    414          (mm_pi*pres(:)*(mm_air_rad+xESP%ray)**2* dsqrt(1._mm_wp+xESP%fmol2fmas))
     429      (mm_pi*pres(:)*(mm_air_rad+xESP%ray)**2* dsqrt(1._mm_wp+xESP%fmol2fmas))
    415430    knu(:) = l(:)/drad(:)                                         ! The knudsen number of the drop
    416431    slf(:) = (1.333_mm_wp+0.71_mm_wp/knu(:))/(1._mm_wp+1._mm_wp/knu(:)) ! Slip flow correction
     
    424439    RETURN
    425440  END SUBROUTINE growth_rate
    426  
     441
    427442
    428443  !-----------------------------------------------------------------------------
     
    433448    !! Compute the tendency of _clouds_ related moments through sedimentation process.
    434449    !!
    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
    440455    !! sedimentation process and then computes the matrix
    441456    !! product with input moments values to get final tendencies.
    442457    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}\)).
    444459    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}\)).
    446461    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}\)).
    448463    INTEGER                                   :: im,nm
    449464    REAL(kind=mm_wp), DIMENSION(:,:), ALLOCATABLE :: moms, momsf,chg_matrix
     465
    450466    nm = 2 + mm_nesp
    451467    ALLOCATE(moms(mm_nla,nm),momsf(mm_nla,nm),chg_matrix(mm_nla,mm_nla))
    452     ! Initializes moms 
     468    ! Initializes moms
    453469    moms(:,1)  = mm_m0ccn * mm_dzlev
    454470    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
    458472    ! Computes exchange matrix
    459473    CALL exchange(mm_drad,mm_drho,mm_dt,chg_matrix)
     
    463477    dm0n = (momsf(:,1)-moms(:,1))/mm_dzlev
    464478    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
    468480    RETURN
    469481  END SUBROUTINE mm_cloud_sedimentation
     
    472484    !! Compute the exchange matrix.
    473485    !!
    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
    477489    !! values over the atmospheric vertical structure. __matrix__ is square 2D-array with same
    478490    !! dimension size than __rad__.
    479491    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rad
    480       !! Cloud drop radius over the atmospheric vertical structure (m).
     492    !! Cloud drop radius over the atmospheric vertical structure (m).
    481493    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rhog
    482       !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)).
     494    !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)).
    483495    REAL(kind=mm_wp), INTENT(in)               :: dt
    484       !! Timestep (s).
     496    !! Timestep (s).
    485497    REAL(kind=mm_wp), INTENT(out)              :: matrix(:,:)
    486       !! The output _exchange matrix_.
    487     INTEGER                                 :: nz,i,j,jj,jinf,jsup
     498    !! The output _exchange matrix_.
     499    INTEGER                                     :: nz,i,j,jj,jinf,jsup
    488500    REAL(kind=mm_wp)                            :: zni,znip1,xf,xft,xcnt
    489501    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: puit
    490502    REAL(kind=mm_wp)                            :: cpte,cpte2
    491     INTEGER, PARAMETER                      :: ichx  = 1
     503    REAL(kind=mm_wp)                            :: zsurf
     504    INTEGER, PARAMETER                          :: ichx  = 1
    492505    matrix = 0._mm_wp ; nz = SIZE(rad) ; ALLOCATE(puit(nz))
    493     ! compute exchange matrix
     506    zsurf = mm_zlev(nz)
     507   
     508    ! compute exchange matrix
    494509    DO i=1,nz
    495510      puit(i) = 0._mm_wp
    496511      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) THEN
     512      ! 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
    503518        xft=0._mm_wp
    504519        xf=1._mm_wp
     
    506521        puit(i)=puit(i)+xf
    507522      ENDIF
    508       ! partial precipitation [ znip1 <= 0 && zni > 0 ] :
    509       IF (zni>0._mm_wp .and. znip1 <= 0._mm_wp) THEN
    510         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)
    511526        xf=(1.-xft)
    512527        xcnt=xcnt+xf
    513528        puit(i)=puit(i)+xf
    514529      ENDIF
    515       ! General case: no ground precipitation [ znip1 > 0 && zni > 0 ]
    516       IF (zni>0._mm_wp.and.znip1>0._mm_wp) THEN
    517         xft = 1._mm_wp       ! on a la totalite de la case
     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
    518533        xf  = 0._mm_wp
    519534        xcnt=xcnt+xf
    520535        puit(i)=puit(i)+xf
    521536      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)
    525544      ! Locate new "drop" position in the verical grid
    526545      jsup=nz+1
     
    531550      ENDDO
    532551      ! 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
    535554        WRITE(*,'(a)') "[EXCHANGE] speaking: The impossible happened !"
    536555        call EXIT(666)
    537556      ENDIF
    538557      ! Volume inside a single level
    539       IF (jsup==jinf.and.jsup<=nz) THEN 
     558      IF (jsup==jinf.and.jsup<=nz) THEN
    540559        xf=1._mm_wp
    541560        xcnt=xcnt+xft*xf
    542561        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
    547566        xf=(zni-mm_zlev(jinf))/(zni-znip1)
    548567        xcnt=xcnt+xf*xft
     
    556575        ENDIF
    557576      ENDIF
    558  
     577
    559578      ! Volume over 3 or more levels
    560579      IF (jinf > jsup+1) THEN
     
    573592          matrix(jj,i)=matrix(jj,i)+xft*xf
    574593        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...
    578598    IF (mm_debug) THEN
    579599      cpte=0._mm_wp ; cpte2=0._mm_wp
     
    582602          cpte=cpte+matrix(jj,j)
    583603        ENDDO
    584         cpte2=cpte+puit(j)
    585604      ENDDO
     605      cpte2=cpte+sum(puit)
    586606      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
    589608      ENDIF
    590609    ENDIF
    591     RETURN
     610
     611    RETURN
    592612  END SUBROUTINE exchange
    593613
     
    595615    !! Compute displacement of a cell under sedimentation process.
    596616    !!
    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
    598618    !! descibed in the following scheme:
    599619    !!
     
    604624    !! @note
    605625    !! 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)]],
    607627    !! [[mm_globals(module):mm_zlay(variable)]] and [[mm_globals(module):mm_zlev(variable)]] and uses __idx__ to
    608628    !! get the relevant value to use on the vertical grid.
    609629    INTEGER, INTENT(in)                        :: ichx
    610       !! Velocity extrapolation control flag (0 for linear, 1 for exponential -preferred -).
     630    !! Velocity extrapolation control flag (0 for linear, 1 for exponential -preferred -).
    611631    INTEGER, INTENT(in)                        :: idx
    612       !! Initial position of the drop (subscript of vertical layers vectors).
     632    !! Initial position of the drop (subscript of vertical layers vectors).
    613633    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rad
    614       !! Cloud drop radius over the atmospheric vertical structure (m).
     634    !! Cloud drop radius over the atmospheric vertical structure (m).
    615635    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: rho
    616       !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)).
     636    !! Cloud drop density over the atmospheric vertical structure (\(kg.m^{-3}\)).
    617637    REAL(kind=mm_wp), INTENT(in)               :: dt
    618       !! Timestep (s).
     638    !! Timestep (s).
    619639    REAL(kind=mm_wp), INTENT(out)              :: zni
    620       !! Final layer center position (m).
     640    !! Final layer upper boundary position (m).
    621641    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
    624644    REAL(kind=mm_wp)            :: alpha,argexp,v0,arg1,arg2
    625645    INTEGER                 :: i,nz
    626646    REAL(kind=mm_wp), PARAMETER :: es = 30._mm_wp
     647
    627648    nz = SIZE(rad)
    628649    ! Linear extrapolation of velocity
     
    636657        ! velocity lower interface
    637658        wi = wsettle(mm_plev(idx+1),mm_btemp(idx+1),mm_zlev(idx+1), &
    638                      rho(idx+1),rad(idx+1))
    639       ELSE 
    640         WRITE(*,'(a)') "[getnzs] speaking:" 
     659          rho(idx+1),rad(idx+1))
     660      ELSE
     661        WRITE(*,'(a)') "[getnzs] speaking:"
    641662        WRITE(*,'(a)') "This is the fatal error..."
    642663        WRITE(*,'(a)') "index is higher than number of levels"
     
    647668      zns = mm_zlev(idx)-mm_dzlev(idx)-w*dt
    648669      RETURN
    649     ! Exponential extrapolation of velocity
     670      ! Exponential extrapolation of velocity
     671
    650672    ELSEIF(ichx==1) THEN
    651       ws = wsettle(mm_plev(idx),mm_btemp(idx),mm_zlev(idx),rho(idx),rad(idx))
    652673      zs = mm_zlev(idx)
    653       wi = 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))
    654675      zi=mm_zlay(idx)
     676      wi = wsettle(mm_play(idx),mm_temp(idx),zi,rho(idx),rad(idx))
    655677      ! ws & wi must be different !
    656678      IF(dabs(wi-ws)/wi <= 1.e-3_mm_wp)  wi=ws/1.001_mm_wp
    657679      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)
    660682      v0 = ws/dexp(argexp)
    661683      arg1=1._mm_wp+v0*alpha*dexp(argexp)*dt
    662684      argexp=MAX(MIN(alpha*(mm_zlev(idx)-mm_dzlev(idx)),es),-es)
    663685      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
    665687        ! correct velocity
    666688        ! divides the velocity argument in arg1 and arg2 :
     
    669691        DO i=1,25
    670692          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)"
    673695            arg1=(arg1+1._mm_wp)/2._mm_wp ; arg2=(arg2+1._mm_wp)/2._mm_wp
    674696          ELSE
    675             EXIT 
     697            EXIT
    676698          ENDIF
    677699        ENDDO
     
    683705        ENDIF
    684706      ENDIF
     707
    685708      zni = mm_zlev(idx)-dlog(arg1)/alpha
    686709      zns = mm_zlev(idx)-mm_dzlev(idx)-dlog(arg2)/alpha
     710
    687711      RETURN
    688     ENDIF 
     712    ENDIF
    689713  END SUBROUTINE getnzs
    690714
    691715  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
    695719    !! radius __rad__. It accounts for the slip-flow transition (no approximation).
    696720    REAL(kind=mm_wp), INTENT(in) :: p   !! The pressure level (Pa).
     
    700724    REAL(kind=mm_wp), INTENT(in) :: rad !! Radius of the particle (m).
    701725    REAL(kind=mm_wp) :: w               !! Settling velocity (\(m.s^{-1}\)).
    702     REAL(kind=mm_wp)            :: g,a,kn,nu
    703     REAL(kind=mm_wp), PARAMETER :: ra = 1.75e-10_mm_wp, nu0 = 1.74e-4_mm_wp, c = 109._mm_wp
    704     ! Computes corrected gravity
    705     g = mm_effg(z)
    706     ! Knudsen number
    707     kn = mm_kboltz*t/(p*4._mm_wp*sqrt(2._mm_wp)*mm_pi*ra**2)/rad
    708     ! Air viscosity
    709     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
    710734    ! 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]
    714739  END FUNCTION wsettle
    715740
     
    723748    !!
    724749    !! @note
    725     !! The computed flux is always positive. 
     750    !! The computed flux is always positive.
    726751    REAL(kind=mm_wp), INTENT(in)               :: rho
    727       !! Tracer density (\(kg.m^{-3}\)).
     752    !! Tracer density (\(kg.m^{-3}\)).
    728753    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: m3
    729       !! Vertical profile of the total volume of tracer (i.e. M3) from __TOP__ to __GROUND__ (\(m^{3}.m^{-3}\)).
     754    !! Vertical profile of the total volume of tracer (i.e. M3) from __TOP__ to __GROUND__ (\(m^{3}.m^{-3}\)).
    730755    REAL(kind=mm_wp), DIMENSION(SIZE(m3)) :: flx
    731       !! Mass sedimentation fluxes at each layer from __TOP__ to __GROUND__ (\(kg.m^{-2}.s^{-1}\)).
     756    !! Mass sedimentation fluxes at each layer from __TOP__ to __GROUND__ (\(kg.m^{-2}.s^{-1}\)).
    732757    REAL(kind=mm_wp), SAVE :: fac = 4._mm_wp/3._mm_wp * mm_pi
    733758    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-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Parameters and global variables module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838
    3939MODULE MM_GLOBALS
    4040  !! Parameters and global variables module.
    41   !! 
     41  !!
    4242  !! # Module overview
    4343  !!
    4444  !! The module defines all the parameters and global variables that are common
    4545  !! to all other modules of the library.
    46   !! 
     46  !!
    4747  !! It is separated in two parts :
    4848  !!
     
    5252  !!   method.
    5353  !! - 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.
    6262  !!     \(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,
    6565  !!     the molar fraction of each condensible species (related to ice components) and some
    6666  !!     scalar variables that holds arrays sizes.
    6767  !!
    6868  !! @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
    7070  !! temperature...) are oriented from the __TOP__ of the atmosphere to the __GROUND__.
    7171  !!
    72   !! @note 
    73   !! The module also imports errors module from __FCCP__ library to get definitions of the error object
     72  !! @note
     73  !! The module also imports errors module from __SWIFT__ library to get definitions of the error object
    7474  !! everywhere in the library ([[mm_globals(module)]] is always imported, except in [[mm_mprec(module)]]).
    7575  !!
    76   !! # Global variables 
     76  !! # Global variables
    7777  !!
    7878  !! [[mm_globals(module)]] module contains the declaration of all global/common variable that are shared
     
    8282  !! the following sections list all the global variables by category.
    8383  !!
    84   !! ## Control flags 
    85   !! 
     84  !! ## Control flags
     85  !!
    8686  !! | Name               | Description
    8787  !! | :----------------- | :-----------------
     
    9393  !! | mm_w_clouds_sed    | Enable/Disable clouds microphysics sedimentation
    9494  !! | 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
    9696  !! | mm_wsed_m3         | Force all aerosols moments to fall at M3 settling velocity
    9797  !! | mm_no_fiadero_w    | Enable/Disable __Fiadero__ correction
     
    101101  !! | Name            | Description
    102102  !! | :-------------- | :-----------------
    103   !! | mm_fiadero_min  | Minimum ratio for __Fiadero__'s correction 
     103  !! | mm_fiadero_min  | Minimum ratio for __Fiadero__'s correction
    104104  !! | 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
    108108  !!
    109109  !! | Name      | Description
     
    131131  !! | mm_w_prod   | Angular frequency of the time-dependent production rate.
    132132  !! | 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\))
    134134  !! | mm_rpla     | Planet radius (m)
    135135  !! | mm_g0       | Planet acceleration due to gravity constant (ground) (\(m.s^{-2}\))
     
    152152  ! the following variables are read-only outside this module.
    153153  ! One must call the afferent subroutine to update them.
    154    
     154
    155155  ! initialization control flags (cannot be updated)
    156156  PROTECTED :: mm_ini,mm_ini_col,mm_ini_aer,mm_ini_cld
     
    165165  ! Moments parameters (derived, are updated with moments parameters)
    166166  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).
    170172
    171173  LOGICAL, SAVE :: mm_w_haze_prod = .true. !! Enable/Disable haze production.
     
    182184  !> Enable/Disable __Fiadero__'s correction.
    183185  !!
    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.
    186188  !!
    187189  !! @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
    189191  !! related to the coupling between the two moments. In order to reduce the instabilities, settling
    190192  !! velocity of moments are forced to be the same, see [[mm_globals(module):mm_wsed_m0(variable)]] and
    191193  !! [[mm_globals(module):mm_wsed_m3(variable)]]).
    192   LOGICAL, SAVE          :: mm_no_fiadero_w = .false. 
     194  LOGICAL, SAVE          :: mm_no_fiadero_w = .false.
    193195
    194196  !> Minimum ratio for __Fiadero__ correction.
    195197  !!
    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
    197199  !! value of the moment's ratio between two adjacents vertical cells to be used within the correction.
    198200  REAL(kind=mm_wp), SAVE :: mm_fiadero_min  = 0.1_mm_wp
     
    200202  !> Maximum ratio for __Fiadero__ correction.
    201203  !!
    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
    203205  !! value of the moment's ratio between two adjacents vertical cells to be used within the correction.
    204206  REAL(kind=mm_wp), SAVE :: mm_fiadero_max  = 10._mm_wp
     
    213215  INTEGER, PARAMETER :: mm_coag_ff = 4 !! FF mode interaction for coagulation.
    214216  !> 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
    216218
    217219  !> Pi number.
    218220  REAL(kind=mm_wp), PARAMETER :: mm_pi = 4._mm_wp*atan(1._mm_wp)
    219221  !> 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
    221223  !> Boltzmann constant (\(J.K^{-1}\)).
    222224  REAL(kind=mm_wp), PARAMETER :: mm_kboltz = 1.3806488e-23_mm_wp
     
    261263
    262264  !> 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
    265267  !! [[mm_globals(module):mm_global_init(interface)]] from the following equation:
    266268  !!
    267269  !! $$ r_{a} = r_{b}^{3/D_{f}}\times r_{m}^{\frac{D_{f}-3}{D_{f}}} $$
    268270  !!
    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
    270272  !! \(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
    272300
    273301  !> Characteristic radius threshold.
    274302  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
    275309
    276310  !> Name of condensible species.
     
    339373  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_temp
    340374  !>  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
    342376  !> Temperature vertical profil at interfaces (K).
    343377  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_btemp
    344378
    345379  !> 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
    348382  !! __TOP__ to the __GROUND__.
    349383  !! @note __mm_dzlev__ is defined on the total number of layers and actually
     
    352386
    353387  !> Atmospheric layers "thickness" (m).
    354   !! 
     388  !!
    355389  !! Atmospheric thickness between the center of two adjacent layers (\(m\))
    356390  !! 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
    359393  !! 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
    361395  !! __GROUND__ layer and below the surface. It is arbitrary and not used.
    362396  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_dzlay
     
    377411  !> Ice components 3rd order moments (\(m^{3}.m^{-3}\)).
    378412  !!
    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
    380414  !! components in the second.
    381   !! @note 
     415  !! @note
    382416  !! Both [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]]
    383417  !! share the same indexing (related to species order).
     
    387421  !!
    388422  !! 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
    391425  !! Both [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]]
    392426  !! share the same indexing (related to species order).
     
    410444  !> Spherical mode \(M_{0}\) settling velocity (\(m.s^{-1}\)).
    411445  !!
    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
    413447  !! the \(0^{th}\) order moment of the spherical mode.
    414448  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    415   !! @note 
     449  !! @note
    416450  !! This variable is always negative.
    417451  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m0as_vsed
     
    419453  !> Spherical mode \(M_{3}\) settling velocity (\(m.s^{-1}\)).
    420454  !!
    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
    422456  !! \(3^{rd}\) order moment of the spherical mode.
    423457  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    424   !! @note 
     458  !! @note
    425459  !! This variable is always negative.
    426460  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m3as_vsed
     
    428462  !> Fractal mode \(M_{0}\) settling velocity (\(m.s^{-1}\)).
    429463  !!
    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
    431465  !! \(0^{th}\) order moment of the fractal mode.
    432466  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    433   !! @note 
     467  !! @note
    434468  !! This variable is always negative.
    435469  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m0af_vsed
     
    437471  !> Fractal mode \(M_{3}\) settling velocity (\(m.s^{-1}\)).
    438472  !!
    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
    440474  !! \(3^{rd}\) order moment of the fractal mode.
    441475  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    442   !! @note 
     476  !! @note
    443477  !! This variable is always negative.
    444478  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_m3af_vsed
     
    448482  !! It is a vector with the vertical layers that contains the mass fluxes for spherical aerosols.
    449483  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    450   !! @note 
     484  !! @note
    451485  !! This variable is always negative.
    452486  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_aer_s_flux
     
    456490  !! It is a vector with the vertical layers that contains the mass fluxes for fractal aerosols
    457491  !! It is updated in [[mm_haze(module):mm_haze_sedimentation(subroutine)]].
    458   !! @note 
     492  !! @note
    459493  !! This variable is always negative.
    460494  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_aer_f_flux
     
    464498  REAL(kind=mm_wp), SAVE :: mm_ccn_prec = 0._mm_wp
    465499
    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).
    470504  !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]].
    471505  !! @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.
    473516  REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE, SAVE :: mm_ccn_flux
    474517
    475518  !> Ice components precipitations (m).
    476519  !!
    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
    478521  !! than [[mm_globals(module):mm_m3ice(variable)]] and [[mm_globals(module):mm_gazs(variable)]].
    479522  !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]].
     
    484527  !> Ice components sedimentation fluxes (\(kg.m^{-2}.s-1\)).
    485528  !!
    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
    487530  !! in the second. It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]].
    488531  !! @note
     
    492535  !> Condensible species saturation ratio (--).
    493536  !!
    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
    495538  !! species in the second.
    496539  !! It is updated in [[mm_clouds(module):mm_cloud_microphysics(subroutine)]].
     
    516559  INTERFACE mm_cloud_properties
    517560    MODULE PROCEDURE cldprop_sc,cldprop_ve
    518   END INTERFACE
     561  END INTERFACE mm_cloud_properties
    519562
    520563  !> Interface to global initialization.
     
    522565  !! The method performs the global initialization of the model.
    523566  !! @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
    525568  !! initializes global variable that are not thread private.
    526569  !!
    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
    531573  INTERFACE mm_global_init
    532574    MODULE PROCEDURE mm_global_init_0,mm_global_init_1
    533   END INTERFACE
     575  END INTERFACE mm_global_init
    534576
    535577  !> Check an option from the configuration system.
     
    538580  !! set a default value if the option is not found. This is an overloaded method
    539581  !! that can take in input either a floating point, integer, logical or string
    540   !! option value. 
     582  !! option value.
    541583  INTERFACE mm_check_opt
    542584    MODULE PROCEDURE check_r1,check_i1,check_l1,check_s1
    543   END INTERFACE
     585  END INTERFACE mm_check_opt
    544586
    545587  ! --- OPENMP ---------------
    546   ! All variable related to column computations should be private to each thread
     588  ! All variables related to column computations should be private to each thread
    547589  !
    548590  !$OMP THREADPRIVATE(mm_ini_col,mm_ini_aer,mm_ini_cld)
     
    551593  !$OMP THREADPRIVATE(mm_m0ccn,mm_m3ccn,mm_m3ice,mm_gazs)
    552594  !$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)
    554596  !$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)
    556598  !$OMP THREADPRIVATE(mm_nla,mm_nle)
    557599
     
    559601
    560602
    561   CONTAINS
     603CONTAINS
    562604
    563605  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)
    568611    !! Initialize global parameters of the model.
    569     !! 
     612    !!
    570613    !! 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. Their
    572     !! 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.
    573616    !! @note
    574617    !! If the method fails to initialize parameters (i.e. returned error is not 0). Then the model
    575618    !! should probably be aborted as the global variables of the model will not be correctly setup.
    576619    !! @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
    584626    REAL(kind=mm_wp), INTENT(in)           :: dt
    585       !! Microphysics timestep in seconds.
     627    !! Microphysics timestep in seconds.
    586628    REAL(kind=mm_wp), INTENT(in)           :: df
    587       !! Fractal dimension of fractal aerosol.
     629    !! Fractal dimension of fractal aerosol.
    588630    REAL(kind=mm_wp), INTENT(in)           :: rm
    589       !! Monomer radius in meter.
     631    !! Monomer radius in meter.
    590632    REAL(kind=mm_wp), INTENT(in)           :: rho_aer
    591       !! Aerosol density in \(kg.m^{-3}\).
     633    !! Aerosol density in \(kg.m^{-3}\).
    592634    REAL(kind=mm_wp), INTENT(in)           :: p_prod
    593       !!  Aerosol production pressure level in Pa.
     635    !!  Aerosol production pressure level in Pa.
    594636    REAL(kind=mm_wp), INTENT(in)           :: tx_prod
    595       !! Spherical aerosol mode production rate in \(kg.m^{-2}.s^{-1}\).
     637    !! Spherical aerosol mode production rate in \(kg.m^{-2}.s^{-1}\).
    596638    REAL(kind=mm_wp), INTENT(in)           :: rc_prod
    597       !! Spherical mode characteristic radius for production in meter.
     639    !! Spherical mode characteristic radius for production in meter.
    598640    REAL(kind=mm_wp), INTENT(in)           :: rplanet
    599       !! Planet radius in meter
     641    !! Planet radius in meter
    600642    REAL(kind=mm_wp), INTENT(in)           :: g0
    601       !! Planet gravity acceleration at ground level in \(m.s^{-2}\).
     643    !! Planet gravity acceleration at ground level in \(m.s^{-2}\).
    602644    REAL(kind=mm_wp), INTENT(in)           :: air_rad
    603       !! Air molecules mean radius in meter.
     645    !! Air molecules mean radius in meter.
    604646    REAL(kind=mm_wp), INTENT(in)           :: air_mmol
    605       !! Air molecules mean molar mass in \(kg.mol^{-1}\).
     647    !! Air molecules mean molar mass in \(kg.mol^{-1}\).
    606648    INTEGER, INTENT(in)                    :: coag_interactions
    607       !! Coagulation interactions process control flag.
     649    !! Coagulation interactions process control flag.
    608650    LOGICAL, INTENT(in)                    :: clouds
    609       !! Clouds microphysics control flag.
     651    !! Clouds microphysics control flag.
    610652    CHARACTER(len=*), INTENT(in)           :: spcfile
    611       !! Clouds microphysics condensible species properties file.
     653    !! Clouds microphysics condensible species properties file.
    612654    REAL(kind=mm_wp), INTENT(in), OPTIONAL :: fiadero_max
    613       !! Maximum moment ratio threshold for Fiadero correction (default: 10.) .
     655    !! Maximum moment ratio threshold for Fiadero correction (default: 10.) .
    614656    REAL(kind=mm_wp), INTENT(in), OPTIONAL :: fiadero_min
    615       !! Minimum moment ratio threshold for Fiadero correction (default: 0.1).
     657    !! Minimum moment ratio threshold for Fiadero correction (default: 0.1).
    616658    LOGICAL, INTENT(in), OPTIONAL          :: w_haze_prod
    617       !! Haze microphysics production process control flag (default: T).
     659    !! Haze microphysics production process control flag (default: T).
    618660    LOGICAL, INTENT(in), OPTIONAL          :: w_haze_sed
    619       !! Haze microphysics sedimentation process control flag (default: T).
     661    !! Haze microphysics sedimentation process control flag (default: T).
    620662    LOGICAL, INTENT(in), OPTIONAL          :: w_haze_coag
    621       !! Haze microphysics coagulation process control flag (default: T).
     663    !! Haze microphysics coagulation process control flag (default: T).
    622664    LOGICAL, INTENT(in), OPTIONAL          :: w_cloud_sed
    623       !! Cloud microphysics nucleation/conensation process control flag (default: __clouds__ value).
     665    !! Cloud microphysics nucleation/conensation process control flag (default: __clouds__ value).
    624666    LOGICAL, INTENT(in), OPTIONAL          :: w_cloud_nucond
    625       !! Cloud microphysics production process control flag (default: __clouds__ value).
     667    !! Cloud microphysics production process control flag (default: __clouds__ value).
    626668    LOGICAL, INTENT(in), OPTIONAL          :: no_fiadero
    627       !! Disable Fiadero correction for haze sedimentation process (default: F).
     669    !! Disable Fiadero correction for haze sedimentation process (default: F).
    628670    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)
    632686    TYPE(error) :: err
    633       !! Error status of the function.
     687    !! Error status of the function.
    634688    INTEGER                                           :: i
    635689    TYPE(cfgparser)                                   :: cp
    636     CHARACTER(len=st_slen)                            :: spcpath
    637     CHARACTER(len=:), ALLOCATABLE                     :: defmsg
    638690    CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species
    639691    REAL(kind=mm_wp)                                  :: zfiamin,zfiamax
    640692    LOGICAL                                           :: zwhp,zwhs,zwhc,zwcs,zwcn,znofia, &
    641693                                                         zwstom0,zwstom3
    642 
    643694    zwhp = .true. ; zwhs = .true. ; zwhc = .true.
    644     zwcs = clouds ; zwcn = clouds 
     695    zwcs = clouds ; zwcn = clouds
    645696    znofia = .false. ; zfiamin = 0.1_mm_wp ; zfiamax = 10._mm_wp
    646697    zwstom0 = .true. ; zwstom3 = .false.
     
    652703
    653704    ! Store options values in global variables...
    654     mm_df          = df 
    655     mm_rm          = rm 
     705    mm_df          = df
     706    mm_rm          = rm
    656707    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
    658709    mm_p_prod      = p_prod
    659710    mm_tx_prod     = tx_prod
     
    662713    mm_g0          = g0
    663714    mm_dt          = dt
    664     mm_air_rad     = mm_air_rad
     715    mm_air_rad     = air_rad
    665716    mm_air_mmol    = air_mmol
    666717    mm_coag_choice = coag_interactions
     
    670721      RETURN
    671722    ENDIF
     723
     724    ! force fractal radius minimum threshold to monomer radius ^^
     725    mm_rcf_min = mm_rm
    672726
    673727    mm_w_clouds = clouds
     
    680734        RETURN
    681735      ENDIF
    682       ! Reads species properties configuration file 
     736      ! Reads species properties configuration file
    683737      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)
    685739      IF (err /= 0) THEN
    686740        err = error("mm_global_init: cannot retrieve 'used_species' values",-1)
     
    691745      ALLOCATE(mm_spcname(mm_nesp),mm_xESPS(mm_nesp))
    692746      DO i=1,mm_nesp
    693         mm_spcname(i) = to_lower(species(i))
     747        mm_spcname(i) = TRIM(species(i))
    694748        IF(.NOT.cfg_has_section(cp,TRIM(mm_spcname(i)))) THEN
    695749          err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1)
     
    708762
    709763    ! 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
    710771    ! haze control flags
    711     IF (PRESENT(w_haze_prod)) THEN 
     772    IF (PRESENT(w_haze_prod)) THEN
    712773      mm_w_haze_prod = w_haze_prod
    713     ELSE 
    714       mm_w_haze_prod = zwhp 
     774    ELSE
     775      mm_w_haze_prod = zwhp
    715776      call printw("mm_haze_production",to_string(mm_w_haze_prod))
    716777    ENDIF
    717     IF (PRESENT(w_haze_sed)) THEN 
     778    IF (PRESENT(w_haze_sed)) THEN
    718779      mm_w_haze_sed = w_haze_sed
    719     ELSE 
    720       mm_w_haze_sed = zwhs 
     780    ELSE
     781      mm_w_haze_sed = zwhs
    721782      call printw("mm_haze_sedimentation",to_string(mm_w_haze_sed))
    722783    ENDIF
    723     IF (PRESENT(w_haze_coag)) THEN 
     784    IF (PRESENT(w_haze_coag)) THEN
    724785      mm_w_haze_coag = w_haze_coag
    725     ELSE 
     786    ELSE
    726787      mm_w_haze_coag = zwhc
    727788      call printw("mm_haze_coagulation",to_string(mm_w_haze_coag))
    728789    ENDIF
    729     IF (PRESENT(force_wsed_to_m0)) THEN 
     790    IF (PRESENT(force_wsed_to_m0)) THEN
    730791      mm_wsed_m0 = force_wsed_to_m0
    731     ELSE 
     792    ELSE
    732793      mm_wsed_m0 = zwstom0
    733794      call printw("mm_wsed_m0",to_string(mm_wsed_m0))
    734795    ENDIF
    735     IF (PRESENT(force_wsed_to_m3)) THEN 
     796    IF (PRESENT(force_wsed_to_m3)) THEN
    736797      mm_wsed_m3 = force_wsed_to_m3
    737     ELSE 
     798    ELSE
    738799      mm_wsed_m3 = zwstom3
    739800      call printw("mm_wsed_m3",to_string(mm_wsed_m3))
    740801    ENDIF
    741     IF (PRESENT(no_fiadero)) THEN 
     802    IF (PRESENT(no_fiadero)) THEN
    742803      mm_no_fiadero_w = no_fiadero
    743     ELSE 
    744       mm_no_fiadero_w = znofia 
     804    ELSE
     805      mm_no_fiadero_w = znofia
    745806      call printw("mm_no_fiadero",to_string(mm_no_fiadero_w))
    746807    ENDIF
    747     IF (PRESENT(fiadero_min)) THEN 
     808    IF (PRESENT(fiadero_min)) THEN
    748809      mm_fiadero_min = fiadero_min
    749     ELSE 
     810    ELSE
    750811      mm_fiadero_min = zfiamin
    751812      call printw("mm_fiadero_min",to_string(mm_fiadero_min))
    752813    ENDIF
    753     IF (PRESENT(fiadero_max)) THEN 
     814    IF (PRESENT(fiadero_max)) THEN
    754815      mm_fiadero_max = fiadero_max
    755     ELSE 
     816    ELSE
    756817      mm_fiadero_max = zfiamax
    757818      call printw("mm_fiadero_max",to_string(mm_fiadero_max))
    758819    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
    759854    ! clouds control flags
    760855    IF (mm_w_clouds) THEN
    761       IF (PRESENT(w_cloud_sed)) THEN 
     856      IF (PRESENT(w_cloud_sed)) THEN
    762857        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))
    766861      ENDIF
    767       IF (PRESENT(w_cloud_nucond)) THEN 
     862      IF (PRESENT(w_cloud_nucond)) THEN
    768863        mm_w_cloud_nucond = w_cloud_nucond
    769       ELSE 
     864      ELSE
    770865        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))
    772867      ENDIF
    773868    ENDIF
     
    781876    mm_ini = err == noerror
    782877
    783     CONTAINS
     878  CONTAINS
    784879
    785880    SUBROUTINE printw(string,value)
     
    788883      CHARACTER(len=*), INTENT(in) :: value  !! (string) Value of the option.
    789884      IF (mm_log) &
    790       WRITE(*,'(a,a,a)') "warning: Parameter "//string//"not given... Using default value: "//value
    791     END SUBROUTINE printw 
     885        WRITE(*,'(a,a,a)') "warning: Parameter "//string//"not given... Using default value: "//value
     886    END SUBROUTINE printw
    792887  END FUNCTION mm_global_init_0
    793888
     
    796891    !!
    797892    !! 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.
    800897    INTEGER                                           :: i
    801898    TYPE(cfgparser)                                   :: spccfg
    802899    CHARACTER(len=st_slen)                            :: spcpath
    803     CHARACTER(len=:), ALLOCATABLE                     :: defmsg
    804900    CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species
    805901    REAL(kind=mm_wp)                                  :: zfiamin,zfiamax
    806902    LOGICAL                                           :: zwhp,zwhs,zwhc,zwcs,zwcn,znofia, &
    807                                                          zwstom0,zwstom3
     903      zwstom0,zwstom3
    808904
    809905    err = noerror
     
    856952      ! Gets species property file path
    857953      err = cfg_get_value(cfg,'specie_cfg',spcpath) ; IF (err /= 0) RETURN
    858       ! Reads species properties configuration file 
     954      ! Reads species properties configuration file
    859955      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)
    861957      IF (err /= 0) THEN
    862958        err = error("mm_global_init: cannot retrieve 'used_species' values",-1)
     
    868964      !mm_spcname(1:mm_nesp) = species(:)
    869965      DO i=1,mm_nesp
    870         mm_spcname(i) = to_lower(species(i))
     966        mm_spcname(i) = TRIM(species(i))
    871967        IF (.NOT.cfg_has_section(spccfg,TRIM(mm_spcname(i)))) THEN
    872968          err = error("mm_global_init: Cannot find "//TRIM(mm_spcname(i))//" properties",-1)
     
    890986
    891987    ! MP2M Optional parameters
     988    err = mm_check_opt(cfg_get_value(cfg,"debug",mm_debug),mm_debug,.false.,wlog=mm_log)
    892989    err = mm_check_opt(cfg_get_value(cfg,"haze_production",mm_w_haze_prod),mm_w_haze_prod,zwhp,wlog=mm_log)
    893990    err = mm_check_opt(cfg_get_value(cfg,"haze_sedimentation",mm_w_haze_sed),mm_w_haze_sed,zwhs,wlog=mm_log)
     
    901998    err = mm_check_opt(cfg_get_value(cfg,"fiadero_max_ratio",mm_fiadero_max),mm_fiadero_max,zfiamax,wlog=mm_log)
    902999
     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
    9031015    err = noerror
    9041016    ! special check for settling velocity
     
    9111023  FUNCTION mm_column_init(plev,zlev,play,zlay,temp) RESULT(err)
    9121024    !! Initialize vertical atmospheric fields.
    913     !! 
     1025    !!
    9141026    !! This subroutine initializes vertical fields needed by the microphysics:
    9151027    !!
    916     !! 1. Save reversed input field into "local" array 
     1028    !! 1. Save reversed input field into "local" array
    9171029    !! 2. Compute thicknesses layers and levels
    9181030    !! 3. Interpolate temperature at levels
     
    9221034    !! @attention
    9231035    !! 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.
    9251037    REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: plev !! Pressure levels (Pa).
    9261038    REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: zlev !! Altitude levels (m).
     
    9301042    TYPE(error) :: err                                 !! Error status of the function.
    9311043    INTEGER :: i
    932     mm_ini_col = .false.                         
     1044    mm_ini_col = .false.
    9331045    err = noerror
    9341046    IF (.NOT.mm_ini) THEN
     
    9801092    ! Hydrostatic equilibrium
    9811093    mm_rhoair(1:mm_nla) = (mm_plev(2:mm_nle)-mm_plev(1:mm_nla)) / &
    982                           (mm_effg(mm_zlay)*mm_dzlev)
    983     mm_ini_col = .true.                         
     1094      (mm_effg(mm_zlay)*mm_dzlev)
     1095    mm_ini_col = .true.
    9841096    ! write out profiles (only if BOTH debug and log are enabled).
    9851097    IF (mm_log.AND.mm_debug) THEN
     
    10031115  FUNCTION mm_aerosols_init(m0aer_s,m3aer_s,m0aer_f,m3aer_f) RESULT(err)
    10041116    !! 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.
    10091121    !! @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.
    10111123    !!
    10121124    !! @attention
    10131125    !! [[mm_globals(module):mm_global_init(interface)]] and [[mm_globals(module):mm_column_init(function)]]
    10141126    !! 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
    10161128    !! vertical atmospheric structure.
    10171129    REAL(kind=mm_wp), DIMENSION(:), INTENT(in) :: m0aer_s !! \(0^{th}\) order moment of the spherical mode (\(m^{-2}\)).
     
    10631175    mm_m0aer_f = m0aer_f(mm_nla:1:-1)/mm_dzlev(:)
    10641176    mm_m3aer_f = m3aer_f(mm_nla:1:-1)/mm_dzlev(:)
     1177
     1178    ! Setup threshold:
     1179    call mm_set_moments_thresholds()
     1180
    10651181    ! aerosols characteristic radii
    1066     ! il faudrait peut etre revoir la gestion des zeros ici et la
    1067     ! remplacer par une valeur seuil des moments.
    1068     !
    1069     !-> JVO 19 : Done. Zero threshold set at espilon from dynamics on the
    1070     ! input moments in calmufi (safer than here). Might still be some unphysical
    1071     ! values after the dynamics near the threshold. Could be a could idea to add
    1072     ! a sanity check filtering too high values of radii.
    1073     !
    1074     ! TBD : Add a sanity check for high radii ????
    10751182    WHERE(mm_m3aer_s > 0._mm_wp .AND. mm_m0aer_s > 0._mm_wp)
    10761183      mm_rcs = mm_get_rcs(mm_m0aer_s,mm_m3aer_s)
     
    10881195  FUNCTION mm_clouds_init(m0ccn,m3ccn,m3ice,gazs) RESULT(err)
    10891196    !! 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
    10931200    !! and density and allocates diagnostic vectors.
    10941201    !! @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.
    10961203    !!
    10971204    !! @attention
    10981205    !! [[mm_globals(module):mm_global_init(interface)]] and [[mm_globals(module):mm_column_init(function)]]
    10991206    !! 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
    11011208    !! vertical atmospheric structure.
    11021209    REAL(kind=mm_wp), DIMENSION(:), INTENT(in)   :: m0ccn !! 0th order moment of the CCN distribution (\(m^{-2}\)).
     
    11211228    !  Actually, mm_nla should always initialized the first time mm_column_init is called, NOT HERE.
    11221229    IF (mm_nla < 0)  mm_nla  = SIZE(gazs,DIM=1)
    1123     ! Note: 
     1230    ! Note:
    11241231    !   here we could check that mm_nesp is the same size of gazs(DIM=2)
    11251232    !   Actually, mm_nesp should be always initialized in mm_global_init, NOT HERE.
     
    11341241    IF (.NOT.ALLOCATED(mm_drho))    ALLOCATE(mm_drho(mm_nla))
    11351242    ! 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
    11361246    IF (.NOT.ALLOCATED(mm_ccn_flux)) THEN
    11371247      ALLOCATE(mm_ccn_flux(mm_nla)) ; mm_ccn_flux(:) = 0._mm_wp
     
    11541264      mm_gazs(:,i)  = gazs(mm_nla:1:-1,i)
    11551265    ENDDO
     1266
     1267    ! Setup threshold :
     1268    call mm_set_moments_cld_thresholds()
     1269
    11561270    ! drop mean radius
    11571271    call mm_cloud_properties(mm_m0ccn,mm_m3ccn,mm_m3ice,mm_drad,mm_drho)
     
    11621276    !! Dump model global parameters on stdout.
    11631277    WRITE(*,'(a)')         "========= YAMMS PARAMETERS ============"
     1278    WRITE(*,'(a,a)')       "mm_fp_precision        : ", mm_wp_s
     1279    WRITE(*,'(a,L2)')      "mm_debug               : ", mm_debug
    11641280    WRITE(*,'(a,L2)')      "mm_w_haze_prod         : ", mm_w_haze_prod
    11651281    WRITE(*,'(a,ES14.7)')  "   mm_p_prod           : ", mm_p_prod
     
    11681284    WRITE(*,'(a,L2)')      "mm_w_haze_coag         : ", mm_w_haze_coag
    11691285    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
    11711287    WRITE(*,'(a,L2)')      "   mm_wsed_m0          : ", mm_wsed_m0
    11721288    WRITE(*,'(a,L2)')      "   mm_wsed_m3          : ", mm_wsed_m3
     
    11781294    WRITE(*,'(a,L2)')      "   mm_w_cloud_nucond   : ", mm_w_cloud_nucond
    11791295    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)')         "---------------------------------------"
    11801307    WRITE(*,'(a,ES14.7)')  "mm_dt                  : ", mm_dt
    11811308    IF (mm_nla > -1) THEN
     
    11911318  END SUBROUTINE mm_dump_parameters
    11921319
     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
    11931377  ELEMENTAL FUNCTION mm_get_rcs(m0,m3) RESULT(res)
    11941378    !! Get the characteristic radius for the spherical aerosols size distribution.
    1195     !! 
     1379    !!
    11961380    !! The method computes the characteristic radius of the size distribution law
    11971381    !! of the spherical aerosols mode according to its moments and its inter-moments
    11981382    !! 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
    12001384    REAL(kind=mm_wp), INTENT(in) :: m3 !! \(3^{rd}\) order moment
    12011385    REAL(kind=mm_wp) :: res            !! Radius
    1202     ! arbitrary: if there is no way to compute radius
    1203     IF (m3 <= 0._mm_wp .OR. m0 <= 0._mm_wp) res = 1._mm_wp
    12041386    res = (m3/m0/mm_alpha_s(3._mm_wp))**(1._mm_wp/3._mm_wp)
    12051387  END FUNCTION mm_get_rcs
     
    12071389  ELEMENTAL FUNCTION mm_get_rcf(m0,m3) RESULT(res)
    12081390    !! Get the characteristic radius for the fractal aerosols size distribution.
    1209     !! 
     1391    !!
    12101392    !! The method computes the characteristic radius of the size distribution law
    12111393    !! of the fractal aerosols mode according to its moments and its inter-moments
    12121394    !! 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
    12141396    REAL(kind=mm_wp), INTENT(in) :: m3 !! \(3^{rd}\) order moment
    12151397    REAL(kind=mm_wp) :: res            !! Radius
    1216     ! arbitrary: if there is no way to compute radius
    1217     IF (m3 <= 0._mm_wp .OR. m0 <= 0._mm_wp) res = 1._mm_wp
    12181398    res = (m3/m0/mm_alpha_f(3._mm_wp))**(1._mm_wp/3._mm_wp)
    12191399  END FUNCTION mm_get_rcf
    12201400
    1221   ELEMENTAL FUNCTION mm_effg(z) RESULT(effg) 
     1401  ELEMENTAL FUNCTION mm_effg(z) RESULT(effg)
    12221402    !! Compute effective gravitational acceleration.
    12231403    REAL(kind=mm_wp), INTENT(in) :: z !! Altitude in meters
     
    12261406    IF (mm_use_effg) effg = effg * (mm_rpla/(mm_rpla+z))**2
    12271407    RETURN
    1228   END FUNCTION mm_effg 
     1408  END FUNCTION mm_effg
    12291409
    12301410  !==================================
     
    12371417    !! The method computes the mean radius and mean density of cloud drops.
    12381418    !!
    1239     !! @bug 
    1240     !! A possible bug can happen because of threshold snippet. If __drad__ is greater than 
    1241     !! __drmax__ (== 100 microns) it is automatically set to __drmax__, but computation of
     1419    !! @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
    12421422    !! __drho__ remains unmodified. So __drho__ is not correct in that case.
    12431423    !!
    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
    12461426    !! need the density of the drop.
    12471427    !!
    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
    12531433    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
    12551435    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 :
    12621441    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
    12741458    RETURN
    12751459  END SUBROUTINE cldprop_sc
     
    12861470    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)           :: drad  !! Output mean drop radius.
    12871471    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
    13131478    RETURN
    13141479  END SUBROUTINE cldprop_ve
    13151480
    1316   ! For configuration file (requires fccp library).
     1481  ! For configuration file (requires swift library).
    13171482
    13181483  FUNCTION read_esp(parser,sec,pp) RESULT (err)
     
    13221487    TYPE(mm_esp), INTENT(out)     :: pp     !! [[mm_globals(module):mm_esp(type)]] object that stores the parameters.
    13231488    TYPE(error)                   :: err    !! Error status of the function.
    1324     err = cfg_get_value(parser,TRIM(sec)//'name',pp%name)       ; IF (err /= 0) RETURN
    1325     err = cfg_get_value(parser,TRIM(sec)//'mas',pp%mas)         ; IF (err /= 0) RETURN
    1326     err = cfg_get_value(parser,TRIM(sec)//'vol',pp%vol)         ; IF (err /= 0) RETURN
    1327     err = cfg_get_value(parser,TRIM(sec)//'ray',pp%ray)         ; IF (err /= 0) RETURN
    1328     err = cfg_get_value(parser,TRIM(sec)//'mas',pp%mas)         ; IF (err /= 0) RETURN
    1329     err = cfg_get_value(parser,TRIM(sec)//'vol',pp%vol)         ; IF (err /= 0) RETURN
    1330     err = cfg_get_value(parser,TRIM(sec)//'ray',pp%ray)         ; IF (err /= 0) RETURN
    1331     err = cfg_get_value(parser,TRIM(sec)//'masmol',pp%masmol)   ; IF (err /= 0) RETURN
    1332     err = cfg_get_value(parser,TRIM(sec)//'rho',pp%rho)         ; IF (err /= 0) RETURN
    1333     err = cfg_get_value(parser,TRIM(sec)//'tc',pp%tc)           ; IF (err /= 0) RETURN
    1334     err = cfg_get_value(parser,TRIM(sec)//'pc',pp%pc)           ; IF (err /= 0) RETURN
    1335     err = cfg_get_value(parser,TRIM(sec)//'tb',pp%tb)           ; IF (err /= 0) RETURN
    1336     err = cfg_get_value(parser,TRIM(sec)//'w',pp%w)             ; IF (err /= 0) RETURN
    1337     err = cfg_get_value(parser,TRIM(sec)//'a_sat',pp%a_sat)     ; IF (err /= 0) RETURN
    1338     err = cfg_get_value(parser,TRIM(sec)//'b_sat',pp%b_sat)     ; IF (err /= 0) RETURN
    1339     err = cfg_get_value(parser,TRIM(sec)//'c_sat',pp%c_sat)     ; IF (err /= 0) RETURN
    1340     err = cfg_get_value(parser,TRIM(sec)//'d_sat',pp%d_sat)     ; IF (err /= 0) RETURN
    1341     err = cfg_get_value(parser,TRIM(sec)//'mteta',pp%mteta)     ; IF (err /= 0) RETURN
    1342     err = cfg_get_value(parser,TRIM(sec)//'tx_prod',pp%tx_prod) ; IF (err /= 0) RETURN
     1489    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
    13431508    RETURN
    13441509  END FUNCTION read_esp
     
    13461511  ! =========================================================================
    13471512  ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1348   !                CONFIGURATION PARSER checking methods 
     1513  !                CONFIGURATION PARSER checking methods
    13491514  ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    13501515  ! =========================================================================
     
    13521517  FUNCTION check_r1(err,var,def,wlog) RESULT(ret)
    13531518    !! 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
    13561521    !! __var__ on error if given.
    13571522    TYPE(error), INTENT(in)                :: err  !! Error object from value getter.
     
    13601525    LOGICAL, INTENT(in), OPTIONAL          :: wlog !! .true. to print warning/error message.
    13611526    TYPE(error) :: ret                             !! Input error.
    1362     CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 
     1527    CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: '
    13631528    LOGICAL                     :: zlog
    13641529    ret = err
     
    13761541  FUNCTION check_l1(err,var,def,wlog) RESULT(ret)
    13771542    !! 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
    13801545    !! __var__ on error if given.
    13811546    TYPE(error), INTENT(in)       :: err  !! Error object from value getter.
     
    13841549    LOGICAL, INTENT(in), OPTIONAL :: wlog !! .true. to print warning/error message.
    13851550    TYPE(error) :: ret                    !! Input error.
    1386     CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 
     1551    CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: '
    13871552    LOGICAL                     :: zlog
    13881553    ret = err
    1389      zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog
     1554    zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog
    13901555    IF (err == 0) RETURN
    13911556    IF (PRESENT(def)) THEN
     
    14001565  FUNCTION check_i1(err,var,def,wlog) RESULT(ret)
    14011566    !! 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
    14041569    !! __var__ on error if given.
    14051570    TYPE(error), INTENT(in)       :: err  !! Error object from value getter.
     
    14111576    LOGICAL                     :: zlog
    14121577    ret = err
    1413      zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog
     1578    zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog
    14141579    IF (err == 0) RETURN
    14151580    IF (PRESENT(def)) THEN
     
    14241589  FUNCTION check_s1(err,var,def,wlog) RESULT(ret)
    14251590    !! 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
    14281593    !! __var__ on error if given.
    14291594    TYPE(error), INTENT(in)                      :: err  !! Error object from value getter.
     
    14321597    LOGICAL, INTENT(in), OPTIONAL                :: wlog !! .true. to print warning/error message.
    14331598    TYPE(error) :: ret                                   !! Input error.
    1434     CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: ' 
     1599    CHARACTER(len=*), PARAMETER :: defmsg = '... Using default value: '
    14351600    LOGICAL                     :: zlog
    1436     ret = err 
     1601    ret = err
    14371602    zlog = .false. ; IF (PRESENT(wlog)) zlog = wlog
    14381603    IF (err == 0) RETURN
  • trunk/LMDZ.TITAN/libf/muphytitan/mm_haze.f90

    r2109 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Haze microphysics module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838MODULE MM_HAZE
    3939  !! Haze microphysics module.
     
    4646  !!
    4747  !! @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
    5151  !! distribution are updated in the production zone by addition of the production rate along a
    5252  !! gaussian shape.
    5353  !!
    5454  !! @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
    5656  !! values (any kind, temperature, pressure, moments...) over the vertical grid are required.
    5757  !!
    5858  !! @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__
    6060  !! to __GROUND__.
    6161  !!
    62   !! @todo 
     62  !! @todo
    6363  !! Modify tests on tendencies vectors to get sure that allocation is done:
    6464  !! Currently, we assume the compiler handles automatic allocation of arrays.
     
    7272
    7373  PUBLIC :: mm_haze_microphysics, mm_haze_coagulation, mm_haze_sedimentation, &
    74             mm_haze_production
    75 
    76   CONTAINS
     74    mm_haze_production
     75
     76CONTAINS
    7777
    7878  !============================================================================
     
    8383    !! Get the evolution of moments tracers through haze microphysics processes.
    8484    !!
    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
    8787    !! atmospheric column.
    8888    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_s
    89       !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-3}\)).
     89    !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-3}\)).
    9090    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_s
    91       !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-3}\)).
     91    !! Tendency of the 3rd order moment of the spherical mode distribution (\(m^{3}.m^{-3}\)).
    9292    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_f
    93       !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)).
     93    !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-3}\)).
    9494    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_f
    95       !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)).
     95    !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-3}\)).
    9696    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm0as
    9797    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: zdm3as
     
    107107    zdm3af(1:mm_nla) = 0._mm_wp
    108108
    109     IF (mm_w_haze_coag) THEN 
     109    IF (mm_w_haze_coag) THEN
    110110      ! Calls coagulation
    111111      call mm_haze_coagulation(dm0a_s,dm3a_s,dm0a_f,dm3a_f)
     
    120120
    121121      ! Updates tendencies
    122       dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as 
     122      dm0a_s=dm0a_s+zdm0as ; dm3a_s=dm3a_s+zdm3as
    123123      dm0a_f=dm0a_f+zdm0af ; dm3a_f=dm3a_f+zdm3af
    124124    ENDIF
     
    127127      call mm_haze_production(zdm0as,zdm3as)
    128128      ! 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
    130130    ENDIF
    131131
     
    137137  ! COAGULATION PROCESS RELATED METHODS
    138138  !============================================================================
    139  
     139
    140140  SUBROUTINE mm_haze_coagulation(dM0s,dM3s,dM0f,dM3f)
    141141    !! Get the evolution of the aerosols moments vertical column due to coagulation process.
    142     !! 
     142    !!
    143143    !! This is main method of the coagulation process:
    144144    !!
     
    149149    !! 5. Finally computes the tendencies of the moments.
    150150    !!
    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
    152152    !! vertical __layers__.
    153153    !!
    154154    !! @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.
    157157    !!
    158158    !! @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),
    160160    !! a floating point exception occured (i.e. a NaN) as we perform a division by zero
    161161    !!
     
    163163    !! Get rid of the fu\*\*\*\* STOP statement...
    164164    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM0s
    165       !! Tendency of the 0th order moment of the spherical size-distribution over a time step (\(m^{-3}\)).
     165    !! Tendency of the 0th order moment of the spherical size-distribution over a time step (\(m^{-3}\)).
    166166    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM3s
    167       !! Tendency of the 3rd order moment of the spherical size-distribution (\(m^{3}.m^{-3}\)).
     167    !! Tendency of the 3rd order moment of the spherical size-distribution (\(m^{3}.m^{-3}\)).
    168168    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM0f
    169       !! Tendency of the 0th order moment of the fractal size-distribution over a time step (\(m^{-3}\)).
     169    !! Tendency of the 0th order moment of the fractal size-distribution over a time step (\(m^{-3}\)).
    170170    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dM3f
    171       !! Tendency of the 3rd order moment of the fractal size-distribution over a time step (\(m^{3}.m^{-3}\)).
     171    !! Tendency of the 3rd order moment of the fractal size-distribution over a time step (\(m^{3}.m^{-3}\)).
    172172    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: c_kco,c_kfm,c_slf,tmp, &
    173                                                    kco,kfm,pco,pfm,mq
     173      kco,kfm,pco,pfm,mq
    174174    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a_ss,a_sf,b_ss,b_ff,c_ss,c_sf
    175175    INTEGER                                     :: i
     
    180180    ! Alloctes local arrays
    181181    ALLOCATE(kco(mm_nla),kfm(mm_nla),c_slf(mm_nla), &
    182              c_kco(mm_nla),c_kfm(mm_nla),mq(mm_nla), &
    183              pco(mm_nla),pfm(mm_nla))
     182      c_kco(mm_nla),c_kfm(mm_nla),mq(mm_nla), &
     183      pco(mm_nla),pfm(mm_nla))
    184184    ALLOCATE(a_ss(mm_nla),a_sf(mm_nla), &
    185              b_ss(mm_nla),b_ff(mm_nla), &
    186              c_ss(mm_nla),c_sf(mm_nla))
    187              
     185      b_ss(mm_nla),b_ff(mm_nla), &
     186      c_ss(mm_nla),c_sf(mm_nla))
     187
    188188    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
    190190    c_ss(:) = 0._mm_wp ; c_sf(:) = 0._mm_wp
    191191
     
    193193    c_kco(:) = mm_get_kco(mm_temp) ; c_kfm(:) = mm_get_kfm(mm_temp)
    194194    ! 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)
    196196
    197197    DO i=1,mm_nla
     
    202202        pfm(i) = mm_ps2s(mm_rcs(i),0,1,mm_temp(i),mm_play(i))
    203203        ! (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))
    206206        IF (kco(i)*(pco(i)-2._mm_wp)+kfm(i)*(pfm(i)-2._mm_wp) /=0) THEN
    207207          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))
     
    267267      ENDIF
    268268    ENDDO
    269    
     269
    270270    DEALLOCATE(kco,kfm,c_kco,c_kfm,pco,pfm,c_slf)
    271271
     
    302302    !! Get &gamma; pre-factor for the 0th order moment with SS interactions in the continuous flow regime.
    303303    !!
    304     !! @note 
     304    !! @note
    305305    !! If __rcs__ is 0, the function returns 0.
    306306    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    320320    !! Get &gamma; pre-factor for the 0th order moment with SF interactions in the continuous flow regime.
    321321    !!
    322     !! @note 
     322    !! @note
    323323    !! If __rcs__ or __rcf__ is 0, the function returns 0.
    324324    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    329329    REAL(kind=mm_wp) :: a1, a2, a3, a4, a5, a6, e, rcff
    330330    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)
    334334    a4=mm_alpha_s(-1._mm_wp) ; a5=mm_alpha_s(-2._mm_wp) ; a6=mm_alpha_f(-2._mm_wp*e)
    335335    ! Computes gamma pre-factor
    336336    res = c_kco*( 2._mm_wp + a1*a2*rcs/rcff + a4*a3*rcff/rcs + c_slf*( a4/rcs + &
    337                          a2/rcff + a5*a3*rcff/rcs**2 + a1*a6*rcs/rcff**2))
     337      a2/rcff + a5*a3*rcff/rcs**2 + a1*a6*rcs/rcff**2))
    338338    RETURN
    339339  END FUNCTION g0sfco
     
    342342    !! Get &gamma; pre-factor for the 0th order moment with FF interactions in the continuous flow regime.
    343343    !!
    344     !! @note 
     344    !! @note
    345345    !! If __rcf__ is 0, the function returns 0.
    346346    REAL(kind=mm_wp), INTENT(in) :: rcf   !! Characteristic radius of the fractal size-distribution.
     
    361361    !! Get &gamma; pre-factor for the 3rd order moment with SS interactions in the continuous flow regime.
    362362    !!
    363     !! @note 
     363    !! @note
    364364    !! If __rcs__ is 0, the function returns 0.
    365365    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    370370    res = 0._mm_wp ; IF (rcs <= 0._mm_wp) RETURN
    371371    ! 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)
    373373    a4=mm_alpha_s(4._mm_wp) ; a5=mm_alpha_s(-1._mm_wp) ; a6=mm_alpha_s(-2._mm_wp)
    374374
    375375    ! 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           c_kco/(a1**2*rcs**3)
     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)
    378378    RETURN
    379379  END FUNCTION g3ssco
     
    382382    !! Get &gamma; pre-factor for the 3rd order moment with SF interactions in the continuous flow regime.
    383383    !!
    384     !! @note 
     384    !! @note
    385385    !! If __rcs__ or __rcf__ is 0, the function returns 0.
    386386    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    392392    res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN
    393393    ! 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)
    396396    a4=mm_alpha_s(2._mm_wp)    ; a5=mm_alpha_f(e)    ; a6=mm_alpha_s(1._mm_wp)
    397397    a7=mm_alpha_f(-2._mm_wp*e) ; a8=mm_alpha_f(3._mm_wp)
    398398    ! Computes gamma pre-factor
    399399    res = (2._mm_wp*a1*rcs**3 + a2*rcs**4*a3/rcff + a4*rcs**2*a5*rcff + &
    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)
     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)
    402402    RETURN
    403403  END FUNCTION g3sfco
     
    406406    !! Get &gamma; pre-factor for the 0th order moment with SS interactions in the Free Molecular flow regime.
    407407    !!
    408     !! @note 
     408    !! @note
    409409    !! If __rcs__ is 0, the function returns 0.
    410410    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    422422
    423423  ELEMENTAL FUNCTION g0sffm(rcs, rcf, c_kfm) RESULT(res)
    424     !> Get &gamma; pre-factor for the 0th order moment with SF interactions in the Free Molecular flow regime. 
    425     !!
    426     !! @note 
     424    !> Get &gamma; pre-factor for the 0th order moment with SF interactions in the Free Molecular flow regime.
     425    !!
     426    !! @note
    427427    !! If __rcs__ or __rcf__ is 0, the function returns 0.
    428428    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    435435    res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN
    436436    ! 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
    439439    e3 = (6._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df)
    440440    e4 = (12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df)
    441441
    442     rcff1 = mm_rb2ra * rcf**e1 
     442    rcff1 = mm_rb2ra * rcf**e1
    443443    rcff2 = rcff1**2
    444     rcff3 = mm_rb2ra * rcf**e3 
     444    rcff3 = mm_rb2ra * rcf**e3
    445445    rcff4 = mm_rb2ra**2 * rcf**e4
    446446
    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)
    448448    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)
    450450    a10=mm_alpha_f(e4)
    451451
    452452    ! Computes gamma pre-factor
    453453    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            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
     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
    456456    RETURN
    457457  END FUNCTION g0sffm
    458458
    459459  ELEMENTAL FUNCTION g0fffm(rcf, c_kfm) RESULT(res)
    460     !! Get &gamma; pre-factor for the 0th order moment with FF interactions in the Free Molecular flow regime. 
    461     !!
    462     !! @note 
     460    !! Get &gamma; pre-factor for the 0th order moment with FF interactions in the Free Molecular flow regime.
     461    !!
     462    !! @note
    463463    !! If __rcf__ is 0, the function returns 0.
    464464    REAL(kind=mm_wp), INTENT(in) :: rcf   !! Characteristic radius of the fractal size-distribution.
    465465    REAL(kind=mm_wp), INTENT(in) :: c_kfm !! Thermodynamic free molecular flow regime pre-factor.
    466     REAL(kind=mm_wp) :: res               !! &gamma; coagulation kernel pre-factor. 
     466    REAL(kind=mm_wp) :: res               !! &gamma; coagulation kernel pre-factor.
    467467    REAL(kind=mm_wp) :: a1, a2, a3, a4, a5, e1, e2, e3, rcff
    468468    res = 0._mm_wp ; IF (rcf <= 0._mm_wp) RETURN
    469469    ! 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)
    471471    e3=(12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df)
    472472    rcff=mm_rb2ra**2*rcf**e3
     
    489489    res = 0._mm_wp ; IF (rcs <= 0._mm_wp) RETURN
    490490    ! 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)
    492492    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)
    494494    a10=mm_alpha_s(3._mm_wp) ; a11=mm_alpha_s(0.5_mm_wp)
    495495    ! Computes gamma pre-factor
    496496    res = (a1 + 2._mm_wp*a2*a3 + a4*a5 + a6*a7 + 2._mm_wp*a8*a9 + a10*a11) &
    497           *mm_get_btk(1,3)*c_kfm/(a10**2*rcs**2.5_mm_wp)
     497      *mm_get_btk(1,3)*c_kfm/(a10**2*rcs**2.5_mm_wp)
    498498    RETURN
    499499  END FUNCTION g3ssfm
     
    502502    !! Get &gamma; pre-factor for the 3rd order moment with SF interactions in the Free Molecular flow regime.
    503503    !!
    504     !! @note 
     504    !! @note
    505505    !! If __rcs__ or __rcf__ is 0, the function returns 0.
    506506    REAL(kind=mm_wp), INTENT(in) :: rcs   !! Characteristic radius of the spherical size-distribution.
     
    512512    res = 0._mm_wp ; IF (rcs <= 0._mm_wp .OR. rcf <= 0._mm_wp) RETURN
    513513    ! 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)
    516516    e3=(12._mm_wp-3._mm_wp*mm_df)/(2._mm_wp*mm_df)
    517517    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)
    521521    a10=mm_alpha_s(3._mm_wp)  ; a11=mm_alpha_f(e3)         ; a12=mm_alpha_f(3._mm_wp)
    522522    ! Computes gamma pre-factor
    523523    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           a10*a11*rcs**3*rcff3)*mm_get_btk(4,3)*c_kfm/(a10*a12*(rcs*rcf)**3)
     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)
    526526    RETURN
    527527  END FUNCTION g3sffm
     
    530530  ! SEDIMENTATION PROCESS RELATED METHODS
    531531  !============================================================================
    532  
     532
    533533  SUBROUTINE mm_haze_sedimentation(dm0s,dm3s,dm0f,dm3f)
    534534    !! Interface to sedimentation algorithm.
    535535    !!
    536536    !! 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.
    538538    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0s
    539       !! Tendency of the 0th order moment of the spherical mode (\(m^{-3}\)).
     539    !! Tendency of the 0th order moment of the spherical mode (\(m^{-3}\)).
    540540    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3s
    541       !! Tendency of the 3rd order moment of the spherical mode (\(m^{3}.m^{-3}\)).
     541    !! Tendency of the 3rd order moment of the spherical mode (\(m^{3}.m^{-3}\)).
    542542    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0f
    543       !! Tendency of the 0th order moment of the fractal mode (\(m^{-3}\)).
     543    !! Tendency of the 0th order moment of the fractal mode (\(m^{-3}\)).
    544544    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3f
    545       !! Tendency of the 3rd order moment of the fractal mode (\(m^{3}.m^{-3}\)).
     545    !! Tendency of the 3rd order moment of the fractal mode (\(m^{3}.m^{-3}\)).
    546546    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
    549548
    550549    ALLOCATE(ft(mm_nle),wth(mm_nle),fdcor(mm_nle))
     
    624623    !! Compute the tendency of the moment through sedimentation process.
    625624    !!
    626     !! 
     625    !!
    627626    !! The method computes the time evolution of the \(k^{th}\) order moment through sedimentation:
    628627    !!
     
    630629    !!
    631630    !! 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
    634633    !! from ancient times. It is based on \cite{toon1988b,fiadeiro1977,turco1979} and is an update of the algorithm
    635634    !! originally implemented in the LMDZ-Titan 2D GCM.
     
    638637    REAL(kind=mm_wp), INTENT(in), DIMENSION(:)  :: ft  !! Downward sedimentation flux  (effective velocity of the moment).
    639638    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
    641640    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: as,bs,cs,mko
    642641    ALLOCATE(as(mm_nla), bs(mm_nla), cs(mm_nla), mko(mm_nla))
     
    648647      bs(1:mm_nla) = -(ft(2:mm_nle)+mm_dzlay(1:mm_nla)/dt)
    649648      cs(1:mm_nla) = -mm_dzlay(1:mm_nla)/dt*mk(1:mm_nla)
    650       ! (Tri)diagonal matrix inversion 
     649      ! (Tri)diagonal matrix inversion
    651650      mko(1) = cs(1)/bs(1)
    652651      DO i=2,mm_nla ; mko(i) = (cs(i)-mko(i-1)*as(i))/bs(i) ; ENDDO
     
    660659      ! interior
    661660      mko(2:mm_nla-1)=(bs(2:mm_nla-1)*mk(1:mm_nla-2) + &
    662                        cs(2:mm_nla-1)*mk(2:mm_nla-1)   &
    663                       )/as(2:mm_nla-1)
     661        cs(2:mm_nla-1)*mk(2:mm_nla-1)   &
     662        )/as(2:mm_nla-1)
    664663    ENDIF
    665664    dmk = mko - mk
     
    670669  SUBROUTINE get_weff(mk,k,df,rc,dt,afun,wth,corf)
    671670    !! 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
    675674    !! equation:
    676     !! 
    677     !! $$ 
     675    !!
     676    !! $$
    678677    !! \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
    680679    !!                     == M_{k}  \times v^{eff}_{M_{k}} \\
    681680    !!     v^{eff}_{M_{k} &=& \dfrac{2 \rho g r_{c}^{\dfrac{3D_{f}-3}{D_{f}}}}
     
    686685    !! $$
    687686    !!
    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
    689688    !! as defined in \cite{toon1988b}.
    690689    !!
    691690    !! @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
    693692    !! be computed.
    694693    REAL(kind=mm_wp), INTENT(in), DIMENSION(mm_nla)            :: mk
    695       !! Moment of order __k__ (\(m^{k}.m^{-3}\)) at each layer.
     694    !! Moment of order __k__ (\(m^{k}.m^{-3}\)) at each layer.
    696695    REAL(kind=mm_wp), INTENT(in), DIMENSION(mm_nla)            :: rc
    697       !! Characteristic radius associated to the moment at each layer.
     696    !! Characteristic radius associated to the moment at each layer.
    698697    REAL(kind=mm_wp), INTENT(in)                               :: k
    699       !! The order of the moment.
     698    !! The order of the moment.
    700699    REAL(kind=mm_wp), INTENT(in)                               :: df
    701       !! Fractal dimension of the aersols.
     700    !! Fractal dimension of the aersols.
    702701    REAL(kind=mm_wp), INTENT(in)                               :: dt
    703       !! Time step (s).
     702    !! Time step (s).
    704703    REAL(kind=mm_wp), INTENT(out), DIMENSION(mm_nle)           :: wth
    705       !! Theoretical Settling velocity at each vertical __levels__ (\( wth \times corf = weff\)).
    706     REAL(kind=mm_wp), INTENT(out), DIMENSION(mm_nle), OPTIONAL :: corf 
    707       !! _Fiadero_ correction factor applied to the theoretical settling velocity at each vertical __levels__.
     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__.
    708707    INTERFACE
    709708      FUNCTION afun(order)
     
    713712        REAL(kind=mm_wp) :: afun              !! Alpha value.
    714713      END FUNCTION afun
    715     END INTERFACE 
     714    END INTERFACE
    716715    INTEGER                             :: i
    717716    REAL(kind=mm_wp)                    :: af1,af2,ar1,ar2
     
    720719    REAL(kind=mm_wp), DIMENSION(mm_nle) :: zcorf
    721720    ! ------------------
    722    
     721
    723722    wth(:) = 0._mm_wp ; zcorf(:) = 1._mm_wp
    724723
    725724    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
    727726    rb2ra = mm_rm**((df-3._mm_wp)/df)
    728727    DO i=2,mm_nla
    729       IF (rc(i-1) <= 0._mm_wp) CYCLE 
     728      IF (rc(i-1) <= 0._mm_wp) CYCLE
    730729      dzb = (mm_dzlay(i)+mm_dzlay(i-1))/2._mm_wp
    731730      csto = 2._mm_wp*mm_rhoaer*mm_effg(mm_zlev(i))/(9._mm_wp*mm_eta_g(mm_btemp(i)))
    732731      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     
    734738      ! now correct velocity to reduce numerical diffusion
    735739      IF (.NOT.mm_no_fiadero_w) THEN
    736740        IF (mk(i) <= 0._mm_wp) THEN
    737           ratio = mm_fiadero_max 
     741          ratio = mm_fiadero_max
    738742        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)
    740744        ENDIF
    741745        ! apply correction
     
    760764  SUBROUTINE mm_haze_production(dm0s,dm3s)
    761765    !! 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
    765769    !! [[mm_globals(module):mm_p_prod(variable)]] pressure level with a fixed sigma of 20km.
    766770    !!
    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
    768772    !! characteristic radius set to [[mm_globals(module):mm_rc_prod(variable)]].
    769773    !!
     
    773777    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3s !! Tendency of M3 (\(m^{3}.m^{-3}\)).
    774778    INTEGER                     :: i
    775     REAL(kind=mm_wp)            :: zprod,cprod,timefact 
     779    REAL(kind=mm_wp)            :: zprod,cprod,timefact
    776780    REAL(kind=mm_wp), PARAMETER :: sigz  = 20e3_mm_wp, &
    777781                                   fnorm = 1._mm_wp/(dsqrt(2._mm_wp*mm_pi)*sigz), &
     
    793797    dm3s(:)= mm_tx_prod *0.75_mm_wp/mm_pi *mm_dt / mm_rhoaer / 2._mm_wp / mm_dzlev(1:mm_nla) * &
    794798             (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))
    796800    dm0s(:) = dm3s(:)/(mm_rc_prod**3*mm_alpha_s(3._mm_wp))
    797801
     
    803807    ENDIF
    804808
    805 
    806809  END SUBROUTINE mm_haze_production
    807810
  • trunk/LMDZ.TITAN/libf/muphytitan/mm_interfaces.f90

    r1897 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Interfaces module for external functions
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838
    3939MODULE MM_INTERFACES
    4040  !! Interfaces to external functions.
    41   !!
    42   !! The module contains the definitions of all "external" functions used by moments model which are
    43   !! left to the developer's responsibility.
    4441  !!
    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.
    4644  !!
    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
    4848  !!   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
    5050  !!   [[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
    5252  !!   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
    5454  !!   applied on each coagulation sub-kernels computed in mm_haze module.
    5555  !! - [[mm_interfaces(module):mm_get_btk(interface)]] should compute the \(b_{k}^{T}\) coefficient of the
     
    6060  PUBLIC
    6161
    62   INTERFACE 
     62  INTERFACE
    6363
    6464    PURE FUNCTION mm_alpha_s(k) RESULT (res)
     
    7070      REAL(kind=mm_wp), INTENT(in) :: k !! Order of the moment.
    7171      REAL(kind=mm_wp) :: res           !! Alpha value.
    72     END FUNCTION mm_alpha_s 
     72    END FUNCTION mm_alpha_s
    7373
    7474    PURE FUNCTION mm_alpha_f(k) RESULT (res)
     
    9999      !! kernel as a function of the temperature, pressure and the characteristic radius of
    100100      !! the mode involved in the coagulation.
    101       !! 
     101      !!
    102102      !! Modes are referred by a two letters uppercase string with the combination of:
    103103      !!
    104104      !! - S : spherical mode
    105105      !! - F : fractal mode
    106       !! 
     106      !!
    107107      !! For example, SS means intra-modal coagulation for spherical particles.
    108108      IMPORT mm_wp
     
    118118    PURE FUNCTION mm_get_btk(t,k) RESULT(res)
    119119      !! Get the \(b_{k}^{T}\) coefficient of the Free Molecular regime.
    120       !! 
     120      !!
    121121      !! The method computes and returns the value of the pre-factor \(b_{k}^{T}\) used to
    122122      !! 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
    125125      !! [scientific documentation](page/haze.html#free-molecular).
    126126      !!
  • trunk/LMDZ.TITAN/libf/muphytitan/mm_lib.f90

    r1897 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: MP2M library interface module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838
    3939MODULE MM_LIB
    4040  !! MP2M library interface module.
    4141  !!
    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
    4343  !! definitions and just __uses__ all others modules of the library.
    4444  USE MM_MPREC
  • trunk/LMDZ.TITAN/libf/muphytitan/mm_methods.f90

    r1897 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
    2 ! 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)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Model miscellaneous methods module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
     38!! corrections: B. de Batz de Trenquelléon (2023)
    3839
    3940MODULE MM_METHODS
     
    4344  !!
    4445  !! 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
    4647  !! 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).
    4748  !!
    4849  !! The module defines the following functions/subroutines/interfaces:
    4950  !!
    50   !! | name        | description 
     51  !! | name        | description
    5152  !! | :---------: | :-------------------------------------------------------------------------------------
    5253  !! | mm_lheatx   | Compute latent heat released
     
    6465  IMPLICIT NONE
    6566
    66   PRIVATE 
    67 
    68   PUBLIC  :: mm_sigX, mm_LheatX, mm_psatX, mm_qsatx, mm_fshape, &
    69              mm_get_kco, mm_get_kfm, mm_eta_g, mm_lambda_g
     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
    7071
    7172  ! ---- INTERFACES
     
    7879  !! FUNCTION mm_sigX(temp,xESP)
    7980  !! ```
    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
    8283  !! computes the result for all the temperatures and returns a vector of same size than __temp__.
    8384  INTERFACE mm_sigX
    8485    MODULE PROCEDURE sigx_sc,sigx_ve
    85   END INTERFACE
     86  END INTERFACE mm_sigX
    8687
    8788  !> Interface to Latent heat computation functions.
    88   !! 
     89  !!
    8990  !! The method computes the latent heat released of a given specie at given temperature(s).
    9091  !!
     
    9394  !! ```
    9495  !!
    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
    9697  !! computes the result for all the temperatures and returns a vector of same size than __temp__.
    9798  INTERFACE mm_LheatX
    9899    MODULE PROCEDURE lheatx_sc,lheatx_ve
    99   END INTERFACE
     100  END INTERFACE mm_LheatX
    100101
    101102  !> Interface to saturation vapor pressure computation functions.
     
    104105  !! FUNCTION mm_psatX(temp,xESP)
    105106  !! ```
    106   !! 
     107  !!
    107108  !! The method computes the saturation vapor pressure of a given specie at given temperature(s).
    108109  !!
    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
    110111  !! computes the result for all the temperatures and returns a vector of same size than __temp__.
    111112  INTERFACE mm_psatX
    112113    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)
    118119  !! and pressure level(s).
    119120  !!
    120121  !! ```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
    125126  !! size !), then the method computes the result for each couple of (temperature, pressure) and returns
    126127  !! a vector of same size than __temp__.
    127128  INTERFACE mm_qsatx
    128129    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
    130147
    131148  !> Interface to shape factor computation functions.
     
    137154  !! ```
    138155  !!
    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
    141158  !! value of __x__ and and returns a vector of same size than __x__.
    142159  INTERFACE mm_fshape
    143160    MODULE PROCEDURE fshape_sc,fshape_ve
    144   END INTERFACE
    145 
    146   CONTAINS
     161  END INTERFACE mm_fshape
     162
     163CONTAINS
    147164
    148165  FUNCTION fshape_sc(cost,rap) RESULT(res)
    149166    !! Get the shape factor of a ccn (scalar).
    150167    !!
    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.
    152169    !! Details about the shape factor can be found in \cite{prup1978}.
    153170    REAL(kind=mm_wp), INTENT(in) :: cost !! Cosine of the contact angle.
     
    160177      phi = dsqrt(1._mm_wp-2._mm_wp*cost*rap+rap**2)
    161178      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)
    163180      c = 3._mm_wp * cost * (rap**2) * ((rap-cost)/phi-1._mm_wp)
    164181      res = 0.5_mm_wp*(a+b+c)
     
    177194    WHERE(rap > 3000._mm_wp)
    178195      res = ((2._mm_wp+cost)*(1._mm_wp-cost)**2)/4._mm_wp
    179     ELSEWHERE 
     196    ELSEWHERE
    180197      phi = dsqrt(1._mm_wp-2._mm_wp*cost*rap+rap**2)
    181198      a = 1._mm_wp + ((1._mm_wp-cost*rap)/phi )**3
     
    192209    !! The method computes the latent heat equation as given in \cite{reid1986} p. 220 (eq. 7-9.4).
    193210    IMPLICIT NONE
    194     ! - DUMMY 
     211    ! - DUMMY
    195212    REAL(kind=mm_wp), INTENT(in) :: temp !! temperature (K).
    196213    TYPE(mm_esp), INTENT(in)     :: xESP !! Specie properties.
    197214    REAL(kind=mm_wp) :: res              !! Latent heat of given specie at given temperature (\(J.kg^{-1}\)).
    198215    REAL(kind=mm_wp) :: ftm
    199     ftm=MIN(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)
    200217    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
    201218  END FUNCTION LHeatX_sc
    202    
     219
    203220  FUNCTION LHeatX_ve(temp,xESP) RESULT(res)
    204221    !! Compute latent heat of a given specie at given temperature (vector).
     
    208225    TYPE(mm_esp), INTENT(in)                   :: xESP !! Specie properties.
    209226    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
    211228    INTEGER      :: i
    212229    DO i=1,SIZE(temp)
    213       ftm=MIN(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)
    214231      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%masmol
     232        xESP%masmol
    216233    ENDDO
    217234  END FUNCTION LHeatX_ve
     
    219236  FUNCTION sigX_sc(temp,xESP) RESULT(res)
    220237    !! Get the surface tension between a given specie and the air (scalar).
    221     !! 
     238    !!
    222239    !! The method computes the surface tension equation as given in \cite{reid1986} p. 637 (eq. 12-3.6).
    223240    REAL(kind=mm_wp), INTENT(in) :: temp !! temperature (K).
     
    229246    sig = 0.1196_mm_wp*(1._mm_wp+(tbr*dlog(xESP%pc/1.01325_mm_wp))/(1._mm_wp-tbr))-0.279_mm_wp
    230247    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*1e3_mm_wp ! dyn/cm2 -> N/m
     248    res = sig*1e-3_mm_wp ! dyn/cm -> N/m
    232249  END FUNCTION sigX_sc
    233  
     250
    234251  FUNCTION sigX_ve(temp,xESP) RESULT(res)
    235252    !! Get the surface tension between a given specie and the air (vector).
     
    240257    REAL(kind=mm_wp), DIMENSION(SIZE(temp)) :: res     !! Surface tensions (\(N.m^{-1}\)).
    241258    INTEGER      :: i
    242     REAL(kind=mm_wp) :: tr,tbr,sig
     259    REAL(kind=mm_wp) :: tr,tbr,sig0,sig
    243260    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_wp
     261    sig0 = 0.1196_mm_wp*(1._mm_wp+(tbr*dlog(xESP%pc/1.01325_mm_wp))/(1._mm_wp-tbr))-0.279_mm_wp
    245262    DO i=1,SIZE(temp)
    246263      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*1e3_mm_wp ! dyn/cm2 -> N/m
     264      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
    249266    ENDDO
    250267  END FUNCTION sigX_ve
     
    252269  FUNCTION psatX_sc(temp,xESP) RESULT(res)
    253270    !! Get saturation vapor pressure for a given specie at given temperature (scalar).
    254     !! 
     271    !!
    255272    !! The method computes the saturation vapor pressure equation given in \cite{reid1986} p. 657 (eq. 1).
    256     !!
    257     !! @warning
    258     !! This subroutine accounts for a specific Titan feature:
    259     !! If __xESP__ corresponds to \(CH_{4}\), the saturation vapor presure is multiplied by 0.85
    260     !! to take into account its dissolution in \(N_{2}\).
    261273    REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K).
    262274    TYPE(mm_esp), INTENT(in)     :: xESP !! Specie properties.
     
    266278    IF (x > 0._mm_wp) THEN
    267279      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)
    269281    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)
    278285    ! now convert bar to Pa
    279286    res = res * 1e5_mm_wp
     
    282289  FUNCTION psatX_ve(temp,xESP) RESULT(res)
    283290    !! Get saturation vapor pressure for a given specie at given temperature (vector).
    284     !! 
     291    !!
    285292    !! See [[mm_methods(module):psatX_sc(function)]].
    286293    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperatures (K).
     
    292299      x = 1._mm_wp-temp(i)/xESP%tc
    293300      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)
    296303      ELSE
    297         qsat = XESP%a_sat*x/abs(1._mm_wp-x)     ! approx for t > tc
     304        qsat = XESP%a_sat*x/abs(1._mm_wp-x) ! approx for t > tc
    298305      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)
    302307    ENDDO
    303     res = res * 1e5_mm_wp  ! bar -> Pa
     308    ! now convert bar to Pa
     309    res = res * 1e5_mm_wp
    304310  END FUNCTION psatX_ve
    305311
    306312  FUNCTION qsatX_sc(temp,pres,xESP) RESULT(res)
    307313    !! 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.
    308318    REAL(kind=mm_wp), INTENT(in) :: temp !! Temperature (K).
    309319    REAL(kind=mm_wp), INTENT(in) :: pres !! Pressure level (Pa).
    310320    TYPE(mm_esp), INTENT(in)    :: xESP  !! Specie properties.
    311321    REAL(kind=mm_wp) :: res              !! Mass mixing ratio of the specie.
    312     REAL(kind=mm_wp) :: x,psat
     322    REAL(kind=mm_wp) :: psat
    313323    psat = mm_psatX(temp,xESP)
    314324    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
    315330  END FUNCTION qsatX_sc
    316331
    317332  FUNCTION qsatX_ve(temp,pres,xESP) RESULT(res)
    318333    !! 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.
    319338    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: temp !! Temperatures (K).
    320339    REAL(kind=mm_wp), INTENT(in), DIMENSION(:) :: pres !! Pressure levels (Pa).
     
    324343    psat = mm_psatX(temp,xESP)
    325344    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
    326350  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
    327410
    328411  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-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! brief: Microphysic processes interface module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838
    3939MODULE MM_MICROPHYSIC
     
    5151
    5252  !! 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)]]
    5555  !! or only aerosols microphysics ([[mm_microphysic(module):muphys_nocld(function)]]) in a single call.
    5656  INTERFACE mm_muphys
    5757    MODULE PROCEDURE muphys_all, muphys_nocld
    58   END INTERFACE
    59 
    60   CONTAINS
    61 
    62 
    63    
     58  END INTERFACE mm_muphys
     59
     60CONTAINS
     61
     62
     63
    6464  FUNCTION muphys_all(dm0a_s,dm3a_s,dm0a_f,dm3a_f,dm0n,dm3n,dm3i,dgazs) RESULT(ret)
    6565    !! 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
    6868    !! (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)]]
    7171    !! module) are initialized/updated correctly (see [[mm_globals(module):mm_global_init(interface)]],
    7272    !! [[mm_globals(module):mm_column_init(function)]],[[mm_globals(module):mm_aerosols_init(function)]] and
    7373    !! [[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
    7777    !! before the latter are called to initialize a new step.
    7878    !! @note
    7979    !! __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.
    8181    !!
    8282    !! It should be a 2D-array with the vertical layers in first dimension and the number of ice components in the second.
    8383    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)   :: dm0a_s
    84       !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)).
     84    !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)).
    8585    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}\)).
    8787    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)   :: dm0a_f
    88       !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)).
     88    !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)).
    8989    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)   :: dm3a_f
    90       !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)).
     90    !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)).
    9191    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)   :: dm0n
    92       !! Tendency of the 0th order moment of the _CCN_ distribution (\(m^{-2}\)).
     92    !! Tendency of the 0th order moment of the _CCN_ distribution (\(m^{-2}\)).
    9393    REAL(kind=mm_wp), INTENT(out), DIMENSION(:)   :: dm3n
    94       !! Tendency of the 3rd order moment of the _CCN_ distribution (\(m^{3}.m^{-2}\)).
     94    !! Tendency of the 3rd order moment of the _CCN_ distribution (\(m^{3}.m^{-2}\)).
    9595    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}\)).
    9797    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}\)).
    9999    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.
    101101    REAL(kind=mm_wp), DIMENSION(SIZE(dm0a_s)) :: zdm0a_f,zdm3a_f
    102102    INTEGER                                   :: i
     
    111111      ! add temporary aerosols tendencies (-> m-3)
    112112      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)
    114114      dm0n   = dm0n(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1)
    115115      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)
    116118      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.
    119123      ENDDO
    120124    ELSE
     
    126130    dm0a_f = dm0a_f(mm_nla:1:-1) * mm_dzlev(mm_nla:1:-1)
    127131    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)
    129137    RETURN
    130138  END FUNCTION muphys_all
     
    132140  FUNCTION muphys_nocld(dm0a_s,dm3a_s,dm0a_f,dm3a_f) RESULT(ret)
    133141    !! 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
    136144    !! only haze microphysics is computed and its tendencies returned.
    137145    !!
    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)]].
    139147    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_s
    140       !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)).
     148    !! Tendency of the 0th order moment of the spherical mode distribution (\(m^{-2}\)).
    141149    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}\)).
    143151    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm0a_f
    144       !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)).
     152    !! Tendency of the 0th order moment of the fractal mode distribution (\(m^{-2}\)).
    145153    REAL(kind=mm_wp), INTENT(out), DIMENSION(:) :: dm3a_f
    146       !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)).
     154    !! Tendency of the 3rd order moment of the fractal mode distribution (\(m^{3}.m^{-2}\)).
    147155    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.
    149157    ret = (mm_ini_col.AND.mm_ini_aer)
    150158    IF (.NOT.ret) RETURN
    151159    IF (mm_w_clouds.AND.mm_debug) THEN
    152160      WRITE(*,'(a)') "WARNING: clouds microphysics enabled but will not be &
    153                      &computed... (wrong interface)"
     161      &computed... (wrong interface)"
    154162    ENDIF
    155163    ! Calls haze microphysics
    156164    call mm_haze_microphysics(dm0a_s,dm3a_s,dm0a_f,dm3a_f)
    157165    ! 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)
    159167    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)
    161169    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)
    162175    RETURN
    163176  END FUNCTION muphys_nocld
    164177
    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)
    168179    !! Get various diagnostic fields of the microphysics.
    169180    !!
     
    171182    !!
    172183    !! - Mass fluxes (aerosols -both mode-, CCN and ices)
     184    !! - Settling velocity (aerosols -total-, CCN and ices)
    173185    !! - Precipitations (aerosols -total-, CCN and ices)
    174186    !! - condensible gazes saturation ratio
    175187    !!
    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
    178190    !! vector (for aerosols and CCN) or 2D-array (with the vertical structure in the first dimension
    179191    !! and number of species in the second, for ice) and are ordered from __GROUND__ to __TOP__.
    180192    !!
    181193    !! @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
    183195    !! the precipitations of each cloud ice components.
    184196    !!
    185197    !! @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
    187199    !! microphysics is disabled (see [[mm_globals(module):mm_w_clouds(variable)]] documentation).
    188200    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}\)).
    189205    REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:)   :: aer_s_flux !! Spherical aerosol mass flux (\(kg.m^{-2}.s^{-1}\)).
    190206    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).
    192207    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).
    194208    REAL(kind=mm_wp), INTENT(out), OPTIONAL, DIMENSION(:,:) :: ice_fluxes !! Ice sedimentation fluxes (\(kg.m^{-2}.s^{-1}\)).
    195209    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)
    198215    IF (PRESENT(aer_s_flux)) aer_s_flux = -mm_aer_s_flux(mm_nla:1:-1)
    199216    IF (PRESENT(aer_f_flux)) aer_f_flux = -mm_aer_f_flux(mm_nla:1:-1)
     
    202219      IF (PRESENT(ccn_prec))   ccn_prec   = ABS(mm_ccn_prec)
    203220      IF (PRESENT(ice_prec))   ice_prec   = ABS(mm_ice_prec)
     221      IF (PRESENT(ccn_w))      ccn_w      = mm_ccn_w(mm_nla:1:-1)
    204222      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,:)
    206224      IF (PRESENT(gazs_sat))   gazs_sat   =  mm_gazs_sat(mm_nla:1:-1,:)
    207     ELSE 
     225    ELSE
    208226      IF (PRESENT(ccn_prec))   ccn_prec   = 0._mm_wp
    209227      IF (PRESENT(ice_prec))   ice_prec   = 0._mm_wp
     228      IF (PRESENT(ccn_w))      ccn_w      = 0._mm_wp
    210229      IF (PRESENT(ccn_flux))   ccn_flux   = 0._mm_wp
    211230      IF (PRESENT(ice_fluxes)) ice_fluxes = 0._mm_wp
     
    216235  SUBROUTINE mm_get_radii(rcsph,rcfra,rccld)
    217236    !! 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
    220239    REAL(kind=mm_wp), INTENT(out), DIMENSION(:), OPTIONAL :: rccld !! Cloud drops mean radius
    221240    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)
    224243    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
    227246    ENDIF
    228247    IF (PRESENT(rccld)) THEN
  • trunk/LMDZ.TITAN/libf/muphytitan/mm_mprec.F90

    r1897 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL-B
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL-B license and that you accept its terms.
     
    3535!! summary: Library floating point precision module.
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838
    3939#ifdef HAVE_CONFIG_H
     
    4242
    4343#ifndef PREC
    44 #define PREC 64 
     44#define PREC 64
    4545#elif (PREC != 32 && PREC != 64 && PREC != 80)
    4646#undef PREC
     
    5252  !!
    5353  !! 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)
    5555  !! declaration statement).
    5656  IMPLICIT NONE
     
    5858#if (PREC == 32)
    5959  !> 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"
    6162#elif (PREC == 64)
    6263  !> 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"
    6466#elif (PREC == 80)
    6567  !> 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"
    6770#endif
    6871END 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
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL license and that you accept its terms.
     
    4444  IMPLICIT NONE
    4545
    46   CONTAINS 
    47    
     46  CONTAINS
     47
    4848  SUBROUTINE mmp_initialize(dt,p_prod,tx_prod,rc_prod,rplanet,g0, air_rad,air_mmol,clouds,cfgpath)
    4949    !! Initialize global parameters of the model.
    50     !! 
     50    !!
    5151    !! 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.
    5454    !! @note
    5555    !! If the subroutine fails to initialize parameters, the run is aborted.
    5656    !!
    5757    !! @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
    5959    !! initializes global variable that are not thread private.
    6060    !!
     
    8787
    8888    INTEGER                                           :: coag_choice
    89     REAL(kind=mm_wp)                                  :: fiad_max, fiad_min,df,rm,rho_aer
    90     LOGICAL                                           :: w_h_prod, w_h_sed, w_h_coag, w_c_sed, w_c_nucond, &
    91                                                          no_fiadero, fwsed_m0, fwsed_m3
     89    REAL(kind=mm_wp)                                  :: fiad_max,fiad_min,df,rm,rho_aer
     90    LOGICAL                                           :: w_h_prod,w_h_sed,w_h_coag,w_c_sed,w_c_nucond, &
     91                                                         no_fiadero,fwsed_m0,fwsed_m3
    9292    TYPE(error)                                       :: err
    9393    INTEGER                                           :: i
     
    9696    CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: species
    9797    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
    98100
    99101    w_h_prod    = .true.
     
    104106    fwsed_m0    = .true.
    105107    fwsed_m3    = .false.
    106     no_fiadero  = .false.
     108    no_fiadero  = .true.
    107109    fiad_min    = 0.1_mm_wp
    108110    fiad_max    = 10._mm_wp
    109111    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
    110118
    111119    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"
    113121    WRITE(*,'(a)') "On error I will simply abort the program. Stay near your computer !"
    114122    WRITE(*,*)
    115123    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.)
    117125    IF (err /= 0) THEN
    118126      ! RETURN AN ERROR !!
    119127      call abort_program(err)
    120128    ENDIF
    121    
     129
    122130    ! YAMMS internal parameters:
    123131    err = mm_check_opt(cfg_get_value(cparser,"rm",rm),rm,50e-9_mm_wp,mm_log)
     
    126134    ! the following parameters are primarily used to test and debug YAMMS.
    127135    ! 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)
    150153
    151154    ! Retrieve clouds species configuration file
     
    156159    ENDIF
    157160
    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 !
    220162    ! spherical mode inter-moments function parameters
    221163    IF (.NOT.cfg_has_section(cparser,'alpha_s')) call abort_program(error("Cannot find [alpha_s] section",-1))
     
    227169    IF (err /= 0) call abort_program(error("alpha_s: "//TRIM(err%msg),-1))
    228170
    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
    236234
    237235    ! btk coefficients
     
    249247    WRITE(*,'(a,L2)')     "electric_charging    : ", mmp_w_qe
    250248    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
    252256  END SUBROUTINE mmp_initialize
    253257
    254258  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
    257261    CHARACTER(len=*), INTENT(in) :: sec    !! Name of the section that contains the parameters.
    258262    TYPE(aprm), INTENT(out)      :: pp     !! [[mmp_gcm(module):aprm(type)]] object that stores the parameters values.
     
    266270  END FUNCTION read_aprm
    267271
    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 parser
    271     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) RETURN
    275     err = cfg_get_value(parser,TRIM(sec)//'/a0',pp%a0) ; IF (err /= 0) RETURN
    276     err = cfg_get_value(parser,TRIM(sec)//'/c',pp%c)   ; IF (err /= 0) RETURN
    277     err = cfg_get_value(parser,TRIM(sec)//'/a',pp%a)   ; IF (err /= 0) RETURN
    278     err = cfg_get_value(parser,TRIM(sec)//'/b',pp%b)   ; IF (err /= 0) RETURN
    279     IF (SIZE(pp%a) /= SIZE(pp%b)) &
    280       err = error("Inconsistent number of coefficients (a and b must have the same size)",3)
    281     RETURN
    282   END FUNCTION read_nprm
    283 
    284272END MODULE MMP_GCM
    285273
  • trunk/LMDZ.TITAN/libf/muphytitan/mmp_globals.f90

    r1926 r3083  
    2727  END TYPE
    2828
    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 of
    34   !! power law functions:
    35   !!
    36   !! $$
    37   !! \displaystyle n\left(r\right) = \frac{A_{0}}{C+\sum_{i=1}^{n} A_{i}\times
    38   !!                                    \left(\frac{r}{r_{c}}\right)^{-b_{i}}}
    39   !! $$
    40   TYPE, PUBLIC :: nprm
    41     !> Scaling factor.
    42     REAL(kind=mm_wp)                            :: a0
    43     !> Characterisitic radius.
    44     REAL(kind=mm_wp)                            :: rc
    45     !> Additional constant to the sum of power law.
    46     REAL(kind=mm_wp)                            :: c
    47     !> Scaling factor of each power law.
    48     REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: a
    49     !> Power of each power law.
    50     REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: b
    51   END TYPE
    52 
    5329  !> Inter-moment relation set of parameters for the spherical mode.
    5430  TYPE(aprm), PUBLIC, SAVE :: mmp_asp
    5531  !> Inter-moment relation set of parameters for the fractal mode.
    5632  TYPE(aprm), PUBLIC, SAVE :: mmp_afp
    57 
    58   !> Size-distribution law parameters of the spherical mode.
    59   TYPE(nprm), PUBLIC, SAVE :: mmp_pns
    60   !> Size-distribution law parameters of the fractal mode.
    61   TYPE(nprm), PUBLIC, SAVE :: mmp_pnf
    6233
    6334  !> Data set for @f$<Q>_{SF}^{M0}@f$.
     
    9263  !> Aerosol electric charge correction control flag.
    9364  LOGICAL, SAVE :: mmp_w_qe   = .true.
    94   !> Optic look-up table file path.
    95   CHARACTER(len=:), ALLOCATABLE, SAVE :: mmp_optic_file
    9665
    9766  CONTAINS
  • trunk/LMDZ.TITAN/libf/muphytitan/mmp_moments.f90

    r1897 r3083  
    1 ! Copyright 2013-2015,2017 Université de Reims Champagne-Ardenne
     1! Copyright 2013-2015,2017,2022 Université de Reims Champagne-Ardenne
    22! Contributor: J. Burgalat (GSMA, URCA)
    33! email of the author : jeremie.burgalat@univ-reims.fr
    4 ! 
     4!
    55! This software is a computer program whose purpose is to compute
    66! microphysics processes using a two-moments scheme.
    7 ! 
     7!
    88! 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,
    1010! modify and/ or redistribute the software under the terms of the CeCILL
    1111! license as circulated by CEA, CNRS and INRIA at the following URL
    12 ! "http://www.cecill.info". 
    13 ! 
     12! "http://www.cecill.info".
     13!
    1414! As a counterpart to the access to the source code and  rights to copy,
    1515! modify and redistribute granted by the license, users are provided only
    1616! with a limited warranty  and the software's author,  the holder of the
    1717! economic rights,  and the successive licensors  have only  limited
    18 ! liability. 
    19 ! 
     18! liability.
     19!
    2020! In this respect, the user's attention is drawn to the risks associated
    2121! with loading,  using,  modifying and/or developing or reproducing the
     
    2525! professionals having in-depth computer knowledge. Users are therefore
    2626! 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!
    3131! The fact that you are presently reading this means that you have had
    3232! knowledge of the CeCILL license and that you accept its terms.
     
    3535!! summary: YAMMS/MP2M model external methods
    3636!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     37!! date: 2013-2015,2017,2022
    3838!!
    3939!! 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
    4343!! of YAMMS library.
    4444
    4545PURE FUNCTION mm_alpha_s(k) RESULT (res)
    4646  !! 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
    4949  !! order moment of the size-distribution law:
    5050  !!
     
    5858  res = SUM(dexp(mmp_asp%a*k**2+mmp_asp%b*k+mmp_asp%c))
    5959  RETURN
    60 END FUNCTION mm_alpha_s 
     60END FUNCTION mm_alpha_s
    6161
    6262PURE FUNCTION mm_alpha_f(k) RESULT (res)
     
    8181  !!
    8282  !! @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
    8484  !! be transferred in the __fractal__ mode, but returns the proportion of particles that remains
    8585  !! in the mode (which is expected by mp2m model).
    8686  !!
    8787  !! @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
    8989  !! since we extrapolate the probability for characteristic radius value out of range.
    9090  !!
    9191  !! @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
    9494  !! of the table with probabilities respectively set to 0 and 1.
    9595  USE LINTDSET
     
    111111  TYPE(dset1d), POINTER :: pp
    112112  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
    114114  SELECT CASE(k+flow)
    115115    CASE(0)      ; pp => mmp_pco0p ! 0 = 0 + 0 -> M0 / CO
     
    119119    CASE DEFAULT ; RETURN
    120120  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
    122122    WRITE(*,'(a)') "mm_moments:ps2s_sc: Cannot interpolate transfert probability"
    123123    call EXIT(10)
    124124  ELSE
    125     ! 05102017: do not care anymore for bad extrapolation: 
     125    ! 05102017: do not care anymore for bad extrapolation:
    126126    ! Bound probability value between 0 and 1
    127127    ! note: The input look-up table still must have strict monotic variation or
     
    139139  !! kernel as a function of the temperature, pressure and the characteristic radius of
    140140  !! the mode involved in the coagulation.
    141   !! 
     141  !!
    142142  !! Modes are referred by a two letters uppercase string with the combination of:
    143143  !!
    144144  !! - S : spherical mode
    145145  !! - F : fractal mode
    146   !! 
     146  !!
    147147  !! For example, SS means intra-modal coagulation for spherical particles.
    148148  !!
     
    159159  CHARACTER(len=2), INTENT(in)  :: modes !! Interaction mode (a combination of [S,F]).
    160160  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).
    162162  REAL(kind=mm_wp) :: res                !! Electric charging correction.
    163163  INTEGER       :: chx,np
    164164  REAL(kind=mm_wp) :: vmin,vmax
    165165  REAL(kind=mm_wp) :: r_tmp, t_tmp
    166   chx = 0 
     166  chx = 0
    167167  IF (.NOT.mmp_w_qe) THEN
    168168    res = 1._mm_wp
     
    177177  SELECT CASE(chx)
    178178    CASE(2)      ! M0/SS
    179       res = 1._mm_wp 
     179      res = 1._mm_wp
    180180    CASE(4)      ! M0/SF
    181181      ! Fix max values of input parameters
     
    211211PURE FUNCTION mm_get_btk(t,k) RESULT(res)
    212212  !! Get the \(b_{k}^{T}\) coefficient of the Free Molecular regime.
    213   !! 
     213  !!
    214214  !! 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)
    216216  !! documentation page.
    217217  !!
     
    244244                                  tsut = 109._mm_wp,    &
    245245                                  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)
    247247  RETURN
    248248END 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.
    3321
    3422!! file: strings.F90
    3523!! summary: Strings manipulation source file
    3624!! author: J. Burgalat
    37 !! date: 2013-2015,2017
     25!! date: 2013-2015,2017,2022
    3826
    3927#include "defined.h"
     
    4129MODULE STRING_OP
    4230  !! Fortran strings manipulation module
    43   !! 
     31  !!
    4432  !! This module provides methods and objects to manipulate Fortran (allocatable) strings. It defines
    4533  !! 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.
    4735  USE ERRORS
    4836  IMPLICIT NONE
    49  
     37
    5038  PRIVATE
    5139
     
    5543  ! errors module (not used but propagated)
    5644  PUBLIC :: stdout,stderr,noerror,error, error_to_string,aborting
    57  
     45
    5846  ! misc module methods
    5947  PUBLIC :: to_string, from_string, string_is, remove_quotes, format_string,     &
     
    8674  INTEGER, PUBLIC, PARAMETER :: st_integer = 4 !! Integer type ID
    8775  INTEGER, PUBLIC, PARAMETER :: st_real    = 5 !! Real type ID
    88  
     76
    8977  !> List of types names
    9078  CHARACTER(len=*), DIMENSION(5), PARAMETER, PUBLIC :: st_type_names = &
     
    9583
    9684
    97  
     85
    9886  INTEGER, PUBLIC, PARAMETER :: FC_BLACK     = 30 !! Black foreground csi code
    9987  INTEGER, PUBLIC, PARAMETER :: FC_RED       = 31 !! Red foreground csi code
     
    120108  INTEGER, PUBLIC, PARAMETER, DIMENSION(21) :: attributes = [FC_BLACK,     &
    121109                                                             FC_RED,       &
    122                                                              FC_GREEN,     & 
     110                                                             FC_GREEN,     &
    123111                                                             FC_YELLOW,    &
    124112                                                             FC_BLUE,      &
     
    133121                                                             BG_MAGENTA,   &
    134122                                                             BG_CYAN,      &
    135                                                              BG_WHITE,     & 
     123                                                             BG_WHITE,     &
    136124                                                             ST_NORMAL,    &
    137125                                                             ST_BOLD,      &
     
    139127                                                             ST_UNDERLINE, &
    140128                                                             ST_BLINK      &
    141                                                             ]     
    142  
     129                                                            ]
     130
    143131  !> Aliases for CSI codes.
    144132  CHARACTER(len=2), DIMENSION(21), PARAMETER, PUBLIC :: csis =(/ &
     
    151139    MODULE PROCEDURE ws_affect
    152140  END INTERFACE
    153  
     141
    154142  !> Clear either a scalar or a vector of list of [[words(type)]]
    155143  !!
    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
    158146  !! object(s) is no longer used to avoid memory leaks.
    159147  !! @note
     
    168156  !! The interface encapsulates two subroutines:
    169157  !!
    170   !! - [[ws_extend_ws(subroutine)]](this,other) which extends __this__ by __other__ 
     158  !! - [[ws_extend_ws(subroutine)]](this,other) which extends __this__ by __other__
    171159  !!   (both are words objects).
    172160  !! - [[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
    174162  !!   __this__ with the resulting tokens.
    175163  INTERFACE words_extend
     
    192180  !!   parenthesis can be omitted.
    193181  !! - __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.
    195183  INTERFACE to_string
    196184    MODULE PROCEDURE int2str_as,int2str_fs
     
    201189    MODULE PROCEDURE dcplx2str_as,dcplx2str_fs
    202190  END INTERFACE
    203  
     191
    204192  !> Convert a string into an intrisinc type
    205193  !!
    206194  !! 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).
    208196  !! They always return an error object which is set to -5 error code (i.e. cannot cast value)
    209197  !! on error, otherwise [[errors(module):noerror(variable)]].
     
    217205  !! The generic interface adds CSI codes to the given value and returns a fortran intrinsic string.
    218206  !!
    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
    220208  !! [[string_op(module):add_csi(function)]].
    221209  !!
     
    251239  !! It's part of the doubly linked list words.
    252240  TYPE, PUBLIC :: word
    253 #if HAVE_FTNDTSTR   
     241#if HAVE_FTNDTSTR
    254242    CHARACTER(len=:), ALLOCATABLE :: value !! Value of the word
    255 #else   
     243#else
    256244    !> Value of the word
    257245    !!
    258     !! @warning 
     246    !! @warning
    259247    !! It is always limited to [[string_op(module):st_slen(variable)]] characters.
    260248    CHARACTER(len=st_slen)        :: value = ''
     
    263251    TYPE(word), PRIVATE, POINTER  :: prev => null() !! Previous word in the list of words
    264252  END TYPE word
    265  
     253
    266254  !> Define a list of words
    267255  TYPE, PUBLIC :: words
     
    270258    TYPE(word), PRIVATE, POINTER :: tail => null() !! Last word in the list
    271259    TYPE(word), PRIVATE, POINTER :: iter => null() !! Current word (iterator)
    272 #if HAVE_FTNPROC 
     260#if HAVE_FTNPROC
    273261    CONTAINS
    274262    PROCEDURE, PRIVATE :: ws_extend_ws
     
    279267      !! Insert a word at given index
    280268    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
    282270    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
    284272    PROCEDURE, PUBLIC :: get         => words_get
    285273      !! Get the word at given index
     
    293281      !! Reverse the list in place
    294282    PROCEDURE, PUBLIC :: reversed    => words_reversed
    295       !! Get a reversed copy of the list 
     283      !! Get a reversed copy of the list
    296284    PROCEDURE, PUBLIC :: dump        => words_dump
    297285      !! Dump words of the list (on per line)
     
    301289      !! Convert the list in a vector
    302290    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
    304292    PROCEDURE, PUBLIC :: remove      => words_remove
    305293      !! Remove a word from the list
     
    318306#endif
    319307  END TYPE words
    320  
     308
    321309  CONTAINS
    322  
     310
    323311  FUNCTION word_length(this) RESULT(lgth)
    324312    !! Get the trimmed length of the word object
     
    327315    INTEGER :: lgth
    328316      !! The length of the word's value (without trailing spaces)
    329 #if HAVE_FTNDTSTR   
     317#if HAVE_FTNDTSTR
    330318    IF (.NOT.ALLOCATED(this%value)) THEN
    331319      lgth = 0 ; RETURN
    332320    ENDIF
    333 #endif   
     321#endif
    334322    lgth = LEN_TRIM(this%value)
    335323    RETURN
    336324  END FUNCTION word_length
    337  
     325
    338326  SUBROUTINE disconnect_word(this)
    339327    !! Disconnect a word object
    340328    !!
    341329    !! 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
    344332    !! object and should be deallocated in order to avoid memory leaks.
    345333    TYPE(word), INTENT(inout) :: this
     
    351339    RETURN
    352340  END SUBROUTINE disconnect_word
    353  
     341
    354342  SUBROUTINE ws_affect(this,other)
    355343    !! words object assignment operator subroutine
     
    365353      cur => other%head
    366354      DO WHILE(associated(cur))
    367 #if HAVE_FTNDTSTR     
     355#if HAVE_FTNDTSTR
    368356        IF (.NOT.ALLOCATED(cur%value)) THEN
    369357          CALL words_append(this,"")
     
    380368    RETURN
    381369  END SUBROUTINE ws_affect
    382  
     370
    383371  SUBROUTINE ini_word(this,value)
    384372    !! Initialize the first word of a list of words
    385373    !!
    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
    387375    !! object in a words object.
    388376    TYPE(words), INTENT(inout)   :: this
    389377      !! A words object reference
    390378    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
    392380    ALLOCATE(this%head)
    393381    this%tail => this%head
     
    401389    !!
    402390    !! 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
    405393    !! the end of the current scope), otherwise memory leaks could occur.
    406394    TYPE(words),INTENT(inout), TARGET :: obj
     
    408396    TYPE(word), POINTER :: cur,next
    409397    IF (obj%nw == 0) RETURN
    410     cur => obj%head 
     398    cur => obj%head
    411399    DO WHILE(ASSOCIATED(cur))
    412400      next => cur%next
     
    426414    !!
    427415    !! 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
    430418    !! of the current scope), otherwise memory leaks could occur.
    431419    TYPE(words),INTENT(inout), DIMENSION(:) :: objs
     
    453441  END SUBROUTINE ws_extend_ws
    454442
    455   SUBROUTINE ws_extend_str(this,str,delimiter,merge,protect) 
     443  SUBROUTINE ws_extend_str(this,str,delimiter,merge,protect)
    456444    !> 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
    458446    !! splitting a string using a set of delimiters.
    459     !! 
     447    !!
    460448    !!   - 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
    463451    !!     special character is seen on the string, it is splitted.
    464452    !!   - If __protect__ is set to .true. THEN delimiter enclosed by
     
    466454    !!   - The optional argument __merge__ instructs the method wether to merge
    467455    !!     or not successive delimiters in the string.
    468     !! 
     456    !!
    469457    !! For example, considering the following string:
    470458    !! <center>@verbatim "I like coffee and bananas." @endverbatim</center>
     
    484472      !! A string to split in words
    485473    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).
    487475    LOGICAL, INTENT(in), OPTIONAL          :: merge
    488476      !! An optional boolean control flag that instructs the method
    489477      !! wether to merge or not successive delimiters (default to .false.)
    490478    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
    492480      !! delimiter characters between quotes are protected
    493481    ! - LOCAL
     
    498486    CHARACTER(len=1), PARAMETER   :: sq = CHAR(39) ! single quote ascii code
    499487    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.
    501489    seps = ' '
    502490    zmerge = .false. ; IF (PRESENT(merge)) zmerge = merge
     
    506494    ENDIF
    507495    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)) &
    509497            .OR.(INDEX(str,dq) == 1 .AND. INDEX(str,dq,.true.) == LEN(str))
    510498    ! no delimiter found or (have outer quotes and should protect)
    511499    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))
    513501      RETURN
    514502    ENDIF
    515     ! We have to loop... 
     503    ! We have to loop...
    516504    i = 1 ; curw=''
    517505    DO
     
    564552    !! Get the pointer of the word object at given index
    565553    !!
    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.
    567555    !! If index is out of range a null poitner is returned.
    568556    OBJECT(words), INTENT(in) :: this
    569       !! A words object 
     557      !! A words object
    570558    INTEGER, INTENT(in)       :: idx
    571559      !! An integer with the index of the desired object in __this__
     
    629617    ELSE
    630618      IF (idx > (this%nw+1)/2) THEN
    631         nx => this%tail 
     619        nx => this%tail
    632620        DO i=1, this%nw - idx ; nx => nx%prev ; ENDDO
    633621      ELSE
    634         nx => this%head 
     622        nx => this%head
    635623        DO i=1, idx-1 ; nx => nx%next ; ENDDO
    636624      ENDIF
     
    647635  SUBROUTINE words_append(this,value)
    648636    !! 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
    651639    !! [[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
    653641    CHARACTER(len=*), INTENT(in) :: value !! A string to append
    654642    !CALL words_insert(this,this%nw+1,value)
     
    668656    !this%tail%value = TRIM(value)
    669657    !this%tail%prev => np
    670     !this%tail%prev%next => this%tail 
     658    !this%tail%prev%next => this%tail
    671659    RETURN
    672660  END SUBROUTINE words_append
     
    677665    !! The method prepends a word to the list of word. This is a convinient wrapper to
    678666    !! [[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
    680668    CHARACTER(len=*), INTENT(in) :: value !! A string to prepend
    681669    CALL words_insert(this,0,value)
     
    685673  FUNCTION words_get(this,idx,case) RESULT (res)
    686674    !! Get the word's value at given index
    687     !! 
     675    !!
    688676    !! The method attempts to get the word's value at the given index. If index is out of range
    689677    !! an empty string is returned.
    690     !! @note 
     678    !! @note
    691679    !! The returned string is always trimmed.
    692680    OBJECT(words), INTENT(in)              :: this
     
    694682    INTEGER, INTENT(in)                    :: idx
    695683      !! 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
    697685      !! An optional string with either 'upper' or 'lower' to get the value converted in the relevant case
    698686    CHARACTER(len=:), ALLOCATABLE :: res
     
    704692    ENDIF
    705693    IF (PRESENT(case)) THEN
    706       IF (case == "upper") res = to_upper(cur%value) 
     694      IF (case == "upper") res = to_upper(cur%value)
    707695      IF (case == "lower") res = to_lower(cur%value)
    708696    ELSE
     
    729717    !!
    730718    !! 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
    732720    INTEGER :: res                    !! An integer with the maximum width (0 if the list is empty)
    733721    TYPE(word), POINTER :: cur
     
    744732  FUNCTION words_get_total_width(this) RESULT(width)
    745733    !! 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
    748736    !! the list of words.
    749     !! @note 
     737    !! @note
    750738    !! Total width is computed using strings::word_length so it only takes
    751739    !! into account trimmed words (without trailing blanks)
    752     !! @note 
     740    !! @note
    753741    !! If csi codes have been added to words elements they are counted in the width.
    754742    OBJECT(words), INTENT(in) :: this !! A words object
     
    795783    DO WHILE(ASSOCIATED(cur))
    796784      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
    798786      cur => cur%prev
    799787    ENDDO
     
    804792  SUBROUTINE words_dump(this,lun)
    805793    !! Dump the list of words
    806     !! 
     794    !!
    807795    !! The method dumps on the given logical unit the elements of the list one by line.
    808796    OBJECT(words), INTENT(in)     :: this
    809797      !! A words object to dump
    810798    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
    812800      !! standard output stream.
    813801    TYPE(word), POINTER :: cur
     
    834822    !! setting it back as values of the list of words.
    835823    OBJECT(words), INTENT(in)              :: this
    836       !! A words object 
     824      !! A words object
    837825    CHARACTER(len=*), INTENT(in), OPTIONAL :: delimiter
    838826      !! An optional string used as delimiter between each words
     
    867855    !! .false., otherwise it returns .true.
    868856    !! @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
    870858    !! values will be truncated.
    871859    OBJECT(words), INTENT(in)                                      :: this
     
    895883    !! Pop a word in the list of words
    896884    !!
    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,
    898886    !! last word of the list is removed.
    899887    !!
     
    906894    INTEGER, INTENT(in), OPTIONAL :: idx
    907895      !! 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.
    910898    CHARACTER(len=:), ALLOCATABLE :: value
    911       !! The word's value at given index 
     899      !! The word's value at given index
    912900    LOGICAL             :: zforward
    913901    INTEGER             :: zidx
     
    935923    !! Remove the word of the list at given index
    936924    !!
    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
    938926    !! of the list is removed.
    939927    !!
     
    947935      !! Index of the word to delete
    948936    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
    951939    INTEGER             :: zidx
    952940    TYPE(word), POINTER :: cur
     
    982970
    983971  FUNCTION words_valid(this) RESULT(ret)
    984     !! Check if the current iterated word is valid 
     972    !! Check if the current iterated word is valid
    985973    OBJECT(words), INTENT(in) :: this !! A words object
    986974    LOGICAL :: ret                    !! A logical flag with .true. if the current iterated word is valid
     
    993981      !! A words object
    994982    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
    996984      !! is not valid (see [[string_op(module):words_valid(function)]]).
    997985    IF (ASSOCIATED(this%iter)) THEN
     
    1001989
    1002990  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
    1006994    !! (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
    1008996    LOGICAL, INTENT(in), OPTIONAL :: to_end !! An optional logical flag with .true. to reset the iterator at the end of the list
    1009997    this%iter => this%head
     
    10181006  FUNCTION tokenize(str,vector,delimiter,merge,protect) RESULT(ok)
    10191007    !! Tokenize a string.
    1020     CHARACTER(len=*), INTENT(in)                             :: str
     1008    CHARACTER(len=*), INTENT(in)                                   :: str
    10211009      !! A string to tokenize
    1022     CHARACTER(len=*), INTENT(out), DIMENSION(:), ALLOCATABLE :: vector
    1023       !! 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,
    10241012      !! the vector is __allocated to 0 elements__ and the method returns .false..
    1025     CHARACTER(len=*), INTENT(in), OPTIONAL                   :: delimiter
    1026       !! 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.
    10271015      !! Note that each character is seen as a single delimiter.
    1028     LOGICAL, INTENT(in), OPTIONAL                            :: merge
    1029       !! 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
    10301018      !! merge or not successive delimiters. Default to .false.
    1031     LOGICAL, INTENT(in), OPTIONAL                            :: protect
    1032       !! 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
    10331021      !! quotes are protected. Default to .true.
    10341022    LOGICAL :: ok
     
    10401028    integer                       :: i,nw
    10411029    ok = .true.
    1042     zmerge = .false. ; zprotect = .true. ; seps = ' ' 
     1030    zmerge = .false. ; zprotect = .true. ; seps = ' '
    10431031    IF (PRESENT(merge)) zmerge = merge
    10441032    IF (PRESENT(protect)) zprotect = protect
     
    10731061    !! The output string is trimmed from leading and trailing blank spaces (after quotes removal !)
    10741062    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).
    10761064    CHARACTER(len=1), PARAMETER   :: sq=CHAR(39), dq=CHAR(34)
    10771065    CHARACTER(len=2), PARAMETER   :: dsq=CHAR(39)//CHAR(34)
     
    10901078    !! Check if string represents an intrinsic type
    10911079    !!
    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
    10931081    !! are checked in a strict way :
    10941082    !!
    10951083    !! - 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
    10971085    !!   __\*\*\*__ is checked to see wether it is numerical or not.
    10981086    !!
     
    11021090    !!   [0-9]*.?[0-9]*?([ed][+-]?[0-9]+)?
    11031091    !! ```
    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
    11051093    !! floating point value.
    11061094    !!
    1107     !! Empty input string is simply considered to be of string type ! 
     1095    !! Empty input string is simply considered to be of string type !
    11081096    CHARACTER(len=*), INTENT(in) :: str
    11091097      !! A string to check
     
    12131201      ALLOCATE(output,source='') ; RETURN
    12141202    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)
    12181206    ! i0 is relative to i1 and must be >= 0
    12191207    IF (PRESENT(idto)) i = MAX(i+idto,0)
    12201208    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
    12231211    c=1 ; mx = LEN_TRIM(str)
    12241212    i = INDEX(str(c:),'\n') ; ti = c+i-1
    12251213    IF (i == 0) THEN
    1226       output=output//TRIM(str(ti+1:mx)) 
     1214      output=output//TRIM(str(ti+1:mx))
    12271215    ELSE
    1228       output=output//TRIM(str(c:ti-1)) ; c=ti+2 
     1216      output=output//TRIM(str(c:ti-1)) ; c=ti+2
    12291217      DO
    12301218        i = INDEX(str(c:),"\n") ; ti = c+i-1
    12311219        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
    12331221        ELSE
    12341222          output=output//idts//str(c:ti-1) ; c = ti+2
     
    12431231
    12441232  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
    12491237    !! csi (see [[string_op(module):attributes(variable)]]).
    12501238    !! @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
    12521240    !! there is not enough space to put a word (with the associated indentation if given). The default
    12531241    !! behavior in that case is to print the word in a new line (with the correct leading blank spaces).
     
    12561244    !! method still computes the paragraph, but each words will be set on a new line with the appropriate
    12571245    !! 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
    12591247    INTEGER, INTENT(in)           :: width  !! An positive integer with the maximum width of a line
    12601248    INTEGER, INTENT(in), OPTIONAL :: idt1   !! An optional integer with the indentation level of the first output line
     
    12781266      output = str ; RETURN
    12791267    ENDIF
    1280     ! check if can just return the string as is 
     1268    ! check if can just return the string as is
    12811269    IF (zmx + l1 <= zw) THEN
    12821270      output=output//TRIM(zs) ; RETURN
    12831271    ENDIF
    1284     j=1 ; jj=1+l1 
    1285     DO 
     1272    j=1 ; jj=1+l1
     1273    DO
    12861274      ! Gets next blank in input string
    12871275      cc = INDEX(TRIM(zs(j:)),CHAR(32))
     
    12901278      ! this value will be substracted to each length test
    12911279      IF (cc == 0) THEN
    1292         l = csis_length(zs(j:)) 
     1280        l = csis_length(zs(j:))
    12931281        IF (jj-1+LEN_TRIM(zs(j:))-l > zw) THEN
    12941282          output = output//idts
     
    12971285        EXIT ! we are at the last word : we must exit the infinite loop !
    12981286      ELSE
    1299         l = csis_length(zs(j:j+cc-1)) 
     1287        l = csis_length(zs(j:j+cc-1))
    13001288        IF (cc+jj-1-l > zw) THEN
    13011289          output=output//idts//zs(j:j+cc-1) ; jj = lo+1+cc+1 - l
     
    13151303      INTEGER :: jc,iesc,im
    13161304      LOGICAL :: tcsi
    1317       value = 0 
     1305      value = 0
    13181306      jc=1
    1319       DO 
     1307      DO
    13201308        IF (jc>LEN(str)) EXIT
    13211309        ! search for escape
    13221310        iesc = INDEX(str(jc:),CHAR(27))
    1323         IF (iesc == 0) EXIT 
     1311        IF (iesc == 0) EXIT
    13241312        ! search for m
    13251313        im = INDEX(str(jc+iesc:),"m")
     
    13281316        ! check if this is really a csi and updates length
    13291317        tcsi = is_csi(str(jc+iesc-1:jc+iesc+im-1))
    1330         jc = jc + iesc 
     1318        jc = jc + iesc
    13311319        IF (tcsi) THEN
    13321320          value=value+im+1
     
    13401328    !! Replace newline escape sequences by spaces
    13411329    !!
    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
    13431331    !! given string and returns the resulting string.
    13441332    CHARACTER(len=*), INTENT(in)           :: str !! A string to process
    13451333    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
    13471335    CHARACTER(len=1) :: zrp
    1348     INTEGER          :: i, j, ns 
     1336    INTEGER          :: i, j, ns
    13491337    zrp = CHAR(32) ; IF(PRESENT(rpl)) zrp = rpl
    13501338    IF (str == NEW_LINE('A')) THEN
    1351       stripped = zrp ; RETURN 
     1339      stripped = zrp ; RETURN
    13521340    ENDIF
    13531341    ns = LEN_TRIM(str)
     
    13571345    ALLOCATE(CHARACTER(len=ns) :: stripped) ; stripped(1:ns) = CHAR(32)
    13581346    i=1 ; j=1
    1359     DO 
     1347    DO
    13601348      IF (str(i:i) == NEW_LINE('A')) THEN
    1361         stripped(j:j) = zrp 
     1349        stripped(j:j) = zrp
    13621350      ELSE IF (i < ns) THEN
    13631351          IF (str(i:i+1) == "\n") THEN
    13641352            stripped(j:j) = zrp ; i=i+1
    13651353          ELSE
    1366             stripped(j:j) = str(i:i) 
     1354            stripped(j:j) = str(i:i)
    13671355          ENDIF
    13681356      ELSE
    1369         stripped(j:j) = str(i:i) 
     1357        stripped(j:j) = str(i:i)
    13701358      ENDIF
    13711359      j=j+1 ; i=i+1
     
    13781366  FUNCTION str_length(str) RESULT(res)
    13791367    !! Get the length of the string object
    1380     !! 
     1368    !!
    13811369    !! The method computes the length of the string. It differs from LEN intrinsic function as
    13821370    !! it does not account for extra-characters of csi codes.
     
    13841372    INTEGER :: res                      !! The actual length of string (i.e. does not account for csi codes)
    13851373    CHARACTER(len=:), ALLOCATABLE :: tmp
    1386     res = 0 
     1374    res = 0
    13871375    IF (LEN(str) /= 0) THEN
    13881376      tmp = reset_csi(str)
     
    14211409    INTEGER :: j,i,ic,icsi,lcsi
    14221410    IF (LEN(str1) > 0) THEN
    1423       str = str1 
     1411      str = str1
    14241412      i = 1
    14251413      DO
     
    14421430            IF (ic >= 97 .AND. ic < 122) str(j:j) = char(ic-32)
    14431431          ENDDO
    1444           i = i + icsi + lcsi-1 
     1432          i = i + icsi + lcsi-1
    14451433        ENDIF
    14461434      ENDDO
     
    14511439
    14521440 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
    14561444   !! its occurences if __all__ is explicitly set to .true..
    14571445    CHARACTER(len=*), INTENT(in)  :: string    !! A string to search in
     
    14691457    zboff = 0 ; IF (zb) zboff = 1
    14701458    IF (LEN(string) == 0) RETURN
    1471     j=1 
    1472     DO 
     1459    j=1
     1460    DO
    14731461      IF (j>LEN(string)) EXIT
    14741462      ! search for substring
     
    14761464      IF (is == 0) THEN
    14771465        ! 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
    14791467      ELSE IF (is == 1) THEN
    14801468        j = j + LEN(substring)
     
    14861474      ! if we only want to str_remove ONE occurence we exit if substring
    14871475      ! has been found
    1488       IF (.NOT.(is==0.OR.za)) EXIT 
     1476      IF (.NOT.(is==0.OR.za)) EXIT
    14891477    ENDDO
    14901478    IF (j <= LEN(string).AND..NOT.zb) str=str//string(j:)
    1491     RETURN 
     1479    RETURN
    14921480  END FUNCTION str_remove
    14931481
    14941482 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
    14981486    !! __new__ or all its occurence(s) if __all__ is explicitly set to .true..
    14991487    CHARACTER(len=*), INTENT(in)  :: string  !! A string to search in
     
    15101498    IF (PRESENT(all)) za = all
    15111499    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
    15151503      IF (j>LEN(string)) EXIT
    15161504      ! search for "old"
     
    15181506      IF (is == 0) THEN
    15191507        ! "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
    15211509      ELSE IF (is == 1) THEN
    15221510        str = str//new
     
    15251513        ! "old" is not at the begin of the string : saves the string
    15261514        str = str//string(j:j+is-2)//new
    1527         j = j + is + LEN(old) - 1 
     1515        j = j + is + LEN(old) - 1
    15281516      ENDIF
    1529       IF (.NOT.(is==0.OR.za)) EXIT 
     1517      IF (.NOT.(is==0.OR.za)) EXIT
    15301518    ENDDO
    15311519    IF (j <= LEN(str)) str=str//string(j:)
    1532     RETURN 
     1520    RETURN
    15331521  END FUNCTION str_replace
    15341522
    15351523  FUNCTION endswith(string,substring,icase) RESULT(ret)
    1536     !! Check if string ends by substring 
     1524    !! Check if string ends by substring
    15371525    CHARACTER(len=*), INTENT(in)  :: string
    15381526      !! @param[in] string A string to check
    15391527    CHARACTER(len=*), INTENT(in)  :: substring
    15401528      !! A string to search in __string__
    1541     LOGICAL, INTENT(in), OPTIONAL :: icase 
     1529    LOGICAL, INTENT(in), OPTIONAL :: icase
    15421530      !! An optional boolean flag with .true. to perform insensitive case search
    15431531    LOGICAL :: ret
    15441532      !! .true. if __string__ ends by __substring__, .false. otherwise.
    15451533    CHARACTER(len=:), ALLOCATABLE :: zthis,zstr
    1546     INTEGER                       :: idx 
    1547     LOGICAL                       :: noc 
     1534    INTEGER                       :: idx
     1535    LOGICAL                       :: noc
    15481536    ret = .false.
    15491537    noc = .false. ; IF (PRESENT(icase)) noc = icase
     
    15601548
    15611549  FUNCTION startswith(string,substring,icase) RESULT(ret)
    1562     !! Check if string starts by substring 
     1550    !! Check if string starts by substring
    15631551    CHARACTER(len=*), INTENT(in)  :: string
    15641552      !! A string to check
    15651553    CHARACTER(len=*), INTENT(in)  :: substring
    15661554      !! A string to search in __string__
    1567     LOGICAL, INTENT(in), OPTIONAL :: icase 
     1555    LOGICAL, INTENT(in), OPTIONAL :: icase
    15681556      !! An optional boolean flag with .true. to perform insensitive case search
    15691557    LOGICAL :: ret
    15701558      !! .true. if __string__ starts by __substring__, .false. otherwise.
    15711559    CHARACTER(len=:), ALLOCATABLE :: zthis,zstr
    1572     INTEGER                       :: idx 
    1573     LOGICAL                       :: noc 
     1560    INTEGER                       :: idx
     1561    LOGICAL                       :: noc
    15741562    ret = .false.
    15751563    noc = .false. ; IF (PRESENT(icase)) noc = icase
     
    15851573  END FUNCTION startswith
    15861574
    1587   ! CSI related functions 
     1575  ! CSI related functions
    15881576  ! ---------------------
    15891577
     
    15941582    !! returns a copy of it.
    15951583    CHARACTER(len=*), INTENT(in)      :: string
    1596       !! @param[in] string A string object reference 
     1584      !! @param[in] string A string object reference
    15971585    INTEGER, INTENT(in), DIMENSION(:) :: attrs
    15981586      !! A vector of integers with the code to add. Each __attrs__ value should refers to one i
     
    16131601      tmp = string
    16141602    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
    16161604    !    if it does not start by an ANSI sequence
    16171605    IF (INDEX(tmp,CHAR(27)//"[") /= 1) &
    16181606    tmp = str_add_to_csi(rcsi,attrs)//tmp
    16191607    ! Loops on new string and updates csi codes
    1620     j=1 
    1621     DO 
     1608    j=1
     1609    DO
    16221610      IF (j>LEN(tmp)) EXIT
    16231611      ! search for escape
     
    16461634    ENDDO
    16471635    IF (INDEX(str,rcsi,.true.) /= LEN(str)-3) str = str//rcsi
    1648     RETURN 
     1636    RETURN
    16491637  END FUNCTION add_csi
    16501638
     
    16521640    !! Remove attributes to the given string
    16531641    !!
    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
    16551643    !! string and returns a copy of it.
    16561644    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
    16601648      !! refers to one of [[string_op(module):attributes(variable)]] values.
    16611649    CHARACTER(len=:), ALLOCATABLE :: str
     
    16761664    ! Loops on new string and updates csi codes
    16771665    j=1 ; csis=""
    1678     DO 
     1666    DO
    16791667      IF (j>LEN(tmp)) EXIT
    16801668      ! search for escape
     
    17051693    ! Add <ESC>[0m at the end of string if not found
    17061694    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,"|")
    17091697    IF (ALL(tks == rcsi)) str = reset_csi(str)
    17101698    DEALLOCATE(tks)
    1711     RETURN 
     1699    RETURN
    17121700  END FUNCTION del_csi
    17131701
    17141702  FUNCTION reset_csi(string) RESULT(str)
    17151703    !! Reset all csi codes of the string
    1716     !! 
     1704    !!
    17171705    !! The method removes __all__ the known escape sequences from the input string.
    17181706    CHARACTER(len=*), INTENT(in) :: string
    17191707      !! Input string
    1720     CHARACTER(len=:), ALLOCATABLE :: str 
     1708    CHARACTER(len=:), ALLOCATABLE :: str
    17211709      !! An allocatable string with the copy of input string stripped off csi codes.
    17221710    INTEGER :: j,iesc,im
    17231711    LOGICAL :: tcsi
    17241712    str = ""
    1725     IF (LEN(string) == 0) RETURN 
    1726     j=1 
    1727     DO 
     1713    IF (LEN(string) == 0) RETURN
     1714    j=1
     1715    DO
    17281716      IF (j>LEN(string)) EXIT
    17291717      ! search for escape
     
    17481736      j = j + iesc ; IF (tcsi) j=j+im
    17491737    ENDDO
    1750     RETURN 
     1738    RETURN
    17511739  END FUNCTION reset_csi
    17521740
    17531741  FUNCTION is_csi(value) RESULT(yes)
    17541742    !! Check if string is a known csi
    1755     !! 
     1743    !!
    17561744    !! The function only check for known csi code which are defined in [[string_op(module):attributes(variable)]].
    17571745    CHARACTER(len=*), INTENT(in) :: value
     
    17601748      !! .true. if it is a known csi, .false. otherwise
    17611749    LOGICAL                                           :: ok
    1762     CHARACTER(len=:), ALLOCATABLE                     :: tmp 
     1750    CHARACTER(len=:), ALLOCATABLE                     :: tmp
    17631751    TYPE(words)                                       :: wtks
    17641752    CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE :: stks
     
    17831771  FUNCTION str_add_to_csi(csi,list) RESULT(ncsi)
    17841772    !! Add a new list of codes to the input csi string
    1785     !! 
     1773    !!
    17861774    !! The method adds all the csi codes given in __list__ that are known by the module and not
    17871775    !! already present in the input csi.
     
    17891777      !! A string with the input csi. It __must__ begin with "<ESC>[" and ends with "m".
    17901778    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
    17931781      !! 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
    17961784      !! be tokenized or none of __list__ values are left after filtering).
    1797     LOGICAL                                            :: ok 
     1785    LOGICAL                                            :: ok
    17981786    CHARACTER(len=st_slen), DIMENSION(:), ALLOCATABLE  :: tks
    17991787    CHARACTER(len=:), ALLOCATABLE                      :: tmp
     
    18011789    INTEGER                                            :: i,j,ni,no
    18021790    ! 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)
    18051793    ok = tokenize(ncsi,tks,"; ",merge=.true.)
    18061794    IF (.NOT.from_string(tks,nums)) THEN
     
    18091797    ENDIF
    18101798    DEALLOCATE(tks)
    1811     ! 1.2) Filter input list of new flags to add 
     1799    ! 1.2) Filter input list of new flags to add
    18121800    ! counts number of valid flags
    1813     j=0 
    1814     DO i=1,SIZE(list) 
     1801    j=0
     1802    DO i=1,SIZE(list)
    18151803      ! new flags must be in attributes but NOT in nums
    18161804      IF (ANY(attributes==list(i).AND..NOT.ANY(nums == list(i)))) j=j+1
     
    18201808    ni = SIZE(nums) ; no = j + ni
    18211809    ALLOCATE(zlist(no)) ; zlist(1:ni) = nums(:) ; j = ni
    1822     DO i=1,SIZE(list) 
     1810    DO i=1,SIZE(list)
    18231811      ! new flags must be in attributes but NOT in nums
    18241812      IF (ANY(attributes==list(i).AND..NOT.ANY(nums == list(i)))) THEN
    18251813        j=j+1 ; zlist(j) = list(i)
    1826       ENDIF 
     1814      ENDIF
    18271815    ENDDO
    18281816    DEALLOCATE(nums)
     
    18311819    ncsi = CHAR(27)//"[0;"
    18321820    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
    18341822      IF (zlist(i) /= 0) THEN
    18351823        tmp = to_string(zlist(i))
     
    18411829      ENDIF
    18421830    ENDDO
    1843     ncsi = ncsi//"m" 
     1831    ncsi = ncsi//"m"
    18441832  END FUNCTION str_add_to_csi
    18451833
     
    18521840      !! An intrinsic Fortran string with the input csi. It __must__ begin with "<ESC>[" and ends with "m".
    18531841    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
    18551843      !! [[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
    18581846      !! be tokenized or none of __list__ values are left after filtering).
    18591847    LOGICAL                                            :: ok
     
    18621850    INTEGER, DIMENSION(:), ALLOCATABLE                 :: nums
    18631851    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
    18691857    ENDIF
    18701858    DEALLOCATE(tks)
     
    18861874    !! Get the position of the first known csi in string
    18871875    !!
    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
    18891877    !! (i.e. values of [[string_op(module):attributes(variable)]]).
    18901878    CHARACTER(len=*), INTENT(in) :: str    !! A string to search in
     
    18941882    pos = 0 ; length = 0
    18951883    ! we need at least 4 chars to create a csi
    1896     IF (LEN_TRIM(str) < 4) RETURN 
     1884    IF (LEN_TRIM(str) < 4) RETURN
    18971885    iesc = INDEX(str,CHAR(27))
    18981886    IF (iesc == 0) RETURN
     
    19751963    COMPLEX(kind=4), INTENT(out) :: value !! Output value
    19761964    LOGICAL :: ret                        !! Return status (.true. on success)
    1977     ! - LOCAL 
     1965    ! - LOCAL
    19781966    CHARACTER(len=:), ALLOCATABLE :: zs
    19791967    ret = .true. ; zs = remove_quotes(str)
     
    20282016    CHARACTER(len=*), INTENT(in), DIMENSION(:)           :: str   !! Vector of strings to convert
    20292017    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)
    20312019    INTEGER                       :: i,ns
    20322020    CHARACTER(len=:), ALLOCATABLE :: zs
     
    20812069
    20822070  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)
    20842072    INTEGER, INTENT(in)           :: value !! Value to convert
    20852073    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    20882076    WRITE(str,*,iostat=err) value
    20892077    str = TRIM(ADJUSTL(str))
    2090     IF (err /= 0) str = '' 
     2078    IF (err /= 0) str = ''
    20912079    RETURN
    20922080  END FUNCTION int2str_as
    20932081
    20942082  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)
    20962084    LOGICAL, INTENT(in)           :: value !! Value to convert
    20972085    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    21052093
    21062094  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)
    21082096    REAL(kind=4), INTENT(in)      :: value !! Value to convert
    21092097    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    21122100    WRITE(str,*, IOSTAT = err) value
    21132101    str=TRIM(ADJUSTL(str))
    2114     IF (err /= 0)  str = '' 
     2102    IF (err /= 0)  str = ''
    21152103    RETURN
    21162104  END FUNCTION real2str_as
    21172105
    21182106  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)
    21202108    REAL(kind=8), INTENT(in)      :: value !! Value to convert
    21212109    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    21242112    WRITE(str,*, IOSTAT = err) value
    21252113    str=TRIM(ADJUSTL(str))
    2126     IF (err /= 0) str = '' 
     2114    IF (err /= 0) str = ''
    21272115    RETURN
    21282116  END FUNCTION dble2str_as
    21292117
    21302118  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)
    21322120    COMPLEX(kind=4), INTENT(in)   :: value !! Value to convert
    21332121    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    21372125    WRITE(str, *, IOSTAT = err) value
    21382126    str = TRIM(ADJUSTL(str))
    2139     IF (err /= 0) str = '' 
     2127    IF (err /= 0) str = ''
    21402128    RETURN
    21412129  END FUNCTION cplx2str_as
    21422130
    21432131  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)
    21452133    COMPLEX(kind=8), INTENT(in)   :: value !! Value to convert
    21462134    CHARACTER(len=:), ALLOCATABLE :: str   !! String with the converted value in output
     
    21502138    WRITE(str, *, IOSTAT = err) value
    21512139    str = TRIM(ADJUSTL(str))
    2152     IF (err /= 0) str = '' 
     2140    IF (err /= 0) str = ''
    21532141    RETURN
    21542142  END FUNCTION dcplx2str_as
    21552143
    21562144  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)
    21582146    INTEGER, INTENT(in)           :: value !! Value to convert
    21592147    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    21632151    WRITE(str, '('//fmt//')', IOSTAT = err) value
    21642152    str = TRIM(ADJUSTL(str))
    2165     IF (err /= 0) str = '' 
     2153    IF (err /= 0) str = ''
    21662154    RETURN
    21672155  END FUNCTION int2str_fs
    21682156
    21692157  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)
    21712159    LOGICAL, INTENT(in)           :: value !! Value to convert
    21722160    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    21762164    WRITE(str, '('//fmt//')', IOSTAT = err) value
    21772165    str=TRIM(ADJUSTL(str))
    2178     IF (err /= 0) str = '' 
     2166    IF (err /= 0) str = ''
    21792167    RETURN
    21802168  END FUNCTION log2str_fs
    21812169
    21822170  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)
    21842172    REAL(kind=4), INTENT(in)      :: value !! Value to convert
    21852173    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    21892177    WRITE(str, '('//fmt//')', IOSTAT = err) value
    21902178    str = TRIM(ADJUSTL(str))
    2191     IF (err /= 0) str = '' 
     2179    IF (err /= 0) str = ''
    21922180    RETURN
    21932181  END FUNCTION real2str_fs
    21942182
    21952183  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)
    21972185    REAL(kind=8), INTENT(in)      :: value !! Value to convert
    21982186    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    22022190    WRITE(str, '('//fmt//')', IOSTAT = err) value
    22032191    str = TRIM(ADJUSTL(str))
    2204     IF (err /= 0) str = '' 
     2192    IF (err /= 0) str = ''
    22052193    RETURN
    22062194  END FUNCTION dble2str_fs
    22072195
    22082196  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)
    22102198    COMPLEX(kind=4), INTENT(in)   :: value !! Value to convert
    22112199    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    22152203    WRITE(str, '('//fmt//')', IOSTAT = err) value
    22162204    str = TRIM(ADJUSTL(str))
    2217     IF (err /= 0) str = '' 
     2205    IF (err /= 0) str = ''
    22182206    RETURN
    22192207  END FUNCTION cplx2str_fs
    22202208
    22212209  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)
    22232211    COMPLEX(kind=8), INTENT(in)   :: value !! Value to convert
    22242212    CHARACTER(len=*), INTENT(in)  :: fmt   !! String format
     
    22282216    WRITE(str, '('//fmt//')', IOSTAT = err) value
    22292217    str = TRIM(ADJUSTL(str))
    2230     IF (err /= 0) str = '' 
     2218    IF (err /= 0) str = ''
    22312219    RETURN
    22322220  END FUNCTION dcplx2str_fs
     
    22402228    INTEGER, INTENT(in)           :: int2 !! Integer to concatenate
    22412229    CHARACTER(len=:), ALLOCATABLE :: str  !! Output string
    2242     ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 
     2230    ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str)
    22432231    WRITE(str,*) int2 ; str = TRIM(ADJUSTL(str))
    22442232    IF (LEN(str1) /= 0) str = str1//str
     
    22512239  FUNCTION fis_cat_int_inv(int2,str1) RESULT(str)
    22522240    !! 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
    22542242    CHARACTER(len=*), INTENT(in)  :: str1 !! String to concatenate
    22552243    CHARACTER(len=:), ALLOCATABLE :: str  !! Output string
    2256     ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str) 
     2244    ALLOCATE(CHARACTER(len=DIGITS(int2)) :: str)
    22572245    WRITE(str,*) int2 ; str = TRIM(ADJUSTL(str))
    22582246    IF (LEN(str1) /= 0) str = str//str1
     
    22662254    CHARACTER(len=:), ALLOCATABLE :: str   !! Output string
    22672255    CHARACTER(len=2) ::tmp
    2268     WRITE(tmp,*) bool2 
     2256    WRITE(tmp,*) bool2
    22692257    str=TRIM(ADJUSTL(tmp))
    22702258    IF (LEN(str1) /= 0) str = str1//str
     
    22772265    CHARACTER(len=*), INTENT(in)  :: str1    !! String to concatenate
    22782266    CHARACTER(len=:), ALLOCATABLE :: str     !! Output string
    2279     CHARACTER(len=2) ::tmp 
    2280     WRITE(tmp,*) bool2 
     2267    CHARACTER(len=2) ::tmp
     2268    WRITE(tmp,*) bool2
    22812269    str = TRIM(ADJUSTL(tmp))
    22822270    IF (LEN(str1) /= 0) str = str//str1
     
    22892277    REAL(kind=4), INTENT(in)      :: real2 !! Simple precision real to concatenate
    22902278    CHARACTER(len=:), ALLOCATABLE :: str     !! Output string
    2291     ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 
     2279    ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str)
    22922280    WRITE(str,*) real2 ; str = TRIM(ADJUSTL(str))
    2293     IF (LEN(str1) /= 0) str=str1//str 
     2281    IF (LEN(str1) /= 0) str=str1//str
    22942282    RETURN
    22952283  END FUNCTION fis_cat_real
     
    23002288    CHARACTER(len=*), INTENT(in)  :: str1  !! String to concatenate
    23012289    CHARACTER(len=:), ALLOCATABLE :: str   !! Output string
    2302     ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str) 
     2290    ALLOCATE(CHARACTER(len=DIGITS(real2)) :: str)
    23032291    WRITE(str,*) real2  ; str = TRIM(ADJUSTL(str))
    23042292    IF (LEN(str1) /= 0) str = str//str1
     
    23112299    REAL(kind=8), INTENT(in)      :: double2 !! Double precision real to concatenate
    23122300    CHARACTER(len=:), ALLOCATABLE :: str     !! Output string
    2313     ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 
     2301    ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str)
    23142302    WRITE(str,*) double2 ; str = TRIM(ADJUSTL(str))
    2315     IF (LEN(str1) /= 0) str=str1//str 
     2303    IF (LEN(str1) /= 0) str=str1//str
    23162304    RETURN
    23172305  END FUNCTION fis_cat_double
     
    23222310    CHARACTER(len=*), INTENT(in)  :: str1    !! String to concatenate
    23232311    CHARACTER(len=:), ALLOCATABLE :: str     !! Output string
    2324     ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str) 
     2312    ALLOCATE(CHARACTER(len=DIGITS(double2)) :: str)
    23252313    WRITE(str,*) double2  ; str = TRIM(ADJUSTL(str))
    23262314    IF (LEN(str1) /= 0) str = str//str1
     
    23292317
    23302318  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
    23342322    CHARACTER(len=:), ALLOCATABLE :: str   !! Output string
    23352323    INTEGER :: sl
     
    23432331  FUNCTION fis_cat_cplx_inv(cplx2,str1) RESULT(str)
    23442332    !! 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
    23472335    CHARACTER(len=:), ALLOCATABLE :: str   !! Output string
    23482336    INTEGER :: sl
     
    23562344
    23572345  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
    23592347    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
    23612349    CHARACTER(len=:), ALLOCATABLE :: str    !! Output string
    23622350    INTEGER :: sl
     
    23702358  FUNCTION fis_cat_dcplx_inv(dcplx2,str1) RESULT(str)
    23712359    !! 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
    23732361    CHARACTER(len=*), INTENT(in)  :: str1   !! string to concatenate
    23742362    CHARACTER(len=:), ALLOCATABLE :: str    !! Output string
     
    23832371
    23842372  SUBROUTINE fis_affect_int(str,int)
    2385     !! Assignment subroutine (using intrinsic integer) 
     2373    !! Assignment subroutine (using intrinsic integer)
    23862374    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
    23882376    str = fis_cat_int('',int)
    23892377  END SUBROUTINE fis_affect_int
    23902378
    23912379  SUBROUTINE fis_affect_bool(str,bool)
    2392     !! Assignment subroutine (using intrinsic logical) 
     2380    !! Assignment subroutine (using intrinsic logical)
    23932381    CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str  !! Output string to be assigned
    23942382    LOGICAL, INTENT(in)                        :: bool !! Input value to assign
     
    23972385
    23982386  SUBROUTINE fis_affect_real(str,float)
    2399     !! Assignment subroutine (using intrinsic real) 
     2387    !! Assignment subroutine (using intrinsic real)
    24002388    CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str   !! Output string to be assigned
    24012389    REAL(kind=4), INTENT(in)                   :: float !! Input value to assign
     
    24042392
    24052393  SUBROUTINE fis_affect_double(str,double)
    2406     !! Assignment subroutine (using intrinsic real(kind=8)) 
     2394    !! Assignment subroutine (using intrinsic real(kind=8))
    24072395    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
    24092397    str = fis_cat_double('',double)
    24102398  END SUBROUTINE fis_affect_double
    24112399
    24122400  SUBROUTINE fis_affect_cplx(str,cplx)
    2413     !! Assignment subroutine (using intrinsic complex) 
     2401    !! Assignment subroutine (using intrinsic complex)
    24142402    CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str  !! Output string to be assigned
    24152403    COMPLEX(kind=4), INTENT(in)                :: cplx !! Input value to assign
     
    24182406
    24192407  SUBROUTINE fis_affect_dcplx(str,dcplx)
    2420     !! Assignment subroutine (using intrinsic complex(kind=8)) 
     2408    !! Assignment subroutine (using intrinsic complex(kind=8))
    24212409    CHARACTER(len=:), INTENT(out), ALLOCATABLE :: str   !! Output string to be assigned
    24222410    COMPLEX(kind=8), INTENT(in)                :: dcplx !! Input value to assign
     
    24292417    !! Only know CSI codes are returned. If no known CSI are found the outputput vector is
    24302418    !! 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
    24322420    INTEGER, DIMENSION(:), ALLOCATABLE :: codes         !! CSI codes.
    24332421    INTEGER :: i,j,n
     
    24542442  FUNCTION fancy_fstr(value,flags,fmt) RESULT(output)
    24552443    !! 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
    24572445    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    24582446    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format (unused for this overload)
    24592447    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    24602448    INTEGER, DIMENSION(:), ALLOCATABLE :: codes
    2461     codes = get_attrs_indexes(flags) 
     2449    codes = get_attrs_indexes(flags)
    24622450    IF (SIZE(codes) == 0) THEN
    24632451      output = value ; RETURN
     
    24692457  FUNCTION fancy_int(value,flags,fmt) RESULT(output)
    24702458    !! 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
    24722460    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    24732461    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    24742462    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    24752463    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)
    24782466    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    24792467    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
     
    24822470  FUNCTION fancy_bool(value,flags,fmt) RESULT(output)
    24832471    !! 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
    24852473    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    24862474    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    24872475    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    24882476    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)
    24912479    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    24922480    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
     
    24952483  FUNCTION fancy_real(value,flags,fmt) RESULT(output)
    24962484    !! 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
    24982486    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    24992487    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    25002488    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    25012489    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)
    25042492    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    25052493    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
    2506   END FUNCTION fancy_real 
     2494  END FUNCTION fancy_real
    25072495
    25082496  FUNCTION fancy_double(value,flags,fmt) RESULT(output)
    25092497    !! 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
    25112499    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    25122500    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    25132501    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    25142502    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)
    25172505    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    25182506    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
     
    25212509  FUNCTION fancy_cplx(value,flags,fmt) RESULT(output)
    25222510    !! 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
    25242512    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    25252513    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    25262514    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    25272515    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)
    25302518    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    25312519    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
    25322520  END FUNCTION fancy_cplx
    2533  
     2521
    25342522  FUNCTION fancy_dcplx(value,flags,fmt) RESULT(output)
    25352523    !! 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
    25372525    CHARACTER(len=2), DIMENSION(:), INTENT(in) :: flags  !! CSI attributes flags
    25382526    CHARACTER(len=*), INTENT(in), OPTIONAL     :: fmt    !! Optional format. If given it must be a valid Fortran format.
    25392527    CHARACTER(len=:), ALLOCATABLE              :: output !! Output fortran instrinsic string
    25402528    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)
    25432531    IF (PRESENT(fmt)) THEN ; tmp = to_string(value,fmt) ; ELSE ; tmp = to_string(value) ; ENDIF
    25442532    IF (SIZE(codes) /= 0) THEN ; output = add_csi(tmp,codes) ; ELSE ; output = tmp ; ENDIF
Note: See TracChangeset for help on using the changeset viewer.