MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_cak_force.t
Go to the documentation of this file.
1!> Module to include CAK radiation line force in (magneto)hydrodynamic models
2!> Computes both the force from free electrons and the force from an ensemble of
3!> lines (various possibilities for the latter).
4!> There is an option to only simulate the pure radial CAK force (with various
5!> corrections applied) as well as the full vector CAK force. Depending on the
6!> chosen option additional output are the CAK line force component(s) and,
7!> when doing a 1-D radial force, the finite disc factor.
8!>
9!> USAGE:
10!>
11!> 1. Include a cak_list in the .par file and activate (m)hd_cak_force in the
12!> (m)hd_list
13!> 2. Create a mod_usr.t file for the problem with appropriate initial and
14!> boundary conditions
15!> 3. In the mod_usr.t header call the mod_cak_force module to have access to
16!> global variables from mod_cak_force, which may be handy for printing or
17!> the computation of other variables inside mod_usr.t
18!> 4. In usr_init of mod_usr.t call the set_cak_force_norm routine and pass
19!> along the stellar radius and wind temperature---this is needed to
20!> correctly compute the (initial) force normalisation inside mod_cak_force
21!> 5. Ensure that the order of calls in usr_init is similar as for test problem
22!> CAKwind_spherical_1D: first reading usr.par list; then set unit scales;
23!> then call (M)HD_activate; then call set_cak_force_norm. This order avoids
24!> an incorrect force normalisation and code crash
25!>
26!> Developed by Florian Driessen (2022)
29 implicit none
30
31 !> Line-ensemble parameters in the Gayley (1995) formalism
32 real(8), public :: cak_alpha, gayley_qbar, gayley_q0
33
34 !> Ray positions + weights for impact parameter and azimuthal radiation angle
35 real(8), allocatable, private :: ay(:), wy(:), aphi(:), wphi(:)
36
37 !> The adiabatic index
38 real(8), private :: cak_gamma
39
40 !> Variables needed to compute force normalisation fnorm in initialisation
41 real(8), private :: lum, dlum, drstar, dke, dclight
42
43 !> To enforce a floor temperature when doing adiabatic (M)HD
44 real(8), private :: tfloor
45
46 !> Switch to choose between the 1-D CAK line force options
47 integer :: cak_1d_opt
48
49 ! Avoid magic numbers in code for 1-D CAK line force option
50 integer, parameter, private :: radstream=0, fdisc=1, fdisc_cutoff=2
51
52 !> Amount of rays in radiation polar and radiation azimuthal direction
53 integer :: nthetaray, nphiray
54
55 !> Extra slots to store quantities in w-array
56 integer :: gcak1_, gcak2_, gcak3_, fdf_
57
58 !> To treat source term in split or unsplit (default) fashion
59 logical :: cak_split=.false.
60
61 !> To activate the original CAK 1-D line force computation
62 logical :: cak_1d_force=.false.
63
64 !> To activate the vector CAK line force computation
65 logical :: cak_vector_force=.false.
66
67 !> To activate the pure radial vector CAK line force computation
68 logical :: fix_vector_force_1d=.false.
69
70 !> Public method
71 public :: set_cak_force_norm
72
73contains
74
75 !> Read this module's parameters from a file
76 subroutine cak_params_read(files)
78
79 character(len=*), intent(in) :: files(:)
80
81 ! Local variable
82 integer :: n
83
84 namelist /cak_list/ cak_alpha, gayley_qbar, gayley_q0, cak_1d_opt, &
87
88 do n = 1,size(files)
89 open(unitpar, file=trim(files(n)), status="old")
90 read(unitpar, cak_list, end=111)
91 111 close(unitpar)
92 enddo
93
94 end subroutine cak_params_read
95
96 !> Initialize the module
97 subroutine cak_init(phys_gamma)
99 use mod_comm_lib, only: mpistop
100
101 real(8), intent(in) :: phys_gamma
102
103 cak_gamma = phys_gamma
104
105 ! Set some defaults when user does not
106 cak_alpha = 0.65d0
107 gayley_qbar = 2000.0d0
108 gayley_q0 = 2000.0d0
109 cak_1d_opt = fdisc
110 nthetaray = 6
111 nphiray = 6
112
114
115 if (cak_1d_force) then
116 gcak1_ = var_set_extravar("gcak1", "gcak1")
117 fdf_ = var_set_extravar("fdfac", "fdfac")
118 endif
119
120 if (cak_vector_force) then
121 gcak1_ = var_set_extravar("gcak1", "gcak1")
122 gcak2_ = var_set_extravar("gcak2", "gcak2")
123 gcak3_ = var_set_extravar("gcak3", "gcak3")
125 endif
126
127 ! Some sanity checks
128 if ((cak_alpha <= 0.0d0) .or. (cak_alpha > 1.0d0)) then
129 call mpistop('CAK error: choose alpha in [0,1[')
130 endif
131
132 if ((gayley_qbar < 0.0d0) .or. (gayley_q0 < 0.0d0)) then
133 call mpistop('CAK error: chosen Qbar or Q0 is < 0')
134 endif
135
136 if (cak_1d_force .and. cak_vector_force) then
137 call mpistop('CAK error: choose either 1-D or vector force')
138 endif
139
140 end subroutine cak_init
141
142 !> Compute some (unitless) variables for CAK force normalisation
143 subroutine set_cak_force_norm(rstar,twind)
145 use mod_constants
146
147 real(8), intent(in) :: rstar, twind
148 double precision :: const_kappae_local
149 const_kappae_local=0.34d0
150
151 lum = 4.0d0*dpi * rstar**2.0d0 * const_sigma * twind**4.0d0
152 dke = const_kappae_local * unit_density * unit_length
153 dclight = const_c/unit_velocity
154 dlum = lum/(unit_density * unit_length**5.0d0 / unit_time**3.0d0)
155 drstar = rstar/unit_length
156 tfloor = twind/unit_temperature
157
158 end subroutine set_cak_force_norm
159
160 !> w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
161 subroutine cak_add_source(qdt,ixI^L,ixO^L,wCT,w,x,energy,qsourcesplit,active)
163 use mod_comm_lib, only: mpistop
164
165 integer, intent(in) :: ixI^L, ixO^L
166 real(8), intent(in) :: qdt, x(ixI^S,1:ndim), wCT(ixI^S,1:nw)
167 real(8), intent(inout) :: w(ixI^S,1:nw)
168 logical, intent(in) :: energy, qsourcesplit
169 logical, intent(inout) :: active
170
171 ! Local variables
172 real(8) :: gl(ixO^S,1:3), ge(ixO^S), ptherm(ixI^S), pmin(ixI^S)
173 integer :: idir
174
175 ! By default add source in unsplit fashion together with the fluxes
176 if (qsourcesplit .eqv. cak_split) then
177
178 active = .true.
179
180 ! Thomson force
181 call get_gelectron(ixi^l,ixo^l,wct,x,ge)
182
183 ! CAK line force
184 gl(ixo^s,1:3) = 0.0d0
185
186 if (cak_1d_force) then
187 call get_cak_force_radial(ixi^l,ixo^l,wct,w,x,gl)
188 elseif (cak_vector_force) then
189 call get_cak_force_vector(ixi^l,ixo^l,wct,w,x,gl)
190 else
191 call mpistop("No valid force option")
192 endif
193
194 ! Update conservative vars: w = w + qdt*gsource
195 do idir = 1,ndir
196 if (idir == 1) gl(ixo^s,idir) = gl(ixo^s,idir) + ge(ixo^s)
197
198 w(ixo^s,iw_mom(idir)) = w(ixo^s,iw_mom(idir)) &
199 + qdt * gl(ixo^s,idir) * wct(ixo^s,iw_rho)
200
201 if (energy) then
202 w(ixo^s,iw_e) = w(ixo^s,iw_e) + qdt * gl(ixo^s,idir) * wct(ixo^s,iw_mom(idir))
203 endif
204 enddo
205
206 ! Impose fixed floor temperature to mimic stellar heating
207 if (energy) then
208 call phys_get_pthermal(w,x,ixi^l,ixo^l,ptherm)
209 pmin(ixo^s) = w(ixo^s,iw_rho) * tfloor
210
211 where (ptherm(ixo^s) < pmin(ixo^s))
212 w(ixo^s,iw_e) = w(ixo^s,iw_e) + (pmin(ixo^s) - ptherm(ixo^s))/(cak_gamma - 1.0d0)
213 endwhere
214 endif
215 endif
216
217 end subroutine cak_add_source
218
219 !> 1-D CAK line force in the Gayley line-ensemble distribution parametrisation
220 subroutine get_cak_force_radial(ixI^L,ixO^L,wCT,w,x,gcak)
222 use mod_comm_lib, only: mpistop
223
224 integer, intent(in) :: ixI^L, ixO^L
225 real(8), intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
226 real(8), intent(inout) :: w(ixI^S,1:nw)
227 real(8), intent(inout) :: gcak(ixO^S,1:3)
228
229 ! Local variables
230 real(8) :: vr(ixI^S), dvrdr(ixO^S)
231 real(8) :: beta_fd(ixO^S), fdfac(ixO^S), taus(ixO^S), ge(ixO^S)
232
233 vr(ixi^s) = wct(ixi^s,iw_mom(1)) / wct(ixi^s,iw_rho)
234 call get_velocity_gradient(ixi^l,ixo^l,vr,x,1,dvrdr)
235
236 if (physics_type == 'hd') then
237 ! Monotonic flow to avoid multiple resonances and radiative coupling
238 dvrdr(ixo^s) = abs(dvrdr(ixo^s))
239 else
240 ! Allow material to fallback to the star in a magnetosphere model
241 dvrdr(ixo^s) = max(dvrdr(ixo^s), smalldouble)
242 endif
243
244 ! Thomson force
245 call get_gelectron(ixi^l,ixo^l,wct,x,ge)
246
247 ! Sobolev optical depth for line ensemble (tau = Qbar * t_r) and the force
248 select case (cak_1d_opt)
249 case(radstream, fdisc)
250 taus(ixo^s) = gayley_qbar * dke * dclight * wct(ixo^s,iw_rho)/dvrdr(ixo^s)
251 gcak(ixo^s,1) = gayley_qbar/(1.0d0 - cak_alpha) &
252 * ge(ixo^s)/taus(ixo^s)**cak_alpha
253
254 case(fdisc_cutoff)
255 taus(ixo^s) = gayley_q0 * dke * dclight * wct(ixo^s,iw_rho)/dvrdr(ixo^s)
256 gcak(ixo^s,1) = gayley_qbar * ge(ixo^s) &
257 * ( (1.0d0 + taus(ixo^s))**(1.0d0 - cak_alpha) - 1.0d0 ) &
258 / ( (1.0d0 - cak_alpha) * taus(ixo^s) )
259 case default
260 call mpistop("Error in force computation.")
261 end select
262
263 ! Finite disk factor parameterisation (Owocki & Puls 1996)
264 beta_fd(ixo^s) = ( 1.0d0 - vr(ixo^s)/(x(ixo^s,1) * dvrdr(ixo^s)) ) &
265 * (drstar/x(ixo^s,1))**2.0d0
266
267 select case (cak_1d_opt)
268 case(radstream)
269 fdfac(ixo^s) = 1.0d0
270 case(fdisc, fdisc_cutoff)
271 where (beta_fd(ixo^s) >= 1.0d0)
272 fdfac(ixo^s) = 1.0d0/(1.0d0 + cak_alpha)
273 elsewhere (beta_fd(ixo^s) < -1.0d10)
274 fdfac(ixo^s) = abs(beta_fd(ixo^s))**cak_alpha / (1.0d0 + cak_alpha)
275 elsewhere (abs(beta_fd(ixo^s)) > 1.0d-3)
276 fdfac(ixo^s) = (1.0d0 - (1.0d0 - beta_fd(ixo^s))**(1.0d0 + cak_alpha)) &
277 / (beta_fd(ixo^s)*(1.0d0 + cak_alpha))
278 elsewhere
279 fdfac(ixo^s) = 1.0d0 - 0.5d0*cak_alpha*beta_fd(ixo^s) &
280 * (1.0d0 + 1.0d0/3.0d0 * (1.0d0 - cak_alpha)*beta_fd(ixo^s))
281 endwhere
282 end select
283
284 ! Correct radial line force for finite disc (if applicable)
285 gcak(ixo^s,1) = gcak(ixo^s,1) * fdfac(ixo^s)
286 gcak(ixo^s,2) = 0.0d0
287 gcak(ixo^s,3) = 0.0d0
288
289 ! Fill the nwextra slots for output
290 w(ixo^s,gcak1_) = gcak(ixo^s,1)
291 w(ixo^s,fdf_) = fdfac(ixo^s)
292
293 end subroutine get_cak_force_radial
294
295 !> Vector CAK line force in the Gayley line-ensemble distribution parametrisation
296 subroutine get_cak_force_vector(ixI^L,ixO^L,wCT,w,x,gcak)
299
300 ! Subroutine arguments
301 integer, intent(in) :: ixI^L, ixO^L
302 real(8), intent(in) :: wCT(ixI^S,1:nw), x(ixI^S,1:ndim)
303 real(8), intent(inout) :: w(ixI^S,1:nw)
304 real(8), intent(inout) :: gcak(ixO^S,1:3)
305
306 ! Local variables
307 real(8) :: a1, a2, a3, wyray, y, wpray, phiray, wtot, mustar, dvndn
308 real(8) :: costp, costp2, sintp, cospp, sinpp, cott0
309 real(8) :: vr(ixI^S), vt(ixI^S), vp(ixI^S)
310 real(8) :: vrr(ixI^S), vtr(ixI^S), vpr(ixI^S)
311 real(8) :: dvrdr(ixO^S), dvtdr(ixO^S), dvpdr(ixO^S)
312 real(8) :: dvrdt(ixO^S), dvtdt(ixO^S), dvpdt(ixO^S)
313 real(8) :: dvrdp(ixO^S), dvtdp(ixO^S), dvpdp(ixO^S)
314 integer :: ix^D, itray, ipray
315
316 ! Initialisation to have full velocity strain tensor expression at all times
317 vt(ixo^s) = 0.0d0; vtr(ixo^s) = 0.0d0
318 vp(ixo^s) = 0.0d0; vpr(ixo^s) = 0.0d0
319 cott0 = 0.0d0
320 dvrdr(ixo^s) = 0.0d0; dvtdr(ixo^s) = 0.0d0; dvpdr(ixo^s) = 0.0d0
321 dvrdt(ixo^s) = 0.0d0; dvtdt(ixo^s) = 0.0d0; dvpdt(ixo^s) = 0.0d0
322 dvrdp(ixo^s) = 0.0d0; dvtdp(ixo^s) = 0.0d0; dvpdp(ixo^s) = 0.0d0
323
324 ! Populate velocity field(s) depending on dimensions and directions
325 vr(ixi^s) = wct(ixi^s,iw_mom(1)) / wct(ixi^s,iw_rho)
326 vrr(ixi^s) = vr(ixi^s) / x(ixi^s,1)
327
328 {^nooned
329 vt(ixi^s) = wct(ixi^s,iw_mom(2)) / wct(ixi^s,iw_rho)
330 vtr(ixi^s) = vt(ixi^s) / x(ixi^s,1)
331
332 if (ndir > 2) then
333 vp(ixi^s) = wct(ixi^s,iw_mom(3)) / wct(ixi^s,iw_rho)
334 vpr(ixi^s) = vp(ixi^s) / x(ixi^s,1)
335 endif
336 }
337
338 ! Derivatives of velocity field in each coordinate direction (r=1,t=2,p=3)
339 call get_velocity_gradient(ixi^l,ixo^l,vr,x,1,dvrdr)
340
341 {^nooned
342 call get_velocity_gradient(ixi^l,ixo^l,vr,x,2,dvrdt)
343 call get_velocity_gradient(ixi^l,ixo^l,vt,x,1,dvtdr)
344 call get_velocity_gradient(ixi^l,ixo^l,vt,x,2,dvtdt)
345
346 if (ndir > 2) then
347 call get_velocity_gradient(ixi^l,ixo^l,vp,x,1,dvpdr)
348 call get_velocity_gradient(ixi^l,ixo^l,vp,x,2,dvpdt)
349 endif
350 }
351 {^ifthreed
352 call get_velocity_gradient(ixi^l,ixo^l,vr,x,3,dvrdp)
353 call get_velocity_gradient(ixi^l,ixo^l,vt,x,3,dvtdp)
354 call get_velocity_gradient(ixi^l,ixo^l,vp,x,3,dvpdp)
355 }
356
357 ! Get total acceleration from all rays at a certain grid point
358 {do ix^db=ixomin^db,ixomax^db\}
359 ! Loop over the rays; first theta then phi radiation angle
360 ! Get weights from current ray and their position
361 do itray = 1,nthetaray
362 wyray = wy(itray)
363 y = ay(itray)
364
365 do ipray = 1,nphiray
366 wpray = wphi(ipray)
367 phiray = aphi(ipray)
368
369 ! Redistribute the phi rays by a small offset
370 ! if (mod(itp,3) == 1) then
371 ! phip = phip + dphi/3.0d0
372 ! elseif (mod(itp,3) == 2) then
373 ! phip = phip - dphi/3.0d0
374 ! endif
375
376 ! === Geometrical factors ===
377 ! Make y quadrature linear in mu, not mu**2; better for gtheta,gphi
378 ! y -> mu quadrature is preserved; y=0 <=> mu=1; y=1 <=> mu=mustar
379 mustar = sqrt(max(1.0d0 - (drstar/x(ix^d,1))**2.0d0, 0.0d0))
380 costp = 1.0d0 - y*(1.0d0 - mustar)
381 costp2 = costp*costp
382 sintp = sqrt(max(1.0d0 - costp2, 0.0d0))
383 sinpp = sin(phiray)
384 cospp = cos(phiray)
385 {^nooned cott0 = cos(x(ix^d,2))/sin(x(ix^d,2))}
386
387 ! More weight close to star, less farther away
388 wtot = wyray * wpray * (1.0d0 - mustar)
389
390 ! Convenients a la Cranmer & Owocki (1995)
391 a1 = costp
392 a2 = sintp * cospp
393 a3 = sintp * sinpp
394
395 ! Get total velocity gradient for one ray with given (theta', phi')
396 dvndn = a1*a1 * dvrdr(ix^d) + a2*a2 * (dvtdt(ix^d) + vrr(ix^d)) &
397 + a3*a3 * (dvpdp(ix^d) + cott0 * vtr(ix^d) + vrr(ix^d)) &
398 + a1*a2 * (dvtdr(ix^d) + dvrdt(ix^d) - vtr(ix^d)) &
399 + a1*a3 * (dvpdr(ix^d) + dvrdp(ix^d) - vpr(ix^d)) &
400 + a2*a3 * (dvpdt(ix^d) + dvtdp(ix^d) - cott0 * vpr(ix^d))
401
402 ! No multiple resonances in CAK
403 dvndn = abs(dvndn)
404
405 ! Convert gradient back from wind coordinates (r',theta',phi') to
406 ! stellar coordinates (r,theta,phi)
407 gcak(ix^d,1) = gcak(ix^d,1) + (dvndn/wct(ix^d,iw_rho))**cak_alpha * a1 * wtot
408 gcak(ix^d,2) = gcak(ix^d,2) + (dvndn/wct(ix^d,iw_rho))**cak_alpha * a2 * wtot
409 gcak(ix^d,3) = gcak(ix^d,3) + (dvndn/wct(ix^d,iw_rho))**cak_alpha * a3 * wtot
410 enddo
411 enddo
412 {enddo\}
413
414 ! Normalisation for line force
415 ! NOTE: extra 1/pi factor comes from integration in radiation Phi angle
416 gcak(ixo^s,:) = (dke*gayley_qbar)**(1.0d0 - cak_alpha)/(1.0d0 - cak_alpha) &
417 * dlum/(4.0d0*dpi*drstar**2.0d0 * dclight**(1.0d0+cak_alpha)) &
418 * gcak(ixo^s,:)/dpi
419
420 if (fix_vector_force_1d) then
421 gcak(ixo^s,2) = 0.0d0
422 gcak(ixo^s,3) = 0.0d0
423 endif
424
425 ! Fill the nwextra slots for output
426 w(ixo^s,gcak1_) = gcak(ixo^s,1)
427 w(ixo^s,gcak2_) = gcak(ixo^s,2)
428 w(ixo^s,gcak3_) = gcak(ixo^s,3)
429
430 end subroutine get_cak_force_vector
431
432 !> Compute continuum radiation force from Thomson scattering
433 subroutine get_gelectron(ixI^L,ixO^L,w,x,ge)
435
436 integer, intent(in) :: ixI^L, ixO^L
437 real(8), intent(in) :: w(ixI^S,1:nw), x(ixI^S,1:ndim)
438 real(8), intent(out):: ge(ixO^S)
439
440 ge(ixo^s) = dke * dlum/(4.0d0*dpi * dclight * x(ixo^s,1)**2.0d0)
441
442 end subroutine get_gelectron
443
444 !> Check time step for total radiation contribution
445 subroutine cak_get_dt(wprim,ixI^L,ixO^L,dtnew,dx^D,x)
447
448 integer, intent(in) :: ixI^L, ixO^L
449 real(8), intent(in) :: dx^D, x(ixI^S,1:ndim)
450 real(8), intent(in) :: wprim(ixI^S,1:nw)
451 real(8), intent(inout) :: dtnew
452
453 ! Local variables
454 real(8) :: ge(ixO^S), max_gr, dt_cak
455
456 call get_gelectron(ixi^l,ixo^l,wprim,x,ge)
457
458 dtnew = bigdouble
459
460 ! Get dt from line force that is saved in the w-array in nwextra slot
461 max_gr = max( maxval(abs(ge(ixo^s) + wprim(ixo^s,gcak1_))), epsilon(1.0d0) )
462 dt_cak = minval( sqrt(block%dx(ixo^s,1)/max_gr) )
463 dtnew = min(dtnew, courantpar*dt_cak)
464
465 {^nooned
466 if (cak_vector_force) then
467 max_gr = max( maxval(abs(wprim(ixo^s,gcak2_))), epsilon(1.0d0) )
468 dt_cak = minval( sqrt(block%dx(ixo^s,1) * block%dx(ixo^s,2)/max_gr) )
469 dtnew = min(dtnew, courantpar*dt_cak)
470
471 {^ifthreed
472 max_gr = max( maxval(abs(wprim(ixo^s,gcak3_))), epsilon(1.0d0) )
473 dt_cak = minval( sqrt(block%dx(ixo^s,1) * sin(block%dx(ixo^s,3))/max_gr) )
474 dtnew = min(dtnew, courantpar*dt_cak)
475 }
476 endif
477 }
478
479 end subroutine cak_get_dt
480
481 !> Compute velocity gradient in direction 'idir' on a non-uniform grid
482 subroutine get_velocity_gradient(ixI^L,ixO^L,vfield,x,idir,grad_vn)
484
485 integer, intent(in) :: ixI^L, ixO^L, idir
486 real(8), intent(in) :: vfield(ixI^S), x(ixI^S,1:ndim)
487 real(8), intent(out) :: grad_vn(ixO^S)
488
489 ! Local variables
490 real(8) :: forw(ixO^S), backw(ixO^S), cent(ixO^S)
491 integer :: jrx^L, hrx^L{^NOONED,jtx^L, htx^L}{^IFTHREED,jpx^L, hpx^L}
492
493 ! Index +1 (j) and index -1 (h) in radial direction; kr(dir,dim)=1, dir=dim
494 jrx^l=ixo^l+kr(1,^d);
495 hrx^l=ixo^l-kr(1,^d);
496
497 {^nooned
498 ! Index +1 (j) and index -1 (h) in polar direction
499 jtx^l=ixo^l+kr(2,^d);
500 htx^l=ixo^l-kr(2,^d);
501 }
502
503 {^ifthreed
504 ! Index +1 (j) and index -1 (h) in azimuthal direction
505 jpx^l=ixo^l+kr(3,^d);
506 hpx^l=ixo^l-kr(3,^d);
507 }
508
509 ! grad(v.n) on non-uniform grid according to Sundqvist & Veronis (1970)
510 select case (idir)
511 case(1) ! Radial forward, backward, and central derivatives
512 forw(ixo^s) = (x(ixo^s,1) - x(hrx^s,1)) * vfield(jrx^s) &
513 / ((x(jrx^s,1) - x(ixo^s,1)) * (x(jrx^s,1) - x(hrx^s,1)))
514
515 backw(ixo^s) = -(x(jrx^s,1) - x(ixo^s,1)) * vfield(hrx^s) &
516 / ((x(ixo^s,1) - x(hrx^s,1)) * (x(jrx^s,1) - x(hrx^s,1)))
517
518 cent(ixo^s) = (x(jrx^s,1) + x(hrx^s,1) - 2.0d0*x(ixo^s,1)) * vfield(ixo^s) &
519 / ((x(ixo^s,1) - x(hrx^s,1)) * (x(jrx^s,1) - x(ixo^s,1)))
520 {^nooned
521 case(2) ! Polar forward, backward, and central derivatives
522 forw(ixo^s) = (x(ixo^s,2) - x(htx^s,2)) * vfield(jtx^s) &
523 / (x(ixo^s,1) * (x(jtx^s,2) - x(ixo^s,2)) * (x(jtx^s,2) - x(htx^s,2)))
524
525 backw(ixo^s) = -(x(jtx^s,2) - x(ixo^s,2)) * vfield(htx^s) &
526 / ( x(ixo^s,1) * (x(ixo^s,2) - x(htx^s,2)) * (x(jtx^s,2) - x(htx^s,2)))
527
528 cent(ixo^s) = (x(jtx^s,2) + x(htx^s,2) - 2.0d0*x(ixo^s,2)) * vfield(ixo^s) &
529 / ( x(ixo^s,1) * (x(ixo^s,2) - x(htx^s,2)) * (x(jtx^s,2) - x(ixo^s,2)))
530 }
531 {^ifthreed
532 case(3) ! Azimuthal forward, backward, and central derivatives
533 forw(ixo^s) = (x(ixo^s,3) - x(hpx^s,3)) * vfield(jpx^s) &
534 / ( x(ixo^s,1)*sin(x(ixo^s,2)) * (x(jpx^s,3) - x(ixo^s,3)) * (x(jpx^s,3) - x(hpx^s,3)))
535
536 backw(ixo^s) = -(x(jpx^s,3) - x(ixo^s,3)) * vfield(hpx^s) &
537 / ( x(ixo^s,1)*sin(x(ixo^s,2)) * (x(ixo^s,3) - x(hpx^s,3)) * (x(jpx^s,3) - x(hpx^s,3)))
538
539 cent(ixo^s) = (x(jpx^s,3) + x(hpx^s,3) - 2.0d0*x(ixo^s,3)) * vfield(ixo^s) &
540 / ( x(ixo^s,1)*sin(x(ixo^s,2)) * (x(ixo^s,3) - x(hpx^s,3)) * (x(jpx^s,3) - x(ixo^s,3)))
541 }
542 end select
543
544 ! Total gradient for given velocity field
545 grad_vn(ixo^s) = backw(ixo^s) + cent(ixo^s) + forw(ixo^s)
546
547 end subroutine get_velocity_gradient
548
549 !> Initialise (theta',phi') radiation angles coming from stellar disc
550 subroutine rays_init(ntheta_point,nphi_point)
552
553 ! Subroutine arguments
554 integer, intent(in) :: ntheta_point, nphi_point
555
556 ! Local variables
557 real(8) :: ymin, ymax, phipmin, phipmax, adum
558 integer :: ii
559
560 ! Minimum and maximum range of theta and phi rays
561 ! NOTE: theta points are cast into y-space
562 ymin = 0.0d0
563 ymax = 1.0d0
564 phipmin = -dpi !0.0d0
565 phipmax = dpi !2.0d0*dpi
566 ! dphi = (phipmax - phipmin) / nphi_point
567
568 if (mype == 0) then
569 allocate(ay(ntheta_point))
570 allocate(wy(ntheta_point))
571 allocate(aphi(nphi_point))
572 allocate(wphi(nphi_point))
573
574 ! theta and phi ray positions and weights: Gauss-Legendre
575 call gauss_legendre_quadrature(ymin,ymax,ntheta_point,ay,wy)
576 call gauss_legendre_quadrature(phipmin,phipmax,nphi_point,aphi,wphi)
577
578 ! theta rays and weights: uniform
579 ! dth = 1.0d0 / nthetap
580 ! adum = ymin + 0.5d0*dth
581 ! do ip = 1,nthetap
582 ! ay(ip) = adum
583 ! wy(ip) = 1.0d0/nthetap
584 ! adum = adum + dth
585 ! !print*,'phipoints'
586 ! !print*,ip,aphi(ip),wphi(ip),dphi
587 ! enddo
588
589 ! phi ray position and weights: uniform
590 ! adum = phipmin + 0.5d0*dphi
591 ! do ii = 1,nphi_point
592 ! aphi(ii) = adum
593 ! wphi(ii) = 1.0d0/nphi_point
594 ! adum = adum + dphi
595 ! enddo
596
597 print*, '==========================='
598 print*, ' Radiation ray setup '
599 print*, '==========================='
600 print*, 'Theta ray points + weights '
601 do ii = 1,ntheta_point
602 print*,ii,ay(ii),wy(ii)
603 enddo
604 print*
605 print*, 'Phi ray points + weights '
606 do ii = 1,nphi_point
607 print*,ii,aphi(ii),wphi(ii)
608 enddo
609 print*
610 endif
611
612 call mpi_barrier(icomm,ierrmpi)
613
614 !===========================
615 ! Broadcast what mype=0 read
616 !===========================
617 if (npe > 1) then
618 call mpi_bcast(ntheta_point,1,mpi_integer,0,icomm,ierrmpi)
619 call mpi_bcast(nphi_point,1,mpi_integer,0,icomm,ierrmpi)
620
621 if (mype /= 0) then
622 allocate(ay(ntheta_point))
623 allocate(wy(ntheta_point))
624 allocate(aphi(nphi_point))
625 allocate(wphi(nphi_point))
626 endif
627
628 call mpi_bcast(ay,ntheta_point,mpi_double_precision,0,icomm,ierrmpi)
629 call mpi_bcast(wy,ntheta_point,mpi_double_precision,0,icomm,ierrmpi)
630 call mpi_bcast(aphi,nphi_point,mpi_double_precision,0,icomm,ierrmpi)
631 call mpi_bcast(wphi,nphi_point,mpi_double_precision,0,icomm,ierrmpi)
632 endif
633
634 end subroutine rays_init
635
636 !> Fast Gauss-Legendre N-point quadrature algorithm by G. Rybicki
637 subroutine gauss_legendre_quadrature(xlow,xhi,n,x,w)
638 ! Given the lower and upper limits of integration xlow and xhi, and given n,
639 ! this routine returns arrays x and w of length n, containing the abscissas
640 ! and weights of the Gauss-Legendre N-point quadrature
642
643 ! Subroutine arguments
644 real(8), intent(in) :: xlow, xhi
645 integer, intent(in) :: n
646 real(8), intent(out) :: x(n), w(n)
647
648 ! Local variables
649 real(8) :: p1, p2, p3, pp, xl, xm, z, z1
650 real(8), parameter :: error=3.0d-14
651 integer :: i, j, m
652
653 m = (n + 1)/2
654 xm = 0.5d0*(xhi + xlow)
655 xl = 0.5d0*(xhi - xlow)
656
657 do i = 1,m
658 z = cos( dpi * (i - 0.25d0)/(n + 0.5d0) )
659 z1 = 2.0d0 * z
660
661 do while (abs(z1 - z) > error)
662 p1 = 1.0d0
663 p2 = 0.0d0
664
665 do j = 1,n
666 p3 = p2
667 p2 = p1
668 p1 = ( (2.0d0*j - 1.0d0)*z*p2 - (j - 1.0d0)*p3 )/j
669 enddo
670
671 pp = n*(z*p1 - p2) / (z*z - 1.0d0)
672 z1 = z
673 z = z1 - p1/pp
674 enddo
675
676 x(i) = xm - xl*z
677 x(n+1-i) = xm + xl*z
678 w(i) = 2.0d0*xl / ((1.0d0 - z*z) * pp*pp)
679 w(n+1-i) = w(i)
680 enddo
681
682 end subroutine gauss_legendre_quadrature
683
684end module mod_cak_force
Module to include CAK radiation line force in (magneto)hydrodynamic models Computes both the force fr...
real(8), public gayley_qbar
real(8), public gayley_q0
logical cak_split
To treat source term in split or unsplit (default) fashion.
subroutine cak_init(phys_gamma)
Initialize the module.
subroutine cak_params_read(files)
Public method.
subroutine cak_get_dt(wprim, ixil, ixol, dtnew, dxd, x)
Check time step for total radiation contribution.
subroutine gauss_legendre_quadrature(xlow, xhi, n, x, w)
Fast Gauss-Legendre N-point quadrature algorithm by G. Rybicki.
real(8), public cak_alpha
Line-ensemble parameters in the Gayley (1995) formalism.
subroutine cak_add_source(qdt, ixil, ixol, wct, w, x, energy, qsourcesplit, active)
w[iw]=w[iw]+qdt*S[wCT,qtC,x] where S is the source based on wCT within ixO
subroutine, public set_cak_force_norm(rstar, twind)
Compute some (unitless) variables for CAK force normalisation.
logical fix_vector_force_1d
To activate the pure radial vector CAK line force computation.
integer gcak1_
Extra slots to store quantities in w-array.
logical cak_vector_force
To activate the vector CAK line force computation.
subroutine get_velocity_gradient(ixil, ixol, vfield, x, idir, grad_vn)
Compute velocity gradient in direction 'idir' on a non-uniform grid.
integer cak_1d_opt
Switch to choose between the 1-D CAK line force options.
subroutine get_cak_force_radial(ixil, ixol, wct, w, x, gcak)
1-D CAK line force in the Gayley line-ensemble distribution parametrisation
subroutine get_gelectron(ixil, ixol, w, x, ge)
Compute continuum radiation force from Thomson scattering.
subroutine get_cak_force_vector(ixil, ixol, wct, w, x, gcak)
Vector CAK line force in the Gayley line-ensemble distribution parametrisation.
logical cak_1d_force
To activate the original CAK 1-D line force computation.
integer nthetaray
Amount of rays in radiation polar and radiation azimuthal direction.
subroutine rays_init(ntheta_point, nphi_point)
Initialise (theta',phi') radiation angles coming from stellar disc.
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter dpi
Pi.
double precision, parameter const_c
universal constants as specified in cgs units
double precision, parameter const_sigma
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
integer, dimension(3, 3) kr
Kronecker delta tensor.
double precision unit_length
Physical scaling factor for length.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
integer mype
The rank of the current MPI task.
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision courantpar
The Courant (CFL) number used for the simulation.
integer ierrmpi
A global MPI error return code.
double precision, dimension(:), allocatable, parameter d
integer npe
The number of MPI tasks.
double precision unit_velocity
Physical scaling factor for velocity.
double precision unit_temperature
Physical scaling factor for temperature.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
procedure(sub_get_pthermal), pointer phys_get_pthermal
Definition mod_physics.t:77
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition mod_physics.t:47
Module with all the methods that users can customize in AMRVAC.