gridBinning_mod sourceΒΆ

  1module gridBinning_mod
  2  ! MODULE gridBinning_mod (prefix='gbi' category='4. Data Object transformations')
  3  !
  4  !:Purpose:  To compute categorical mean and standard deviation for gridded data
  5  !           contained in a gridStateVector or in an ensemble of
  6  !           gridStateVectors (e.g. the respective mean over land and sea)
  7  !
  8  use midasMpi_mod
  9  use ensembleStateVector_mod
 10  use gridStateVector_mod
 11  use gridStateVectorFileIO_mod
 12  use utilities_mod
 13  use horizontalCoord_mod
 14  use timeCoord_mod
 15  implicit none
 16  save
 17  private
 18
 19  ! public procedures
 20  public :: struct_gbi
 21  public :: gbi_setup, gbi_deallocate
 22  public :: gbi_stdDev, gbi_mean
 23
 24  type :: struct_gbi
 25    character(len=24) :: binningStrategy
 26    type(struct_gsv)  :: statevector_bin2d
 27    integer           :: numBins2d
 28  end type struct_gbi
 29
 30  integer, external  :: get_max_rss
 31
 32  ! Control parameter for the level of listing output
 33  logical, parameter :: verbose = .true.
 34
 35  ! module interfaces
 36  interface gbi_stdDev
 37    module procedure gbi_stdDev_ens
 38  end interface gbi_stdDev
 39
 40  interface gbi_mean
 41    module procedure gbi_mean_gsv
 42  end interface gbi_mean
 43
 44contains
 45
 46  !--------------------------------------------------------------------------
 47  ! gbi_setup
 48  !--------------------------------------------------------------------------
 49  subroutine gbi_setup(gbi, binningStrategy, statevector_template, hco_coregrid, &
 50                       mpi_distribution_opt, writeBinsToFile_opt)
 51    implicit none
 52
 53    ! Arguments:
 54    type(struct_gbi),           intent(inout) :: gbi
 55    character(len=*),           intent(in)    :: binningStrategy
 56    type(struct_gsv),           intent(in)    :: statevector_template
 57    type(struct_hco), pointer,  intent(in)    :: hco_coregrid
 58    character(len=*), optional, intent(in)    :: mpi_distribution_opt
 59    logical,          optional, intent(in)    :: writeBinsToFile_opt
 60
 61    ! Locals:
 62    type(struct_gsv) :: statevector_landSeaTopo
 63    integer :: myLonBeg, myLonEnd
 64    integer :: myLatBeg, myLatEnd
 65    integer :: latIndex, lonIndex
 66    real(8) :: binCategory
 67    logical :: allocHeightSfc
 68    logical :: writeBinsToFile
 69    logical :: skip
 70    logical :: mpi_local
 71    real(4), pointer :: bin2d(:,:,:)
 72    real(4), pointer :: data2d(:,:,:)
 73    character(len=24) :: mpi_distribution
 74
 75    !
 76    !- 1.  Allocate a 2D statevector that will contains the bin category for each 
 77    !      grid point
 78    !
 79    if (.not. gsv_isAllocated(statevector_template)) then
 80      call utl_abort('gbi_setup: the input template statevector was not allocated')
 81    end if
 82
 83    mpi_local = statevector_template%mpi_local
 84    if (present(mpi_distribution_opt)) then
 85      mpi_distribution = mpi_distribution_opt
 86      if ( mpi_distribution ==  'None') then
 87        mpi_local = .false.
 88      end if
 89    else
 90      mpi_distribution = 'Tiles'
 91    end if
 92
 93    if (trim(binningStrategy) == 'landSeaTopo') then
 94      allocHeightSfc = .true.
 95    else
 96      allocHeightSfc = .false.
 97    end if
 98
 99    call gsv_allocate(gbi%statevector_bin2d, 1, statevector_template%hco,    &
100                      statevector_template%vco, varNames_opt=(/'BIN'/),      &
101                      mpi_distribution_opt=mpi_distribution, dataKind_opt=4, &
102                      dateStamp_opt=statevector_template%dateStamp3d,        &
103                      mpi_local_opt=mpi_local, allocHeightSfc_opt=allocHeightSfc)
104
105    !
106    !- 2.  Set the bins
107    !
108    call gsv_getField(gbi%statevector_bin2d,bin2d)
109
110    myLonBeg = gbi%statevector_bin2d%myLonBeg
111    myLonEnd = gbi%statevector_bin2d%myLonEnd
112    myLatBeg = gbi%statevector_bin2d%myLatBeg
113    myLatEnd = gbi%statevector_bin2d%myLatEnd
114
115    select case(trim(binningStrategy))
116    case ('GridPoint')
117      if (mmpi_myid == 0) then
118        write(*,*) 'gbi_setup : BIN_TYPE = No horizontal averaging '
119        write(*,*) '            > One bin per horizontal grid point'
120      end if
121
122      gbi%numBins2d = statevector_template%hco%ni * statevector_template%hco%nj
123      binCategory = 0
124      do latIndex = 1, statevector_template%hco%nj
125        do lonIndex = 1, statevector_template%hco%ni
126          binCategory = binCategory + 1
127          if (lonIndex >= myLonBeg .and. lonIndex <= myLatEnd .and. &
128              latIndex >= myLatBeg .and. latIndex <= myLatEnd ) then
129            bin2d(lonIndex,latIndex,1) = real(binCategory,4)
130          end if
131        end do
132      end do
133
134    case ('YrowBand')
135      if (mmpi_myid == 0) then
136        write(*,*)
137        write(*,*) 'gbi_setup : BIN_TYPE = One bin per Y row'
138      end if
139
140      gbi%numBins2d = statevector_template%hco%nj
141      binCategory = 0
142      do latIndex = 1, statevector_template%hco%nj
143        binCategory = binCategory + 1
144        if (latIndex >= myLatBeg .and. latIndex <= myLatEnd ) then
145          bin2d(:,latIndex,1) = real(binCategory,4)
146        end if
147      end do
148
149    case ('HorizontalMean','FullDomain')
150      if (mmpi_myid == 0) then
151        write(*,*)
152        write(*,*) 'gbi_setup : BIN_TYPE = Average over all horizontal points'
153      end if
154
155      gbi%numBins2d = 1
156      binCategory   = 1
157      bin2d(:,:,1)  = real(binCategory,4)
158
159    case ('landSeaTopo')
160      if (mmpi_myid == 0) then
161        write(*,*)
162        write(*,*) 'gbi_setup : BIN_TYPE = land/sea binning + storage of the topography field'
163      end if
164
165      call gsv_allocate(statevector_landSeaTopo, 1, statevector_template%hco,     &
166                        statevector_template%vco, varNames_opt=(/'MG'/),          &
167                        mpi_distribution_opt=mpi_distribution, dataKind_opt=4,    &
168                        dateStamp_opt=statevector_template%dateStamp3d,           &
169                        mpi_local_opt=mpi_local, hInterpolateDegree_opt='LINEAR', &
170                        allocHeightSfc_opt=.true. )
171
172      call gio_readFromFile(statevector_landSeaTopo, './dataForGridBinning.fst', ' ', ' ', &
173                            readHeightSfc_opt=.true.)
174
175      call gsv_getField(statevector_landSeaTopo,data2d)
176
177      gbi%numBins2d = 2 ! (land or sea)
178      do latIndex= myLatBeg, myLatEnd
179        do lonIndex = myLonBeg, myLonEnd
180
181          skip = .false.
182          if (.not. statevector_template%hco%global) then
183            if (lonIndex > hco_coregrid%ni .or. latIndex > hco_coregrid%nj) then
184              ! We are in the extension zone
185              skip = .true.
186            end if
187          end if
188
189          if (skip) then
190            bin2d(lonIndex,latIndex,1) = -1.0
191          else
192            if (data2D(lonIndex,latIndex,1) >= 0.05) then
193              bin2d(lonIndex,latIndex,1) = 1.0 ! land point
194            else
195              bin2d(lonIndex,latIndex,1) = 2.0 ! sea  point
196            end if
197          end if
198
199        end do
200      end do
201
202      ! Store the topography in gbi%statevector_bin2d
203      call gsv_copyHeightSfc(statevector_landSeaTopo, & ! IN
204                         gbi%statevector_bin2d )    ! OUT
205
206      call gsv_deallocate(statevector_landSeaTopo)
207
208    case default
209      call utl_abort('gbi_setup : Invalid Binning Strategy : '//trim(BinningStrategy))
210    end select
211
212    !
213    !- 3.  Write the bins to a file (if desired)
214    !
215    if ( present(writeBinsToFile_opt) ) then
216      writeBinsToFile = writeBinsToFile_opt
217    else
218      writeBinsToFile = .false.
219    end if
220    
221    if (writeBinsToFile .and. (mpi_local .or. mmpi_myid == 0) ) then
222      call gio_writeToFile(gbi%statevector_bin2d, './gridBinning.fst', & ! IN
223                           'BINNING')                                    ! IN
224    end if
225
226  end subroutine gbi_setup
227  
228  !--------------------------------------------------------------------------
229  ! gbi_deallocate
230  !--------------------------------------------------------------------------
231  subroutine gbi_deallocate(gbi)
232    implicit none
233
234    ! Arguments:
235    type(struct_gbi), intent(inout) :: gbi
236
237    call gsv_deallocate(gbi%statevector_bin2d)
238
239  end subroutine gbi_deallocate
240
241  !--------------------------------------------------------------------------
242  ! gbi_mean_gsv
243  !--------------------------------------------------------------------------
244  subroutine gbi_mean_gsv(gbi, statevector_in, statevector_out)
245    implicit none
246
247    ! Arguments:
248    type(struct_gbi), intent(in)    :: gbi
249    type(struct_gsv), intent(inout) :: statevector_in
250    type(struct_gsv), intent(inout) :: statevector_out
251
252    ! Locals:
253    integer :: myBinCount(gbi%numBins2d)
254    integer ::   binCount(gbi%numBins2d)
255    real(8) :: myBinSum  (gbi%numBins2d)
256    real(8) ::   binMean (gbi%numBins2d)
257    real(8), pointer :: field4d(:,:,:,:)
258    real(8), pointer :: mean4d (:,:,:,:)
259    real(4), pointer :: bin2d(:,:,:)
260    integer :: myLonBeg, myLonEnd
261    integer :: myLatBeg, myLatEnd
262    integer :: latIndex, lonIndex, varLevIndex, stepIndex, binIndex
263    integer :: nVarLev, nStep, ier
264
265    if (mmpi_myid == 0 .and. verbose) then
266      write(*,*)
267      write(*,*) 'gbi_mean_gsv: Starting...'
268    end if
269
270    nVarLev   = statevector_in%nk
271    nStep     = statevector_in%numStep
272    myLonBeg  = statevector_in%myLonBeg
273    myLonEnd  = statevector_in%myLonEnd
274    myLatBeg  = statevector_in%myLatBeg
275    myLatEnd  = statevector_in%myLatEnd
276
277    call gsv_getField(statevector_in,field4d)
278    call gsv_getField(statevector_out,mean4d)
279
280    call gsv_getField(gbi%statevector_bin2d,bin2d)
281
282    do stepIndex = 1, nStep
283      do varLevIndex = 1, nVarLev
284
285        !- Sum the values per bin
286        myBinCount(:) = 0
287        myBinSum  (:) = 0.d0
288        do latIndex= myLatBeg, myLatEnd
289          do lonIndex = myLonBeg, myLonEnd
290            binIndex = int(bin2d(lonIndex,latIndex,1))
291            if (binIndex /= -1) then
292              myBinCount(binIndex) = myBinCount(binIndex) + 1
293              myBinSum(binIndex)   = myBinSum(binIndex)   + field4d(lonIndex,latIndex,varLevIndex,stepIndex)
294            end if
295          end do
296        end do
297
298        !- Compute the mean per bin
299        call rpn_comm_allreduce(myBinCount,binCount,gbi%numBins2d,"MPI_INTEGER"         ,"MPI_SUM","GRID",ier)
300        do binIndex = 1, gbi%numBins2d
301          binMean(binIndex) = myBinSum(binIndex)
302          call mmpi_allreduce_sumreal8scalar(binMean(binIndex),"GRID")
303        end do
304
305        do binIndex = 1, gbi%numBins2d
306          if (binCount(binIndex) /= 0 ) then
307            binMean(binIndex) = binMean(binIndex) / real(binCount(binIndex),8)
308          else
309            binMean(binIndex) = 0.d0
310          end if
311        end do
312
313        !- Distribute the bin mean values at each grid point
314        do latIndex= myLatBeg, myLatEnd
315          do lonIndex = myLonBeg, myLonEnd
316            binIndex = int(bin2d(lonIndex,latIndex,1))
317            if (binIndex /= -1) then
318              mean4d(lonIndex,latIndex,varLevIndex,stepIndex) = binMean(binIndex)
319            else
320              mean4d(lonIndex,latIndex,varLevIndex,stepIndex) = 0.d0
321            end if
322          end do
323        end do
324
325      end do
326    end do
327
328    if (mmpi_myid == 0 .and. verbose) then
329      write(*,*)
330      write(*,*) 'gbi_mean_gsv: Done!'
331    end if
332
333  end subroutine gbi_mean_gsv
334
335  !--------------------------------------------------------------------------
336  ! gbi_stdDev_ens
337  !--------------------------------------------------------------------------
338  subroutine gbi_stdDev_ens(gbi, ens, statevector)
339    implicit none
340
341    ! Arguments:
342    type(struct_gbi), intent(in)    :: gbi
343    type(struct_ens), intent(inout) :: ens
344    type(struct_gsv), intent(inout) :: statevector
345
346    ! Locals:
347    integer :: myBinCount(gbi%numBins2d)
348    integer :: binCount  (gbi%numBins2d)
349    real(8) :: myBinSum  (gbi%numBins2d)
350    real(8) :: binStdDev (gbi%numBins2d)
351    real(4), pointer :: ptr4d_r4 (:,:,:,:)
352    real(8), pointer :: stdDev_r8(:,:,:,:)
353    real(4), pointer :: bin2d(:,:,:)
354    integer :: myLonBeg, myLonEnd
355    integer :: myLatBeg, myLatEnd
356    integer :: latIndex, lonIndex, varLevIndex, stepIndex, binIndex, memberIndex
357    integer :: nVarLev, nStep, nEns, ier
358    character(len=4), pointer :: varNamesList(:)
359
360    if (mmpi_myid == 0 .and. verbose) then
361      write(*,*)
362      write(*,*) 'gbi_stdDev_ens: Starting...'
363    end if
364
365    if (.not. gsv_isAllocated(statevector)) then
366      nullify(varNamesList)
367      call ens_varNamesList(varNamesList,ens) 
368      call gsv_allocate(statevector, ens_getNumStep(ens),               &
369           ens_getHco(ens), ens_getVco(ens), varNames_opt=varNamesList, &
370           datestamp_opt=tim_getDatestamp(), mpi_local_opt=.true.,      &
371           dataKind_opt=8 )
372    end if
373
374    call ens_getLatLonBounds(ens, myLonBeg, myLonEnd, myLatBeg, myLatEnd)
375
376    nVarLev = ens_getNumK(ens)
377    nStep   = ens_getNumStep(ens)
378    nEns    = ens_getNumMembers(ens)
379
380    call gsv_getField(statevector,stdDev_r8)
381    call gsv_getField(gbi%statevector_bin2d,bin2d)
382
383    do varLevIndex = 1, nVarLev
384
385      ptr4d_r4 => ens_getOneLev_r4(ens,varLevIndex)
386
387      do stepIndex = 1, nStep
388
389        !- Sum the square values per bin
390        myBinCount(:) = 0
391        myBinSum  (:) = 0.d0
392        do latIndex = myLatBeg, myLatEnd
393          do lonIndex = myLonBeg, myLonEnd
394            binIndex = int(bin2d(lonIndex,latIndex,1))
395            if (binIndex /= -1) then
396              do memberIndex = 1, nEns
397                myBinCount(binIndex) = myBinCount(binIndex) + 1
398                myBinSum(binIndex)   = myBinSum(binIndex)   + real(ptr4d_r4(memberIndex,stepIndex,lonIndex,latIndex),8)**2
399              end do
400            end if
401          end do
402        end do
403
404        !- Compute the stdDev per bin
405        call rpn_comm_allreduce(myBinCount,binCount ,gbi%numBins2d,"MPI_INTEGER"         ,"MPI_SUM","GRID",ier)
406        call rpn_comm_allreduce(myBinSum  ,binStdDev,gbi%numBins2d,"MPI_DOUBLE_PRECISION","MPI_SUM","GRID",ier)
407
408        do binIndex = 1, gbi%numBins2d
409          if (binCount(binIndex) /= 0 ) then
410            binStdDev(binIndex) = sqrt(binStdDev(binIndex) / real(binCount(binIndex)-1,8))
411          else
412            binStdDev(binIndex) = 0.d0
413          end if
414        end do
415
416        !- Distribute the bin stdDev values at each grid point
417        do latIndex= myLatBeg, myLatEnd
418          do lonIndex = myLonBeg, myLonEnd
419            binIndex = int(bin2d(lonIndex,latIndex,1))
420            if (binIndex /= -1) then
421              stdDev_r8(lonIndex,latIndex,varLevIndex,stepIndex) = binStdDev(binIndex)
422            else
423              stdDev_r8(lonIndex,latIndex,varLevIndex,stepIndex) = 0.d0
424            end if
425          end do
426        end do
427
428      end do
429    end do
430
431    if (mmpi_myid == 0 .and. verbose) then
432      write(*,*)
433      write(*,*) 'gbi_stdDev_ens: Done!'
434    end if
435    
436  end subroutine gbi_stdDev_ens
437
438end module gridBinning_mod