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

  subroutine da_varbc_precond (iv) 1,3

   !---------------------------------------------------------------------------
   !  PURPOSE:  Calculate covariance matrix b/w bias predictors 
   !            for VarBC preconditioning
   !
   !  Called from da_get_innov_vector_radiance
   !
   !  HISTORY: 11/07/2007 - Creation                     Tom Auligne
   !---------------------------------------------------------------------------

   implicit none

   type (iv_type), intent (inout)   :: iv             ! Innovation

   integer                          :: inst, n, i, j, k, ii, jj
   integer                          :: npred, npredmax, num_rad, num_rad_active
   real, allocatable 		    :: hessian(:,:)
   real*8, allocatable 		    :: eignvec(:,:), eignval(:)
   real                             :: hessian_local, bgerr_local, pred_i, pred_j
   
   if ( iv%num_inst &lt; 1 ) RETURN

   if (trace_use) call da_trace_entry("da_varbc_precond")
   
   write(unit=stdout,fmt='(A)') 'VARBC: Estimate Hessian for preconditioning'

   do inst = 1, iv%num_inst      ! loop for sensors
      npredmax = iv%instid(inst)%varbc_info%npredmax
 
      allocate ( hessian(npredmax, npredmax) )
      allocate ( eignvec(npredmax, npredmax) )
      allocate ( eignval(npredmax)           )

      do k = 1, iv%instid(inst)%nchan         ! loop for channels
         npred = iv%instid(inst)%varbc(k)%npred
         if (npred   &lt;= 0) cycle              ! VarBC channel only     

         num_rad        = iv%instid(inst)%num_rad
         if (num_rad &gt; 0) then
            num_rad_active = COUNT( (iv%instid(inst)%info%proc_domain(1,1:num_rad)) &amp;
                               .AND.(iv%instid(inst)%tb_qc(k,1:num_rad) &gt; qc_varbc_bad) )
         else
            num_rad_active = 0
         end if
         iv%instid(inst)%varbc(k)%nobs  = wrf_dm_sum_integer(num_rad_active)
	    
         if ( satinfo(inst)%iuse(k) == 1 ) &amp;
            write(unit=stdout,fmt='(A,I6,3A,I5)') &amp;
	    'VARBC:',iv%instid(inst)%varbc(k)%nobs,' active observations for ', &amp;
            trim(adjustl(iv%instid(inst)%rttovid_string)),' channel',           &amp;
	    iv%instid(inst)%ichan(k)
	    
         if (iv%instid(inst)%varbc(k)%nobs == 0) cycle
	 
        !---------------------------------------------------------	 
	! Calculate estimation of the Hessian for preconditioning
        !---------------------------------------------------------	 
         do i = 1, npred
	    ii = iv%instid(inst)%varbc(k)%ipred(i)

	   ! Observation term
           !------------------		 
            do j = i, npred
	       jj = iv%instid(inst)%varbc(k)%ipred(j)
	       hessian_local = 0.0	
	       
               do n= 1, num_rad      ! loop for pixel      
                  if (iv%instid(inst)%tb_qc(k,n) &lt;= qc_varbc_bad)   cycle  ! good obs only
	          if (.not. iv%instid(inst)%info%proc_domain(1,n))  cycle  ! do not sum up HALO data
		  
		  if (ii == iv%instid(inst)%varbc_info%gammapred) then
		     pred_i = iv%instid(inst)%gamma_jacobian(k,n)
		  else
   	    	     pred_i = iv%instid(inst)%varbc_info%pred(ii,n)
		  end if   

		  if (jj == iv%instid(inst)%varbc_info%gammapred) then
		     pred_j = iv%instid(inst)%gamma_jacobian(k,n)
		  else
		     pred_j = iv%instid(inst)%varbc_info%pred(jj,n)		  
		  end if   
			      
       	          hessian_local = hessian_local + pred_i * pred_j / &amp;
	                          iv%instid(inst)%tb_error(k,n)**2				     
               end do                                               !  end loop for pixel
	       
	       ! Sum hessian preconditioning across processors
               hessian(i,j) = wrf_dm_sum_real(hessian_local)	
	       hessian(j,i) = hessian(i,j)  	       
	    end do
         
	   ! Background term
           !-----------------
            if (iv%instid(inst)%varbc_info%nbgerr(ii) &lt;= 0) cycle
	    bgerr_local = 0.0
	    do n= 1, num_rad    
               if (iv%instid(inst)%tb_qc(k,n) &lt;= qc_varbc_bad)   cycle  ! good obs only
               if (.not. iv%instid(inst)%info%proc_domain(1,n))  cycle  ! do not sum up HALO data

   	       bgerr_local = bgerr_local + iv%instid(inst)%tb_error(k,n)**2  / &amp;
                                             varbc_nbgerr
	                                   ! iv%instid(inst)%varbc_info%nbgerr(ii)
	    end do

            iv%instid(inst)%varbc(k)%bgerr(i) = wrf_dm_sum_real(bgerr_local) / &amp;
	                                        iv%instid(inst)%varbc(k)%nobs

	    if (iv%instid(inst)%varbc(k)%bgerr(i) &gt; 0) &amp;          
   	       hessian(i,i) = hessian(i,i) + 1/iv%instid(inst)%varbc(k)%bgerr(i)
	 end do   

        !--------------------------------------------------	 
	! Preconditioning = inverse square root of Hessian
        !--------------------------------------------------	 	 
         hessian = hessian / varbc_factor**2
	 
	 if (npred == 1) then
	    iv%instid(inst)%varbc(k)%vtox(1,1)     = 1.0 / sqrt(hessian(1,1))
         else 
	    call da_eof_decomposition(npred, hessian(1:npred,1:npred), &amp;
	    	            eignvec(1:npred,1:npred),eignval(1:npred))

	    if (ANY(eignval(1:npred) &lt;= 0)) then		    
	       write(unit=stdout,fmt='(3A,I4,A,10F18.5)') &amp;
	       'VARBC: non-positive Hessian for ', iv%instid(inst)%rttovid_string, &amp;
	              ' ,channel ',k,'--&gt; Eigenvalues =',eignval(1:npred) 
	       do i = 1, npred
	          if (hessian(i,i) &gt; 0) &amp;
	             iv%instid(inst)%varbc(k)%vtox(i,i) = 1.0 / sqrt(hessian(i,i))
	       end do
	    else
 	       do i = 1, npred
	          do j = i, npred
                     iv%instid(inst)%varbc(k)%vtox(i,j) = sum(          &amp;
		                           eignvec(i,1:npred)         * &amp;
			                   sqrt(1.0/eignval(1:npred)) * &amp;
			                   eignvec(j,1:npred) )
		       
		     iv%instid(inst)%varbc(k)%vtox(j,i) = &amp;
          	     iv%instid(inst)%varbc(k)%vtox(i,j)
                  end do
	       end do
	    end if
	 end if   
      end do                     !  end loop for channels	
      deallocate(hessian, eignvec, eignval)   
   end do                        !  end loop for sensor


   if (trace_use) call da_trace_exit("da_varbc_precond")

 end subroutine da_varbc_precond