ROMS
Loading...
Searching...
No Matches
tl_congrad.F
Go to the documentation of this file.
1#include "cppdefs.h"
2
3#if (defined SENSITIVITY_4DVAR || \
4 defined tl_rbl4dvar || \
5 defined tl_r4dvar) && \
6 !defined RPCG
7
8 SUBROUTINE tl_congrad (ng, model, outLoop, innLoop, NinnLoop, &
9 & Lcgini)
10!
11!git $Id$
12!=================================================== Andrew M. Moore ===
13! Copyright (c) 2002-2025 The ROMS Group Hernan G. Arango !
14! Licensed under a MIT/X style license !
15! See License_ROMS.md !
16!=======================================================================
17! !
18! Weak Constraint 4-Dimensional Variational (4DVar) Pre-conditioned !
19! Conjugate Gradient Algorithm !
20
21# if defined R4DVAR_ANA_SENSITIVITY || defined TL_R4DVAR
22! !
23! The indirect representer method solves the system: !
24! !
25! (R_n + Cobs) * Beta_n = h_n !
26! !
27! h_n = Xo - H * X_n !
28! !
29! where R_n is the representer matrix, Cobs is the observation-error !
30! covariance, Beta_n are the representer coefficients, h_n is the !
31! misfit between observations (Xo) and model (H*X_n), and H is the !
32! linearized observation operator. Here, _n denotes iteration. !
33! !
34! This system does not need to be solved explicitly by inverting the !
35! symmetric stabilized representer matrix, P_n: !
36! !
37! P_n = R_n + Cobs !
38! !
39! but by computing the action of P_n on any vector PSI, such that !
40! !
41! P_n * PSI = R_n * PSI + Cobs * PSI !
42! !
43! The representer matrix is not explicitly computed but evaluated by !
44! one integration backward of the adjoint model and one integration !
45! forward of the tangent linear model for any forcing vector PSI. !
46! !
47! Notice that "ObsScale" vector is used for screenning observations. !
48! This scale is one (zero) for good (bad) observations. !
49! !
50! Currently, parallelization of this algorithm is not needed because !
51! each parallel node has a full copy of the assimilation vectors. !
52! !
53! This code solves Ax=b by minimizing the cost function !
54! 0.5*x*A*x-x*b, assuming an initial guess of x=x0. In this case the !
55! gradient is Ax-b and the Hessian is A. !
56! !
57! Reference: !
58! !
59! Chua, B. S. and A. F. Bennett, 2001: An inverse ocean modeling !
60! sytem, Ocean Modelling, 3, 137-165. !
61
62# elif defined RBL4DVAR_ANA_SENSITIVITY || defined TL_RBL4DVAR
63! !
64! Solve the system (following Courtier, 1997): !
65! !
66! (H M_n B (M_n)' H' + Cobs) * w_n = d_n !
67! !
68! d_n = yo - H * Xb_n !
69! !
70! where M_n is the tangent linear model matrix and _n denotes a !
71! sequence of outer-loop estimates, Cobs is the observation-error !
72! covariance, B is the background error covariance, d_n is the !
73! misfit between observations (yo) and model (H * Xb_n), and H is !
74! the linearized observation operator. !
75! !
76! The analysis increment is: !
77! !
78! dx_n = B M' H' w_n !
79! !
80! so that Xa = Xb + dx_n. !
81! !
82! The system does not need to be solved explicitly by inverting !
83! the symmetric matrix, P_n: !
84! !
85! P_n = H M_n B (M_n)' H' + Cobs !
86! !
87! but by computing the action of P_n on any vector PSI, such that !
88! !
89! P_n * PSI = H M_n B (M_n)' H' * PSI + Cobs * PSI !
90! !
91! The (H M_n B (M_n)' H') matrix is not explicitly computed but !
92! evaluated by one integration backward of the adjoint model and !
93! one integration forward of the tangent linear model for any !
94! forcing vector PSI. !
95! !
96! A preconditioned conjugate gradient algorithm is used to compute !
97! an approximation PSI for w_n. !
98! !
99! Reference: !
100! !
101! Courtier, P., 1997: Dual formulation of four-dimensional !
102! variational assimilation, Quart. J. Roy. Meteor. Soc., !
103! 123, 2449-2461. !
104# endif
105! !
106! Lanczos Algorithm Reference: !
107! !
108! Fisher, M., 1998: Minimization Algorithms for Variational Data !
109! Assimilation. In Seminar on Recent Developments in Numerical !
110! Methods for Atmospheric Modelling, 1998. !
111! !
112! Tchimanga, J., S. Gratton, A.T. Weaver, and A. Sartenaer, 2008: !
113! Limited-memory preconditioners, with application to incremental !
114! four-dimensional variational ocean data assimilation, Q.J.R. !
115! Meteorol. Soc., 134, 753-771. !
116! !
117!=======================================================================
118!
119 USE mod_param
120 USE mod_parallel
121 USE mod_fourdvar
122 USE mod_iounits
123 USE mod_scalars
124
125# ifdef DISTRIBUTE
126!
128# endif
129 implicit none
130!
131! Imported variable declarations
132!
133 logical, intent(in) :: Lcgini
134 integer, intent(in) :: ng, model, outLoop, innLoop, NinnLoop
135!
136! Local variable declarations.
137!
138 logical :: Ltrans
139
140 integer :: i, j, iobs, ivec, Lscale, info
141
142 real(r8) :: dla, zbet
143 real(r8) :: tl_dla
144# ifdef MINRES
145 real(r8) :: zsum, zck, zgk
146 real(r8) :: tl_zsum, tl_zck, tl_zgk
147# endif
148
149 real(r8), dimension(NinnLoop) :: zu, zgam
150 real(r8), dimension(NinnLoop) :: tl_zu, tl_zrhs
151 real(r8), dimension(Ndatum(ng)) :: pgrad, zt
152 real(r8), dimension(Ndatum(ng)) :: tl_px, tl_pgrad, tl_zt
153# ifdef MINRES
154 real(r8), dimension(innLoop,innLoop) :: ztriT, zLT, zLTt
155 real(r8), dimension(innLoop,innLoop) :: tl_ztriT, tl_zLT
156 real(r8), dimension(innLoop,innLoop) :: tl_zLTt
157 real(r8), dimension(innLoop) :: tau, zwork1, ze, zeref
158 real(r8), dimension(innLoop) :: tl_tau, tl_zwork1, tl_ze, tl_zeref
159# endif
160!
161!=======================================================================
162! Weak constraint 4DVar conjugate gradient, Lanczos-based algorithm.
163!=======================================================================
164!
165! This conjugate gradient algorithm is not run in parallel since the
166! weak constraint is done in observation space. Mostly all the
167! variables are 1D arrays. Therefore, in parallel applications (only
168! distributed-memory is possible) the master node does the computations
169! and then broadcasts results to remaining nodes in the communicator.
170!
171! This version of congrad solves A(x+x0)=b for x, by minimizing
172! J=0.5*x'Ax-x'(b+Ax0), where x0 is a first-guess estimate of the
173! representer coefficients from the previous outer-loop.
174! For the first outer-loop, x0=0. In the code x0=cg_pxsave and
175! x=px.
176!
177 ltrans=.false.
178
179 master_thread : IF (master) THEN
180!
181! Initialize cg_Gnorm. The TL of precond is not available.
182!
183 DO i=1,outloop
184 cg_gnorm(i)=cg_gnorm_v(i)
185 END DO
186!
187! Initialize internal parameters. This is needed here for output
188! reasons.
189!
190 IF (innloop.eq.0) THEN
191
192# if defined RBL4DVAR || defined TL_RBL4DVAR
193!
194! If this is the first inner-loop, save NLmodVal in BCKmodVal.
195!
196 DO iobs=1,ndatum(ng)
197 bckmodval(iobs)=nlmodval(iobs)
198 END DO
199# endif
200!
201! If this is the first outer-loop, clear the solution vector px.
202!
203 IF ((outloop.eq.1).or.(.not.lhotstart)) THEN
204!
205! For the first outer-loop, x0=0.
206!
207 DO iobs=1,ndatum(ng)
208 tl_px(iobs)=0.0_r8
209 tl_cg_pxsave(iobs)=0.0_r8
210 END DO
211!
212! If this is the first pass of the inner loop, set up the vectors and
213! store the first guess. The initial starting guess is assumed to be
214! zero in which case the gradient is just: -(obs-model).
215! A first-level preconditioning is applied using the inverse of the
216! observation error standard deviations (i.e. sqrt(ObsErr)).
217!
218 DO iobs=1,ndatum(ng)
219# if defined RBL4DVAR || defined TL_RBL4DVAR
220!^ pgrad(iobs)=-ObsScale(iobs)* &
221!^ & (ObsVal(iobs)-BCKmodVal(iobs))
222!^
223 tl_pgrad(iobs)=-obsscale(iobs)*tl_obsval(iobs)
224# else
225!^ pgrad(iobs)=-ObsScale(iobs)* &
226!^ & (ObsVal(iobs)-TLmodVal(iobs))
227!<> tl_pgrad(iobs)=-ObsScale(iobs)* &
228!<> & (tl_ObsVal(iobs)-tl_TLmodVal(iobs))
229!^
230 tl_pgrad(iobs)=-obsscale(iobs)* &
231 & (tl_obsval(iobs)-tlmodval(iobs))
232# endif
233!
234! Convert pgrad from x-space to v-space.
235!
236 IF (obserr(iobs).NE.0.0_r8) THEN
237!^ pgrad(iobs)=pgrad(iobs)/SQRT(ObsErr(iobs))
238!^
239 tl_pgrad(iobs)=tl_pgrad(iobs)/sqrt(obserr(iobs))
240 END IF
241!^ vgrad0(iobs)=pgrad(iobs)
242!^
243 END DO
244!
245! If preconditioning, convert pgrad from v-space to y-space.
246!
247!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
248!^ Lscale=2 ! SQRT spectral LMP
249!^ Ltrans=.TRUE.
250!^ CALL rprecond (ng, Lscale, Ltrans, outLoop, NinnLoop, &
251!^ & pgrad)
252!^ END IF
253!^
254!^ cg_Gnorm(outLoop)=0.0_r8
255!^
256 tl_cg_gnorm(outloop)=0.0_r8
257!^ vgnorm(outLoop)=0.0_r8
258!^
259 DO iobs=1,ndatum(ng)
260!^ zgrad0(iobs,outLoop)=pgrad(iobs)
261!^
262 tl_zgrad0(iobs)=tl_pgrad(iobs)
263!^ cg_Gnorm(outLoop)=cg_Gnorm(outLoop)+ &
264!^ & zgrad0(iobs)*zgrad0(iobs)
265!^
266 tl_cg_gnorm(outloop)=tl_cg_gnorm(outloop)+ &
267 & 2.0_r8*tl_zgrad0(iobs)* &
268 & zgrad0(iobs,outloop)
269!^ vgnorm(outLoop)=vgnorm(outLoop)+vgrad0(iobs)*vgrad0(iobs)
270!^
271 END DO
272!^ cg_Gnorm(outLoop)=SQRT(cg_Gnorm(outLoop))
273!^
274 tl_cg_gnorm(outloop)=0.5_r8*tl_cg_gnorm(outloop)/ &
275 & cg_gnorm(outloop)
276!^ vgnorm(outLoop)=SQRT(vgnorm(outLoop))
277!^
278 DO iobs=1,ndatum(ng)
279!^ zcglwk(iobs,1,outLoop)=pgrad(iobs)/cg_Gnorm(outLoop)
280!^
281 tl_zcglwk(iobs,1)=(tl_pgrad(iobs)- &
282 & tl_cg_gnorm(outloop)* &
283 & zcglwk(iobs,1,outloop))/ &
284 & cg_gnorm(outloop)
285!^ ADmodVal(iobs)=zcglwk(iobs,1,outLoop)
286!<> tl_ADmodVal(iobs)=tl_zcglwk(iobs,1)
287!^
288 admodval(iobs)=tl_zcglwk(iobs,1)
289 END DO
290!
291! If preconditioning, convert ADmodVal from y-space to v-space.
292!
293!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
294!^ Lscale=2 ! SQRT spectral LMP
295!^ Ltrans=.FALSE.
296!^ CALL rprecond (ng, Lscale, Ltrans, outLoop, NinnLoop, &
297!^ & ADmodVal)
298!^ END IF
299!
300! Convert ADmodVal from v-space to x-space.
301!
302 DO iobs=1,ndatum(ng)
303 IF (obserr(iobs).NE.0.0_r8) THEN
304!^ ADmodVal(iobs)=ADmodVal(iobs)/SQRT(ObsErr(iobs))
305!<> tl_ADmodVal(iobs)=tl_ADmodVal(iobs)/SQRT(ObsErr(iobs))
306!^
307 admodval(iobs)=admodval(iobs)/sqrt(obserr(iobs))
308 END IF
309 END DO
310
311!^ cg_QG(1,outLoop)=0.0_r8
312!^
313 tl_cg_qg(1)=0.0_r8
314 DO iobs=1,ndatum(ng)
315!^ cg_QG(1,outLoop)=cg_QG(1,outLoop)+ &
316!^ & zcglwk(iobs,1,outLoop)*zgrad0(iobs)
317!^
318 tl_cg_qg(1)=tl_cg_qg(1)+ &
319 & tl_zcglwk(iobs,1)*zgrad0(iobs,outloop)+ &
320 & zcglwk(iobs,1,outloop)*tl_zgrad0(iobs)
321 END DO
322
323 ELSE
324 IF (lcgini) THEN
325!
326! When outer>1 we need to evaluate Ax0 so for inner=0 we use
327! cg_pxsave in v-space as the starting vector.
328!
329 DO iobs=1,ndatum(ng)
330!^ ADmodVal(iobs)=cg_pxsave(iobs)
331!<> tl_ADmodVal(iobs)=tl_cg_pxsave(iobs)
332!^
333 admodval(iobs)=tl_cg_pxsave(iobs)
334# if defined RBL4DVAR || defined TL_RBL4DVAR
335!^ cg_innov(iobs)=-ObsScale(iobs)* &
336!^ & (ObsVal(iobs)-BCKmodVal(iobs))
337!<> tl_cg_innov(iobs)=0.0_r8
338!^
339 tl_cg_innov(iobs)=-obsscale(iobs)*tl_obsval(iobs)
340# else
341!^ cg_innov(iobs)=-ObsScale(iobs)* &
342!^ & (ObsVal(iobs)-TLmodVal(iobs))
343!<> tl_cg_innov(iobs)=-ObsScale(iobs)* &
344!<> & (tl_ObsVal(iobs)-tl_TLmodVal(iobs))
345!^
346 tl_cg_innov(iobs)=-obsscale(iobs)* &
347 & (tl_obsval(iobs)-tlmodval(iobs))
348# endif
349 END DO
350!
351! Convert ADmodVal from v-space to x-space and cg_innov (the
352! contribution to the starting gradient) from x-space to v-space.
353!
354 DO iobs=1,ndatum(ng)
355 IF (obserr(iobs).NE.0.0_r8) THEN
356!^ ADmodVal(iobs)=ADmodVal(iobs)/SQRT(ObsErr(iobs))
357!<> tl_ADmodVal(iobs)=tl_ADmodVal(iobs)/SQRT(ObsErr(iobs))
358!^
359 admodval(iobs)=admodval(iobs)/sqrt(obserr(iobs))
360!^ cg_innov(iobs)=cg_innov(iobs)/SQRT(ObsErr(iobs))
361!^
362 tl_cg_innov(iobs)=tl_cg_innov(iobs)/sqrt(obserr(iobs))
363 END IF
364 END DO
365
366 ELSE
367
368 DO iobs=1,ndatum(ng)
369!
370! Convert gradient contribution from x-space to v-space.
371!
372!^ pgrad(iobs)=ObsScale(iobs)*TLmodVal(iobs)
373!^ tl_pgrad(iobs)=ObsScale(iobs)*tl_TLmodVal(iobs)
374!^
375 tl_pgrad(iobs)=obsscale(iobs)*tlmodval(iobs)
376 IF (obserr(iobs).NE.0.0_r8) THEN
377!^ pgrad(iobs)=pgrad(iobs)/SQRT(ObsErr(iobs))
378!^
379 tl_pgrad(iobs)=tl_pgrad(iobs)/sqrt(obserr(iobs))
380 END IF
381!
382! Add I*x0=cg_pxsave contribution to the gradient and the term
383! -b=cg_innov (everything is in v-space at this point).
384!
385!^ pgrad(iobs)=pgrad(iobs)+ObsScale(iobs)* &
386!^ & (cg_pxsave(iobs)+cg_innov(iobs))
387!^
388 tl_pgrad(iobs)=tl_pgrad(iobs)+obsscale(iobs)* &
389 & (tl_cg_pxsave(iobs)+tl_cg_innov(iobs))
390!^ vgrad0(iobs)=pgrad(iobs)
391!^
392 END DO
393!
394! If preconditioning, convert pgrad from v-space to y-space.
395!
396!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
397!^ Lscale=2 ! SQRT spectral LMP
398!^ Ltrans=.TRUE.
399!^ CALL rprecond(ng, Lscale, Ltrans, outLoop, NinnLoop, &
400!^ & pgrad)
401!^ END IF
402!^
403!^ cg_Gnorm(outLoop)=0.0_r8
404!^
405 tl_cg_gnorm(outloop)=0.0_r8
406!^ vgnorm(outLoop)=0.0_r8
407!^
408 DO iobs=1,ndatum(ng)
409!^ zgrad0(iobs,outLoop)=pgrad(iobs)
410!^
411 tl_zgrad0(iobs)=tl_pgrad(iobs)
412!^ cg_Gnorm(outLoop)=cg_Gnorm(outLoop)+ &
413!^ & zgrad0(iobs,outLoop)* &
414!^ & zgrad0(iobs,outLoop)
415!^
416 tl_cg_gnorm(outloop)=tl_cg_gnorm(outloop)+ &
417 & 2.0_r8*tl_zgrad0(iobs)* &
418 & zgrad0(iobs,outloop)
419!^ vgnorm(outLoop)=vgnorm(outLoop)+ &
420!^ & vgrad0(iobs)*vgrad0(iobs)
421!^
422 END DO
423!^ cg_Gnorm(outLoop)=SQRT(cg_Gnorm(outLoop))
424!^
425 tl_cg_gnorm(outloop)=0.5_r8*tl_cg_gnorm(outloop)/ &
426 & cg_gnorm(outloop)
427!^ vgnorm(outLoop)=SQRT(vgnorm(outLoop))
428!^
429 DO iobs=1,ndatum(ng)
430!^ zcglwk(iobs,1,outLoop)=pgrad(iobs)/cg_Gnorm(outLoop)
431!^
432 tl_zcglwk(iobs,1)=(tl_pgrad(iobs)- &
433 & tl_cg_gnorm(outloop)* &
434 & zcglwk(iobs,1,outloop))/ &
435 & cg_gnorm(outloop)
436!^ ADmodVal(iobs)=zcglwk(iobs,1,outLoop)
437!<> tl_ADmodVal(iobs)=tl_zcglwk(iobs,1)
438!^
439 admodval(iobs)=tl_zcglwk(iobs,1)
440 END DO
441!
442! If preconditioning, convert ADmodVal from y-space to v-space.
443!
444!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
445!^ Lscale=2 ! SQRT spectral LMP
446!^ Ltrans=.FALSE.
447!^ CALL rprecond(ng, Lscale, Ltrans, outLoop, NinnLoop, &
448!^ & ADmodVal)
449!^ END IF
450!^
451 DO iobs=1,ndatum(ng)
452 IF (obserr(iobs).NE.0.0_r8) THEN
453!^ ADmodVal(iobs)=ADmodVal(iobs)/SQRT(ObsErr(iobs))
454!<> tl_ADmodVal(iobs)=tl_ADmodVal(iobs)/SQRT(ObsErr(iobs))
455!^
456 admodval(iobs)=admodval(iobs)/sqrt(obserr(iobs))
457 END IF
458 END DO
459!^ cg_QG(1,outLoop)=0.0_r8
460!^
461 tl_cg_qg(1)=0.0_r8
462 DO iobs=1,ndatum(ng)
463!^ cg_QG(1,outLoop)=cg_QG(1,outLoop)+ &
464!^ & zcglwk(iobs,1,outLoop)* &
465!^ & zgrad0(iobs,outLoop)
466!^
467 tl_cg_qg(1)=tl_cg_qg(1)+ &
468 & tl_zcglwk(iobs,1)*zgrad0(iobs,outloop)+ &
469 & zcglwk(iobs,1,outloop)*tl_zgrad0(iobs)
470 END DO
471
472 END IF
473
474 END IF
475
476 ELSE
477!
478! After the initialization, for every other inner loop, calculate a
479! new Lanczos vector, store it in the matrix, and update search.
480!
481 DO iobs=1,ndatum(ng)
482 pgrad(iobs)=obsscale(iobs)*tlmodval_s(iobs,innloop,outloop)
483!<> tl_pgrad(iobs)=ObsScale(iobs)*tl_TLmodVal(iobs)
484 tl_pgrad(iobs)=obsscale(iobs)*tlmodval(iobs)
485!
486! Convert gradient contribution from x-space to v-space.
487!
488 IF (obserr(iobs).NE.0.0_r8) THEN
489 pgrad(iobs)=pgrad(iobs)/sqrt(obserr(iobs))
490 tl_pgrad(iobs)=tl_pgrad(iobs)/sqrt(obserr(iobs))
491 END IF
492 END DO
493
494 DO iobs=1,ndatum(ng)
495 zt(iobs)=zcglwk(iobs,innloop,outloop)
496 tl_zt(iobs)=tl_zcglwk(iobs,innloop)
497 END DO
498!
499! If preconditioning, convert zt from y-space to v-space.
500!
501!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
502!^ Lscale=2 ! SQRT spectral LMP
503!^ Ltrans=.FALSE.
504!^ CALL rprecond(ng, Lscale, Ltrans, outLoop, NinnLoop, zt)
505!^ END IF
506!^
507 DO iobs=1,ndatum(ng)
508 pgrad(iobs)=pgrad(iobs)+obsscale(iobs)*zt(iobs)
509 tl_pgrad(iobs)=tl_pgrad(iobs)+obsscale(iobs)*tl_zt(iobs)
510 END DO
511!
512! If preconditioning, convert pgrad from v-space to y-space.
513!
514!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
515!^ Lscale=2 ! SQRT spectral LMP
516!^ Ltrans=.TRUE.
517!^ CALL rprecond(ng, Lscale, Ltrans, outLoop, NinnLoop, pgrad)
518!^ END IF
519!^
520!^ cg_delta(innLoop,outLoop)=0.0_r8
521!^
522 tl_cg_delta(innloop)=0.0_r8
523 DO iobs=1,ndatum(ng)
524!^ cg_delta(innLoop,outLoop)=cg_delta(innLoop,outLoop)+ &
525!^ & zcglwk(iobs,innLoop,outLoop)* &
526!^ & pgrad(iobs)
527!^
528 tl_cg_delta(innloop)=tl_cg_delta(innloop)+ &
529 & tl_zcglwk(iobs,innloop)*pgrad(iobs)+ &
530 & zcglwk(iobs,innloop,outloop)* &
531 & tl_pgrad(iobs)
532 END DO
533!
534! Exit, if not a positive definite algorithm.
535!
536!^ IF (cg_delta(innLoop,outLoop).le.0.0_r8) THEN
537!^ WRITE (stdout,20) cg_delta(innLoop,outLoop), outLoop, &
538!^ & innLoop
539!^ exit_flag=8
540!^ END IF
541!^
542!
543! Compute the new Lanczos vector.
544!
545 DO iobs=1,ndatum(ng)
546 pgrad(iobs)=pgrad(iobs)- &
547 cg_delta(innloop,outloop)* &
548 & zcglwk(iobs,innloop,outloop)
549 tl_pgrad(iobs)=tl_pgrad(iobs)- &
550 & tl_cg_delta(innloop)* &
551 & zcglwk(iobs,innloop,outloop)- &
552 & cg_delta(innloop,outloop)* &
553 & tl_zcglwk(iobs,innloop)
554 END DO
555 IF (innloop.gt.1) THEN
556 DO iobs=1,ndatum(ng)
557 pgrad(iobs)=pgrad(iobs)- &
558 & cg_beta(innloop,outloop)* &
559 & zcglwk(iobs,innloop-1,outloop)
560 tl_pgrad(iobs)=tl_pgrad(iobs)- &
561 & tl_cg_beta(innloop)* &
562 & zcglwk(iobs,innloop-1,outloop)- &
563 & cg_beta(innloop,outloop)* &
564 & tl_zcglwk(iobs,innloop-1)
565 END DO
566 END IF
567!
568! Orthonormalize against previous Lanczos vectors.
569!
570 DO ivec=innloop,1,-1
571!^ cg_dla(ivec,outLoop)=0.0_r8
572!^
573 tl_dla=0.0_r8
574 DO iobs=1,ndatum(ng)
575!^ cg_dla(ivec,outLoop)=cg_dla(ivec,outLoop)+ &
576!^ & pgrad(iobs)* &
577!^ & zcglwk(iobs,ivec,outLoop)
578!^
579 tl_dla=tl_dla+ &
580 & tl_pgrad(iobs)*zcglwk(iobs,ivec,outloop)+ &
581 & pgrad(iobs)*tl_zcglwk(iobs,ivec)
582 END DO
583 DO iobs=1,ndatum(ng)
584 pgrad(iobs)=pgrad(iobs)- &
585 & cg_dla(ivec,outloop)* &
586 & zcglwk(iobs,ivec,outloop)
587 tl_pgrad(iobs)=tl_pgrad(iobs)- &
588 & cg_dla(ivec,outloop)*tl_zcglwk(iobs,ivec)- &
589 & tl_dla*zcglwk(iobs,ivec,outloop)
590 END DO
591 END DO
592!
593!^ cg_beta(innLoop+1,outLoop)=0.0_r8
594!^
595 tl_cg_beta(innloop+1)=0.0_r8
596 DO iobs=1,ndatum(ng)
597!^ cg_beta(innLoop+1,outLoop)=cg_beta(innLoop+1,outLoop)+ &
598!^ & pgrad(iobs)*pgrad(iobs)
599!^
600 tl_cg_beta(innloop+1)=tl_cg_beta(innloop+1)+ &
601 & 2.0_r8*tl_pgrad(iobs)*pgrad(iobs)
602 END DO
603!^ cg_beta(innLoop+1,outLoop)=SQRT(cg_beta(innLoop+1,outLoop))
604!^
605 tl_cg_beta(innloop+1)=0.5_r8*tl_cg_beta(innloop+1)/ &
606 & cg_beta(innloop+1,outloop)
607!
608 DO iobs=1,ndatum(ng)
609!^ zcglwk(iobs,innLoop+1,outLoop)=pgrad(iobs)/ &
610!^ & cg_beta(innLoop+1,outLoop)
611!^
612 tl_zcglwk(iobs,innloop+1)=(tl_pgrad(iobs)- &
613 & tl_cg_beta(innloop+1)* &
614 & zcglwk(iobs,innloop+1,outloop))/ &
615 & cg_beta(innloop+1,outloop)
616 END DO
617!
618!^ cg_QG(innLoop+1,outLoop)=0.0_r8
619!^
620 tl_cg_qg(innloop+1)=0.0_r8
621 DO iobs=1,ndatum(ng)
622!^ cg_QG(innLoop+1,outLoop)=cg_QG(innLoop+1,outLoop)+ &
623!^ & zcglwk(iobs,innLoop+1,outLoop)*
624!^ & zgrad0(iobs)
625!^
626 tl_cg_qg(innloop+1)=tl_cg_qg(innloop+1)+ &
627 & tl_zcglwk(iobs,innloop+1)* &
628 & zgrad0(iobs,outloop)+ &
629 & zcglwk(iobs,innloop+1,outloop)* &
630 & tl_zgrad0(iobs)
631 END DO
632 IF (innloop.eq.ninnloop) THEN
633# ifdef MINRES
634!
635! Use the minimum residual method as described by Paige and Saunders
636! ("Sparse Indefinite Systems of Linear Equations", 1975, SIAM Journal
637! on Numerical Analysis, 617-619). Specifically we refer to equations
638! 6.10 and 6.11 of this paper.
639!
640! Perform a LQ factorization of the tridiagonal matrix.
641!
642 ztrit=0.0_r8
643 tl_ztrit=0.0_r8
644 DO i=1,innloop
645 ztrit(i,i)=cg_delta(i,outloop)
646 tl_ztrit(i,i)=tl_cg_delta(i)
647 END DO
648 DO i=1,innloop-1
649 ztrit(i,i+1)=cg_beta(i+1,outloop)
650 tl_ztrit(i,i+1)=tl_cg_beta(i+1)
651 END DO
652 DO i=2,innloop
653 ztrit(i,i-1)=cg_beta(i,outloop)
654 tl_ztrit(i,i-1)=tl_cg_beta(i)
655 END DO
656!
657! Note: tl_sqlq also computes the LQ factorization of ztriT.
658!
659 CALL tl_sqlq(innloop, ztrit, tl_ztrit, tau, tl_tau, zwork1, &
660 & tl_zwork1)
661!
662! Isolate L=zLT and its transpose.
663!
664 zlt=0.0_r8
665 tl_zlt=0.0_r8
666 zltt=0.0_r8
667 tl_zltt=0.0_r8
668 DO i=1,innloop
669 DO j=1,i
670 zlt(i,j)=ztrit(i,j)
671 tl_zlt(i,j)=tl_ztrit(i,j)
672 END DO
673 END DO
674 DO j=1,innloop
675 DO i=1,innloop
676 zltt(i,j)=zlt(j,i)
677 tl_zltt(i,j)=tl_zlt(j,i)
678 END DO
679 END DO
680!
681! Now form ze=beta1*Q*e1.
682!
683 ze=0.0_r8
684 tl_ze=0.0_r8
685 DO i=1,innloop
686 ze(i)=-cg_qg(i,outloop)
687 tl_ze(i)=-tl_cg_qg(i)
688 END DO
689 DO i=1,innloop
690 DO j=1,innloop
691 zeref(j)=0.0_r8
692 tl_zeref(j)=0.0_r8
693 END DO
694 zeref(i)=1.0_r8
695 tl_zeref(i)=0.0_r8
696 DO j=i+1,innloop
697 zeref(j)=ztrit(i,j)
698 tl_zeref(j)=tl_ztrit(i,j)
699 END DO
700 zsum=0.0_r8
701 tl_zsum=0.0_r8
702 DO j=1,innloop
703 zsum=zsum+ze(j)*zeref(j)
704 tl_zsum=tl_zsum+tl_ze(j)*zeref(j)+ze(j)*tl_zeref(j)
705 END DO
706 DO j=1,innloop
707 ze(j)=ze(j)-tau(i)*zsum*zeref(j)
708 tl_ze(j)=tl_ze(j)-tl_tau(i)*zsum*zeref(j)- &
709 & tau(i)*tl_zsum*zeref(j)- &
710 & tau(i)*zsum*tl_zeref(j)
711 END DO
712 END DO
713!
714! Now form ze=D*ze (using equation 5.6 and 6.5 also).
715!
716 zgk=sqrt(zlt(innloop,innloop)*zlt(innloop,innloop)+ &
717 & cg_beta(innloop+1,outloop)*cg_beta(innloop+1,outloop))
718 IF (zgk.GT.0.0_r8) THEN
719 tl_zgk=(tl_zlt(innloop,innloop)*zlt(innloop,innloop)+ &
720 & tl_cg_beta(innloop+1)*cg_beta(innloop+1,outloop))/ &
721 & zgk
722 ELSE
723 tl_zgk=0.0_r8
724 ENDIF
725 zck=zlt(innloop,innloop)/zgk
726 tl_zck=tl_zlt(innloop,innloop)/zgk-tl_zgk*zck/zgk
727 ze(innloop)=zck*ze(innloop)
728 tl_ze(innloop)=tl_zck*ze(innloop)+zck*tl_ze(innloop)
729!
730! Now compute tl_ze=inv(L')*(tl_ze-tl_L'*ze).
731!
732! First solve for ze=inv(L')*ze.
733!
734 DO j=innloop,1,-1
735 ze(j)=ze(j)/zltt(j,j)
736 DO i=1,j-1
737 ze(i)=ze(i)-ze(j)*zltt(i,j)
738 END DO
739 END DO
740!
741! Next compute tl_rhs=tl_L'*ze then subtract from tl_ze.
742!
743 DO i=1,innloop
744 tl_zrhs(i)=0.0_r8
745 DO j=1,innloop
746 tl_zrhs(i)=tl_zrhs(i)+tl_zltt(i,j)*ze(j)
747 END DO
748 tl_ze(i)=tl_ze(i)-tl_zrhs(i)
749 END DO
750!
751! Now solve the linear triangular system.
752!
753 DO j=innloop,1,-1
754 tl_ze(j)=tl_ze(j)/zltt(j,j)
755 DO i=1,j-1
756 tl_ze(i)=tl_ze(i)-tl_ze(j)*zltt(i,j)
757 END DO
758 END DO
759!
760! Copy the solution ze into zu.
761!
762 DO i=1,innloop
763 zu(i)=ze(i)
764 tl_zu(i)=tl_ze(i)
765 END DO
766# else
767!
768! Calculate the new solution based upon the new, orthonormalized
769! Lanczos vector. First, the tridiagonal system is solved by
770! decomposition and forward/backward substitution.
771!
772 IF (ninnloop.eq.1) THEN
773 zu(1)=-cg_qg(1,outloop)/cg_delta(1,outloop)
774 tl_zrhs(1)=-tl_cg_qg(1)-tl_cg_delta(1)*zu(1)
775 tl_zu(1)=tl_zrhs(1)/cg_delta(1,outloop)
776 ELSE
777!
778! Compute zu first.
779!
780 zbet=cg_delta(1,outloop)
781 zu(1)=-cg_qg(1,outloop)/zbet
782 DO ivec=2,innloop
783 zgam(ivec)=cg_beta(ivec,outloop)/zbet
784 zbet=cg_delta(ivec,outloop)- &
785 & cg_beta(ivec,outloop)*zgam(ivec)
786 zu(ivec)=(-cg_qg(ivec,outloop)-cg_beta(ivec,outloop)* &
787 & zu(ivec-1))/zbet
788 END DO
789 DO ivec=innloop-1,1,-1
790 zu(ivec)=zu(ivec)-zgam(ivec+1)*zu(ivec+1)
791 END DO
792!
793! Now compute tl_zrhs.
794!
795 tl_zrhs(1)=-tl_cg_qg(1)- &
796 & tl_cg_delta(1)*zu(1)- &
797 & tl_cg_beta(2)*zu(2)
798 DO ivec=2,innloop-1
799 tl_zrhs(ivec)=-tl_cg_qg(ivec)- &
800 & tl_cg_beta(ivec)*zu(ivec-1)- &
801 & tl_cg_delta(ivec)*zu(ivec)- &
802 & tl_cg_beta(ivec+1)*zu(ivec+1)
803 END DO
804 tl_zrhs(innloop)=-tl_cg_qg(innloop)- &
805 & tl_cg_beta(innloop)*zu(innloop-1)- &
806 & tl_cg_delta(innloop)*zu(innloop)
807!
808! Now solve the TL tridiagonal system A*dx=b-dA*x
809!
810 zbet=cg_delta(1,outloop)
811 tl_zu(1)=tl_zrhs(1)/zbet
812 DO ivec=2,innloop
813 zgam(ivec)=cg_beta(ivec,outloop)/zbet
814 zbet=cg_delta(ivec,outloop)- &
815 & cg_beta(ivec,outloop)*zgam(ivec)
816 tl_zu(ivec)=(tl_zrhs(ivec)-cg_beta(ivec,outloop)* &
817 & tl_zu(ivec-1))/zbet
818 END DO
819
820 DO ivec=innloop-1,1,-1
821!^ zu(ivec)=zu(ivec)-zgam(ivec+1)*zu(ivec+1)
822!^
823 tl_zu(ivec)=tl_zu(ivec)-zgam(ivec+1)*tl_zu(ivec+1)
824 END DO
825 END IF
826
827!^ DO iobs=1,Ndatum(ng)
828!^ zw(iobs)=zgrad0(iobs)+ &
829!^ & cg_beta(innLoop+1,outLoop)* &
830!^ & zcglwk(iobs,innLoop+1,outLoop)*zwork(innLoop,3)
831!^ END DO
832# endif
833
834 DO iobs=1,ndatum(ng)
835!^ px(iobs)=0.0_r8
836!^
837 tl_px(iobs)=0.0_r8
838 DO ivec=1,innloop
839!^ px(iobs)=px(iobs)+ &
840!^ & zcglwk(iobs,ivec,outLoop)*zu(ivec)
841!^
842 tl_px(iobs)=tl_px(iobs)+ &
843 & tl_zcglwk(iobs,ivec)*zu(ivec)+ &
844 & zcglwk(iobs,ivec,outloop)*tl_zu(ivec)
845!^ zw(iobs)=zw(iobs)- &
846!^ & zcglwk(iobs,ivec,outLoop)*cg_QG(ivec,outLoop)
847!^
848 END DO
849 END DO
850!
851! If preconditioning, convert px from y-space to v-space.
852! We will always keep px in v-space.
853!
854!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
855!^ Lscale=2 ! SQRT spectral LMP
856!^ Ltrans=.FALSE.
857!^ CALL rprecond(ng, Lscale, Ltrans, outLoop, NinnLoop, px)
858!^ END IF
859!^
860 END IF
861!
862! Put the new trial solution into the adjoint vector for the next loop
863! Put the final solution into the adjoint vector when converged
864! of on the final inner-loop.
865!
866 IF ((innloop.eq.ninnloop)) THEN
867!
868! Note: px is already in v-space so there is no need to convert
869! if preconditioning. cg_pxsave is also in v-space.
870!
871 DO iobs=1,ndatum(ng)
872!^ ADmodVal(iobs)=px(iobs)
873!<> tl_ADmodVal(iobs)=tl_px(iobs)
874!^
875 admodval(iobs)=tl_px(iobs)
876 END DO
877 IF (lhotstart) THEN
878 DO iobs=1,ndatum(ng)
879!^ ADmodVal(iobs)=ADmodVal(iobs)+cg_pxsave(iobs)
880!<> tl_ADmodVal(iobs)=tl_ADmodVal(iobs)+tl_cg_pxsave(iobs)
881!^
882 admodval(iobs)=admodval(iobs)+tl_cg_pxsave(iobs)
883 END DO
884 DO iobs=1,ndatum(ng)
885!^ cg_pxsave(iobs)=ADmodVal(iobs)
886!<> tl_cg_pxsave(iobs)=tl_ADmodVal(iobs)
887!^
888 tl_cg_pxsave(iobs)=admodval(iobs)
889 END DO
890 END IF
891 ELSE
892 DO iobs=1,ndatum(ng)
893!^ ADmodVal(iobs)=zcglwk(iobs,innLoop+1,outLoop)
894!<> tl_ADmodVal(iobs)=tl_zcglwk(iobs,innLoop+1)
895!^
896 admodval(iobs)=tl_zcglwk(iobs,innloop+1)
897 END DO
898!
899! If preconditioning, convert ADmodVal from y-space to v-space.
900!
901!^ IF (Lprecond.and.(outLoop.gt.1)) THEN
902!^ Lscale=2 ! SQRT spectral LMP
903!^ Ltrans=.FALSE.
904!^ CALL rprecond (ng, Lscale, Ltrans, outLoop, NinnLoop, &
905!^ & ADmodVal)
906!^ END IF
907!^
908 END IF
909!
910! Convert ADmodVal from v-space to x-space.
911!
912 DO iobs=1,ndatum(ng)
913 IF (obserr(iobs).NE.0.0_r8) THEN
914!^ ADmodVal(iobs)=ADmodVal(iobs)/SQRT(ObsErr(iobs))
915!<> tl_ADmodVal(iobs)=tl_ADmodVal(iobs)/SQRT(ObsErr(iobs))
916!^
917 admodval(iobs)=admodval(iobs)/sqrt(obserr(iobs))
918 END IF
919 END DO
920 END IF
921
922 END IF master_thread
923
924# ifdef DISTRIBUTE
925!
926! Broadcast new solution to other nodes.
927!
928 CALL mp_bcasti (ng, model, exit_flag)
929 CALL mp_bcastf (ng, model, admodval)
930 CALL mp_bcastf (ng, model, tl_cg_qg(:))
931 CALL mp_bcastf (ng, model, tl_cg_gnorm(:))
932 CALL mp_bcastf (ng, model, tl_cg_pxsave(:))
933 CALL mp_bcastf (ng, model, tl_cg_innov(:))
934 CALL mp_bcastf (ng, model, tl_cg_beta(:))
935 CALL mp_bcastf (ng, model, tl_cg_delta(:))
936 CALL mp_bcastf (ng, model, tl_zcglwk(:,:))
937# endif
938!
939 RETURN
940 END SUBROUTINE tl_congrad
941#else
942 SUBROUTINE tl_congrad
943 RETURN
944 END SUBROUTINE tl_congrad
945#endif
real(dp), dimension(:), allocatable cg_gnorm_v
real(dp), dimension(:,:), allocatable cg_beta
real(r8), dimension(:), allocatable tl_obsval
integer, dimension(:), allocatable ndatum
real(r8), dimension(:,:), allocatable cg_dla
real(dp), dimension(:,:), allocatable cg_qg
real(r8), dimension(:), allocatable tl_cg_innov
real(dp), dimension(:), allocatable tl_cg_qg
real(r8), dimension(:), allocatable obsscale
real(r8), dimension(:), allocatable obserr
real(r8), dimension(:), allocatable tl_zgrad0
logical lhotstart
real(dp), dimension(:), allocatable tl_cg_delta
real(dp), dimension(:), allocatable cg_gnorm
real(r8), dimension(:,:), allocatable tl_zcglwk
real(dp), dimension(:), allocatable tl_cg_beta
real(r8), dimension(:), allocatable admodval
real(r8), dimension(:,:,:), allocatable zcglwk
real(r8), dimension(:), allocatable nlmodval
real(dp), dimension(:,:), allocatable cg_delta
real(r8), dimension(:), allocatable tl_cg_pxsave
real(r8), dimension(:,:), allocatable zgrad0
logical master
integer exit_flag
subroutine tl_congrad
Definition tl_congrad.F:943
subroutine tl_sqlq(innloop, a, tl_a, tau, tl_tau, y, tl_y)
Definition tl_sqlq.F:8