pringle.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: pringle.f90 #
5 !# #
6 !# Copyright (C) 2008-2019 #
7 !# Bjoern Sperling <sperling@astrophysik.uni-kiel.de> #
8 !# Tobias Illenseer <tillense@astrophysik.uni-kiel.de> #
9 !# #
10 !# This program is free software; you can redistribute it and/or modify #
11 !# it under the terms of the GNU General Public License as published by #
12 !# the Free Software Foundation; either version 2 of the License, or (at #
13 !# your option) any later version. #
14 !# #
15 !# This program is distributed in the hope that it will be useful, but #
16 !# WITHOUT ANY WARRANTY; without even the implied warranty of #
17 !# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or #
18 !# NON INFRINGEMENT. See the GNU General Public License for more #
19 !# details. #
20 !# #
21 !# You should have received a copy of the GNU General Public License #
22 !# along with this program; if not, write to the Free Software #
23 !# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
24 !# #
25 !#############################################################################
26 
27 !----------------------------------------------------------------------------!
47 !----------------------------------------------------------------------------!
48 PROGRAM pringle_test
49  USE fosite_mod
50  USE common_dict
51 #include "tap.h"
52  IMPLICIT NONE
53  !--------------------------------------------------------------------------!
54  ! simulation parameters
55  REAL, PARAMETER :: tsim = 2.0e-2 ! simulation time [TVIS] see below
56  ! should be < 1 ~ viscous time scale
57  ! these are the basic parameters; for stable solutions one requires
58  ! MA >> 1 and RE > MA
59  REAL, PARAMETER :: re = 1.0e+4 ! Reynolds number (at R=1)
60  REAL, PARAMETER :: ma = 1.0e+2 ! Mach number (at R=1)
61  REAL, PARAMETER :: mdisk = 1.0e-2 ! disk mass << 1 = central mass
62  ! lower limit for nitial density
63  REAL, PARAMETER :: rhomin = 1.0e-20 ! minimal initial density
64  ! viscosity prescription
65 ! INTEGER, PARAMETER :: VISTYPE = BETA
66  INTEGER, PARAMETER :: vistype = powerlaw
67  REAL, PARAMETER :: pl_exp = 0.0 ! exponent for power law viscosity
68  REAL, PARAMETER :: tvis = 4./3.*re ! viscous time scale
69  REAL, PARAMETER :: tinit = 1.0e-3 ! time for initial condition [TVIS]
70  ! mesh settings
71  !**************************************************************************!
80  !**************************************************************************!
81  INTEGER, PARAMETER :: mgeo = cylindrical
82 ! INTEGER, PARAMETER :: MGEO = LOGCYLINDRICAL
83 ! INTEGER, PARAMETER :: MGEO = SPHERICAL !!! ATTENTION: not applicable in 1D
84  INTEGER, PARAMETER :: xres = 400 ! x-resolution
85  INTEGER, PARAMETER :: yres = 1 ! y-resolution
86  INTEGER, PARAMETER :: zres = 1 ! z-resolution
87  REAL, PARAMETER :: rmin = 0.05 ! min radius of comp. domain
88  REAL, PARAMETER :: rmax = 2.0 ! max radius of comp. domain
89  REAL, PARAMETER :: gpar = 1.0 ! geometry scaling parameter
90  ! output parameters
91  INTEGER, PARAMETER :: onum = 10 ! number of output data sets
92  CHARACTER(LEN=256), PARAMETER & ! output data dir
93  :: odir = './'
94  CHARACTER(LEN=256), PARAMETER & ! output data file name
95  :: ofname = 'pringle'
96  ! derived parameters
97  REAL, PARAMETER :: csiso = 1./ma ! isothermal speed of sound
98  REAL :: x0 = 0.0 ! cartesian position of point
99  REAL :: y0 = 0.0 ! mass (default: origin)
100  REAL :: z0 = 0.0 !
101  !--------------------------------------------------------------------------!
102  CLASS(fosite), ALLOCATABLE :: sim
103  REAL, DIMENSION(:), ALLOCATABLE :: sigma
104  REAL :: sum_numer, sum_denom
105  INTEGER :: n,den,vx,vy
106  REAL :: next_output_time
107  INTEGER :: i,j,k
108  LOGICAL :: ok
109  !--------------------------------------------------------------------------!
110 
111  ALLOCATE(sim)
112  CALL sim%InitFosite()
113 
114 #ifdef PARALLEL
115  IF (sim%GetRank().EQ.0) THEN
116 #endif
117 tap_plan(4)
118 #ifdef PARALLEL
119  END IF
120 #endif
121 
122  CALL makeconfig(sim, sim%config)
123  CALL sim%Setup()
124  CALL initdata(sim,sim%Mesh, sim%Physics, sim%Timedisc)
125  next_output_time = sim%Datafile%time
126  IF (ASSOCIATED(sim%Timedisc%solution)) THEN
127 #ifdef HAVE_FGSL
128  DO WHILE((sim%Timedisc%maxiter.LE.0).OR.(sim%iter.LE.sim%Timedisc%maxiter))
129  ! advance numerical solution
130  IF(sim%Step()) EXIT
131  IF (next_output_time.LT.sim%Datafile%time) THEN
132  ! compute exact solution for next output time step
133  next_output_time = sim%Datafile%time
134  SELECT TYPE(pvar => sim%Timedisc%solution)
135  TYPE IS (statevector_eulerisotherm)
136  k=sim%Mesh%KMIN
137  DO j=sim%Mesh%JMIN,sim%Mesh%JMAX
138  DO i=sim%Mesh%IMIN,sim%Mesh%IMAX
139  IF (vistype.EQ.beta) THEN
140  CALL viscousring_analytic(1.0,next_output_time/tvis+tinit, &
141  sim%Mesh%radius%bcenter(i,j,k), &
142  pvar%density%data3d(i,j,k),pvar%velocity%data4d(i,j,k,1))
143  ELSE
144  CALL viscousring_analytic(pl_exp,next_output_time/tvis+tinit, &
145  sim%Mesh%radius%bcenter(i,j,k), &
146  pvar%density%data3d(i,j,k),pvar%velocity%data4d(i,j,k,1))
147  END IF
148  END DO
149  END DO
150  END SELECT
151  END IF
152  END DO
153 #else
154  CALL sim%Error("pringle","computation of analytical solution requires GSL support")
155 #endif
156  ELSE
157  CALL sim%Run()
158  END IF
159  ok = .NOT.sim%aborted
160  ALLOCATE(sigma(sim%Physics%VNUM))
161  ! compare with exact solution if requested
162  IF (ASSOCIATED(sim%Timedisc%solution)) THEN
163  DO n=1,sim%Physics%VNUM
164  ! use L1 norm to estimate the deviation from the exact solution:
165  ! Σ |pvar - pvar_exact| / Σ |pvar_exact|
166  sum_numer = sum(abs(sim%Timedisc%pvar%data4d(sim%Mesh%IMIN:sim%Mesh%IMAX,&
167  sim%Mesh%JMIN:sim%Mesh%JMAX,sim%Mesh%KMIN:sim%Mesh%KMAX,n) &
168  -sim%Timedisc%solution%data4d(sim%Mesh%IMIN:sim%Mesh%IMAX,&
169  sim%Mesh%JMIN:sim%Mesh%JMAX,sim%Mesh%KMIN:sim%Mesh%KMAX,n)))
170  sum_denom = sum(abs(sim%Timedisc%solution%data4d(sim%Mesh%IMIN:sim%Mesh%IMAX,&
171  sim%Mesh%JMIN:sim%Mesh%JMAX,sim%Mesh%KMIN:sim%Mesh%KMAX,n)))
172 #ifdef PARALLEL
173  IF (sim%GetRank().GT.0) THEN
174  CALL mpi_reduce(sum_numer,sum_numer,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
175  CALL mpi_reduce(sum_denom,sum_denom,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
176  ELSE
177  CALL mpi_reduce(mpi_in_place,sum_numer,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
178  CALL mpi_reduce(mpi_in_place,sum_denom,1,default_mpi_real,mpi_sum,0,mpi_comm_world,sim%ierror)
179 #endif
180  sigma(n) = sum_numer / sum_denom
181 #ifdef PARALLEL
182  END IF
183 #endif
184  END DO
185  ELSE
186  sigma(:) = 0.0
187  END IF
188 
189  den = sim%Physics%DENSITY
190  vx = sim%Physics%XVELOCITY
191  vy = sim%Physics%YVELOCITY
192 
193 #ifdef PARALLEL
194  IF (sim%GetRank().EQ.0) THEN
195 #endif
196 tap_check(ok,"stoptime reached")
197 ! These lines are very long if expanded. So we can't indent it or it will be cropped.
198 tap_check_small(sigma(den),5.0e-02,"density deviation < 5%")
199 tap_check_small(sigma(vx),8.0e-02,"radial velocity deviation < 8%")
200 ! skip azimuthal velocity deviation, because exact value is 0
201 tap_check_small(sigma(vy),2.0e-04,"azimuthal velocity deviation < 0.02%")
202 tap_done
203 #ifdef PARALLEL
204  END IF
205 #endif
206 
207  IF (ALLOCATED(sigma)) DEALLOCATE(sigma)
208  CALL sim%Finalize()
209  DEALLOCATE(sim)
210 
211 CONTAINS
212 
213  SUBROUTINE makeconfig(Sim, config)
214  USE functions, ONLY : asinh
215  IMPLICIT NONE
216  !------------------------------------------------------------------------!
217  CLASS(fosite) :: Sim
218  TYPE(Dict_TYP),POINTER :: config
219  !------------------------------------------------------------------------!
220  ! Local variable declaration
221  INTEGER :: bc(6)
222  TYPE(Dict_TYP), POINTER :: mesh, physics, boundary, datafile, &
223  grav, vis, timedisc, fluxes, sources
224  REAL :: x1,x2,y1,y2,z1,z2,cvis
225  !------------------------------------------------------------------------!
226  INTENT(INOUT) :: sim
227  !------------------------------------------------------------------------!
228  ! mesh settings and boundary conditions
229  SELECT CASE(mgeo)
230  CASE(cylindrical)
231  x1 = rmin
232  x2 = rmax
233  y1 = -pi
234  y2 = pi
235  z1 = 0.0
236  z2 = 0.0
237 ! bc(WEST) = NO_GRADIENTS
238 ! bc(EAST) = NO_GRADIENTS
239 ! bc(WEST) = ABSORBING
240 ! bc(EAST) = ABSORBING
241  bc(west) = custom
242  bc(east) = custom
243  bc(south) = periodic
244  bc(north) = periodic
245  bc(bottom) = no_gradients
246  bc(top) = no_gradients
247  !!! ATTENTION: empirical formula found for standard parameters
248  !!! seems to work for RMIN=0.05 and XRES <= 1000
249  cvis = (xres/1207.0)**1.9
250  CASE(logcylindrical)
251  x1 = log(rmin/gpar)
252  x2 = log(rmax/gpar)
253  y1 = -pi
254  y2 = pi
255  z1 = 0.0
256  z2 = 0.0
257  bc(west) = no_gradients
258  bc(east) = no_gradients
259  bc(south) = periodic
260  bc(north) = periodic
261  bc(bottom) = no_gradients
262  bc(top) = no_gradients
263  cvis = 0.1
264  CASE(spherical)
265  x1 = rmin
266  x2 = rmax
267  y1 = pi/2 ! - 0.05*PI
268  y2 = pi/2 ! + 0.05*PI
269  z1 = -pi
270  z2 = pi
271 ! bc(WEST) = NO_GRADIENTS
272 ! bc(EAST) = NO_GRADIENTS
273  bc(west) = custom
274  bc(east) = custom
275  bc(south) = no_gradients
276  bc(north) = no_gradients
277  bc(bottom) = periodic
278  bc(top) = periodic
279  !!! ATTENTION: empirical formula found for standard parameters
280  !!! seems to work for RMIN=0.05 and XRES <= 1000
281  cvis = (xres/1207.0)**1.9
282  CASE DEFAULT
283  CALL sim%Error("pringle::MakeConfig","mesh geometry not supported for Pringle disk")
284  END SELECT
285 
286  ! mesh settings
287  mesh => dict( &
288  "meshtype" / midpoint, &
289  "geometry" / mgeo, &
290  "inum" / xres, &
291  "jnum" / yres, &
292  "knum" / zres, &
293  "xmin" / x1, &
294  "xmax" / x2, &
295  "ymin" / y1, &
296  "ymax" / y2, &
297  "zmin" / z1, &
298  "zmax" / z2, &
299 ! "use_fargo" / 1, &
300 ! "fargo" / 2, &
301  "gparam" / gpar)
302 
303  ! boundary conditions
304  boundary => dict( &
305  "western" / bc(west), &
306  "eastern" / bc(east), &
307  "southern" / bc(south), &
308  "northern" / bc(north), &
309  "bottomer" / bc(bottom), &
310  "topper" / bc(top))
311 
312 
313  ! physics settings
314  physics => dict( &
315  "problem" / euler_isotherm, &
316  "units" / geometrical, &
317  "cs" / csiso)
318 
319  ! flux calculation and reconstruction method
320  fluxes => dict( &
321  "order" / linear, &
322  "fluxtype" / kt, &
323  "variables" / primitive, &
324  "limiter" / vanleer, &
325  "theta" / 1.2)
326 
327  ! source term due to viscosity
328  vis => dict( &
329  "stype" / viscosity, &
330  "vismodel" / vistype, &
331  "dynconst" / (1./re), &
332  "exponent" / pl_exp, &
333  "cvis" / cvis)
334 
335  ! source term due to a point mass
336  grav => dict( &
337  "stype" / gravity, &
338  "pmass/gtype"/ pointmass, & ! grav. accel. of a point mass
339  "pmass/mass" / 1.0, & ! non-dim. mass of the accreting object
340  "pmass/x" / x0, & ! cartesian position of point mass
341  "pmass/y" / y0, &
342  "pmass/outbound" / 0) ! disable accretion
343 
344  ! combine all source terms
345  sources => dict( &
346  "grav" / grav, &
347  "viscosity" / vis)
348 
349  ! time discretization settings
350  timedisc => dict( &
351  "method" / ssprk, &
352  "stoptime" / (tsim * tvis), &
353  "cfl" / 0.4, &
354  "dtlimit" / (1e-10 * tvis), &
355 ! "rhstype" / 1, &
356  "maxiter" / 100000000, &
357  "tol_rel" / 0.01, &
358  "tol_abs" / (/0.0,1e-5,0.0/))
359 
360  ! enable output of analytical solution
361 #ifdef HAVE_FGSL
362  IF (mgeo.EQ.cylindrical) &
363  CALL setattr(timedisc,"output/solution",1)
364 #endif
365 
366  ! initialize data input/output
367  datafile => dict( &
368  "fileformat"/ vtk, &
369  "filename" / (trim(odir) // trim(ofname)), &
370  "count" / onum)
371 
372  config => dict( &
373  "mesh" / mesh, &
374  "physics" / physics, &
375  "boundary" / boundary, &
376  "fluxes" / fluxes, &
377  "sources" / sources, &
378  "timedisc" / timedisc, &
379  "datafile" / datafile)
380  END SUBROUTINE makeconfig
381 
382  SUBROUTINE initdata(Sim,Mesh,Physics,Timedisc)
383  IMPLICIT NONE
384  !------------------------------------------------------------------------!
385  CLASS(fosite), INTENT(INOUT) :: Sim
386  CLASS(physics_base), INTENT(IN) :: Physics
387  CLASS(mesh_base), INTENT(IN) :: Mesh
388  CLASS(timedisc_base), INTENT(INOUT) :: Timedisc
389  !------------------------------------------------------------------------!
390  ! Local variable declaration
391  CLASS(sources_base), POINTER :: sp
392  CLASS(sources_gravity), POINTER :: gp
393  INTEGER :: i,j,k
394  REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,Mesh%KGMIN:Mesh%KGMAX,3) &
395  :: posvec,ephi
396  REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,Mesh%KGMIN:Mesh%KGMAX) :: radius
397  REAL :: r,vr,vphi,sden,mu
398  CHARACTER(LEN=64) :: value
399  !------------------------------------------------------------------------!
400  IF (abs(x0).LE.tiny(x0).AND.abs(y0).LE.tiny(y0)) THEN
401  ! no shift of point mass set radius and posvec to Mesh defaults
402  radius(:,:,:) = mesh%radius%bcenter(:,:,:)
403  posvec(:,:,:,:) = mesh%posvec%bcenter(:,:,:,:)
404  ELSE
405  ! shifted point mass position:
406  ! compute curvilinear components of shift vector
407  posvec(:,:,:,1) = x0
408  posvec(:,:,:,2) = y0
409  posvec(:,:,:,3) = z0
410  CALL mesh%Geometry%Convert2Curvilinear(mesh%bcenter,posvec,posvec)
411  ! subtract the result from the position vector:
412  ! this gives you the curvilinear components of all vectors pointing
413  ! from the point mass to the bary center of any cell on the mesh
414  posvec(:,:,:,:) = mesh%posvec%bcenter(:,:,:,:) - posvec(:,:,:,:)
415  ! compute its absolute value
416  radius(:,:,:) = sqrt(posvec(:,:,:,1)**2+posvec(:,:,:,2)**2+posvec(:,:,:,3)**2)
417  END IF
418 
419  ! curvilinear components of azimuthal unit vector
420  ! (maybe with respect to shifted origin)
421  ! from ephi = ez x er = ez x posvec/radius = ez x (rxi*exi + reta*eeta)/r
422  ! = rxi/r*(ez x exi) + reta/r*(ez x eeta) = rxi/r*eeta - reta/r*exi
423  ! because (ez,exi,eeta) is right handed orthonormal set of basis vectors
424  ephi(:,:,:,1) = -posvec(:,:,:,2)/radius(:,:,:)
425  ephi(:,:,:,2) = posvec(:,:,:,1)/radius(:,:,:)
426  ephi(:,:,:,3) = 0.0
427 
428  ! custom boundary conditions if requested
429  SELECT TYPE(bwest => timedisc%Boundary%boundary(west)%p)
430  CLASS IS (boundary_custom)
431  CALL bwest%SetCustomBoundaries(mesh,physics, &
432  (/custom_nograd,custom_extrapol,custom_kepler/))
433  END SELECT
434  SELECT TYPE(beast => timedisc%Boundary%boundary(east)%p)
435  CLASS IS (boundary_custom)
436  CALL beast%SetCustomBoundaries(mesh,physics, &
437  (/custom_logexpol,custom_outflow,custom_kepler/))
438  END SELECT
439 
440  ! get gravitational acceleration
441  sp => sim%Sources
442  DO
443  IF (ASSOCIATED(sp).EQV..false.) RETURN
444  SELECT TYPE(sp)
445  CLASS IS(sources_gravity)
446  gp => sp
447  EXIT
448  END SELECT
449  sp => sp%next
450  END DO
451  IF (.NOT.ASSOCIATED(sp)) CALL physics%Error("pringle::InitData","no gravity term initialized")
452 
453  SELECT CASE(vistype)
454  CASE(beta)
455  mu=1.0
456  CASE(powerlaw)
457  mu=pl_exp
458  CASE DEFAULT
459  CALL timedisc%Error("pringle::InitData","only pringle and beta viscosity possible")
460  END SELECT
461 
462  ! initial condition
463  SELECT TYPE(pvar => timedisc%pvar)
464  TYPE IS(statevector_eulerisotherm)
465  DO k=mesh%KGMIN,mesh%KGMAX
466  DO j=mesh%JGMIN,mesh%JGMAX
467  DO i=mesh%IMIN,mesh%IGMAX
468  ! distance to center of mass
469  r = radius(i,j,k)
470  ! Keplerian velocity
471  vphi = sqrt(1.0/r)
472 #ifdef HAVE_FGSL
473  ! use exact solution at time TINIT
474  CALL viscousring_analytic(mu,tinit,r,sden,vr)
475 #else
476  ! use approximation for TINIT << 1
477  ! no need for modified Bessel functions
478  CALL viscousring_approx(mu,tinit,r,sden,vr)
479 #endif
480  pvar%density%data3d(i,j,k) = rhomin + sden
481  ! curvilinear velocity components
482  pvar%velocity%data4d(i,j,k,1:2) = &
483  vr*posvec(i,j,k,1:2)/r + vphi*ephi(i,j,k,1:2)
484 ! pvar%velocity%data4d(i,j,k,1:2) = vr*posvec(i,j,k,1:2)/r
485 ! p%velocity%data4d(i,j,k,2) = vphi
486  END DO
487  END DO
488  END DO
489 ! CALL gp%UpdateGravity(Mesh,Sim%Physics,Sim%Fluxes,pvar,0.0,0.0)
490 ! pvar%velocity%data4d(:,:,:,1:Physics%VDIM) = &
491 ! Timedisc%GetCentrifugalVelocity(Mesh,Sim%Physics,Sim%Fluxes,Sim%Sources,(/0.,0.,1./), &
492 ! gp%accel%data4d)
493  CLASS DEFAULT
494  CALL timedisc%Error("pringle::InitData","only isothermal physics possible")
495  END SELECT
496 
497  IF (ASSOCIATED(timedisc%solution)) THEN
498  ! store initial condition in exact solution array
499  timedisc%solution = timedisc%pvar
500  END IF
501 
502  ! check fargo and set background velocity field
503  IF (mesh%FARGO.EQ.2) &
504  timedisc%w(:,:) = sqrt(1.0/radius(:,mesh%JMIN,:))
505 
506  ! transform to conservative variables
507  CALL physics%Convert2Conservative(timedisc%pvar,timedisc%cvar)
508 
509  CALL mesh%Info(" DATA-----> initial condition: " // "pringle disk")
510  WRITE(value,"(ES9.3)") tvis
511  CALL mesh%Info(" " // "viscous timescale: " //trim(value))
512  WRITE(value,"(ES9.3)") re
513  CALL mesh%Info(" " // "Reynolds number: " //trim(value))
514  WRITE(value,"(ES9.3)") ma
515  CALL mesh%Info(" " // "Mach number: " //trim(value))
516 
517  END SUBROUTINE initdata
518 
519 
520  SUBROUTINE viscousring_approx(mu,tau,r,Sigma,vr)
521  IMPLICIT NONE
522  !--------------------------------------------------------------------!
523  REAL, INTENT(IN) :: mu,tau,r
524  REAL, INTENT(OUT) :: Sigma,vr
525  !--------------------------------------------------------------------!
526  REAL :: lambda,x,r4l,invr4l
527  !--------------------------------------------------------------------!
528  lambda = 1./(4.0-mu)
529  r4l = r**(0.25/lambda)
530  x = 2*lambda**2 / tau * r**(0.25/lambda)
531  invr4l = 1./r4l
532  sigma = mdisk/sqrt((4*pi)**3 * tau) * r4l**(1.5-9*lambda) &
533  * exp(-lambda**2/tau*(1.0-r4l)**2)
534  vr = -1.5/re * ((x*tau)/(2*lambda*lambda))**(4*lambda-2.) &
535  * (1.0 - 0.5*x/lambda * (x*tau/(2*lambda*lambda) - 1.0))
536  END SUBROUTINE viscousring_approx
537 
538 #ifdef HAVE_FGSL
539  SUBROUTINE viscousring_analytic(mu,tau,r,Sigma,vr)
540  IMPLICIT NONE
541  !--------------------------------------------------------------------!
542  REAL, INTENT(IN) :: mu,tau,r
543  REAL, INTENT(OUT) :: Sigma,vr
544  !--------------------------------------------------------------------!
545  REAL :: lambda,r4l,x
546  !--------------------------------------------------------------------!
547  lambda = 1./(4.0-mu)
548  r4l = r**(0.25/lambda)
549  x = 2*lambda**2 / tau * r4l
550  sigma = mdisk/(4*pi) * (lambda/tau) * r4l**2 * r**(-2.25) &
551  * exp(-lambda**2/tau*(1.0+r4l**2)) &
552  * modified_bessel_inu(lambda,x)
553  vr = -1.5/re * ((x*tau)/(2*lambda*lambda))**(4*lambda-2.) &
554  * (1.0 - 0.5*x/lambda * (x*tau/(2*lambda*lambda) &
555  - modified_bessel_inu(1+lambda,x)/modified_bessel_inu(lambda,x)))
556  END SUBROUTINE viscousring_analytic
557 
558  FUNCTION modified_bessel_inu(nu,x) RESULT(Inu)
559  USE fgsl
560  IMPLICIT NONE
561  !--------------------------------------------------------------------!
562  REAL, INTENT(IN) :: nu,x
563  REAL :: inu
564  !--------------------------------------------------------------------!
565  INTEGER :: n
566  !--------------------------------------------------------------------!
567  IF (aint(nu).EQ.nu) THEN
568  ! nu is an integer -> use modified bessel functions of integer order
569  n = int(nu)
570  inu = fgsl_sf_bessel_icn(n,x)
571  ELSE
572  ! nu is not an integer -> use representation of modified bessel functions
573  ! through hypergeometric functions 0F1
574  inu = (0.5*x)**nu / fgsl_sf_gamma(1.0+nu) * fgsl_sf_hyperg_0f1(1.0+nu,(0.5*x)**2)
575  END IF
576  END FUNCTION modified_bessel_inu
577 #endif
578 
579 END PROGRAM pringle_test
type(dict_typ) function, pointer, public dict(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20)
Construct a new dictionary from several key/value pairs. Together with the Assign subroutine and over...
Mathematical functions.
Definition: functions.f90:48
subroutine initdata(Mesh, Physics, Fluxes, Timedisc)
Definition: bondi2d.f90:274
real function modified_bessel_inu(nu, x)
Definition: pringle.f90:559
main fosite class
Definition: fosite.f90:71
elemental real function, public asinh(x)
inverse hyperbolic sine function
Definition: functions.f90:100
program pringle_test
Definition: pringle.f90:48
subroutine makeconfig(Sim, config)
Definition: bondi2d.f90:165
Dictionary for generic data types.
Definition: common_dict.f90:61
subroutine viscousring_analytic(mu, tau, r, Sigma, vr)
Definition: pringle.f90:540
subroutine viscousring_approx(mu, tau, r, Sigma, vr)
Definition: pringle.f90:521