Afivo  0.3
euler_gas_dynamics.f90
1 #include "../src/cpp_macros.h"
2 
3 program 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 
163 contains
164 
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
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
175  integer, intent(in) :: s_prev(n_prev)
176  real(dp), intent(in) :: w_prev(n_prev)
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
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
242  integer, intent(in) :: n_var
243  integer, intent(in) :: flux_dim
244  real(dp), intent(in) :: u(n_values, n_var)
245  real(dp), intent(out) :: w(n_values)
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
254  integer, intent(in) :: n_var
255  integer, intent(in) :: flux_dim
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 
327 end 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