9 public add_increment_soil
10 public add_increment_snow
11 public calculate_landinc_mask
12 public apply_land_da_adjustments_soil
13 public apply_land_da_adjustments_snd
14 public lsm_noah, lsm_noahmp
16 integer,
parameter :: lsm_noah=1
17 integer,
parameter :: lsm_noahmp=2
21 integer,
parameter :: lsoil_incr=3
23 real,
parameter :: tfreez=273.16
55 subroutine add_increment_soil(rla,rlo,stc_state,smc_state,slc_state,stc_updated, slc_updated, &
56 soilsnow_tile,soilsnow_fg_tile,lensfc,lsoil,idim,jdim,lsm, myrank)
60 use read_write_data,
only : idim_gaus, jdim_gaus, &
61 stc_inc_gaus, soilsnow_gaus, slc_inc_gaus
66 integer,
intent(in) :: lensfc, lsoil, idim, jdim, myrank, lsm
68 integer,
intent(in) :: soilsnow_tile(lensfc), soilsnow_fg_tile(lensfc)
69 real,
intent(inout) :: rla(lensfc), rlo(lensfc)
70 real,
intent(inout) :: stc_state(lensfc, lsoil)
71 real,
intent(inout) :: slc_state(lensfc, lsoil)
72 real,
intent(inout) :: smc_state(lensfc, lsoil)
73 integer,
intent(out) :: stc_updated(lensfc), slc_updated(lensfc)
75 integer :: iopt, nret, kgds_gaus(200)
76 integer :: igaus, jgaus, ij
77 integer :: mask_tile, mask_fg_tile
78 integer :: itile, jtile
80 integer :: igausp1, jgausp1
81 logical :: upd_slc, upd_stc
84 integer,
allocatable :: id1(:,:), id2(:,:), jdc(:,:)
87 real :: stc_inc(lsoil)
88 real :: slc_inc(lsoil)
89 real,
allocatable :: xpts(:), ypts(:), lats(:), lons(:)
90 real,
allocatable :: dum2d(:,:), lats_rad(:), lons_rad(:)
91 real,
allocatable :: agrid(:,:,:), s2c(:,:,:)
93 integer :: k, nother, nsnowupd, nnosoilnear
94 integer :: nstcupd, nslcupd, nfrozen, nfrozen_upd
95 logical :: gaus_has_soil, soil_freeze, soil_ice
103 kgds_gaus(2) = idim_gaus
104 kgds_gaus(3) = jdim_gaus
108 kgds_gaus(7) = -90000
109 kgds_gaus(8) = nint(-360000./float(idim_gaus))
110 kgds_gaus(9) = nint((360.0 / float(idim_gaus))*1000.0)
112 kgds_gaus(10) = jdim_gaus/2
117 if (lsm==lsm_noah)
then 120 elseif (lsm==lsm_noahmp)
then 126 print*,
'adjust soil using gsi increments on gaussian grid' 127 print*,
'updating soil temps', upd_stc
128 print*,
'updating soil moisture', upd_slc
129 print*,
'adjusting first ', lsoil_incr,
' surface layers only' 137 allocate(xpts(idim_gaus*jdim_gaus))
138 allocate(ypts(idim_gaus*jdim_gaus))
139 allocate(lats(idim_gaus*jdim_gaus))
140 allocate(lons(idim_gaus*jdim_gaus))
146 call gdswzd(kgds_gaus,iopt,(idim_gaus*jdim_gaus),fill,xpts,ypts,lons,lats,nret)
148 if (nret /= (idim_gaus*jdim_gaus))
then 149 print*,
'fatal error: problem in gdswzd. stop.' 150 call mpi_abort(mpi_comm_world, 12, ierr)
153 deallocate (xpts, ypts)
155 allocate(dum2d(idim_gaus,jdim_gaus))
156 dum2d = reshape(lats, (/idim_gaus,jdim_gaus/) )
159 allocate(lats_rad(jdim_gaus))
162 lats_rad(j) = dum2d(1,jdim_gaus-j+1) * 3.1415926 / 180.0
165 dum2d = reshape(lons, (/idim_gaus,jdim_gaus/) )
167 allocate(lons_rad(idim_gaus))
168 lons_rad = dum2d(:,1) * 3.1415926 / 180.0
172 allocate(agrid(idim,jdim,2))
173 agrid(:,:,1) = reshape(rlo, (/idim,jdim/) )
174 agrid(:,:,2) = reshape(rla, (/idim,jdim/) )
175 agrid = agrid * 3.1415926 / 180.0
177 allocate(id1(idim,jdim))
178 allocate(id2(idim,jdim))
179 allocate(jdc(idim,jdim))
180 allocate(s2c(idim,jdim,4))
188 call remap_coef( 1, idim, 1, jdim, idim_gaus, jdim_gaus, &
189 lons_rad, lats_rad, id1, id2, jdc, s2c, agrid )
191 deallocate(lons_rad, lats_rad, agrid)
207 ij_loop :
do ij = 1, lensfc
209 mask_tile = soilsnow_tile(ij)
210 mask_fg_tile = soilsnow_fg_tile(ij)
216 if (mask_tile <= 0)
then 224 jtile = (ij-1) / idim + 1
226 if (itile==0) itile = idim
232 if (mask_fg_tile == 2 .or. mask_tile == 2)
then 233 nsnowupd = nsnowupd + 1
241 if (mask_tile == 1)
then 243 igaus = id1(itile,jtile)
244 jgaus = jdc(itile,jtile)
245 igausp1 = id2(itile,jtile)
246 jgausp1 = jdc(itile,jtile)+1
249 gaus_has_soil = .false.
250 if (soilsnow_gaus(igaus,jgaus) == 1 .or. &
251 soilsnow_gaus(igausp1,jgaus) == 1 .or. &
252 soilsnow_gaus(igausp1,jgausp1) == 1 .or. &
253 soilsnow_gaus(igaus,jgausp1) == 1) gaus_has_soil = .true.
255 if (.not. gaus_has_soil)
then 256 nnosoilnear = nnosoilnear + 1
264 if (soilsnow_gaus(igaus,jgaus) == 1)
then 267 stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,1) * stc_inc_gaus(k,igaus,jgaus))
269 slc_inc(k) = slc_inc(k) + (s2c(itile,jtile,1) * slc_inc_gaus(k,igaus,jgaus))
271 wsum = wsum + s2c(itile,jtile,1)
274 if (soilsnow_gaus(igausp1,jgaus) == 1)
then 277 stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,2) * stc_inc_gaus(k,igausp1,jgaus))
279 slc_inc(k) = slc_inc(k) + (s2c(itile,jtile,2) * slc_inc_gaus(k,igausp1,jgaus))
281 wsum = wsum + s2c(itile,jtile,2)
284 if (soilsnow_gaus(igausp1,jgausp1) == 1)
then 287 stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,3) * stc_inc_gaus(k,igausp1,jgausp1))
289 slc_inc(k) = slc_inc(k) + (s2c(itile,jtile,3) * slc_inc_gaus(k,igausp1,jgausp1))
291 wsum = wsum + s2c(itile,jtile,3)
294 if (soilsnow_gaus(igaus,jgausp1) == 1)
then 297 stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,4) * stc_inc_gaus(k,igaus,jgausp1))
299 slc_inc(k) = slc_inc(k) + (s2c(itile,jtile,4) * slc_inc_gaus(k,igaus,jgausp1))
301 wsum = wsum + s2c(itile,jtile,4)
306 stc_inc(k) = stc_inc(k) / wsum
307 slc_inc(k) = slc_inc(k) / wsum
317 if ( stc_state(ij,k) < tfreez) soil_freeze=.true.
318 if ( smc_state(ij,k) - slc_state(ij,k) > 0.001 ) soil_ice=.true.
321 stc_state(ij,k) = stc_state(ij,k) + stc_inc(k)
324 nstcupd = nstcupd + 1
328 if ( (stc_state(ij,k) < tfreez) .and. (.not. soil_freeze) .and. (k==1) ) &
329 nfrozen_upd = nfrozen_upd + 1
332 if ( (.not. soil_freeze ) .and. (.not. soil_ice ) )
then 335 nslcupd = nslcupd + 1
339 slc_state(ij,k) = max(slc_state(ij,k) + slc_inc(k), 0.0)
340 smc_state(ij,k) = max(smc_state(ij,k) + slc_inc(k), 0.0)
343 if (k==1) nfrozen = nfrozen+1
352 write(*,
'(a,i2)')
'statistics of grids number processed for rank : ', myrank
353 write(*,
'(a,i8)')
' soil grid total', lensfc
354 write(*,
'(a,i8)')
' soil grid cells slc updated = ',nslcupd
355 write(*,
'(a,i8)')
' soil grid cells stc updated = ',nstcupd
356 write(*,
'(a,i8)')
' soil grid cells not updated, frozen = ',nfrozen
357 write(*,
'(a,i8)')
' soil grid cells update, became frozen = ',nfrozen_upd
358 write(*,
'(a,i8)')
' (not updated) soil grid cells, no soil nearby on gsi grid = ',nnosoilnear
359 write(*,
'(a,i8)')
' (not updated yet) snow grid cells = ', nsnowupd
360 write(*,
'(a,i8)')
' grid cells, without soil or snow = ', nother
362 deallocate(id1, id2, jdc, s2c)
364 end subroutine add_increment_soil
378 subroutine add_increment_snow(snd_inc,mask,lensfc,snd)
382 integer,
intent(in) :: lensfc
383 real,
intent(in) :: snd_inc(lensfc)
384 integer,
intent(in) :: mask(lensfc)
385 real,
intent(inout) :: snd(lensfc)
391 if (mask(i) > 0)
then 392 snd(i) = max( snd(i) + snd_inc(i), 0.)
396 end subroutine add_increment_snow
408 subroutine calculate_landinc_mask(smc,swe,vtype,lensfc,veg_type_landice,mask)
412 integer,
intent(in) :: lensfc, veg_type_landice
413 real,
intent(in) :: smc(lensfc), swe(lensfc)
414 real,
intent(in) :: vtype(lensfc)
415 integer,
intent(out) :: mask(lensfc)
423 if (smc(i) .LT. 0.99)
then 424 if (swe(i) .GT. 0.001)
then 430 if ( nint(vtype(i)) == veg_type_landice )
then 435 end subroutine calculate_landinc_mask
465 subroutine apply_land_da_adjustments_soil(lsm, isot, ivegsrc,lensfc, &
466 lsoil, rsoiltype, mask, stc_bck, stc_adj, smc_adj, slc_adj, &
467 stc_updated, slc_updated, zsoil)
470 use set_soilveg_snippet_mod,
only: set_soilveg
471 use sflx_snippet,
only: frh2o
475 integer,
intent(in) :: lsm, lensfc, lsoil, isot, ivegsrc
476 real,
intent(in) :: rsoiltype(lensfc)
477 integer,
intent(in) :: mask(lensfc)
478 real,
intent(in) :: stc_bck(lensfc, lsoil)
479 integer,
intent(in) :: stc_updated(lensfc), slc_updated(lensfc)
480 real,
intent(inout) :: smc_adj(lensfc,lsoil), slc_adj(lensfc,lsoil)
481 real,
intent(inout) :: stc_adj(lensfc, lsoil)
482 real(kind=4),
intent(in) :: zsoil(lsoil)
485 logical :: frzn_bck, frzn_anl
486 logical :: soil_freeze, soil_ice
488 integer :: i, l, n_freeze, n_thaw, ierr, n_revert
489 integer :: myrank, soiltype, iret, n_stc, n_slc
490 logical :: upd_slc, upd_stc
494 real,
parameter :: tfreez=273.16
495 real,
dimension(30) :: maxsmc, bb, satpsi
496 real,
dimension(4) :: dz
498 call mpi_comm_rank(mpi_comm_world, myrank, ierr)
500 if (lsm==lsm_noah)
then 503 elseif (lsm==lsm_noahmp)
then 511 call set_soilveg(isot, ivegsrc, maxsmc, bb, satpsi, iret)
513 print *,
'FATAL ERROR: problem in set_soilveg' 514 call mpi_abort(mpi_comm_world, 10, ierr)
517 print *,
'Adjusting noah model smc after stc DA update' 523 if (mask(i) > 0)
then 525 frzn_bck = (stc_bck(i,l) .LT. tfreez )
526 frzn_anl = (stc_adj(i,l) .LT. tfreez )
528 if (frzn_bck .eqv. frzn_anl)
then 530 elseif (frzn_bck .and. .not. frzn_anl)
then 533 n_freeze = n_freeze + 1
537 soiltype = nint(rsoiltype(i))
539 call frh2o(stc_adj(i,l), smc_adj(i,l),slc_adj(i,l), maxsmc(soiltype), &
540 bb(soiltype), satpsi(soiltype),slc_new)
542 slc_adj(i,l) = max( min( slc_new, smc_adj(i,l)), 0.0 )
546 print *,
'adjusted: ', n_thaw,
' thawed,', n_freeze,
' frozen' 552 print *,
'Reverting frozen noah-mp model stc back to background' 558 if (stc_updated(i) == 1 )
then 564 if ( min(stc_bck(i,l),stc_adj(i,l)) < tfreez) soil_freeze=.true.
565 if ( smc_adj(i,l) - slc_adj(i,l) > 0.001 ) soil_ice=.true.
566 if ( soil_freeze .or. soil_ice )
then 568 if (l==1) n_revert = n_revert+1
569 stc_adj(i,l)=stc_bck(i,l)
580 dz(l) = -zsoil(l) + zsoil(l-1)
582 print *,
'Applying soil moisture mins ' 585 if (slc_updated(i) == 1 )
then 591 slc_adj(i,l) = max( 0.001/dz(l), slc_adj(i,l) )
592 smc_adj(i,l) = max( 0.001/dz(l), smc_adj(i,l) )
599 print *,
'FATAL ERROR: unrecognised LSM,', lsm
600 call mpi_abort(mpi_comm_world, 10, ierr)
603 write(*,
'(a,i2)')
'statistics of grids number processed for rank : ', myrank
604 write(*,
'(a,i8)')
' soil grid total', lensfc
605 write(*,
'(a,i8)')
' soil grid cells with slc update', n_slc
606 write(*,
'(a,i8)')
' soil grid cells with stc update', n_stc
607 write(*,
'(a,i8)')
' soil grid cells reverted', n_revert
609 end subroutine apply_land_da_adjustments_soil
626 subroutine apply_land_da_adjustments_snd(lsm, lensfc, mask, swe_bck, snd_bck, snd_anl, swe_adj)
629 use bulk_snow_module,
only: calc_density
633 integer,
intent(in) :: lsm, lensfc
634 integer,
intent(in) :: mask(lensfc)
635 real,
intent(in) :: swe_bck(lensfc), snd_bck(lensfc)
636 real,
intent(in) :: snd_anl(lensfc)
637 real,
intent(inout) :: swe_adj(lensfc)
639 integer :: ierr, myrank, i
641 real :: density(lensfc)
643 call mpi_comm_rank(mpi_comm_world, myrank, ierr)
645 if (lsm .NE. lsm_noah)
then 646 print *,
'FATAL ERROR: apply_land_da_adjustments not coded for models other than noah', lsm
647 call mpi_abort(mpi_comm_world, 10, ierr)
651 call calc_density(lensfc, mask, swe_bck, snd_bck, myrank, density)
654 if ( mask(i)>0 )
then 655 swe_adj(i) = snd_anl(i)*density(i)
660 end subroutine apply_land_da_adjustments_snd
662 end module land_increments
Module containing utility routines.