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