<p><b>duda</b> 2010-02-24 14:47:50 -0700 (Wed, 24 Feb 2010)</p><p>Add positive definite and monotonic limiters for scalar transport.<br>
Limiting is controlled by new namelist parameters config_positive_definite<br>
and config_monotonic.<br>
<br>
Note: the new code still needs to be modified to work with <br>
multiple blocks per process.<br>
<br>
<br>
M    src/module_time_integration.F<br>
M    Registry/Registry<br>
M    namelist.input<br>
</p><hr noshade><pre><font color="gray">Modified: branches/hyd_model/Registry/Registry
===================================================================
--- branches/hyd_model/Registry/Registry        2010-02-24 21:06:01 UTC (rev 119)
+++ branches/hyd_model/Registry/Registry        2010-02-24 21:47:50 UTC (rev 120)
@@ -15,6 +15,8 @@
 namelist integer   sw_model config_number_of_sub_steps  4
 namelist integer   sw_model config_theta_adv_order      2
 namelist integer   sw_model config_scalar_adv_order     2
+namelist logical   sw_model config_positive_definite    false
+namelist logical   sw_model config_monotonic            true
 namelist character io       config_input_name           grid.nc
 namelist character io       config_output_name          output.nc
 namelist character io       config_restart_name         restart.nc

Modified: branches/hyd_model/namelist.input
===================================================================
--- branches/hyd_model/namelist.input        2010-02-24 21:06:01 UTC (rev 119)
+++ branches/hyd_model/namelist.input        2010-02-24 21:47:50 UTC (rev 120)
@@ -11,8 +11,10 @@
    config_h_theta_eddy_visc2 = 0.0
    config_h_theta_eddy_visc4 = 0.0
    config_v_theta_eddy_visc2 = 0.0
-   config_theta_adv_order = 2
-   config_scalar_adv_order = 2
+   config_theta_adv_order = 3
+   config_scalar_adv_order = 3
+   config_positive_definite = .false.
+   config_monotonic = .true.
 /
 
 &amp;io

Modified: branches/hyd_model/src/module_time_integration.F
===================================================================
--- branches/hyd_model/src/module_time_integration.F        2010-02-24 21:06:01 UTC (rev 119)
+++ branches/hyd_model/src/module_time_integration.F        2010-02-24 21:47:50 UTC (rev 120)
@@ -262,9 +262,21 @@
 
         block =&gt; domain % blocklist
         do while (associated(block))
-           call advance_scalars( block % intermediate_step(TEND),                            &amp;
-                                 block % time_levs(1) % state, block % time_levs(2) % state, &amp;
-                                 block % mesh, rk_timestep(rk_step) )
+           !
+           ! Note: The advance_scalars_mono routine can be used without limiting, and thus, encompasses 
+           !       the functionality of the advance_scalars routine; however, it is noticeably slower, 
+           !       so we keep the advance_scalars routine as well
+           !
+           if (rk_step &lt; 3 .or. (.not. config_monotonic .and. .not. config_positive_definite)) then
+              call advance_scalars( block % intermediate_step(TEND),                            &amp;
+                                    block % time_levs(1) % state, block % time_levs(2) % state, &amp;
+                                    block % mesh, rk_timestep(rk_step) )
+           else
+              call advance_scalars_mono( block % intermediate_step(TEND),                            &amp;
+                                         block % time_levs(1) % state, block % time_levs(2) % state, &amp;
+                                         block % mesh, rk_timestep(rk_step), rk_step, 3, &amp;
+                                         domain % dminfo, block % parinfo % cellsToSend, block % parinfo % cellsToRecv )
+           end if
            block =&gt; block % next
         end do
 
@@ -1313,7 +1325,12 @@
       integer :: nVertLevels
 
       real (kind=RKIND), dimension(:), pointer :: fnm, fnp, rdnw
+      real (kind=RKIND) :: coef_3rd_order
 
+      coef_3rd_order = 0.
+      if (config_scalar_adv_order == 3) coef_3rd_order = 1.0
+      if (config_scalar_adv_order == 3 .and. config_monotonic) coef_3rd_order = 0.25
+
       scalar_old  =&gt; s_old % tracers % array
       scalar_new  =&gt; s_new % tracers % array
       deriv_two   =&gt; grid % deriv_two % array
@@ -1384,12 +1401,25 @@
                      if (uhAvg(k,iEdge) &gt; 0) then
                         flux = dvEdge(iEdge) * uhAvg(k,iEdge) * (          &amp;
                                                0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
-                                               -(dcEdge(iEdge) **2) * (d2fdx2_cell1) / 6. )
+                                                -(dcEdge(iEdge) **2) * (d2fdx2_cell1 + d2fdx2_cell2) / 12.          &amp;
+                                                -(dcEdge(iEdge) **2) * coef_3rd_order*(d2fdx2_cell1 - d2fdx2_cell2) / 12. )
                      else
                         flux = dvEdge(iEdge) *  uhAvg(k,iEdge) * (          &amp;
                                                0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
-                                               -(dcEdge(iEdge) **2) * (d2fdx2_cell2) / 6. )
+                                                -(dcEdge(iEdge) **2) * (d2fdx2_cell1 + d2fdx2_cell2) / 12.          &amp;
+                                                +(dcEdge(iEdge) **2) * coef_3rd_order*(d2fdx2_cell1 - d2fdx2_cell2) / 12. )
                      end if
+
+! old version of the above code, with coef_3rd_order assumed to be 1.0
+!                     if (uhAvg(k,iEdge) &gt; 0) then
+!                        flux = dvEdge(iEdge) * uhAvg(k,iEdge) * (          &amp;
+!                                               0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
+!                                               -(dcEdge(iEdge) **2) * (d2fdx2_cell1) / 6. )
+!                     else
+!                        flux = dvEdge(iEdge) *  uhAvg(k,iEdge) * (          &amp;
+!                                               0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
+!                                               -(dcEdge(iEdge) **2) * (d2fdx2_cell2) / 6. )
+!                     end if
     
                      scalar_tend(iTracer,k,cell1) = scalar_tend(iTracer,k,cell1) - flux/areaCell(cell1)
                      scalar_tend(iTracer,k,cell2) = scalar_tend(iTracer,k,cell2) + flux/areaCell(cell2)
@@ -1462,6 +1492,349 @@
    end subroutine advance_scalars
 
 
+   subroutine advance_scalars_mono( tend, s_old, s_new, grid, dt, rk_step, rk_order, dminfo, cellsToSend, cellsToRecv)
+   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
+   !
+   ! Input: s - current model state
+   !        grid - grid metadata
+   !
+   ! Output: tend - computed scalar tendencies
+   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
+
+      implicit none
+
+      type (grid_state), intent(in) :: tend
+      type (grid_state), intent(in) :: s_old
+      type (grid_state), intent(out) :: s_new
+      type (grid_meta), intent(in) :: grid
+      integer, intent(in) :: rk_step, rk_order
+      real (kind=RKIND), intent(in) :: dt
+      type (dm_info), intent(in) :: dminfo
+      type (exchange_list), pointer :: cellsToSend, cellsToRecv
+
+      integer :: i, iCell, iEdge, k, iTracer, cell_upwind, cell1, cell2
+      real (kind=RKIND) :: flux, tracer_edge, d2fdx2_cell1, d2fdx2_cell2
+      real (kind=RKIND) :: fdir, flux_upwind, h_flux_upwind, s_upwind
+
+      real (kind=RKIND), dimension(:,:,:), pointer :: scalar_old, scalar_new, scalar_tend
+      real (kind=RKIND), dimension(:,:,:), pointer :: deriv_two
+      real (kind=RKIND), dimension(:,:), pointer :: uhAvg, h_old, h_new, wwAvg
+      real (kind=RKIND), dimension(:), pointer :: dvEdge, dcEdge, areaCell
+      integer, dimension(:,:), pointer :: cellsOnEdge
+
+      real (kind=RKIND), dimension( grid % nTracers, grid % nEdges) :: h_flux
+      real (kind=RKIND), dimension( grid % nTracers, grid % nCells, 2 ) :: v_flux, v_flux_upwind, s_update
+      real (kind=RKIND), dimension( grid % nTracers, grid % nCells, 2 ) :: scale_out, scale_in
+      real (kind=RKIND), dimension( grid % nTracers ) :: s_max, s_min, s_max_update, s_min_update
+
+      integer :: nVertLevels, km0, km1, ktmp, kcp1, kcm1
+
+      real (kind=RKIND), dimension(:), pointer :: fnm, fnp, rdnw
+      real (kind=RKIND), parameter :: eps=1.e-20
+      real (kind=RKIND) :: coef_3rd_order
+
+      scalar_old  =&gt; s_old % tracers % array
+      scalar_new  =&gt; s_new % tracers % array
+      deriv_two   =&gt; grid % deriv_two % array
+      uhAvg       =&gt; grid % uhAvg % array
+      dvEdge      =&gt; grid % dvEdge % array
+      dcEdge      =&gt; grid % dcEdge % array
+      cellsOnEdge =&gt; grid % cellsOnEdge % array
+      scalar_tend =&gt; tend % tracers % array
+      h_old       =&gt; s_old % h % array
+      h_new       =&gt; s_new % h % array
+      wwAvg       =&gt; grid % wwAvg % array
+      areaCell    =&gt; grid % areaCell % array
+
+      fnm         =&gt; grid % fnm % array
+      fnp         =&gt; grid % fnp % array
+      rdnw        =&gt; grid % rdnw % array
+
+      nVertLevels = grid % nVertLevels
+
+      scalar_tend = 0.  !  testing purposes - we have no sources or sinks
+
+      !
+      ! Runge Kutta integration, so we compute fluxes from scalar_new values, update starts from scalar_old
+      !
+
+      km1 = 1
+      km0 = 2
+      v_flux(:,:,km1) = 0.
+      v_flux_upwind(:,:,km1) = 0.
+      scale_out(:,:,:) = 1.
+      scale_in(:,:,:) = 1.
+
+      coef_3rd_order = 0.
+      if (config_scalar_adv_order == 3) coef_3rd_order = 1.0
+      if (config_scalar_adv_order == 3 .and. config_monotonic) coef_3rd_order = 0.25
+
+      do k = 1, grid % nVertLevels
+         kcp1 = min(k+1,grid % nVertLevels)
+         kcm1 = max(k-1,1)
+
+!  vertical flux
+
+         do iCell=1,grid % nCells
+
+            if (k &lt; grid % nVertLevels) then
+               cell_upwind = k
+               if (wwAvg(k+1,iCell) &gt;= 0) cell_upwind = k+1
+               do iTracer=1,grid % nTracers
+                  v_flux(iTracer,iCell,km0) = dt * wwAvg(k+1,iCell) *   &amp;
+                       (fnm(k+1) * scalar_new(iTracer,k+1,iCell) + fnp(k+1) * scalar_new(iTracer,k,iCell))
+                  v_flux_upwind(iTracer,iCell,km0) = dt * wwAvg(k+1,iCell) * scalar_old(iTracer,cell_upwind,iCell)
+                  v_flux(iTracer,iCell,km0) = v_flux(iTracer,iCell,km0) - v_flux_upwind(iTracer,iCell,km0)
+!                  v_flux(iTracer,iCell,km0) = 0.  ! use only upwind - for testing
+                  s_update(iTracer,iCell,km0) = scalar_old(iTracer,k,iCell) * h_old(k,iCell)  &amp;
+                            - rdnw(k) * (v_flux_upwind(iTracer,iCell,km0) - v_flux_upwind(iTracer,iCell,km1))
+               end do
+            else
+               do iTracer=1,grid % nTracers
+                  v_flux(iTracer,iCell,km0) = 0.
+                  v_flux_upwind(iTracer,iCell,km0) = 0.
+                  s_update(iTracer,iCell,km0) = scalar_old(iTracer,k,iCell) * h_old(k,iCell)  &amp;
+                            - rdnw(k) * (v_flux_upwind(iTracer,iCell,km0) - v_flux_upwind(iTracer,iCell,km1))
+               end do
+            end if
+
+         end do
+
+! horizontal flux
+
+         if (config_scalar_adv_order == 2) then
+
+            do iEdge=1,grid%nEdges
+               cell1 = cellsOnEdge(1,iEdge)
+               cell2 = cellsOnEdge(2,iEdge)
+               if (cell1 &gt; 0 .and. cell2 &gt; 0) then
+                  cell_upwind = cell2
+                  if (uhAvg(k,iEdge) &gt;= 0) cell_upwind = cell1
+                  do iTracer=1,grid % nTracers
+                     tracer_edge = 0.5 * (scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))
+                     h_flux(iTracer,iEdge) = dt * uhAvg(k,iEdge) * dvEdge(iEdge) * tracer_edge
+                     h_flux_upwind = dt * uhAvg(k,iEdge) * dvEdge(iEdge) * scalar_old(iTracer,k,cell_upwind)
+                     h_flux(iTracer,iEdge) = h_flux(iTracer,iEdge) - h_flux_upwind
+!                     h_flux(iTracer,iEdge) = 0.  ! use only upwind - for testing
+                     s_update(iTracer,cell1,km0) = s_update(iTracer,cell1,km0) - h_flux_upwind / grid % areaCell % array(cell1)
+                     s_update(iTracer,cell2,km0) = s_update(iTracer,cell2,km0) + h_flux_upwind / grid % areaCell % array(cell2)
+                  end do 
+               end if
+            end do 
+
+         else if (config_scalar_adv_order &gt;= 3) then
+
+            do iEdge=1,grid%nEdges
+               cell1 = cellsOnEdge(1,iEdge)
+               cell2 = cellsOnEdge(2,iEdge)
+               if (cell1 &gt; 0 .and. cell2 &gt; 0) then
+                  cell_upwind = cell2
+                  if (uhAvg(k,iEdge) &gt;= 0) cell_upwind = cell1
+                  do iTracer=1,grid % nTracers
+  
+                     d2fdx2_cell1 = deriv_two(1,1,iEdge) * scalar_new(iTracer,k,cell1)
+                     d2fdx2_cell2 = deriv_two(1,2,iEdge) * scalar_new(iTracer,k,cell2)
+                     do i=1, grid % nEdgesOnCell % array (cell1)
+                        if ( grid % CellsOnCell % array (i,cell1) &gt; 0) &amp;
+                        d2fdx2_cell1 = d2fdx2_cell1 + &amp;
+                                       deriv_two(i+1,1,iEdge) * scalar_new(iTracer,k,grid % CellsOnCell % array (i,cell1))
+                     end do
+                     do i=1, grid % nEdgesOnCell % array (cell2)
+                        if ( grid % CellsOnCell % array (i,cell2) &gt; 0) &amp;
+                        d2fdx2_cell2 = d2fdx2_cell2 + &amp;
+                                       deriv_two(i+1,2,iEdge) * scalar_new(iTracer,k,grid % CellsOnCell % array (i,cell2))
+                     end do
+    
+                     if (uhAvg(k,iEdge) &gt; 0) then
+                        flux = dvEdge(iEdge) * uhAvg(k,iEdge) * (          &amp;
+                                               0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
+                                                -(dcEdge(iEdge) **2) * (d2fdx2_cell1 + d2fdx2_cell2) / 12.          &amp;
+                                                -(dcEdge(iEdge) **2) * coef_3rd_order*(d2fdx2_cell1 - d2fdx2_cell2) / 12. )
+                     else
+                        flux = dvEdge(iEdge) *  uhAvg(k,iEdge) * (          &amp;
+                                               0.5*(scalar_new(iTracer,k,cell1) + scalar_new(iTracer,k,cell2))      &amp;
+                                                -(dcEdge(iEdge) **2) * (d2fdx2_cell1 + d2fdx2_cell2) / 12.          &amp;
+                                                +(dcEdge(iEdge) **2) * coef_3rd_order*(d2fdx2_cell1 - d2fdx2_cell2) / 12. )
+                     end if
+   
+                     h_flux(iTracer,iEdge) = dt * flux
+                     h_flux_upwind = dt * uhAvg(k,iEdge) * dvEdge(iEdge) * scalar_old(iTracer,k,cell_upwind)
+                     h_flux(iTracer,iEdge) = h_flux(iTracer,iEdge) - h_flux_upwind
+!                     h_flux(iTracer,iEdge) = 0.  ! use only upwind - for testing
+                     s_update(iTracer,cell1,km0) = s_update(iTracer,cell1,km0) - h_flux_upwind / grid % areaCell % array(cell1)
+                     s_update(iTracer,cell2,km0) = s_update(iTracer,cell2,km0) + h_flux_upwind / grid % areaCell % array(cell2)
+                  end do 
+               end if
+            end do 
+
+         end if
+
+
+         if ( (rk_step == rk_order) .and. (config_monotonic .or. config_positive_definite) ) then   
+
+!*************************************************************************************************************
+!---  limiter - we limit horizontal and vertical fluxes on level k 
+!---  (these are h fluxes contributing to level k scalars, and v flux contributing to level k, k-1 tracers)
+
+            do iCell=1,grid % nCells
+  
+               do iTracer=1,grid % nTracers
+   
+                  s_max(iTracer) = max(scalar_old(iTracer,k,iCell), scalar_old(iTracer,kcp1,iCell), scalar_old(iTracer,kcm1,iCell))
+                  s_min(iTracer) = min(scalar_old(iTracer,k,iCell), scalar_old(iTracer,kcp1,iCell), scalar_old(iTracer,kcm1,iCell))
+                  s_max_update(iTracer) = s_update(iTracer,iCell,km0)
+                  s_min_update(iTracer) = s_update(iTracer,iCell,km0)
+    
+                  ! add in vertical flux to get max and min estimate
+                  s_max_update(iTracer) = s_max_update(iTracer)  &amp;
+                     - rdnw(k) * (max(0.,v_flux(iTracer,iCell,km0)) - min(0.,v_flux(iTracer,iCell,km1)))
+                  s_min_update(iTracer) = s_min_update(iTracer)  &amp;
+                     - rdnw(k) * (min(0.,v_flux(iTracer,iCell,km0)) - max(0.,v_flux(iTracer,iCell,km1)))
+    
+               end do
+   
+               do i = 1, grid % nEdgesOnCell % array(iCell)  ! go around the edges of each cell
+                  if (grid % cellsOnCell % array(i,iCell) &gt; 0) then
+                     do iTracer=1,grid % nTracers
+    
+                        s_max(iTracer)  = max(scalar_old(iTracer,k,grid % cellsOnCell % array(i,iCell)), s_max(iTracer))
+                        s_min(iTracer)  = min(scalar_old(iTracer,k,grid % cellsOnCell % array(i,iCell)), s_min(iTracer))
+     
+                        iEdge = grid % EdgesOnCell % array (i,iCell)
+                        if (iCell == cellsOnEdge(1,iEdge)) then
+                           fdir = 1.0
+                        else
+                           fdir = -1.0
+                        end if
+                        flux = -fdir * h_flux(iTracer,iEdge)/grid % areaCell % array(iCell)
+                        s_max_update(iTracer) = s_max_update(iTracer) + max(0.,flux)
+                        s_min_update(iTracer) = s_min_update(iTracer) + min(0.,flux)
+    
+                     end do
+                  end if
+   
+               end do
+   
+               if( config_positive_definite ) s_min(:) = 0.
+   
+               do iTracer=1,grid % nTracers
+                  scale_out (iTracer,iCell,km0) = 1.
+                  scale_in (iTracer,iCell,km0) = 1.
+                  s_max_update (iTracer) =  s_max_update (iTracer) / h_new (k,iCell)
+                  s_min_update (iTracer) =  s_min_update (iTracer) / h_new (k,iCell)
+                  s_upwind = s_update(iTracer,iCell,km0) / h_new(k,iCell)
+                  if ( s_max_update(iTracer) &gt; s_max(iTracer) .and. config_monotonic)   &amp;
+                     scale_in (iTracer,iCell,km0) = max(0.,(s_max(iTracer)-s_upwind)/(s_max_update(iTracer)-s_upwind+eps))
+                  if ( s_min_update(iTracer) &lt; s_min(iTracer) )   &amp;
+                     scale_out (iTracer,iCell,km0) = max(0.,(s_upwind-s_min(iTracer))/(s_upwind-s_min_update(iTracer)+eps))
+                end do
+  
+            end do ! end loop over cells to compute scale factor
+
+
+            call dmpar_exch_halo_field2dReal(dminfo, scale_out(:,:,1), &amp;
+                                             grid % nTracers, grid % nCells, &amp;
+                                             cellsToSend, cellsToRecv)
+            call dmpar_exch_halo_field2dReal(dminfo, scale_out(:,:,2), &amp;
+                                             grid % nTracers, grid % nCells, &amp;
+                                             cellsToSend, cellsToRecv)
+            call dmpar_exch_halo_field2dReal(dminfo, scale_in(:,:,1), &amp;
+                                             grid % nTracers, grid % nCells, &amp;
+                                             cellsToSend, cellsToRecv)
+            call dmpar_exch_halo_field2dReal(dminfo, scale_in(:,:,2), &amp;
+                                             grid % nTracers, grid % nCells, &amp;
+                                             cellsToSend, cellsToRecv)
+
+       ! rescale the horizontal fluxes

+            do iEdge = 1, grid % nEdges
+               cell1 = grid % cellsOnEdge % array(1,iEdge)
+               cell2 = grid % cellsOnEdge % array(2,iEdge)
+               if (cell1 &gt; 0 .and. cell2 &gt; 0) then
+                  do iTracer=1,grid % nTracers
+                     flux = h_flux(iTracer,iEdge)
+                     if (flux &gt; 0) then
+                        flux = flux * min(scale_out(iTracer,cell1,km0), scale_in(iTracer,cell2,km0))
+                     else
+                        flux = flux * min(scale_in(iTracer,cell1,km0), scale_out(iTracer,cell2,km0))
+                     end if
+                     h_flux(iTracer,iEdge) = flux
+                  end do
+               end if
+            end do

+       ! rescale the vertical flux

+            do iCell=1,grid % nCells
+               do iTracer=1,grid % nTracers
+                  flux =  v_flux(iTracer,iCell,km1)
+                  if (flux &gt; 0) then
+                     flux = flux * min(scale_out(iTracer,iCell,km0), scale_in(iTracer,iCell,km1))
+                  else
+                     flux = flux * min(scale_in(iTracer,iCell,km0), scale_out(iTracer,iCell,km1))
+                  end if
+                  v_flux(iTracer,iCell,km1) = flux
+               end do
+            end do
+
+!  end of limiter
+!*******************************************************************************************************************
+
+         end if
+
+!---  update
+
+         do iCell=1,grid % nCells
+            !  add in upper vertical flux that was just renormalized
+            do iTracer=1,grid % nTracers
+               s_update(iTracer,iCell,km0) = s_update(iTracer,iCell,km0) + rdnw(k) * v_flux(iTracer,iCell,km1)
+               if (k &gt; 1) s_update(iTracer,iCell,km1) = s_update(iTracer,iCell,km1) - rdnw(k-1)*v_flux(iTracer,iCell,km1)
+            end do
+         end do

+         do iEdge=1,grid%nEdges
+            cell1 = cellsOnEdge(1,iEdge)
+            cell2 = cellsOnEdge(2,iEdge)
+            if (cell1 &gt; 0 .and. cell2 &gt; 0) then
+               do iTracer=1,grid % nTracers
+                  s_update(iTracer,cell1,km0) = s_update(iTracer,cell1,km0) - &amp;
+                      h_flux(iTracer,iEdge) / grid % areaCell % array(cell1)
+                  s_update(iTracer,cell2,km0) = s_update(iTracer,cell2,km0) + &amp;
+                      h_flux(iTracer,iEdge) / grid % areaCell % array(cell2)
+               end do 
+            end if
+         end do 

+         ! decouple from mass
+         if (k &gt; 1) then
+            do iCell=1,grid % nCells
+               do iTracer=1,grid % nTracers
+                  s_update(iTracer,iCell,km1) = s_update(iTracer,iCell,km1) / h_new(k-1,iCell)
+               end do
+            end do

+            do iCell=1,grid % nCells
+               do iTracer=1,grid % nTracers
+                  scalar_new(iTracer,k-1,iCell) = s_update(iTracer,iCell,km1) 
+               end do
+            end do
+         end if

+         ktmp = km1
+         km1 = km0
+         km0 = ktmp
+
+      end do
+
+      do iCell=1,grid % nCells
+         do iTracer=1,grid % nTracers
+            scalar_new(iTracer,grid % nVertLevels,iCell) = s_update(iTracer,iCell,km1) / h_new(grid%nVertLevels,iCell)
+         end do
+      end do
+
+   end subroutine advance_scalars_mono
+
+
    subroutine compute_solve_diagnostics(dt, s, grid)
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
    ! Compute diagnostic fields used in the tendency computations

</font>
</pre>