MPI-AMRVAC  3.0
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
mod_mf_phys.t
Go to the documentation of this file.
1 !> Magnetofriction module
2 module mod_mf_phys
3  use mod_global_parameters, only: std_len
4  implicit none
5  private
6 
7  !> viscosity coefficient in s cm^-2 for solar corona (Cheung 2012 ApJ)
8  double precision, public :: mf_nu = 1.d-15
9 
10  !> maximal limit of magnetofrictional velocity in cm s^-1 (Pomoell 2019 A&A)
11  double precision, public :: mf_vmax = 3.d6
12 
13  !> decay scale of frictional velocity
14  double precision, public :: mf_decay_scale(2*^nd)=0.d0
15 
16  !> Whether particles module is added
17  logical, public, protected :: mf_particles = .false.
18 
19  !> Whether GLM-MHD is used
20  logical, public, protected :: mf_glm = .false.
21 
22  !> Whether divB cleaning sources are added splitting from fluid solver
23  logical, public, protected :: source_split_divb = .false.
24 
25  !> GLM-MHD parameter: ratio of the diffusive and advective time scales for div b
26  !> taking values within [0, 1]
27  double precision, public :: mf_glm_alpha = 0.5d0
28 
29  !> MHD fourth order
30  logical, public, protected :: mf_4th_order = .false.
31 
32  !> set to true if need to record electric field on cell edges
33  logical, public, protected :: mf_record_electric_field = .false.
34 
35  !> Indices of the momentum density
36  integer, allocatable, public, protected :: mom(:)
37 
38  !> Indices of the magnetic field
39  integer, allocatable, public, protected :: mag(:)
40 
41  !> Indices of the GLM psi
42  integer, public, protected :: psi_
43 
44  !> The resistivity
45  double precision, public :: mf_eta = 0.0d0
46 
47  !> The hyper-resistivity
48  double precision, public :: mf_eta_hyper = 0.0d0
49 
50  !> Method type to clean divergence of B
51  character(len=std_len), public, protected :: typedivbfix = 'ct'
52 
53  !> Method type of constrained transport
54  character(len=std_len), public, protected :: type_ct = 'average'
55 
56  !> Whether divB is computed with a fourth order approximation
57  logical, public, protected :: mf_divb_4thorder = .false.
58 
59  !> Method type in a integer for good performance
60  integer :: type_divb
61 
62  !> Coefficient of diffusive divB cleaning
63  double precision :: divbdiff = 0.8d0
64 
65  !> Update all equations due to divB cleaning
66  character(len=std_len) :: typedivbdiff = 'all'
67 
68  !> Use a compact way to add resistivity
69  logical :: compactres = .false.
70 
71  !> Add divB wave in Roe solver
72  logical, public :: divbwave = .true.
73 
74  !> Helium abundance over Hydrogen
75  double precision, public, protected :: he_abundance=0.1d0
76 
77  !> To control divB=0 fix for boundary
78  logical, public, protected :: boundary_divbfix(2*^nd)=.true.
79 
80  !> To skip * layer of ghost cells during divB=0 fix for boundary
81  integer, public, protected :: boundary_divbfix_skip(2*^nd)=0
82 
83  !> clean divb in the initial condition
84  logical, public, protected :: clean_initial_divb=.false.
85 
86  ! DivB cleaning methods
87  integer, parameter :: divb_none = 0
88  integer, parameter :: divb_multigrid = -1
89  integer, parameter :: divb_glm = 1
90  integer, parameter :: divb_powel = 2
91  integer, parameter :: divb_janhunen = 3
92  integer, parameter :: divb_linde = 4
93  integer, parameter :: divb_lindejanhunen = 5
94  integer, parameter :: divb_lindepowel = 6
95  integer, parameter :: divb_lindeglm = 7
96  integer, parameter :: divb_ct = 8
97 
98 
99  ! Public methods
100  public :: mf_phys_init
101  public :: mf_get_v
102  public :: mf_get_v_idim
103  public :: mf_to_conserved
104  public :: mf_to_primitive
105  public :: mf_face_to_center
106  public :: get_divb
107  public :: get_current
108  public :: get_normalized_divb
109  public :: b_from_vector_potential
110  public :: mf_mag_en_all
111  public :: record_force_free_metrics
112  {^nooned
113  public :: mf_clean_divb_multigrid
114  }
115 
116 contains
117 
118  !> Read this module's parameters from a file
119  subroutine mf_read_params(files)
121  use mod_particles, only: particles_eta
122  character(len=*), intent(in) :: files(:)
123  integer :: n
124 
125  namelist /mf_list/ mf_nu, mf_vmax, mf_decay_scale, &
127  particles_eta, mf_record_electric_field,&
129  typedivbdiff, type_ct, compactres, divbwave, he_abundance, si_unit, &
132 
133  do n = 1, size(files)
134  open(unitpar, file=trim(files(n)), status="old")
135  read(unitpar, mf_list, end=111)
136 111 close(unitpar)
137  end do
138 
139  end subroutine mf_read_params
140 
141  !> Write this module's parameters to a snapsoht
142  subroutine mf_write_info(fh)
144  integer, intent(in) :: fh
145  integer, parameter :: n_par = 1
146  double precision :: values(n_par)
147  character(len=name_len) :: names(n_par)
148  integer, dimension(MPI_STATUS_SIZE) :: st
149  integer :: er
150 
151  call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
152 
153  names(1) = "nu"
154  values(1) = mf_nu
155  call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
156  call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
157  end subroutine mf_write_info
158 
159  subroutine mf_angmomfix(fC,x,wnew,ixI^L,ixO^L,idim)
161  double precision, intent(in) :: x(ixI^S,1:ndim)
162  double precision, intent(inout) :: fC(ixI^S,1:nwflux,1:ndim), wnew(ixI^S,1:nw)
163  integer, intent(in) :: ixI^L, ixO^L
164  integer, intent(in) :: idim
165  integer :: hxO^L, kxC^L, iw
166  double precision :: inv_volume(ixI^S)
167 
168  call mpistop("to do")
169 
170  end subroutine mf_angmomfix
171 
172  subroutine mf_phys_init()
174  use mod_physics
175  use mod_particles, only: particles_init, particles_eta, particles_etah
176  {^nooned
178  }
179 
180  integer :: itr, idir
181 
182  call mf_read_params(par_files)
183 
184  physics_type = "mf"
185  phys_energy = .false.
187 
188  if(ndim==1) typedivbfix='none'
189  select case (typedivbfix)
190  case ('none')
191  type_divb = divb_none
192  {^nooned
193  case ('multigrid')
194  type_divb = divb_multigrid
195  use_multigrid = .true.
196  mg%operator_type = mg_laplacian
198  }
199  case ('glm')
200  mf_glm = .true.
201  need_global_cmax = .true.
202  type_divb = divb_glm
203  case ('powel', 'powell')
204  type_divb = divb_powel
205  case ('janhunen')
206  type_divb = divb_janhunen
207  case ('linde')
208  type_divb = divb_linde
209  case ('lindejanhunen')
210  type_divb = divb_lindejanhunen
211  case ('lindepowel')
212  type_divb = divb_lindepowel
213  case ('lindeglm')
214  mf_glm = .true.
215  need_global_cmax = .true.
216  type_divb = divb_lindeglm
217  case ('ct')
218  type_divb = divb_ct
219  stagger_grid = .true.
220  case default
221  call mpistop('Unknown divB fix')
222  end select
223 
224  ! Whether diagonal ghost cells are required for the physics
225  if(type_divb < divb_linde) phys_req_diagonal = .false.
226 
227  ! set velocity field as flux variables
228  allocate(mom(ndir))
229  mom(:) = var_set_momentum(ndir)
230 
231  ! set magnetic field as flux variables
232  allocate(mag(ndir))
233  mag(:) = var_set_bfield(ndir)
234 
235  ! start with magnetic field and skip velocity when update ghostcells
236  iwstart=mag(1)
237  allocate(start_indices(number_species),stop_indices(number_species))
238  ! set the index of the first flux variable for species 1
239  start_indices(1)=mag(1)
240 
241  if (mf_glm) then
242  psi_ = var_set_fluxvar('psi', 'psi', need_bc=.false.)
243  else
244  psi_ = -1
245  end if
246 
247  ! set number of variables which need update ghostcells
248  nwgc=nwflux-ndir
249 
250  ! set the index of the last flux variable for species 1
251  stop_indices(1)=nwflux
252 
253  ! determine number of stagger variables
254  if(stagger_grid) nws=ndim
255 
256  nvector = 2 ! No. vector vars
257  allocate(iw_vector(nvector))
258  iw_vector(1) = mom(1) - 1 ! TODO: why like this?
259  iw_vector(2) = mag(1) - 1 ! TODO: why like this?
260 
261  ! Check whether custom flux types have been defined
262  if (.not. allocated(flux_type)) then
263  allocate(flux_type(ndir, nw))
265  else if (any(shape(flux_type) /= [ndir, nw])) then
266  call mpistop("phys_check error: flux_type has wrong shape")
267  end if
268  do idir=1,ndir
269  if(ndim>1) flux_type(idir,mag(idir))=flux_tvdlf
270  end do
271  if(mf_glm .and. ndim>1) flux_type(:,psi_)=flux_tvdlf
272 
286 
287  if(type_divb==divb_glm) then
289  end if
290 
291  ! pass to global variable to record electric field
293 
294  ! Initialize particles module
295  if(mf_particles) then
296  call particles_init()
297  phys_req_diagonal = .true.
298  ! never allow Hall effects in particles when doing magnetofrictional
299  particles_etah=0.0d0
300  if(mype==0) then
301  write(*,*) '*****Using particles: with mf_eta, mf_eta_hyper :', mf_eta, mf_eta_hyper
302  write(*,*) '*****Using particles: particles_eta, particles_etah :', particles_eta, particles_etah
303  end if
304  end if
305 
306  ! if using ct stagger grid, boundary divb=0 is not done here
307  if(stagger_grid) then
311  else if(ndim>1) then
313  end if
314 
315  {^nooned
316  ! clean initial divb
318  }
319 
320  ! derive units from basic units
321  call mf_physical_units()
322 
323  end subroutine mf_phys_init
324 
325  subroutine mf_check_params
327 
328  end subroutine mf_check_params
329 
330  subroutine mf_physical_units()
332  double precision :: mp,kB,miu0,c_lightspeed
333  ! Derive scaling units
334  if(si_unit) then
335  mp=mp_si
336  kb=kb_si
337  miu0=miu0_si
338  c_lightspeed=c_si
339  else
340  mp=mp_cgs
341  kb=kb_cgs
342  miu0=4.d0*dpi
343  c_lightspeed=const_c
344  end if
345  if(unit_density/=1.d0) then
347  else
348  ! unit of numberdensity is independent by default
350  end if
351  if(unit_velocity/=1.d0) then
355  else if(unit_pressure/=1.d0) then
359  else if(unit_magneticfield/=1.d0) then
363  else
364  ! unit of temperature is independent by default
368  end if
369  if(unit_time/=1.d0) then
371  else
372  ! unit of length is independent by default
374  end if
375  ! Additional units needed for the particles
376  c_norm=c_lightspeed/unit_velocity
378  if (.not. si_unit) unit_charge = unit_charge*const_c
380 
381  ! get dimensionless mf nu
383 
384  ! get dimensionless maximal mf velocity limit
386 
387  end subroutine mf_physical_units
388 
389  !> Transform primitive variables into conservative ones
390  subroutine mf_to_conserved(ixI^L,ixO^L,w,x)
392  integer, intent(in) :: ixi^l, ixo^l
393  double precision, intent(inout) :: w(ixi^s, nw)
394  double precision, intent(in) :: x(ixi^s, 1:ndim)
395 
396  ! nothing to do for mf
397  end subroutine mf_to_conserved
398 
399  !> Transform conservative variables into primitive ones
400  subroutine mf_to_primitive(ixI^L,ixO^L,w,x)
402  integer, intent(in) :: ixi^l, ixo^l
403  double precision, intent(inout) :: w(ixi^s, nw)
404  double precision, intent(in) :: x(ixi^s, 1:ndim)
405 
406  ! nothing to do for mf
407  end subroutine mf_to_primitive
408 
409  !> Calculate v vector
410  subroutine mf_get_v(w,x,ixI^L,ixO^L,v)
412 
413  integer, intent(in) :: ixi^l, ixo^l
414  double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
415  double precision, intent(out) :: v(ixi^s,ndir)
416 
417  integer :: idir
418 
419  do idir=1,ndir
420  v(ixo^s,idir) = w(ixo^s, mom(idir))
421  end do
422 
423  end subroutine mf_get_v
424 
425  !> Calculate v component
426  subroutine mf_get_v_idim(w,x,ixI^L,ixO^L,idim,v)
428 
429  integer, intent(in) :: ixi^l, ixo^l, idim
430  double precision, intent(in) :: w(ixi^s,nw), x(ixi^s,1:ndim)
431  double precision, intent(out) :: v(ixi^s)
432 
433  v(ixo^s) = w(ixo^s, mom(idim))
434 
435  end subroutine mf_get_v_idim
436 
437  !> Calculate cmax_idim=csound+abs(v_idim) within ixO^L
438  subroutine mf_get_cmax(w,x,ixI^L,ixO^L,idim,cmax)
440 
441  integer, intent(in) :: ixI^L, ixO^L, idim
442  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
443  double precision, intent(inout) :: cmax(ixI^S)
444 
445  cmax(ixo^s)=abs(w(ixo^s,mom(idim)))+one
446 
447  end subroutine mf_get_cmax
448 
449  !> Estimating bounds for the minimum and maximum signal velocities
450  subroutine mf_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
452  use mod_variables
453 
454  integer, intent(in) :: ixI^L, ixO^L, idim
455  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
456  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
457  double precision, intent(in) :: x(ixI^S,1:ndim)
458  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
459  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
460  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
461 
462  double precision, dimension(ixI^S) :: tmp1
463 
464  tmp1(ixo^s)=0.5d0*(wlc(ixo^s,mom(idim))+wrc(ixo^s,mom(idim)))
465  if(present(cmin)) then
466  cmax(ixo^s,1)=max(tmp1(ixo^s)+one,zero)
467  cmin(ixo^s,1)=min(tmp1(ixo^s)-one,zero)
468  else
469  cmax(ixo^s,1)=abs(tmp1(ixo^s))+one
470  end if
471 
472  end subroutine mf_get_cbounds
473 
474  !> prepare velocities for ct methods
475  subroutine mf_get_ct_velocity(vcts,wLp,wRp,ixI^L,ixO^L,idim,cmax,cmin)
477 
478  integer, intent(in) :: ixI^L, ixO^L, idim
479  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
480  double precision, intent(in) :: cmax(ixI^S)
481  double precision, intent(in), optional :: cmin(ixI^S)
482  type(ct_velocity), intent(inout):: vcts
483 
484  integer :: idimE,idimN
485 
486  ! calculate velocities related to different UCT schemes
487  select case(type_ct)
488  case('average')
489  case('uct_contact')
490  if(.not.allocated(vcts%vnorm)) allocate(vcts%vnorm(ixi^s,1:ndim))
491  ! get average normal velocity at cell faces
492  vcts%vnorm(ixo^s,idim)=0.5d0*(wlp(ixo^s,mom(idim))+wrp(ixo^s,mom(idim)))
493  case('uct_hll')
494  if(.not.allocated(vcts%vbarC)) then
495  allocate(vcts%vbarC(ixi^s,1:ndir,2),vcts%vbarLC(ixi^s,1:ndir,2),vcts%vbarRC(ixi^s,1:ndir,2))
496  allocate(vcts%cbarmin(ixi^s,1:ndim),vcts%cbarmax(ixi^s,1:ndim))
497  end if
498  ! Store magnitude of characteristics
499  if(present(cmin)) then
500  vcts%cbarmin(ixo^s,idim)=max(-cmin(ixo^s),zero)
501  vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
502  else
503  vcts%cbarmax(ixo^s,idim)=max( cmax(ixo^s),zero)
504  vcts%cbarmin(ixo^s,idim)=vcts%cbarmax(ixo^s,idim)
505  end if
506 
507  idimn=mod(idim,ndir)+1 ! 'Next' direction
508  idime=mod(idim+1,ndir)+1 ! Electric field direction
509  ! Store velocities
510  vcts%vbarLC(ixo^s,idim,1)=wlp(ixo^s,mom(idimn))
511  vcts%vbarRC(ixo^s,idim,1)=wrp(ixo^s,mom(idimn))
512  vcts%vbarC(ixo^s,idim,1)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,1) &
513  +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
514  /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
515 
516  vcts%vbarLC(ixo^s,idim,2)=wlp(ixo^s,mom(idime))
517  vcts%vbarRC(ixo^s,idim,2)=wrp(ixo^s,mom(idime))
518  vcts%vbarC(ixo^s,idim,2)=(vcts%cbarmax(ixo^s,idim)*vcts%vbarLC(ixo^s,idim,2) &
519  +vcts%cbarmin(ixo^s,idim)*vcts%vbarRC(ixo^s,idim,1))&
520  /(vcts%cbarmax(ixo^s,idim)+vcts%cbarmin(ixo^s,idim))
521  case default
522  call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
523  end select
524 
525  end subroutine mf_get_ct_velocity
526 
527  !> Calculate total pressure within ixO^L including magnetic pressure
528  subroutine mf_get_p_total(w,x,ixI^L,ixO^L,p)
530 
531  integer, intent(in) :: ixI^L, ixO^L
532  double precision, intent(in) :: w(ixI^S,nw)
533  double precision, intent(in) :: x(ixI^S,1:ndim)
534  double precision, intent(out) :: p(ixI^S)
535 
536  p(ixo^s) = 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
537 
538  end subroutine mf_get_p_total
539 
540  !> Calculate fluxes within ixO^L.
541  subroutine mf_get_flux(wC,w,x,ixI^L,ixO^L,idim,f)
543  use mod_usr_methods
544  use mod_geometry
545 
546  integer, intent(in) :: ixI^L, ixO^L, idim
547  ! conservative w
548  double precision, intent(in) :: wC(ixI^S,nw)
549  ! primitive w
550  double precision, intent(in) :: w(ixI^S,nw)
551  double precision, intent(in) :: x(ixI^S,1:ndim)
552  double precision,intent(out) :: f(ixI^S,nwflux)
553 
554  integer :: idir
555 
556  ! flux of velocity field is zero, frictional velocity is given in addsource2
557  f(ixo^s,mom(:))=0.d0
558 
559  ! compute flux of magnetic field
560  ! f_i[b_k]=v_i*b_k-v_k*b_i
561  do idir=1,ndir
562  if (idim==idir) then
563  ! f_i[b_i] should be exactly 0, so we do not use the transport flux
564  if (mf_glm) then
565  f(ixo^s,mag(idir))=w(ixo^s,psi_)
566  else
567  f(ixo^s,mag(idir))=zero
568  end if
569  else
570  f(ixo^s,mag(idir))=w(ixo^s,mom(idim))*w(ixo^s,mag(idir))-w(ixo^s,mag(idim))*w(ixo^s,mom(idir))
571  end if
572  end do
573 
574  if (mf_glm) then
575  !f_i[psi]=Ch^2*b_{i} Eq. 24e and Eq. 38c Dedner et al 2002 JCP, 175, 645
576  f(ixo^s,psi_) = cmax_global**2*w(ixo^s,mag(idim))
577  end if
578 
579  end subroutine mf_get_flux
580 
581  !> Add global source terms to update frictional velocity on complete domain
582  subroutine mf_velocity_update(qt,psa)
585  double precision, intent(in) :: qt !< Current time
586  type(state), target :: psa(max_blocks) !< Compute based on this state
587 
588  integer :: iigrid,igrid
589  logical :: stagger_flag
590  logical :: firstmf=.true.
591 
592  if(firstmf) then
593  ! point bc mpi datatype to partial type for velocity field
601  firstmf=.false.
602  end if
603 
604  !$OMP PARALLEL DO PRIVATE(igrid)
605  do iigrid=1,igridstail_active; igrid=igrids_active(iigrid);
606  block=>psa(igrid)
607  call frictional_velocity(psa(igrid)%w,psa(igrid)%x,ixg^ll,ixm^ll)
608  end do
609  !$OMP END PARALLEL DO
610 
611  ! only update mf velocity in ghost cells
612  stagger_flag=stagger_grid
619  bcphys=.false.
620  stagger_grid=.false.
621  call getbc(qt,0.d0,psa,mom(1),ndir,.true.)
622  bcphys=.true.
629  stagger_grid=stagger_flag
630 
631  end subroutine mf_velocity_update
632 
633  !> w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
634  subroutine mf_add_source(qdt,ixI^L,ixO^L,wCT,w,x,qsourcesplit,active,wCTprim)
636 
637  integer, intent(in) :: ixI^L, ixO^L
638  double precision, intent(in) :: qdt
639  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
640  double precision, intent(inout) :: w(ixI^S,1:nw)
641  logical, intent(in) :: qsourcesplit
642  logical, intent(inout) :: active
643  double precision, intent(in), optional :: wCTprim(ixI^S,1:nw)
644 
645  if (.not. qsourcesplit) then
646 
647  ! Sources for resistivity in eqs. for e, B1, B2 and B3
648  if (abs(mf_eta)>smalldouble)then
649  active = .true.
650  call add_source_res2(qdt,ixi^l,ixo^l,wct,w,x)
651  end if
652 
653  if (mf_eta_hyper>0.d0)then
654  active = .true.
655  call add_source_hyperres(qdt,ixi^l,ixo^l,wct,w,x)
656  end if
657 
658  end if
659 
660  {^nooned
661  if(.not.source_split_divb .and. .not.qsourcesplit .and. istep==nstep) then
662  ! Sources related to div B
663  select case (type_divb)
664  case (divb_none)
665  ! Do nothing
666  case (divb_glm)
667  active = .true.
668  call add_source_glm(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
669  case (divb_powel)
670  active = .true.
671  call add_source_powel(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
672  case (divb_janhunen)
673  active = .true.
674  call add_source_janhunen(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
675  case (divb_linde)
676  active = .true.
677  call add_source_linde(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
678  case (divb_lindejanhunen)
679  active = .true.
680  call add_source_linde(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
681  call add_source_janhunen(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
682  case (divb_lindepowel)
683  active = .true.
684  call add_source_linde(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
685  call add_source_powel(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
686  case (divb_lindeglm)
687  active = .true.
688  call add_source_linde(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
689  call add_source_glm(dt,ixi^l,ixo^l,pso(block%igrid)%w,w,x)
690  case (divb_ct)
691  continue ! Do nothing
692  case (divb_multigrid)
693  continue ! Do nothing
694  case default
695  call mpistop('Unknown divB fix')
696  end select
697  else if(source_split_divb .and. qsourcesplit) then
698  ! Sources related to div B
699  select case (type_divb)
700  case (divb_none)
701  ! Do nothing
702  case (divb_glm)
703  active = .true.
704  call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
705  case (divb_powel)
706  active = .true.
707  call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
708  case (divb_janhunen)
709  active = .true.
710  call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
711  case (divb_linde)
712  active = .true.
713  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
714  case (divb_lindejanhunen)
715  active = .true.
716  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
717  call add_source_janhunen(qdt,ixi^l,ixo^l,wct,w,x)
718  case (divb_lindepowel)
719  active = .true.
720  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
721  call add_source_powel(qdt,ixi^l,ixo^l,wct,w,x)
722  case (divb_lindeglm)
723  active = .true.
724  call add_source_linde(qdt,ixi^l,ixo^l,wct,w,x)
725  call add_source_glm(qdt,ixi^l,ixo^l,wct,w,x)
726  case (divb_ct)
727  continue ! Do nothing
728  case (divb_multigrid)
729  continue ! Do nothing
730  case default
731  call mpistop('Unknown divB fix')
732  end select
733  end if
734  }
735 
736  end subroutine mf_add_source
737 
738  subroutine frictional_velocity(w,x,ixI^L,ixO^L)
740 
741  integer, intent(in) :: ixI^L, ixO^L
742  double precision, intent(in) :: x(ixI^S,1:ndim)
743  double precision, intent(inout) :: w(ixI^S,1:nw)
744 
745  double precision :: xmin(ndim),xmax(ndim)
746  double precision :: decay(ixO^S)
747  double precision :: current(ixI^S,7-2*ndir:3),tmp(ixO^S)
748  integer :: ix^D, idirmin,idir,jdir,kdir
749 
750  call get_current(w,ixi^l,ixo^l,idirmin,current)
751  ! extrapolate current for the outmost layer,
752  ! because extrapolation of B at boundaries introduces artificial current
753 {
754  if(block%is_physical_boundary(2*^d-1)) then
755  current(ixomin^d^d%ixO^s,:)=current(ixomin^d+1^d%ixO^s,:)
756  end if
757  if(block%is_physical_boundary(2*^d)) then
758  current(ixomax^d^d%ixO^s,:)=current(ixomax^d-1^d%ixO^s,:)
759  end if
760 \}
761  w(ixo^s,mom(:))=0.d0
762  ! calculate Lorentz force
763  do idir=1,ndir; do jdir=idirmin,3; do kdir=1,ndir
764  if(lvc(idir,jdir,kdir)/=0) then
765  if(lvc(idir,jdir,kdir)==1) then
766  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))+current(ixo^s,jdir)*w(ixo^s,mag(kdir))
767  else
768  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))-current(ixo^s,jdir)*w(ixo^s,mag(kdir))
769  end if
770  end if
771  end do; end do; end do
772 
773  tmp(ixo^s)=sum(w(ixo^s,mag(:))**2,dim=ndim+1)
774  ! frictional coefficient
775  where(tmp(ixo^s)/=0.d0)
776  tmp(ixo^s)=1.d0/(tmp(ixo^s)*mf_nu)
777  endwhere
778 
779  do idir=1,ndir
780  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))*tmp(ixo^s)
781  end do
782 
783  ! decay frictional velocity near selected boundaries
784  ^d&xmin(^d)=xprobmin^d\
785  ^d&xmax(^d)=xprobmax^d\
786  decay(ixo^s)=1.d0
787  do idir=1,ndim
788  if(mf_decay_scale(2*idir-1)>0.d0) decay(ixo^s)=decay(ixo^s)*&
789  (1.d0-exp(-(x(ixo^s,idir)-xmin(idir))/mf_decay_scale(2*idir-1)))
790  if(mf_decay_scale(2*idir)>0.d0) decay(ixo^s)=decay(ixo^s)*&
791  (1.d0-exp((x(ixo^s,idir)-xmax(idir))/mf_decay_scale(2*idir)))
792  end do
793 
794  ! saturate mf velocity at mf_vmax
795  tmp(ixo^s)=sqrt(sum(w(ixo^s,mom(:))**2,dim=ndim+1))/mf_vmax+1.d-12
796  tmp(ixo^s)=dtanh(tmp(ixo^s))/tmp(ixo^s)
797  do idir=1,ndir
798  w(ixo^s,mom(idir))=w(ixo^s,mom(idir))*tmp(ixo^s)*decay(ixo^s)
799  end do
800 
801  end subroutine frictional_velocity
802 
803  !> Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in
804  !> each direction, non-conservative. If the fourthorder precompiler flag is
805  !> set, uses fourth order central difference for the laplacian. Then the
806  !> stencil is 5 (2 neighbours).
807  subroutine add_source_res1(qdt,ixI^L,ixO^L,wCT,w,x)
809  use mod_usr_methods
810  use mod_geometry
811 
812  integer, intent(in) :: ixI^L, ixO^L
813  double precision, intent(in) :: qdt
814  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
815  double precision, intent(inout) :: w(ixI^S,1:nw)
816  integer :: ixA^L,idir,jdir,kdir,idirmin,idim,jxO^L,hxO^L,ix
817  integer :: lxO^L, kxO^L
818 
819  double precision :: tmp(ixI^S),tmp2(ixI^S)
820 
821  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
822  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S)
823  double precision :: gradeta(ixI^S,1:ndim), Bf(ixI^S,1:ndir)
824 
825  ! Calculating resistive sources involve one extra layer
826  if (mf_4th_order) then
827  ixa^l=ixo^l^ladd2;
828  else
829  ixa^l=ixo^l^ladd1;
830  end if
831 
832  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
833  call mpistop("Error in add_source_res1: Non-conforming input limits")
834 
835  ! Calculate current density and idirmin
836  call get_current(wct,ixi^l,ixo^l,idirmin,current)
837 
838  if (mf_eta>zero)then
839  eta(ixa^s)=mf_eta
840  gradeta(ixo^s,1:ndim)=zero
841  else
842  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
843  ! assumes that eta is not function of current?
844  do idim=1,ndim
845  call gradient(eta,ixi^l,ixo^l,idim,tmp)
846  gradeta(ixo^s,idim)=tmp(ixo^s)
847  end do
848  end if
849 
850  bf(ixi^s,1:ndir)=wct(ixi^s,mag(1:ndir))
851 
852  do idir=1,ndir
853  ! Put B_idir into tmp2 and eta*Laplace B_idir into tmp
854  if (mf_4th_order) then
855  tmp(ixo^s)=zero
856  tmp2(ixi^s)=bf(ixi^s,idir)
857  do idim=1,ndim
858  lxo^l=ixo^l+2*kr(idim,^d);
859  jxo^l=ixo^l+kr(idim,^d);
860  hxo^l=ixo^l-kr(idim,^d);
861  kxo^l=ixo^l-2*kr(idim,^d);
862  tmp(ixo^s)=tmp(ixo^s)+&
863  (-tmp2(lxo^s)+16.0d0*tmp2(jxo^s)-30.0d0*tmp2(ixo^s)+16.0d0*tmp2(hxo^s)-tmp2(kxo^s)) &
864  /(12.0d0 * dxlevel(idim)**2)
865  end do
866  else
867  tmp(ixo^s)=zero
868  tmp2(ixi^s)=bf(ixi^s,idir)
869  do idim=1,ndim
870  jxo^l=ixo^l+kr(idim,^d);
871  hxo^l=ixo^l-kr(idim,^d);
872  tmp(ixo^s)=tmp(ixo^s)+&
873  (tmp2(jxo^s)-2.0d0*tmp2(ixo^s)+tmp2(hxo^s))/dxlevel(idim)**2
874  end do
875  end if
876 
877  ! Multiply by eta
878  tmp(ixo^s)=tmp(ixo^s)*eta(ixo^s)
879 
880  ! Subtract grad(eta) x J = eps_ijk d_j eta J_k if eta is non-constant
881  if (mf_eta<zero)then
882  do jdir=1,ndim; do kdir=idirmin,3
883  if (lvc(idir,jdir,kdir)/=0)then
884  if (lvc(idir,jdir,kdir)==1)then
885  tmp(ixo^s)=tmp(ixo^s)-gradeta(ixo^s,jdir)*current(ixo^s,kdir)
886  else
887  tmp(ixo^s)=tmp(ixo^s)+gradeta(ixo^s,jdir)*current(ixo^s,kdir)
888  end if
889  end if
890  end do; end do
891  end if
892 
893  ! Add sources related to eta*laplB-grad(eta) x J to B and e
894  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))+qdt*tmp(ixo^s)
895 
896  end do ! idir
897 
898  end subroutine add_source_res1
899 
900  !> Add resistive source to w within ixO
901  !> Uses 5 point stencil (2 neighbours) in each direction, conservative
902  subroutine add_source_res2(qdt,ixI^L,ixO^L,wCT,w,x)
904  use mod_usr_methods
905  use mod_geometry
906 
907  integer, intent(in) :: ixI^L, ixO^L
908  double precision, intent(in) :: qdt
909  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
910  double precision, intent(inout) :: w(ixI^S,1:nw)
911 
912  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
913  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S),curlj(ixI^S,1:3)
914  double precision :: tmpvec(ixI^S,1:3)
915  integer :: ixA^L,idir,idirmin,idirmin1
916 
917  ! resistive term already added as an electric field component
918  if(stagger_grid .and. ndim==ndir) return
919 
920  ixa^l=ixo^l^ladd2;
921 
922  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
923  call mpistop("Error in add_source_res2: Non-conforming input limits")
924 
925  ixa^l=ixo^l^ladd1;
926  ! Calculate current density within ixL: J=curl B, thus J_i=eps_ijk*d_j B_k
927  ! Determine exact value of idirmin while doing the loop.
928  call get_current(wct,ixi^l,ixa^l,idirmin,current)
929 
930  if (mf_eta>zero)then
931  eta(ixa^s)=mf_eta
932  else
933  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,current,eta)
934  end if
935 
936  ! dB/dt= -curl(J*eta), thus B_i=B_i-eps_ijk d_j Jeta_k
937  tmpvec(ixa^s,1:ndir)=zero
938  do idir=idirmin,3
939  tmpvec(ixa^s,idir)=current(ixa^s,idir)*eta(ixa^s)
940  end do
941  curlj=0.d0
942  call curlvector(tmpvec,ixi^l,ixo^l,curlj,idirmin1,1,3)
943  if(stagger_grid) then
944  if(ndim==2.and.ndir==3) then
945  ! if 2.5D
946  w(ixo^s,mag(ndir)) = w(ixo^s,mag(ndir))-qdt*curlj(ixo^s,ndir)
947  end if
948  else
949  w(ixo^s,mag(1:ndir)) = w(ixo^s,mag(1:ndir))-qdt*curlj(ixo^s,1:ndir)
950  end if
951 
952  end subroutine add_source_res2
953 
954  !> Add Hyper-resistive source to w within ixO
955  !> Uses 9 point stencil (4 neighbours) in each direction.
956  subroutine add_source_hyperres(qdt,ixI^L,ixO^L,wCT,w,x)
958  use mod_geometry
959 
960  integer, intent(in) :: ixI^L, ixO^L
961  double precision, intent(in) :: qdt
962  double precision, intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
963  double precision, intent(inout) :: w(ixI^S,1:nw)
964  !.. local ..
965  double precision :: current(ixI^S,7-2*ndir:3)
966  double precision :: tmpvec(ixI^S,1:3),tmpvec2(ixI^S,1:3),tmp(ixI^S),ehyper(ixI^S,1:3)
967  integer :: ixA^L,idir,jdir,kdir,idirmin,idirmin1
968 
969  ixa^l=ixo^l^ladd3;
970  if (iximin^d>ixamin^d.or.iximax^d<ixamax^d|.or.) &
971  call mpistop("Error in add_source_hyperres: Non-conforming input limits")
972 
973  call get_current(wct,ixi^l,ixa^l,idirmin,current)
974  tmpvec(ixa^s,1:ndir)=zero
975  do jdir=idirmin,3
976  tmpvec(ixa^s,jdir)=current(ixa^s,jdir)
977  end do
978 
979  ixa^l=ixo^l^ladd2;
980  call curlvector(tmpvec,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
981 
982  ixa^l=ixo^l^ladd1;
983  tmpvec(ixa^s,1:ndir)=zero
984  call curlvector(tmpvec2,ixi^l,ixa^l,tmpvec,idirmin1,1,3)
985  ehyper(ixa^s,1:ndir) = - tmpvec(ixa^s,1:ndir)*mf_eta_hyper
986 
987  ixa^l=ixo^l;
988  tmpvec2(ixa^s,1:ndir)=zero
989  call curlvector(ehyper,ixi^l,ixa^l,tmpvec2,idirmin1,1,3)
990 
991  do idir=1,ndir
992  w(ixo^s,mag(idir)) = w(ixo^s,mag(idir))-tmpvec2(ixo^s,idir)*qdt
993  end do
994 
995  end subroutine add_source_hyperres
996 
997  subroutine add_source_glm(qdt,ixI^L,ixO^L,wCT,w,x)
998  ! Add divB related sources to w within ixO
999  ! corresponding to Dedner JCP 2002, 175, 645 _equation 24_
1000  ! giving the EGLM-MHD scheme
1002  use mod_geometry
1003 
1004  integer, intent(in) :: ixI^L, ixO^L
1005  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
1006  double precision, intent(inout) :: w(ixI^S,1:nw)
1007  double precision:: divb(ixI^S)
1008  integer :: idim,idir
1009  double precision :: gradPsi(ixI^S)
1010 
1011  ! We calculate now div B
1012  call get_divb(wct,ixi^l,ixo^l,divb, mf_divb_4thorder)
1013 
1014  ! dPsi/dt = - Ch^2/Cp^2 Psi
1015  if (mf_glm_alpha < zero) then
1016  w(ixo^s,psi_) = abs(mf_glm_alpha)*wct(ixo^s,psi_)
1017  else
1018  ! implicit update of Psi variable
1019  ! equation (27) in Mignone 2010 J. Com. Phys. 229, 2117
1020  if(slab_uniform) then
1021  w(ixo^s,psi_) = dexp(-qdt*cmax_global*mf_glm_alpha/minval(dxlevel(:)))*w(ixo^s,psi_)
1022  else
1023  w(ixo^s,psi_) = dexp(-qdt*cmax_global*mf_glm_alpha/minval(block%ds(ixo^s,:),dim=ndim+1))*w(ixo^s,psi_)
1024  end if
1025  end if
1026 
1027  ! gradient of Psi
1028  do idim=1,ndim
1029  select case(typegrad)
1030  case("central")
1031  call gradient(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
1032  case("limited")
1033  call gradients(wct(ixi^s,psi_),ixi^l,ixo^l,idim,gradpsi)
1034  end select
1035  end do
1036 
1037  end subroutine add_source_glm
1038 
1039  !> Add divB related sources to w within ixO corresponding to Powel
1040  subroutine add_source_powel(qdt,ixI^L,ixO^L,wCT,w,x)
1042 
1043  integer, intent(in) :: ixI^L, ixO^L
1044  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
1045  double precision, intent(inout) :: w(ixI^S,1:nw)
1046  double precision :: divb(ixI^S),v(ixI^S,1:ndir)
1047  integer :: idir
1048 
1049  ! We calculate now div B
1050  call get_divb(wct,ixi^l,ixo^l,divb, mf_divb_4thorder)
1051 
1052  ! calculate velocity
1053  call mf_get_v(wct,x,ixi^l,ixo^l,v)
1054 
1055  ! b = b - qdt v * div b
1056  do idir=1,ndir
1057  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*v(ixo^s,idir)*divb(ixo^s)
1058  end do
1059 
1060  end subroutine add_source_powel
1061 
1062  subroutine add_source_janhunen(qdt,ixI^L,ixO^L,wCT,w,x)
1063  ! Add divB related sources to w within ixO
1064  ! corresponding to Janhunen, just the term in the induction equation.
1066 
1067  integer, intent(in) :: ixI^L, ixO^L
1068  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
1069  double precision, intent(inout) :: w(ixI^S,1:nw)
1070  double precision :: divb(ixI^S),v(ixI^S,1:ndir)
1071  integer :: idir
1072 
1073  ! We calculate now div B
1074  call get_divb(wct,ixi^l,ixo^l,divb, mf_divb_4thorder)
1075 
1076  ! calculate velocity
1077  call mf_get_v(wct,x,ixi^l,ixo^l,v)
1078 
1079  ! b = b - qdt v * div b
1080  do idir=1,ndir
1081  w(ixo^s,mag(idir))=w(ixo^s,mag(idir))-qdt*v(ixo^s,idir)*divb(ixo^s)
1082  end do
1083 
1084  end subroutine add_source_janhunen
1085 
1086  subroutine add_source_linde(qdt,ixI^L,ixO^L,wCT,w,x)
1087  ! Add Linde's divB related sources to wnew within ixO
1089  use mod_geometry
1090 
1091  integer, intent(in) :: ixI^L, ixO^L
1092  double precision, intent(in) :: qdt, wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
1093  double precision, intent(inout) :: w(ixI^S,1:nw)
1094  integer :: idim, idir, ixp^L, i^D, iside
1095  double precision :: divb(ixI^S),graddivb(ixI^S)
1096  logical, dimension(-1:1^D&) :: leveljump
1097 
1098  ! Calculate div B
1099  ixp^l=ixo^l^ladd1;
1100  call get_divb(wct,ixi^l,ixp^l,divb, mf_divb_4thorder)
1101 
1102  ! for AMR stability, retreat one cell layer from the boarders of level jump
1103  {do i^db=-1,1\}
1104  if(i^d==0|.and.) cycle
1105  if(neighbor_type(i^d,block%igrid)==2 .or. neighbor_type(i^d,block%igrid)==4) then
1106  leveljump(i^d)=.true.
1107  else
1108  leveljump(i^d)=.false.
1109  end if
1110  {end do\}
1111 
1112  ixp^l=ixo^l;
1113  do idim=1,ndim
1114  select case(idim)
1115  {case(^d)
1116  do iside=1,2
1117  i^dd=kr(^dd,^d)*(2*iside-3);
1118  if (leveljump(i^dd)) then
1119  if (iside==1) then
1120  ixpmin^d=ixomin^d-i^d
1121  else
1122  ixpmax^d=ixomax^d-i^d
1123  end if
1124  end if
1125  end do
1126  \}
1127  end select
1128  end do
1129 
1130  ! Add Linde's diffusive terms
1131  do idim=1,ndim
1132  ! Calculate grad_idim(divb)
1133  select case(typegrad)
1134  case("central")
1135  call gradient(divb,ixi^l,ixp^l,idim,graddivb)
1136  case("limited")
1137  call gradients(divb,ixi^l,ixp^l,idim,graddivb)
1138  end select
1139 
1140  ! Multiply by Linde's eta*dt = divbdiff*(c_max*dx)*dt = divbdiff*dx**2
1141  if (slab_uniform) then
1142  graddivb(ixp^s)=graddivb(ixp^s)*divbdiff/(^d&1.0d0/dxlevel(^d)**2+)
1143  else
1144  graddivb(ixp^s)=graddivb(ixp^s)*divbdiff &
1145  /(^d&1.0d0/block%ds(ixp^s,^d)**2+)
1146  end if
1147 
1148  w(ixp^s,mag(idim))=w(ixp^s,mag(idim))+graddivb(ixp^s)
1149  end do
1150 
1151  end subroutine add_source_linde
1152 
1153  !> Calculate div B within ixO
1154  subroutine get_divb(w,ixI^L,ixO^L,divb, fourthorder)
1156  use mod_geometry
1157 
1158  integer, intent(in) :: ixi^l, ixo^l
1159  double precision, intent(in) :: w(ixi^s,1:nw)
1160  double precision, intent(inout) :: divb(ixi^s)
1161  logical, intent(in), optional :: fourthorder
1162 
1163  integer :: ixc^l, idir
1164 
1165  if(stagger_grid) then
1166  divb(ixo^s)=0.d0
1167  do idir=1,ndim
1168  ixc^l=ixo^l-kr(idir,^d);
1169  divb(ixo^s)=divb(ixo^s)+block%ws(ixo^s,idir)*block%surfaceC(ixo^s,idir)-&
1170  block%ws(ixc^s,idir)*block%surfaceC(ixc^s,idir)
1171  end do
1172  divb(ixo^s)=divb(ixo^s)/block%dvolume(ixo^s)
1173  else
1174  select case(typediv)
1175  case("central")
1176  call divvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,divb,fourthorder)
1177  case("limited")
1178  call divvectors(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,divb)
1179  end select
1180  end if
1181 
1182  end subroutine get_divb
1183 
1184  !> get dimensionless div B = |divB| * volume / area / |B|
1185  subroutine get_normalized_divb(w,ixI^L,ixO^L,divb)
1186 
1188 
1189  integer, intent(in) :: ixi^l, ixo^l
1190  double precision, intent(in) :: w(ixi^s,1:nw)
1191  double precision :: divb(ixi^s), dsurface(ixi^s)
1192 
1193  double precision :: invb(ixo^s)
1194  integer :: ixa^l,idims
1195 
1196  call get_divb(w,ixi^l,ixo^l,divb)
1197  invb(ixo^s)=sqrt(mf_mag_en_all(w,ixi^l,ixo^l))
1198  where(invb(ixo^s)/=0.d0)
1199  invb(ixo^s)=1.d0/invb(ixo^s)
1200  end where
1201  if(slab_uniform) then
1202  divb(ixo^s)=0.5d0*abs(divb(ixo^s))*invb(ixo^s)/sum(1.d0/dxlevel(:))
1203  else
1204  ixamin^d=ixomin^d-1;
1205  ixamax^d=ixomax^d-1;
1206  dsurface(ixo^s)= sum(block%surfaceC(ixo^s,:),dim=ndim+1)
1207  do idims=1,ndim
1208  ixa^l=ixo^l-kr(idims,^d);
1209  dsurface(ixo^s)=dsurface(ixo^s)+block%surfaceC(ixa^s,idims)
1210  end do
1211  divb(ixo^s)=abs(divb(ixo^s))*invb(ixo^s)*&
1212  block%dvolume(ixo^s)/dsurface(ixo^s)
1213  end if
1214 
1215  end subroutine get_normalized_divb
1216 
1217  !> Calculate idirmin and the idirmin:3 components of the common current array
1218  !> make sure that dxlevel(^D) is set correctly.
1219  subroutine get_current(w,ixI^L,ixO^L,idirmin,current,fourthorder)
1221  use mod_geometry
1222 
1223  integer, intent(in) :: ixo^l, ixi^l
1224  double precision, intent(in) :: w(ixi^s,1:nw)
1225  integer, intent(out) :: idirmin
1226  logical, intent(in), optional :: fourthorder
1227  integer :: idir, idirmin0
1228 
1229  ! For ndir=2 only 3rd component of J can exist, ndir=1 is impossible for MHD
1230  double precision :: current(ixi^s,7-2*ndir:3)
1231 
1232  idirmin0 = 7-2*ndir
1233 
1234  if(present(fourthorder)) then
1235  call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir,fourthorder)
1236  else
1237  call curlvector(w(ixi^s,mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
1238  end if
1239 
1240  end subroutine get_current
1241 
1242  !> If resistivity is not zero, check diffusion time limit for dt
1243  subroutine mf_get_dt(w,ixI^L,ixO^L,dtnew,dx^D,x)
1245  use mod_usr_methods
1246 
1247  integer, intent(in) :: ixI^L, ixO^L
1248  double precision, intent(inout) :: dtnew
1249  double precision, intent(in) :: dx^D
1250  double precision, intent(in) :: w(ixI^S,1:nw)
1251  double precision, intent(in) :: x(ixI^S,1:ndim)
1252 
1253  integer :: idirmin,idim
1254  double precision :: dxarr(ndim)
1255  double precision :: current(ixI^S,7-2*ndir:3),eta(ixI^S)
1256 
1257  dtnew = bigdouble
1258 
1259  ^d&dxarr(^d)=dx^d;
1260  if (mf_eta>zero)then
1261  dtnew=dtdiffpar*minval(dxarr(1:ndim))**2/mf_eta
1262  else if (mf_eta<zero)then
1263  call get_current(w,ixi^l,ixo^l,idirmin,current)
1264  call usr_special_resistivity(w,ixi^l,ixo^l,idirmin,x,current,eta)
1265  dtnew=bigdouble
1266  do idim=1,ndim
1267  if(slab_uniform) then
1268  dtnew=min(dtnew,&
1269  dtdiffpar/(smalldouble+maxval(eta(ixo^s)/dxarr(idim)**2)))
1270  else
1271  dtnew=min(dtnew,&
1272  dtdiffpar/(smalldouble+maxval(eta(ixo^s)/block%ds(ixo^s,idim)**2)))
1273  end if
1274  end do
1275  end if
1276 
1277  if(mf_eta_hyper>zero) then
1278  if(slab_uniform) then
1279  dtnew=min(dtdiffpar*minval(dxarr(1:ndim))**4/mf_eta_hyper,dtnew)
1280  else
1281  dtnew=min(dtdiffpar*minval(block%ds(ixo^s,1:ndim))**4/mf_eta_hyper,dtnew)
1282  end if
1283  end if
1284  end subroutine mf_get_dt
1285 
1286  ! Add geometrical source terms to w
1287  subroutine mf_add_source_geom(qdt,ixI^L,ixO^L,wCT,w,x)
1289  use mod_geometry
1290 
1291  integer, intent(in) :: ixI^L, ixO^L
1292  double precision, intent(in) :: qdt, x(ixI^S,1:ndim)
1293  double precision, intent(inout) :: wCT(ixI^S,1:nw), w(ixI^S,1:nw)
1294 
1295  integer :: iw,idir
1296  double precision :: tmp(ixI^S)
1297 
1298  integer :: mr_,mphi_ ! Polar var. names
1299  integer :: br_,bphi_
1300 
1301  mr_=mom(1); mphi_=mom(1)-1+phi_ ! Polar var. names
1302  br_=mag(1); bphi_=mag(1)-1+phi_
1303 
1304  select case (coordinate)
1305  case (cylindrical)
1306  if (angmomfix) then
1307  call mpistop("angmomfix not implemented yet in MHD")
1308  endif
1309  call mf_get_p_total(wct,x,ixi^l,ixo^l,tmp)
1310  if(phi_>0) then
1311  if(.not.stagger_grid) then
1312  w(ixo^s,bphi_)=w(ixo^s,bphi_)+qdt/x(ixo^s,1)*&
1313  (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
1314  -wct(ixo^s,br_)*wct(ixo^s,mphi_))
1315  end if
1316  end if
1317  if(mf_glm) w(ixo^s,br_)=w(ixo^s,br_)+qdt*wct(ixo^s,psi_)/x(ixo^s,1)
1318  case (spherical)
1319  ! b1
1320  if(mf_glm) then
1321  w(ixo^s,mag(1))=w(ixo^s,mag(1))+qdt/x(ixo^s,1)*2.0d0*wct(ixo^s,psi_)
1322  end if
1323 
1324  {^nooned
1325  ! b2
1326  if(.not.stagger_grid) then
1327  tmp(ixo^s)=wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
1328  -wct(ixo^s,mom(2))*wct(ixo^s,mag(1))
1329  if(mf_glm) then
1330  tmp(ixo^s)=tmp(ixo^s) &
1331  + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
1332  end if
1333  w(ixo^s,mag(2))=w(ixo^s,mag(2))+qdt*tmp(ixo^s)/x(ixo^s,1)
1334  end if
1335  }
1336 
1337  if(ndir==3) then
1338  ! b3
1339  if(.not.stagger_grid) then
1340  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
1341  -wct(ixo^s,mom(3))*wct(ixo^s,mag(1))) {^nooned &
1342  -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
1343  -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
1344  /dsin(x(ixo^s,2)) }
1345  w(ixo^s,mag(3))=w(ixo^s,mag(3))+qdt*tmp(ixo^s)/x(ixo^s,1)
1346  end if
1347  end if
1348  end select
1349 
1350  end subroutine mf_add_source_geom
1351 
1352  !> Compute 2 times total magnetic energy
1353  function mf_mag_en_all(w, ixI^L, ixO^L) result(mge)
1355  integer, intent(in) :: ixi^l, ixo^l
1356  double precision, intent(in) :: w(ixi^s, nw)
1357  double precision :: mge(ixo^s)
1358 
1359  mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
1360  end function mf_mag_en_all
1361 
1362  !> Compute full magnetic field by direction
1363  function mf_mag_i_all(w, ixI^L, ixO^L,idir) result(mgf)
1365  integer, intent(in) :: ixi^l, ixo^l, idir
1366  double precision, intent(in) :: w(ixi^s, nw)
1367  double precision :: mgf(ixo^s)
1368 
1369  mgf = w(ixo^s, mag(idir))
1370  end function mf_mag_i_all
1371 
1372  !> Compute evolving magnetic energy
1373  function mf_mag_en(w, ixI^L, ixO^L) result(mge)
1374  use mod_global_parameters, only: nw, ndim
1375  integer, intent(in) :: ixi^l, ixo^l
1376  double precision, intent(in) :: w(ixi^s, nw)
1377  double precision :: mge(ixo^s)
1378 
1379  mge = 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
1380  end function mf_mag_en
1381 
1382  subroutine mf_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
1384  use mod_usr_methods
1385  integer, intent(in) :: ixI^L, ixO^L, idir
1386  double precision, intent(in) :: qt
1387  double precision, intent(inout) :: wLC(ixI^S,1:nw), wRC(ixI^S,1:nw)
1388  double precision, intent(inout) :: wLp(ixI^S,1:nw), wRp(ixI^S,1:nw)
1389  type(state) :: s
1390  double precision :: dB(ixI^S), dPsi(ixI^S)
1391 
1392  ! Solve the Riemann problem for the linear 2x2 system for normal
1393  ! B-field and GLM_Psi according to Dedner 2002:
1394  ! This implements eq. (42) in Dedner et al. 2002 JcP 175
1395  ! Gives the Riemann solution on the interface
1396  ! for the normal B component and Psi in the GLM-MHD system.
1397  ! 23/04/2013 Oliver Porth
1398  db(ixo^s) = wrp(ixo^s,mag(idir)) - wlp(ixo^s,mag(idir))
1399  dpsi(ixo^s) = wrp(ixo^s,psi_) - wlp(ixo^s,psi_)
1400 
1401  wlp(ixo^s,mag(idir)) = 0.5d0 * (wrp(ixo^s,mag(idir)) + wlp(ixo^s,mag(idir))) &
1402  - 0.5d0/cmax_global * dpsi(ixo^s)
1403  wlp(ixo^s,psi_) = 0.5d0 * (wrp(ixo^s,psi_) + wlp(ixo^s,psi_)) &
1404  - 0.5d0*cmax_global * db(ixo^s)
1405 
1406  wrp(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
1407  wrp(ixo^s,psi_) = wlp(ixo^s,psi_)
1408 
1409  end subroutine mf_modify_wlr
1410 
1411  subroutine mf_boundary_adjust(igrid,psb)
1413  integer, intent(in) :: igrid
1414  type(state), target :: psb(max_blocks)
1415 
1416  integer :: iB, idims, iside, ixO^L, i^D
1417 
1418  block=>ps(igrid)
1419  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1420  do idims=1,ndim
1421  ! to avoid using as yet unknown corner info in more than 1D, we
1422  ! fill only interior mesh ranges of the ghost cell ranges at first,
1423  ! and progressively enlarge the ranges to include corners later
1424  do iside=1,2
1425  i^d=kr(^d,idims)*(2*iside-3);
1426  if (neighbor_type(i^d,igrid)/=1) cycle
1427  ib=(idims-1)*2+iside
1428  if(.not.boundary_divbfix(ib)) cycle
1429  if(any(typeboundary(:,ib)==bc_special)) then
1430  ! MF nonlinear force-free B field extrapolation and data driven
1431  ! require normal B of the first ghost cell layer to be untouched by
1432  ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
1433  select case (idims)
1434  {case (^d)
1435  if (iside==2) then
1436  ! maximal boundary
1437  ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
1438  ixomax^dd=ixghi^dd;
1439  else
1440  ! minimal boundary
1441  ixomin^dd=ixglo^dd;
1442  ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
1443  end if \}
1444  end select
1445  call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
1446  end if
1447  end do
1448  end do
1449 
1450  end subroutine mf_boundary_adjust
1451 
1452  subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
1454 
1455  integer, intent(in) :: ixG^L,ixO^L,iB
1456  double precision, intent(inout) :: w(ixG^S,1:nw)
1457  double precision, intent(in) :: x(ixG^S,1:ndim)
1458 
1459  double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
1460  integer :: ix^D,ixF^L
1461 
1462  select case(ib)
1463  case(1)
1464  ! 2nd order CD for divB=0 to set normal B component better
1465  {^iftwod
1466  ixfmin1=ixomin1+1
1467  ixfmax1=ixomax1+1
1468  ixfmin2=ixomin2+1
1469  ixfmax2=ixomax2-1
1470  if(slab_uniform) then
1471  dx1x2=dxlevel(1)/dxlevel(2)
1472  do ix1=ixfmax1,ixfmin1,-1
1473  w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
1474  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
1475  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
1476  enddo
1477  else
1478  do ix1=ixfmax1,ixfmin1,-1
1479  w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
1480  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
1481  +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
1482  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
1483  -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
1484  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
1485  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
1486  end do
1487  end if
1488  }
1489  {^ifthreed
1490  ixfmin1=ixomin1+1
1491  ixfmax1=ixomax1+1
1492  ixfmin2=ixomin2+1
1493  ixfmax2=ixomax2-1
1494  ixfmin3=ixomin3+1
1495  ixfmax3=ixomax3-1
1496  if(slab_uniform) then
1497  dx1x2=dxlevel(1)/dxlevel(2)
1498  dx1x3=dxlevel(1)/dxlevel(3)
1499  do ix1=ixfmax1,ixfmin1,-1
1500  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1501  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
1502  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
1503  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
1504  +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
1505  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
1506  end do
1507  else
1508  do ix1=ixfmax1,ixfmin1,-1
1509  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1510  ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
1511  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
1512  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
1513  +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
1514  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
1515  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
1516  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
1517  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
1518  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
1519  +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
1520  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
1521  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
1522  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
1523  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1524  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
1525  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
1526  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
1527  end do
1528  end if
1529  }
1530  case(2)
1531  {^iftwod
1532  ixfmin1=ixomin1-1
1533  ixfmax1=ixomax1-1
1534  ixfmin2=ixomin2+1
1535  ixfmax2=ixomax2-1
1536  if(slab_uniform) then
1537  dx1x2=dxlevel(1)/dxlevel(2)
1538  do ix1=ixfmin1,ixfmax1
1539  w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
1540  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
1541  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
1542  enddo
1543  else
1544  do ix1=ixfmin1,ixfmax1
1545  w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
1546  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
1547  -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
1548  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
1549  +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
1550  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
1551  /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
1552  end do
1553  end if
1554  }
1555  {^ifthreed
1556  ixfmin1=ixomin1-1
1557  ixfmax1=ixomax1-1
1558  ixfmin2=ixomin2+1
1559  ixfmax2=ixomax2-1
1560  ixfmin3=ixomin3+1
1561  ixfmax3=ixomax3-1
1562  if(slab_uniform) then
1563  dx1x2=dxlevel(1)/dxlevel(2)
1564  dx1x3=dxlevel(1)/dxlevel(3)
1565  do ix1=ixfmin1,ixfmax1
1566  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1567  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
1568  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
1569  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
1570  -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
1571  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
1572  end do
1573  else
1574  do ix1=ixfmin1,ixfmax1
1575  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1576  ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
1577  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
1578  block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
1579  -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
1580  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
1581  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
1582  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
1583  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
1584  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
1585  -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
1586  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
1587  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
1588  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
1589  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1590  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
1591  /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
1592  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
1593  end do
1594  end if
1595  }
1596  case(3)
1597  {^iftwod
1598  ixfmin1=ixomin1+1
1599  ixfmax1=ixomax1-1
1600  ixfmin2=ixomin2+1
1601  ixfmax2=ixomax2+1
1602  if(slab_uniform) then
1603  dx2x1=dxlevel(2)/dxlevel(1)
1604  do ix2=ixfmax2,ixfmin2,-1
1605  w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
1606  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
1607  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
1608  enddo
1609  else
1610  do ix2=ixfmax2,ixfmin2,-1
1611  w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
1612  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
1613  +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
1614  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
1615  -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
1616  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
1617  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
1618  end do
1619  end if
1620  }
1621  {^ifthreed
1622  ixfmin1=ixomin1+1
1623  ixfmax1=ixomax1-1
1624  ixfmin3=ixomin3+1
1625  ixfmax3=ixomax3-1
1626  ixfmin2=ixomin2+1
1627  ixfmax2=ixomax2+1
1628  if(slab_uniform) then
1629  dx2x1=dxlevel(2)/dxlevel(1)
1630  dx2x3=dxlevel(2)/dxlevel(3)
1631  do ix2=ixfmax2,ixfmin2,-1
1632  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
1633  ix2+1,ixfmin3:ixfmax3,mag(2)) &
1634  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
1635  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
1636  +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
1637  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
1638  end do
1639  else
1640  do ix2=ixfmax2,ixfmin2,-1
1641  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
1642  ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
1643  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
1644  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
1645  +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
1646  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1647  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
1648  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
1649  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1650  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
1651  +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
1652  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
1653  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
1654  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
1655  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1656  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
1657  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
1658  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
1659  end do
1660  end if
1661  }
1662  case(4)
1663  {^iftwod
1664  ixfmin1=ixomin1+1
1665  ixfmax1=ixomax1-1
1666  ixfmin2=ixomin2-1
1667  ixfmax2=ixomax2-1
1668  if(slab_uniform) then
1669  dx2x1=dxlevel(2)/dxlevel(1)
1670  do ix2=ixfmin2,ixfmax2
1671  w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
1672  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
1673  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
1674  end do
1675  else
1676  do ix2=ixfmin2,ixfmax2
1677  w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
1678  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
1679  -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
1680  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
1681  +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
1682  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
1683  /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
1684  end do
1685  end if
1686  }
1687  {^ifthreed
1688  ixfmin1=ixomin1+1
1689  ixfmax1=ixomax1-1
1690  ixfmin3=ixomin3+1
1691  ixfmax3=ixomax3-1
1692  ixfmin2=ixomin2-1
1693  ixfmax2=ixomax2-1
1694  if(slab_uniform) then
1695  dx2x1=dxlevel(2)/dxlevel(1)
1696  dx2x3=dxlevel(2)/dxlevel(3)
1697  do ix2=ixfmin2,ixfmax2
1698  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
1699  ix2-1,ixfmin3:ixfmax3,mag(2)) &
1700  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
1701  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
1702  -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
1703  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
1704  end do
1705  else
1706  do ix2=ixfmin2,ixfmax2
1707  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
1708  ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
1709  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
1710  block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
1711  -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
1712  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1713  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
1714  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
1715  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1716  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
1717  -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
1718  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
1719  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
1720  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
1721  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1722  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
1723  /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
1724  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
1725  end do
1726  end if
1727  }
1728  {^ifthreed
1729  case(5)
1730  ixfmin1=ixomin1+1
1731  ixfmax1=ixomax1-1
1732  ixfmin2=ixomin2+1
1733  ixfmax2=ixomax2-1
1734  ixfmin3=ixomin3+1
1735  ixfmax3=ixomax3+1
1736  if(slab_uniform) then
1737  dx3x1=dxlevel(3)/dxlevel(1)
1738  dx3x2=dxlevel(3)/dxlevel(2)
1739  do ix3=ixfmax3,ixfmin3,-1
1740  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
1741  ixfmin2:ixfmax2,ix3+1,mag(3)) &
1742  +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
1743  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
1744  +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
1745  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
1746  end do
1747  else
1748  do ix3=ixfmax3,ixfmin3,-1
1749  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
1750  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
1751  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
1752  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
1753  +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
1754  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1755  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
1756  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
1757  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1758  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
1759  +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
1760  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
1761  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
1762  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
1763  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
1764  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
1765  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
1766  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
1767  end do
1768  end if
1769  case(6)
1770  ixfmin1=ixomin1+1
1771  ixfmax1=ixomax1-1
1772  ixfmin2=ixomin2+1
1773  ixfmax2=ixomax2-1
1774  ixfmin3=ixomin3-1
1775  ixfmax3=ixomax3-1
1776  if(slab_uniform) then
1777  dx3x1=dxlevel(3)/dxlevel(1)
1778  dx3x2=dxlevel(3)/dxlevel(2)
1779  do ix3=ixfmin3,ixfmax3
1780  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
1781  ixfmin2:ixfmax2,ix3-1,mag(3)) &
1782  -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
1783  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
1784  -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
1785  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
1786  end do
1787  else
1788  do ix3=ixfmin3,ixfmax3
1789  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
1790  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
1791  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
1792  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
1793  -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
1794  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1795  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
1796  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
1797  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1798  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
1799  -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
1800  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
1801  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
1802  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
1803  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
1804  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
1805  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
1806  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
1807  end do
1808  end if
1809  }
1810  case default
1811  call mpistop("Special boundary is not defined for this region")
1812  end select
1813 
1814  end subroutine fixdivb_boundary
1815 
1816  {^nooned
1817  subroutine mf_clean_divb_multigrid(qdt, qt, active)
1818  use mod_forest
1821  use mod_geometry
1822 
1823  double precision, intent(in) :: qdt !< Current time step
1824  double precision, intent(in) :: qt !< Current time
1825  logical, intent(inout) :: active !< Output if the source is active
1826  integer :: iigrid, igrid, id
1827  integer :: n, nc, lvl, ix^l, ixc^l, idim
1828  type(tree_node), pointer :: pnode
1829  double precision :: tmp(ixg^t), grad(ixg^t, ndim)
1830  double precision :: res
1831  double precision, parameter :: max_residual = 1d-3
1832  double precision, parameter :: residual_reduction = 1d-10
1833  integer, parameter :: max_its = 50
1834  double precision :: residual_it(max_its), max_divb
1835 
1836  mg%operator_type = mg_laplacian
1837 
1838  ! Set boundary conditions
1839  do n = 1, 2*ndim
1840  idim = (n+1)/2
1841  select case (typeboundary(mag(idim), n))
1842  case (bc_symm)
1843  ! d/dx B = 0, take phi = 0
1844  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1845  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1846  case (bc_asymm)
1847  ! B = 0, so grad(phi) = 0
1848  mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
1849  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1850  case (bc_cont)
1851  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1852  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1853  case (bc_special)
1854  ! Assume Dirichlet boundary conditions, derivative zero
1855  mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
1856  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1857  case (bc_periodic)
1858  ! Nothing to do here
1859  case default
1860  write(*,*) "mf_clean_divb_multigrid warning: unknown boundary type"
1861  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1862  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1863  end select
1864  end do
1865 
1866  ix^l=ixm^ll^ladd1;
1867  max_divb = 0.0d0
1868 
1869  ! Store divergence of B as right-hand side
1870  do iigrid = 1, igridstail
1871  igrid = igrids(iigrid);
1872  pnode => igrid_to_node(igrid, mype)%node
1873  id = pnode%id
1874  lvl = mg%boxes(id)%lvl
1875  nc = mg%box_size_lvl(lvl)
1876 
1877  ! Geometry subroutines expect this to be set
1878  block => ps(igrid)
1879  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1880 
1881  call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
1883  mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
1884  max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
1885  end do
1886 
1887  ! Solve laplacian(phi) = divB
1888  if(stagger_grid) then
1889  call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
1890  mpi_max, icomm, ierrmpi)
1891 
1892  if (mype == 0) print *, "Performing multigrid divB cleaning"
1893  if (mype == 0) print *, "iteration vs residual"
1894  ! Solve laplacian(phi) = divB
1895  do n = 1, max_its
1896  call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
1897  if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
1898  if (residual_it(n) < residual_reduction * max_divb) exit
1899  end do
1900  if (mype == 0 .and. n > max_its) then
1901  print *, "divb_multigrid warning: not fully converged"
1902  print *, "current amplitude of divb: ", residual_it(max_its)
1903  print *, "multigrid smallest grid: ", &
1904  mg%domain_size_lvl(:, mg%lowest_lvl)
1905  print *, "note: smallest grid ideally has <= 8 cells"
1906  print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
1907  print *, "note: dx/dy/dz should be similar"
1908  end if
1909  else
1910  do n = 1, max_its
1911  call mg_fas_vcycle(mg, max_res=res)
1912  if (res < max_residual) exit
1913  end do
1914  if (res > max_residual) call mpistop("divb_multigrid: no convergence")
1915  end if
1916 
1917 
1918  ! Correct the magnetic field
1919  do iigrid = 1, igridstail
1920  igrid = igrids(iigrid);
1921  pnode => igrid_to_node(igrid, mype)%node
1922  id = pnode%id
1923 
1924  ! Geometry subroutines expect this to be set
1925  block => ps(igrid)
1926  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1927 
1928  ! Compute the gradient of phi
1929  tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
1930 
1931  if(stagger_grid) then
1932  do idim =1, ndim
1933  ixcmin^d=ixmlo^d-kr(idim,^d);
1934  ixcmax^d=ixmhi^d;
1935  call gradientx(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim),.false.)
1936  ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
1937  end do
1938  call mf_face_to_center(ixm^ll,ps(igrid))
1939  else
1940  do idim = 1, ndim
1941  call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
1942  end do
1943  ! Apply the correction B* = B - gradient(phi)
1944  ps(igrid)%w(ixm^t, mag(1:ndim)) = &
1945  ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
1946  end if
1947 
1948  end do
1949 
1950  active = .true.
1951 
1952  end subroutine mf_clean_divb_multigrid
1953  }
1954 
1955  subroutine mf_update_faces(ixI^L,ixO^L,qt,qdt,wprim,fC,fE,sCT,s,vcts)
1957 
1958  integer, intent(in) :: ixI^L, ixO^L
1959  double precision, intent(in) :: qt, qdt
1960  ! cell-center primitive variables
1961  double precision, intent(in) :: wprim(ixI^S,1:nw)
1962  type(state) :: sCT, s
1963  type(ct_velocity) :: vcts
1964  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
1965  double precision, intent(inout) :: fE(ixI^S,7-2*ndim:3)
1966 
1967  select case(type_ct)
1968  case('average')
1969  call update_faces_average(ixi^l,ixo^l,qt,qdt,fc,fe,sct,s)
1970  case('uct_contact')
1971  call update_faces_contact(ixi^l,ixo^l,qt,qdt,wprim,fc,fe,sct,s,vcts)
1972  case('uct_hll')
1973  call update_faces_hll(ixi^l,ixo^l,qt,qdt,fe,sct,s,vcts)
1974  case default
1975  call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
1976  end select
1977 
1978  end subroutine mf_update_faces
1979 
1980  !> get electric field though averaging neighors to update faces in CT
1981  subroutine update_faces_average(ixI^L,ixO^L,qt,qdt,fC,fE,sCT,s)
1983  use mod_usr_methods
1984 
1985  integer, intent(in) :: ixI^L, ixO^L
1986  double precision, intent(in) :: qt, qdt
1987  type(state) :: sCT, s
1988  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
1989  double precision, intent(inout) :: fE(ixI^S,7-2*ndim:3)
1990 
1991  integer :: hxC^L,ixC^L,jxC^L,ixCm^L
1992  integer :: idim1,idim2,idir,iwdim1,iwdim2
1993  double precision :: circ(ixI^S,1:ndim)
1994  ! current on cell edges
1995  double precision :: jce(ixI^S,7-2*ndim:3)
1996 
1997  associate(bfaces=>s%ws,x=>s%x)
1998 
1999  ! Calculate contribution to FEM of each edge,
2000  ! that is, estimate value of line integral of
2001  ! electric field in the positive idir direction.
2002 
2003  ! if there is resistivity, get eta J
2004  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
2005 
2006  do idim1=1,ndim
2007  iwdim1 = mag(idim1)
2008  do idim2=1,ndim
2009  iwdim2 = mag(idim2)
2010  do idir=7-2*ndim,3! Direction of line integral
2011  ! Allow only even permutations
2012  if (lvc(idim1,idim2,idir)==1) then
2013  ixcmax^d=ixomax^d;
2014  ixcmin^d=ixomin^d+kr(idir,^d)-1;
2015  ! Assemble indices
2016  jxc^l=ixc^l+kr(idim1,^d);
2017  hxc^l=ixc^l+kr(idim2,^d);
2018  ! Interpolate to edges
2019  fe(ixc^s,idir)=quarter*(fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
2020  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
2021 
2022  ! add current component of electric field at cell edges E=-vxB+eta J
2023  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
2024 
2025  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
2026  ! times time step and edge length
2027  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
2028 
2029  end if
2030  end do
2031  end do
2032  end do
2033 
2034  ! allow user to change inductive electric field, especially for boundary driven applications
2035  if(associated(usr_set_electric_field)) &
2036  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
2037 
2038  circ(ixi^s,1:ndim)=zero
2039 
2040  ! Calculate circulation on each face
2041 
2042  do idim1=1,ndim ! Coordinate perpendicular to face
2043  ixcmax^d=ixomax^d;
2044  ixcmin^d=ixomin^d-kr(idim1,^d);
2045  do idim2=1,ndim
2046  do idir=7-2*ndim,3 ! Direction of line integral
2047  ! Assemble indices
2048  if(lvc(idim1,idim2,idir)/=0) then
2049  hxc^l=ixc^l-kr(idim2,^d);
2050  ! Add line integrals in direction idir
2051  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
2052  +lvc(idim1,idim2,idir)&
2053  *(fe(ixc^s,idir)&
2054  -fe(hxc^s,idir))
2055  end if
2056  end do
2057  end do
2058  ! Divide by the area of the face to get dB/dt
2059  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
2060  ! Time update
2061  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
2062  end do
2063 
2064  end associate
2065 
2066  end subroutine update_faces_average
2067 
2068  !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
2069  subroutine update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
2071  use mod_usr_methods
2072 
2073  integer, intent(in) :: ixI^L, ixO^L
2074  double precision, intent(in) :: qt, qdt
2075  ! cell-center primitive variables
2076  double precision, intent(in) :: wp(ixI^S,1:nw)
2077  type(state) :: sCT, s
2078  type(ct_velocity) :: vcts
2079  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
2080  double precision, intent(inout) :: fE(ixI^S,7-2*ndim:3)
2081 
2082  double precision :: circ(ixI^S,1:ndim)
2083  ! electric field at cell centers
2084  double precision :: ECC(ixI^S,7-2*ndim:3)
2085  ! gradient of E at left and right side of a cell face
2086  double precision :: EL(ixI^S),ER(ixI^S)
2087  ! gradient of E at left and right side of a cell corner
2088  double precision :: ELC(ixI^S),ERC(ixI^S)
2089  ! current on cell edges
2090  double precision :: jce(ixI^S,7-2*ndim:3)
2091  integer :: hxC^L,ixC^L,jxC^L,ixA^L,ixB^L
2092  integer :: idim1,idim2,idir,iwdim1,iwdim2
2093 
2094  associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm)
2095 
2096  ecc=0.d0
2097  ! Calculate electric field at cell centers
2098  do idim1=1,ndim; do idim2=1,ndim; do idir=7-2*ndim,3
2099  if(lvc(idim1,idim2,idir)==1)then
2100  ecc(ixi^s,idir)=ecc(ixi^s,idir)+wp(ixi^s,mag(idim1))*wp(ixi^s,mom(idim2))
2101  else if(lvc(idim1,idim2,idir)==-1) then
2102  ecc(ixi^s,idir)=ecc(ixi^s,idir)-wp(ixi^s,mag(idim1))*wp(ixi^s,mom(idim2))
2103  endif
2104  enddo; enddo; enddo
2105 
2106  ! if there is resistivity, get eta J
2107  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
2108 
2109  ! Calculate contribution to FEM of each edge,
2110  ! that is, estimate value of line integral of
2111  ! electric field in the positive idir direction.
2112  ! evaluate electric field along cell edges according to equation (41)
2113  do idim1=1,ndim
2114  iwdim1 = mag(idim1)
2115  do idim2=1,ndim
2116  iwdim2 = mag(idim2)
2117  do idir=7-2*ndim,3 ! Direction of line integral
2118  ! Allow only even permutations
2119  if (lvc(idim1,idim2,idir)==1) then
2120  ixcmax^d=ixomax^d;
2121  ixcmin^d=ixomin^d+kr(idir,^d)-1;
2122  ! Assemble indices
2123  jxc^l=ixc^l+kr(idim1,^d);
2124  hxc^l=ixc^l+kr(idim2,^d);
2125  ! average cell-face electric field to cell edges
2126  fe(ixc^s,idir)=quarter*&
2127  (fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
2128  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
2129 
2130  ! add slope in idim2 direction from equation (50)
2131  ixamin^d=ixcmin^d;
2132  ixamax^d=ixcmax^d+kr(idim1,^d);
2133  el(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(ixa^s,idir)
2134  hxc^l=ixa^l+kr(idim2,^d);
2135  er(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(hxc^s,idir)
2136  where(vnorm(ixc^s,idim1)>0.d0)
2137  elc(ixc^s)=el(ixc^s)
2138  else where(vnorm(ixc^s,idim1)<0.d0)
2139  elc(ixc^s)=el(jxc^s)
2140  else where
2141  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
2142  end where
2143  hxc^l=ixc^l+kr(idim2,^d);
2144  where(vnorm(hxc^s,idim1)>0.d0)
2145  erc(ixc^s)=er(ixc^s)
2146  else where(vnorm(hxc^s,idim1)<0.d0)
2147  erc(ixc^s)=er(jxc^s)
2148  else where
2149  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
2150  end where
2151  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
2152 
2153  ! add slope in idim1 direction from equation (50)
2154  jxc^l=ixc^l+kr(idim2,^d);
2155  ixamin^d=ixcmin^d;
2156  ixamax^d=ixcmax^d+kr(idim2,^d);
2157  el(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(ixa^s,idir)
2158  hxc^l=ixa^l+kr(idim1,^d);
2159  er(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(hxc^s,idir)
2160  where(vnorm(ixc^s,idim2)>0.d0)
2161  elc(ixc^s)=el(ixc^s)
2162  else where(vnorm(ixc^s,idim2)<0.d0)
2163  elc(ixc^s)=el(jxc^s)
2164  else where
2165  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
2166  end where
2167  hxc^l=ixc^l+kr(idim1,^d);
2168  where(vnorm(hxc^s,idim2)>0.d0)
2169  erc(ixc^s)=er(ixc^s)
2170  else where(vnorm(hxc^s,idim2)<0.d0)
2171  erc(ixc^s)=er(jxc^s)
2172  else where
2173  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
2174  end where
2175  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
2176 
2177  ! add current component of electric field at cell edges E=-vxB+eta J
2178  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
2179 
2180  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
2181  ! times time step and edge length
2182  fe(ixc^s,idir)=fe(ixc^s,idir)*qdt*s%dsC(ixc^s,idir)
2183  if (.not.slab) then
2184  where(abs(x(ixc^s,r_)+half*dxlevel(r_))<1.0d-9)
2185  fe(ixc^s,idir)=zero
2186  end where
2187  end if
2188  end if
2189  end do
2190  end do
2191  end do
2192 
2193  ! allow user to change inductive electric field, especially for boundary driven applications
2194  if(associated(usr_set_electric_field)) &
2195  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
2196 
2197  circ(ixi^s,1:ndim)=zero
2198 
2199  ! Calculate circulation on each face
2200  do idim1=1,ndim ! Coordinate perpendicular to face
2201  ixcmax^d=ixomax^d;
2202  ixcmin^d=ixomin^d-kr(idim1,^d);
2203  do idim2=1,ndim
2204  do idir=7-2*ndim,3 ! Direction of line integral
2205  ! Assemble indices
2206  if(lvc(idim1,idim2,idir)/=0) then
2207  hxc^l=ixc^l-kr(idim2,^d);
2208  ! Add line integrals in direction idir
2209  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
2210  +lvc(idim1,idim2,idir)&
2211  *(fe(ixc^s,idir)&
2212  -fe(hxc^s,idir))
2213  end if
2214  end do
2215  end do
2216  ! Divide by the area of the face to get dB/dt
2217  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
2218  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
2219  elsewhere
2220  circ(ixc^s,idim1)=zero
2221  end where
2222  ! Time update cell-face magnetic field component
2223  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
2224  end do
2225 
2226  end associate
2227 
2228  end subroutine update_faces_contact
2229 
2230  !> update faces
2231  subroutine update_faces_hll(ixI^L,ixO^L,qt,qdt,fE,sCT,s,vcts)
2234  use mod_usr_methods
2235 
2236  integer, intent(in) :: ixI^L, ixO^L
2237  double precision, intent(in) :: qt, qdt
2238  double precision, intent(inout) :: fE(ixI^S,7-2*ndim:3)
2239  type(state) :: sCT, s
2240  type(ct_velocity) :: vcts
2241 
2242  double precision :: vtilL(ixI^S,2)
2243  double precision :: vtilR(ixI^S,2)
2244  double precision :: btilL(ixI^S,ndim)
2245  double precision :: btilR(ixI^S,ndim)
2246  double precision :: cp(ixI^S,2)
2247  double precision :: cm(ixI^S,2)
2248  double precision :: circ(ixI^S,1:ndim)
2249  ! current on cell edges
2250  double precision :: jce(ixI^S,7-2*ndim:3)
2251  integer :: hxC^L,ixC^L,ixCp^L,jxC^L,ixCm^L
2252  integer :: idim1,idim2,idir
2253 
2254  associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
2255  cbarmax=>vcts%cbarmax)
2256 
2257  ! Calculate contribution to FEM of each edge,
2258  ! that is, estimate value of line integral of
2259  ! electric field in the positive idir direction.
2260 
2261  ! Loop over components of electric field
2262 
2263  ! idir: electric field component we need to calculate
2264  ! idim1: directions in which we already performed the reconstruction
2265  ! idim2: directions in which we perform the reconstruction
2266 
2267  ! if there is resistivity, get eta J
2268  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
2269 
2270  do idir=7-2*ndim,3
2271  ! Indices
2272  ! idir: electric field component
2273  ! idim1: one surface
2274  ! idim2: the other surface
2275  ! cyclic permutation: idim1,idim2,idir=1,2,3
2276  ! Velocity components on the surface
2277  ! follow cyclic premutations:
2278  ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
2279 
2280  ixcmax^d=ixomax^d;
2281  ixcmin^d=ixomin^d-1+kr(idir,^d);
2282 
2283  ! Set indices and directions
2284  idim1=mod(idir,3)+1
2285  idim2=mod(idir+1,3)+1
2286 
2287  jxc^l=ixc^l+kr(idim1,^d);
2288  ixcp^l=ixc^l+kr(idim2,^d);
2289 
2290  ! Reconstruct transverse transport velocities
2291  call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
2292  vtill(ixi^s,2),vtilr(ixi^s,2))
2293 
2294  call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
2295  vtill(ixi^s,1),vtilr(ixi^s,1))
2296 
2297  ! Reconstruct magnetic fields
2298  ! Eventhough the arrays are larger, reconstruct works with
2299  ! the limits ixG.
2300  call reconstruct(ixi^l,ixc^l,idim2,bfacesct(ixi^s,idim1),&
2301  btill(ixi^s,idim1),btilr(ixi^s,idim1))
2302 
2303  call reconstruct(ixi^l,ixc^l,idim1,bfacesct(ixi^s,idim2),&
2304  btill(ixi^s,idim2),btilr(ixi^s,idim2))
2305 
2306  ! Take the maximum characteristic
2307 
2308  cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
2309  cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
2310 
2311  cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
2312  cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
2313 
2314 
2315  ! Calculate eletric field
2316  fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
2317  + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
2318  - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
2319  /(cp(ixc^s,1)+cm(ixc^s,1)) &
2320  +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
2321  + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
2322  - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
2323  /(cp(ixc^s,2)+cm(ixc^s,2))
2324 
2325  ! add current component of electric field at cell edges E=-vxB+eta J
2326  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
2327 
2328  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
2329  ! times time step and edge length
2330  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
2331 
2332  if (.not.slab) then
2333  where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
2334  fe(ixc^s,idir)=zero
2335  end where
2336  end if
2337 
2338  end do
2339 
2340  ! allow user to change inductive electric field, especially for boundary driven applications
2341  if(associated(usr_set_electric_field)) &
2342  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
2343 
2344  circ(ixi^s,1:ndim)=zero
2345 
2346  ! Calculate circulation on each face: interal(fE dot dl)
2347 
2348  do idim1=1,ndim ! Coordinate perpendicular to face
2349  ixcmax^d=ixomax^d;
2350  ixcmin^d=ixomin^d-kr(idim1,^d);
2351  do idim2=1,ndim
2352  do idir=7-2*ndim,3 ! Direction of line integral
2353  ! Assemble indices
2354  if(lvc(idim1,idim2,idir)/=0) then
2355  hxc^l=ixc^l-kr(idim2,^d);
2356  ! Add line integrals in direction idir
2357  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
2358  +lvc(idim1,idim2,idir)&
2359  *(fe(ixc^s,idir)&
2360  -fe(hxc^s,idir))
2361  end if
2362  end do
2363  end do
2364  ! Divide by the area of the face to get dB/dt
2365  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
2366  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
2367  elsewhere
2368  circ(ixc^s,idim1)=zero
2369  end where
2370  ! Time update
2371  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
2372  end do
2373 
2374  end associate
2375  end subroutine update_faces_hll
2376 
2377  !> calculate eta J at cell edges
2378  subroutine get_resistive_electric_field(ixI^L,ixO^L,sCT,s,jce)
2380  use mod_usr_methods
2381  use mod_geometry
2382 
2383  integer, intent(in) :: ixI^L, ixO^L
2384  type(state), intent(in) :: sCT, s
2385  ! current on cell edges
2386  double precision :: jce(ixI^S,7-2*ndim:3)
2387 
2388  ! current on cell centers
2389  double precision :: jcc(ixI^S,7-2*ndir:3)
2390  ! location at cell faces
2391  double precision :: xs(ixGs^T,1:ndim)
2392  ! resistivity
2393  double precision :: eta(ixI^S)
2394  double precision :: gradi(ixGs^T)
2395  integer :: ix^D,ixC^L,ixA^L,ixB^L,idir,idirmin,idim1,idim2
2396 
2397  associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
2398  ! calculate current density at cell edges
2399  jce=0.d0
2400  do idim1=1,ndim
2401  do idim2=1,ndim
2402  do idir=7-2*ndim,3
2403  if (lvc(idim1,idim2,idir)==0) cycle
2404  ixcmax^d=ixomax^d+1;
2405  ixcmin^d=ixomin^d+kr(idir,^d)-2;
2406  ixbmax^d=ixcmax^d-kr(idir,^d)+1;
2407  ixbmin^d=ixcmin^d;
2408  ! current at transverse faces
2409  xs(ixb^s,:)=x(ixb^s,:)
2410  xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
2411  call gradientx(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,.false.)
2412  if (lvc(idim1,idim2,idir)==1) then
2413  jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
2414  else
2415  jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
2416  end if
2417  end do
2418  end do
2419  end do
2420  ! get resistivity
2421  if(mf_eta>zero)then
2422  jce(ixi^s,:)=jce(ixi^s,:)*mf_eta
2423  else
2424  ixa^l=ixo^l^ladd1;
2425  call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
2426  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,jcc,eta)
2427  ! calcuate eta on cell edges
2428  do idir=7-2*ndim,3
2429  ixcmax^d=ixomax^d;
2430  ixcmin^d=ixomin^d+kr(idir,^d)-1;
2431  jcc(ixc^s,idir)=0.d0
2432  {do ix^db=0,1\}
2433  if({ ix^d==1 .and. ^d==idir | .or.}) cycle
2434  ixamin^d=ixcmin^d+ix^d;
2435  ixamax^d=ixcmax^d+ix^d;
2436  jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
2437  {end do\}
2438  jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
2439  jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
2440  enddo
2441  end if
2442 
2443  end associate
2444  end subroutine get_resistive_electric_field
2445 
2446  !> calculate cell-center values from face-center values
2447  subroutine mf_face_to_center(ixO^L,s)
2449  ! Non-staggered interpolation range
2450  integer, intent(in) :: ixo^l
2451  type(state) :: s
2452 
2453  integer :: fxo^l, gxo^l, hxo^l, jxo^l, kxo^l, idim
2454 
2455  associate(w=>s%w, ws=>s%ws)
2456 
2457  ! calculate cell-center values from face-center values in 2nd order
2458  do idim=1,ndim
2459  ! Displace index to the left
2460  ! Even if ixI^L is the full size of the w arrays, this is ok
2461  ! because the staggered arrays have an additional place to the left.
2462  hxo^l=ixo^l-kr(idim,^d);
2463  ! Interpolate to cell barycentre using arithmetic average
2464  ! This might be done better later, to make the method less diffusive.
2465  w(ixo^s,mag(idim))=half/s%surface(ixo^s,idim)*&
2466  (ws(ixo^s,idim)*s%surfaceC(ixo^s,idim)&
2467  +ws(hxo^s,idim)*s%surfaceC(hxo^s,idim))
2468  end do
2469 
2470  ! calculate cell-center values from face-center values in 4th order
2471  !do idim=1,ndim
2472  ! gxO^L=ixO^L-2*kr(idim,^D);
2473  ! hxO^L=ixO^L-kr(idim,^D);
2474  ! jxO^L=ixO^L+kr(idim,^D);
2475 
2476  ! ! Interpolate to cell barycentre using fourth order central formula
2477  ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
2478  ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
2479  ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
2480  ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
2481  ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
2482  !end do
2483 
2484  ! calculate cell-center values from face-center values in 6th order
2485  !do idim=1,ndim
2486  ! fxO^L=ixO^L-3*kr(idim,^D);
2487  ! gxO^L=ixO^L-2*kr(idim,^D);
2488  ! hxO^L=ixO^L-kr(idim,^D);
2489  ! jxO^L=ixO^L+kr(idim,^D);
2490  ! kxO^L=ixO^L+2*kr(idim,^D);
2491 
2492  ! ! Interpolate to cell barycentre using sixth order central formula
2493  ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
2494  ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
2495  ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
2496  ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
2497  ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
2498  ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
2499  ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
2500  !end do
2501 
2502  end associate
2503 
2504  end subroutine mf_face_to_center
2505 
2506  !> calculate magnetic field from vector potential
2507  subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
2510 
2511  integer, intent(in) :: ixis^l, ixi^l, ixo^l
2512  double precision, intent(inout) :: ws(ixis^s,1:nws)
2513  double precision, intent(in) :: x(ixi^s,1:ndim)
2514 
2515  double precision :: adummy(ixis^s,1:3)
2516 
2517  call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
2518 
2519  end subroutine b_from_vector_potential
2520 
2523 
2524  double precision :: sum_jbb_ipe, sum_j_ipe, sum_l_ipe, f_i_ipe, volume_pe
2525  double precision :: sum_jbb, sum_j, sum_l, f_i, volume, cw_sin_theta
2526  integer :: iigrid, igrid, ix^d
2527  integer :: amode, istatus(mpi_status_size)
2528  integer, save :: fhmf
2529  character(len=800) :: filename,filehead
2530  character(len=800) :: line,datastr
2531  logical :: patchwi(ixg^t)
2532  logical, save :: logmfopened=.false.
2533 
2534  sum_jbb_ipe = 0.d0
2535  sum_j_ipe = 0.d0
2536  sum_l_ipe = 0.d0
2537  f_i_ipe = 0.d0
2538  volume_pe=0.d0
2539  do iigrid=1,igridstail; igrid=igrids(iigrid);
2540  block=>ps(igrid)
2541  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
2542  call mask_inner(ixg^ll,ixm^ll,ps(igrid)%w,ps(igrid)%x,patchwi,volume_pe)
2543  sum_jbb_ipe = sum_jbb_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2544  ps(igrid)%x,1,patchwi)
2545  sum_j_ipe = sum_j_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2546  ps(igrid)%x,2,patchwi)
2547  f_i_ipe=f_i_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2548  ps(igrid)%x,3,patchwi)
2549  sum_l_ipe = sum_l_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2550  ps(igrid)%x,4,patchwi)
2551  end do
2552  call mpi_reduce(sum_jbb_ipe,sum_jbb,1,mpi_double_precision,&
2553  mpi_sum,0,icomm,ierrmpi)
2554  call mpi_reduce(sum_j_ipe,sum_j,1,mpi_double_precision,mpi_sum,0,&
2555  icomm,ierrmpi)
2556  call mpi_reduce(f_i_ipe,f_i,1,mpi_double_precision,mpi_sum,0,&
2557  icomm,ierrmpi)
2558  call mpi_reduce(sum_l_ipe,sum_l,1,mpi_double_precision,mpi_sum,0,&
2559  icomm,ierrmpi)
2560  call mpi_reduce(volume_pe,volume,1,mpi_double_precision,mpi_sum,0,&
2561  icomm,ierrmpi)
2562 
2563  if(mype==0) then
2564  ! current- and volume-weighted average of the sine of the angle
2565  ! between the magnetic field B and the current density J
2566  cw_sin_theta = sum_jbb/sum_j
2567  ! volume-weighted average of the absolute value of the fractional
2568  ! magnetic flux change
2569  f_i = f_i/volume
2570  sum_j=sum_j/volume
2571  sum_l=sum_l/volume
2572  if(.not.logmfopened) then
2573  ! generate filename
2574  write(filename,"(a,a)") trim(base_filename), "_mf_metrics.csv"
2575 
2576  ! Delete the log when not doing a restart run
2577  if (restart_from_file == undefined) then
2578  open(unit=20,file=trim(filename),status='replace')
2579  close(20, status='delete')
2580  end if
2581 
2582  amode=ior(mpi_mode_create,mpi_mode_wronly)
2583  amode=ior(amode,mpi_mode_append)
2584  call mpi_file_open(mpi_comm_self,filename,amode,mpi_info_null,fhmf,ierrmpi)
2585  logmfopened=.true.
2586  filehead=" it,time,CW_sin_theta,current,Lorenz_force,f_i"
2587  if (it == 0) then
2588  call mpi_file_write(fhmf,filehead,len_trim(filehead), &
2589  mpi_character,istatus,ierrmpi)
2590  call mpi_file_write(fhmf,achar(10),1,mpi_character,istatus,ierrmpi)
2591  end if
2592  end if
2593  line=''
2594  write(datastr,'(i6,a)') it,','
2595  line=trim(line)//trim(datastr)
2596  write(datastr,'(es13.6,a)') global_time,','
2597  line=trim(line)//trim(datastr)
2598  write(datastr,'(es13.6,a)') cw_sin_theta,','
2599  line=trim(line)//trim(datastr)
2600  write(datastr,'(es13.6,a)') sum_j,','
2601  line=trim(line)//trim(datastr)
2602  write(datastr,'(es13.6,a)') sum_l,','
2603  line=trim(line)//trim(datastr)
2604  write(datastr,'(es13.6)') f_i
2605  line=trim(line)//trim(datastr)//new_line('A')
2606  call mpi_file_write(fhmf,line,len_trim(line),mpi_character,istatus,ierrmpi)
2607  if(.not.time_advance) then
2608  call mpi_file_close(fhmf,ierrmpi)
2609  logmfopened=.false.
2610  end if
2611  end if
2612 
2613  end subroutine record_force_free_metrics
2614 
2615  subroutine mask_inner(ixI^L,ixO^L,w,x,patchwi,volume_pe)
2617 
2618  integer, intent(in) :: ixI^L,ixO^L
2619  double precision, intent(in):: w(ixI^S,nw),x(ixI^S,1:ndim)
2620  double precision, intent(inout) :: volume_pe
2621  logical, intent(out) :: patchwi(ixI^S)
2622 
2623  double precision :: xO^L
2624  integer :: ix^D
2625 
2626  {xomin^d = xprobmin^d + 0.05d0*(xprobmax^d-xprobmin^d)\}
2627  {xomax^d = xprobmax^d - 0.05d0*(xprobmax^d-xprobmin^d)\}
2628  if(slab) then
2629  xomin^nd = xprobmin^nd
2630  else
2631  xomin1 = xprobmin1
2632  end if
2633 
2634  {do ix^db=ixomin^db,ixomax^db\}
2635  if({ x(ix^dd,^d) > xomin^d .and. x(ix^dd,^d) < xomax^d | .and. }) then
2636  patchwi(ix^d)=.true.
2637  volume_pe=volume_pe+block%dvolume(ix^d)
2638  else
2639  patchwi(ix^d)=.false.
2640  endif
2641  {end do\}
2642 
2643  end subroutine mask_inner
2644 
2645  function integral_grid_mf(ixI^L,ixO^L,w,x,iw,patchwi)
2647 
2648  integer, intent(in) :: ixi^l,ixo^l,iw
2649  double precision, intent(in) :: x(ixi^s,1:ndim)
2650  double precision :: w(ixi^s,nw+nwauxio)
2651  logical, intent(in) :: patchwi(ixi^s)
2652 
2653  double precision, dimension(ixI^S,7-2*ndir:3) :: current
2654  double precision, dimension(ixI^S,1:ndir) :: bvec,qvec
2655  double precision :: integral_grid_mf,tmp(ixi^s),bm2
2656  integer :: ix^d,idirmin0,idirmin,idir,jdir,kdir
2657 
2658  integral_grid_mf=0.d0
2659  select case(iw)
2660  case(1)
2661  ! Sum(|JxB|/|B|*dvolume)
2662  bvec(ixo^s,:)=w(ixo^s,mag(:))
2663  call get_current(w,ixi^l,ixo^l,idirmin,current)
2664  ! calculate Lorentz force
2665  qvec(ixo^s,1:ndir)=zero
2666  do idir=1,ndir; do jdir=idirmin,3; do kdir=1,ndir
2667  if(lvc(idir,jdir,kdir)/=0)then
2668  if(lvc(idir,jdir,kdir)==1)then
2669  qvec(ixo^s,idir)=qvec(ixo^s,idir)+current(ixo^s,jdir)*bvec(ixo^s,kdir)
2670  else
2671  qvec(ixo^s,idir)=qvec(ixo^s,idir)-current(ixo^s,jdir)*bvec(ixo^s,kdir)
2672  end if
2673  end if
2674  end do; end do; end do
2675 
2676  {do ix^db=ixomin^db,ixomax^db\}
2677  if(patchwi(ix^d)) then
2678  bm2=sum(bvec(ix^d,:)**2)
2679  if(bm2/=0.d0) bm2=1.d0/bm2
2680  integral_grid_mf=integral_grid_mf+sqrt(sum(qvec(ix^d,:)**2)*&
2681  bm2)*block%dvolume(ix^d)
2682  end if
2683  {end do\}
2684  case(2)
2685  ! Sum(|J|*dvolume)
2686  call get_current(w,ixi^l,ixo^l,idirmin,current)
2687  {do ix^db=ixomin^db,ixomax^db\}
2688  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+sqrt(sum(current(ix^d,:)**2))*&
2689  block%dvolume(ix^d)
2690  {end do\}
2691  case(3)
2692  ! f_i solenoidal property of B: (dvolume |div B|)/(dsurface |B|)
2693  ! Sum(f_i*dvolume)
2694  call get_normalized_divb(w,ixi^l,ixo^l,tmp)
2695  {do ix^db=ixomin^db,ixomax^db\}
2696  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+tmp(ix^d)*block%dvolume(ix^d)
2697  {end do\}
2698  case(4)
2699  ! Sum(|JxB|*dvolume)
2700  bvec(ixo^s,:)=w(ixo^s,mag(:))
2701  call get_current(w,ixi^l,ixo^l,idirmin,current)
2702  ! calculate Lorentz force
2703  qvec(ixo^s,1:ndir)=zero
2704  do idir=1,ndir; do jdir=idirmin,3; do kdir=1,ndir
2705  if(lvc(idir,jdir,kdir)/=0)then
2706  if(lvc(idir,jdir,kdir)==1)then
2707  qvec(ixo^s,idir)=qvec(ixo^s,idir)+current(ixo^s,jdir)*bvec(ixo^s,kdir)
2708  else
2709  qvec(ixo^s,idir)=qvec(ixo^s,idir)-current(ixo^s,jdir)*bvec(ixo^s,kdir)
2710  end if
2711  end if
2712  end do; end do; end do
2713 
2714  {do ix^db=ixomin^db,ixomax^db\}
2715  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+&
2716  sqrt(sum(qvec(ix^d,:)**2))*block%dvolume(ix^d)
2717  {end do\}
2718  end select
2719  return
2720  end function integral_grid_mf
2721 
2722 end module mod_mf_phys
subroutine mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: comm_lib.t:194
subroutine b_from_vector_potentiala(ixIsL, ixIL, ixOL, ws, x, A)
calculate magnetic field from vector potential A at cell edges
subroutine reconstruct(ixIL, ixCL, idir, q, qL, qR)
Reconstruct scalar q within ixO^L to 1/2 dx in direction idir Return both left and right reconstructe...
Module with basic grid data structures.
Definition: mod_forest.t:2
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition: mod_forest.t:32
Module with geometry-related routines (e.g., divergence, curl)
Definition: mod_geometry.t:2
subroutine divvectors(qvec, ixIL, ixOL, divq)
Calculate divergence of a vector qvec within ixL using limited extrapolation to cell edges.
Definition: mod_geometry.t:571
integer coordinate
Definition: mod_geometry.t:6
integer, parameter spherical
Definition: mod_geometry.t:10
integer, parameter cylindrical
Definition: mod_geometry.t:9
subroutine gradient(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir.
Definition: mod_geometry.t:320
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...
Definition: mod_geometry.t:626
subroutine gradients(q, ixIL, ixOL, idir, gradq)
Calculate gradient of a scalar q within ixL in direction idir first use limiter to go from cell cente...
Definition: mod_geometry.t:421
subroutine divvector(qvec, ixIL, ixOL, divq, fourthorder, sixthorder)
Calculate divergence of a vector qvec within ixL.
Definition: mod_geometry.t:479
subroutine gradientx(q, x, ixIL, ixOL, idir, gradq, fourth_order)
Calculate gradient of a scalar q in direction idir at cell interfaces.
Definition: mod_geometry.t:364
update ghost cells of all blocks including physical boundaries
integer, dimension(-1:2^d &,-1:1^d &), target type_recv_srl_f
integer, dimension(-1:1^d &, 0:3^d &), target type_recv_p_p1
integer, dimension(-1:1^d &, 0:3^d &), target type_send_p_p1
integer, dimension(-1:2^d &,-1:1^d &), target type_send_srl_p1
integer, dimension(-1:1^d &, 0:3^d &), target type_send_p_f
integer, dimension(:^d &,:^d &), pointer type_recv_srl
subroutine create_bc_mpi_datatype(nwstart, nwbc)
integer, dimension(-1:2^d &,-1:1^d &), target type_recv_srl_p1
integer, dimension(:^d &,:^d &), pointer type_send_srl
integer, dimension(-1:1^d &, 0:3^d &), target type_recv_r_f
integer, dimension(:^d &,:^d &), pointer type_recv_r
integer, dimension(:^d &,:^d &), pointer type_send_r
integer, dimension(-1:1^d &, 0:3^d &), target type_recv_r_p1
integer, dimension(-1:1^d &, 0:3^d &), target type_recv_p_f
subroutine getbc(time, qdt, psb, nwstart, nwbc, req_diag)
do update ghost cells of all blocks including physical boundaries
integer, dimension(-1:2^d &,-1:1^d &), target type_send_srl_f
integer, dimension(-1:1^d &,-1:1^d &), target type_send_r_p1
integer, dimension(:^d &,:^d &), pointer type_recv_p
integer, dimension(:^d &,:^d &), pointer type_send_p
integer, dimension(-1:1^d &,-1:1^d &), target type_send_r_f
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 nstep
How many sub-steps the time integrator takes.
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
double precision unit_charge
Physical scaling factor for charge.
integer ixghi
Upper index of grid block arrays.
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
double precision unit_time
Physical scaling factor for time.
double precision unit_density
Physical scaling factor for density.
integer, parameter unitpar
file handle for IO
integer, parameter bc_asymm
double precision global_time
The global simulation time.
double precision unit_mass
Physical scaling factor for mass.
integer istep
Index of the sub-step in a multi-step time integrator.
integer, dimension(3, 3) kr
Kronecker delta tensor.
integer it
Number of time steps taken.
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
double precision unit_numberdensity
Physical scaling factor for number density.
double precision unit_pressure
Physical scaling factor for pressure.
integer, parameter ndim
Number of spatial dimensions for grid variables.
logical angmomfix
Enable to strictly conserve the angular momentum (works both in cylindrical and spherical coordinates...
double precision unit_length
Physical scaling factor for length.
logical stagger_grid
True for using stagger grid.
double precision cmax_global
global fastest wave speed needed in fd scheme and glm method
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
double precision bdip
amplitude of background dipolar, quadrupolar, octupolar, user's field
integer mype
The rank of the current MPI task.
character(len=std_len) typediv
integer, dimension(:), allocatable, parameter d
integer ndir
Number of spatial dimensions (components) for vector variables.
integer ixm
the mesh range (within a block with ghost cells)
integer ierrmpi
A global MPI error return code.
logical slab
Cartesian geometry or not.
integer, parameter bc_periodic
integer, parameter bc_special
boundary condition types
double precision unit_magneticfield
Physical scaling factor for magnetic field.
integer nwauxio
Number of auxiliary variables that are only included in output.
double precision unit_velocity
Physical scaling factor for velocity.
character(len=std_len) restart_from_file
If not 'unavailable', resume from snapshot with this base file name.
double precision c_norm
Normalised speed of light.
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
integer, parameter bc_cont
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision, dimension(:,:), allocatable dx
integer nghostcells
Number of ghost cells surrounding a grid.
integer, parameter bc_symm
character(len= *), parameter undefined
logical need_global_cmax
need global maximal wave speed
logical use_multigrid
Use multigrid (only available in 2D and 3D)
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 r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
logical record_electric_field
True for record electric field.
double precision, dimension(ndim) dxlevel
integer, parameter ixglo
Lower index of grid block arrays (always 1)
Magnetofriction module.
Definition: mod_mf_phys.t:2
double precision, public mf_nu
viscosity coefficient in s cm^-2 for solar corona (Cheung 2012 ApJ)
Definition: mod_mf_phys.t:8
logical, public, protected mf_divb_4thorder
Whether divB is computed with a fourth order approximation.
Definition: mod_mf_phys.t:57
subroutine frictional_velocity(w, x, ixIL, ixOL)
Definition: mod_mf_phys.t:739
subroutine mf_get_ct_velocity(vcts, wLp, wRp, ixIL, ixOL, idim, cmax, cmin)
prepare velocities for ct methods
Definition: mod_mf_phys.t:476
subroutine add_source_hyperres(qdt, ixIL, ixOL, wCT, w, x)
Add Hyper-resistive source to w within ixO Uses 9 point stencil (4 neighbours) in each direction.
Definition: mod_mf_phys.t:957
subroutine, public mf_to_primitive(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
Definition: mod_mf_phys.t:401
subroutine, public mf_phys_init()
Definition: mod_mf_phys.t:173
subroutine mf_get_flux(wC, w, x, ixIL, ixOL, idim, f)
Calculate fluxes within ixO^L.
Definition: mod_mf_phys.t:542
subroutine add_source_glm(qdt, ixIL, ixOL, wCT, w, x)
Definition: mod_mf_phys.t:998
subroutine mf_check_params
Definition: mod_mf_phys.t:326
subroutine add_source_janhunen(qdt, ixIL, ixOL, wCT, w, x)
Definition: mod_mf_phys.t:1063
subroutine, public mf_face_to_center(ixOL, s)
calculate cell-center values from face-center values
Definition: mod_mf_phys.t:2448
subroutine mf_modify_wlr(ixIL, ixOL, qt, wLC, wRC, wLp, wRp, s, idir)
Definition: mod_mf_phys.t:1383
logical, public, protected mf_record_electric_field
set to true if need to record electric field on cell edges
Definition: mod_mf_phys.t:33
subroutine add_source_linde(qdt, ixIL, ixOL, wCT, w, x)
Definition: mod_mf_phys.t:1087
subroutine update_faces_hll(ixIL, ixOL, qt, qdt, fE, sCT, s, vcts)
update faces
Definition: mod_mf_phys.t:2232
subroutine, public b_from_vector_potential(ixIsL, ixIL, ixOL, ws, x)
calculate magnetic field from vector potential
Definition: mod_mf_phys.t:2508
logical, public, protected clean_initial_divb
clean divb in the initial condition
Definition: mod_mf_phys.t:84
subroutine mf_add_source_geom(qdt, ixIL, ixOL, wCT, w, x)
Definition: mod_mf_phys.t:1288
subroutine fixdivb_boundary(ixGL, ixOL, w, x, iB)
Definition: mod_mf_phys.t:1453
logical, public divbwave
Add divB wave in Roe solver.
Definition: mod_mf_phys.t:72
subroutine mf_get_cmax(w, x, ixIL, ixOL, idim, cmax)
Calculate cmax_idim=csound+abs(v_idim) within ixO^L.
Definition: mod_mf_phys.t:439
subroutine mf_get_p_total(w, x, ixIL, ixOL, p)
Calculate total pressure within ixO^L including magnetic pressure.
Definition: mod_mf_phys.t:529
double precision, public mf_vmax
maximal limit of magnetofrictional velocity in cm s^-1 (Pomoell 2019 A&A)
Definition: mod_mf_phys.t:11
integer, dimension(:), allocatable, public, protected mag
Indices of the magnetic field.
Definition: mod_mf_phys.t:39
logical, public, protected mf_glm
Whether GLM-MHD is used.
Definition: mod_mf_phys.t:20
subroutine get_resistive_electric_field(ixIL, ixOL, sCT, s, jce)
calculate eta J at cell edges
Definition: mod_mf_phys.t:2379
double precision, public mf_eta_hyper
The hyper-resistivity.
Definition: mod_mf_phys.t:48
subroutine add_source_res2(qdt, ixIL, ixOL, wCT, w, x)
Add resistive source to w within ixO Uses 5 point stencil (2 neighbours) in each direction,...
Definition: mod_mf_phys.t:903
subroutine, public get_normalized_divb(w, ixIL, ixOL, divb)
get dimensionless div B = |divB| * volume / area / |B|
Definition: mod_mf_phys.t:1186
subroutine add_source_res1(qdt, ixIL, ixOL, wCT, w, x)
Add resistive source to w within ixO Uses 3 point stencil (1 neighbour) in each direction,...
Definition: mod_mf_phys.t:808
subroutine, public get_current(w, ixIL, ixOL, idirmin, current, fourthorder)
Calculate idirmin and the idirmin:3 components of the common current array make sure that dxlevel(^D)...
Definition: mod_mf_phys.t:1220
subroutine mf_get_cbounds(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
Estimating bounds for the minimum and maximum signal velocities.
Definition: mod_mf_phys.t:451
double precision function integral_grid_mf(ixIL, ixOL, w, x, iw, patchwi)
Definition: mod_mf_phys.t:2646
subroutine mf_velocity_update(qt, psa)
Add global source terms to update frictional velocity on complete domain.
Definition: mod_mf_phys.t:583
double precision function, dimension(ixo^s) mf_mag_en(w, ixIL, ixOL)
Compute evolving magnetic energy.
Definition: mod_mf_phys.t:1374
double precision, public mf_glm_alpha
GLM-MHD parameter: ratio of the diffusive and advective time scales for div b taking values within [0...
Definition: mod_mf_phys.t:27
subroutine mf_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
If resistivity is not zero, check diffusion time limit for dt.
Definition: mod_mf_phys.t:1244
subroutine mask_inner(ixIL, ixOL, w, x, patchwi, volume_pe)
Definition: mod_mf_phys.t:2616
logical, dimension(2 *^nd), public, protected boundary_divbfix
To control divB=0 fix for boundary.
Definition: mod_mf_phys.t:78
subroutine update_faces_average(ixIL, ixOL, qt, qdt, fC, fE, sCT, s)
get electric field though averaging neighors to update faces in CT
Definition: mod_mf_phys.t:1982
subroutine mf_add_source(qdt, ixIL, ixOL, wCT, w, x, qsourcesplit, active, wCTprim)
w[iws]=w[iws]+qdt*S[iws,wCT] where S is the source based on wCT within ixO
Definition: mod_mf_phys.t:635
character(len=std_len), public, protected type_ct
Method type of constrained transport.
Definition: mod_mf_phys.t:54
double precision function, dimension(ixo^s), public mf_mag_en_all(w, ixIL, ixOL)
Compute 2 times total magnetic energy.
Definition: mod_mf_phys.t:1354
character(len=std_len), public, protected typedivbfix
Method type to clean divergence of B.
Definition: mod_mf_phys.t:51
subroutine, public get_divb(w, ixIL, ixOL, divb, fourthorder)
Calculate div B within ixO.
Definition: mod_mf_phys.t:1155
subroutine, public mf_to_conserved(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
Definition: mod_mf_phys.t:391
subroutine mf_angmomfix(fC, x, wnew, ixIL, ixOL, idim)
Definition: mod_mf_phys.t:160
subroutine mf_boundary_adjust(igrid, psb)
Definition: mod_mf_phys.t:1412
integer, dimension(2 *^nd), public, protected boundary_divbfix_skip
To skip * layer of ghost cells during divB=0 fix for boundary.
Definition: mod_mf_phys.t:81
subroutine add_source_powel(qdt, ixIL, ixOL, wCT, w, x)
Add divB related sources to w within ixO corresponding to Powel.
Definition: mod_mf_phys.t:1041
double precision, dimension(2 *^nd), public mf_decay_scale
decay scale of frictional velocity
Definition: mod_mf_phys.t:14
subroutine, public record_force_free_metrics()
Definition: mod_mf_phys.t:2522
subroutine mf_write_info(fh)
Write this module's parameters to a snapsoht.
Definition: mod_mf_phys.t:143
logical, public, protected mf_4th_order
MHD fourth order.
Definition: mod_mf_phys.t:30
integer, public, protected psi_
Indices of the GLM psi.
Definition: mod_mf_phys.t:42
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
Definition: mod_mf_phys.t:36
subroutine, public mf_clean_divb_multigrid(qdt, qt, active)
Definition: mod_mf_phys.t:1818
logical, public, protected mf_particles
Whether particles module is added.
Definition: mod_mf_phys.t:17
double precision function, dimension(ixo^s) mf_mag_i_all(w, ixIL, ixOL, idir)
Compute full magnetic field by direction.
Definition: mod_mf_phys.t:1364
subroutine, public mf_get_v(w, x, ixIL, ixOL, v)
Calculate v vector.
Definition: mod_mf_phys.t:411
double precision, public mf_eta
The resistivity.
Definition: mod_mf_phys.t:45
subroutine update_faces_contact(ixIL, ixOL, qt, qdt, wp, fC, fE, sCT, s, vcts)
update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
Definition: mod_mf_phys.t:2070
logical, public, protected source_split_divb
Whether divB cleaning sources are added splitting from fluid solver.
Definition: mod_mf_phys.t:23
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
Definition: mod_mf_phys.t:75
subroutine mf_update_faces(ixIL, ixOL, qt, qdt, wprim, fC, fE, sCT, s, vcts)
Definition: mod_mf_phys.t:1956
subroutine, public mf_get_v_idim(w, x, ixIL, ixOL, idim, v)
Calculate v component.
Definition: mod_mf_phys.t:427
subroutine mf_physical_units()
Definition: mod_mf_phys.t:331
Module to couple the octree-mg library to AMRVAC. This file uses the VACPP preprocessor,...
type(mg_t) mg
Data structure containing the multigrid tree.
Module containing all the particle routines.
Definition: mod_particles.t:2
subroutine particles_init()
Initialize particle data and parameters.
Definition: mod_particles.t:15
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition: mod_physics.t:4
procedure(sub_get_ct_velocity), pointer phys_get_ct_velocity
Definition: mod_physics.t:82
procedure(sub_convert), pointer phys_to_primitive
Definition: mod_physics.t:59
integer, parameter flux_tvdlf
Indicates the flux should be treated with tvdlf.
Definition: mod_physics.t:48
procedure(sub_write_info), pointer phys_write_info
Definition: mod_physics.t:79
procedure(sub_get_flux), pointer phys_get_flux
Definition: mod_physics.t:66
logical phys_req_diagonal
Whether the physics routines require diagonal ghost cells, for example for computing a curl.
Definition: mod_physics.t:27
procedure(sub_get_cbounds), pointer phys_get_cbounds
Definition: mod_physics.t:65
procedure(sub_get_dt), pointer phys_get_dt
Definition: mod_physics.t:69
procedure(sub_add_source_geom), pointer phys_add_source_geom
Definition: mod_physics.t:70
procedure(sub_check_params), pointer phys_check_params
Definition: mod_physics.t:56
integer, parameter flux_default
Indicates a normal flux.
Definition: mod_physics.t:46
integer, dimension(:, :), allocatable flux_type
Array per direction per variable, which can be used to specify that certain fluxes have to be treated...
Definition: mod_physics.t:43
procedure(sub_update_faces), pointer phys_update_faces
Definition: mod_physics.t:83
procedure(sub_convert), pointer phys_to_conserved
Definition: mod_physics.t:58
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition: mod_physics.t:19
procedure(sub_clean_divb), pointer phys_clean_divb
Definition: mod_physics.t:87
procedure(sub_boundary_adjust), pointer phys_boundary_adjust
Definition: mod_physics.t:78
procedure(sub_global_source), pointer phys_global_source_after
Definition: mod_physics.t:72
procedure(sub_add_source), pointer phys_add_source
Definition: mod_physics.t:71
procedure(sub_face_to_center), pointer phys_face_to_center
Definition: mod_physics.t:84
procedure(sub_modify_wlr), pointer phys_modify_wlr
Definition: mod_physics.t:60
procedure(sub_angmomfix), pointer phys_angmomfix
Definition: mod_physics.t:80
procedure(sub_get_cmax), pointer phys_get_cmax
Definition: mod_physics.t:61
procedure(sub_get_v), pointer phys_get_v
Definition: mod_physics.t:68
logical phys_energy
Solve energy equation or not.
Definition: mod_physics.t:30
procedure(sub_special_advance), pointer phys_special_advance
Definition: mod_physics.t:73
Module with all the methods that users can customize in AMRVAC.
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_electric_field), pointer usr_set_electric_field
The data structure that contains information about a tree node/grid block.
Definition: mod_forest.t:11