2 |
|
|
3 |
IMPLICIT NONE |
IMPLICIT NONE |
4 |
|
|
5 |
|
private fz |
6 |
|
|
7 |
contains |
contains |
8 |
|
|
9 |
SUBROUTINE soil(nisurf, snow, tsurf, tsoil, soilcap, soilflux) |
SUBROUTINE soil(nisurf, snow, tsurf, tsoil, soilcap, soilflux) |
33 |
! F0 = A + B (Ts(t)) |
! F0 = A + B (Ts(t)) |
34 |
! Soilcap = B * dt |
! Soilcap = B * dt |
35 |
|
|
36 |
|
! Libraries: |
37 |
|
use jumble, only: new_unit |
38 |
|
|
39 |
use comconst, only: dtphys |
use comconst, only: dtphys |
|
USE indicesol, only: nbsrf, is_lic, is_oce, is_sic, is_ter |
|
40 |
USE dimphy, only: klon |
USE dimphy, only: klon |
41 |
USE dimsoil, only: nsoilmx |
USE dimsoil, only: nsoilmx |
42 |
|
USE indicesol, only: nbsrf, is_lic, is_oce, is_sic, is_ter |
43 |
USE suphec_m, only: rtt |
USE suphec_m, only: rtt |
44 |
|
|
45 |
INTEGER, intent(in):: nisurf ! sub-surface index |
INTEGER, intent(in):: nisurf ! surface type index |
46 |
REAL, intent(in):: snow(:) ! (knon) |
REAL, intent(in):: snow(:) ! (knon) |
47 |
REAL, intent(in):: tsurf(:) ! (knon) surface temperature at time-step t (K) |
REAL, intent(in):: tsurf(:) ! (knon) surface temperature at time-step t (K) |
48 |
|
|
49 |
real, intent(inout):: tsoil(:, :) ! (knon, nsoilmx) |
real, intent(inout):: tsoil(:, :) ! (knon, nsoilmx) |
50 |
! temperature inside the ground (K) |
! temperature inside the ground (K), layer 1 nearest to the surface |
51 |
|
|
52 |
REAL, intent(out):: soilcap(:) ! (knon) |
REAL, intent(out):: soilcap(:) ! (knon) |
53 |
! specific heat per unit surface (W m-2 s K-1) |
! specific heat per unit surface (W m-2 s K-1) |
56 |
! surface diffusive flux from ground (W m-2) |
! surface diffusive flux from ground (W m-2) |
57 |
|
|
58 |
! Local: |
! Local: |
59 |
|
INTEGER knon, ig, jk, unit |
|
INTEGER knon, ig, jk |
|
60 |
REAL zdz2(nsoilmx) |
REAL zdz2(nsoilmx) |
61 |
real z1(size(tsurf), nbsrf) ! (knon, nbsrf) |
real z1(size(tsurf), nbsrf) ! (knon, nbsrf) |
62 |
REAL min_period, dalph_soil |
REAL min_period ! in s |
63 |
|
real dalph_soil ! rapport entre les \'epaisseurs de 2 couches successives |
64 |
REAL ztherm_i(size(tsurf)) ! (knon) |
REAL ztherm_i(size(tsurf)) ! (knon) |
65 |
REAL, save:: dz1(nsoilmx), dz2(nsoilmx) |
REAL, save:: dz1(nsoilmx), dz2(nsoilmx) |
66 |
REAL, save:: zc(klon, nsoilmx, nbsrf), zd(klon, nsoilmx, nbsrf) |
REAL, save:: zc(klon, nsoilmx, nbsrf), zd(klon, nsoilmx, nbsrf) |
67 |
REAL, save:: lambda |
REAL, save:: lambda |
68 |
LOGICAL:: firstsurf(nbsrf) = .TRUE. |
LOGICAL:: firstsurf(nbsrf) = .TRUE. |
69 |
REAL:: isol = 2000., isno = 2000., iice = 2000. |
REAL, parameter:: isol = 2000., isno = 2000., iice = 2000. |
70 |
|
REAL rk, fz1, rk1, rk2 ! depths |
|
! Depths: |
|
|
REAL rk, fz1, rk1, rk2 |
|
71 |
|
|
72 |
!----------------------------------------------------------------------- |
!----------------------------------------------------------------------- |
73 |
|
|
74 |
knon = size(tsurf) |
knon = size(tsurf) |
75 |
|
|
76 |
! Calcul de l'inertie thermique. On initialise \`a iice m\^eme |
! Calcul de l'inertie thermique. On initialise \`a iice m\^eme |
77 |
! au-dessus d'un point de mer au cas o\`u le point de mer devienne |
! au-dessus d'un point de mer pour le cas o\`u le point de mer |
78 |
! point de glace au pas suivant. On corrige si on a un point de |
! deviendrait point de glace au pas suivant. On corrige si on a un |
79 |
! terre avec ou sans glace. |
! point de terre avec ou sans glace. |
80 |
|
|
81 |
IF (nisurf==is_sic) THEN |
select case (nisurf) |
82 |
DO ig = 1, knon |
case (is_sic) |
83 |
ztherm_i(ig) = iice |
DO ig = 1, knon |
84 |
IF (snow(ig) > 0.) ztherm_i(ig) = isno |
IF (snow(ig) > 0.) then |
85 |
END DO |
ztherm_i(ig) = isno |
86 |
ELSE IF (nisurf==is_lic) THEN |
else |
87 |
DO ig = 1, knon |
ztherm_i(ig) = iice |
88 |
ztherm_i(ig) = iice |
end IF |
89 |
IF (snow(ig) > 0.) ztherm_i(ig) = isno |
END DO |
90 |
|
case (is_lic) |
91 |
|
DO ig = 1, knon |
92 |
|
IF (snow(ig) > 0.) then |
93 |
|
ztherm_i(ig) = isno |
94 |
|
else |
95 |
|
ztherm_i(ig) = iice |
96 |
|
end IF |
97 |
|
END DO |
98 |
|
case (is_ter) |
99 |
|
DO ig = 1, knon |
100 |
|
IF (snow(ig) > 0.) then |
101 |
|
ztherm_i(ig) = isno |
102 |
|
else |
103 |
|
ztherm_i(ig) = isol |
104 |
|
end IF |
105 |
END DO |
END DO |
106 |
ELSE IF (nisurf==is_ter) THEN |
case (is_oce) |
|
DO ig = 1, knon |
|
|
ztherm_i(ig) = isol |
|
|
IF (snow(ig) > 0.) ztherm_i(ig) = isno |
|
|
END DO |
|
|
ELSE IF (nisurf==is_oce) THEN |
|
107 |
DO ig = 1, knon |
DO ig = 1, knon |
108 |
ztherm_i(ig) = iice |
ztherm_i(ig) = iice |
109 |
END DO |
END DO |
110 |
ELSE |
case default |
111 |
PRINT *, 'valeur d indice non prevue', nisurf |
PRINT *, 'soil: unexpected subscript value:', nisurf |
112 |
STOP 1 |
STOP 1 |
113 |
END IF |
END select |
114 |
|
|
115 |
IF (firstsurf(nisurf)) THEN |
IF (firstsurf(nisurf)) THEN |
116 |
! ground levels |
! ground levels |
117 |
! grnd=z / l where l is the skin depth of the diurnal cycle: |
! grnd=z / l where l is the skin depth of the diurnal cycle: |
118 |
|
|
119 |
min_period = 1800. ! en secondes |
min_period = 1800. |
120 |
dalph_soil = 2. ! rapport entre les epaisseurs de 2 couches succ. |
dalph_soil = 2. |
121 |
|
call new_unit(unit) |
122 |
OPEN(99, FILE='soil.def', STATUS='old', FORM='formatted', ERR=9999) |
OPEN(unit, FILE = 'soil.def', STATUS = 'old', action = "read", & |
123 |
READ(99, *) min_period |
position = 'rewind', ERR = 9999) |
124 |
READ(99, *) dalph_soil |
READ(unit, fmt = *) min_period |
125 |
|
READ(unit, fmt = *) dalph_soil |
126 |
PRINT *, 'Discretization for the soil model' |
PRINT *, 'Discretization for the soil model' |
127 |
PRINT *, 'First level e-folding depth', min_period, ' dalph', & |
PRINT *, 'First level e-folding depth', min_period, ' dalph', & |
128 |
dalph_soil |
dalph_soil |
129 |
CLOSE(99) |
CLOSE(unit) |
130 |
9999 CONTINUE |
9999 CONTINUE |
131 |
|
|
132 |
! la premiere couche represente un dixieme de cycle diurne |
! La premi\`ere couche repr\'esente un dixi\`eme de cycle diurne : |
133 |
fz1 = sqrt(min_period / 3.14) |
fz1 = sqrt(min_period / 3.14) |
134 |
|
|
135 |
DO jk = 1, nsoilmx |
DO jk = 1, nsoilmx |
136 |
rk1 = jk |
rk1 = jk |
137 |
rk2 = jk - 1 |
rk2 = jk - 1 |
138 |
dz2(jk) = fz(rk1) - fz(rk2) |
dz2(jk) = fz(rk1, dalph_soil, fz1) - fz(rk2, dalph_soil, fz1) |
139 |
END DO |
END DO |
140 |
|
|
141 |
DO jk = 1, nsoilmx - 1 |
DO jk = 1, nsoilmx - 1 |
142 |
rk1 = jk + .5 |
rk1 = jk + .5 |
143 |
rk2 = jk - .5 |
rk2 = jk - .5 |
144 |
dz1(jk) = 1. / (fz(rk1) - fz(rk2)) |
dz1(jk) = 1. / (fz(rk1, dalph_soil, fz1) - fz(rk2, dalph_soil, fz1)) |
145 |
END DO |
END DO |
146 |
lambda = fz(.5) * dz1(1) |
|
147 |
|
lambda = fz(.5, dalph_soil, fz1) * dz1(1) |
148 |
PRINT *, 'full layers, intermediate layers (seconds)' |
PRINT *, 'full layers, intermediate layers (seconds)' |
149 |
|
|
150 |
DO jk = 1, nsoilmx |
DO jk = 1, nsoilmx |
151 |
rk = jk |
rk = jk |
152 |
rk1 = jk + .5 |
rk1 = jk + .5 |
153 |
rk2 = jk - .5 |
rk2 = jk - .5 |
154 |
PRINT *, 'fz=', fz(rk1) * fz(rk2) * 3.14, fz(rk) * fz(rk) * 3.14 |
PRINT *, 'fz=', fz(rk1, dalph_soil, fz1) * fz(rk2, dalph_soil, fz1) & |
155 |
|
* 3.14, fz(rk, dalph_soil, fz1) * fz(rk, dalph_soil, fz1) * 3.14 |
156 |
END DO |
END DO |
157 |
! PB |
|
158 |
firstsurf(nisurf) = .FALSE. |
firstsurf(nisurf) = .FALSE. |
159 |
ELSE |
ELSE |
160 |
! Computation of the soil temperatures using the Zc and Zd |
! Computation of the soil temperatures using the Zc and Zd |
161 |
! coefficient computed at the previous time-step: |
! coefficient computed at the previous time-step: |
162 |
|
|
163 |
! surface temperature |
! Surface temperature: |
164 |
DO ig = 1, knon |
DO ig = 1, knon |
165 |
tsoil(ig, 1) = (lambda * zc(ig, 1, nisurf) + tsurf(ig)) & |
tsoil(ig, 1) = (lambda * zc(ig, 1, nisurf) + tsurf(ig)) & |
166 |
/ (lambda * (1. - zd(ig, 1, nisurf)) + 1.) |
/ (lambda * (1. - zd(ig, 1, nisurf)) + 1.) |
167 |
END DO |
END DO |
168 |
|
|
169 |
! other temperatures |
! Other temperatures: |
170 |
DO jk = 1, nsoilmx - 1 |
DO jk = 1, nsoilmx - 1 |
171 |
DO ig = 1, knon |
DO ig = 1, knon |
172 |
tsoil(ig, jk + 1) = zc(ig, jk, nisurf) & |
tsoil(ig, jk + 1) = zc(ig, jk, nisurf) & |
204 |
END DO |
END DO |
205 |
END DO |
END DO |
206 |
|
|
207 |
! computation of the surface diffusive flux from ground and |
! Computation of the surface diffusive flux from ground and |
208 |
! calorific capacity of the ground: |
! calorific capacity of the ground: |
209 |
|
|
210 |
DO ig = 1, knon |
DO ig = 1, knon |
211 |
soilflux(ig) = ztherm_i(ig) * dz1(1) * (zc(ig, 1, nisurf) + (zd(ig, 1, & |
soilflux(ig) = ztherm_i(ig) * dz1(1) * (zc(ig, 1, nisurf) & |
212 |
nisurf) - 1.) * tsoil(ig, 1)) |
+ (zd(ig, 1, nisurf) - 1.) * tsoil(ig, 1)) |
213 |
soilcap(ig) = ztherm_i(ig) * (dz2(1) & |
soilcap(ig) = ztherm_i(ig) * (dz2(1) & |
214 |
+ dtphys * (1. - zd(ig, 1, nisurf)) * dz1(1)) |
+ dtphys * (1. - zd(ig, 1, nisurf)) * dz1(1)) |
215 |
z1(ig, nisurf) = lambda * (1. - zd(ig, 1, nisurf)) + 1. |
z1(ig, nisurf) = lambda * (1. - zd(ig, 1, nisurf)) + 1. |
218 |
* z1(ig, nisurf) - lambda * zc(ig, 1, nisurf) - tsurf(ig)) / dtphys |
* z1(ig, nisurf) - lambda * zc(ig, 1, nisurf) - tsurf(ig)) / dtphys |
219 |
END DO |
END DO |
220 |
|
|
221 |
contains |
END SUBROUTINE soil |
222 |
|
|
223 |
|
!**************************************************************** |
224 |
|
|
225 |
pure real function fz(rk) |
pure real function fz(rk, dalph_soil, fz1) |
226 |
|
|
227 |
real, intent(in):: rk |
real, intent(in):: rk |
228 |
|
|
229 |
!----------------------------------------- |
real, intent(in):: dalph_soil |
230 |
|
! rapport entre les \'epaisseurs de 2 couches successives |
231 |
|
|
232 |
fz = fz1 * (dalph_soil**rk - 1.) / (dalph_soil - 1.) |
real, intent(in):: fz1 ! depth |
233 |
|
|
234 |
end function fz |
!----------------------------------------- |
235 |
|
|
236 |
END SUBROUTINE soil |
fz = fz1 * (dalph_soil**rk - 1.) / (dalph_soil - 1.) |
237 |
|
|
238 |
|
end function fz |
239 |
|
|
240 |
end module soil_m |
end module soil_m |