Afivo  0.3
helmholtz_variable_stencil.f90

Example of solving a Helmholtz equation with a stencil that varies in time. Useful ingredient for the implicit solution of diffusion equations.

1 #include "../src/cpp_macros.h"
2 
6 program helmholtz_variable_stencil
7  use m_af_all
8 
9  implicit none
10 
11  integer, parameter :: box_size = 8
12  integer :: i_err
13 
14  real(dp), parameter :: domain_len = 2 * acos(-1.0_dp)
15  real(dp), parameter :: diffusion_coeff = 1.0_dp
16 #if NDIM == 1
17  real(dp), parameter :: solution_modes(NDIM) = [1]
18 #elif NDIM == 2
19  real(dp), parameter :: solution_modes(NDIM) = [1, 1]
20 #elif NDIM == 3
21  real(dp), parameter :: solution_modes(NDIM) = [1, 1, 0]
22 #endif
23 
24  type(af_t) :: tree
25  type(mg_t) :: mg
26  integer :: i, n, k_factor, n_steps, n_steps_initial
27  real(dp) :: time, dt, dt_initial
28  character(len=100) :: fname
29 
30  print *, "Running helmholtz_variable_stencil_" // dimname // ""
31  print *, "Number of threads", af_get_max_threads()
32 
33  dt_initial = 0.1_dp
34  n_steps_initial = 10
35 
36  call af_add_cc_variable(tree, "phi", ix=mg%i_phi)
37  call af_add_cc_variable(tree, "rhs", ix=mg%i_rhs)
38  call af_add_cc_variable(tree, "tmp", ix=mg%i_tmp)
39  call af_add_cc_variable(tree, "err", ix=i_err)
40 
41  call af_init(tree, box_size, [dtimes(domain_len)], &
42  [dtimes(box_size)], periodic=[dtimes(.true.)])
43 
44  mg%sides_bc => af_bc_dirichlet_zero ! Method for boundary conditions
45  mg%helmholtz_lambda = 0. ! Updated below
46  mg%helmholtz_lambda = 1/(diffusion_coeff * dt_initial)
47 
48  call mg_init(tree, mg)
49  call af_print_info(tree)
50  call af_refine_up_to_lvl(tree, 3)
51 
52  i = 0
53 
54  do k_factor = 1, 10
55  time = 0
56  dt = dt_initial / k_factor
57  n_steps = n_steps_initial * k_factor
58  mg%helmholtz_lambda = 1/(diffusion_coeff * dt)
59  print *, k_factor, dt, n_steps
60 
61  if (k_factor > 1) call mg_update_operator_stencil(tree, mg)
62 
63  call af_loop_box(tree, set_initial_condition)
64  call af_gc_tree(tree, [mg%i_phi])
65 
66  do n = 1, n_steps
67  call af_loop_box(tree, set_rhs)
68  call mg_fas_fmg(tree, mg, .true., .true.)
69  time = time + dt
70  call af_loop_box_arg(tree, set_error, [time])
71  end do
72 
73  write(fname, "(A,I0)") "output/helmholtz_variable_stencil_" // dimname // "_", k_factor
74  call af_write_silo(tree, trim(fname), k_factor, time)
75  end do
76 
77 contains
78 
80  subroutine set_initial_condition(box)
81  type(box_t), intent(inout) :: box
82  integer :: IJK, nc
83  real(dp) :: rr(NDIM)
84 
85  nc = box%n_cell
86 
87  do kji_do(0,nc+1)
88  rr = af_r_cc(box, [ijk])
89  box%cc(ijk, mg%i_phi) = solution(rr, 0.0_dp)
90  end do; close_do
91  end subroutine set_initial_condition
92 
94  subroutine set_error(box, time)
95  type(box_t), intent(inout) :: box
96  real(dp), intent(in) :: time(:)
97  integer :: IJK, nc
98  real(dp) :: rr(NDIM)
99 
100  nc = box%n_cell
101  do kji_do(1,nc)
102  rr = af_r_cc(box, [ijk])
103  box%cc(ijk, i_err) = &
104  box%cc(ijk, mg%i_phi) - solution(rr, time(1))
105  end do; close_do
106  end subroutine set_error
107 
108  function solution(rr, t) result(sol)
109  real(dp), intent(in) :: rr(NDIM), t
110  real(dp) :: sol, tmp(NDIM)
111 
112  tmp = solution_modes * rr
113  sol = 1 + product(cos(tmp)) * &
114  exp(-sum(solution_modes**2) * diffusion_coeff * t)
115  end function solution
116 
118  subroutine set_rhs(box)
119  type(box_t), intent(inout) :: box
120  integer :: nc
121 
122  nc = box%n_cell
123  box%cc(dtimes(1:nc), mg%i_rhs) = -1/(dt * diffusion_coeff) * &
124  box%cc(dtimes(1:nc), mg%i_phi)
125  end subroutine set_rhs
126 
127 end program helmholtz_variable_stencil
Module which contains all Afivo modules, so that a user does not have to include them separately.
Definition: m_af_all.f90:3