source: trunk/LMDZ.COMMON/libf/evolution/maths.F90 @ 4110

Last change on this file since 4110 was 4110, checked in by jbclement, 3 days ago

PEM:

  • Introduction of a configurable display/logging system with options 'out2term', 'out2log', 'verbosity_lvl'. All messages now use verbosity levels ('LVL_NFO', 'LVL_WRN', 'LVL_ERR' and 'LVL_DBG').
  • Code encapsulation improvements with systematic privacy/protection of module variables.
  • Addition of workflow safety checks for required executables, dependencies (e.g. 'ncdump'), input files and callphys keys.
  • Renaming of PEM starting and diagnostic files ("startevol.nc" into "startevo.nc", "diagevol.nc" into "diagevo.nc").

JBC

File size: 10.2 KB
Line 
1module maths
2!-----------------------------------------------------------------------
3! NAME
4!     maths
5!
6! DESCRIPTION
7!     The module contains all the mathematical subroutines used in the PEM.
8!
9! AUTHORS & DATE
10!     L. Lange
11!     JB Clement, 2023-2025
12!
13! NOTES
14!     Adapted from Schorghofer MSIM (N.S, Icarus 2010)
15!-----------------------------------------------------------------------
16
17! DEPENDENCIES
18! ------------
19use numerics, only: dp, di, k4, minieps
20
21! DECLARATION
22! -----------
23implicit none
24
25! PARAMETERS
26! ----------
27real(dp), parameter :: pi = 4._dp*atan(1._dp) ! PI = 3.14159...
28
29contains
30!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31
32!=======================================================================
33SUBROUTINE deriv1(z,nz,y,y0,ybot,dzY)
34!-----------------------------------------------------------------------
35! NAME
36!     deriv1
37!
38! DESCRIPTION
39!     Compute the first derivative of a function y(z) on an irregular grid.
40!
41! AUTHORS & DATE
42!     N.S (Icarus 2010)
43!     L. Lange
44!     JB Clement, 2023-2025
45!
46! NOTES
47!     Upper boundary conditions: y(0) = y0
48!     Lower boundary condition: yp = ybottom
49!-----------------------------------------------------------------------
50
51! DECLARATION
52! -----------
53implicit none
54
55! ARGUMENTS
56! ---------
57integer(di),             intent(in)  :: nz       ! number of layer
58real(dp), dimension(nz), intent(in)  :: z        ! depth layer
59real(dp), dimension(nz), intent(in)  :: y        ! function which needs to be derived
60real(dp),                intent(in)  :: y0, ybot ! boundary conditions
61real(dp), dimension(nz), intent(out) :: dzY      ! derivative of y w.r.t depth
62
63! LOCAL VARIABLES
64! ---------------
65integer(di) :: j
66real(dp)    :: hm, hp, c1, c2, c3
67
68! CODE
69! ----
70hp = z(2) - z(1)
71c1 = z(1)/(hp*z(2))
72c2 = 1/z(1) - 1/(z(2) - z(1))
73c3 = -hp/(z(1)*z(2))
74dzY(1) = c1*y(2) + c2*y(1) + c3*y0
75do j = 2,nz - 1
76    hp = z(j + 1) - z(j)
77    hm = z(j) - z(j - 1)
78    c1 = +hm/(hp*(z(j + 1) - z(j - 1)))
79    c2 = 1._dp/hm - 1._dp/hp
80    c3 = -hp/(hm*(z(j + 1) - z(j - 1)))
81    dzY(j) = c1*y(j + 1) + c2*y(j) + c3*y(j - 1)
82end do
83dzY(nz) = (ybot - y(nz - 1))/(2._dp*(z(nz) - z(nz - 1)))
84
85END SUBROUTINE deriv1
86!=======================================================================
87
88!=======================================================================
89SUBROUTINE deriv2_simple(z,nz,y,y0,yNp1,yp2)
90!-----------------------------------------------------------------------
91! NAME
92!     deriv2_simple
93!
94! DESCRIPTION
95!     Compute the second derivative of a function y(z) on an irregular grid.
96!
97! AUTHORS & DATE
98!     N.S (Icarus 2010)
99!     JB Clement, 2023-2025
100!
101! NOTES
102!     Boundary conditions: y(0) = y0, y(nz + 1) = yNp1
103!-----------------------------------------------------------------------
104
105! DECLARATION
106! -----------
107implicit none
108
109! ARGUMENTS
110! ---------
111integer(di),             intent(in)  :: nz
112real(dp), dimension(nz), intent(in)  :: z, y
113real(dp),                intent(in)  :: y0, yNp1
114real(dp), dimension(nz), intent(out) :: yp2
115
116! LOCAL VARIABLES
117! ---------------
118integer(di) :: j
119real(dp)    :: hm, hp, c1, c2, c3
120
121! CODE
122! ----
123c1 = +2._dp/((z(2) - z(1))*z(2))
124c2 = -2._dp/((z(2) - z(1))*z(1))
125c3 = +2._dp/(z(1)*z(2))
126yp2(1) = c1*y(2) + c2*y(1) + c3*y0
127do j = 2,nz - 1
128    hp = z(j + 1) - z(j)
129    hm = z(j) - z(j - 1)
130    c1 = +2._dp/(hp*(z(j + 1) - z(j - 1)))
131    c2 = -2._dp/(hp*hm)
132    c3 = +2._dp/(hm*(z(j + 1) - z(j - 1)))
133    yp2(j) = c1*y(j + 1) + c2*y(j) + c3*y(j - 1)
134end do
135yp2(nz) = (yNp1 - 2._dp*y(nz) + y(nz - 1))/(z(nz) - z(nz - 1))**2
136
137END SUBROUTINE deriv2_simple
138!=======================================================================
139
140!=======================================================================
141SUBROUTINE  deriv1_onesided(j,z,nz,y,dy_zj)
142!-----------------------------------------------------------------------
143! NAME
144!     deriv1_onesided
145!
146! DESCRIPTION
147!     First derivative of function y(z) at z(j) one-sided derivative
148!     on irregular grid.
149!
150! AUTHORS & DATE
151!     N.S (Icarus 2010)
152!     JB Clement, 2023-2025
153!
154! NOTES
155!
156!-----------------------------------------------------------------------
157
158! DECLARATION
159! -----------
160implicit none
161
162! ARGUMENTS
163! ---------
164integer(di),             intent(in)  :: nz, j
165real(dp), dimension(nz), intent(in)  :: z, y
166real(dp),                intent(out) :: dy_zj
167
168! LOCAL VARIABLES
169! ---------------
170real(dp) :: h1, h2, c1, c2, c3
171
172! CODE
173! ----
174if (j < 1 .or. j > nz - 2) then
175    dy_zj = -1._dp
176else
177    h1 = z(j + 1) - z(j)
178    h2 = z(j + 2)- z(j + 1)
179    c1 = -(2._dp*h1 + h2)/(h1*(h1 + h2))
180    c2 = (h1 + h2)/(h1*h2)
181    c3 = -h1/(h2*(h1 + h2))
182    dy_zj = c1*y(j) + c2*y(j + 1) + c3*y(j + 2)
183end if
184
185END SUBROUTINE deriv1_onesided
186!=======================================================================
187
188!=======================================================================
189PURE SUBROUTINE colint(y,z,nz,i1,i2,integral)
190!-----------------------------------------------------------------------
191! NAME
192!     colint
193!
194! DESCRIPTION
195!     Column integrates y on irregular grid.
196!
197! AUTHORS & DATE
198!     N.S (Icarus 2010)
199!     JB Clement, 2023-2025
200!
201! NOTES
202!
203!-----------------------------------------------------------------------
204
205! DECLARATION
206! -----------
207implicit none
208
209! ARGUMENTS
210! ---------
211integer(di),             intent(in)  :: nz, i1, i2
212real(dp), dimension(nz), intent(in)  :: y, z
213real(dp),                intent(out) :: integral
214
215! LOCAL VARIABLES
216! ---------------
217integer(di)             :: i
218real(dp), dimension(nz) :: dz
219
220! CODE
221! ----
222dz(1) = (z(2) - 0.)/2
223do i = 2,nz - 1
224    dz(i) = (z(i + 1) - z(i - 1))/2.
225end do
226dz(nz) = z(nz) - z(nz - 1)
227integral = sum(y(i1:i2)*dz(i1:i2))
228
229END SUBROUTINE colint
230!=======================================================================
231
232!=======================================================================
233SUBROUTINE findroot(y1,y2,z1,z2,zr)
234!-----------------------------------------------------------------------
235! NAME
236!     findroot
237!
238! DESCRIPTION
239!     Compute the root zr, between two values y1 and y2 at depth z1,z2.
240!
241! AUTHORS & DATE
242!     L. Lange
243!     JB Clement, 2023-2025
244!
245! NOTES
246!
247!-----------------------------------------------------------------------
248
249! DECLARATION
250! -----------
251implicit none
252
253! ARGUMENTS
254! ---------
255real(dp), intent(in)  :: y1, y2
256real(dp), intent(in)  :: z1, z2
257real(dp), intent(out) :: zr
258
259! CODE
260! ----
261zr = (y1*z2 - y2*z1)/(y1 - y2)
262
263END SUBROUTINE findroot
264!=======================================================================
265
266!=======================================================================
267SUBROUTINE solve_tridiag(a,b,c,d,n,x,error)
268!-----------------------------------------------------------------------
269! NAME
270!     solve_tridiag
271!
272! DESCRIPTION
273!     Solve a tridiagonal system Ax = d using the Thomas' algorithm
274!     a: sub-diagonal
275!     b: main diagonal
276!     c: super-diagonal
277!     d: right-hand side
278!     x: solution
279!
280! AUTHORS & DATE
281!     JB Clement, 2025
282!
283! NOTES
284!
285!-----------------------------------------------------------------------
286
287! DECLARATION
288! -----------
289implicit none
290
291! ARGUMENTS
292! ---------
293integer(di),                intent(in)  :: n
294real(dp), dimension(n),     intent(in)  :: b, d
295real(dp), dimension(n - 1), intent(in)  :: a, c
296real(dp), dimension(n),     intent(out) :: x
297integer(di),                intent(out) :: error
298
299! LOCAL VARIABLES
300! ---------------
301integer(di)            :: i
302real(dp)               :: m
303real(dp), dimension(n) :: cp, dp
304
305! CODE
306! ----
307! Check stability: diagonally dominant condition
308error = 0
309if (abs(b(1)) < abs(c(1))) then
310    error = 1
311    return
312end if
313do i = 2,n - 1
314    if (abs(b(i)) < abs(a(i - 1)) + abs(c(i))) then
315        error = 1
316        return
317    end if
318end do
319if (abs(b(n)) < abs(a(n - 1))) then
320    error = 1
321    return
322end if
323
324! Initialization
325cp(1) = c(1)/b(1)
326dp(1) = d(1)/b(1)
327
328! Forward sweep
329do i = 2,n - 1
330    m = b(i) - a(i - 1)*cp(i - 1)
331    cp(i) = c(i)/m
332    dp(i) = (d(i) - a(i - 1)*dp(i - 1))/m
333end do
334m = b(n) - a(n - 1)*cp(n - 1)
335dp(n) = (d(n) - a(n - 1)*dp(n - 1))/m
336
337! Backward substitution
338x(n) = dp(n)
339do i = n - 1,1,-1
340    x(i) = dp(i) - cp(i)*x(i + 1)
341end do
342
343END SUBROUTINE solve_tridiag
344!=======================================================================
345
346!=======================================================================
347SUBROUTINE solve_steady_heat(n,z,mz,kappa,mkappa,T_left,q_right,T)
348!-----------------------------------------------------------------------
349! NAME
350!     solve_steady_heat
351!
352! DESCRIPTION
353!     Solve 1D steady-state heat equation with space-dependent thermal diffusivity.
354!     Uses Thomas algorithm to solve tridiagonal system.
355!     Left boundary: prescribed temperature (Dirichlet).
356!     Right boundary: prescribed thermal flux (Neumann).
357!
358! AUTHORS & DATE
359!     JB Clement, 2025
360!
361! NOTES
362!     Grid points at z, mid-grid points at mz.
363!     Thermal diffusivity specified at both grids (kappa, mkappa).
364!-----------------------------------------------------------------------
365
366! DEPENDENCIES
367! ------------
368use stoppage, only: stop_clean
369
370! DECLARATION
371! -----------
372implicit none
373
374! ARGUMENTS
375! ---------
376integer(di),                intent(in)  :: n
377real(dp), dimension(n),     intent(in)  :: z, kappa
378real(dp), dimension(n - 1), intent(in)  :: mz, mkappa
379real(dp),                   intent(in)  :: T_left, q_right
380real(dp), dimension(n),     intent(out) :: T
381
382! LOCAL VARIABLES
383! ---------------
384integer(di)                :: i, error
385real(dp), dimension(n)     :: b, d
386real(dp), dimension(n - 1) :: a, c
387
388! CODE
389! ----
390! Initialization
391a = 0._dp; b = 0._dp; c = 0._dp; d = 0._dp
392
393! Left boundary condition (Dirichlet: prescribed temperature)
394b(1) = 1._dp
395d(1) = T_left
396
397! Internal points
398do i = 2,n - 1
399    a(i - 1) = -mkappa(i - 1)/((mz(i) - mz(i - 1))*(z(i) - z(i - 1)))
400    c(i) = -mkappa(i)/((mz(i) - mz(i - 1))*(z(i + 1) - z(i)))
401    b(i) = -(a(i - 1) + c(i))
402end do
403
404! Right boundary condition (Neumann: prescribed temperature)
405a(n - 1) = kappa(n - 1)/(z(n) - z(n - 1))
406b(n) = -kappa(n)/(z(n) - z(n - 1))
407d(n) = q_right
408
409! Solve the tridiagonal linear system with the Thomas' algorithm
410call solve_tridiag(a,b,c,d,n,T,error)
411if (error /= 0) call stop_clean(__FILE__,__LINE__,"unstable solving!",1)
412
413END SUBROUTINE solve_steady_heat
414!=======================================================================
415
416end module maths
Note: See TracBrowser for help on using the repository browser.