LCOV - code coverage report
Current view: top level - chemistry/pp_none - mo_imp_sol.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 120 0.0 %
Date: 2024-12-17 17:57:11 Functions: 0 2 0.0 %

          Line data    Source code
       1             : module mo_imp_sol
       2             :   use shr_kind_mod, only : r8 => shr_kind_r8
       3             :   use chem_mods, only : clscnt4, gas_pcnst, clsmap
       4             :   use cam_logfile, only : iulog
       5             :   implicit none
       6             :   private
       7             :   public :: imp_slv_inti, imp_sol
       8             :   save
       9             :   real(r8), parameter :: rel_err = 1.e-3_r8
      10             :   real(r8), parameter :: high_rel_err = 1.e-4_r8
      11             :   !-----------------------------------------------------------------------
      12             :   ! Newton-Raphson iteration limits
      13             :   !-----------------------------------------------------------------------
      14             :   integer, parameter :: itermax = 11
      15             :   integer, parameter :: cut_limit = 5
      16             :   real(r8), parameter :: small = 1.e-40_r8
      17             :   real(r8) :: epsilon(clscnt4)
      18             :   logical :: factor(itermax)
      19             : contains
      20           0 :   subroutine imp_slv_inti
      21             :     !-----------------------------------------------------------------------
      22             :     ! ... Initialize the implict solver
      23             :     !-----------------------------------------------------------------------
      24             :     use mo_chem_utls, only : get_spc_ndx
      25             :     implicit none
      26             :     !-----------------------------------------------------------------------
      27             :     ! ... Local variables
      28             :     !-----------------------------------------------------------------------
      29             :     integer :: m, ox_ndx, o3a_ndx
      30             :     real(r8) :: eps(gas_pcnst)
      31           0 :     factor(:) = .true.
      32             :     eps(:) = rel_err
      33           0 :     ox_ndx = get_spc_ndx( 'OX' )
      34           0 :     if( ox_ndx < 1 ) then
      35           0 :        ox_ndx = get_spc_ndx( 'O3' )
      36             :     end if
      37           0 :     if( ox_ndx > 0 ) then
      38           0 :        eps(ox_ndx) = high_rel_err
      39             :     end if
      40           0 :     m = get_spc_ndx( 'NO' )
      41           0 :     if( m > 0 ) then
      42           0 :        eps(m) = high_rel_err
      43             :     end if
      44           0 :     m = get_spc_ndx( 'NO2' )
      45           0 :     if( m > 0 ) then
      46           0 :        eps(m) = high_rel_err
      47             :     end if
      48           0 :     m = get_spc_ndx( 'NO3' )
      49           0 :     if( m > 0 ) then
      50           0 :        eps(m) = high_rel_err
      51             :     end if
      52           0 :     m = get_spc_ndx( 'HNO3' )
      53           0 :     if( m > 0 ) then
      54           0 :        eps(m) = high_rel_err
      55             :     end if
      56           0 :     m = get_spc_ndx( 'HO2NO2' )
      57           0 :     if( m > 0 ) then
      58           0 :        eps(m) = high_rel_err
      59             :     end if
      60           0 :     m = get_spc_ndx( 'N2O5' )
      61           0 :     if( m > 0 ) then
      62           0 :        eps(m) = high_rel_err
      63             :     end if
      64           0 :     m = get_spc_ndx( 'OH' )
      65           0 :     if( m > 0 ) then
      66           0 :        eps(m) = high_rel_err
      67             :     end if
      68           0 :     m = get_spc_ndx( 'HO2' )
      69           0 :     if( m > 0 ) then
      70           0 :        eps(m) = high_rel_err
      71             :     end if
      72           0 :     o3a_ndx = get_spc_ndx( 'O3A' )
      73           0 :     if( o3a_ndx > 0 ) then
      74           0 :        eps(m) = high_rel_err
      75             :     end if
      76           0 :     m = get_spc_ndx( 'XNO' )
      77           0 :     if( m > 0 ) then
      78           0 :        eps(m) = high_rel_err
      79             :     end if
      80           0 :     m = get_spc_ndx( 'XNO2' )
      81           0 :     if( m > 0 ) then
      82           0 :        eps(m) = high_rel_err
      83             :     end if
      84           0 :     m = get_spc_ndx( 'XNO3' )
      85           0 :     if( m > 0 ) then
      86           0 :        eps(m) = high_rel_err
      87             :     end if
      88           0 :     m = get_spc_ndx( 'XHNO3' )
      89           0 :     if( m > 0 ) then
      90           0 :        eps(m) = high_rel_err
      91             :     end if
      92           0 :     m = get_spc_ndx( 'XHO2NO2' )
      93           0 :     if( m > 0 ) then
      94           0 :        eps(m) = high_rel_err
      95             :     end if
      96           0 :     m = get_spc_ndx( 'XNO2NO3' )
      97           0 :     if( m > 0 ) then
      98           0 :        eps(m) = high_rel_err
      99             :     end if
     100           0 :     m = get_spc_ndx( 'NO2XNO3' )
     101           0 :     if( m > 0 ) then
     102           0 :        eps(m) = high_rel_err
     103             :     end if
     104             :     do m = 1,clscnt4
     105             :        epsilon(m) = eps(clsmap(m,4))
     106             :     end do
     107           0 :   end subroutine imp_slv_inti
     108           0 :   subroutine imp_sol( base_sol, reaction_rates, het_rates, extfrc, delt, &
     109           0 :                       ncol,nlev, lchnk, prod_out, loss_out )
     110             :     !-----------------------------------------------------------------------
     111             :     ! ... imp_sol advances the volumetric mixing ratio
     112             :     ! forward one time step via the fully implicit euler scheme.
     113             :     ! this source is meant for small l1 cache machines such as
     114             :     ! the intel pentium and itanium cpus
     115             :     !-----------------------------------------------------------------------
     116             :     use chem_mods, only : rxntot, extcnt, nzcnt, permute, cls_rxt_cnt
     117             :     use mo_tracname, only : solsym
     118             :     use mo_lin_matrix, only : linmat
     119             :     use mo_nln_matrix, only : nlnmat
     120             :     use mo_lu_factor, only : lu_fac
     121             :     use mo_lu_solve, only : lu_slv
     122             :     use mo_prod_loss, only : imp_prod_loss
     123             :     use mo_indprd, only : indprd
     124             :     use time_manager, only : get_nstep
     125             :     use perf_mod, only : t_startf, t_stopf
     126             :     implicit none
     127             :     !-----------------------------------------------------------------------
     128             :     ! ... dummy args
     129             :     !-----------------------------------------------------------------------
     130             :     integer, intent(in) :: ncol ! columns in chunck
     131             :     integer, intent(in) :: nlev
     132             :     integer, intent(in) :: lchnk ! chunk id
     133             :     real(r8), intent(in) :: delt ! time step (s)
     134             :     real(r8), intent(in) :: reaction_rates(ncol,nlev,max(1,rxntot)) ! rxt rates (1/cm^3/s)
     135             :     real(r8), intent(in) :: extfrc(ncol,nlev,max(1,extcnt)) ! external in-situ forcing (1/cm^3/s)
     136             :     real(r8), intent(in) :: het_rates(ncol,nlev,max(1,gas_pcnst)) ! washout rates (1/s)
     137             :     real(r8), intent(inout) :: base_sol(ncol,nlev,gas_pcnst) ! species mixing ratios (vmr)
     138             :     real(r8), intent(out) :: prod_out(ncol,nlev,max(1,clscnt4))
     139             :     real(r8), intent(out) :: loss_out(ncol,nlev,max(1,clscnt4))
     140             :     !-----------------------------------------------------------------------
     141             :     ! ... local variables
     142             :     !-----------------------------------------------------------------------
     143             :     integer :: nr_iter, &
     144             :          lev, &
     145             :          i, &
     146             :          j, &
     147             :          k, l, &
     148             :          m
     149             :     integer :: fail_cnt, cut_cnt, stp_con_cnt
     150             :     integer :: nstep
     151             :     real(r8) :: interval_done, dt, dti
     152             :     real(r8) :: max_delta(max(1,clscnt4))
     153             :     real(r8) :: sys_jac(max(1,nzcnt))
     154             :     real(r8) :: lin_jac(max(1,nzcnt))
     155             :     real(r8), dimension(max(1,clscnt4)) :: &
     156             :          solution, &
     157             :          forcing, &
     158             :          iter_invariant, &
     159             :          prod, &
     160             :          loss
     161             :     real(r8) :: lrxt(max(1,rxntot))
     162             :     real(r8) :: lsol(max(1,gas_pcnst))
     163             :     real(r8) :: lhet(max(1,gas_pcnst))
     164             :     real(r8), dimension(ncol,nlev,max(1,clscnt4)) :: &
     165           0 :          ind_prd
     166             :     logical :: convergence
     167             :     logical :: frc_mask, iter_conv
     168             :     logical :: converged(max(1,clscnt4))
     169           0 :     solution(:) = 0._r8
     170             :     !-----------------------------------------------------------------------
     171             :     ! ... class independent forcing
     172             :     !-----------------------------------------------------------------------
     173           0 :     if( cls_rxt_cnt(1,4) > 0 .or. extcnt > 0 ) then
     174             :        call indprd( 4, ind_prd, clscnt4, base_sol, extfrc, &
     175           0 :             reaction_rates, ncol )
     176             :     else
     177           0 :        do m = 1,max(1,clscnt4)
     178           0 :           ind_prd(:,:,m) = 0._r8
     179             :        end do
     180             :     end if
     181           0 :     level_loop : do lev = 1,nlev
     182           0 :        column_loop : do i = 1,ncol
     183             :           !-----------------------------------------------------------------------
     184             :           ! ... transfer from base to local work arrays
     185             :           !-----------------------------------------------------------------------
     186             :           do m = 1,rxntot
     187             :              lrxt(m) = reaction_rates(i,lev,m)
     188             :           end do
     189             :           if( gas_pcnst > 0 ) then
     190             :              do m = 1,gas_pcnst
     191             :                 lhet(m) = het_rates(i,lev,m)
     192             :              end do
     193             :           end if
     194             :           !-----------------------------------------------------------------------
     195             :           ! ... time step loop
     196             :           !-----------------------------------------------------------------------
     197           0 :           dt = delt
     198           0 :           cut_cnt = 0
     199           0 :           fail_cnt = 0
     200           0 :           stp_con_cnt = 0
     201           0 :           interval_done = 0._r8
     202             :           time_step_loop : do
     203           0 :              dti = 1._r8 / dt
     204             :              !-----------------------------------------------------------------------
     205             :              ! ... transfer from base to local work arrays
     206             :              !-----------------------------------------------------------------------
     207             :              do m = 1,gas_pcnst
     208             :                 lsol(m) = base_sol(i,lev,m)
     209             :              end do
     210             :              !-----------------------------------------------------------------------
     211             :              ! ... transfer from base to class array
     212             :              !-----------------------------------------------------------------------
     213             :              do k = 1,clscnt4
     214             :                 j = clsmap(k,4)
     215             :                 m = permute(k,4)
     216             :                 solution(m) = lsol(j)
     217             :              end do
     218             :              !-----------------------------------------------------------------------
     219             :              ! ... set the iteration invariant part of the function f(y)
     220             :              !-----------------------------------------------------------------------
     221           0 :              if( cls_rxt_cnt(1,4) > 0 .or. extcnt > 0 ) then
     222             :                 do m = 1,clscnt4
     223             :                    iter_invariant(m) = dti * solution(m) + ind_prd(i,lev,m)
     224             :                 end do
     225             :              else
     226             :                 do m = 1,clscnt4
     227             :                    iter_invariant(m) = dti * solution(m)
     228             :                 end do
     229             :              end if
     230             :              !-----------------------------------------------------------------------
     231             :              ! ... the linear component
     232             :              !-----------------------------------------------------------------------
     233           0 :              if( cls_rxt_cnt(2,4) > 0 ) then
     234           0 :                 call t_startf( 'lin_mat' )
     235           0 :                 call linmat( lin_jac, lsol, lrxt, lhet )
     236           0 :                 call t_stopf( 'lin_mat' )
     237             :              end if
     238             :              !=======================================================================
     239             :              ! the newton-raphson iteration for f(y) = 0
     240             :              !=======================================================================
     241           0 :              iter_loop : do nr_iter = 1,itermax
     242             :                 !-----------------------------------------------------------------------
     243             :                 ! ... the non-linear component
     244             :                 !-----------------------------------------------------------------------
     245           0 :                 if( factor(nr_iter) ) then
     246           0 :                    call t_startf( 'nln_mat' )
     247           0 :                    call nlnmat( sys_jac, lsol, lrxt, lin_jac, dti )
     248           0 :                    call t_stopf( 'nln_mat' )
     249             :                    !-----------------------------------------------------------------------
     250             :                    ! ... factor the "system" matrix
     251             :                    !-----------------------------------------------------------------------
     252           0 :                    call t_startf( 'lu_fac' )
     253           0 :                    call lu_fac( sys_jac )
     254           0 :                    call t_stopf( 'lu_fac' )
     255             :                 end if
     256             :                 !-----------------------------------------------------------------------
     257             :                 ! ... form f(y)
     258             :                 !-----------------------------------------------------------------------
     259           0 :                 call t_startf( 'prod_loss' )
     260           0 :                 call imp_prod_loss( prod, loss, lsol, lrxt, lhet )
     261           0 :                 call t_stopf( 'prod_loss' )
     262             :                 do m = 1,clscnt4
     263             :                    forcing(m) = solution(m)*dti - (iter_invariant(m) + prod(m) - loss(m))
     264             :                 end do
     265             :                 !-----------------------------------------------------------------------
     266             :                 ! ... solve for the mixing ratio at t(n+1)
     267             :                 !-----------------------------------------------------------------------
     268           0 :                 call t_startf( 'lu_slv' )
     269           0 :                 call lu_slv( sys_jac, forcing )
     270           0 :                 call t_stopf( 'lu_slv' )
     271             :                 do m = 1,clscnt4
     272             :                    solution(m) = solution(m) + forcing(m)
     273             :                 end do
     274             :                 !-----------------------------------------------------------------------
     275             :                 ! ... convergence measures
     276             :                 !-----------------------------------------------------------------------
     277             :                 if( nr_iter > 1 ) then
     278             :                    do k = 1,clscnt4
     279             :                       m = permute(k,4)
     280             :                       if( abs(solution(m)) > 1.e-20_r8 ) then
     281             :                          max_delta(k) = abs( forcing(m)/solution(m) )
     282             :                       else
     283             :                          max_delta(k) = 0._r8
     284             :                       end if
     285             :                    end do
     286             :                 end if
     287             :                 !-----------------------------------------------------------------------
     288             :                 ! ... limit iterate
     289             :                 !-----------------------------------------------------------------------
     290           0 :                 where( solution(:) < 0._r8 )
     291             :                    solution(:) = 0._r8
     292             :                 endwhere
     293             :                 !-----------------------------------------------------------------------
     294             :                 ! ... transfer latest solution back to work array
     295             :                 !-----------------------------------------------------------------------
     296             :                 do k = 1,clscnt4
     297             :                    j = clsmap(k,4)
     298             :                    m = permute(k,4)
     299             :                    lsol(j) = solution(m)
     300             :                 end do
     301             :                 !-----------------------------------------------------------------------
     302             :                 ! ... check for convergence
     303             :                 !-----------------------------------------------------------------------
     304           0 :                 converged(:) = .true.
     305           0 :                 if( nr_iter > 1 ) then
     306             :                    do k = 1,clscnt4
     307             :                       m = permute(k,4)
     308             :                       frc_mask = abs( forcing(m) ) > small
     309             :                       if( frc_mask ) then
     310             :                          converged(k) = abs(forcing(m)) <= epsilon(k)*abs(solution(m))
     311             :                       else
     312             :                          converged(k) = .true.
     313             :                       end if
     314             :                    end do
     315           0 :                    convergence = all( converged(:) )
     316           0 :                    if( convergence ) then
     317             :                       exit
     318             :                    end if
     319             :                 end if
     320             :              end do iter_loop
     321             :              !-----------------------------------------------------------------------
     322             :              ! ... check for newton-raphson convergence
     323             :              !-----------------------------------------------------------------------
     324           0 :              if( .not. convergence ) then
     325             :                 !-----------------------------------------------------------------------
     326             :                 ! ... non-convergence
     327             :                 !-----------------------------------------------------------------------
     328           0 :                 fail_cnt = fail_cnt + 1
     329           0 :                 nstep = get_nstep()
     330             :                 write(iulog,'('' imp_sol: Time step '',1p,e21.13,'' failed to converge @ (lchnk,lev,col,nstep) = '',4i6)') &
     331           0 :                      dt,lchnk,lev,i,nstep
     332           0 :                 stp_con_cnt = 0
     333           0 :                 if( cut_cnt < cut_limit ) then
     334           0 :                    cut_cnt = cut_cnt + 1
     335           0 :                    if( cut_cnt < cut_limit ) then
     336           0 :                       dt = .5_r8 * dt
     337             :                    else
     338           0 :                       dt = .1_r8 * dt
     339             :                    end if
     340             :                    cycle time_step_loop
     341             :                 else
     342             :                    write(iulog,'('' imp_sol: Failed to converge @ (lchnk,lev,col,nstep,dt,time) = '',4i6,1p,2e21.13)') &
     343           0 :                         lchnk,lev,i,nstep,dt,interval_done+dt
     344             :                    do m = 1,clscnt4
     345           0 :                       if( .not. converged(m) ) then
     346             :                          write(iulog,'(1x,a8,1x,1pe10.3)') solsym(clsmap(m,4)), max_delta(m)
     347             :                       end if
     348             :                    end do
     349             :                 end if
     350             :              end if
     351             :              !-----------------------------------------------------------------------
     352             :              ! ... check for interval done
     353             :              !-----------------------------------------------------------------------
     354           0 :              interval_done = interval_done + dt
     355           0 :              if( abs( delt - interval_done ) <= .0001_r8 ) then
     356           0 :                 if( fail_cnt > 0 ) then
     357           0 :                    write(iulog,*) 'imp_sol : @ (lchnk,lev,col) = ',lchnk,lev,i,' failed ',fail_cnt,' times'
     358             :                 end if
     359             :                 exit time_step_loop
     360             :              else
     361             :                 !-----------------------------------------------------------------------
     362             :                 ! ... transfer latest solution back to base array
     363             :                 !-----------------------------------------------------------------------
     364           0 :                 if( convergence ) then
     365           0 :                    stp_con_cnt = stp_con_cnt + 1
     366             :                 end if
     367             :                 do m = 1,gas_pcnst
     368             :                    base_sol(i,lev,m) = lsol(m)
     369             :                 end do
     370           0 :                 if( stp_con_cnt >= 2 ) then
     371           0 :                    dt = 2._r8*dt
     372           0 :                    stp_con_cnt = 0
     373             :                 end if
     374           0 :                 dt = min( dt,delt-interval_done )
     375             :                 ! write(iulog,'('' imp_sol: New time step '',1p,e21.13)') dt
     376             :              end if
     377             :           end do time_step_loop
     378             :           !-----------------------------------------------------------------------
     379             :           ! ... Transfer latest solution back to base array
     380             :           !-----------------------------------------------------------------------
     381           0 :           cls_loop: do k = 1,clscnt4
     382             :              j = clsmap(k,4)
     383             :              m = permute(k,4)
     384             :              base_sol(i,lev,j) = solution(m)
     385             :              ! output diagnostics
     386             :              prod_out(i,lev,k) = prod(k) + ind_prd(i,lev,k)
     387             :              loss_out(i,lev,k) = loss(k)
     388             :           end do cls_loop
     389             :        end do column_loop
     390             :     end do level_loop
     391           0 :   end subroutine imp_sol
     392             : end module mo_imp_sol

Generated by: LCOV version 1.14