ROMS
Loading...
Searching...
No Matches
obs_sen_r4dvar_analysis.h
Go to the documentation of this file.
1 MODULE roms_kernel_mod
2!
3!git $Id$
4!=================================================== Andrew M. Moore ===
5! Copyright (c) 2002-2025 The ROMS Group Hernan G. Arango !
6! Licensed under a MIT/X style license !
7! See License_ROMS.md !
8!=======================================================================
9! !
10! ROMS Strong/Weak Constraint 4-Dimensional Variational Data !
11! Assimilation and Observation Sensitivity Driver: Indirect !
12! Representer Approach (R4D-Var). !
13! Dual formulation in observarion space. !
14! !
15! This driver is used for weak constraint 4D-Var where errors are !
16! considered in both model and observations. It also computes the !
17! the sensitivity of the assimilation system to each observation. !
18! It measures the degree to which each observation contributes to !
19! the uncertainty in the estimate. This analysis can be used to !
20! determine the type of measurements that need to be made, where !
21! to observe, and when. !
22! !
23! The routines in this driver control the initialization, time- !
24! stepping, and finalization of ROMS model following ESMF !
25! conventions: !
26! !
27! ROMS_initialize !
28! ROMS_run !
29! ROMS_finalize !
30! !
31! References: !
32! !
33! Moore, A.M., H.G. Arango, G. Broquet, B.S. Powell, A.T. Weaver, !
34! and J. Zavala-Garay, 2011: The Regional Ocean Modeling System !
35! (ROMS) 4-dimensional variational data assimilations systems, !
36! Part I - System overview and formulation, Prog. Oceanogr., 91, !
37! 34-49, doi:10.1016/j.pocean.2011.05.004. !
38! !
39! Moore, A.M., H.G. Arango, G. Broquet, C. Edward, M. Veneziani, !
40! B. Powell, D. Foley, J.D. Doyle, D. Costa, and P. Robinson, !
41! 2011: The Regional Ocean Modeling System (ROMS) 4-dimensional !
42! variational data assimilations systems, Part II - Performance !
43! and application to the California Current System, Prog. !
44! Oceanogr., 91, 50-73, doi:10.1016/j.pocean.2011.05.003. !
45! !
46! Moore, A.M., H.G. Arango, G. Broquet, C. Edward, M. Veneziani, !
47! B. Powell, D. Foley, J.D. Doyle, D. Costa, and P. Robinson, !
48! 2011: The Regional Ocean Modeling System (ROMS) 4-dimensional !
49! variational data assimilations systems, Part III - Observation !
50! impact and observation sensitivity in the California Current !
51! System, Prog. Oceanogr., 91, 74-94, !
52! doi:10.1016/j.pocean.2011.05.005. !
53! !
54!=======================================================================
55!
56 USE mod_param
57 USE mod_parallel
58 USE mod_arrays
59 USE mod_fourdvar
60 USE mod_iounits
61 USE mod_ncparam
62 USE mod_netcdf
63#if defined PIO_LIB && defined DISTRIBUTE
65#endif
66 USE mod_scalars
67 USE mod_stepping
68!
69#ifdef ADJUST_BOUNDARY
71#endif
73 USE mod_ocean, ONLY : initialize_ocean
74!
75 USE ad_wrt_his_mod, ONLY : ad_wrt_his
77 USE congrad_mod, ONLY : congrad
80 USE def_mod_mod, ONLY : def_mod
81 USE def_norm_mod, ONLY : def_norm
82 USE get_state_mod, ONLY : get_state
83 USE inp_par_mod, ONLY : inp_par
84#ifdef MCT_LIB
85# ifdef ATM_COUPLING
86 USE mct_coupler_mod, ONLY : initialize_ocn2atm_coupling
87# endif
88# ifdef WAV_COUPLING
89 USE mct_coupler_mod, ONLY : initialize_ocn2wav_coupling
90# endif
91#endif
96 USE tl_def_ini_mod, ONLY : tl_def_ini
97 USE wrt_ini_mod, ONLY : wrt_ini
98 USE wrt_rst_mod, ONLY : wrt_rst
99#if defined BALANCE_OPERATOR && defined ZETA_ELLIPTIC
101#endif
102!
103 implicit none
104!
105 PUBLIC :: roms_initialize
106 PUBLIC :: roms_run
107 PUBLIC :: roms_finalize
108!
109 CONTAINS
110!
111 SUBROUTINE roms_initialize (first, mpiCOMM)
112!
113!=======================================================================
114! !
115! This routine allocates and initializes ROMS state variables !
116! and internal and external parameters. !
117! !
118!=======================================================================
119!
120! Imported variable declarations.
121!
122 logical, intent(inout) :: first
123!
124 integer, intent(in), optional :: mpiCOMM
125!
126! Local variable declarations.
127!
128 logical :: allocate_vars = .true.
129!
130#ifdef DISTRIBUTE
131 integer :: MyError, MySize
132#endif
133 integer :: STDrec, Tindex
134 integer :: chunk_size, ng, thread
135#ifdef _OPENMP
136 integer :: my_threadnum
137#endif
138!
139 character (len=*), parameter :: MyFile = &
140 & __FILE__//", ROMS_initialize"
141
142#ifdef DISTRIBUTE
143!
144!-----------------------------------------------------------------------
145! Set distribute-memory (mpi) world communictor.
146!-----------------------------------------------------------------------
147!
148 IF (PRESENT(mpicomm)) THEN
149 ocn_comm_world=mpicomm
150 ELSE
151 ocn_comm_world=mpi_comm_world
152 END IF
153 CALL mpi_comm_rank (ocn_comm_world, myrank, myerror)
154 CALL mpi_comm_size (ocn_comm_world, mysize, myerror)
155#endif
156!
157!-----------------------------------------------------------------------
158! On first pass, initialize model parameters a variables for all
159! nested/composed grids. Notice that the logical switch "first"
160! is used to allow multiple calls to this routine during ensemble
161! configurations.
162!-----------------------------------------------------------------------
163!
164 IF (first) THEN
165 first=.false.
166!
167! Initialize parallel control switches. These scalars switches are
168! independent from standard input parameters.
169!
171!
172! Set the ROMS standard output unit to write verbose execution info.
173! Notice that the default standard out unit in Fortran is 6.
174!
175! In some applications like coupling or disjointed mpi-communications,
176! it is advantageous to write standard output to a specific filename
177! instead of the default Fortran standard output unit 6. If that is
178! the case, it opens such formatted file for writing.
179!
180 IF (set_stdoutunit) THEN
182 set_stdoutunit=.false.
183 END IF
184!
185! Read in model tunable parameters from standard input. Allocate and
186! initialize variables in several modules after the number of nested
187! grids and dimension parameters are known.
188!
189 CALL inp_par (inlm)
190 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
191!
192! Set domain decomposition tile partition range. This range is
193! computed only once since the "first_tile" and "last_tile" values
194! are private for each parallel thread/node.
195!
196#if defined _OPENMP
197 mythread=my_threadnum()
198#elif defined DISTRIBUTE
200#else
201 mythread=0
202#endif
203 DO ng=1,ngrids
204 chunk_size=(ntilex(ng)*ntilee(ng)+numthreads-1)/numthreads
205 first_tile(ng)=mythread*chunk_size
206 last_tile(ng)=first_tile(ng)+chunk_size-1
207 END DO
208!
209! Initialize internal wall clocks. Notice that the timings does not
210! includes processing standard input because several parameters are
211! needed to allocate clock variables.
212!
213 IF (master) THEN
214 WRITE (stdout,10)
215 10 FORMAT (/,' Process Information:',/)
216 END IF
217!
218 DO ng=1,ngrids
219 DO thread=thread_range
220 CALL wclock_on (ng, inlm, 0, __line__, myfile)
221 END DO
222 END DO
223!
224! Allocate and initialize modules variables.
225!
226 CALL roms_allocate_arrays (allocate_vars)
228 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
229
230 END IF
231
232#if defined MCT_LIB && (defined ATM_COUPLING || defined WAV_COUPLING)
233!
234!-----------------------------------------------------------------------
235! Initialize coupling streams between model(s).
236!-----------------------------------------------------------------------
237!
238 DO ng=1,ngrids
239# ifdef ATM_COUPLING
240 CALL initialize_ocn2atm_coupling (ng, myrank)
241# endif
242# ifdef WAV_COUPLING
243 CALL initialize_ocn2wav_coupling (ng, myrank)
244# endif
245 END DO
246#endif
247
248#if !defined RECOMPUTE_4DVAR
249!
250!-----------------------------------------------------------------------
251! If the required vectors and arrays from congrad from a previous
252! run of the assimilation cycle are available, read them here from
253! LCZ(ng)%name NetCDF file.
254!-----------------------------------------------------------------------
255!
256 sourcefile=myfile
257 DO ng=1,ngrids
258 SELECT CASE (lcz(ng)%IOtype)
259 CASE (io_nf90)
260 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
261 & 'cg_beta', cg_beta)
262 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
263
264 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
265 & 'cg_delta', cg_delta)
266 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
267
268 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
269 & 'cg_Gnorm_v', cg_gnorm_v)
270 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
271
272 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
273 & 'cg_dla', cg_dla)
274 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
275
276 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
277 & 'cg_QG', cg_qg)
278 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
279
280 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
281 & 'zgrad0', zgrad0)
282 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
283
284 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
285 & 'zcglwk', zcglwk)
286 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
287
288 CALL netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
289 & 'TLmodVal_S', tlmodval_s, &
290 & broadcast = .false.) ! Master use only
291 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
292
293# if defined PIO_LIB && defined DISTRIBUTE
294 CASE (io_pio)
295 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
296 & 'cg_beta', cg_beta)
297 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
298
299 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
300 & 'cg_delta', cg_delta)
301 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
302
303 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
304 & 'cg_Gnorm_v', cg_gnorm_v)
305 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
306
307 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
308 & 'cg_dla', cg_dla)
309 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
310
311 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
312 & 'cg_QG', cg_qg)
313 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
314
315 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
316 & 'zgrad0', zgrad0)
317 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
318
319 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
320 & 'zcglwk', zcglwk)
321 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
322
323 CALL pio_netcdf_get_fvar (ng, itlm, lcz(ng)%name, &
324 & 'TLmodVal_S', tlmodval_s)
325 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
326# endif
327 END SELECT
328 END DO
329#endif
330!
331!-----------------------------------------------------------------------
332! Read in standard deviation factors for error covariance.
333!-----------------------------------------------------------------------
334!
335! Initial conditions standard deviation. They are loaded in Tindex=1
336! of the e_var(...,Tindex) state variables.
337!
338 stdrec=1
339 tindex=1
340 DO ng=1,ngrids
341 CALL get_state (ng, 10, 10, std(1,ng), stdrec, tindex)
342 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
343 END DO
344!
345! Model error standard deviation. They are loaded in Tindex=2
346! of the e_var(...,Tindex) state variables.
347!
348 stdrec=1
349 tindex=2
350 IF (nsa.eq.2) THEN
351 DO ng=1,ngrids
352 CALL get_state (ng, 11, 11, std(2,ng), stdrec, tindex)
353 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
354 END DO
355 END IF
356
357#ifdef ADJUST_BOUNDARY
358!
359! Open boundary conditions standard deviation.
360!
361 stdrec=1
362 tindex=1
363 DO ng=1,ngrids
364 CALL get_state (ng, 12, 12, std(3,ng), stdrec, tindex)
365 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
366 END DO
367#endif
368#if defined ADJUST_WSTRESS || defined ADJUST_STFLUX
369!
370! Surface forcing standard deviation.
371!
372 stdrec=1
373 tindex=1
374 DO ng=1,ngrids
375 CALL get_state (ng, 13, 13, std(4,ng), stdrec, tindex)
376 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
377 END DO
378#endif
379!
380 RETURN
381 END SUBROUTINE roms_initialize
382!
383 SUBROUTINE roms_run (RunInterval)
384!
385!=======================================================================
386! !
387! This routine time-steps ROMS nonlinear, tangent linear and !
388! adjoint models. !
389! !
390!=======================================================================
391!
392! Imported variable declarations
393!
394 real(dp), intent(in) :: RunInterval ! seconds
395!
396! Local variable declarations.
397!
398 logical :: Lcgini, Linner, Lposterior
399!
400 integer :: my_inner, my_outer
401 integer :: Lbck, Lini, Rec, Rec1, Rec2
402 integer :: i, lstr, ng, status, tile
403 integer :: Fcount, NRMrec
404
405 integer, dimension(Ngrids) :: Nrec
406!
407 real(r8) :: str_day, end_day
408!
409 character (len=14) :: driver
410 character (len=20) :: string
411
412 character (len=*), parameter :: MyFile = &
413 & __FILE__//", ROMS_run"
414!
415!=======================================================================
416! Run model for all nested grids, if any.
417!=======================================================================
418!
419! Initialize relevant parameters.
420!
421 DO ng=1,ngrids
422#if defined ADJUST_STFLUX || defined ADJUST_WSTRESS
423 lfinp(ng)=1 ! forcing index for input
424 lfout(ng)=1 ! forcing index for output history files
425#endif
426#ifdef ADJUST_BOUNDARY
427 lbinp(ng)=1 ! boundary index for input
428 lbout(ng)=1 ! boundary index for output history files
429#endif
430 lold(ng)=1 ! old minimization time index
431 lnew(ng)=2 ! new minimization time index
432 END DO
433 lini=1 ! NLM initial conditions record in INI
434 lbck=2 ! background record in INI
435 rec1=1
436 rec2=2
437 nrun=1
438 outer=0
439 inner=0
440 erstr=1
442 driver='obs_sen_w4dvar'
443!
444!-----------------------------------------------------------------------
445! Configure weak constraint 4DVAR algorithm: Indirect Representer
446! Approach.
447!-----------------------------------------------------------------------
448!
449! Initialize the switch to gather weak constraint forcing.
450!
451 DO ng=1,ngrids
452 wrtforce(ng)=.false.
453 END DO
454!
455! Initialize and set nonlinear model initial conditions.
456!
457 DO ng=1,ngrids
458 wrtnlmod(ng)=.true.
459 wrtrpmod(ng)=.false.
460 wrttlmod(ng)=.false.
461 END DO
462!
463 CALL initial
464 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
465!
466! Save nonlinear initial conditions (currently in time index 1,
467! background) into record "Lini" of INI(ng)%name NetCDF file. The
468! record "Lbck" becomes the background state record and the record
469! "Lini" becomes current nonlinear initial conditions.
470!
471 DO ng=1,ngrids
472 ini(ng)%Rindex=1
473 fcount=ini(ng)%load
474 ini(ng)%Nrec(fcount)=1
475#ifdef DISTRIBUTE
476 CALL wrt_ini (ng, myrank, 1)
477#else
478 CALL wrt_ini (ng, -1, 1)
479#endif
480 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
481 END DO
482!
483! Set nonlinear output history file as the initial basic state
484! trajectory.
485!
486 DO ng=1,ngrids
487 ldefhis(ng)=.true.
488 lwrthis(ng)=.true.
489 WRITE (his(ng)%name,10) trim(fwd(ng)%head), outer
490 lstr=len_trim(his(ng)%name)
491 his(ng)%base=his(ng)%name(1:lstr-3)
492 END DO
493!
494!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
495! Model-error covariance normalization and stardard deviation factors.
496!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
497!
498! Compute or read in the error covariance normalization factors.
499! If computing, write out factors to NetCDF. This is an expensive
500! computation that needs to be computed only once for a particular
501! application grid and decorrelation scales.
502!
503 DO ng=1,ngrids
504 IF (any(lwrtnrm(:,ng))) THEN
505 CALL def_norm (ng, inlm, 1)
506 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
507
508 IF (nsa.eq.2) THEN
509 CALL def_norm (ng, inlm, 2)
510 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
511 END IF
512
513#ifdef ADJUST_BOUNDARY
514 CALL def_norm (ng, inlm, 3)
515 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
516#endif
517
518#if defined ADJUST_WSTRESS || defined ADJUST_STFLUX
519 CALL def_norm (ng, inlm, 4)
520 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
521#endif
522
523 DO tile=first_tile(ng),last_tile(ng),+1
524 CALL normalization (ng, tile, 2)
525 END DO
526 ldefnrm(1:4,ng)=.false.
527 lwrtnrm(1:4,ng)=.false.
528 ELSE
529 nrmrec=1
530 CALL get_state (ng, 14, 14, nrm(1,ng), nrmrec, 1)
531 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
532
533 IF (nsa.eq.2) THEN
534 CALL get_state (ng, 15, 15, nrm(2,ng), nrmrec, 2)
535 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
536 END IF
537
538#ifdef ADJUST_BOUNDARY
539 CALL get_state (ng, 16, 16, nrm(3,ng), nrmrec, 1)
540 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
541#endif
542
543#if defined ADJUST_WSTRESS || defined ADJUST_STFLUX
544 CALL get_state (ng, 17, 17, nrm(4,ng), nrmrec, 1)
545 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
546#endif
547 END IF
548 END DO
549
550#if !defined RECOMPUTE_4DVAR && defined BALANCE_OPERATOR && \
551 defined zeta_elliptic
552!
553! Compute the reference zeta and biconjugate gradient arrays
554! required for the balance of free surface.
555!
556 IF (balance(isfsur)) THEN
557 DO ng=1,ngrids
558 CALL get_state (ng, inlm, 2, ini(ng), lini, lini)
559 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
560!
561 DO tile=first_tile(ng),last_tile(ng),+1
562 CALL balance_ref (ng, tile, lini)
563 CALL biconj (ng, tile, inlm, lini)
564 END DO
565 wrtzetaref(ng)=.true.
566 END DO
567 END IF
568#endif
569!
570! Define tangent linear initial conditions file.
571!
572 DO ng=1,ngrids
573 ldefitl(ng)=.true.
574 CALL tl_def_ini (ng)
575 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
576 END DO
577!
578! Define TLM/RPM impulse forcing NetCDF file.
579!
580 DO ng=1,ngrids
581 ldeftlf(ng)=.true.
582 CALL def_impulse (ng)
583 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
584 END DO
585!
586! Define output 4DVAR NetCDF file containing all processed data
587! at observation locations.
588!
589 DO ng=1,ngrids
590 ldefmod(ng)=.true.
591 CALL def_mod (ng)
592 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
593 END DO
594!
595! Write out outer loop beeing processed.
596!
597 sourcefile=myfile
598 DO ng=1,ngrids
599 SELECT CASE (dav(ng)%IOtype)
600 CASE (io_nf90)
601 CALL netcdf_put_ivar (ng, inlm, dav(ng)%name, &
602 & 'Nimpact', nimpact, &
603 & (/0/), (/0/), &
604 & ncid = dav(ng)%ncid)
605
606#if defined PIO_LIB && defined DISTRIBUTE
607 CASE (io_pio)
608 CALL pio_netcdf_put_ivar (ng, inlm, dav(ng)%name, &
609 & 'Nimpact', nimpact, &
610 & (/0/), (/0/), &
611 & piofile = dav(ng)%pioFile)
612#endif
613 END SELECT
614 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
615 END DO
616!
617!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
618! Run nonlinear model and compute basic state trajectory. It processes
619! and writes the observations accept/reject flag (ObsScale) once to
620! allow background quality control, if any.
621!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
622!
623 DO ng=1,ngrids
624 wrtobsscale(ng)=.true.
625 IF (master) THEN
626 WRITE (stdout,20) 'NL', ng, ntstart(ng), ntend(ng)
627 END IF
628 END DO
629!
630#ifdef SOLVE3D
631 CALL main3d (runinterval)
632#else
633 CALL main2d (runinterval)
634#endif
635 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
636!
637 DO ng=1,ngrids
638 wrtnlmod(ng)=.false.
639 wrtobsscale(ng)=.false.
640 END DO
641
642#ifdef FORWARD_FLUXES
643!
644! Set the BLK structure to contain the nonlinear model surface fluxes
645! needed by the tangent linear and adjoint models. Also, set switches
646! to process that structure in routine "check_multifile". Notice that
647! it is possible to split the solution into multiple NetCDF files to
648! reduce their size.
649!
650! The switch LreadFRC is deactivated because all the atmospheric
651! forcing, including shortwave radiation, is read from the NLM
652! surface fluxes or is assigned during ESM coupling. Such fluxes
653! are available from the QCK structure. There is no need for reading
654! and processing from the FRC structure input forcing-files.
655!
656 CALL edit_multifile ('QCK2BLK')
657 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
658 DO ng=1,ngrids
659 lreadblk(ng)=.true.
660 lreadfrc(ng)=.false.
661 lreadqck(ng)=.false.
662 END DO
663#endif
664
665#ifdef RECOMPUTE_4DVAR
666!
667!-----------------------------------------------------------------------
668! Solve the system:
669!
670! (R_n + Cobs) * Beta_n = h_n
671!
672! h_n = Xo - H * X_n
673!
674! where R_n is the representer matrix, Cobs is the observation-error
675! covariance, Beta_n are the representer coefficients, h_n is the
676! misfit between observations (Xo) and model (H * X_n), and H is
677! the linearized observation operator. Here, _n denotes a sequence
678! of estimates.
679!
680! The system does not need to be solved explicitly by inverting the
681! symmetric stabilized representer matrix, P_n:
682!
683! P_n = R_n + Cobs
684!
685! but by computing the action of P_n on any vector PSI, such that
686!
687! P_n * PSI = R_n * PSI + Cobs * PSI
688!
689! The representer matrix is not explicitly computed but evaluated by
690! one integration backward of the adjoint model and one integration
691! forward of the tangent linear model for any forcing vector PSI.
692!
693! A preconditioned conjugate gradient algorithm is used to compute
694! an approximation PSI for Beta_n.
695!
696!-----------------------------------------------------------------------
697!
698! If the required vectors and arrays from congrad from a previous run
699! of the assimilation cycle are not available, rerun the 4D-Var cycle.
700!
701 outer_loop : DO my_outer=1,1
702 outer=my_outer
703 inner=0
704!
705!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
706! Run representer model and compute a "prior estimate" state
707! trajectory, X_n(t). Use linearized state trajectory (X_n-1) as
708! basic state.
709!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
710!
711! Set representer model basic state trajectory file to previous outer
712! loop file (outer-1). If outer=1, the basic state trajectory is the
713! nonlinear model.
714!
715 DO ng=1,ngrids
716 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
717 lstr=len_trim(fwd(ng)%name)
718 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
719 END DO
720!
721! Set structure for the nonlinear forward trajectory to be processed
722! by the tangent linear and adjoint models. Also, set switches to
723! process the FWD structure in routine "check_multifile". Notice that
724! it is possible to split solution into multiple NetCDF files to reduce
725! their size.
726!
727 IF (outer.eq.1) THEN
728 CALL edit_multifile ('HIS2FWD')
729 ELSE
730 CALL edit_multifile ('TLM2FWD')
731 END IF
732 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
733 DO ng=1,ngrids
734 lreadfwd(ng)=.true.
735 END DO
736!
737! Set representer model output file name. The strategy is to write
738! the representer solution at the beginning of each outer loop.
739!
740 DO ng=1,ngrids
741 ideftlm(ng)=-1
742 ldeftlm(ng)=.true.
743 lwrttlm(ng)=.true.
744 WRITE (tlm(ng)%name,10) trim(tlm(ng)%head), outer
745 lstr=len_trim(tlm(ng)%name)
746 tlm(ng)%base=tlm(ng)%name(1:lstr-3)
747 END DO
748!
749! Activate switch to write the representer model at observation points.
750! Turn off writing into history file and turn off impulse forcing.
751!
752 DO ng=1,ngrids
753 wrtrpmod(ng)=.true.
754 sporadicimpulse(ng)=.false.
755 frequentimpulse(ng)=.false.
756 END DO
757
758# ifndef DATALESS_LOOPS
759!
760! As in the nonlinear model, initialize always the representer model
761! here with the background or reference state (IRP(ng)%name, record
762! Rec1).
763!
764 DO ng=1,ngrids
765 irp(ng)%Rindex=rec1
766 CALL rp_initial (ng)
767 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
768 END DO
769!
770! Run representer model using the nonlinear trajectory as a basic
771! state. Compute model solution at observation points, H * X_n.
772!
773 DO ng=1,ngrids
774 IF (master) THEN
775 WRITE (stdout,20) 'RP', ng, ntstart(ng), ntend(ng)
776 END IF
777 END DO
778!
779# ifdef SOLVE3D
780 CALL rp_main3d (runinterval)
781# else
782 CALL rp_main2d (runinterval)
783# endif
784 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
785!
786! Report data penalty function.
787!
788 DO ng=1,ngrids
789 IF (master) THEN
790 DO i=0,nstatevar(ng)
791 IF (i.eq.0) THEN
792 string='Total'
793 ELSE
794 string=vname(1,idsvar(i))
795 END IF
796 IF (fourdvar(ng)%DataPenalty(i).ne.0.0_r8) THEN
797 WRITE (stdout,30) outer, inner, 'RPM', &
798 & fourdvar(ng)%DataPenalty(i), &
799 & trim(string)
800 END IF
801 END DO
802 END IF
803!
804! Write out initial data penalty function to NetCDF file.
805!
806 sourcefile=myfile
807 SELECT CASE (dav(ng)%IOtype)
808 CASE (io_nf90)
809 CALL netcdf_put_fvar (ng, irpm, dav(ng)%name, &
810 & 'RP_iDataPenalty', &
811 & fourdvar(ng)%DataPenalty(0:), &
812 & (/1,outer/), &
813 & (/nstatevar(ng)+1,1/), &
814 & ncid = dav(ng)%ncid)
815# if defined PIO_LIB && defined DISTRIBUTE
816 CASE (io_pio)
817 CALL pio_netcdf_put_fvar (ng, irpm, dav(ng)%name, &
818 & 'RP_iDataPenalty', &
819 & fourdvar(ng)%DataPenalty(0:), &
820 & (/1,outer/), &
821 & (/nstatevar(ng)+1,1/), &
822 & piofile = dav(ng)%pioFile)
823# endif
824 END SELECT
825 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
826!
827! Clean penalty array before next run of RP model.
828!
829 fourdvar(ng)%DataPenalty=0.0_r8
830 END DO
831!
832! Turn off IO switches.
833!
834 DO ng=1,ngrids
835 ldeftlm(ng)=.false.
836 lwrttlm(ng)=.false.
837 wrtrpmod(ng)=.false.
838 END DO
839!
840! Clear tangent linear forcing arrays before entering inner-loop.
841! This is very important since these arrays are non-zero after
842! running the representer model and must be zero when running the
843! tangent linear model.
844!
845 DO ng=1,ngrids
846 DO tile=first_tile(ng),last_tile(ng),+1
847 CALL initialize_forces (ng, tile, itlm)
848# ifdef ADJUST_BOUNDARY
849 CALL initialize_boundary (ng, tile, itlm)
850# endif
851 END DO
852 END DO
853
854# if defined BALANCE_OPERATOR && defined ZETA_ELLIPTIC
855!
856! Compute the reference zeta and biconjugate gradient arrays
857! required for the balance of free surface.
858!
859 IF (balance(isfsur)) THEN
860 DO ng=1,ngrids
861 CALL get_state (ng, inlm, 2, ini(ng), lini, lini)
862 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
863!
864 DO tile=first_tile(ng),last_tile(ng),+1
865 CALL balance_ref (ng, tile, lini)
866 CALL biconj (ng, tile, inlm, lini)
867 END DO
868 wrtzetaref(ng)=.true.
869 END DO
870 END IF
871# endif
872!
873 inner_loop : DO my_inner=0,ninner
874 inner=my_inner
875!
876! Initialize conjugate gradient algorithm depending on hot start or
877! outer loop index.
878!
879 IF (inner.eq.0) THEN
880 lcgini=.true.
881 DO ng=1,ngrids
882 CALL congrad (ng, irpm, outer, inner, ninner, lcgini)
883 END DO
884 END IF
885!
886! If initialization step, skip the inner-loop computations.
887!
888 linner=.false.
889 IF ((inner.ne.0).or.(nrun.ne.1)) THEN
890 IF (((inner.eq.0).and.lhotstart).or.(inner.ne.0)) THEN
891 linner=.true.
892 END IF
893 END IF
894!
895! Start inner loop computations.
896!
897 inner_compute : IF (linner) THEN
898!
899!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
900! Integrate adjoint model forced with any vector PSI at the observation
901! locations and generate adjoint trajectory, Lambda_n(t).
902!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
903!
904! Initialize the adjoint model from rest.
905!
906 DO ng=1,ngrids
907 lsen4dvar(ng)=.false.
908 CALL ad_initial (ng)
910 & __line__, myfile)) RETURN
911 wrtmisfit(ng)=.false.
912 END DO
913
914# ifdef RPM_RELAXATION
915!
916! Adjoint of representer relaxation is not applied during the
917! inner-loops.
918!
919 DO ng=1,ngrids
920 lweakrelax(ng)=.false.
921 END DO
922# endif
923!
924! Set adjoint history NetCDF parameters. Define adjoint history
925! file only once to avoid opening too many files.
926!
927 DO ng=1,ngrids
928 wrtforce(ng)=.true.
929 IF (nrun.gt.1) ldefadj(ng)=.false.
930 fcount=adm(ng)%load
931 adm(ng)%Nrec(fcount)=0
932 adm(ng)%Rindex=0
933 END DO
934!
935! Time-step adjoint model backwards forced with current PSI vector.
936!
937 DO ng=1,ngrids
938 IF (master) THEN
939 WRITE (stdout,20) 'AD', ng, ntstart(ng), ntend(ng)
940 END IF
941 END DO
942!
943# ifdef SOLVE3D
944 CALL ad_main3d (runinterval)
945# else
946 CALL ad_main2d (runinterval)
947# endif
948 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
949!
950! Write out last weak-constraint forcing (WRTforce is still .TRUE.)
951! record into the adjoint history file. Note that the weak-constraint
952! forcing is delayed by nADJ time-steps.
953!
954 DO ng=1,ngrids
955# ifdef DISTRIBUTE
956 CALL ad_wrt_his (ng, myrank)
957# else
958 CALL ad_wrt_his (ng, -1)
959# endif
961 & __line__, myfile)) RETURN
962 END DO
963!
964! Write out adjoint initial condition record into the adjoint
965! history file.
966!
967 DO ng=1,ngrids
968 wrtforce(ng)=.false.
969# ifdef DISTRIBUTE
970 CALL ad_wrt_his (ng, myrank)
971# else
972 CALL ad_wrt_his (ng, -1)
973# endif
975 & __line__, myfile)) RETURN
976 END DO
977!
978! Convolve adjoint trajectory with error covariances.
979!
980 lposterior=.false.
981 CALL error_covariance (itlm, driver, outer, inner, &
982 & lbck, lini, lold, lnew, &
983 & rec1, rec2, lposterior)
984 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
985!
986! Convert the current adjoint solution in ADM(ng)%name to impulse
987! forcing. Write out impulse forcing into TLF(ng)%name NetCDF file.
988! To facilitate the forcing to the TLM and RPM, the forcing is
989! processed and written in increasing time coordinates (recall that
990! the adjoint solution in ADM(ng)%name is backwards in time).
991!
992 IF (master) THEN
993 WRITE (stdout,40) outer, inner
994 END IF
995 DO ng=1,ngrids
996 tlf(ng)%Rindex=0
997# ifdef DISTRIBUTE
998 CALL wrt_impulse (ng, myrank, iadm, adm(ng)%name)
999# else
1000 CALL wrt_impulse (ng, -1, iadm, adm(ng)%name)
1001# endif
1002
1004 & __line__, myfile)) RETURN
1005 END DO
1006!
1007!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1008! Integrate tangent linear model forced by the convolved adjoint
1009! trajectory (impulse forcing) to compute R_n * PSI at observation
1010! points.
1011!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1012!
1013 DO ng=1,ngrids
1014 wrtnlmod(ng)=.false.
1015 wrttlmod(ng)=.true.
1016 END DO
1017!
1018! If weak constraint, the impulses are time-interpolated at each
1019! time-steps.
1020!
1021 DO ng=1,ngrids
1022 IF (frcrec(ng).gt.3) THEN
1023 frequentimpulse(ng)=.true.
1024 END IF
1025 END DO
1026!
1027! Initialize tangent linear model from ITL(ng)%name, record Rec1.
1028!
1029 DO ng=1,ngrids
1030 itl(ng)%Rindex=rec1
1031 CALL tl_initial (ng)
1033 & __line__, myfile)) RETURN
1034 END DO
1035!
1036! Activate switch to write out initial misfit between model and
1037! observations.
1038!
1039 IF ((outer.eq.1).and.(inner.eq.1)) THEN
1040 DO ng=1,ngrids
1041 wrtmisfit(ng)=.true.
1042 END DO
1043 END IF
1044!
1045! Set tangent linear history NetCDF parameters. Define tangent linear
1046! history file at the beggining of each inner loop to avoid opening
1047! too many NetCDF files.
1048!
1049 DO ng=1,ngrids
1050 IF (inner.gt.1) ldeftlm(ng)=.false.
1051 fcount=tlm(ng)%load
1052 tlm(ng)%Nrec(fcount)=0
1053 tlm(ng)%Rindex=0
1054 END DO
1055!
1056! Run tangent linear model forward and force with convolved adjoint
1057! trajectory impulses. Compute R_n * PSI at observation points which
1058! are used in the conjugate gradient algorithm.
1059!
1060 DO ng=1,ngrids
1061 IF (master) THEN
1062 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
1063 END IF
1064 END DO
1065!
1066# ifdef SOLVE3D
1067 CALL tl_main3d (runinterval)
1068# else
1069 CALL tl_main2d (runinterval)
1070# endif
1071 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1072
1073 DO ng=1,ngrids
1074 wrtnlmod(ng)=.false.
1075 wrttlmod(ng)=.false.
1076 END DO
1077!
1078!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1079! Use conjugate gradient algorithm to find a better approximation
1080! PSI to representer coefficients Beta_n.
1081!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1082!
1083 nrun=nrun+1
1084 DO ng=1,ngrids
1085 lcgini=.false.
1086 CALL congrad (ng, irpm, outer, inner, ninner, lcgini)
1088 & __line__, myfile)) RETURN
1089 END DO
1090
1091 END IF inner_compute
1092
1093 END DO inner_loop
1094!
1095! Close tangent linear NetCDF file.
1096!
1097 sourcefile=myfile
1098 DO ng=1,ngrids
1099 CALL close_file (ng, itlm, tlm(ng))
1100 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1101 END DO
1102!
1103!-----------------------------------------------------------------------
1104! Once that the representer coefficients, Beta_n, have been
1105! approximated with sufficient accuracy, compute estimates of
1106! Lambda_n and Xhat_n by carrying out one backward intergration
1107! of the adjoint model and one forward itegration of the representer
1108! model.
1109!-----------------------------------------------------------------------
1110!
1111! Initialize the adjoint model always from rest.
1112!
1113 DO ng=1,ngrids
1114 lsen4dvar(ng)=.false.
1115 CALL ad_initial (ng)
1116 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1117 END DO
1118
1119# ifdef RPM_RELAXATION
1120!
1121! Adjoint of representer relaxation is applied during the
1122! outer-loops.
1123!
1124 DO ng=1,ngrids
1125 lweakrelax(ng)=.true.
1126 END DO
1127# endif
1128!
1129! Set adjoint history NetCDF parameters. Define adjoint history
1130! file one to avoid opening to many files.
1131!
1132 DO ng=1,ngrids
1133 wrtforce(ng)=.true.
1134 IF (nrun.gt.1) ldefadj(ng)=.false.
1135 fcount=adm(ng)%load
1136 adm(ng)%Nrec(fcount)=0
1137 adm(ng)%Rindex=0
1138 END DO
1139!
1140! Time-step adjoint model backwards forced with estimated representer
1141! coefficients, Beta_n.
1142!
1143 DO ng=1,ngrids
1144 IF (master) THEN
1145 WRITE (stdout,20) 'AD', ng, ntstart(ng), ntend(ng)
1146 END IF
1147 END DO
1148!
1149# ifdef SOLVE3D
1150 CALL ad_main3d (runinterval)
1151# else
1152 CALL ad_main2d (runinterval)
1153# endif
1154 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1155!
1156! Write out last weak-constraint forcing (WRTforce is still .TRUE.)
1157! record into the adjoint history file. Note that the weak-constraint
1158! forcing is delayed by nADJ time-steps.
1159!
1160 DO ng=1,ngrids
1161# ifdef DISTRIBUTE
1162 CALL ad_wrt_his (ng, myrank)
1163# else
1164 CALL ad_wrt_his (ng, -1)
1165# endif
1166 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1167 END DO
1168!
1169! Write out adjoint initial condition record into the adjoint
1170! history file.
1171!
1172 DO ng=1,ngrids
1173 wrtforce(ng)=.false.
1174# ifdef DISTRIBUTE
1175 CALL ad_wrt_his (ng, myrank)
1176# else
1177 CALL ad_wrt_his (ng, -1)
1178# endif
1179 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1180 END DO
1181!
1182! Convolve adjoint trajectory with error covariances.
1183!
1184 lposterior=.false.
1185 CALL error_covariance (irpm, driver, outer, inner, &
1186 & lbck, lini, lold, lnew, &
1187 & rec1, rec2, lposterior)
1188 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1189!
1190! Convert the current adjoint solution in ADM(ng)%name to impulse
1191! forcing. Write out impulse forcing into TLF(ng)%name NetCDF file.
1192! To facilitate the forcing to the TLM and RPM, the forcing is
1193! processed and written in increasing time coordinates (recall that
1194! the adjoint solution in ADM(ng)%name is backwards in time).
1195!
1196 IF (master) THEN
1197 WRITE (stdout,40) outer, inner
1198 END IF
1199 DO ng=1,ngrids
1200 tlf(ng)%Rindex=0
1201# ifdef DISTRIBUTE
1202 CALL wrt_impulse (ng, myrank, iadm, adm(ng)%name)
1203# else
1204 CALL wrt_impulse (ng, -1, iadm, adm(ng)%name)
1205# endif
1206 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1207 END DO
1208
1209# endif /* !DATALESS_LOOPS */
1210!
1211!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1212! Run representer model and compute a "new estimate" of the state
1213! trajectory, X_n(t).
1214!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1215!
1216! Set new basic state trajectory for next outer loop.
1217!
1218 DO ng=1,ngrids
1219 ideftlm(ng)=-1
1220 ldeftlm(ng)=.true.
1221 lwrttlm(ng)=.true.
1222 wrtnlmod(ng)=.false.
1223 wrttlmod(ng)=.true.
1224 wrtrpmod(ng)=.true.
1225 WRITE (tlm(ng)%name,10) trim(fwd(ng)%head), outer
1226 lstr=len_trim(tlm(ng)%name)
1227 tlm(ng)%base=tlm(ng)%name(1:lstr-3)
1228 END DO
1229!
1230! If weak constraint, the impulses are time-interpolated at each
1231! time-steps.
1232!
1233 DO ng=1,ngrids
1234 IF (frcrec(ng).gt.3) THEN
1235 frequentimpulse(ng)=.true.
1236 END IF
1237 END DO
1238!
1239! Initialize representer model IRP(ng)%name file, record Rec2.
1240!
1241 DO ng=1,ngrids
1242# ifdef DATALESS_LOOPS
1243 irp(ng)%Rindex=rec1
1244# else
1245 irp(ng)%Rindex=rec2
1246# endif
1247 CALL rp_initial (ng)
1248 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1249 END DO
1250!
1251! Activate switch to write out final misfit between model and
1252! observations.
1253!
1254 IF (outer.eq.nouter) THEN
1255 DO ng=1,ngrids
1256 wrtmisfit(ng)=.true.
1257 END DO
1258 END IF
1259!
1260! Run representer model using previous linearized trajectory, X_n-1, as
1261! basic state and forced with convolved adjoint trajectory impulses.
1262!
1263 DO ng=1,ngrids
1264 IF (master) THEN
1265 WRITE (stdout,20) 'RP', ng, ntstart(ng), ntend(ng)
1266 END IF
1267 END DO
1268!
1269# ifdef SOLVE3D
1270 CALL rp_main3d (runinterval)
1271# else
1272 CALL rp_main2d (runinterval)
1273# endif
1274 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1275!
1276! Report data penalty function.
1277!
1278 DO ng=1,ngrids
1279 IF (master) THEN
1280 DO i=0,nstatevar(ng)
1281 IF (i.eq.0) THEN
1282 string='Total'
1283 ELSE
1284 string=vname(1,idsvar(i))
1285 END IF
1286 IF (fourdvar(ng)%DataPenalty(i).ne.0.0_r8) THEN
1287 WRITE (stdout,30) outer, inner, 'RPM', &
1288 & fourdvar(ng)%DataPenalty(i), &
1289 & trim(string)
1290# ifdef DATALESS_LOOPS
1291 WRITE (stdout,30) outer, inner, 'NLM', &
1292 & fourdvar(ng)%NLPenalty(i), &
1293 & trim(string)
1294# endif
1295 END IF
1296 END DO
1297 END IF
1298 END DO
1299!
1300! Write out final data penalty function to NetCDF file.
1301!
1302 sourcefile=myfile
1303 DO ng=1,ngrids
1304 SELECT CASE (dav(ng)%IOtype)
1305 CASE (io_nf90)
1306 CALL netcdf_put_fvar (ng, irpm, dav(ng)%name, &
1307 & 'RP_fDataPenalty', &
1308 & fourdvar(ng)%DataPenalty(0:), &
1309 & (/1,outer/), &
1310 & (/nstatevar(ng)+1,1/), &
1311 & ncid = dav(ng)%ncid)
1312
1313# if defined PIO_LIB && defined DISTRIBUTE
1314 CASE (io_pio)
1315 CALL pio_netcdf_put_fvar (ng, irpm, dav(ng)%name, &
1316 & 'RP_fDataPenalty', &
1317 & fourdvar(ng)%DataPenalty(0:), &
1318 & (/1,outer/), &
1319 & (/nstatevar(ng)+1,1/), &
1320 & piofile = dav(ng)%pioFile)
1321# endif
1322 END SELECT
1323 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1324 END DO
1325!
1326! Clean array before next run of RP model.
1327!
1328 DO ng=1,ngrids
1329 fourdvar(ng)%DataPenalty=0.0_r8
1330# ifdef DATALESS_LOOPS
1331 fourdvar(ng)%NLPenalty=0.0_r8
1332# endif
1333 wrtnlmod(ng)=.false.
1334 wrttlmod(ng)=.false.
1335 END DO
1336!
1337! Close current forward NetCDF file.
1338!
1339 DO ng=1,ngrids
1340 CALL close_file (ng, irpm, fwd(ng))
1341 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1342
1343 IF (his(ng)%IOtype.eq.io_nf90) THEN
1344 his(ng)%ncid=-1
1345#if defined PIO_LIB && defined DISTRIBUTE
1346 ELSE IF (his(ng)%IOtype.eq.io_pio) THEN
1347 his(ng)%pioFile%fh=-1
1348#endif
1349 END IF
1350 END DO
1351
1352 END DO outer_loop
1353
1354#endif /* RECOMPUTE_4DVAR */
1355!!
1356!! Compute and report model-observation comparison statistics.
1357!!
1358!! DO ng=1,Ngrids
1359#ifdef DISTRIBUTE
1360!! CALL stats_modobs (ng, MyRank)
1361#else
1362!! CALL stats_modobs (ng, -1)
1363#endif
1364!! END DO
1365!
1366!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1367! Adjoint of W4DVar to compute the observation sensitivity.
1368!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1369!
1370! Reset the start and end times for the adjoint forcing.
1371!
1372 DO ng=1,ngrids
1373 str_day=tdays(ng)
1374 end_day=str_day-ntimes(ng)*dt(ng)*sec2day
1375 IF ((dstrs(ng).eq.0.0_r8).and.(dends(ng).eq.0.0_r8)) THEN
1376 dstrs(ng)=end_day
1377 dends(ng)=str_day
1378 END IF
1379 IF (master) THEN
1380 WRITE (stdout,70) 'AD', dends(ng), dstrs(ng)
1381 END IF
1382 END DO
1383!
1384! WARNING: ONLY 1 outer loop can be used for this application.
1385! ======= For more than 1 outer-loop, we require the second
1386! derivative of each model operator (i.e. the tangent linear
1387! of the tangent linear operator).
1388!
1389 ad_outer_loop : DO my_outer=1,1,-1
1390 outer=my_outer
1391 inner=0
1392!
1393!-----------------------------------------------------------------------
1394! Run the adjoint model initialized and forced by dI/dx where I is the
1395! chosen function of the analysis/forecast state x.
1396!-----------------------------------------------------------------------
1397!
1398! Set basic state trajectory.
1399!
1400 DO ng=1,ngrids
1401 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
1402 lstr=len_trim(fwd(ng)%name)
1403 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
1404 END DO
1405 IF ((outer.eq.1).and.master) THEN
1406 WRITE (stdout,50)
1407 END IF
1408!
1409! Initialize the adjoint model: initialize using dI/dxf is
1410! appropriate.
1411!
1412 lstiffness=.false.
1413 DO ng=1,ngrids
1414 lsen4dvar(ng)=.true.
1415 CALL ad_initial (ng)
1416 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1417 END DO
1418!
1419! Set adjoint history NetCDF parameters. Define adjoint history
1420! file one to avoid opening to many files.
1421!
1422 DO ng=1,ngrids
1423 wrtforce(ng)=.true.
1424 IF (nrun.gt.1) ldefadj(ng)=.false.
1425 fcount=adm(ng)%load
1426 adm(ng)%Nrec(fcount)=0
1427 adm(ng)%Rindex=0
1428 END DO
1429!
1430! NOTE: THE ADM IS FORCED BY dI/dx ONLY when outer=Nouter.
1431!
1432! Time-step adjoint model backwards.
1433! ??? What do we do in the case of model error? Save forcing for TLM?
1434!
1435 DO ng=1,ngrids
1436 IF (master) THEN
1437 WRITE (stdout,20) 'AD', ng, ntstart(ng), ntend(ng)
1438 END IF
1439 END DO
1440!
1441#ifdef SOLVE3D
1442 CALL ad_main3d (runinterval)
1443#else
1444 CALL ad_main2d (runinterval)
1445#endif
1446 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1447!
1448! Write out last weak-constraint forcing (WRTforce is still .TRUE.)
1449! record into the adjoint history file. Note that the weak-constraint
1450! forcing is delayed by nADJ time-steps.
1451!
1452 DO ng=1,ngrids
1453#ifdef DISTRIBUTE
1454 CALL ad_wrt_his (ng, myrank)
1455#else
1456 CALL ad_wrt_his (ng, -1)
1457#endif
1458 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1459 END DO
1460!
1461! Write out adjoint initial condition record into the adjoint
1462! history file.
1463!
1464 DO ng=1,ngrids
1465 wrtforce(ng)=.false.
1466#ifdef DISTRIBUTE
1467 CALL ad_wrt_his (ng, myrank)
1468#else
1469 CALL ad_wrt_his (ng, -1)
1470#endif
1471 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1472 END DO
1473!
1474! Convolve adjoint trajectory with error covariances.
1475!
1476 lposterior=.false.
1477 CALL error_covariance (itlm, driver, outer, inner, &
1478 & lbck, lini, lold, lnew, &
1479 & rec1, rec2, lposterior)
1480 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1481!
1482! Convert the current adjoint solution in ADM(ng)%name to impulse
1483! forcing. Write out impulse forcing into TLF(ng)%name NetCDF file.
1484! To facilitate the forcing to the TLM and RPM, the forcing is
1485! processed and written in increasing time coordinates (recall that
1486! the adjoint solution in ADM(ng)%name is backwards in time).
1487!
1488! AMM: Do not know what to do in the weak constraint case yet.
1489!
1490!! IF (Master) THEN
1491!! WRITE (stdout,40) outer, inner
1492!! END IF
1493!! DO ng=1,Ngrids
1494!! TLF(ng)%Rindex=0
1495#ifdef DISTRIBUTE
1496!! CALL wrt_impulse (ng, MyRank, iADM, ADM(ng)%name)
1497#else
1498!! CALL wrt_impulse (ng, -1, iADM, ADM(ng)%name)
1499#endif
1500!! IF (FoundError(exit_flag, NoError, __LINE__, MyFile)) RETURN
1501!! END DO
1502!
1503!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1504! Integrate tangent linear model forced by the convolved adjoint
1505! trajectory.
1506!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1507!
1508 DO ng=1,ngrids
1509 wrtnlmod(ng)=.false.
1510 wrttlmod(ng)=.true.
1511 lwrttlm(ng)=.false.
1512 END DO
1513!
1514! Clear tangent linear forcing arrays before entering inner-loop.
1515! This is very important since these arrays are non-zero after
1516! running the representer model and must be zero when running the
1517! tangent linear model.
1518!
1519 DO ng=1,ngrids
1520 DO tile=first_tile(ng),last_tile(ng),+1
1521 CALL initialize_forces (ng, tile, itlm)
1522#ifdef ADJUST_BOUNDARY
1523 CALL initialize_boundary (ng, tile, itlm)
1524#endif
1525 END DO
1526 END DO
1527!
1528! Set basic state trajectory.
1529!
1530 DO ng=1,ngrids
1531 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
1532 lstr=len_trim(fwd(ng)%name)
1533 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
1534 END DO
1535!
1536! If weak constraint, the impulses are time-interpolated at each
1537! time-steps.
1538!
1539 DO ng=1,ngrids
1540 IF (frcrec(ng).gt.3) THEN
1541 frequentimpulse(ng)=.true.
1542 END IF
1543 END DO
1544!
1545! Initialize tangent linear model from ITL(ng)%name, record 1.
1546!
1547 DO ng=1,ngrids
1548 itl(ng)%Rindex=rec1
1549 CALL tl_initial (ng)
1550 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1551 END DO
1552
1553#ifdef RPM_RELAXATION
1554!
1555! Activate the tangent linear relaxation terms if used.
1556!
1557 DO ng=1,ngrids
1558 lweakrelax(ng)=.true.
1559 END DO
1560#endif
1561!
1562! Run tangent linear model forward and force with convolved adjoint
1563! trajectory impulses. Compute (HMBM'H')_n * PSI at observation points
1564! which are used in the conjugate gradient algorithm.
1565!
1566 DO ng=1,ngrids
1567 IF (master) THEN
1568 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
1569 END IF
1570 END DO
1571!
1572#ifdef SOLVE3D
1573 CALL tl_main3d (runinterval)
1574#else
1575 CALL tl_main2d (runinterval)
1576#endif
1577 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1578
1579 DO ng=1,ngrids
1580 wrtnlmod(ng)=.false.
1581 wrttlmod(ng)=.false.
1582 END DO
1583
1584#ifdef OBS_IMPACT
1585!
1586! Compute observation impact to the data assimilation system.
1587!
1588 DO ng=1,ngrids
1589 CALL rep_matrix (ng, itlm, outer, ninner)
1590 END DO
1591#else
1592!
1593! Set basic state trajectory for adjoint inner-loops.
1594!
1595 DO ng=1,ngrids
1596 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
1597 lstr=len_trim(fwd(ng)%name)
1598 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
1599 END DO
1600!
1601! Clear tangent linear forcing arrays before entering inner-loop.
1602! This is very important since these arrays are non-zero after
1603! running the representer model and must be zero when running the
1604! tangent linear model.
1605!
1606 DO ng=1,ngrids
1607 DO tile=first_tile(ng),last_tile(ng),+1
1608 CALL initialize_forces (ng, tile, itlm)
1609# ifdef ADJUST_BOUNDARY
1610 CALL initialize_boundary (ng, tile, itlm)
1611# endif
1612 END DO
1613 END DO
1614!
1615 ad_inner_loop : DO my_inner=ninner,1,-1
1616 inner=my_inner
1617
1618 IF (master) THEN
1619 WRITE (stdout,60) 'Adjoint of', uppercase('w4dvar'), &
1620 & outer, inner
1621 END IF
1622!
1623! Call adjoint conjugate gradient algorithm.
1624!
1625 lcgini=.false.
1626 DO ng=1,ngrids
1627 CALL ad_congrad (ng, iadm, outer, inner, ninner, lcgini)
1628 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1629 END DO
1630!
1631! Initialize the adjoint model from rest.
1632!
1633 DO ng=1,ngrids
1634 lsen4dvar(ng)=.false.
1635 CALL ad_initial (ng)
1636 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1637 wrtmisfit(ng)=.false.
1638 END DO
1639
1640# ifdef RPM_RELAXATION
1641!
1642! Adjoint of representer relaxation is not applied during the
1643! inner-loops.
1644!
1645 DO ng=1,ngrids
1646 lweakrelax(ng)=.false.
1647 END DO
1648# endif
1649!
1650! Set adjoint history NetCDF parameters. Define adjoint history
1651! file only once to avoid opening too many files.
1652!
1653 DO ng=1,ngrids
1654 wrtforce(ng)=.true.
1655 IF (nrun.gt.1) ldefadj(ng)=.false.
1656 fcount=adm(ng)%load
1657 adm(ng)%Nrec(fcount)=0
1658 adm(ng)%Rindex=0
1659 END DO
1660!
1661! Time-step adjoint model backwards forced with current PSI vector.
1662!
1663 DO ng=1,ngrids
1664 IF (master) THEN
1665 WRITE (stdout,20) 'AD', ng, ntstart(ng), ntend(ng)
1666 END IF
1667 END DO
1668!
1669# ifdef SOLVE3D
1670 CALL ad_main3d (runinterval)
1671# else
1672 CALL ad_main2d (runinterval)
1673# endif
1674 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1675!
1676! Write out last weak-constraint forcing (WRTforce is still .TRUE.)
1677! record into the adjoint history file. Note that the weak-constraint
1678! forcing is delayed by nADJ time-steps
1679!
1680 DO ng=1,ngrids
1681# ifdef DISTRIBUTE
1682 CALL ad_wrt_his (ng, myrank)
1683# else
1684 CALL ad_wrt_his (ng, -1)
1685# endif
1686 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1687 END DO
1688!
1689! Write out adjoint initial condition record into the adjoint
1690! history file.
1691!
1692 DO ng=1,ngrids
1693 wrtforce(ng)=.false.
1694# ifdef DISTRIBUTE
1695 CALL ad_wrt_his (ng, myrank)
1696# else
1697 CALL ad_wrt_his (ng, -1)
1698# endif
1699 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1700 END DO
1701!
1702! Convolve adjoint trajectory with error covariances.
1703!
1704 lposterior=.false.
1705 CALL error_covariance (itlm, driver, outer, inner, &
1706 & lbck, lini, lold, lnew, &
1707 & rec1, rec2, lposterior)
1708 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1709!
1710! ??? Do we need the adjoint of impulse here???
1711!
1712! Convert the current adjoint solution in ADM(ng)%name to impulse
1713! forcing. Write out impulse forcing into TLF(ng)%name NetCDF file.
1714! To facilitate the forcing to the TLM and RPM, the forcing is
1715! processed and written in increasing time coordinates (recall that
1716! the adjoint solution in ADM(ng)%name is backwards in time).
1717!
1718!! IF (Master) THEN
1719!! WRITE (stdout,40) outer, inner
1720!! END IF
1721!! DO ng=1,Ngrids
1722!! TLF(ng)%Rindex=0
1723# ifdef DISTRIBUTE
1724!! CALL wrt_impulse (ng, MyRank, iADM, ADM(ng)%name)
1725# else
1726!! CALL wrt_impulse (ng, -1, iADM, ADM(ng)%name)
1727# endif
1728!! IF (FoundError(exit_flag, NoError, __LINE__, MyFile)) RETURN
1729!!
1730!! AMM: Don't know what to do yet in the weak constraint case.
1731!!
1732!! END DO
1733!
1734!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1735! Integrate tangent linear model.
1736!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1737!
1738 DO ng=1,ngrids
1739 tlm(ng)%name=trim(tlm(ng)%base)//'.nc'
1740 wrtnlmod(ng)=.false.
1741 wrttlmod(ng)=.true.
1742 END DO
1743!
1744! If weak constraint, the impulses are time-interpolated at each
1745! time-steps.
1746!
1747 DO ng=1,ngrids
1748 IF (frcrec(ng).gt.3) THEN
1749 frequentimpulse(ng)=.true.
1750 END IF
1751 END DO
1752!
1753! Initialize tangent linear model from ITL(ng)%name, record Rec1.
1754!
1755 DO ng=1,ngrids
1756 itl(ng)%Rindex=rec1
1757 CALL tl_initial (ng)
1758 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1759 END DO
1760
1761# ifdef RPM_RELAXATION
1762!
1763! Deactivate the tangent linear relaxation terms if used.
1764!
1765 DO ng=1,ngrids
1766 lweakrelax(ng)=.false.
1767 END DO
1768# endif
1769!
1770! Activate switch to write out initial misfit between model and
1771! observations.
1772!
1773 IF ((outer.eq.1).and.(inner.eq.1)) THEN
1774 DO ng=1,ngrids
1775 wrtmisfit(ng)=.true.
1776 END DO
1777 END IF
1778!
1779! Set tangent linear history NetCDF parameters. Define tangent linear
1780! history file at the beggining of each inner loop to avoid opening
1781! too many NetCDF files.
1782!
1783 DO ng=1,ngrids
1784 IF (inner.lt.ninner) ldeftlm(ng)=.false.
1785 fcount=tlm(ng)%load
1786 tlm(ng)%Nrec(fcount)=0
1787 tlm(ng)%Rindex=0
1788 END DO
1789!
1790! Run tangent linear model forward and force with convolved adjoint
1791! trajectory impulses. Compute R_n * PSI at observation points which
1792! are used in the conjugate gradient algorithm.
1793!
1794 DO ng=1,ngrids
1795 IF (master) THEN
1796 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
1797 END IF
1798 END DO
1799!
1800# ifdef SOLVE3D
1801 CALL tl_main3d (runinterval)
1802# else
1803 CALL tl_main2d (runinterval)
1804# endif
1805 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1806
1807 DO ng=1,ngrids
1808 wrtnlmod(ng)=.false.
1809 wrttlmod(ng)=.false.
1810 END DO
1811
1812 END DO ad_inner_loop
1813!
1814! Call adjoint conjugate gradient algorithm.
1815!
1816 inner=0
1817 lcgini=.true.
1818 DO ng=1,ngrids
1819 CALL ad_congrad (ng, itlm, outer, inner, ninner, lcgini)
1820 END DO
1821
1822#endif /* !OBS_IMPACT */
1823
1824#ifdef OBS_IMPACT
1825!
1826! Write out total observation impact.
1827!
1828 IF (outer.eq.1) THEN
1829 sourcefile=myfile
1830 DO ng=1,ngrids
1831 SELECT CASE (dav(ng)%IOtype)
1832 CASE (io_nf90)
1833 CALL netcdf_put_fvar (ng, itlm, dav(ng)%name, &
1834 & 'ObsImpact_total', ad_obsval, &
1835 & (/1/), (/mobs/), &
1836 & ncid = dav(ng)%ncid)
1838 & __line__, myfile)) RETURN
1839
1840 CALL netcdf_sync (ng, inlm, dav(ng)%name, dav(ng)%ncid)
1842 & __line__, myfile)) RETURN
1843
1844# if defined PIO_LIB && defined DISTRIBUTE
1845 CASE (io_pio)
1846 CALL pio_netcdf_put_fvar (ng, itlm, dav(ng)%name, &
1847 & 'ObsImpact_total', ad_obsval, &
1848 & (/1/), (/mobs/), &
1849 & piofile = dav(ng)%pioFile)
1851 & __line__, myfile)) RETURN
1852
1853 CALL pio_netcdf_sync (ng, inlm, dav(ng)%name, &
1854 & dav(ng)%pioFile)
1856 & __line__, myfile)) RETURN
1857# endif
1858 END SELECT
1859 END DO
1860 END IF
1861#else
1862!
1863! Write out observation sensitivity.
1864!
1865 IF (outer.eq.1) THEN
1866 sourcefile=myfile
1867 DO ng=1,ngrids
1868 SELECT CASE (dav(ng)%IOtype)
1869 CASE (io_nf90)
1870 CALL netcdf_put_fvar (ng, itlm, dav(ng)%name, &
1871 & 'ObsSens_total', ad_obsval, &
1872 & (/1/), (/mobs/), &
1873 & ncid = dav(ng)%ncid)
1875 & __line__, myfile)) RETURN
1876
1877 CALL netcdf_sync (ng, inlm, dav(ng)%name, dav(ng)%ncid)
1879 & __line__, myfile)) RETURN
1880
1881# if defined PIO_LIB && defined DISTRIBUTE
1882 CASE (io_pio)
1883 CALL pio_netcdf_put_fvar (ng, itlm, dav(ng)%name, &
1884 & 'ObsSens_total', ad_obsval, &
1885 & (/1/), (/mobs/), &
1886 & piofile = dav(ng)%pioFile)
1888 & __line__, myfile)) RETURN
1889
1890 CALL pio_netcdf_sync (ng, inlm, dav(ng)%name, &
1891 & dav(ng)%pioFile)
1893 & __line__, myfile)) RETURN
1894# endif
1895 END SELECT
1896 END DO
1897 END IF
1898#endif
1899!
1900! Close tangent linear NetCDF file.
1901!
1902 sourcefile=myfile
1903 DO ng=1,ngrids
1904 CALL close_file (ng, itlm, tlm(ng))
1905 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1906 END DO
1907
1908#if defined OBS_IMPACT && defined OBS_IMPACT_SPLIT
1909!
1910!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1911! Integrate tangent linear model with initial condition increments
1912! only to compute the observation impact associated with the initial
1913! conditions.
1914!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
1915!
1916 DO ng=1,ngrids
1917 wrtnlmod(ng)=.false.
1918 wrttlmod(ng)=.true.
1919 lwrttlm(ng)=.false.
1920 END DO
1921!
1922! Clear tangent linear forcing arrays before entering inner-loop.
1923! This is very important since these arrays are non-zero after
1924! running the representer model and must be zero when running the
1925! tangent linear model.
1926!
1927 DO ng=1,ngrids
1928 DO tile=first_tile(ng),last_tile(ng),+1
1929 CALL initialize_forces (ng, tile, itlm)
1930# ifdef ADJUST_BOUNDARY
1931 CALL initialize_boundary (ng, tile, itlm)
1932# endif
1933 END DO
1934 END DO
1935!
1936! Set basic state trajectory.
1937!
1938 DO ng=1,ngrids
1939 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
1940 lstr=len_trim(fwd(ng)%name)
1941 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
1942 END DO
1943!
1944! If weak constraint, the impulses are time-interpolated at each
1945! time-steps.
1946!
1947 DO ng=1,ngrids
1948 IF (frcrec(ng).gt.3) THEN
1949 frequentimpulse(ng)=.true.
1950 END IF
1951 END DO
1952!
1953! Initialize tangent linear model from ITL(ng)%name, record 1.
1954!
1955 DO ng=1,ngrids
1956 itl(ng)%Rindex=rec1
1957 CALL tl_initial (ng)
1958 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1959 END DO
1960!
1961! Clear tangent linear forcing arrays and boundary arrays
1962! before the obs impact initial condition calculation.
1963!
1964 DO ng=1,ngrids
1965 DO tile=first_tile(ng),last_tile(ng),+1
1966 CALL initialize_forces (ng, tile, itlm)
1967# ifdef ADJUST_BOUNDARY
1968 CALL initialize_boundary (ng, tile, itlm)
1969# endif
1970 END DO
1971 END DO
1972
1973# ifdef RPM_RELAXATION
1974!
1975! Activate the tangent linear relaxation terms if used.
1976!
1977 DO ng=1,ngrids
1978 lweakrelax(ng)=.true.
1979 END DO
1980# endif
1981!
1982! Run tangent linear model forward and force with convolved adjoint
1983! trajectory impulses. Compute (HMBM'H')_n * PSI at observation points
1984! which are used in the conjugate gradient algorithm.
1985!
1986 DO ng=1,ngrids
1987 IF (master) THEN
1988 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
1989 END IF
1990 END DO
1991!
1992# ifdef SOLVE3D
1993 CALL tl_main3d (runinterval)
1994# else
1995 CALL tl_main2d (runinterval)
1996# endif
1997 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
1998
1999 DO ng=1,ngrids
2000 wrtnlmod(ng)=.false.
2001 wrttlmod(ng)=.false.
2002 END DO
2003!
2004! Compute observation impact to the data assimilation system.
2005!
2006 DO ng=1,ngrids
2007 CALL rep_matrix (ng, itlm, outer, ninner)
2008 END DO
2009!
2010! Write out observation sentivity.
2011!
2012 IF (outer.eq.1) THEN
2013 sourcefile=myfile
2014 DO ng=1,ngrids
2015 SELECT CASE (dav(ng)%IOtype)
2016 CASE (io_nf90)
2017 CALL netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2018 & 'ObsImpact_IC', ad_obsval, &
2019 & (/1/), (/mobs/), &
2020 & ncid = dav(ng)%ncid)
2022 & __line__, myfile)) RETURN
2023
2024 CALL netcdf_sync (ng, inlm, dav(ng)%name, dav(ng)%ncid)
2026 & __line__, myfile)) RETURN
2027
2028# if defined PIO_LIB && defined DISTRIBUTE
2029 CASE (io_pio)
2030 CALL pio_netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2031 & 'ObsImpact_IC', ad_obsval, &
2032 & (/1/), (/mobs/), &
2033 & piofile = dav(ng)%pioFile)
2035 & __line__, myfile)) RETURN
2036
2037 CALL pio_netcdf_sync (ng, inlm, dav(ng)%name, &
2038 & dav(ng)%pioFile)
2040 & __line__, myfile)) RETURN
2041# endif
2042 END SELECT
2043 END DO
2044 END IF
2045
2046# if defined ADJUST_WSTRESS || defined ADJUST_STFLUX
2047!
2048!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2049! Integrate tangent linear model with surface forcing increments
2050! only to compute the observations impact associated with the
2051! surface forcing.
2052!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2053!
2054 DO ng=1,ngrids
2055 wrtnlmod(ng)=.false.
2056 wrttlmod(ng)=.true.
2057 lwrttlm(ng)=.false.
2058 END DO
2059!
2060! Clear tangent linear forcing arrays before entering inner-loop.
2061! This is very important since these arrays are non-zero after
2062! running the representer model and must be zero when running the
2063! tangent linear model.
2064!
2065 DO ng=1,ngrids
2066 DO tile=first_tile(ng),last_tile(ng),+1
2067 CALL initialize_forces (ng, tile, itlm)
2068# ifdef ADJUST_BOUNDARY
2069 CALL initialize_boundary (ng, tile, itlm)
2070# endif
2071 END DO
2072 END DO
2073!
2074! Set basic state trajectory.
2075!
2076 DO ng=1,ngrids
2077 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
2078 lstr=len_trim(fwd(ng)%name)
2079 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
2080 END DO
2081!
2082! If weak constraint, the impulses are time-interpolated at each
2083! time-steps.
2084!
2085 DO ng=1,ngrids
2086 IF (frcrec(ng).gt.3) THEN
2087 frequentimpulse(ng)=.true.
2088 END IF
2089 END DO
2090!
2091! Initialize tangent linear model from ITL(ng)%name, record 1.
2092!
2093 DO ng=1,ngrids
2094 itl(ng)%Rindex=rec1
2095 CALL tl_initial (ng)
2096 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
2097 END DO
2098!
2099! Clear tangent initial condition arrays and boundary arrays
2100! before the obs impact initial condition calculation.
2101!
2102 DO ng=1,ngrids
2103 DO tile=first_tile(ng),last_tile(ng),+1
2104 CALL initialize_ocean (ng, tile, itlm)
2105# ifdef ADJUST_BOUNDARY
2106 CALL initialize_boundary (ng, tile, itlm)
2107# endif
2108 END DO
2109 END DO
2110
2111# ifdef RPM_RELAXATION
2112!
2113! Activate the tangent linear relaxation terms if used.
2114!
2115 DO ng=1,ngrids
2116 lweakrelax(ng)=.true.
2117 END DO
2118# endif
2119!
2120! Run tangent linear model forward and force with convolved adjoint
2121! trajectory impulses. Compute (HMBM'H')_n * PSI at observation points
2122! which are used in the conjugate gradient algorithm.
2123!
2124 DO ng=1,ngrids
2125 IF (master) THEN
2126 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
2127 END IF
2128 END DO
2129!
2130# ifdef SOLVE3D
2131 CALL tl_main3d (runinterval)
2132# else
2133 CALL tl_main2d (runinterval)
2134# endif
2135 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
2136
2137 DO ng=1,ngrids
2138 wrtnlmod(ng)=.false.
2139 wrttlmod(ng)=.false.
2140 END DO
2141!
2142! Compute observation impact to the data assimilation system.
2143!
2144 DO ng=1,ngrids
2145 CALL rep_matrix (ng, itlm, outer, ninner)
2146 END DO
2147!
2148! Write out observation sentivity.
2149!
2150 IF (outer.eq.1) THEN
2151 sourcefile=myfile
2152 DO ng=1,ngrids
2153 SELECT CASE (dav(ng)%IOtype)
2154 CASE (io_nf90)
2155 CALL netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2156 & 'ObsImpact_FC', ad_obsval, &
2157 & (/1/), (/mobs/), &
2158 & ncid = dav(ng)%ncid)
2160 & __line__, myfile)) RETURN
2161
2162 CALL netcdf_sync (ng, inlm, dav(ng)%name, dav(ng)%ncid)
2164 & __line__, myfile)) RETURN
2165
2166# if defined PIO_LIB && defined DISTRIBUTE
2167 CASE (io_pio)
2168 CALL pio_netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2169 & 'ObsImpact_FC', ad_obsval, &
2170 & (/1/), (/mobs/), &
2171 & piofile = dav(ng)%pioFile)
2173 & __line__, myfile)) RETURN
2174
2175 CALL pio_netcdf_sync (ng, inlm, dav(ng)%name, &
2176 & dav(ng)%pioFile)
2178 & __line__, myfile)) RETURN
2179# endif
2180 END SELECT
2181 END DO
2182 END IF
2183# endif
2184
2185# if defined ADJUST_BOUNDARY
2186!
2187!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2188! Integrate tangent linear model with boundary condition increments
2189! only to compute the observation impact associated with the boundary
2190! conditions.
2191!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
2192!
2193 DO ng=1,ngrids
2194 wrtnlmod(ng)=.false.
2195 wrttlmod(ng)=.true.
2196 lwrttlm(ng)=.false.
2197 END DO
2198!
2199! Clear tangent linear forcing arrays before entering inner-loop.
2200! This is very important since these arrays are non-zero after
2201! running the representer model and must be zero when running the
2202! tangent linear model.
2203!
2204 DO ng=1,ngrids
2205 DO tile=first_tile(ng),last_tile(ng),+1
2206 CALL initialize_forces (ng, tile, itlm)
2207# ifdef ADJUST_BOUNDARY
2208 CALL initialize_boundary (ng, tile, itlm)
2209# endif
2210 END DO
2211 END DO
2212!
2213! Set basic state trajectory.
2214!
2215 DO ng=1,ngrids
2216 WRITE (fwd(ng)%name,10) trim(fwd(ng)%head), outer-1
2217 lstr=len_trim(fwd(ng)%name)
2218 fwd(ng)%base=fwd(ng)%name(1:lstr-3)
2219 END DO
2220!
2221! If weak constraint, the impulses are time-interpolated at each
2222! time-steps.
2223!
2224 DO ng=1,ngrids
2225 IF (frcrec(ng).gt.3) THEN
2226 frequentimpulse(ng)=.true.
2227 END IF
2228 END DO
2229!
2230! Initialize tangent linear model from ITL(ng)%name, record Rec1.
2231!
2232 DO ng=1,ngrids
2233 itl(ng)%Rindex=rec1
2234 CALL tl_initial (ng)
2235 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
2236 END DO
2237!
2238! Clear tangent linear initial condition and forcing arrays
2239! before the obs impact initial condition calculation.
2240!
2241 DO ng=1,ngrids
2242 DO tile=first_tile(ng),last_tile(ng),+1
2243 CALL initialize_ocean (ng, tile, itlm)
2244 CALL initialize_forces (ng, tile, itlm)
2245 END DO
2246 END DO
2247
2248# ifdef RPM_RELAXATION
2249!
2250! Activate the tangent linear relaxation terms if used.
2251!
2252 DO ng=1,ngrids
2253 lweakrelax(ng)=.true.
2254 END DO
2255# endif
2256!
2257! Run tangent linear model forward and force with convolved adjoint
2258! trajectory impulses. Compute (HMBM'H')_n * PSI at observation points
2259! which are used in the conjugate gradient algorithm.
2260!
2261 DO ng=1,ngrids
2262 IF (master) THEN
2263 WRITE (stdout,20) 'TL', ng, ntstart(ng), ntend(ng)
2264 END IF
2265 END DO
2266!
2267# ifdef SOLVE3D
2268 CALL tl_main3d (runinterval)
2269# else
2270 CALL tl_main2d (runinterval)
2271# endif
2272 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
2273
2274 DO ng=1,ngrids
2275 wrtnlmod(ng)=.false.
2276 wrttlmod(ng)=.false.
2277 END DO
2278!
2279! Compute observation impact to the data assimilation system.
2280!
2281 DO ng=1,ngrids
2282 CALL rep_matrix (ng, itlm, outer, ninner)
2283 END DO
2284!
2285! Write out observation sentivity.
2286!
2287 IF (outer.eq.1) THEN
2288 sourcefile=myfile
2289 DO ng=1,ngrids
2290 SELECT CASE (dav(ng)%IOtype)
2291 CASE (io_nf90)
2292 CALL netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2293 & 'ObsImpact_BC', ad_obsval, &
2294 & (/1/), (/mobs/), &
2295 & ncid = dav(ng)%ncid)
2297 & __line__, myfile)) RETURN
2298
2299 CALL netcdf_sync (ng, inlm, dav(ng)%name, dav(ng)%ncid)
2301 & __line__, myfile)) RETURN
2302
2303# if defined PIO_LIB && defined DISTRIBUTE
2304 CASE (io_pio)
2305 CALL pio_netcdf_put_fvar (ng, itlm, dav(ng)%name, &
2306 & 'ObsImpact_BC', ad_obsval, &
2307 & (/1/), (/mobs/), &
2308 & piofile = dav(ng)%pioFile)
2310 & __line__, myfile)) RETURN
2311
2312 CALL pio_netcdf_sync (ng, inlm, dav(ng)%name, &
2313 & dav(ng)%pioFile)
2315 & __line__, myfile)) RETURN
2316# endif
2317 END SELECT
2318 END DO
2319 END IF
2320# endif
2321#endif /* OBS_IMPACT_SPLIT */
2322!
2323! Close current forward NetCDF file.
2324!
2325 sourcefile=myfile
2326 DO ng=1,ngrids
2327 CALL close_file (ng, inlm, fwd(ng))
2328 IF (founderror(exit_flag, noerror, __line__, myfile)) RETURN
2329!
2330 IF (his(ng)%IOtype.eq.io_nf90) THEN
2331 his(ng)%ncid=-1
2332#if defined PIO_LIB && defined DISTRIBUTE
2333 ELSE IF (his(ng)%IOtype.eq.io_pio) THEN
2334 his(ng)%pioFile%fh=-1
2335#endif
2336 END IF
2337 END DO
2338
2339 END DO ad_outer_loop
2340!
2341 10 FORMAT (a,'_outer',i0,'.nc')
2342 20 FORMAT (/,1x,a,1x,'ROMS: started time-stepping:', &
2343 & ' (Grid: ',i2.2,' TimeSteps: ',i8.8,' - ',i8.8,')',/)
2344 30 FORMAT (' (',i3.3,',',i3.3,'): ',a,' data penalty, Jdata = ', &
2345 & 1p,e17.10,0p,t68,a)
2346 40 FORMAT (/,' Converting Convolved Adjoint Trajectory to', &
2347 & ' Impulses: Outer = ',i3.3,' Inner = ',i3.3,/)
2348 50 FORMAT (/,'ROMS: Started adjoint Sensitivity calculation', &
2349 & ' ...',/)
2350 60 FORMAT (/,'ROMS: ',a,1x,a,', Outer = ',i3.3, &
2351 & ' Inner = ',i3.3,/)
2352 70 FORMAT (/,1x,a,1x,'ROMS: adjoint forcing time range: ', &
2353 & f12.4,' - ',f12.4 ,/)
2354!
2355 RETURN
2356 END SUBROUTINE roms_run
2357!
2358 SUBROUTINE roms_finalize
2359!
2360!=======================================================================
2361! !
2362! This routine terminates ROMS nonlinear, tangent linear, and !
2363! adjoint models execution. !
2364! !
2365!=======================================================================
2366!
2367 USE mod_param
2368 USE mod_parallel
2369 USE mod_iounits
2370 USE mod_ncparam
2371 USE mod_scalars
2372!
2373! Local variable declarations.
2374!
2375 integer :: Fcount, ng, thread
2376!
2377 character (len=*), parameter :: MyFile = &
2378 & __FILE__//", ROMS_finalize"
2379!
2380!-----------------------------------------------------------------------
2381! Read and write observation variables for completeness.
2382!-----------------------------------------------------------------------
2383!
2384 DO ng=1,ngrids
2385#ifdef DISTRIBUTE
2386 CALL stats_modobs (ng, myrank)
2387#else
2388 CALL stats_modobs (ng, -1)
2389#endif
2390 END DO
2391!
2392!-----------------------------------------------------------------------
2393! If blowing-up, save latest model state into RESTART NetCDF file.
2394!-----------------------------------------------------------------------
2395!
2396! If cycling restart records, write solution into record 3.
2397!
2398 IF (exit_flag.eq.1) THEN
2399 DO ng=1,ngrids
2400 IF (lwrtrst(ng)) THEN
2401 IF (master) WRITE (stdout,10)
2402 10 FORMAT (/,' Blowing-up: Saving latest model state into ', &
2403 & ' RESTART file',/)
2404 fcount=rst(ng)%load
2405 IF (lcyclerst(ng).and.(rst(ng)%Nrec(fcount).ge.2)) THEN
2406 rst(ng)%Rindex=2
2407 lcyclerst(ng)=.false.
2408 END IF
2411#ifdef DISTRIBUTE
2412 CALL wrt_rst (ng, myrank)
2413#else
2414 CALL wrt_rst (ng, -1)
2415#endif
2416 END IF
2417 END DO
2418 END IF
2419!
2420!-----------------------------------------------------------------------
2421! Stop model and time profiling clocks, report memory requirements, and
2422! close output NetCDF files.
2423!-----------------------------------------------------------------------
2424!
2425! Stop time clocks.
2426!
2427 IF (master) THEN
2428 WRITE (stdout,20)
2429 20 FORMAT (/,'Elapsed wall CPU time for each process (seconds):',/)
2430 END IF
2431!
2432 DO ng=1,ngrids
2433 DO thread=thread_range
2434 CALL wclock_off (ng, inlm, 0, __line__, myfile)
2435 END DO
2436 END DO
2437!
2438! Report dynamic memory and automatic memory requirements.
2439!
2440 CALL memory
2441!
2442! Close IO files.
2443!
2444 DO ng=1,ngrids
2445 CALL close_inp (ng, inlm)
2446 END DO
2447 CALL close_out
2448!
2449 RETURN
2450 END SUBROUTINE roms_finalize
2451
2452 END MODULE roms_kernel_mod
subroutine ad_congrad
subroutine ad_initial(ng)
Definition ad_initial.F:4
subroutine ad_main2d
Definition ad_main2d.F:586
subroutine ad_main3d(runinterval)
Definition ad_main3d.F:4
subroutine edit_multifile(task)
subroutine initial
Definition initial.F:3
subroutine main2d
Definition main2d.F:746
subroutine main3d(runinterval)
Definition main3d.F:4
subroutine memory
Definition memory.F:3
subroutine, public ad_wrt_his(ng, tile)
Definition ad_wrt_his.F:66
subroutine, public close_out
Definition close_io.F:175
subroutine, public close_file(ng, model, s, ncname, lupdate)
Definition close_io.F:43
subroutine, public close_inp(ng, model)
Definition close_io.F:92
subroutine, public congrad(ng, model, outloop, innloop, ninnloop, lcgini)
Definition congrad.F:163
subroutine, public error_covariance(model, driver, outloop, innloop, rbck, rini, rold, rnew, rec1, rec2, lposterior)
Definition convolve.F:215
subroutine, public def_impulse(ng)
Definition def_impulse.F:49
subroutine, public def_mod(ng)
Definition def_mod.F:49
subroutine, public def_norm(ng, model, ifile)
Definition def_norm.F:53
subroutine, public get_state(ng, model, msg, s, inirec, tindex)
Definition get_state.F:90
subroutine, public inp_par(model)
Definition inp_par.F:56
subroutine, public roms_initialize_arrays
Definition mod_arrays.F:351
subroutine, public roms_allocate_arrays(allocate_vars)
Definition mod_arrays.F:114
subroutine, public initialize_boundary(ng, tile, model)
subroutine, public initialize_forces(ng, tile, model)
real(dp), dimension(:), allocatable cg_gnorm_v
type(t_fourdvar), dimension(:), allocatable fourdvar
real(dp), dimension(:,:), allocatable cg_beta
real(r8), dimension(:,:), allocatable cg_dla
real(dp), dimension(:,:), allocatable cg_qg
logical, dimension(:), allocatable wrtmisfit
logical, dimension(:), allocatable wrtrpmod
logical, dimension(:), allocatable lsen4dvar
real(r8), dimension(:,:), allocatable ad_obsval
logical, dimension(:), allocatable wrttlmod
logical, dimension(:), allocatable wrtnlmod
logical, dimension(:), allocatable wrtforce
logical lhotstart
integer nimpact
real(r8), dimension(:,:,:), allocatable zcglwk
logical, dimension(:), allocatable wrtobsscale
real(dp), dimension(:,:), allocatable cg_delta
logical, dimension(:), allocatable lweakrelax
logical, dimension(:), allocatable wrtzetaref
integer, dimension(:), allocatable nstatevar
real(r8), dimension(:,:), allocatable zgrad0
type(t_io), dimension(:), allocatable lcz
type(t_io), dimension(:,:), allocatable std
type(t_io), dimension(:), allocatable his
type(t_io), dimension(:,:), allocatable nrm
type(t_io), dimension(:), allocatable adm
type(t_io), dimension(:), allocatable irp
type(t_io), dimension(:), allocatable tlf
type(t_io), dimension(:), allocatable tlm
type(t_io), dimension(:), allocatable itl
type(t_io), dimension(:), allocatable dav
type(t_io), dimension(:), allocatable fwd
type(t_io), dimension(:), allocatable rst
type(t_io), dimension(:), allocatable ini
integer stdout
character(len=256) sourcefile
integer, parameter io_nf90
Definition mod_ncparam.F:95
integer, parameter io_pio
Definition mod_ncparam.F:96
integer, dimension(:), allocatable ideftlm
integer isfsur
character(len=maxlen), dimension(6, 0:nv) vname
integer, dimension(:), allocatable idsvar
subroutine, public netcdf_sync(ng, model, ncname, ncid)
subroutine, public initialize_ocean(ng, tile, model)
Definition mod_ocean.F:1526
subroutine, public initialize_parallel
integer numthreads
integer, dimension(:), allocatable first_tile
integer mythread
logical master
integer, dimension(:), allocatable last_tile
integer ocn_comm_world
integer, parameter inlm
Definition mod_param.F:662
integer, parameter irpm
Definition mod_param.F:664
integer, dimension(:), allocatable ntilex
Definition mod_param.F:685
integer, parameter iadm
Definition mod_param.F:665
integer ngrids
Definition mod_param.F:113
integer, dimension(:), allocatable ntilee
Definition mod_param.F:686
integer, parameter itlm
Definition mod_param.F:663
integer nsa
Definition mod_param.F:612
subroutine, public pio_netcdf_sync(ng, model, ncname, piofile)
integer ninner
logical, dimension(:,:), allocatable lwrtnrm
logical, dimension(:), allocatable lreadqck
integer nouter
integer, dimension(:), allocatable ntimes
logical, dimension(:), allocatable ldefitl
real(dp), dimension(:), allocatable dt
logical lstiffness
integer blowup
logical, dimension(:), allocatable balance
logical, dimension(:), allocatable ldeftlf
integer erend
integer, dimension(:), allocatable frcrec
logical, dimension(:), allocatable lreadfrc
real(dp), dimension(:), allocatable tdays
real(r8), dimension(:), allocatable dends
logical, dimension(:), allocatable ldefadj
logical, dimension(:), allocatable frequentimpulse
logical, dimension(:), allocatable ldefhis
real(dp), parameter sec2day
integer, dimension(:), allocatable ntend
logical, dimension(:), allocatable ldefmod
logical, dimension(:,:), allocatable ldefnrm
integer exit_flag
logical, dimension(:), allocatable sporadicimpulse
integer erstr
real(r8), dimension(:), allocatable dstrs
logical, dimension(:), allocatable lwrthis
logical, dimension(:), allocatable lwrttlm
logical, dimension(:), allocatable lwrtrst
logical, dimension(:), allocatable ldeftlm
integer, dimension(:), allocatable ntstart
integer nrun
logical, dimension(:), allocatable lreadfwd
integer inner
integer noerror
logical, dimension(:), allocatable lcyclerst
integer outer
logical, dimension(:), allocatable lreadblk
integer, dimension(:), allocatable lold
integer, dimension(:), allocatable lbout
integer, dimension(:), allocatable lfinp
integer, dimension(:), allocatable lbinp
integer, dimension(:), allocatable lnew
integer, dimension(:), allocatable lfout
subroutine, public normalization(ng, tile, ifac)
subroutine, public roms_finalize
Definition ad_roms.h:283
subroutine, public roms_run(runinterval)
Definition ad_roms.h:239
subroutine, public roms_initialize(first, mpicomm)
Definition ad_roms.h:52
subroutine, public stats_modobs(ng, tile)
integer function, public stdout_unit(mymaster)
Definition stdout_mod.F:48
logical, save set_stdoutunit
Definition stdout_mod.F:41
character(len(sinp)) function, public uppercase(sinp)
Definition strings.F:582
logical function, public founderror(flag, noerr, line, routine)
Definition strings.F:52
subroutine, public tl_def_ini(ng)
Definition tl_def_ini.F:43
subroutine, public wrt_ini(ng, tile, tindex, outrec)
Definition wrt_ini.F:89
subroutine, public wrt_rst(ng, tile)
Definition wrt_rst.F:63
subroutine, public biconj(ng, tile, model, lbck)
subroutine, public balance_ref(ng, tile, lbck)
subroutine rep_matrix(ng, model, outloop, ninnloop)
Definition rep_matrix.F:4
subroutine rp_initial(ng)
Definition rp_initial.F:4
subroutine rp_main2d
Definition rp_main2d.F:410
subroutine rp_main3d(runinterval)
Definition rp_main3d.F:4
recursive subroutine wclock_off(ng, model, region, line, routine)
Definition timers.F:148
recursive subroutine wclock_on(ng, model, region, line, routine)
Definition timers.F:3
subroutine tl_initial(ng)
Definition tl_initial.F:4
subroutine tl_main2d
Definition tl_main2d.F:429
subroutine tl_main3d(runinterval)
Definition tl_main3d.F:4