afivo-streamer 1.1
1D/2D/3D streamer simulations with AMR
Loading...
Searching...
No Matches
m_fluid.f90
Go to the documentation of this file.
1!> Fluid model module
2module m_fluid
3#include "../afivo/src/cpp_macros.h"
4 use m_af_all
5 use m_streamer
6 use m_model
7
8 implicit none
9 private
10
11 logical, private :: last_step
12
13 ! Public methods
14 public :: forward_euler
15
16contains
17
18 !> Advance fluid model using forward Euler step. If the equation is written as
19 !> y' = f(y), the result is: y(s_out) = y(s_prev) + f(y(s_dt)), where the
20 !> s_... refer to temporal states.
21 subroutine forward_euler(tree, dt, dt_stiff, dt_lim, time, s_deriv, n_prev, &
22 s_prev, w_prev, s_out, i_step, n_steps)
23 use m_chemistry
24 use m_field
25 use m_dt
27 use m_dielectric
28 use omp_lib
29 type(af_t), intent(inout) :: tree
30 real(dp), intent(in) :: dt !< Time step
31 real(dp), intent(in) :: dt_stiff !< Time step for stiff terms (IMEX)
32 real(dp), intent(inout) :: dt_lim !< Computed time step limit
33 real(dp), intent(in) :: time !< Current time
34 integer, intent(in) :: s_deriv !< State to compute derivatives from
35 integer, intent(in) :: n_prev !< Number of previous states
36 integer, intent(in) :: s_prev(n_prev) !< Previous states
37 real(dp), intent(in) :: w_prev(n_prev) !< Weights of previous states
38 integer, intent(in) :: s_out !< Output state
39 integer, intent(in) :: i_step !< Step of the integrator
40 integer, intent(in) :: n_steps !< Total number of steps
41 integer :: ix, id_out
42 real(dp) :: t1, t2, t3
43
44 ! Set current rates to zero; they are summed below
47
48 last_step = (i_step == n_steps)
49
50 ! Since field_compute is called after performing time integration, we don't
51 ! have to call it again for the first sub-step of the next iteration
52 t1 = omp_get_wtime()
53 if (i_step > 1) call field_compute(tree, mg, s_deriv, time, .true.)
54 t2 = omp_get_wtime()
56
57 call flux_upwind_tree(tree, flux_num_species, flux_species, s_deriv, &
58 flux_variables, 2, dt_limits(1:2), flux_upwind, flux_direction, &
59 flux_dummy_line_modify, af_limiter_koren_t)
60 t3 = omp_get_wtime()
61 wc_time_flux = wc_time_flux + t3 - t2
62
63 if (transport_data_ions%n_mobile_ions > 0 .and. &
64 ion_se_yield > 0.0_dp) then
65 ! Handle secondary electron emission from ions
66 call af_loop_box(tree, handle_ion_se_flux, .true.)
67 end if
68
69 t1 = omp_get_wtime()
70 call flux_update_densities(tree, dt, size(all_densities), &
72 flux_species, flux_variables, s_deriv, n_prev, s_prev, &
73 w_prev, s_out, add_source_terms, 2, dt_limits(3:4), set_box_mask)
74 t2 = omp_get_wtime()
76
77 if (st_use_dielectric) then
78 ! Update surface charge and handle photon emission
79 ! @todo For parallelization, think about corner cells with two surfaces
80 do ix = 1, diel%max_ix
81 if (diel%surfaces(ix)%in_use) then
82 id_out = diel%surfaces(ix)%id_out
83
84 ! Convert fluxes onto dielectric to surface charge, and handle
85 ! secondary emission
86 call dielectric_update_surface_charge(tree%boxes(id_out), &
87 diel%surfaces(ix), dt, n_prev, s_prev, w_prev, s_out)
88
89 ! Add secondary emission from photons hitting the surface
90 call dielectric_photon_emission(tree%boxes(id_out), &
91 diel%surfaces(ix), dt, s_out)
92 end if
93 end do
94 end if
95
96 ! Set time step limit
98 dt_lim = min(dt_max, minval(dt_limits))
99 end subroutine forward_euler
100
101 !> Compute flux for the fluid model
102 subroutine flux_upwind(nf, n_var, flux_dim, u, flux, cfl_sum, &
103 n_other_dt, other_dt, box, line_ix, s_deriv)
104 use m_af_flux_schemes
106 use m_gas
107 use m_lookup_table
109 integer, intent(in) :: nf !< Number of cell faces
110 integer, intent(in) :: n_var !< Number of variables
111 integer, intent(in) :: flux_dim !< In which dimension fluxes are computed
112 real(dp), intent(in) :: u(nf, n_var) !< Face values
113 real(dp), intent(out) :: flux(nf, n_var) !< Computed fluxes
114 !> Terms per cell-center to be added to CFL sum, see flux_upwind_box
115 real(dp), intent(out) :: cfl_sum(nf-1)
116 integer, intent(in) :: n_other_dt !< Number of non-cfl time step restrictions
117 real(dp), intent(inout) :: other_dt(n_other_dt) !< Non-cfl time step restrictions
118 type(box_t), intent(in) :: box !< Current box
119 integer, intent(in) :: line_ix(ndim-1) !< Index of line for dim /= flux_dim
120 integer, intent(in) :: s_deriv !< State to compute derivatives from
121
122 real(dp), parameter :: five_third = 5/3.0_dp
123
124 real(dp) :: e_cc(0:nf) !< Cell-centered field strengths
125 real(dp) :: e_x(nf) !< Face-centered field components
126 real(dp) :: n_gas(0:nf) !< Gas number density at cell centers
127 real(dp) :: ne_cc(0:nf) !< Electron density at cell centers
128 real(dp) :: en_cc(0:nf) !< Electron energy density at cell centers
129 real(dp) :: v(nf) !< Velocity at cell faces
130 real(dp) :: dc(nf) !< Diffusion coefficient at cell faces
131 real(dp) :: tmp_fc(nf), n_inv(nf)
132 real(dp) :: mu(nf), sigma(nf), inv_dx, cfl_factor
133 integer :: n, nc, flux_ix
134
135 nc = box%n_cell
136 inv_dx = 1/box%dr(flux_dim)
137
138 ! Inside dielectrics, set the flux to zero
139 if (st_use_dielectric) then
140 if (box%cc(dtimes(1), i_eps) > 1.0_dp) then
141 flux = 0.0_dp
142 return
143 end if
144 end if
145
146 if (gas_constant_density) then
147 n_inv = 1/gas_number_density
148 else
149 ! Compute gas number density at cell faces
150 call flux_get_line_1cc(box, i_gas_dens, flux_dim, line_ix, n_gas)
151 do n = 1, nc+1
152 n_inv(n) = 2 / (n_gas(n-1) + n_gas(n))
153 end do
154 end if
155
156 call flux_get_line_1fc(box, electric_fld, flux_dim, line_ix, e_x)
157 call flux_get_line_1cc(box, i_electron+s_deriv, flux_dim, line_ix, ne_cc)
158
160 call flux_get_line_1cc(box, i_electron_energy+s_deriv, &
161 flux_dim, line_ix, en_cc)
162
163 ! Get mean electron energies at cell faces
164 tmp_fc = mean_electron_energy(u(:, 2), u(:, 1))
165 mu = lt_get_col(td_ee_tbl, td_ee_mobility, tmp_fc) * n_inv
166 dc = lt_get_col(td_ee_tbl, td_ee_diffusion, tmp_fc) * n_inv
167 else
168 call flux_get_line_1cc(box, i_electric_fld, flux_dim, line_ix, e_cc)
169
170 ! Compute field strength at cell faces, which is used to compute the
171 ! mobility and diffusion coefficient at the interface
172 tmp_fc = 0.5_dp * (e_cc(0:nc) + e_cc(1:nc+1)) * si_to_townsend * n_inv
173 mu = lt_get_col(td_tbl, td_mobility, tmp_fc) * n_inv
174 dc = lt_get_col(td_tbl, td_diffusion, tmp_fc) * n_inv
175 end if
176
177 ! Compute velocity, -mu accounts for negative electron charge
178 v = -mu * e_x
179
180 ! Combine advective and diffusive flux
181 flux(:, 1) = v * u(:, 1) - dc * inv_dx * (ne_cc(1:nc+1) - ne_cc(0:nc))
182
183 ! Electron conductivity
184 sigma = mu * u(:, 1)
185
187 flux(:, 2) = five_third * (v * u(:, 2) - &
188 dc * inv_dx * (en_cc(1:nc+1) - en_cc(0:nc)))
189 cfl_factor = five_third
190 else
191 cfl_factor = 1.0_dp
192 end if
193
194 ! Used to determine electron CFL time step
195 cfl_sum = cfl_factor * max(abs(v(2:)), abs(v(:nf-1))) * inv_dx + &
196 2 * max(dc(2:), dc(:nf-1)) * inv_dx**2
197
198 ! Ion fluxes (note: ions are slow, so their CFL condition is ignored)
199 do n = 1, transport_data_ions%n_mobile_ions
200 flux_ix = flux_num_electron_vars + n
201 mu = transport_data_ions%mobilities(n) * n_inv
202 v = flux_species_charge_sign(flux_ix) * mu * e_x
203 flux(:, flux_ix) = v * u(:, flux_ix)
204 sigma = sigma + mu * u(:, flux_ix)
205 end do
206
207 ! Dielectric relaxation time
208 other_dt(1) = uc_eps0 / (uc_elem_charge * max(maxval(sigma), 1e-100_dp))
209 end subroutine flux_upwind
210
211 !> Determine the direction of fluxes
212 subroutine flux_direction(box, line_ix, s_deriv, n_var, flux_dim, direction_positive)
213 type(box_t), intent(in) :: box !< Current box
214 integer, intent(in) :: line_ix(ndim-1) !< Index of line for dim /= flux_dim
215 integer, intent(in) :: s_deriv !< State to compute derivatives from
216 integer, intent(in) :: flux_dim !< In which dimension fluxes are computed
217 integer, intent(in) :: n_var !< Number of variables
218 !> True means positive flow (to the "right"), false to the left
219 logical, intent(out) :: direction_positive(box%n_cell+1, n_var)
220 real(dp) :: e_x(box%n_cell+1)
221 integer :: n
222
223 call flux_get_line_1fc(box, electric_fld, flux_dim, line_ix, e_x)
224 do n = 1, n_var
225 direction_positive(:, n) = (flux_species_charge_sign(n) * e_x > 0)
226 end do
227 end subroutine flux_direction
228
229 !> Get average of cell-centered quantity at a cell face
230 pure function cc_average_at_cell_face(box, IJK, idim, iv) result(avg)
231 type(box_t), intent(in) :: box
232 integer, intent(in) :: ijk !< Face index
233 integer, intent(in) :: idim !< Direction of the cell face
234 integer, intent(in) :: iv !< Index of cell-centered variable
235 real(dp) :: avg
236
237#if NDIM == 1
238 avg = 0.5_dp * (box%cc(i-1, iv) + box%cc(i, iv))
239#elif NDIM == 2
240 select case (idim)
241 case (1)
242 avg = 0.5_dp * (box%cc(i-1, j, iv) + box%cc(i, j, iv))
243 case default
244 avg = 0.5_dp * (box%cc(i, j-1, iv) + box%cc(i, j, iv))
245 end select
246#elif NDIM == 3
247 select case (idim)
248 case (1)
249 avg = 0.5_dp * (box%cc(i-1, j, k, iv) + box%cc(i, j, k, iv))
250 case (2)
251 avg = 0.5_dp * (box%cc(i, j-1, k, iv) + box%cc(i, j, k, iv))
252 case default
253 avg = 0.5_dp * (box%cc(i, j, k-1, iv) + box%cc(i, j, k, iv))
254 end select
255#endif
256 end function cc_average_at_cell_face
257
258 !> Get inner product of face-centered variables
259 pure function fc_inner_product(box, IJK, flux_a, flux_b) result(inprod)
260 type(box_t), intent(in) :: box
261 integer, intent(in) :: ijk !< Face index
262 integer, intent(in) :: flux_a !< Index of first face-centered variable
263 integer, intent(in) :: flux_b !< Index of second face-centered variable
264 real(dp) :: inprod
265
266 inprod = 0.5_dp * sum(box%fc(ijk, :, flux_a) * box%fc(ijk, :, flux_b))
267#if NDIM == 1
268 inprod = inprod + 0.5_dp * (&
269 box%fc(i+1, 1, flux_a) * box%fc(i+1, 1, flux_b))
270#elif NDIM == 2
271 inprod = inprod + 0.5_dp * (&
272 box%fc(i+1, j, 1, flux_a) * box%fc(i+1, j, 1, flux_b) + &
273 box%fc(i, j+1, 2, flux_a) * box%fc(i, j+1, 2, flux_b))
274#elif NDIM == 3
275 inprod = inprod + 0.5_dp * (&
276 box%fc(i+1, j, k, 1, flux_a) * box%fc(i+1, j, k, 1, flux_b) + &
277 box%fc(i, j+1, k, 2, flux_a) * box%fc(i, j+1, k, 2, flux_b) + &
278 box%fc(i, j, k+1, 3, flux_a) * box%fc(i, j, k+1, 3, flux_b))
279#endif
280 end function fc_inner_product
281
282 !> Get inverse gas density at a cell face, between cell-centered index i-1 and
283 !> i along dimension idim
284 pure real(dp) function get_n_inv_face(box, IJK, idim)
285 use m_gas
286 type(box_t), intent(in) :: box
287 integer, intent(in) :: ijk
288 integer, intent(in) :: idim !< Direction of flux through cell face
289
290 if (gas_constant_density) then
291 get_n_inv_face = gas_inverse_number_density
292 else
293 get_n_inv_face = 1 / cc_average_at_cell_face(box, ijk, idim, i_gas_dens)
294 end if
295 end function get_n_inv_face
296
297 !> Add chemistry and photoionization source terms
298 subroutine add_source_terms(box, dt, n_vars, i_cc, s_deriv, s_out, n_dt, dt_lim, mask)
299 use omp_lib
301 use m_gas
302 use m_chemistry
303 use m_photoi
304 use m_dt
305 use m_lookup_table
307 type(box_t), intent(inout) :: box
308 real(dp), intent(in) :: dt
309 integer, intent(in) :: n_vars
310 integer, intent(in) :: i_cc(n_vars)
311 integer, intent(in) :: s_deriv
312 integer, intent(in) :: s_out
313 integer, intent(in) :: n_dt
314 real(dp), intent(inout) :: dt_lim(n_dt)
315 logical, intent(in) :: mask(dtimes(box%n_cell))
316
317 real(dp) :: tmp, gain, loss_rate
318 real(dp) :: rates(box%n_cell**ndim, n_reactions)
319 real(dp) :: derivs(box%n_cell**ndim, n_species)
320 real(dp) :: dens(box%n_cell**ndim, n_species)
321 real(dp) :: fields(box%n_cell**ndim), box_rates(n_reactions)
322 real(dp) :: source_factor(box%n_cell**ndim)
323 real(dp) :: mean_energies(box%n_cell**ndim)
324 integer :: ijk, ix, nc, n_cells, n, iv
325 integer :: tid
326 real(dp), parameter :: eps = 1e-100_dp
327
328 nc = box%n_cell
329 n_cells = box%n_cell**ndim
330
331 ! Skip this routine if there are no cells to update
332 if (.not. any(mask)) return
333
334 if (gas_constant_density) then
335 ! Compute field in Townsends
336 tmp = 1 / gas_number_density
337 fields = si_to_townsend * tmp * &
338 pack(box%cc(dtimes(1:nc), i_electric_fld), .true.)
339 else
340 do n = 1, n_gas_species
341 dens(:, n) = gas_fractions(n) * &
342 pack(box%cc(dtimes(1:nc), i_gas_dens), .true.)
343 end do
344
345 fields(:) = si_to_townsend * pack( &
346 box%cc(dtimes(1:nc), i_electric_fld) / &
347 box%cc(dtimes(1:nc), i_gas_dens), .true.)
348 end if
349
350 dens(:, n_gas_species+1:n_species) = reshape(box%cc(dtimes(1:nc), &
352
353 ! It is assumed that species densities should be non-negative. When
354 ! computing the effect of chemical reactions, this can also help with
355 ! stability, see e.g. http://dx.doi.org/10.1088/1749-4699/6/1/015001
356 dens = max(dens, 0.0_dp)
357
359 mean_energies = pack(mean_electron_energy(&
360 box%cc(dtimes(1:nc), i_electron_energy+s_out), &
361 box%cc(dtimes(1:nc), i_electron+s_out)), .true.)
362 call get_rates(fields, rates, n_cells, mean_energies)
363 else
364 mean_energies = 0.0_dp
365 call get_rates(fields, rates, n_cells)
366 end if
367
370 call compute_source_factor(box, nc, dens(:, ix_electron), &
371 fields, s_deriv, source_factor)
372 else
373 source_factor(:) = 1.0_dp
374 end if
375
377 ! Prevent ionization in cells with a low number of electrons. Note
378 ! that that the radius is not taken into account for axisymmetric
379 ! cases, as this would lead to artifacts.
380 where (dens(:, ix_electron) * minval(box%dr)**3 < &
382 source_factor = 0.0_dp
383 end where
384 end if
385
386 if (i_srcfac > 0) then
387 ! Write source factor to variable
388 box%cc(dtimes(1:nc), i_srcfac) = &
389 reshape(source_factor, [dtimes(nc)])
390 end if
391
392 do n = 1, n_reactions
393 if (reactions(n)%reaction_type == ionization_reaction) then
394 rates(:, n) = rates(:, n) * source_factor
395 end if
396 end do
397 end if
398
399 ! Note that this routine updates its rates argument
400 call get_derivatives(dens, rates, derivs, n_cells)
401
402 if (last_step) then
403 tid = omp_get_thread_num() + 1
404
405 ! Update chemistry time step. Note that 'dens' is already non-negative.
406 if (dt_chemistry_nmin > 0) then
407 ! The time step is restricted by both the production and destruction
408 ! rate of species
409 tmp = minval((dens + dt_chemistry_nmin) / max(abs(derivs), eps))
410 else if (dt_chemistry_limit_loss) then
411 ! Prevent negative values due to too much removal of a species
412 tmp = minval(max(dens, eps) / max(-derivs, eps))
413 else
414 tmp = 1e100_dp
415 end if
416
417 dt_lim(1) = tmp
418
419 ! Keep track of chemical production at last time integration step
420 call chemical_rates_box(box, nc, rates, box_rates)
421
422 !> Integrate rates over space and time into global storage
423 st_current_rates(1:n_reactions, tid) = &
424 st_current_rates(1:n_reactions, tid) + box_rates
425
426 ! Keep track of J.E
427 call sum_global_jdote(box, tid)
428 end if
429
430 ix = 0
431 do kji_do(1,nc)
432 ix = ix + 1
433 if (.not. mask(ijk)) cycle
434
435 if (photoi_enabled) then
436 derivs(ix, ix_electron) = derivs(ix, ix_electron) + &
437 box%cc(ijk, i_photo)
438 derivs(ix, photoi_species_index) = &
439 derivs(ix, photoi_species_index) + box%cc(ijk, i_photo)
440 end if
441
443 gain = -fc_inner_product(box, ijk, flux_elec, electric_fld)
444 loss_rate = lt_get_col(td_ee_tbl, td_ee_loss, mean_energies(ix))
445 box%cc(ijk, i_electron_energy+s_out) = box%cc(ijk, i_electron_energy+s_out) &
446 + dt * (gain - loss_rate * box%cc(ijk, i_electron+s_out))
447 end if
448 end do; close_do
449
450 do n = n_gas_species+1, n_species
451 ix = 0
452 iv = species_itree(n)
453 do kji_do(1,nc)
454 ix = ix + 1
455 if (.not. mask(ijk)) cycle
456 box%cc(ijk, iv+s_out) = box%cc(ijk, iv+s_out) + dt * derivs(ix, n)
457 end do; close_do
458 end do
459
460 if (model_has_energy_equation) then
461 ! Set time step restriction for energy loss
462 tmp = maxval(mean_energies)
463 dt_lim(2) = tmp/lt_get_col(td_ee_tbl, td_ee_loss, tmp)
464 end if
465
466 end subroutine add_source_terms
467
468 !> Set a mask to true in the gas phase, where the solution should be updated
469 subroutine set_box_mask(box, mask)
470 type(box_t), intent(in) :: box
471 logical, intent(out) :: mask(dtimes(box%n_cell))
472 integer :: n, nc, ijk
473 real(dp) :: coords(box%n_cell, ndim), r(ndim)
474 real(dp), parameter :: eps = 1e-10_dp
475
476 nc = box%n_cell
477 mask = .true.
478
479 ! Do no update chemistry inside electrode
480 if (st_use_electrode) then
481 where (box%cc(dtimes(1:nc), i_lsf) <= 0.0_dp)
482 mask = .false.
483 end where
484 end if
485
486 ! Inside a dielectric, do not update the species densities
487 if (st_use_dielectric) then
488 where (abs(box%cc(dtimes(1:nc), i_eps) - 1) > eps)
489 mask = .false.
490 end where
491 end if
492
493 ! Optionally limit chemistry to a particular region
494 if (st_plasma_region_enabled) then
495 ! Compute box coordinates
496 do n = 1, ndim
497 coords(:, n) = box%r_min(n) + box%dr(n) * [(i-0.5_dp, i=1,nc)]
498 end do
499
500 do kji_do(1,nc)
501 r(1) = coords(i, 1)
502#if NDIM > 1
503 r(2) = coords(j, 2)
504#endif
505#if NDIM > 2
506 r(3) = coords(k, 3)
507#endif
508 if (any(r < st_plasma_region_rmin) .or. &
509 any(r > st_plasma_region_rmax)) then
510 mask(ijk) = .false.
511 end if
512 end do; close_do
513 end if
514
515 end subroutine set_box_mask
516
517 !> Get mean electron energy
518 pure elemental real(dp) function mean_electron_energy(n_energy, n_e)
519 real(dp), intent(in) :: n_energy, n_e
520 mean_electron_energy = n_energy / max(n_e, 1.0_dp)
521 end function mean_electron_energy
522
523 !> Compute adjustment factor for electron source terms. Used to reduce them in
524 !> certain regimes.
525 subroutine compute_source_factor(box, nc, elec_dens, fields, s_dt, source_factor)
526 use m_gas
528 use m_lookup_table
529 type(box_t), intent(inout) :: box
530 integer, intent(in) :: nc
531 real(dp), intent(in) :: elec_dens(nc**ndim)
532 real(dp), intent(in) :: fields(nc**ndim)
533 integer, intent(in) :: s_dt
534 real(dp), intent(out) :: source_factor(nc**ndim)
535 real(dp) :: mobilities(nc**ndim)
536 real(dp) :: n_inv(nc**ndim)
537 real(dp) :: inv_dr(ndim)
538 real(dp), parameter :: small_flux = 1.0e-9_dp ! A small flux
539 integer :: ix, ijk
540
541 inv_dr = 1/box%dr
542
543 if (gas_constant_density) then
544 n_inv = 1 / gas_number_density
545 else
546 n_inv = pack(1 / box%cc(dtimes(1:nc), i_gas_dens), .true.)
547 end if
548
549 mobilities = lt_get_col(td_tbl, td_mobility, fields) * n_inv
550
551 select case (st_source_factor)
552 case (source_factor_flux)
553 ix = 0
554 do kji_do(1,nc)
555 ix = ix + 1
556
557 ! Compute norm of flux at cell center
558#if NDIM == 1
559 source_factor(ix) = 0.5_dp * norm2([ &
560 box%fc(i, 1, flux_elec) + box%fc(i+1, 1, flux_elec)])
561#elif NDIM == 2
562 source_factor(ix) = 0.5_dp * norm2([ &
563 box%fc(i, j, 1, flux_elec) + box%fc(i+1, j, 1, flux_elec), &
564 box%fc(i, j, 2, flux_elec) + box%fc(i, j+1, 2, flux_elec)])
565#elif NDIM == 3
566 source_factor(ix) = 0.5_dp * norm2([ &
567 box%fc(i, j, k, 1, flux_elec) + box%fc(i+1, j, k, 1, flux_elec), &
568 box%fc(i, j, k, 2, flux_elec) + box%fc(i, j+1, k, 2, flux_elec), &
569 box%fc(i, j, k, 3, flux_elec) + box%fc(i, j, k+1, 3, flux_elec)])
570#endif
571 end do; close_do
572
573 ! Compute source factor as |flux|/(n_e * mu * E)
574 source_factor = (source_factor + small_flux) / (small_flux + &
575 elec_dens * mobilities * &
576 pack(box%cc(dtimes(1:nc), i_electric_fld), .true.))
577 case default
578 error stop "This type of source factor not implemented"
579 end select
580
581 source_factor = min(1.0_dp, source_factor)
582 source_factor = max(0.0_dp, source_factor)
583 end subroutine compute_source_factor
584
585 !> Handle secondary emission from positive ions at the domain walls
586 subroutine handle_ion_se_flux(box)
588 type(box_t), intent(inout) :: box
589 integer :: nc, nb, n, ion_flux, flux_ix
590
591 nc = box%n_cell
592
593 ! Return if there is no physical boundary
594 if (all(box%neighbors >= af_no_box)) return
595
596 do nb = 1, af_num_neighbors
597 ! Check for physical boundary
598 if (box%neighbors(nb) < af_no_box) then
599
600 ! Loop over positive ion species
601 do n = 1, transport_data_ions%n_mobile_ions
602 flux_ix = flux_num_electron_vars + n
603 if (flux_species_charge(flux_ix) > 0.0_dp) then
604 ion_flux = flux_variables(flux_ix)
605 select case (nb)
606#if NDIM == 1
607 case (af_neighb_lowx)
608 box%fc(1, 1, flux_elec) = box%fc(1, 1, flux_elec) - &
609 ion_se_yield * min(0.0_dp, box%fc(1, 1, ion_flux))
610 case (af_neighb_highx)
611 box%fc(nc+1, 1, flux_elec) = box%fc(nc+1, 1, flux_elec) - &
612 ion_se_yield * max(0.0_dp, box%fc(1, 1, ion_flux))
613#elif NDIM == 2
614 case (af_neighb_lowx)
615 box%fc(1, 1:nc, 1, flux_elec) = &
616 box%fc(1, 1:nc, 1, flux_elec) - ion_se_yield * &
617 min(0.0_dp, box%fc(1, 1:nc, 1, ion_flux))
618 case (af_neighb_highx)
619 box%fc(nc+1, 1:nc, 1, flux_elec) = &
620 box%fc(nc+1, 1:nc, 1, flux_elec) - ion_se_yield * &
621 max(0.0_dp, box%fc(nc+1, 1:nc, 1, ion_flux))
622 case (af_neighb_lowy)
623 box%fc(1:nc, 1, 2, flux_elec) = &
624 box%fc(1:nc, 1, 2, flux_elec) - ion_se_yield * &
625 min(0.0_dp, box%fc(1:nc, 1, 2, ion_flux))
626 case (af_neighb_highy)
627 box%fc(1:nc, nc+1, 2, flux_elec) = &
628 box%fc(1:nc, nc+1, 2, flux_elec) - ion_se_yield * &
629 max(0.0_dp, box%fc(1:nc, nc+1, 2, ion_flux))
630#elif NDIM == 3
631 case (af_neighb_lowx)
632 box%fc(1, 1:nc, 1:nc, 1, flux_elec) = &
633 box%fc(1, 1:nc, 1:nc, 1, flux_elec) - ion_se_yield * &
634 min(0.0_dp, box%fc(1, 1:nc, 1:nc, 1, ion_flux))
635 case (af_neighb_highx)
636 box%fc(nc+1, 1:nc, 1:nc, 1, flux_elec) = &
637 box%fc(nc+1, 1:nc, 1:nc, 1, flux_elec) - ion_se_yield * &
638 max(0.0_dp, box%fc(nc+1, 1:nc, 1:nc, 1, ion_flux))
639 case (af_neighb_lowy)
640 box%fc(1:nc, 1:nc, 1, 2, flux_elec) = &
641 box%fc(1:nc, 1:nc, 1, 2, flux_elec) - ion_se_yield * &
642 min(0.0_dp, box%fc(1:nc, 1:nc, 1, 2, ion_flux))
643 case (af_neighb_highy)
644 box%fc(1:nc, nc+1, 1:nc, 2, flux_elec) = &
645 box%fc(1:nc, nc+1, 1:nc, 2, flux_elec) - ion_se_yield * &
646 max(0.0_dp, box%fc(1:nc, nc+1, 1:nc, 2, ion_flux))
647 case (af_neighb_lowz)
648 box%fc(1:nc, 1:nc, 1, 3, flux_elec) = &
649 box%fc(1:nc, 1:nc, 1, 3, flux_elec) - ion_se_yield * &
650 min(0.0_dp, box%fc(1:nc, 1:nc, 1, 3, ion_flux))
651 case (af_neighb_highz)
652 box%fc(1:nc, 1:nc, nc+1, 3, flux_elec) = &
653 box%fc(1:nc, 1:nc, nc+1, 3, flux_elec) - ion_se_yield * &
654 max(0.0_dp, box%fc(1:nc, 1:nc, nc+1, 3, ion_flux))
655#endif
656
657 end select
658 end if
659 end do
660 end if
661 end do
662
663 end subroutine handle_ion_se_flux
664
665 !> Volume integrate chemical reaction rates
666 subroutine chemical_rates_box(box, nc, rates, box_rates)
667 use m_chemistry
668 type(box_t), intent(in) :: box
669 integer, intent(in) :: nc
670 real(dp), intent(in) :: rates(nc**ndim, n_reactions)
671 real(dp), intent(out) :: box_rates(n_reactions)
672#if NDIM == 2
673 integer :: i, n
674 real(dp) :: w(nc), tmp(nc, nc)
675#endif
676
677 if (box%coord_t == af_xyz) then
678 box_rates = sum(rates, dim=1) * product(box%dr)
679#if NDIM == 2
680 else if (box%coord_t == af_cyl) then
681 box_rates(:) = 0
682
683 ! Get volume versus radius
684 do i = 1, nc
685 w(i) = af_cyl_volume_cc(box, i)
686 end do
687
688 do n = 1, n_reactions
689 tmp = reshape(rates(:, n), [nc, nc])
690 do i = 1, nc
691 tmp(i, :) = w(i) * tmp(i, :)
692 end do
693 box_rates(n) = box_rates(n) + sum(tmp)
694 end do
695#endif
696 else
697 error stop "Unknown box coordinates"
698 end if
699 end subroutine chemical_rates_box
700
701 !> Integrate J.E over space into global storage
702 subroutine sum_global_jdote(box, tid)
704 type(box_t), intent(in) :: box
705 integer, intent(in) :: tid !< Thread id
706 integer :: ijk, nc
707 real(dp) :: jdote, tmp
708 real(dp) :: volume(box%n_cell)
709
710 jdote = 0.0_dp
711
712 volume = product(box%dr)
713
714#if NDIM == 2
715 if (box%coord_t == af_cyl) then
716 ! Cylindrical case
717 do i = 1, box%n_cell
718 volume(i) = af_cyl_volume_cc(box, i)
719 end do
720 end if
721#endif
722
723 nc = box%n_cell
724 do kji_do(1, nc)
725 tmp = fc_inner_product(box, ijk, flux_elec, electric_fld)
726 jdote = jdote + tmp * volume(i)
727 end do; close_do
728
729 st_current_jdote(1, tid) = st_current_jdote(1, tid) + &
730 jdote * uc_elec_charge
731 end subroutine sum_global_jdote
732
733end module m_fluid
Module for handling chemical reactions.
integer, parameter, public ionization_reaction
Identifier for ionization reactions.
subroutine, public get_rates(fields, rates, n_cells, energy_ev)
Compute reaction rates.
subroutine, public get_derivatives(dens, rates, derivs, n_cells)
Compute derivatives due to chemical reactions. Note that the 'rates' argument is modified.
integer, dimension(max_num_species), public, protected species_itree
species_itree(n) holds the index of species n in the tree (cell-centered variables)
integer, public, protected n_species
Number of species present.
integer, public, protected n_plasma_species
Number of plasma species present.
type(reaction_t), dimension(max_num_reactions), public, protected reactions
List of reactions.
integer, public, protected n_gas_species
Number of gas species present.
integer, public, protected n_reactions
Number of reactions present.
Module with settings and routines to handle dielectrics.
type(surfaces_t), public diel
To store dielectric surface.
subroutine, public dielectric_photon_emission(box, surface, dt, s_out)
subroutine, public dielectric_update_surface_charge(box, surface, dt, n_prev, s_prev, w_prev, s_out)
Update charge on dielectric surface based on particle fluxes. In case of secondary emission,...
Module to set the time step.
Definition m_dt.f90:2
real(dp), dimension(dt_num_cond), public dt_limits
Definition m_dt.f90:13
real(dp), public, protected dt_max
Definition m_dt.f90:40
real(dp), public, protected dt_chemistry_nmin
If > 0, a density to control the accuracy of the chemistry time step.
Definition m_dt.f90:34
logical, public, protected dt_chemistry_limit_loss
Limit dt to prevent negative densities due to loss reactions.
Definition m_dt.f90:37
real(dp), public, protected dt_cfl_number
CFL number to use.
Definition m_dt.f90:31
Module to compute electric fields.
Definition m_field.f90:2
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
real(dp), dimension(:), allocatable, public, protected gas_fractions
Definition m_gas.f90:24
integer, public, protected i_gas_dens
Definition m_gas.f90:45
real(dp), parameter, public si_to_townsend
Definition m_gas.f90:39
logical, public, protected gas_constant_density
Whether the gas has a constant density.
Definition m_gas.f90:12
real(dp), public, protected gas_number_density
Definition m_gas.f90:33
real(dp), public, protected gas_inverse_number_density
Definition m_gas.f90:36
Module to set the type of model.
Definition m_model.f90:2
logical, public, protected model_has_energy_equation
Whether the model has an energy equation.
Definition m_model.f90:20
Top-module for photoionization, which can make use of different methods.
Definition m_photoi.f90:2
integer, public, protected photoi_species_index
Index of species ionized by photoionization (in list of chemical species)
Definition m_photoi.f90:30
logical, public, protected photoi_enabled
Whether photoionization is enabled.
Definition m_photoi.f90:15
integer, public, protected i_photo
Optional variable (when using photoionization)
Definition m_photoi.f90:55
This module contains several pre-defined variables like:
Definition m_streamer.f90:6
integer, public, protected flux_num_electron_vars
Number of electron flux variables.
integer, dimension(:), allocatable, public, protected flux_species_charge_sign
List of the signs of the charges of the flux species (+- 1)
integer, parameter, public source_factor_none
integer, public, protected i_eps
Index can be set to include a dielectric.
real(dp), public wc_time_field
integer, public, protected i_srcfac
Index of correction factor for source terms.
integer, dimension(:), allocatable, public, protected flux_variables
List of all flux variables (face-centered index)
integer, public, protected st_source_factor
Use source factor to prevent unphysical effects due to diffusion.
type(mg_t), public mg
Multigrid option structure.
real(dp), dimension(:, :), allocatable, public st_current_jdote
Current sum of J.E per thread.
integer, public, protected i_electron_energy
Index of electron energy density.
integer, dimension(:), allocatable, public, protected flux_species
List of all flux species (cell-centered index)
real(dp), public wc_time_source
integer, public, protected ix_electron
Index of electron density (in species list)
logical, public, protected st_use_dielectric
Whether a dielectric is used.
integer, public, protected flux_elec
Index of electron flux.
integer, public, protected i_electron
Index of electron density.
integer, public, protected electric_fld
Index of electric field vector.
real(dp), public wc_time_flux
integer, public, protected i_electric_fld
Index of electric field norm.
integer, dimension(:), allocatable, public, protected all_densities
Index of all densities that evolve in time.
integer, public, protected flux_num_species
Number of flux variables.
real(dp), dimension(:, :), allocatable, public st_current_rates
Current sum of reaction rates per thread.
real(dp), public, protected st_source_min_electrons_per_cell
Minimum number of electrons per cell to include source terms.
Module that provides routines for reading in arbritrary transport data.
real(dp), public, protected ion_se_yield
Secondary electron emission yield for positive ions.
type(lt_t), public, protected td_tbl
integer, parameter, public td_diffusion
Electron diffusion constant.
integer, public, protected td_ee_diffusion
Electron diffusion coefficient as a function of energy.
integer, public, protected td_ee_mobility
Electron mobility as a function of energy.
integer, parameter, public td_mobility
Electron mobility.
type(lt_t), public, protected td_ee_tbl
integer, public, protected td_ee_loss
Electron energy loss.
type(ion_transport_t), public transport_data_ions
Module that contains physical and numerical constants.
real(dp), parameter uc_elem_charge
real(dp), parameter uc_eps0