MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_radiative_cooling.t
Go to the documentation of this file.
1!> module radiative cooling -- add optically thin radiative cooling
2!>
3!> only uses the (Townsend) exact integration method, can be used in HD, ffhd, MHD, twofl
4!>
5!> Assumptions: full ionized plasma dominated by H and He, ionization equilibrium
6!> Formula: Q=-n_H*n_e*f(T), positive f(T) function is pre-computed and tabulated or a piecewise power law
7!> Uses the various cooling tables stored in mod_radloss_tables.t
8!>
10
11 use mod_global_parameters, only: std_len
12 use mod_physics
14 use mod_comm_lib, only: mpistop
15 implicit none
16
17 !> Helium abundance over Hydrogen
18 double precision, private :: He_abundance
19
20 !> The adiabatic index
21 double precision, private :: rc_gamma
22
23 !> The adiabatic index minus 1
24 double precision, private :: rc_gamma_1
25
26 !> inverse of the adiabatic index minus 1
27 double precision, private :: invgam
28
29 abstract interface
30 subroutine get_subr1(w,x,ixI^L,ixO^L,res)
32 integer, intent(in) :: ixI^L, ixO^L
33 double precision, intent(in) :: w(ixI^S,nw)
34 double precision, intent(in) :: x(ixI^S,1:ndim)
35 double precision, intent(out):: res(ixI^S)
36 end subroutine get_subr1
37 end interface
38
40
41 double precision :: rad_damp_height
42 double precision :: rad_damp_scale
43
44 ! these are set in init method
45 double precision, allocatable :: tcool(:), lcool(:), dldtcool(:)
46 double precision, allocatable :: yc(:)
47 double precision :: tref, lref, tcoolmin,tcoolmax
48 double precision :: lgtcoolmin, lgtcoolmax, lgstep
49
50 ! The piecewise powerlaw (PPL) tabels and variabels
51 ! x_* en t_* are given as log_10
52 double precision, allocatable :: y_ppl(:), t_ppl(:), l_ppl(:), a_ppl(:)
53
54 !> Lower limit of temperature
55 double precision :: tlow
56
57 !> Index of the energy density
58 integer :: e_
59 !> Index of cut off temperature for TRAC
60 integer :: tcoff_
61
62 ! these are set as parameters
63 !> Resolution of temperature in interpolated tables
64 integer :: ncool
65
66 integer :: n_ppl
67
68 !> Fixed temperature not lower than tlow
69 logical :: tfix
70
71 !> Add cooling source in a split way (.true.) or un-split way (.false.)
72 logical :: rc_split
73
74 logical :: isppl = .false.
75
76 !> cutoff radiative cooling below rad_damp_height
77 logical :: rad_damp
78 !> whether background equilibrium contribution is split off
79 logical :: has_equi = .false.
80 !> whether background equilibrium is compensated in thermal balance
81 logical :: subtract_equi = .false.
82
83 double precision, allocatable :: frac_lowfip(:)
84 !> Index of primitive FIP abundance variable, -1 if disabled
85 integer :: fip_ = -1
86 !> Enable local Newton cooling/heating approximation for optically thick losses
87 logical :: rad_newton = .false.
88 double precision :: rad_newton_pthick = 25.d0
89 double precision :: rad_newton_trad = 0.006d0
90 double precision :: rad_newton_rhosurf = 1.d4
91
92 !> Name of cooling curve
93 character(len=std_len) :: coolcurve
94
95 procedure(get_subr1), pointer, nopass :: get_rho => null()
96 procedure(get_subr1), pointer, nopass :: get_rho_equi => null()
97 procedure(get_subr1), pointer, nopass :: get_pthermal => null()
98 procedure(get_subr1), pointer, nopass :: get_pthermal_equi => null()
99 procedure(get_subr1), pointer, nopass :: get_var_rfactor => null()
100 procedure(get_subr1), pointer, nopass :: get_temperature_equi => null()
101
102 end type rc_fluid
103
104 contains
105
106 !> Radiative cooling initialization
107 subroutine radiative_cooling_init_params(phys_gamma,He_abund)
109 double precision, intent(in) :: phys_gamma,He_abund
110
111 rc_gamma=phys_gamma
112 he_abundance=he_abund
113 end subroutine radiative_cooling_init_params
114
115 subroutine radiative_cooling_init(fl,read_params)
117 interface
118 subroutine read_params(fl)
120 import rc_fluid
121 type(rc_fluid), intent(inout) :: fl
122
123 end subroutine read_params
124 end interface
125
126 type(rc_fluid), intent(inout) :: fl
127
128 double precision, dimension(:), allocatable :: t_table
129 double precision, dimension(:), allocatable :: L_table
130 double precision, dimension(:), allocatable :: f_table
131 double precision :: ratt, fact1, fact2, fact3, dL1, dL2
132 double precision :: tstep, Lstep
133 integer :: ntable, i, j
134 logical :: jump
135 Character(len=65) :: PPL_curves(1:6)
136
137 fl%ncool=4000
138 fl%coolcurve='JCcorona'
139 fl%tlow=bigdouble
140 fl%Tfix=.false.
141 fl%rc_split=.false.
142 fl%rad_damp=.false.
143 fl%rad_damp_height=0.5d0
144 fl%rad_damp_scale=0.15d0
145 call read_params(fl)
146
147 if (fl%fip_ > 0) then
148 select case (trim(fl%coolcurve))
149 case ('Dere_photo', 'Dere_photo_DM')
150 case default
151 call mpistop("FIP cooling requires coolcurve='Dere_photo' or 'Dere_photo_DM'")
152 end select
153 end if
154
155 if(fl%rc_split) any_source_split=.true.
156
157 ! Checks if coolcurve is a piecewise power law (PPL)
158 ppl_curves = [Character(len=65) :: 'Hildner','FM', 'Rosner', 'Klimchuk','SPEX_DM_rough','SPEX_DM_fine']
159 do i=1,size(ppl_curves)
160 if (ppl_curves(i)==fl%coolcurve) then
161 fl%isPPL = .true.
162 end if
163 end do
164
165 ! Init for PPL
166 if (fl%isPPL) then
167 ! Read in tables and create t_PPL, l_PPL, a_PPL
168 select case(fl%coolcurve)
169
170 case('Hildner')
171 if(mype ==0) &
172 print *,'Use Hildner (1974) piecewise power law'
173 fl%n_PPL = n_hildner
174 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
175 allocate(fl%a_PPL(1:fl%n_PPL))
176 fl%t_PPL(1:fl%n_PPL+1) = t_hildner(1:n_hildner+1)
177 fl%a_PPL(1:fl%n_PPL) = a_hildner(1:n_hildner)
178 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_hildner(1:n_hildner) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
179
180 case('FM')
181 if(mype==0) &
182 print *,'Use Forbes and Malherbe (1991)-like piecewise power law'
183 fl%n_PPL = n_fm
184 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
185 allocate(fl%a_PPL(1:fl%n_PPL))
186 fl%t_PPL(1:fl%n_PPL+1) = t_fm(1:n_fm+1)
187 fl%a_PPL(1:fl%n_PPL) = a_fm(1:n_fm)
188 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_fm(1:n_fm) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
189
190 case('Rosner')
191 if(mype==0) &
192 print *,'Use piecewise power law according to Rosner (1978)'
193 if(mype ==0) &
194 print *,'and extended by Priest (1982) from Van Der Linden (1991)'
195 fl%n_PPL = n_rosner
196 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
197 allocate(fl%a_PPL(1:fl%n_PPL))
198 fl%t_PPL(1:fl%n_PPL+1) = t_rosner(1:n_rosner+1)
199 fl%a_PPL(1:fl%n_PPL) = a_rosner(1:n_rosner)
200 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_rosner(1:n_rosner) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
201
202 case('Klimchuk')
203 if(mype==0) &
204 print *,'Use Klimchuk (2008) piecewise power law'
205 fl%n_PPL = n_klimchuk
206 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
207 allocate(fl%a_PPL(1:fl%n_PPL))
208 fl%t_PPL(1:fl%n_PPL+1) = t_klimchuk(1:n_klimchuk+1)
209 fl%a_PPL(1:fl%n_PPL) = a_klimchuk(1:n_klimchuk)
210 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_klimchuk(1:n_klimchuk) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
211
212 case('SPEX_DM_rough')
213 if(mype==0) &
214 print *,'Use the rough piece wise power law fit to the SPEX_DM curve (2009)'
215 fl%n_PPL = n_spex_dm_rough
216 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
217 allocate(fl%a_PPL(1:fl%n_PPL))
218 fl%t_PPL(1:fl%n_PPL+1) = t_spex_dm_rough(1:n_spex_dm_rough+1)
219 fl%a_PPL(1:fl%n_PPL) = a_spex_dm_rough(1:n_spex_dm_rough)
220 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_spex_dm_rough(1:n_spex_dm_rough) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
221
222 case('SPEX_DM_fine')
223 if(mype==0) &
224 print *,'Use the fine, detailed piece wise power law fit to the SPEX_DM curve (2009)'
225 fl%n_PPL = n_spex_dm_fine
226 allocate(fl%t_PPL(1:fl%n_PPL+1), fl%l_PPL(1:fl%n_PPL+1))
227 allocate(fl%a_PPL(1:fl%n_PPL))
228 fl%t_PPL(1:fl%n_PPL+1) = t_spex_dm_fine(1:n_spex_dm_fine+1)
229 fl%a_PPL(1:fl%n_PPL) = a_spex_dm_fine(1:n_spex_dm_fine)
230 fl%l_PPL(1:fl%n_PPL) = 10.d0**x_spex_dm_fine(1:n_spex_dm_fine) * (10.d0**fl%t_PPL(1:fl%n_PPL))**fl%a_PPL(1:fl%n_PPL)
231
232 case default
233 call mpistop("This piecewise power law is unknown")
234 end select
235
236 ! Go from logarithmic to actual values.
237 fl%t_PPL(1:fl%n_PPL+1) = 10.d0**fl%t_PPL(1:fl%n_PPL+1)
238 ! Change unit of table if SI is used instead of cgs
239 if (si_unit) fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * 10.0d0**(-13)
240
241 ! Make dimensionless
242 fl%t_PPL(1:fl%n_PPL+1) = fl%t_PPL(1:fl%n_PPL+1) / unit_temperature
243 fl%l_PPL(1:fl%n_PPL) = fl%l_PPL(1:fl%n_PPL) * unit_numberdensity**2 * unit_time / unit_pressure * (1.d0+2.d0*he_abundance)
244
245 ! Set tref en lref
246 fl%l_PPL(fl%n_PPL+1) = fl%l_PPL(fl%n_PPL) * ( fl%t_PPL(fl%n_PPL+1) / fl%t_PPL(fl%n_PPL) )**fl%a_PPL(fl%n_PPL)
247 fl%lref = fl%l_PPL(fl%n_PPL+1)
248 fl%tref = fl%t_PPL(fl%n_PPL+1)
249
250 ! Set tcoolmin and tcoolmax
251 fl%tcoolmin = fl%t_PPL(1)
252 fl%tcoolmax = fl%t_PPL(fl%n_PPL+1)
253 ! smaller value for lowest temperatures from cooling table and user's choice
254 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
255 !create y_PPL
256 call create_y_ppl(fl)
257
258 else
259
260 ! Init for interpolatable tables
261 allocate(fl%tcool(1:fl%ncool), fl%Lcool(1:fl%ncool), fl%dLdtcool(1:fl%ncool))
262 allocate(fl%Yc(1:fl%ncool))
263 if(fl%fip_ > 0) allocate(fl%frac_lowFIP(1:fl%ncool))
264
265 fl%tcool(1:fl%ncool) = zero
266 fl%Lcool(1:fl%ncool) = zero
267 fl%dLdtcool(1:fl%ncool) = zero
268
269 ! Read in the selected cooling curve
270 select case(fl%coolcurve)
271
272 case('JCcorona')
273 if(mype ==0) &
274 print *,'Use Colgan & Feldman (2008) cooling curve'
275 if(mype ==0) &
276 print *,'This version only till 10000 K, beware for floor T treatment'
277 ntable = n_jccorona
278 allocate(t_table(1:ntable))
279 allocate(l_table(1:ntable))
280 t_table(1:ntable) = t_jccorona(1:n_jccorona)
281 l_table(1:ntable) = l_jccorona(1:n_jccorona)
282
283 case('DM')
284 if(mype ==0) &
285 print *,'Use Dalgarno & McCray (1972) cooling curve'
286 ntable = n_dm
287 allocate(t_table(1:ntable))
288 allocate(l_table(1:ntable))
289 t_table(1:ntable) = t_dm(1:n_dm)
290 l_table(1:ntable) = l_dm(1:n_dm)
291
292 case('MB')
293 if(mype ==0) &
294 write(*,'(3a)') 'Use MacDonald & Bailey (1981) cooling curve '&
295 ,'as implemented in ZEUS-3D, with the values '&
296 ,'from Dalgarno & McCRay (1972) for low temperatures.'
297 ntable = n_mb + 20
298 allocate(t_table(1:ntable))
299 allocate(l_table(1:ntable))
300 t_table(1:ntable) = t_dm(1:21)
301 l_table(1:ntable) = l_dm(1:21)
302 t_table(22:ntable) = t_mb(2:n_mb)
303 l_table(22:ntable) = l_mb(2:n_mb)
304
305 case('MLcosmol')
306 if(mype ==0) &
307 print *,'Use Mellema & Lundqvist (2002) cooling curve '&
308 ,'for zero metallicity '
309 ntable = n_mlcosmol
310 allocate(t_table(1:ntable))
311 allocate(l_table(1:ntable))
312 t_table(1:ntable) = t_mlcosmol(1:n_mlcosmol)
313 l_table(1:ntable) = l_mlcosmol(1:n_mlcosmol)
314
315 case('MLwc')
316 if(mype ==0) &
317 print *,'Use Mellema & Lundqvist (2002) cooling curve '&
318 ,'for WC-star metallicity '
319 ntable = n_mlwc
320 allocate(t_table(1:ntable))
321 allocate(l_table(1:ntable))
322 t_table(1:ntable) = t_mlwc(1:n_mlwc)
323 l_table(1:ntable) = l_mlwc(1:n_mlwc)
324
325 case('MLsolar1')
326 if(mype ==0) &
327 print *,'Use Mellema & Lundqvist (2002) cooling curve '&
328 ,'for solar metallicity '
329 ntable = n_mlsolar1
330 allocate(t_table(1:ntable))
331 allocate(l_table(1:ntable))
332 t_table(1:ntable) = t_mlsolar1(1:n_mlsolar1)
333 l_table(1:ntable) = l_mlsolar1(1:n_mlsolar1)
334
335 case('cloudy_ism')
336 if(mype ==0) &
337 print *,'Use Cloudy based cooling curve '&
338 ,'for ism metallicity '
339 ntable = n_cl_ism
340 allocate(t_table(1:ntable))
341 allocate(l_table(1:ntable))
342 t_table(1:ntable) = t_cl_ism(1:n_cl_ism)
343 l_table(1:ntable) = l_cl_ism(1:n_cl_ism)
344
345 case('cloudy_solar')
346 if(mype ==0) &
347 print *,'Use Cloudy based cooling curve '&
348 ,'for solar metallicity '
349 ntable = n_cl_solar
350 allocate(t_table(1:ntable))
351 allocate(l_table(1:ntable))
352 t_table(1:ntable) = t_cl_solar(1:n_cl_solar)
353 l_table(1:ntable) = l_cl_solar(1:n_cl_solar)
354
355 case('SPEX')
356 if(mype ==0) &
357 print *,'Use SPEX cooling curve (Schure et al. 2009) '&
358 ,'for solar metallicity '
359 ntable = n_spex
360 allocate(t_table(1:ntable))
361 allocate(l_table(1:ntable))
362 t_table(1:ntable) = t_spex(1:n_spex)
363 l_table(1:ntable) = l_spex(1:n_spex) + log10(nenh_spex(1:n_spex))
364
365 case('SPEX_DM')
366 if(mype ==0) then
367 print *, 'Use SPEX cooling curve for solar metallicity above 10^4 K. '
368 print *, 'At lower temperatures,use Dalgarno & McCray (1972), '
369 print *, 'with a pre-set ionization fraction of 10^-3. '
370 print *, 'as described by Schure et al. (2009). '
371 endif
372 ntable = n_spex + n_dm_2 - 6
373 allocate(t_table(1:ntable))
374 allocate(l_table(1:ntable))
375 t_table(1:n_dm_2-1) = t_dm_2(1:n_dm_2-1)
376 l_table(1:n_dm_2-1) = l_dm_2(1:n_dm_2-1)
377 t_table(n_dm_2:ntable) = t_spex(6:n_spex)
378 l_table(n_dm_2:ntable) = l_spex(6:n_spex) + log10(nenh_spex(6:n_spex))
379
380 case('Dere_corona')
381 if(mype ==0) &
382 print *,'Use Dere (2009) cooling curve for solar corona'
383 ntable = n_dere
384 allocate(t_table(1:ntable))
385 allocate(l_table(1:ntable))
386 t_table(1:ntable) = t_dere(1:n_dere)
387 l_table(1:ntable) = l_dere_corona(1:n_dere)
388
389 case('Dere_corona_DM')
390 if(mype==0)&
391 print *, 'Combination of Dere_corona (2009) for high temperatures and'
392 if(mype==0)&
393 print *, 'Dalgarno & McCray (1972), DM2, for low temperatures'
394 ntable = n_dere + n_dm_2 - 1
395 allocate(t_table(1:ntable))
396 allocate(l_table(1:ntable))
397 t_table(1:n_dm_2-1) = t_dm_2(1:n_dm_2-1)
398 l_table(1:n_dm_2-1) = l_dm_2(1:n_dm_2-1)
399 t_table(n_dm_2:ntable) = t_dere(1:n_dere)
400 l_table(n_dm_2:ntable) = l_dere_corona(1:n_dere)
401
402 case('Dere_photo')
403 if(mype ==0) &
404 print *,'Use Dere (2009) cooling curve for solar photophere'
405 ntable = n_dere
406 allocate(t_table(1:ntable))
407 allocate(l_table(1:ntable))
408 if (fl%fip_ > 0) allocate(f_table(1:ntable))
409 t_table(1:ntable) = t_dere(1:n_dere)
410 l_table(1:ntable) = l_dere_photo(1:n_dere)
411 if (fl%fip_ > 0) f_table(1:ntable) = lowfip_frac(1:n_dere)
412
413 case('Dere_photo_DM')
414 if(mype==0)&
415 print *, 'Combination of Dere_photo (2009) for high temperatures and'
416 if(mype==0)&
417 print *, 'Dalgarno & McCray (1972), DM2, for low temperatures'
418 ntable = n_dere + n_dm_2 - 1
419 allocate(t_table(1:ntable))
420 allocate(l_table(1:ntable))
421 if (fl%fip_ > 0) allocate(f_table(1:ntable))
422 t_table(1:n_dm_2-1) = t_dm_2(1:n_dm_2-1)
423 l_table(1:n_dm_2-1) = l_dm_2(1:n_dm_2-1)
424 t_table(n_dm_2:ntable) = t_dere(1:n_dere)
425 l_table(n_dm_2:ntable) = l_dere_photo(1:n_dere)
426 if (fl%fip_ > 0) then
427 f_table(1:n_dm_2-1) = zero
428 f_table(n_dm_2:ntable) = lowfip_frac(1:n_dere)
429 end if
430
431 case('Colgan')
432 if(mype==0) &
433 print *, 'Use Colgan (2008) cooling curve'
434 ntable = n_colgan
435 allocate(t_table(1:ntable))
436 allocate(l_table(1:ntable))
437 t_table(1:ntable) = t_colgan(1:n_colgan)
438 l_table(1:ntable) = l_colgan(1:n_colgan)
439
440 case('Colgan_DM')
441 if(mype==0)&
442 print *, 'Combination of Colgan (2008) for high temperatures and'
443 if(mype==0)&
444 print *, 'Dalgarno & McCray (1972), DM2, for low temperatures'
445 ntable = n_colgan + n_dm_2
446 allocate(t_table(1:ntable))
447 allocate(l_table(1:ntable))
448 t_table(1:n_dm_2) = t_dm_2(1:n_dm_2)
449 l_table(1:n_dm_2) = l_dm_2(1:n_dm_2)
450 t_table(n_dm_2+1:ntable) = t_colgan(1:n_colgan)
451 l_table(n_dm_2+1:ntable) = l_colgan(1:n_colgan)
452
453 case default
454 call mpistop("This coolingcurve is unknown")
455 end select
456
457 ! create cooling table(s) for use in amrvac
458 fl%tcoolmax = t_table(ntable)
459 fl%tcoolmin = t_table(1)
460 ratt = (fl%tcoolmax-fl%tcoolmin)/( dble(fl%ncool-1) + smalldouble)
461
462 fl%tcool(1) = fl%tcoolmin
463 fl%Lcool(1) = l_table(1)
464
465 fl%tcool(fl%ncool) = fl%tcoolmax
466 fl%Lcool(fl%ncool) = l_table(ntable)
467
468 if (fl%fip_ > 0) then
469 fl%frac_lowFIP(1) = f_table(1)
470 fl%frac_lowFIP(fl%ncool) = f_table(ntable)
471 end if
472
473 do i=2,fl%ncool ! loop to create one table
474 fl%tcool(i) = fl%tcool(i-1)+ratt
475 do j=1,ntable-1 ! loop to create one spot on a table
476 ! Second order polynomial interpolation, except at the outer edge,
477 ! or in case of a large jump.
478 if(fl%tcool(i) < t_table(j+1)) then
479 if(j.eq. ntable-1 )then
480 fact1 = (fl%tcool(i)-t_table(j+1)) &
481 /(t_table(j)-t_table(j+1))
482 fact2 = (fl%tcool(i)-t_table(j)) &
483 /(t_table(j+1)-t_table(j))
484 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
485 if (fl%fip_ > 0) then
486 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
487 end if
488 exit
489 else
490 dl1 = l_table(j+1)-l_table(j)
491 dl2 = l_table(j+2)-l_table(j+1)
492 jump =(max(dabs(dl1),dabs(dl2)) > 2*min(dabs(dl1),dabs(dl2)))
493 end if
494 if( jump ) then
495 fact1 = (fl%tcool(i)-t_table(j+1)) &
496 /(t_table(j)-t_table(j+1))
497 fact2 = (fl%tcool(i)-t_table(j)) &
498 /(t_table(j+1)-t_table(j))
499 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2
500 if (fl%fip_ > 0) then
501 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2
502 end if
503 exit
504 else
505 fact1 = ((fl%tcool(i)-t_table(j+1)) &
506 * (fl%tcool(i)-t_table(j+2))) &
507 / ((t_table(j)-t_table(j+1)) &
508 * (t_table(j)-t_table(j+2)))
509 fact2 = ((fl%tcool(i)-t_table(j)) &
510 * (fl%tcool(i)-t_table(j+2))) &
511 / ((t_table(j+1)-t_table(j)) &
512 * (t_table(j+1)-t_table(j+2)))
513 fact3 = ((fl%tcool(i)-t_table(j)) &
514 * (fl%tcool(i)-t_table(j+1))) &
515 / ((t_table(j+2)-t_table(j)) &
516 * (t_table(j+2)-t_table(j+1)))
517 fl%Lcool(i) = l_table(j)*fact1 + l_table(j+1)*fact2 &
518 + l_table(j+2)*fact3
519 if (fl%fip_ > 0) then
520 fl%frac_lowFIP(i) = f_table(j)*fact1 + f_table(j+1)*fact2 &
521 + f_table(j+2)*fact3
522 end if
523 exit
524 end if
525 end if
526 end do ! end loop to find create one spot on a table
527 end do ! end loop to create one table
528
529 ! Go from logarithmic to actual values.
530 fl%tcool(1:fl%ncool) = 10.0d0**fl%tcool(1:fl%ncool)
531 fl%Lcool(1:fl%ncool) = 10.0d0**fl%Lcool(1:fl%ncool)
532
533 ! Change unit of table if SI is used instead of cgs
534 if (si_unit) fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * 10.0d0**(-13)
535
536 ! Scale both T and Lambda
537 fl%tcool(1:fl%ncool) = fl%tcool(1:fl%ncool) / unit_temperature
538 fl%Lcool(1:fl%ncool) = fl%Lcool(1:fl%ncool) * unit_numberdensity**2 * unit_time / unit_pressure * (1.d0+2.d0*he_abundance)
539
540 fl%tcoolmin = fl%tcool(1)+smalldouble ! avoid pointless interpolation
541 ! smaller value for lowest temperatures from cooling table and user's choice
542 if (fl%tlow==bigdouble) fl%tlow=fl%tcoolmin
543 fl%tcoolmax = fl%tcool(fl%ncool)
544 fl%lgtcoolmin = dlog10(fl%tcoolmin)
545 fl%lgtcoolmax = dlog10(fl%tcoolmax)
546 fl%lgstep = (fl%lgtcoolmax-fl%lgtcoolmin) * 1.d0 / (fl%ncool-1)
547 fl%dLdtcool(1) = (fl%Lcool(2)-fl%Lcool(1))/(fl%tcool(2)-fl%tcool(1))
548 fl%dLdtcool(fl%ncool) = (fl%Lcool(fl%ncool)-fl%Lcool(fl%ncool-1))/(fl%tcool(fl%ncool)-fl%tcool(fl%ncool-1))
549
550 do i=2,fl%ncool-1
551 fl%dLdtcool(i) = (fl%Lcool(i+1)-fl%Lcool(i-1))/(fl%tcool(i+1)-fl%tcool(i-1))
552 end do
553
554 deallocate(t_table)
555 deallocate(l_table)
556 if (allocated(f_table)) deallocate(f_table)
557
558 fl%tref = fl%tcoolmax
559 fl%lref = fl%Lcool(fl%ncool)
560 fl%Yc(fl%ncool) = zero
561 do i=fl%ncool-1, 1, -1
562 fl%Yc(i) = fl%Yc(i+1)
563 do j=1,100
564 tstep = 1.0d-2*(fl%tcool(i+1)-fl%tcool(i))
565 call findl(fl%tcool(i+1)-j*tstep, lstep, fl)
566 fl%Yc(i) = fl%Yc(i) + fl%lref/fl%tref*tstep/lstep
567 end do
568 end do
569 end if
570
571 rc_gamma_1=rc_gamma-1.d0
572 invgam = 1.d0/rc_gamma_1
573
574 end subroutine radiative_cooling_init
575
576 subroutine create_y_ppl(fl)
577 ! creates the constants of integration needed for solving
578 ! the cooling law exact for a piecewise power law
579 ! In correspondence with eq. A6 of Townsend (2009)
581 type(rc_fluid) :: fl
582 double precision :: y_extra, factor
583 integer :: i
584
585 allocate(fl%y_PPL(1:fl%n_PPL+1))
586
587 fl%y_PPL(1:fl%n_PPL+1) = zero
588
589 do i=fl%n_PPL, 1, -1
590 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
591 if (fl%a_PPL(i) == 1.d0) then
592 y_extra = log( fl%t_PPL(i) / fl%t_PPL(i+1) )
593 else
594 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / fl%t_PPL(i+1) )**(fl%a_PPL(i)-1) )
595 end if
596 fl%y_PPL(i) = fl%y_PPL(i+1) - factor*y_extra
597 end do
598 end subroutine create_y_ppl
599
600 subroutine getvar_cooling(ixI^L,ixO^L,w,x,coolrate,fl)
601 ! Create extra variable to show cooling rate in the output
602 ! Uses a simple explicit scheme.
603 ! N.B. Since there is no knowledge of the timestep size,
604 ! there is no upper limit for the cooling rate.
606
607 integer, intent(in) :: ixI^L,ixO^L
608 double precision, intent(in) :: x(ixI^S,1:ndim)
609 double precision :: w(ixI^S,1:nw)
610 double precision, intent(out):: coolrate(ixI^S)
611 type(rc_fluid), intent(in) :: fl
612
613 double precision :: pth(ixI^S),rho(ixI^S)
614 double precision :: L1,Te(ixI^S),Rfactor(ixI^S)
615 integer :: ix^D
616
617 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
618 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
619 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
620 te(ixo^s) = pth(ixo^s) / (rho(ixo^s)*rfactor(ixo^s))
621
622 {do ix^db = ixo^lim^db\}
623 ! Determine explicit cooling
624 if(te(ix^d) <= fl%tcoolmin) then
625 l1 = zero
626 else if(te(ix^d) >= fl%tcoolmax)then
627 call calc_l_extended(te(ix^d),l1,fl)
628 l1 = l1*rho(ix^d)**2
629 else
630 call findl(te(ix^d),l1,fl)
631 l1 = l1*rho(ix^d)**2
632 end if
633 if(slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height) then
634 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
635 end if
636 coolrate(ix^d) = l1
637 {end do\}
638 end subroutine getvar_cooling
639
640 subroutine getvar_cooling_exact(qdt, ixI^L, ixO^L, wCT, w, x, coolrate, fl)
641 ! Calculates cooling rate using the exact cooling method,
643
644 integer, intent(in) :: ixI^L, ixO^L
645 double precision, intent(in) :: qdt, x(ixI^S, 1:ndim), wCT(ixI^S, 1:nw)
646 double precision :: w(ixI^S, 1:nw)
647 double precision, intent(out) :: coolrate(ixI^S)
648 type(rc_fluid), intent(in) :: fl
649 double precision :: y1, y2, l1, tlocal2
650 double precision :: Te(ixI^S), pnew(ixI^S), rho(ixI^S), rhonew(ixI^S)
651 double precision :: emin, Lmax, fact, Rfactor(ixI^S), pth(ixI^S)
652 integer :: ix^D
653
654 call fl%get_pthermal(wct, x, ixi^l, ixo^l, pth)
655 call fl%get_rho(wct, x, ixi^l, ixo^l, rho)
656 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
657 te(ixo^s)=pth(ixo^s)/(rho(ixo^s)*rfactor(ixo^s))
658
659 call fl%get_pthermal(w, x, ixi^l, ixo^l, pnew)
660 call fl%get_rho(w, x, ixi^l, ixo^l, rhonew)
661
662 fact=fl%lref*qdt/fl%tref
663
664 {do ix^db = ixo^lim^db\}
665 emin = rhonew(ix^d) * fl%tlow * rfactor(ix^d) * invgam
666 lmax = max(zero, ( pnew(ix^d)*invgam - emin ) / qdt)
667
668 ! No cooling if temperature is below floor level.
669 ! Assuming Bremsstrahlung if temperature is higher than maximum.
670 if( te(ix^d)<= fl%tcoolmin) then
671 l1 = zero
672 else if( te(ix^d)>= fl%tcoolmax ) then
673 call calc_l_extended(te(ix^d), l1, fl)
674 l1 = l1 * rho(ix^d)**2
675 l1 = min(l1, lmax)
676 else
677 call findy(te(ix^d), y1, fl)
678 y2 = y1 + fact * rho(ix^d)*rc_gamma_1
679 call findt(tlocal2, y2, fl)
680 if( tlocal2 <= fl%tcoolmin ) then
681 l1 = lmax
682 else
683 l1 = (te(ix^d)- tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam/qdt
684 end if
685 l1 = min(l1, lmax)
686 end if
687 if(slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) .le. fl%rad_damp_height) then
688 l1 = l1*exp(-(x(ix^d,ndim)-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
689 end if
690 coolrate(ix^d) = l1
691 {end do\}
692 end subroutine getvar_cooling_exact
693
694 subroutine radiative_cooling_add_source(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,&
695 qsourcesplit,active,fl)
696 ! w[iw]=w[iw]+qdt*S[wCT,x] where S is the source based on wCT within ixO
698 integer, intent(in) :: ixI^L, ixO^L
699 double precision, intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
700 double precision, intent(inout) :: w(ixI^S,1:nw)
701 logical, intent(in) :: qsourcesplit
702 logical, intent(inout) :: active
703 type(rc_fluid), intent(in) :: fl
704 double precision, allocatable, dimension(:^D&) :: Lequi
705
706 if(qsourcesplit .eqv.fl%rc_split) then
707 active = .true.
708 call cool_exact(qdt,ixi^l,ixo^l,wct,wctprim,w,x,fl)
709 if(fl%subtract_equi) then
710 allocate(lequi(ixi^s))
711 call get_cool_equi(qdt,ixi^l,ixo^l,wct,w,x,fl,lequi)
712 w(ixo^s,fl%e_) = w(ixo^s,fl%e_)+lequi(ixo^s)
713 deallocate(lequi)
714 endif
715 if( fl%Tfix ) call floortemperature(qdt,ixi^l,ixo^l,wct,w,x,fl)
716 end if
717 end subroutine radiative_cooling_add_source
718
719 subroutine floortemperature(qdt,ixI^L,ixO^L,wCT,w,x,fl)
720 ! Force minimum temperature to a fixed temperature
722 integer, intent(in) :: ixI^L, ixO^L
723 double precision, intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
724 double precision, intent(inout) :: w(ixI^S,1:nw)
725 type(rc_fluid), intent(in) :: fl
726 double precision :: etherm(ixI^S), rho(ixI^S), Rfactor(ixI^S),emin
727 integer :: ix^D
728
729 call fl%get_pthermal(w,x,ixi^l,ixo^l,etherm)
730 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
731 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
732 {do ix^db = ixo^lim^db\}
733 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)
734 if(etherm(ix^d) < emin) then
735 w(ix^d,fl%e_)=w(ix^d,fl%e_)+(emin-etherm(ix^d))*invgam
736 end if
737 {end do\}
738 end subroutine floortemperature
739
740 subroutine get_cool_equi(qdt,ixI^L,ixO^L,wCT,w,x,fl,res)
742
743 integer, intent(in) :: ixI^L, ixO^L
744 double precision, intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
745 double precision, intent(inout) :: w(ixI^S,1:nw)
746 type(rc_fluid), intent(in) :: fl
747 double precision, intent(out) :: res(ixI^S)
748
749 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),L1,Tlocal2
750 double precision :: Te(ixI^S)
751 double precision :: emin, Lmax
752 double precision :: Y1, Y2
753 double precision :: de, emax,fact
754 integer :: ix^D
755
756 call fl%get_pthermal_equi(wct,x,ixi^l,ixo^l,pth)
757 call fl%get_rho_equi(wct,x,ixi^l,ixo^l,rho)
758 call fl%get_temperature_equi(wct,x,ixi^l,ixo^l,te)
759 rfactor(ixo^s)=pth(ixo^s)/(rho(ixo^s)*te(ixo^s))
760
761 res=0d0
762
763 fact = fl%lref*qdt/fl%tref
764 {do ix^db = ixo^lim^db\}
765 emin = rho(ix^d)*fl%tlow*rfactor(ix^d)*invgam
766 lmax = max(zero,(pth(ix^d)*invgam-emin)/qdt)
767 emax = max(zero, pth(ix^d)*invgam-emin)
768 if( te(ix^d)<=fl%tcoolmin ) then
769 ! temperature is below floor level, no cooling.
770 l1 = zero
771 else if( te(ix^d)>=fl%tcoolmax )then
772 call calc_l_extended(te(ix^d), l1,fl)
773 l1 = l1*rho(ix^d)**2
774 if(phys_trac) then
775 if(te(ix^d)<block%wextra(ix^d,fl%Tcoff_)) then
776 l1=l1*sqrt((te(ix^d)/block%wextra(ix^d,fl%Tcoff_))**5)
777 end if
778 end if
779 l1 = min(l1,lmax)
780 res(ix^d) = l1*qdt
781 else
782 call findy(te(ix^d),y1,fl)
783 y2 = y1 + fact * rho(ix^d)*rc_gamma_1
784 call findt(tlocal2,y2,fl)
785 if(tlocal2<=fl%tcoolmin) then
786 de = emax
787 else
788 de = (te(ix^d)-tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
789 end if
790 if(phys_trac) then
791 if(te(ix^d)<block%wextra(ix^d,fl%Tcoff_)) then
792 de=de*sqrt((te(ix^d)/block%wextra(ix^d,fl%Tcoff_))**5)
793 end if
794 end if
795 de = min(de,emax)
796 res(ix^d) = de
797 end if
798 {end do\}
799 end subroutine get_cool_equi
800
801 subroutine cool_exact(qdt,ixI^L,ixO^L,wCT,wCTprim,w,x,fl)
802 ! Cooling routine using exact integration method from Townsend 2009
804 integer, intent(in) :: ixI^L, ixO^L
805 double precision, intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw), wCTprim(ixI^S,1:nw)
806 double precision, intent(inout) :: w(ixI^S,1:nw)
807 type(rc_fluid), intent(in) :: fl
808 double precision :: Y1, Y2
809 double precision :: L1, pth(ixI^S), Tlocal2, pnew(ixI^S)
810 double precision :: rho(ixI^S), Te(ixI^S), rhonew(ixI^S), Rfactor(ixI^S)
811 double precision :: emin, Lmax, fact
812 double precision :: de_thin, de_thick, emax, emax_rem
813 double precision :: T1, T2, p1(ixI^S), tau, xi
814 double precision :: xi_arr(ixI^S), emax_rem_arr(ixI^S)
815 double precision :: cool_fac, fip_prim, frac_lowFIP, fip_factor
816 integer :: ix^D
817
818 call fl%get_rho(wct,x,ixi^l,ixo^l,rho)
819 call fl%get_var_Rfactor(wct,x,ixi^l,ixo^l,rfactor)
820 if(fl%has_equi) then
821 ! need pressure splitting for getting total pressure
822 call fl%get_pthermal(wct,x,ixi^l,ixo^l,te)
823 te(ixo^s)=te(ixo^s)/(rho(ixo^s)*rfactor(ixo^s))
824 else
825 te(ixo^s)=wctprim(ixo^s,iw_e)/(rho(ixo^s)*rfactor(ixo^s))
826 end if
827 call fl%get_pthermal(w,x,ixi^l,ixo^l,pnew)
828 call fl%get_rho(w,x,ixi^l,ixo^l,rhonew)
829
830 fact = fl%lref*qdt/fl%tref
831
832 xi_arr = one
833 emax_rem_arr = zero
834 {do ix^db = ixo^lim^db\}
835 emin = rhonew(ix^d)*fl%tlow*rfactor(ix^d)*invgam
836 lmax = max(zero,pnew(ix^d)*invgam-emin)/qdt
837 emax = max(zero,pnew(ix^d)*invgam-emin)
838 if (te(ix^d)<=fl%tcoolmin) cycle
839 if (fl%rad_newton) then
840 xi = exp(-pnew(ix^d) / fl%rad_newton_pthick)
841 xi = min(max(xi, zero), one)
842 else
843 xi = one
844 end if
845 cool_fac = xi
846
847 ! ------- (A) OPTICALLY-THIN PART --------
848 ! --- FIP factor with T-dependent r(T) ---
849 if (fl%fip_ > 0) then
850 fip_prim = min(maxfip, max(minfip, wctprim(ix^d,fl%fip_)))
851 ! frac_lowFIP(T) in [0,1]: low-FIP contribution to total Lambda at T
852 frac_lowfip = lowfip_fraction(te(ix^d), fl)
853 ! Effective multiplicative factor on Lambda(T) for this time step:
854 ! Lambda_eff(T) = g_fip * Lambda(T), with g_fip frozen at T^n
855 fip_factor = one - frac_lowfip + fip_prim * frac_lowfip
856 cool_fac = cool_fac * fip_factor
857 end if
858 ! --- geometric damping of optically thin radiative losses ---
859 ! Suppress optically thin cooling near the lower boundary (chromosphere/photosphere)
860 ! using a phenomenological Gaussian height-dependent damping.
861 if (slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) <= xprobmin1 + fl%rad_damp_height) then
862 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmin1-fl%rad_damp_height)**2/fl%rad_damp_scale**2)
863 end if
864 {^ifoned
865 if (slab_uniform .and. fl%rad_damp .and. x(ix^d,ndim) >= xprobmax1 - fl%rad_damp_height) then
866 cool_fac = cool_fac * exp(-(x(ix^d,ndim)-xprobmax1+fl%rad_damp_height)**2/fl%rad_damp_scale**2)
867 end if
868 }
869
870 ! If the temperature is higher than the maximum table value,
871 ! assume Bremsstrahlung and cool explicitly.
872 if (te(ix^d) >= fl%tcoolmax) then
873 call calc_l_extended(te(ix^d), l1, fl)
874 l1 = l1 * rho(ix^d)**2
875 l1 = min(cool_fac * l1, lmax)
876 de_thin = l1*qdt
877 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
878 else
879 ! Map T^n to Y-space
880 call findy(te(ix^d), y1, fl)
881 ! FIP and cutoff are included here as multiplicative factors in Lambda_eff.
882 y2 = y1 + cool_fac * fact * rho(ix^d) * rc_gamma_1
883 ! Invert Y(T) to get T^{n+1}
884 call findt(tlocal2, y2, fl)
885 ! Convert delta_T to an energy loss delta_e, respecting internal-energy floor.
886 if (tlocal2 <= fl%tcoolmin) then
887 de_thin = emax
888 else
889 de_thin = (te(ix^d) - tlocal2)*rho(ix^d)*rfactor(ix^d)*invgam
890 end if
891 ! --- TRAC modification: approximate, NOT strictly EI ---
892 ! This rescaling is applied *after* the EI step and depends on T^n,
893 ! so it does not correspond to integrating dT/dt with a modified
894 ! Lambda(T). Kept here for practical reason, but should be
895 ! understood as an approximate correction on top of EI.
896 if (phys_trac) then
897 if (te(ix^d) < block%wextra(ix^d,fl%Tcoff_)) then
898 de_thin = de_thin * sqrt( (te(ix^d)/block%wextra(ix^d,fl%Tcoff_))**5 )
899 end if
900 end if
901 de_thin = min(de_thin, emax)
902 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thin
903 if (fl%rad_newton) then
904 xi_arr(ix^d) = xi
905 emax_rem_arr(ix^d) = max(zero, emax - de_thin)
906 end if
907 end if
908 {end do\}
909
910 ! ------- (B) OPTICALLY-THICK (NEWTON) PART --------
911 if (fl%rad_newton) then
912 call fl%get_pthermal(w, x, ixi^l, ixo^l, p1)
913 {do ix^db = ixo^lim^db\}
914 t1 = p1(ix^d) / (rho(ix^d) * rfactor(ix^d))
915 tau = max(0.1d0 * sqrt( fl%rad_newton_rhosurf / rho(ix^d)), 4.d0 * qdt)
916 t2 = fl%rad_newton_trad + (t1 - fl%rad_newton_trad) * exp(-qdt / tau)
917 de_thick = min((one - xi_arr(ix^d)) * (t1 - t2) * rho(ix^d) * rfactor(ix^d) * invgam, emax_rem_arr(ix^d))
918 w(ix^d,fl%e_) = w(ix^d,fl%e_) - de_thick
919 {end do\}
920 end if
921 end subroutine cool_exact
922
923 subroutine calc_l_extended (tpoint, lpoint,fl)
924 ! Calculate l for t beyond tcoolmax
925 ! Assumes Bremsstrahlung for the interpolated tables
926 ! Uses the power law for piecewise power laws
927 double precision, intent(IN) :: tpoint
928 double precision, intent(OUT) :: lpoint
929 type(rc_fluid), intent(in) :: fl
930
931 if(fl%isPPL) then
932 lpoint =fl%l_PPL(fl%n_PPL) * ( tpoint / fl%t_PPL(fl%n_PPL) )**fl%a_PPL(fl%n_PPL)
933 else
934 lpoint = fl%Lcool(fl%ncool) * sqrt( tpoint / fl%tcoolmax)
935 end if
936 end subroutine calc_l_extended
937
938 double precision function lowfip_fraction(tpoint, fl)
940
941 double precision, intent(in) :: tpoint
942 type(rc_fluid), intent(in) :: fl
943
944 double precision :: lgtp
945 integer :: jl
946
947 if (tpoint <= fl%tcool(1)) then
948 lowfip_fraction = fl%frac_lowFIP(1)
949 return
950 else if (tpoint >= fl%tcool(fl%ncool)) then
951 lowfip_fraction = fl%frac_lowFIP(fl%ncool)
952 return
953 end if
954
955 lgtp = dlog10(tpoint)
956 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
957 jl = max(1, min(fl%ncool-1, jl))
958
959 lowfip_fraction = fl%frac_lowFIP(jl) &
960 + (tpoint - fl%tcool(jl)) &
961 * (fl%frac_lowFIP(jl+1) - fl%frac_lowFIP(jl)) &
962 / (fl%tcool(jl+1) - fl%tcool(jl))
963 end function lowfip_fraction
964
965 subroutine findl (tpoint,Lpoint,fl)
966 ! Fast search option to find correct point
967 ! in cooling curve
969
970 double precision,intent(IN) :: tpoint
971 double precision, intent(OUT) :: Lpoint
972 type(rc_fluid), intent(in) :: fl
973
974 double precision :: lgtp
975 integer :: jl,i
976
977 if(fl%isPPL) then
978 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
979 lpoint = fl%l_PPL(i) * (tpoint / fl%t_PPL(i))**fl%a_PPL(i)
980 else
981 lgtp = dlog10(tpoint)
982 jl = int((lgtp - fl%lgtcoolmin) /fl%lgstep) + 1
983 lpoint = fl%Lcool(jl)+ (tpoint-fl%tcool(jl)) &
984 * (fl%Lcool(jl+1)-fl%Lcool(jl)) &
985 / (fl%tcool(jl+1)-fl%tcool(jl))
986 end if
987
988 end subroutine findl
989
990 subroutine findy (tpoint,Ypoint,fl)
991 ! Fast search option to find correct point in cooling time
993
994 double precision,intent(IN) :: tpoint
995 double precision, intent(OUT) :: Ypoint
996 type(rc_fluid), intent(in) :: fl
997
998 double precision :: lgtp
999 double precision :: y_extra,factor
1000 integer :: jl,i
1001
1002 if(fl%isPPL) then
1003 i = maxloc(fl%t_PPL, dim=1, mask=fl%t_PPL<tpoint)
1004 factor = fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i) / (fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1))
1005 if(fl%a_PPL(i)==1.d0) then
1006 y_extra = log( fl%t_PPL(i) / tpoint )
1007 else
1008 y_extra = 1 / (1 - fl%a_PPL(i)) * (1 - ( fl%t_PPL(i) / tpoint )**(fl%a_PPL(i)-1) )
1009 end if
1010 ypoint = fl%y_PPL(i) + factor*y_extra
1011 else
1012 lgtp = dlog10(tpoint)
1013 jl = int((lgtp - fl%lgtcoolmin) / fl%lgstep) + 1
1014 ypoint = fl%Yc(jl)+ (tpoint-fl%tcool(jl)) &
1015 * (fl%Yc(jl+1)-fl%Yc(jl)) &
1016 / (fl%tcool(jl+1)-fl%tcool(jl))
1017 end if
1018
1019 end subroutine findy
1020
1021 subroutine findt (tpoint,Ypoint,fl)
1022 ! Fast search option to find correct temperature
1023 ! from temporal evolution function. Only possible this way because T is a monotonously
1024 ! decreasing function for the interpolated tables
1025 ! Uses eq. A7 from Townsend 2009 for piecewise power laws
1027
1028 double precision,intent(OUT) :: tpoint
1029 double precision, intent(IN) :: Ypoint
1030 type(rc_fluid), intent(in) :: fl
1031
1032 double precision :: factor
1033 integer :: jl,jc,jh,i
1034
1035 if(fl%isPPL) then
1036 i = minloc(fl%y_PPL, dim=1, mask=fl%y_PPL>ypoint)
1037 factor = fl%l_PPL(i) * fl%t_PPL(fl%n_PPL+1) / (fl%l_PPL(fl%n_PPL+1) * fl%t_PPL(i))
1038 if(fl%a_PPL(i)==1.d0) then
1039 tpoint = fl%t_PPL(i) * exp( -1.d0 * factor * ( ypoint - fl%y_PPL(i)))
1040 else
1041 tpoint = fl%t_PPL(i) * (1 - (1 - fl%a_PPL(i)) * factor * (ypoint - fl%y_PPL(i)))**(1 / (1 - fl%a_PPL(i)))
1042 end if
1043 else
1044 if(ypoint >= fl%Yc(1)) then
1045 tpoint = fl%tcoolmin
1046 else if (ypoint == fl%Yc(fl%ncool)) then
1047 tpoint = fl%tcoolmax
1048 else
1049 jl=0
1050 jh=fl%ncool+1
1051 do
1052 if(jh-jl <= 1) exit
1053 jc=(jh+jl)/2
1054 if(ypoint <= fl%Yc(jc)) then
1055 jl=jc
1056 else
1057 jh=jc
1058 end if
1059 end do
1060 ! Linear interpolation to obtain correct temperature
1061 tpoint = fl%tcool(jl)+ (ypoint-fl%Yc(jl)) &
1062 * (fl%tcool(jl+1)-fl%tcool(jl)) &
1063 / (fl%Yc(jl+1)-fl%Yc(jl))
1064 end if
1065 end if
1066 end subroutine findt
1067
1068end module mod_radiative_cooling
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
integer, parameter unitpar
file handle for IO
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
logical phys_trac
Use TRAC for MHD or 1D HD.
logical slab_uniform
uniform Cartesian geometry or not (stretched Cartesian)
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
module radiative cooling – add optically thin radiative cooling
subroutine getvar_cooling(ixil, ixol, w, x, coolrate, fl)
subroutine radiative_cooling_init_params(phys_gamma, he_abund)
Radiative cooling initialization.
subroutine findl(tpoint, lpoint, fl)
subroutine get_cool_equi(qdt, ixil, ixol, wct, w, x, fl, res)
subroutine radiative_cooling_init(fl, read_params)
subroutine radiative_cooling_add_source(qdt, ixil, ixol, wct, wctprim, w, x, qsourcesplit, active, fl)
subroutine calc_l_extended(tpoint, lpoint, fl)
double precision function lowfip_fraction(tpoint, fl)
subroutine cool_exact(qdt, ixil, ixol, wct, wctprim, w, x, fl)
subroutine findt(tpoint, ypoint, fl)
subroutine floortemperature(qdt, ixil, ixol, wct, w, x, fl)
subroutine getvar_cooling_exact(qdt, ixil, ixol, wct, w, x, coolrate, fl)
subroutine findy(tpoint, ypoint, fl)
module containing all optically thin radiative cooling tables
double precision, dimension(1:101) l_dere_corona
double precision, dimension(1:71) t_mlsolar1
double precision, dimension(1:151) l_cl_solar
double precision, dimension(1:5) t_fm
double precision, dimension(1:14) a_spex_dm_fine
double precision, dimension(1:9) a_rosner
double precision, dimension(1:110) l_spex
double precision, dimension(1:51) l_mb
double precision, dimension(1:10) t_rosner
double precision, dimension(1:5) a_hildner
double precision, dimension(1:9) x_rosner
double precision, dimension(1:7) x_klimchuk
double precision, dimension(1:151) l_cl_ism
double precision, dimension(1:8) t_spex_dm_rough
double precision, dimension(1:110) nenh_spex
double precision, dimension(1:110) t_spex
double precision, dimension(1:76) l_dm_2
double precision, dimension(1:15) t_spex_dm_fine
double precision, dimension(1:7) x_spex_dm_rough
double precision, dimension(1:14) x_spex_dm_fine
double precision, dimension(1:71) l_mlsolar1
double precision, dimension(1:45) t_jccorona
double precision, dimension(1:5) x_hildner
double precision, dimension(1:71) t_mlcosmol
double precision, dimension(1:151) t_cl_ism
double precision, dimension(1:151) t_cl_solar
double precision, dimension(1:51) t_mb
double precision, dimension(1:8) t_klimchuk
double precision, dimension(1:55) t_colgan
double precision, dimension(1:55) l_colgan
double precision, dimension(1:4) a_fm
double precision, dimension(1:101) l_dere_photo
double precision, dimension(1:45) l_jccorona
double precision, dimension(1:71) l_mlwc
double precision, dimension(1:71) l_dm
double precision, dimension(1:71) t_mlwc
double precision, dimension(1:7) a_spex_dm_rough
double precision, dimension(1:71) t_dm
double precision, dimension(1:7) a_klimchuk
double precision, dimension(1:71) l_mlcosmol
double precision, dimension(1:76) t_dm_2
double precision, dimension(1:6) t_hildner
double precision, dimension(1:4) x_fm
double precision, dimension(1:101) t_dere
double precision, dimension(1:101) lowfip_frac