<HTML> <BODY BGCOLOR=#ccccdd LINK=#0000aa VLINK=#0000ff ALINK=#ff0000 ><BASE TARGET="bottom_target"><PRE>
<A NAME='DA_MINIMISE_LZ'><A href='../../html_code/minimisation/da_minimise_lz.inc.html#DA_MINIMISE_LZ' TARGET='top_target'><IMG SRC="../../gif/bar_red.gif" border=0></A>

subroutine da_minimise_lz(grid, config_flags,            &amp; 1,11
                           it, cv_size, xbx, be, iv,     &amp;
                           j_grad_norm_target, xhat, qhat, cv, &amp;
                           re, y, j_cost, eignvec, eignval, neign)

   !-------------------------------------------------------------------------
   ! Purpose:         Main Lanczos minimisation routine 
   !
   ! Here 
   !    cv   is updated in outer-loop.
   !    xhat is the control variable in inner-loop.
   !
   ! Called from da_solve
   !
   ! History: 07/30/2008  Creation (Tom Auligne)
   !
   ! Reference: Golub and Van Loan 1996 (p493)
   !
   !-------------------------------------------------------------------------

   implicit none

   type(domain), intent(inout)       :: grid
   type(grid_config_rec_type), intent(inout) :: config_flags
   integer, intent(in)               :: it                            ! external iteration.
   integer, intent(in)               :: cv_size                       ! Total cv size
   type (xbx_type),intent(inout)     :: xbx                           ! Header &amp; non-gridded vars.
   type (be_type), intent(in)        :: be                            ! background error structure.
   type (iv_type), intent(inout)     :: iv                            ! ob. increment vector.
   real, intent(inout)               :: j_grad_norm_target            ! Target norm.
   real, intent(out)                 :: xhat(1:cv_size)               ! control variable (local).
   real, intent(out)                 :: qhat(1:cv_size, 0:ntmax(it))  ! cv copy.
   real, intent(inout)               :: cv(1:cv_size)                 ! control variable (local).
   type (y_type), intent(inout)      :: re                            ! residual (o-a) structure.
   type (y_type), intent(inout)      :: y                             ! y = H(x_inc) structure.
   type (j_type), intent(out)        :: j_cost                        ! cost function
   real*8, intent(out)               :: eignvec(ntmax(it), ntmax(it))
   real*8, intent(out)               :: eignval(ntmax(it))
   integer, intent(out)              :: neign
   
   integer                           :: i, j, k, n, inst, iter
#ifdef CLOUD_CV
   integer                           :: mz(13), info, nsstwrk
#else
   integer                           :: mz(7), info, nsstwrk
#endif
   integer                           :: npred, ipred
   integer                           :: jp_start, jp_end       ! Start/end indices of Jp.
   real                              :: fhat(1:cv_size)        ! cv copy.
   real                              :: ghat(1:cv_size)        ! cv copy.
   real                              :: ghat0(1:cv_size)       ! cv copy.
   real                              :: shat(1:cv_size)        ! cv copy.
   real                              :: gdot, rho, mu, bndlm
   real                              :: alpha(ntmax(it)), beta(0:ntmax(it))
   real*8                            :: subdiag(ntmax(it))
   real                              :: c(cv_size), d(ntmax(it))
   real*8                            :: sstwrk(2*ntmax(it)-2)
   real                              :: bnds(ntmax(it))
   real                              :: adj_rhs, adj_sum_rhs ! &lt; cv, cv &gt;
   real                              :: j_total, j0_total
   real                              :: dfs, dfsmax
   
   if (trace_use) call da_trace_entry("da_minimise_lz")

   write(unit=stdout,fmt='(A)') 'Minimize cost function using Lanczos method'
   write(unit=stdout,fmt=*) ' '

   !-------------------------------------------------------------------------
   ! [1.0] Initialization:
   !-------------------------------------------------------------------------
#ifdef CLOUD_CV
   mz = (/ be%v1%mz, be%v2%mz, be%v3%mz, be%v4%mz, be%v5%mz,  be%v6%mz, be%v7%mz,  be%v8%mz, be%v9%mz, be%v10%mz, be%v11%mz, be%alpha%mz, be % ne /)
#else
   mz = (/ be%v1%mz, be%v2%mz, be%v3%mz, be%v4%mz, be%v5%mz,be%alpha%mz, be % ne /)
#endif   
   jp_start   = be % cv % size_jb + be % cv % size_je + 1
   jp_end     = be % cv % size_jb + be % cv % size_je + be % cv % size_jp
   
   call da_calculate_j(it, 0, cv_size, be%cv%size_jb, be%cv%size_je, be%cv%size_jp, &amp;
                       be%cv%size_jl, xbx, be, iv, xhat, cv, re, y, j_cost, ghat0, grid, config_flags)
 
   j0_total = j_cost%total
   if (j0_total == 0.0) then
      if (trace_use) call da_trace_exit("da_minimise_lz")
      return
   end if
   ghat      = - ghat0
   beta(0)   = SQRT(da_dot_cv(cv_size, ghat, ghat, grid, mz, jp_start, jp_end))
   qhat(:,0) = 0.0
   j_grad_norm_target = beta(0)

   write(unit=stdout,fmt='("Starting outer iteration : ",i3)') it
   write(unit=stdout,fmt=11) j0_total, beta(0),eps(it)
11 format('Starting cost function: ' ,1PD15.8,', Gradient: ',1PD15.8,/,&amp;
          'For this outer iteration, the targeted reduction is:       ',1PD15.8)
   write(unit=stdout,fmt='(A)') &amp;
      '----------------------------------------------------------'
   write(unit=stdout,fmt='(A)') 'Iter     Cost Function       Info Content'

   !-------------------------------------------------------------------------
   ! [2.0] Iteratively solve for minimum of cost function:
   !-------------------------------------------------------------------------
   do iter=1, ntmax(it)
      qhat(:,iter) = ghat / beta(iter-1)
      
      call da_calculate_gradj(it,iter,cv_size,be%cv%size_jb,be%cv%size_je,be%cv%size_jp, &amp;
                              be%cv%size_jl, xbx,be,iv,qhat(:,iter),y,fhat,grid,config_flags)
       
    ! Apply Lanczos recurrence and orthonormalize new gradient (using modified Gramm-Schmidt)
    !----------------------------------------------------------------------------------------
      alpha(iter) = da_dot_cv(cv_size, qhat(:,iter), fhat, grid, mz, jp_start, jp_end)

      ghat        = fhat - alpha(iter)*qhat(:,iter) - beta(iter-1)*qhat(:,iter-1)
      do i = iter, 1, -1
         gdot = da_dot_cv(cv_size, ghat, qhat(:,i), grid, mz, jp_start, jp_end)
         ghat = ghat - gdot * qhat(:,i)
      end do

      beta(iter)  = SQRT(da_dot_cv (cv_size, ghat, ghat, grid, mz, jp_start, jp_end))
      
    ! Lanczos iteration  
    !------------------
      if (iter == 1) then
         d(1) = alpha(1)
	 c    = qhat(:,1)
	 rho  = beta(0) / alpha(1)
	 xhat = rho * qhat(:,1)
         dfs  = da_dot_cv(cv_size, xhat, xhat, grid, mz, jp_start, jp_end)
         dfsmax = dfs
      else
         mu      = beta(iter-1) / d(iter-1)
	 d(iter) = alpha(iter) - beta(iter-1)*mu
	 c       = qhat(:,iter) - mu*c
	 rho     = - mu*d(iter-1)*rho / d(iter)
	 xhat    = xhat + rho*c
         dfs     = da_dot_cv(cv_size, rho*c, rho*c, grid, mz, jp_start, jp_end)
         if (dfs &gt; dfsmax) dfsmax = dfs
      end if
      
    ! Determine eigenvalues and eigenvectors of the Lanczos tri-diagonal matrix
    !--------------------------------------------------------------------------
      eignval(1:iter)   = alpha(1:iter)
      subdiag(1:iter-1) = beta(1:iter-1)
      nsstwrk           = MAX(2*iter-2,1)
      info              = 0
      call DSTEQR('I',iter,eignval(1:iter),subdiag(1:iter-1),eignvec(:,1:iter),ntmax(it),&amp;
	           sstwrk(1:nsstwrk),info)
      if (info /=0) write(stdout,*) 'Error in Lanczos minimization: SSTEQR returned ',info 
            
    ! Count converged eigenpairs (using Arnoldi relation)
    !----------------------------------------------------
      bndlm        = eps(it) * eignval(iter)  
      bnds(1:iter) = abs(beta(iter) * eignvec(iter,1:iter))
      neign        = COUNT(bnds(1:iter) &lt;= bndlm)
               
    ! Print Cost Function and Infomation Content
    !-----------------------------------
      j_total = j0_total + 0.5 * da_dot_cv(cv_size,ghat0,xhat,grid,mz,jp_start,jp_end)
      write(unit=stdout,fmt=12)iter, j_total, dfs      	 
12    format(i3,5x,1PD15.8,5x,1PD15.8)

    ! Stop minimization based on Information Content
    ! ----------------------------------------------
      if (sqrt(dfs) &lt; eps(it) * sqrt(dfsmax)) exit

    ! Option to calculate J Cost Function explicitly
    ! ----------------------------------------------
      if (calculate_cg_cost_fn) &amp;
         call da_calculate_j(it, iter, cv_size, be%cv%size_jb, be%cv%size_je, be%cv%size_jp, &amp;
	                     be%cv%size_jl, xbx, be, iv, xhat, cv, re, y, j_cost, fhat, grid, config_flags)
   end do

   !-------------------------------------------------------------------------
   ! End of the minimization of cost function
   !-------------------------------------------------------------------------
   iter = MIN(iter, ntmax(it))
   
   write(unit=stdout,fmt='(A)') &amp;
      '----------------------------------------------------------'
   write(unit=stdout,fmt='(A)') " "
   write(unit=stdout, fmt='("Inner iteration stopped after ",i4," iterations")') iter
   write(unit=stdout,fmt='(A)') " "

   call da_calculate_j(it, iter, cv_size, be%cv%size_jb, be%cv%size_je, be%cv%size_jp, &amp;
                       be%cv%size_jl, xbx, be, iv, xhat, cv, re, y, j_cost, ghat, grid, config_flags)

   write(unit=stdout,fmt=15) iter, j_cost%total , &amp;
                             SQRT(da_dot_cv(cv_size, ghat, ghat, grid, mz, jp_start, jp_end))
15  format('Final: ',I3,' iter, J=',1PD15.8,', g=',1PD15.8)
   write(unit=stdout,fmt='(A)') &amp;
      '----------------------------------------------------------'

   write(stdout,*) 'Ritz eigenvalues: ',eignval(iter:1:-1)     
   write(stdout,*) 'Number of converged eigenpairs: ', neign
   neign = iter

   if (trace_use) call da_trace_exit("da_minimise_lz")

end subroutine da_minimise_lz