FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
tridiagonal.inc
1!***********************************************************************
2!* GNU Lesser General Public License
3!*
4!* This file is part of the GFDL Flexible Modeling System (FMS).
5!*
6!* FMS is free software: you can redistribute it and/or modify it under
7!* the terms of the GNU Lesser General Public License as published by
8!* the Free Software Foundation, either version 3 of the License, or (at
9!* your option) any later version.
10!*
11!* FMS is distributed in the hope that it will be useful, but WITHOUT
12!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14!* for more details.
15!*
16!* You should have received a copy of the GNU Lesser General Public
17!* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18!***********************************************************************
19
20!> @addtogroup tridiagonal_mod
21!> @{
22
23!> @brief Sets up and solves the tridiagonal system of equations
24!!
25!> For simplicity, A and C are assumed to be dimensioned the same size
26!! as B, D, and X, although any input values for A(N) and C(1) are ignored.
27!! There are no checks to make sure the sizes agree.
28!!
29!! The value of A(N) is modified on output, and B and C are unchanged.
30!!
31!! For mixed precision, this routine uses the kind size macro(FMS_TRID_KIND_) to determine
32!! which module variables are used/stored. This means a,b, and c values will only be stored for calls
33!! of the same real kind value unless store_both_kinds is present and .true..
34subroutine tri_invert_(x,d,a,b,c, store_both_kinds)
35
36 real(FMS_TRID_KIND_), intent(out), dimension(:,:,:) :: x !< Solution to the tridiagonal system of equations
37 real(FMS_TRID_KIND_), intent(in), dimension(:,:,:) :: d !< The right-hand side term, see the schematic above.
38 real(FMS_TRID_KIND_), optional, dimension(:,:,:) :: a,b,c !< Left hand side terms(see schematic on module page).
39 !! If not provided, values from last call are used
40 logical, optional :: store_both_kinds !< Will save module state
41 !! variables for both kind types in order to be used in
42 !! subsequent calls with either kind.
43
44 real(FMS_TRID_KIND_), dimension(size(x,1),size(x,2),size(x,3)) :: f
45 integer, parameter :: kindl = fms_trid_kind_
46
47 integer :: k
48
49 if(present(a)) then
50 !$OMP SINGLE
51 init_var = .true.
52 if(allocated(trid_real_type%e)) deallocate(trid_real_type%e)
53 if(allocated(trid_real_type%g)) deallocate(trid_real_type%g)
54 if(allocated(trid_real_type%bb)) deallocate(trid_real_type%bb)
55 if(allocated(trid_real_type%cc)) deallocate(trid_real_type%cc)
56 allocate(trid_real_type%e (size(x,1),size(x,2),size(x,3)))
57 allocate(trid_real_type%g (size(x,1),size(x,2),size(x,3)))
58 allocate(trid_real_type%bb(size(x,1),size(x,2)))
59 allocate(trid_real_type%cc(size(x,1),size(x,2),size(x,3)))
60 !$OMP END SINGLE
61
62 trid_real_type%e(:,:,1) = - a(:,:,1) / b(:,:,1)
63 a(:,:,size(x,3)) = 0.0_kindl
64
65 do k= 2,size(x,3)
66 trid_real_type%g(:,:,k) = 1.0_kindl/(b(:,:,k)+c(:,:,k)*trid_real_type%e(:,:,k-1))
67 trid_real_type%e(:,:,k) = - a(:,:,k)* trid_real_type%g(:,:,k)
68 end do
69 trid_real_type%cc = c
70 trid_real_type%bb = 1.0_kindl/b(:,:,1)
71
72 end if
73
74 if(.not.init_var) call mpp_error(fatal, 'tri_invert: a,b,and c args not provided or previously calculated.')
75
76 f(:,:,1) = d(:,:,1)*trid_real_type%bb
77 do k= 2, size(x,3)
78 f(:,:,k) = (d(:,:,k) - trid_real_type%cc(:,:,k)*f(:,:,k-1))*trid_real_type%g(:,:,k)
79 end do
80
81 x(:,:,size(x,3)) = f(:,:,size(x,3))
82 do k = size(x,3)-1,1,-1
83 x(:,:,k) = trid_real_type%e(:,:,k)*x(:,:,k+1)+f(:,:,k)
84 end do
85
86 ! stores both kind values for subsequent calculations if running with option
87 if( present(store_both_kinds)) then
88 if( store_both_kinds ) then
89 if( fms_trid_kind_ .eq. r8_kind) then
90 tridiag_r4%e = real(trid_real_type%e, r4_kind)
91 tridiag_r4%g = real(trid_real_type%g, r4_kind)
92 tridiag_r4%cc = real(trid_real_type%cc, r4_kind)
93 tridiag_r4%bb = real(trid_real_type%bb, r4_kind)
94 init_tridiagonal_r4 = .true.
95 else
96 tridiag_r8%e = real(trid_real_type%e, r8_kind)
97 tridiag_r8%g = real(trid_real_type%g, r8_kind)
98 tridiag_r8%cc = real(trid_real_type%cc, r8_kind)
99 tridiag_r8%bb = real(trid_real_type%bb, r8_kind)
100 init_tridiagonal_r8 = .true.
101 endif
102 endif
103 endif
104
105 return
106end subroutine TRI_INVERT_
subroutine tri_invert_(x, d, a, b, c, store_both_kinds)
Sets up and solves the tridiagonal system of equations.