bMatrixDiff_mod sourceΒΆ

  1MODULE bMatrixDiff_mod
  2  ! MODULE bMatrixDiff_mod (prefix='bdiff' category='2. B and R matrices')
  3  !
  4  !:Purpose:  Performs transformation from control vector to analysis increment 
  5  !           (and the adjoint transformation) using the background-error
  6  !           covariance matrix based on correlations modelled using a
  7  !           diffusion operator.
  8  !
  9  use midasMpi_mod
 10  use gridStateVector_mod
 11  use gridStateVectorFileIO_mod
 12  use horizontalCoord_mod
 13  use verticalCoord_mod
 14  use varNameList_mod
 15  use physicsFunctions_mod
 16  use utilities_mod
 17  use diffusion_mod
 18  implicit none
 19  save
 20  private
 21
 22  ! public procedures
 23  public :: bdiff_Setup, bdiff_BSqrt, bdiff_BSqrtAd, bdiff_Finalize
 24  public :: bdiff_getScaleFactor, bdiff_reduceToMPILocal
 25
 26  logical             :: initialized = .false.
 27  integer             :: nj_l, ni_l
 28  integer             :: cvDim_mpilocal, cvDim_mpiglobal
 29
 30  integer, allocatable :: diffID(:)
 31
 32  ! Background-error covariance matrix elements.
 33  real(8), allocatable :: stddev(:,:,:)
 34
 35  integer, parameter  :: maxNumVars = 200
 36  real(8)             :: scaleFactor_sigma(maxNumVars)
 37
 38  ! read in from the namelist:
 39  real(8)          :: scaleFactor(maxNumVars)     ! scale factor applied to variances
 40  character(len=4) :: stddevMode                  ! can be 'GD2D' or 'HOMO'
 41  real(8)          :: homogeneous_std(maxNumVars) ! homogeneous standard deviation (when stddevMode is 'HOMO')
 42
 43  ! Number of incremental variables/fields
 44  integer             :: numvar2d
 45  ! Start position of each field in composite arrays
 46  integer, allocatable :: nsposit(:)
 47  ! Name list of incremental variables/fields
 48  character(len=4), allocatable :: bdiff_varNameList(:)
 49
 50  integer             :: myLatBeg, myLatEnd
 51  integer             :: myLonBeg, myLonEnd
 52  integer             :: latPerPE, latPerPEmax, lonPerPE, lonPerPEmax
 53
 54  integer,external    :: get_max_rss
 55
 56  integer             :: nulbgst = 0
 57
 58CONTAINS
 59
 60  !--------------------------------------------------------------------------
 61  ! bdiff_setup
 62  !--------------------------------------------------------------------------
 63  subroutine bdiff_setup ( hco_in, vco_in, cvDim_out, mode_opt )
 64    !
 65    !:Purpose: Setup the diffusion B matrix
 66    !
 67    implicit none
 68
 69    ! Arguments:
 70    type(struct_hco), pointer,  intent(in)  :: hco_in
 71    type(struct_vco), pointer,  intent(in)  :: vco_in
 72    integer         ,           intent(out) :: cvDim_out
 73    character(len=*), optional, intent(in)  :: mode_opt
 74
 75    ! Locals:
 76    character(len=15)         :: bdiff_mode
 77    type(struct_vco), pointer :: vco_anl
 78    integer                   :: nulnam, ierr, fnom, fclos
 79    integer                   :: variableIndex, latIndex, latIndexIgnore
 80    real(8)                   :: maxDistance
 81    real(8), allocatable      :: distance(:)
 82    character(len=*), parameter :: myName = 'bdiff_setup'
 83    ! namelist variables
 84    real    :: corr_len( maxNumVars )  ! Horizontal correlation length scale (km)
 85    real    :: stab( maxNumVars )      ! Stability criteria (definitely < 0.5)
 86    integer :: nsamp(maxNumVars)       ! Number of samples in the estimation of the normalization factors by randomization
 87    real(8) :: latIgnoreFraction       ! Relative zonal grid spacing limit where lats near each numerical pole are ignored
 88    logical :: useImplicit(maxNumVars) ! choose to use implicit formulation of diffusion operator (.true.) or explicit version (.false.)
 89    
 90    NAMELIST /NAMBDIFF/ corr_len, stab, nsamp, useImplicit, scaleFactor, stddevMode, homogeneous_std, latIgnoreFraction
 91
 92    call utl_tmg_start(65,'----B_DIFF_Setup')
 93    if(mmpi_myid == 0) write(*,*) myName//': starting'
 94    if(mmpi_myid == 0) write(*,*) myName//': Memory Used: ',get_max_rss()/1024,'Mb'
 95
 96    ! default values for namelist variables
 97    corr_len(:) = 10.0
 98    stab(:)     = 0.2
 99    nsamp(:)    = 10000
100    useImplicit(:) = .false.
101    scaleFactor(:) = 0.0d0
102    stddevMode  = 'GD2D'
103    homogeneous_std(:) = -1.0d0
104    latIgnoreFraction = 1.0d6 ! large value so that nothing is ignored by default
105
106    if ( .not. utl_isNamelistPresent('NAMBDIFF','./flnml') ) then
107      if ( mmpi_myid == 0 ) then
108        write(*,*) 'bdiff_setup: nambdiff is missing in the namelist.'
109        write(*,*) '             The default values will be taken.'
110      end if
111    else
112      nulnam = 0
113      ierr = fnom( nulnam,'./flnml','FTN+SEQ+R/O',0)
114      read( nulnam, nml = nambdiff, iostat = ierr )
115      if ( ierr /= 0 ) call utl_abort( myName//': Error reading namelist')
116      if ( mmpi_myid == 0) write( *, nml = nambdiff )
117      ierr = fclos( nulnam )
118    end if
119
120    if ( sum(scaleFactor(:) ) == 0.0d0 ) then
121      if( mmpi_myid == 0) write(*,*) myName//': scaleFactor=0, skipping rest of setup'
122      cvdim_out = 0
123      call utl_tmg_stop(65)
124      return
125    end if
126
127    if ( present( mode_opt ) ) then
128      if ( trim( mode_opt ) == 'Analysis' .or. trim( mode_opt ) == 'BackgroundCheck' ) then
129        bdiff_mode = trim( mode_opt )
130        if( mmpi_myid == 0 ) write(*,*)
131        if( mmpi_myid == 0 ) write(*,*) myName//': Mode activated = ', trim(bdiff_mode)
132      else
133        write(*,*)
134        write(*,*)  myName//'mode = ', trim(mode_opt)
135        call utl_abort( myName//': unknown mode' )
136      end if
137    else
138      bdiff_mode = 'Analysis'
139      if( mmpi_myid == 0 ) write(*,*)
140      if( mmpi_myid == 0 ) write(*,*) myName//': analysis mode activated (by default)'
141    end if
142
143    vco_anl => vco_in
144    if (vco_anl%Vcode  /= 5002 .and. vco_anl%Vcode /= 5005 .and. vco_anl%Vcode /= 0 ) then
145      write(*,*)  myName//'vco_anl%Vcode = ', vco_anl%Vcode
146      call utl_abort( myName//': unknown vertical coordinate type!')
147    end if
148
149    numvar2d = 0
150
151    allocate( bdiff_varNameList( vnl_numvarmax ) )
152    bdiff_varNameList( : )=''
153    allocate( nsposit( vnl_numvarmax + 1 ) )
154    nsposit(1) = 1
155
156    ! Find the 2D variables (within NAMSTATE namelist)
157
158    if ( gsv_varExist( varName = 'GL  ' )) then
159
160      numvar2d = numvar2d + 1
161      nsposit( numvar2d + 1 ) = nsposit( numvar2d ) + 1
162      bdiff_varNameList( numvar2d ) = 'GL  '
163
164    end if
165   
166    if ( gsv_varExist( varName = 'TM  ')) then
167
168      numvar2d = numvar2d + 1
169      nsposit( numvar2d + 1 ) = nsposit( numvar2d ) + 1
170      bdiff_varNameList( numvar2d ) = 'TM  '
171
172    end if
173
174    if ( numvar2d == 0) then
175       
176      if ( mmpi_myid == 0) then
177        write(*,*) myName//': Bdiff matrix not produced.'
178        write(*,*) myName//': END'
179      end if
180      call utl_tmg_stop(65)
181      cvdim_out = 0
182      return
183      
184    else if (mmpi_myid == 0) then
185
186      write(*,*) myName//': number of 2D variables', numvar2d, bdiff_varNameList( 1 : numvar2d )
187
188    end if
189
190    if ( trim(bdiff_mode) == 'BackgroundCheck' ) then
191      cvDim_out = 9999 ! Dummy value > 0 to indicate to the background check (s/r ose_compute_HBHT_ensemble) 
192                       ! that Diff is used
193      call utl_tmg_stop(65)
194      return
195    end if
196
197    ! Assumes the input 'scalefactor' is a scaling factor of the variances.
198
199    do variableIndex = 1, numvar2d
200      if ( scaleFactor( variableIndex ) > 0.0d0 ) then 
201        scaleFactor_sigma( variableIndex ) = sqrt( scaleFactor( variableIndex ) )
202      else
203        scaleFactor_sigma( variableIndex ) = 0.0d0
204      end if
205    end do
206
207    ni_l = hco_in%ni
208    nj_l = hco_in%nj
209
210    ! Compute latIndexIgnore from latIgnoreFraction
211    if (latIgnoreFraction < 1.0) then
212      allocate(distance(nj_l))
213      do latIndex = 1, nj_l
214        distance(latIndex) = &
215             phf_calcDistance(real(hco_in%lat2d_4(ni_l/2,latIndex),8), real(hco_in%lon2d_4((ni_l/2)+1,latIndex),8), &
216                              real(hco_in%lat2d_4(ni_l/2,latIndex),8), real(hco_in%lon2d_4((ni_l/2)  ,latIndex),8))
217      end do
218      maxDistance = maxval(distance(:))
219      if (mmpi_myid==0) write(*,*) myName//': maxDistance = ', maxDistance
220      latIndexIgnore = 0
221      latLoop: do latIndex = 1, nj_l
222        if (distance(latIndex)/maxDistance > latIgnoreFraction) then
223          if (mmpi_myid==0) then
224            write(*,*) '   latIndex-1, distance, fraction = ', latIndex-1, distance(latIndex-1), distance(latIndex-1)/maxDistance 
225            write(*,*) '***latIndex  , distance, fraction = ', latIndex  , distance(latIndex  ), distance(latIndex  )/maxDistance 
226            write(*,*) '   latIndex+1, distance, fraction = ', latIndex+1, distance(latIndex+1), distance(latIndex+1)/maxDistance
227          end if
228          latIndexIgnore = latIndex
229          exit latLoop
230        end if
231      end do latLoop
232      deallocate(distance)
233    else
234      latIndexIgnore = 0
235    end if
236    if (mmpi_myid==0) write(*,*) myName//': latIndexIgnore = ', latIndexIgnore
237
238    allocate( diffID( numvar2d ) )
239    do variableIndex = 1, numvar2d
240      write(*,*) myName//': setup the diffusion operator for the variable ', bdiff_varNameList( variableIndex ) 
241      diffID( variableIndex ) = diff_setup ( variableIndex, bdiff_varNameList(1:numvar2d), hco_in, vco_in, corr_len( variableIndex ), &
242                                             stab( variableIndex ), nsamp( variableIndex ), useImplicit( variableIndex ), &
243                                             latIndexIgnore )
244    end do
245
246    call mmpi_setup_latbands( nj_l, latPerPE, latPerPEmax, myLatBeg, myLatEnd )
247    call mmpi_setup_lonbands( ni_l, lonPerPE, lonPerPEmax, myLonBeg, myLonEnd )
248
249    ! compute mpilocal control vector size
250    cvDim_mpilocal = lonPerPE * latPerPE * numvar2d
251    cvDim_out = cvDim_mpilocal
252
253    ! also compute mpiglobal control vector dimension
254    call rpn_comm_allreduce( cvDim_mpilocal, cvDim_mpiglobal, 1, "mpi_integer", "mpi_sum", "GRID", ierr )
255
256    allocate(stddev(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d))
257
258    call bdiff_rdstats( hco_in, vco_in )
259
260    if(mmpi_myid == 0) write(*,*) myName//': Memory Used: ',get_max_rss()/1024,'Mb'
261
262    if(mmpi_myid == 0) write(*,*) myName//': END'
263
264    initialized = .true.
265
266    call utl_tmg_stop(65)
267
268  end subroutine bdiff_setup
269  
270  !--------------------------------------------------------------------------
271  ! bdiff_getScaleFactor
272  !--------------------------------------------------------------------------
273  subroutine bdiff_getScaleFactor( scaleFactor_out )
274    !
275    !:Purpose: Return the specified scaleFactor.
276    !    
277    implicit none
278
279    ! Arguments:
280    real(8), intent(out) :: scaleFactor_out(:)
281
282    ! Locals:
283    integer :: variableIndex
284
285    do variableIndex = 1, numvar2d
286       
287      scaleFactor_out( variableIndex ) = scaleFactor( variableIndex )
288       
289    end do
290
291  end subroutine bdiff_getScaleFactor
292  
293  !--------------------------------------------------------------------------
294  ! bdiff_rdstats
295  !--------------------------------------------------------------------------
296  subroutine bdiff_rdstats( hco_in, vco_in )
297    !
298    !:Purpose: To read background-error stats file.
299    !
300    implicit none
301    
302    ! Arguments:
303    type(struct_hco), pointer, intent(in) :: hco_in
304    type(struct_vco), pointer, intent(in) :: vco_in
305    
306    ! Locals:
307    integer :: ierr, nmax, fnom, fstouv, fstfrm, fclos
308    integer :: variableIndex
309    logical :: lExists
310    character(len=12) :: bFileName1 = './bgstddev'
311    character(len=8)  :: bFileName2 = './bgcov'
312    character(len=*), parameter :: myName = 'bdiff_rdstats'
313    
314    write(*,*) myName//': stddevMode is ', stddevMode
315    write(*,*) myName//': Number of 2D variables', numvar2d, bdiff_varNameList( 1 : numvar2d )
316    
317    if ( stddevMode == 'GD2D' ) then
318
319      inquire( file = bFileName1, exist = lExists )
320       
321      if ( lexists ) then
322        ierr = fnom(nulbgst, bFileName1, 'RND+OLD+R/O', 0)
323        if ( ierr == 0 ) then
324          nmax = fstouv(nulbgst, 'RND+OLD')
325        else
326          call utl_abort( myName//': error opening file '//trim(bFileName1))
327        end if
328      else
329        ! Assume background-error stats in file bgcov. 
330        inquire( file = bFileName2, exist = lExists )  
331        if ( lexists ) then 
332          ierr = fnom( nulbgst, bFileName2, 'RND+OLD+R/O', 0 )
333          if ( ierr == 0 ) then
334            nmax = fstouv(nulbgst, 'RND+OLD')
335          else
336            call utl_abort( myName//': error opening file '//trim(bFileName2) )
337          end if
338        else
339          call utl_abort( myName//': no background error statistics file found!!' )
340        end if
341      end if
342
343      call bdiff_readBGstdField( hco_in, vco_in )
344
345      ierr = fstfrm(nulbgst)
346      ierr = fclos(nulbgst)
347
348    else if ( stddevMode == 'HOMO' ) then
349
350      do variableIndex = 1, numvar2d
351        write(*,*) myName//': stdev = ', homogeneous_std( variableIndex ), ' for variable ', bdiff_varNameList( variableIndex )    
352        stddev( :, :, variableIndex) = homogeneous_std( variableIndex )
353      end do
354       
355    else
356
357      call utl_abort( myName//': unknown stddevMode: '//trim(stddevMode) )
358
359    end if
360
361    call bdiff_scalestd
362
363    write(*,*) myName//': END '
364    
365  end subroutine bdiff_rdstats
366
367  !--------------------------------------------------------------------------
368  ! bdiff_readBGstdField
369  !--------------------------------------------------------------------------
370  subroutine bdiff_readBGstdField( hco_in, vco_in )
371    !
372    !:Purpose: to read 2D background error standard deviation field
373    !          stored on Z, U or G grid and interpolate it to the analysis grid
374    !
375    implicit none
376    
377    ! Arguments:
378    type(struct_hco), pointer, intent(in) :: hco_in 
379    type(struct_vco), pointer, intent(in) :: vco_in
380
381    ! Locals:
382    integer                     :: variableIndex, ierr
383    type(struct_gsv)            :: statevector
384    real(4), pointer            :: field3D_r4_ptr(:,:,:)
385    real(8)                     :: minStddev, maxStddev
386    character(len=*), parameter :: myName = 'bdiff_readBGstdField'
387
388    write(*,*) myName//': Reading 2D fields from ./bgstddev...'
389    write(*,*) myName//': Number of 2D variables', numvar2d, bdiff_varNameList( 1 : numvar2d )
390
391    call gsv_allocate( statevector, 1, hco_in, vco_in, dateStamp_opt=-1, &
392                       dataKind_opt=4, mpi_local_opt=.true., &
393                       hInterpolateDegree_opt='LINEAR', &
394                       varNames_opt=bdiff_varNameList(1:numvar2d) )
395    call gsv_zero( statevector )
396    call gio_readFromFile(statevector, './bgstddev', 'STDDEV', ' ', unitConversion_opt = .false. )
397
398    do variableIndex = 1, numvar2d
399      call gsv_getField( statevector, field3D_r4_ptr, bdiff_varNameList( variableIndex ) )
400      stddev( :, :, variableIndex ) = dble( field3D_r4_ptr( :, :, 1 ) )
401      if (mmpi_nprocs > 1) then
402        call rpn_comm_allreduce(minval(stddev(:,:,variableIndex)),minStddev,1,'mpi_real8','mpi_min','GRID',ierr)
403        call rpn_comm_allreduce(maxval(stddev(:,:,variableIndex)),maxStddev,1,'mpi_real8','mpi_max','GRID',ierr)
404      else
405        minStddev = minval(stddev(:,:,variableIndex))
406        maxStddev = maxval(stddev(:,:,variableIndex))
407      end if
408      write(*,*) myName//': variable ', bdiff_varNameList( variableIndex ),' min/max: ', &
409                 minStddev, maxStddev
410    end do
411   
412    call gsv_deallocate( statevector )
413
414  end subroutine bdiff_readBGstdField
415
416  !--------------------------------------------------------------------------
417  ! bdiff_scalestd
418  !--------------------------------------------------------------------------
419  subroutine bdiff_scalestd
420    !
421    !:Purpose: To scale background-error standard-deviation values.
422    !
423    implicit none
424
425    ! Locals:
426    integer :: variableIndex
427    character(len=*), parameter :: myName = 'bdiff_scalestd'
428    
429    do variableIndex = 1, numvar2d
430       
431      write(*,*) myName//': scaling ', bdiff_varNameList( variableIndex ), ' STD field with the factor ',  scaleFactor_sigma( variableIndex )
432       
433      stddev( :, :, variableIndex ) = scaleFactor_sigma( variableIndex ) * stddev( : , : , variableIndex )
434      
435    end do
436
437  end subroutine bdiff_scalestd
438
439  !--------------------------------------------------------------------------
440  ! bdiff_bSqrt
441  !--------------------------------------------------------------------------
442  subroutine bdiff_bSqrt( controlVector_in, statevector )
443    !
444    !:Purpose: Apply the sqrt of the B matrix 
445    !    
446    implicit none
447
448    ! Arguments:
449    real(8),          intent(in)    :: controlVector_in( cvDim_mpilocal )
450    type(struct_gsv), intent(inout) :: statevector
451
452    ! Locals:
453    real(8) :: gd_in( myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
454    real(8) :: gd_out(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
455    integer :: variableIndex
456    character(len=*), parameter :: myName = 'bdiff_bSqrt'
457    
458    if( .not. initialized) then
459      if( mmpi_myid == 0 ) write(*,*) myName//': bMatrixDIFF not initialized'
460      return
461    end if
462
463    if(mmpi_myid == 0) write(*,*) myName//': starting'
464
465    call bdiff_cain( controlVector_in, gd_in )
466
467    do variableIndex = 1, numvar2d
468
469      ! Apply square root of the diffusion operator.
470      call diff_Csqrt( diffID( variableIndex ), gd_in( :, :, variableIndex ), gd_out( :, :, variableIndex ) )
471
472      ! Multiply by the diagonal matrix of background error standard deviations.
473      gd_out( :, :, variableIndex ) = gd_out( :, :, variableIndex ) * stddev( :, :, variableIndex )
474
475    end do
476
477    call bdiff_copyToStatevector( statevector, gd_out )
478
479    if(mmpi_myid == 0) write(*,*) myName//': Memory Used: ',get_max_rss()/1024,'Mb'
480    if(mmpi_myid == 0) write(*,*) myName//': done'
481
482  end subroutine bdiff_bSqrt
483
484  !--------------------------------------------------------------------------
485  ! bdiff_bSqrtAd
486  !--------------------------------------------------------------------------
487  subroutine bdiff_bSqrtAd( statevector, controlVector_out )
488    !
489    !:Purpose: Apply the adjoint (i.e. transpose) of the sqrt of the B matrix
490    !    
491    implicit none
492
493    ! Arguments:
494    type(struct_gsv), intent(in)  :: statevector
495    real(8),          intent(out) :: controlVector_out(cvDim_mpilocal)
496
497    ! Locals:
498    real(8) :: gd_in( myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
499    real(8) :: gd_out(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
500    integer :: variableIndex
501    character(len=*), parameter :: myName = 'bdiff_bSqrtAd'
502
503    if ( .not. initialized ) then
504      if ( mmpi_myid == 0 ) write(*,*) myName//': bMatrixDIFF not initialized'
505      return
506    end if
507
508    if(mmpi_myid == 0) write(*,*)  myName//': starting'
509
510    call bdiff_copyFromStatevector( statevector, gd_in )
511
512    do variableIndex = 1, numvar2d
513
514      ! Multiply by the diagonal matrix of background-error standard deviations.
515      gd_in( :, :, variableIndex ) = gd_in( :, :, variableIndex ) * stddev( :, :, variableIndex )
516
517      ! Apply the adjoint of the square root of the diffusion operator.
518      call diff_Csqrtadj( diffID( variableIndex ), gd_in( :, :, variableIndex ), gd_out( :, :, variableIndex) )
519
520    end do
521
522    call bdiff_cainad(gd_out, controlVector_out)
523
524    if ( mmpi_myid == 0) write(*,*) myName//': Memory Used: ', get_max_rss()/1024,'Mb'
525    if ( mmpi_myid == 0) write(*,*) myNAme//': done'
526
527  end subroutine bdiff_bSqrtAd
528
529  !--------------------------------------------------------------------------
530  ! bdiff_copyToStatevector
531  !--------------------------------------------------------------------------
532  subroutine bdiff_copyToStatevector ( statevector, gd )
533    !
534    !:Purpose: Copy the working array to a statevector object 
535    !    
536    implicit none
537
538    ! Arguments:
539    real(8),          intent(in)    :: gd(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
540    type(struct_gsv), intent(inout) :: statevector
541
542    ! Locals:
543    integer :: jlon, jlev, jlev2, jlat, variableIndex, ilev1, ilev2
544    real(4), pointer :: field_r4(:,:,:)
545    real(8), pointer :: field_r8(:,:,:)
546    character(len=*), parameter :: myName = 'bdiff_copyToStatevector'
547    
548    do variableIndex = 1, numvar2d
549
550      ilev1 = nsposit( variableIndex )
551      ilev2 = nsposit( variableIndex + 1 ) - 1 
552
553      if ( mmpi_myid == 0) write(*,*) myName//': ',bdiff_varNameList( variableIndex )
554      
555      if (gsv_getDataKind(statevector) == 4) then
556        call gsv_getField( statevector, field_r4, bdiff_varNameList( variableIndex ) )
557        do jlev = ilev1, ilev2
558          jlev2 = jlev-ilev1+1
559          do jlat = myLatBeg, myLatEnd
560            do jlon = myLonBeg, myLonEnd
561              field_r4(jlon,jlat,jlev2) = gd(jlon,jlat,jlev)
562            end do
563          end do
564        end do
565      else
566        call gsv_getField( statevector, field_r8, bdiff_varNameList( variableIndex ) )
567        do jlev = ilev1, ilev2
568          jlev2 = jlev-ilev1+1
569          do jlat = myLatBeg, myLatEnd
570            do jlon = myLonBeg, myLonEnd
571              field_r8(jlon,jlat,jlev2) = gd(jlon,jlat,jlev)
572            end do
573          end do
574        end do
575      end if
576
577    end do
578
579  end subroutine bdiff_copyToStatevector
580
581  !--------------------------------------------------------------------------
582  ! bdiff_copyFromStatevector
583  !--------------------------------------------------------------------------
584  subroutine bdiff_copyFromStatevector( statevector, gd )
585    !
586    !:Purpose: Copy the contents of the statevector object to the working array
587    !    
588    implicit none
589
590    ! Arguments:
591    type(struct_gsv), intent(in)  :: statevector
592    real(8),          intent(out) :: gd(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
593
594    ! Locals:
595    integer :: jlon, jlev, jlev2, jlat, variableIndex, ilev1, ilev2
596    real(4), pointer :: field_r4(:,:,:)
597    real(8), pointer :: field_r8(:,:,:)
598    character(len=*), parameter :: myName = 'bdiff_copyFromStatevector'
599
600    do variableIndex = 1, numvar2d
601
602      ilev1 = nsposit( variableIndex )
603      ilev2 = nsposit( variableIndex + 1 ) - 1 
604
605      if ( mmpi_myid == 0) write(*,*) myName//': ',bdiff_varNameList( variableIndex )
606      if (gsv_getDataKind(statevector) == 4) then
607        call gsv_getField(statevector, field_r4, bdiff_varNameList( variableIndex ))
608        do jlev = ilev1, ilev2
609          jlev2 = jlev-ilev1+1
610          do jlat = myLatBeg, myLatEnd
611            do jlon = myLonBeg, myLonEnd
612              gd( jlon, jlat, jlev ) = field_r4( jlon, jlat, jlev2 )
613            end do
614          end do
615        end do
616      else
617        call gsv_getField(statevector, field_r8, bdiff_varNameList( variableIndex ))
618        do jlev = ilev1, ilev2
619          jlev2 = jlev-ilev1+1
620          do jlat = myLatBeg, myLatEnd
621            do jlon = myLonBeg, myLonEnd
622              gd( jlon, jlat, jlev ) = field_r8( jlon, jlat, jlev2 )
623            end do
624          end do
625        end do
626      end if
627    end do
628
629  end subroutine bdiff_copyFromStatevector
630
631  !--------------------------------------------------------------------------
632  ! bdiff_reduceToMPILocal
633  !--------------------------------------------------------------------------
634  subroutine bdiff_reduceToMPILocal(cv_mpilocal,cv_mpiglobal)
635    !
636    !:Purpose: Extract the subset of the global control vector needed for local MPI task
637    !
638    implicit none
639
640    ! Arguments:
641    real(8), intent(out) :: cv_mpilocal(:)
642    real(8), intent(in)  :: cv_mpiglobal(:)
643
644    ! Locals:
645    integer :: jn, jlat, jlon, jlev, ierr
646    real(8), allocatable :: gd_mpiGlobal(:,:,:)
647
648    allocate(gd_mpiGlobal(ni_l,nj_l,numvar2d))
649    gd_mpiGlobal(:,:,:) = 0.0d0
650
651    jn = 0
652    if (mmpi_myid == 0) then
653      do jlev = 1, numvar2d
654        do jlat = 1, nj_l
655          do jlon = 1, ni_l
656            jn = jn + 1
657            gd_mpiGlobal( jlon, jlat, jlev ) = cv_mpiglobal( jn )
658          end do
659        end do
660      end do
661    end if 
662    call rpn_comm_bcast(gd_mpiGlobal, size(gd_mpiGlobal), 'MPI_REAL8', 0, 'GRID', ierr)
663    
664    jn = 0
665    do jlev = 1, numvar2d
666      do jlat = myLatBeg, myLatEnd
667        do jlon = myLonBeg, myLonEnd
668          jn = jn + 1
669          cv_mpilocal(jn) = gd_mpiGlobal(jlon,jlat,jlev)
670        end do
671      end do
672    end do
673
674    deallocate(gd_mpiGlobal)
675
676  end subroutine bdiff_reduceToMPILocal
677
678  !--------------------------------------------------------------------------
679  ! bdiff_cain
680  !--------------------------------------------------------------------------
681  subroutine bdiff_cain( controlVector_in, gd_out )
682    !
683    !:Purpose: Transform from control vector to working array
684    !    
685    implicit none
686
687    ! Arguments:
688    real(8), intent(in)  :: controlVector_in(cvDim_mpilocal)
689    real(8), intent(out) :: gd_out(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
690
691    ! Locals:
692    integer :: jn, jlev, jlon, jlat
693
694    jn = 0
695    do jlev = 1, numvar2d
696      do jlat = myLatBeg, myLatEnd
697        do jlon = myLonBeg, myLonEnd
698          jn = jn + 1
699          gd_out( jlon, jlat, jlev ) = ControlVector_in( jn )
700        end do
701      end do
702    end do
703
704  end subroutine bdiff_cain
705
706  !--------------------------------------------------------------------------
707  ! bdiff_cainAd
708  !--------------------------------------------------------------------------
709  subroutine bdiff_cainAd( gd_in, diffControlVector_out )
710    !
711    !:Purpose: Transform from working array to control vector
712    !        
713    implicit none
714
715    ! Arguments:
716    real(8), intent(in)  :: gd_in(myLonBeg:myLonEnd, myLatBeg:myLatEnd, numvar2d)
717    real(8), intent(out) :: diffControlVector_out(cvDim_mpilocal)
718
719    ! Locals:
720    integer :: jn, jlev, jlon, jlat
721
722    jn = 0
723    do jlev = 1, numvar2d
724      do jlat = myLatBeg, myLatEnd
725        do jlon = myLonBeg, myLonEnd
726          jn = jn + 1
727          diffControlVector_out(jn) = gd_in(jlon,jlat,jlev)
728        end do
729      end do
730    end do
731
732  end subroutine bdiff_cainAd
733
734  !--------------------------------------------------------------------------
735  ! bdiff_Finalize
736  !--------------------------------------------------------------------------
737  subroutine bdiff_Finalize()
738    !
739    !:Purpose: Deallocate some arrays after we don't need the B matrix anymore. 
740    !        
741    implicit none
742
743    if ( initialized ) then
744      initialized = .false.
745      deallocate( stddev )
746      deallocate( diffID )
747      deallocate( nsposit )
748      deallocate( bdiff_varNameList )
749    end if
750
751  end subroutine bdiff_Finalize
752
753end module bMatrixDiff_mod