MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code
mod_mf_phys.t
Go to the documentation of this file.
1 !> Magnetofriction module
2 module mod_mf_phys
3  use mod_global_parameters, only: std_len
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,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), w(ixI^S,1:nw)
1226 
1227  integer :: iw,idir
1228  double precision :: tmp(ixI^S)
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  call mf_get_p_total(wct,x,ixi^l,ixo^l,tmp)
1239  if(phi_>0) then
1240  if(.not.stagger_grid) then
1241  w(ixo^s,bphi_)=w(ixo^s,bphi_)+qdt/x(ixo^s,1)*&
1242  (wct(ixo^s,bphi_)*wct(ixo^s,mr_) &
1243  -wct(ixo^s,br_)*wct(ixo^s,mphi_))
1244  end if
1245  end if
1246  if(mf_glm) w(ixo^s,br_)=w(ixo^s,br_)+qdt*wct(ixo^s,psi_)/x(ixo^s,1)
1247  case (spherical)
1248  ! b1
1249  if(mf_glm) then
1250  w(ixo^s,mag(1))=w(ixo^s,mag(1))+qdt/x(ixo^s,1)*2.0d0*wct(ixo^s,psi_)
1251  end if
1252 
1253  {^nooned
1254  ! b2
1255  if(.not.stagger_grid) then
1256  tmp(ixo^s)=wct(ixo^s,mom(1))*wct(ixo^s,mag(2)) &
1257  -wct(ixo^s,mom(2))*wct(ixo^s,mag(1))
1258  if(mf_glm) then
1259  tmp(ixo^s)=tmp(ixo^s) &
1260  + dcos(x(ixo^s,2))/dsin(x(ixo^s,2))*wct(ixo^s,psi_)
1261  end if
1262  w(ixo^s,mag(2))=w(ixo^s,mag(2))+qdt*tmp(ixo^s)/x(ixo^s,1)
1263  end if
1264  }
1265 
1266  if(ndir==3) then
1267  ! b3
1268  if(.not.stagger_grid) then
1269  tmp(ixo^s)=(wct(ixo^s,mom(1))*wct(ixo^s,mag(3)) &
1270  -wct(ixo^s,mom(3))*wct(ixo^s,mag(1))) {^nooned &
1271  -(wct(ixo^s,mom(3))*wct(ixo^s,mag(2)) &
1272  -wct(ixo^s,mom(2))*wct(ixo^s,mag(3)))*dcos(x(ixo^s,2)) &
1273  /dsin(x(ixo^s,2)) }
1274  w(ixo^s,mag(3))=w(ixo^s,mag(3))+qdt*tmp(ixo^s)/x(ixo^s,1)
1275  end if
1276  end if
1277  end select
1278 
1279  end subroutine mf_add_source_geom
1280 
1281  !> Compute 2 times total magnetic energy
1282  function mf_mag_en_all(w, ixI^L, ixO^L) result(mge)
1284  integer, intent(in) :: ixi^l, ixo^l
1285  double precision, intent(in) :: w(ixi^s, nw)
1286  double precision :: mge(ixo^s)
1287 
1288  mge = sum(w(ixo^s, mag(:))**2, dim=ndim+1)
1289  end function mf_mag_en_all
1290 
1291  !> Compute full magnetic field by direction
1292  function mf_mag_i_all(w, ixI^L, ixO^L,idir) result(mgf)
1294  integer, intent(in) :: ixi^l, ixo^l, idir
1295  double precision, intent(in) :: w(ixi^s, nw)
1296  double precision :: mgf(ixo^s)
1297 
1298  mgf = w(ixo^s, mag(idir))
1299  end function mf_mag_i_all
1300 
1301  !> Compute evolving magnetic energy
1302  function mf_mag_en(w, ixI^L, ixO^L) result(mge)
1303  use mod_global_parameters, only: nw, ndim
1304  integer, intent(in) :: ixi^l, ixo^l
1305  double precision, intent(in) :: w(ixi^s, nw)
1306  double precision :: mge(ixo^s)
1307 
1308  mge = 0.5d0 * sum(w(ixo^s, mag(:))**2, dim=ndim+1)
1309  end function mf_mag_en
1310 
1311  subroutine mf_modify_wlr(ixI^L,ixO^L,qt,wLC,wRC,wLp,wRp,s,idir)
1313  use mod_usr_methods
1314  integer, intent(in) :: ixI^L, ixO^L, idir
1315  double precision, intent(in) :: qt
1316  double precision, intent(inout) :: wLC(ixI^S,1:nw), wRC(ixI^S,1:nw)
1317  double precision, intent(inout) :: wLp(ixI^S,1:nw), wRp(ixI^S,1:nw)
1318  type(state) :: s
1319  double precision :: dB(ixI^S), dPsi(ixI^S)
1320 
1321  ! Solve the Riemann problem for the linear 2x2 system for normal
1322  ! B-field and GLM_Psi according to Dedner 2002:
1323  ! This implements eq. (42) in Dedner et al. 2002 JcP 175
1324  ! Gives the Riemann solution on the interface
1325  ! for the normal B component and Psi in the GLM-MHD system.
1326  ! 23/04/2013 Oliver Porth
1327  db(ixo^s) = wrp(ixo^s,mag(idir)) - wlp(ixo^s,mag(idir))
1328  dpsi(ixo^s) = wrp(ixo^s,psi_) - wlp(ixo^s,psi_)
1329 
1330  wlp(ixo^s,mag(idir)) = 0.5d0 * (wrp(ixo^s,mag(idir)) + wlp(ixo^s,mag(idir))) &
1331  - 0.5d0/cmax_global * dpsi(ixo^s)
1332  wlp(ixo^s,psi_) = 0.5d0 * (wrp(ixo^s,psi_) + wlp(ixo^s,psi_)) &
1333  - 0.5d0*cmax_global * db(ixo^s)
1334 
1335  wrp(ixo^s,mag(idir)) = wlp(ixo^s,mag(idir))
1336  wrp(ixo^s,psi_) = wlp(ixo^s,psi_)
1337 
1338  end subroutine mf_modify_wlr
1339 
1340  subroutine mf_boundary_adjust(igrid,psb)
1342  integer, intent(in) :: igrid
1343  type(state), target :: psb(max_blocks)
1344 
1345  integer :: iB, idims, iside, ixO^L, i^D
1346 
1347  block=>ps(igrid)
1348  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1349  do idims=1,ndim
1350  ! to avoid using as yet unknown corner info in more than 1D, we
1351  ! fill only interior mesh ranges of the ghost cell ranges at first,
1352  ! and progressively enlarge the ranges to include corners later
1353  do iside=1,2
1354  i^d=kr(^d,idims)*(2*iside-3);
1355  if (neighbor_type(i^d,igrid)/=1) cycle
1356  ib=(idims-1)*2+iside
1357  if(.not.boundary_divbfix(ib)) cycle
1358  if(any(typeboundary(:,ib)==bc_special)) then
1359  ! MF nonlinear force-free B field extrapolation and data driven
1360  ! require normal B of the first ghost cell layer to be untouched by
1361  ! fixdivB=0 process, set boundary_divbfix_skip(iB)=1 in par file
1362  select case (idims)
1363  {case (^d)
1364  if (iside==2) then
1365  ! maximal boundary
1366  ixomin^dd=ixghi^d+1-nghostcells+boundary_divbfix_skip(2*^d)^d%ixOmin^dd=ixglo^dd;
1367  ixomax^dd=ixghi^dd;
1368  else
1369  ! minimal boundary
1370  ixomin^dd=ixglo^dd;
1371  ixomax^dd=ixglo^d-1+nghostcells-boundary_divbfix_skip(2*^d-1)^d%ixOmax^dd=ixghi^dd;
1372  end if \}
1373  end select
1374  call fixdivb_boundary(ixg^ll,ixo^l,psb(igrid)%w,psb(igrid)%x,ib)
1375  end if
1376  end do
1377  end do
1378 
1379  end subroutine mf_boundary_adjust
1380 
1381  subroutine fixdivb_boundary(ixG^L,ixO^L,w,x,iB)
1383 
1384  integer, intent(in) :: ixG^L,ixO^L,iB
1385  double precision, intent(inout) :: w(ixG^S,1:nw)
1386  double precision, intent(in) :: x(ixG^S,1:ndim)
1387 
1388  double precision :: dx1x2,dx1x3,dx2x1,dx2x3,dx3x1,dx3x2
1389  integer :: ix^D,ixF^L
1390 
1391  select case(ib)
1392  case(1)
1393  ! 2nd order CD for divB=0 to set normal B component better
1394  {^iftwod
1395  ixfmin1=ixomin1+1
1396  ixfmax1=ixomax1+1
1397  ixfmin2=ixomin2+1
1398  ixfmax2=ixomax2-1
1399  if(slab_uniform) then
1400  dx1x2=dxlevel(1)/dxlevel(2)
1401  do ix1=ixfmax1,ixfmin1,-1
1402  w(ix1-1,ixfmin2:ixfmax2,mag(1))=w(ix1+1,ixfmin2:ixfmax2,mag(1)) &
1403  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
1404  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
1405  enddo
1406  else
1407  do ix1=ixfmax1,ixfmin1,-1
1408  w(ix1-1,ixfmin2:ixfmax2,mag(1))=( (w(ix1+1,ixfmin2:ixfmax2,mag(1))+&
1409  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1,ixfmin2:ixfmax2,1)&
1410  +(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
1411  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
1412  -(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
1413  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
1414  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
1415  end do
1416  end if
1417  }
1418  {^ifthreed
1419  ixfmin1=ixomin1+1
1420  ixfmax1=ixomax1+1
1421  ixfmin2=ixomin2+1
1422  ixfmax2=ixomax2-1
1423  ixfmin3=ixomin3+1
1424  ixfmax3=ixomax3-1
1425  if(slab_uniform) then
1426  dx1x2=dxlevel(1)/dxlevel(2)
1427  dx1x3=dxlevel(1)/dxlevel(3)
1428  do ix1=ixfmax1,ixfmin1,-1
1429  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1430  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
1431  +dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
1432  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
1433  +dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
1434  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
1435  end do
1436  else
1437  do ix1=ixfmax1,ixfmin1,-1
1438  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1439  ( (w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
1440  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
1441  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
1442  +(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
1443  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
1444  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
1445  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
1446  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
1447  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
1448  +(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
1449  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
1450  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
1451  -(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
1452  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1453  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
1454  /block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
1455  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
1456  end do
1457  end if
1458  }
1459  case(2)
1460  {^iftwod
1461  ixfmin1=ixomin1-1
1462  ixfmax1=ixomax1-1
1463  ixfmin2=ixomin2+1
1464  ixfmax2=ixomax2-1
1465  if(slab_uniform) then
1466  dx1x2=dxlevel(1)/dxlevel(2)
1467  do ix1=ixfmin1,ixfmax1
1468  w(ix1+1,ixfmin2:ixfmax2,mag(1))=w(ix1-1,ixfmin2:ixfmax2,mag(1)) &
1469  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))-&
1470  w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))
1471  enddo
1472  else
1473  do ix1=ixfmin1,ixfmax1
1474  w(ix1+1,ixfmin2:ixfmax2,mag(1))=( (w(ix1-1,ixfmin2:ixfmax2,mag(1))+&
1475  w(ix1,ixfmin2:ixfmax2,mag(1)))*block%surfaceC(ix1-1,ixfmin2:ixfmax2,1)&
1476  -(w(ix1,ixfmin2+1:ixfmax2+1,mag(2))+w(ix1,ixfmin2:ixfmax2,mag(2)))*&
1477  block%surfaceC(ix1,ixfmin2:ixfmax2,2)&
1478  +(w(ix1,ixfmin2:ixfmax2,mag(2))+w(ix1,ixfmin2-1:ixfmax2-1,mag(2)))*&
1479  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,2) )&
1480  /block%surfaceC(ix1,ixfmin2:ixfmax2,1)-w(ix1,ixfmin2:ixfmax2,mag(1))
1481  end do
1482  end if
1483  }
1484  {^ifthreed
1485  ixfmin1=ixomin1-1
1486  ixfmax1=ixomax1-1
1487  ixfmin2=ixomin2+1
1488  ixfmax2=ixomax2-1
1489  ixfmin3=ixomin3+1
1490  ixfmax3=ixomax3-1
1491  if(slab_uniform) then
1492  dx1x2=dxlevel(1)/dxlevel(2)
1493  dx1x3=dxlevel(1)/dxlevel(3)
1494  do ix1=ixfmin1,ixfmax1
1495  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1496  w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)) &
1497  -dx1x2*(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))-&
1498  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2))) &
1499  -dx1x3*(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))-&
1500  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))
1501  end do
1502  else
1503  do ix1=ixfmin1,ixfmax1
1504  w(ix1+1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))=&
1505  ( (w(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))+&
1506  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1)))*&
1507  block%surfaceC(ix1-1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)&
1508  -(w(ix1,ixfmin2+1:ixfmax2+1,ixfmin3:ixfmax3,mag(2))+&
1509  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2)))*&
1510  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,2)&
1511  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(2))+&
1512  w(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,mag(2)))*&
1513  block%surfaceC(ix1,ixfmin2-1:ixfmax2-1,ixfmin3:ixfmax3,2)&
1514  -(w(ix1,ixfmin2:ixfmax2,ixfmin3+1:ixfmax3+1,mag(3))+&
1515  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3)))*&
1516  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,3)&
1517  +(w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(3))+&
1518  w(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1519  block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3-1:ixfmax3-1,3) )&
1520  /block%surfaceC(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,1)-&
1521  w(ix1,ixfmin2:ixfmax2,ixfmin3:ixfmax3,mag(1))
1522  end do
1523  end if
1524  }
1525  case(3)
1526  {^iftwod
1527  ixfmin1=ixomin1+1
1528  ixfmax1=ixomax1-1
1529  ixfmin2=ixomin2+1
1530  ixfmax2=ixomax2+1
1531  if(slab_uniform) then
1532  dx2x1=dxlevel(2)/dxlevel(1)
1533  do ix2=ixfmax2,ixfmin2,-1
1534  w(ixfmin1:ixfmax1,ix2-1,mag(2))=w(ixfmin1:ixfmax1,ix2+1,mag(2)) &
1535  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
1536  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
1537  enddo
1538  else
1539  do ix2=ixfmax2,ixfmin2,-1
1540  w(ixfmin1:ixfmax1,ix2-1,mag(2))=( (w(ixfmin1:ixfmax1,ix2+1,mag(2))+&
1541  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2,2)&
1542  +(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
1543  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
1544  -(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
1545  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
1546  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
1547  end do
1548  end if
1549  }
1550  {^ifthreed
1551  ixfmin1=ixomin1+1
1552  ixfmax1=ixomax1-1
1553  ixfmin3=ixomin3+1
1554  ixfmax3=ixomax3-1
1555  ixfmin2=ixomin2+1
1556  ixfmax2=ixomax2+1
1557  if(slab_uniform) then
1558  dx2x1=dxlevel(2)/dxlevel(1)
1559  dx2x3=dxlevel(2)/dxlevel(3)
1560  do ix2=ixfmax2,ixfmin2,-1
1561  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
1562  ix2+1,ixfmin3:ixfmax3,mag(2)) &
1563  +dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
1564  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
1565  +dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
1566  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
1567  end do
1568  else
1569  do ix2=ixfmax2,ixfmin2,-1
1570  w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))=&
1571  ( (w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))+&
1572  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
1573  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)&
1574  +(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
1575  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1576  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
1577  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
1578  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1579  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
1580  +(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
1581  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
1582  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
1583  -(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
1584  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1585  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
1586  /block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)-&
1587  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
1588  end do
1589  end if
1590  }
1591  case(4)
1592  {^iftwod
1593  ixfmin1=ixomin1+1
1594  ixfmax1=ixomax1-1
1595  ixfmin2=ixomin2-1
1596  ixfmax2=ixomax2-1
1597  if(slab_uniform) then
1598  dx2x1=dxlevel(2)/dxlevel(1)
1599  do ix2=ixfmin2,ixfmax2
1600  w(ixfmin1:ixfmax1,ix2+1,mag(2))=w(ixfmin1:ixfmax1,ix2-1,mag(2)) &
1601  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))-&
1602  w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))
1603  end do
1604  else
1605  do ix2=ixfmin2,ixfmax2
1606  w(ixfmin1:ixfmax1,ix2+1,mag(2))=( (w(ixfmin1:ixfmax1,ix2-1,mag(2))+&
1607  w(ixfmin1:ixfmax1,ix2,mag(2)))*block%surfaceC(ixfmin1:ixfmax1,ix2-1,2)&
1608  -(w(ixfmin1+1:ixfmax1+1,ix2,mag(1))+w(ixfmin1:ixfmax1,ix2,mag(1)))*&
1609  block%surfaceC(ixfmin1:ixfmax1,ix2,1)&
1610  +(w(ixfmin1:ixfmax1,ix2,mag(1))+w(ixfmin1-1:ixfmax1-1,ix2,mag(1)))*&
1611  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,1) )&
1612  /block%surfaceC(ixfmin1:ixfmax1,ix2,2)-w(ixfmin1:ixfmax1,ix2,mag(2))
1613  end do
1614  end if
1615  }
1616  {^ifthreed
1617  ixfmin1=ixomin1+1
1618  ixfmax1=ixomax1-1
1619  ixfmin3=ixomin3+1
1620  ixfmax3=ixomax3-1
1621  ixfmin2=ixomin2-1
1622  ixfmax2=ixomax2-1
1623  if(slab_uniform) then
1624  dx2x1=dxlevel(2)/dxlevel(1)
1625  dx2x3=dxlevel(2)/dxlevel(3)
1626  do ix2=ixfmin2,ixfmax2
1627  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=w(ixfmin1:ixfmax1,&
1628  ix2-1,ixfmin3:ixfmax3,mag(2)) &
1629  -dx2x1*(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))-&
1630  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1))) &
1631  -dx2x3*(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))-&
1632  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))
1633  end do
1634  else
1635  do ix2=ixfmin2,ixfmax2
1636  w(ixfmin1:ixfmax1,ix2+1,ixfmin3:ixfmax3,mag(2))=&
1637  ( (w(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,mag(2))+&
1638  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2)))*&
1639  block%surfaceC(ixfmin1:ixfmax1,ix2-1,ixfmin3:ixfmax3,2)&
1640  -(w(ixfmin1+1:ixfmax1+1,ix2,ixfmin3:ixfmax3,mag(1))+&
1641  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1642  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,1)&
1643  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(1))+&
1644  w(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,mag(1)))*&
1645  block%surfaceC(ixfmin1-1:ixfmax1-1,ix2,ixfmin3:ixfmax3,1)&
1646  -(w(ixfmin1:ixfmax1,ix2,ixfmin3+1:ixfmax3+1,mag(3))+&
1647  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3)))*&
1648  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,3)&
1649  +(w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(3))+&
1650  w(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,mag(3)))*&
1651  block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3-1:ixfmax3-1,3) )&
1652  /block%surfaceC(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,2)-&
1653  w(ixfmin1:ixfmax1,ix2,ixfmin3:ixfmax3,mag(2))
1654  end do
1655  end if
1656  }
1657  {^ifthreed
1658  case(5)
1659  ixfmin1=ixomin1+1
1660  ixfmax1=ixomax1-1
1661  ixfmin2=ixomin2+1
1662  ixfmax2=ixomax2-1
1663  ixfmin3=ixomin3+1
1664  ixfmax3=ixomax3+1
1665  if(slab_uniform) then
1666  dx3x1=dxlevel(3)/dxlevel(1)
1667  dx3x2=dxlevel(3)/dxlevel(2)
1668  do ix3=ixfmax3,ixfmin3,-1
1669  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=w(ixfmin1:ixfmax1,&
1670  ixfmin2:ixfmax2,ix3+1,mag(3)) &
1671  +dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
1672  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
1673  +dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
1674  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
1675  end do
1676  else
1677  do ix3=ixfmax3,ixfmin3,-1
1678  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))=&
1679  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))+&
1680  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
1681  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)&
1682  +(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
1683  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1684  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
1685  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
1686  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1687  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
1688  +(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
1689  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
1690  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
1691  -(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
1692  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
1693  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
1694  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)-&
1695  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
1696  end do
1697  end if
1698  case(6)
1699  ixfmin1=ixomin1+1
1700  ixfmax1=ixomax1-1
1701  ixfmin2=ixomin2+1
1702  ixfmax2=ixomax2-1
1703  ixfmin3=ixomin3-1
1704  ixfmax3=ixomax3-1
1705  if(slab_uniform) then
1706  dx3x1=dxlevel(3)/dxlevel(1)
1707  dx3x2=dxlevel(3)/dxlevel(2)
1708  do ix3=ixfmin3,ixfmax3
1709  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=w(ixfmin1:ixfmax1,&
1710  ixfmin2:ixfmax2,ix3-1,mag(3)) &
1711  -dx3x1*(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))-&
1712  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1))) &
1713  -dx3x2*(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))-&
1714  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))
1715  end do
1716  else
1717  do ix3=ixfmin3,ixfmax3
1718  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3+1,mag(3))=&
1719  ( (w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,mag(3))+&
1720  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3)))*&
1721  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3-1,3)&
1722  -(w(ixfmin1+1:ixfmax1+1,ixfmin2:ixfmax2,ix3,mag(1))+&
1723  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1724  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,1)&
1725  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(1))+&
1726  w(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,mag(1)))*&
1727  block%surfaceC(ixfmin1-1:ixfmax1-1,ixfmin2:ixfmax2,ix3,1)&
1728  -(w(ixfmin1:ixfmax1,ixfmin2+1:ixfmax2+1,ix3,mag(2))+&
1729  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2)))*&
1730  block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,2)&
1731  +(w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(2))+&
1732  w(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,mag(2)))*&
1733  block%surfaceC(ixfmin1:ixfmax1,ixfmin2-1:ixfmax2-1,ix3,2) )&
1734  /block%surfaceC(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,3)-&
1735  w(ixfmin1:ixfmax1,ixfmin2:ixfmax2,ix3,mag(3))
1736  end do
1737  end if
1738  }
1739  case default
1740  call mpistop("Special boundary is not defined for this region")
1741  end select
1742 
1743  end subroutine fixdivb_boundary
1744 
1745  {^nooned
1746  subroutine mf_clean_divb_multigrid(qdt, qt, active)
1747  use mod_forest
1750  use mod_geometry
1751 
1752  double precision, intent(in) :: qdt !< Current time step
1753  double precision, intent(in) :: qt !< Current time
1754  logical, intent(inout) :: active !< Output if the source is active
1755  integer :: iigrid, igrid, id
1756  integer :: n, nc, lvl, ix^l, ixc^l, idim
1757  type(tree_node), pointer :: pnode
1758  double precision :: tmp(ixg^t), grad(ixg^t, ndim)
1759  double precision :: res
1760  double precision, parameter :: max_residual = 1d-3
1761  double precision, parameter :: residual_reduction = 1d-10
1762  integer, parameter :: max_its = 50
1763  double precision :: residual_it(max_its), max_divb
1764 
1765  mg%operator_type = mg_laplacian
1766 
1767  ! Set boundary conditions
1768  do n = 1, 2*ndim
1769  idim = (n+1)/2
1770  select case (typeboundary(mag(idim), n))
1771  case (bc_symm)
1772  ! d/dx B = 0, take phi = 0
1773  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1774  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1775  case (bc_asymm)
1776  ! B = 0, so grad(phi) = 0
1777  mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
1778  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1779  case (bc_cont)
1780  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1781  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1782  case (bc_special)
1783  ! Assume Dirichlet boundary conditions, derivative zero
1784  mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
1785  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1786  case (bc_periodic)
1787  ! Nothing to do here
1788  case default
1789  write(*,*) "mf_clean_divb_multigrid warning: unknown boundary type"
1790  mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
1791  mg%bc(n, mg_iphi)%bc_value = 0.0_dp
1792  end select
1793  end do
1794 
1795  ix^l=ixm^ll^ladd1;
1796  max_divb = 0.0d0
1797 
1798  ! Store divergence of B as right-hand side
1799  do iigrid = 1, igridstail
1800  igrid = igrids(iigrid);
1801  pnode => igrid_to_node(igrid, mype)%node
1802  id = pnode%id
1803  lvl = mg%boxes(id)%lvl
1804  nc = mg%box_size_lvl(lvl)
1805 
1806  ! Geometry subroutines expect this to be set
1807  block => ps(igrid)
1808  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1809 
1810  call get_divb(ps(igrid)%w(ixg^t, 1:nw), ixg^ll, ixm^ll, tmp, &
1812  mg%boxes(id)%cc({1:nc}, mg_irhs) = tmp(ixm^t)
1813  max_divb = max(max_divb, maxval(abs(tmp(ixm^t))))
1814  end do
1815 
1816  ! Solve laplacian(phi) = divB
1817  if(stagger_grid) then
1818  call mpi_allreduce(mpi_in_place, max_divb, 1, mpi_double_precision, &
1819  mpi_max, icomm, ierrmpi)
1820 
1821  if (mype == 0) print *, "Performing multigrid divB cleaning"
1822  if (mype == 0) print *, "iteration vs residual"
1823  ! Solve laplacian(phi) = divB
1824  do n = 1, max_its
1825  call mg_fas_fmg(mg, n>1, max_res=residual_it(n))
1826  if (mype == 0) write(*, "(I4,E11.3)") n, residual_it(n)
1827  if (residual_it(n) < residual_reduction * max_divb) exit
1828  end do
1829  if (mype == 0 .and. n > max_its) then
1830  print *, "divb_multigrid warning: not fully converged"
1831  print *, "current amplitude of divb: ", residual_it(max_its)
1832  print *, "multigrid smallest grid: ", &
1833  mg%domain_size_lvl(:, mg%lowest_lvl)
1834  print *, "note: smallest grid ideally has <= 8 cells"
1835  print *, "multigrid dx/dy/dz ratio: ", mg%dr(:, 1)/mg%dr(1, 1)
1836  print *, "note: dx/dy/dz should be similar"
1837  end if
1838  else
1839  do n = 1, max_its
1840  call mg_fas_vcycle(mg, max_res=res)
1841  if (res < max_residual) exit
1842  end do
1843  if (res > max_residual) call mpistop("divb_multigrid: no convergence")
1844  end if
1845 
1846 
1847  ! Correct the magnetic field
1848  do iigrid = 1, igridstail
1849  igrid = igrids(iigrid);
1850  pnode => igrid_to_node(igrid, mype)%node
1851  id = pnode%id
1852 
1853  ! Geometry subroutines expect this to be set
1854  block => ps(igrid)
1855  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1856 
1857  ! Compute the gradient of phi
1858  tmp(ix^s) = mg%boxes(id)%cc({:,}, mg_iphi)
1859 
1860  if(stagger_grid) then
1861  do idim =1, ndim
1862  ixcmin^d=ixmlo^d-kr(idim,^d);
1863  ixcmax^d=ixmhi^d;
1864  call gradientx(tmp,ps(igrid)%x,ixg^ll,ixc^l,idim,grad(ixg^t,idim),.false.)
1865  ps(igrid)%ws(ixc^s,idim)=ps(igrid)%ws(ixc^s,idim)-grad(ixc^s,idim)
1866  end do
1867  call mf_face_to_center(ixm^ll,ps(igrid))
1868  else
1869  do idim = 1, ndim
1870  call gradient(tmp,ixg^ll,ixm^ll,idim,grad(ixg^t, idim))
1871  end do
1872  ! Apply the correction B* = B - gradient(phi)
1873  ps(igrid)%w(ixm^t, mag(1:ndim)) = &
1874  ps(igrid)%w(ixm^t, mag(1:ndim)) - grad(ixm^t, :)
1875  end if
1876 
1877  end do
1878 
1879  active = .true.
1880 
1881  end subroutine mf_clean_divb_multigrid
1882  }
1883 
1884  subroutine mf_update_faces(ixI^L,ixO^L,qt,qdt,wprim,fC,fE,sCT,s,vcts)
1886 
1887  integer, intent(in) :: ixI^L, ixO^L
1888  double precision, intent(in) :: qt, qdt
1889  ! cell-center primitive variables
1890  double precision, intent(in) :: wprim(ixI^S,1:nw)
1891  type(state) :: sCT, s
1892  type(ct_velocity) :: vcts
1893  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
1894  double precision, intent(inout) :: fE(ixI^S,sdim:3)
1895 
1896  select case(type_ct)
1897  case('average')
1898  call update_faces_average(ixi^l,ixo^l,qt,qdt,fc,fe,sct,s)
1899  case('uct_contact')
1900  call update_faces_contact(ixi^l,ixo^l,qt,qdt,wprim,fc,fe,sct,s,vcts)
1901  case('uct_hll')
1902  call update_faces_hll(ixi^l,ixo^l,qt,qdt,fe,sct,s,vcts)
1903  case default
1904  call mpistop('choose average, uct_contact,or uct_hll for type_ct!')
1905  end select
1906 
1907  end subroutine mf_update_faces
1908 
1909  !> get electric field though averaging neighors to update faces in CT
1910  subroutine update_faces_average(ixI^L,ixO^L,qt,qdt,fC,fE,sCT,s)
1912  use mod_usr_methods
1913 
1914  integer, intent(in) :: ixI^L, ixO^L
1915  double precision, intent(in) :: qt, qdt
1916  type(state) :: sCT, s
1917  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
1918  double precision, intent(inout) :: fE(ixI^S,sdim:3)
1919 
1920  integer :: hxC^L,ixC^L,jxC^L,ixCm^L
1921  integer :: idim1,idim2,idir,iwdim1,iwdim2
1922  double precision :: circ(ixI^S,1:ndim)
1923  ! current on cell edges
1924  double precision :: jce(ixI^S,sdim:3)
1925 
1926  associate(bfaces=>s%ws,x=>s%x)
1927 
1928  ! Calculate contribution to FEM of each edge,
1929  ! that is, estimate value of line integral of
1930  ! electric field in the positive idir direction.
1931 
1932  ! if there is resistivity, get eta J
1933  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
1934 
1935  do idim1=1,ndim
1936  iwdim1 = mag(idim1)
1937  do idim2=1,ndim
1938  iwdim2 = mag(idim2)
1939  do idir=sdim,3! Direction of line integral
1940  ! Allow only even permutations
1941  if (lvc(idim1,idim2,idir)==1) then
1942  ixcmax^d=ixomax^d;
1943  ixcmin^d=ixomin^d+kr(idir,^d)-1;
1944  ! Assemble indices
1945  jxc^l=ixc^l+kr(idim1,^d);
1946  hxc^l=ixc^l+kr(idim2,^d);
1947  ! Interpolate to edges
1948  fe(ixc^s,idir)=quarter*(fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
1949  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
1950 
1951  ! add current component of electric field at cell edges E=-vxB+eta J
1952  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
1953 
1954  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
1955  ! times time step and edge length
1956  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
1957 
1958  end if
1959  end do
1960  end do
1961  end do
1962 
1963  ! allow user to change inductive electric field, especially for boundary driven applications
1964  if(associated(usr_set_electric_field)) &
1965  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
1966 
1967  circ(ixi^s,1:ndim)=zero
1968 
1969  ! Calculate circulation on each face
1970 
1971  do idim1=1,ndim ! Coordinate perpendicular to face
1972  ixcmax^d=ixomax^d;
1973  ixcmin^d=ixomin^d-kr(idim1,^d);
1974  do idim2=1,ndim
1975  do idir=sdim,3 ! Direction of line integral
1976  ! Assemble indices
1977  if(lvc(idim1,idim2,idir)/=0) then
1978  hxc^l=ixc^l-kr(idim2,^d);
1979  ! Add line integrals in direction idir
1980  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
1981  +lvc(idim1,idim2,idir)&
1982  *(fe(ixc^s,idir)&
1983  -fe(hxc^s,idir))
1984  end if
1985  end do
1986  end do
1987  ! Divide by the area of the face to get dB/dt
1988  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
1989  ! Time update
1990  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
1991  end do
1992 
1993  end associate
1994 
1995  end subroutine update_faces_average
1996 
1997  !> update faces using UCT contact mode by Gardiner and Stone 2005 JCP 205, 509
1998  subroutine update_faces_contact(ixI^L,ixO^L,qt,qdt,wp,fC,fE,sCT,s,vcts)
2000  use mod_usr_methods
2001 
2002  integer, intent(in) :: ixI^L, ixO^L
2003  double precision, intent(in) :: qt, qdt
2004  ! cell-center primitive variables
2005  double precision, intent(in) :: wp(ixI^S,1:nw)
2006  type(state) :: sCT, s
2007  type(ct_velocity) :: vcts
2008  double precision, intent(in) :: fC(ixI^S,1:nwflux,1:ndim)
2009  double precision, intent(inout) :: fE(ixI^S,sdim:3)
2010 
2011  double precision :: circ(ixI^S,1:ndim)
2012  ! electric field at cell centers
2013  double precision :: ECC(ixI^S,sdim:3)
2014  ! gradient of E at left and right side of a cell face
2015  double precision :: EL(ixI^S),ER(ixI^S)
2016  ! gradient of E at left and right side of a cell corner
2017  double precision :: ELC(ixI^S),ERC(ixI^S)
2018  ! current on cell edges
2019  double precision :: jce(ixI^S,sdim:3)
2020  integer :: hxC^L,ixC^L,jxC^L,ixA^L,ixB^L
2021  integer :: idim1,idim2,idir,iwdim1,iwdim2
2022 
2023  associate(bfaces=>s%ws,x=>s%x,w=>s%w,vnorm=>vcts%vnorm)
2024 
2025  ecc=0.d0
2026  ! Calculate electric field at cell centers
2027  do idim1=1,ndim; do idim2=1,ndim; do idir=sdim,3
2028  if(lvc(idim1,idim2,idir)==1)then
2029  ecc(ixi^s,idir)=ecc(ixi^s,idir)+wp(ixi^s,mag(idim1))*wp(ixi^s,mom(idim2))
2030  else if(lvc(idim1,idim2,idir)==-1) then
2031  ecc(ixi^s,idir)=ecc(ixi^s,idir)-wp(ixi^s,mag(idim1))*wp(ixi^s,mom(idim2))
2032  endif
2033  enddo; enddo; enddo
2034 
2035  ! if there is resistivity, get eta J
2036  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
2037 
2038  ! Calculate contribution to FEM of each edge,
2039  ! that is, estimate value of line integral of
2040  ! electric field in the positive idir direction.
2041  ! evaluate electric field along cell edges according to equation (41)
2042  do idim1=1,ndim
2043  iwdim1 = mag(idim1)
2044  do idim2=1,ndim
2045  iwdim2 = mag(idim2)
2046  do idir=sdim,3 ! Direction of line integral
2047  ! Allow only even permutations
2048  if (lvc(idim1,idim2,idir)==1) then
2049  ixcmax^d=ixomax^d;
2050  ixcmin^d=ixomin^d+kr(idir,^d)-1;
2051  ! Assemble indices
2052  jxc^l=ixc^l+kr(idim1,^d);
2053  hxc^l=ixc^l+kr(idim2,^d);
2054  ! average cell-face electric field to cell edges
2055  fe(ixc^s,idir)=quarter*&
2056  (fc(ixc^s,iwdim1,idim2)+fc(jxc^s,iwdim1,idim2)&
2057  -fc(ixc^s,iwdim2,idim1)-fc(hxc^s,iwdim2,idim1))
2058 
2059  ! add slope in idim2 direction from equation (50)
2060  ixamin^d=ixcmin^d;
2061  ixamax^d=ixcmax^d+kr(idim1,^d);
2062  el(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(ixa^s,idir)
2063  hxc^l=ixa^l+kr(idim2,^d);
2064  er(ixa^s)=fc(ixa^s,iwdim1,idim2)-ecc(hxc^s,idir)
2065  where(vnorm(ixc^s,idim1)>0.d0)
2066  elc(ixc^s)=el(ixc^s)
2067  else where(vnorm(ixc^s,idim1)<0.d0)
2068  elc(ixc^s)=el(jxc^s)
2069  else where
2070  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
2071  end where
2072  hxc^l=ixc^l+kr(idim2,^d);
2073  where(vnorm(hxc^s,idim1)>0.d0)
2074  erc(ixc^s)=er(ixc^s)
2075  else where(vnorm(hxc^s,idim1)<0.d0)
2076  erc(ixc^s)=er(jxc^s)
2077  else where
2078  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
2079  end where
2080  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
2081 
2082  ! add slope in idim1 direction from equation (50)
2083  jxc^l=ixc^l+kr(idim2,^d);
2084  ixamin^d=ixcmin^d;
2085  ixamax^d=ixcmax^d+kr(idim2,^d);
2086  el(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(ixa^s,idir)
2087  hxc^l=ixa^l+kr(idim1,^d);
2088  er(ixa^s)=-fc(ixa^s,iwdim2,idim1)-ecc(hxc^s,idir)
2089  where(vnorm(ixc^s,idim2)>0.d0)
2090  elc(ixc^s)=el(ixc^s)
2091  else where(vnorm(ixc^s,idim2)<0.d0)
2092  elc(ixc^s)=el(jxc^s)
2093  else where
2094  elc(ixc^s)=0.5d0*(el(ixc^s)+el(jxc^s))
2095  end where
2096  hxc^l=ixc^l+kr(idim1,^d);
2097  where(vnorm(hxc^s,idim2)>0.d0)
2098  erc(ixc^s)=er(ixc^s)
2099  else where(vnorm(hxc^s,idim2)<0.d0)
2100  erc(ixc^s)=er(jxc^s)
2101  else where
2102  erc(ixc^s)=0.5d0*(er(ixc^s)+er(jxc^s))
2103  end where
2104  fe(ixc^s,idir)=fe(ixc^s,idir)+0.25d0*(elc(ixc^s)+erc(ixc^s))
2105 
2106  ! add current component of electric field at cell edges E=-vxB+eta J
2107  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
2108 
2109  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
2110  ! times time step and edge length
2111  fe(ixc^s,idir)=fe(ixc^s,idir)*qdt*s%dsC(ixc^s,idir)
2112  if (.not.slab) then
2113  where(abs(x(ixc^s,r_)+half*dxlevel(r_))<1.0d-9)
2114  fe(ixc^s,idir)=zero
2115  end where
2116  end if
2117  end if
2118  end do
2119  end do
2120  end do
2121 
2122  ! allow user to change inductive electric field, especially for boundary driven applications
2123  if(associated(usr_set_electric_field)) &
2124  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
2125 
2126  circ(ixi^s,1:ndim)=zero
2127 
2128  ! Calculate circulation on each face
2129  do idim1=1,ndim ! Coordinate perpendicular to face
2130  ixcmax^d=ixomax^d;
2131  ixcmin^d=ixomin^d-kr(idim1,^d);
2132  do idim2=1,ndim
2133  do idir=sdim,3 ! Direction of line integral
2134  ! Assemble indices
2135  if(lvc(idim1,idim2,idir)/=0) then
2136  hxc^l=ixc^l-kr(idim2,^d);
2137  ! Add line integrals in direction idir
2138  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
2139  +lvc(idim1,idim2,idir)&
2140  *(fe(ixc^s,idir)&
2141  -fe(hxc^s,idir))
2142  end if
2143  end do
2144  end do
2145  ! Divide by the area of the face to get dB/dt
2146  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
2147  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
2148  elsewhere
2149  circ(ixc^s,idim1)=zero
2150  end where
2151  ! Time update cell-face magnetic field component
2152  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
2153  end do
2154 
2155  end associate
2156 
2157  end subroutine update_faces_contact
2158 
2159  !> update faces
2160  subroutine update_faces_hll(ixI^L,ixO^L,qt,qdt,fE,sCT,s,vcts)
2163  use mod_usr_methods
2164 
2165  integer, intent(in) :: ixI^L, ixO^L
2166  double precision, intent(in) :: qt, qdt
2167  double precision, intent(inout) :: fE(ixI^S,sdim:3)
2168  type(state) :: sCT, s
2169  type(ct_velocity) :: vcts
2170 
2171  double precision :: vtilL(ixI^S,2)
2172  double precision :: vtilR(ixI^S,2)
2173  double precision :: btilL(ixI^S,ndim)
2174  double precision :: btilR(ixI^S,ndim)
2175  double precision :: cp(ixI^S,2)
2176  double precision :: cm(ixI^S,2)
2177  double precision :: circ(ixI^S,1:ndim)
2178  ! current on cell edges
2179  double precision :: jce(ixI^S,sdim:3)
2180  integer :: hxC^L,ixC^L,ixCp^L,jxC^L,ixCm^L
2181  integer :: idim1,idim2,idir
2182 
2183  associate(bfaces=>s%ws,bfacesct=>sct%ws,x=>s%x,vbarc=>vcts%vbarC,cbarmin=>vcts%cbarmin,&
2184  cbarmax=>vcts%cbarmax)
2185 
2186  ! Calculate contribution to FEM of each edge,
2187  ! that is, estimate value of line integral of
2188  ! electric field in the positive idir direction.
2189 
2190  ! Loop over components of electric field
2191 
2192  ! idir: electric field component we need to calculate
2193  ! idim1: directions in which we already performed the reconstruction
2194  ! idim2: directions in which we perform the reconstruction
2195 
2196  ! if there is resistivity, get eta J
2197  if(mf_eta/=zero) call get_resistive_electric_field(ixi^l,ixo^l,sct,s,jce)
2198 
2199  do idir=sdim,3
2200  ! Indices
2201  ! idir: electric field component
2202  ! idim1: one surface
2203  ! idim2: the other surface
2204  ! cyclic permutation: idim1,idim2,idir=1,2,3
2205  ! Velocity components on the surface
2206  ! follow cyclic premutations:
2207  ! Sx(1),Sx(2)=y,z ; Sy(1),Sy(2)=z,x ; Sz(1),Sz(2)=x,y
2208 
2209  ixcmax^d=ixomax^d;
2210  ixcmin^d=ixomin^d-1+kr(idir,^d);
2211 
2212  ! Set indices and directions
2213  idim1=mod(idir,3)+1
2214  idim2=mod(idir+1,3)+1
2215 
2216  jxc^l=ixc^l+kr(idim1,^d);
2217  ixcp^l=ixc^l+kr(idim2,^d);
2218 
2219  ! Reconstruct transverse transport velocities
2220  call reconstruct(ixi^l,ixc^l,idim2,vbarc(ixi^s,idim1,1),&
2221  vtill(ixi^s,2),vtilr(ixi^s,2))
2222 
2223  call reconstruct(ixi^l,ixc^l,idim1,vbarc(ixi^s,idim2,2),&
2224  vtill(ixi^s,1),vtilr(ixi^s,1))
2225 
2226  ! Reconstruct magnetic fields
2227  ! Eventhough the arrays are larger, reconstruct works with
2228  ! the limits ixG.
2229  call reconstruct(ixi^l,ixc^l,idim2,bfacesct(ixi^s,idim1),&
2230  btill(ixi^s,idim1),btilr(ixi^s,idim1))
2231 
2232  call reconstruct(ixi^l,ixc^l,idim1,bfacesct(ixi^s,idim2),&
2233  btill(ixi^s,idim2),btilr(ixi^s,idim2))
2234 
2235  ! Take the maximum characteristic
2236 
2237  cm(ixc^s,1)=max(cbarmin(ixcp^s,idim1),cbarmin(ixc^s,idim1))
2238  cp(ixc^s,1)=max(cbarmax(ixcp^s,idim1),cbarmax(ixc^s,idim1))
2239 
2240  cm(ixc^s,2)=max(cbarmin(jxc^s,idim2),cbarmin(ixc^s,idim2))
2241  cp(ixc^s,2)=max(cbarmax(jxc^s,idim2),cbarmax(ixc^s,idim2))
2242 
2243 
2244  ! Calculate eletric field
2245  fe(ixc^s,idir)=-(cp(ixc^s,1)*vtill(ixc^s,1)*btill(ixc^s,idim2) &
2246  + cm(ixc^s,1)*vtilr(ixc^s,1)*btilr(ixc^s,idim2) &
2247  - cp(ixc^s,1)*cm(ixc^s,1)*(btilr(ixc^s,idim2)-btill(ixc^s,idim2)))&
2248  /(cp(ixc^s,1)+cm(ixc^s,1)) &
2249  +(cp(ixc^s,2)*vtill(ixc^s,2)*btill(ixc^s,idim1) &
2250  + cm(ixc^s,2)*vtilr(ixc^s,2)*btilr(ixc^s,idim1) &
2251  - cp(ixc^s,2)*cm(ixc^s,2)*(btilr(ixc^s,idim1)-btill(ixc^s,idim1)))&
2252  /(cp(ixc^s,2)+cm(ixc^s,2))
2253 
2254  ! add current component of electric field at cell edges E=-vxB+eta J
2255  if(mf_eta/=zero) fe(ixc^s,idir)=fe(ixc^s,idir)+jce(ixc^s,idir)
2256 
2257  if(record_electric_field) s%we(ixc^s,idir)=fe(ixc^s,idir)
2258  ! times time step and edge length
2259  fe(ixc^s,idir)=qdt*s%dsC(ixc^s,idir)*fe(ixc^s,idir)
2260 
2261  if (.not.slab) then
2262  where(abs(x(ixc^s,r_)+half*dxlevel(r_)).lt.1.0d-9)
2263  fe(ixc^s,idir)=zero
2264  end where
2265  end if
2266 
2267  end do
2268 
2269  ! allow user to change inductive electric field, especially for boundary driven applications
2270  if(associated(usr_set_electric_field)) &
2271  call usr_set_electric_field(ixi^l,ixo^l,qt,qdt,fe,sct)
2272 
2273  circ(ixi^s,1:ndim)=zero
2274 
2275  ! Calculate circulation on each face: interal(fE dot dl)
2276 
2277  do idim1=1,ndim ! Coordinate perpendicular to face
2278  ixcmax^d=ixomax^d;
2279  ixcmin^d=ixomin^d-kr(idim1,^d);
2280  do idim2=1,ndim
2281  do idir=sdim,3 ! Direction of line integral
2282  ! Assemble indices
2283  if(lvc(idim1,idim2,idir)/=0) then
2284  hxc^l=ixc^l-kr(idim2,^d);
2285  ! Add line integrals in direction idir
2286  circ(ixc^s,idim1)=circ(ixc^s,idim1)&
2287  +lvc(idim1,idim2,idir)&
2288  *(fe(ixc^s,idir)&
2289  -fe(hxc^s,idir))
2290  end if
2291  end do
2292  end do
2293  ! Divide by the area of the face to get dB/dt
2294  where(s%surfaceC(ixc^s,idim1) > 1.0d-9*s%dvolume(ixc^s))
2295  circ(ixc^s,idim1)=circ(ixc^s,idim1)/s%surfaceC(ixc^s,idim1)
2296  elsewhere
2297  circ(ixc^s,idim1)=zero
2298  end where
2299  ! Time update
2300  bfaces(ixc^s,idim1)=bfaces(ixc^s,idim1)-circ(ixc^s,idim1)
2301  end do
2302 
2303  end associate
2304  end subroutine update_faces_hll
2305 
2306  !> calculate eta J at cell edges
2307  subroutine get_resistive_electric_field(ixI^L,ixO^L,sCT,s,jce)
2309  use mod_usr_methods
2310  use mod_geometry
2311 
2312  integer, intent(in) :: ixI^L, ixO^L
2313  type(state), intent(in) :: sCT, s
2314  ! current on cell edges
2315  double precision :: jce(ixI^S,sdim:3)
2316 
2317  ! current on cell centers
2318  double precision :: jcc(ixI^S,7-2*ndir:3)
2319  ! location at cell faces
2320  double precision :: xs(ixGs^T,1:ndim)
2321  ! resistivity
2322  double precision :: eta(ixI^S)
2323  double precision :: gradi(ixGs^T)
2324  integer :: ix^D,ixC^L,ixA^L,ixB^L,idir,idirmin,idim1,idim2
2325 
2326  associate(x=>s%x,dx=>s%dx,w=>s%w,wct=>sct%w,wcts=>sct%ws)
2327  ! calculate current density at cell edges
2328  jce=0.d0
2329  do idim1=1,ndim
2330  do idim2=1,ndim
2331  do idir=sdim,3
2332  if (lvc(idim1,idim2,idir)==0) cycle
2333  ixcmax^d=ixomax^d+1;
2334  ixcmin^d=ixomin^d+kr(idir,^d)-2;
2335  ixbmax^d=ixcmax^d-kr(idir,^d)+1;
2336  ixbmin^d=ixcmin^d;
2337  ! current at transverse faces
2338  xs(ixb^s,:)=x(ixb^s,:)
2339  xs(ixb^s,idim2)=x(ixb^s,idim2)+half*dx(ixb^s,idim2)
2340  call gradientx(wcts(ixgs^t,idim2),xs,ixgs^ll,ixc^l,idim1,gradi,.false.)
2341  if (lvc(idim1,idim2,idir)==1) then
2342  jce(ixc^s,idir)=jce(ixc^s,idir)+gradi(ixc^s)
2343  else
2344  jce(ixc^s,idir)=jce(ixc^s,idir)-gradi(ixc^s)
2345  end if
2346  end do
2347  end do
2348  end do
2349  ! get resistivity
2350  if(mf_eta>zero)then
2351  jce(ixi^s,:)=jce(ixi^s,:)*mf_eta
2352  else
2353  ixa^l=ixo^l^ladd1;
2354  call get_current(wct,ixi^l,ixa^l,idirmin,jcc)
2355  call usr_special_resistivity(wct,ixi^l,ixa^l,idirmin,x,jcc,eta)
2356  ! calcuate eta on cell edges
2357  do idir=sdim,3
2358  ixcmax^d=ixomax^d;
2359  ixcmin^d=ixomin^d+kr(idir,^d)-1;
2360  jcc(ixc^s,idir)=0.d0
2361  {do ix^db=0,1\}
2362  if({ ix^d==1 .and. ^d==idir | .or.}) cycle
2363  ixamin^d=ixcmin^d+ix^d;
2364  ixamax^d=ixcmax^d+ix^d;
2365  jcc(ixc^s,idir)=jcc(ixc^s,idir)+eta(ixa^s)
2366  {end do\}
2367  jcc(ixc^s,idir)=jcc(ixc^s,idir)*0.25d0
2368  jce(ixc^s,idir)=jce(ixc^s,idir)*jcc(ixc^s,idir)
2369  enddo
2370  end if
2371 
2372  end associate
2373  end subroutine get_resistive_electric_field
2374 
2375  !> calculate cell-center values from face-center values
2376  subroutine mf_face_to_center(ixO^L,s)
2378  ! Non-staggered interpolation range
2379  integer, intent(in) :: ixo^l
2380  type(state) :: s
2381 
2382  integer :: fxo^l, gxo^l, hxo^l, jxo^l, kxo^l, idim
2383 
2384  associate(w=>s%w, ws=>s%ws)
2385 
2386  ! calculate cell-center values from face-center values in 2nd order
2387  do idim=1,ndim
2388  ! Displace index to the left
2389  ! Even if ixI^L is the full size of the w arrays, this is ok
2390  ! because the staggered arrays have an additional place to the left.
2391  hxo^l=ixo^l-kr(idim,^d);
2392  ! Interpolate to cell barycentre using arithmetic average
2393  ! This might be done better later, to make the method less diffusive.
2394  w(ixo^s,mag(idim))=half/s%surface(ixo^s,idim)*&
2395  (ws(ixo^s,idim)*s%surfaceC(ixo^s,idim)&
2396  +ws(hxo^s,idim)*s%surfaceC(hxo^s,idim))
2397  end do
2398 
2399  ! calculate cell-center values from face-center values in 4th order
2400  !do idim=1,ndim
2401  ! gxO^L=ixO^L-2*kr(idim,^D);
2402  ! hxO^L=ixO^L-kr(idim,^D);
2403  ! jxO^L=ixO^L+kr(idim,^D);
2404 
2405  ! ! Interpolate to cell barycentre using fourth order central formula
2406  ! w(ixO^S,mag(idim))=(0.0625d0/s%surface(ixO^S,idim))*&
2407  ! ( -ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
2408  ! +9.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
2409  ! +9.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
2410  ! -ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) )
2411  !end do
2412 
2413  ! calculate cell-center values from face-center values in 6th order
2414  !do idim=1,ndim
2415  ! fxO^L=ixO^L-3*kr(idim,^D);
2416  ! gxO^L=ixO^L-2*kr(idim,^D);
2417  ! hxO^L=ixO^L-kr(idim,^D);
2418  ! jxO^L=ixO^L+kr(idim,^D);
2419  ! kxO^L=ixO^L+2*kr(idim,^D);
2420 
2421  ! ! Interpolate to cell barycentre using sixth order central formula
2422  ! w(ixO^S,mag(idim))=(0.00390625d0/s%surface(ixO^S,idim))* &
2423  ! ( +3.0d0*ws(fxO^S,idim)*s%surfaceC(fxO^S,idim) &
2424  ! -25.0d0*ws(gxO^S,idim)*s%surfaceC(gxO^S,idim) &
2425  ! +150.0d0*ws(hxO^S,idim)*s%surfaceC(hxO^S,idim) &
2426  ! +150.0d0*ws(ixO^S,idim)*s%surfaceC(ixO^S,idim) &
2427  ! -25.0d0*ws(jxO^S,idim)*s%surfaceC(jxO^S,idim) &
2428  ! +3.0d0*ws(kxO^S,idim)*s%surfaceC(kxO^S,idim) )
2429  !end do
2430 
2431  end associate
2432 
2433  end subroutine mf_face_to_center
2434 
2435  !> calculate magnetic field from vector potential
2436  subroutine b_from_vector_potential(ixIs^L, ixI^L, ixO^L, ws, x)
2439 
2440  integer, intent(in) :: ixis^l, ixi^l, ixo^l
2441  double precision, intent(inout) :: ws(ixis^s,1:nws)
2442  double precision, intent(in) :: x(ixi^s,1:ndim)
2443 
2444  double precision :: adummy(ixis^s,1:3)
2445 
2446  call b_from_vector_potentiala(ixis^l, ixi^l, ixo^l, ws, x, adummy)
2447 
2448  end subroutine b_from_vector_potential
2449 
2452 
2453  double precision :: sum_jbb_ipe, sum_j_ipe, sum_l_ipe, f_i_ipe, volume_pe
2454  double precision :: sum_jbb, sum_j, sum_l, f_i, volume, cw_sin_theta
2455  integer :: iigrid, igrid, ix^d
2456  integer :: amode, istatus(mpi_status_size)
2457  integer, save :: fhmf
2458  character(len=800) :: filename,filehead
2459  character(len=800) :: line,datastr
2460  logical :: patchwi(ixg^t)
2461  logical, save :: logmfopened=.false.
2462 
2463  sum_jbb_ipe = 0.d0
2464  sum_j_ipe = 0.d0
2465  sum_l_ipe = 0.d0
2466  f_i_ipe = 0.d0
2467  volume_pe=0.d0
2468  do iigrid=1,igridstail; igrid=igrids(iigrid);
2469  block=>ps(igrid)
2470  ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
2471  call mask_inner(ixg^ll,ixm^ll,ps(igrid)%w,ps(igrid)%x,patchwi,volume_pe)
2472  sum_jbb_ipe = sum_jbb_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2473  ps(igrid)%x,1,patchwi)
2474  sum_j_ipe = sum_j_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2475  ps(igrid)%x,2,patchwi)
2476  f_i_ipe=f_i_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2477  ps(igrid)%x,3,patchwi)
2478  sum_l_ipe = sum_l_ipe+integral_grid_mf(ixg^ll,ixm^ll,ps(igrid)%w,&
2479  ps(igrid)%x,4,patchwi)
2480  end do
2481  call mpi_reduce(sum_jbb_ipe,sum_jbb,1,mpi_double_precision,&
2482  mpi_sum,0,icomm,ierrmpi)
2483  call mpi_reduce(sum_j_ipe,sum_j,1,mpi_double_precision,mpi_sum,0,&
2484  icomm,ierrmpi)
2485  call mpi_reduce(f_i_ipe,f_i,1,mpi_double_precision,mpi_sum,0,&
2486  icomm,ierrmpi)
2487  call mpi_reduce(sum_l_ipe,sum_l,1,mpi_double_precision,mpi_sum,0,&
2488  icomm,ierrmpi)
2489  call mpi_reduce(volume_pe,volume,1,mpi_double_precision,mpi_sum,0,&
2490  icomm,ierrmpi)
2491 
2492  if(mype==0) then
2493  ! current- and volume-weighted average of the sine of the angle
2494  ! between the magnetic field B and the current density J
2495  cw_sin_theta = sum_jbb/sum_j
2496  ! volume-weighted average of the absolute value of the fractional
2497  ! magnetic flux change
2498  f_i = f_i/volume
2499  sum_j=sum_j/volume
2500  sum_l=sum_l/volume
2501  if(.not.logmfopened) then
2502  ! generate filename
2503  write(filename,"(a,a)") trim(base_filename), "_mf_metrics.csv"
2504 
2505  ! Delete the log when not doing a restart run
2506  if (restart_from_file == undefined) then
2507  open(unit=20,file=trim(filename),status='replace')
2508  close(20, status='delete')
2509  end if
2510 
2511  amode=ior(mpi_mode_create,mpi_mode_wronly)
2512  amode=ior(amode,mpi_mode_append)
2513  call mpi_file_open(mpi_comm_self,filename,amode,mpi_info_null,fhmf,ierrmpi)
2514  logmfopened=.true.
2515  filehead=" it,time,CW_sin_theta,current,Lorenz_force,f_i"
2516  if (it == 0) then
2517  call mpi_file_write(fhmf,filehead,len_trim(filehead), &
2518  mpi_character,istatus,ierrmpi)
2519  call mpi_file_write(fhmf,achar(10),1,mpi_character,istatus,ierrmpi)
2520  end if
2521  end if
2522  line=''
2523  write(datastr,'(i6,a)') it,','
2524  line=trim(line)//trim(datastr)
2525  write(datastr,'(es13.6,a)') global_time,','
2526  line=trim(line)//trim(datastr)
2527  write(datastr,'(es13.6,a)') cw_sin_theta,','
2528  line=trim(line)//trim(datastr)
2529  write(datastr,'(es13.6,a)') sum_j,','
2530  line=trim(line)//trim(datastr)
2531  write(datastr,'(es13.6,a)') sum_l,','
2532  line=trim(line)//trim(datastr)
2533  write(datastr,'(es13.6)') f_i
2534  line=trim(line)//trim(datastr)//new_line('A')
2535  call mpi_file_write(fhmf,line,len_trim(line),mpi_character,istatus,ierrmpi)
2536  if(.not.time_advance) then
2537  call mpi_file_close(fhmf,ierrmpi)
2538  logmfopened=.false.
2539  end if
2540  end if
2541 
2542  end subroutine record_force_free_metrics
2543 
2544  subroutine mask_inner(ixI^L,ixO^L,w,x,patchwi,volume_pe)
2546 
2547  integer, intent(in) :: ixI^L,ixO^L
2548  double precision, intent(in):: w(ixI^S,nw),x(ixI^S,1:ndim)
2549  double precision, intent(inout) :: volume_pe
2550  logical, intent(out) :: patchwi(ixI^S)
2551 
2552  double precision :: xO^L
2553  integer :: ix^D
2554 
2555  {xomin^d = xprobmin^d + 0.05d0*(xprobmax^d-xprobmin^d)\}
2556  {xomax^d = xprobmax^d - 0.05d0*(xprobmax^d-xprobmin^d)\}
2557  if(slab) then
2558  xomin^nd = xprobmin^nd
2559  else
2560  xomin1 = xprobmin1
2561  end if
2562 
2563  {do ix^db=ixomin^db,ixomax^db\}
2564  if({ x(ix^dd,^d) > xomin^d .and. x(ix^dd,^d) < xomax^d | .and. }) then
2565  patchwi(ix^d)=.true.
2566  volume_pe=volume_pe+block%dvolume(ix^d)
2567  else
2568  patchwi(ix^d)=.false.
2569  endif
2570  {end do\}
2571 
2572  end subroutine mask_inner
2573 
2574  function integral_grid_mf(ixI^L,ixO^L,w,x,iw,patchwi)
2576 
2577  integer, intent(in) :: ixi^l,ixo^l,iw
2578  double precision, intent(in) :: x(ixi^s,1:ndim)
2579  double precision :: w(ixi^s,nw+nwauxio)
2580  logical, intent(in) :: patchwi(ixi^s)
2581 
2582  double precision, dimension(ixI^S,7-2*ndir:3) :: current
2583  double precision, dimension(ixI^S,1:ndir) :: bvec,qvec
2584  double precision :: integral_grid_mf,tmp(ixi^s),bm2
2585  integer :: ix^d,idirmin0,idirmin,idir,jdir,kdir
2586 
2587  integral_grid_mf=0.d0
2588  select case(iw)
2589  case(1)
2590  ! Sum(|JxB|/|B|*dvolume)
2591  bvec(ixo^s,:)=w(ixo^s,mag(:))
2592  call get_current(w,ixi^l,ixo^l,idirmin,current)
2593  ! calculate Lorentz force
2594  qvec(ixo^s,1:ndir)=zero
2595  do idir=1,ndir; do jdir=idirmin,3; do kdir=1,ndir
2596  if(lvc(idir,jdir,kdir)/=0)then
2597  if(lvc(idir,jdir,kdir)==1)then
2598  qvec(ixo^s,idir)=qvec(ixo^s,idir)+current(ixo^s,jdir)*bvec(ixo^s,kdir)
2599  else
2600  qvec(ixo^s,idir)=qvec(ixo^s,idir)-current(ixo^s,jdir)*bvec(ixo^s,kdir)
2601  end if
2602  end if
2603  end do; end do; end do
2604 
2605  {do ix^db=ixomin^db,ixomax^db\}
2606  if(patchwi(ix^d)) then
2607  bm2=sum(bvec(ix^d,:)**2)
2608  if(bm2/=0.d0) bm2=1.d0/bm2
2609  integral_grid_mf=integral_grid_mf+sqrt(sum(qvec(ix^d,:)**2)*&
2610  bm2)*block%dvolume(ix^d)
2611  end if
2612  {end do\}
2613  case(2)
2614  ! Sum(|J|*dvolume)
2615  call get_current(w,ixi^l,ixo^l,idirmin,current)
2616  {do ix^db=ixomin^db,ixomax^db\}
2617  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+sqrt(sum(current(ix^d,:)**2))*&
2618  block%dvolume(ix^d)
2619  {end do\}
2620  case(3)
2621  ! f_i solenoidal property of B: (dvolume |div B|)/(dsurface |B|)
2622  ! Sum(f_i*dvolume)
2623  call get_normalized_divb(w,ixi^l,ixo^l,tmp)
2624  {do ix^db=ixomin^db,ixomax^db\}
2625  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+tmp(ix^d)*block%dvolume(ix^d)
2626  {end do\}
2627  case(4)
2628  ! Sum(|JxB|*dvolume)
2629  bvec(ixo^s,:)=w(ixo^s,mag(:))
2630  call get_current(w,ixi^l,ixo^l,idirmin,current)
2631  ! calculate Lorentz force
2632  qvec(ixo^s,1:ndir)=zero
2633  do idir=1,ndir; do jdir=idirmin,3; do kdir=1,ndir
2634  if(lvc(idir,jdir,kdir)/=0)then
2635  if(lvc(idir,jdir,kdir)==1)then
2636  qvec(ixo^s,idir)=qvec(ixo^s,idir)+current(ixo^s,jdir)*bvec(ixo^s,kdir)
2637  else
2638  qvec(ixo^s,idir)=qvec(ixo^s,idir)-current(ixo^s,jdir)*bvec(ixo^s,kdir)
2639  end if
2640  end if
2641  end do; end do; end do
2642 
2643  {do ix^db=ixomin^db,ixomax^db\}
2644  if(patchwi(ix^d)) integral_grid_mf=integral_grid_mf+&
2645  sqrt(sum(qvec(ix^d,:)**2))*block%dvolume(ix^d)
2646  {end do\}
2647  end select
2648  return
2649  end function integral_grid_mf
2650 
2651 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 spherical
Definition: mod_geometry.t:11
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 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:2377
subroutine mf_modify_wlr(ixIL, ixOL, qt, wLC, wRC, wLp, wRp, s, idir)
Definition: mod_mf_phys.t:1312
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 mf_add_source_geom(qdt, dtfactor, ixIL, ixOL, wCT, w, x)
Definition: mod_mf_phys.t:1220
subroutine update_faces_hll(ixIL, ixOL, qt, qdt, fE, sCT, s, vcts)
update faces
Definition: mod_mf_phys.t:2161
subroutine, public b_from_vector_potential(ixIsL, ixIL, ixOL, ws, x)
calculate magnetic field from vector potential
Definition: mod_mf_phys.t:2437
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:1382
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:2308
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:2575
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:1303
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:2545
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:1911
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:1283
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:1341
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:2451
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:1747
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:1293
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:1999
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:1885
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:81
procedure(sub_convert), pointer phys_to_primitive
Definition: mod_physics.t:59
integer, parameter flux_tvdlf
Indicates the flux should be treated with tvdlf.
Definition: mod_physics.t:48
procedure(sub_write_info), pointer phys_write_info
Definition: mod_physics.t:79
procedure(sub_get_flux), pointer phys_get_flux
Definition: mod_physics.t:67
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:66
procedure(sub_get_dt), pointer phys_get_dt
Definition: mod_physics.t:69
procedure(sub_add_source_geom), pointer phys_add_source_geom
Definition: mod_physics.t:70
procedure(sub_check_params), pointer phys_check_params
Definition: mod_physics.t:56
integer, parameter flux_default
Indicates a normal flux.
Definition: mod_physics.t:46
integer, dimension(:, :), allocatable flux_type
Array per direction per variable, which can be used to specify that certain fluxes have to be treated...
Definition: mod_physics.t:43
procedure(sub_update_faces), pointer phys_update_faces
Definition: mod_physics.t:82
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:86
procedure(sub_boundary_adjust), pointer phys_boundary_adjust
Definition: mod_physics.t:78
procedure(sub_global_source), pointer phys_global_source_after
Definition: mod_physics.t:72
procedure(sub_add_source), pointer phys_add_source
Definition: mod_physics.t:71
procedure(sub_face_to_center), pointer phys_face_to_center
Definition: mod_physics.t:83
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:68
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:73
Module with all the methods that users can customize in AMRVAC.
procedure(special_resistivity), pointer usr_special_resistivity
procedure(set_electric_field), pointer usr_set_electric_field
The data structure that contains information about a tree node/grid block.
Definition: mod_forest.t:11