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