ensPostProcess_mod sourceΒΆ

   1module ensPostProcess_mod
   2  ! MODULE ensPostProcess_mod (prefix='epp' category='1. High-level functionality')
   3  !
   4  !:Purpose:  Various routines that are used to modify or process
   5  !           ensembles, usually produced by the LETKF.
   6  !
   7  use midasMpi_mod
   8  use utilities_mod
   9  use mathPhysConstants_mod
  10  use timeCoord_mod
  11  use verticalCoord_mod
  12  use horizontalCoord_mod
  13  use ensembleStateVector_mod
  14  use gridStateVector_mod
  15  use gridStateVectorFileIO_mod
  16  use interpolation_mod
  17  use randomNumber_mod
  18  use controlVector_mod
  19  use gridVariableTransforms_mod
  20  use bMatrix_mod
  21  use humidityLimits_mod
  22  use varNameList_mod
  23  use fileNames_mod
  24  use clibInterfaces_mod
  25  use calcHeightAndPressure_mod
  26  implicit none
  27  save
  28  private
  29
  30  ! public procedures
  31  public :: epp_postProcess
  32  
  33contains
  34
  35  !----------------------------------------------------------------------
  36  ! epp_postProcess
  37  !----------------------------------------------------------------------
  38  subroutine epp_postProcess(ensembleTrl, ensembleAnl, &
  39                             stateVectorHeightSfc, stateVectorCtrlTrl, &
  40                             writeTrlEnsemble, outputOnlyEnsMean_opt)
  41    !
  42    !:Purpose:  Perform numerous post-processing steps to the ensemble
  43    !           produced by the LETKF algorithm.
  44    !
  45    implicit none
  46
  47    ! Arguments:
  48    type(struct_ens),  intent(inout) :: ensembleTrl
  49    type(struct_ens),  intent(inout) :: ensembleAnl
  50    type(struct_gsv),  intent(in)    :: stateVectorHeightSfc
  51    type(struct_gsv),  intent(inout) :: stateVectorCtrlTrl
  52    logical,           intent(in)    :: writeTrlEnsemble
  53    logical, optional, intent(in)    :: outputOnlyEnsMean_opt
  54
  55    ! Locals:
  56    integer                   :: ierr, nEns, dateStamp, datePrint, timePrint, imode, randomSeedRandomPert
  57    integer                   :: stepIndex, middleStepIndex, nulnam
  58    integer, allocatable      :: dateStampListInc(:)
  59    type(struct_hco), pointer :: hco_ens
  60    type(struct_vco), pointer :: vco_ens
  61    type(struct_gsv)          :: stateVectorMeanAnl, stateVectorMeanAnlRaw, stateVectorMeanTrl
  62    type(struct_gsv)          :: stateVectorMeanInc
  63    type(struct_gsv)          :: stateVectorAnalIncMask
  64    type(struct_gsv)          :: stateVectorStdDevAnl, stateVectorStdDevAnlRaw, stateVectorStdDevAnlPert, stateVectorStdDevTrl
  65    type(struct_gsv)          :: stateVectorMeanIncSubSample
  66    type(struct_gsv)          :: stateVectorMeanAnlSubSample
  67    type(struct_gsv)          :: stateVectorMeanAnlSfcPres
  68    type(struct_gsv)          :: stateVectorMeanAnlSfcPresMpiGlb
  69    type(struct_ens)          :: ensembleTrlSubSample
  70    type(struct_ens)          :: ensembleAnlSubSample
  71    type(struct_ens)          :: ensembleAnlSubSampleUnPert
  72    character(len=12)         :: etiket
  73    type(struct_ens)          :: ensembleAnlInc
  74    type(struct_ens)          :: ensembleAnlIncSubSample
  75    character(len=256)        :: outFileName
  76    character(len=4), pointer :: varNames(:)
  77    character(len=12)         :: hInterpolationDegree = 'LINEAR'
  78    integer, external         :: fnom, fclos, newdate
  79    logical                   :: outputOnlyEnsMean
  80
  81    ! Namelist variables
  82    integer  :: randomSeed           ! seed used for random perturbation additive inflation
  83    logical  :: includeYearInSeed    ! switch for choosing to include year in default random seed
  84    logical  :: writeSubSample       ! write sub-sample members for initializing medium-range fcsts
  85    logical  :: writeSubSampleUnPert ! write unperturbed sub-sample members for medium-range fcsts
  86    real(8)  :: alphaRTPS            ! RTPS coefficient (between 0 and 1; 0 means no relaxation)
  87    real(8)  :: alphaRTPP            ! RTPP coefficient (between 0 and 1; 0 means no relaxation)
  88    real(8)  :: alphaRandomPert      ! Random perturbation additive inflation coeff (0->1)
  89    real(8)  :: alphaRandomPertSubSample ! Random pert. additive inflation coeff for medium-range fcsts
  90    logical  :: huLimitsBeforeRecenter   ! Choose to apply humidity limits before recentering
  91    logical  :: imposeSaturationLimit  ! switch for choosing to impose saturation limit of humidity
  92    logical  :: imposeRttovHuLimits    ! switch for choosing to impose the RTTOV limits on humidity
  93    real(8)  :: weightRecenter(vco_maxNumLevels)  ! weight applied to recentering increment (between 0 and 1; 0 means no recentering)
  94    real(8)  :: weightRecenterLand     ! weight applied to recentering increment for land variables
  95    integer  :: numMembersToRecenter   ! number of members that get recentered on supplied analysis
  96    logical  :: useOptionTableRecenter ! use values in the optiontable file
  97    character(len=8)  :: etiket_anl ! etiket for ensemble output files (member number will be appended)
  98    character(len=8)  :: etiket_inc ! etiket for ensemble output files (member number will be appended)
  99    character(len=8)  :: etiket_trl ! etiket for ensemble output files (member number will be appended)
 100    character(len=12) :: etiket_anlmean ! etiket for mean of analyses and mean of increments files
 101    character(len=12) :: etiket_anlrms  ! etiket for rms of analyses files
 102    character(len=12) :: etiket_anlmean_raw ! etiket for mean of raw analyses
 103    character(len=12) :: etiket_anlrms_raw  ! etiket for rms of raw analyses
 104    character(len=12) :: etiket_anlmeanpert ! etiket for mean of perturbed analyses
 105    character(len=12) :: etiket_anlrmspert  ! etiket for rms of perturbed analyses
 106    character(len=12) :: etiket_trlmean     ! etiket for mean of trials
 107    character(len=12) :: etiket_trlrms      ! etiket for rms of trials
 108    integer  :: numBits ! number of bits when writing ensemble mean and spread
 109    logical  :: useAnalIncMask        ! mask out the increment on the pilot zone
 110    logical  :: writeRawAnalStats     ! write mean and standard deviation of the raw analysis ensemble
 111    logical  :: useMemberAsHuRefState ! use each member as reference state for variable transforms 
 112
 113    NAMELIST /namEnsPostProcModule/randomSeed, includeYearInSeed, writeSubSample, writeSubSampleUnPert,  &
 114                                   alphaRTPS, alphaRTPP, alphaRandomPert, alphaRandomPertSubSample,      &
 115                                   huLimitsBeforeRecenter, imposeSaturationLimit, imposeRttovHuLimits,   &
 116                                   weightRecenter, weightRecenterLand, numMembersToRecenter,  &
 117                                   useOptionTableRecenter,  &
 118                                   etiket_anl, etiket_inc, etiket_trl, etiket_anlmean, etiket_anlrms,    &
 119                                   etiket_anlmeanpert, etiket_anlrmspert,  &
 120                                   etiket_anlmean_raw, etiket_anlrms_raw,  &
 121                                   etiket_trlmean, etiket_trlrms, numBits, useAnalIncMask,  &
 122                                   writeRawAnalStats, useMemberAsHuRefState
 123
 124    if (present(outputOnlyEnsMean_opt)) then
 125      outputOnlyEnsMean = outputOnlyEnsMean_opt
 126    else
 127      outputOnlyEnsMean = .false.
 128    end if
 129
 130    !- Extract the grid definitions and ensemble size
 131    if (ens_isAllocated(ensembleTrl)) then
 132      hco_ens => ens_getHco(ensembleTrl)
 133      vco_ens => ens_getVco(ensembleTrl)
 134      nEns = ens_getNumMembers(ensembleTrl)
 135    else
 136      hco_ens => ens_getHco(ensembleAnl)
 137      vco_ens => ens_getVco(ensembleAnl)
 138      nEns = ens_getNumMembers(ensembleAnl)
 139    end if
 140
 141    !- Setting default namelist variable values
 142    randomSeed            =  -999
 143    includeYearInSeed     = .false.
 144    writeSubSample        = .false.
 145    writeSubSampleUnPert  = .false.
 146    alphaRTPS             =  0.0D0
 147    alphaRTPP             =  0.0D0
 148    alphaRandomPert       =  0.0D0
 149    alphaRandomPertSubSample =  -1.0D0
 150    huLimitsBeforeRecenter = .true.
 151    imposeSaturationLimit = .false.
 152    imposeRttovHuLimits   = .false.
 153    weightRecenter(:)     = -1.0D0 ! means no specified values
 154    weightRecenterLand    = -1.0D0 ! means same recentering for land as other variables
 155    numMembersToRecenter  = -1     ! means all members recentered by default
 156    useOptionTableRecenter = .false.
 157    ! For the next 3 variables, the member number will be appended to this string
 158    ! for files '${trialdate}_006_${member}'
 159    etiket_trl = 'E27_0_0P'
 160    ! for files '${analdate}_000_${member}', 'subspace/${analdate}_000_${member}' and 'subspace_unpert/${analdate}_000_${member}'
 161    ! the member=0000 will contain the mean analysis
 162    etiket_anl = 'E27_0_0P'
 163    ! for files '${analdate}_000_inc_${member}' and 'subspace/${analdate}_000_inc_${member}'
 164    ! the member=0000 will contain the mean increment
 165    etiket_inc = 'E27_0_0P'
 166    !
 167    etiket_anlmean = 'E27_0_0PAVG' ! for file '${analdate}_000_analmean'
 168    etiket_anlrms = 'E27_0_0PRMS'  ! for file '${analdate}_000_analrms'
 169    etiket_anlmeanpert = 'E27_0_0PAVGP'  ! for file '${analdate}_000_analpertmean'
 170    etiket_anlrmspert = 'E27_0_0PRMSP'  ! for file '${analdate}_000_analpertrms'
 171    etiket_anlmean_raw = 'E27_0_0PAVGR'  ! for file '${analdate}_000_analmean_raw'
 172    etiket_anlrms_raw = 'E27_0_0PRMSR'  ! for file '${analdate}_000_analrms_raw'
 173    etiket_trlmean = 'E27_0_0PAVG' ! for file '${trialdate}_006_trialmean'
 174    etiket_trlrms = 'E27_0_0PRMS' ! for file '${trialdate}_006_trialrms'
 175    !
 176    numBits = 16
 177    useAnalIncMask = .false.
 178    writeRawAnalStats = .false.
 179    useMemberAsHuRefState = .false.
 180
 181    !- Read the namelist
 182    nulnam = 0
 183    ierr = fnom(nulnam, './flnml', 'FTN+SEQ+R/O', 0)
 184    read(nulnam, nml=namEnsPostProcModule, iostat=ierr)
 185    if ( ierr /= 0) call utl_abort('epp_postProc: Error reading namelist')
 186    if ( mmpi_myid == 0 ) write(*,nml=namEnsPostProcModule)
 187    ierr = fclos(nulnam)
 188
 189    if (alphaRTPS < 0.0D0) alphaRTPS = 0.0D0
 190    if (alphaRTPP < 0.0D0) alphaRTPP = 0.0D0
 191    if (alphaRandomPert < 0.0D0) alphaRandomPert = 0.0D0
 192    if (alphaRandomPertSubSample < 0.0D0) alphaRandomPertSubSample = 0.0D0
 193    if (numMembersToRecenter == -1) numMembersToRecenter = nEns ! default behaviour
 194
 195    if (writeSubSample) then
 196      if (.not.(ens_isAllocated(ensembleTrl).and.ens_isAllocated(ensembleAnl))) then
 197        call utl_abort('epp_postProc: subSample can only be produced if both Anl and Trl ensembles available')
 198      end if
 199    end if
 200
 201    if (writeSubSampleUnPert) then
 202      if (.not.ens_isAllocated(ensembleAnl)) then
 203        call utl_abort('epp_postProc: subSampleUnPert can only be produced if Anl ensemble available')
 204      end if
 205    end if
 206
 207    if (writeRawAnalStats) then
 208      if (.not.ens_isAllocated(ensembleAnl)) then
 209        call utl_abort('epp_postProc: RawAnalStats can only be produced if Anl ensemble available')
 210      end if
 211    end if
 212
 213    if (ens_isAllocated(ensembleTrl)) then
 214      !- Allocate and compute ensemble mean Trl
 215      call gsv_allocate( stateVectorMeanTrl, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 216                         mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 217                         dataKind_opt=4, allocHeightSfc_opt=.true., &
 218                         hInterpolateDegree_opt = hInterpolationDegree, &
 219                         allocHeight_opt=.false., allocPressure_opt=.false. )
 220      call gsv_zero(stateVectorMeanTrl)
 221      call ens_computeMean(ensembleTrl)
 222      call ens_copyEnsMean(ensembleTrl, stateVectorMeanTrl)
 223      
 224      !- Allocate and compute ensemble spread stddev Trl
 225      call gsv_allocate( stateVectorStdDevTrl, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 226                         mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 227                         hInterpolateDegree_opt = hInterpolationDegree, &
 228                         dataKind_opt=4, allocHeight_opt=.false., allocPressure_opt=.false. )
 229      call gsv_zero(stateVectorStdDevTrl)
 230      call ens_computeStdDev(ensembleTrl)
 231      call ens_copyEnsStdDev(ensembleTrl, stateVectorStdDevTrl)
 232    end if
 233
 234    if (ens_isAllocated(ensembleAnl)) then
 235      !- Allocate and compute ensemble mean Anl
 236      call gsv_allocate( stateVectorMeanAnl, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 237                         mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 238                         dataKind_opt=4, allocHeightSfc_opt=.true., &
 239                         hInterpolateDegree_opt = hInterpolationDegree, &
 240                         allocHeight_opt=.false., allocPressure_opt=.false. )
 241      call gsv_zero(stateVectorMeanAnl)
 242      call ens_computeMean(ensembleAnl)
 243      call ens_copyEnsMean(ensembleAnl, stateVectorMeanAnl)
 244
 245      !- Allocate and compute ensemble spread stddev Anl
 246      call gsv_allocate( stateVectorStdDevAnl, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 247                         mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 248                         hInterpolateDegree_opt = hInterpolationDegree, &
 249                         dataKind_opt=4, allocHeight_opt=.false., allocPressure_opt=.false. )
 250      call gsv_zero(stateVectorStdDevAnl)
 251      call ens_computeStdDev(ensembleAnl)
 252      call ens_copyEnsStdDev(ensembleAnl, stateVectorStdDevAnl)
 253
 254      !- Keep the mean and standard deviation of the raw analysis for outputs, if requested
 255      if (writeRawAnalStats) then
 256        call gsv_allocate( stateVectorMeanAnlRaw, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 257                           mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 258                           dataKind_opt=4, allocHeightSfc_opt=.true., &
 259                           hInterpolateDegree_opt = hInterpolationDegree, &
 260                           allocHeight_opt=.false., allocPressure_opt=.false. )
 261        call gsv_allocate( stateVectorStdDevAnlRaw, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 262                           mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 263                           hInterpolateDegree_opt = hInterpolationDegree, &
 264                           dataKind_opt=4, allocHeight_opt=.false., allocPressure_opt=.false. )
 265        call gsv_copy(stateVectorMeanAnl, stateVectorMeanAnlRaw)
 266        call gsv_copy(stateVectorStdDevAnl, stateVectorStdDevAnlRaw)
 267      end if
 268
 269      if (ens_isAllocated(ensembleTrl)) then
 270        !- Apply RTPP, if requested
 271        if (alphaRTPP > 0.0D0) then
 272          call epp_RTPP(ensembleAnl, ensembleTrl, stateVectorMeanAnl, &
 273                        stateVectorMeanTrl, alphaRTPP)
 274          ! recompute the analysis spread stddev
 275          call ens_computeStdDev(ensembleAnl)
 276          call ens_copyEnsStdDev(ensembleAnl, stateVectorStdDevAnl)
 277        end if
 278
 279        !- Apply RTPS, if requested
 280        if (alphaRTPS > 0.0D0) then
 281          call epp_RTPS(ensembleAnl, stateVectorStdDevAnl, stateVectorStdDevTrl, &
 282                        stateVectorMeanAnl, alphaRTPS)
 283          ! recompute the analysis spread stddev
 284          call ens_computeStdDev(ensembleAnl)
 285          call ens_copyEnsStdDev(ensembleAnl, stateVectorStdDevAnl)
 286        end if
 287      end if
 288
 289      !- Impose limits on humidity *before* recentering, if requested
 290      if (huLimitsBeforeRecenter) then
 291        if (imposeSaturationLimit .or. imposeRttovHuLimits) then
 292          if (mmpi_myid == 0) write(*,*) ''
 293          if (mmpi_myid == 0) write(*,*) 'epp_postProcess: limits will be imposed on the humidity of analysis ensemble'
 294          if (mmpi_myid == 0 .and. imposeSaturationLimit ) write(*,*) '              -> Saturation Limit'
 295          if (mmpi_myid == 0 .and. imposeRttovHuLimits   ) write(*,*) '              -> Rttov Limit'
 296          if ( imposeSaturationLimit ) call qlim_saturationLimit(ensembleAnl)
 297          if ( imposeRttovHuLimits   ) call qlim_rttovLimit     (ensembleAnl)
 298          ! And recompute analysis mean
 299          call ens_computeMean(ensembleAnl)
 300          call ens_copyEnsMean(ensembleAnl, stateVectorMeanAnl)
 301        end if
 302      end if
 303
 304      !- Recenter analysis ensemble on supplied analysis
 305      if (any(weightRecenter(:) >= 0.0d0) .or. useOptionTableRecenter) then
 306        write(*,*) 'epp_postProcess: Recenter analyses on supplied analysis'
 307        call epp_hybridRecentering(ensembleAnl, weightRecenter, weightRecenterLand, &
 308                                   useOptionTableRecenter, numMembersToRecenter)
 309        ! And recompute analysis mean
 310        call ens_computeMean(ensembleAnl)
 311        call ens_copyEnsMean(ensembleAnl, stateVectorMeanAnl)
 312        ! And recompute the analysis spread stddev
 313        call ens_computeStdDev(ensembleAnl)
 314        call ens_copyEnsStdDev(ensembleAnl, stateVectorStdDevAnl)
 315      end if
 316
 317      !- Impose limits on humidity *after* recentering, if requested
 318      if (.not.huLimitsBeforeRecenter) then
 319        if (imposeSaturationLimit .or. imposeRttovHuLimits) then
 320          if (mmpi_myid == 0) write(*,*) ''
 321          if (mmpi_myid == 0) write(*,*) 'epp_postProcess: limits will be imposed on the humidity of analysis ensemble'
 322          if (mmpi_myid == 0 .and. imposeSaturationLimit ) write(*,*) '              -> Saturation Limit'
 323          if (mmpi_myid == 0 .and. imposeRttovHuLimits   ) write(*,*) '              -> Rttov Limit'
 324          if ( imposeSaturationLimit ) call qlim_saturationLimit(ensembleAnl)
 325          if ( imposeRttovHuLimits   ) call qlim_rttovLimit     (ensembleAnl)
 326          ! And recompute analysis mean
 327          call ens_computeMean(ensembleAnl)
 328          call ens_copyEnsMean(ensembleAnl, stateVectorMeanAnl)
 329        end if
 330      end if
 331
 332      !- If SubSample requested, copy sub-sample of analysis and trial members
 333      if (writeSubSample) then
 334        ! Copy sub-sampled analysis and trial ensemble members
 335        call epp_selectSubSample(ensembleAnl, ensembleAnlSubSample,  &
 336                                 ensembleTrl, ensembleTrlSubSample)
 337
 338        ! Create subdirectory for outputting sub sample increments
 339        ierr = clib_mkdir_r('subspace')
 340
 341        ! Allocate stateVectors to store and output sub-sampled ensemble mean analysis
 342        call gsv_allocate( stateVectorMeanAnlSubSample, tim_nstepobsinc,  &
 343                           hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 344                           mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 345                           dataKind_opt=4, allocHeightSfc_opt=.true., &
 346                           hInterpolateDegree_opt = hInterpolationDegree, &
 347                           allocHeight_opt=.false., allocPressure_opt=.false. )
 348        call gsv_zero(stateVectorMeanAnlSubSample)
 349
 350      end if
 351
 352      !- If unperturbed SubSample requested, copy sub-sample of analysis members
 353      if (writeSubSampleUnPert) then
 354        ! Copy sub-sampled analysis ensemble members
 355        call epp_selectSubSample(ensembleAnl, ensembleAnlSubSampleUnPert)
 356
 357        ! Create subdirectory for outputting sub sample members without perturbations
 358        ierr = clib_mkdir_r('subspace_unpert')
 359
 360      end if
 361
 362      !- Apply random additive inflation, if requested
 363      if (alphaRandomPert > 0.0D0) then
 364        ! If namelist value is -999, set random seed using the date (as in standard EnKF)
 365        if (randomSeed == -999) then
 366          imode = -3 ! stamp to printable date and time: YYYYMMDD, HHMMSShh
 367          dateStamp = tim_getDateStamp()
 368          ierr = newdate(dateStamp, datePrint, timePrint, imode)
 369          timePrint = timePrint/1000000
 370          datePrint =  datePrint*100 + timePrint
 371          if (includeYearInSeed) then
 372            ! Remove the century, keeping 2 digits of the year
 373            randomSeedRandomPert = datePrint - 100000000*(datePrint/100000000)
 374          else
 375            ! Remove the year and add 9
 376            randomSeedRandomPert = 9 + datePrint - 1000000*(datePrint/1000000)
 377          end if
 378        else
 379          randomSeedRandomPert = randomSeed
 380        end if
 381        write(*,*) 'epp_postProcess: randomSeed for additive inflation set to ', &
 382             randomSeedRandomPert
 383        if (ens_isAllocated(ensembleTrl)) then
 384          call epp_addRandomPert(ensembleAnl, stateVectorMeanTrl, alphaRandomPert, &
 385               randomSeedRandomPert, useMemberAsHuRefState)
 386        else
 387          call epp_addRandomPert(ensembleAnl, stateVectorMeanAnl, alphaRandomPert, &
 388               randomSeedRandomPert, useMemberAsHuRefState)
 389        end if
 390      end if
 391
 392      !- Recompute the analysis spread stddev after inflation and humidity limits
 393      call gsv_allocate( stateVectorStdDevAnlPert, tim_nstepobsinc, hco_ens, vco_ens, &
 394                         dateStamp_opt=tim_getDateStamp(),  &
 395                         mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 396                         hInterpolateDegree_opt = hInterpolationDegree, &
 397                         dataKind_opt=4, allocHeight_opt=.false., &
 398                         allocPressure_opt=.false. )
 399      call ens_computeStdDev(ensembleAnl)
 400      call ens_copyEnsStdDev(ensembleAnl, stateVectorStdDevAnlPert)
 401
 402      !- If SubSample requested, do remaining processing and output of sub-sampled members
 403      if (writeSubSample) then
 404
 405        ! Apply random additive inflation to sub-sampled ensemble, if requested
 406        if (alphaRandomPertSubSample > 0.0D0) then
 407          ! If namelist value is -999, set random seed using the date (as in standard EnKF)
 408          if (randomSeed == -999) then
 409            imode = -3 ! stamp to printable date and time: YYYYMMDD, HHMMSShh
 410            dateStamp = tim_getDateStamp()
 411            ierr = newdate(dateStamp, datePrint, timePrint, imode)
 412            timePrint = timePrint/1000000
 413            datePrint =  datePrint*100 + timePrint
 414            if (includeYearInSeed) then
 415              ! Remove the century, keeping 2 digits of the year
 416              randomSeedRandomPert = datePrint - 100000000*(datePrint/100000000)
 417            else
 418              ! Remove the year and add 9
 419              randomSeedRandomPert = 9 + datePrint - 1000000*(datePrint/1000000)
 420            end if
 421          else
 422            randomSeedRandomPert = randomSeed
 423          end if
 424          write(*,*) 'epp_postProcess: randomSeed for additive inflation set to ', &
 425               randomSeedRandomPert
 426          call epp_addRandomPert(ensembleAnlSubSample, stateVectorMeanTrl,  &
 427                                 alphaRandomPertSubSample, randomSeedRandomPert, &
 428                                 useMemberAsHuRefState)
 429        end if
 430
 431        ! Compute analysis mean of sub-sampled ensemble
 432        call ens_computeMean(ensembleAnlSubSample)
 433
 434        ! Shift members to have same mean as full ensemble
 435        call ens_recenter(ensembleAnlSubSample, stateVectorMeanAnl,  &
 436                          recenteringCoeffScalar_opt=1.0D0)
 437
 438        ! Re-compute analysis mean of sub-sampled ensemble
 439        call ens_computeMean(ensembleAnlSubSample)
 440        call ens_copyEnsMean(ensembleAnlSubSample, stateVectorMeanAnlSubSample)
 441        
 442      end if ! writeSubsample
 443
 444      !- If SubSample requested, do remaining processing and output of sub-sampled members
 445      if (writeSubSampleUnPert) then
 446
 447        ! Compute analysis mean of sub-sampled ensemble
 448        call ens_computeMean(ensembleAnlSubSampleUnPert)
 449
 450        ! Shift members to have same mean as full ensemble
 451        call ens_recenter(ensembleAnlSubSampleUnPert, stateVectorMeanAnl,  &
 452                          recenteringCoeffScalar_opt=1.0D0)
 453
 454      end if
 455
 456    end if ! ens_isAllocated(ensembleAnl)
 457
 458    !
 459    !- Transform data before computing the increments and writing to files.
 460    !
 461    if (ens_isAllocated(ensembleAnl)) then
 462      call gvt_transform(ensembleAnl,'AllTransformedToModel',allowOverWrite_opt=.true.)
 463      call gvt_transform(stateVectorMeanAnl,'AllTransformedToModel',allowOverWrite_opt=.true.)
 464      if (writeSubSample) then
 465        call gvt_transform(ensembleAnlSubSample,'AllTransformedToModel',allowOverWrite_opt=.true.)
 466        call gvt_transform(stateVectorMeanAnlSubSample,'AllTransformedToModel',allowOverWrite_opt=.true.)
 467      end if
 468      if (writeSubSampleUnPert) then
 469        call gvt_transform(ensembleAnlSubSampleUnPert,'AllTransformedToModel',allowOverWrite_opt=.true.)
 470      end if
 471    end if
 472
 473    ! When we read ensemble trials we always need to transform them either for incremnets or for writing
 474    if (ens_isAllocated(ensembleTrl)) then
 475      call gvt_transform(ensembleTrl,'AllTransformedToModel',allowOverWrite_opt=.true.)
 476      call gvt_transform(stateVectorCtrlTrl,'AllTransformedToModel',allowOverWrite_opt=.true.)
 477      call gvt_transform(stateVectorMeanTrl,'AllTransformedToModel',allowOverWrite_opt=.true.)
 478      if (writeSubSample) then
 479        call gvt_transform(ensembleTrlSubSample,'AllTransformedToModel',allowOverWrite_opt=.true.)
 480      end if
 481    end if
 482
 483    !
 484    !- Compute increments
 485    !
 486    if (ens_isAllocated(ensembleAnl).and.ens_isAllocated(ensembleTrl)) then
 487
 488      !- Read the analysis mask (in LAM mode only) - N.B. different from land/sea mask!!!
 489      if (.not. hco_ens%global .and. useAnalIncMask) then
 490        call gio_getMaskLAM(stateVectorAnalIncMask, hco_ens, vco_ens, hInterpolationDegree)
 491      end if
 492
 493      ! initialize the vector for the ensemble increment
 494      allocate(dateStampListInc(tim_nstepobsinc))
 495      call tim_getstamplist(dateStampListInc,tim_nstepobsinc,tim_getDatestamp())
 496      nullify(varNames)
 497      call ens_varNamesList(varNames,ensembleTrl)
 498      call ens_allocate(ensembleAnlInc, nEns, tim_nstepobsinc, hco_ens, vco_ens, &
 499                        dateStampListInc, varNames_opt=varNames)
 500      call ens_copy(ensembleTrl,ensembleAnlInc)
 501      deallocate(varNames)
 502
 503      ! Compute the ensemble increments
 504      call ens_add(ensembleAnl, ensembleAnlInc, scaleFactorInOut_opt=-1.0D0)
 505      
 506      !- Mask the ensemble increments for LAM grid and recompute ensemble analysis
 507      if (.not. hco_ens%global .and. useAnalIncMask) then
 508        call ens_applyMaskLAM(ensembleAnlInc, stateVectorAnalIncMask)
 509        call ens_copy(ensembleAnlInc,ensembleAnl)
 510        call ens_add(ensembleTrl,ensembleAnl)
 511      end if
 512
 513      ! Compute mean increment for converted model variables (e.g. VIS and PR)
 514      nullify(varNames)
 515      call gsv_varNamesList(varNames, stateVectorMeanAnl)
 516      call gsv_allocate( stateVectorMeanInc, tim_nstepobsinc, hco_ens, vco_ens, &
 517                         dateStamp_opt=tim_getDateStamp(),  &
 518                         mpi_local_opt=.true., mpi_distribution_opt='Tiles',  &
 519                         hInterpolateDegree_opt = hInterpolationDegree, &
 520                         dataKind_opt=4, allocHeightSfc_opt=.true., varNames_opt=varNames )
 521      call gsv_copy(stateVectorMeanAnl, stateVectorMeanInc)
 522      deallocate(varNames)
 523
 524      call gsv_add(stateVectorCtrlTrl, stateVectorMeanInc, scaleFactor_opt=-1.0D0)
 525
 526      !- Mask the mean increment for LAM grid and recompute the mean analysis
 527      if (.not. hco_ens%global .and. useAnalIncMask) then
 528        call gsv_applyMaskLAM(stateVectorMeanInc, stateVectorAnalIncMask)
 529        call gsv_copy(stateVectorMeanInc,stateVectorMeanAnl)
 530        call gsv_add(stateVectorCtrlTrl,stateVectorMeanAnl)
 531      end if
 532
 533      ! If subsample reqested compute the subsample increments
 534      if (writeSubSample) then
 535        ! Compute ensemble increments for subsample
 536        nullify(varNames)
 537        call ens_varNamesList(varNames,ensembleAnlSubSample)
 538        call ens_allocate(ensembleAnlIncSubSample, ens_getNumMembers(ensembleAnlSubSample), &
 539                          tim_nstepobsinc, hco_ens, vco_ens, dateStampListInc, varNames_opt=varNames)
 540        call ens_copy(ensembleTrlSubSample,ensembleAnlIncSubSample)
 541        deallocate(varNames)
 542        
 543        call ens_add(ensembleAnlSubSample,ensembleAnlIncSubSample,scaleFactorInOut_opt=-1.0D0)
 544
 545        !- Mask the ensemble increment for LAM grid and recompute the mean analysis
 546        if (.not. hco_ens%global .and. useAnalIncMask) then
 547          call ens_applyMaskLAM(ensembleAnlIncSubSample, stateVectorAnalIncMask)
 548          call ens_copy(ensembleAnlIncSubSample,ensembleAnlSubSample)
 549          call ens_add(ensembleTrlSubSample,ensembleAnlSubSample)
 550        end if
 551
 552        ! Compute mean increment with respect to mean of full trial ensemble
 553        nullify(varNames)
 554        call gsv_varNamesList(varNames, stateVectorMeanAnlSubSample)
 555        call gsv_allocate( stateVectorMeanIncSubSample, tim_nstepobsinc,  &
 556                           hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
 557                           mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 558                           dataKind_opt=4, allocHeightSfc_opt=.true., &
 559                           hInterpolateDegree_opt = hInterpolationDegree, &
 560!                           allocHeight_opt=.false., allocPressure_opt=.false., &
 561                           varNames_opt=varNames )
 562        call gsv_copy(stateVectorMeanAnlSubSample, stateVectorMeanIncSubSample)
 563        deallocate(varNames)
 564
 565        call gsv_add(stateVectorCtrlTrl, stateVectorMeanIncSubSample, scaleFactor_opt=-1.0D0)
 566
 567        !- Mask the mean increment for LAM grid and recompute the mean analysis
 568        if (.not. hco_ens%global .and. useAnalIncMask) then
 569          call gsv_applyMaskLAM(stateVectorMeanIncSubSample, stateVectorAnalIncMask)
 570          call gsv_copy(stateVectorMeanIncSubSample,stateVectorMeanAnlSubSample)
 571          call gsv_add(stateVectorCtrlTrl,stateVectorMeanAnlSubSample)
 572        end if
 573      end if
 574
 575    end if !- end of increment computation
 576
 577    !
 578    !- Output everything
 579    !
 580
 581    !- Output ens stddev and mean in trialrms, analrms and analpertrms files
 582
 583    ! determine middle timestep for output of these files
 584    middleStepIndex = (tim_nstepobsinc + 1) / 2
 585
 586    if (ens_isAllocated(ensembleTrl)) then
 587      ! output trialmean, trialrms
 588      call utl_tmg_start(5,'--WriteEnsMeanRms')
 589      call fln_ensTrlFileName(outFileName, '.', tim_getDateStamp())
 590      outFileName = trim(outFileName) // '_trialmean'
 591      call ens_copyMaskToGsv(ensembleTrl, stateVectorMeanTrl)
 592      do stepIndex = 1, tim_nstepobsinc
 593        call gio_writeToFile(stateVectorMeanTrl, outFileName, etiket_trlmean,  &
 594                             typvar_opt='P', writeHeightSfc_opt=.false., numBits_opt=numBits,  &
 595                             stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 596      end do
 597      call fln_ensTrlFileName(outFileName, '.', tim_getDateStamp())
 598      outFileName = trim(outFileName) // '_trialrms'
 599      call ens_copyMaskToGsv(ensembleTrl, stateVectorStdDevTrl)
 600      call gio_writeToFile(stateVectorStdDevTrl, outFileName, etiket_trlrms,  &
 601                           typvar_opt='P', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 602                           stepIndex_opt=middleStepIndex, containsFullField_opt=.false.)
 603      outFileName = trim(outFileName) // '_ascii'
 604      call epp_printRmsStats(stateVectorStdDevTrl,outFileName,elapsed=0.0D0,ftype='F',nEns=nEns)
 605      call utl_tmg_stop(5)
 606
 607      ! output the trial ensemble if requested (because it was interpolated)
 608      if (writeTrlEnsemble) then
 609        call utl_tmg_start(3,'--WriteEnsemble')
 610        if (.not. outputOnlyEnsMean) then
 611          call ens_writeEnsemble(ensembleTrl, '.', '', etiket_trl, 'P',  &
 612                                 numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 613                                 containsFullField_opt=.true.)
 614        end if
 615        call utl_tmg_stop(3)
 616      end if
 617    end if
 618
 619    ! all outputs related to analysis ensemble
 620    if (ens_isAllocated(ensembleAnl)) then
 621
 622      !- Prepare stateVector with only MeanAnl surface pressure and surface height
 623      if (gsv_isAllocated(stateVectorHeightSfc)) then
 624        call gsv_allocate( stateVectorMeanAnlSfcPres, tim_nstepobsinc, hco_ens, vco_ens,   &
 625                           dateStamp_opt=tim_getDateStamp(),  &
 626                           mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
 627                           hInterpolateDegree_opt = hInterpolationDegree, &
 628                           dataKind_opt=4, allocHeightSfc_opt=.true., varNames_opt=(/'P0'/) )
 629        call gsv_zero(stateVectorMeanAnlSfcPres)
 630        if (mmpi_myid <= (nEns-1)) then
 631          call gsv_allocate( stateVectorMeanAnlSfcPresMpiGlb, tim_nstepobsinc, hco_ens, vco_ens,   &
 632                             dateStamp_opt=tim_getDateStamp(),  &
 633                             mpi_local_opt=.false., &
 634                             hInterpolateDegree_opt = hInterpolationDegree, &
 635                             dataKind_opt=4, allocHeightSfc_opt=.true., varNames_opt=(/'P0'/) )
 636          call gsv_zero(stateVectorMeanAnlSfcPresMpiGlb)
 637        end if
 638        call gsv_copy(stateVectorMeanAnl, stateVectorMeanAnlSfcPres, allowVarMismatch_opt=.true.)
 639        call gsv_copyHeightSfc(stateVectorHeightSfc, stateVectorMeanAnlSfcPres)
 640        call gsv_transposeTilesToMpiGlobal(stateVectorMeanAnlSfcPresMpiGlb, stateVectorMeanAnlSfcPres)
 641      end if
 642      
 643      ! output analmean, analrms
 644      call utl_tmg_start(5,'--WriteEnsMeanRms')
 645      call fln_ensAnlFileName(outFileName, '.', tim_getDateStamp())
 646      outFileName = trim(outFileName) // '_analmean'
 647      call ens_copyMaskToGsv(ensembleAnl, stateVectorMeanAnl)
 648      do stepIndex = 1, tim_nstepobsinc
 649        call gio_writeToFile(stateVectorMeanAnl, outFileName, etiket_anlmean,  &
 650                             typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 651                             stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 652      end do
 653      call fln_ensAnlFileName(outFileName, '.', tim_getDateStamp())
 654      outFileName = trim(outFileName) // '_analrms'
 655      call ens_copyMaskToGsv(ensembleAnl, stateVectorStdDevAnl)
 656      call gio_writeToFile(stateVectorStdDevAnl, outFileName, etiket_anlrms,  &
 657                           typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 658                           stepIndex_opt=middleStepIndex, containsFullField_opt=.false.)
 659      outFileName = trim(outFileName) // '_ascii'
 660      call epp_printRmsStats(stateVectorStdDevAnl,outFileName,elapsed=0.0D0,ftype='A',nEns=nEns)
 661
 662      ! output analmean_raw and analrms_raw, if requested
 663      if (writeRawAnalStats) then
 664        call fln_ensAnlFileName(outFileName, '.', tim_getDateStamp())
 665        outFileName = trim(outFileName) // '_analmean_raw'
 666        call ens_copyMaskToGsv(ensembleAnl, stateVectorMeanAnlRaw)
 667        do stepIndex = 1, tim_nstepobsinc
 668          call gio_writeToFile(stateVectorMeanAnlRaw, outFileName, etiket_anlmean_raw,  &
 669                               typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 670                               stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 671        end do
 672        call fln_ensAnlFileName(outFileName, '.', tim_getDateStamp())
 673        outFileName = trim(outFileName) // '_analrms_raw'
 674        call ens_copyMaskToGsv(ensembleAnl, stateVectorStdDevAnl)
 675        call gio_writeToFile(stateVectorStdDevAnlRaw, outFileName, etiket_anlrms_raw,  &
 676                             typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 677                             stepIndex_opt=middleStepIndex, containsFullField_opt=.false.)
 678        outFileName = trim(outFileName) // '_ascii'
 679        call epp_printRmsStats(stateVectorStdDevAnlRaw,outFileName,elapsed=0.0D0,ftype='A',nEns=nEns)
 680      end if  ! writeRawAnalStats
 681
 682      if (alphaRandomPert > 0.0D0) then
 683        ! output analpertmean, analpertrms
 684        call fln_ensAnlFileName( outFileName, '.', tim_getDateStamp() )
 685        outFileName = trim(outFileName) // '_analpertmean'
 686        call ens_copyMaskToGsv(ensembleAnl, stateVectorMeanAnl)
 687        do stepIndex = 1, tim_nstepobsinc
 688          call gio_writeToFile(stateVectorMeanAnl, outFileName, etiket_anlmeanpert,  &
 689                               typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 690                               stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 691        end do
 692        call fln_ensAnlFileName( outFileName, '.', tim_getDateStamp() )
 693        outFileName = trim(outFileName) // '_analpertrms'
 694        call ens_copyMaskToGsv(ensembleAnl, stateVectorStdDevAnlPert)
 695        call gio_writeToFile(stateVectorStdDevAnlPert, outFileName, etiket_anlrmspert,  &
 696                             typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 697                             stepIndex_opt=middleStepIndex, containsFullField_opt=.false.)
 698        outFileName = trim(outFileName) // '_ascii'
 699        call epp_printRmsStats(stateVectorStdDevAnlPert,outFileName,elapsed=0.0D0,ftype='P',nEns=nEns)
 700      end if
 701      call utl_tmg_stop(5)
 702
 703      !- Output the ensemble mean increment (include MeanAnl Psfc) and ensemble increments
 704      if (ens_isAllocated(ensembleTrl)) then
 705        call utl_tmg_start(5,'--WriteEnsMeanRms')
 706        ! output ensemble mean increment
 707        call fln_ensAnlFileName( outFileName, '.', tim_getDateStamp(), 0, ensFileNameSuffix_opt='inc' )
 708        call ens_copyMaskToGsv(ensembleAnl, stateVectorMeanInc)
 709        ! here we assume 4 digits for the ensemble member!!!!
 710        etiket = trim(etiket_inc) // '0000'
 711        do stepIndex = 1, tim_nstepobsinc
 712          call gio_writeToFile(stateVectorMeanInc, outFileName, etiket,  &
 713                               typvar_opt='R', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 714                               stepIndex_opt=stepIndex, containsFullField_opt=.false.)
 715          if (gsv_isAllocated(stateVectorMeanAnlSfcPres)) then
 716            call gio_writeToFile(stateVectorMeanAnlSfcPres, outFileName, etiket,  &
 717                                 typvar_opt='A', writeHeightSfc_opt=.true., &
 718                                 stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 719          end if
 720        end do
 721        call utl_tmg_stop(5)
 722
 723        !- Output all ensemble member increments
 724        call utl_tmg_start(3,'--WriteEnsemble')
 725        if (.not. outputOnlyEnsMean) then
 726          call ens_writeEnsemble(ensembleAnlInc, '.', '', etiket_inc, 'R',  &
 727                                 numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 728                                 containsFullField_opt=.false., resetTimeParams_opt=.true.)
 729          if (gsv_isAllocated(stateVectorMeanAnlSfcPresMpiGlb)) then
 730            ! Also write the reference (analysis) surface pressure to increment files
 731            call epp_writeToAllMembers(stateVectorMeanAnlSfcPresMpiGlb, nEns,  &
 732                                       etiket='ENS_INC', typvar='A', fileNameSuffix='inc',  &
 733                                       ensPath='.')
 734          end if
 735        end if
 736        call utl_tmg_stop(3)
 737
 738      end if ! allocated(ensembleTrl)
 739
 740      ! output ensemble mean analysis state
 741      call utl_tmg_start(5,'--WriteEnsMeanRms')
 742      call fln_ensAnlFileName( outFileName, '.', tim_getDateStamp(), 0 )
 743      call ens_copyMaskToGsv(ensembleAnl, stateVectorMeanAnl)
 744      ! here we assume 4 digits for the ensemble member!!!!
 745      etiket = trim(etiket_anl) // '0000'
 746      do stepIndex = 1, tim_nstepobsinc
 747        call gio_writeToFile(stateVectorMeanAnl, outFileName, etiket,  &
 748                             typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 749                             stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 750      end do
 751      call utl_tmg_stop(5)
 752
 753      !- Output all ensemble member analyses
 754      ! convert transformed to model variables for analysis and trial ensembles
 755      call utl_tmg_start(3,'--WriteEnsemble')
 756      if (.not. outputOnlyEnsMean) then
 757        call ens_writeEnsemble(ensembleAnl, '.', '', etiket_anl, 'A',  &
 758                               numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 759                               containsFullField_opt=.true.)
 760      end if
 761      call utl_tmg_stop(3)
 762
 763      !- Output the sub-sampled ensemble analyses and increments
 764      if (writeSubSample) then
 765        call utl_tmg_start(5,'--WriteEnsMeanRms')
 766        ! Output the ensemble mean increment (include MeanAnl Psfc)
 767        call fln_ensAnlFileName( outFileName, 'subspace', tim_getDateStamp(), 0, ensFileNameSuffix_opt='inc' )
 768        ! here we assume 4 digits for the ensemble member!!!!
 769        etiket = trim(etiket_inc) // '0000'
 770        do stepIndex = 1, tim_nstepobsinc
 771          call gio_writeToFile(stateVectorMeanIncSubSample, outFileName, etiket,  &
 772                               typvar_opt='R', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 773                               stepIndex_opt=stepIndex, containsFullField_opt=.false.)
 774          if (gsv_isAllocated(stateVectorMeanAnlSfcPres)) then
 775            call gio_writeToFile(stateVectorMeanAnlSfcPres, outFileName, etiket,  &
 776                                 typvar_opt='A', writeHeightSfc_opt=.true., &
 777                                 stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 778          end if
 779        end do
 780
 781        ! Output the ensemble mean analysis state
 782        call fln_ensAnlFileName( outFileName, 'subspace', tim_getDateStamp(), 0 )
 783        ! here we assume 4 digits for the ensemble member!!!!
 784        etiket = trim(etiket_anl) // '0000'
 785        do stepIndex = 1, tim_nstepobsinc
 786          call gio_writeToFile(stateVectorMeanAnlSubSample, outFileName, etiket,  &
 787                               typvar_opt='A', writeHeightSfc_opt=.false., numBits_opt=numBits, &
 788                               stepIndex_opt=stepIndex, containsFullField_opt=.true.)
 789        end do
 790        call utl_tmg_stop(5)
 791
 792        ! Output the sub-sampled analysis ensemble members
 793        call utl_tmg_start(3,'--WriteEnsemble')
 794        if (.not. outputOnlyEnsMean) then
 795          call ens_writeEnsemble(ensembleAnlSubSample, 'subspace', '', etiket_anl, 'A',  &
 796                                 numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 797                                 containsFullField_opt=.true.)
 798        end if
 799        call utl_tmg_stop(3)
 800
 801        ! Output the sub-sampled ensemble increments (include MeanAnl Psfc)
 802        call utl_tmg_start(3,'--WriteEnsemble')
 803        if (.not. outputOnlyEnsMean) then
 804          call ens_writeEnsemble(ensembleAnlIncSubSample, 'subspace', '', etiket_inc, 'R',  &
 805                                 numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 806                                 containsFullField_opt=.false., resetTimeParams_opt=.true.)
 807          ! Also write the reference (analysis) surface pressure to increment files
 808          if (gsv_isAllocated(stateVectorMeanAnlSfcPresMpiGlb)) then
 809            call epp_writeToAllMembers(stateVectorMeanAnlSfcPresMpiGlb,  &
 810                                       ens_getNumMembers(ensembleAnlSubSample),  &
 811                                       etiket=etiket_inc, typvar='A', fileNameSuffix='inc',  &
 812                                       ensPath='subspace')
 813          end if
 814        end if
 815        call utl_tmg_stop(3)
 816
 817      end if ! writeSubSample
 818
 819      !- Output the unperturbed sub-sampled ensemble analyses
 820      if (writeSubSampleUnPert) then
 821
 822        ! Output the sub-sampled analysis ensemble members
 823        call utl_tmg_start(3,'--WriteEnsemble')
 824        if (.not. outputOnlyEnsMean) then
 825          call ens_writeEnsemble(ensembleAnlSubSampleUnPert, 'subspace_unpert', '', etiket_anl, 'A',  &
 826                                 numBits_opt=16, etiketAppendMemberNumber_opt=.true.,  &
 827                                 containsFullField_opt=.true.)
 828        end if
 829        call utl_tmg_stop(3)
 830
 831      end if
 832
 833    end if ! ens_isAllocated(ensembleAnl)
 834
 835  end subroutine epp_postProcess
 836
 837  !----------------------------------------------------------------------
 838  ! epp_writeToAllMembers (private subroutine)
 839  !----------------------------------------------------------------------
 840  subroutine epp_writeToAllMembers(stateVector, nEns, etiket, typvar,  &
 841                                    fileNameSuffix, ensPath)
 842    !
 843    !:Purpose:   Write the contents of the supplied stateVector to all
 844    !            ensemble member files in an efficient parallel way.
 845    !
 846    implicit none
 847
 848    ! Arguments:
 849    type(struct_gsv), intent(in) :: stateVector
 850    integer         , intent(in) :: nEns
 851    character(len=*), intent(in) :: etiket
 852    character(len=*), intent(in) :: typvar
 853    character(len=*), intent(in) :: fileNameSuffix
 854    character(len=*), intent(in) :: ensPath
 855
 856    ! Locals:
 857    integer            :: memberIndex, stepIndex, writeFilePE(nEns)
 858    character(len=4)   :: memberIndexStr
 859    character(len=256) :: outFileName
 860
 861    do memberIndex = 1, nEns
 862      writeFilePE(memberIndex) = mod(memberIndex-1, mmpi_nprocs)
 863    end do
 864
 865    do memberIndex = 1, nEns
 866
 867      if (mmpi_myid == writeFilePE(memberIndex)) then
 868
 869        call fln_ensAnlFileName( outFileName, ensPath, tim_getDateStamp(),  &
 870                                 memberIndex, ensFileNameSuffix_opt=fileNameSuffix )
 871        write(memberIndexStr,'(I4.4)') memberIndex
 872
 873        do stepIndex = 1, tim_nstepobsinc
 874          call gio_writeToFile(stateVector, outFileName,  &
 875                               trim(etiket) // memberIndexStr,  &
 876                               typvar_opt=trim(typvar), writeHeightSfc_opt=.true., &
 877                               stepIndex_opt=stepIndex, containsFullField_opt=.true., &
 878                               numBits_opt=16)
 879        end do
 880
 881      end if
 882
 883    end do
 884
 885  end subroutine epp_writeToAllMembers
 886
 887  !--------------------------------------------------------------------------
 888  ! epp_RTPS
 889  !--------------------------------------------------------------------------
 890  subroutine epp_RTPS(ensembleAnl, stateVectorStdDevAnl, stateVectorStdDevTrl, &
 891                      stateVectorMeanAnl, alphaRTPS)
 892    !:Purpose: Apply Relaxation To Prior Spread ensemble inflation according
 893    !           to the factor alphaRTPS (usually between 0 and 1).
 894    implicit none
 895
 896    ! Arguments:
 897    type(struct_ens), intent(inout) :: ensembleAnl
 898    type(struct_gsv), intent(in)    :: stateVectorStdDevAnl
 899    type(struct_gsv), intent(in)    :: stateVectorStdDevTrl
 900    type(struct_gsv), intent(in)    :: stateVectorMeanAnl
 901    real(8)         , intent(in)    :: alphaRTPS
 902
 903    ! Locals:
 904    integer :: varLevIndex, latIndex, lonIndex, stepIndex, memberIndex
 905    integer :: nEns, numVarLev, myLonBeg, myLonEnd, myLatBeg, myLatEnd
 906    real(8) :: factorRTPS
 907    real(4), pointer     :: stdDevTrl_ptr_r4(:,:,:,:), stdDevAnl_ptr_r4(:,:,:,:)
 908    real(4), pointer     :: meanAnl_ptr_r4(:,:,:,:), memberAnl_ptr_r4(:,:,:,:)
 909
 910    write(*,*) 'epp_RTPS: Starting'
 911
 912    call gsv_getField(stateVectorStdDevTrl,stdDevTrl_ptr_r4)
 913    call gsv_getField(stateVectorStdDevAnl,stdDevAnl_ptr_r4)
 914    call gsv_getField(stateVectorMeanAnl,meanAnl_ptr_r4)
 915
 916    nEns = ens_getNumMembers(ensembleAnl)
 917    numVarLev = ens_getNumK(ensembleAnl)
 918    call ens_getLatLonBounds(ensembleAnl, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
 919    do varLevIndex = 1, numVarLev
 920      memberAnl_ptr_r4 => ens_getOneLev_r4(ensembleAnl,varLevIndex)
 921      do latIndex = myLatBeg, myLatEnd
 922        do lonIndex = myLonBeg, myLonEnd
 923          do stepIndex = 1, tim_nstepobsinc
 924            ! compute the inflation factor for RTPS
 925            if ( stdDevAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) > 0.0 ) then
 926              factorRTPS = 1.0D0 + alphaRTPS *  &
 927                           ( stdDevTrl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) -  &
 928                             stdDevAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) ) /  &
 929                           stdDevAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex)
 930            else
 931              factorRTPS = 0.0D0
 932            end if
 933            ! apply the inflation factor to all Anl members (in place)
 934            if (factorRTPS > 0.0D0) then
 935              do memberIndex = 1, nEns
 936                memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) =  &
 937                     factorRTPS *  &
 938                     ( memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) -  &
 939                       meanAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) ) +  &
 940                     meanAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex)
 941              end do ! memberIndex
 942            end if ! factorRTPS > 0
 943          end do ! stepIndex
 944        end do ! lonIndex
 945      end do ! latIndex
 946    end do ! varLevIndex
 947
 948    write(*,*) 'epp_RTPS: Finished'
 949
 950  end subroutine epp_RTPS
 951
 952  !--------------------------------------------------------------------------
 953  ! epp_RTPP
 954  !--------------------------------------------------------------------------
 955  subroutine epp_RTPP(ensembleAnl, ensembleTrl, stateVectorMeanAnl, &
 956                      stateVectorMeanTrl, alphaRTPP)
 957    !:Purpose: Apply Relaxation To Prior Perturbation ensemble inflation according
 958    !           to the factor alphaRTPP (usually between 0 and 1).
 959    implicit none
 960
 961    ! Arguments:
 962    type(struct_ens), intent(inout) :: ensembleAnl
 963    type(struct_ens), intent(inout) :: ensembleTrl
 964    type(struct_gsv), intent(in)    :: stateVectorMeanAnl
 965    type(struct_gsv), intent(in)    :: stateVectorMeanTrl
 966    real(8)         , intent(in)    :: alphaRTPP
 967
 968    ! Locals:
 969    integer :: varLevIndex, latIndex, lonIndex, stepIndex, memberIndex
 970    integer :: nEns, numVarLev, myLonBeg, myLonEnd, myLatBeg, myLatEnd
 971    real(4), pointer     :: meanAnl_ptr_r4(:,:,:,:), meanTrl_ptr_r4(:,:,:,:)
 972    real(4), pointer     :: memberAnl_ptr_r4(:,:,:,:), memberTrl_ptr_r4(:,:,:,:)
 973
 974    write(*,*) 'epp_RTPP: Starting'
 975
 976    call gsv_getField(stateVectorMeanAnl, meanAnl_ptr_r4)
 977    call gsv_getField(stateVectorMeanTrl, meanTrl_ptr_r4)
 978
 979    nEns = ens_getNumMembers(ensembleAnl)
 980    numVarLev = ens_getNumK(ensembleAnl)
 981    call ens_getLatLonBounds(ensembleAnl, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
 982
 983    do varLevIndex = 1, numVarLev
 984      memberAnl_ptr_r4 => ens_getOneLev_r4(ensembleAnl,varLevIndex)
 985      memberTrl_ptr_r4 => ens_getOneLev_r4(ensembleTrl,varLevIndex)
 986      do latIndex = myLatBeg, myLatEnd
 987        do lonIndex = myLonBeg, myLonEnd
 988          do stepIndex = 1, tim_nstepobsinc
 989            ! apply RTPP to all Anl members (in place)
 990            ! member_anl = mean_anl + (1-a)*(member_anl-mean_anl) + a*(member_trl-mean_trl)
 991            do memberIndex = 1, nEns
 992              memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) =  &
 993                   meanAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) + &
 994                   (1.0D0 - alphaRTPP) * &
 995                   ( memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) -  &
 996                     meanAnl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) ) +  &
 997                   alphaRTPP * &
 998                   ( memberTrl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) -  &
 999                     meanTrl_ptr_r4(lonIndex,latIndex,varLevIndex,stepIndex) )
1000            end do ! memberIndex
1001          end do ! stepIndex
1002        end do ! lonIndex
1003      end do ! latIndex
1004    end do ! varLevIndex
1005
1006    write(*,*) 'epp_RTPP: Finished'
1007
1008  end subroutine epp_RTPP
1009
1010  !--------------------------------------------------------------------------
1011  ! epp_addRandomPert
1012  !--------------------------------------------------------------------------
1013  subroutine epp_addRandomPert(ensembleAnl, stateVectorRefState, alphaRandomPert, &
1014                               randomSeed, useMemberAsHuRefState)
1015    !:Purpose: Apply additive inflation using random perturbations from sampling
1016    !           the B matrix as defined by the regular namelist block NAMBHI, NAMBEN, etc.
1017    !           The scale factor alphaRandomPert (usually between 0 and 1) is used
1018    !           to simply multiply the resulting perturbations before adding to the original
1019    !           members. The perturbations have zero ensemble mean.
1020    implicit none
1021
1022    ! Arguments:
1023    type(struct_ens), intent(inout) :: ensembleAnl
1024    type(struct_gsv), intent(in)    :: stateVectorRefState
1025    real(8)         , intent(in)    :: alphaRandomPert
1026    integer         , intent(in)    :: randomSeed
1027    logical         , intent(in)    :: useMemberAsHuRefState
1028
1029    ! Locals:
1030    type(struct_gsv)         :: stateVectorPerturbation
1031    type(struct_gsv)         :: stateVectorPerturbationInterp
1032    type(struct_gsv)         :: stateVectorHuRefState
1033    type(struct_gsv)         :: stateVectorHuRefStateInterp
1034    type(struct_gsv)         :: stateVectorP0Ref
1035    type(struct_vco), pointer :: vco_randomPert, vco_ens
1036    type(struct_hco), pointer :: hco_randomPert, hco_ens, hco_core
1037    character(len=12)  :: etiket
1038    real(8), allocatable :: controlVector_mpiglobal(:), controlVector(:)
1039    real(8), allocatable :: perturbationMean(:,:,:)
1040    real(8), pointer     :: PsfcRef(:,:,:,:)
1041    real(8), pointer     :: perturbation_ptr(:,:,:)
1042    real(4), pointer     :: memberAnl_ptr_r4(:,:,:,:)
1043    integer :: cvIndex, memberIndex, varLevIndex, lonIndex, latIndex, stepIndex
1044    integer :: nEns, numVarLev, myLonBeg, myLonEnd, myLatBeg, myLatEnd, varIndex
1045    integer :: middleStepIndex
1046    logical, save :: firstCall = .true.
1047    character(len=4), pointer :: varNamesWithLQ(:)
1048    character(len=4) :: varName
1049
1050    call utl_tmg_start(4,'--AddEnsRandomPert')
1051
1052    ! Determine middle timestep
1053    middleStepIndex = (tim_nstepobsinc + 1) / 2
1054
1055    ! Get ensemble dimensions
1056    nEns = ens_getNumMembers(ensembleAnl)
1057    numVarLev = ens_getNumK(ensembleAnl)
1058    call ens_getLatLonBounds(ensembleAnl, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
1059    vco_ens => ens_getVco(ensembleAnl)
1060    hco_ens => ens_getHco(ensembleAnl)
1061
1062    ! Define the horiz/vertical coordinate for perturbation calculation
1063    nullify(vco_randomPert)
1064    nullify(hco_randomPert)
1065    call hco_setupFromFile(hco_randomPert, './analysisgrid', 'ANALYSIS', 'Analysis' ) ! IN
1066    if ( hco_randomPert % global ) then
1067      etiket = 'BGCK_STDDEV'
1068    else
1069      etiket = 'STDDEV'
1070    end if
1071    call vco_setupFromFile(vco_randomPert, './bgcov', etiket)
1072
1073    ! Special modification to vco_randomPert if a soil variables is present
1074    if ( vco_getNumLev(vco_ens,'OT','I0') > 0 .or. &
1075         vco_getNumLev(vco_ens,'OT','I1') > 0 ) then
1076      write(*,*)
1077      write(*,*) 'epp_addRandomPert: copying number of levels for land surface variables!' 
1078      write(*,*)
1079      vco_randomPert%nlev_Other(:) = vco_ens%nlev_Other(:)
1080    end if
1081
1082    ! Get list of variable names in the ensemble and modify if necessary
1083    nullify(varNamesWithLQ)
1084    call ens_varNamesList(varNamesWithLQ,ensembleAnl)
1085    if (useMemberAsHuRefState .and. ens_varExist(ensembleAnl,'HU')) then
1086      ! Replace HU with LQ so we can apply the transform directly in this routine
1087      do varIndex = 1, size(varNamesWithLQ)
1088        if (varNamesWithLQ(varIndex) == 'HU') varNamesWithLQ(varIndex) = 'LQ'
1089      end do
1090      if (mmpi_myid == 0) write(*,*) 'epp_addRandomPert: varNamesWithLQ = ', varNamesWithLQ(:)
1091    end if
1092
1093    hco_core => hco_randomPert
1094    if (firstCall) then
1095      call utl_tmg_stop(4) ! stop counter, since Bmat has it's own counters
1096      call bmat_setup(hco_randomPert, hco_core, vco_randomPert)
1097      firstCall = .false.
1098      call utl_tmg_start(4,'--AddEnsRandomPert')
1099    end if
1100    call gvt_setup(hco_randomPert, hco_core, vco_randomPert)
1101
1102    call rng_setup(abs(randomSeed))
1103
1104    allocate(controlVector(cvm_nvadim))
1105    allocate(controlVector_mpiglobal(cvm_nvadim_mpiglobal))
1106    allocate(perturbationMean(myLonBeg:myLonEnd,myLatBeg:myLatEnd,numVarLev))
1107    perturbationMean(:,:,:) = 0.0d0
1108
1109    ! NOTE: The following stateVectors will include LQ instead of HU when
1110    !       useMemberAsHuRefState=true. This results in the perturbations
1111    !       being provided by bmat_sqrtB in terms of LQ, allowing the conversion
1112    !       from LQ to HU to be done within this subroutine using the HU field
1113    !       of each ensemble member.
1114    call gsv_allocate(stateVectorPerturbation, 1, hco_randomPert, vco_randomPert, &
1115                      dateStamp_opt=tim_getDateStamp(), mpi_local_opt=.true., &
1116                      hInterpolateDegree_opt='LINEAR', &
1117                      varNames_opt=varNamesWithLQ)
1118    call gsv_allocate(stateVectorPerturbationInterp, 1, hco_ens, vco_ens, &
1119                      dateStamp_opt=tim_getDateStamp(), mpi_local_opt=.true., &
1120                      hInterpolateDegree_opt='LINEAR', &
1121                      varNames_opt=varNamesWithLQ)
1122    call gsv_getField(stateVectorPerturbationInterp,perturbation_ptr)
1123
1124    ! allocate a minimal reference P0
1125    call gsv_allocate(statevectorP0Ref, 1, hco_ens, vco_randomPert, &
1126                      dateStamp_opt=tim_getDateStamp(), mpi_local_opt=.true., &
1127                      hInterpolateDegree_opt='LINEAR', &
1128                      varNames_opt=(/'P0'/))
1129    call gsv_getField(statevectorP0Ref, PsfcRef, 'P0')
1130    PsfcRef(:,:,:,:) = 100000.0D0
1131
1132
1133    ! prepare the reference state HU field for transforming LQ to HU perturbations
1134    if (ens_varExist(ensembleAnl,'HU')) then
1135      call gsv_allocate(stateVectorHuRefState, 1, hco_ens, vco_ens,   &
1136                        dateStamp_opt=tim_getDateStamp(), mpi_local_opt=.true., &
1137                        allocHeightSfc_opt=.true., hInterpolateDegree_opt='LINEAR', &
1138                        hExtrapolateDegree_opt='MINIMUM', &
1139                        varNames_opt=(/'HU','P0'/) )
1140      if (.not. useMemberAsHuRefState) then
1141        ! use the single provided state as the reference state and interpolate to perturbation grid
1142        call gsv_copy(stateVectorRefState, stateVectorHuRefState, allowVarMismatch_opt=.true.)
1143        call gsv_allocate(stateVectorHuRefStateInterp, 1, hco_randomPert, vco_randomPert,   &
1144                          dateStamp_opt=tim_getDateStamp(), mpi_local_opt=.true., &
1145                          allocHeightSfc_opt=.true., hInterpolateDegree_opt='LINEAR', &
1146                          hExtrapolateDegree_opt='MINIMUM', &
1147                          varNames_opt=(/'HU','P0'/) )
1148        call int_interp_gsv(stateVectorHuRefState, stateVectorHuRefStateInterp)
1149        call gsv_deallocate(stateVectorHuRefState)
1150      end if
1151    end if
1152
1153    do memberIndex = 1, nEns
1154
1155      if( mmpi_myid == 0 ) then
1156        write(*,*) 
1157        write(*,*) 'Computing random perturbation number= ', memberIndex
1158      end if
1159
1160      ! global vector random control vector (independent of mpi topology)
1161      do cvIndex = 1, cvm_nvadim_mpiglobal
1162        controlVector_mpiglobal(cvIndex) = rng_gaussian()
1163      end do
1164      call bmat_reduceToMPILocal( controlVector, controlVector_mpiglobal )
1165
1166      call utl_tmg_stop(4) ! stop counter, since Bmat has it's own counters
1167      if (ens_varExist(ensembleAnl,'HU') .and. .not.useMemberAsHuRefState) then
1168        ! Use supplied reference state for LQ to HU conversion
1169        call bmat_sqrtB(controlVector, cvm_nvadim, &       ! IN
1170                        stateVectorPerturbation,   &       ! OUT
1171                        stateVectorRef_opt=stateVectorHuRefStateInterp) ! IN
1172      else
1173        ! No conversion from LQ to HU done in bmat_sqrtB
1174        call bmat_sqrtB(controlVector, cvm_nvadim, &   ! IN
1175                        stateVectorPerturbation)       ! OUT
1176      end if
1177      call utl_tmg_start(4,'--AddEnsRandomPert')
1178
1179      call int_interp_gsv(stateVectorPerturbation, stateVectorPerturbationInterp, &
1180                          statevectorRef_opt=statevectorP0Ref)
1181
1182      ! If desired, use member itself as reference state for LQ to HU conversion
1183      if (ens_varExist(ensembleAnl,'HU') .and. useMemberAsHuRefState) then
1184        call ens_copyMember(ensembleAnl, stateVectorHuRefState, memberIndex)
1185        call gvt_transform( stateVectorPerturbationInterp,  &          ! INOUT
1186                            'LQtoHU_tlm', &                            ! IN
1187                            stateVectorRef_opt=stateVectorHuRefState ) ! IN
1188      end if
1189
1190      ! scale the perturbation by the specified factor
1191      call gsv_scale(stateVectorPerturbationInterp, alphaRandomPert)
1192
1193      write(*,*) 'epp_addRandomPert: member ', memberIndex, ', perturbation min/maxval = ',  &
1194                 minval(perturbation_ptr), maxval(perturbation_ptr)
1195
1196      do varLevIndex = 1, numVarLev
1197        varName = ens_getVarNameFromK(ensembleAnl,varLevIndex)
1198        memberAnl_ptr_r4 => ens_getOneLev_r4(ensembleAnl,varLevIndex)
1199        do latIndex = myLatBeg, myLatEnd
1200          do lonIndex = myLonBeg, myLonEnd
1201
1202            perturbationMean(lonIndex, latIndex, varLevIndex) =   &
1203                 perturbationMean(lonIndex, latIndex, varLevIndex) +  &
1204                 perturbation_ptr(lonIndex, latIndex, varLevIndex) / real(nEns, 8)
1205
1206            ! Add perturbation to member
1207            do stepIndex = 1, tim_nstepobsinc
1208              memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) =  &
1209                   memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) +  &
1210                   perturbation_ptr(lonIndex, latIndex, varLevIndex)
1211            end do ! stepIndex
1212
1213          end do ! lonIndex
1214        end do ! latIndex
1215      end do ! varLevIndex
1216
1217    end do ! memberIndex
1218
1219    ! remove the ensemble mean of the perturbations
1220    do varLevIndex = 1, numVarLev
1221      memberAnl_ptr_r4 => ens_getOneLev_r4(ensembleAnl,varLevIndex)
1222      do latIndex = myLatBeg, myLatEnd
1223        do lonIndex = myLonBeg, myLonEnd
1224          do stepIndex = 1, tim_nstepobsinc
1225            do memberIndex = 1, nEns
1226              memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) =  &
1227                   memberAnl_ptr_r4(memberIndex,stepIndex,lonIndex,latIndex) -  &
1228                   perturbationMean(lonIndex, latIndex, varLevIndex)
1229            end do ! memberIndex
1230          end do ! stepIndex
1231        end do ! lonIndex
1232      end do ! latIndex
1233    end do ! varLevIndex
1234
1235    deallocate(controlVector)
1236    deallocate(controlVector_mpiglobal)
1237    deallocate(perturbationMean)
1238    call gsv_deallocate(stateVectorPerturbation)
1239    call gsv_deallocate(stateVectorPerturbationInterp)
1240    call gsv_deallocate(stateVectorP0Ref)
1241    if (gsv_isAllocated(stateVectorHuRefStateInterp)) then
1242      call gsv_deallocate(stateVectorHuRefStateInterp)
1243    end if
1244
1245    call utl_tmg_stop(4)
1246
1247  end subroutine epp_addRandomPert
1248
1249  !-----------------------------------------------------------------
1250  ! epp_selectSubSample
1251  !-----------------------------------------------------------------
1252  subroutine epp_selectSubSample(ensembleAnl, ensembleAnlSubSample,  &
1253                                  ensembleTrl_opt, ensembleTrlSubSample_opt)
1254    !:Purpose: Create sub-sampled ensembles of analyses and trials based on
1255    !           the contents of the ascii files 'sampletable' which lists
1256    !           the member indices for the subsample.
1257    implicit none
1258
1259    ! Arguments:
1260    type(struct_ens)          , intent(in)  :: ensembleAnl
1261    type(struct_ens)          , intent(out) :: ensembleAnlSubSample
1262    type(struct_ens), optional, intent(in)  :: ensembleTrl_opt
1263    type(struct_ens), optional, intent(out) :: ensembleTrlSubSample_opt
1264
1265    ! Locals:
1266    type(struct_gsv) :: stateVectorMember
1267    integer :: nulFile, ierr, status, numSubSample
1268    integer :: memberIndex, memberIndexSubSample, memberIndexFull
1269    integer :: memberIndexesSubSample(1000), memberIndexesFull(1000)
1270    integer, allocatable :: dateStampListInc(:)
1271    integer, external :: fnom, fclos
1272
1273    numSubSample = 0
1274
1275    nulFile = 0
1276    ierr = fnom(nulFile, './sampletable', 'FTN+SEQ+R/O', 0)
1277    do
1278      read(nulFile,*, IOSTAT=status) memberIndexSubSample, memberIndexFull
1279      if (status < 0) exit
1280
1281      numSubSample = numSubSample + 1
1282      write(*,*) 'epp_selectSubSample: ', memberIndexSubSample, memberIndexFull
1283      memberIndexesSubSample(numSubSample) = memberIndexSubSample
1284      memberIndexesFull(numSubSample) = memberIndexFull
1285    end do
1286    ierr = fclos(nulFile)
1287
1288    write(*,*) 'epp_selectSubSample: number of subSample members = ', numSubSample
1289
1290    allocate(dateStampListInc(tim_nstepobsinc))
1291    call tim_getstamplist(dateStampListInc,tim_nstepobsinc,tim_getDatestamp())
1292
1293    call ens_allocate(ensembleAnlSubSample, numSubSample, tim_nstepobsinc,  &
1294                      ens_getHco(ensembleAnl), ens_getVco(ensembleAnl), dateStampListInc)
1295    if (present(ensembleTrlSubSample_opt)) then
1296      call ens_allocate(ensembleTrlSubSample_opt, numSubSample, tim_nstepobsinc,  &
1297                        ens_getHco(ensembleAnl), ens_getVco(ensembleAnl), dateStampListInc)
1298    end if
1299
1300    call gsv_allocate(stateVectorMember, tim_nstepobsinc,  &
1301                      ens_getHco(ensembleAnl), ens_getVco(ensembleAnl),  &
1302                      dateStamp_opt=tim_getDateStamp(),  &
1303                      mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
1304                      dataKind_opt=4, allocHeightSfc_opt=.false., &
1305                      allocHeight_opt=.false., allocPressure_opt=.false. )
1306
1307    do memberIndex = 1, numSubSample
1308      ! copy analysis ensemble member
1309      call ens_copyMember(ensembleAnl, stateVectorMember,  &
1310                          memberIndexesFull(memberIndex))
1311      call ens_insertMember(ensembleAnlSubSample, stateVectorMember,  &
1312                            memberIndexesSubSample(memberIndex))
1313
1314      if (present(ensembleTrl_opt) .and. present(ensembleTrlSubSample_opt)) then
1315        ! copy trial ensemble member
1316        call ens_copyMember(ensembleTrl_opt, stateVectorMember,  &
1317                            memberIndexesFull(memberIndex))
1318        call ens_insertMember(ensembleTrlSubSample_opt, stateVectorMember,  &
1319                              memberIndexesSubSample(memberIndex))
1320      end if
1321    end do
1322
1323    call gsv_deallocate(stateVectorMember)
1324    deallocate(dateStampListInc)
1325
1326  end subroutine epp_selectSubSample
1327
1328  !-----------------------------------------------------------------
1329  ! epp_hybridRecentering
1330  !-----------------------------------------------------------------
1331  subroutine epp_hybridRecentering(ensembleAnl, weightRecenter, weightRecenterLand, &
1332                                   useOptionTableRecenter, numMembersToRecenter)
1333    !:Purpose: Modify an ensemble by recentering the members on a state provided
1334    !           in the file "recentering_analysis".
1335    !           The "weightRecenter" and "numMembersToRecenter" are used in the calculation
1336    !           to determine the amount of recentering and how many members it is
1337    !           applied to. Alternatively the information in the "optiontable" file
1338    !           can be used to perform a different amount of recentering on each
1339    !           member.
1340    implicit none
1341
1342    ! Arguments:
1343    type(struct_ens), intent(inout) :: ensembleAnl
1344    real(8)         , intent(in)    :: weightRecenter(:)
1345    real(8)         , intent(in)    :: weightRecenterLand
1346    logical         , intent(in)    :: useOptionTableRecenter
1347    integer         , intent(in)    :: numMembersToRecenter
1348
1349    ! Locals:
1350    type(struct_gsv) :: stateVectorRecenterAnl
1351    type(struct_hco), pointer :: hco_ens => null()
1352    type(struct_vco), pointer :: vco_ens => null()
1353    character(len=30)    :: recenterAnlFileName = 'recentering_analysis'
1354    character(len=20)    :: stringArray(100)
1355    character(len=1000)  :: textLine
1356    integer              :: stepIndex, memberIndex, columnIndex
1357    integer              :: numMembers, numColumns, nulFile, status
1358    logical              :: recenterAnlFileExists
1359    real(8), allocatable :: weightArray(:,:)
1360    real(8), allocatable :: weightArrayLand(:)
1361    real(8)              :: weightFound
1362    integer, external    :: fnom, fclos
1363
1364    ! check if recentering analysis file exists
1365    inquire(file=recenterAnlFileName, exist=recenterAnlFileExists)
1366    if (.not. recenterAnlFileExists) then
1367      write(*,*) 'epp_hybridRecentering: RecenterAnlFileName = ', recenterAnlFileName
1368      call utl_abort('epp_hybridRecentering: The recentering analysis file does not exist')
1369    end if
1370
1371    hco_ens => ens_getHco(ensembleAnl)
1372    vco_ens => ens_getVco(ensembleAnl)
1373    numMembers = ens_getNumMembers(ensembleAnl)
1374
1375    allocate( weightArray(vco_maxNumLevels,0:numMembers) )
1376    allocate( weightArrayLand(0:numMembers) )
1377
1378    ! read the optiontable file, if requested    
1379    if (useOptionTableRecenter) then
1380      write(*,*) 'epp_hybridRecentering: using optiontable file to specify recentering weights.'
1381      nulFile = 0
1382      status = fnom(nulFile, './optiontable', 'FMT+SEQ+R/O', 0)
1383      read(nulFile,'(a)', IOSTAT=status) textLine
1384      if (status /= 0) then
1385        call utl_abort('epp_hybridRecentering: unable to read optiontable file')
1386      end if
1387      call utl_parseColumns(textLine, numColumns)
1388      if (mmpi_myid==0) write(*,*) 'epp_hybridRecentering: optiontable file has ', numColumns, ' columns.'
1389      rewind(nulFile)
1390      do memberIndex = 0, numMembers
1391        read(nulFile,'(a)') textLine
1392        call utl_parseColumns(textLine, numColumns, stringArray_opt=stringArray)
1393        if (mmpi_myid==0) write(*,*) memberIndex, (stringArray(columnIndex),columnIndex=1,numColumns)
1394        read(stringArray(numColumns),'(f6.3)') weightFound
1395        weightArray(:,memberIndex) = weightFound
1396        if (mmpi_myid==0) write(*,*) 'weightArray = ', weightArray(1,memberIndex)
1397      end do
1398      status = fclos(nulFile)
1399    else
1400      if (any(weightRecenter(1:vco_getNumLev(vco_ens,'MM')) == -1.d0)) then
1401        write(*,*) ''
1402        write(*,*) 'Number of weightRecenter coefficients needed = ', vco_getNumLev(vco_ens,'MM')
1403        write(*,*) 'Provided values : '
1404        write(*,*) weightRecenter(1:vco_getNumLev(vco_ens,'MM'))
1405        call utl_abort('epp_hybridRecentering: A valid weightRecenter coefficient was not provided for all the vertical levels')
1406      end if
1407      do memberIndex = 0, numMembers
1408        weightArray(:,memberIndex) = weightRecenter(:)
1409      end do
1410    end if
1411
1412    do memberIndex = 0, numMembers
1413      weightArrayLand(memberIndex) = weightRecenterLand
1414    end do
1415    
1416    ! allocate and read in recentering analysis state
1417    call gsv_allocate( stateVectorRecenterAnl, tim_nstepobsinc, hco_ens, vco_ens, dateStamp_opt=tim_getDateStamp(),  &
1418                       mpi_local_opt=.true., mpi_distribution_opt='Tiles', &
1419                       dataKind_opt=4, allocHeightSfc_opt=.false., &
1420                       hInterpolateDegree_opt = 'LINEAR', &
1421                       allocHeight_opt=.false., allocPressure_opt=.false. )
1422    call gsv_zero(stateVectorRecenterAnl)
1423
1424    do stepIndex = 1, tim_nstepobsinc
1425      call gio_readFromFile( stateVectorRecenterAnl, recenterAnlFileName, ' ', ' ',  &
1426                             stepIndex_opt=stepIndex, containsFullField_opt=.true., &
1427                             readHeightSfc_opt=.false. )
1428    end do
1429    
1430    ! apply recentering
1431    call ens_recenter(ensembleAnl, stateVectorRecenterAnl, &
1432                      recenteringCoeff_opt=weightArray(:,1:numMembers),  &
1433                      numMembersToRecenter_opt=numMembersToRecenter, &
1434                      recenteringCoeffLand_opt=weightArrayLand)
1435
1436    call gsv_deallocate(stateVectorRecenterAnl)
1437    if ( allocated(weightArray) ) deallocate(weightArray)
1438
1439  end subroutine epp_hybridRecentering
1440
1441  !-----------------------------------------------------------------
1442  ! epp_printRmsStats
1443  !-----------------------------------------------------------------
1444  subroutine epp_printRmsStats(stateVectorStdDev,fileName,elapsed,ftype,nEns)
1445    !
1446    !:Purpose: Print statistics of a field to an ASCII output file
1447    !
1448    implicit none
1449
1450    ! Arguments:
1451    type(struct_gsv), intent(in) :: stateVectorStdDev
1452    character(len=*), intent(in) :: fileName
1453    real(8),          intent(in) :: elapsed
1454    character(len=1), intent(in) :: ftype
1455    integer,          intent(in) :: nEns
1456
1457    ! Locals:
1458    real(8), allocatable          :: rmsvalue(:) 
1459    type(struct_vco), pointer     :: vco
1460    type(struct_hco), pointer     :: hco
1461    character(len=4), allocatable :: nomvar_v(:)
1462    character(len=4)              :: varLevel
1463    real(8), allocatable          :: scaleFactor(:)
1464    real(4), allocatable          :: pressureOrDepth(:)
1465    integer :: ierr, latIndex, lonIndex, nulFile
1466    integer :: kIndex, kIndexCount, levIndex, numK, nLev_M, kIndexUU, kIndexVV
1467    real(4), pointer              :: stdDev_ptr_r4(:,:,:)
1468    real(8)                       :: pSfc(1,1)
1469    real(8), pointer              :: pressures_T(:,:,:), pressures_M(:,:,:)
1470    integer, external             :: fnom, fclos
1471    real(8), save, allocatable    :: weight(:,:)
1472    logical, save                 :: firstCall = .true.
1473
1474    vco => gsv_getVco(stateVectorStdDev)
1475    nLev_M = vco_getNumLev(vco,'MM')
1476
1477    numK = gsv_getNumK(stateVectorStdDev)
1478    allocate(nomvar_v(numK))
1479    allocate(pressureOrDepth(numK))
1480    allocate(rmsvalue(numK))
1481    allocate(scaleFactor(numK))
1482
1483    ! compute a 2D weight field used for horizontal averaging
1484    hco => gsv_getHco(stateVectorStdDev)
1485    if (firstCall) then
1486      ! weights are reduced in the overlap region in case of a Yin-Yang grid
1487      allocate(weight(stateVectorStdDev%ni,stateVectorStdDev%nj))
1488      weight(:,:) = 0.0d0
1489      call hco_weight(hco, weight)
1490      firstCall = .false.
1491    end if
1492    ! compute global mean variance accounting for weights
1493    call gsv_getField(stateVectorStdDev,stdDev_ptr_r4)
1494    rmsvalue(:) = 0.0D0
1495    do kIndex = 1, numK
1496      do latIndex = stateVectorStdDev%myLatBeg, stateVectorStdDev%myLatEnd
1497        do lonIndex = stateVectorStdDev%myLonBeg, stateVectorStdDev%myLonEnd
1498          rmsvalue(kIndex) = rmsvalue(kIndex) +  &
1499               (stdDev_ptr_r4(lonIndex,latIndex,kIndex)**2) *  &
1500               weight(lonIndex,latIndex)
1501        end do
1502      end do
1503      call mmpi_allreduce_sumreal8scalar(rmsvalue(kIndex),'GRID')
1504      rmsvalue(kIndex) = rmsvalue(kIndex)**0.5
1505    end do
1506
1507    if (vco%vgridPresent) then
1508      ! compute pressure for a column where Psfc=1000hPa
1509      pSfc(1,1) = 1000.0D2 !1000 hPa
1510      ! pressure levels
1511      call czp_fetch3DLevels(vco, pSfc, fldM_opt=pressures_M, fldT_opt=pressures_T)
1512
1513      ! set the variable name and pressure for each element of column
1514      do kIndex = 1, numK
1515        levIndex = gsv_getLevFromK(stateVectorStdDev, kIndex)
1516        nomvar_v(kIndex) = gsv_getVarNameFromK(stateVectorStdDev,kIndex)
1517        varLevel = vnl_varLevelFromVarname(nomvar_v(kIndex))
1518        if (varLevel == 'MM') then
1519          pressureOrDepth(kIndex) = pressures_M(1,1,levIndex)/Psfc(1,1)
1520        else if (varLevel == 'TH') then
1521          pressureOrDepth(kIndex) = pressures_T(1,1,levIndex)/Psfc(1,1)
1522        else
1523          pressureOrDepth(kIndex) = 1.0
1524        end if
1525      end do
1526      deallocate(pressures_M)
1527      deallocate(pressures_T)
1528
1529    else if (vco%nLev_depth > 0) then
1530
1531      ! set the variable name and depth for each element of column
1532      do kIndex = 1, numK
1533        nomvar_v(kIndex) = gsv_getVarNameFromK(stateVectorStdDev,kIndex)
1534        if (vnl_varLevelFromVarName(nomvar_v(kIndex)) == 'SS') then
1535          pressureOrDepth(kIndex) = 0.0
1536        else
1537          levIndex = gsv_getLevFromK(stateVectorStdDev, kIndex)
1538          pressureOrDepth(kIndex) = vco%depths(levIndex)
1539        end if
1540      end do
1541
1542    else
1543
1544      call utl_abort('epp_printRmsStats: Unknown type of levels')
1545
1546    end if
1547
1548    ! set the scaleFactor and rmsvalue for each element of column
1549    do kIndex = 1, numK
1550      if ( (nomvar_v(kIndex) == 'UU') .or. (nomvar_v(kIndex) == 'VV') ) then
1551        scaleFactor(kIndex) = MPC_KNOTS_PER_M_PER_S_R8
1552      else if (nomvar_v(kIndex) == 'P0') then
1553        scaleFactor(kIndex) = MPC_MBAR_PER_PA_R8
1554      else
1555        scaleFactor(kIndex) = 1.0d0
1556      end if
1557      rmsvalue(kIndex) = scaleFactor(kIndex) * rmsvalue(kIndex)
1558    end do
1559
1560    ! write to file
1561    if (mmpi_myid == 0) then
1562      write(*,*) 'epp_printRmsStats: Opening ascii output file: ', trim(fileName)
1563      nulFile = 0
1564      ierr = fnom (nulFile, fileName, 'SEQ+R/W', 0)
1565      if (ierr /= 0) then
1566        call utl_abort('epp_printRmsStats: Cannot open ascii output file')
1567      end if
1568
1569      kIndexCount = 0
1570      if ( (nomvar_v(1) == 'UU') .and. (nomvar_v(1+nLev_M) == 'VV') ) then        
1571        do levIndex = 1, nLev_M
1572          kIndexCount = kIndexCount + 2
1573          kIndexUU = levIndex
1574          kIndexVV = levIndex + nLev_M
1575          write(nulFile,100) &
1576               elapsed,ftype,nEns,nomvar_v(kIndexUU),pressureOrDepth(kIndexUU),rmsvalue(kIndexUU)
1577          write(nulFile,100) &
1578               elapsed,ftype,nEns,nomvar_v(kIndexVV),pressureOrDepth(kIndexVV),rmsvalue(kIndexVV)
1579        end do
1580      end if
1581      do kIndex = kIndexCount+1, numK
1582        write(nulFile,100) &
1583             elapsed,ftype,nEns,nomvar_v(kIndex),pressureOrDepth(kIndex),rmsvalue(kIndex)   
1584      end do
1585      ierr = fclos(nulFile)
1586    end if
1587
1588100 format(f7.2,1x,A1,1x,I5,1x,A4,1x,f12.7,1x,(2E12.5))
1589
1590    deallocate(nomvar_v)
1591    deallocate(pressureOrDepth)
1592    deallocate(scaleFactor)
1593    deallocate(rmsvalue)
1594
1595  end subroutine epp_printRmsStats
1596
1597end module ensPostProcess_mod