afivo-streamer 1.1
1D/2D/3D streamer simulations with AMR
Loading...
Searching...
No Matches
streamer.f90
Go to the documentation of this file.
1!> Program to perform streamer simulations with AMR
2program streamer
3#include "../afivo/src/cpp_macros.h"
4 use iso_fortran_env, only: error_unit
5 use m_config
6 use m_af_all
7 use m_streamer
8 use m_field
10 use m_refine
11 use m_photoi
12 use m_chemistry
13 use m_gas
14 use m_coupling
15 use m_fluid
16 use m_dt
17 use m_types
19 use m_output
20 use m_dielectric
22 use m_model
23 use m_analysis
24 use omp_lib
25
26 implicit none
27
28 integer, parameter :: int8 = selected_int_kind(18)
29 integer, parameter :: max_attemps_per_time_step = 10
30 integer, parameter :: datfile_version = 30
31 integer(int8) :: t_start, t_current, count_rate
32 real(dp) :: wc_time = 0.0_dp, inv_count_rate
33 real(dp) :: time_last_print, time_last_output
34 integer :: i, it, n, coord_type, box_bytes
35 integer :: n_steps_rejected
36 integer, allocatable :: ref_links(:, :)
37 logical :: write_out
38 real(dp) :: time, dt, dt_lim, photoi_prev_time
39 real(dp) :: dt_gas_lim, dt_lim_step
40 real(dp) :: fraction_steps_rejected
41 real(dp) :: memory_limit_gb
42 type(af_t) :: tree_copy ! Used when reading a tree from a file
43 type(ref_info_t) :: ref_info ! Contains info about refinement changes
44 integer :: output_cnt = 0 ! Number of output files written
45 character(len=string_len) :: restart_from_file = undefined_str
46 real(dp) :: max_field
47 type(af_loc_t) :: loc_field, loc_field_t0
48 real(dp) :: pos_emax(ndim), pos_emax_t0(ndim)
49 real(dp) :: breakdown_field_td, current_output_dt
50 real(dp) :: time_until_next_pulse
51 real(dp) :: field_energy, field_energy_prev
52 real(dp) :: tmp, field_energy_prev_time
53 logical :: step_accepted, start_of_new_pulse
54
55 ! To keep track of the computational cost of different parts
56 real(dp) :: t1, t2, t3
57
58 !> The configuration for the simulation
59 type(cfg_t) :: cfg
60 !> This contains the full grid information
61 type(af_t) :: tree
62
63 call print_program_name()
64
65 ! Parse command line configuration files and options
66 call cfg_update_from_arguments(cfg)
67
68 call cfg_add_get(cfg, "restart_from_file", restart_from_file, &
69 "If set, restart simulation from a previous .dat file")
70
71 memory_limit_gb = 4.0_dp**(ndim-1) ! 1, 4, 16 GB for 1D, 2D, 3D
72 call cfg_add_get(cfg, "memory_limit_GB", memory_limit_gb, &
73 "Memory limit (GB)")
74
75 call initialize_modules(cfg, tree, mg, restart_from_file /= undefined_str)
76
77 call cfg_write(cfg, trim(output_name) // "_out.cfg", custom_first=.true.)
78
79 call chemistry_get_breakdown_field(breakdown_field_td, 1.0e3_dp)
80 write(*, '(A,E12.4)') " Estimated breakdown field (Td): ", breakdown_field_td
81
82 ! Specify default methods for all the variables
83 do i = 1, size(all_densities)
84 call af_set_cc_methods(tree, all_densities(i), &
85 bc_species, af_gc_interp_lim, st_prolongation_method)
86 end do
87
88 if (.not. gas_constant_density) then
89 if (gas_dynamics) then
90 ! Let the gas density evolve in time
91 call af_set_cc_methods(tree, i_gas_dens, &
92 af_bc_neumann_zero, af_gc_interp, st_prolongation_method)
93 else
94 ! The gas density is specified by a function
95 call af_set_cc_methods(tree, i_gas_dens, &
96 funcval=set_gas_density_from_user_function)
97 end if
98 end if
99
100 do i = 1, tree%n_var_cell
101 if (tree%cc_write_output(i) .and. .not. &
102 (tree%has_cc_method(i) .or. i == i_phi)) then
103 call af_set_cc_methods(tree, i, af_bc_neumann_zero, &
104 af_gc_interp, st_prolongation_method)
105 end if
106 end do
107
108 ! These values are overwritten when restarting
109 it = 0
110 time = 0.0_dp ! Simulation time (all times are in s)
111 global_time = time
112 photoi_prev_time = time ! Time of last photoionization computation
113 dt = global_dt
114 n_steps_rejected = 0
115 fraction_steps_rejected = 0.0_dp
116 pos_emax_t0 = 0.0_dp ! Initial streamer position
117
118 ! Initialize the tree (which contains all the mesh information)
119 if (restart_from_file /= undefined_str) then
120 tree_copy = tree ! Store the settings
121 call af_read_tree(tree, restart_from_file, read_sim_data)
122
123 ! Restore some of the settings
124 tree%cc_write_output = tree_copy%cc_write_output
125 tree%cc_write_binary = tree_copy%cc_write_binary
126 tree%fc_write_binary = tree_copy%fc_write_binary
127
128 box_bytes = af_box_bytes(tree%n_cell, tree%n_var_cell, tree%n_var_face)
129 tree%box_limit = nint(memory_limit_gb * 2.0_dp**30 / box_bytes)
130
131 if (tree%n_cell /= st_box_size) &
132 error stop "restart_from_file: incompatible box size"
133
134 if (tree%n_var_cell /= tree_copy%n_var_cell) then
135 write(error_unit, *) "n_var_cell here:", tree_copy%n_var_cell
136 write(error_unit, *) "n_var_cell file:", tree%n_var_cell
137 error stop "restart_from_file: incompatible variable list"
138 end if
139
140 if (st_use_dielectric) error stop "Restarting not support with dielectric"
141
142 ! @todo more consistency checks
143
144 ! This routine always needs to be called when using multigrid
145 call mg_init(tree, mg)
146 else
147 if (st_cylindrical) then
148 coord_type = af_cyl
149 else
150 coord_type = af_xyz
151 end if
152
153 call af_init(tree, st_box_size, st_domain_origin + st_domain_len, &
154 st_coarse_grid_size, periodic=st_periodic, coord=coord_type, &
155 r_min=st_domain_origin, mem_limit_gb=memory_limit_gb)
156
157 ! Set up the initial conditions
158 call set_initial_conditions(tree, mg)
159
160 ! Write initial output
161 output_cnt = 0 ! Number of output files written
162 call output_write(tree, output_cnt, 0.0_dp, write_sim_data)
163 end if
164
165 print *, "Simulation output: ", trim(output_name)
166 print *, "Number of threads: ", af_get_max_threads()
167 call af_print_info(tree)
168 call af_stencil_print_info(tree)
169
170 ! Initial wall clock time
171 call system_clock(t_start, count_rate)
172 inv_count_rate = 1.0_dp / count_rate
173 time_last_print = -1e10_dp
174 time_last_output = time
175
176 call field_compute_energy(tree, field_energy_prev)
177 field_energy_prev_time = time
178
179 do
180 it = it + 1
181 if (time >= st_end_time) exit
182
183 if (associated(user_generic_method)) then
184 call user_generic_method(tree, time)
185 end if
186
187 ! Initialize starting position of streamer
189 call af_tree_max_cc(tree, i_electric_fld, max_field, loc_field_t0)
190 pos_emax_t0 = af_r_loc(tree, loc_field_t0)
191 end if
192
193 ! Check if streamer length exceeds the defined maximal streamer length
195 call af_tree_max_cc(tree, i_electric_fld, max_field, loc_field)
196 pos_emax = af_r_loc(tree, loc_field)
197
198 if (norm2(pos_emax_t0 - pos_emax) >= st_end_streamer_length) then
199 print *, "Streamer reached its desired length"
200 exit
201 end if
202 end if
203
204 ! Update wall clock time
205 call system_clock(t_current)
206 wc_time = (t_current - t_start) * inv_count_rate
207
208 ! Every ST_print_status_interval, print some info about progress
209 if (wc_time - time_last_print > output_status_delay) then
210 call output_status(tree, time, wc_time, it, dt)
211 time_last_print = wc_time
212 end if
213
214 time_until_next_pulse = field_pulse_period - modulo(time, field_pulse_period)
215
216 if (abs(current_voltage) > 0.0_dp .or. &
217 time_until_next_pulse < refine_prepulse_time) then
218 current_output_dt = output_dt
220 else
221 current_output_dt = output_dt * output_dt_factor_pulse_off
223 end if
224
225 ! Every output_dt, write output
226 write_out = (time + dt >= time_last_output + current_output_dt)
227 if (write_out) then
228 ! Ensure that dt is non-negative, even when current_output_dt changes
229 dt = max(0.0_dp, time_last_output + current_output_dt - time)
230 end if
231
232 ! Make sure to capture the start of the next pulse
233 start_of_new_pulse = (dt >= time_until_next_pulse)
234 if (start_of_new_pulse) then
235 dt = max(time_until_next_pulse, dt_min)
236 end if
237
238 if (photoi_enabled .and. mod(it, photoi_per_steps) == 0) then
239 t1 = omp_get_wtime()
240 call photoi_set_src(tree, time - photoi_prev_time)
241 t2 = omp_get_wtime()
243 photoi_prev_time = time
244 end if
245
246 if (st_use_electrode) then
247 call set_electrode_densities(tree)
248 end if
249
250 ! Advance over dt, but make a copy first so that we can try again if dt was too large
251 dt_lim = huge_real
252 step_accepted = .false.
253 do n = 1, max_attemps_per_time_step
254 t1 = omp_get_wtime()
255 call copy_current_state()
256 t2 = omp_get_wtime()
258
259 call af_advance(tree, dt, dt_lim_step, time, all_densities, &
261
262 ! dt_lim is the minimum over all steps taken (including rejected ones)
263 dt_lim = min(dt_lim, dt_lim_step)
264
265 ! Check if dt was small enough for the new state
266 step_accepted = (dt <= dt_lim_step)
267
268 if (step_accepted) then
269 exit
270 else
271 n_steps_rejected = n_steps_rejected + 1
272 write (*, "(I0,A,I0,A,2E12.4,A,F6.2)") it, " Step rejected (#", &
273 n_steps_rejected, ") (dt, dt_lim) = ", dt, dt_lim, &
274 " frac", fraction_steps_rejected
275 call output_status(tree, time, wc_time, it, dt)
276
277 ! Go back to previous state and try with a smaller dt
278 dt = dt_safety_factor * dt_lim_step
279 time = global_time
280 write_out = .false. ! Since we advance less far in time
281 call restore_previous_state()
282 end if
283 end do
284
285 ! The approximate fraction of rejected steps, over the last ~100
286 fraction_steps_rejected = 0.99_dp * fraction_steps_rejected
287 if (n > 1) fraction_steps_rejected = fraction_steps_rejected + 0.01_dp
288
289 if (n == max_attemps_per_time_step+1) &
290 error stop "All time steps were rejected"
291
292 ! Update global variable based on current space-integrated data
294 sum(st_current_rates(1:n_reactions, :), dim=2) * dt
296 sum(st_current_jdote(1, :)) * dt
297
298 ! Estimate electric current according to Sato's equation V*I = sum(J.E),
299 ! where J includes both the conduction current and the displacement
300 ! current, see 10.1088/0022-3727/32/5/005.
301 ! The latter is computed through the field energy, which contains
302 ! some noise, so the current is only updated every N iterations.
303 if (mod(it, current_update_per_steps) == 0) then
304 call field_compute_energy(tree, field_energy)
305
306 ! Time derivative of field energy
307 tmp = (field_energy - field_energy_prev)/(time - field_energy_prev_time)
308 field_energy_prev = field_energy
309 field_energy_prev_time = time
310
311 ! Add J.E term
312 if (abs(current_voltage) > 0.0_dp) then
315 else
318 end if
319 end if
320
321 ! Make sure field is available for latest time state
322 t1 = omp_get_wtime()
323 call field_compute(tree, mg, 0, time, .true.)
324 t2 = omp_get_wtime()
325 wc_time_field = wc_time_field + t2 - t1
326
327 if (gas_dynamics) then
328 call coupling_add_fluid_source(tree, dt)
329
330 ! Go back to time at beginning of step
331 time = global_time
332
333 call af_advance(tree, dt, dt_gas_lim, time, &
336 else
337 dt_gas_lim = dt_max
338 end if
339
340 ! Do not increase time step when many steps are rejected. Here we use a
341 ! pretty arbitrary threshold of 0.1
343 if (fraction_steps_rejected > 0.1_dp) tmp = 1.0_dp
344
345 dt = min(tmp * global_dt, dt_safety_factor * min(dt_lim, dt_gas_lim))
346
347 if (start_of_new_pulse) then
348 ! Start a new pulse with a small time step
349 dt = dt_min
350 if (associated(user_new_pulse_conditions)) then
351 call af_loop_box(tree, user_new_pulse_conditions)
352 end if
353 end if
354
355 ! dt is modified when writing output, global_dt not
356 global_dt = dt
357 global_time = time
358
359 if (global_dt < dt_min) then
360 write(error_unit, "(A,E12.4,A)") " Time step (dt =", global_dt, &
361 ") getting too small"
362 write(error_unit, *) "See the documentation on time integration"
363 call output_status(tree, time, wc_time, it, dt)
364 write_out = .true.
365 end if
366
367 t1 = omp_get_wtime()
368 if (write_out) then
369 output_cnt = output_cnt + 1
370 time_last_output = global_time
371 call output_write(tree, output_cnt, wc_time, write_sim_data)
372 if (st_use_dielectric .and. surface_output) then
373 call surface_write_output(tree, diel, [i_photon_flux, i_surf_dens], &
374 ["photon_flux", "surf_dens "], output_name, output_cnt)
375 end if
376 end if
377 t2 = omp_get_wtime()
379
380 if (global_dt < dt_min) error stop "dt too small"
381
383 if (axisymmetric_is_branching(tree)) then
384 error stop "Branching detected, abort"
385 end if
386 end if
387
388 if (mod(it, refine_per_steps) == 0) then
389 ! Restrict species, for the ghost cells near refinement boundaries
390 call af_restrict_tree(tree, all_densities)
391 call af_gc_tree(tree, all_densities)
392
393 if (gas_dynamics) then
394 call af_restrict_tree(tree, gas_vars)
395 call af_gc_tree(tree, gas_vars)
396 end if
397
398 if (st_use_dielectric) then
399 ! Make sure there are no refinement jumps across the dielectric
400 call surface_get_refinement_links(diel, ref_links)
401 call af_adjust_refinement(tree, refine_routine, ref_info, &
402 refine_buffer_width, ref_links)
403 call surface_update_after_refinement(tree, diel, ref_info)
404 else
405 call af_adjust_refinement(tree, refine_routine, ref_info, &
407 end if
408
409 if (ref_info%n_add > 0 .or. ref_info%n_rm > 0) then
410 ! Compute the field on the new mesh
411 call field_compute(tree, mg, 0, time, .true.)
412
413 ! Compute photoionization on new mesh
414 if (photoi_enabled) then
415 call photoi_set_src(tree, time - photoi_prev_time)
416 photoi_prev_time = time
417 end if
418 end if
419 end if
420
421 t3 = omp_get_wtime()
423 end do
424
425 call output_status(tree, time, wc_time, it, dt)
426
427 write(*, "(A)") "Computational cost breakdown (%)"
428 write(*, "(7(A10))") "flux", "source", "copy", "field", "output", &
429 "refine", "photoi"
430 write(*, "(7(F10.2))") 1e2*wc_time_flux/wc_time, 1e2*wc_time_source/wc_time, &
431 1e2*wc_time_copy_state/wc_time, 1e2*wc_time_field/wc_time, &
432 1e2*wc_time_output/wc_time, 1e2*wc_time_refine/wc_time, &
433 1e2*wc_time_photoi/wc_time
434
435contains
436
437 subroutine initialize_modules(cfg, tree, mg, restart)
438 use m_user
439 use m_table_data
441
442 type(cfg_t), intent(inout) :: cfg
443 type(af_t), intent(inout) :: tree
444 type(mg_t), intent(inout) :: mg
445 logical, intent(in) :: restart
446
447 call model_initialize(cfg)
448 call user_initialize(cfg, tree)
449 call dt_initialize(cfg)
451
452 call table_data_initialize(cfg)
453 call gas_initialize(tree, cfg)
455 call chemistry_initialize(tree, cfg)
456 call st_initialize(tree, cfg, ndim)
457 call photoi_initialize(tree, cfg)
458 call refine_initialize(cfg)
459 call field_initialize(tree, cfg, mg)
460 call init_cond_initialize(tree, cfg)
461 call output_initialize(tree, cfg)
462 call dielectric_initialize(tree, cfg)
463
464 call output_initial_summary(tree)
465
466 end subroutine initialize_modules
467
468 subroutine set_initial_conditions(tree, mg)
469 type(af_t), intent(inout) :: tree
470 type(mg_t), intent(inout) :: mg
471 integer :: n, lvl, i, id, n_surface_variables
472
473 ! Refine up to maximal grid spacing
474 do lvl = 1, af_max_lvl-1
475 if (all(af_lvl_dr(tree, lvl) <= refine_max_dx)) exit
476 end do
477 call af_refine_up_to_lvl(tree, lvl)
478
479 ! Set initial conditions
480 call af_loop_box(tree, init_cond_set_box)
481 if (associated(user_initial_conditions)) then
482 call af_loop_box(tree, user_initial_conditions)
483 else if (st_use_dielectric) then
484 error stop "use_dielectric requires user_initial_conditions to be set"
485 end if
486
487 ! This placement is so that users can set epsilon before the coarse grid
488 ! solver is constructed
489 call mg_init(tree, mg)
490
491 if (st_use_dielectric) then
492 ! To store the photon flux (single state), surface charge (multiple
493 ! states) and a copy of the surface charge
494 n_surface_variables = af_advance_num_steps(time_integrator) + 2
495 call surface_initialize(tree, i_eps, diel, n_surface_variables)
496 end if
497
498 do n = 1, 100
499 call field_compute(tree, mg, 0, time, .false.)
500
501 if (st_use_dielectric) then
502 ! Make sure there are no refinement jumps across the dielectric
503 call surface_get_refinement_links(diel, ref_links)
504 call af_adjust_refinement(tree, refine_routine, ref_info, &
505 refine_buffer_width, ref_links)
506 call surface_update_after_refinement(tree, diel, ref_info)
507 else
508 call af_adjust_refinement(tree, refine_routine, ref_info, &
510 end if
511
512 ! Set initial conditions on newly added boxes
513 do lvl = 1, size(ref_info%lvls)
514 !$omp parallel do private(id)
515 do i = 1, size(ref_info%lvls(lvl)%add)
516 id = ref_info%lvls(lvl)%add(i)
517 call init_cond_set_box(tree%boxes(id))
518 if (associated(user_initial_conditions)) &
519 call user_initial_conditions(tree%boxes(id))
520 end do
521 !$omp end parallel do
522 end do
523
524 if (ref_info%n_add == 0) exit
525 end do
526
527 end subroutine set_initial_conditions
528
529 subroutine write_sim_data(my_unit)
530 integer, intent(in) :: my_unit
531
532 write(my_unit) datfile_version
533
534 write(my_unit) it
535 write(my_unit) output_cnt
536 write(my_unit) time
537 write(my_unit) global_time
538 write(my_unit) photoi_prev_time
539 write(my_unit) global_dt
540
541 write(my_unit) st_global_rates
542 write(my_unit) st_global_jdote
543 write(my_unit) fraction_steps_rejected
544 end subroutine write_sim_data
545
546 subroutine read_sim_data(my_unit)
547 integer, intent(in) :: my_unit
548 integer :: version
549
550 read(my_unit) version
551 if (version /= datfile_version) error stop "Different datfile version"
552
553 read(my_unit) it
554 read(my_unit) output_cnt
555 read(my_unit) time
556 read(my_unit) global_time
557 read(my_unit) photoi_prev_time
558 read(my_unit) global_dt
559
560 read(my_unit) st_global_rates
561 read(my_unit) st_global_jdote
562 read(my_unit) fraction_steps_rejected
563
564 dt = global_dt
565 end subroutine read_sim_data
566
567 subroutine print_program_name()
568 print *, " __ _ _____ _ "
569 print *, " /\ / _(_) / ____| | "
570 print *, " / \ | |_ ___ _____ _____| (___ | |_ _ __ ___ __ _ _ __ ___ ___ _ __ "
571 print *, " / /\ \ | _| \ \ / / _ \______\___ \| __| '__/ _ \/ _` | '_ ` _ \ / _ \ '__|"
572 print *, " / ____ \| | | |\ V / (_) | ____) | |_| | | __/ (_| | | | | | | __/ | "
573 print *, " /_/ \_\_| |_| \_/ \___/ |_____/ \__|_| \___|\__,_|_| |_| |_|\___|_| "
574 print *, " "
575 end subroutine print_program_name
576
577 !> Set species boundary conditions at the electrode
578 subroutine set_electrode_densities(tree)
579 type(af_t), intent(inout) :: tree
580
581 call af_loop_box(tree, electrode_species_bc)
582 end subroutine set_electrode_densities
583
584 !> Set species boundary conditions at the electrode
585 !> @todo Set Neumann boundary conditions in the actual flux computation
586 subroutine electrode_species_bc(box)
587 type(box_t), intent(inout) :: box
588 real(dp) :: lsf_nb(2*NDIM), dens_nb(2*NDIM)
589 integer :: nc, IJK
590
591 if (iand(box%tag, mg_lsf_box) == 0) return
592
593 nc = box%n_cell
594 do kji_do(1, nc)
595 if (box%cc(ijk, i_lsf) < 0) then
596 ! Set all species densities to zero
597 box%cc(ijk, all_densities) = 0.0_dp
598
599#if NDIM == 1
600 lsf_nb = [box%cc(i-1, i_lsf), &
601 box%cc(i+1, i_lsf)]
602#elif NDIM == 2
603 lsf_nb = [box%cc(i-1, j, i_lsf), &
604 box%cc(i+1, j, i_lsf), &
605 box%cc(i, j-1, i_lsf), &
606 box%cc(i, j+1, i_lsf)]
607#elif NDIM == 3
608 lsf_nb = [box%cc(i-1, j, k, i_lsf), &
609 box%cc(i+1, j, k, i_lsf), &
610 box%cc(i, j-1, k, i_lsf), &
611 box%cc(i, j+1, k, i_lsf), &
612 box%cc(i, j, k-1, i_lsf), &
613 box%cc(i, j, k+1, i_lsf)]
614#endif
615
616 if (any(lsf_nb > 0) .and. &
617 associated(bc_species, af_bc_neumann_zero)) then
618 ! At the boundary of the electrode
619#if NDIM == 1
620 dens_nb = [box%cc(i-1, i_electron), &
621 box%cc(i+1, i_electron)]
622#elif NDIM == 2
623 dens_nb = [box%cc(i-1, j, i_electron), &
624 box%cc(i+1, j, i_electron), &
625 box%cc(i, j-1, i_electron), &
626 box%cc(i, j+1, i_electron)]
627#elif NDIM == 3
628 dens_nb = [box%cc(i-1, j, k, i_electron), &
629 box%cc(i+1, j, k, i_electron), &
630 box%cc(i, j-1, k, i_electron), &
631 box%cc(i, j+1, k, i_electron), &
632 box%cc(i, j, k-1, i_electron), &
633 box%cc(i, j, k+1, i_electron)]
634#endif
635
636 ! Set electron density to average of outside neighbors
637 box%cc(ijk, i_electron) = sum(dens_nb, mask=(lsf_nb > 0)) / &
638 count(lsf_nb > 0)
639 ! Set first positive ion density for charge neutrality
640 box%cc(ijk, i_1pos_ion) = box%cc(ijk, i_electron)
641 end if
642 end if
643 end do; close_do
644 end subroutine electrode_species_bc
645
646 !> Copy current state for densities and field
647 subroutine copy_current_state()
648 integer :: n_states
649
650 n_states = af_advance_num_steps(time_integrator)
651 call af_tree_copy_ccs(tree, all_densities, all_densities+n_states)
652
653 ! Copy potential
654 call af_tree_copy_cc(tree, i_phi, i_phi+1)
655
656 if (st_use_dielectric) then
657 call surface_copy_variable(diel, i_surf_dens, i_surf_dens+n_states)
658 end if
659 end subroutine copy_current_state
660
661 !> Restore state for densities and field
662 subroutine restore_previous_state()
663 integer :: n_states
664
665 n_states = af_advance_num_steps(time_integrator)
666
667 call af_tree_copy_ccs(tree, all_densities+n_states, all_densities)
668
669 ! Copy potential and compute field again
670 call af_tree_copy_cc(tree, i_phi+1, i_phi)
671 call field_from_potential(tree, mg)
672
673 if (st_use_dielectric) then
674 call surface_copy_variable(diel, i_surf_dens+n_states, i_surf_dens )
675 end if
676 end subroutine restore_previous_state
677
678 !> A wrapper routine to set the gas density in a box by a user-defined
679 !> function
680 subroutine set_gas_density_from_user_function(box, iv)
681 type(box_t), intent(inout) :: box !< Box to fill values in
682 integer, intent(in) :: iv !< Index of variable
683 integer :: IJK, nc
684 nc = box%n_cell
685
686 do kji_do(0, nc+1)
687 box%cc(ijk, iv) = user_gas_density(box, ijk)
688 end do; close_do
689 end subroutine set_gas_density_from_user_function
690
691 logical function axisymmetric_is_branching(tree)
692 type(af_t), intent(in) :: tree
693 real(dp) :: max_field, axis_field, rmin(NDIM), rmax(NDIM)
694 type(af_loc_t) :: loc_field
695
696 ! Get location of max(E) in full domain
697 call af_tree_max_cc(tree, i_electric_fld, max_field, loc_field)
698
699 ! Compare with maximum in region near axis
700 rmin = 0.0_dp
701 rmax(1) = 1e-2_dp * st_domain_len(1)
702 rmax(2:) = st_domain_len(2:)
703 call analysis_max_var_region(tree, i_electric_fld, rmin, &
704 rmax, axis_field, loc_field)
705
706 axisymmetric_is_branching = (max_field > 1.1_dp * axis_field)
707
708 if (axisymmetric_is_branching) print *, max_field, axis_field
709 end function axisymmetric_is_branching
710
711end program streamer
Module with routines to help analyze simulations.
Definition m_analysis.f90:2
Module for handling chemical reactions.
subroutine, public chemistry_initialize(tree, cfg)
Initialize module and load chemical reactions.
subroutine, public chemistry_get_breakdown_field(field_td, min_growth_rate)
Get the breakdown field in Townsend.
integer, public, protected n_reactions
Number of reactions present.
Module for the coupling between the gas dynamics and the fluid model.
Definition m_coupling.f90:2
subroutine, public coupling_add_fluid_source(tree, dt)
Add source terms form the fluid model to the Euler equations.
subroutine, public coupling_update_gas_density(tree)
Update gas number density in the fluid model.
Module with settings and routines to handle dielectrics.
integer, parameter, public i_surf_dens
logical, public, protected surface_output
subroutine, public dielectric_initialize(tree, cfg)
type(surfaces_t), public diel
To store dielectric surface.
integer, parameter, public i_photon_flux
Module to set the time step.
Definition m_dt.f90:2
integer, public, protected time_integrator
Which time integrator is used.
Definition m_dt.f90:49
real(dp), public, protected dt_max
Definition m_dt.f90:40
real(dp), public, protected dt_safety_factor
Definition m_dt.f90:28
subroutine, public dt_initialize(cfg)
Initialize the time step module.
Definition m_dt.f90:57
real(dp), public, protected dt_min
Definition m_dt.f90:43
real(dp), public, protected dt_max_growth_factor
Maximal relative increase dt for the next iteration.
Definition m_dt.f90:46
Module to compute electric fields.
Definition m_field.f90:2
real(dp), public, protected field_pulse_period
Time of one complete voltage pulse.
Definition m_field.f90:33
subroutine, public field_compute_energy(tree, field_energy)
Compute total field energy in Joule, defined as the volume integral over 1/2 * epsilon * E^2.
Definition m_field.f90:765
real(dp), public, protected current_voltage
The current applied voltage.
Definition m_field.f90:90
subroutine, public field_initialize(tree, cfg, mg)
Initialize this module.
Definition m_field.f90:108
subroutine, public field_compute(tree, mg, s_in, time, have_guess)
Compute electric field on the tree. First perform multigrid to get electric potential,...
Definition m_field.f90:406
Fluid model module.
Definition m_fluid.f90:2
subroutine, public forward_euler(tree, dt, dt_stiff, dt_lim, time, s_deriv, n_prev, s_prev, w_prev, s_out, i_step, n_steps)
Advance fluid model using forward Euler step. If the equation is written as y' = f(y),...
Definition m_fluid.f90:23
Module that stores parameters related to the gas.
Definition m_gas.f90:2
subroutine, public gas_forward_euler(tree, dt, dt_stiff, dt_lim, time, s_deriv, n_prev, s_prev, w_prev, s_out, i_step, n_steps)
A forward-Euler method for the Euler equations.
Definition m_gas.f90:204
logical, public, protected gas_dynamics
Whether the gas dynamics are simulated.
Definition m_gas.f90:15
integer, public, protected i_gas_dens
Definition m_gas.f90:45
integer, dimension(n_vars_euler), public, protected gas_vars
Definition m_gas.f90:69
logical, public, protected gas_constant_density
Whether the gas has a constant density.
Definition m_gas.f90:12
subroutine, public gas_initialize(tree, cfg)
Initialize this module.
Definition m_gas.f90:101
Module to help setting up initial conditions.
subroutine, public init_cond_set_box(box)
Sets the initial condition.
subroutine, public init_cond_initialize(tree, cfg)
Set the initial conditions from the configuration.
Module to set the type of model.
Definition m_model.f90:2
subroutine, public model_initialize(cfg)
Initialize the module.
Definition m_model.f90:28
Module with methods and parameters related to writing output.
Definition m_output.f90:2
integer, public, protected output_dt_factor_pulse_off
Definition m_output.f90:91
subroutine, public output_status(tree, time, wc_time, it, dt)
Print short status message.
Definition m_output.f90:853
real(dp), public, protected output_dt
Definition m_output.f90:22
subroutine, public output_initial_summary(tree)
Write a summary of the model and parameters used.
Definition m_output.f90:294
character(len=string_len), public, protected output_name
Definition m_output.f90:16
real(dp), public, protected output_status_delay
Definition m_output.f90:88
subroutine, public output_initialize(tree, cfg)
Definition m_output.f90:127
subroutine, public output_write(tree, output_cnt, wc_time, write_sim_data)
Definition m_output.f90:308
Top-module for photoionization, which can make use of different methods.
Definition m_photoi.f90:2
subroutine, public photoi_set_src(tree, dt)
Sets the photoionization.
Definition m_photoi.f90:141
logical, public, protected photoi_enabled
Whether photoionization is enabled.
Definition m_photoi.f90:15
subroutine, public photoi_initialize(tree, cfg)
Initialize photoionization parameters.
Definition m_photoi.f90:65
integer, public, protected photoi_per_steps
Update photoionization every N time step.
Definition m_photoi.f90:49
Module with grid refinement settings and routines.
Definition m_refine.f90:2
integer, public, protected refine_buffer_width
Definition m_refine.f90:10
subroutine, public refine_initialize(cfg)
Initialize the grid refinement options.
Definition m_refine.f90:93
real(dp), public current_electrode_dx
Definition m_refine.f90:47
real(dp), public refine_electrode_dx
Definition m_refine.f90:43
real(dp), public, protected refine_prepulse_time
Definition m_refine.f90:54
integer, public, protected refine_per_steps
Definition m_refine.f90:13
procedure(af_subr_ref), pointer, public refine_routine
Definition m_refine.f90:83
real(dp), public, protected electrode_derefine_factor
Definition m_refine.f90:51
real(dp), public, protected refine_max_dx
Definition m_refine.f90:19
This module contains several pre-defined variables like:
Definition m_streamer.f90:6
logical, public, protected st_cylindrical
Whether cylindrical coordinates are used.
real(dp), public wc_time_refine
procedure(af_subr_prolong), pointer, public, protected st_prolongation_method
Method used to prolong (interpolate) densities.
real(dp), public wc_time_output
integer, public, protected i_eps
Index can be set to include a dielectric.
real(dp), dimension(:), allocatable, public st_global_rates
Global sum of reaction rates.
integer, public, protected current_update_per_steps
Per how many iterations the electric current is computed.
integer, public, protected st_initial_streamer_pos_steps_wait
Wait n steps before initializing streamer begin position.
real(dp), public wc_time_field
real(dp), public st_global_jdote_current
Electric current through electrodes due to J.E.
real(dp), public global_dt
Global time step.
type(mg_t), public mg
Multigrid option structure.
integer, dimension(ndim), public, protected st_coarse_grid_size
Size of the coarse grid.
subroutine, public st_initialize(tree, cfg, ndim)
Create the configuration file with default values.
integer, public, protected st_box_size
The size of the boxes that we use to construct our mesh.
real(dp), dimension(:, :), allocatable, public st_current_jdote
Current sum of J.E per thread.
logical, dimension(ndim), public, protected st_periodic
Whether the domain is periodic (per dimension)
real(dp), public global_time
Global time.
procedure(af_subr_bc), pointer, public, protected bc_species
Boundary condition for the plasma species.
logical, public, protected st_use_electrode
Whether to include an electrode.
real(dp), public wc_time_source
integer, public, protected i_lsf
Index can be set to include an electrode.
logical, public, protected st_use_dielectric
Whether a dielectric is used.
integer, public, protected i_electron
Index of electron density.
integer, public, protected i_1pos_ion
Index of first positive ion species.
logical, public, protected st_abort_axisymmetric_if_branching
Abort axisymmetric simulations if there is branching.
integer, public, protected i_phi
Index of electrical potential.
real(dp), public wc_time_flux
real(dp), public st_global_jdote
Global sum of J.E.
integer, public, protected i_electric_fld
Index of electric field norm.
real(dp), public wc_time_copy_state
real(dp), public, protected st_end_streamer_length
Streamer length at which the simulation will stop.
real(dp), dimension(ndim), public, protected st_domain_len
Domain length per dimension.
real(dp), public, protected st_end_time
End time of the simulation.
real(dp), dimension(ndim), public, protected st_domain_origin
Origin of domain.
integer, dimension(:), allocatable, public, protected all_densities
Index of all densities that evolve in time.
real(dp), public wc_time_photoi
logical, public, protected st_use_end_streamer_length
Whether streamer length is used as a simulation stopping.
real(dp), dimension(:, :), allocatable, public st_current_rates
Current sum of reaction rates per thread.
real(dp), public st_global_displ_current
Electric current through electrodes due to displacement current.
Module with settings and routines for tabulated data.
subroutine, public table_data_initialize(cfg)
Initialize this module.
Module that provides routines for reading in arbritrary transport data.
subroutine, public transport_data_initialize(cfg)
Initialize the transport coefficients.
Module with basic types.
Definition m_types.f90:2
real(dp), parameter huge_real
Huge number.
Definition m_types.f90:16
character(len= *), parameter undefined_str
Undefined string.
Definition m_types.f90:10
Module that contains physical and numerical constants.
This module contains all the methods that users can customize.
procedure(generic_subr), pointer user_generic_method
Generic procedure that is called every time step.
procedure(af_subr), pointer user_initial_conditions
If defined, call this routine after setting initial conditions.
procedure(af_subr), pointer user_new_pulse_conditions
If defined, call this routine after a new voltage pulse starts.
Template for user code, this one simply uses the default routines.
Definition m_user.f90:2
subroutine, public user_initialize(cfg, tree)
Definition m_user.f90:16
program streamer
Program to perform streamer simulations with AMR.
Definition streamer.f90:2
subroutine initialize_modules(cfg, tree, mg, restart)
Definition streamer.f90:438