program main

  use vtype_module
  use fi_module
  use ni3_module

  use sortac_module, only : sortac

#ifdef MPI
  use mpi
#endif


  implicit none


  character(128) :: CtlFN  = 'sort_ac.conf'
!!$  character(128) :: CtlFN2 = 'sort_ac_file.conf'
  character(extstr) :: CtlFN3 = 'many.conf'

  integer :: FileUnit
  integer :: iostat

!!$  integer           :: InNcID
!!$  character(stdstr) :: Mode


  logical :: FlagChkConstVMR
  logical :: FlagKeyMolACAverage
  logical :: FlagNonKeyMolACAverage
  logical :: FlagPFRatioOne
  logical :: FlagSortPFRatioAverage

  integer, parameter :: MaxNmlArySize = 256
  real(8)            :: WNBnds(MaxNmlArySize)
  integer            :: BandNBin(MaxNmlArySize)
  integer            :: KeyMolNum(MaxNmlArySize)

  integer              :: NKeyMol
  integer, allocatable :: a_KeyMolNum      (:)

  integer              :: NBand
  real(8), allocatable :: a_BandWNBnds     (:)
  integer, allocatable :: a_BandNBin       (:)
  integer, allocatable :: ab_BandKeyMolNum (:,:)

  integer              :: NBandCur = 1
  real(8), allocatable :: a_BandCurWNBnds     (:)
  integer, allocatable :: a_BandCurNBin       (:)
  integer, allocatable :: ab_BandCurKeyMolNum (:,:)

  integer :: n


  ! 設定変数, 他
  ! setteing parameter, values
  !
  character(128) :: InOrgOptPropNcFN
                          ! 
                          ! input file name for original optical properties
!!$  logical        :: FlagOutSpeFlux
!!$  character(128) :: OutSpeFluxNcFN
  character(128) :: OutOptPropNcFN
!!$  character(128) :: OutFluxNcFN
!!$  character(128) :: OutTendencyNcFN

  character(128) :: StrSpeNcFN

!!$  real(8) :: CentStarConst
!!$  real(8) :: InAngle
                          ! sec (太陽光入射角) [1]
                          ! sec (angle of incidence) [1]
!!$  real(8) :: SurfAlbedo
                          ! 地表面アルベド [1]
                          ! surface albedo [1]


  character(128) :: InNcFN
  character(128) :: OutNcFN

  real(8) :: PressForPFSort

!!$  integer :: kmax

  logical :: FlagSort
  logical :: FlagBinning
  logical :: FlagBinningDemonstration
  logical :: FlagCorrelation
  logical :: FlagKeyMolAbsOverlap

  integer              :: NGaussReg
  real(8), allocatable :: a_GaussRegBnds(:)
  real(8)              :: GaussRegBnds(MaxNmlArySize)


  character(128) :: Method

!!$  integer :: iLoop
  integer :: iMode
  integer :: iBand

  integer :: iBands
  integer :: iBande
  integer :: iModes
  integer :: iModee

!!$  integer :: k
!!$  integer :: m
  integer :: iKeyMol


  character(len=extstr)     :: FileNameTail

  integer :: iTemp
  integer :: iTemps
  integer :: iTempe
  integer :: Mol1Num
  integer :: iVMRMol1
  integer :: iVMRMol1s
  integer :: iVMRMol1e
  integer :: Mol2Num
  integer :: iVMRMol2
  integer :: iVMRMol2s
  integer :: iVMRMol2e
  integer :: Mol3Num
  integer :: iVMRMol3
  integer :: iVMRMol3s
  integer :: iVMRMol3e

  integer :: NTemp
  integer :: NVMRMol1
  integer :: NVMRMol2
  integer :: NVMRMol3


  integer :: iLoop
  integer :: NLoop
  integer :: iLoops
  integer :: iLoope

  integer :: iRank

  integer :: IErr
  integer :: NProcs
  integer :: MyRank


  namelist /band_mode_nml/ &
    & iBands, iBande, iModes, iModee
  namelist /flag_nml/ &
!!$    & FlagChkConstH2OMR, FlagKeyMolACAverage, FlagNonKeyMolACAverage
    & FlagChkConstVMR
!!$  namelist /file_nml/ &
!!$    & InProfNcFn, &
!!$!    & InNcFN, OutNcFN
!!$    & InOrgOptPropNcFN, &
!!$    & FlagOutSpeFlux,  &
!!$    & OutSpeFluxNcFN,  &
!!$    & OutFluxNcFN,     &
!!$    & OutTendencyNcFN, &
!!$    & OutOptPropNcFN
  namelist /band_nml/ &
    & NBand, WNBnds, BandNBin, KeyMolNum
  namelist /star_nml/ &
    & StrSpeNcFN

  namelist /gauss_region_nml/ &
    & NGaussReg, GaussRegBnds


  namelist /many_nml/ &
    & iTemps, iTempe, &
    & Mol1Num, iVMRMol1s, iVMRMol1e, &
    & Mol2Num, iVMRMol2s, iVMRMol2e, &
    & Mol3Num, iVMRMol3s, iVMRMol3e

!!$  namelist /press_nml/ &
!!$    & PressForPFSort


#ifdef MPI
  call mpi_init( IErr )
  call mpi_comm_size( mpi_comm_world, NProcs, IErr )
  call mpi_comm_rank( mpi_comm_world, MyRank, IErr )
#else
  NProcs = 1
  MyRank = 0
#endif




  FlagChkConstVMR      = .true.

  StrSpeNcFN = ""

  NBand = 1
  WNBnds    = -999.0d0
  WNBnds(1) = 0.0d0
  WNBnds(2) = 1.0d100
  KeyMolNum    = -1
  KeyMolNum(1) = 1
  BandNBin     = -1
  BandNBin(1)  = 10

  GaussRegBnds = 0.0d0


!!$  PressForPFSort = -1.0d0
  PressForPFSort = 1.0d5


  ! Read a namelist file

  call fi_open( CtlFN, "read", FileUnit )
  !
  rewind( FileUnit )
  read( FileUnit, nml = band_mode_nml, iostat = iostat )
  write( 6, * ) iostat
  if ( iostat /= 0 ) then
    stop 'Namelist, band_mode_nml, is something wrong.'
  end if
  write( 6, nml = band_mode_nml )
  !
  rewind( FileUnit )
  read( FileUnit, nml = flag_nml, iostat = iostat )
  if ( iostat /= 0 ) then
    stop 'Namelist, flag_nml, is something wrong.'
  end if
  write( 6, nml = flag_nml )
  !
  rewind( FileUnit )
  read( FileUnit, nml = band_nml, iostat = iostat )
  if ( iostat /= 0 ) then
    stop 'Namelist, band_nml, is something wrong.'
  end if
  write( 6, nml = band_nml )
  !
  rewind( FileUnit )
  read( FileUnit, nml = star_nml, iostat = iostat )
  if ( iostat /= 0 ) then
    stop 'Namelist, star_nml, is something wrong.'
  end if
  write( 6, nml = star_nml )
  !
  rewind( FileUnit )
  read( FileUnit, nml = gauss_region_nml, iostat = iostat )
  if ( iostat /= 0 ) then
    stop 'Namelist, gauss_region_nml, is something wrong.'
  end if
  write( 6, nml = gauss_region_nml )
  !
  ! PressForPFSort is not used, now.
!!$  rewind( FileUnit )
!!$  read( FileUnit, nml = press_nml, iostat = iostat )
!!$  if ( iostat /= 0 ) then
!!$    stop 'Namelist, press_nml, is something wrong.'
!!$  end if
!!$  write( 6, nml = press_nml )
  !
  close( FileUnit )

!!$  call fi_open( CtlFN2, "read", FileUnit )
!!$  !
!!$  rewind( FileUnit )
!!$  read( FileUnit, nml = file_nml, iostat = iostat )
!!$  if ( iostat > 0 ) then
!!$    stop 'Namelist in file_nml is something wrong.'
!!$  end if
!!$  write( 6, nml = file_nml )
!!$  !
!!$  close( FileUnit )

  call fi_open( CtlFN3, "read", FileUnit )
  !
  rewind( FileUnit )
  read( FileUnit, nml = many_nml, iostat = iostat )
  if ( iostat > 0 ) then
    stop 'Namelist in file_nml is something wrong.'
  end if
  write( 6, nml = many_nml )
  !
  close( FileUnit )


  if ( PressForPFSort < 0.0d0 ) then
    write( 6, * ) 'PressForPFSort is negative: ', PressForPFSort
    stop
  end if


  allocate( a_GaussRegBnds(0:NGaussReg) )
  a_GaussRegBnds = GaussRegBnds(1:NGaussReg+1)
  ! check
  if ( NGaussReg <= 0 ) then
    write( 6, * ) "NGaussReg is not appropriate: ", NGaussReg
    stop
  end if
  if ( ( a_GaussRegBnds(0) /= 0.0d0 ) .or. ( a_GaussRegBnds(NGaussReg) /= 1.0d0 ) ) then
    write( 6, * ) "GaussRegBnds is not appropriate: ", a_GaussRegBnds
    stop
  end if



  NTemp    = iTempe    - iTemps    + 1
  NVMRMol1 = iVMRMol1e - iVMRMol1s + 1
  NVMRMol2 = iVMRMol2e - iVMRMol2s + 1
  NVMRMol3 = iVMRMol3e - iVMRMol3s + 1

  NLoop = NTemp * NVMRMol1 * NVMRMol2 * NVMRMol3

  iLoope = 0
  do iRank = 0, MyRank
    iLoops = iLoope + 1
    iLoope = iLoops + NLoop / NProcs - 1
    if ( iRank < mod( NLoop, NProcs ) ) then
      iLoope = iLoope + 1
    end if
  end do
  ! check
  if ( iLoope > NLoop ) then
    write( 6, * ) 'Unexpected number of maximum of loop: ', iLoope, NLoop
  end if


  do iLoop = iLoops, iLoope

    iTemp       = iTemps       &
      & + ( iLoop - 1 ) / ( NVMRMol1 * NVMRMol2 * NVMRMol3 )
    iVMRMol1 = iVMRMol1s &
      & + mod( ( iLoop - 1 ) / ( NVMRMol2 * NVMRMol3 ), NVMRMol1 )
    iVMRMol2 = iVMRMol2s &
      & + mod( ( iLoop - 1 ) / ( NVMRMol3 ), NVMRMol2 )
    iVMRMol3 = iVMRMol3s &
      & + mod( ( iLoop - 1 ), NVMRMol3 )


    write( FileNameTail, '(a,i3.3,3(a,i2.2,a,i3.3),a)' ) &
      & "T-", iTemp, &
      & "_M", Mol1Num, "-", iVMRMol1, &
      & "_M", Mol2Num, "-", iVMRMol2, &
      & "_M", Mol3Num, "-", iVMRMol3, &
      & ".nc"


    InOrgOptPropNcFN = "../prog05_calc_ac_many_mpi/out/ac_" // trim( FileNameTail )
    OutOptPropNcFN   = "out/ac_" // trim( FileNameTail )

    write( 6, * ) 'Input : ', trim( InOrgOptPropNcFN )
    write( 6, * ) 'Output: ', trim( OutOptPropNcFN )



    do n = 1, MaxNmlArySize
      if ( KeyMolNum(n) < 0 ) then
        exit
      end if
    end do
    NKeyMol = n - 1
    allocate( a_KeyMolNum(1:NKeyMol) )
    a_KeyMolNum(1:NKeyMol) = KeyMolNum(1:NKeyMol)




    InNcFN = InOrgOptPropNcFN



    if ( NBand+1 > MaxNmlArySize ) then
      stop 'Array size is too large.'
    end if
    do n = 1, NBand
      if ( WNBnds(n) > WNBnds(n+1) ) then
        stop 'Band bounds does not increase monotonicaly.'
      end if
    end do


!!$  RatioSolarConst = SolConst/(StB*SolTemp*SolTemp*SolTemp*SolTemp)


    allocate( a_BandWNBnds     (0:NBand) )
    allocate( a_BandNBin       (1:NBand) )
    allocate( ab_BandKeyMolNum (1:NKeyMol,1:NBand) )

    a_BandWNBnds   (0:NBand) = WNBnds   (1:NBand+1)
    a_BandNBin     (1:NBand) = BandNBin (1:NBand  )

    do n = 1, NBand
      ab_BandKeyMolNum(:,n) = a_KeyMolNum
    end do


    ! check
    do iBand = 1+1, NBand
      do iKeyMol = 1, NKeyMol
        if ( ab_BandKeyMolNum(iKeyMol,iBand) /= ab_BandKeyMolNum(iKeyMol,1) ) then
          write( 6, * ) 'Now, KeyMolNum has to be the same for all bands.'
          write( 6, * ) ab_BandKeyMolNum
          stop
        end if
      end do
    end do




    do iBand = max( iBands, 0 ), min( iBande, NBand+1 )
!!$  do iBand = 1, NBand+1
!!$  do iBand = NBand+1, NBand+1
!!$  do iBand = 0, 0
!!$  do iBand = 1, 1
!!$  do iBand = 4, 4
!!$  do iBand = 10, 10

!!$    if ( iBand == 0 ) then
      if ( ( iBand == 0 ) .or. ( iBand == NBand+1 ) ) then
        NBandCur = NBand
        allocate( a_BandCurWNBnds     (0:NBandCur) )
        allocate( a_BandCurNBin       (1:NBandCur) )

        a_BandCurWNBnds   (0:NBandCur) = a_BandWNBnds   (0:NBandCur)
        a_BandCurNBin     (1:NBandCur) = a_BandNBin     (1:NBandCur)

        allocate( ab_BandCurKeyMolNum (1:NKeyMol,1:NBandCur) )
        ab_BandCurKeyMolNum(:,1:NBandCur) = ab_BandKeyMolNum(:,1:NBandCur)
      else
        NBandCur = 1
        allocate( a_BandCurWNBnds  (0:NBandCur) )
        allocate( a_BandCurNBin    (1:NBandCur) )

        a_BandCurWNBnds   (0:NBandCur) = a_BandWNBnds   (iBand-1:iBand)
        a_BandCurNBin     (1:NBandCur) = a_BandNBin     (iBand  :iBand)

        allocate( ab_BandCurKeyMolNum (1:NKeyMol,1:NBandCur) )
        ab_BandCurKeyMolNum(:,1:NBandCur) = ab_BandKeyMolNum(:,iBand:iBand)
      end if



      do iMode = iModes, iModee
!!$    do iLoop = 0, 0
!!$    do iLoop = 0, 1
!!$    do iLoop = 0, 3
!!$    do iLoop = 0, 4
!!$    do iLoop = 0, 5
!!$    do iLoop = 0, 6
!!$    do iLoop = 0, 7
!!$    do iLoop = 0, 9
!!$    do iLoop = 1, 1
!!$    do iLoop = 2, 2
!!$    do iLoop = 3, 3
!!$    do iLoop = 4, 4
!!$    do iLoop = 5, 5
!!$    do iLoop = 6, 6
!!$    do iLoop = 7, 7
!!$    do iLoop = 7, 9
!!$    do iLoop = 8, 9
        write( 6, * ) 'iBand = ', iBand
        write( 6, * ) 'iMode = ', iMode


        select case ( iMode )
        case ( 0 )
          FlagSort                 = .false.
          Method                   = 'LBL'
          FlagCorrelation          = .false.
          FlagKeyMolAbsOverlap     = .false.
          FlagPFRatioOne           = .false.
          FlagSortPFRatioAverage   = .false.
          FlagBinning              = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 1 )
          FlagSort               = .false.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .false.
          FlagKeyMolAbsOverlap   = .false.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 2 )
          FlagSort               = .true.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .false.
          FlagKeyMolAbsOverlap   = .false.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 3 )
          FlagSort               = .true.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .false.
          FlagKeyMolAbsOverlap   = .true.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 4 )
          FlagSort               = .true.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .false.
          FlagKeyMolAbsOverlap   = .false.
          FlagPFRatioOne         = .true.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 5 )
          FlagSort               = .true.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .true.
          FlagKeyMolAbsOverlap   = .true.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 6 )
          FlagSort               = .true.
          Method                 = 'LBLConstPF'
          FlagCorrelation        = .true.
          FlagKeyMolAbsOverlap   = .true.
          FlagPFRatioOne         = .true.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 7 ) ! no effect (meaningless) now
          FlagSort                 = .true.
          Method                   = 'LBLConstPF'
          FlagCorrelation          = .false.
          FlagKeyMolAbsOverlap     = .true.
          FlagPFRatioOne           = .false.
          FlagSortPFRatioAverage   = .true.
          FlagBinning              = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 8 ) ! the "best" with correlation before binning (2016/12/14)
          FlagSort                 = .true.
          Method                   = 'KDDevelop'
          FlagCorrelation          = .true.
          FlagKeyMolAbsOverlap     = .true.
          FlagPFRatioOne           = .false.
          FlagSortPFRatioAverage   = .false.
          FlagBinning              = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 9 )
          FlagSort                 = .true.
          Method                   = 'KDDevelop'
          FlagCorrelation          = .true.
          FlagKeyMolAbsOverlap     = .true.
          FlagPFRatioOne           = .false.
          FlagSortPFRatioAverage   = .true.
          FlagBinning              = .true.
          FlagBinningDemonstration = .true.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 10 ) ! the "best" with correlation and binning (2016/12/16)
          FlagSort                 = .true.
          Method                   = 'KDDevelop'
          FlagCorrelation          = .true.
          FlagKeyMolAbsOverlap     = .true.
          FlagPFRatioOne           = .false.
          FlagSortPFRatioAverage   = .true.
          FlagBinning              = .true.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 11 )
          FlagSort               = .true.
          Method                 = 'KDDevelop'
          FlagCorrelation        = .true.
          FlagKeyMolAbsOverlap   = .true.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .false.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case ( 12 )
          FlagSort               = .true.
          Method                 = 'KDDevelop'
          FlagCorrelation        = .true.
          FlagKeyMolAbsOverlap   = .true.
          FlagPFRatioOne         = .false.
          FlagSortPFRatioAverage = .false.
          FlagBinning            = .true.
          FlagBinningDemonstration = .false.
          FlagKeyMolACAverage      = .false.
          FlagNonKeyMolACAverage   = .true.
        case default
          stop 'Unexpected value of iMode'
        end select

        write( 6, * ) "KeyMolNum                : "
        do n = 1, NBandCur
          write( 6, * ) "  Band: ", n, " : ", &
            & ( ab_BandCurKeyMolNum(iKeyMol,n), iKeyMol = 1, NKeyMol )
        end do
        write( 6, * ) "FlagSort                 : ", FlagSort
        write( 6, * ) "Method                   : ", trim( Method )
        write( 6, * ) "FlagCorrelation          : ", FlagCorrelation
        write( 6, * ) "FlagKeyMolAbsOverlap     : ", FlagKeyMolAbsOverlap
        write( 6, * ) "FlagPFRatioOne           : ", FlagPFRatioOne
        write( 6, * ) "FlagSortPFRatioAverage   : ", FlagSortPFRatioAverage
        write( 6, * ) "FlagBinning              : ", FlagBinning
        write( 6, * ) "FlagBinningDemonstration : ", FlagBinningDemonstration
        write( 6, * ) "FlagKeyMolACAverage      : ", FlagKeyMolACAverage
        write( 6, * ) "FlagNonKeyMolACAverage   : ", FlagNonKeyMolACAverage

        InNcFN = InOrgOptPropNcFN
        write( OutNcFN, '(a,a,i2.2,a,i2.2,a)' ) &
          & OutOptPropNcFN(1:len_trim(OutOptPropNcFN)-3), '-', iband, '-', iMode, '.nc'
        call sortac( &
          & FlagSort, &
          & InNcFN, InNcFN, OutNcFN, &
          & FlagChkConstVMR, FlagBinning, FlagBinningDemonstration, &
          & FlagKeyMolACAverage, FlagNonKeyMolACAverage, &
          & FlagPFRatioOne, &
          & FlagSortPFRatioAverage, &
          !        & NBand, a_BandWNBnds, a_BandKeyMolNum, a_BandNBin &
          & FlagCorrelation, &
          & FlagKeyMolAbsOverlap, &
          & StrSpeNcFN, &
          & NBandCur, a_BandCurWNBnds, a_BandCurNBin, &
          & NKeyMol, ab_BandCurKeyMolNum, &
          & NGaussReg, a_GaussRegBnds, &
          & PressForPFSort &
          & )

      end do


      deallocate( a_BandCurWNBnds      )
      deallocate( a_BandCurNBin        )
      deallocate( ab_BandCurKeyMolNum  )

    end do

    deallocate( a_KeyMolNum )

    deallocate( a_BandWNBnds      )
    deallocate( a_BandNBin        )
    deallocate( ab_BandKeyMolNum  )

  end do

  deallocate( a_GaussRegBnds )


  write( 6, * ) "Finish"

#ifdef MPI
  call mpi_finalize( IErr )
#endif

end program main
