1 | subroutine conductionQ(nz,z,dt,Qn,Qnp1,T,ti,rhoc,emiss,Tsurf, & |
---|
2 | & Fgeotherm,Fsurf) |
---|
3 | !*********************************************************************** |
---|
4 | ! conductionQ: program to calculate the diffusion of temperature |
---|
5 | ! into the ground and thermal emission at the surface |
---|
6 | ! with variable thermal properties on irregular grid |
---|
7 | ! Crank-Nicolson scheme, flux conservative |
---|
8 | ! uses Samar's radiation formula |
---|
9 | ! Eqn: rhoc*T_t = (k*T_z)_z |
---|
10 | ! BC (z=0): Q(t) + kT_z = em*sig*T^4 |
---|
11 | ! BC (z=L): heat flux = Fgeotherm |
---|
12 | ! |
---|
13 | ! nz = number of grid points |
---|
14 | ! dt = time step |
---|
15 | ! Qn,Qnp1 = net solar insolation at time steps n and n+1 [W/m^2] |
---|
16 | ! T = vertical temperature profile [K] (in- and output) |
---|
17 | ! ti = thermal inertia [J m^-2 K^-1 s^-1/2] VECTOR |
---|
18 | ! rhoc = rho*c VECTOR where rho=density [kg/m^3] and |
---|
19 | ! c=specific heat [J K^-1 kg^-1] |
---|
20 | ! ti and rhoc are not allowed to vary in the layers immediately |
---|
21 | ! adjacent to the surface or the bottom |
---|
22 | ! emiss = emissivity |
---|
23 | ! Tsurf = surface temperature [K] (in- and output) |
---|
24 | ! Fgeotherm = geothermal heat flux at bottom boundary [W/m^2] |
---|
25 | ! Fsurf = heat flux at surface [W/m^2] (output) |
---|
26 | ! |
---|
27 | ! Grid: surface is at z=0 |
---|
28 | ! z(0)=0, z(2)=3*z(1), i.e., the top layer has half the width |
---|
29 | ! T(1) is at z(1); ...; T(i) is at z(i) |
---|
30 | ! k(i), rhoc(i), ti(i) are midway between z(i-1) and z(i) |
---|
31 | ! |
---|
32 | ! originally written by Samar Khatiwala, 2001 |
---|
33 | ! extended to variable thermal properties |
---|
34 | ! and irregular grid by Norbert Schorghofer |
---|
35 | ! added predictor-corrector 9/2019 |
---|
36 | !*********************************************************************** |
---|
37 | |
---|
38 | implicit none |
---|
39 | real*8, parameter :: sigSB=5.6704d-8 |
---|
40 | |
---|
41 | integer, intent(IN) :: nz |
---|
42 | real*8, intent(IN) :: z(nz), dt, Qn, Qnp1, ti(nz),rhoc(nz) |
---|
43 | real*8, intent(IN) :: emiss, Fgeotherm |
---|
44 | real*8, intent(INOUT) :: T(nz), Tsurf |
---|
45 | real*8, intent(OUT) :: Fsurf |
---|
46 | integer i, iter |
---|
47 | real*8 k(nz), k1, alpha(nz), gamma(nz), Tr |
---|
48 | real*8 a(nz), b(nz), c(nz), r(nz), Told(nz) |
---|
49 | real*8 arad, brad, ann, annp1, bn, buf, dz, beta |
---|
50 | |
---|
51 | ! set some constants |
---|
52 | k(:) = ti(:)**2/rhoc(:) ! thermal conductivity |
---|
53 | dz = 2.*z(1) |
---|
54 | beta = dt/rhoc(1)/(2.*dz**2) ! assumes rhoc(0)=rhoc(1) |
---|
55 | alpha(1) = beta*k(2) |
---|
56 | gamma(1) = beta*k(1) |
---|
57 | do i=2,nz-1 |
---|
58 | buf = dt/(z(i+1)-z(i-1)) |
---|
59 | alpha(i) = 2.*k(i+1)*buf/(rhoc(i)+rhoc(i+1))/(z(i+1)-z(i)) |
---|
60 | gamma(i) = 2.*k(i)*buf/(rhoc(i)+rhoc(i+1))/(z(i)-z(i-1)) |
---|
61 | enddo |
---|
62 | buf = dt/(z(nz)-z(nz-1))**2 |
---|
63 | gamma(nz) = k(nz)*buf/(2*rhoc(nz)) ! assumes rhoc(nz+1)=rhoc(nz) |
---|
64 | |
---|
65 | k1 = k(1)/dz |
---|
66 | |
---|
67 | ! elements of tridiagonal matrix |
---|
68 | a(:) = -gamma(:) ! a(1) is not used |
---|
69 | b(:) = 1. + alpha(:) + gamma(:) ! b(1) has to be reset at every timestep |
---|
70 | c(:) = -alpha(:) ! c(nz) is not used |
---|
71 | b(nz) = 1. + gamma(nz) |
---|
72 | |
---|
73 | Tr = Tsurf ! 'reference' temperature |
---|
74 | iter = 0 |
---|
75 | Told(:) = T(:) |
---|
76 | 30 continue ! in rare case of iterative correction |
---|
77 | |
---|
78 | ! Emission |
---|
79 | arad = -3.*emiss*sigSB*Tr**4 |
---|
80 | brad = 2.*emiss*sigSB*Tr**3 |
---|
81 | ann = (Qn-arad)/(k1+brad) |
---|
82 | annp1 = (Qnp1-arad)/(k1+brad) |
---|
83 | bn = (k1-brad)/(k1+brad) |
---|
84 | b(1) = 1. + alpha(1) + gamma(1) - gamma(1)*bn |
---|
85 | |
---|
86 | ! Set RHS |
---|
87 | r(1) = gamma(1)*(annp1+ann) + & |
---|
88 | & (1.-alpha(1)-gamma(1)+gamma(1)*bn)*T(1) + alpha(1)*T(2) |
---|
89 | do concurrent (i=2:nz-1) |
---|
90 | r(i) = gamma(i)*T(i-1) + (1.-alpha(i)-gamma(i))*T(i)+ alpha(i)*T(i+1) |
---|
91 | enddo |
---|
92 | r(nz) = gamma(nz)*T(nz-1) + (1.-gamma(nz))*T(nz) & |
---|
93 | & + dt/rhoc(nz)*Fgeotherm/(z(nz)-z(nz-1)) ! assumes rhoc(nz+1)=rhoc(nz) |
---|
94 | |
---|
95 | ! Solve for T at n+1 |
---|
96 | call tridag(a,b,c,r,T,nz) ! update by tridiagonal inversion |
---|
97 | |
---|
98 | Tsurf = 0.5*(annp1 + bn*T(1) + T(1)) ! (T0+T1)/2 |
---|
99 | |
---|
100 | ! iterative predictor-corrector |
---|
101 | if ((Tsurf > 1.2*Tr .or. Tsurf < 0.8*Tr) .and. iter<10) then ! linearization error expected |
---|
102 | ! redo until Tr is within 20% of new surface temperature |
---|
103 | ! (under most circumstances, the 20% threshold is never exceeded) |
---|
104 | iter = iter+1 |
---|
105 | Tr = sqrt(Tr*Tsurf) ! linearize around an intermediate temperature |
---|
106 | T(:) = Told(:) |
---|
107 | goto 30 |
---|
108 | endif |
---|
109 | !if (iter>=5) print *,'consider taking shorter time steps',iter |
---|
110 | !if (iter>=10) print *,'warning: too many iterations' |
---|
111 | |
---|
112 | Fsurf = - k(1)*(T(1)-Tsurf)/z(1) ! heat flux into surface |
---|
113 | end subroutine conductionQ |
---|