UFO
ufo_rttovonedvarcheck_minimize_newton_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2020 Met Office
2 ! This software is licensed under the terms of the Apache Licence Version 2.0
3 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
4 
5 !> Fortran module to perform newton steepest descent minimization
6 
8 
9 use kinds
10 use ufo_constants_mod, only: zero
11 use fckit_log_module, only : fckit_log
21 use ufo_utils_mod, only: ops_cholesky
22 
23 implicit none
24 private
25 
26 ! public subroutines
28 
29 contains
30 
31 !------------------------------------------------------------------------------
32 !> Get the jacobian used in the 1D-Var.
33 !!
34 !! \details Heritage: Ops_SatRad_MinimizeNewton_RTTOV12.f90
35 !!
36 !! Find the most probable atmospheric state vector by minimizing a cost function
37 !! through a series of iterations. if a solution exists, the iterations will
38 !! converge when the iterative increments are acceptably small. A limit on the
39 !! total number of iterations allowed, is imposed.
40 !!
41 !! Using the formulation given by Rodgers (1976) :
42 !!
43 !! Delta_x = xn + (xb-xn).I' + Wn.(ym-y(xn) - H.(xb-xn)) <br>
44 !! where: <br> x is an atmospheric state vector, subscripted b=background,n=nth
45 !! iteration <br>
46 !! I' is a diagonal matrix with I'(J,J) = B_damped(J,J)/B_undamped(J,J)
47 !! although, however, damping will no longer be used <br>
48 !! Wn = B.Hn'.(Hn.B.Hn'+R)^-1 <br>
49 !! B is the background error covariance matrix <br>
50 !! R is the combined forward model and ob error covariance matrix <br>
51 !!
52 !! Delta_x is checked for convergence after each iteration
53 !!
54 !! The loop is exited with convergence if either of the following conditions are
55 !! true, depending on whether UseJforConvergence is true or false <br>
56 !! -# if UseJforConvergence is true then the change in total cost function from
57 !! one iteration to the next is sufficiently small to imply convergence
58 !! -# if UseJforConvergence is false then the increments to the atmospheric
59 !! state vector are sufficiently small to imply convergence at an acceptable
60 !! solution <br>
61 !! Either of the following two conditions will cause the 1dvar to stop and exit
62 !! with an error. <br>
63 !! -# The increments are sufficiently large to suppose a solution will not
64 !! be found.
65 !! -# The maximum number of allowed iterations has been reached. in most
66 !! cases, one of the above criteria will have occurred.
67 !!
68 !! References:
69 !!
70 !! Rodgers, Retrieval of atmospheric temperature and composition from
71 !! remote measurements of thermal radiation, Rev. Geophys.Sp.Phys. 14, 1976.
72 !!
73 !! Eyre, inversion of cloudy satellite sounding radiances by nonlinear
74 !! optimal estimation. I: Theory and simulation for TOVS,QJ,July 89.
75 !!
76 !! \author Met Office
77 !!
78 !! \date 09/06/2020: Created
79 !!
81  ob, &
82  r_matrix, &
83  b_matrix, &
84  b_inv, &
85  b_sigma, &
86  local_geovals, &
87  hofxdiags, &
88  rttov_simobs, &
89  profile_index, &
90  onedvar_success)
91 
92 implicit none
93 
94 type(ufo_rttovonedvarcheck), intent(inout) :: self !< Main 1D-Var object
95 type(ufo_rttovonedvarcheck_ob), intent(inout) :: ob !< satellite metadata
96 type(ufo_rttovonedvarcheck_rsubmatrix), intent(in) :: r_matrix !< observation error covariance
97 real(kind_real), intent(in) :: b_matrix(:,:) !< state error covariance
98 real(kind_real), intent(in) :: b_inv(:,:) !< inverse of the state error covariance
99 real(kind_real), intent(in) :: b_sigma(:) !< standard deviations of the state error covariance diagonal
100 type(ufo_geovals), intent(inout) :: local_geovals !< model data at obs location
101 type(ufo_geovals), intent(inout) :: hofxdiags !< model data containing the jacobian
102 type(ufo_radiancerttov), intent(inout) :: rttov_simobs
103 type(ufo_rttovonedvarcheck_profindex), intent(in) :: profile_index !< index array for x vector
104 logical, intent(out) :: onedvar_success !< convergence flag
105 
106 ! Local declarations:
107 character(len=*), parameter :: routinename = "ufo_rttovonedvarcheck_minimize_newton"
108 integer :: inversionstatus
109 logical :: outofrange
110 logical :: converged
111 logical :: error
112 integer :: iter
113 integer :: rterrorcode
114 integer :: nchans
115 integer :: nprofelements
116 real(kind_real) :: jcost ! current value
117 real(kind_real) :: jcostold ! previous iteration value
118 real(kind_real) :: jcostorig ! initial value
119 real(kind_real) :: deltaj
120 real(kind_real) :: deltajo
121 
122 real(kind_real), allocatable :: oldprofile(:)
123 real(kind_real), allocatable :: guessprofile(:)
124 real(kind_real), allocatable :: backprofile(:)
125 real(kind_real), allocatable :: h_matrix(:,:)
126 real(kind_real), allocatable :: diffprofile(:)
127 real(kind_real), allocatable :: absdiffprofile(:)
128 real(kind_real), allocatable :: xdiff(:)
129 real(kind_real), allocatable :: ydiff(:)
130 real(kind_real), allocatable :: y(:)
131 real(kind_real), allocatable :: y0(:)
132 real(kind_real), allocatable :: out_h_matrix(:,:)
133 real(kind_real), allocatable :: out_y(:)
134 type(ufo_geovals) :: geovals
135 real(kind_real) :: jout(3)
136 
137 integer :: ii, jj
138 
139 ! ---------
140 ! Setup
141 ! ---------
142 converged = .false.
143 onedvar_success = .false.
144 error = .false.
145 nchans = size(ob % channels_used)
146 inversionstatus = 0
147 nprofelements = profile_index % nprofelements
148 allocate(oldprofile(nprofelements))
149 allocate(guessprofile(nprofelements))
150 allocate(backprofile(nprofelements))
151 allocate(h_matrix(nchans,nprofelements))
152 allocate(diffprofile(nprofelements))
153 allocate(absdiffprofile(nprofelements))
154 allocate(xdiff(nprofelements))
155 allocate(ydiff(nchans))
156 allocate(y(nchans))
157 allocate(y0(nchans))
158 geovals = local_geovals
159 
160 if (self % FullDiagnostics) call ufo_geovals_print(geovals,1)
161 call fckit_log % debug("Using Newton solver")
162 
163 jcost = 1.0e4_kind_real
164 
165 iterations: do iter = 1, self % max1DVarIterations
166 
167  !-------------------------
168  ! 1. Generate new profile
169  !-------------------------
170  ! Save cost from previous iteration
171  if (self % UseJForConvergence) then
172  jcostold = jcost
173  end if
174 
175  ! initialise RTerrorcode and profile increments on first iteration
176  if (iter == 1) then
177 
178  rterrorcode = 0
179  diffprofile(:) = zero
180  jcostold = 1.0e4_kind_real
181 
182  ! Map GeovaLs to 1D-var profile using B matrix profile structure
183  call ufo_rttovonedvarcheck_geovals2profvec(geovals, profile_index, &
184  ob, guessprofile(:))
185 
186  if (self % FullDiagnostics) &
187  write(*,*) "Humidity GuessProfile 1st iteration = ",guessprofile(profile_index % qt(1):profile_index % qt(2))
188 
189  end if
190 
191  ! Save current profile
192  oldprofile(:) = guessprofile(:)
193 
194  ! Get jacobian and hofx
195  call ufo_rttovonedvarcheck_get_jacobian(self, geovals, ob, ob % channels_used, &
196  profile_index, guessprofile(:), &
197  hofxdiags, rttov_simobs, y(:), h_matrix)
198 
199  if (iter == 1) then
200  backprofile(:) = guessprofile(:)
201  y0(:) = y(:)
202  do ii = 1, size(ob % channels_all)
203  do jj = 1, size(ob % channels_used)
204  if (ob % channels_all(ii) == ob % channels_used(jj)) then
205  ob % background_BT(ii) = y0(jj)
206  end if
207  end do
208  end do
209  end if
210 
211  ! exit on error
212  if (rterrorcode /= 0) then
213  write(*,*) "Radiative transfer error"
214  exit iterations
215  end if
216 
217  !-----------------------------------------------------
218  ! 1a. if UseJForConvergence is true
219  ! then compute costfunction for latest profile
220  ! and determine convergence using change in cost fn
221  !-----------------------------------------------------
222 
223  ! Profile differences
224  xdiff(:) = guessprofile(:) - backprofile(:)
225  ydiff(:) = ob % yobs(:) - y(:)
226 
227  if (self % FullDiagnostics) then
228  write(*,*) "Ob BT = "
229  write(*,'(10F10.3)') ob % yobs(:)
230  write(*,*) "HofX BT = "
231  write(*,'(10F10.3)') y(:)
232  end if
233 
234  if (self % UseJForConvergence) then
235 
236  call ufo_rttovonedvarcheck_costfunction(xdiff, b_inv, ydiff, r_matrix, jout)
237  jcost = jout(1)
238 
239  ! exit on error
240  if (inversionstatus /= 0) exit iterations
241 
242  ! store initial cost value
243  if (iter == 1) jcostorig = jcost
244 
245  ! check for convergence
246  if (iter > 1) then
247 
248  if (self % JConvergenceOption == 1) then
249 
250  ! percentage change tested between iterations
251  deltaj = abs((jcost - jcostold) / max(jcost, tiny(zero)))
252 
253  ! default test for checking that overall cost is getting smaller
254  deltajo = -1.0_kind_real
255 
256  else
257 
258  ! absolute change tested between iterations
259  deltaj = abs(jcost - jcostold)
260 
261  ! change between current cost and initial
262  deltajo = jcost - jcostorig
263 
264  end if
265 
266  if (self % FullDiagnostics) THEN
267  write (*, '(A,F12.5)') 'Cost Function = ', jcost
268  write (*, '(A,F12.5)') 'Cost Function old = ', jcostold
269  write (*, '(A,F12.5)') 'Cost Function Increment = ', deltaj
270  end if
271 
272  if (deltaj < self % cost_convergencefactor .and. &
273  deltajo < zero) then ! overall is cost getting smaller?
274  converged = .true.
275  if (self % FullDiagnostics) then
276  write (*, '(A,I0)') 'Iteration', iter
277  write (*, '(A)') '------------'
278  write (*, '(A,L1)') 'Status: converged = ', converged
279  write (*, '(A)') 'New profile:'
280  call ufo_geovals_print(geovals, 1)
281  write (*, '(A)')
282  write (*, '(A,3F12.5)') 'Cost Function, increment, cost_convergencefactor = ', &
283  jcost, deltaj, self % cost_convergencefactor
284  end if
285  exit iterations
286  end if
287 
288  end if
289 
290  end if ! end of specific code for cost test convergence
291 
292  ! Iterate (Guess) profile vector
293  if (nchans > nprofelements) then
294  call fckit_log % debug("Many Chans")
296  nchans, &
297  h_matrix(:,:), & ! in
298  transpose(h_matrix(:,:)), & ! in
299  nprofelements, &
300  diffprofile, &
301  b_inv, &
302  r_matrix, &
303  inversionstatus)
304  else ! nchans <= nprofelements
305  call fckit_log % debug("Few Chans")
307  nchans, &
308  h_matrix(:,:), & ! in
309  transpose(h_matrix(:,:)), & ! in
310  nprofelements, &
311  diffprofile, &
312  b_matrix, &
313  r_matrix, &
314  inversionstatus)
315 
316  if (self % FullDiagnostics) then
317  write(*,*) "After newton fewchans start"
318  call ufo_rttovonedvarcheck_printiterinfo(ob % yobs(:), y(:), &
319  ob % channels_used, guessprofile, &
320  backprofile, diffprofile, b_inv, h_matrix )
321  write(*,*) "After newton fewchans finish"
322  end if
323 
324  end if
325 
326  if (inversionstatus /= 0) then
327  inversionstatus = 1
328  write(*,*) "inversion failed"
329  exit iterations
330  end if
331 
332  guessprofile(:) = backprofile(:) + diffprofile(:)
333 
334  !---------------------------------------------------------
335  ! 2. Check new profile and transfer to forward model format
336  !---------------------------------------------------------
337 
338  ! Check profile and constrain humidity variables
339  call ufo_rttovonedvarcheck_checkiteration (self, & ! in
340  geovals, & ! in
341  profile_index, & ! in
342  guessprofile(:), & ! inout
343  outofrange) ! out
344 
345  ! Update geovals with guess profile
346  call ufo_rttovonedvarcheck_profvec2geovals(geovals, profile_index, &
347  ob, guessprofile, self % UseQtSplitRain)
348 
349  ! if qtotal in retrieval vector check cloud
350  ! variables for current iteration
351 
352  if ((.NOT. outofrange) .and. profile_index % qt(1) > 0) then
353 
354  if (iter >= self % IterNumForLWPCheck) then
355 
356  call ufo_rttovonedvarcheck_checkcloudyiteration( geovals, & ! in
357  profile_index, & ! in
358  self % nlevels, & ! in
359  outofrange ) ! out
360 
361  end if
362 
363  end if
364 
365  !-------------------------------------------------
366  ! 3. Check for convergence using change in profile
367  ! This is performed if UseJforConvergence is false
368  !-------------------------------------------------
369 
370  absdiffprofile(:) = zero
371 
372  if ((.NOT. outofrange) .and. (.NOT. self % UseJForConvergence))then
373  absdiffprofile(:) = abs(guessprofile(:) - oldprofile(:))
374  if (all(absdiffprofile(:) <= b_sigma(:) * self % ConvergenceFactor)) then
375  call fckit_log % debug("Profile used for convergence")
376  converged = .true.
377  end if
378  end if
379 
380  !---------------------
381  ! 4. output diagnostics
382  !---------------------
383 
384  if (self % FullDiagnostics) then
385  write (*, '(A,I0)') 'Iteration', iter
386  write (*, '(A)') '------------'
387  write (*, '(A,L1)') 'Status: converged = ', converged
388  if (outofrange) write (*, '(A)') 'exiting with bad increments'
389  write (*, '(A)') 'New profile:'
390  call ufo_geovals_print(geovals, 1)
391  write (*, '(A)')
392  end if
393 
394  ! exit conditions
395 
396  if (converged .OR. outofrange) exit iterations
397 
398 end do iterations
399 
400 ! Pass convergence flag out
401 onedvar_success = converged
402 
403 ! Recalculate final cost - to make sure output when profile has not converged
404 call ufo_rttovonedvarcheck_costfunction(xdiff, b_inv, ydiff, r_matrix, jout)
405 ob % final_cost = jout(1)
406 ob % niter = iter
407 ob % final_bt_diff = ydiff
408 
409 ! Pass output profile, final BTs and final cost out
410 if (converged) then
411  ob % output_profile(:) = guessprofile(:)
412 
413  ! If lwp output required then recalculate
414  if (self % Store1DVarLWP) then
415  call ufo_rttovonedvarcheck_checkcloudyiteration( geovals, & ! in
416  profile_index, & ! in
417  self % nlevels, & ! in
418  outofrange, & ! out
419  outlwp = ob % LWP ) ! out
420  end if
421 
422  ! Recalculate final BTs for all channels
423  allocate(out_h_matrix(size(ob % channels_all),nprofelements))
424  allocate(out_y(size(ob % channels_all)))
425  call ufo_rttovonedvarcheck_get_jacobian(self, geovals, ob, ob % channels_all, &
426  profile_index, guessprofile(:), &
427  hofxdiags, rttov_simobs, out_y(:), out_h_matrix)
428  ob % output_BT(:) = out_y(:)
429  deallocate(out_y)
430  deallocate(out_h_matrix)
431 end if
432 
433 !---------------------
434 ! 4. output diagnostics
435 !---------------------
436 
437 if (self % UseJForConvergence .and. self % FullDiagnostics) then
438  write(*,'(A70,3F10.3,I5,2L5)') "Newton J initial, final, lowest, iter, converged, outofrange = ", &
439  jcostorig, jcost, jcost, iter, onedvar_success, outofrange
440 end if
441 
442 ! ----------
443 ! Tidy up
444 ! ----------
445 if (allocated(oldprofile)) deallocate(oldprofile)
446 if (allocated(guessprofile)) deallocate(guessprofile)
447 if (allocated(backprofile)) deallocate(backprofile)
448 if (allocated(h_matrix)) deallocate(h_matrix)
449 if (allocated(diffprofile)) deallocate(diffprofile)
450 if (allocated(absdiffprofile)) deallocate(absdiffprofile)
451 if (allocated(xdiff)) deallocate(xdiff)
452 if (allocated(ydiff)) deallocate(ydiff)
453 if (allocated(y)) deallocate(y)
454 if (allocated(y0)) deallocate(y0)
455 
456 call fckit_log % debug("finished with ufo_rttovonedvarcheck_minimize_newton")
457 
459 
460 !------------------------------------------------------------------------------
461 !> Update the profile if newber of channels is less than number of elements in
462 !! the profile
463 !!
464 !! \details Heritage: Ops_SatRad_NewtonFewChans.f90
465 !!
466 !! Updates the profile vector DeltaProfile according to Rodgers (1976), Eqn. 101:
467 !!
468 !! x_(n+1) = xb + B.Hn'.Q <br>
469 !! Q = U^-1.V <br>
470 !! where: <br> x is an atmospheric state vector, subscripted b=background,n=nth
471 !! iteration <br>
472 !! U = (Hn.B.Hn'+R) <br>
473 !! V = (ym-y(xn) - H.(xb-xn)) <br>
474 !! ym is the measurement vector (i.e. observed brightness temperatures) <br>
475 !! y(xn) is the observation vector calculated for xn <br>
476 !! ym and y(xn) are not used individually at all, hence these are input
477 !! as a difference vector DeltaBT. <br>
478 !! B is the background error covariance matrix <br>
479 !! R is the combined forward model and ob error covariance matrix <br>
480 !! H is the forward model gradient (w.r.t. xn) matrix <br>
481 !! H' is the transpose of H <br>
482 !!
483 !! Q = U^-1.V is solved by Cholesky decomposition.
484 !!
485 !! This routine should be used when: <br>
486 !! -# The length of the observation vector is less than the length
487 !! of the state vector.
488 !!
489 !! Note on input/output variable DeltaProfile:
490 !!
491 !! On input, DeltaProfile is x(n-1)-xb. <br>
492 !! in construction of variable v, the sign is reversed: <br>
493 !! V = (ym-y(xn) + H.(xn-xb)) -- see equation in description above. <br>
494 !! On output, DeltaProfile is xn-xb and should be ADDED to the background
495 !! profile
496 !!
497 !! References:
498 !!
499 !! Rodgers, Retrieval of atmospheric temperature and composition from
500 !! remote measurements of thermal radiation, Rev. Geophys.Sp.Phys. 14, 1976.
501 !!
502 !! Rodgers, inverse Methods for Atmospheres: Theory and Practice. World
503 !! Scientific Publishing, 2000.
504 !!
505 !! \author Met Office
506 !!
507 !! \date 09/06/2020: Created
508 !!
510  nChans, &
511  H_Matrix, &
512  H_Matrix_T, &
513  nprofelements, &
514  DeltaProfile, &
515  B_matrix, &
516  r_matrix, &
517  Status)
518 
519 implicit none
520 
521 ! subroutine arguments:
522 real(kind_real), intent(in) :: DeltaBT(:) !< y-y(x)
523 integer, intent(in) :: nChans !< number of channels
524 real(kind_real), intent(in) :: H_Matrix(:,:) !< Jacobian
525 real(kind_real), intent(in) :: H_Matrix_T(:,:) !< (Jacobian)^T
526 integer, intent(in) :: nprofelements !< number of elements in x profile
527 real(kind_real), intent(inout) :: DeltaProfile(:) !< x-xb
528 real(kind_real), intent(in) :: B_matrix(:,:) !< state error covariance
529 type(ufo_rttovonedvarcheck_rsubmatrix), intent(in) :: r_matrix !< observation error covariance
530 integer, intent(out) :: Status !< check if Cholesky decomposition fails
531 
532 ! Local declarations:
533 character(len=*), parameter :: RoutineName = "ufo_rttovonedvarcheck_NewtonFewChans"
534 integer :: Element
535 integer :: i
536 real(kind_real) :: HB(nChans,nprofelements) ! Scratch vector
537 real(kind_real) :: Q(nChans) ! Q = U^-1.V
538 real(kind_real) :: U(nChans,nChans) ! U = H.B.H^T + R
539 real(kind_real) :: V(nChans) ! V = (y-y(x_n))-H^T(xb-x_n)
540 
541 status = 0
542 
543 !---------------------------------------------------------------------------
544 ! 1. Calculate the U and V vectors for the three forms of R matrix allowed
545 ! for.
546 !---------------------------------------------------------------------------
547 hb = matmul(h_matrix, b_matrix)
548 u = matmul(hb, h_matrix_t)
549 
550 ! Plus sign is not in error - it reverses sign of DeltaProfile to change
551 ! from xn-xb to xb-xn
552 
553 v = deltabt + matmul(h_matrix, deltaprofile)
554 
555 !---------------------------------------------------------------------------
556 ! 1.1. Add the R matrix into the U matrix. U = U + R
557 !---------------------------------------------------------------------------
558 !U = U + R_Matrix
559 call r_matrix % add_to_matrix(u, u)
560 
561 ! Calculate Q=(U^-1).V
562 !------
563 
564 call ops_cholesky (u, &
565  v, &
566  nchans, &
567  q, &
568  status)
569 if (status /= 0) goto 9999
570 
571 ! Delta profile is (HB)^T.Q
572 !------
573 
574 deltaprofile = matmul(transpose(hb), q)
575 
576 9999 continue
578 
579 !------------------------------------------------------------------------------
580 !> Update the profile if number of channels is more than number of elements in
581 !! the profile
582 !!
583 !! \details Heritage: Ops_SatRad_NewtonManyChans.f90
584 !!
585 !! Updates the profile vector Delta_Profile according to Rodgers (1976), Eqn.
586 !! 100, extended to allow for additional cost function terms.
587 !!
588 !! x_(n+1) = xb + U^-1.V <br>
589 !! where <br> U=(B^-1 + H^T R^-1 H + J2) <br>
590 !! V=H^T R^-1 [(ym-y(x_n))+H(x_n-xb)] - J1 <br>
591 !! and <br> J_extra=J0+J1.(x-xb)+(x-xb)^T.J2.(x-xb) is the additional cost
592 !! function <br>
593 !! x is an atmospheric state vector, subscripted b=background,n=nth
594 !! iteration <br>
595 !! ym is the measurement vector (i.e. observed brightness temperatures) <br>
596 !! y(xn) is the observation vector calculated for xn <br>
597 !! ym and y(xn) are not used individually at all, hence these are input
598 !! as a difference vector DeltaBT. <br>
599 !! B is the background error covariance matrix <br>
600 !! R is the combined forward model and ob error covariance matrix <br>
601 !! H is the forward model gradient (w.r.t. xn) matrix <br>
602 !! H' is the transpose of H <br>
603 !!
604 !! When J_extra is zero this is simply Rogers (1976), Eqn. 100.
605 !!
606 !! U^-1.V is solved using Cholesky decomposition.
607 !!
608 !! This routine should be used when:
609 !! -# The length of the observation vector is greater than the length
610 !! of the state vector
611 !!
612 !! References:
613 !!
614 !! Rodgers, Retrieval of atmospheric temperature and composition from
615 !! remote measurements of thermal radiation, Rev. Geophys.Sp.Phys. 14, 1976.
616 !!
617 !! Rodgers, inverse Methods for Atmospheres: Theory and Practice. World
618 !! Scientific Publishing, 2000.
619 !!
620 !! \author Met Office
621 !!
622 !! \date 09/06/2020: Created
623 !!
625  nChans, &
626  H_Matrix, &
627  H_Matrix_T, &
628  nprofelements, &
629  DeltaProfile, &
630  B_inverse, &
631  r_matrix, &
632  Status)
633 
634 implicit none
635 
636 ! subroutine arguments:
637 real(kind_real), intent(in) :: DeltaBT(:) !< y-y(x)
638 integer, intent(in) :: nChans !< number of channels
639 real(kind_real), intent(in) :: H_Matrix(:,:) !< Jacobian
640 real(kind_real), intent(in) :: H_Matrix_T(:,:) !< (Jacobian)^T
641 integer, intent(in) :: nprofelements !< number of elements in profile vector
642 real(kind_real), intent(inout) :: DeltaProfile(:) !< x-xb
643 real(kind_real), intent(in) :: B_inverse(:,:) !< inverse state error covariance
644 type(ufo_rttovonedvarcheck_rsubmatrix), intent(in) :: r_matrix !< observation error covariance
645 integer, intent(out) :: Status !< check if Cholesky decomposition fails
646 
647 ! Local declarations:
648 character(len=*), parameter :: RoutineName = 'ufo_rttovonedvarcheck_NewtonManyChans'
649 real(kind_real) :: HTR(nprofelements, nChans) ! Scratch vector
650 real(kind_real) :: U(nprofelements, nprofelements) ! U = H.B.H^T + R
651 real(kind_real) :: V(nprofelements) ! V = (y-y(x_n))-H^T(xb-x_n)
652 
653 status = 0
654 
655 !---------------------------------------------------------------------------
656 ! 1. Calculate HTR for the three allowed forms of R matrix. if required, the
657 ! matrix is tested to determine whether it is stored as an inverse and
658 ! inverted if not.
659 !---------------------------------------------------------------------------
660 !HTR = matmul(H_matrix_T, R_inverse)
661 call r_matrix % multiply_inverse_matrix(h_matrix_t,htr)
662 
663 !---------------------------------------------------------------------------
664 ! 2. Calculate U and V
665 !---------------------------------------------------------------------------
666 
667 u = matmul(htr, h_matrix)
668 v = matmul(htr, deltabt)
669 v = v + matmul(u, deltaprofile)
670 
671 !---------------------------------------------------------------------------
672 ! 3. Add on inverse of B-matrix to U.
673 !---------------------------------------------------------------------------
674 
675 u = u + b_inverse
676 
677 !---------------------------------------------------------------------------
678 ! 5. Calculate new profile increment.
679 !---------------------------------------------------------------------------
680 
681 call ops_cholesky (u, &
682  v, &
683  nprofelements, &
684  deltaprofile, &
685  status)
686 
688 
689 !---------------------------------------------------
690 
real(kind_real), parameter, public zero
subroutine, public ufo_geovals_print(self, iobs)
Fortran module for radiancerttov observation operator.
Fortran module constants used throughout the rttovonedvarcheck filter.
Fortran module to get the jacobian for the 1D-Var.
subroutine, public ufo_rttovonedvarcheck_get_jacobian(self, geovals, ob, channels, profindex, prof_x, hofxdiags, rttov_simobs, hofx, H_matrix)
Get the jacobian used in the 1D-Var.
Fortran module to perform newton steepest descent minimization.
subroutine ufo_rttovonedvarcheck_newtonfewchans(DeltaBT, nChans, H_Matrix, H_Matrix_T, nprofelements, DeltaProfile, B_matrix, r_matrix, Status)
Update the profile if newber of channels is less than number of elements in the profile.
subroutine, public ufo_rttovonedvarcheck_minimize_newton(self, ob, r_matrix, b_matrix, b_inv, b_sigma, local_geovals, hofxdiags, rttov_simobs, profile_index, onedvar_success)
Get the jacobian used in the 1D-Var.
subroutine ufo_rttovonedvarcheck_newtonmanychans(DeltaBT, nChans, H_Matrix, H_Matrix_T, nprofelements, DeltaProfile, B_inverse, r_matrix, Status)
Update the profile if number of channels is more than number of elements in the profile.
Fortran module containing subroutines used by both minimizers.
subroutine, public ufo_rttovonedvarcheck_geovals2profvec(geovals, profindex, ob, prof_x)
Copy geovals data (and ob) to profile.
subroutine, public ufo_rttovonedvarcheck_checkiteration(self, geovals, profindex, profile, OutOfRange)
Constrain profile humidity and check temperature values are okay.
subroutine, public ufo_rttovonedvarcheck_profvec2geovals(geovals, profindex, ob, prof_x, UseQtsplitRain)
Copy profile data to geovals (and ob).
subroutine, public ufo_rttovonedvarcheck_printiterinfo(yob, hofx, channels, guessprofile, backprofile, diffprofile, binv, hmatrix)
Print detailed information for each iteration for diagnostics.
subroutine, public ufo_rttovonedvarcheck_checkcloudyiteration(geovals, profindex, nlevels_1dvar, OutOfRange, OutLWP)
Check cloud during iteration.
subroutine, public ufo_rttovonedvarcheck_costfunction(DeltaProf, b_inv, DeltaObs, r_matrix, Jcost)
Calculate the cost function.
Fortran module which contains the observation metadata for a single observation.
Fortran module containing profile index.
Fortran derived type to hold data for the observation covariance.
Fortran module containing main type, setup and utilities for the main rttovonedvarcheck object.
Fortran module with various useful routines.
subroutine, public ops_cholesky(U, V, N, Q, ErrorCode)
Do cholesky decomposition.
type to hold interpolated fields required by the obs operators
Fortran derived type for the observation type.