Skip to content

Commit 3fb7f21

Browse files
committed
Merge branch 'mpaiao-pr-zsoifl' (PR #7319)
Add an alternate way of defining soil layers and depth to bedrock in ELM. These changes were implemented with the intention of being bit-for-bit with previously generated surface files. 1. The code no longer expects nlevsoi in the surface file to be 10 (the default in ELM). Instead, it will use nlevsoi provided in the surface file, as long as nlevsoi <= nlevgrnd. 2. If ZSOI(nlevsoi) is provided in the surface file, ELM will use these layers instead of the default, and append layers between nlevsoi+1 and nlevgrnd if needed using the default parameters, plus an offset to ensure that zsoi always increases. 4. The scaling parameters for the soil layers are now declared in elm_varpar.F90, to avoid magic numbers. 5. Slightly revised the code that reads the grid-cell dependent depth to bedrock, so it works with either aveDTB (the original name in ELM) and zbedrock (the name in CLM), so surface files borrowed from CLM would still work with ELM and generate the same soil layers. 6. Deleted some unused variables and (I think) unecessary calls to check_dim for nlevsoi so the surface file can have different values. [BFB]
2 parents 0276ea7 + 27cc375 commit 3fb7f21

File tree

4 files changed

+124
-47
lines changed

4 files changed

+124
-47
lines changed

components/elm/src/biogeophys/SoilStateType.F90

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module SoilStateType
1111
use ncdio_pio , only : ncd_pio_openfile, ncd_inqfdims, ncd_pio_closefile, ncd_inqdid, ncd_inqdlen
1212
use elm_varpar , only : more_vertlayers, numpft, numrad
1313
use elm_varpar , only : nlevsoi, nlevgrnd, nlevlak, nlevsoifl, nlayer, nlayert, nlevurb, nlevsno
14+
use elm_varpar , only : scalez, zecoeff
1415
use landunit_varcon , only : istice, istdlak, istwet, istsoil, istcrop, istice_mec
1516
use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv, icol_road_imperv
1617
use elm_varcon , only : zsoi, dzsoi, zisoi, spval, namet, grlnd
@@ -440,6 +441,11 @@ subroutine InitCold(this, bounds)
440441
call getfil (fsurdat, locfn, 0)
441442
call ncd_pio_openfile (ncid, locfn, 0)
442443

444+
! --------------------------------------------------------------------
445+
! Make sure nlevsoifl and nlevsoi match. At this point, we keep this test, but
446+
! initVertical should have taken care of nlevsoi when the value in the input file
447+
! differs from the default (10 layers).
448+
! --------------------------------------------------------------------
443449
call ncd_inqdlen(ncid,dimid,nlevsoifl,name='nlevsoi')
444450
if ( .not. more_vertlayers )then
445451
if ( nlevsoifl /= nlevsoi )then
@@ -450,6 +456,38 @@ subroutine InitCold(this, bounds)
450456
! read in layers, interpolate to high resolution grid later
451457
end if
452458

459+
460+
461+
! --------------------------------------------------------------------
462+
! Define the soil layers from the input file. We first check if ZSOI is available
463+
! in the file, in which case we read the information directly from the file. Otherwise,
464+
! we assume the original ELM parameters. The input soil depths will be used for
465+
! interpolating soil properties (e.g., sand and clay).
466+
! --------------------------------------------------------------------
467+
allocate(zsoifl(1:nlevsoifl), zisoifl(0:nlevsoifl), dzsoifl(1:nlevsoifl))
468+
! Try to read soil information from the file.
469+
call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoifl, dim1name=grlnd, readvar=readvar)
470+
if (.not. readvar ) then
471+
! Variable ZSOI not found, use the ELM parameters.
472+
do j = 1, nlevsoifl
473+
zsoifl(j) = scalez*(exp(zecoeff*(j-0.5_r8))-1._r8) !node depths
474+
end do
475+
end if
476+
477+
dzsoifl(1) = 0.5_r8*(zsoifl(1)+zsoifl(2)) !thickness b/n two interfaces
478+
do j = 2,nlevsoifl-1
479+
dzsoifl(j)= 0.5_r8*(zsoifl(j+1)-zsoifl(j-1))
480+
enddo
481+
dzsoifl(nlevsoifl) = zsoifl(nlevsoifl)-zsoifl(nlevsoifl-1)
482+
483+
zisoifl(0) = 0._r8
484+
do j = 1, nlevsoifl-1
485+
zisoifl(j) = 0.5_r8*(zsoifl(j)+zsoifl(j+1)) !interface depths
486+
enddo
487+
zisoifl(nlevsoifl) = zsoifl(nlevsoifl) + 0.5_r8*dzsoifl(nlevsoifl)
488+
489+
490+
453491
! Read in organic matter dataset
454492

455493
organic_max = ParamsShareInst%organic_max
@@ -548,27 +586,6 @@ subroutine InitCold(this, bounds)
548586

549587
call ncd_pio_closefile(ncid)
550588

551-
! --------------------------------------------------------------------
552-
! get original soil depths to be used in interpolation of sand and clay
553-
! --------------------------------------------------------------------
554-
555-
allocate(zsoifl(1:nlevsoifl), zisoifl(0:nlevsoifl), dzsoifl(1:nlevsoifl))
556-
do j = 1, nlevsoifl
557-
zsoifl(j) = 0.025*(exp(0.5_r8*(j-0.5_r8))-1._r8) !node depths
558-
enddo
559-
560-
dzsoifl(1) = 0.5_r8*(zsoifl(1)+zsoifl(2)) !thickness b/n two interfaces
561-
do j = 2,nlevsoifl-1
562-
dzsoifl(j)= 0.5_r8*(zsoifl(j+1)-zsoifl(j-1))
563-
enddo
564-
dzsoifl(nlevsoifl) = zsoifl(nlevsoifl)-zsoifl(nlevsoifl-1)
565-
566-
zisoifl(0) = 0._r8
567-
do j = 1, nlevsoifl-1
568-
zisoifl(j) = 0.5_r8*(zsoifl(j)+zsoifl(j+1)) !interface depths
569-
enddo
570-
zisoifl(nlevsoifl) = zsoifl(nlevsoifl) + 0.5_r8*dzsoifl(nlevsoifl)
571-
572589
! --------------------------------------------------------------------
573590
! Set soil hydraulic and thermal properties: non-lake
574591
! --------------------------------------------------------------------

components/elm/src/main/elm_varpar.F90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ module elm_varpar
7272

7373
integer, parameter :: nlevslp = 11 ! number of slope percentile levels
7474

75+
! Parameters that define the thickness of the soil layers. By default, we define the
76+
! mid-point of the soil layers as:
77+
!
78+
! zsoi(j) = scalez * ( exp( zecoeff * (j - 0.5_r8) ) - 1.0_r8 )
79+
!
80+
! The default values scalez = 0.025_r8 and zecoeff = 0.50_r8 trace back to the original
81+
! ELM configuration, but depending on the specific needs by the user, these can be
82+
! modified.
83+
real(r8), parameter :: scalez = 0.025_r8
84+
real(r8), parameter :: zecoeff = 0.50_r8
85+
7586
! constants for decomposition cascade
7687

7788
integer :: i_met_lit

components/elm/src/main/initVerticalMod.F90

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ module initVerticalMod
1414
use spmdMod , only : masterproc
1515
use elm_varpar , only : more_vertlayers, nlevsno, nlevgrnd, nlevlak
1616
use elm_varpar , only : toplev_equalspace, nlev_equalspace
17-
use elm_varpar , only : nlevsoi, nlevsoifl, nlevurb, nlevslp
17+
use elm_varpar , only : nlevsoi, nlevsoifl, nlevurb, nlevslp
18+
use elm_varpar , only : nlevdecomp, scalez, zecoeff
1819
use elm_varctl , only : fsurdat, iulog, use_var_soil_thick
1920
use elm_varctl , only : use_vancouver, use_mexicocity, use_vertsoilc, use_extralakelayers, use_extrasnowlayers
2021
use elm_varctl , only : use_erosion, use_polygonal_tundra
@@ -26,7 +27,7 @@ module initVerticalMod
2627
use ColumnType , only : col_pp
2728
use ColumnDataType , only : col_ws
2829
use SnowHydrologyMod, only : InitSnowLayers
29-
use ncdio_pio
30+
use ncdio_pio , only : file_desc_t, ncd_io, ncd_pio_openfile, ncd_pio_closefile , ncd_inqdlen
3031
use topounit_varcon , only : max_topounits
3132
use GridcellType , only : grc_pp
3233
!
@@ -50,12 +51,16 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof)
5051
real(r8) , intent(in) :: thick_wall(bounds%begl:)
5152
real(r8) , intent(in) :: thick_roof(bounds%begl:)
5253
!
53-
! LOCAL VARAIBLES:
54-
integer :: c,l,t,ti,topi,g,i,j,lev ! indices
54+
! LOCAL PARAMETERS
55+
integer, parameter :: ndtbname = 2 ! Number of names to try for depth to bedrock
56+
!
57+
! LOCAL VARIABLES:
58+
integer :: c,l,t,ti,topi,g,i,j,lev,n ! indices
5559
type(file_desc_t) :: ncid ! netcdf id
56-
logical :: readvar
60+
logical :: readvar ! Flag: variable was successfully read
5761
integer :: dimid ! dimension id
5862
character(len=256) :: locfn ! local filename
63+
real(r8) ,pointer :: zsoi_in(:) ! read in - soil information
5964
real(r8) ,pointer :: std (:) ! read in - topo_std
6065
real(r8) ,pointer :: tslope (:) ! read in - topo_slope
6166
real(r8) ,pointer :: gradz(:) ! read in - gradz (polygonal tundra only)
@@ -68,7 +73,6 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof)
6873
real(r8) :: slopebeta ! temporary
6974
real(r8) :: slopemax ! temporary
7075
integer :: ier ! error status
71-
real(r8) :: scalez = 0.025_r8 ! Soil layer thickness discretization (m)
7276
real(r8) :: thick_equal = 0.2
7377
real(r8) ,pointer :: lakedepth_in(:,:) ! read in - lakedepth
7478
real(r8), allocatable :: zurb_wall(:,:) ! wall (layer node depth)
@@ -80,6 +84,7 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof)
8084
real(r8) :: depthratio ! ratio of lake depth to standard deep lake depth
8185
integer :: begc, endc
8286
integer :: begl, endl
87+
character(len=256), dimension(ndtbname) :: dtbname ! List of possible names for depth to bedrock
8388
!------------------------------------------------------------------------
8489

8590
begc = bounds%begc; endc= bounds%endc
@@ -95,47 +100,81 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof)
95100
call ncd_pio_openfile (ncid, locfn, 0)
96101

97102
call ncd_inqdlen(ncid, dimid, nlevsoifl, name='nlevsoi')
98-
if ( .not. more_vertlayers )then
99-
if ( nlevsoifl /= nlevsoi )then
100-
call shr_sys_abort(' ERROR: Number of soil layers on file does NOT match the number being used'//&
103+
104+
105+
if ( .not. more_vertlayers ) then
106+
! Removed the requirement for nlevsoifl to match nlevsoi, but we make sure the
107+
! number of input layers do not exceed the maximum allocated, to avoid segmentation
108+
! violation errors.
109+
if ( nlevsoifl > nlevgrnd ) then
110+
call shr_sys_abort(' ERROR: Number of soil layers on file exceeds the maximum number of layers allowed (nlevgrnd)'//&
101111
errMsg(__FILE__, __LINE__))
112+
elseif ( nlevsoifl /= nlevsoi ) then
113+
! Surface file has a different number of soil levels, update the simulation to
114+
! match the surface file.
115+
nlevsoi = nlevsoifl
116+
if (use_vertsoilc) nlevdecomp = nlevsoifl
102117
end if
103118
else
104119
! read in layers, interpolate to high resolution grid later
105120
end if
106121

107122
! --------------------------------------------------------------------
108-
! Define layer structure for soil, lakes, urban walls and roof
109-
! Vertical profile of snow is not initialized here - but below
110-
! --------------------------------------------------------------------
111-
112-
! Soil layers and interfaces (assumed same for all non-lake patches)
123+
! Define layer structure for soil, lakes, urban walls and roof. We first check
124+
! whether or not soil layers exist in the surfacefile. If so, we use the layers from
125+
! the file. Otherwise, we define the layers using the default parameters, but
126+
! further checking if the run should include intermediate layers with equal
127+
! thicknesses.
128+
! In soil layers and interfaces (assumed same for all non-lake patches),
113129
! "0" refers to soil surface and "nlevsoi" refers to the bottom of model soil
114-
115-
if ( more_vertlayers )then
130+
!
131+
! Note: vertical profile of snow is not initialized here - but below
132+
! --------------------------------------------------------------------
133+
! Try to read soil information from the file.
134+
allocate (zsoi_in(nlevsoi))
135+
call ncd_io(ncid=ncid, varname='ZSOI', flag='read', data=zsoi_in, dim1name=grlnd, readvar=readvar)
136+
if ( readvar ) then
137+
! -----------------------------------------------------------------
138+
! File contains soil information. We must complete the soil depth information for
139+
! layers beneath nlevsoi, using the original scaling parameters for increasing the
140+
! depth of the layers, but acknowledging that the layer must be beneath the deepest
141+
! input soil layer.
142+
! -----------------------------------------------------------------
143+
zsoi(1:nlevsoi) = zsoi_in(1:nlevsoi)
144+
do j = nlevsoi+1, nlevgrnd
145+
zsoi(j) = zsoi(nlevsoi) + &
146+
scalez*(exp(zecoeff*(j -0.5_r8))-exp(zecoeff*(nlevsoi-0.5_r8)))
147+
end do
148+
149+
150+
elseif ( more_vertlayers )then
116151
! replace standard exponential grid with a grid that starts out exponential,
117152
! then has several evenly spaced layers, then finishes off exponential.
118153
! this allows the upper soil to behave as standard, but then continues
119154
! with higher resolution to a deeper depth, so that, for example, permafrost
120155
! dynamics are not lost due to an inability to resolve temperature, moisture,
121156
! and biogeochemical dynamics at the base of the active layer
122157
do j = 1, toplev_equalspace
123-
zsoi(j) = scalez*(exp(0.5_r8*(j-0.5_r8))-1._r8) !node depths
158+
zsoi(j) = scalez*(exp(zecoeff*(j-0.5_r8))-1._r8) !node depths
124159
enddo
125160

126161
do j = toplev_equalspace+1,toplev_equalspace + nlev_equalspace
127162
zsoi(j) = zsoi(j-1) + thick_equal
128163
enddo
129164

130165
do j = toplev_equalspace + nlev_equalspace +1, nlevgrnd
131-
zsoi(j) = scalez*(exp(0.5_r8*((j - nlev_equalspace)-0.5_r8))-1._r8) + nlev_equalspace * thick_equal
166+
zsoi(j) = scalez*(exp(zecoeff*((j - nlev_equalspace)-0.5_r8))-1._r8) + nlev_equalspace * thick_equal
132167
enddo
133168
else
134-
169+
! -----------------------------------------------------------------
170+
! Soil layers not available from the input, and no additional layers needed. Use the
171+
! default soil thickness settings.
172+
! -----------------------------------------------------------------
135173
do j = 1, nlevgrnd
136-
zsoi(j) = scalez*(exp(0.5_r8*(j-0.5_r8))-1._r8) !node depths
174+
zsoi(j) = scalez*(exp(zecoeff*(j-0.5_r8))-1._r8) !node depths
137175
enddo
138176
end if
177+
deallocate(zsoi_in)
139178

140179
dzsoi(1) = 0.5_r8*(zsoi(1)+zsoi(2)) !thickness b/n two interfaces
141180
do j = 2,nlevgrnd-1
@@ -629,9 +668,22 @@ subroutine initVertical(bounds, snow_depth, thick_wall, thick_roof)
629668

630669
if (use_var_soil_thick) then
631670
allocate(dtb(bounds%begg:bounds%endg,1:max_topounits))
632-
call ncd_io(ncid=ncid, varname='aveDTB', flag='read', data=dtb, dim1name=grlnd, readvar=readvar)
671+
672+
! ELM and CLM use different names for depth to bedrock in the surface file
673+
! ('aveDTB' and 'zbedrock', respectively). To keep cross-model compatibility, we
674+
! test both names before falling back to the default number of layers.
675+
dtbname(1) = 'aveDTB'
676+
dtbname(2) = 'zbedrock'
677+
readvar = .false.
678+
do n=1,ndtbname
679+
if (.not. readvar) then
680+
call ncd_io(ncid=ncid, varname=dtbname(n), flag='read', data=dtb, dim1name=grlnd, readvar=readvar)
681+
end if
682+
end do
683+
684+
633685
if (.not. readvar) then
634-
write(iulog,*) 'aveDTB not in surfdata: reverting to default 10 layers.'
686+
write(iulog,fmt='(a,i5,a)') 'aveDTB not in surfdata: reverting to default ',nlevsoi,' layers.'
635687
do c = begc,endc
636688
col_pp%nlevbed(c) = nlevsoi
637689
col_pp%zibed(c) = zisoi(nlevsoi)

components/elm/src/main/surfrdMod.F90

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module surfrdMod
99
use shr_kind_mod , only : r8 => shr_kind_r8
1010
use shr_log_mod , only : errMsg => shr_log_errMsg
1111
use abortutils , only : endrun
12-
use elm_varpar , only : nlevsoifl, numpft, numcft
12+
use elm_varpar , only : numpft, numcft
1313
use landunit_varcon , only : numurbl
1414
use elm_varcon , only : grlnd
1515
use elm_varctl , only : iulog, scmlat, scmlon, single_column, firrig_data
@@ -712,7 +712,6 @@ subroutine surfrd_special(begg, endg, ncid, ns,ntpu)
712712
! !LOCAL VARIABLES:
713713
integer :: n,nl,nurb,g, t,tm,ti ! indices
714714
integer :: dimid,varid ! netCDF id's
715-
real(r8) :: nlevsoidata(nlevsoifl)
716715
logical :: found ! temporary for error check
717716
integer :: nindx ! temporary for error check
718717
integer :: ier ! error status
@@ -750,7 +749,6 @@ subroutine surfrd_special(begg, endg, ncid, ns,ntpu)
750749
allocate(pctglc_mec_tot(begg:endg,1:max_topounits))
751750
allocate(pctspec(begg:endg,1:max_topounits))
752751

753-
call check_dim(ncid, 'nlevsoi', nlevsoifl)
754752

755753
! Obtain non-grid surface properties of surface dataset other than percent pft
756754

@@ -1533,7 +1531,6 @@ subroutine surfrd_topounit_data(begg, endg, lfsurdat)
15331531
call getfil( lfsurdat, locfn, 0 )
15341532
call ncd_pio_openfile (ncid, trim(locfn), 0)
15351533

1536-
!call check_dim(ncid, 'nlevsoi', nlevsoifl)
15371534
call check_var(ncid=ncid, varname='MaxTopounitElv', vardesc=vardesc, readvar=readvar)
15381535
if (readvar) then
15391536
call ncd_io(ncid=ncid, varname='MaxTopounitElv', flag='read', data=maxTopoElv, &

0 commit comments

Comments
 (0)