MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_ard_phys.t
Go to the documentation of this file.
1!> Module containing the physics routines for advection-reaction-diffusion equations
2!>
3!> This module can be seen as an extension of the reaction-diffusion (rd) module
4!> and includes the same reaction systems and more: the Gray-Scott model, the
5!> Schnakenberg model, the Brusselator model, the diffusive logistic equation,
6!> an analytical testcase from "Numerical solution of time-dependent advection-
7!> diffusion-reaction equations" by Hundsdorfer & Verwer, the Oregonator model,
8!> the extended Brusselator model, the diffusive Lorenz system and the advection-
9!> diffusion equation. See the documentation of the advection-reaction-diffusion
10!> module for more information.
11!>
12!> An advection term can be aplied to these systems of the form:
13!> nabla( (A1/adv_pow) * u^(adv_pow) ) (for the first unknown)
14!> nabla( (A2/adv_pow) * v^(adv_pow) ) (for the second unknown, if applicable)
15!> nabla( (A3/adv_pow) * w^(adv_pow) ) (for the third unknown, if applicable)
16!>
17!> IMEX methods are also supported. The implicit system is solved by a
18!> multigrid solver coupled into MPI-AMRVAC.
19!>
22 use mod_comm_lib, only: mpistop
23
24 implicit none
25 private
26
27 !> Indices of the unknowns
28 integer, protected, public :: u_ = 1
29 integer, protected, public :: v_ = 2 !< For 2 or more equations
30 integer, protected, public :: w_ = 3 !< For 3 or more equations
31
32 !> Whether particles module is added
33 logical, public, protected :: ard_particles = .false.
34
35 !> Parameter with which to multiply the reaction timestep restriction
36 double precision, public, protected :: dtreacpar = 0.5d0
37
38 !> Name of the system to be solved
39 character(len=20), public, protected :: equation_name = "gray-scott"
40 integer :: number_of_species = 2
41 integer :: equation_type = 1
42 integer, parameter :: eq_gray_scott = 1 ! Gray-Scott model
43 integer, parameter :: eq_schnakenberg = 2 ! Schnakenberg model
44 integer, parameter :: eq_brusselator = 3 ! Brusselator model
45 integer, parameter :: eq_logistic = 4 ! Logistic equation
46 integer, parameter :: eq_analyt_hunds = 5
47 integer, parameter :: eq_belousov_fn = 6 ! Field-Noyes model, or Oregonator
48 integer, parameter :: eq_ext_brusselator = 7 ! Extended Brusselator
49 integer, parameter :: eq_lorenz = 8 ! Lorenz system
50 integer, parameter :: eq_no_reac = 9 ! Advection-diffusion equation
51
52 !> Diffusion coefficient for first species (u)
53 double precision, public, protected :: d1 = 0.05d0
54 !> Diffusion coefficient for second species (v) (if applicable)
55 double precision, public, protected :: d2 = 1.0d0
56 !> Diffusion coefficient for third species (w) (if applicable)
57 double precision, public, protected :: d3 = 1.0d0
58
59 !> Power of the unknown in the advection term (1 for linear)
60 integer, public, protected :: adv_pow = 1
61
62 !> Advection coefficients for first species (u)
63 double precision, public, protected :: a1(^nd) = 0.0d0
64 !> Advection coefficients for second species (v) (if applicable)
65 double precision, public, protected :: a2(^nd) = 0.0d0
66 !> Advection coefficients for third species (w) (if applicable)
67 double precision, public, protected :: a3(^nd) = 0.0d0
68
69 !> Parameters for Schnakenberg model
70 double precision, public, protected :: sb_alpha = 0.1305d0
71 double precision, public, protected :: sb_beta = 0.7695d0
72 double precision, public, protected :: sb_kappa = 100.0d0
73
74 !> Feed rate for Gray-Scott model
75 double precision, public, protected :: gs_f = 0.046d0
76 !> Kill rate for Gray-Scott model
77 double precision, public, protected :: gs_k = 0.063d0
78
79 !> Parameters for Brusselator model
80 double precision, public, protected :: br_a = 4.5d0
81 double precision, public, protected :: br_b = 8.0d0
82 double precision, public, protected :: br_c = 1.0d0
83 double precision, public, protected :: br_d = 1.0d0
84
85 !> Parameter for logistic model (Fisher / KPP equation)
86 double precision, public, protected :: lg_lambda = 1.0d0
87
88 !> Parameters for the Field-Noyes model of the Belousov-Zhabotinsky reaction
89 double precision, public, protected :: bzfn_epsilon = 1.0d0
90 double precision, public, protected :: bzfn_delta = 1.0d0
91 double precision, public, protected :: bzfn_lambda = 1.0d0
92 double precision, public, protected :: bzfn_mu = 1.0d0
93
94 !> Parameter for Lorenz system (Rayleigh number)
95 double precision, public, protected :: lor_r = 28.0d0
96 !> Parameter for Lorenz system (Prandtl number)
97 double precision, public, protected :: lor_sigma = 10.0d0
98 !> Parameter for Lorenz system (aspect ratio of the convection rolls)
99 double precision, public, protected :: lor_b = 8.0d0 / 3.0d0
100
101 !> Whether to handle the explicitly handled source term in split fashion
102 logical :: ard_source_split = .false.
103 double precision, public, protected :: ard_mg_tol = 1.0d-7 !< multigrid: max_residual = ard_mg_tol/qdt
104
105 !> Boundary condition information for the multigrid method
106 type(mg_bc_t), public :: ard_mg_bc(3, mg_num_neighbors)
107
108 ! Public methods
109 public :: ard_phys_init
110
111contains
112
113 !> Read this module's parameters from a file
114 subroutine ard_params_read(files)
116 character(len=*), intent(in) :: files(:)
117 integer :: n
118
119 namelist /ard_list/ d1, d2, d3, adv_pow, a1, a2, a3, sb_alpha, sb_beta, sb_kappa, &
122 ard_source_split, dtreacpar, ard_mg_tol
123
124 do n = 1, size(files)
125 open(unitpar, file=trim(files(n)), status='old')
126 read(unitpar, ard_list, end=111)
127111 close(unitpar)
128 end do
129
130 !> Set the equation type and number of species
131 select case (equation_name)
132 case ("gray-scott")
133 equation_type = eq_gray_scott
134 number_of_species = 2
135 case ("schnakenberg")
136 equation_type = eq_schnakenberg
137 number_of_species = 2
138 case ("brusselator")
139 equation_type = eq_brusselator
140 number_of_species = 2
141 case ("logistic")
142 equation_type = eq_logistic
143 number_of_species = 1
144 case ("analyt_hunds")
145 equation_type = eq_analyt_hunds
146 number_of_species = 1
147 case ("belousov_fieldnoyes")
148 equation_type = eq_belousov_fn
149 number_of_species = 3
150 case ("ext_brusselator")
151 equation_type = eq_ext_brusselator
152 number_of_species = 3
153 case ("lorenz")
154 equation_type = eq_lorenz
155 number_of_species = 3
156 case ("no_reac")
157 equation_type = eq_no_reac
158 number_of_species = 1
159 case default
160 call mpistop("Unknown equation_name (valid: gray-scott, schnakenberg, ...)")
161 end select
162
163 end subroutine ard_params_read
164
165 !> Write this modules parameters to a snapshot
166 subroutine ard_write_info(fh)
168 integer, intent(in) :: fh
169 integer, parameter :: n_par = 0
170 integer, dimension(MPI_STATUS_SIZE) :: st
171 integer :: er
172 integer :: idim
173
174 call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
175 end subroutine ard_write_info
176
177 subroutine ard_phys_init()
179 use mod_physics
181
182 call ard_params_read(par_files)
183
184 physics_type = "ard"
185 phys_energy = .false.
187
188 allocate(start_indices(number_species),stop_indices(number_species))
189 ! set the index of the first flux variable for species 1
190 start_indices(1)=1
191 ! Use the first variable as a density
192 u_ = var_set_fluxvar("u", "u")
193 if (number_of_species >= 2) then
194 v_ = var_set_fluxvar("v", "v")
195 end if
196 if (number_of_species >= 3) then
197 w_ = var_set_fluxvar("w", "w")
198 end if
199
200 ! set number of variables which need update ghostcells
201 nwgc=nwflux
202 ! set the index of the last flux variable for species 1
203 stop_indices(1)=nwflux
204
205 ! Check whether custom flux types have been defined
206 if (.not. allocated(flux_type)) then
207 allocate(flux_type(ndir, nw))
209 else if (any(shape(flux_type) /= [ndir, nw])) then
210 call mpistop("phys_check error: flux_type has wrong shape")
211 end if
212 if (all([a1, a2, a3] == 0.0d0)) fix_conserve_global = .false. ! no advection: no fluxes to fix at AMR boundaries
213
214 phys_get_cmax => ard_get_cmax
215 phys_get_cbounds => ard_get_cbounds
216 phys_get_flux => ard_get_flux
217 phys_to_conserved => ard_to_conserved
218 phys_to_primitive => ard_to_primitive
219 phys_add_source_geom => ard_add_source_geom
220 phys_add_source => ard_add_source
221 phys_get_dt => ard_get_dt
222 phys_write_info => ard_write_info
223 phys_check_params => ard_check_params
224 phys_implicit_update => ard_implicit_update
225 phys_evaluate_implicit => ard_evaluate_implicit
226
227
228 end subroutine ard_phys_init
229
230 subroutine ard_check_params
233 use mod_geometry, only: coordinate
235 use mod_particles, only: npayload,nusrpayload,ngridvars,num_particles,physics_type_particles
236 integer :: n, i, iw, species_list(number_of_species)
237
238 ! Initialize particles module
239 if (ard_particles) then
240 call particles_init()
241 end if
242
243 if (use_imex_scheme) then
244 use_multigrid = .true.
245 select case(number_of_species)
246 case(1)
247 species_list = [u_]
248 if (d1 == 0.0d0) then
249 write(*, *) "Diffusion coefficient cannot be zero in IMEX scheme"
250 call mpistop("Zero diffusion in IMEX scheme")
251 end if
252 case(2)
253 species_list = [u_, v_]
254 if ((d1 == 0.0d0) .or. (d2 == 0.0d0)) then
255 write(*, *) "Diffusion coefficient cannot be zero in IMEX scheme"
256 call mpistop("Zero diffusion in IMEX scheme")
257 end if
258 case(3)
259 species_list = [u_, v_, w_]
260 if ((d1 == 0.0d0) .or. (d2 == 0.0d0) .or. (d3 == 0.0d0)) then
261 write(*, *) "Diffusion coefficient cannot be zero in IMEX scheme"
262 call mpistop("Zero diffusion in IMEX scheme")
263 end if
264 end select
265
266 do i = 1, number_of_species
267 iw = species_list(i)
268
269 ! Set boundary conditions for the multigrid solver
270 do n = 1, 2*ndim
271 select case (typeboundary(iw, n))
272 case (bc_symm)
273 ! d/dx u = 0
274 ard_mg_bc(i, n)%bc_type = mg_bc_neumann
275 ard_mg_bc(i, n)%bc_value = 0.0_dp
276 case (bc_asymm)
277 ! u = 0
278 ard_mg_bc(i, n)%bc_type = mg_bc_dirichlet
279 ard_mg_bc(i, n)%bc_value = 0.0_dp
280 case (bc_cont)
281 ! d/dx u = 0
282 ard_mg_bc(i, n)%bc_type = mg_bc_neumann
283 ard_mg_bc(i, n)%bc_value = 0.0_dp
284 case (bc_periodic)
285 ! Nothing to do here
286 case (bc_special)
287 if (associated(usr_special_mg_bc)) then
288 call usr_special_mg_bc(n)
289 else if (.not. associated(ard_mg_bc(i, n)%boundary_cond)) then
290 call mpistop("special BC for MG not defined")
291 endif
292 !!if (.not. associated(ard_mg_bc(i, n)%boundary_cond)) then
293 !! write(*, "(A,I0,A,I0,A)") "typeboundary(", iw, ",", n, &
294 !! ") is 'special', but the corresponding method " // &
295 !! "ard_mg_bc(i, n)%boundary_cond is not set"
296 !! call mpistop("ard_mg_bc(i, n)%boundary_cond not set")
297 !!end if
298 case default
299 write(*,*) "ard_check_params warning: unknown boundary type"
300 ard_mg_bc(i, n)%bc_type = mg_bc_dirichlet
301 ard_mg_bc(i, n)%bc_value = 0.0_dp
302 end select
303 end do
304 end do
305 end if
306
307
308 if(mype==0)then
309 write(*,*)'====ARD run with settings===================='
310 write(*,*)'Using mod_ard_phys with settings:'
311 write(*,*)'Dimensionality :',ndim
312 write(*,*)'vector components:',ndir
313 write(*,*)'coordinate set to type,slab:',coordinate,slab
314 write(*,*)'number of variables nw=',nw
315 write(*,*)' start index iwstart=',iwstart
316 write(*,*)'number of vector variables=',nvector
317 write(*,*)'number of stagger variables nws=',nws
318 write(*,*)'number of variables with BCs=',nwgc
319 write(*,*)'number of vars with fluxes=',nwflux
320 write(*,*)'number of vars with flux + BC=',nwfluxbc
321 write(*,*)'number of auxiliary variables=',nwaux
322 write(*,*)'number of extra vars without flux=',nwextra
323 write(*,*)'number of extra vars for wextra=',nw_extra
324 write(*,*)'number of auxiliary I/O variables=',nwauxio
325 write(*,*)' ard_particles=',ard_particles
326 if(ard_particles) then
327 write(*,*) '*****Using particles: npayload,ngridvars :', npayload,ngridvars
328 write(*,*) '*****Using particles: nusrpayload :', nusrpayload
329 write(*,*) '*****Using particles: num_particles :', num_particles
330 write(*,*) '*****Using particles: physics_type_particles=',physics_type_particles
331 end if
332 write(*,*)'number of ghostcells=',nghostcells
333 write(*,*)'==========================================='
334 endif
335
336
337 end subroutine ard_check_params
338
339 subroutine ard_to_conserved(ixI^L, ixO^L, w, x)
341 integer, intent(in) :: ixi^l, ixo^l
342 double precision, intent(inout) :: w(ixi^s, nw)
343 double precision, intent(in) :: x(ixi^s, 1:^nd)
344
345 ! Do nothing (primitive and conservative are equal for ard module)
346 end subroutine ard_to_conserved
347
348 subroutine ard_to_primitive(ixI^L, ixO^L, w, x)
350 integer, intent(in) :: ixi^l, ixo^l
351 double precision, intent(inout) :: w(ixi^s, nw)
352 double precision, intent(in) :: x(ixi^s, 1:^nd)
353
354 ! Do nothing (primitive and conservative are equal for ard module)
355 end subroutine ard_to_primitive
356
357 subroutine ard_get_cmax(w, x, ixI^L, ixO^L, idim, cmax)
359 integer, intent(in) :: ixi^l, ixo^l, idim
360 double precision, intent(in) :: w(ixi^s, nw), x(ixi^s, 1:^nd)
361 double precision, intent(inout) :: cmax(ixi^s)
362
363 cmax(ixo^s) = abs(a1(idim) * w(ixo^s,u_)**(adv_pow-1))
364 if (number_of_species >= 2) then
365 cmax(ixo^s) = max(cmax(ixo^s), abs(a2(idim) * w(ixo^s,v_)**(adv_pow-1)))
366 end if
367 if (number_of_species >= 3) then
368 cmax(ixo^s) = max(cmax(ixo^s), abs(a3(idim) * w(ixo^s,w_)**(adv_pow-1)))
369 end if
370
371 end subroutine ard_get_cmax
372
373 subroutine ard_get_cbounds(wLC, wRC, wLp, wRp, x, ixI^L, ixO^L, idim,Hspeed, cmax, cmin)
375 use mod_variables
376 integer, intent(in) :: ixi^l, ixo^l, idim
377 double precision, intent(in) :: wlc(ixi^s, nw), wrc(ixi^s,nw)
378 double precision, intent(in) :: wlp(ixi^s, nw), wrp(ixi^s,nw)
379 double precision, intent(in) :: x(ixi^s, 1:^nd)
380 double precision, intent(in) :: hspeed(ixi^s,1:number_species)
381 double precision, intent(inout) :: cmax(ixi^s,1:number_species)
382 double precision, intent(inout), optional :: cmin(ixi^s,1:number_species)
383
384 double precision :: wmean(ixi^s,nw)
385
386 ! Since the advection coefficient can depend on unknowns,
387 ! some average over the left and right state should be taken
388 wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
389
390 if (present(cmin)) then
391 cmin(ixo^s,1) = min(a1(idim) * wmean(ixo^s,u_)**(adv_pow-1), zero)
392 cmax(ixo^s,1) = max(a1(idim) * wmean(ixo^s,u_)**(adv_pow-1), zero)
393 if (number_of_species >= 2) then
394 cmin(ixo^s,1) = min(cmin(ixo^s,1), a2(idim) * wmean(ixo^s,v_)**(adv_pow-1))
395 cmax(ixo^s,1) = max(cmax(ixo^s,1), a2(idim) * wmean(ixo^s,v_)**(adv_pow-1))
396 end if
397 if (number_of_species >= 3) then
398 cmin(ixo^s,1) = min(cmin(ixo^s,1), a3(idim) * wmean(ixo^s,w_)**(adv_pow-1))
399 cmax(ixo^s,1) = max(cmax(ixo^s,1), a3(idim) * wmean(ixo^s,w_)**(adv_pow-1))
400 end if
401 else
402 cmax(ixo^s,1) = maxval(abs(a1(idim) * wmean(ixo^s,u_)**(adv_pow-1)))
403 if (number_of_species >=2) then
404 cmax(ixo^s,1) = max(cmax(ixo^s,1), maxval(abs(a2(idim) * wmean(ixo^s,v_)**(adv_pow-1))))
405 end if
406 if (number_of_species >=3) then
407 cmax(ixo^s,1) = max(cmax(ixo^s,1), maxval(abs(a3(idim) * wmean(ixo^s,w_)**(adv_pow-1))))
408 end if
409 end if
410
411 end subroutine ard_get_cbounds
412
413 subroutine ard_get_dt(w, ixI^L, ixO^L, dtnew, dx^D, x)
415 integer, intent(in) :: ixi^l, ixo^l
416 double precision, intent(in) :: dx^d, x(ixi^s, 1:^nd)
417 double precision, intent(in) :: w(ixi^s, 1:nw)
418 double precision, intent(inout) :: dtnew
419 double precision :: maxrate
420 double precision :: maxd
421 double precision :: maxa
422
423 dtnew = bigdouble
424
425 ! dt < dx^2 / (2 * ndim * diffusion_coeff)
426 ! use dtdiffpar < 1 for explicit and > 1 for imex/split
427 maxd = d1
428 if (number_of_species >= 2) then
429 maxd = max(maxd, d2)
430 end if
431 if (number_of_species >= 3) then
432 maxd = max(maxd, d3)
433 end if
434 dtnew = min(dtnew, dtdiffpar * minval([ dx^d ])**2 / (2 * ndim * maxd))
435
436 ! Estimate time step for reactions
437 select case (equation_type)
438 case (eq_gray_scott)
439 maxrate = max(maxval(w(ixo^s, v_))**2 + gs_f, &
440 maxval(w(ixo^s, v_) * w(ixo^s, u_)) - gs_f - gs_k)
441 case (eq_schnakenberg)
442 maxrate = sb_kappa * max(maxval(abs(w(ixo^s, v_) * w(ixo^s, u_) - 1)), &
443 maxval(w(ixo^s, u_))**2)
444 case (eq_brusselator)
445 maxrate = max( maxval(w(ixo^s, u_)*w(ixo^s, v_) - (br_b+1)), &
446 maxval(w(ixo^s, u_)**2) )
447 case (eq_ext_brusselator)
448 maxrate = max( maxval(w(ixo^s, u_)*w(ixo^s, v_) - (br_b+1)) + br_c, &
449 maxval(w(ixo^s, u_)**2) )
450 maxrate = max(maxrate, br_d)
451 case (eq_logistic)
452 maxrate = lg_lambda*maxval(abs(1 - w(ixo^s, u_))) ! abs for safety, normally u < 1
453 case (eq_analyt_hunds)
454 maxrate = maxval(w(ixo^s, u_)*abs(1 - w(ixo^s, u_))) / d1
455 case (eq_belousov_fn)
456 maxrate = max(&
457 maxval(abs(1.0d0 - w(ixo^s, w_) - w(ixo^s, u_))) / bzfn_epsilon, &
458 maxval(bzfn_lambda + w(ixo^s, u_)) / bzfn_delta &
459 )
460 case (eq_lorenz)
461 ! det(J) = sigma(b(r-1) + x*(x*+y*))
462 maxrate = max(lor_sigma, 1.0d0, lor_b)
463 case (eq_no_reac)
464 ! No reaction term, so no influence on timestep
465 maxrate = zero
466 case default
467 maxrate = one
468 call mpistop("Unknown equation type")
469 end select
470
471 dtnew = min(dtnew, dtreacpar / maxrate)
472
473 end subroutine ard_get_dt
474
475 ! Add the flux from the advection term
476 subroutine ard_get_flux(wC, w, x, ixI^L, ixO^L, idim, f)
478 integer, intent(in) :: ixi^l, ixo^l, idim
479 double precision, intent(in) :: wc(ixi^s, 1:nw)
480 double precision, intent(in) :: w(ixi^s, 1:nw)
481 double precision, intent(in) :: x(ixi^s, 1:^nd)
482 double precision, intent(out) :: f(ixi^s, nwflux)
483
484 f(ixo^s, u_) = (a1(idim)/adv_pow) * w(ixo^s,u_)**adv_pow
485 if (number_of_species >=2) then
486 f(ixo^s, v_) = (a2(idim)/adv_pow) * w(ixo^s,v_)**adv_pow
487 end if
488 if (number_of_species >=3) then
489 f(ixo^s, w_) = (a3(idim)/adv_pow) * w(ixo^s,w_)**adv_pow
490 end if
491
492 end subroutine ard_get_flux
493
494 subroutine ard_add_source_geom(qdt, dtfactor, ixI^L, ixO^L, wCT, wprim,w, x)
495
496 ! Add geometrical source terms
497 ! There are no geometrical source terms
498
500
501 integer, intent(in) :: ixi^l, ixo^l
502 double precision, intent(in) :: qdt, dtfactor, x(ixi^s, 1:^nd)
503 double precision, intent(inout) :: wct(ixi^s, 1:nw), wprim(ixi^s,1:nw),w(ixi^s, 1:nw)
504
505 end subroutine ard_add_source_geom
506
507 ! w[iw]= w[iw]+qdt*S[wCT, qtC, x] where S is the source based on wCT within ixO
508 subroutine ard_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
510 integer, intent(in) :: ixi^l, ixo^l
511 double precision, intent(in) :: qdt, dtfactor
512 double precision, intent(in) :: wct(ixi^s, 1:nw),wctprim(ixi^s,1:nw), x(ixi^s, 1:ndim)
513 double precision, intent(inout) :: w(ixi^s, 1:nw)
514 double precision :: lpl_u(ixo^s), lpl_v(ixo^s), lpl_w(ixo^s)
515 logical, intent(in) :: qsourcesplit
516 logical, intent(inout) :: active
517
518 ! here we add the reaction terms (always) and the diffusion if no imex is used
519 if (qsourcesplit .eqv. ard_source_split) then
520 if (.not.use_imex_scheme) then
521 call ard_laplacian(ixi^l, ixo^l, wct(ixi^s, u_), lpl_u)
522 if (number_of_species >= 2) then
523 call ard_laplacian(ixi^l, ixo^l, wct(ixi^s, v_), lpl_v)
524 end if
525 if (number_of_species >= 3) then
526 call ard_laplacian(ixi^l, ixo^l, wct(ixi^s, w_), lpl_w)
527 end if
528 else
529 ! for all IMEX scheme variants: only add the reactions
530 lpl_u = 0.0d0
531 lpl_v = 0.0d0
532 lpl_w = 0.0d0
533 end if
534
535 select case (equation_type)
536 case (eq_gray_scott)
537 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u - &
538 wct(ixo^s, u_) * wct(ixo^s, v_)**2 + &
539 gs_f * (1 - wct(ixo^s, u_)))
540 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v + &
541 wct(ixo^s, u_) * wct(ixo^s, v_)**2 - &
542 (gs_f + gs_k) * wct(ixo^s, v_))
543 case (eq_schnakenberg)
544 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
545 + sb_kappa * (sb_alpha - wct(ixo^s, u_) + &
546 wct(ixo^s, u_)**2 * wct(ixo^s, v_)))
547 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v &
548 + sb_kappa * (sb_beta - wct(ixo^s, u_)**2 * wct(ixo^s, v_)))
549 case (eq_brusselator)
550 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
551 + br_a - (br_b + 1) * wct(ixo^s, u_) &
552 + wct(ixo^s, u_)**2 * wct(ixo^s, v_))
553 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v &
554 + br_b * wct(ixo^s, u_) - wct(ixo^s, u_)**2 * wct(ixo^s, v_))
555 case (eq_ext_brusselator)
556 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
557 + br_a - (br_b + 1) * wct(ixo^s, u_) &
558 + wct(ixo^s, u_)**2 * wct(ixo^s, v_) &
559 - br_c * wct(ixo^s, u_) + br_d * wct(ixo^s, w_))
560 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v &
561 + br_b * wct(ixo^s, u_) &
562 - wct(ixo^s, u_)**2 * wct(ixo^s, v_))
563 w(ixo^s, w_) = w(ixo^s, w_) + qdt * (d3 * lpl_w &
564 + br_c * wct(ixo^s, u_) - br_d * wct(ixo^s, w_))
565 case (eq_logistic)
566 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
567 + lg_lambda * wct(ixo^s, u_) * (1 - wct(ixo^s, u_)))
568 case (eq_analyt_hunds)
569 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
570 + 1.0d0/d1 * wct(ixo^s, u_)**2 * (1 - wct(ixo^s, u_)))
571 case (eq_belousov_fn)
572 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
573 + 1.0d0/bzfn_epsilon * (bzfn_lambda * wct(ixo^s, w_) &
574 - wct(ixo^s, u_)*wct(ixo^s, w_) + wct(ixo^s, u_) &
575 - wct(ixo^s, u_)**2))
576 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v &
577 + wct(ixo^s, u_) - wct(ixo^s, v_))
578 w(ixo^s, w_) = w(ixo^s, w_) + qdt * (d3 * lpl_w &
579 + 1.0d0/bzfn_delta * (-bzfn_lambda * wct(ixo^s, w_) &
580 - wct(ixo^s, u_)*wct(ixo^s, w_) + bzfn_mu * wct(ixo^s, v_)))
581 case (eq_lorenz)
582 ! xdot = sigma.(y-x)
583 w(ixo^s, u_) = w(ixo^s, u_) + qdt * (d1 * lpl_u &
584 + lor_sigma * (wct(ixo^s, v_) - wct(ixo^s, u_)))
585 ! ydot = r.x - y - x.z
586 w(ixo^s, v_) = w(ixo^s, v_) + qdt * (d2 * lpl_v &
587 + lor_r * wct(ixo^s, u_) - wct(ixo^s, v_) &
588 - wct(ixo^s, u_)*wct(ixo^s, w_))
589 ! zdot = x.y - b.z
590 w(ixo^s, w_) = w(ixo^s, w_) + qdt * (d3 * lpl_w &
591 + wct(ixo^s, u_)*wct(ixo^s, v_) - lor_b * wct(ixo^s, w_))
592 case (eq_no_reac)
593 w(ixo^s, u_) = w(ixo^s, u_) + qdt * d1 * lpl_u
594 case default
595 call mpistop("Unknown equation type")
596 end select
597
598 ! enforce getbc call after source addition
599 active = .true.
600 end if
601
602 end subroutine ard_add_source
603
604 !> Compute the Laplacian using a standard second order scheme. For now this
605 !> method only works in slab geometries. Requires one ghost cell only.
606 subroutine ard_laplacian(ixI^L,ixO^L,var,lpl)
608 integer, intent(in) :: ixi^l, ixo^l
609 double precision, intent(in) :: var(ixi^s)
610 double precision, intent(out) :: lpl(ixo^s)
611 integer :: idir, jxo^l, hxo^l
612 double precision :: h_inv2
613
614 if (slab) then
615 lpl(ixo^s) = 0.0d0
616 do idir = 1, ndim
617 hxo^l=ixo^l-kr(idir,^d);
618 jxo^l=ixo^l+kr(idir,^d);
619 h_inv2 = 1/dxlevel(idir)**2
620 lpl(ixo^s) = lpl(ixo^s) + h_inv2 * &
621 (var(jxo^s) - 2 * var(ixo^s) + var(hxo^s))
622 end do
623 else
624 call mpistop("ard_laplacian not implemented in this geometry")
625 end if
626
627 end subroutine ard_laplacian
628
629 subroutine put_laplacians_onegrid(ixI^L,ixO^L,w)
631 integer, intent(in) :: ixi^l, ixo^l
632 double precision, intent(inout) :: w(ixi^s, 1:nw)
633
634 double precision :: lpl_u(ixo^s), lpl_v(ixo^s), lpl_w(ixo^s)
635
636 call ard_laplacian(ixi^l, ixo^l, w(ixi^s, u_), lpl_u)
637 if (number_of_species >= 2) then
638 call ard_laplacian(ixi^l, ixo^l, w(ixi^s, v_), lpl_v)
639 end if
640 if (number_of_species >= 3) then
641 call ard_laplacian(ixi^l, ixo^l, w(ixi^s, w_), lpl_w)
642 end if
643
644 w(ixo^s,u_) = d1*lpl_u
645 if (number_of_species >= 2) then
646 w(ixo^s,v_) = d2*lpl_v
647 end if
648 if (number_of_species >= 3) then
649 w(ixo^s,w_) = d3*lpl_w
650 end if
651
652 end subroutine put_laplacians_onegrid
653
654 !> inplace update of psa==>F_im(psa)
655 subroutine ard_evaluate_implicit(qtC,psa)
657 type(state), target :: psa(max_blocks)
658 double precision, intent(in) :: qtc
659
660 integer :: iigrid, igrid, level
661 integer :: ixo^l
662
663 !ixO^L=ixG^LL^LSUB1;
664 ixo^l=ixm^ll;
665 !$OMP PARALLEL DO PRIVATE(igrid)
666 do iigrid=1,igridstail; igrid=igrids(iigrid);
667 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
668 call put_laplacians_onegrid(ixg^ll,ixo^l,psa(igrid)%w)
669 end do
670 !$OMP END PARALLEL DO
671
672 end subroutine ard_evaluate_implicit
673
674 !> Implicit solve of psa=psb+dtfactor*dt*F_im(psa)
675 subroutine ard_implicit_update(dtfactor,qdt,qtC,psa,psb)
677 use mod_forest
678
679 type(state), target :: psa(max_blocks)
680 type(state), target :: psb(max_blocks)
681 double precision, intent(in) :: qdt
682 double precision, intent(in) :: qtc
683 double precision, intent(in) :: dtfactor
684
685 integer :: n
686 double precision :: res, max_residual, lambda
687
688 integer :: iw_to,iw_from
689 integer :: iigrid, igrid, id
690 integer :: nc, lvl
691 type(tree_node), pointer :: pnode
692 real(dp) :: fac
693
694 ! Avoid setting a very restrictive limit to the residual when the time step
695 ! is small (as the operator is ~ 1/(D * qdt))
696 if (qdt < dtmin) then
697 if(mype==0)then
698 print *,'skipping implicit solve: dt too small!'
699 print *,'Currently at time=',global_time,' time step=',qdt,' dtmin=',dtmin
700 endif
701 return
702 endif
703 max_residual = ard_mg_tol/qdt
704
705 mg%operator_type = mg_helmholtz
706 call mg_set_methods(mg)
707
708 if (.not. mg%is_allocated) call mpistop("multigrid tree not allocated yet")
709
710 ! First handle the u variable ***************************************
711 lambda = 1/(dtfactor * qdt * d1)
712 call helmholtz_set_lambda(lambda)
713 mg%bc(:, mg_iphi) = ard_mg_bc(1, :)
714
715 call mg_copy_to_tree(u_, mg_irhs, factor=-lambda, state_from=psb)
716 call mg_copy_to_tree(u_, mg_iphi, state_from=psb)
717
718 call mg_fas_fmg(mg, .true., max_res=res)
719 do n = 1, 10
720 call mg_fas_vcycle(mg, max_res=res)
721 if (res < max_residual) exit
722 end do
723
724 if (res > max_residual) call mpistop("u_multigrid: no convergence")
725
726 call mg_copy_from_tree_gc(mg_iphi, u_, state_to=psa)
727 ! Done with the u variable ***************************************
728
729 ! Next handle the v variable ***************************************
730 if (number_of_species >= 2) then
731 lambda = 1/(dtfactor * qdt * d2)
732 call helmholtz_set_lambda(lambda)
733 mg%bc(:, mg_iphi) = ard_mg_bc(2, :)
734
735 call mg_copy_to_tree(v_, mg_irhs, factor=-lambda, state_from=psb)
736 call mg_copy_to_tree(v_, mg_iphi, state_from=psb)
737
738 call mg_fas_fmg(mg, .true., max_res=res)
739 do n = 1, 10
740 call mg_fas_vcycle(mg, max_res=res)
741 if (res < max_residual) exit
742 end do
743
744 if (res > max_residual) call mpistop("v_multigrid: no convergence")
745 call mg_copy_from_tree_gc(mg_iphi, v_, state_to=psa)
746 end if
747 ! Done with the v variable ***************************************
748
749 ! Next handle the w variable ***************************************
750 if (number_of_species >= 3) then
751 lambda = 1/(dtfactor * qdt * d3)
752 call helmholtz_set_lambda(lambda)
753 mg%bc(:, mg_iphi) = ard_mg_bc(3, :)
754
755 call mg_copy_to_tree(w_, mg_irhs, factor=-lambda, state_from=psb)
756 call mg_copy_to_tree(w_, mg_iphi, state_from=psb)
757
758 call mg_fas_fmg(mg, .true., max_res=res)
759 do n = 1, 10
760 call mg_fas_vcycle(mg, max_res=res)
761 if (res < max_residual) exit
762 end do
763
764 if (res > max_residual) call mpistop("w_multigrid: no convergence")
765 call mg_copy_from_tree_gc(mg_iphi, w_, state_to=psa)
766 end if
767 ! Done with the w variable ***************************************
768
769 end subroutine ard_implicit_update
770
771end module mod_ard_phys
Module containing the physics routines for advection-reaction-diffusion equations.
double precision, public, protected br_a
Parameters for Brusselator model.
double precision, dimension(^nd), public, protected a3
Advection coefficients for third species (w) (if applicable).
double precision, public, protected lg_lambda
Parameter for logistic model (Fisher / KPP equation).
double precision, public, protected gs_k
Kill rate for Gray-Scott model.
integer, public, protected v_
For 2 or more equations.
double precision, public, protected sb_alpha
Parameters for Schnakenberg model.
double precision, public, protected gs_f
Feed rate for Gray-Scott model.
double precision, public, protected sb_beta
double precision, public, protected br_b
double precision, public, protected br_c
subroutine, public ard_phys_init()
double precision, public, protected sb_kappa
character(len=20), public, protected equation_name
Name of the system to be solved.
integer, public, protected u_
Indices of the unknowns.
double precision, public, protected lor_b
Parameter for Lorenz system (aspect ratio of the convection rolls).
double precision, public, protected dtreacpar
Parameter with which to multiply the reaction timestep restriction.
double precision, public, protected bzfn_mu
double precision, public, protected lor_sigma
Parameter for Lorenz system (Prandtl number).
integer, public, protected adv_pow
Power of the unknown in the advection term (1 for linear).
double precision, public, protected d1
Diffusion coefficient for first species (u).
double precision, public, protected d2
Diffusion coefficient for second species (v) (if applicable).
type(mg_bc_t), dimension(3, mg_num_neighbors), public ard_mg_bc
Boundary condition information for the multigrid method.
double precision, public, protected bzfn_epsilon
Parameters for the Field-Noyes model of the Belousov-Zhabotinsky reaction.
logical, public, protected ard_particles
Whether particles module is added.
double precision, public, protected lor_r
Parameter for Lorenz system (Rayleigh number).
double precision, dimension(^nd), public, protected a2
Advection coefficients for second species (v) (if applicable).
double precision, public, protected d3
Diffusion coefficient for third species (w) (if applicable).
double precision, public, protected bzfn_lambda
integer, public, protected w_
For 3 or more equations.
double precision, public, protected ard_mg_tol
multigrid: max_residual = ard_mg_tol/qdt
double precision, dimension(^nd), public, protected a1
Advection coefficients for first species (u).
double precision, public, protected bzfn_delta
double precision, public, protected br_d
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module with basic grid data structures.
Definition mod_forest.t:2
Module with geometry-related routines (e.g., divergence, curl).
Definition mod_geometry.t:2
integer coordinate
Definition mod_geometry.t:7
This module contains definitions of global parameters and variables and some generic functions/subrou...
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
integer, parameter unitpar
file handle for IO
double precision global_time
The global simulation time.
logical use_imex_scheme
whether IMEX in use or not
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
integer nwauxio
Number of auxiliary variables that are only included in output.
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
integer nghostcells
Number of ghost cells surrounding a grid.
logical fix_conserve_global
Whether to apply flux conservation at refinement boundaries.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
logical use_multigrid
Use multigrid (only available in 2D and 3D).
double precision dtmin
Stop the simulation when the time step becomes smaller than this value.
integer max_blocks
The maximum number of grid blocks in a processor.
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
Module containing all the particle routines.
subroutine particles_init()
Initialize particle data and parameters.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_convert), pointer phys_to_primitive
Definition mod_physics.t:52
procedure(sub_write_info), pointer phys_write_info
Definition mod_physics.t:83
procedure(sub_get_flux), pointer phys_get_flux
Definition mod_physics.t:65
procedure(sub_evaluate_implicit), pointer phys_evaluate_implicit
Definition mod_physics.t:89
procedure(sub_get_cbounds), pointer phys_get_cbounds
Definition mod_physics.t:64
procedure(sub_get_dt), pointer phys_get_dt
Definition mod_physics.t:71
procedure(sub_add_source_geom), pointer phys_add_source_geom
Definition mod_physics.t:72
procedure(sub_check_params), pointer phys_check_params
Definition mod_physics.t:49
integer, parameter flux_default
Indicates a normal flux.
Definition mod_physics.t:24
integer, dimension(:, :), allocatable flux_type
Array per direction per variable, which can be used to specify that certain fluxes have to be treated...
Definition mod_physics.t:21
procedure(sub_convert), pointer phys_to_conserved
Definition mod_physics.t:51
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition mod_physics.t:47
procedure(sub_implicit_update), pointer phys_implicit_update
Definition mod_physics.t:88
procedure(sub_add_source), pointer phys_add_source
Definition mod_physics.t:73
procedure(sub_get_cmax), pointer phys_get_cmax
Definition mod_physics.t:60
logical phys_energy
Solve energy equation or not.
Definition mod_physics.t:37
Module with all the methods that users can customize in AMRVAC.
procedure(special_mg_bc), pointer usr_special_mg_bc
integer nw
Total number of variables.
integer number_species
number of species: each species has different characterictic speeds and should be used accordingly in...
integer nwflux
Number of flux variables.
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:14