forked from xcompact3d/x3d2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtime_integrator.f90
162 lines (129 loc) · 4.06 KB
/
time_integrator.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
module m_time_integrator
use m_allocator, only: allocator_t, field_t, flist_t
use m_base_backend, only: base_backend_t
use m_common, only: dp, DIR_X
implicit none
private adams_bashforth
type :: time_intg_t
integer :: istep, order, nvars, nolds
real(dp) :: coeffs(4, 4)
type(flist_t), allocatable :: olds(:, :)
type(flist_t), allocatable :: curr(:)
type(flist_t), allocatable :: deriv(:)
class(base_backend_t), pointer :: backend
class(allocator_t), pointer :: allocator
contains
procedure :: step
procedure :: adams_bashforth
end type time_intg_t
interface time_intg_t
module procedure init
end interface time_intg_t
contains
function init(backend, allocator, order, nvars)
implicit none
type(time_intg_t) :: init
class(base_backend_t), pointer :: backend
class(allocator_t), pointer :: allocator
integer, intent(in), optional :: order
integer, intent(in), optional :: nvars
integer :: i, j
! initialize Adams-Bashforth coefficients
init%coeffs(:, 1) = [1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp]
init%coeffs(:, 2) = [1.5_dp, -0.5_dp, 0.0_dp, 0.0_dp]
init%coeffs(:, 3) = &
[23._dp/12._dp, -4._dp/3._dp, 5._dp/12._dp, 0.0_dp]
init%coeffs(:, 4) = &
[55._dp/24._dp, -59._dp/24._dp, 37._dp/24._dp, -3._dp/8._dp]
! set variables
init%backend => backend
init%allocator => allocator
if (present(order)) then
init%order = order
else
init%order = 1
end if
if (present(nvars)) then
init%nvars = nvars
else
init%nvars = 3
end if
init%istep = 1
init%nolds = init%order - 1
! allocate memory
allocate (init%olds(init%nvars, init%nolds))
allocate (init%curr(init%nvars))
allocate (init%deriv(init%nvars))
! Request all the storage for old timesteps
do i = 1, init%nvars
do j = 1, init%nolds
init%olds(i, j)%ptr => allocator%get_block(DIR_X)
end do
end do
end function init
subroutine step(self, u, v, w, du, dv, dw, dt)
implicit none
class(time_intg_t), intent(inout) :: self
class(field_t), target, intent(inout) :: u, v, w
class(field_t), target, intent(in) :: du, dv, dw
real(dp), intent(in) :: dt
! assign pointer to variables
self%curr(1)%ptr => u
self%curr(2)%ptr => v
self%curr(3)%ptr => w
! assign pointer to variables
self%deriv(1)%ptr => du
self%deriv(2)%ptr => dv
self%deriv(3)%ptr => dw
call self%adams_bashforth(dt)
! increment step counter
self%istep = self%istep + 1
end subroutine step
subroutine adams_bashforth(self, dt)
class(time_intg_t), intent(inout) :: self
real(dp), intent(in) :: dt
integer :: i, j
integer :: order
order = min(self%istep, self%order)
do i = 1, self%nvars
! update solution
call self%backend%vecadd(self%coeffs(1, order)*dt, &
self%deriv(i)%ptr, &
1._dp, self%curr(i)%ptr)
do j = 2, order
call self%backend%vecadd(self%coeffs(j, order)*dt, &
self%olds(i, j - 1)%ptr, &
1._dp, self%curr(i)%ptr)
end do
! rotate pointers
if (order < self%order) then
! for startup
if (self%istep > 1) then
call rotate(self%olds(i, :), order)
end if
else
! after startup
if (self%order > 2) then
call rotate(self%olds(i, :), order - 1)
end if
end if
! update olds(1) with new derivative
if (self%order > 1) then
call self%backend%vecadd(1.0_dp, self%deriv(i)%ptr, 0._dp, &
self%olds(i, 1)%ptr)
end if
end do
end subroutine adams_bashforth
subroutine rotate(sol, n)
type(flist_t), intent(inout) :: sol(:)
integer, intent(in) :: n
integer :: i
class(field_t), pointer :: ptr
! rotate pointer
ptr => sol(n)%ptr
do i = n, 2, -1
sol(i)%ptr => sol(i - 1)%ptr
end do
sol(1)%ptr => ptr
end subroutine rotate
end module m_time_integrator