MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_magnetofriction.t
Go to the documentation of this file.
1!> module mod_magnetofriction.t
2!> Purpose: use magnetofrictional method to relax 3D magnetic field to
3!> force-free field
4!> 01.04.2016 developed by Chun Xia and Yang Guo
5!> 04.10.2017 modulized by Chun Xia
6!> Usage:
7!> in amrvac.par:
8!> &methodlist
9!> time_stepper='onestep' ! time marching scheme, or 'twostep','threestep'
10!> flux_method=13*'cd4' ! or 'tvdlf', 'fd'
11!> limiter= 13*'koren' ! or 'vanleer','cada3','mp5' so on
12!> /
13!> &meshlist
14!> ditregrid=20 ! set iteration interval for adjusting AMR
15!> /
16!> &mhd_list
17!> mhd_magnetofriction=.true.
18!> /
19!> &mf_list
20!> mf_it_max=60000 ! set the maximum iteration number
21!> mf_ditsave=20000 ! set iteration interval for data output
22!> mf_cc=0.3 ! stability coefficient controls numerical stability
23!> mf_cy=0.2 ! frictional velocity coefficient
24!> mf_cdivb=0.01 ! divb cleaning coefficient controls diffusion speed of divb
25!> /
27 implicit none
28
29 !> stability coefficient controls numerical stability
30 double precision :: mf_cc
31 !> frictional velocity coefficient
32 double precision :: mf_cy, mf_cy_max
33 !> divb cleaning coefficient controls diffusion speed of divb
34 double precision :: mf_cdivb, mf_cdivb_max
35 !> TVDLF dissipation coefficient controls the dissipation term
36 double precision :: mf_tvdlfeps, mf_tvdlfeps_min
37 !> time in magnetofriction process
38 double precision :: tmf
39 !> maximal speed for fd scheme
40 double precision :: cmax_mype
41 !> maximal speed for fd scheme
42 double precision :: cmax_global
43 !> maximal limit of magnetofrictional velocity in cm s^-1 (Pomoell 2019 A&A)
44 double precision, public :: mf_vmax = 3.d6
45
46 !> Index of the density (in the w array)
47 integer, private, protected :: rho_
48
49 !> Indices of the momentum density
50 integer, allocatable, private, protected :: mom(:)
51
52 !> Indices of the magnetic field
53 integer, allocatable, private, protected :: mag(:)
54
55 integer :: mf_ditsave
56 integer :: mf_it_max
57 integer :: mf_it
58 !> How to open the MF diagnostics CSV: auto, append, or replace.
59 character(len=16) :: mf_log_mode
60 !> Optional diagnostics filename; empty uses <base_filename>_mflog.csv.
61 character(len=256) :: mf_log_filename
62 logical :: mf_advance
63 logical :: fix_conserve_at_step = .true.
64
65 !> Whether this run continues an existing MF diagnostics series.
66 logical :: mf_continue_run = .false.
67
68contains
69 !> Read this module"s parameters from a file
70 subroutine mf_params_read(files)
72 character(len=*), intent(in) :: files(:)
73 integer :: n
74
75 namelist /mf_list/ mf_ditsave, mf_it_max, mf_it, mf_cc, mf_cy, mf_cy_max, &
78
79 do n = 1, size(files)
80 open(unitpar, file=trim(files(n)), status="old")
81 read(unitpar, mf_list, end=111)
82111 close(unitpar)
83 end do
84
85 end subroutine mf_params_read
86
87 !> Initialize the module
91
92 rho_=iw_rho
93 allocate(mom(ndir))
94 mom=iw_mom
95 allocate(mag(ndir))
96 mag=iw_mag
97
98 mf_it=0 ! set the initial iteration number
99 mf_it_max=60000 ! set the maximum iteration number
100 mf_ditsave=20000 ! set iteration interval for data output
101 mf_cc=0.3d0 ! stability coefficient controls numerical stability
102 mf_cy=0.2d0 ! frictional velocity coefficient. The default value is mf_cy itself.
103 mf_cy_max=mf_cy ! maximum of the frictional velocity coefficient
104 mf_cdivb=0.01d0 ! divb cleaning coefficient controls diffusion speed of divb
105 mf_cdivb_max=mf_cdivb ! maximum of the divb cleaning coefficient
106 mf_tvdlfeps=1.d0 ! coefficient to control the TVDLF dissipation
107 mf_tvdlfeps_min = mf_tvdlfeps ! minimum of the TVDLF dissipation coefficient
108 mf_log_mode='auto'
110 ! get dimensionless maximal mf velocity limit
112
114
118
120
121 end subroutine magnetofriction_init
122
125 use mod_physics
128 use mod_amr_grid, only: resettree
129 use mod_comm_lib, only: mpistop
130
131 double precision :: dvolume(ixG^T),dsurface(ixG^T),dvone
132 double precision :: dtfff,dtfff_pe,dtnew,dx^D
133 double precision :: cwsin_theta_new,cwsin_theta_old
134 double precision :: sum_jbb,sum_jbb_ipe,sum_j,sum_j_ipe,sum_l_ipe,sum_l
135 double precision :: f_i_ipe,f_i,volumepe,volume,tmpt,time_in
136 double precision, external :: integral_grid
137 integer :: i,iigrid, igrid, idims,ix^D,hxM^LL,fhmf,tmpit,i^D
138 logical :: patchwi(ixG^T), stagger_flag
139
140 ! not do fix conserve and getbc for staggered values if stagger is used
141 stagger_flag=stagger_grid
142 stagger_grid=.false.
143
144 time_in=mpi_wtime()
145 if(mype==0) write(*,*) 'Evolving to force-free field using magnetofricitonal method...'
146 if(prolongprimitive) call mpistop('use prolongprimitive=.false. in MF module')
147 mf_advance=.false.
148 dtfff=1.d-2
149 tmpt=global_time
150 tmpit=it
152 i=mf_it
153 ! MF checkpoints store the MF iteration in the standard snapshot header.
154 ! Recover it automatically unless the user explicitly supplied mf_it.
155 if(i==0 .and. it>0) i=it
156 select case(trim(mf_log_mode))
157 case('auto')
158 ! Potential-field snapshots normally have it=0, whereas MF checkpoints
159 ! store their positive MF iteration in the standard snapshot header.
160 mf_continue_run=(i>0)
161 case('append')
162 mf_continue_run=.true.
163 case('replace')
164 mf_continue_run=.false.
165 case default
166 call mpistop("mf_log_mode must be 'auto', 'append', or 'replace'")
167 end select
168 if(snapshotini==0 .and. i==0) then
169 call saveamrfile(1)
170 call saveamrfile(2)
171 end if
172 mf_advance=.true.
173 ! point bc mpi datatype to partial type for magnetic field
180 ! create bc mpi datatype for ghostcells update
181 call create_bc_mpi_datatype(mag(1),ndir)
182 ! point bc mpi datatype to partial type for velocity field
189 ! create bc mpi datatype for ghostcells update
190 call create_bc_mpi_datatype(mom(1),ndir)
191 ! convert conservative variables to primitive ones which are used during MF
192 do iigrid=1,igridstail; igrid=igrids(iigrid);
193 call phys_to_primitive(ixg^ll,ixm^ll,ps(igrid)%w,ps(igrid)%x)
194 end do
195 ! calculate magnetofrictional velocity
196 call mf_velocity_update(dtfff)
197 ! update velocity in ghost cells
198 call getbc(tmf,0.d0,ps,mom(1),ndir)
199 ! calculate initial values of metrics
200 if(i==0) then
201 call metrics
202 call printlog_mf
203 end if
204 ! magnetofrictional loops
205 do
206 ! calculate time step based on Cmax= Alfven speed + abs(frictional speed)
207 dtfff_pe=bigdouble
208 cmax_mype=zero
209 do iigrid=1,igridstail; igrid=igrids(iigrid);
210 block=>ps(igrid)
211 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
212 call getdtfff_courant(ps(igrid)%w,ps(igrid)%x,ixg^ll,ixm^ll,dtnew)
213 dtfff_pe=min(dtfff_pe,dtnew)
214 end do
215 call mpi_allreduce(dtfff_pe,dtfff,1,mpi_double_precision,mpi_min, &
217 call mpi_allreduce(cmax_mype,cmax_global,1,mpi_double_precision,&
218 mpi_max,icomm,ierrmpi)
219
220 ! =======
221 ! evolve
222 ! =======
223 call advectmf(1,ndim,tmf,dtfff)
224
225 if(i>=10000) then
226 mf_tvdlfeps = 0.9998d0 * mf_tvdlfeps
228 end if
229 if(i<=60000) then
230 mf_cy=1.0001d0*mf_cy
231 mf_cy = min(mf_cy_max,mf_cy)
232 end if
233 if(i>=100000) then
234 mf_cdivb=1.0000018d0*mf_cdivb
236 end if
237
238 i=i+1
239 tmf=tmf+dtfff
240 if(mod(i,10)==0) then
241 ! calculate metrics
242 call metrics
243 call printlog_mf
244 end if
245 if(mod(i,mf_ditsave)==0) then
246 it=i
248 do iigrid=1,igridstail; igrid=igrids(iigrid);
249 call phys_to_conserved(ixg^ll,ixg^ll,ps(igrid)%w,ps(igrid)%x)
250 end do
251 mf_advance=.false.
252 call saveamrfile(1)
253 call saveamrfile(2)
254 do iigrid=1,igridstail; igrid=igrids(iigrid);
255 call phys_to_primitive(ixg^ll,ixg^ll,ps(igrid)%w,ps(igrid)%x)
256 end do
257 mf_advance=.true.
258 if(mype==0) then
259 write(*,*) "itmf=",i
260 write(*,*) '<CW sin theta>:',cwsin_theta_new
261 write(*,*) '<f_i>:',f_i
262 write(*,*) '----------------------------------------------------------'
263 end if
264 end if
265 ! reconstruct AMR grid every 10 step
266 if(mod(i,ditregrid)==0 .and. refine_max_level>1) call resettree
267 if (i>=mf_it_max) then
268 if(mod(i,10)/=0) then
269 ! calculate metrics
270 call metrics
271 call printlog_mf
272 end if
273 if(mype==0) then
274 write (*,*) 'Reach maximum iteration step!'
275 write (*,*) 'The total iteration step is:', i
276 end if
277 exit
278 end if
279 enddo
280 ! point bc mpi data type back to full type for MHD
287 bcphys=.true.
288 ! set velocity back to zero and convert primitive variables back to conservative ones
289 do iigrid=1,igridstail; igrid=igrids(iigrid);
290 ps(igrid)%w(ixg^t,mom(:))=zero
291 call phys_to_conserved(ixg^ll,ixm^ll,ps(igrid)%w,ps(igrid)%x)
292 end do
293 global_time=tmpt
294 it=tmpit
295 if (mype==0) call mpi_file_close(fhmf,ierrmpi)
296 mf_advance=.false.
297 ! restore stagger_grid value
298 stagger_grid=stagger_flag
299 if(mype==0) write(*,*) 'Magnetofriction phase took : ',mpi_wtime()-time_in,' sec'
300 contains
301
302 subroutine metrics
303
304 sum_jbb_ipe = 0.d0
305 sum_j_ipe = 0.d0
306 sum_l_ipe = 0.d0
307 f_i_ipe = 0.d0
308 volumepe=0.d0
309 dsurface=zero
310 do iigrid=1,igridstail; igrid=igrids(iigrid);
311 block=>ps(igrid)
312 dvolume(ixm^t)=block%dvolume(ixm^t)
313 do idims=1,ndim
314 hxm^ll=ixm^ll-kr(idims,^d);
315 dsurface(ixm^t)=dsurface(ixm^t)+block%surfaceC(hxm^t,idims)
316 end do
317 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
318 call mask_inner(ixg^ll,ixm^ll,ps(igrid)%w,ps(igrid)%x)
319 sum_jbb_ipe = sum_jbb_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
320 ps(igrid)%x,1,patchwi)
321 sum_j_ipe = sum_j_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
322 ps(igrid)%x,2,patchwi)
323 f_i_ipe=f_i_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
324 ps(igrid)%x,3,patchwi)
325 sum_l_ipe = sum_l_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
326 ps(igrid)%x,4,patchwi)
327 end do
328 call mpi_allreduce(sum_jbb_ipe,sum_jbb,1,mpi_double_precision,&
329 mpi_sum,icomm,ierrmpi)
330 call mpi_allreduce(sum_j_ipe,sum_j,1,mpi_double_precision,mpi_sum,&
332 call mpi_allreduce(f_i_ipe,f_i,1,mpi_double_precision,mpi_sum,&
334 call mpi_allreduce(sum_l_ipe,sum_l,1,mpi_double_precision,mpi_sum,&
336 call mpi_allreduce(volumepe,volume,1,mpi_double_precision,mpi_sum,&
338 ! current- and volume-weighted average of the sine of the angle
339 ! between the magnetic field B and the current density J
340 cwsin_theta_new = sum_jbb/sum_j
341 ! volume-weighted average of the absolute value of the fractional
342 ! magnetic flux change
343 f_i = f_i/volume
344 sum_j=sum_j/volume
345 sum_l=sum_l/volume
346 end subroutine metrics
347
348 subroutine mask_inner(ixI^L,ixO^L,w,x)
349
350 integer, intent(in) :: ixI^L,ixO^L
351 double precision, intent(in):: w(ixI^S,nw),x(ixI^S,1:ndim)
352 double precision :: xO^L
353 integer :: ix^D
354
355 {xomin^d = xprobmin^d + 0.05d0*(xprobmax^d-xprobmin^d)\}
356 {xomax^d = xprobmax^d - 0.05d0*(xprobmax^d-xprobmin^d)\}
357 if(slab) then
358 xomin^nd = xprobmin^nd
359 else
360 xomin1 = xprobmin1
361 end if
362
363 {do ix^db=ixomin^db,ixomax^db\}
364 if({ x(ix^dd,^d) > xomin^d .and. x(ix^dd,^d) < xomax^d | .and. }) then
365 patchwi(ix^d)=.true.
366 volumepe=volumepe+dvolume(ix^d)
367 else
368 patchwi(ix^d)=.false.
369 endif
370 {end do\}
371
372 end subroutine mask_inner
373
374 subroutine printlog_mf
375 integer :: amode, status(MPI_STATUS_SIZE)
376 integer :: truncate_unit, ios
377 character(len=800) :: filename,filehead
378 character(len=2048) :: line,datastr
379 logical, save :: logmfopened=.false.
380 logical :: logfile_exists
381
382 if(mype==0) then
383 if(.not.logmfopened) then
384 ! generate filename
385 if(len_trim(mf_log_filename)>0) then
386 filename=trim(mf_log_filename)
387 else
388 write(filename,"(a,a)") trim(base_filename), "_mflog.csv"
389 end if
390
391 inquire(file=trim(filename),exist=logfile_exists)
392 if(.not.mf_continue_run) then
393 ! A potential-field (or otherwise unrelated) restart begins a
394 ! new MF relaxation, so discard diagnostics from an older run.
395 open(newunit=truncate_unit,file=trim(filename),status='replace', &
396 action='write',iostat=ios)
397 if(ios/=0) call mpistop('Unable to replace magnetofriction log file')
398 close(truncate_unit)
399 logfile_exists=.false.
400 end if
401
402 amode=ior(mpi_mode_create,mpi_mode_wronly)
403 amode=ior(amode,mpi_mode_append)
404 call mpi_file_open(mpi_comm_self,filename,amode,mpi_info_null,fhmf,ierrmpi)
405 logmfopened=.true.
406 ! Preserve a single header when continuing an existing MF run.
407 if(.not.logfile_exists) then
408 filehead=" itmf, dt, <f_i>, <CW sin theta>, <Current>, <Lorenz force>"
409 call mpi_file_write(fhmf,filehead,len_trim(filehead), &
410 mpi_character,status,ierrmpi)
411 call mpi_file_write(fhmf,achar(10),1,mpi_character,status,ierrmpi)
412 end if
413 end if
414 line=''
415 write(datastr,'(i6,a)') i,','
416 line=trim(line)//trim(datastr)
417 write(datastr,'(es13.6,a)') dtfff,','
418 line=trim(line)//trim(datastr)
419 write(datastr,'(es13.6,a)') f_i,','
420 line=trim(line)//trim(datastr)
421 write(datastr,'(es13.6,a)') cwsin_theta_new,','
422 line=trim(line)//trim(datastr)
423 write(datastr,'(es13.6,a)') sum_j,','
424 line=trim(line)//trim(datastr)
425 write(datastr,'(es13.6)') sum_l
426 line=trim(line)//trim(datastr)//new_line('A')
427 call mpi_file_write(fhmf,line,len_trim(line),mpi_character,status,ierrmpi)
428 end if
429
430 end subroutine printlog_mf
431
432 function integral_grid_mf(ixI^L,ixO^L,w,x,iw,patchwi)
433 use mod_geometry
434
435 integer, intent(in) :: ixI^L,ixO^L,iw
436 double precision, intent(in) :: x(ixI^S,1:ndim)
437 double precision, intent(in) :: w(ixI^S,nw+nwauxio)
438 logical, intent(in) :: patchwi(ixI^S)
439
440 double precision, dimension(ixI^S,1:ndir) :: bvec,qvec,current
441 double precision :: integral_grid_mf,tmp(ixI^S),b_mag(ixI^S)
442 integer :: ix^D,i,idirmin,idir,jdir,kdir
443
444 integral_grid_mf=0.d0
445 select case(iw)
446 case(1)
447 ! Sum(dvolume*|JxB|/|B|)
448 if(b0field) then
449 bvec(ixi^s,:)=w(ixi^s,mag(:))+block%b0(ixi^s,mag(:),0)
450 else
451 bvec(ixi^s,:)=w(ixi^s,mag(:))
452 endif
453 call get_current(w,ixi^l,ixo^l,idirmin,current)
454 ! calculate Lorentz force
455 qvec(ixo^s,1:ndir)=zero
456 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
457 if(lvc(idir,jdir,kdir)/=0)then
458 tmp(ixo^s)=current(ixo^s,jdir)*bvec(ixo^s,kdir)
459 if(lvc(idir,jdir,kdir)==1)then
460 qvec(ixo^s,idir)=qvec(ixo^s,idir)+tmp(ixo^s)
461 else
462 qvec(ixo^s,idir)=qvec(ixo^s,idir)-tmp(ixo^s)
463 endif
464 endif
465 enddo; enddo; enddo
466
467 {do ix^db=ixomin^db,ixomax^db\}
468 if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+sqrt(sum(qvec(ix^d,:)**2)/&
469 sum(bvec(ix^d,:)**2))*dvolume(ix^d)
470 {end do\}
471 case(2)
472 ! Sum(dvolume*|J|)
473 call get_current(w,ixi^l,ixo^l,idirmin,current)
474 {do ix^db=ixomin^db,ixomax^db\}
475 if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+sqrt(sum(current(ix^d,:)**2))*&
476 dvolume(ix^d)
477 {end do\}
478 case(3)
479 ! f_i solenoidal property of B: (dvolume |div B|)/(dsurface |B|)
480 ! Sum(dvolume*f_i)
481 if(b0field) then
482 bvec(ixi^s,:)=w(ixi^s,mag(:))+block%b0(ixi^s,mag(:),0)
483 else
484 bvec(ixi^s,:)=w(ixi^s,mag(:))
485 endif
486 call divvector(bvec,ixi^l,ixo^l,tmp)
487 {do ix^db=ixomin^db,ixomax^db\}
488 if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+abs(tmp(ix^d))*&
489 dvolume(ix^d)**2/sqrt(sum(bvec(ix^d,:)**2))/dsurface(ix^d)
490 {end do\}
491 case(4)
492 ! Sum(|JxB|)
493 if(b0field) then
494 bvec(ixi^s,:)=w(ixi^s,mag(:))+block%b0(ixi^s,mag(:),0)
495 else
496 bvec(ixi^s,:)=w(ixi^s,mag(:))
497 endif
498 call curlvector(bvec,ixi^l,ixo^l,current,idirmin,1,ndir)
499 ! calculate Lorentz force
500 qvec(ixo^s,1:ndir)=zero
501 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
502 if(lvc(idir,jdir,kdir)/=0)then
503 tmp(ixo^s)=current(ixo^s,jdir)*bvec(ixo^s,kdir)
504 if(lvc(idir,jdir,kdir)==1)then
505 qvec(ixo^s,idir)=qvec(ixo^s,idir)+tmp(ixo^s)
506 else
507 qvec(ixo^s,idir)=qvec(ixo^s,idir)-tmp(ixo^s)
508 endif
509 endif
510 enddo; enddo; enddo
511
512 {do ix^db=ixomin^db,ixomax^db\}
513 if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+sqrt(sum(qvec(ix^d,:)**2))*dvolume(ix^d)
514 {end do\}
515 end select
516 return
517 end function integral_grid_mf
518
519 end subroutine magnetofriction
520
521 subroutine mf_velocity_update(dtfff)
523
524 double precision, intent(in) :: dtfff
525 double precision :: vhatmax,vhatmax_pe,vhatmaxgrid
526 integer :: i,iigrid, igrid
527
528 vhatmax_pe=smalldouble
529 do iigrid=1,igridstail; igrid=igrids(iigrid);
530 block=>ps(igrid)
531 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
532 call vhat(ps(igrid)%w,ps(igrid)%x,ixg^ll,ixm^ll,vhatmaxgrid)
533 vhatmax_pe=max(vhatmax_pe,vhatmaxgrid)
534 end do
535 call mpi_allreduce(vhatmax_pe,vhatmax,1,mpi_double_precision,mpi_max, &
537 do iigrid=1,igridstail; igrid=igrids(iigrid);
538 block=>ps(igrid)
539 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
540 ! calculate frictional velocity
541 call frictional_velocity(ps(igrid)%w,ps(igrid)%x,ixg^ll,ixm^ll,vhatmax,dtfff)
542 end do
543
544 end subroutine mf_velocity_update
545
546 subroutine vhat(w,x,ixI^L,ixO^L,vhatmaxgrid)
547 ! Calculate v_hat
549
550 integer, intent(in) :: ixI^L, ixO^L
551 double precision, intent(inout) :: w(ixI^S,nw)
552 double precision, intent(in) :: x(ixI^S,1:ndim)
553 double precision, intent(out) :: vhatmaxgrid
554
555 double precision :: current(ixI^S,7-2*ndir:3),tmp(ixI^S),dxhm
556 double precision :: dxhms(ixO^S)
557 integer :: idirmin,idir,jdir,kdir
558
559 call get_current(w,ixi^l,ixo^l,idirmin,current)
560 w(ixi^s,mom(:))=0.d0
561 ! calculate Lorentz force
562 do idir=1,ndir; do jdir=1,ndir; do kdir=idirmin,3
563 if(lvc(idir,jdir,kdir)/=0)then
564 if(b0field) then
565 tmp(ixo^s)=current(ixo^s,jdir)*(w(ixo^s,mag(kdir))+block%b0(ixo^s,kdir,0))
566 else
567 tmp(ixo^s)=current(ixo^s,jdir)*w(ixo^s,mag(kdir))
568 endif
569 if(lvc(idir,jdir,kdir)==1)then
570 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))+tmp(ixo^s)
571 else
572 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-tmp(ixo^s)
573 endif
574 endif
575 enddo; enddo; enddo
576
577 ! 1/B**2
578 if(b0field) then
579 tmp(ixo^s)=1.d0/(sum((w(ixo^s,mag(:))+block%b0(ixo^s,:,0))**2,dim=ndim+1)+smalldouble)
580 else
581 tmp(ixo^s)=1.d0/(sum(w(ixo^s,mag(:))**2,dim=ndim+1)+smalldouble)
582 endif
583
584 if(slab_uniform) then
585 dxhm=dble(ndim)/(^d&1.0d0/dxlevel(^d)+)
586 do idir=1,ndir
587 w(ixo^s,mom(idir))=dxhm*w(ixo^s,mom(idir))*tmp(ixo^s)
588 end do
589 else
590 dxhms(ixo^s)=dble(ndim)/sum(1.d0/block%dx(ixo^s,:),dim=ndim+1)
591 do idir=1,ndir
592 w(ixo^s,mom(idir))=dxhms(ixo^s)*w(ixo^s,mom(idir))*tmp(ixo^s)
593 end do
594 end if
595 vhatmaxgrid=maxval(sqrt(sum(w(ixo^s,mom(:))**2,dim=ndim+1)))
596
597 end subroutine vhat
598
599 subroutine frictional_velocity(w,x,ixI^L,ixO^L,qvmax,qdt)
601
602 integer, intent(in) :: ixI^L, ixO^L
603 double precision, intent(in) :: x(ixI^S,1:ndim),qdt,qvmax
604 double precision, intent(inout) :: w(ixI^S,1:nw)
605
606 double precision :: dxhm,disbd(6),bfzone^D
607 double precision :: dxhms(ixO^S)
608 integer :: ix^D, idir
609 logical :: buffer
610
611 if(slab_uniform) then
612 dxhm=dble(ndim)/(^d&1.0d0/dxlevel(^d)+)
613 dxhm=mf_cc*mf_cy/qvmax*dxhm/qdt
614 ! dxhm=mf_cc*mf_cy/qvmax
615 w(ixo^s,mom(:))=w(ixo^s,mom(:))*dxhm
616 else
617 dxhms(ixo^s)=dble(ndim)/sum(1.d0/block%dx(ixo^s,:),dim=ndim+1)
618 dxhms(ixo^s)=mf_cc*mf_cy/qvmax*dxhms(ixo^s)/qdt
619 ! dxhm=mf_cc*mf_cy/qvmax
620 do idir=1,ndir
621 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))*dxhms(ixo^s)
622 end do
623 end if
624
625{^ifthreed
626 bfzone1=0.05d0*(xprobmax1-xprobmin1)
627 bfzone2=0.05d0*(xprobmax2-xprobmin2)
628 bfzone3=0.05d0*(xprobmax3-xprobmin3)
629 {do ix^db=ixomin^db,ixomax^db\}
630 disbd(1)=x(ix^d,1)-xprobmin1
631 disbd(2)=xprobmax1-x(ix^d,1)
632 disbd(3)=x(ix^d,2)-xprobmin2
633 disbd(4)=xprobmax2-x(ix^d,2)
634 disbd(5)=x(ix^d,3)-xprobmin1
635 disbd(6)=xprobmax3-x(ix^d,3)
636
637 if(slab) then
638 if(disbd(1)<bfzone1) then
639 w(ix^d,mom(:))=(1.d0-((bfzone1-disbd(1))/bfzone1)**2)*w(ix^d,mom(:))
640 endif
641 else
642 if(disbd(5)<bfzone3) then
643 w(ix^d,mom(:))=(1.d0-((bfzone3-disbd(5))/bfzone3)**2)*w(ix^d,mom(:))
644 endif
645 end if
646 if(disbd(2)<bfzone1) then
647 w(ix^d,mom(:))=(1.d0-((bfzone1-disbd(2))/bfzone1)**2)*w(ix^d,mom(:))
648 endif
649 if(disbd(3)<bfzone2) then
650 w(ix^d,mom(:))=(1.d0-((bfzone2-disbd(3))/bfzone2)**2)*w(ix^d,mom(:))
651 endif
652 if(disbd(4)<bfzone2) then
653 w(ix^d,mom(:))=(1.d0-((bfzone2-disbd(4))/bfzone2)**2)*w(ix^d,mom(:))
654 endif
655 if(disbd(6)<bfzone3) then
656 w(ix^d,mom(:))=(1.d0-((bfzone3-disbd(6))/bfzone3)**2)*w(ix^d,mom(:))
657 endif
658 {end do\}
659}
660
661 ! saturate mf velocity at mf_vmax
662 dxhms(ixo^s)=sqrt(sum(w(ixo^s,mom(:))**2,dim=ndim+1))/mf_vmax+1.d-12
663 dxhms(ixo^s)=dtanh(dxhms(ixo^s))/dxhms(ixo^s)
664 do idir=1,ndir
665 w(ixo^s,mom(idir))=w(ixo^s,mom(idir))*dxhms(ixo^s)
666 end do
667 end subroutine frictional_velocity
668
669 subroutine advectmf(idim^LIM,qt,qdt)
670 ! integrate all grids by one step of its delta(global_time)
671 ! This subroutine is in VAC terminology equivalent to
672 ! `advect' (with the difference that it will `advect' all grids)
675 use mod_comm_lib, only: mpistop
676
677 integer, intent(in) :: idim^LIM
678 double precision, intent(in) :: qt, qdt
679
680 integer :: iigrid, igrid
681
682 call init_comm_fix_conserve(idim^lim,ndir)
684
685 do iigrid=1,igridstail; igrid=igrids(iigrid);
686 ps1(igrid)%w=ps(igrid)%w
687 end do
688
689 istep=0
690
691 select case (t_stepper)
692 case (onestep)
693 call advect1mf(flux_method,qdt,one,idim^lim,qt,ps1,qt,ps)
694 case (twostep)
695 ! predictor step
696 fix_conserve_at_step = .false.
697 call advect1mf(typepred1,qdt,half,idim^lim,qt,ps,qt,ps1)
698 ! corrector step
700 call advect1mf(flux_method,qdt,one,idim^lim,qt+half*qdt,ps1,qt,ps)
701 case (threestep)
702 ! three step Runge-Kutta in accordance with Gottlieb & Shu 1998
703 call advect1mf(flux_method,qdt,one,idim^lim,qt,ps,qt,ps1)
704
705 do iigrid=1,igridstail; igrid=igrids(iigrid);
706 ps2(igrid)%w(ixg^t,1:nwflux)=0.75d0*ps(igrid)%w(ixg^t,1:nwflux)+0.25d0*&
707 ps1(igrid)%w(ixg^t,1:nwflux)
708 if (nw>nwflux) ps2(igrid)%w(ixg^t,nwflux+1:nw) = &
709 ps(igrid)%w(ixg^t,nwflux+1:nw)
710 end do
711
712 call advect1mf(flux_method,qdt,0.25d0,idim^lim,qt+qdt,ps1,qt+dt*0.25d0,ps2)
713
714 do iigrid=1,igridstail_active; igrid=igrids_active(iigrid);
715 ps(igrid)%w(ixg^t,1:nwflux)=1.0d0/3.0d0*ps(igrid)%w(ixg^t,1:nwflux)+&
716 2.0d0/3.0d0*ps2(igrid)%w(ixg^t,1:nwflux)
717 end do
718
719 call advect1mf(flux_method,qdt,2.0d0/3.0d0,idim^lim,qt+qdt/2.0d0,ps2,qt+qdt/3.0d0,ps)
720 case default
721 call mpistop("unkown time_stepper in advectmf")
722 end select
723
724 end subroutine advectmf
725
726 subroutine advect1mf(method,dtin,dtfactor,idim^LIM,qtC,psa,qt,psb)
727 ! Integrate all grids by one partial step
728 ! This subroutine is equivalent to VAC's `advect1', but does
729 ! the advection for all grids
733
734 integer, intent(in) :: idim^LIM
735 type(state) :: psa(max_blocks)! Compute fluxes based on this state
736 type(state) :: psb(max_blocks) ! update on this state
737 double precision, intent(in) :: dtin,dtfactor, qtC, qt
738 integer, intent(in) :: method(nlevelshi)
739
740 double precision :: qdt
741 integer :: iigrid, igrid, level, i^D
742 logical :: setigrid
743
744 istep=istep+1
745
746 ! loop over all grids to arrive at equivalent
747 qdt=dtfactor*dtin
748 do iigrid=1,igridstail; igrid=igrids(iigrid);
749 block=>ps(igrid)
750 level=node(plevel_,igrid)
751
752 call process1_gridmf(method(level),igrid,qdt,ixg^ll,idim^lim,qtc,&
753 psa(igrid)%w,qt,psb(igrid)%w)
754 end do
755
756 ! opedit: Send flux for all grids, expects sends for all
757 ! nsend_fc(^D), set in connectivity.t.
758
759 if (fix_conserve_at_step) then
760 call recvflux(idim^lim)
761 call sendflux(idim^lim)
762 call fix_conserve(psb,idim^lim,mag(1),ndir)
763 end if
764 ! point bc mpi datatype to partial type for magnetic field
771 ! update B in ghost cells
772 call getbc(qt+qdt,qdt,psb,mag(1),ndir)
773 ! calculate magnetofrictional velocity
774 call mf_velocity_update(qdt)
775 ! point bc mpi datatype to partial type for velocity field
782 ! update magnetofrictional velocity in ghost cells
783 call getbc(qt+qdt,qdt,psb,mom(1),ndir)
784
785 end subroutine advect1mf
786
787 subroutine process1_gridmf(method,igrid,qdt,ixG^L,idim^LIM,qtC,wCT,qt,w)
788 ! This subroutine is equivalent to VAC's `advect1' for one grid
791 use mod_comm_lib, only: mpistop
792
793 integer, intent(in) :: method
794 integer, intent(in) :: igrid, ixG^L, idim^LIM
795 double precision, intent(in) :: qdt, qtC, qt
796 double precision :: wCT(ixG^S,1:nw), w(ixG^S,1:nw)
797 double precision :: dx^D, fC(ixG^S,1:ndir,1:ndim)
798 integer :: ixO^L
799
800 dx^d=rnode(rpdx^d_,igrid);
801 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
802 fc=0.d0
803
804 ixo^l=ixg^l^lsubnghostcells;
805 select case (method)
806 case (fs_cd4)
807 !================================
808 ! 4th order central difference
809 !================================
810 call centdiff4mf(qdt,ixg^l,ixo^l,idim^lim,qtc,wct,qt,w,fc,dx^d,ps(igrid)%x)
811 case (fs_tvdlf)
812 !================================
813 ! TVDLF
814 !================================
815 call tvdlfmf(qdt,ixg^l,ixo^l,idim^lim,qtc,wct,qt,w,fc,dx^d,ps(igrid)%x)
816 case (fs_hancock)
817 ! hancock predict (first) step for twostep tvdlf and tvdmu scheme
818 call hancockmf(qdt,ixg^l,ixo^l,idim^lim,qtc,wct,qt,w,dx^d,ps(igrid)%x)
819 case (fs_fd)
820 !================================
821 ! finite difference
822 !================================
823 call fdmf(qdt,ixg^l,ixo^l,idim^lim,qtc,wct,qt,w,fc,dx^d,ps(igrid)%x)
824 case default
825 call mpistop("unknown flux scheme in advect1_gridmf")
826 end select
827
828 if (fix_conserve_at_step) then
829 call store_flux(igrid,fc,idim^lim,ndir)
830 end if
831
832 end subroutine process1_gridmf
833
834 subroutine upwindlrmf(ixI^L,ixL^L,ixR^L,idim,w,wCT,wLC,wRC,x)
835 ! Determine the upwinded wLC(ixL) and wRC(ixR) from w.
836 ! the wCT is only used when PPM is exploited.
838 use mod_limiter
839
840 integer, intent(in) :: ixI^L, ixL^L, ixR^L, idim
841 double precision, dimension(ixI^S,1:nw) :: w, wCT
842 double precision, dimension(ixI^S,1:nw) :: wLC, wRC
843 double precision, dimension(ixI^S,1:ndim) :: x
844
845 double precision :: ldw(ixI^S), rdw(ixI^S), dwC(ixI^S)
846 integer :: jxR^L, ixC^L, jxC^L, iw
847
848 if (type_limiter(block%level) == limiter_mp5) then
849 call mp5limiter(ixi^l,ixl^l,idim,w,wlc,wrc)
850 else if (type_limiter(block%level) == limiter_ppm) then
851 call ppmlimiter(ixi^l,ixm^ll,idim,w,wct,wlc,wrc)
852 else
853 jxr^l=ixr^l+kr(idim,^d);
854 ixcmax^d=jxrmax^d; ixcmin^d=ixlmin^d-kr(idim,^d);
855 jxc^l=ixc^l+kr(idim,^d);
856
857 do iw=1,nwflux
858 if (loglimit(iw)) then
859 w(ixcmin^d:jxcmax^d,iw)=dlog10(w(ixcmin^d:jxcmax^d,iw))
860 wlc(ixl^s,iw)=dlog10(wlc(ixl^s,iw))
861 wrc(ixr^s,iw)=dlog10(wrc(ixr^s,iw))
862 end if
863
864 dwc(ixc^s)=w(jxc^s,iw)-w(ixc^s,iw)
865
866 ! limit flux from left and/or right
867 call dwlimiter2(dwc,ixi^l,ixc^l,idim,type_limiter(block%level),ldw,rdw)
868 wlc(ixl^s,iw)=wlc(ixl^s,iw)+half*ldw(ixl^s)
869 wrc(ixr^s,iw)=wrc(ixr^s,iw)-half*rdw(jxr^s)
870
871 if (loglimit(iw)) then
872 w(ixcmin^d:jxcmax^d,iw)=10.0d0**w(ixcmin^d:jxcmax^d,iw)
873 wlc(ixl^s,iw)=10.0d0**wlc(ixl^s,iw)
874 wrc(ixr^s,iw)=10.0d0**wrc(ixr^s,iw)
875 end if
876 end do
877
878 endif
879
880 end subroutine upwindlrmf
881
882 subroutine getfluxmf(w,x,ixI^L,ixO^L,idir,idim,f)
883 ! Calculate lux f_idim[idir] within ixO^L.
885
886 integer, intent(in) :: ixI^L, ixO^L, idir, idim
887 double precision, intent(in) :: w(ixI^S,nw)
888 double precision, intent(in) :: x(ixI^S,1:ndim)
889 double precision,intent(out) :: f(ixI^S)
890
891 ! compute flux of magnetic field
892 ! f_i[b_k]=v_i*b_k-v_k*b_i
893 if (idim==idir) then
894 f(ixo^s)=zero
895 else
896 f(ixo^s)=w(ixo^s,mom(idim))*w(ixo^s,mag(idir))-w(ixo^s,mag(idim))*w(ixo^s,mom(idir))
897 if (b0field) then
898 f(ixo^s)=f(ixo^s)&
899 +w(ixo^s,mom(idim))*block%B0(ixo^s,idir,idim)&
900 -w(ixo^s,mom(idir))*block%B0(ixo^s,idim,idim)
901 end if
902 end if
903
904 end subroutine getfluxmf
905
906 subroutine tvdlfmf(qdt,ixI^L,ixO^L,idim^LIM,qtC,wCT,qt,wnew,fC,dx^D,x)
907 ! method=='tvdlf' --> 2nd order TVD-Lax-Friedrich scheme.
908 ! method=='tvdlf1' --> 1st order TVD-Lax-Friedrich scheme.
910 use mod_comm_lib, only: mpistop
911
912 double precision, intent(in) :: qdt, qtC, qt, dx^D
913 integer, intent(in) :: ixI^L, ixO^L, idim^LIM
914 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
915 double precision, dimension(ixI^S,1:nw) :: wCT, wnew
916 double precision, dimension(ixI^S,1:ndir,1:ndim) :: fC
917
918 double precision, dimension(ixI^S,1:nw) :: wLC, wRC, wmean
919 double precision, dimension(ixI^S) :: fLC, fRC
920 double precision, dimension(ixI^S) :: cmaxC
921 double precision :: dxinv(1:ndim), inv_volume(ixO^S)
922 integer :: idims, idir, ix^L, hxO^L, ixC^L, ixCR^L, jxC^L, kxC^L, kxR^L
923
924 ! The flux calculation contracts by one in the idim direction it is applied.
925 ! The limiter contracts the same directions by one more, so expand ixO by 2.
926 ix^l=ixo^l;
927 do idims= idim^lim
928 ix^l=ix^l^ladd2*kr(idims,^d);
929 end do
930 if (ixi^l^ltix^l|.or.|.or.) &
931 call mpistop("Error in tvdlfmf: Nonconforming input limits")
932
933 ^d&dxinv(^d)=-qdt/dx^d;
934 fc=0.d0
935 do idims= idim^lim
936 b0i=idims
937
938 hxo^l=ixo^l-kr(idims,^d);
939 ! ixC is centered index in the idim direction from ixOmin-1/2 to ixOmax+1/2
940 ixcmax^d=ixomax^d; ixcmin^d=hxomin^d;
941 ! Calculate wRC=uR_{j+1/2} and wLC=uL_j+1/2
942 jxc^l=ixc^l+kr(idims,^d);
943 kxcmin^d=iximin^d; kxcmax^d=iximax^d-kr(idims,^d);
944 kxr^l=kxc^l+kr(idims,^d);
945 ixcr^l=ixc^l;
946
947 wrc(kxc^s,1:nwflux)=wct(kxr^s,1:nwflux)
948 wlc(kxc^s,1:nwflux)=wct(kxc^s,1:nwflux)
949
950 call upwindlrmf(ixi^l,ixcr^l,ixcr^l,idims,wct,wct,wlc,wrc,x)
951
952 ! For the high order Lax-Friedrich TVDLF scheme the limiter is based on
953 ! the maximum eigenvalue, it is calculated in advance.
954 ! determine mean state and store in wLC
955 wmean=0.5d0*(wlc+wrc)
956 call getcmaxfff(wmean,ixg^ll,ixc^l,idims,cmaxc)
957
958 ! Calculate fLC=f(uL_j+1/2) and fRC=f(uR_j+1/2) for each idir
959 do idir=1,ndir
960 call getfluxmf(wlc,x,ixg^ll,ixc^l,idir,idims,flc)
961 call getfluxmf(wrc,x,ixg^ll,ixc^l,idir,idims,frc)
962 ! To save memory we use fLC to store (F_L+F_R)/2=half*(fLC+fRC)
963 flc(ixc^s)=half*(flc(ixc^s)+frc(ixc^s))
964
965 ! Add TVDLF dissipation to the flux
966 if (idir==idims) then
967 flc(ixc^s)=flc(ixc^s)-mf_tvdlfeps*tvdlfeps*cmaxc(ixc^s)*half*(wrc(ixc^s,mag(idir))-wlc(ixc^s,mag(idir)))
968 end if
969 if (slab_uniform) then
970 fc(ixc^s,idir,idims)=flc(ixc^s)
971 else
972 fc(ixc^s,idir,idims)=block%surfaceC(ixc^s,idims)*flc(ixc^s)
973 end if
974
975 end do ! Next idir
976 end do ! Next idims
977 b0i=0
978
979 !Now update the state:
980 do idims= idim^lim
981 hxo^l=ixo^l-kr(idims,^d);
982 ! Multiply the fluxes by -dt/dx since Flux fixing expects this
983 if (slab_uniform) then
984 fc(ixi^s,:,idims)=dxinv(idims)*fc(ixi^s,:,idims)
985 wnew(ixo^s,mag(:))=wnew(ixo^s,mag(:)) &
986 + (fc(ixo^s,:,idims)-fc(hxo^s,:,idims))
987 else
988 inv_volume = 1.0d0/block%dvolume(ixo^s)
989 fc(ixi^s,:,idims)=-qdt*fc(ixi^s,:,idims)
990
991 do idir = 1, ndir
992 wnew(ixo^s,mag(idir))=wnew(ixo^s,mag(idir)) + (fc(ixo^s,idir,idims)-fc(hxo^s,idir,idims)) * &
993 inv_volume
994 end do
995 end if
996
997 end do ! Next idims
998
999 if (.not.slab) call addgeometrymf(qdt,ixi^l,ixo^l,wct,wnew,x)
1000 call divbclean(qdt,ixi^l,ixo^l,wct,wnew,x)
1001
1002 end subroutine tvdlfmf
1003
1004 subroutine hancockmf(qdt,ixI^L,ixO^L,idim^LIM,qtC,wCT,qt,wnew,dx^D,x)
1005 ! The non-conservative Hancock predictor for TVDLFmf
1006 ! on entry:
1007 ! input available on ixI^L=ixG^L asks for output on ixO^L=ixG^L^LSUBnghostcells
1008 ! one entry: (predictor): wCT -- w_n wnew -- w_n qdt=dt/2
1009 ! on exit : (predictor): wCT -- w_n wnew -- w_n+1/2
1011 use mod_comm_lib, only: mpistop
1012
1013 integer, intent(in) :: ixI^L, ixO^L, idim^LIM
1014 double precision, intent(in) :: qdt, qtC, qt, dx^D, x(ixI^S,1:ndim)
1015 double precision, intent(inout) :: wCT(ixI^S,1:nw), wnew(ixI^S,1:nw)
1016
1017 double precision, dimension(ixI^S,1:nw) :: wLC, wRC
1018 double precision, dimension(ixI^S) :: fLC, fRC
1019 double precision :: dxinv(1:ndim)
1020 integer :: idims, idir, ix^L, hxO^L, ixtest^L
1021
1022 ! Expand limits in each idims direction in which fluxes are added
1023 ix^l=ixo^l;
1024 do idims= idim^lim
1025 ix^l=ix^l^laddkr(idims,^d);
1026 end do
1027 if (ixi^l^ltix^l|.or.|.or.) &
1028 call mpistop("Error in Hancockmf: Nonconforming input limits")
1029
1030 ^d&dxinv(^d)=-qdt/dx^d;
1031 do idims= idim^lim
1032 b0i=idims
1033 ! Calculate w_j+g_j/2 and w_j-g_j/2
1034 ! First copy all variables, then upwind wLC and wRC.
1035 ! wLC is to the left of ixO, wRC is to the right of wCT.
1036 hxo^l=ixo^l-kr(idims,^d);
1037
1038 wrc(hxo^s,1:nwflux)=wct(ixo^s,1:nwflux)
1039 wlc(ixo^s,1:nwflux)=wct(ixo^s,1:nwflux)
1040
1041 call upwindlrmf(ixi^l,ixo^l,hxo^l,idims,wct,wct,wlc,wrc,x)
1042
1043 ! Advect mag(idir)
1044 do idir=1,ndir
1045 ! Calculate the fLC and fRC fluxes
1046 call getfluxmf(wrc,x,ixi^l,hxo^l,idir,idims,frc)
1047 call getfluxmf(wlc,x,ixi^l,ixo^l,idir,idims,flc)
1048
1049 if (slab_uniform) then
1050 wnew(ixo^s,mag(idir))=wnew(ixo^s,mag(idir))+dxinv(idims)* &
1051 (flc(ixo^s)-frc(hxo^s))
1052 else
1053 wnew(ixo^s,mag(idir))=wnew(ixo^s,mag(idir))-qdt/block%dvolume(ixo^s) &
1054 *(block%surfaceC(ixo^s,idims)*flc(ixo^s) &
1055 -block%surfaceC(hxo^s,idims)*frc(hxo^s))
1056 end if
1057 end do
1058 end do ! next idims
1059 b0i=0
1060
1061 if (.not.slab) call addgeometrymf(qdt,ixi^l,ixo^l,wct,wnew,x)
1062
1063 end subroutine hancockmf
1064
1065 subroutine fdmf(qdt,ixI^L,ixO^L,idim^LIM,qtC,wCT,qt,wnew,fC,dx^D,x)
1067 double precision, intent(in) :: qdt, qtC, qt, dx^D
1068 integer, intent(in) :: ixI^L, ixO^L, idim^LIM
1069 double precision, dimension(ixI^S,1:ndim), intent(in) :: x
1070
1071 double precision, dimension(ixI^S,1:nw), intent(inout) :: wCT, wnew
1072 double precision, dimension(ixI^S,1:ndir,1:ndim), intent(out) :: fC
1073
1074 double precision, dimension(ixI^S) :: fCT
1075 double precision, dimension(ixI^S,1:nw) :: fm, fp, fmR, fpL
1076 double precision, dimension(ixI^S) :: v
1077 double precision :: dxinv(1:ndim)
1078 integer :: idims, idir, ixC^L, ix^L, hxO^L, ixCR^L
1079
1080 ^d&dxinv(^d)=-qdt/dx^d;
1081 do idims= idim^lim
1082
1083 ! Get fluxes for the whole grid (mesh+nghostcells)
1084 {^d& ixcmin^d = ixomin^d - nghostcells * kr(idims,^d)\}
1085 {^d& ixcmax^d = ixomax^d + nghostcells * kr(idims,^d)\}
1086
1087 hxo^l=ixo^l-kr(idims,^d);
1088 ! ix is centered index in the idim direction from ixOmin-1/2 to ixOmax+1/2
1089 ixmax^d=ixomax^d; ixmin^d=hxomin^d;
1090 ixcr^l=ixc^l;
1091
1092 do idir=1,ndir
1093 call getfluxmf(wct,x,ixg^ll,ixcr^l,idir,idims,fct)
1094 ! Lax-Friedrich splitting:
1095 fp(ixcr^s,mag(idir)) = half * (fct(ixcr^s) + mf_tvdlfeps * tvdlfeps * cmax_global * wct(ixcr^s,mag(idir)))
1096 fm(ixcr^s,mag(idir)) = half * (fct(ixcr^s) - mf_tvdlfeps * tvdlfeps * cmax_global * wct(ixcr^s,mag(idir)))
1097 end do ! iw loop
1098
1099 ! now do the reconstruction of fp and fm:
1100 call reconstructlmf(ixi^l,ix^l,idims,fp,fpl)
1101 call reconstructrmf(ixi^l,ix^l,idims,fm,fmr)
1102
1103 do idir=1,ndir
1104 if (slab_uniform) then
1105 fc(ix^s,idir,idims) = dxinv(idims) * (fpl(ix^s,mag(idir)) + fmr(ix^s,mag(idir)))
1106 wnew(ixo^s,mag(idir))=wnew(ixo^s,mag(idir))+ &
1107 (fc(ixo^s,idir,idims)-fc(hxo^s,idir,idims))
1108 else
1109 fc(ix^s,idir,idims)=-qdt*block%surfaceC(ix^s,idims) * (fpl(ix^s,mag(idir)) + fmr(ix^s,mag(idir)))
1110 wnew(ixo^s,mag(idir))=wnew(ixo^s,mag(idir))+ &
1111 (fc(ixo^s,idir,idims)-fc(hxo^s,idir,idims))/block%dvolume(ixo^s)
1112 end if
1113 end do ! iw loop
1114
1115 end do !idims loop
1116
1117 if (.not.slab) call addgeometrymf(qdt,ixi^l,ixo^l,wct,wnew,x)
1118 call divbclean(qdt,ixi^l,ixo^l,wct,wnew,x)
1119
1120 end subroutine fdmf
1121
1122 subroutine reconstructlmf(ixI^L,iL^L,idims,w,wLC)
1124 use mod_limiter
1125
1126 integer, intent(in) :: ixI^L, iL^L, idims
1127 double precision, intent(in) :: w(ixI^S,1:nw)
1128
1129 double precision, intent(out) :: wLC(ixI^S,1:nw)
1130
1131 double precision :: ldw(ixI^S), dwC(ixI^S)
1132 integer :: jxR^L, ixC^L, jxC^L, kxC^L, iw
1133
1134 select case (type_limiter(block%level))
1135 case (limiter_mp5)
1136 call mp5limiterl(ixi^l,il^l,idims,w,wlc)
1137 case (limiter_weno5)
1138 call weno5limiterl(ixi^l,il^l,idims,w,wlc,1)
1139 case (limiter_wenoz5)
1140 call weno5limiterl(ixi^l,il^l,idims,w,wlc,2)
1141 case default
1142
1143 kxcmin^d=iximin^d; kxcmax^d=iximax^d-kr(idims,^d);
1144
1145 wlc(kxc^s,1:nwflux) = w(kxc^s,1:nwflux)
1146
1147 jxr^l=il^l+kr(idims,^d);
1148
1149 ixcmax^d=jxrmax^d; ixcmin^d=ilmin^d-kr(idims,^d);
1150 jxc^l=ixc^l+kr(idims,^d);
1151
1152 do iw=1,nwflux
1153 dwc(ixc^s)=w(jxc^s,iw)-w(ixc^s,iw)
1154
1155 call dwlimiter2(dwc,ixi^l,ixc^l,idims,type_limiter(block%level),ldw=ldw)
1156
1157 wlc(il^s,iw)=wlc(il^s,iw)+half*ldw(il^s)
1158 end do
1159 end select
1160
1161 end subroutine reconstructlmf
1162
1163 subroutine reconstructrmf(ixI^L,iL^L,idims,w,wRC)
1165 use mod_limiter
1166
1167 integer, intent(in) :: ixI^L, iL^L, idims
1168 double precision, intent(in) :: w(ixI^S,1:nw)
1169
1170 double precision, intent(out) :: wRC(ixI^S,1:nw)
1171
1172 double precision :: rdw(ixI^S), dwC(ixI^S)
1173 integer :: jxR^L, ixC^L, jxC^L, kxC^L, kxR^L, iw
1174
1175 select case (type_limiter(block%level))
1176 case (limiter_mp5)
1177 call mp5limiterr(ixi^l,il^l,idims,w,wrc)
1178 case (limiter_weno5)
1179 call weno5limiterr(ixi^l,il^l,idims,w,wrc,1)
1180 case (limiter_wenoz5)
1181 call weno5limiterr(ixi^l,il^l,idims,w,wrc,2)
1182 case default
1183
1184 kxcmin^d=iximin^d; kxcmax^d=iximax^d-kr(idims,^d);
1185 kxr^l=kxc^l+kr(idims,^d);
1186
1187 wrc(kxc^s,1:nwflux)=w(kxr^s,1:nwflux)
1188
1189 jxr^l=il^l+kr(idims,^d);
1190 ixcmax^d=jxrmax^d; ixcmin^d=ilmin^d-kr(idims,^d);
1191 jxc^l=ixc^l+kr(idims,^d);
1192
1193 do iw=1,nwflux
1194 dwc(ixc^s)=w(jxc^s,iw)-w(ixc^s,iw)
1195 call dwlimiter2(dwc,ixi^l,ixc^l,idims,type_limiter(block%level),rdw=rdw)
1196
1197 wrc(il^s,iw)=wrc(il^s,iw)-half*rdw(jxr^s)
1198 end do
1199 end select
1200
1201 end subroutine reconstructrmf
1202
1203 subroutine centdiff4mf(qdt,ixI^L,ixO^L,idim^LIM,qtC,wCT,qt,w,fC,dx^D,x)
1204 ! Advance the flow variables from global_time to global_time+qdt within ixO^L by
1205 ! fourth order centered differencing in space
1206 ! for the dw/dt+dF_i(w)/dx_i=S type equation.
1207 ! wCT contains the time centered variables at time qtC for flux and source.
1208 ! w is the old value at qt on input and the new value at qt+qdt on output.
1210 use mod_comm_lib, only: mpistop
1211
1212 integer, intent(in) :: ixI^L, ixO^L, idim^LIM
1213 double precision, intent(in) :: qdt, qtC, qt, dx^D
1214 double precision :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
1215 double precision, intent(in) :: x(ixI^S,1:ndim)
1216 double precision :: fC(ixI^S,1:ndir,1:ndim)
1217
1218 double precision :: v(ixI^S,ndim), f(ixI^S)
1219 double precision, dimension(ixI^S,1:nw) :: wLC, wRC
1220 double precision, dimension(ixI^S) :: vLC, vRC,cmaxLC,cmaxRC
1221 double precision :: dxinv(1:ndim)
1222 integer :: idims, idir, idirmin,ix^D
1223 integer :: ix^L, hxO^L, ixC^L, jxC^L, hxC^L, kxC^L, kkxC^L, kkxR^L
1224
1225 ! two extra layers are needed in each direction for which fluxes are added.
1226 ix^l=ixo^l;
1227 do idims= idim^lim
1228 ix^l=ix^l^ladd2*kr(idims,^d);
1229 end do
1230
1231 if (ixi^l^ltix^l|.or.|.or.) then
1232 call mpistop("Error in evolve_CentDiff4: Non-conforming input limits")
1233 end if
1234 ^d&dxinv(^d)=-qdt/dx^d;
1235
1236 ! Add fluxes to w
1237 do idims= idim^lim
1238 b0i=idims
1239 ix^l=ixo^l^ladd2*kr(idims,^d);
1240 hxo^l=ixo^l-kr(idims,^d);
1241
1242 ixcmin^d=hxomin^d; ixcmax^d=ixomax^d;
1243 hxc^l=ixc^l-kr(idims,^d);
1244 jxc^l=ixc^l+kr(idims,^d);
1245 kxc^l=ixc^l+2*kr(idims,^d);
1246
1247 kkxcmin^d=iximin^d; kkxcmax^d=iximax^d-kr(idims,^d);
1248 kkxr^l=kkxc^l+kr(idims,^d);
1249 wrc(kkxc^s,1:nwflux)=wct(kkxr^s,1:nwflux)
1250 wlc(kkxc^s,1:nwflux)=wct(kkxc^s,1:nwflux)
1251
1252 call upwindlrmf(ixi^l,ixc^l,ixc^l,idims,wct,wct,wlc,wrc,x)
1253
1254 ! Calculate velocities from upwinded values
1255 call getcmaxfff(wlc,ixg^ll,ixc^l,idims,cmaxlc)
1256 call getcmaxfff(wrc,ixg^ll,ixc^l,idims,cmaxrc)
1257 ! now take the maximum of left and right states
1258 vlc(ixc^s)=max(cmaxrc(ixc^s),cmaxlc(ixc^s))
1259
1260 do idir=1,ndir
1261 ! Get non-transported flux
1262 call getfluxmf(wct,x,ixi^l,ix^l,idir,idims,f)
1263 ! Center flux to interface
1264 ! f_i+1/2= (-f_(i+2) +7 f_(i+1) + 7 f_i - f_(i-1))/12
1265 fc(ixc^s,idir,idims)=(-f(kxc^s)+7.0d0*(f(jxc^s)+f(ixc^s))-f(hxc^s))/12.0d0
1266 ! add rempel dissipative flux, only second order version for now
1267 ! one could gradually reduce the dissipative flux to improve solutions
1268 ! for computing steady states (Keppens et al. 2012, JCP)
1269 fc(ixc^s,idir,idims)=fc(ixc^s,idir,idims)-mf_tvdlfeps*tvdlfeps*half*vlc(ixc^s) &
1270 *(wrc(ixc^s,mag(idir))-wlc(ixc^s,mag(idir)))
1271
1272 if (slab_uniform) then
1273 fc(ixc^s,idir,idims)=dxinv(idims)*fc(ixc^s,idir,idims)
1274 ! result: f_(i+1/2)-f_(i-1/2) = [-f_(i+2)+8(f_(i+1)+f_(i-1))-f_(i-2)]/12
1275 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+(fc(ixo^s,idir,idims)-fc(hxo^s,idir,idims))
1276 else
1277 fc(ixc^s,idir,idims)=-qdt*block%surfaceC(ixc^s,idims)*fc(ixc^s,idir,idims)
1278 w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+ &
1279 (fc(ixo^s,idir,idims)-fc(hxo^s,idir,idims))/block%dvolume(ixo^s)
1280 end if
1281 end do !next idir
1282 end do !next idims
1283 b0i=0
1284
1285 if (.not.slab) call addgeometrymf(qdt,ixi^l,ixo^l,wct,w,x)
1286 call divbclean(qdt,ixi^l,ixo^l,wct,w,x)
1287
1288 end subroutine centdiff4mf
1289
1290 subroutine getdtfff_courant(w,x,ixI^L,ixO^L,dtnew)
1291 ! compute CFL limited dt (for variable time stepping)
1293
1294 integer, intent(in) :: ixI^L, ixO^L
1295 double precision, intent(in) :: x(ixI^S,1:ndim)
1296 double precision, intent(inout) :: w(ixI^S,1:nw), dtnew
1297
1298 double precision :: courantmax, dxinv(1:ndim)
1299 double precision :: cmax(ixI^S),tmp(ixI^S),alfven(ixI^S)
1300 integer :: idims
1301
1302 dtnew=bigdouble
1303 courantmax=0.d0
1304 ^d&dxinv(^d)=1.d0/dxlevel(^d);
1305
1306 do idims=1,ndim
1307 call getcmaxfff(w,ixi^l,ixo^l,idims,cmax)
1308 cmax_mype = max(cmax_mype,maxval(cmax(ixo^s)))
1309 if (.not.slab_uniform) then
1310 tmp(ixo^s)=cmax(ixo^s)/block%dx(ixo^s,idims)
1311 courantmax=max(courantmax,maxval(tmp(ixo^s)))
1312 else
1313 tmp(ixo^s)=cmax(ixo^s)*dxinv(idims)
1314 courantmax=max(courantmax,maxval(tmp(ixo^s)))
1315 end if
1316 end do
1317 ! courantmax='max( c/dx)'
1318 if (courantmax>smalldouble) dtnew=min(dtnew,mf_cc/courantmax)
1319
1320 end subroutine getdtfff_courant
1321
1322 subroutine getcmaxfff(w,ixI^L,ixO^L,idims,cmax)
1324
1325 logical :: new_cmax,needcmin
1326 integer, intent(in) :: ixI^L, ixO^L, idims
1327 double precision, intent(in) :: w(ixI^S,1:nw)
1328 double precision, intent(out) :: cmax(ixI^S)
1329
1330 ! calculate alfven speed
1331 if(b0field) then
1332 cmax(ixo^s)=sqrt(sum((w(ixo^s,mag(:))+block%b0(ixo^s,:,0))**2,dim=ndim+1)/w(ixo^s,rho_))
1333 else
1334 cmax(ixo^s)=sqrt(sum(w(ixo^s,mag(:))**2,dim=ndim+1)/w(ixo^s,rho_))
1335 endif
1336 cmax(ixo^s)=cmax(ixo^s)+abs(w(ixo^s,mom(idims)))
1337
1338 end subroutine getcmaxfff
1339
1340 !> Clean divergence of magnetic field by Janhunen's and Linde's source terms
1341 subroutine divbclean(qdt,ixI^L,ixO^L,wCT,w,x)
1343 use mod_geometry
1344
1345 integer, intent(in) :: ixI^L, ixO^L
1346 double precision, intent(in) :: x(ixI^S,1:ndim),wCT(ixI^S,1:nw),qdt
1347 double precision, intent(inout) :: w(ixI^S,1:nw)
1348 double precision :: divb(ixI^S),graddivb(ixI^S),bdivb(ixI^S,1:ndir)
1349 integer :: idims, ix^L, ixp^L, i^D, iside
1350
1351 ! Calculate div B
1352 ix^l=ixo^l^ladd1;
1353 call get_divb(wct,ixi^l,ix^l,divb)
1354
1355 ixp^l=ixo^l;
1356
1357 ! Add Linde's diffusive terms
1358 do idims=1,ndim
1359 ! Calculate grad_idim(divb)
1360 call gradient(divb,ixi^l,ixp^l,idims,graddivb)
1361
1362 ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
1363 if (slab_uniform) then
1364 graddivb(ixp^s)=graddivb(ixp^s)*mf_cdivb/(^d&1.0d0/dxlevel(^d)**2+)
1365 else
1366 graddivb(ixp^s)=graddivb(ixp^s)*mf_cdivb &
1367 /(^d&1.0d0/block%dx(ixp^s,^d)**2+)
1368 end if
1369 ! B_idim += eta*grad_idim(divb)
1370 ! with Janhunen's term
1371 !w(ixp^S,mag(idims))=w(ixp^S,mag(idims))+&
1372 ! graddivb(ixp^S)-qdt*w(ixp^S,mom(idims))*divb(ixp^S)
1373 ! without Janjunen's term
1374 w(ixp^s,mag(idims))=w(ixp^s,mag(idims))+&
1375 graddivb(ixp^s)
1376 end do
1377
1378 end subroutine divbclean
1379
1380 subroutine addgeometrymf(qdt,ixI^L,ixO^L,wCT,w,x)
1381 ! Add geometrical source terms to w
1383 use mod_geometry
1384
1385 integer, intent(in) :: ixI^L, ixO^L
1386 double precision, intent(in) :: qdt, x(ixI^S,1:ndim)
1387 double precision, intent(inout) :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
1388 !.. local ..
1389 double precision :: tmp(ixI^S)
1390 integer :: iw
1391 integer :: mr_,mphi_ ! Polar var. names
1392 integer :: br_,bphi_
1393
1394 mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
1395 br_=mag(1); bphi_=mag(1)-1+phi_
1396
1397 select case (coordinate)
1398 case (cylindrical)
1399 if(phi_>0) then
1400 ! s[Bphi]=(Bphi*vr-Br*vphi)/radius
1401 tmp(ixo^s)=(wct(ixo^s,bphi_)*wct(ixo^s,mom(1)) &
1402 -wct(ixo^s,br_)*wct(ixo^s,mom(3)))
1403 w(ixo^s,bphi_)=w(ixo^s,bphi_)+qdt*tmp(ixo^s)/x(ixo^s,1)
1404 end if
1405 case (spherical)
1406 {^nooned
1407 ! s[b2]=(vr*Btheta-vtheta*Br)/r
1408 ! + cot(theta)*psi/r
1409 tmp(ixo^s)= wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
1410 -wct(ixo^s,mom(2))*wct(ixo^s,mag(1))
1411 if (b0field) then
1412 tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom(1))*block%b0(ixo^s,2,0) &
1413 -wct(ixo^s,mom(2))*block%b0(ixo^s,1,0)
1414 end if
1415 ! Divide by radius and add to w
1416 w(ixo^s,mag(2))=w(ixo^s,mag(2))+qdt*tmp(ixo^s)/x(ixo^s,1)
1417 }
1418 if(ndir==3) then
1419 ! s[b3]=(vr*Bphi-vphi*Br)/r
1420 ! -cot(theta)*(vphi*Btheta-vtheta*Bphi)/r
1421 tmp(ixo^s)=wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
1422 -wct(ixo^s,mom(3))*wct(ixo^s,mag(1)){^nooned &
1423 -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
1424 -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
1425 /dsin(x(ixo^s,2)) }
1426 if (b0field) then
1427 tmp(ixo^s)=tmp(ixo^s)+wct(ixo^s,mom(1))*block%b0(ixo^s,3,0) &
1428 -wct(ixo^s,mom(3))*block%b0(ixo^s,1,0){^nooned &
1429 -(wct(ixo^s,mom(3))*block%b0(ixo^s,2,0) &
1430 -wct(ixo^s,mom(2))*block%b0(ixo^s,3,0))*dcos(x(ixo^s,2)) &
1431 /dsin(x(ixo^s,2)) }
1432 end if
1433 ! Divide by radius and add to w
1434 w(ixo^s,mag(3))=w(ixo^s,mag(3))+qdt*tmp(ixo^s)/x(ixo^s,1)
1435 end if
1436 end select
1437
1438 end subroutine addgeometrymf
1439
1440 !> Calculate idirmin and the idirmin:3 components of the common current array
1441 !> make sure that dxlevel(^D) is set correctly.
1442 subroutine get_current(w,ixI^L,ixO^L,idirmin,current)
1444 use mod_geometry
1445
1446 integer :: idirmin0
1447 integer :: ixO^L, idirmin, ixI^L
1448 double precision :: w(ixI^S,1:nw)
1449
1450 ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
1451 double precision :: current(ixI^S,7-2*ndir:3),bvec(ixI^S,1:ndir)
1452 integer :: idir
1453
1454 idirmin0 = 7-2*ndir
1455
1456 bvec(ixi^s,1:ndir)=w(ixi^s,mag(1:ndir))
1457
1458 call curlvector(bvec,ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
1459
1460 if(b0field) current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+&
1461 block%J0(ixo^s,idirmin0:3)
1462
1463 end subroutine get_current
1464
1465 !> Calculate div B within ixO
1466 subroutine get_divb(w,ixI^L,ixO^L,divb)
1467 use mod_geometry
1469
1470 integer, intent(in) :: ixI^L, ixO^L
1471 double precision, intent(in) :: w(ixI^S,1:nw)
1472 double precision :: divb(ixI^S)
1473
1474 double precision :: bvec(ixI^S,1:ndir)
1475
1476 bvec(ixi^s,:)=w(ixi^s,mag(:))
1477
1478 select case(typediv)
1479 case("central")
1480 call divvector(bvec,ixi^l,ixo^l,divb)
1481 case("limited")
1482 call divvectors(bvec,ixi^l,ixo^l,divb)
1483 end select
1484 end subroutine get_divb
1485
1486end module mod_magnetofriction
subroutine metrics
subroutine, public resettree
reset AMR and (de)allocate boundary flux storage at level changes
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for flux conservation near refinement boundaries.
subroutine, public init_comm_fix_conserve(idimlim, nwfluxin)
subroutine, public recvflux(idimlim)
subroutine, public sendflux(idimlim)
subroutine, public store_flux(igrid, fc, idimlim, nwfluxin)
subroutine, public fix_conserve(psb, idimlim, nw0, nwfluxin)
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
subroutine divvector(qvec, ixil, ixol, divq, nth_in)
integer coordinate
Definition mod_geometry.t:7
integer, parameter spherical
integer, parameter cylindrical
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
subroutine gradient(q, ixil, ixol, idir, gradq, nth_in)
subroutine divvectors(qvec, ixil, ixol, divq)
Calculate divergence of a vector qvec within ixL using limited extrapolation to cell edges.
update ghost cells of all blocks including physical boundaries
integer, dimension(0:3^d &), target type_recv_p_p1
integer, dimension( :^d &), pointer type_recv_r
integer, dimension(-1:1^d &), target type_send_srl_p1
integer, dimension(-1:1^d &), target type_send_r_p2
subroutine getbc(time, qdt, psb, nwstart, nwbc)
do update ghost cells of all blocks including physical boundaries
integer, dimension(0:3^d &), target type_send_p_f
integer, dimension( :^d &), pointer type_send_p
integer, dimension(0:3^d &), target type_recv_p_p2
integer, dimension( :^d &), pointer type_send_srl
integer, dimension(-1:1^d &), target type_send_r_p1
integer, dimension(-1:1^d &), target type_send_srl_p2
subroutine create_bc_mpi_datatype(nwstart, nwbc)
integer, dimension(0:3^d &), target type_send_p_p2
integer, dimension(0:3^d &), target type_recv_r_f
integer, dimension(-1:1^d &), target type_recv_srl_f
integer, dimension(-1:1^d &), target type_send_r_f
integer, dimension(-1:1^d &), target type_send_srl_f
integer, dimension(0:3^d &), target type_send_p_p1
integer, dimension( :^d &), pointer type_send_r
integer, dimension(0:3^d &), target type_recv_r_p1
integer, dimension(0:3^d &), target type_recv_r_p2
integer, dimension(-1:1^d &), target type_recv_srl_p2
integer, dimension( :^d &), pointer type_recv_p
integer, dimension(-1:1^d &), target type_recv_srl_p1
integer, dimension(0:3^d &), target type_recv_p_f
integer, dimension( :^d &), pointer type_recv_srl
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
integer, dimension(:), allocatable typepred1
The spatial discretization for the predictor step when using a two step PC method.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
integer, parameter unitpar
file handle for IO
double precision global_time
The global simulation time.
integer istep
Index of the sub-step in a multi-step time integrator.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer snapshotini
Resume from the snapshot with this index.
integer it
Number of time steps taken.
logical, dimension(:), allocatable loglimit
integer ditregrid
Reconstruct the AMR grid once every ditregrid iteration(s)
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical stagger_grid
True for using stagger grid.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
integer b0i
background magnetic field location indicator
integer mype
The rank of the current MPI task.
character(len=std_len) typediv
double precision dt
global time step
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
integer, dimension(:), allocatable flux_method
Which flux scheme of spatial discretization to use (per grid level)
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
double precision unit_velocity
Physical scaling factor for velocity.
logical prolongprimitive
prolongate primitive variables in level-jump ghost cells
logical b0field
split magnetic field as background B0 field
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
integer, dimension(:), allocatable type_limiter
Type of slope limiter used for reconstructing variables on cell edges.
integer nghostcells
Number of ghost cells surrounding a grid.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
integer t_stepper
time stepper type
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
integer refine_max_level
Maximal number of AMR levels.
integer, parameter fs_hancock
integer, dimension(:,:), allocatable node
Module for reading input and writing output.
subroutine saveamrfile(ifile)
Module with slope/flux limiters.
Definition mod_limiter.t:2
integer, parameter limiter_ppm
Definition mod_limiter.t:25
subroutine dwlimiter2(dwc, ixil, ixcl, idims, typelim, ldw, rdw)
Limit the centered dwC differences within ixC for iw in direction idim. The limiter is chosen accordi...
integer, parameter limiter_weno5
Definition mod_limiter.t:29
integer, parameter limiter_wenoz5
Definition mod_limiter.t:31
integer, parameter limiter_mp5
Definition mod_limiter.t:26
module mod_magnetofriction.t Purpose: use magnetofrictional method to relax 3D magnetic field to forc...
subroutine fdmf(qdt, ixil, ixol, idimlim, qtc, wct, qt, wnew, fc, dxd, x)
subroutine getdtfff_courant(w, x, ixil, ixol, dtnew)
subroutine hancockmf(qdt, ixil, ixol, idimlim, qtc, wct, qt, wnew, dxd, x)
subroutine getfluxmf(w, x, ixil, ixol, idir, idim, f)
subroutine reconstructrmf(ixil, ill, idims, w, wrc)
subroutine getcmaxfff(w, ixil, ixol, idims, cmax)
subroutine divbclean(qdt, ixil, ixol, wct, w, x)
Clean divergence of magnetic field by Janhunen's and Linde's source terms.
subroutine centdiff4mf(qdt, ixil, ixol, idimlim, qtc, wct, qt, w, fc, dxd, x)
double precision mf_tvdlfeps
TVDLF dissipation coefficient controls the dissipation term.
character(len=16) mf_log_mode
How to open the MF diagnostics CSV: auto, append, or replace.
subroutine magnetofriction_init()
Initialize the module.
double precision, public mf_vmax
maximal limit of magnetofrictional velocity in cm s^-1 (Pomoell 2019 A&A)
subroutine vhat(w, x, ixil, ixol, vhatmaxgrid)
double precision tmf
time in magnetofriction process
subroutine get_current(w, ixil, ixol, idirmin, current)
Calculate idirmin and the idirmin:3 components of the common current array make sure that dxlevel(^D)...
double precision mf_cy_max
subroutine addgeometrymf(qdt, ixil, ixol, wct, w, x)
logical mf_continue_run
Whether this run continues an existing MF diagnostics series.
subroutine frictional_velocity(w, x, ixil, ixol, qvmax, qdt)
double precision mf_cdivb
divb cleaning coefficient controls diffusion speed of divb
subroutine upwindlrmf(ixil, ixll, ixrl, idim, w, wct, wlc, wrc, x)
subroutine mf_velocity_update(dtfff)
double precision cmax_mype
maximal speed for fd scheme
subroutine process1_gridmf(method, igrid, qdt, ixgl, idimlim, qtc, wct, qt, w)
subroutine advect1mf(method, dtin, dtfactor, idimlim, qtc, psa, qt, psb)
double precision mf_cy
frictional velocity coefficient
subroutine advectmf(idimlim, qt, qdt)
double precision mf_tvdlfeps_min
character(len=256) mf_log_filename
Optional diagnostics filename; empty uses <base_filename>_mflog.csv.
subroutine tvdlfmf(qdt, ixil, ixol, idimlim, qtc, wct, qt, wnew, fc, dxd, x)
double precision mf_cdivb_max
double precision mf_cc
stability coefficient controls numerical stability
subroutine mf_params_read(files)
Read this module"s parameters from a file.
double precision cmax_global
maximal speed for fd scheme
subroutine reconstructlmf(ixil, ill, idims, w, wlc)
subroutine get_divb(w, ixil, ixol, divb)
Calculate div B within ixO.
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_convert), pointer phys_to_conserved
Definition mod_physics.t:51
Module with all the methods that users can customize in AMRVAC.
procedure(p_no_args), pointer usr_before_main_loop