global_cycle  1.6.0
 All Data Structures Files Functions Variables
land_increments.f90
Go to the documentation of this file.
1 
4 
6 
7  private
8 
9  public add_increment_soil
12 
13 contains
14 
33 
34 subroutine add_increment_soil(rla,rlo,stc_state,soilsnow_tile, soilsnow_fg_tile, &
35  lensfc,lsoil,idim,jdim, myrank)
36 
37  use utils
38  use gdswzd_mod
39  use read_write_data, only : idim_gaus, jdim_gaus, &
40  stc_inc_gaus, soilsnow_gaus
41  use mpi
42 
43  implicit none
44 
45  integer, intent(in) :: lensfc, lsoil, idim, jdim, myrank
46 
47  integer, intent(in) :: soilsnow_tile(lensfc), soilsnow_fg_tile(lensfc)
48  real, intent(inout) :: rla(lensfc), rlo(lensfc)
49  real, intent(inout) :: stc_state(lensfc, lsoil)
50 
51  integer :: iopt, nret, kgds_gaus(200)
52  integer :: igaus, jgaus, ij
53  integer :: mask_tile, mask_fg_tile
54  integer :: itile, jtile
55  integer :: j, ierr
56  integer :: igausp1, jgausp1
57  real :: fill
58 
59  integer, allocatable :: id1(:,:), id2(:,:), jdc(:,:)
60 
61  real :: wsum
62  real :: stc_inc(lsoil)
63  real, allocatable :: xpts(:), ypts(:), lats(:), lons(:)
64  real, allocatable :: dum2d(:,:), lats_rad(:), lons_rad(:)
65  real, allocatable :: agrid(:,:,:), s2c(:,:,:)
66 
67  integer :: k, nother, nsnowupd, nnosoilnear, nsoilupd, nsnowchange
68  logical :: gaus_has_soil
69 
70  integer, parameter :: lsoil_incr=3 ! number of layers to add incrments to
71 
72  ! this produces the same lat/lon as can be read in from the file
73 
74  kgds_gaus = 0
75  kgds_gaus(1) = 4 ! oct 6 - type of grid (gaussian)
76  kgds_gaus(2) = idim_gaus ! oct 7-8 - # pts on latitude circle
77  kgds_gaus(3) = jdim_gaus
78  kgds_gaus(4) = 90000 ! oct 11-13 - lat of origin
79  kgds_gaus(5) = 0 ! oct 14-16 - lon of origin
80  kgds_gaus(6) = 128 ! oct 17 - resolution flag
81  kgds_gaus(7) = -90000 ! oct 18-20 - lat of extreme point
82  kgds_gaus(8) = nint(-360000./float(idim_gaus)) ! oct 21-23 - lon of extreme point
83  kgds_gaus(9) = nint((360.0 / float(idim_gaus))*1000.0)
84  ! oct 24-25 - longitude direction incr.
85  kgds_gaus(10) = jdim_gaus/2 ! oct 26-27 - number of circles pole to equator
86  kgds_gaus(12) = 255 ! oct 29 - reserved
87  kgds_gaus(20) = 255 ! oct 5 - not used, set to 255
88 
89  print*
90  print*,'adjust soil temperature using gsi increments on gaussian grid'
91  print*,'adjusting first ', lsoil_incr, ' surface layers only'
92 
93  !----------------------------------------------------------------------
94  ! call gdswzd to compute the lat/lon of each gsi gaussian grid point.
95  !----------------------------------------------------------------------
96 
97  iopt = 0
98  fill = -9999.
99  allocate(xpts(idim_gaus*jdim_gaus))
100  allocate(ypts(idim_gaus*jdim_gaus))
101  allocate(lats(idim_gaus*jdim_gaus))
102  allocate(lons(idim_gaus*jdim_gaus))
103  xpts = fill
104  ypts = fill
105  lats = fill
106  lons = fill
107 
108  call gdswzd(kgds_gaus,iopt,(idim_gaus*jdim_gaus),fill,xpts,ypts,lons,lats,nret)
109 
110  if (nret /= (idim_gaus*jdim_gaus)) then
111  print*,'fatal error: problem in gdswzd. stop.'
112  call mpi_abort(mpi_comm_world, 12, ierr)
113  endif
114 
115  deallocate (xpts, ypts)
116 
117  allocate(dum2d(idim_gaus,jdim_gaus))
118  dum2d = reshape(lats, (/idim_gaus,jdim_gaus/) )
119  deallocate(lats)
120 
121  allocate(lats_rad(jdim_gaus))
122 
123  do j = 1, jdim_gaus
124  lats_rad(j) = dum2d(1,jdim_gaus-j+1) * 3.1415926 / 180.0
125  enddo
126 
127  dum2d = reshape(lons, (/idim_gaus,jdim_gaus/) )
128  deallocate(lons)
129  allocate(lons_rad(idim_gaus))
130  lons_rad = dum2d(:,1) * 3.1415926 / 180.0
131 
132  deallocate(dum2d)
133 
134  allocate(agrid(idim,jdim,2))
135  agrid(:,:,1) = reshape(rlo, (/idim,jdim/) )
136  agrid(:,:,2) = reshape(rla, (/idim,jdim/) )
137  agrid = agrid * 3.1415926 / 180.0
138 
139  allocate(id1(idim,jdim))
140  allocate(id2(idim,jdim))
141  allocate(jdc(idim,jdim))
142  allocate(s2c(idim,jdim,4))
143 
144  !----------------------------------------------------------------------
145  ! compute bilinear weights for each model point from the nearest
146  ! four gsi/gaussian points. does not account for mask. that
147  ! happens later.
148  !----------------------------------------------------------------------
149 
150  call remap_coef( 1, idim, 1, jdim, idim_gaus, jdim_gaus, &
151  lons_rad, lats_rad, id1, id2, jdc, s2c, agrid )
152 
153  deallocate(lons_rad, lats_rad, agrid)
154  !
155  ! initialize variables for counts statitics to be zeros
156  !
157 
158  !
159  nother = 0 ! grid cells not land
160  nsnowupd = 0 ! grid cells with snow (temperature not yet updated)
161  nsnowchange = 0 ! grid cells where no temp upd made, because snow occurence changed
162  nnosoilnear = 0 ! grid cells where model has soil, but 4 closest gaus grids don't
163  ! (no update made here)
164  nsoilupd = 0
165 
166 
167  ij_loop : do ij = 1, lensfc
168 
169  ! for now, do not make a temperature update if snow differs
170  ! between fg and anal (allow correction of snow to
171  ! address temperature error first)
172 
173 
174  mask_tile = soilsnow_tile(ij)
175  mask_fg_tile = soilsnow_fg_tile(ij)
176 
177  !----------------------------------------------------------------------
178  ! mask: 1 - soil, 2 - snow, 0 - neither
179  !----------------------------------------------------------------------
180 
181  if (mask_tile == 0) then ! skip if neither soil nor snow
182  nother = nother + 1
183  cycle ij_loop
184  endif
185 
186 
187  ! get i,j index on array of (idim,jdim) from known ij
188 
189  jtile = (ij-1) / idim + 1
190  itile = mod(ij,idim)
191  if (itile==0) itile = idim
192 
193  !----------------------------------------------------------------------
194  ! if the snow analysis has chnaged to occurence of snow, skip the
195  ! temperature analysis
196  !----------------------------------------------------------------------
197 
198  if ((mask_fg_tile == 2 .and. mask_tile == 1) .or. &
199  (mask_fg_tile == 1 .and. mask_tile == 2) ) then
200  nsnowchange = nsnowchange + 1
201  cycle ij_loop
202  endif
203 
204  !----------------------------------------------------------------------
205  ! do update to soil temperature grid cells, using bilinear interp
206  !----------------------------------------------------------------------
207 
208  if (mask_tile == 1) then
209  ! these are the four nearest grid cells on the gaus grid
210  igaus = id1(itile,jtile)
211  jgaus = jdc(itile,jtile)
212  igausp1 = id2(itile,jtile)
213  jgausp1 = jdc(itile,jtile)+1
214 
215  ! make sure gaus grid has soil nearby
216  gaus_has_soil = .false.
217  if (soilsnow_gaus(igaus,jgaus) == 1 .or. &
218  soilsnow_gaus(igausp1,jgaus) == 1 .or. &
219  soilsnow_gaus(igausp1,jgausp1) == 1 .or. &
220  soilsnow_gaus(igaus,jgausp1) == 1) gaus_has_soil = .true.
221 
222  if (.not. gaus_has_soil) then
223  nnosoilnear = nnosoilnear + 1
224  cycle ij_loop
225  endif
226 
227  ! calcualate weighted increment over nearby grid cells that have soil
228 
229  ! Draper: to-do, code adding increments to soil moisture.
230  ! will require converting to soil wetness index first
231  ! (need to add soil properties to the increment file)
232 
233  nsoilupd = nsoilupd + 1
234 
235  stc_inc = 0.0
236  wsum = 0.0
237 
238  if (soilsnow_gaus(igaus,jgaus) == 1) then
239  do k = 1, lsoil_incr
240  stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,1) * stc_inc_gaus(k,igaus,jgaus))
241  enddo
242  wsum = wsum + s2c(itile,jtile,1)
243  endif
244 
245  if (soilsnow_gaus(igausp1,jgaus) == 1) then
246  do k = 1, lsoil_incr
247  stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,2) * stc_inc_gaus(k,igausp1,jgaus))
248  enddo
249  wsum = wsum + s2c(itile,jtile,2)
250  endif
251 
252  if (soilsnow_gaus(igausp1,jgausp1) == 1) then
253  do k = 1, lsoil_incr
254  stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,3) * stc_inc_gaus(k,igausp1,jgausp1))
255  enddo
256  wsum = wsum + s2c(itile,jtile,3)
257  endif
258 
259  if (soilsnow_gaus(igaus,jgausp1) == 1) then
260  do k = 1, lsoil_incr
261  stc_inc(k) = stc_inc(k) + (s2c(itile,jtile,4) * stc_inc_gaus(k,igaus,jgausp1))
262  enddo
263  wsum = wsum + s2c(itile,jtile,4)
264  endif
265 
266  ! add increment
267  do k = 1, lsoil_incr
268  stc_inc(k) = stc_inc(k) / wsum
269  stc_state(ij,k) = stc_state(ij,k) + stc_inc(k)
270  ! todo, apply some bounds?
271  enddo
272 
273  elseif(mask_tile==2) then
274  !print *, 'csd2', rlo(ij), rla(ij)
275  nsnowupd = nsnowupd + 1
276 
277  endif ! if soil/snow point
278 
279  enddo ij_loop
280 
281  write(*,'(a,i2)') 'statistics of grids number processed for rank : ', myrank
282  write(*,'(a,i8)') ' soil grid cells updated = ',nsoilupd
283  write(*,'(a,i8)') ' (not updated) soil grid cells, no soil nearby on gsi grid = ',nnosoilnear
284  write(*,'(a,i8)') ' (not updated) soil grid cells, change in presence of snow = ', nsnowchange
285  write(*,'(a,i8)') ' (not updated yet) snow grid cells = ', nsnowupd
286  write(*,'(a,i8)') ' grid cells, without soil of snow = ', nother
287 
288  nother = 0 ! grid cells not land
289  nsnowupd = 0 ! grid cells where no temp upd made, because snow occurence changed
290  nnosoilnear = 0 ! grid cells where model has soil, but 4 closest gaus grids don't
291  ! (no update made here)
292  nsoilupd = 0
293 
294  deallocate(id1, id2, jdc, s2c)
295 
296 end subroutine add_increment_soil
297 
305 subroutine calculate_soilsnowmask(smc,swe,lensfc,mask)
306 
307  implicit none
308 
309  integer, intent(in) :: lensfc
310  real, intent(in) :: smc(lensfc), swe(lensfc)
311  integer, intent(out) :: mask(lensfc)
312 
313  integer :: i
314 
315  mask = 0
316  do i=1,lensfc
317  if (smc(i) .LT. 1.0) then
318  mask(i) = 1
319  endif
320  end do
321 
322  do i=1,lensfc
323  if (swe(i) .GT. 0.001) then
324  mask(i) = 2
325  endif
326  end do
327 
328 end subroutine calculate_soilsnowmask
329 
336 
351 
352 subroutine apply_land_da_adjustments(update_type, lsm, isot, ivegsrc,lensfc, &
353  lsoil, rsoiltype, smc_bck, slc_bck,stc_bck, smc_anl, slc_anl, stc_anl)
354 
355  use mpi
356  use set_soilveg_snippet_mod, only: set_soilveg
357  use sflx_snippet, only: frh2o
358 
359  implicit none
360 
361  character(len=3), intent(in) :: update_type
362  integer, intent(in) :: lsm, lensfc, lsoil, isot, ivegsrc
363  real, intent(in) :: rsoiltype(lensfc) ! soil types, as real
364  real, intent(in) :: smc_bck(lensfc,lsoil), slc_bck(lensfc,lsoil)
365  real, intent(in) :: stc_bck(lensfc, lsoil)
366  real, intent(inout) :: smc_anl(lensfc,lsoil), slc_anl(lensfc,lsoil)
367  real, intent(inout) :: stc_anl(lensfc, lsoil)
368 
369  logical :: frzn_bck, frzn_anl
370 
371  integer :: i, l, n_freeze, n_thaw, ierr
372  integer :: myrank, soiltype, iret
373 
374  real :: slc_new
375 
376  integer, parameter :: lsm_noah=1
378  real, parameter :: tfreez=273.16
379  real, dimension(30) :: maxsmc, bb, satpsi
380 
381  call mpi_comm_rank(mpi_comm_world, myrank, ierr)
382 
383  if (lsm .NE. lsm_noah) then
384  print *, 'FATAL ERROR: apply_land_da_adjustments not coded for models other than noah', lsm
385  call mpi_abort(mpi_comm_world, 10, ierr)
386  endif
387 
388  ! initialise soil properties
389  call set_soilveg(isot, ivegsrc, maxsmc, bb, satpsi, iret)
390  if (iret < 0) then
391  print *, 'FATAL ERROR: problem in set_soilveg'
392  call mpi_abort(mpi_comm_world, 10, ierr)
393  endif
394 
395  select case (update_type)
396 
397  case ('stc')
398  print *, 'Adjusting smc after stc DA update'
399 
400  n_freeze = 0
401  n_thaw = 0
402 
403  do i=1,lensfc
404  do l = 1, lsoil
405  if (smc_bck(i,l) < 1.0) then ! if soil location
406  frzn_bck = (stc_bck(i,l) .LT. tfreez )
407  frzn_anl = (stc_anl(i,l) .LT. tfreez )
408 
409  if (frzn_bck .eqv. frzn_anl) then
410  cycle
411  elseif (frzn_bck .and. .not. frzn_anl) then
412  n_thaw = n_thaw + 1
413  else
414  n_freeze = n_freeze + 1
415  endif
416 
417  ! make adjustment (same routine for both)
418  soiltype = nint(rsoiltype(i))
419  ! bb and maxsmc are in the namelist_soilveg, need soiltype index
420  call frh2o(stc_anl(i,l), smc_anl(i,l),slc_anl(i,l), maxsmc(soiltype), &
421  bb(soiltype), satpsi(soiltype),slc_new)
422 
423  slc_anl(i,l) = max( min( slc_new, smc_anl(i,l)), 0.0 )
424  endif
425  enddo
426  enddo
427 
428  print *, 'adjusted: ', n_thaw,' thawed,', n_freeze, ' frozen'
429 
430  case default
431  print *, 'FATAL ERROR: apply_land_da_adjustments not code for variable', lsm
432  call mpi_abort(mpi_comm_world, 10, ierr)
433  end select
434 
435 end subroutine apply_land_da_adjustments
436 
437 end module land_increments
subroutine, public calculate_soilsnowmask(smc, swe, lensfc, mask)
Calculate soil mask for land on model grid.
subroutine, public add_increment_soil(rla, rlo, stc_state, soilsnow_tile, soilsnow_fg_tile, lensfc, lsoil, idim, jdim, myrank)
Read in gsi file with soil state increments (on the gaussian grid), interpolate increments to the cub...
subroutine, public apply_land_da_adjustments(update_type, lsm, isot, ivegsrc, lensfc, lsoil, rsoiltype, smc_bck, slc_bck, stc_bck, smc_anl, slc_anl, stc_anl)
Make adjustments to dependent variables after applying land increments.
subroutine, public remap_coef(is, ie, js, je, im, jm, lon, lat, id1, id2, jdc, s2c, agrid)
Generate the weights and index of the grids used in the bilinear interpolation.
Definition: utils.F90:38
real function tfreez(salinity)
Compute the freezing point of water as a function of salinity.
Definition: cycle.f90:1822
This module contains routines that read and write data.
Module containing utility routines.
Definition: utils.F90:7