gridStateVectorFileIO_mod sourceΒΆ

   1module gridStateVectorFileIO_mod
   2  ! MODULE gridStateVectorFileIO_mod (prefix='gio' category='4. Data Object transformations')
   3  !
   4  !:Purpose: The grid-point state vector I/O methods for reading from and writing to
   5  !          files.
   6  !
   7  use mpi
   8  use midasMpi_mod
   9  use gridStateVector_mod
  10  use interpolation_mod
  11  use utilities_mod
  12  use verticalCoord_mod
  13  use horizontalCoord_mod
  14  use oceanMask_mod
  15  use varNameList_mod
  16  use ramDisk_mod
  17  use timeCoord_mod
  18  use mathPhysConstants_mod
  19  use codePrecision_mod
  20  use Vgrid_Descriptors
  21  implicit none
  22  save
  23  private
  24
  25  ! public subroutines and functions
  26  public :: gio_readFromFile, gio_readTrials, gio_readFile
  27  public :: gio_readMaskFromFile
  28  public :: gio_getMaskLAM
  29  public :: gio_writeToFile
  30  public :: gio_fileUnitsToStateUnits
  31
  32  integer, external :: get_max_rss
  33
  34  ! Namelist variables
  35  logical :: interpToPhysicsGrid  ! for LAM grid, choose to keep physics variables on their original grid
  36
  37  contains
  38  !--------------------------------------------------------------------------
  39  ! gio_readFromFile
  40  !--------------------------------------------------------------------------
  41  subroutine gio_readFromFile(statevector_out, fileName, etiket_in, typvar_in, &
  42                              stepIndex_opt, unitConversion_opt, &
  43                              statevectorRef_opt, readHeightSfc_opt, &
  44                              containsFullField_opt, vcoFileIn_opt)
  45    !
  46    !:Purpose: Read an RPN standard file and put the contents into a
  47    !           stateVector object. Main high level wrapper subroutine.
  48    !
  49    implicit none
  50
  51    ! Arguments:
  52    type(struct_gsv),                    intent(inout) :: statevector_out
  53    character(len=*),                    intent(in)    :: fileName
  54    character(len=*),                    intent(in)    :: etiket_in
  55    character(len=*),                    intent(in)    :: typvar_in
  56    integer,          optional,          intent(in)    :: stepIndex_opt
  57    logical,          optional,          intent(in)    :: unitConversion_opt
  58    type(struct_gsv), optional,          intent(in)    :: statevectorRef_opt ! Reference statevector providing optional fields (P0, TT, HU)
  59    logical,          optional,          intent(in)    :: readHeightSfc_opt
  60    logical,          optional,          intent(in)    :: containsFullField_opt
  61    type(struct_vco), optional, pointer, intent(in)    :: vcoFileIn_opt
  62
  63    ! Locals:
  64    logical           :: doHorizInterp, doVertInterp, unitConversion
  65    logical           :: readHeightSfc, containsFullField
  66    logical           :: foundVarNameInFile 
  67    integer           :: stepIndex, varIndex
  68    character(len=4)  :: varName
  69    type(struct_vco), pointer :: vco_file
  70    type(struct_hco), pointer :: hco_file
  71
  72    nullify(vco_file, hco_file)
  73
  74    write(*,*)
  75    write(*,*) 'gio_readFromFile: START'
  76    call utl_tmg_start(160,'low-level--gsv_readFromFile')
  77
  78    if ( present(stepIndex_opt) ) then
  79      stepIndex = stepIndex_opt
  80    else
  81      stepIndex = statevector_out%anltime
  82    end if
  83    if (stepIndex > stateVector_out%numStep .or. stepIndex < 1) then
  84      write(*,*) 'stepIndex = ', stepIndex
  85      call utl_abort('gio_readFromFile: invalid value for stepIndex')
  86    end if
  87
  88    if ( present(unitConversion_opt) ) then
  89      unitConversion = unitConversion_opt
  90    else
  91      unitConversion = .true.
  92    end if
  93
  94    if (present(containsFullField_opt)) then
  95      containsFullField = containsFullField_opt
  96    else
  97      containsFullField = .true.
  98    end if
  99    write(*,*) 'gio_readFromFile: containsFullField = ', containsFullField
 100
 101    if ( present(readHeightSfc_opt) ) then
 102      readHeightSfc = readHeightSfc_opt
 103    else
 104      readHeightSfc = .false.
 105    end if
 106
 107    ! set up vertical and horizontal coordinate for input file
 108    if (present(vcoFileIn_opt)) then
 109      vco_file => vcoFileIn_opt
 110      write(*,*)
 111      write(*,*) 'gio_readFromFile: vertical levels defined in user-supplied vco object will be read'
 112    else
 113      call vco_setupFromFile(vco_file,trim(fileName), beSilent_opt=.true.)
 114      write(*,*)
 115      write(*,*) 'gio_readFromFile: all the vertical levels will be read from ', trim(fileName) 
 116    end if
 117
 118    foundVarNameInFile = .false.
 119
 120    do varIndex = 1, vnl_numvarmax
 121      varName = vnl_varNameList(varIndex)
 122
 123      if (.not. gsv_varExist(statevector_out,varName)) cycle
 124
 125      ! make sure variable is in the file
 126      if (.not. utl_varNamePresentInFile(varName,fileName_opt=trim(fileName))) cycle
 127
 128      ! adopt a variable on the full/dynamic LAM grid
 129      if (.not. statevector_out%hco%global .and. (trim(varName) == 'TM' .or. trim(varName) == 'MG')) cycle
 130
 131      foundVarNameInFile = .true.
 132
 133      exit
 134
 135    end do
 136
 137    ! special case when only TM (Surface Temperature) is in the file:
 138    if (.not. foundVarNameInFile) then
 139      varname = 'TM'
 140      if (gsv_varExist( statevector_out, varname) .and. &
 141          utl_varNamePresentInFile(varname, fileName_opt = trim(fileName))) &
 142        foundVarNameInFile = .true.
 143    end if   
 144
 145    ! to be safe for situations where, e.g. someone wants to only read MG from a file
 146    if (.not. foundVarNameInFile) then
 147      varname = 'P0'
 148      if (utl_varNamePresentInFile( varname, fileName_opt = trim( fileName))) &
 149        foundVarNameInFile = .true.
 150    end if   
 151
 152    if (.not. foundVarNameInFile) call utl_abort('gio_readFromFile: NO variables found in the file!!!')
 153
 154    write(*,*) 'gio_readFromFile: defining hco by varname= ', varName
 155
 156    call hco_setupFromFile(hco_file, trim(fileName), etiket_in, gridName_opt='FILEGRID', varName_opt = varName)
 157
 158    ! test if horizontal and/or vertical interpolation needed for statevector grid
 159    doVertInterp = .not.vco_equal(vco_file,statevector_out%vco)
 160    doHorizInterp = .not.hco_equal(hco_file,statevector_out%hco)
 161    write(*,*) 'gio_readFromFile: doVertInterp = ', doVertInterp, ', doHorizInterp = ', doHorizInterp
 162
 163    ! call appropriate subroutine to do actual work
 164    if ((doVertInterp .or. doHorizInterp) .and. statevector_out%mpi_distribution=='Tiles') then
 165      call readFromFileAndInterpToTiles(statevector_out, fileName,  &
 166             vco_file, hco_file, etiket_in, typvar_in, stepIndex, unitConversion,  &
 167             readHeightSfc, containsFullField, statevectorRef_opt=statevectorRef_opt)
 168    else if ((doVertInterp .or. doHorizInterp) .and. .not.stateVector_out%mpi_local) then
 169      call readFromFileAndInterp1Proc(statevector_out, fileName,  &
 170             vco_file, hco_file, etiket_in, typvar_in, stepIndex, unitConversion,  &
 171             readHeightSfc, containsFullField)
 172    else if (.not.(doVertInterp .or. doHorizInterp) .and. stateVector_out%mpi_local) then
 173      call readFromFileAndTransposeToTiles(statevector_out, fileName,  &
 174             etiket_in, typvar_in, stepIndex, unitConversion,  &
 175             readHeightSfc, containsFullField)
 176    else
 177      call readFromFileOnly(statevector_out, fileName,  &
 178                                etiket_in, typvar_in, stepIndex, unitConversion,  &
 179                                readHeightSfc, containsFullField)
 180    end if
 181
 182    call utl_tmg_stop(160)
 183    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 184    write(*,*) 'gio_readFromFile: END'
 185
 186  end subroutine gio_readFromFile
 187
 188  !--------------------------------------------------------------------------
 189  ! readFromFileAndInterpToTiles
 190  !--------------------------------------------------------------------------
 191  subroutine readFromFileAndInterpToTiles(statevector_out, fileName,  &
 192             vco_file, hco_file, etiket_in, typvar_in, stepIndex, unitConversion,  &
 193             readHeightSfc, containsFullField, statevectorRef_opt)
 194    !
 195    !:Purpose: Read an RPN standard file and put the contents into a
 196    !           stateVector object. Wrapper subroutine that also proceed with
 197    !           distributed interpolation on MPI tiles.
 198    !
 199    !:Note: this routine currently only works correctly for reading FULL FIELDS,
 200    !        not increments or perturbations... because of the HU -> LQ conversion
 201    implicit none
 202
 203    ! Arguments:
 204    type(struct_gsv),           intent(inout) :: statevector_out
 205    character(len=*),           intent(in)    :: fileName
 206    type(struct_vco), pointer,  intent(in)    :: vco_file
 207    type(struct_hco), pointer,  intent(in)    :: hco_file
 208    character(len=*),           intent(in)    :: etiket_in
 209    character(len=*),           intent(in)    :: typvar_in
 210    integer,                    intent(in)    :: stepIndex
 211    logical,                    intent(in)    :: unitConversion
 212    logical,                    intent(in)    :: readHeightSfc
 213    logical,                    intent(in)    :: containsFullField
 214    type(struct_gsv), optional, intent(in)    :: statevectorRef_opt ! Reference statevector providing optional fields (P0, TT, HU)
 215
 216    ! Locals:
 217    real(4), pointer     :: field3d_r4_ptr(:,:,:)
 218    real(8), pointer     :: field_in_ptr(:,:,:,:), field_out_ptr(:,:,:,:)
 219    character(len=4), pointer :: varNamesToRead(:)
 220    type(struct_gsv) :: statevector_file_r4, statevector_tiles 
 221    type(struct_gsv) :: statevector_hinterp_r4, statevector_vinterp
 222
 223    nullify(field3d_r4_ptr, field_in_ptr, field_out_ptr)
 224
 225    write(*,*) ''
 226    write(*,*) 'readFromFileAndInterpToTiles: START'
 227
 228    nullify(varNamesToRead)
 229    call gsv_varNamesList(varNamesToRead, statevector_out)
 230
 231    !-- 1.0 Read the file, distributed over mpi task with respect to variables/levels
 232
 233    ! initialize single precision 3D working copy of statevector for reading file
 234    call gsv_allocate(statevector_file_r4, 1, hco_file, vco_file,                &
 235                      dateStamp_opt=statevector_out%datestamplist(stepIndex),    &
 236                      mpi_local_opt=.true., mpi_distribution_opt='VarsLevs',     &
 237                      dataKind_opt=4, allocHeightSfc_opt=readHeightSfc,          &
 238                      varNames_opt=varNamesToRead,                               &
 239                      hInterpolateDegree_opt=statevector_out%hInterpolateDegree, &
 240                      hExtrapolateDegree_opt=statevector_out%hExtrapolateDegree )
 241
 242    call gio_readFile(statevector_file_r4, filename, etiket_in, typvar_in,  &
 243                      containsFullField, readHeightSfc_opt=readHeightSfc)
 244
 245    !-- 2.0 Horizontal Interpolation
 246
 247    ! initialize single precision 3D working copy of statevector for horizontal interpolation result
 248    call gsv_allocate(statevector_hinterp_r4, 1, statevector_out%hco, vco_file,  &
 249                      dateStamp_opt=statevector_out%datestamplist(stepIndex),    &
 250                      mpi_local_opt=.true., mpi_distribution_opt='VarsLevs',     &
 251                      dataKind_opt=4, allocHeightSfc_opt=readHeightSfc,          &
 252                      varNames_opt=varNamesToRead,                               &
 253                      hInterpolateDegree_opt=statevector_out%hInterpolateDegree, &
 254                      hExtrapolateDegree_opt=statevector_out%hExtrapolateDegree )
 255
 256    call int_hInterp_gsv(statevector_file_r4, statevector_hinterp_r4)
 257
 258    call gsv_deallocate(statevector_file_r4)
 259
 260    !-- 3.0 Unit conversion
 261
 262    if ( unitConversion ) then
 263      call gio_fileUnitsToStateUnits( statevector_hinterp_r4, containsFullField )
 264    end if
 265
 266    !-- 4.0 MPI communication from vars/levels to lat/lon tiles
 267
 268    ! initialize double precision 3D working copy of statevector for mpi communication result
 269    call gsv_allocate(statevector_tiles, 1, statevector_out%hco, vco_file,    &
 270                      dateStamp_opt=statevector_out%datestamplist(stepIndex), &
 271                      mpi_local_opt=.true., mpi_distribution_opt='Tiles',     &
 272                      dataKind_opt=8, allocHeightSfc_opt=readHeightSfc,               &
 273                      varNames_opt=varNamesToRead )
 274
 275    call gsv_transposeVarsLevsToTiles(statevector_hinterp_r4, statevector_tiles)
 276
 277    call gsv_deallocate(statevector_hinterp_r4)
 278
 279    !-- 5.0 Vertical interpolation
 280
 281    ! initialize double precision 3D working copy of statevector for mpi communication result
 282    call gsv_allocate(statevector_vinterp, 1, statevector_out%hco, statevector_out%vco, &
 283                      dateStamp_opt=statevector_out%datestamplist(stepIndex), &
 284                      mpi_local_opt=.true., mpi_distribution_opt='Tiles', dataKind_opt=8, &
 285                      allocHeightSfc_opt=readHeightSfc, varNames_opt=varNamesToRead )
 286
 287    call int_vInterp_gsv( statevector_tiles, statevector_vinterp, & 
 288                          statevectorRef_opt=statevectorRef_opt)
 289
 290    call gsv_deallocate(statevector_tiles)
 291
 292    !-- 6.0 Copy result to output statevector
 293    call gsv_copy(statevector_vinterp, statevector_out, stepIndexOut_opt=stepIndex)
 294
 295    call gsv_deallocate(statevector_vinterp)
 296    deallocate(varNamesToRead)
 297
 298    write(*,*) 'readFromFileAndInterpToTiles: END'
 299
 300  end subroutine readFromFileAndInterpToTiles
 301
 302  !--------------------------------------------------------------------------
 303  ! readFromFileAndTransposeToTiles
 304  !--------------------------------------------------------------------------
 305  subroutine readFromFileAndTransposeToTiles(statevector_out, fileName,  &
 306             etiket_in, typvar_in, stepIndex, unitConversion,  &
 307             readHeightSfc, containsFullField)
 308    !
 309    !:Purpose: Read an RPN standard file and put the contents into a
 310    !           stateVector object. Wrapper subroutine that also proceed with
 311    !           distributed transposition on MPI tiles.
 312    !
 313    !:Note: this routine currently only works correctly for reading FULL FIELDS,
 314    !        not increments or perturbations... because of the HU -> LQ conversion
 315    implicit none
 316
 317    ! Arguments:
 318    type(struct_gsv), intent(inout) :: statevector_out
 319    character(len=*), intent(in)    :: fileName
 320    character(len=*), intent(in)    :: etiket_in
 321    character(len=*), intent(in)    :: typvar_in
 322    integer,          intent(in)    :: stepIndex
 323    logical,          intent(in)    :: unitConversion
 324    logical,          intent(in)    :: readHeightSfc
 325    logical,          intent(in)    :: containsFullField
 326
 327    ! Locals:
 328    real(4), pointer     :: field3d_r4_ptr(:,:,:)
 329    real(8), pointer     :: field_in_ptr(:,:,:,:), field_out_ptr(:,:,:,:)
 330    character(len=4), pointer :: varNamesToRead(:)
 331    type(struct_gsv) :: statevector_file_r4, statevector_tiles
 332
 333    nullify(field3d_r4_ptr, field_in_ptr, field_out_ptr)
 334
 335    write(*,*) ''
 336    write(*,*) 'readFromFileAndTransposeToTiles: START'
 337
 338    nullify(varNamesToRead)
 339    call gsv_varNamesList(varNamesToRead, statevector_out)
 340
 341    !-- 1.0 Read the file, distributed over mpi task with respect to variables/levels
 342
 343    ! initialize single precision 3D working copy of statevector for reading file
 344    call gsv_allocate(statevector_file_r4, 1, statevector_out%hco, statevector_out%vco, &
 345                      dateStamp_opt=statevector_out%datestamplist(stepIndex),           &
 346                      mpi_local_opt=.true., mpi_distribution_opt='VarsLevs',            &
 347                      dataKind_opt=4, allocHeightSfc_opt=readHeightSfc,                         &
 348                      varNames_opt=varNamesToRead )
 349
 350    call gio_readFile(statevector_file_r4, filename, etiket_in, typvar_in,  &
 351                      containsFullField, readHeightSfc_opt=readHeightSfc)
 352
 353    !-- 2.0 Unit conversion
 354    if ( unitConversion ) then
 355      call gio_fileUnitsToStateUnits( statevector_file_r4, containsFullField )
 356    end if
 357
 358    !-- 3.0 MPI communication from vars/levels to lat/lon tiles
 359    call gsv_allocate(statevector_tiles, 1, statevector_out%hco, statevector_out%vco, &
 360                      dateStamp_opt=statevector_out%datestamplist(stepIndex), &
 361                      mpi_local_opt=.true., mpi_distribution_opt='Tiles',     &
 362                      dataKind_opt=8, allocHeightSfc_opt=readHeightSfc,               &
 363                      varNames_opt=varNamesToRead)
 364
 365    call gsv_transposeVarsLevsToTiles(statevector_file_r4, statevector_tiles)
 366
 367    !-- 4.0 Copy result to output statevector
 368    call gsv_copy(statevector_tiles, statevector_out, stepIndexOut_opt=stepIndex)
 369
 370    call gsv_deallocate(statevector_tiles)
 371    call gsv_deallocate(statevector_file_r4)
 372    deallocate(varNamesToRead)
 373
 374    write(*,*) 'readFromFileAndTransposeToTiles: END'
 375
 376  end subroutine readFromFileAndTransposeToTiles
 377
 378  !--------------------------------------------------------------------------
 379  ! readFromFileAndInterp1Proc
 380  !--------------------------------------------------------------------------
 381  subroutine readFromFileAndInterp1Proc(statevector_out_r4, fileName,  &
 382             vco_file, hco_file, etiket_in, typvar_in, stepIndex, unitConversion,  &
 383             readHeightSfc, containsFullField)
 384    !
 385    !:Purpose: Read an RPN standard file and put the contents into a
 386    !           stateVector object. Wrapper subroutine that also proceed with
 387    !           (serial) interpolation.
 388    !
 389    implicit none
 390
 391    ! Arguments:
 392    type(struct_gsv),          intent(inout)  :: statevector_out_r4
 393    character(len=*),          intent(in)     :: fileName
 394    type(struct_vco), pointer, intent(in)     :: vco_file
 395    type(struct_hco), pointer, intent(in)     :: hco_file
 396    character(len=*),          intent(in)     :: etiket_in
 397    character(len=*),          intent(in)     :: typvar_in
 398    integer,                   intent(in)     :: stepIndex
 399    logical,                   intent(in)     :: unitConversion
 400    logical,                   intent(in)     :: readHeightSfc
 401    logical,                   intent(in)     :: containsFullField
 402
 403    ! Locals:
 404    real(4), pointer :: field_in_ptr(:,:,:,:), field_out_ptr(:,:,:,:)
 405    character(len=4), pointer :: varNamesToRead(:)
 406    type(struct_gsv) :: statevector_file_r4, statevector_hinterp_r4
 407    type(struct_gsv) :: statevector_vinterp_r4
 408
 409    nullify(field_in_ptr, field_out_ptr)
 410
 411    write(*,*) ''
 412    write(*,*) 'readFromFileAndInterp1Proc: START'
 413
 414    nullify(varNamesToRead)
 415    call gsv_varNamesList(varNamesToRead, statevector_out_r4)
 416
 417    !-- 1.0 Read the file
 418
 419    ! initialize single precision 3D working copy of statevector for reading file
 420    call gsv_allocate(statevector_file_r4, 1, hco_file, vco_file,                    &
 421                      dateStamp_opt=statevector_out_r4%datestamplist(stepIndex),     &
 422                      mpi_local_opt=.false., dataKind_opt=4,                         &
 423                      allocHeightSfc_opt=readHeightSfc, varNames_opt=varNamesToRead, &
 424                      hInterpolateDegree_opt=statevector_out_r4%hInterpolateDegree,  &
 425                      hExtrapolateDegree_opt=statevector_out_r4%hExtrapolateDegree)
 426
 427    call gio_readFile(statevector_file_r4, filename, etiket_in, typvar_in,  &
 428                      containsFullField, readHeightSfc_opt=readHeightSfc)
 429
 430    !-- 2.0 Horizontal Interpolation
 431
 432    ! initialize single precision 3D working copy of statevector for horizontal interpolation result
 433    call gsv_allocate(statevector_hinterp_r4, 1, statevector_out_r4%hco, vco_file,   &
 434                      dateStamp_opt=statevector_out_r4%datestamplist(stepIndex),     &
 435                      mpi_local_opt=.false., dataKind_opt=4,                         &
 436                      allocHeightSfc_opt=readHeightSfc, varNames_opt=varNamesToRead, &
 437                      hInterpolateDegree_opt=statevector_out_r4%hInterpolateDegree,  &
 438                      hExtrapolateDegree_opt=statevector_out_r4%hExtrapolateDegree)
 439
 440    call int_hInterp_gsv(statevector_file_r4, statevector_hinterp_r4)
 441
 442    call gsv_deallocate(statevector_file_r4)
 443
 444    !-- 3.0 Unit conversion (must come before vertical interp to get Psfc in Pascals)
 445
 446    if ( unitConversion ) then
 447      call gio_fileUnitsToStateUnits( statevector_hinterp_r4, containsFullField )
 448    end if
 449
 450    !-- 4.0 Vertical interpolation
 451
 452    ! initialize double precision 3D working copy of statevector for mpi communication result
 453    call gsv_allocate(statevector_vinterp_r4, 1, statevector_out_r4%hco, statevector_out_r4%vco, &
 454                      dateStamp_opt=statevector_out_r4%datestamplist(stepIndex),                 &
 455                      mpi_local_opt=.false., dataKind_opt=4,                                     &
 456                      allocHeightSfc_opt=readHeightSfc, varNames_opt=varNamesToRead)
 457
 458    call int_vInterp_gsv(statevector_hinterp_r4,statevector_vinterp_r4)
 459
 460    call gsv_deallocate(statevector_hinterp_r4)
 461
 462    !-- 5.0 Copy result to output statevector
 463    call gsv_copy(statevector_vinterp_r4, statevector_out_r4, stepIndexOut_opt=stepIndex)
 464
 465    call gsv_deallocate(statevector_vinterp_r4)
 466    deallocate(varNamesToRead)
 467
 468    write(*,*) 'readFromFileAndInterp1Proc: END'
 469
 470  end subroutine readFromFileAndInterp1Proc
 471
 472  !--------------------------------------------------------------------------
 473  ! readFromFileOnly
 474  !--------------------------------------------------------------------------
 475  subroutine readFromFileOnly(statevector_out, fileName, etiket_in, typvar_in, &
 476                              stepIndex, unitConversion, readHeightSfc, &
 477                              containsFullField)
 478    !
 479    !:Purpose: Read an RPN standard file and put the contents into a
 480    !           stateVector object.  Wrapper subroutine
 481    !
 482    implicit none
 483
 484    ! Arguments:
 485    type(struct_gsv), intent(inout) :: statevector_out
 486    character(len=*), intent(in)    :: fileName
 487    character(len=*), intent(in)    :: etiket_in
 488    character(len=*), intent(in)    :: typvar_in
 489    integer         , intent(in)    :: stepIndex
 490    logical         , intent(in)    :: unitConversion
 491    logical         , intent(in)    :: readHeightSfc
 492    logical         , intent(in)    :: containsFullField
 493
 494    write(*,*) ''
 495    write(*,*) 'readFromFileOnly: Do simple reading with no interpolation and no mpi redistribution'
 496
 497    call gio_readFile(statevector_out, filename, etiket_in, typvar_in,  &
 498                      containsFullField, readHeightSfc_opt = readHeightSfc, &
 499                      stepIndex_opt = stepIndex)
 500
 501    if (unitConversion) then
 502      call gio_fileUnitsToStateUnits(statevector_out, containsFullField, stepIndex_opt = stepIndex)
 503    end if
 504
 505    write(*,*) 'readFromFileOnly: END'
 506
 507  end subroutine readFromFileOnly
 508
 509  !--------------------------------------------------------------------------
 510  ! gio_readFile
 511  !--------------------------------------------------------------------------
 512  subroutine gio_readFile(statevector, filename, etiket_in, typvar_in, &
 513                          containsFullField, readHeightSfc_opt, stepIndex_opt, &
 514                          ignoreDate_opt)
 515    !
 516    !:Purpose: Read an RPN standard file and put the contents into a
 517    !           stateVector object.  Low level subroutine that does the actual
 518    !           file reading.
 519    !
 520    implicit none
 521
 522    ! Arguments:
 523    type(struct_gsv),  intent(inout) :: statevector
 524    character(len=*),  intent(in)    :: fileName
 525    character(len=*),  intent(in)    :: etiket_in
 526    character(len=*),  intent(in)    :: typvar_in
 527    logical,           intent(in)    :: containsFullField
 528    logical, optional, intent(in)    :: readHeightSfc_opt
 529    integer, optional, intent(in)    :: stepIndex_opt
 530    logical, optional, intent(in)    :: ignoreDate_opt
 531
 532    ! Locals:
 533    integer :: nulfile, ierr, ip1, ni_file, nj_file, nk_file, kIndex, stepIndex
 534    integer :: ikey, levIndex
 535    integer :: stepIndexBeg, stepIndexEnd, ni_var, nj_var, nk_var
 536    integer :: fnom, fstouv, fclos, fstfrm, fstlir, fstinf
 537    integer :: fstprm, EZscintID_var, ezdefset, ezqkdef
 538    integer :: dateo_var, deet_var, npas_var, nbits_var, datyp_var
 539    integer :: ip1_var, ip2_var, ip3_var, swa_var, lng_var, dltf_var, ubc_var
 540    integer :: extra1_var, extra2_var, extra3_var
 541    integer :: ig1_var, ig2_var, ig3_var, ig4_var
 542    integer :: varIndex, dateStampList(statevector%numStep)
 543    character(len=4 ) :: nomvar_var
 544    character(len=2 ) :: typvar_var
 545    character(len=1 ) :: grtyp_var
 546    character(len=12) :: etiket_var
 547    real(4), pointer :: field_r4_ptr(:,:,:,:)
 548    real(8), pointer :: field_r8_ptr(:,:,:,:)
 549    real(4), pointer :: gd2d_file_r4(:,:), gd2d_r4_UV_ptr(:,:,:)
 550    real(8), pointer :: gd2d_r8_UV_ptr(:,:,:)
 551    real(8), pointer :: heightSfc_ptr(:,:)
 552    real(4), allocatable :: gd2d_var_r4(:,:)
 553    character(len=4)  :: varName, varNameToRead
 554    character(len=4)  :: varLevel
 555    type(struct_vco), pointer :: vco_file
 556    type(struct_hco), pointer :: hco_file
 557    logical :: foundVarNameInFile, ignoreDate
 558
 559    write(*,*) 'gio_readFile: starting'
 560    write(*,*) 'Memory Used: ', get_max_rss()/1024, 'Mb'
 561
 562    call readNml()
 563
 564    vco_file => gsv_getVco(statevector)
 565
 566    if (statevector%mpi_distribution /= 'VarsLevs' .and. &
 567        statevector%mpi_local) then
 568      call utl_abort('gio_readFile: statevector must have ' //   &
 569                     'complete horizontal fields on each mpi task.')
 570    end if
 571
 572    if (present(stepIndex_opt)) then
 573      stepIndexBeg = stepIndex_opt
 574      stepIndexEnd = stepIndex_opt
 575    else
 576      stepIndexBeg = 1
 577      stepIndexEnd = statevector%numStep
 578    end if
 579
 580    if (present(ignoreDate_opt)) then
 581      ignoreDate = ignoreDate_opt
 582    else
 583      ignoreDate = .false.
 584    end if
 585
 586    if (.not. associated(statevector%dateStampList)) then
 587      call utl_abort('gio_readFile: dateStampList of statevector is not associated with a target!')
 588    else
 589      dateStampList(:) = statevector%dateStampList(:)
 590      if (ignoreDate) then
 591        write(*,*) 'gio_readFile: as requested, ignoring the date when reading fields'
 592        dateStampList(:) = -1
 593      end if
 594    end if
 595
 596    !- Open input field
 597    nulfile = 0
 598    write(*,*) 'gio_readFile: file name = ', trim(fileName)
 599    ierr = fnom(nulfile, trim(fileName), 'RND+OLD+R/O', 0)
 600
 601    if (ierr >= 0) then
 602      ierr  =  fstouv(nulfile,'RND+OLD')
 603    else
 604      call utl_abort('gio_readFile: problem opening input file')
 605    end if
 606
 607    if (nulfile == 0) then
 608      call utl_abort('gio_readFile: unit number for input file not valid')
 609    end if
 610
 611    ! Read surface height if requested
 612    if (present(readHeightSfc_opt)) then
 613      if (readHeightSfc_opt .and. gsv_isAssocHeightSfc(statevector)) then
 614        write(*,*) 'gio_readFile: reading the surface height'
 615        varName = 'GZ'
 616        ip1 = statevector%vco%ip1_sfc
 617        typvar_var = typvar_in
 618        ikey = fstinf(nulfile, ni_file, nj_file, nk_file,  &
 619                      -1, etiket_in, &
 620                      -1, -1, -1, typvar_var, varName)
 621
 622        if (ikey < 0) then
 623          if (trim(typvar_in) /= "") then
 624            typvar_var(2:2) = '@'
 625            ikey = fstinf(nulfile, ni_file, nj_file, nk_file,  &
 626                          -1, etiket_in, &
 627                          -1, -1, -1, typvar_var, varName)
 628          end if
 629          if (ikey < 0) then
 630            write(*,*) 'gio_readFile: etiket_in = ', etiket_in
 631            write(*,*) 'gio_readFile: typvar_in = ', typvar_in
 632            call utl_abort('gio_readFile: Problem with reading surface height from file')
 633          end if
 634        end if
 635
 636        if (ni_file /= statevector%hco%ni .or. nj_file /= statevector%hco%nj) then
 637          write(*,*) 'ni, nj in file        = ', ni_file, nj_file
 638          write(*,*) 'ni, nj in statevector = ', statevector%hco%ni, statevector%hco%nj
 639          call utl_abort('gio_readFile: Dimensions of surface height not consistent')
 640        end if
 641
 642        allocate(gd2d_file_r4(ni_file, nj_file))
 643        gd2d_file_r4(:,:) = 0.0d0
 644        ierr = fstlir(gd2d_file_r4(:,:), nulfile, ni_file, nj_file, nk_file, &
 645                      -1, etiket_in, ip1, -1, -1, typvar_var,varName)
 646        if (ierr < 0) then
 647          write(*,*) 'ip1 = ', ip1
 648          write(*,*) 'etiket_in = ', etiket_in
 649          write(*,*) 'typvar_var = ', typvar_var
 650          call utl_abort('gio_readFile: Problem with reading surface height from file')
 651        end if
 652        heightSfc_ptr => gsv_getHeightSfc(statevector)
 653        heightSfc_ptr = real(gd2d_file_r4(1:gsv_getHco(statevector)%ni, &
 654                                          1:gsv_getHco(statevector)%nj), 8) * 10.0d0
 655        deallocate(gd2d_file_r4)
 656      end if
 657    end if
 658
 659    nullify(hco_file)
 660    nullify(gd2d_file_r4)
 661    if (statevector%mykCount > 0) then
 662      if (statevector%hco%global) then
 663
 664        foundVarNameInFile = .false.
 665        do varIndex = 1, vnl_numvarmax
 666          varName = vnl_varNameList(varIndex)
 667
 668          if (.not. gsv_varExist(statevector, varName)) cycle
 669
 670          ! make sure variable is in the file
 671          if (.not. utl_varNamePresentInFile(varName, fileName_opt = trim(fileName))) cycle
 672
 673          ! adopt a variable on the full/dynamic LAM grid
 674          if ((trim(varName) == 'TM' .or. trim(varName) == 'MG')) cycle
 675
 676          foundVarNameInFile = .true.
 677
 678          exit
 679        end do
 680
 681        ! special case when only TM (Surface Temperature) is in the file:
 682        if (.not. foundVarNameInFile) then
 683          varname = 'TM'
 684          if (gsv_varExist(statevector, varname) .and. &
 685              utl_varNamePresentInFile(varname, fileName_opt = trim(fileName))) &
 686            foundVarNameInFile = .true.
 687        end if   
 688
 689        ! to be safe for situations where, e.g. someone wants to only read MG from a file
 690        if (.not. foundVarNameInFile) then
 691          varname = 'P0'
 692          if (utl_varNamePresentInFile(varname, fileName_opt = trim( fileName))) &
 693            foundVarNameInFile = .true.
 694        end if
 695
 696        if (.not. foundVarNameInFile) call utl_abort('gio_readFile: NO variable is in the file')
 697
 698        call hco_setupFromFile(hco_file, filename, ' ', 'INPUTFILE', varName_opt = varName)
 699
 700      else
 701        ! In LAM mode, force the input file dimensions to be always identical to the input statevector dimensions
 702        hco_file => statevector%hco
 703
 704        ! Also attempt to set up the physics grid
 705        if (interpToPhysicsGrid) then
 706          var_loop: do varIndex = 1, vnl_numvarmax
 707            varName = vnl_varNameList(varIndex)
 708            if (.not. gsv_varExist(statevector, varName)) cycle var_loop
 709            if (.not. vnl_isPhysicsVar(varName)) cycle var_loop
 710            if (utl_varNamePresentInFile(varName, fileName_opt = filename) .and. &
 711               .not. associated(statevector%hco_physics)) then
 712              write(*,*) 'gio_readFile: set up physics grid using the variable:', varName
 713              call hco_SetupFromFile(statevector%hco_physics, filename, ' ', &
 714                                     'INPUTFILE', varName_opt = varName)
 715              exit var_loop
 716            end if
 717          end do var_loop
 718        end if
 719
 720      end if
 721      allocate(gd2d_file_r4(hco_file%ni, hco_file%nj))
 722      gd2d_file_r4(:,:) = 0.0
 723    end if
 724
 725    ! Read all other fields needed for this MPI task
 726    if (statevector%dataKind == 4) then
 727      call gsv_getField(statevector, field_r4_ptr)
 728    else
 729      call gsv_getField(statevector, field_r8_ptr)
 730    end if
 731
 732    do stepIndex = stepIndexBeg, stepIndexEnd
 733      k_loop: do kIndex = statevector%mykBeg, statevector%mykEnd
 734        varName = gsv_getVarNameFromK(statevector, kIndex)
 735        levIndex = gsv_getLevFromK(statevector, kIndex)
 736
 737        if (.not.gsv_varExist(statevector, varName)) cycle k_loop
 738
 739        ! Check that the wanted field is present in the file
 740        if (utl_varNamePresentInFile(varName, fileUnit_opt = nulfile)) then
 741          varNameToRead = varName
 742        else
 743          select case (trim(varName))
 744          case ('LVIS')
 745            varNameToRead = 'VIS'
 746          case ('Z_T', 'Z_M', 'P_T', 'P_M')
 747            cycle k_loop
 748          case ('LPR')
 749            varNameToRead = 'PR'
 750          case default
 751            call utl_abort('gio_readFile: variable '//trim(varName)//' was not found in '//trim(fileName))
 752          end select
 753        end if
 754
 755        varLevel = vnl_varLevelFromVarname(varNameToRead)
 756        if (varLevel == 'MM') then
 757          ip1 = vco_file%ip1_M(levIndex)
 758        else if (varLevel == 'TH') then
 759          ip1 = vco_file%ip1_T(levIndex)
 760        else if (varLevel == 'SF') then
 761          ip1 = -1
 762        else if (varLevel == 'SFTH') then
 763          ip1 = vco_file%ip1_T_2m
 764        else if (varLevel == 'SFMM') then
 765          ip1 = vco_file%ip1_M_10m
 766        else if (varLevel == 'OT') then
 767          ip1 = vco_ip1_other(levIndex)
 768        else if (varLevel == 'DP') then
 769          ip1 = vco_file%ip1_depth(levIndex)
 770        else if (varLevel == 'SS') then
 771          ip1 = -1
 772        else
 773          write(*,*) 'varLevel =', varLevel
 774          call utl_abort('gio_readFile: unknown varLevel')
 775        end if
 776
 777        typvar_var = typvar_in
 778
 779        ! Make sure that the input variable has the same grid size than hco_file
 780        ikey = fstinf(nulfile, ni_var, nj_var, nk_var,     &
 781                      datestamplist(stepIndex), etiket_in, &
 782                      -1, -1, -1, typvar_var, varNameToRead)
 783
 784        if (ikey < 0) then
 785          if (trim(typvar_in) /= '') then
 786            typvar_var(2:2) = '@'
 787            ikey = fstinf(nulfile, ni_var, nj_var, nk_var, &
 788                          datestamplist(stepIndex), etiket_in, &
 789                          -1, -1, -1, typvar_var, varNameToRead)
 790          end if
 791          if (ikey < 0) then
 792            write(*,*) 'gio_readFile: looking for datestamp = ', datestamplist(stepIndex)
 793            write(*,*) 'gio_readFile: etiket_in = ', etiket_in
 794            write(*,*) 'gio_readFile: typvar_in = ', typvar_in
 795            call utl_abort('gio_readFile: cannot find field ' // trim(varNameToRead) // ' in file ' // trim(fileName))
 796          end if
 797        end if
 798
 799        ierr = fstprm(ikey,                                                               & ! IN
 800                      dateo_var, deet_var, npas_var, ni_var, nj_var, nk_var, nbits_var,   & ! OUT
 801                      datyp_var, ip1_var, ip2_var, ip3_var, typvar_var, nomvar_var,       & ! OUT
 802                      etiket_var, grtyp_var, ig1_var, ig2_var, ig3_var, ig4_var, swa_var, & ! OUT
 803                      lng_var, dltf_var, ubc_var, extra1_var, extra2_var, extra3_var )      ! OUT
 804        statevector%deet                      = deet_var
 805        statevector%ip2List(stepIndex)        = ip2_var
 806        statevector%npasList(stepIndex)       = npas_var
 807        statevector%dateOriginList(stepIndex) = dateo_var
 808        statevector%etiket                    = etiket_var
 809
 810        ! Check if we found a mask field by mistake - if yes, need to fix the code!
 811        if (typvar_var == '@@') then
 812          call utl_abort('gio_readFile: read a mask file by mistake - need to modify file or fix the code')
 813        end if
 814
 815        if (ni_var == hco_file%ni .and. nj_var == hco_file%nj) then
 816          ierr = fstlir(gd2d_file_r4(:,:), nulfile, ni_file, nj_file, nk_file,  &
 817                        datestamplist(stepIndex), etiket_in, ip1, -1, -1,  &
 818                        typvar_var, varNameToRead)
 819        else
 820          ! Special cases for variables that are on a different horizontal grid in LAM (e.g. TG)
 821          write(*,*)
 822          write(*,*) 'gio_readFile: variable on a different horizontal grid = ',trim(varNameToRead)
 823          write(*,*) ni_var, hco_file%ni, nj_var, hco_file%nj
 824          if (interpToPhysicsGrid) then
 825            if (associated(statevector%hco_physics)) then
 826              if (ni_var == statevector%hco_physics%ni .and. &
 827                  nj_var == statevector%hco_physics%nj) then
 828                write(*,*) 'gio_readFile: this variable on same grid as other physics variables'
 829                statevector%onPhysicsGrid(vnl_varListIndex(varName)) = .true.
 830              else
 831                call utl_abort('gio_readFile: this variable not on same grid as other physics variables')
 832              end if
 833            else
 834              call utl_abort('gio_readFile: physics grid has not been set up')
 835            end if
 836          end if
 837
 838          if (statevector%hco%global) then
 839            call utl_abort('gio_readFile: This is not allowed in global mode!')
 840          end if
 841
 842          EZscintID_var  = ezqkdef(ni_var, nj_var, grtyp_var, ig1_var, ig2_var, ig3_var, ig4_var, nulfile) ! IN
 843
 844          allocate(gd2d_var_r4(ni_var, nj_var))
 845          gd2d_var_r4(:,:) = 0.0
 846
 847          ierr = fstlir(gd2d_var_r4(:,:), nulfile, ni_var, nj_var, nk_var,  &
 848                        datestamplist(stepIndex), etiket_in, ip1, -1, -1,  &
 849                        typvar_in, varNameToRead)
 850
 851          ierr = ezdefset(hco_file%EZscintID, EZscintID_var)
 852          ierr = int_hInterpScalar(gd2d_file_r4, gd2d_var_r4, &
 853                                   interpDegree = 'NEAREST', extrapDegree_opt = 'NEUTRAL')
 854
 855          ! read the corresponding mask if it exists
 856          if (typvar_var(2:2) == '@') then
 857            write(*,*) 'gio_readFile: read mask that needs interpolation for variable name: ', nomvar_var
 858            call utl_abort('gio_readFile: not implemented yet')
 859          end if
 860
 861          deallocate(gd2d_var_r4)
 862        end if
 863
 864        if (varNameToRead == varName .or. .not. containsFullField) then
 865
 866          if (statevector%dataKind == 4) then
 867            field_r4_ptr(:,:, kIndex, stepIndex) = gd2d_file_r4(1:statevector%hco%ni, 1:statevector%hco%nj)
 868          else
 869            field_r8_ptr(:,:, kIndex, stepIndex) = real(gd2d_file_r4(1:statevector%hco%ni, 1:statevector%hco%nj), 8)
 870          end if
 871
 872        else
 873
 874          select case (trim(varName))
 875          case ('LVIS')
 876
 877            if (statevector%dataKind == 4) then
 878              field_r4_ptr(:,:, kIndex, stepIndex) = &
 879                 log(max(min(gd2d_file_r4(1:statevector%hco%ni, 1:statevector%hco%nj), &
 880                         mpc_maximum_vis_r4), mpc_minimum_vis_r4))
 881            else
 882              field_r8_ptr(:,:, kIndex, stepIndex) = real(&
 883                 log(max(min(gd2d_file_r4(1:statevector%hco%ni, 1:statevector%hco%nj), &
 884                         mpc_maximum_vis_r4), mpc_minimum_vis_r4)), 8)
 885            end if 
 886
 887          case ('LPR')
 888
 889            if (statevector%dataKind == 4) then
 890              field_r4_ptr(:,:, kIndex, stepIndex) = &
 891                 log(mpc_minimum_pr_r4 + max(0.0, gd2d_file_r4(1:statevector%hco%ni, &
 892                                                               1:statevector%hco%nj)))
 893            else
 894              field_r8_ptr(:,:, kIndex, stepIndex) = real(&
 895                 log(mpc_minimum_pr_r4 + max(0.0, gd2d_file_r4(1:statevector%hco%ni, &
 896                                                               1:statevector%hco%nj))), 8)
 897            end if
 898
 899          case default
 900            call utl_abort('gio_readFile: Oups! This should not happen... Check the code.')
 901          end select
 902        endif
 903
 904        if (ierr < 0)then
 905          write(*,*) varNameToRead, ip1, datestamplist(stepIndex)
 906          call utl_abort('gio_readFile: Problem with reading file')
 907        end if
 908
 909        ! When mpi distribution could put UU on a different mpi task than VV
 910        ! or only one wind component present in statevector
 911        ! then we re-read the corresponding UV component and store it
 912        if (statevector%extraUVallocated) then
 913          if (varName == 'UU') then
 914            ierr = fstlir(gd2d_file_r4(:,:),nulfile, ni_file, nj_file, nk_file, &
 915                          datestamplist(stepIndex), etiket_in, ip1, -1, -1,  &
 916                          typvar_in, 'VV')
 917
 918            if (statevector%dataKind == 4) then
 919              call gsv_getFieldUV(statevector, gd2d_r4_UV_ptr, kIndex)
 920              gd2d_r4_UV_ptr(1:gsv_getHco(statevector)%ni, &
 921                             1:gsv_getHco(statevector)%nj, stepIndex) &
 922                 = gd2d_file_r4(1:gsv_getHco(statevector)%ni, &
 923                                1:gsv_getHco(statevector)%nj)
 924            else
 925              call gsv_getFieldUV(statevector, gd2d_r8_UV_ptr, kIndex)
 926              gd2d_r8_UV_ptr(1:gsv_getHco(statevector)%ni, &
 927                             1:gsv_getHco(statevector)%nj, stepIndex) &
 928                 = real(gd2d_file_r4(1:gsv_getHco(statevector)%ni, &
 929                                     1:gsv_getHco(statevector)%nj), 8)
 930            end if
 931
 932          else if (varName == 'VV') then
 933            ierr = fstlir(gd2d_file_r4(:,:), nulfile, ni_file, nj_file, nk_file,  &
 934                          datestamplist(stepIndex), etiket_in, ip1, -1, -1,  &
 935                          typvar_in, 'UU')
 936
 937            if (statevector%dataKind == 4) then
 938              call gsv_getFieldUV(statevector, gd2d_r4_UV_ptr, kIndex)
 939              gd2d_r4_UV_ptr(1:gsv_getHco(statevector)%ni, &
 940                             1:gsv_getHco(statevector)%nj, stepIndex) &
 941                   = gd2d_file_r4(1:gsv_getHco(statevector)%ni, &
 942                                  1:gsv_getHco(statevector)%nj)
 943            else
 944              call gsv_getFieldUV(statevector, gd2d_r8_UV_ptr, kIndex)
 945              gd2d_r8_UV_ptr(1:gsv_getHco(statevector)%ni, &
 946                             1:gsv_getHco(statevector)%nj, stepIndex) &
 947                   = real(gd2d_file_r4(1:gsv_getHco(statevector)%ni, &
 948                                       1:gsv_getHco(statevector)%nj), 8)
 949            end if
 950
 951          end if
 952        end if
 953
 954      end do k_loop
 955    end do
 956
 957    if (statevector%hco%global .and. statevector%mykCount > 0) then
 958      write(*,*) 'deallocating hco_file'
 959      call hco_deallocate(hco_file)
 960    end if
 961
 962    ierr = fstfrm(nulfile)
 963    ierr = fclos(nulfile)        
 964    if (associated(gd2d_file_r4)) deallocate(gd2d_file_r4)
 965
 966    ! Read in an oceanMask if it is present in the file
 967    call gio_readMaskFromFile(statevector, trim(filename))
 968
 969    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
 970    write(*,*) 'gio_readFile: finished'
 971
 972  end subroutine gio_readFile
 973
 974  !--------------------------------------------------------------------------
 975  ! gio_readMaskFromFile
 976  !--------------------------------------------------------------------------
 977  subroutine gio_readMaskFromFile(stateVector, filename)
 978    !
 979    !:Purpose: Check if any ocean mask fields exist. If so, read for the surface
 980    !           or all ocean depth levels.
 981    !
 982    implicit none
 983
 984    ! Arguments:
 985    type(struct_gsv), intent(inout) :: stateVector
 986    character(len=*), intent(in)    :: fileName
 987
 988    call ocm_readMaskFromFile(stateVector%oceanMask,gsv_getHco(statevector), &
 989                              gsv_getVco(statevector), filename)
 990
 991  end subroutine gio_readMaskFromFile
 992
 993  !--------------------------------------------------------------------------
 994  ! gio_getMaskLAM
 995  !--------------------------------------------------------------------------
 996  subroutine gio_getMaskLAM(statevector_mask, hco_ptr, vco_ptr, hInterpolateDegree_opt)
 997    !
 998    !:Purpose: To read a LAM mask from a file (./analinc_mask by default).
 999    !
1000    implicit none
1001
1002    ! Arguments:
1003    type(struct_gsv),           intent(inout) :: statevector_mask
1004    type(struct_hco), pointer,  intent(in)    :: hco_ptr
1005    type(struct_vco), pointer,  intent(in)    :: vco_ptr
1006    character(len=*), optional, intent(in)    :: hInterpolateDegree_opt
1007
1008    ! Locals:
1009    character(len=12) :: hInterpolationDegree
1010
1011    if (present(hInterpolateDegree_opt)) then
1012      hInterpolationDegree = hInterpolateDegree_opt
1013    else
1014      hInterpolationDegree = 'LINEAR'
1015    end if
1016
1017    call gsv_allocate(statevector_mask, 1, hco_ptr, vco_ptr, dateStamp_opt=-1, &
1018                      dataKind_opt=pre_incrReal, &
1019                      mpi_local_opt=.true., varNames_opt=(/'MSKC'/),           &
1020                      hInterpolateDegree_opt=hInterpolationDegree)
1021    call gio_readFromFile(statevector_mask, './analinc_mask', ' ', ' ', unitConversion_opt=.false., &
1022                          vcoFileIn_opt=vco_ptr)
1023
1024  end subroutine gio_getMaskLAM
1025
1026  !--------------------------------------------------------------------------
1027  ! gio_readTrials
1028  !--------------------------------------------------------------------------
1029  subroutine gio_readTrials(stateVectorTrialIn)
1030    !
1031    !:Purpose: Reading trials
1032    !
1033    implicit none
1034
1035    ! Arguments:
1036    type(struct_gsv), target, intent(inout) :: stateVectorTrialIn
1037
1038    ! Locals:
1039    logical             :: fileExists, allocHeightSfc
1040    logical             :: useInputStateVectorTrial 
1041    integer, parameter  :: maxNumTrials = 100
1042    integer             :: fnom, fstouv, fclos, fstfrm, fstinf
1043    integer             :: ierr, ikey, stepIndex, stepIndexToRead, trialIndex, nulTrial
1044    integer             :: ni_file, nj_file, nk_file, dateStamp, varNameIndex
1045    integer             :: procToRead, numBatch, batchIndex, stepIndexBeg, stepIndexEnd
1046    character(len=2)          :: fileNumber
1047    character(len=512)        :: fileName
1048    character(len=4)          :: varNameForDateStampSearch
1049    character(len=4), pointer :: varNamesToRead(:)
1050    type(struct_gsv), target  :: stateVectorTrial
1051    type(struct_gsv), pointer :: stateVectorTrial_ptr 
1052    type(struct_gsv)          :: stateVector_1step_r4
1053
1054    call utl_tmg_start(1,'--ReadTrials')
1055
1056    if ( mmpi_myid == 0 ) then
1057      write(*,*) ''
1058      write(*,*) 'gio_readTrials: START'
1059      write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
1060    end if
1061
1062    if ( gsv_varExist(stateVectorTrialIn,'Z_T') .or. &
1063         gsv_varExist(stateVectorTrialIn,'Z_M') .or. &
1064         gsv_varExist(stateVectorTrialIn,'P_T') .or. &
1065         gsv_varExist(stateVectorTrialIn,'P_M') ) then
1066
1067      useInputStateVectorTrial = .false.
1068
1069      allocHeightSfc = ( stateVectorTrialIn%vco%Vcode /= 0 )
1070
1071      ! Allocate single-precision statevector without Z/P to read trials
1072      call gsv_allocate( stateVectorTrial, stateVectorTrialIn%numStep, &
1073                         stateVectorTrialIn%hco, stateVectorTrialIn%vco, &
1074                         dateStamp_opt=tim_getDateStamp(), &
1075                         mpi_local_opt=stateVectorTrialIn%mpi_local, &
1076                         mpi_distribution_opt='Tiles', dataKind_opt=4,  &
1077                         allocHeightSfc_opt=allocHeightSfc, &
1078                         hInterpolateDegree_opt=stateVectorTrialIn%hInterpolateDegree, &
1079                         allocHeight_opt=.false., allocPressure_opt=.false., &
1080                         beSilent_opt=.false. )
1081      call gsv_zero( stateVectorTrial )
1082      stateVectorTrial_ptr => stateVectorTrial
1083    else
1084      useInputStateVectorTrial = .true.
1085
1086      stateVectorTrial_ptr => stateVectorTrialIn
1087    end if
1088
1089    nullify(varNamesToRead)
1090    call gsv_varNamesList(varNamesToRead, stateVectorTrial_ptr)
1091
1092    varNameForDateStampSearch = ' '
1093    do varNameIndex = 1, size(varNamesToRead)
1094      select case (trim(varNamesToRead(varNameIndex)))
1095      case ('Z_T','Z_M','P_T','P_M')
1096        cycle
1097      case default
1098        varNameForDateStampSearch = varNamesToRead(varNameIndex)
1099        exit
1100      end select
1101    end do
1102
1103    ! warn if not enough mpi tasks
1104    if ( mmpi_nprocs < stateVectorTrial_ptr%numStep ) then
1105      write(*,*) 'gio_readTrials: number of trial time steps, mpi tasks = ', stateVectorTrial_ptr%numStep, mmpi_nprocs
1106      write(*,*) 'gio_readTrials: for better efficiency, the number of mpi tasks should '
1107      write(*,*) '                be at least as large as number of trial time steps'
1108    end if
1109
1110    allocHeightSfc = stateVectorTrial_ptr%heightSfcPresent
1111
1112    ! figure out number of batches of time steps for reading
1113    numBatch = ceiling(real(stateVectorTrial_ptr%numStep) / real(mmpi_nprocs))
1114    write(*,*) 'gio_readTrials: reading will be done by number of batches = ', numBatch
1115
1116    BATCH: do batchIndex = 1, numBatch
1117
1118      stepIndexBeg = 1 + (batchIndex - 1) * mmpi_nprocs
1119      stepIndexEnd = min(stateVectorTrial_ptr%numStep, stepIndexBeg + mmpi_nprocs - 1)
1120      write(*,*) 'gio_readTrials: batchIndex, stepIndexBeg/End = ', batchIndex, stepIndexBeg, stepIndexEnd
1121
1122      ! figure out which time step I will read, if any (-1 if none)
1123      stepIndexToRead = -1
1124      do stepIndex = stepIndexBeg, stepIndexEnd
1125        procToRead = nint( real(stepIndex - stepIndexBeg) * real(mmpi_nprocs) / real(stepIndexEnd - stepIndexBeg + 1) )
1126        if ( procToRead == mmpi_myid ) stepIndexToRead = stepIndex
1127        if ( mmpi_myid == 0 ) write(*,*) 'gio_readTrials: stepIndex, procToRead = ', stepIndex, procToRead
1128      end do
1129
1130      ! loop over all times for which stateVector is allocated
1131      if ( stepIndexToRead /= -1 ) then
1132        dateStamp = stateVectorTrial_ptr%dateStampList(stepIndexToRead)
1133        write(*,*) 'gio_readTrials: reading background for time step: ',stepIndexToRead, dateStamp
1134        write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
1135
1136        ! identify which trial file corresponds with current datestamp
1137        ikey = 0
1138        do trialIndex = 1, maxNumTrials
1139          write(fileNumber,'(I2.2)') trialIndex
1140          fileName = 'trlm_' // trim(fileNumber)
1141          inquire(file=trim(fileName),exist=fileExists)
1142          if ( .not. fileExists ) exit
1143          nulTrial = 0
1144          ierr = fnom(nulTrial,trim(fileName),'RND+OLD+R/O',0)
1145          ierr = fstouv(nulTrial,'RND+OLD')
1146          ikey = fstinf(nulTrial, ni_file, nj_file, nk_file,  &
1147                        dateStamp, ' ', -1, -1, -1, ' ', varNameForDateStampSearch)
1148          ierr = fstfrm(nulTrial)
1149          ierr = fclos(nulTrial)
1150          if ( ikey > 0 ) exit
1151        end do
1152
1153        if ( ikey <= 0 .or. .not.fileExists ) then 
1154          write(*,*) 'stepIndexToRead, dateStamp = ', stepIndexToRead, dateStamp
1155          call utl_abort('gio_readTrials: trial file not found for this increment timestep')
1156        end if
1157
1158        ! allocate stateVector for storing just 1 time step
1159        if ( batchIndex == 1 ) then
1160          call gsv_allocate( stateVector_1step_r4, 1, stateVectorTrial_ptr%hco, stateVectorTrial_ptr%vco, &
1161                             dateStamp_opt=dateStamp, mpi_local_opt=.false., dataKind_opt=4,        &
1162                             allocHeightSfc_opt=allocHeightSfc, varNames_opt=varNamesToRead,        &
1163                             hInterpolateDegree_opt=stateVectorTrial_ptr%hInterpolateDegree,           &
1164                             hExtrapolateDegree_opt=stateVectorTrial_ptr%hExtrapolateDegree)
1165          call gsv_zero( stateVector_1step_r4 )
1166        else
1167          call gsv_modifyDate( stateVector_1step_r4, dateStamp )
1168        end if
1169
1170        ! read the trial file for this timestep
1171        fileName = ram_fullWorkingPath(fileName)
1172        call gio_readFromFile(stateVector_1step_r4, fileName, ' ', 'P',  &
1173                              readHeightSfc_opt=allocHeightSfc)
1174
1175        ! remove from ram disk to save some space
1176        ierr = ram_remove(fileName)
1177      else
1178
1179        if ( gsv_isAllocated(stateVector_1step_r4) ) call gsv_deallocate(stateVector_1step_r4)
1180
1181      end if ! I read a time step
1182
1183      if ( stateVectorTrial_ptr%mpi_distribution == 'VarsLevs' ) then
1184        call gsv_transposeStepToVarsLevs(stateVector_1step_r4, stateVectorTrial_ptr, stepIndexBeg)
1185      else if ( stateVectorTrial_ptr%mpi_distribution == 'Tiles' ) then
1186        call gsv_transposeStepToTiles(stateVector_1step_r4, stateVectorTrial_ptr, stepIndexBeg)
1187      else
1188        call utl_abort( 'gio_readTrials: not compatible with mpi_distribution = ' // &
1189                        trim(stateVectorTrial_ptr%mpi_distribution) )
1190      end if
1191
1192      write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
1193
1194      if ( gsv_isAllocated(stateVector_1step_r4) .and. batchIndex == numBatch ) then
1195        call gsv_deallocate(stateVector_1step_r4)
1196      end if
1197
1198    end do BATCH
1199
1200    if ( .not. useInputStateVectorTrial ) then
1201      call gsv_copy( stateVectorTrial_ptr, stateVectorTrialIn, allowVarMismatch_opt=.true. )
1202      call gsv_deallocate( stateVectorTrial )
1203    end if
1204
1205    write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
1206    write(*,*) 'gio_readTrials: FINISHED'
1207    write(*,*) ''
1208
1209    call utl_tmg_stop(1)
1210
1211  end subroutine gio_readTrials
1212
1213  !--------------------------------------------------------------------------
1214  ! gio_writeToFile
1215  !--------------------------------------------------------------------------
1216  subroutine gio_writeToFile(statevector_in, fileName, etiket_in, &
1217                             scaleFactor_opt, ip3_opt, stepIndex_opt, typvar_opt,&
1218                             HUcontainsLQ_opt, unitConversion_opt, &
1219                             writeHeightSfc_opt, numBits_opt, containsFullField_opt)
1220    !
1221    !:Purpose: Write a statevector object to an RPN standard file.
1222    !
1223    implicit none
1224
1225    ! Arguments:
1226    type(struct_gsv), target,   intent(in) :: statevector_in
1227    character(len=*),           intent(in) :: fileName
1228    character(len=*),           intent(in) :: etiket_in
1229    real(8),          optional, intent(in) :: scaleFactor_opt
1230    integer,          optional, intent(in) :: ip3_opt, stepIndex_opt
1231    character(len=*), optional, intent(in) :: typvar_opt
1232    logical,          optional, intent(in) :: HUcontainsLQ_opt
1233    logical,          optional, intent(in) :: unitConversion_opt
1234    logical,          optional, intent(in) :: writeHeightSfc_opt
1235    integer,          optional, intent(in) :: numBits_opt
1236    logical,          optional, intent(in) :: containsFullField_opt
1237
1238    ! Locals:
1239    logical :: iDoWriting, unitConversion, containsFullField
1240    integer :: fclos, fnom, fstouv, fstfrm
1241    integer :: nulfile, stepIndex
1242    integer :: ierr, fstecr, ezdefset
1243    integer :: ni, nj, nk
1244    integer :: dateo, npak, levIndex, nlev, varIndex, maskLevIndex
1245    integer :: ip1, ip2, ip3, deet, npas, datyp
1246    integer :: ig1 ,ig2 ,ig3 ,ig4
1247    integer :: yourid, nsize, youridy, youridx
1248    real(4) :: factor_r4, work_r4
1249    character(len=1)          :: grtyp
1250    character(len=4)          :: nomvar
1251    character(len=2)          :: typvar
1252    character(len=12)         :: etiket
1253    character(len=4)          :: varLevel
1254    character(len=4), pointer :: varNamesToRead(:)
1255    integer, allocatable :: mask(:,:)
1256    real(4), allocatable :: work2d_r4(:,:), work2dFile_r4(:,:), gd_send_r4(:,:), gd_recv_r4(:,:,:)
1257    real(8), pointer :: field_r8(:,:,:,:), heightSfc_ptr(:,:)
1258    real(4), pointer :: field_r4(:,:,:,:)
1259    type(struct_gsv), pointer :: statevector
1260    type(struct_gsv), target  :: statevector_tiles
1261
1262    write(*,*) 'gio_writeToFile: START'
1263
1264    call utl_tmg_start(161,'low-level--gsv_writeToFile')
1265
1266    call readNml()
1267
1268    !
1269    !- 1.  Since this routine can only work with 'Tiles' distribution when mpi_local = .true., 
1270    !      transpose a statevector using 'VarsLevs' distribution
1271    !
1272    if ( stateVector_in%mpi_distribution == 'VarsLevs' .and. &
1273         stateVector_in%mpi_local ) then
1274      nullify(varNamesToRead)
1275      call gsv_varNamesList(varNamesToRead,statevector_in) 
1276      call gsv_allocate(statevector_tiles, statevector_in%numStep, statevector_in%hco, &
1277                        statevector_in%vco, dataKind_opt=statevector_in%dataKind,      &
1278                        mpi_local_opt=.true., mpi_distribution_opt='Tiles',            &
1279                        dateStampList_opt=statevector_in%dateStampList,                &
1280                        varNames_opt=varNamesToRead)
1281      call gsv_transposeVarsLevsToTiles(statevector_in, statevector_tiles)
1282      statevector => stateVector_tiles
1283      deallocate(varNamesToRead)
1284    else
1285      statevector => stateVector_in
1286    end if
1287
1288    !
1289    !- 2.  Set some variables
1290    !
1291    if ( .not. statevector%mpi_local ) then
1292      write(*,*) 'gio_writeToFile: writing statevector that is already mpiglobal!'
1293    end if
1294
1295    if (present(ip3_opt)) then
1296      ip3 = ip3_opt
1297    else
1298      ip3 = 0
1299    end if
1300
1301    if (present(unitConversion_opt)) then
1302      unitConversion = unitConversion_opt
1303    else
1304      unitConversion = .true.
1305    end if
1306
1307    if (present(containsFullField_opt)) then
1308      containsFullField = containsFullField_opt
1309    else
1310      containsFullField = .false.
1311    end if
1312    write(*,*) 'gio_writeToFile: containsFullField = ', containsFullField
1313
1314    ! if step index not specified, choose anltime (usually center of window)
1315    if (present(stepIndex_opt)) then
1316      stepIndex = stepIndex_opt
1317    else
1318      stepIndex = statevector%anltime
1319    end if
1320
1321    if ( present(numBits_opt) ) then
1322      npak = -numBits_opt
1323    else
1324      npak = -32
1325    end if
1326
1327    ! initialization of parameters for writing to file
1328    if (statevector%dateOriginList(stepIndex) /= mpc_missingValue_int) then
1329      dateo = statevector%dateOriginList(stepIndex)
1330    else
1331      dateo  = statevector%dateStampList(stepIndex)
1332    end if
1333
1334    if (statevector%deet /= mpc_missingValue_int) then
1335      deet = statevector%deet
1336    else
1337      deet = 0
1338    end if
1339
1340    if (statevector%npasList(stepIndex) /= mpc_missingValue_int) then
1341      npas = statevector%npasList(stepIndex)
1342    else
1343      npas = 0
1344    end if
1345
1346    if (statevector%ip2List(stepIndex) /= mpc_missingValue_int) then
1347      ip2 = statevector%ip2List(stepIndex)
1348    else
1349      ip2 = 0
1350    end if
1351
1352    if (statevector%etiket /= 'UNDEFINED') then
1353      etiket = statevector%etiket
1354    else
1355      etiket = trim(etiket_in)
1356    end if
1357
1358    ni     = statevector%ni
1359    nj     = statevector%nj
1360    nk     = 1
1361    if ( present(typvar_opt) ) then
1362      typvar = trim(typvar_opt)
1363    else
1364      typvar = 'R'
1365    end if
1366    if ( statevector%oceanMask%maskPresent ) then
1367      typvar(2:2) = '@'
1368    end if
1369    grtyp  = statevector%hco%grtyp
1370    ig1    = statevector%hco%ig1
1371    ig2    = statevector%hco%ig2
1372    ig3    = statevector%hco%ig3
1373    ig4    = statevector%hco%ig4
1374    datyp  = 134
1375
1376    ! only proc 0 does writing or each proc when data is global 
1377    ! (assuming only called for proc with global data)
1378    iDoWriting = (mmpi_myid == 0) .or. (.not. statevector%mpi_local)
1379
1380    !
1381    !- 3.  Write the global StateVector
1382    !
1383    if (iDoWriting) then
1384
1385      !- Open output field
1386      nulfile = 0
1387      write(*,*) 'gio_writeToFile: file name = ',trim(fileName)
1388      ierr = fnom(nulfile,trim(fileName),'RND+APPEND',0)
1389
1390      if ( ierr >= 0 ) then
1391        ierr  =  fstouv(nulfile,'RND')
1392      else
1393        call utl_abort('gio_writeToFile: problem opening output file')
1394      end if
1395
1396      if (nulfile == 0 ) then
1397        call utl_abort('gio_writeToFile: unit number for output file not valid')
1398      end if
1399
1400      !- Write TicTacToc
1401      if ( (mmpi_myid == 0 .and. statevector%mpi_local) .or. .not.statevector%mpi_local ) then
1402        call writeTicTacToc(statevector,nulfile,etiket) ! IN
1403      endif
1404
1405    end if
1406
1407    allocate(gd_send_r4(statevector%lonPerPEmax,statevector%latPerPEmax))
1408    if ( mmpi_myid == 0 .or. (.not. statevector%mpi_local) ) then
1409      allocate(work2d_r4(statevector%ni,statevector%nj))
1410      if (statevector%mpi_local) then
1411        ! Receive tile data from all mpi tasks
1412        allocate(gd_recv_r4(statevector%lonPerPEmax,statevector%latPerPEmax,mmpi_nprocs))
1413      else
1414        ! Already have entire domain on mpi task (lat/lonPerPEmax == nj/ni)
1415        allocate(gd_recv_r4(statevector%lonPerPEmax,statevector%latPerPEmax,1))
1416      end if
1417    else
1418      allocate(gd_recv_r4(1,1,1))
1419      allocate(work2d_r4(1,1))
1420    end if
1421
1422    ! Write surface height, if requested
1423    if ( present(writeHeightSfc_opt) ) then
1424      if ( writeHeightSfc_opt .and. gsv_isAssocHeightSfc(statevector) ) then
1425        write(*,*) 'gio_writeToFile: writing surface height'
1426        heightSfc_ptr => gsv_getHeightSfc(statevector)
1427        ! MPI communication
1428        gd_send_r4(1:statevector%lonPerPE, &
1429                   1:statevector%latPerPE) =  &
1430             real(heightSfc_ptr(statevector%myLonBeg:statevector%myLonEnd, &
1431                                    statevector%myLatBeg:statevector%myLatEnd),4)
1432        if ( (mmpi_nprocs > 1) .and. statevector%mpi_local ) then
1433          nsize = statevector%lonPerPEmax * statevector%latPerPEmax
1434          call rpn_comm_gather(gd_send_r4, nsize, 'mpi_real4',  &
1435                               gd_recv_r4, nsize, 'mpi_real4', 0, 'grid', ierr )
1436        else
1437          ! just copy when either nprocs is 1 or data is global
1438          gd_recv_r4(:,:,1) = gd_send_r4(:,:)
1439        end if
1440        if ( mmpi_myid == 0 .and. statevector%mpi_local ) then
1441          !$OMP PARALLEL DO PRIVATE(youridy,youridx,yourid)
1442          do youridy = 0, (mmpi_npey-1)
1443            do youridx = 0, (mmpi_npex-1)
1444              yourid = youridx + youridy*mmpi_npex
1445                work2d_r4(statevector%allLonBeg(youridx+1):statevector%allLonEnd(youridx+1),  &
1446                          statevector%allLatBeg(youridy+1):statevector%allLatEnd(youridy+1)) = &
1447                  gd_recv_r4(1:statevector%allLonPerPE(youridx+1),  &
1448                             1:statevector%allLatPerPE(youridy+1),yourid+1)
1449            end do
1450          end do
1451          !$OMP END PARALLEL DO
1452        else if ( .not. statevector%mpi_local ) then
1453          work2d_r4(:,:) = gd_recv_r4(:,:,1)
1454        end if
1455
1456        ! now do writing
1457        if (iDoWriting) then
1458          ip1 = statevector%vco%ip1_sfc
1459          nomvar = 'GZ'
1460
1461          !- Scale
1462          factor_r4 = real(1.0d0/10.0d0,4)
1463          work2d_r4(:,:) = factor_r4 * work2d_r4(:,:)
1464
1465          !- Writing to file
1466          ierr = fstecr(work2d_r4, work_r4, npak, nulfile, dateo, deet, npas, ni, nj, &
1467                        nk, ip1, ip2, ip3, typvar, nomvar, etiket, grtyp,      &
1468                        ig1, ig2, ig3, ig4, datyp, .false.)
1469        end if ! iDoWriting
1470
1471      end if
1472    end if
1473
1474    do varIndex = 1, vnl_numvarmax 
1475 
1476      if (gsv_varExist(statevector,vnl_varNameList(varIndex)) ) then
1477
1478        nlev = statevector%varNumLev(varIndex)
1479
1480        do levIndex = 1, nlev
1481
1482          if ( statevector%dataKind == 8 ) then
1483            call gsv_getField(statevector,field_r8,vnl_varNameList(varIndex))
1484            gd_send_r4(1:statevector%lonPerPE,  &
1485                       1:statevector%latPerPE) =  &
1486                real(field_r8(statevector%myLonBeg:statevector%myLonEnd, &
1487                              statevector%myLatBeg:statevector%myLatEnd,levIndex,stepIndex),4)
1488          else
1489            call gsv_getField(statevector,field_r4,vnl_varNameList(varIndex))
1490            gd_send_r4(1:statevector%lonPerPE,  &
1491                       1:statevector%latPerPE) =  &
1492                field_r4(statevector%myLonBeg:statevector%myLonEnd, &
1493                         statevector%myLatBeg:statevector%myLatEnd,levIndex,stepIndex)
1494          end if
1495
1496          nsize = statevector%lonPerPEmax*statevector%latPerPEmax
1497          if ( (mmpi_nprocs > 1) .and. (statevector%mpi_local) ) then
1498            call rpn_comm_gather(gd_send_r4, nsize, 'mpi_real4',  &
1499                                 gd_recv_r4, nsize, 'mpi_real4', 0, 'grid', ierr )
1500          else
1501            ! just copy when either nprocs is 1 or data is global
1502            gd_recv_r4(:,:,1) = gd_send_r4(:,:)
1503          end if
1504
1505          if ( mmpi_myid == 0 .and. statevector%mpi_local ) then
1506            !$OMP PARALLEL DO PRIVATE(youridy,youridx,yourid)
1507            do youridy = 0, (mmpi_npey-1)
1508              do youridx = 0, (mmpi_npex-1)
1509                yourid = youridx + youridy*mmpi_npex
1510                work2d_r4(statevector%allLonBeg(youridx+1):statevector%allLonEnd(youridx+1),  &
1511                            statevector%allLatBeg(youridy+1):statevector%allLatEnd(youridy+1)) = &
1512                    gd_recv_r4(1:statevector%allLonPerPE(youridx+1),  &
1513                               1:statevector%allLatPerPE(youridy+1), yourid+1)
1514              end do
1515            end do
1516            !$OMP END PARALLEL DO
1517          else if ( .not. statevector%mpi_local ) then
1518            work2d_r4(:,:) = gd_recv_r4(:,:,1)
1519          end if
1520
1521          ! now do writing
1522          if (iDoWriting) then
1523
1524            ! Set the ip1 value
1525            if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'MM') then
1526              ip1 = statevector%vco%ip1_M(levIndex)
1527            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'TH') then
1528              ip1 = statevector%vco%ip1_T(levIndex)
1529            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'SF') then
1530              ip1 = 0
1531            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'SFTH') then
1532              ip1 = statevector%vco%ip1_T_2m
1533            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'SFMM') then
1534              ip1 = statevector%vco%ip1_M_10m
1535            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'OT') then
1536              ip1 = vco_ip1_other(levIndex)
1537            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'DP') then
1538              ip1 = statevector%vco%ip1_depth(levIndex)
1539            else if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'SS') then
1540              ip1 = statevector%vco%ip1_seaLevel
1541            else
1542              varLevel = vnl_varLevelFromVarname(vnl_varNameList(varIndex))
1543              write(*,*) 'gio_writeToFile: unknown type of vertical level: ', varLevel
1544              call utl_abort('gio_writeToFile')
1545            end if
1546
1547            ! Set the level index for the mask (if present)
1548            if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'DP') then
1549              maskLevIndex = levIndex
1550            else
1551              maskLevIndex = 1
1552            end if
1553             
1554            ! Set the output variable name
1555            nomvar = trim(vnl_varNameList(varIndex))
1556            if ( trim(nomvar) == 'HU' .and. present(HUcontainsLQ_opt) ) then
1557               if ( HUcontainsLQ_opt ) nomvar = 'LQ'
1558            end if
1559
1560            if ( vnl_varKindFromVarname(trim(nomvar)) == 'CH' .and. containsFullField ) then 
1561              ! Impose lower limits
1562              if ( gsv_minValVarKindCH(vnl_varListIndex(nomvar)) > 1.01*mpc_missingValue_r8 ) &
1563                work2d_r4(:,:) = max( work2d_r4(:,:), real(gsv_minValVarKindCH(vnl_varListIndex(trim(nomvar)))) )
1564            end if
1565 
1566            ! Set the conversion factor
1567            if ( unitConversion ) then
1568
1569              if ( trim(nomvar) == 'UU' .or. trim(nomvar) == 'VV') then
1570                factor_r4 = mpc_knots_per_m_per_s_r4 ! m/s -> knots
1571              else if ( trim(nomvar) == 'P0' .or. trim(nomvar) == 'UP' .or.  &
1572                        trim(nomvar) == 'PB' .or. trim(nomvar) == 'P0LS' ) then
1573                factor_r4 = 0.01 ! Pa -> hPa
1574              else if ( vnl_varKindFromVarname(trim(nomvar)) == 'CH' ) then 
1575                if ( gsv_conversionVarKindCHtoMicrograms ) then
1576                  ! Apply inverse transform of unit conversion
1577                  if ( trim(nomvar) == 'TO3' .or. trim(nomvar) == 'O3L' ) then
1578                    factor_r4 = 1.0E-9*mpc_molar_mass_dry_air_r4 &
1579                              /vnl_varMassFromVarName(trim(nomvar)) ! micrograms/kg -> vmr
1580                  else
1581                    factor_r4 = 1.0d0 ! no conversion
1582                  end if
1583                else
1584                  factor_r4 = 1.0d0 ! no conversion
1585                end if
1586              else
1587                factor_r4 = 1.0d0 ! no conversion
1588              end if
1589            else
1590              factor_r4 = 1.0
1591            end if
1592
1593            if (present(scaleFactor_opt)) factor_r4 = factor_r4 * real(scaleFactor_opt,4)
1594
1595            !- Scale
1596            work2d_r4(:,:) = factor_r4 * work2d_r4(:,:)
1597
1598            !- Convert Kelvin to Celcius only if full field
1599            if (containsFullField .and. (trim(nomvar) == 'TT' .or. trim(nomvar) == 'TM')  ) then
1600              where (work2d_r4(:,:) > 100.0)
1601                work2d_r4(:,:) = work2d_r4(:,:) - mpc_k_c_degree_offset_r4
1602              end where
1603            end if
1604
1605            !- Do interpolation back to physics grid, if needed
1606            if ( interpToPhysicsGrid .and. statevector%onPhysicsGrid(varIndex) ) then
1607              write(*,*) 'writeToFile: interpolate this variable back to physics grid: ', &
1608                         nomvar, associated(statevector%hco_physics)
1609              allocate(work2dFile_r4(statevector%hco_physics%ni,statevector%hco_physics%nj))
1610              work2dFile_r4(:,:) = 0.0
1611              ierr = ezdefset( statevector%hco_physics%EZscintID, statevector%hco%EZscintID )
1612              ierr = int_hInterpScalar( work2dFile_r4, work2d_r4, &
1613                                        interpDegree='NEAREST', extrapDegree_opt='NEUTRAL' )
1614
1615              !- Writing to file
1616              ierr = fstecr(work2dFile_r4, work_r4, npak, nulfile, dateo, deet, npas, &
1617                            statevector%hco_physics%ni, statevector%hco_physics%nj, &
1618                            nk, ip1, ip2, ip3, typvar, nomvar, etiket, grtyp,      &
1619                            statevector%hco_physics%ig1, statevector%hco_physics%ig2, &
1620                            statevector%hco_physics%ig3, statevector%hco_physics%ig4, &
1621                            datyp, .false.)
1622              deallocate(work2dFile_r4)
1623
1624            else
1625
1626              !- Writing to file
1627              ierr = fstecr(work2d_r4, work_r4, npak, nulfile, dateo, deet, npas, ni, nj, &
1628                            nk, ip1, ip2, ip3, typvar, nomvar, etiket, grtyp,      &
1629                            ig1, ig2, ig3, ig4, datyp, .false.)
1630
1631            end if
1632
1633            if ( statevector%oceanMask%maskPresent ) then
1634              if (.not.allocated(mask)) allocate(mask(ni,nj))
1635              call ocm_copyToInt(statevector%oceanMask,mask,maskLevIndex)
1636              ierr = fstecr(mask, work_r4, -1, nulfile, dateo, deet, npas, ni, nj, &
1637                            nk, ip1, ip2, ip3, '@@', nomvar, etiket, grtyp,      &
1638                            ig1, ig2, ig3, ig4, 2, .false.)
1639            end if
1640
1641          end if ! iDoWriting
1642
1643        end do ! levIndex
1644
1645      end if ! varExist
1646
1647    end do ! varIndex
1648
1649    deallocate(work2d_r4)
1650    deallocate(gd_send_r4)
1651    deallocate(gd_recv_r4)
1652    if (allocated(mask)) deallocate(mask)
1653
1654    if (iDoWriting) then
1655      ierr = fstfrm(nulfile)
1656      ierr = fclos(nulfile)        
1657    end if
1658
1659    !
1660    !- 4.  Ending
1661    !
1662    if ( stateVector_in%mpi_distribution == 'VarsLevs' .and. &
1663         stateVector_in%mpi_local ) then
1664      call gsv_deallocate(statevector_tiles)
1665    end if
1666
1667    call utl_tmg_stop(161)
1668    write(*,*) 'gio_writeToFile: END'
1669
1670  end subroutine gio_writeToFile
1671
1672  !--------------------------------------------------------------------------
1673  ! writeTicTacToc
1674  !--------------------------------------------------------------------------
1675  subroutine writeTicTacToc(statevector,iun,etiket)
1676    !
1677    !:Purpose: Write a statevector object grid descriptors to an RPN standard
1678    !           file.
1679    !
1680    implicit none
1681
1682    ! Arguments:
1683    type(struct_gsv), intent(in) :: statevector
1684    integer,          intent(in) :: iun
1685    character(len=*), intent(in) :: etiket
1686
1687    ! Locals:
1688    integer :: ier
1689    integer :: dateo, npak, status, fstecr
1690    integer :: ip1,ip2,ip3,deet,npas,datyp,ig1,ig2,ig3,ig4
1691    integer :: ig1_tictac,ig2_tictac,ig3_tictac,ig4_tictac
1692    character(len=1)  :: grtyp
1693    character(len=2)  :: typvar
1694
1695    !
1696    !- 1.  Writing Tic-Tac
1697    !
1698    if ( statevector % hco % grtyp == 'Z' ) then
1699      npak     = -32
1700      deet     =  0
1701      ip1      =  statevector%hco%ig1
1702      ip2      =  statevector%hco%ig2
1703      ip3      =  statevector%hco%ig3
1704      npas     =  0
1705      datyp    =  1
1706      grtyp    =  statevector%hco%grtypTicTac
1707      typvar   = 'X'
1708      dateo =  0
1709
1710      call cxgaig ( grtyp,                                          & ! IN
1711                    ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac, & ! OUT
1712                    real(statevector%hco%xlat1), real(statevector%hco%xlon1),   & ! IN
1713                    real(statevector%hco%xlat2), real(statevector%hco%xlon2)  )   ! IN
1714
1715      ig1      =  ig1_tictac
1716      ig2      =  ig2_tictac
1717      ig3      =  ig3_tictac
1718      ig4      =  ig4_tictac
1719
1720      ier = utl_fstecr(statevector%hco%lon*mpc_degrees_per_radian_r8, npak, &
1721                       iun, dateo, deet, npas, statevector%ni, 1, 1, ip1,    &
1722                       ip2, ip3, typvar, '>>', etiket, grtyp, ig1,          &
1723                       ig2, ig3, ig4, datyp, .true.)
1724
1725      ier = utl_fstecr(statevector%hco%lat*mpc_degrees_per_radian_r8, npak, &
1726                       iun, dateo, deet, npas, 1, statevector%nj, 1, ip1,    &
1727                       ip2, ip3, typvar, '^^', etiket, grtyp, ig1,          &
1728                       ig2, ig3, ig4, datyp, .true.)
1729
1730      ! Also write the tic tac for the physics grid
1731      if ( any(statevector%onPhysicsGrid(:)) ) then
1732
1733        ip1      =  statevector%hco_physics%ig1
1734        ip2      =  statevector%hco_physics%ig2
1735        ip3      =  statevector%hco_physics%ig3
1736        grtyp    =  statevector%hco_physics%grtypTicTac
1737        
1738        call cxgaig ( grtyp,                                          & ! IN
1739                      ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac, & ! OUT
1740                      real(statevector%hco_physics%xlat1), real(statevector%hco_physics%xlon1),   & ! IN
1741                      real(statevector%hco_physics%xlat2), real(statevector%hco_physics%xlon2)  )   ! IN
1742
1743        ig1      =  ig1_tictac
1744        ig2      =  ig2_tictac
1745        ig3      =  ig3_tictac
1746        ig4      =  ig4_tictac
1747
1748        ier = utl_fstecr(statevector%hco_physics%lon*mpc_degrees_per_radian_r8, npak, &
1749                         iun, dateo, deet, npas, statevector%hco_physics%ni, 1, 1, ip1,    &
1750                         ip2, ip3, typvar, '>>', etiket, grtyp, ig1,          &
1751                         ig2, ig3, ig4, datyp, .true.)
1752
1753        ier = utl_fstecr(statevector%hco_physics%lat*mpc_degrees_per_radian_r8, npak, &
1754                         iun, dateo, deet, npas, 1, statevector%hco_physics%nj, 1, ip1,    &
1755                         ip2, ip3, typvar, '^^', etiket, grtyp, ig1,          &
1756                         ig2, ig3, ig4, datyp, .true.)
1757      end if
1758
1759    else if ( statevector % hco % grtyp == 'U' ) then
1760      npak     = -32
1761      ier = fstecr(statevector%hco%tictacU, statevector%hco%tictacU, npak, iun, 0, 0, 0, size(statevector%hco%tictacU), 1, 1  , &
1762                   statevector%hco%ig1, statevector%hco%ig2,  statevector%hco%ig3, 'X', '^>', etiket, &
1763                   'F', 1, 0, 0, 0, 5, .false.)
1764
1765    else if ( statevector % hco % grtyp == 'Y' ) then
1766      npak     = -32
1767      deet     =  0
1768      ip1      =  statevector%hco%ig1
1769      ip2      =  statevector%hco%ig2
1770      ip3      =  statevector%hco%ig3
1771      npas     =  0
1772      datyp    =  1
1773      grtyp    =  statevector%hco%grtypTicTac
1774      typvar   = 'X'
1775      dateo =  0
1776
1777      call cxgaig ( grtyp,                                          & ! IN
1778                    ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac, & ! OUT
1779                    real(statevector%hco%xlat1), real(statevector%hco%xlon1),   & ! IN
1780                    real(statevector%hco%xlat2), real(statevector%hco%xlon2)  )   ! IN
1781
1782      ig1      =  ig1_tictac
1783      ig2      =  ig2_tictac
1784      ig3      =  ig3_tictac
1785      ig4      =  ig4_tictac
1786
1787      ier = utl_fstecr(statevector%hco%lon2d_4*mpc_degrees_per_radian_r8, npak, &
1788                       iun, dateo, deet, npas, statevector%ni, statevector%nj, 1,    &
1789                       ip1, ip2, ip3, typvar, '>>', etiket, grtyp,          &
1790                       ig1, ig2, ig3, ig4, datyp, .true.)
1791
1792      ier = utl_fstecr(statevector%hco%lat2d_4*mpc_degrees_per_radian_r8, npak, &
1793                       iun, dateo, deet, npas, statevector%ni, statevector%nj, 1,    &
1794                       ip1, ip2, ip3, typvar, '^^', etiket, grtyp,          &
1795                       ig1, ig2, ig3, ig4, datyp, .true.)
1796
1797
1798    end if
1799
1800    !
1801    !- Writing Toc-Toc
1802    !
1803    if ( statevector%vco%vgridPresent ) then
1804      status = vgd_write(statevector%vco%vgrid,iun,'fst')
1805      if ( status /= VGD_OK ) then
1806        call utl_abort('writeTicTacToc: ERROR with vgd_write')
1807      end if
1808    end if
1809
1810  end subroutine writeTicTacToc
1811
1812  !--------------------------------------------------------------------------
1813  ! gio_fileUnitsToStateUnits
1814  !--------------------------------------------------------------------------
1815  subroutine gio_fileUnitsToStateUnits(statevector, containsFullField, stepIndex_opt)
1816    !
1817    !:Purpose: Unit conversion needed after reading RPN standard file
1818    !
1819    implicit none
1820
1821    ! Arguments:
1822    type(struct_gsv),  intent(inout)  :: statevector
1823    logical,           intent(in)     :: containsFullField
1824    integer, optional, intent(in)     :: stepIndex_opt
1825
1826    ! Locals:
1827    integer :: stepIndex, stepIndexBeg, stepIndexEnd, kIndex
1828    real(4), pointer :: field_r4_ptr(:,:,:,:), fieldUV_r4_ptr(:,:,:)
1829    real(8), pointer :: field_r8_ptr(:,:,:,:), fieldUV_r8_ptr(:,:,:)
1830    real(8)          :: multFactor
1831    character(len=4) :: varName
1832
1833    if (present(stepIndex_opt)) then
1834      stepIndexBeg = stepIndex_opt
1835      stepIndexEnd = stepIndex_opt
1836    else
1837      stepIndexBeg = 1
1838      stepIndexEnd = statevector%numStep
1839    end if
1840
1841    if (statevector%dataKind == 4) then
1842      call gsv_getField(statevector, field_r4_ptr)
1843    else
1844      call gsv_getField(statevector, field_r8_ptr)
1845    end if
1846
1847    step_loop: do stepIndex = stepIndexBeg, stepIndexEnd
1848
1849      ! Do unit conversion for all variables
1850      KINDEXCYCLE: do kIndex = statevector%mykBeg, statevector%mykEnd
1851        varName = gsv_getVarNameFromK(statevector, kIndex)
1852
1853        if (trim(varName) == 'UU' .or. trim(varName) == 'VV') then
1854          multFactor = mpc_m_per_s_per_knot_r8 ! knots -> m/s
1855        else if (trim(varName) == 'P0' .or. trim(varName) == 'P0LS') then
1856          multFactor = mpc_pa_per_mbar_r8 ! hPa -> Pa
1857        else if (vnl_varKindFromVarname(trim(varName)) == 'CH') then 
1858          if (gsv_conversionVarKindCHtoMicrograms) then
1859            if (trim(varName) == 'TO3' .or. trim(varName) == 'O3L') then
1860              ! Convert from volume mixing ratio to micrograms/kg
1861              ! Standard ozone input would not require this conversion as it is already in micrograms/kg
1862              multFactor = 1.0d9 * vnl_varMassFromVarName(trim(varName)) / &
1863                           mpc_molar_mass_dry_air_r8 ! vmr -> micrograms/kg
1864            else
1865              multFactor = 1.0d0 ! no conversion
1866            end if
1867          else
1868            multFactor = 1.0d0 ! no conversion
1869          end if
1870        else
1871          multFactor = 1.0d0 ! no conversion
1872        end if
1873
1874        if (multFactor /= 1.0d0) then
1875          if (statevector%dataKind == 4) then
1876            field_r4_ptr(:,:, kIndex, stepIndex) = real(multFactor * field_r4_ptr(:,:, kIndex, stepIndex), 4)
1877          else
1878            field_r8_ptr(:,:, kIndex, stepIndex) = real(multFactor * field_r8_ptr(:,:, kIndex, stepIndex), 8)
1879          end if
1880        end if
1881
1882        if (trim(varName) == 'TT' .and. containsFullField) then
1883          if (statevector%dataKind == 4) then
1884            field_r4_ptr(:,:, kIndex, stepIndex) = real(field_r4_ptr(:,:, kIndex, stepIndex) +  &
1885                                                        mpc_k_c_degree_offset_r8, 4)
1886          else
1887            field_r8_ptr(:,:, kIndex, stepIndex) = real(field_r8_ptr(:,:, kIndex, stepIndex) +  &
1888                                                        mpc_k_c_degree_offset_r8, 8)
1889          end if
1890        end if
1891
1892        if (trim(varName) == 'TM' .and. containsFullField) then
1893          if (statevector%dataKind == 4) then
1894            where (field_r4_ptr(:,:, kIndex, stepIndex) < 100.0)
1895              field_r4_ptr(:,:, kIndex, stepIndex) = real(field_r4_ptr(:,:, kIndex, stepIndex) + &
1896                                                          mpc_k_c_degree_offset_r8, 4)
1897            end where
1898          else
1899            where (field_r8_ptr(:,:, kIndex, stepIndex) < 100.0)
1900              field_r8_ptr(:,:, kIndex, stepIndex) = real(field_r8_ptr(:,:, kIndex, stepIndex) + &
1901                                                          mpc_k_c_degree_offset_r8, 8)
1902            end where
1903          end if
1904        end if
1905
1906        if (trim(varName) == 'VIS' .and. containsFullField) then
1907          if (statevector%dataKind == 4) then
1908            field_r4_ptr(:,:, kIndex, stepIndex) = min(field_r4_ptr(:,:, kIndex, stepIndex), mpc_maximum_vis_r4)
1909          else
1910            field_r8_ptr(:,:, kIndex, stepIndex) = min(field_r8_ptr(:,:, kIndex, stepIndex), mpc_maximum_vis_r8)
1911          end if
1912        end if
1913
1914        if (vnl_varKindFromVarname(trim(varName)) == 'CH' .and. containsFullField) then 
1915          if (gsv_minValVarKindCH(vnl_varListIndex(varName)) > 1.01 * mpc_missingValue_r8) then
1916            if (statevector%dataKind == 4) then
1917              field_r4_ptr(:,:, kIndex, stepIndex) = max(field_r4_ptr(:,:, kIndex, stepIndex), &
1918                                                         real(gsv_minValVarKindCH(vnl_varListIndex(trim(varName)))))
1919            else
1920              field_r8_ptr(:,:, kIndex, stepIndex) = max(field_r8_ptr(:,:, kIndex, stepIndex), &
1921                                                         real(gsv_minValVarKindCH(vnl_varListIndex(trim(varName)))))
1922            end if
1923          end if
1924        end if
1925
1926        if (trim(varName) == 'PR' .and. containsFullField) then
1927          if (statevector%dataKind == 4) then
1928            field_r4_ptr(:,:, kIndex, stepIndex) = max(field_r4_ptr(:,:, kIndex, stepIndex), 0.0)
1929          else
1930            field_r8_ptr(:,:, kIndex, stepIndex) = max(field_r8_ptr(:,:, kIndex, stepIndex), 0.0)
1931          end if
1932        end if
1933      end do KINDEXCYCLE
1934
1935      ! Do unit conversion for extra copy of winds, if present
1936      IFWINDS: if (statevector%extraUVallocated) then
1937        multFactor = mpc_m_per_s_per_knot_r8 ! knots -> m/s
1938
1939        if (statevector%dataKind == 4) then
1940          !$OMP PARALLEL DO PRIVATE (kIndex, fieldUV_r4_ptr)
1941          do kIndex = statevector%myUVkBeg, statevector%myUVkEnd
1942            nullify(fieldUV_r4_ptr)
1943            call gsv_getFieldUV(statevector, fieldUV_r4_ptr, kIndex)
1944            fieldUV_r4_ptr(:,:, stepIndex) = real(multFactor * fieldUV_r4_ptr(:,:, stepIndex), 4)
1945          end do
1946          !$OMP END PARALLEL DO
1947        else
1948          !$OMP PARALLEL DO PRIVATE (kIndex, fieldUV_r8_ptr)
1949          do kIndex = statevector%myUVkBeg, statevector%myUVkEnd
1950            nullify(fieldUV_r8_ptr)
1951            call gsv_getFieldUV(statevector, fieldUV_r8_ptr, kIndex)
1952            fieldUV_r8_ptr(:,:, stepIndex) = real(multFactor * fieldUV_r8_ptr(:,:, stepIndex), 8)
1953          end do
1954          !$OMP END PARALLEL DO
1955        end if
1956      end if IFWINDS
1957
1958    end do step_loop
1959
1960  end subroutine gio_fileUnitsToStateUnits
1961
1962  !--------------------------------------------------------------------------
1963  ! readNml (private)
1964  !--------------------------------------------------------------------------
1965  subroutine readNml()
1966    !
1967    !:Purpose: Read the namelist NAMSTIO
1968    !
1969    implicit none
1970
1971    ! Locals:
1972    integer       :: nulnam, ierr, fnom, fclos
1973    logical, save :: firstCall = .true.
1974
1975    NAMELIST /NAMSTIO/interpToPhysicsGrid
1976
1977    if (firstCall) then
1978      
1979      ! set the default values
1980      interpToPhysicsGrid = .false.
1981
1982      ! read the namelist block if it exists
1983      if ( .not. utl_isNamelistPresent('NAMSTIO','./flnml') ) then
1984        if ( mmpi_myid == 0 ) then
1985          write(*,*) 'readNml (gio): namstio is missing in the namelist. The default values will be taken.'
1986        end if
1987      else
1988        ! Read namelist NAMSTIO
1989        nulnam = 0
1990        ierr = fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
1991        read(nulnam,nml=namstio,iostat=ierr)
1992        if (ierr /= 0) call utl_abort('readNml (gio): Error reading namelist')
1993        if (mmpi_myid == 0) write(*,nml=namstio)
1994        ierr = fclos(nulnam)
1995      end if
1996
1997      firstCall = .false.
1998
1999    end if
2000
2001  end subroutine readNml
2002
2003end module gridStateVectorFileIO_mod