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.
double precision, dimension(:), allocatable, parameter d
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.
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:70
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition mod_physics.t:49
Module with all the methods that users can customize in AMRVAC.