bondi3d.f90
Go to the documentation of this file.
1!#############################################################################
2!# #
3!# fosite - 3D hydrodynamical simulation program #
4!# module: bondi3d.f90 #
5!# #
6!# Copyright (C) 2006-2018 #
7!# Tobias Illenseer <tillense@astrophysik.uni-kiel.de> #
8!# #
9!# This program is free software; you can redistribute it and/or modify #
10!# it under the terms of the GNU General Public License as published by #
11!# the Free Software Foundation; either version 2 of the License, or (at #
12!# your option) any later version. #
13!# #
14!# This program is distributed in the hope that it will be useful, but #
15!# WITHOUT ANY WARRANTY; without even the implied warranty of #
16!# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or #
17!# NON INFRINGEMENT. See the GNU General Public License for more #
18!# details. #
19!# #
20!# You should have received a copy of the GNU General Public License #
21!# along with this program; if not, write to the Free Software #
22!# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
23!# #
24!#############################################################################
25
26!----------------------------------------------------------------------------!
41!----------------------------------------------------------------------------!
42PROGRAM bondi3d
43 USE fosite_mod
44#include "tap.h"
45 IMPLICIT NONE
46 !--------------------------------------------------------------------------!
47 ! general constants
48 REAL, PARAMETER :: msun = 1.989e+30 ! solar mass [kg] !
49 REAL, PARAMETER :: gn = 6.67408e-11 ! gravitional constant (SI) !
50 ! simulation parameters
51 REAL, PARAMETER :: tsim = 50.0 ! simulation time [TAU] !
52 REAL, PARAMETER :: accmass = 1.0*msun ! mass of the accreting object !
53 REAL, PARAMETER :: gamma = 1.4 ! ratio of specific heats !
54 ! boundary conditions
55 REAL, PARAMETER :: rhoinf = 3.351e-17 ! density at infinity [kg/m^3] !
56 REAL, PARAMETER :: csinf = 537.0 ! sound speed at infinity [m/s]!
57 ! mesh settings
58! INTEGER, PARAMETER :: MGEO = SPHERICAL ! geometry of the mesh !
59 INTEGER, PARAMETER :: mgeo = logspherical
60 INTEGER, PARAMETER :: xres = 16 ! x-resolution !
61 INTEGER, PARAMETER :: yres = 6 ! y-resolution !
62 INTEGER, PARAMETER :: zres = 12 ! z-resolution !
63 REAL, PARAMETER :: rin = 0.1 ! inner/outer radii in terms of!
64 REAL, PARAMETER :: rout = 2.0 ! the Bondi radius RB, ROUT > 1!
65 ! output parameters
66 INTEGER, PARAMETER :: onum = 10 ! number of output data sets
67 CHARACTER(LEN=256), PARAMETER & ! output data dir
68 :: odir = './'
69 CHARACTER(LEN=256), PARAMETER & ! output data file name
70 :: ofname = 'bondi3d'
71 ! some derives quandities
72 REAL :: rb ! Bondi radius
73 REAL :: tau ! free fall time scale
74 !--------------------------------------------------------------------------!
75 CLASS(fosite), ALLOCATABLE :: sim
76 REAL, DIMENSION(:), ALLOCATABLE :: sigma
77 REAL :: sum_numer, sum_denom
78 INTEGER :: n,den,vel,pre
79 LOGICAL :: ok
80 !--------------------------------------------------------------------------!
81
82 ALLOCATE(sim)
83 CALL sim%InitFosite()
84
85#ifdef PARALLEL
86 IF (sim%GetRank().EQ.0) THEN
87#endif
88tap_plan(4)
89#ifdef PARALLEL
90 END IF
91#endif
92
93 CALL makeconfig(sim, sim%config)
94! CALL PrintDict(Sim%config)
95 CALL sim%Setup()
96 ! set initial condition
97 CALL initdata(sim%Mesh,sim%Physics,sim%Timedisc)
98 ! compute numerical solution
99 CALL sim%Run()
100 ok = .NOT.sim%aborted
101 ! compare with exact solution if requested
102 IF (ASSOCIATED(sim%Timedisc%solution)) THEN
103 ALLOCATE(sigma(sim%Physics%VNUM))
104 DO n=1,sim%Physics%VNUM
105 ! use L1 norm to estimate the deviation from the exact solution:
106 ! Σ |pvar - pvar_exact| / Σ |pvar_exact|
107 sum_numer = sum(abs(sim%Timedisc%pvar%data2d(:,n)-sim%Timedisc%solution%data2d(:,n)), &
108 mask=sim%Mesh%without_ghost_zones%mask1d(:))
109 sum_denom = sum(abs(sim%Timedisc%solution%data2d(:,n)),mask=sim%Mesh%without_ghost_zones%mask1d(:))
110#ifdef PARALLEL
111 IF (sim%GetRank().GT.0) THEN
112 CALL mpi_reduce(sum_numer,sum_numer,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
113 CALL mpi_reduce(sum_denom,sum_denom,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
114 ELSE
115 CALL mpi_reduce(mpi_in_place,sum_numer,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
116 CALL mpi_reduce(mpi_in_place,sum_denom,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
117#endif
118 sigma(n) = sum_numer / sum_denom
119#ifdef PARALLEL
120 END IF
121#endif
122 END DO
123 ELSE
124 sigma(:) = 0.0
125 END IF
126
127 den = sim%Physics%DENSITY
128 vel = sim%Physics%XVELOCITY
129 pre = sim%Physics%PRESSURE
130
131#ifdef PARALLEL
132 IF (sim%GetRank().EQ.0) THEN
133#endif
134tap_check(ok,"stoptime reached")
135! These lines are very long if expanded. So we can't indent it or it will be cropped.
136tap_check_small(sigma(den),2.0e-02,"density deviation < 2%")
137tap_check_small(sigma(vel),2.0e-02,"radial velocity deviation < 2%")
138! skip azimuthal velocity deviation, because exact value is 0
139tap_check_small(sigma(pre),1.0e-02,"pressure deviation < 1%")
140tap_done
141#ifdef PARALLEL
142 END IF
143#endif
144
145 IF (ALLOCATED(sigma)) DEALLOCATE(sigma)
146 CALL sim%Finalize()
147 DEALLOCATE(sim)
148
149CONTAINS
150
151 SUBROUTINE makeconfig(Sim, config)
152 IMPLICIT NONE
153 !------------------------------------------------------------------------!
154 CLASS(fosite) :: Sim
155 TYPE(dict_typ), POINTER :: config
156 !------------------------------------------------------------------------!
157 ! Local variable declaration
158 INTEGER :: bc(6)
159 TYPE(dict_typ), POINTER :: mesh, physics, boundary, datafile, &
160 grav, pmass, timedisc, fluxes
161 REAL :: x1,x2,y1,y2,z1,z2
162 !------------------------------------------------------------------------!
163 INTENT(INOUT) :: sim
164 !------------------------------------------------------------------------!
165 ! derived constants
166 rb = gn * accmass / csinf**2 ! bondi radius [m] !
167 tau = rb / csinf ! free fall time scale [s] !
168
169 ! geometry dependent setttings
170 SELECT CASE(mgeo)
171 CASE(spherical)
172 x1 = rin * rb
173 x2 = rout * rb
174 y1 = 0.0
175 y2 = pi
176 z1 = 0.0
177 z2 = 2*pi
178 bc(west) = absorbing
179 bc(east) = custom
180 bc(south) = axis
181 bc(north) = axis
182 bc(bottom) = periodic
183 bc(top) = periodic
184 CASE(logspherical)
185 x1 = log(rin)
186 x2 = log(rout)
187 y1 = 0.0
188 y2 = pi
189 z1 = 0.0
190 z2 = 2*pi
191 bc(west) = absorbing
192 bc(east) = custom
193 bc(south) = axis
194 bc(north) = axis
195 bc(bottom) = periodic
196 bc(top) = periodic
197 CASE DEFAULT
198 CALL sim%Physics%Error("bondi3d::MakeConfig","geometry currently not supported")
199 END SELECT
200
201 mesh => dict( &
202 "meshtype" / midpoint, &
203 "geometry" / mgeo, &
204 "inum" / xres, &
205 "jnum" / yres, &
206 "knum" / zres, &
207 "xmin" / x1, &
208 "xmax" / x2, &
209 "ymin" / y1, &
210 "ymax" / y2, &
211 "zmin" / z1, &
212 "zmax" / z2, &
213 "output/radius" / 1, &
214 "gparam" / rb)
215
216 ! boundary conditions
217 boundary => dict( &
218 "western" / bc(west), &
219 "eastern" / bc(east), &
220 "southern" / bc(south), &
221 "northern" / bc(north), &
222 "bottomer" / bc(bottom), &
223 "topper" / bc(top))
224
225 ! physics settings
226 physics => dict( &
227 "problem" / euler, &
228 "gamma" / gamma)
229
230 ! flux calculation and reconstruction method
231 fluxes => dict( &
232 "order" / linear, &
233 "fluxtype" / kt, &
234 "variables" / primitive, &
235 "limiter" / monocent, &
236 "theta" / 1.2)
237
238 ! gravity term due to a point mass
239 pmass => dict( &
240 "gtype" / pointmass, &
241 "mass" / accmass, &
242 "outbound" / 0)
243
244 ! source term due to all gravity terms
245 grav => dict( &
246 "stype" / gravity, &
247 "pmass" / pmass)
248
249 ! time discretization settings
250 timedisc => dict( &
251 "method" / modified_euler, &
252 "order" / 3, &
253 "cfl" / 0.4, &
254 "stoptime" / (tsim * tau), &
255 "dtlimit" / (1.0e-6 * tau), &
256 "output/solution" / 1, &
257 "maxiter" / 100000)
258
259 ! initialize data input/output
260 datafile => dict( &
261 "fileformat" / xdmf, &
262 "filename" / (trim(odir) // trim(ofname)), &
263 "count" / onum)
264
265 config => dict( &
266 "mesh" / mesh, &
267 "physics" / physics, &
268 "boundary" / boundary, &
269 "fluxes" / fluxes, &
270 "sources/grav" / grav, &
271 "timedisc" / timedisc, &
272 "datafile" / datafile)
273 END SUBROUTINE makeconfig
274
275
276 SUBROUTINE initdata(Mesh,Physics,Timedisc)
277 IMPLICIT NONE
278 !------------------------------------------------------------------------!
279 CLASS(physics_base), INTENT(IN) :: Physics
280 CLASS(mesh_base), INTENT(IN) :: Mesh
281 CLASS(timedisc_base), INTENT(INOUT) :: Timedisc
282 !------------------------------------------------------------------------!
283 ! Local variable declaration
284 REAL :: r,rho,vr,cs2
285 INTEGER :: i,j,k,l
286 CHARACTER(LEN=64) :: info_str
287 !------------------------------------------------------------------------!
288 ! initial condition
289 SELECT TYPE(pvar => timedisc%pvar)
290 TYPE IS(statevector_euler)
291 ! constant density and pressure, vanishing velocity
292 pvar%density%data1d(:) = rhoinf
293 pvar%velocity%data1d(:) = 0.
294 pvar%pressure%data1d(:) = rhoinf * csinf**2 / gamma
295 CLASS DEFAULT
296 CALL physics%Error("bondi3d::InitData","only non-isothermal HD supported")
297 END SELECT
298
299 CALL physics%Convert2Conservative(timedisc%pvar,timedisc%cvar)
300
301 ! store exact stationary solution if requested,
302 ! i.e. output/solution == 1 in timedisc config
303 IF (ASSOCIATED(timedisc%solution)) THEN
304 ! compute the stationary 2D planar bondi solution
305 SELECT TYPE(pvar => timedisc%solution)
306 TYPE IS(statevector_euler)
307 DO k=mesh%KMIN,mesh%KMAX
308 DO j=mesh%JMIN,mesh%JMAX
309 DO i=mesh%IMIN,mesh%IMAX
310 r = mesh%radius%bcenter(i,j,k)
311 CALL bondi(r/rb,gamma,rhoinf,csinf,rho,vr)
312 cs2 = csinf**2 * (rho/rhoinf)**(gamma-1.0)
313 pvar%density%data3d(i,j,k) = rho
314 ! set the minimum of the exact velocity to some value > 0
315 ! for comparison with the numerical results
316!NEC$ UNROLL(3)
317 DO l=1,physics%VDIM
318 pvar%velocity%data4d(i,j,k,l) = sign(&
319 max(epsilon(cs2),abs(vr*mesh%posvec%bcenter(i,j,k,l)/r)), &
320 vr*mesh%posvec%bcenter(i,j,k,l))
321 END DO
322 pvar%pressure%data3d(i,j,k) = rho * cs2 / gamma
323 END DO
324 END DO
325 END DO
326 END SELECT
327 END IF
328
329 ! boundary condition: subsonic inflow according to Bondi's solution
330 ! calculate Bondi solution for y=ymin..ymax at xmax
331 SELECT TYPE(beast => timedisc%Boundary%boundary(east)%p)
332 CLASS IS (boundary_custom)
333 ! this tells the boundary routine the actual boundary condition for each variable
334 CALL beast%SetCustomBoundaries(mesh,physics, &
335 (/custom_fixed,custom_nograd,custom_fixed,custom_fixed,custom_fixed/))
336 DO k=mesh%KMIN,mesh%KMAX
337 DO j=mesh%JMIN,mesh%JMAX
338 DO i=1,mesh%GNUM
339 ! get distance to the origin for each boundary cell
340 r = mesh%radius%bcenter(mesh%IMAX+i,j,k)
341 CALL bondi(r/rb,gamma,rhoinf,csinf,rho,vr)
342 cs2 = csinf**2 * (rho/rhoinf)**(gamma-1.0)
343 beast%data(i,j,k,physics%DENSITY) = rho
344 DO l=1,physics%VDIM
345 beast%data(i,j,k,physics%XVELOCITY+l-1) &
346 = vr*mesh%posvec%bcenter(mesh%IMAX+i,j,k,l)/r
347 END DO
348 beast%data(i,j,k,physics%PRESSURE) = rho * cs2 / gamma
349 END DO
350 END DO
351 END DO
352 END SELECT
353
354 WRITE(info_str,"(ES10.3)") rb
355 CALL mesh%Info(" " // "Bondi radius: " &
356 // trim(info_str) // " m")
357 WRITE(info_str,"(ES10.3)") tau
358 CALL mesh%Info(" " // "Free fall time: " &
359 // trim(info_str) // " s")
360 END SUBROUTINE initdata
361
362
363 SUBROUTINE bondi(r,gamma,rhoinf,csinf,rho,vr)
364 USE roots
365 IMPLICIT NONE
366 !------------------------------------------------------------------------!
367 ! computes the Bondi solution for spherically symmetric accretion !
368 ! uses funcd, GetRoot !
369 ! INPUT paramter: !
370 ! r : radius in units of the Bondi radius r_b = G*M/csinf**2 !
371 ! gamma : ratio of specific heats (1 < gamma < 5/3) !
372 ! rhoinf: density at infinity !
373 ! csinf : speed of sound at infinity !
374 ! OUTPUT paramter: !
375 ! rho : density @ r !
376 ! vr : radial velocity @ r !
377 !------------------------------------------------------------------------!
378 REAL, INTENT(IN) :: r,gamma,rhoinf,csinf
379 REAL, INTENT(OUT) :: rho,vr
380 !------------------------------------------------------------------------!
381 INTERFACE
382 PURE SUBROUTINE funcd(x,fx,dfx,plist)
383 IMPLICIT NONE
384 REAL, INTENT(IN) :: x
385 REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
386 REAL, INTENT(OUT) :: fx,dfx
387 END SUBROUTINE funcd
388 END INTERFACE
389 !------------------------------------------------------------------------!
390 REAL, PARAMETER :: xacc = 1.0e-6 ! accuracy for root finding
391 REAL :: gp1,gm1,g35,rc,chi,lambda,psi,gr
392 INTEGER :: err
393 COMMON /funcd_parameter/ gm1, gr
394 !------------------------------------------------------------------------!
395 ! for convenience
396 gm1 = gamma - 1.0
397 gp1 = gamma + 1.0
398 g35 = 0.5 * (5.0-3.0*gamma)
399
400 ! critical radius
401 rc = 0.5 * g35
402 ! critical dimensionless accretion rate
403 lambda = 0.25 * g35**(-g35/gm1)
404
405 ! Newton-Raphson to solve Bondis equations for psi
406 chi = r**2 / lambda
407 gr = chi**(2.*gm1/gp1) * (1./gm1 + 1./r)
408 IF (r.LT.rc) THEN
409 CALL getroot_newton(funcd,1.0,gr,psi,err)
410 ELSE
411 CALL getroot_newton(funcd,1.0e-6,1.0,psi,err)
412 END IF
413
414 ! return values
415 rho = rhoinf * chi**(-2./gp1) / psi ! density
416 vr = -csinf * chi**(-gm1/gp1) * psi ! radial velocity
417 END SUBROUTINE bondi
418
419
420END PROGRAM bondi3d
421
422
423! for exact Bondi solution at the outer boundary
424PURE SUBROUTINE funcd(y,fy,dfy,plist)
425 IMPLICIT NONE
426 !------------------------------------------------------------------------!
427 REAL, INTENT(IN) :: y
428 REAL, INTENT(OUT) :: fy,dfy
429 REAL, INTENT(IN), DIMENSION(:), OPTIONAL :: plist
430 !------------------------------------------------------------------------!
431 REAL :: gm1,gr
432 COMMON /funcd_parameter/ gm1,gr
433 !------------------------------------------------------------------------!
434 fy = 0.5*y*y + y**(-gm1) / gm1 - gr
435 dfy = y - y**(-gm1-1.)
436END SUBROUTINE funcd
subroutine initdata(Mesh, Physics, Fluxes, Timedisc)
Definition: bondi2d.f90:274
pure subroutine funcd(y, fy, dfy, plist)
Definition: bondi2d.f90:416
subroutine makeconfig(Sim, config)
Definition: bondi2d.f90:165
subroutine bondi(r, gamma, rhoinf, csinf, rho, vr)
Definition: bondi2d.f90:363
program bondi3d
Program and data initialization for 3D Bondi accretion.
Definition: bondi3d.f90:42
root finding subroutines
Definition: roots.f90:45
subroutine, public getroot_newton(funcd, x1, x2, root, error, plist, xm, iterations)
Definition: roots.f90:247
main fosite class
Definition: fosite.f90:71