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