Skip to content
Snippets Groups Projects
mode_options.f90 10.1 KiB
Newer Older
module mode_options
  implicit none

  integer,parameter :: nbavailoptions = 10
  integer,parameter :: TYPEUNDEF = -1, TYPEINT = 1, TYPELOG = 2, TYPEREAL = 3, TYPECHAR = 4
  integer,parameter :: MODEUNDEF = -11, MODECDF2CDF = 11, MODELFI2CDF = 12, MODECDF2LFI = 13

  integer,parameter :: OPTCDF3   = 1, OPTCDF4   = 2, OPTCOMPRESS = 3
  integer,parameter :: OPTHELP   = 4, OPTLIST   = 5, OPTMERGE    = 6
  integer,parameter :: OPTOUTPUT = 7, OPTREDUCE = 8, OPTSPLIT    = 9
  integer,parameter :: OPTVAR    = 10

  type option
    logical :: set = .false.
    character(len=:),allocatable :: long_name
    character :: short_name
    logical :: has_argument
    integer :: type = TYPEUNDEF
    integer :: ivalue
    logical :: lvalue
    real    :: rvalue
    character(len=:),allocatable :: cvalue
  end type option

contains
subroutine read_commandline(options,hinfile,houtfile,runmode)
  implicit none

  type(option),dimension(:),allocatable,intent(out) :: options
  character(len=:),allocatable,intent(out)          :: hinfile
  character(len=:),allocatable,intent(out)          :: houtfile
  integer,intent(out)                               :: runmode

  logical :: finished
  character(len=:),allocatable :: command, fullcommand


  call GET_COMMAND_ARGUMENT(NUMBER=0,LENGTH=sz)
  allocate(character(len=sz)::fullcommand)
  call GET_COMMAND_ARGUMENT(NUMBER=0,VALUE=fullcommand)

  idx = index(fullcommand,'/',back=.true.)
  allocate(character(len=sz-idx)::command)
  command=fullcommand(idx+1:)

  select case (command)
    case ('cdf2cdf')
      runmode = MODECDF2CDF
    case ('cdf2lfi')
      runmode = MODECDF2LFI
    case ('lfi2cdf')
      runmode = MODELFI2CDF
    case default
      runmode = MODEUNDEF
      print *,'Error: program started with unknown command: ',command
      call help()
  end select
  deallocate(command,fullcommand)

  call init_options(options)

  nbargs = COMMAND_ARGUMENT_COUNT()

  if (nbargs==0) then
    print *,'Error: no input file given'
    call help()
  end if

  if (nbargs>1) then
    finished = .false.
    do while(.not.finished)
      call get_option(options,finished)
    end do
  end if

  call GET_COMMAND_ARGUMENT(NUMBER=nbargs,LENGTH=sz)
  allocate(character(len=sz)::hinfile)
  call GET_COMMAND_ARGUMENT(NUMBER=COMMAND_ARGUMENT_COUNT(),VALUE=hinfile)

  call check_options(options,hinfile,runmode)

  !Remove level in the filename if merging LFI splitted files and output name not set by option
    if (options(OPTMERGE)%set) then
      houtfile=hinfile(1:len(hinfile)-9)
    end if
  end if

end subroutine read_commandline

subroutine init_options(options)
  implicit none

  type(option),dimension(:),allocatable,intent(out) :: options

  allocate(options(nbavailoptions))

  options(OPTCDF3)%long_name    = "cdf3"
  options(OPTCDF3)%short_name   = '3'
  options(OPTCDF3)%has_argument = .false.

  options(OPTCDF4)%long_name    = "cdf4"
  options(OPTCDF4)%short_name   = '4'
  options(OPTCDF4)%has_argument = .false.

  options(OPTCOMPRESS)%long_name    = "compress"
  options(OPTCOMPRESS)%short_name   = 'c'
  options(OPTCOMPRESS)%has_argument = .true.
  options(OPTCOMPRESS)%type         = TYPEINT

  options(OPTHELP)%long_name    = "help"
  options(OPTHELP)%short_name   = 'h'
  options(OPTHELP)%has_argument = .false.

  options(OPTLIST)%long_name    = "list"
  options(OPTLIST)%short_name   = 'l'
  options(OPTLIST)%has_argument = .false.

  options(OPTMERGE)%long_name    = "merge"
  options(OPTMERGE)%short_name   = 'm'
  options(OPTMERGE)%has_argument = .true.
  options(OPTMERGE)%type         = TYPEINT

  options(OPTOUTPUT)%long_name    = "output"
  options(OPTOUTPUT)%short_name   = 'o'
  options(OPTOUTPUT)%has_argument = .true.
  options(OPTOUTPUT)%type         = TYPECHAR

  options(OPTREDUCE)%long_name    = "reduce-precision"
  options(OPTREDUCE)%short_name   = 'r'
  options(OPTREDUCE)%has_argument = .false.

  options(OPTSPLIT)%long_name    = "split"
  options(OPTSPLIT)%short_name   = 's'
  options(OPTSPLIT)%has_argument = .false.

  options(OPTVAR)%long_name    = "var"
  options(OPTVAR)%short_name   = 'v'
  options(OPTVAR)%has_argument = .true.
  options(OPTVAR)%type         = TYPECHAR

end subroutine init_options

subroutine get_option(options,finished)
  implicit none

  integer,parameter :: MAXARGSIZE=512

  logical,intent(out) :: finished
  type(option),dimension(:),intent(inout) :: options

  integer,save              :: argnum = 1
  integer                   :: i, sz
  logical                   :: found
  character(len=MAXARGSIZE) :: arg

  found = .false.
  call GET_COMMAND_ARGUMENT(NUMBER=argnum,VALUE=arg,LENGTH=sz)
  if(sz>MAXARGSIZE) print *,'Error: argument bigger than ',MAXARGSIZE
  if ( INDEX(arg,'--')==1 .AND. sz>2) then
    do i=1,nbavailoptions
      if (options(i)%long_name == trim(arg(3:))) then
        found = .true.
        exit
      end if
    end do
  else if ( INDEX(arg,'-')==1 ) then
    do i=1,nbavailoptions
      if (options(i)%short_name == trim(arg(2:))) then
        found = .true.
        exit
      end if
    end do
  else
    print *,'Error: ',trim(arg),' is not an option'
    call help()
  end if

  if ( .not.found ) then
    print *,'Error: unknown option: ',trim(arg)
    call help()
  end if

  if (options(i)%set) then
    print *,'Error: at least 1 option is set several times!'
    call help()
  end if

  options(i)%set = .true.
  if (options(i)%has_argument) then
    argnum = argnum + 1
    if (argnum >= COMMAND_ARGUMENT_COUNT()) then
      print *,'Error: argument for option ',trim(arg),' not found'
      call help()
    end if
    call GET_COMMAND_ARGUMENT(NUMBER=argnum,VALUE=arg,LENGTH=sz)
    if(sz>MAXARGSIZE) print *,'Error: argument bigger than ',MAXARGSIZE
    select case (options(i)%type)
      case (TYPEINT)
        read (arg,*) options(i)%ivalue
      case (TYPELOG)
        read (arg,*) options(i)%lvalue
      case (TYPEREAL)
        read (arg,*) options(i)%rvalue
      case (TYPECHAR)
        options(i)%cvalue = arg
      case default
        print *,'Error: unknown option type'
        call help()
    end select
  end if

  argnum = argnum + 1

  if (argnum >= COMMAND_ARGUMENT_COUNT()) finished = .true.

end subroutine get_option

subroutine check_options(options,infile,runmode)
  implicit none

  type(option),dimension(:),intent(inout) :: options
  character(len=:),allocatable,intent(in) :: infile
  integer,intent(in)                      :: runmode

  integer :: idx1, idx2


  !Check if help has been asked
  if (options(OPTHELP)%set) then
    call help()
  end if

  !Use NetCF-4 by default
  if (.NOT.options(OPTCDF3)%set) then
    options(OPTCDF4)%set = .true.
  else
    if (options(OPTCDF4)%set) then
      print *,'Warning: NetCDF-3 and NetCDF-4 options are not compatible'
      print *,'NetCDF-4 is forced'
      options(OPTCDF3)%set = .false.
    end if
  end if

  !Check compression level
  if (options(OPTCOMPRESS)%set) then
    if (options(OPTCOMPRESS)%ivalue < 1 .OR. options(OPTCOMPRESS)%ivalue > 9 ) then
      print *,'Error: compression level should in the 1 to 9 interval'
      call help()
    end if
  end if

  !Check list option
  if (options(OPTLIST)%set .AND. runmode/=MODELFI2CDF) then
    print *,'Error: list option is only valid for lfi2cdf'
    call help()
  end if

  !Merge flag only supported if -v is set
  if (options(OPTMERGE)%set .AND. .NOT.options(OPTVAR)%set) then
    print *,'Error: merge option must be used with var option'
    call help()
  end if

  !Split flag only supported if -v is set
  if (options(OPTSPLIT)%set .AND. .NOT.options(OPTVAR)%set) then
      options(OPTSPLIT)%set = .false.
      print *,"Warning: split option is forced to disable"
  end if

  !Determine outfile name if not given
  if (.NOT.options(OPTOUTPUT)%set) then
    idx1 = index(infile,'/',back=.true.)
    idx2 = index(infile,'.',back=.true.)
    options(OPTOUTPUT)%cvalue = infile(idx1+1:idx2-1)
  end if

end subroutine check_options

subroutine help()
  implicit none

!TODO: -l option for cdf2cdf and cdf2lfi
  print *,"Usage : lfi2cdf [-h --help] [--cdf4 -4] [-l] [-v --var var1[,...]] [-r --reduce-precision]"
  print *,"                [-m --merge number_of_z_levels] [-s --split] [-o --output output-file.nc]"
  print *,"                [-c --compress compression_level] input-file.lfi"
  print *,"        cdf2cdf [-h --help] [--cdf4 -4] [-v --var var1[,...]] [-r --reduce-precision]"
  print *,"                [-m --merge number_of_z_levels] [-s --split] [-o --output output-file.nc]"
  print *,"                [-c --compress compression_level] input-file.nc"
  print *,"        cdf2lfi [-o --output output-file.lfi] input-file.nc"
  print *,""
  print *,"Options:"
  print *,"  --cdf3, -3"
  print *,"     Write netCDF file in netCDF-3 format (cdf2cdf and lfi2cdf only)"
  print *,"  --cdf4, -4 (by default)"
  print *,"     Write netCDF file in netCDF-4 format (HDF5 compatible) (cdf2cdf and lfi2cdf only)"
  print *,"  --compress, -c compression_level"
  print *,"     Compress data. The compression level should be in the 1 to 9 interval."
  print *,"     Only supported with the netCDF-4 format (cdf2cdf and lfi2cdf only)"
  print *,"  --help, -h"
  print *,"     Print this text"
  print *,"  --list, -l"
  print *,"     List all the fields of the LFI file and returns (lfi2cdf only)"
  print *,"  --merge, -m number_of_z_levels"
  print *,"     Merge LFI files which are split by vertical level (cdf2cdf and lfi2cdf only)"
  print *,"  --output, -o"
  print *,"     Name of file for the output"
  print *,"  --reduce-precision, -r"
  print *,"     Reduce the precision of the floating point variables to single precision (cdf2cdf and lfi2cdf only)"
  print *,"  --split, -s"
  print *,"     Split variables specified with the -v option (one per file) (cdf2cdf and lfi2cdf only)"
  print *,"  --var, -v var1[,...]"
  print *,"     List of the variable to write in the output file. Variables names have to be separated by commas (,)."
  print *,"     A variable can be computed from the sum of existing variables (format: new_var=var1+var2[+...])"
  print *,"     (cdf2cdf and lfi2cdf only)"
  print *,""
  stop

end subroutine help

end module mode_options