MPI-AMRVAC  3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
mod_srhd_phys.t
Go to the documentation of this file.
1 !> Special Relativistic Hydrodynamics (with EOS) physics module
3  use mod_physics
4  use mod_constants
5  use mod_comm_lib, only: mpistop
6  implicit none
7  private
8 
9  !> Whether particles module is added
10  logical, public, protected :: srhd_particles = .false.
11 
12  !> Number of tracer species
13  integer, public,protected :: srhd_n_tracer = 0
14 
15  !> Index of the density (in the w array)
16  integer, public,protected :: rho_
17  integer, public,protected :: d_
18 
19  !> Indices of the momentum density
20  integer, allocatable, public, protected :: mom(:)
21 
22  !> Indices of the tracers
23  integer, allocatable, public, protected :: tracer(:)
24 
25  !> Index of the energy density
26  integer, public,protected :: e_
27  !> Index of the gas pressure should equal e_
28  integer, public,protected :: p_
29 
30  !> Index of the Lorentz factor
31  integer, public,protected :: lfac_
32 
33  !> Index of the inertia
34  integer, public,protected :: xi_
35 
36  !> Whether synge eos is used
37  logical, public :: srhd_eos = .false.
38 
39  !> The adiabatic index and derived values
40  double precision, public :: srhd_gamma = 5.d0/3.0d0
41  double precision, public :: gamma_1,inv_gamma_1,gamma_to_gamma_1
42 
43  !> The smallest allowed energy
44  double precision, public :: small_e
45  !> The smallest allowed inertia
46  double precision, public :: small_xi
47 
48  !> Allows overruling default corner filling (for debug mode, otherwise corner primitives fail)
49  logical, public, protected :: srhd_force_diagonal = .false.
50 
51  !> Helium abundance over Hydrogen
52  double precision, public, protected :: he_abundance=0.0d0
53 
54  !> parameters for NR in con2prim
55  integer, public :: maxitnr = 100
56  double precision, public :: absaccnr = 1.0d-8
57  double precision, public :: tolernr = 1.0d-9
58  double precision, public :: dmaxvel = 1.0d-7
59  double precision, public :: lfacmax
60  double precision, public :: minp, minrho, smalltau, smallxi
61 
62  ! Public methods
63  public :: srhd_phys_init
64  public :: srhd_get_pthermal
65  public :: srhd_get_auxiliary
66  public :: srhd_get_auxiliary_prim
67  public :: srhd_get_csound2
68  public :: srhd_to_conserved
69  public :: srhd_to_primitive
70  public :: srhd_check_params
71  public :: srhd_check_w
72  public :: srhd_get_geff_eos
73  public :: srhd_get_enthalpy_eos
74 contains
75 
76  !> Read this module's parameters from a file
77  subroutine srhd_read_params(files)
79  character(len=*), intent(in) :: files(:)
80  integer :: n
81 
82  namelist /srhd_list/ srhd_n_tracer, srhd_eos, srhd_gamma, &
85 
86  do n = 1, size(files)
87  open(unitpar, file=trim(files(n)), status="old")
88  read(unitpar, srhd_list, end=111)
89 111 close(unitpar)
90  end do
91 
92  end subroutine srhd_read_params
93 
94  !> Write this module's parameters to a snapshot
95  subroutine srhd_write_info(fh)
97  integer, intent(in) :: fh
98  integer, parameter :: n_par = 1
99  double precision :: values(n_par)
100  character(len=name_len) :: names(n_par)
101  integer, dimension(MPI_STATUS_SIZE) :: st
102  integer :: er
103 
104  call mpi_file_write(fh, n_par, 1, mpi_integer, st, er)
105 
106  names(1) = "gamma"
107  values(1) = srhd_gamma
108  call mpi_file_write(fh, values, n_par, mpi_double_precision, st, er)
109  call mpi_file_write(fh, names, n_par * name_len, mpi_character, st, er)
110 
111  end subroutine srhd_write_info
112 
113  !> Initialize the module
114  subroutine srhd_phys_init()
116  use mod_particles, only: particles_init
117  integer :: itr,idir
118 
119  call srhd_read_params(par_files)
120 
121  physics_type = "srhd"
122  phys_energy = .true.
123  phys_total_energy = .true.
124  phys_gamma = srhd_gamma
125 
126  ! unused physics options
127  phys_internal_e = .false.
128  phys_partial_ionization=.false.
129  phys_trac=.false.
130 
132 
133  ! note: number_species is 1 for srhd
134  allocate(start_indices(number_species),stop_indices(number_species))
135  ! set the index of the first flux variable for species 1
136  start_indices(1)=1
137 
138  ! Determine flux variables
139  rho_ = var_set_rho()
140  d_=rho_
141 
142  allocate(mom(ndir))
143  mom(:) = var_set_momentum(ndir)
144 
145  ! Set index of energy variable
146  e_ = var_set_energy()
147  p_ = e_
148 
149  ! Whether diagonal ghost cells are required for the physics
150  phys_req_diagonal = .false.
151 
152  ! derive units from basic units
153  call srhd_physical_units()
154 
155  if (srhd_force_diagonal) then
156  ! ensure corners are filled, otherwise divide by zero when getting primitives
157  ! --> only for debug purposes
158  phys_req_diagonal = .true.
159  endif
160 
161  allocate(tracer(srhd_n_tracer))
162 
163  ! Set starting index of tracers
164  do itr = 1, srhd_n_tracer
165  tracer(itr) = var_set_fluxvar("trc", "trp", itr, need_bc=.false.)
166  end do
167 
168  ! Set index for auxiliary variables
169  ! MUST be after the possible tracers (which have fluxes)
170  xi_ = var_set_auxvar('xi','xi')
171  lfac_= var_set_auxvar('lfac','lfac')
172 
173  ! set number of variables which need update ghostcells
174  nwgc=nwflux+nwaux
175 
176  ! set the index of the last flux variable for species 1
177  stop_indices(1)=nwflux
178 
179  ! Check whether custom flux types have been defined
180  if (.not. allocated(flux_type)) then
181  allocate(flux_type(ndir, nw))
182  flux_type = flux_default
183  else if (any(shape(flux_type) /= [ndir, nw])) then
184  call mpistop("phys_check error: flux_type has wrong shape")
185  end if
186 
187  nvector = 1 ! No. vector vars
188  allocate(iw_vector(nvector))
189  iw_vector(1) = mom(1) - 1
190 
191  ! dummy for now, no extra source terms precoded
192  phys_add_source => srhd_add_source
193  phys_get_dt => srhd_get_dt
194  ! copied in from HD/MHD, for certain limiters
195  phys_get_a2max => srhd_get_a2max
196 
197  ! actual srhd routines
198  phys_check_params => srhd_check_params
199  phys_check_w => srhd_check_w
200  phys_get_cmax => srhd_get_cmax
201  phys_get_cbounds => srhd_get_cbounds
202  phys_get_flux => srhd_get_flux
203  phys_add_source_geom => srhd_add_source_geom
204  phys_to_conserved => srhd_to_conserved
205  phys_to_primitive => srhd_to_primitive
206  phys_get_pthermal => srhd_get_pthermal
207  phys_get_auxiliary => srhd_get_auxiliary
208  phys_get_auxiliary_prim => srhd_get_auxiliary_prim
209  phys_get_pthermal => srhd_get_pthermal
210  phys_get_v => srhd_get_v
211  phys_write_info => srhd_write_info
212  phys_handle_small_values => srhd_handle_small_values
213 
214  ! Initialize particles module
215  if (srhd_particles) then
216  call particles_init()
217  phys_req_diagonal = .true.
218  end if
219 
220  end subroutine srhd_phys_init
221 
222  subroutine srhd_check_params
224 
225  if (srhd_gamma <= 0.0d0 .or. srhd_gamma == 1.0d0) &
226  call mpistop ("Error: srhd_gamma <= 0 or srhd_gamma == 1")
227  ! additional useful values
228  gamma_1=srhd_gamma-1.0d0
229  inv_gamma_1=1.0d0/gamma_1
231 
232  ! the following sets small_e and small_xi from small_density/small_pressure
233  ! according to the srhd_eos used
235 
236  if(mype==0)then
237  write(*,*)'------------------------------------------------------------'
238  write(*,*)'Using EOS set via srhd_eos=',srhd_eos
239  write(*,*)'Maximal lorentz factor (via dmaxvel) is=',lfacmax
240  write(*,*)'Use fixes set through check/fix small values:', check_small_values,fix_small_values
241  write(*,*)'Controlled with small pressure/density:', small_pressure,small_density
242  write(*,*)'Derived small values: xi and e ',small_xi,small_e
243  write(*,*)'------------------------------------------------------------'
244  endif
245 
246  end subroutine srhd_check_params
247 
250  double precision :: mp,kB
251 
252  ! Derive scaling units
253  if(si_unit) then
254  mp=mp_si
255  kb=kb_si
256  unit_velocity=c_si
257  else
258  mp=mp_cgs
259  kb=kb_cgs
260  unit_velocity=const_c
261  end if
262  if(unit_numberdensity*unit_length<=0.0d0)then
263  call mpistop("Abort: must set positive values for unit length and numberdensity")
264  endif
265  ! we assume user sets: unit_numberdensity, unit_length, He_abundance
266  ! then together with light speed c, all units fixed
272 
273  end subroutine srhd_physical_units
274 
275  !> Returns logical argument flag T where values are not ok
276  subroutine srhd_check_w(primitive, ixI^L, ixO^L, w, flag)
278  logical, intent(in) :: primitive
279  integer, intent(in) :: ixi^l, ixo^l
280  double precision, intent(in) :: w(ixi^s, nw)
281  logical, intent(inout) :: flag(ixi^s,1:nw)
282 
283  flag=.false.
284 
285  ! NOTE: we should not check or use nwaux variables here
286  if(primitive) then
287  where(w(ixo^s,rho_) < small_density) flag(ixo^s,rho_) = .true.
288  where(w(ixo^s,p_) < small_pressure) flag(ixo^s,p_) = .true.
289  else
290  where(w(ixo^s,d_) < small_density) flag(ixo^s,d_) = .true.
291  where(w(ixo^s,e_) < small_e) flag(ixo^s,e_) = .true.
292  endif
293 
294  end subroutine srhd_check_w
295 
296  !> Returns logical argument flag T where auxiliary values are not ok
297  subroutine srhd_check_w_aux(ixI^L, ixO^L, w, flag)
299  integer, intent(in) :: ixI^L, ixO^L
300  double precision, intent(in) :: w(ixI^S, nw)
301  logical, intent(inout) :: flag(ixI^S,1:nw)
302 
303  flag=.false.
304 
305  where(w(ixo^s,xi_) < small_xi) flag(ixo^s,xi_) = .true.
306  where(w(ixo^s,lfac_) < one) flag(ixo^s,lfac_) = .true.
307 
308  if(any(flag(ixo^s,xi_)))then
309  write(*,*)'auxiliary xi too low: abort'
310  call mpistop('auxiliary check failed')
311  endif
312  if(any(flag(ixo^s,lfac_)))then
313  write(*,*)'auxiliary lfac too low: abort'
314  call mpistop('auxiliary check failed')
315  endif
316 
317  end subroutine srhd_check_w_aux
318 
319  !> Set auxiliary variables lfac and xi from a primitive state
320  !> only used when handle_small_values average on primitives
321  subroutine srhd_get_auxiliary_prim(ixI^L,ixO^L,w)
323  integer, intent(in) :: ixi^l, ixo^l
324  double precision, intent(inout) :: w(ixi^s, nw)
325  double precision, dimension(ixO^S) :: rho,rhoh,pth
326 
327  ! assume four-velocity in momentum vector (i.e. lfac*v)
328  rho(ixo^s) = sum(w(ixo^s, mom(:))**2, dim=ndim+1)
329  w(ixo^s,lfac_) = dsqrt(1.0d0+rho(ixo^s))
330 
331  rho(ixo^s)=w(ixo^s,rho_)
332  pth(ixo^s)=w(ixo^s,p_)
333  ! compute rho*h (enthalpy h) from density-pressure
334  call srhd_get_enthalpy_eos(ixo^l,rho,pth,rhoh)
335 
336  ! fill auxiliary variable xi= lfac^2 rhoh
337  w(ixo^s,xi_) = w(ixo^s,lfac_)**2.0d0*rhoh(ixo^s)
338 
339  end subroutine srhd_get_auxiliary_prim
340 
341  !> Compute auxiliary variables lfac and xi from a conservative state
342  !> using srhd_con2prim to calculate enthalpy and lorentz factor
343  subroutine srhd_get_auxiliary(ixI^L,ixO^L,w,x)
345  implicit none
346 
347  integer, intent(in) :: ixi^l,ixo^l
348  double precision, intent(inout) :: w(ixi^s, nw)
349  double precision, intent(in) :: x(ixi^s, 1:ndim)
350 
351  integer :: ix^d,ierror,idir
352  integer :: flag_error(ixo^s)
353  double precision :: ssqr
354 
355  if(srhd_eos)then
356  {do ix^db=ixomin^db,ixomax^db\}
357  ierror=0
358  ssqr=0.0d0
359  do idir=1,ndir
360  ssqr= ssqr+w(ix^d,mom(idir))**2
361  enddo
362  if(w(ix^d,d_)<small_density)then
363  print *,'entering con2prim with', w(ix^d,lfac_),w(ix^d,xi_), &
364  w(ix^d,d_),ssqr,w(ix^d,e_)
365  print *,'in position',ix^d,x(ix^d,1:ndim)
367  if(check_small_values) call mpistop('small density on entry con2prim')
369  endif
370  if(w(ix^d,e_)<small_e)then
371  print *,'entering con2prim with', w(ix^d,lfac_),w(ix^d,xi_), &
372  w(ix^d,d_),ssqr,w(ix^d,e_)
373  print *,'in position',ix^d,x(ix^d,1:ndim)
375  if(check_small_values) call mpistop('small energy on entry con2prim')
376  if(fix_small_values) w(ix^d,e_)=small_e
377  endif
378  call con2prim_eos(w(ix^d,lfac_),w(ix^d,xi_), &
379  w(ix^d,d_),ssqr,w(ix^d,e_),ierror)
380  flag_error(ix^d) = ierror
381  {enddo^d&\}
382  else
383  {do ix^db=ixomin^db,ixomax^db\}
384  ierror=0
385  ssqr=0.0d0
386  do idir=1,ndir
387  ssqr= ssqr+w(ix^d,mom(idir))**2
388  enddo
389  if(w(ix^d,d_)<small_density)then
390  print *,'entering con2prim with', w(ix^d,lfac_),w(ix^d,xi_), &
391  w(ix^d,d_),ssqr,w(ix^d,e_)
392  print *,'in position',ix^d,x(ix^d,1:ndim)
394  if(check_small_values) call mpistop('small density on entry con2prim')
396  endif
397  if(w(ix^d,e_)<small_e)then
398  print *,'entering con2prim with', w(ix^d,lfac_),w(ix^d,xi_), &
399  w(ix^d,d_),ssqr,w(ix^d,e_)
400  print *,'in position',ix^d,x(ix^d,1:ndim)
402  if(check_small_values) call mpistop('small energy on entry con2prim')
403  if(fix_small_values) w(ix^d,e_)=small_e
404  endif
405  call con2prim(w(ix^d,lfac_),w(ix^d,xi_), &
406  w(ix^d,d_),ssqr,w(ix^d,e_),ierror)
407  flag_error(ix^d) = ierror
408  {enddo^d&\}
409  endif
410 
411  if(check_small_values)then
412  if(any(flag_error(ixo^s)/=0))then
413  print *,flag_error(ixo^s)
414  call mpistop('Problem when getting auxiliaries')
415  ! call srhd_handle_small_values(.false.,w,x,ixI^L,ixO^L,'srhd_get_auxiliary')
416  end if
417  end if
418 
419  end subroutine srhd_get_auxiliary
420 
421  !> Transform primitive variables into conservative ones
422  subroutine srhd_to_conserved(ixI^L, ixO^L, w, x)
424  integer, intent(in) :: ixi^l, ixo^l
425  double precision, intent(inout) :: w(ixi^s, nw)
426  double precision, intent(in) :: x(ixi^s, 1:ndim)
427  integer :: idir,itr
428  double precision, dimension(ixO^S) :: rhoh,rho,pth
429 
430  ! assume four-velocity in momentum vector (i.e. lfac*v)
431  ! use rhoh slot for temporary array
432  rhoh(ixo^s) = sum(w(ixo^s, mom(:))**2, dim=ndim+1)
433  w(ixo^s,lfac_) = dsqrt(1.0d0+rhoh(ixo^s))
434 
435  rho(ixo^s)=w(ixo^s,rho_)
436  pth(ixo^s)=w(ixo^s,p_)
437  ! compute rho*h (enthalpy h) from density-pressure
438  call srhd_get_enthalpy_eos(ixo^l,rho,pth,rhoh)
439 
440  ! compute rhoh*lfac (recycle rhoh)
441  rhoh(ixo^s)= rhoh(ixo^s)*w(ixo^s,lfac_)
442  ! fill auxiliary variable xi= lfac^2 rhoh
443  w(ixo^s,xi_) = w(ixo^s,lfac_)*rhoh(ixo^s)
444 
445  ! set conservative density: d = lfac * rho
446  w(ixo^s,d_)=w(ixo^s,lfac_)*rho(ixo^s)
447 
448  ! Convert four-velocity (lfac*v) to momentum (xi*v=[rho*h*lfac^2]*v)
449  do idir = 1, ndir
450  w(ixo^s, mom(idir)) = rhoh(ixo^s)*w(ixo^s, mom(idir))
451  end do
452 
453  ! set tau = xi-p-d energy variable
454  w(ixo^s,e_) = w(ixo^s,xi_)-pth(ixo^s)-w(ixo^s,d_)
455 
456  do itr=1,srhd_n_tracer
457  w(ixo^s,tracer(itr)) = w(ixo^s,d_)*w(ixo^s,tracer(itr))
458  end do
459 
460  end subroutine srhd_to_conserved
461 
462  !> Transform conservative variables into primitive ones
463  subroutine srhd_to_primitive(ixI^L, ixO^L, w, x)
465  integer, intent(in) :: ixi^l, ixo^l
466  double precision, intent(inout) :: w(ixi^s, nw)
467  double precision, intent(in) :: x(ixi^s, 1:ndim)
468  integer :: idir,itr
469  double precision, dimension(ixO^S) :: rho,rhoh,e
470  double precision, dimension(ixI^S) :: pth
471  character(len=30) :: subname_loc
472 
473  ! get auxiliary variables lfac and xi from conserved set
474  call srhd_get_auxiliary(ixi^l,ixo^l,w,x)
475 
476  ! from d to rho (d=rho*lfac)
477  rho(ixo^s) = w(ixo^s,d_)/w(ixo^s,lfac_)
478 
479  ! compute pressure
480  ! deduce rho*h from xi/lfac^2
481  rhoh(ixo^s) = w(ixo^s,xi_)/w(ixo^s,lfac_)**2.0d0
482  call srhd_get_pressure_eos(ixi^l,ixo^l,rho,rhoh,pth,e)
483 
484  w(ixo^s,rho_)=rho(ixo^s)
485  ! from xi*v to U=lfac*v (four-velocity)
486  do idir=1,ndir
487  w(ixo^s,mom(idir)) = w(ixo^s,lfac_)*w(ixo^s,mom(idir))&
488  /w(ixo^s,xi_)
489  end do
490  w(ixo^s,p_)=pth(ixo^s)
491 
492  do itr=1,srhd_n_tracer
493  w(ixo^s,tracer(itr)) = w(ixo^s,tracer(itr)) &
494  /(rho(ixo^s)*w(ixo^s,lfac_))
495  end do
496 
497  end subroutine srhd_to_primitive
498 
499  !> Calculate v vector from conservatives
500  subroutine srhd_get_v(w,x,ixI^L,ixO^L,v)
502  integer, intent(in) :: ixI^L, ixO^L
503  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
504  double precision, intent(out) :: v(ixI^S,1:ndir)
505  integer :: idir
506 
507  ! get v from xi*v
508  do idir=1,ndir
509  v(ixo^s,idir) = w(ixo^s, mom(idir))/w(ixo^s,xi_)
510  end do
511 
512  end subroutine srhd_get_v
513 
514  !> Calculate the square of the thermal sound speed csound2 within ixO^L.
515  !> here computed from conservative set WITH ADDED rho*h
516  !> local version: does not do con2prim
517  subroutine srhd_get_csound2_rhoh(w,x,ixI^L,ixO^L,rhoh,csound2)
519  integer, intent(in) :: ixI^L, ixO^L
520  double precision, intent(in) :: w(ixI^S,nw),rhoh(ixO^S)
521  double precision, intent(in) :: x(ixI^S,1:ndim)
522  double precision, intent(out) :: csound2(ixO^S)
523 
524  double precision :: rho(ixO^S)
525 
526  rho=w(ixo^s,d_)/w(ixo^s,lfac_)
527  call srhd_get_csound2_eos(ixi^l,ixo^l,rho,rhoh,csound2)
528 
529  end subroutine srhd_get_csound2_rhoh
530 
531  !> Calculate the square of the thermal sound speed csound2 within ixO^L.
532  !> here computed from conservative set and uses con2prim!!!
533  !> public version!
534  subroutine srhd_get_csound2(w,x,ixI^L,ixO^L,csound2)
536  integer, intent(in) :: ixi^l, ixo^l
537  double precision, intent(inout) :: w(ixi^s,nw)
538  double precision, intent(in) :: x(ixi^s,1:ndim)
539  double precision, intent(out) :: csound2(ixo^s)
540 
541  double precision :: rho(ixo^s),rhoh(ixo^s)
542 
543  ! get auxiliary variables lfac and xi from conserved set
544  call srhd_get_auxiliary(ixi^l,ixo^l,w,x)
545  ! quantify rho, rho*h
546  rho = w(ixo^s,d_)/w(ixo^s,lfac_)
547  rhoh = w(ixo^s,xi_)/w(ixo^s,lfac_)**2.0d0
548  call srhd_get_csound2_eos(ixi^l,ixo^l,rho,rhoh,csound2)
549 
550  end subroutine srhd_get_csound2
551 
552  !> Calculate thermal pressure p within ixO^L
553  !> must follow after update conservative with auxiliaries
554  subroutine srhd_get_pthermal(w, x, ixI^L, ixO^L, pth)
557 
558  integer, intent(in) :: ixi^l, ixo^l
559  double precision, intent(in) :: w(ixi^s, nw)
560  double precision, intent(in) :: x(ixi^s, 1:ndim)
561  double precision, intent(out) :: pth(ixi^s)
562 
563  integer :: iw, ix^d
564  double precision :: rho(ixo^s),rhoh(ixo^s),e(ixo^s)
565 
566  ! quantify rho, rho*h, tau and get pthermal
567  rho = w(ixo^s,d_)/w(ixo^s,lfac_)
568  rhoh = w(ixo^s,xi_)/w(ixo^s,lfac_)**2.0d0
569  call srhd_get_pressure_eos(ixi^l,ixo^l,rho,rhoh,pth,e)
570 
571  end subroutine srhd_get_pthermal
572 
573  !> dummy addsource subroutine
574  ! w[iw]= w[iw]+qdt*S[wCT, qtC, x] where S is the source based on wCT within ixO
575  subroutine srhd_add_source(qdt,dtfactor,ixI^L,ixO^L,wCT,wCTprim,w,x,qsourcesplit,active)
577 
578  integer, intent(in) :: ixI^L, ixO^L
579  double precision, intent(in) :: qdt,dtfactor
580  double precision, intent(in) :: wCT(ixI^S, 1:nw),wCTprim(ixI^S,1:nw), x(ixI^S, 1:ndim)
581  double precision, intent(inout) :: w(ixI^S, 1:nw)
582  logical, intent(in) :: qsourcesplit
583  logical, intent(inout) :: active
584 
585  end subroutine srhd_add_source
586 
587  !> dummy get_dt subroutine
588  subroutine srhd_get_dt(w, ixI^L, ixO^L, dtnew, dx^D, x)
590 
591  integer, intent(in) :: ixI^L, ixO^L
592  double precision, intent(in) :: dx^D, x(ixI^S, 1:^ND)
593  double precision, intent(in) :: w(ixI^S, 1:nw)
594  double precision, intent(inout) :: dtnew
595 
596  dtnew = bigdouble
597 
598  end subroutine srhd_get_dt
599 
600  !> Calculate cmax_idim within ixO^L
601  !> used especially for setdt CFL limit
602  subroutine srhd_get_cmax(w, x, ixI^L, ixO^L, idim, cmax)
604 
605  integer, intent(in) :: ixI^L, ixO^L, idim
606  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S, 1:ndim)
607  double precision, intent(inout) :: cmax(ixI^S)
608 
609  double precision :: wc(ixI^S,nw)
610  double precision, dimension(ixO^S) :: csound2,tmp1,tmp2,v2
611  double precision, dimension(ixI^S) :: vidim, cmin
612 
613  logical :: flag(ixI^S,1:nw)
614 
615  !!call srhd_check_w_aux(ixI^L, ixO^L, w, flag)
616 
617  ! input w is in primitive form TODO use it
618  wc=w
619  call srhd_to_conserved(ixi^l, ixo^l, wc, x)
620  ! auxiliaries are filled here
621  tmp1(ixo^s)=wc(ixo^s,xi_)/wc(ixo^s,lfac_)**2.0d0
622  v2(ixo^s)=1.0d0-1.0d0/wc(ixo^s,lfac_)**2
623  call srhd_get_csound2_rhoh(wc,x,ixi^l,ixo^l,tmp1,csound2)
624  vidim(ixo^s) = wc(ixo^s, mom(idim))/wc(ixo^s, xi_)
625  tmp2(ixo^s)=vidim(ixo^s)**2.0d0
626  tmp1(ixo^s)=1.0d0-v2(ixo^s)*csound2(ixo^s) &
627  -tmp2(ixo^s)*(1.0d0-csound2(ixo^s))
628  tmp2(ixo^s)=dsqrt(csound2(ixo^s)*(one-v2(ixo^s))*tmp1(ixo^s))
629  tmp1(ixo^s)=vidim(ixo^s)*(one-csound2(ixo^s))
630  cmax(ixo^s)=(tmp1(ixo^s)+tmp2(ixo^s))/(one-v2(ixo^s)*csound2(ixo^s))
631  cmin(ixo^s)=(tmp1(ixo^s)-tmp2(ixo^s))/(one-v2(ixo^s)*csound2(ixo^s))
632  ! Limit by speed of light
633  cmin(ixo^s) = max(cmin(ixo^s), - 1.0d0)
634  cmin(ixo^s) = min(cmin(ixo^s), 1.0d0)
635  cmax(ixo^s) = max(cmax(ixo^s), - 1.0d0)
636  cmax(ixo^s) = min(cmax(ixo^s), 1.0d0)
637  ! now take extremal value only for dt limit
638  cmax(ixo^s) = max(dabs(cmax(ixo^s)),dabs(cmin(ixo^s)))
639 
640  end subroutine srhd_get_cmax
641 
642  subroutine srhd_get_a2max(w,x,ixI^L,ixO^L,a2max)
644 
645  integer, intent(in) :: ixI^L, ixO^L
646  double precision, intent(in) :: w(ixI^S, nw), x(ixI^S,1:ndim)
647  double precision, intent(inout) :: a2max(ndim)
648  double precision :: a2(ixI^S,ndim,nw)
649  integer :: gxO^L,hxO^L,jxO^L,kxO^L,i
650 
651  a2=zero
652  do i = 1,ndim
653  !> 4th order
654  hxo^l=ixo^l-kr(i,^d);
655  gxo^l=hxo^l-kr(i,^d);
656  jxo^l=ixo^l+kr(i,^d);
657  kxo^l=jxo^l+kr(i,^d);
658  a2(ixo^s,i,1:nwflux)=dabs(-w(kxo^s,1:nwflux)+16.d0*w(jxo^s,1:nwflux)&
659  -30.d0*w(ixo^s,1:nwflux)+16.d0*w(hxo^s,1:nwflux)-w(gxo^s,1:nwflux))
660  a2max(i)=maxval(a2(ixo^s,i,1:nwflux))/12.d0/dxlevel(i)**2
661  end do
662 
663  end subroutine srhd_get_a2max
664 
665  !> local version for recycling code when computing cmax-cmin
666  subroutine srhd_get_cmax_loc(ixI^L,ixO^L,vidim,csound2,v2,cmax,cmin)
668  integer, intent(in) :: ixI^L, ixO^L
669  double precision, intent(in) :: vidim(ixI^S)
670  double precision, intent(in), dimension(ixO^S) :: csound2
671  double precision, intent(in) :: v2(ixI^S)
672  double precision, intent(out) :: cmax(ixI^S)
673  double precision, intent(out) :: cmin(ixI^S)
674 
675  double precision, dimension(ixI^S):: tmp1,tmp2
676 
677  tmp2(ixo^s)=vidim(ixo^s)**2.0d0
678  tmp1(ixo^s)=1.0d0-v2(ixo^s)*csound2(ixo^s) &
679  -tmp2(ixo^s)*(1.0d0-csound2(ixo^s))
680  tmp2(ixo^s)=dsqrt(csound2(ixo^s)*(one-v2(ixo^s))*tmp1(ixo^s))
681  tmp1(ixo^s)=vidim(ixo^s)*(one-csound2(ixo^s))
682  cmax(ixo^s)=(tmp1(ixo^s)+tmp2(ixo^s))/(one-v2(ixo^s)*csound2(ixo^s))
683  ! Limit by speed of light
684  cmax(ixo^s) = max(cmax(ixo^s), - 1.0d0)
685  cmax(ixo^s) = min(cmax(ixo^s), 1.0d0)
686  cmin(ixo^s)=(tmp1(ixo^s)-tmp2(ixo^s))/(one-v2(ixo^s)*csound2(ixo^s))
687  ! Limit by speed of light
688  cmin(ixo^s) = max(cmin(ixo^s), - 1.0d0)
689  cmin(ixo^s) = min(cmin(ixo^s), 1.0d0)
690 
691  end subroutine srhd_get_cmax_loc
692 
693  !> Estimating bounds for the minimum and maximum signal velocities
694  !> here we will not use Hspeed at all (one species only)
695  subroutine srhd_get_cbounds(wLC,wRC,wLp,wRp,x,ixI^L,ixO^L,idim,Hspeed,cmax,cmin)
697  use mod_variables
698 
699  integer, intent(in) :: ixI^L, ixO^L, idim
700  ! conservative left and right status
701  double precision, intent(in) :: wLC(ixI^S, nw), wRC(ixI^S, nw)
702  ! primitive left and right status
703  double precision, intent(in) :: wLp(ixI^S, nw), wRp(ixI^S, nw)
704  double precision, intent(in) :: x(ixI^S, 1:ndim)
705  double precision, intent(inout) :: cmax(ixI^S,1:number_species)
706  double precision, intent(inout), optional :: cmin(ixI^S,1:number_species)
707  double precision, intent(in) :: Hspeed(ixI^S,1:number_species)
708 
709  double precision :: wmean(ixI^S,nw)
710  double precision, dimension(ixO^S) :: csound2,tmp1,tmp2,tmp3
711  double precision, dimension(ixI^S) :: vidim,cmaxL,cmaxR,cminL,cminR,v2
712 
713  logical :: flag(ixI^S,1:nw)
714 
715  select case(boundspeed)
716  case(1) ! we do left-right first and take maximals
717  !!call srhd_check_w(.true.,ixI^L, ixO^L, wLp, flag)
718  !!call srhd_check_w_aux(ixI^L, ixO^L, wLp, flag)
719  tmp1=wlp(ixo^s,rho_)
720  tmp2=wlp(ixo^s,xi_)/wlp(ixo^s,lfac_)**2.0d0
721  tmp3=wlp(ixo^s,p_)
722  call srhd_get_csound2_prim_eos(ixo^l,tmp1,tmp2,tmp3,csound2)
723  vidim(ixo^s) = wlp(ixo^s, mom(idim))/wlp(ixo^s, lfac_)
724  v2(ixo^s) = 1.0d0-1.0d0/wlp(ixo^s,lfac_)**2
725  call srhd_get_cmax_loc(ixi^l,ixo^l,vidim,csound2,v2,cmaxl,cminl)
726 
727  !!call srhd_check_w(.true.,ixI^L, ixO^L, wRp, flag)
728  !!call srhd_check_w_aux(ixI^L, ixO^L, wRp, flag)
729  tmp1=wrp(ixo^s,rho_)
730  tmp2=wrp(ixo^s,xi_)/wrp(ixo^s,lfac_)**2.0d0
731  tmp3=wrp(ixo^s,p_)
732  call srhd_get_csound2_prim_eos(ixo^l,tmp1,tmp2,tmp3,csound2)
733  vidim(ixo^s) = wrp(ixo^s, mom(idim))/wrp(ixo^s, lfac_)
734  v2(ixo^s) = 1.0d0-1.0d0/wrp(ixo^s,lfac_)**2
735  call srhd_get_cmax_loc(ixi^l,ixo^l,vidim,csound2,v2,cmaxr,cminr)
736 
737  if(present(cmin))then
738  ! for HLL
739  cmax(ixo^s,1)=max(cmaxl(ixo^s),cmaxr(ixo^s))
740  cmin(ixo^s,1)=min(cminl(ixo^s),cminr(ixo^s))
741  else
742  ! for TVDLF
743  cmaxl(ixo^s)=max(cmaxl(ixo^s),dabs(cminl(ixo^s)))
744  cmaxr(ixo^s)=max(cmaxr(ixo^s),dabs(cminr(ixo^s)))
745  cmax(ixo^s,1)=max(cmaxl(ixo^s),cmaxr(ixo^s))
746  endif
747  case(2) ! this is cmaxmean from conservatives
748  ! here we do arithmetic mean of conservative vars
749  wmean(ixo^s,1:nwflux)=0.5d0*(wlc(ixo^s,1:nwflux)+wrc(ixo^s,1:nwflux))
750  ! get auxiliary variables
751  call srhd_get_auxiliary(ixi^l,ixo^l,wmean,x)
752  ! here tmp1 is rhoh
753  tmp1=wmean(ixo^s,xi_)/wmean(ixo^s,lfac_)**2.0d0
754  call srhd_get_csound2_rhoh(wmean,x,ixi^l,ixo^l,tmp1,csound2)
755  vidim(ixo^s) = wmean(ixo^s, mom(idim))/wmean(ixo^s, xi_)
756  v2(ixo^s)=1.0d0-1.0d0/wmean(ixo^s,lfac_)**2
757  call srhd_get_cmax_loc(ixi^l,ixo^l,vidim,csound2,v2,cmaxl,cminl)
758  if(present(cmin)) then
759  cmax(ixo^s,1)=cmaxl(ixo^s)
760  cmin(ixo^s,1)=cminl(ixo^s)
761  else
762  cmax(ixo^s,1)=max(cmaxl(ixo^s),dabs(cminl(ixo^s)))
763  endif
764  case(3) ! this is cmaxmean from primitives
765  ! here we do arithmetic mean of primitive vars
766  wmean(ixo^s,1:nwflux)=0.5d0*(wlp(ixo^s,1:nwflux)+wrp(ixo^s,1:nwflux))
767  ! get auxiliary variables for wmean (primitive array)
768  call srhd_get_auxiliary_prim(ixi^l,ixo^l,wmean)
769  ! here tmp1 is rhoh
770  tmp1=wmean(ixo^s,rho_)
771  tmp2=wmean(ixo^s,xi_)/wmean(ixo^s,lfac_)**2.0d0
772  tmp3=wmean(ixo^s,p_)
773  call srhd_get_csound2_prim_eos(ixo^l,tmp1,tmp2,tmp3,csound2)
774  vidim(ixo^s) = wmean(ixo^s, mom(idim))/wmean(ixo^s, lfac_)
775  v2(ixo^s) = 1.0d0-1.0d0/wmean(ixo^s,lfac_)**2
776  call srhd_get_cmax_loc(ixi^l,ixo^l,vidim,csound2,v2,cmaxl,cminl)
777  if(present(cmin)) then
778  cmax(ixo^s,1)=cmaxl(ixo^s)
779  cmin(ixo^s,1)=cminl(ixo^s)
780  else
781  cmax(ixo^s,1)=max(cmaxl(ixo^s),dabs(cminl(ixo^s)))
782  endif
783  end select
784 
785  end subroutine srhd_get_cbounds
786 
787  !> Calculate fluxes within ixO^L.
788  subroutine srhd_get_flux(wC,wP,x,ixI^L,ixO^L,idim,f)
790  integer, intent(in) :: ixI^L, ixO^L, idim
791  ! conservative w
792  double precision, intent(in) :: wC(ixI^S,nw)
793  ! primitive w
794  double precision, intent(in) :: wP(ixI^S,nw)
795  double precision, intent(in) :: x(ixI^S,1:ndim)
796  double precision,intent(out) :: f(ixI^S,nwflux)
797 
798  double precision :: pth(ixI^S)
799  double precision :: v(ixI^S,1:ndir)
800  integer :: iw,idir
801 
802  pth(ixo^s)=wp(ixo^s,p_)
803  do idir=1,ndir
804  v(ixo^s,idir) = wp(ixo^s, mom(idir))/wp(ixo^s,lfac_)
805  end do
806 
807  ! Get flux of density d, namely D*v
808  f(ixo^s,d_)=v(ixo^s,idim)*wc(ixo^s,rho_)
809 
810  ! Get flux of tracer
811  do iw=1,srhd_n_tracer
812  f(ixo^s,tracer(iw))=v(ixo^s,idim)*wc(ixo^s,tracer(iw))
813  end do
814 
815  ! Get flux of momentum
816  ! f_i[m_k]=v_i*m_k [+pth if i==k]
817  do idir=1,ndir
818  f(ixo^s,mom(idir))= v(ixo^s,idim)*wc(ixo^s,mom(idir))
819  end do
820  f(ixo^s,mom(idim))=pth(ixo^s)+f(ixo^s,mom(idim))
821 
822  ! Get flux of energy
823  ! f_i[e]=v_i*e+v_i*pth
824  f(ixo^s,e_)=v(ixo^s,idim)*(wc(ixo^s,e_) + pth(ixo^s))
825 
826  end subroutine srhd_get_flux
827 
828  !> Add geometrical source terms to w
829  subroutine srhd_add_source_geom(qdt, dtfactor, ixI^L, ixO^L, wCT, wprim, w, x)
832  use mod_geometry
833  integer, intent(in) :: ixI^L, ixO^L
834  double precision, intent(in) :: qdt, dtfactor, x(ixI^S, 1:ndim)
835  double precision, intent(inout) :: wCT(ixI^S, 1:nw), wprim(ixI^S, 1:nw), w(ixI^S, 1:nw)
836 
837  double precision :: pth(ixI^S), source(ixI^S), v(ixI^S,1:ndir)
838  integer :: idir, h1x^L{^NOONED, h2x^L}
839  integer :: mr_,mphi_ ! Polar var. names
840  double precision :: exp_factor(ixI^S), del_exp_factor(ixI^S), exp_factor_primitive(ixI^S)
841 
842  select case (coordinate)
843 
844  case(cartesian_expansion)
845  !the user provides the functions of exp_factor and del_exp_factor
846  if(associated(usr_set_surface)) &
847  call usr_set_surface(ixi^l,x,block%dx,exp_factor,del_exp_factor,exp_factor_primitive)
848  ! get auxiliary variables lfac and xi from conserved set
849  call srhd_get_auxiliary(ixi^l,ixo^l,wct,x)
850  call srhd_get_pthermal(wct, x, ixi^l, ixo^l, source)
851  source(ixo^s) = source(ixo^s)*del_exp_factor(ixo^s)/exp_factor(ixo^s)
852  w(ixo^s,mom(1)) = w(ixo^s,mom(1)) + qdt*source(ixo^s)
853 
854  case (cylindrical)
855  mr_ = mom(r_)
856  ! get auxiliary variables lfac and xi from conserved set
857  call srhd_get_auxiliary(ixi^l,ixo^l,wct,x)
858  call srhd_get_pthermal(wct, x, ixi^l, ixo^l, source)
859  if (phi_ > 0) then
860  mphi_ = mom(phi_)
861  source(ixo^s) = source(ixo^s) + wct(ixo^s, mphi_)*wprim(ixo^s,mom(phi_))
862  w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * source(ixo^s) / x(ixo^s, r_)
863  source(ixo^s) = -wct(ixo^s, mphi_) * wprim(ixo^s,mom(r_))
864  w(ixo^s, mphi_) = w(ixo^s, mphi_) + qdt * source(ixo^s) / x(ixo^s, r_)
865  else
866  w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * source(ixo^s) / x(ixo^s, r_)
867  end if
868 
869  case (spherical)
870  mr_ = mom(r_)
871  h1x^l=ixo^l-kr(1,^d); {^nooned h2x^l=ixo^l-kr(2,^d);}
872  ! s[mr]=((stheta*vtheta+sphi*vphi)+2*p)/r
873  ! get auxiliary variables lfac and xi from conserved set
874  call srhd_get_auxiliary(ixi^l,ixo^l,wct,x)
875  call srhd_get_pthermal(wct, x, ixi^l, ixo^l, pth)
876  source(ixo^s) = pth(ixo^s) * x(ixo^s, 1) &
877  *(block%surfaceC(ixo^s, 1) - block%surfaceC(h1x^s, 1)) &
878  /block%dvolume(ixo^s)
879  if (ndir > 1) then
880  do idir = 2, ndir
881  source(ixo^s) = source(ixo^s) + wct(ixo^s, mom(idir))*wprim(ixo^s,mom(idir))
882  end do
883  end if
884  w(ixo^s, mr_) = w(ixo^s, mr_) + qdt * source(ixo^s) / x(ixo^s, 1)
885 
886  {^nooned
887  ! s[mtheta]=-(stheta*vr)/r+cot(theta)*(sphi*vphi+p)/r
888  source(ixo^s) = pth(ixo^s) * x(ixo^s, 1) &
889  * (block%surfaceC(ixo^s, 2) - block%surfaceC(h2x^s, 2)) &
890  / block%dvolume(ixo^s)
891  if (ndir == 3) then
892  source(ixo^s) = source(ixo^s) + (wct(ixo^s, mom(3))*v(ixo^s,ndir)) / dtan(x(ixo^s, 2))
893  end if
894  source(ixo^s) = source(ixo^s) - wct(ixo^s, mom(2)) * wprim(ixo^s, mom(1))
895  w(ixo^s, mom(2)) = w(ixo^s, mom(2)) + qdt * source(ixo^s) / x(ixo^s, 1)
896 
897  if (ndir == 3) then
898  ! s[mphi]=-(sphi*vr)/r-cot(theta)*(sphi*vtheta)/r
899  source(ixo^s) = -(wct(ixo^s, mom(3)) * wprim(ixo^s, mom(1))) &
900  - (wct(ixo^s, mom(3)) * wprim(ixo^s, mom(2))) / dtan(x(ixo^s, 2))
901  w(ixo^s, mom(3)) = w(ixo^s, mom(3)) + qdt * source(ixo^s) / x(ixo^s, 1)
902  end if
903  }
904  end select
905 
906  end subroutine srhd_add_source_geom
907 
908  !> handles bootstrapping
909  subroutine srhd_handle_small_values(primitive, w, x, ixI^L, ixO^L, subname)
911  use mod_small_values
912  logical, intent(in) :: primitive
913  integer, intent(in) :: ixI^L,ixO^L
914  double precision, intent(inout) :: w(ixI^S,1:nw)
915  double precision, intent(in) :: x(ixI^S,1:ndim)
916  character(len=*), intent(in) :: subname
917 
918  integer :: n,idir
919  logical :: flag(ixI^S,1:nw),flagall(ixI^S)
920 
921  call srhd_check_w(primitive, ixi^l, ixo^l, w, flag)
922 
923  if (any(flag)) then
924  select case (small_values_method)
925  case ("replace")
926  ! any faulty cell is replaced by physical lower limit
927  flagall(ixo^s)=(flag(ixo^s,rho_).or.flag(ixo^s,e_))
928 
929  where(flagall(ixo^s))
930  ! D or rho: no difference primitive-conservative
931  w(ixo^s,rho_) = small_density
932  !w(ixO^S,lfac_)= 1.0d0
933  !w(ixO^S,xi_) = small_xi
934  endwhere
935  !do idir = 1, ndir
936  ! where(flagall(ixO^S)) w(ixO^S, mom(idir)) = 0.0d0
937  !end do
938  if(primitive) then
939  where(flagall(ixo^s)) w(ixo^s, p_) = small_pressure
940  else
941  where(flagall(ixo^s)) w(ixo^s, e_) = small_e
942  endif
943 
944  case ("average")
945  ! note: in small_values_average we use
946  ! small_values_fix_iw(1:nw) and small_values_daverage
947  ! when fails, may use small_pressure/small_density
948  if(primitive)then
949  ! averaging for all primitive fields (p, lfac*v, tau))
950  call small_values_average(ixi^l, ixo^l, w, x, flag)
951  ! update the auxiliaries from primitives
952  call srhd_get_auxiliary_prim(ixi^l,ixo^l,w)
953  else
954  ! do averaging of density d
955  call small_values_average(ixi^l, ixo^l, w, x, flag, d_)
956  ! do averaging of energy tau
957  call small_values_average(ixi^l, ixo^l, w, x, flag, e_)
958  ! and now hope for the best....
959  endif
960  case default
961  if(.not.primitive) then
962  ! note that we throw error here, which assumes w is primitive
963  write(*,*) "handle_small_values default: note reporting conservatives!"
964  end if
965  call small_values_error(w, x, ixi^l, ixo^l, flag, subname)
966  end select
967  end if
968 
969  end subroutine srhd_handle_small_values
970 
971  !> calculate effective gamma
972  subroutine srhd_get_geff_eos(w,ixI^L,ixO^L,varconserve,Geff)
973  use mod_global_parameters, only: nw
974  !================== IMPORTANT ==================!
975  !This subroutine is used with conserved variables in w when varconserve=T
976  !This subroutine is used with primitive variables in w when varconserve=F
977  ! both cases assume updated auxiliary variables xi_ en lfac_
978  !===============================================!
979  integer, intent(in) :: ixi^l,ixo^l
980  double precision, intent(in) :: w(ixi^s, 1:nw)
981  logical, intent(in) :: varconserve
982  double precision, intent(out) :: geff(ixi^s)
983 
984  double precision, dimension(ixO^S) :: pth,rho,e_th,e
985 
986  if (srhd_eos) then
987  if (varconserve) then
988  pth(ixo^s)=w(ixo^s,xi_)-w(ixo^s,e_)-w(ixo^s,d_)
989  rho(ixo^s)=w(ixo^s,d_)/w(ixo^s,lfac_)
990  e_th = pth*inv_gamma_1
991  e = e_th+dsqrt(e_th**2+rho**2)
992  geff(ixo^s) = srhd_gamma-half*gamma_1 * &
993  (one-(rho(ixo^s)/e(ixo^s))**2)
994  else
995  ! primitives available
996  e_th = w(ixo^s,p_)*inv_gamma_1
997  e = e_th+dsqrt(e_th**2+w(ixo^s,rho_)**2)
998  geff(ixo^s) = srhd_gamma-half*gamma_1 * &
999  (one-(w(ixo^s,rho_)/e(ixo^s))**2)
1000  end if
1001  else
1002  geff(ixo^s) = srhd_gamma
1003  endif
1004 
1005  end subroutine srhd_get_geff_eos
1006 
1007  !> Compute the small value limits
1010  implicit none
1011  ! local small values
1012  double precision :: LsmallE,Lsmallp,Lsmallrho
1013 
1014  ! the maximal allowed Lorentz factor
1015  lfacmax=one/dsqrt(one-(one-dmaxvel)**2)
1018  if(small_density*small_pressure<=0.0d0)then
1019  call mpistop("must set finite values small-density/pressure for small value treatments")
1020  endif
1021  if(srhd_eos)then
1022  lsmallp=(one+10.d0*small_pressure)*small_pressure
1023  lsmallrho=(one+10.d0*small_density)*small_density
1024  !!Lsmallp=small_pressure
1025  !!Lsmallrho=small_density
1026  lsmalle=lsmallp*inv_gamma_1+&
1027  dsqrt((lsmallp*inv_gamma_1)**2+lsmallrho**2)
1028  small_xi=half*((srhd_gamma+one)*lsmalle-&
1029  gamma_1*lsmallrho*(lsmallrho/lsmalle))
1030  small_e=small_xi-lsmallp-lsmallrho
1031  else
1034  endif
1037 
1038  end subroutine srhd_get_smallvalues_eos
1039 
1040  !> Compute the enthalpy rho*h from rho and pressure p
1041  subroutine srhd_get_enthalpy_eos(ixO^L,rho,p,rhoh)
1043  integer, intent(in) :: ixo^l
1044  double precision, intent(in) :: rho(ixo^s),p(ixo^s)
1045  double precision, intent(out) :: rhoh(ixo^s)
1046 
1047  double precision, dimension(ixO^S) :: e_th,e
1048  integer :: ix^d
1049 
1050  if(srhd_eos) then
1051  e_th = p*inv_gamma_1
1052  e = e_th+dsqrt(e_th**2+rho**2)
1053  ! writing rho/E on purpose, for numerics
1054  rhoh = half*((srhd_gamma+one)*e &
1055  - gamma_1*rho*(rho/e))
1056  else
1057  rhoh = rho+gamma_to_gamma_1*p
1058  end if
1059 
1060  if (check_small_values) then
1061  {do ix^db= ixo^lim^db\}
1062  if(rhoh(ix^d)<small_xi) then
1063  write(*,*) "local pressure and density",p(ix^d),rho(ix^d)
1064  write(*,*) "Error: small value of enthalpy rho*h=",rhoh(ix^d),&
1065  " encountered when call srhd_get_enthalpy_eos"
1066  call mpistop('enthalpy below small_xi: stop (may need to turn on fixes)')
1067  end if
1068  {enddo^d&\}
1069  end if
1070 
1071  if (fix_small_values) then
1072  {do ix^db= ixo^lim^db\}
1073  if(rhoh(ix^d)<small_xi) then
1074  rhoh(ix^d)=small_xi
1075  endif
1076  {enddo^d&\}
1077  endif
1078 
1079  end subroutine srhd_get_enthalpy_eos
1080 
1081  !> Calculate thermal pressure p from density rho and enthalpy rho*h
1082  !> will provide p (and E if srhd_eos)
1083  subroutine srhd_get_pressure_eos(ixI^L,ixO^L,rho,rhoh,p,E)
1085  integer, intent(in) :: ixI^L, ixO^L
1086  double precision, intent(in) :: rho(ixO^S),rhoh(ixO^S)
1087  double precision, intent(out) :: p(ixI^S)
1088  double precision, intent(out) :: E(ixO^S)
1089  integer :: ix^D
1090 
1091  if(srhd_eos) then
1092  e = (rhoh+dsqrt(rhoh**2+(srhd_gamma**2-one)*rho**2)) &
1093  /(srhd_gamma+one)
1094  p(ixo^s) = half*gamma_1* (e-rho*(rho/e))
1095  else
1096  p(ixo^s) = (rhoh-rho)/gamma_to_gamma_1
1097  end if
1098 
1099  if (check_small_values) then
1100  {do ix^db= ixo^lim^db\}
1101  if(p(ix^d)<small_pressure) then
1102  write(*,*) "local enthalpy rho*h and density rho",rhoh(ix^d),rho(ix^d)
1103  if(srhd_eos) write(*,*) 'E, rho^2/E, difference', &
1104  e(ix^d),rho(ix^d)**2/e(ix^d),e(ix^d)-rho(ix^d)**2/e(ix^d)
1105  write(*,*) "Error: small value of gas pressure",p(ix^d),&
1106  " encountered when call srhd_get_pressure_eos"
1107  call mpistop('pressure below small_pressure: stop (may need to turn on fixes)')
1108  end if
1109  {enddo^d&\}
1110  end if
1111 
1112  if (fix_small_values) then
1113  {do ix^db= ixo^lim^db\}
1114  if(p(ix^d)<small_pressure) then
1115  p(ix^d)=small_pressure
1116  if(srhd_eos)e(ix^d)=max(small_e,e(ix^d))
1117  endif
1118  {enddo^d&\}
1119  endif
1120 
1121  end subroutine srhd_get_pressure_eos
1122 
1123  !> Calculate the square of the thermal sound speed csound2 within ixO^L.
1124  !> available rho - rho*h
1125  subroutine srhd_get_csound2_eos(ixI^L,ixO^L,rho,rhoh,csound2)
1127  integer, intent(in) :: ixI^L, ixO^L
1128  double precision, intent(in) :: rho(ixO^S),rhoh(ixO^S)
1129  double precision, intent(out) :: csound2(ixO^S)
1130 
1131  double precision :: p(ixI^S)
1132  double precision :: E(ixO^S)
1133  integer :: ix^D
1134 
1135  call srhd_get_pressure_eos(ixi^l,ixo^l,rho,rhoh,p,e)
1136  if(srhd_eos) then
1137  csound2(ixo^s)=(p(ixo^s)*((srhd_gamma+one)&
1138  +gamma_1*(rho(ixo^s)/e(ixo^s))**2))&
1139  /(2.0d0*rhoh(ixo^s))
1140  else
1141  csound2(ixo^s)=srhd_gamma*p(ixo^s)/rhoh(ixo^s)
1142  end if
1143 
1144  if (check_small_values) then
1145  {do ix^db= ixo^lim^db\}
1146  if(csound2(ix^d)>=1.0d0.or.csound2(ix^d)<=0.0d0) then
1147  write(*,*) "sound speed error with p - rho - rhoh",p(ix^d),rhoh(ix^d),rho(ix^d)
1148  if(srhd_eos) write(*,*) 'and E', e(ix^d)
1149  write(*,*) "Error: value of csound2",csound2(ix^d),&
1150  " encountered when call srhd_get_csound2_eos"
1151  call mpistop('sound speed stop (may need to turn on fixes)')
1152  end if
1153  {enddo^d&\}
1154  end if
1155 
1156  if (fix_small_values) then
1157  {do ix^db= ixo^lim^db\}
1158  if(csound2(ix^d)>=1.0d0) then
1159  csound2(ix^d)=1.0d0-1.0d0/lfacmax**2
1160  endif
1161  if(csound2(ix^d)<=0.0d0) then
1162  csound2(ix^d)=srhd_gamma*small_pressure/small_xi
1163  endif
1164  {enddo^d&\}
1165  endif
1166 
1167  end subroutine srhd_get_csound2_eos
1168 
1169  !> Calculate the square of the thermal sound speed csound2 within ixO^L.
1170  !> available rho - rho*h - p
1171  subroutine srhd_get_csound2_prim_eos(ixO^L,rho,rhoh,p,csound2)
1173  integer, intent(in) :: ixO^L
1174  double precision, intent(in) :: rho(ixO^S),rhoh(ixO^S),p(ixO^S)
1175  double precision, intent(out) :: csound2(ixO^S)
1176 
1177  double precision :: E(ixO^S)
1178  integer :: ix^D
1179 
1180  if(srhd_eos) then
1181  e = (rhoh+dsqrt(rhoh**2+(srhd_gamma**2-one)&
1182  *rho**2))/(srhd_gamma+one)
1183  csound2(ixo^s)=(p*((srhd_gamma+one)&
1184  +gamma_1*(rho/e)**2))&
1185  /(2.0d0*rhoh)
1186  else
1187  csound2(ixo^s)=srhd_gamma*p/rhoh
1188  end if
1189 
1190  if (check_small_values) then
1191  {do ix^db= ixo^lim^db\}
1192  if(csound2(ix^d)>=1.0d0.or.csound2(ix^d)<=0.0d0) then
1193  write(*,*) "sound speed error with p - rho - rhoh",p(ix^d),rhoh(ix^d),rho(ix^d)
1194  if(srhd_eos) write(*,*) 'and E', e(ix^d)
1195  write(*,*) "Error: value of csound2",csound2(ix^d),&
1196  " encountered when call srhd_get_csound2_prim_eos"
1197  call mpistop('sound speed stop (may need to turn on fixes)')
1198  end if
1199  {enddo^d&\}
1200  end if
1201 
1202  if (fix_small_values) then
1203  {do ix^db= ixo^lim^db\}
1204  if(csound2(ix^d)>=1.0d0) then
1205  csound2(ix^d)=1.0d0-1.0d0/lfacmax**2
1206  endif
1207  if(csound2(ix^d)<=0.0d0) then
1208  csound2(ix^d)=srhd_gamma*small_pressure/small_xi
1209  endif
1210  {enddo^d&\}
1211  endif
1212 
1213  end subroutine srhd_get_csound2_prim_eos
1214 
1215  !> con2prim: (D,S**2,tau) --> compute auxiliaries lfac and xi
1216  subroutine con2prim_eos(lfac,xi,myd,myssqr,mytau,ierror)
1217  use mod_con2prim_vars
1218 
1219  double precision, intent(in) :: myd, myssqr, mytau
1220  double precision, intent(inout) :: lfac, xi
1221  integer, intent(inout) :: ierror
1222 
1223  ! .. local ..
1224  double precision:: f,df,lfacl
1225  !------------------------------------------------------------------
1226 
1227  ! Save the input-state in mod_con2prim_vars
1228  d = myd; ssqr = myssqr; tau = mytau;
1229 
1230  ierror=0
1231 
1232  ! Check if guess is close enough: gives f,df,lfacl
1233  if(xi>smallxi)then
1234  call funcd_eos(xi,f,df,lfacl,d,ssqr,tau,ierror)
1235  if (ierror == 0 .and. dabs(f/df)<absaccnr) then
1236  xi = xi - f/df
1237  lfac = lfacl
1238  return
1239  else
1240  ierror = 0
1241  end if
1242  else
1243  write(*,*)'entering con2prim_eos with xi=',xi
1244  end if
1245 
1246  ! ierror=1 : must have D>=minrho, tau>=smalltau
1247  !if(d<minrho .or. tau<smalltau)then
1248  ! ierror=1
1249  ! return
1250  !endif
1251 
1252  call con2primhydro_eos(lfac,xi,d,ssqr,tau,ierror)
1253 
1254  end subroutine con2prim_eos
1255 
1256  subroutine funcd_eos(xi,f,df,mylfac,d,ssqr,tau,ierror)
1257  double precision, intent(in) :: xi,d,ssqr,tau
1258  double precision, intent(out) :: f,df,mylfac
1259  integer, intent(inout) :: ierror
1260 
1261  ! .. local ..
1262  double precision :: dlfac
1263  double precision :: vsqr,p,dpdxi
1264  !-----------------------------------------------------------------
1265 
1266  vsqr = ssqr/xi**2
1267 
1268  if (vsqr<one) then
1269  mylfac = one/dsqrt(one-vsqr)
1270  dlfac = -mylfac**3*ssqr/(xi**3)
1271  !===== Pressure, calculate using EOS =====!
1272  call funcpressure_eos(xi,mylfac,d,dlfac,p,dpdxi)
1273  !=========================================!
1274  f = xi-tau-d-p
1275  df = one-dpdxi
1276  else
1277  ! print *,'Erroneous input to funcd since vsqr=',vsqr,' >=1'
1278  ! print *,'input values d, ssqr, tau:',d,ssqr,tau
1279  ierror =6
1280  return
1281  end if
1282 
1283  end subroutine funcd_eos
1284 
1285  !> SRHD iteration solves for p via NR, and then gives xi as output
1286  subroutine con2primhydro_eos(lfac,xi,d,sqrs,tau,ierror)
1287  double precision, intent(out) :: xi,lfac
1288  double precision, intent(in) :: d,sqrs,tau
1289  integer,intent(inout) :: ierror
1290 
1291  ! .. local ..
1292  integer :: ni,niiter,nit,n2it,ni3
1293  double precision :: pcurrent,pnew
1294  double precision :: er,er1,ff,df,dp,v2
1295  double precision :: pmin,lfac2inv,pLabs,pRabs,pprev
1296  double precision :: s2overcubeG2rh
1297  double precision :: xicurrent,h,dhdp
1298  double precision :: oldff1,oldff2,Nff
1299  double precision :: pleft,pright
1300  !---------------------------------------------------------------------
1301 
1302  ierror=0
1303  ! ierror=0 : ok
1304  ! we already checked D>=minrho, tau>=smalltau (ierror=1)
1305  !
1306  ! ierror<>0
1307  !
1308  ! ierror=2 : maxitnr reached without convergence
1309  ! ierror=3 : final pressure value < smallp or xi<smallxi during iteration
1310  ! ierror=4 : final v^2=1 hence problem as lfac=1/0
1311  ! ierror=5 : nonmonotonic function f (as df=0)
1312 
1313  ! left and right brackets for p-range
1314  pmin=dsqrt(sqrs)/(one-dmaxvel)-tau-d
1315  plabs=max(minp,pmin)
1316  prabs=1.0d99
1317  ! start value from input
1318  pcurrent=plabs
1319 
1320  er1=one
1321  pprev=pcurrent
1322 
1323  ! Fudge Parameters
1324  oldff1=1.0d7 ! High number
1325  oldff2=1.0d9 ! High number bigger then oldff1
1326  n2it = 0
1327  nit = 0
1328 
1329  loopnr: do ni=1,maxitnr
1330  nit = nit + 1
1331  !=== Relax NR iteration accuracy=======!
1332  if(nit>maxitnr/4)then
1333  ! mix pressure value for convergence
1334  pcurrent=half*(pcurrent+pprev)
1335  ! relax accuracy requirement
1336  er1=10.0d0*er1
1337  nit = nit - maxitnr/10
1338  endif
1339  !=======================================!
1340 
1341  niiter=ni
1342  xicurrent=tau+d+pcurrent
1343 
1344  if(xicurrent<smallxi) then
1345  ! print *,'stop: too small xi iterate:',xicurrent
1346  ! print *,'for pressure iterate p',pcurrent
1347  ! print *,'pressure bracket pLabs pRabs',pLabs,pRabs
1348  ! print *,'iteration number:',ni
1349  ! print *,'values for d,s,tau,s2:',d,sqrs,tau,sqrs
1350  ierror=3
1351  return
1352  endif
1353 
1354  v2=sqrs/xicurrent**2
1355  lfac2inv=one - v2
1356  if(lfac2inv>zero) then
1357  lfac=one/dsqrt(lfac2inv)
1358  else
1359  ! print *,'stop: negative or zero factor 1-v2:',lfac2inv
1360  ! print *,'for pressure iterate p',pcurrent
1361  ! print *,'absolute pressure bracket pLabs pRabs',pLabs,pRabs
1362  ! print *,'iteration number:',ni
1363  ! print *,'values for d,s,tau,s2:',d,sqrs,tau,sqrs
1364  ! print *,'values for v2,xi:',v2,xicurrent
1365  ierror=4
1366  return
1367  endif
1368 
1369  s2overcubeg2rh=sqrs/(xicurrent**3)
1370  !== calculation done using the EOS ==!
1371  call funcenthalpy_eos(pcurrent,lfac2inv,d,sqrs,xicurrent,&
1372  s2overcubeg2rh,h,dhdp)
1373  !=======================================!
1374  ff=-xicurrent*lfac2inv + h
1375  df=- two*sqrs/xicurrent**2 + dhdp - lfac2inv
1376 
1377  if (ff*df==zero) then
1378  if (ff==zero) then
1379  exit ! zero found
1380  else
1381  ! print *,'stop: df becomes zero, non-monotonic f(p)!'
1382  ierror=5
1383  return
1384  endif
1385  else
1386  pnew=pcurrent-ff/df
1387  if (ff*df>zero) then
1388  ! pressure iterate has decreased
1389  ! restrict to left
1390  pnew=max(pnew,plabs)
1391  else ! ff*df<0
1392  ! pressure iterate has increased
1393  ! restrict to right
1394  pnew=min(pnew,prabs)
1395  endif
1396  endif
1397 
1398  !===============================================!
1399  dp=pcurrent-pnew
1400  er=two*dabs(dp)/(pnew+pcurrent)
1401  if(((er<tolernr*er1).or.(dabs(dp)<absaccnr))) exit loopnr
1402  !===============================================!
1403 
1404  ! For very small values of pressure, NR algorithm is not efficient to
1405  ! find root, use Euler algorithm to find precise value of pressure
1406  if((dabs(oldff2-ff) < 1.0d-8 .or. niiter >= maxitnr-maxitnr/20).and.&
1407  ff * oldff1 < zero .and. dabs(ff)>absaccnr)then
1408 
1409  n2it=n2it+1
1410  if(n2it<=3) pcurrent=half*(pnew+pcurrent)
1411  if(n2it>3)then
1412  pright =pcurrent
1413  pleft=pprev
1414  pcurrent=half*(pleft+pright)
1415  dicho: do ni3=1,maxitnr
1416  !===================!
1417  xicurrent=tau+d+pcurrent
1418  v2=sqrs/xicurrent**2
1419  lfac2inv=one - v2
1420 
1421  if(lfac2inv>zero)then
1422  lfac=one/dsqrt(lfac2inv)
1423  else
1424  ierror=4
1425  return
1426  endif
1427  !===================!
1428 
1429  !== calculation done using the EOS ==!
1430  call bisection_enthalpy_eos(pnew,lfac2inv,d,xicurrent,h)
1431  nff=-xicurrent*lfac2inv + h
1432  !=======================================!
1433  !==== Iterate ====!
1434  if(ff * nff < zero)then
1435  pleft=pcurrent
1436  else
1437  pright=pcurrent
1438  endif
1439 
1440  pcurrent=half*(pleft+pright)
1441  !==================!
1442 
1443  !=== The iteration converged ===!
1444  if(2.0d0*dabs(pleft-pright)/(pleft+pright)< absaccnr &
1445  .or. dabs(ff)<absaccnr)then
1446  pnew=pcurrent
1447  exit loopnr
1448  endif
1449  !==============================!
1450 
1451  !==============================!
1452 
1453  !=== conserve the last value of Nff ===!
1454  ff=nff
1455  !======================================!
1456  enddo dicho
1457  endif
1458 
1459  else
1460  !====== There is no problems, continue the NR iteration ======!
1461  pprev=pcurrent
1462  pcurrent=pnew
1463  !=============================================================!
1464  endif
1465 
1466 
1467  !=== keep the values of the 2 last ff ===!
1468  oldff2=oldff1
1469  oldff1=ff
1470  !========================================!
1471  enddo loopnr
1472 
1473  if(niiter==maxitnr)then
1474  ierror=2
1475  return
1476  endif
1477 
1478  if(pcurrent<minp) then
1479  ierror=3
1480  return
1481  endif
1482 
1483  !------------------------------!
1484  xi=tau+d+pcurrent
1485  v2=sqrs/xicurrent**2
1486  lfac2inv=one - v2
1487  if(lfac2inv>zero) then
1488  lfac=one/dsqrt(lfac2inv)
1489  else
1490  ierror=4
1491  return
1492  endif
1493 
1494  end subroutine con2primhydro_eos
1495 
1496  !> pointwise evaluations used in con2prim
1497  !> compute pointwise value for pressure p and dpdxi
1498  subroutine funcpressure_eos(xicurrent,lfac,d,dlfacdxi,p,dpdxi)
1499 
1500  double precision, intent(in) :: xicurrent,lfac,d,dlfacdxi
1501  double precision, intent(out) :: p,dpdxi
1502  ! .. local ..
1503  double precision :: rho,h,E,dhdxi,rhotoE
1504  double precision :: dpdchi,dEdxi
1505 
1506  ! rhoh here called h
1507  h=xicurrent/(lfac**2)
1508  rho=d/lfac
1509  e = (h+dsqrt(h**2+(srhd_gamma**2-one)*rho**2)) &
1510  /(srhd_gamma+one)
1511  ! output pressure
1512  rhotoe = rho/e
1513  p = half*gamma_1*(e-rho*rhotoe)
1514 
1515  dhdxi = one/(lfac**2)-2.0d0*xicurrent/(lfac**2)*dlfacdxi/lfac
1516 
1517  dedxi=(dhdxi+(h*dhdxi-(srhd_gamma**2-one)*rho**2*dlfacdxi/lfac)&
1518  /dsqrt(h**2+(srhd_gamma**2-one)*rho**2))&
1519  /(srhd_gamma+one)
1520 
1521  ! output pressure derivative to xi
1522  dpdxi=half*gamma_1*(2.0d0*rho*rhotoe*dlfacdxi/lfac+&
1523  (one+rhotoe**2)*dedxi)
1524 
1525  end subroutine funcpressure_eos
1526 
1527  !> pointwise evaluations used in con2prim
1528  !> returns enthalpy rho*h (h) and derivative d(rho*h)/dp (dhdp)
1529  subroutine funcenthalpy_eos(pcurrent,lfac2inv,d,sqrs,xicurrent,dv2d2p,h,dhdp)
1530 
1531  double precision, intent(in) :: pcurrent,lfac2inv,d,sqrs,xicurrent,dv2d2p
1532  double precision, intent(out):: h,dhdp
1533 
1534  ! local
1535  double precision:: rho,E_th,E,dE_thdp,dEdp
1536 
1537  rho=d*dsqrt(lfac2inv)
1538  e_th = pcurrent*inv_gamma_1
1539  e = (e_th + dsqrt(e_th**2+rho**2))
1540  !== Enthalpy ==!
1541  h = half*((srhd_gamma+one)*e-gamma_1*rho*(rho/e))
1542  !=== Derivative of thermal energy ===!
1543  de_thdp = one*inv_gamma_1
1544  !=== Derivative of internal energy ===!
1545  dedp = de_thdp * (one+e_th/dsqrt(e_th**2+rho**2))&
1546  + d**2*dv2d2p/dsqrt(e_th**2+rho**2)
1547  !====== Derivative of Enthalpy ======!
1548  dhdp = half*((srhd_gamma+one)*dedp + &
1549  gamma_1*(rho*(rho/e))*(-2.0d0*dv2d2p/lfac2inv+dedp/e))
1550  end subroutine funcenthalpy_eos
1551 
1552  !> pointwise evaluations used in con2prim
1553  !> returns enthalpy rho*h (h)
1554  subroutine bisection_enthalpy_eos(pcurrent,lfac2inv,d,xicurrent,h)
1555 
1556  double precision, intent(in) :: pcurrent,lfac2inv,d,xicurrent
1557  double precision, intent(out):: h
1558 
1559  ! local
1560  double precision:: rho,E_th,E
1561 
1562  rho=d*dsqrt(lfac2inv)
1563  e_th = pcurrent*inv_gamma_1
1564  e = (e_th + dsqrt(e_th**2+rho**2))
1565  !== Enthalpy ==!
1566  h = half*((srhd_gamma+one)*e-gamma_1*rho*(rho/e))
1567 
1568  return
1569  end subroutine bisection_enthalpy_eos
1570 
1571  !> con2prim: (D,S**2,tau) --> compute auxiliaries lfac and xi
1572  subroutine con2prim(lfac,xi,myd,myssqr,mytau,ierror)
1573  use mod_con2prim_vars
1574 
1575  double precision, intent(in) :: myd, myssqr, mytau
1576  double precision, intent(inout) :: lfac, xi
1577  integer, intent(inout) :: ierror
1578 
1579  ! .. local ..
1580  double precision:: f,df,lfacl
1581  !------------------------------------------------------------------
1582 
1583  ! Save the input-state in mod_con2prim_vars
1584  d = myd; ssqr = myssqr; tau = mytau;
1585 
1586  ierror=0
1587 
1588  ! Check if guess is close enough: gives f,df,lfacl
1589  if(xi>smallxi)then
1590  call funcd(xi,f,df,lfacl,d,ssqr,tau,ierror)
1591  if (ierror == 0 .and. dabs(f/df)<absaccnr) then
1592  xi = xi - f/df
1593  lfac = lfacl
1594  return
1595  else
1596  ierror = 0
1597  end if
1598  else
1599  write(*,*) 'entering con2prim with xi=',xi
1600  end if
1601 
1602  ! ierror=1 : must have D>=minrho, tau>=smalltau
1603  !if(d<minrho .or. tau<smalltau)then
1604  ! ierror=1
1605  ! return
1606  !endif
1607 
1608  call con2primhydro(lfac,xi,d,ssqr,tau,ierror)
1609 
1610  end subroutine con2prim
1611 
1612  subroutine funcd(xi,f,df,mylfac,d,ssqr,tau,ierror)
1613  double precision, intent(in) :: xi,d,ssqr,tau
1614  double precision, intent(out) :: f,df,mylfac
1615  integer, intent(inout) :: ierror
1616 
1617  ! .. local ..
1618  double precision :: dlfac
1619  double precision :: vsqr,p,dpdxi
1620  !-----------------------------------------------------------------
1621 
1622  vsqr = ssqr/xi**2
1623 
1624  if (vsqr<one) then
1625  mylfac = one/dsqrt(one-vsqr)
1626  dlfac = -mylfac**3*ssqr/(xi**3)
1627  !===== Pressure, calculate using EOS =====!
1628  call funcpressure(xi,mylfac,d,dlfac,p,dpdxi)
1629  !=========================================!
1630  f = xi-tau-d-p
1631  df = one-dpdxi
1632  else
1633  ! print *,'Erroneous input to funcd since vsqr=',vsqr,' >=1'
1634  ! print *,'input values d, ssqr, tau:',d,ssqr,tau
1635  ierror =6
1636  return
1637  end if
1638 
1639  end subroutine funcd
1640 
1641  !> SRHD iteration solves for p via NR, and then gives xi as output
1642  subroutine con2primhydro(lfac,xi,d,sqrs,tau,ierror)
1643  double precision, intent(out) :: xi,lfac
1644  double precision, intent(in) :: d,sqrs,tau
1645  integer,intent(inout) :: ierror
1646 
1647  ! .. local ..
1648  integer :: ni,niiter,nit,n2it,ni3
1649  double precision :: pcurrent,pnew
1650  double precision :: er,er1,ff,df,dp,v2
1651  double precision :: pmin,lfac2inv,pLabs,pRabs,pprev
1652  double precision :: s2overcubeG2rh
1653  double precision :: xicurrent,h,dhdp
1654  double precision :: oldff1,oldff2,Nff
1655  double precision :: pleft,pright
1656  !---------------------------------------------------------------------
1657 
1658  ierror=0
1659  ! ierror=0 : ok
1660  ! we already checked D>=minrho, tau>=smalltau (ierror=1)
1661  !
1662  ! ierror<>0
1663  !
1664  ! ierror=2 : maxitnr reached without convergence
1665  ! ierror=3 : final pressure value < smallp or xi<smallxi during iteration
1666  ! ierror=4 : final v^2=1 hence problem as lfac=1/0
1667  ! ierror=5 : nonmonotonic function f (as df=0)
1668 
1669  ! left and right brackets for p-range
1670  pmin=dsqrt(sqrs)/(one-dmaxvel)-tau-d
1671  plabs=max(minp,pmin)
1672  prabs=1.0d99
1673  ! start value from input
1674  pcurrent=plabs
1675 
1676  er1=one
1677  pprev=pcurrent
1678 
1679  ! Fudge Parameters
1680  oldff1=1.0d7 ! High number
1681  oldff2=1.0d9 ! High number bigger then oldff1
1682  n2it = 0
1683  nit = 0
1684 
1685  loopnr: do ni=1,maxitnr
1686  nit = nit + 1
1687  !=== Relax NR iteration accuracy=======!
1688  if(nit>maxitnr/4)then
1689  ! mix pressure value for convergence
1690  pcurrent=half*(pcurrent+pprev)
1691  ! relax accuracy requirement
1692  er1=10.0d0*er1
1693  nit = nit - maxitnr/10
1694  endif
1695  !=======================================!
1696 
1697  niiter=ni
1698  xicurrent=tau+d+pcurrent
1699 
1700  if(xicurrent<smallxi) then
1701  ! print *,'stop: too small xi iterate:',xicurrent
1702  ! print *,'for pressure iterate p',pcurrent
1703  ! print *,'pressure bracket pLabs pRabs',pLabs,pRabs
1704  ! print *,'iteration number:',ni
1705  ! print *,'values for d,s,tau,s2:',d,sqrs,tau,sqrs
1706  ierror=3
1707  return
1708  endif
1709 
1710  v2=sqrs/xicurrent**2
1711  lfac2inv=one - v2
1712  if(lfac2inv>zero) then
1713  lfac=one/dsqrt(lfac2inv)
1714  else
1715  ! print *,'stop: negative or zero factor 1-v2:',lfac2inv
1716  ! print *,'for pressure iterate p',pcurrent
1717  ! print *,'absolute pressure bracket pLabs pRabs',pLabs,pRabs
1718  ! print *,'iteration number:',ni
1719  ! print *,'values for d,s,tau,s2:',d,sqrs,tau,sqrs
1720  ! print *,'values for v2,xi:',v2,xicurrent
1721  ierror=4
1722  return
1723  endif
1724 
1725  s2overcubeg2rh=sqrs/(xicurrent**3)
1726  !== calculation done using the EOS ==!
1727  call funcenthalpy(pcurrent,lfac2inv,d,sqrs,xicurrent,&
1728  s2overcubeg2rh,h,dhdp)
1729  !=======================================!
1730  ff=-xicurrent*lfac2inv + h
1731  df=- two*sqrs/xicurrent**2 + dhdp - lfac2inv
1732 
1733  if (ff*df==zero) then
1734  if (ff==zero) then
1735  exit ! zero found
1736  else
1737  ! print *,'stop: df becomes zero, non-monotonic f(p)!'
1738  ierror=5
1739  return
1740  endif
1741  else
1742  pnew=pcurrent-ff/df
1743  if (ff*df>zero) then
1744  ! pressure iterate has decreased
1745  ! restrict to left
1746  pnew=max(pnew,plabs)
1747  else ! ff*df<0
1748  ! pressure iterate has increased
1749  ! restrict to right
1750  pnew=min(pnew,prabs)
1751  endif
1752  endif
1753 
1754  !===============================================!
1755  dp=pcurrent-pnew
1756  er=two*dabs(dp)/(pnew+pcurrent)
1757  if(((er<tolernr*er1).or.(dabs(dp)<absaccnr))) exit loopnr
1758  !===============================================!
1759 
1760  ! For very small values of pressure, NR algorithm is not efficient to
1761  ! find root, use Euler algorithm to find precise value of pressure
1762  if((dabs(oldff2-ff) < 1.0d-8 .or. niiter >= maxitnr-maxitnr/20).and.&
1763  ff * oldff1 < zero .and. dabs(ff)>absaccnr)then
1764 
1765  n2it=n2it+1
1766  if(n2it<=3) pcurrent=half*(pnew+pcurrent)
1767  if(n2it>3)then
1768  pright =pcurrent
1769  pleft=pprev
1770  pcurrent=half*(pleft+pright)
1771  dicho: do ni3=1,maxitnr
1772  !===================!
1773  xicurrent=tau+d+pcurrent
1774  v2=sqrs/xicurrent**2
1775  lfac2inv=one - v2
1776 
1777  if(lfac2inv>zero)then
1778  lfac=one/dsqrt(lfac2inv)
1779  else
1780  ierror=4
1781  return
1782  endif
1783  !===================!
1784 
1785  !== calculation done using the EOS ==!
1786  call bisection_enthalpy(pnew,lfac2inv,d,xicurrent,h)
1787  nff=-xicurrent*lfac2inv + h
1788  !=======================================!
1789  !==== Iterate ====!
1790  if(ff * nff < zero)then
1791  pleft=pcurrent
1792  else
1793  pright=pcurrent
1794  endif
1795 
1796  pcurrent=half*(pleft+pright)
1797  !==================!
1798 
1799  !=== The iteration converged ===!
1800  if(2.0d0*dabs(pleft-pright)/(pleft+pright)< absaccnr &
1801  .or. dabs(ff)<absaccnr)then
1802  pnew=pcurrent
1803  exit loopnr
1804  endif
1805  !==============================!
1806 
1807  !==============================!
1808 
1809  !=== conserve the last value of Nff ===!
1810  ff=nff
1811  !======================================!
1812  enddo dicho
1813  endif
1814 
1815  else
1816  !====== There is no problems, continue the NR iteration ======!
1817  pprev=pcurrent
1818  pcurrent=pnew
1819  !=============================================================!
1820  endif
1821 
1822 
1823  !=== keep the values of the 2 last ff ===!
1824  oldff2=oldff1
1825  oldff1=ff
1826  !========================================!
1827  enddo loopnr
1828 
1829  if(niiter==maxitnr)then
1830  ierror=2
1831  return
1832  endif
1833 
1834  if(pcurrent<minp) then
1835  ierror=3
1836  return
1837  endif
1838 
1839  !------------------------------!
1840  xi=tau+d+pcurrent
1841  v2=sqrs/xicurrent**2
1842  lfac2inv=one - v2
1843  if(lfac2inv>zero) then
1844  lfac=one/dsqrt(lfac2inv)
1845  else
1846  ierror=4
1847  return
1848  endif
1849 
1850  end subroutine con2primhydro
1851 
1852  !> pointwise evaluations used in con2prim
1853  !> compute pointwise value for pressure p and dpdxi
1854  subroutine funcpressure(xicurrent,lfac,d,dlfacdxi,p,dpdxi)
1855 
1856  double precision, intent(in) :: xicurrent,lfac,d,dlfacdxi
1857  double precision, intent(out) :: p,dpdxi
1858  ! .. local ..
1859  double precision :: rho,h,E,dhdxi,rhotoE
1860  double precision :: dpdchi,dEdxi
1861 
1862  ! rhoh here called h
1863  h=xicurrent/(lfac**2)
1864  rho=d/lfac
1865  ! output pressure
1866  p = (h - rho)/gamma_to_gamma_1
1867  dpdchi = one/gamma_to_gamma_1
1868  dpdxi = dpdchi * one/lfac**2
1869  ! zero case dlfacdxi implies zero velocity (ssqr=0)
1870  if (dlfacdxi /= 0.0d0) &
1871  dpdxi = dpdxi + dpdchi * ((d*lfac-2.0d0*xicurrent)/lfac**3) * dlfacdxi
1872 
1873  end subroutine funcpressure
1874 
1875  !> pointwise evaluations used in con2prim
1876  !> returns enthalpy rho*h (h) and derivative d(rho*h)/dp (dhdp)
1877  subroutine funcenthalpy(pcurrent,lfac2inv,d,sqrs,xicurrent,dv2d2p,h,dhdp)
1878 
1879  double precision, intent(in) :: pcurrent,lfac2inv,d,sqrs,xicurrent,dv2d2p
1880  double precision, intent(out):: h,dhdp
1881 
1882  ! local
1883  double precision:: rho,E_th,E,dE_thdp,dEdp
1884 
1885  rho=d*dsqrt(lfac2inv)
1886  h = rho + gamma_to_gamma_1 * pcurrent
1887  dhdp = gamma_to_gamma_1 + d/dsqrt(lfac2inv)*sqrs/xicurrent**3
1888  end subroutine funcenthalpy
1889 
1890  !> pointwise evaluations used in con2prim
1891  !> returns enthalpy rho*h (h)
1892  subroutine bisection_enthalpy(pcurrent,lfac2inv,d,xicurrent,h)
1893 
1894  double precision, intent(in) :: pcurrent,lfac2inv,d,xicurrent
1895  double precision, intent(out):: h
1896 
1897  ! local
1898  double precision:: rho,E_th,E
1899 
1900  rho=d*dsqrt(lfac2inv)
1901  h = rho + gamma_to_gamma_1 * pcurrent
1902 
1903  return
1904  end subroutine bisection_enthalpy
1905 
1906 end module mod_srhd_phys
Calculate w(iw)=w(iw)+qdt*SOURCE[wCT,qtC,x] within ixO for all indices iw=iwmin......
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Definition: mod_comm_lib.t:208
double precision ssqr
double precision d
double precision tau
Module for physical and numeric constants.
Definition: mod_constants.t:2
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
integer, parameter cartesian_expansion
Definition: mod_geometry.t:12
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 small_pressure
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
double precision unit_mass
Physical scaling factor for mass.
integer, dimension(3, 3) kr
Kronecker delta tensor.
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 use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer mype
The rank of the current MPI task.
double precision, dimension(:), allocatable, parameter d
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision unit_velocity
Physical scaling factor for velocity.
double precision unit_temperature
Physical scaling factor for temperature.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
logical phys_trac
Use TRAC for MHD or 1D HD.
logical fix_small_values
fix small values with average or replace methods
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
double precision small_density
integer r_
Indices for cylindrical coordinates FOR TESTS, negative value when not used:
integer boundspeed
bound (left/min and right.max) speed of Riemann fan
logical check_small_values
check and optionally fix unphysical small values (density, gas pressure)
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
Module for handling problematic values in simulations, such as negative pressures.
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
subroutine, public small_values_average(ixIL, ixOL, w, x, w_flag, windex)
subroutine, public small_values_error(wprim, x, ixIL, ixOL, w_flag, subname)
character(len=20), public small_values_method
How to handle small values.
Special Relativistic Hydrodynamics (with EOS) physics module.
Definition: mod_srhd_phys.t:2
subroutine srhd_add_source(qdt, dtfactor, ixIL, ixOL, wCT, wCTprim, w, x, qsourcesplit, active)
dummy addsource subroutine
subroutine srhd_get_flux(wC, wP, x, ixIL, ixOL, idim, f)
Calculate fluxes within ixO^L.
logical, public, protected srhd_force_diagonal
Allows overruling default corner filling (for debug mode, otherwise corner primitives fail)
Definition: mod_srhd_phys.t:49
subroutine srhd_physical_units
double precision, public tolernr
Definition: mod_srhd_phys.t:57
subroutine srhd_get_cmax_loc(ixIL, ixOL, vidim, csound2, v2, cmax, cmin)
local version for recycling code when computing cmax-cmin
integer, public, protected srhd_n_tracer
Number of tracer species.
Definition: mod_srhd_phys.t:13
double precision, public inv_gamma_1
Definition: mod_srhd_phys.t:41
subroutine srhd_write_info(fh)
Write this module's parameters to a snapshot.
Definition: mod_srhd_phys.t:96
subroutine srhd_get_cmax(w, x, ixIL, ixOL, idim, cmax)
Calculate cmax_idim within ixO^L used especially for setdt CFL limit.
integer, dimension(:), allocatable, public, protected tracer
Indices of the tracers.
Definition: mod_srhd_phys.t:23
subroutine, public srhd_get_auxiliary(ixIL, ixOL, w, x)
Compute auxiliary variables lfac and xi from a conservative state using srhd_con2prim to calculate en...
subroutine, public srhd_get_pthermal(w, x, ixIL, ixOL, pth)
Calculate thermal pressure p within ixO^L must follow after update conservative with auxiliaries.
double precision, public absaccnr
Definition: mod_srhd_phys.t:56
double precision, public small_e
The smallest allowed energy.
Definition: mod_srhd_phys.t:44
integer, public, protected lfac_
Index of the Lorentz factor.
Definition: mod_srhd_phys.t:31
subroutine funcd_eos(xi, f, df, mylfac, d, ssqr, tau, ierror)
double precision, public gamma_to_gamma_1
Definition: mod_srhd_phys.t:41
subroutine funcd(xi, f, df, mylfac, d, ssqr, tau, ierror)
subroutine srhd_get_csound2_eos(ixIL, ixOL, rho, rhoh, csound2)
Calculate the square of the thermal sound speed csound2 within ixO^L. available rho - rho*h.
subroutine, public srhd_get_auxiliary_prim(ixIL, ixOL, w)
Set auxiliary variables lfac and xi from a primitive state only used when handle_small_values average...
integer, public maxitnr
parameters for NR in con2prim
Definition: mod_srhd_phys.t:55
subroutine, public srhd_phys_init()
Initialize the module.
double precision, public gamma_1
Definition: mod_srhd_phys.t:41
double precision, public, protected he_abundance
Helium abundance over Hydrogen.
Definition: mod_srhd_phys.t:52
subroutine, public srhd_get_csound2(w, x, ixIL, ixOL, csound2)
Calculate the square of the thermal sound speed csound2 within ixO^L. here computed from conservative...
double precision, public small_xi
The smallest allowed inertia.
Definition: mod_srhd_phys.t:46
subroutine, public srhd_to_conserved(ixIL, ixOL, w, x)
Transform primitive variables into conservative ones.
integer, dimension(:), allocatable, public, protected mom
Indices of the momentum density.
Definition: mod_srhd_phys.t:20
subroutine srhd_get_csound2_rhoh(w, x, ixIL, ixOL, rhoh, csound2)
Calculate the square of the thermal sound speed csound2 within ixO^L. here computed from conservative...
subroutine srhd_get_v(w, x, ixIL, ixOL, v)
Calculate v vector from conservatives.
subroutine, public srhd_get_enthalpy_eos(ixOL, rho, p, rhoh)
Compute the enthalpy rho*h from rho and pressure p.
double precision, public minp
Definition: mod_srhd_phys.t:60
subroutine, public srhd_to_primitive(ixIL, ixOL, w, x)
Transform conservative variables into primitive ones.
logical, public srhd_eos
Whether synge eos is used.
Definition: mod_srhd_phys.t:37
double precision, public lfacmax
Definition: mod_srhd_phys.t:59
integer, public, protected d_
Definition: mod_srhd_phys.t:17
subroutine srhd_handle_small_values(primitive, w, x, ixIL, ixOL, subname)
handles bootstrapping
subroutine srhd_get_dt(w, ixIL, ixOL, dtnew, dxD, x)
dummy get_dt subroutine
subroutine srhd_get_smallvalues_eos
Compute the small value limits.
subroutine srhd_get_pressure_eos(ixIL, ixOL, rho, rhoh, p, E)
Calculate thermal pressure p from density rho and enthalpy rho*h will provide p (and E if srhd_eos)
subroutine, public srhd_check_params
subroutine srhd_add_source_geom(qdt, dtfactor, ixIL, ixOL, wCT, wprim, w, x)
Add geometrical source terms to w.
integer, public, protected p_
Index of the gas pressure should equal e_.
Definition: mod_srhd_phys.t:28
subroutine con2prim_eos(lfac, xi, myd, myssqr, mytau, ierror)
con2prim: (D,S**2,tau) --> compute auxiliaries lfac and xi
subroutine srhd_get_csound2_prim_eos(ixOL, rho, rhoh, p, csound2)
Calculate the square of the thermal sound speed csound2 within ixO^L. available rho - rho*h - p.
subroutine srhd_get_cbounds(wLC, wRC, wLp, wRp, x, ixIL, ixOL, idim, Hspeed, cmax, cmin)
Estimating bounds for the minimum and maximum signal velocities here we will not use Hspeed at all (o...
logical, public, protected srhd_particles
Whether particles module is added.
Definition: mod_srhd_phys.t:10
double precision, public smalltau
Definition: mod_srhd_phys.t:60
double precision, public dmaxvel
Definition: mod_srhd_phys.t:58
integer, public, protected e_
Index of the energy density.
Definition: mod_srhd_phys.t:26
subroutine srhd_check_w_aux(ixIL, ixOL, w, flag)
Returns logical argument flag T where auxiliary values are not ok.
double precision, public minrho
Definition: mod_srhd_phys.t:60
subroutine, public srhd_check_w(primitive, ixIL, ixOL, w, flag)
Returns logical argument flag T where values are not ok.
subroutine srhd_get_a2max(w, x, ixIL, ixOL, a2max)
double precision, public smallxi
Definition: mod_srhd_phys.t:60
integer, public, protected xi_
Index of the inertia.
Definition: mod_srhd_phys.t:34
double precision, public srhd_gamma
The adiabatic index and derived values.
Definition: mod_srhd_phys.t:40
integer, public, protected rho_
Index of the density (in the w array)
Definition: mod_srhd_phys.t:16
subroutine, public srhd_get_geff_eos(w, ixIL, ixOL, varconserve, Geff)
calculate effective gamma
Module with all the methods that users can customize in AMRVAC.
procedure(set_surface), pointer usr_set_surface
integer nwflux
Number of flux variables.
Definition: mod_variables.t:8