Afivo 0.3
All Classes Namespaces Functions Variables Pages
euler_gas_dynamics.f90
1#include "../src/cpp_macros.h"
2
3program kt_euler
4 use m_af_all
5 implicit none
6
7 integer, parameter :: n_vars = 2+ndim
8 integer, parameter :: ncells = 8
9 integer, parameter :: coord_type = af_xyz
10 real(dp), parameter :: euler_gamma = 1.4_dp
11 integer, parameter :: time_integrator = af_heuns_method
12
13 ! Indices defining the order of the flux variables
14 integer, parameter :: i_rho = 1
15 integer, parameter :: i_mom(NDIM) = [2, 3]
16 integer, parameter :: i_e = 4
17
18 integer :: variables(n_vars)
19 integer :: cc_rho, cc_mom(2), cc_e
20 integer :: fluxes(n_vars)
21 real(dp) :: l_max(NDIM), l_min(NDIM)
22 integer :: grid(NDIM)
23 logical :: periodicBC(NDIM)
24 real(dp) :: u0(4, n_vars)
25 type(af_t) :: tree
26 real(dp) :: dt, dt_lim, time, end_time, dt_output
27 real(dp) :: dt_amr, time_prev_refine
28 character(len=100) :: fname
29 character(len=20) :: carg
30 integer :: n, output_cnt
31 real(dp) :: rho_max
32 logical :: benchmark
33 logical :: use_amr
34
35 ! AMR stuff
36 type(ref_info_t) :: refine_info
37 integer :: refine_steps
38
39 character(len=10) :: var_names(n_vars)
40
41 var_names(i_rho) = "rho"
42 var_names(i_mom) = ["mom_x", "mom_y"]
43 var_names(i_e) = "E"
44
45 print *, "Running Euler 2D with KT scheme"
46 print *, "Number of threads", af_get_max_threads()
47
48 do n = 1, n_vars
49 call af_add_cc_variable(tree, var_names(n), ix=variables(n), n_copies=2)
50 call af_add_fc_variable(tree, "flux", ix=fluxes(n))
51 call af_set_cc_methods(tree, variables(n), af_bc_neumann_zero)
52 end do
53
54 cc_rho = variables(i_rho)
55 cc_mom = variables(i_mom)
56 cc_e = variables(i_e)
57
58 carg = "sod"
59 if (command_argument_count() > 0) then
60 call get_command_argument(1, carg)
61 end if
62 print *, "Initial condition type: ", trim(carg)
63
64 select case (carg)
65 case ("first")
66 u0(:, i_e) = [1.0_dp, 0.4_dp, 0.0439_dp, 0.15_dp]
67 u0(:, i_rho) = [1.0_dp, 0.5197_dp, 0.1072_dp, 0.2579_dp]
68 u0(:, i_mom(1)) = [0.0_dp, -0.7259_dp, -0.7259_dp, 0.0_dp]
69 u0(:, i_mom(2)) = [0.0_dp, 0.0_dp, -1.4045_dp, -1.4045_dp]
70 case ("sixth")
71 u0(:, i_e) = [1.0_dp, 1.0_dp, 1.0_dp, 1.0_dp]
72 u0(:, i_rho) = [1.0_dp, 2.0_dp, 1.0_dp, 3.0_dp]
73 u0(:, i_mom(1)) = [0.75_dp, 0.75_dp, -0.75_dp, -0.75_dp]
74 u0(:, i_mom(2)) = [-0.5_dp, 0.5_dp, 0.5_dp, -0.5_dp]
75 case ("sod")
76 ! 1D Sod shock test case
77 u0(:, i_rho) = [0.125_dp, 1.0_dp, 1.0_dp, 0.125_dp]
78 u0(:, i_e) = [0.1_dp, 1.0_dp, 1.0_dp, 0.1_dp]
79 u0(:, i_mom(1)) = [0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp]
80 u0(:, i_mom(2)) = [0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp]
81 case default
82 error stop "Unknown initial condition"
83 end select
84
85 call to_conservative(4, n_vars, u0)
86
87 use_amr = .false.
88 if (command_argument_count() > 1) then
89 call get_command_argument(2, carg)
90 read(carg, *) use_amr
91 end if
92 print *, "Use AMR: ", use_amr
93
94 benchmark = .false.
95 if (command_argument_count() > 2) then
96 call get_command_argument(3, carg)
97 read(carg, *) benchmark
98 end if
99 print *, "Benchmark: ", benchmark
100
101 grid(:) = 50*ncells
102 l_max(:) = 1.0_dp
103 l_min(:) = 0.0_dp
104 periodicbc(:) = .false.
105
106 call af_init(tree, ncells, l_max-l_min, grid, &
107 periodic=periodicbc, r_min=l_min, &
108 coord=coord_type)
109
110 if (use_amr) then
111 do
112 refine_steps = refine_steps + 1
113 !Settng init conds for each refinement is needed as we use that data as
114 !refinement criterion
115 call af_loop_box(tree, set_init_conds)
116 call af_gc_tree(tree, variables)
117 call af_adjust_refinement(tree, ref_rout, refine_info, 1)
118 if (refine_info%n_add == 0) exit
119 end do
120 call af_restrict_tree(tree, variables)
121 call af_gc_tree(tree, variables)
122 else
123 call af_loop_box(tree, set_init_conds)
124 call af_gc_tree(tree, variables)
125 end if
126
127 time = 0.0_dp
128 time_prev_refine = time
129 end_time = 0.2_dp
130 dt = 0.0_dp ! Start from zero time step
131 output_cnt = 0
132 dt_output = end_time / 20
133 dt_amr = end_time / 100
134
135 do
136 if (.not. benchmark .and. output_cnt * dt_output <= time) then
137 write(fname, "(A,I0)") "output/euler_" // dimname // "_", output_cnt
138 call af_write_silo(tree, trim(fname), output_cnt, time, &
139 add_vars = write_primitives, add_names=["xVel","yVel","pres"])
140 output_cnt = output_cnt + 1
141 end if
142
143 call af_advance(tree, dt, dt_lim, time, variables, &
144 time_integrator, forward_euler)
145
146 dt = 0.8_dp * dt_lim
147
148 if (use_amr .and. time > time_prev_refine + dt_amr) then
149 call af_gc_tree(tree, variables)
150 call af_adjust_refinement(tree, ref_rout, refine_info, 1)
151 time_prev_refine = time
152 end if
153
154 call af_tree_maxabs_cc(tree, variables(i_rho), rho_max)
155 if (rho_max > 10.0_dp) &
156 error stop "solution diverging!"
157
158 if (time > end_time) exit
159 end do
160
161 call af_destroy(tree)
162
163contains
164
165 !> [forward_euler_gasd]
166 subroutine forward_euler(tree, dt, dt_stiff, dt_lim, time, s_deriv, n_prev, &
167 s_prev, w_prev, s_out, i_step, n_steps)
168 type(af_t), intent(inout) :: tree
169 real(dp), intent(in) :: dt
170 real(dp), intent(in) :: dt_stiff !< Time step for stiff terms
171 real(dp), intent(inout) :: dt_lim
172 real(dp), intent(in) :: time
173 integer, intent(in) :: s_deriv
174 integer, intent(in) :: n_prev !< Number of previous states
175 integer, intent(in) :: s_prev(n_prev) !< Previous states
176 real(dp), intent(in) :: w_prev(n_prev) !< Weights of previous states
177 integer, intent(in) :: s_out
178 integer, intent(in) :: i_step, n_steps
179 real(dp) :: dummy_dt(0)
180
181 call flux_generic_tree(tree, n_vars, variables, s_deriv, fluxes, dt_lim, &
182 max_wavespeed, get_fluxes, flux_dummy_modify, flux_dummy_line_modify, &
183 to_primitive, to_conservative, af_limiter_vanleer_t)
184 call flux_update_densities(tree, dt, n_vars, variables, n_vars, variables, fluxes, &
185 s_deriv, n_prev, s_prev, w_prev, s_out, flux_dummy_source, 0, dummy_dt)
186 end subroutine forward_euler
187 !> [forward_euler_gasd]
188
189 subroutine set_init_conds(box)
190 type(box_t), intent(inout) :: box
191 integer :: IJK, nc
192 real(dp) :: rr(NDIM)
193
194 nc = box%n_cell
195
196 do kji_do(0, nc+1)
197 rr = af_r_cc(box, [ijk])
198 if (rr(1) > 0.5_dp .and. rr(2) > 0.5_dp) then
199 box%cc(ijk, variables) = u0(1, :)
200 elseif (rr(1) <= 0.5_dp .and. rr(2) >= 0.5_dp) then
201 box%cc(ijk, variables) = u0(2, :)
202 elseif (rr(1) <= 0.5_dp .and. rr(2) <= 0.5_dp) then
203 box%cc(ijk, variables) = u0(3, :)
204 else
205 box%cc(ijk, variables) = u0(4, :)
206 end if
207 end do; close_do
208 end subroutine set_init_conds
209
210 subroutine to_primitive(n_values, n_vars, u)
211 integer, intent(in) :: n_values, n_vars
212 real(dp), intent(inout) :: u(n_values, n_vars)
213
214 u(:, i_mom(1)) = u(:, i_mom(1))/u(:, i_rho)
215 u(:, i_mom(2)) = u(:, i_mom(2))/u(:, i_rho)
216 u(:, i_e) = (euler_gamma-1.0_dp) * (u(:, i_e) - &
217 0.5_dp*u(:, i_rho)* sum(u(:, i_mom(:))**2, dim=2))
218 end subroutine to_primitive
219
220 subroutine to_conservative(n_values, n_vars, u)
221 integer, intent(in) :: n_values, n_vars
222 real(dp), intent(inout) :: u(n_values, n_vars)
223 real(dp) :: kin_en(n_values)
224 real(dp) :: inv_fac
225 integer :: i
226
227 ! Compute kinetic energy (0.5 * rho * velocity^2)
228 kin_en = 0.5_dp * u(:, i_rho) * sum(u(:, i_mom(:))**2, dim=2)
229
230 ! Compute energy from pressure and kinetic energy
231 inv_fac = 1/(euler_gamma - 1.0_dp)
232 u(:, i_e) = u(:, i_e) * inv_fac + kin_en
233
234 ! Compute momentum from density and velocity components
235 do i = 1, ndim
236 u(:, i_mom(i)) = u(:, i_rho) * u(:, i_mom(i))
237 end do
238 end subroutine to_conservative
239
240 subroutine max_wavespeed(n_values, n_var, flux_dim, u, w)
241 integer, intent(in) :: n_values !< Number of cell faces
242 integer, intent(in) :: n_var !< Number of variables
243 integer, intent(in) :: flux_dim !< In which dimension fluxes are computed
244 real(dp), intent(in) :: u(n_values, n_var) !< Primitive variables
245 real(dp), intent(out) :: w(n_values) !< Maximum speed
246 real(dp) :: sound_speeds(n_values)
247
248 sound_speeds = sqrt(euler_gamma * u(:, i_e) / u(:, i_rho))
249 w = sound_speeds + abs(u(:, i_mom(flux_dim)))
250 end subroutine max_wavespeed
251
252 subroutine get_fluxes(n_values, n_var, flux_dim, u, flux, box, line_ix, s_deriv)
253 integer, intent(in) :: n_values !< Number of cell faces
254 integer, intent(in) :: n_var !< Number of variables
255 integer, intent(in) :: flux_dim !< In which dimension fluxes are computed
256 real(dp), intent(in) :: u(n_values, n_var)
257 real(dp), intent(out) :: flux(n_values, n_var)
258 type(box_t), intent(in) :: box
259 integer, intent(in) :: line_ix(NDIM-1)
260 integer, intent(in) :: s_deriv
261 real(dp) :: E(n_values), inv_fac
262 integer :: i
263
264 ! Compute left and right flux for conservative variables from the primitive
265 ! reconstructed values.
266
267 ! Density flux
268 flux(:, i_rho) = u(:, i_rho) * u(:, i_mom(flux_dim))
269
270 ! Momentum flux
271 do i = 1, ndim
272 flux(:, i_mom(i)) = u(:, i_rho) * &
273 u(:, i_mom(i)) * u(:, i_mom(flux_dim))
274 end do
275
276 ! Add pressure term
277 flux(:, i_mom(flux_dim)) = flux(:, i_mom(flux_dim)) + u(:, i_e)
278
279 ! Compute energy
280 inv_fac = 1/(euler_gamma-1.0_dp)
281 e = u(:, i_e) * inv_fac + 0.5_dp * u(:, i_rho) * &
282 sum(u(:, i_mom(:))**2, dim=2)
283
284 ! Energy flux
285 flux(:, i_e) = u(:, i_mom(flux_dim)) * (e + u(:, i_e))
286
287 end subroutine get_fluxes
288
289 subroutine ref_rout( box, cell_flags )
290 type(box_t), intent(in) :: box
291 integer, intent(out) :: cell_flags(DTIMES(box%n_cell))
292 real(dp) :: diff, tol
293 integer :: IJK, nc
294
295 nc = box%n_cell
296 tol = 1.0e-6_dp
297 do kji_do(1,nc)
298 diff = box%dr(1)**2*abs(box%cc(i+1,j,i_rho)+box%cc(i-1,j,i_rho) &
299 -2*box%cc(i,j,i_rho)) + &
300 box%dr(2)**2*abs(box%cc(i,j+1,i_rho)+box%cc(i,j-1,i_rho) &
301 -2*box%cc(i,j,i_rho))
302 if (diff > tol .and. box%lvl < 3) then
303 cell_flags(ijk) = af_do_ref
304 else if (diff < 0.1_dp*tol) then
305 cell_flags(ijk) = af_rm_ref
306 else
307 cell_flags(ijk) = af_keep_ref
308 end if
309 end do; close_do
310 end subroutine ref_rout
311
312 subroutine write_primitives(box, new_vars, n_var)
313 type(box_t), intent(in) :: box
314 integer, intent(in) :: n_var
315 real(dp) :: new_vars(DTIMES(0:box%n_cell+1),n_var)
316
317 ! X Velocity
318 new_vars(dtimes(:), 1) = box%cc(dtimes(:), cc_mom(1))/box%cc(dtimes(:), cc_rho)
319 ! Y Velocity
320 new_vars(dtimes(:), 2) = box%cc(dtimes(:), cc_mom(2))/box%cc(dtimes(:), cc_rho)
321 ! Pressure
322 new_vars(dtimes(:), 3) = (euler_gamma-1.0_dp)*(box%cc(dtimes(:), cc_e) - &
323 sum(box%cc(dtimes(:), cc_mom(:))**2, dim=ndim+1) &
324 /(2.0_dp*box%cc(dtimes(:), cc_rho)))
325 end subroutine write_primitives
326
327end program kt_euler
Module which contains all Afivo modules, so that a user does not have to include them separately.
Definition: m_af_all.f90:3