1program midas_diagBmatrix
2 !
3 !:Purpose: Program for computing diagnostics of the background-error covariances (**B**) and
4 ! localization (**L**) matrices
5 !
6 ! ---
7 !
8 !:Algorithm: The ``diagBmatrix`` program performs two different types of diagnostics
9 ! based on the namelist options.
10 !
11 ! - **Columns of B and L**: Allow to extract columns of **B** (the background-error covariances matrix)
12 ! which is a useful way to simulate single-observation (a.k.a pseudo-obs) experiments without using
13 ! real observations.
14 ! See e.g. Figs 5 and 6 in <https://doi.org/10.1175/MWR-D-18-0248.1>.
15 ! If localization is used, the corresponding columns of the localization matrix (**L**) will be outputed.
16 ! - **Implied variances**: Compute the variances resulting from an ensemble of random perturbations
17 ! generated from the provided **B** matrix, including hybrid covariances. This allow to evaluate the impact
18 ! of various choices in the design of **B** on the modification to the variances of the ensemble of
19 ! background-error estimates used to derivate **B**, i.e. the "measured" variances.
20 !
21 ! ---
22 !
23 !============================================= ==============================================================
24 ! Input and Output Files Description of file
25 !============================================= ==============================================================
26 ! ``flnml`` In - Main namelist file with parameters user may modify
27 ! ``ensemble/$YYYYMMDDHH_$HHH_$NNNN`` In - Background ensemble member files
28 ! ``bgcov`` In - **B** nmc matrix for the random perturbations
29 ! ``analysis_grid`` In - Horizontal grid file on which the random perturbations
30 ! are generated
31 ! ``trlm_$NN`` (e.g. ``trlm_01``) In - Background state (a.k.a. trial) files for each timestep
32 ! Only needed if a LQ-HU transform is used in **B**
33 ! ``columnB_$VAR_$YYYYMMDDHH.fst`` Out - Column of **B**
34 ! ``columnBnorm_$VAR_$YYYYMMDDHH.fst`` Out - Column of **B** normalize by the value at the pseudo-obs location
35 ! ``columnL_$YYYYMMDDHH.fst`` Out - Column of **L** (only when ensemble-derived **B** is use)
36 ! ``stddev_$YYYYMMDDHH.fst`` Out - Implied variances
37 !============================================= ==============================================================
38 !
39 ! --
40 !
41 !:Synopsis: Below is a summary of the ``diagBmatrix`` program calling sequence:
42 !
43 ! - **Initial setups:**
44 !
45 ! - Read the NAMDIAG namelist and check/modify some values.
46 !
47 ! - Setup horizontal and vertical grid objects from the provided template file (./analysisgrid)
48 !
49 ! - Various modules are setup: ``gridStateVector_mod``, ``timeCoord_mod`` and ``bmatrix_mod``
50 !
51 ! - **Columns of B and L:**
52 !
53 ! - Attribute time bin of the pseudo-obs based on the namelist option.
54 !
55 ! - For each variables and prescribed pseudo-obs positions:
56 ! 1) create a Dirac delta distribution (zero everywhere except at obs location).
57 ! This is equivalent to impose (O-F / sigma_obs) = 1 at one location.
58 ! 2) apply **B** ^(1/2)^T **B** ^1/2 and output the results into a file
59 ! 3) normalize the results by the value at the pseudo-obs position
60 ! and output to a file
61 !
62 ! - If bMatrixEnsemble_mod is activated, for each prescribed pseudo-obs positions:
63 ! 1) create a Dirac delta distribution
64 ! 2) apply **L** ^(1/2)^T **L** ^1/2 and output the results into a file
65 !
66 ! - **Implied variances:**
67 !
68 ! - For each member of the chosen random ensemble size:
69 ! 1) create a random control vector
70 ! 2) apply **B** ^1/2
71 ! 3) store the resulting 3D state in randomEns
72 !
73 ! - Compute and remove the ensemble mean
74 !
75 ! - Compute the ensemble standard deviations at each grid point and output to a file
76 !
77 ! - Compute the zonal and domain mean standard deviations and output to the same file
78 !
79 !======================== ============ ==============================================================
80 ! Module Namelist Description of what is controlled
81 !======================== ============ ==============================================================
82 ! ``timeCoord_mod`` ``NAMTIME`` assimilation time window length, temporal resolution of
83 ! the background state and increment
84 ! ``bMatrixEnsemble_mod`` ``NAMBEN`` weight and other parameters for ensemble-based **B** matrix
85 ! component
86 ! ``bMatrixHI_mod`` ``NAMBHI`` weight and other parameters for the climatological **B** matrix
87 ! component based on homogeneous-isotropic covariances
88 ! represented in spectral space
89 ! Other **B** matrix modules various weight and other parameters for each type of **B** matrix
90 !======================== ============ ==============================================================
91 !
92
93 use version_mod
94 use midasMpi_mod
95 use controlVector_mod
96 use gridVariableTransforms_mod
97 use varNameList_mod
98 use gridStateVector_mod
99 use gridStateVectorFileIO_mod
100 use ensembleStateVector_mod
101 use bMatrix_mod
102 use bMatrixEnsemble_mod
103 use localization_mod
104 use horizontalCoord_mod
105 use advection_mod
106 use verticalCoord_mod
107 use timeCoord_mod
108 use randomNumber_mod
109 use utilities_mod
110 use ramDisk_mod
111 implicit none
112
113 type(struct_gsv) :: statevector, statevectorEnsAmplitude
114 type(struct_ens) :: ensAmplitude
115 type(struct_hco), pointer :: hco_anl => null()
116 type(struct_hco), pointer :: hco_core => null()
117 type(struct_vco), pointer :: vco_anl => null()
118 type(struct_loc), pointer :: loc => null()
119 type(struct_adv), pointer :: adv_amplitudeAssimWindow
120
121 real(8), pointer :: field4d(:,:,:,:)
122 real(8), pointer :: field3d(:,:,:)
123 real(8), pointer :: ensAmplitude_oneLev(:,:,:,:)
124 real(4), allocatable :: randomEns(:,:,:,:)
125 real(8), allocatable :: mean(:,:,:)
126 real(8), allocatable :: stddev(:,:,:)
127 real(8), allocatable :: stddev_zm(:,:),stddev_zm2(:,:)
128 real(8), allocatable :: stddev_dm(:,:),stddev_dm2(:,:)
129 real(8), allocatable :: zonalMeanStddev(:)
130 real(8), allocatable :: controlVector(:), controlVector_global(:)
131
132 real(8) :: centralValue, centralValueLocal
133
134 integer :: fclos, fnom, fstopc, newdate, get_max_rss
135 integer :: ierr, nsize, iseed, nulnam, nultxt
136 integer :: ensIndex, index, kIndex, nkgdim, levIndex, lonIndex, latIndex
137 integer :: dateTime, datePrint, timePrint, dateStamp, numLoc, numStepAmplitude
138 integer :: nlevs, nlevs2, varIndex, ip3
139 integer :: locIndex, stepIndexInc, nEns, numBensInstance, instanceIndex
140 integer :: amp3dStepIndex, nLonLatPos, lonLatPosIndex
141 integer :: oneobs_timeStepIndex
142
143 integer, parameter :: lonPosIndex = 1
144 integer, parameter :: latPosIndex = 2
145
146 integer :: latPerPE, latPerPEmax, lonPerPE, lonPerPEmax
147 integer :: myLatBeg, myLatEnd
148 integer :: myLonBeg, myLonEnd
149 integer, allocatable :: dateStampList(:)
150
151 character(len=128) :: filename, filenameInc, filenameIncNorm, filenameEnsAmp
152 character(len=10) :: datestr
153 character(len=4) :: varName
154 character(len=1) :: locIndexString
155 character(len=2) :: instanceIndexString
156
157 character(len=4), parameter :: varNameALFAatm(1) = (/ 'ALFA' /)
158 character(len=4), parameter :: varNameALFAsfc(1) = (/ 'ALFS' /)
159 character(len=4) :: varNameALFA(1)
160
161 ! namelist variables
162 integer :: numperturbations ! number of perturbations for randomization estimate of stddev
163 integer :: nrandseed ! initial random seed value
164 integer :: oneobs_levs(100) ! list of level indexes where B matrix columns are computed
165 integer :: oneobs_lonlat(100,2) ! list of lon,lat index pairs where B matrix columns are computed
166 character(len=128) :: oneobs_timeStep ! can be 'first', 'last' or 'middle'
167 character(len=4) :: oneobs_varName ! can be 'all' or a specific variable name (default='all')
168 logical :: writeEnsAmplitude ! choose to write ensemble amplitude fields (for ensemble B)
169 logical :: writeTextStddev ! choose to write stddev to text file in addition to standard file
170 logical :: writePsiChiStddev ! choose to also write stddev of Psi/Chi in addition to UU/VV
171
172 namelist /namdiag/numperturbations, nrandseed, oneobs_levs, oneobs_lonlat, &
173 oneobs_varName, oneobs_timeStep, writeEnsAmplitude, writeTextStddev, writePsiChiStddev
174
175 call ver_printNameAndVersion('diagBmatrix','Diagnositcs of the B matrix')
176
177 ! MPI, tmg initialization
178 call mmpi_initialize
179 call tmg_init(mmpi_myid, 'TMG_INFO')
180 call utl_tmg_start(0,'Main')
181 ierr = fstopc('MSGLVL','ERRORS',0)
182
183 ! Set default values for namelist NAMDIAG parameters
184 numperturbations = -1
185 nrandseed = 1
186 oneobs_varName = 'all'
187 oneobs_timeStep = 'middle'
188 oneobs_levs(:) = -1
189 oneobs_lonlat(:,:)= -1
190 writeEnsAmplitude = .false.
191 writeTextStddev = .false.
192 writePsiChiStddev = .false.
193
194 ! Read the parameters from NAMDIAG
195 nulnam=0
196 ierr=fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
197 read(nulnam,nml=namdiag,iostat=ierr)
198 if(ierr.ne.0) call utl_abort('midas-diagBmatrix: Error reading namelist')
199 write(*,nml=namdiag)
200 ierr=fclos(nulnam)
201
202 nlevs=0
203 do index = 1, size(oneobs_levs)
204 if (oneobs_levs(index) >= 1) nlevs=nlevs+1
205 end do
206 nLonLatPos=0
207 do index = 1, size(oneobs_lonlat(:,lonPosIndex))
208 if (oneobs_lonlat(index,lonPosIndex) >= 1 .and. oneobs_lonlat(index,latPosIndex) >= 1) nLonLatPos=nLonLatPos+1
209 end do
210
211 ! Top Level Control setup
212 call ram_setup
213
214 !- Initialize the Temporal grid and set dateStamp from env variable
215 call tim_setup()
216 if (tim_getDateStamp() == 0) then
217 call utl_abort('midas-diagBmatrix: date must be set by env variable MIDAS_DATE')
218 end if
219
220 ! Build date-time string from dateStamp
221 dateStamp = tim_getDateStamp()
222 ierr = newdate(dateStamp,datePrint,timePrint,-3)
223 dateTime = datePrint*100 + timePrint/1000000
224 write(datestr,'(i10.10)') dateTime
225 write(*,*)' datePrint= ',datePrint,' timePrint= ',timePrint
226 write(*,*)' date= ',dateTime,' stamp= ',dateStamp
227
228 ! Initialize variables of the model states
229 call gsv_setup
230
231 ! Initialize the Analysis horizontal grid
232 call hco_SetupFromFile( hco_anl,'./analysisgrid', 'ANALYSIS', 'Analysis' ) ! IN
233
234 if ( hco_anl % global ) then
235 hco_core => hco_anl
236 else
237 !- Iniatilized the core (Non-Exteded) analysis grid
238 call hco_SetupFromFile( hco_core, './analysisgrid', 'COREGRID', 'AnalysisCore' ) ! IN
239 end if
240
241 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
242
243 ! Initialize the vertical coordinate from the statistics file
244 call vco_SetupFromFile( vco_anl, & ! OUT
245 './analysisgrid') ! IN
246
247 ! Allocate the statevector
248 call gsv_allocate(statevector, tim_nstepobsinc, hco_anl, vco_anl, &
249 datestamp_opt=tim_getDatestamp(), mpi_local_opt=.true., &
250 allocHeight_opt=.false., allocPressure_opt=.false.)
251 call gsv_zero(statevector)
252 nkgdim = statevector%nk
253
254 ! Setup the B matrix
255 call bmat_setup(hco_anl,hco_core,vco_anl)
256
257 !- Initialize the gridded variable transform module
258 call gvt_setup(hco_anl,hco_core,vco_anl)
259 if ( gsv_varExist(varName='HU') ) call gvt_setupRefFromTrialFiles('HU')
260
261 ! Setup of the L matrix done in bmat_setup
262 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
263
264 !
265 !==============================================
266 !- Compute columns of B and L matrices
267 !==============================================
268 !
269 if ( nLevs >= 1 .and. nLonLatPos >= 1 ) then
270
271 !
272 !- Compute columns of the B matrix
273 !
274 select case(trim(oneobs_timeStep))
275 case ('first')
276 oneobs_timeStepIndex = 1
277 case ('middle')
278 if (mod(tim_nstepobsinc,2) == 0) then
279 write(*,*)
280 write(*,*) 'odd number of nstepobsinc a required for obs place in the middle of the analysis window '
281 write(*,*) 'tim_nstepobsinc = ', tim_nstepobsinc
282 call utl_abort('midas-diagBmatrix')
283 end if
284 oneobs_timeStepIndex = (tim_nstepobsinc+1)/2
285 case ('last')
286 oneobs_timeStepIndex = tim_nstepobsinc
287 case default
288 write(*,*)
289 write(*,*) 'Unsupported oneobs_timeStep : ', trim(oneobs_timeStep)
290 call utl_abort('midas-diagBmatrix')
291 end select
292
293 allocate(controlVector(cvm_nvadim))
294
295 write(*,*) '********************************************'
296 write(*,*) 'midas-diagBmatrix: Compute columns of B matrix'
297 write(*,*) '********************************************'
298 write(*,*)
299 write(*,*) ' temporal location = ',trim(oneobs_timeStep), oneobs_timeStepIndex
300 write(*,*) ' number of levels = ',nLevs
301 write(*,*) ' number of lon-lat positions = ', nLonLatPos
302
303 do varIndex = 1, vnl_numvarmax
304
305 if ( .not. gsv_varExist(varName=vnl_varNameList(varIndex)) ) cycle
306 if ( trim(oneobs_varName) /= 'all' .and. (trim(oneobs_varName) /= trim(vnl_varNameList(varIndex))) ) cycle
307
308 filenameInc = 'columnB_' // trim(vnl_varNameList(varIndex)) // '_' // datestr // '.fst'
309 filenameIncNorm= 'columnBnorm_' // trim(vnl_varNameList(varIndex)) // '_' // datestr // '.fst'
310 filenameEnsAmp = 'ensAmplitude_' // trim(vnl_varNameList(varIndex)) // '_'
311
312 write(*,*)
313 write(*,*) 'midas-diagBmatrix: simulating a pseudo-observation of ', trim(vnl_varNameList(varIndex))
314
315 if(vnl_varLevelFromVarname(vnl_varNameList(varIndex)).eq.'SF') then
316 nlevs2 = 1
317 else
318 nlevs2 = nlevs
319 end if
320
321 ip3 = 0
322 do levIndex = 1, nlevs2
323 do lonLatPosIndex = 1, nLonLatPos
324
325 latIndex = oneobs_lonlat(lonLatPosIndex,latPosIndex)
326 lonIndex = oneobs_lonlat(lonLatPosIndex,lonPosIndex)
327
328 call gsv_zero(statevector)
329 call gsv_getField(statevector,field4d,vnl_varNameList(varIndex))
330
331 if ( latIndex >= statevector%myLatBeg .and. latIndex <= statevector%myLatEnd .and. &
332 lonIndex >= statevector%myLonBeg .and. lonIndex <= statevector%myLonEnd ) then
333 if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)) == 'SF') then
334 field4d(lonIndex,latIndex,1 ,oneobs_timeStepIndex) = 1.0D0
335 else
336 field4d(lonIndex,latIndex,oneobs_levs(levIndex),oneobs_timeStepIndex) = 1.0D0
337 end if
338 end if
339
340 controlVector(:)=0.0d0
341 call bmat_sqrtBT(controlVector,cvm_nvadim,statevector)
342 call bmat_sqrtB (controlVector,cvm_nvadim,statevector)
343
344 write(*,*)'midas-diagBmatrix: writing out the column of B, levIndex,lonIndex,latIndex=',levIndex,lonIndex,latIndex
345
346 ip3 = ip3 + 1
347
348 do stepIndexInc = 1, tim_nstepobsinc
349 call gio_writeToFile(statevector,filenameInc,'1OBS_'//trim(vnl_varNameList(varIndex)), &
350 stepIndex_opt=stepIndexInc, ip3_opt=ip3, unitConversion_opt=.true.)
351 end do
352
353 ! Normalized the result to get correlation-like pattern
354 centralValueLocal = 0.d0
355 if ( latIndex >= statevector%myLatBeg .and. latIndex <= statevector%myLatEnd .and. &
356 lonIndex >= statevector%myLonBeg .and. lonIndex <= statevector%myLonEnd ) then
357 if (vnl_varLevelFromVarname(vnl_varNameList(varIndex)).eq.'SF') then
358 centralValueLocal = field4d(lonIndex,latIndex,1 ,oneobs_timeStepIndex)
359 else
360 centralValueLocal = field4d(lonIndex,latIndex,oneobs_levs(levIndex),oneobs_timeStepIndex)
361 end if
362 end if
363 call rpn_comm_allreduce(centralValueLocal, centralValue, 1, &
364 "MPI_DOUBLE_PRECISION", "MPI_SUM", "GRID", ierr)
365
366 write(*,*) 'midas-diagBmatrix: centralValue found = ', centralValue
367
368 if (centralValue /= 0.d0) then
369 call gsv_scale(statevector,1.d0/centralValue)
370 else
371 call utl_abort('midas-diagBmatrix: central value equals 0!')
372 end if
373
374 do stepIndexInc = 1, tim_nstepobsinc
375 call gio_writeToFile(statevector,filenameIncNorm,'1OBSNRM_'//trim(vnl_varNameList(varIndex)), &
376 stepIndex_opt=stepIndexInc, ip3_opt=ip3, &
377 unitConversion_opt=.false.)
378 end do
379
380 ! Write the ensemble amplitude fields (i.e., the alphas) when Bens is active
381 if (writeEnsAmplitude) call ben_writeAmplitude('./',filenameEnsAmp, ip3) ! IN
382
383 end do
384 end do
385 end do
386
387 deallocate(controlVector)
388
389 !
390 !- Compute columns of the L matrix
391 !
392 numLoc = ben_getNumLoc()
393 numBensInstance = ben_getNumInstance()
394 numStepAmplitude = ben_getNumStepAmplitudeAssimWindow()
395 amp3dStepIndex = ben_getAmp3dStepIndexAssimWindow()
396
397 if (numStepAmplitude > 1) then
398 allocate(datestampList(numStepAmplitude))
399 call tim_getstamplist(dateStampList,numStepAmplitude,tim_getDatestamp())
400 nEns = ben_getnEns()
401 adv_amplitudeAssimWindow => ben_getAmplitudeAssimWindow()
402 else
403 allocate(datestampList(1))
404 datestampList(1) = dateStamp
405 end if
406
407 do instanceIndex = 1, numBensInstance
408 do locIndex = 1, numLoc ! (this loop will be done only when localization is used in B)
409 loc => ben_getLoc(locIndex,instanceIndex_opt=instanceIndex)
410
411 if (loc%vco%Vcode == 5002 .or. loc%vco%Vcode == 5005) then
412 varNameALFA(:) = varNameALFAatm(:)
413 else ! vco_anl%Vcode == -1
414 varNameALFA(:) = varNameALFAsfc(:)
415 end if
416
417 call mmpi_setup_latbands(loc%hco%nj, latPerPE, latPerPEmax, myLatBeg, myLatEnd)
418 call mmpi_setup_lonbands(loc%hco%ni, lonPerPE, lonPerPEmax, myLonBeg, myLonEnd)
419
420 call ens_allocate(ensAmplitude, loc%nEnsOverDimension, numStepAmplitude, loc%hco, loc%vco, &
421 datestampList=dateStampList, varNames_opt=varNameALFA, dataKind_opt=8)
422
423 call gsv_allocate(statevectorEnsAmplitude, numStepAmplitude, loc%hco, loc%vco, &
424 dateStampList_opt=dateStampList, varNames_opt=varNameALFA, dataKind_opt=8, &
425 mpi_local_opt=.true.)
426
427 allocate(controlVector(loc%cvDim))
428
429 write(*,*) '********************************************'
430 write(*,*) 'midas-diagBmatrix: Compute columns of L matrix'
431 write(*,*) '********************************************'
432
433 write(*,*) ' number of levels = ', nlevs
434 write(*,*) ' number of lon-lat positions = ', nLonLatPos
435
436 if (numLoc > 1) then
437 write(locIndexString,'(i1)') locIndex
438 filename = 'columnL_' // trim(loc%locType) // '_' // locIndexString // '_' // datestr // '.fst'
439 else
440 if (numBensInstance > 1) then
441 write(instanceIndexString,'(I2.2)') instanceIndex
442 filename = 'columnL_i' // trim(instanceIndexString) // '_' // trim(loc%locType) // '_' // datestr // '.fst'
443 else
444 filename = 'columnL_' // trim(loc%locType) // '_' // datestr // '.fst'
445 end if
446 end if
447
448 ip3 = 0
449 do levIndex = 1, nlevs2
450 do lonLatPosIndex = 1, nLonLatPos
451
452 latIndex = oneobs_lonlat(lonLatPosIndex,latPosIndex)
453 lonIndex = oneobs_lonlat(lonLatPosIndex,lonPosIndex)
454
455 call ens_zero(ensAmplitude)
456 call gsv_zero(statevectorEnsAmplitude)
457 if ( latIndex >= statevector%myLatBeg .and. latIndex <= statevector%myLatEnd .and. &
458 lonIndex >= statevector%myLonBeg .and. lonIndex <= statevector%myLonEnd ) then
459 ensAmplitude_oneLev => ens_getOneLev_r8(ensAmplitude,oneobs_levs(levIndex))
460 ensAmplitude_oneLev(:,oneobs_timeStepIndex,lonIndex,latIndex) = 1.d0
461 end if
462 controlVector(:)=0.0d0
463
464 if (numStepAmplitude > 1) then
465 call adv_ensemble_ad(ensAmplitude, & ! INOUT
466 adv_amplitudeAssimWindow, nEns) ! IN
467 end if
468
469 call loc_LsqrtAd(loc, & ! IN
470 ensAmplitude, & ! IN
471 controlVector, & ! OUT
472 amp3dStepIndex) ! IN
473 call loc_Lsqrt (loc, & ! IN
474 controlVector, & ! IN
475 ensAmplitude, & ! OUT
476 amp3dStepIndex) ! IN
477
478 if (numStepAmplitude > 1) then
479 call adv_ensemble_tl(ensAmplitude, & ! INOUT
480 adv_amplitudeAssimWindow, nEns) ! IN
481 end if
482
483 write(*,*)'midas-diagBmatrix: writing out the column of L, levIndex,lonIndex,latIndex=',levIndex,lonIndex,latIndex
484 call flush(6)
485
486 ip3 = ip3 + 1
487 call ens_copyMember(ensAmplitude, statevectorEnsAmplitude, 1)
488 do stepIndexInc = 1, numStepAmplitude
489 call gio_writeToFile(statevectorEnsAmplitude,filename,'ONEOBS', &
490 stepIndex_opt=stepIndexInc, ip3_opt=ip3,unitConversion_opt=.false.)
491 end do
492
493 end do
494 end do
495
496 deallocate(controlVector)
497 call ens_deallocate(ensAmplitude)
498 call gsv_deallocate(statevectorEnsAmplitude)
499
500 end do ! localization index (if active in B)
501 end do ! Bens instance
502
503 end if ! if any oneobs selected
504
505 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
506
507 !
508 !==============================================
509 !- Compute the stddev from random perturbations
510 !==============================================
511 !
512 if ( numperturbations > 1 ) then
513
514 write(*,*) '********************************************'
515 write(*,*) 'midas-diagBmatrix: Compute the stddev from random perturbations'
516 write(*,*) '********************************************'
517
518 allocate(controlVector(cvm_nvadim))
519 allocate(controlVector_global(cvm_nvadim_mpiglobal))
520
521 call gsv_zero(statevector)
522
523 ! Allocate the randomEns, mean and stddev
524 allocate(randomEns(statevector%myLonBeg:statevector%myLonEnd,statevector%myLatBeg:statevector%myLatEnd,nkgdim,numperturbations))
525 allocate(mean(statevector%myLonBeg:statevector%myLonEnd,statevector%myLatBeg:statevector%myLatEnd,nkgdim))
526 allocate(stddev(statevector%myLonBeg:statevector%myLonEnd,statevector%myLatBeg:statevector%myLatEnd,nkgdim))
527
528 iseed = abs(nrandseed)
529 call rng_setup(iseed)
530
531 call gsv_getField(statevector,field3d)
532
533 !
534 !- Compute the ensemble of random perturbations
535 !
536 do ensIndex = 1, numperturbations
537 write(*,*) 'midas-diagBmatrix: computing member number= ',ensIndex
538 call flush(6)
539
540 !- Global vector (same for each processors)
541 do index = 1, cvm_nvadim_mpiglobal
542 controlVector_global(index) = rng_gaussian()
543 end do
544
545 !- Extract only the subvector for this processor
546 call bmat_reduceToMPILocal(controlVector, & ! OUT
547 controlVector_global ) ! IN
548
549 !- Transform to control variables in physical space
550 call bmat_sqrtB(controlVector,cvm_nvadim,statevector)
551
552 if ( writePsiChiStddev ) call gvt_transform(statevector,'UVtoPsiChi')
553
554 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
555 do kIndex = 1, nkgdim
556 do latIndex = statevector%myLatBeg, statevector%myLatEnd
557 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
558 randomEns(lonIndex,latIndex,kIndex,ensIndex) = field3d(lonIndex,latIndex,kIndex)
559 end do
560 end do
561 end do
562 !$OMP END PARALLEL DO
563
564 end do ! Loop on ens member
565
566 !
567 !- Compute the ensemble mean
568 !
569 mean(:,:,:) = 0.0d0
570 do ensIndex = 1, numperturbations
571 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
572 do kIndex = 1, nkgdim
573 do latIndex = statevector%myLatBeg, statevector%myLatEnd
574 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
575 mean(lonIndex,latIndex,kIndex) = mean(lonIndex,latIndex,kIndex) + randomEns(lonIndex,latIndex,kIndex,ensIndex)
576 end do
577 end do
578 end do
579 !$OMP END PARALLEL DO
580 end do
581
582 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
583 do kIndex = 1, nkgdim
584 do latIndex = statevector%myLatBeg, statevector%myLatEnd
585 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
586 mean(lonIndex,latIndex,kIndex) = mean(lonIndex,latIndex,kIndex)/real(numperturbations,8)
587 end do
588 end do
589 end do
590 !$OMP END PARALLEL DO
591
592 !
593 !- Remove the ensemble mean from the ensemble
594 !
595 !$OMP PARALLEL DO PRIVATE (lonIndex,ensIndex,latIndex,kIndex)
596 do ensIndex = 1, numperturbations
597 do kIndex = 1, nkgdim
598 do latIndex = statevector%myLatBeg, statevector%myLatEnd
599 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
600 randomEns(lonIndex,latIndex,kIndex,ensIndex) = randomEns(lonIndex,latIndex,kIndex,ensIndex) - mean(lonIndex,latIndex,kIndex)
601 end do
602 end do
603 end do
604 end do
605 !$OMP END PARALLEL DO
606 deallocate(mean)
607
608 !
609 !- Compute the ensemble stddev
610 !
611 stddev(:,:,:) = 0.0d0
612
613 do ensIndex = 1, numperturbations
614 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
615 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
616 do latIndex = statevector%myLatBeg, statevector%myLatEnd
617 do kIndex = 1, nkgdim
618 stddev(lonIndex,latIndex,kIndex) = stddev(lonIndex,latIndex,kIndex) + &
619 (randomEns(lonIndex,latIndex,kIndex,ensIndex)**2)/real(numperturbations,8)
620 end do
621 end do
622 end do
623 !$OMP END PARALLEL DO
624 end do
625 deallocate(randomEns)
626
627 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
628 do kIndex = 1, nkgdim
629 do latIndex = statevector%myLatBeg, statevector%myLatEnd
630 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
631 stddev(lonIndex,latIndex,kIndex) = sqrt(stddev(lonIndex,latIndex,kIndex))
632 end do
633 end do
634 end do
635 !$OMP END PARALLEL DO
636
637 !- Insert results in statevector
638 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
639 do kIndex = 1, nkgdim
640 do latIndex = statevector%myLatBeg, statevector%myLatEnd
641 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
642 field3d(lonIndex,latIndex,kIndex) = stddev(lonIndex,latIndex,kIndex)
643 end do
644 end do
645 end do
646 !$OMP END PARALLEL DO
647 deallocate(stddev)
648
649 !- Write to file
650 call gio_writeToFile(statevector,'stddev_' // datestr // '.fst','GD_STDDEV', &
651 unitConversion_opt=.true.)
652
653 !
654 !- Compute the zonal mean std dev
655 !
656 write(*,*) 'midas-diagBmatrix: Compute the zonal mean stddev'
657 call flush(6)
658
659 allocate(stddev_zm(hco_anl%nj,nkgdim))
660 allocate(stddev_zm2(hco_anl%nj,nkgdim))
661 stddev_zm(:,:) = 0.d0
662 stddev_zm2(:,:) = 0.d0
663
664 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
665 do kIndex = 1, nkgdim
666 do latIndex = statevector%myLatBeg, statevector%myLatEnd
667 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
668 stddev_zm(latIndex,kIndex) = stddev_zm(latIndex,kIndex) + (field3d(lonIndex,latIndex,kIndex)**2)/real(hco_anl%ni,8)
669 end do
670 end do
671 end do
672 !$OMP END PARALLEL DO
673
674 nsize = statevector%nj*nkgdim
675 call rpn_comm_allreduce(stddev_zm,stddev_zm2,nsize, &
676 "MPI_DOUBLE_PRECISION","MPI_SUM","GRID",ierr)
677
678 !- Insert results in statevector
679 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
680 do kIndex = 1, nkgdim
681 do latIndex = statevector%myLatBeg, statevector%myLatEnd
682 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
683 if(stddev_zm2(latIndex,kIndex)> 0.0d0) then
684 field3d(lonIndex,latIndex,kIndex) = sqrt(stddev_zm2(latIndex,kIndex))
685 else
686 field3d(lonIndex,latIndex,kIndex) = 0.0d0
687 end if
688 end do
689 end do
690 end do
691 !$OMP END PARALLEL DO
692 deallocate(stddev_zm)
693 deallocate(stddev_zm2)
694
695 call gio_writeToFile(statevector,'stddev_' // datestr // '.fst','ZM_STDDEV', &
696 unitConversion_opt=.true.)
697
698 ! Write the zonal mean stddev to a text file, if requested
699 if ( writeTextStddev ) then
700 allocate(zonalMeanStddev(statevector%latPerPE * mmpi_npey))
701 do varIndex = 1, vnl_numvarmax
702 if (.not. gsv_varExist(varName=vnl_varNameList(varIndex)) ) cycle
703
704 write(*,*) 'midas-diagBmatrix: writing zonal mean stddev to text file for variable: ', vnl_varNameList(varIndex)
705 call gsv_getField(statevector,field3d,vnl_varNameList(varIndex))
706
707 varName = vnl_varNameList(varIndex)
708 if ( varName == 'HU' ) varName = 'LQ'
709 filename = 'stddev_ZM_' // trim(varName) // '_' // datestr // '.txt'
710 nultxt = 0
711 if ( mmpi_myid == 0 ) ierr = fnom(nultxt,trim(filename),'FTN',0)
712
713 do levIndex = 1, gsv_getNumLevFromVarName(statevector,vnl_varNameList(varIndex))
714 nsize = statevector%latPerPE
715 call rpn_comm_gather(field3d(1,:,levIndex), nsize, 'mpi_double_precision', &
716 zonalMeanStddev, nsize, 'mpi_double_precision', 0, 'NS', ierr )
717 if ( mmpi_myid == 0 ) then
718 do latIndex = 1, statevector%nj
719 write(nultxt,*) field3d(1,latIndex,levIndex)
720 end do
721 end if
722 end do
723
724 if ( mmpi_myid == 0 ) ierr = fclos(nulnam)
725
726 end do
727 deallocate(zonalMeanStddev)
728
729 end if
730
731 !
732 !- Compute the domain mean std dev
733 !
734 write(*,*) 'midas-diagBmatrix: Compute the domain mean stddev'
735 call flush(6)
736
737 allocate(stddev_dm(hco_anl%ni,nkgdim))
738 allocate(stddev_dm2(hco_anl%ni,nkgdim))
739 stddev_dm(:,:) = 0.d0
740 stddev_dm2(:,:) = 0.d0
741
742 !$OMP PARALLEL DO PRIVATE (latIndex,kIndex)
743 do kIndex = 1, nkgdim
744 do latIndex = statevector%myLatBeg, statevector%myLatEnd
745 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
746 stddev_dm(lonIndex,kIndex) = stddev_dm(lonIndex,kIndex) + (field3d(lonIndex,latIndex,kIndex)**2)/real(hco_anl%nj,8)
747 end do
748 end do
749 end do
750 !$OMP END PARALLEL DO
751
752 nsize = statevector%ni*nkgdim
753 call rpn_comm_allreduce(stddev_dm,stddev_dm2,nsize, &
754 "MPI_DOUBLE_PRECISION","MPI_SUM","GRID",ierr)
755
756 !- Insert results in statevector
757 !$OMP PARALLEL DO PRIVATE (lonIndex,latIndex,kIndex)
758 do kIndex = 1, nkgdim
759 do latIndex = statevector%myLatBeg, statevector%myLatEnd
760 do lonIndex = statevector%myLonBeg, statevector%myLonEnd
761 if(stddev_dm2(lonIndex,kIndex)> 0.0d0) then
762 field3d(lonIndex,latIndex,kIndex) = sqrt(stddev_dm2(lonIndex,kIndex))
763 else
764 field3d(lonIndex,latIndex,kIndex) = 0.0d0
765 end if
766 end do
767 end do
768 end do
769 !$OMP END PARALLEL DO
770 deallocate(stddev_dm)
771 deallocate(stddev_dm2)
772 deallocate(controlVector)
773 deallocate(controlVector_global)
774
775 call gio_writeToFile(statevector,'stddev_' // datestr // '.fst','DM_STDDEV', &
776 unitConversion_opt=.true.)
777
778 end if ! if numperturbations.gt.1
779
780 call gsv_deallocate(statevector)
781
782 write(*,*) 'Memory Used: ',get_max_rss()/1024,'Mb'
783
784 ! MPI, tmg finalize
785 call utl_tmg_stop(0)
786 call tmg_terminate(mmpi_myid, 'TMG_INFO')
787 call rpn_comm_finalize(ierr)
788
789 write(*,*) ' --------------------------------'
790 write(*,*) ' midas-diagBmatrix ENDS'
791 write(*,*) ' --------------------------------'
792
793end program midas_diagBmatrix