vortex3d.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: vortex2d.f90 #
5 !# #
6 !# Copyright (C) 2006-2014 #
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 !----------------------------------------------------------------------------!
32 !----------------------------------------------------------------------------!
33 PROGRAM vortex3d
34  USE fosite_mod
35 #include "tap.h"
36  IMPLICIT NONE
37  !--------------------------------------------------------------------------!
38  ! simulation parameters
39  REAL, PARAMETER :: tsim = 30.0 ! simulation stop time
40  REAL, PARAMETER :: gamma = 1.4 ! ratio of specific heats
41  REAL, PARAMETER :: csiso = &
42 ! 0.0 ! non-isothermal simulation
43  1.127 ! isothermal simulation
44  ! with CSISO as sound speed
45  ! initial condition (dimensionless units)
46  REAL, PARAMETER :: rhoinf = 1. ! ambient density
47  REAL, PARAMETER :: pinf = 1. ! ambient pressure
48  REAL, PARAMETER :: vstr = 5.0 ! nondimensional vortex strength
49  REAL, PARAMETER :: uinf = 0.0 ! cartesian components of constant
50  REAL, PARAMETER :: vinf = 0.0 ! global velocity field
51  REAL, PARAMETER :: winf = 0.0
52  REAL, PARAMETER :: x0 = 0.0 ! vortex position (cart. coords.)
53  REAL, PARAMETER :: y0 = 0.0
54  REAL, PARAMETER :: z0 = 0.0
55  REAL, PARAMETER :: r0 = 1.0 ! size of vortex
56  REAL, PARAMETER :: omega = 0.0 ! angular speed of rotational frame
57  ! around [X0,Y0]
58  ! mesh settings
59  INTEGER, PARAMETER :: mgeo = cylindrical
60  INTEGER, PARAMETER :: xres = 40 ! x-resolution
61  INTEGER, PARAMETER :: yres = 40 ! y-resolution
62  INTEGER, PARAMETER :: zres = 1 ! z-resolution
63  REAL, PARAMETER :: rmin = 1.0e-2 ! inner radius for polar grids
64  REAL, PARAMETER :: rmax = 5.0 ! outer radius
65  REAL, PARAMETER :: zmin = -1.0 ! extent in z-direction
66  REAL, PARAMETER :: zmax = 1.0
67  REAL, PARAMETER :: gpar = 1.0 ! geometry scaling parameter !
68  ! physics settings
69 !!$ LOGICAL, PARAMETER :: WITH_IAR = .TRUE. ! use EULER2D_IAMROT
70  LOGICAL, PARAMETER :: with_iar = .false.
71 
72  ! output parameters
73  INTEGER, PARAMETER :: onum = 10 ! number of output data sets
74  CHARACTER(LEN=256), PARAMETER & ! output data dir
75  :: odir = './'
76  CHARACTER(LEN=256), PARAMETER & ! output data file name
77  :: ofname = 'vortex3d'
78  !--------------------------------------------------------------------------!
79  CLASS(fosite),ALLOCATABLE :: sim
80  CLASS(marray_compound), POINTER :: pvar_init
81  REAL :: sigma
82  !--------------------------------------------------------------------------!
83 
84  tap_plan(1)
85 
86  ALLOCATE(sim)
87  CALL sim%InitFosite()
88  CALL makeconfig(sim, sim%config)
89  CALL sim%Setup()
90  CALL initdata(sim%Mesh, sim%Physics, sim%Timedisc)
91  CALL sim%Physics%new_statevector(pvar_init,primitive)
92  pvar_init = sim%Timedisc%pvar
93  CALL sim%Run()
94  ! compare with initial condition
95  sigma = sqrt(sum((sim%Timedisc%pvar%data1d(:)-pvar_init%data1d(:))**2)/SIZE(pvar_init%data1d))
96  CALL sim%Finalize()
97  CALL pvar_init%Destroy()
98  DEALLOCATE(sim,pvar_init)
99  tap_check_small(sigma,3.8e-2,"vortex3d")
100  tap_done
101 
102 CONTAINS
103 
104  SUBROUTINE makeconfig(Sim, config)
105  USE functions, ONLY : asinh
106  IMPLICIT NONE
107  !------------------------------------------------------------------------!
108  TYPE(fosite) :: Sim
109  TYPE(Dict_TYP),POINTER :: config
110  !------------------------------------------------------------------------!
111  ! Local variable declaration
112  INTEGER :: bc(6)
113  TYPE(Dict_TYP), POINTER :: mesh, physics, boundary, datafile, &
114  timedisc, fluxes, sources, rotframe
115  REAL :: x1,x2,y1,y2,z1,z2
116  !------------------------------------------------------------------------!
117  INTENT(INOUT) :: sim
118  !------------------------------------------------------------------------!
119  ! mesh settings and boundary conditions
120  SELECT CASE(mgeo)
121  CASE(cartesian)
122  x1 = -rmax
123  x2 = rmax
124  y1 = -rmax
125  y2 = rmax
126  bc(west) = no_gradients
127  bc(east) = no_gradients
128  bc(south) = no_gradients
129  bc(north) = no_gradients
130  bc(bottom) = no_gradients
131  bc(top) = no_gradients
132  CASE(cylindrical)
133  x1 = rmin
134  x2 = rmax
135  y1 = 0.0
136  y2 = 2.0*pi
137  bc(west) = no_gradients
138  bc(east) = no_gradients
139  bc(south) = periodic
140  bc(north) = periodic
141  bc(bottom) = no_gradients
142  bc(top) = no_gradients
143  CASE DEFAULT
144  CALL sim%Error("vortex3d::MakeConfig","geometry currently not supported")
145  END SELECT
146  IF (zres.GT.1) THEN
147  z1 = zmin
148  z2 = zmax
149  ELSE
150  z1 = 0
151  z2 = 0
152  END IF
153 
154  !mesh settings
155  mesh => dict( &
156  "meshtype" / midpoint, &
157  "geometry" / mgeo, &
158  "omega" / omega, &
159  "inum" / xres, &
160  "jnum" / yres, &
161  "knum" / zres, &
162  "xmin" / x1, &
163  "xmax" / x2, &
164  "ymin" / y1, &
165  "ymax" / y2, &
166  "zmin" / z1, &
167  "zmax" / z2, &
168  "gparam" / gpar )
169 
170  ! boundary conditions
171  boundary => dict( &
172  "western" / bc(west), &
173  "eastern" / bc(east), &
174  "southern" / bc(south), &
175  "northern" / bc(north), &
176  "bottomer" / bc(bottom), &
177  "topper" / bc(top) )
178 
179  ! physics settings
180  IF (csiso.GT.tiny(csiso)) THEN
181  physics => dict("problem" / euler_isotherm, &
182  "cs" / csiso) ! isothermal sound speed !
183  ELSE
184 ! IF (WITH_IAR) THEN
185 ! ! REMARK: the optimal softening parameter depends on mesh geometry, limiter and
186 ! ! possibly other settings; modify this starting with the default of 1.0, if the
187 ! ! results show odd behaviour near the center of rotation; larger values increase
188 ! ! softening; 0.5 give reasonable results for PP limiter on cartesian mesh
189 ! physics => Dict("problem" / EULER2D_IAMT, &
190 ! "centrot_x" / X0,"centrot_y" / Y0, & ! center of rotation !
191 ! "softening" / 0.5, & ! softening parameter !
192 ! "gamma" / GAMMA ) ! ratio of specific heats !
193 ! ELSE
194  physics => dict("problem" / euler, &
195  "gamma" / gamma)
196 ! END IF
197  END IF
198 
199  ! flux calculation and reconstruction method
200  fluxes => dict( &
201  "fluxtype" / kt, &
202 ! "order" / CONSTANT, &
203  "order" / linear, &
204  "variables" / primitive, &
205  "limiter" / vanleer, & ! PP limiter gives better results than
206  "theta" / 1.0e-20, & ! should be < EPS for PP limiter
207  "output/slopes" / 0)
208 
209  ! activate inertial forces due to rotating frame if OMEGA > 0
210  NULLIFY(sources)
211  IF (omega.GT.tiny(omega)) THEN
212  rotframe => dict("stype" / rotating_frame, &
213  "x" / x0, &
214  "y" / y0)
215  sources => dict("rotframe" / rotframe)
216  END IF
217 
218  ! time discretization settings
219  timedisc => dict(&
220  "method" / modified_euler, &
221  "order" / 3, &
222  "cfl" / 0.4, &
223  "stoptime" / tsim, &
224  "dtlimit" / 1.0e-4, &
225  "maxiter" / 1000000, &
226 ! "output/fluxes" / 1, &
227  "output/iangularmomentum" / 1, &
228  "output/rothalpy" / 1 )
229 
230  ! initialize data input/output
231  datafile => dict(&
232  "fileformat" / vtk, &
233  "filename" / (trim(odir) // trim(ofname)), &
234  "count" / onum)
235 
236  config => dict("mesh" / mesh, &
237  "physics" / physics, &
238  "boundary" / boundary, &
239  "fluxes" / fluxes, &
240  "timedisc" / timedisc, &
241  "datafile" / datafile )
242 
243  ! add sources terms
244  IF (ASSOCIATED(sources)) &
245  CALL setattr(config, "sources", sources)
246 
247  END SUBROUTINE makeconfig
248 
249 
250  SUBROUTINE initdata(Mesh,Physics,Timedisc)
251  IMPLICIT NONE
252  !------------------------------------------------------------------------!
253  CLASS(physics_base),INTENT(IN) :: Physics
254  CLASS(mesh_base),INTENT(IN) :: Mesh
255  CLASS(timedisc_base),INTENT(INOUT):: Timedisc
256  !------------------------------------------------------------------------!
257  ! Local variable declaration
258  INTEGER :: n
259  REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,Mesh%KGMIN:Mesh%KGMAX) &
260  :: radius,dist_axis,domega
261  REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,Mesh%KGMIN:Mesh%KGMAX,3) &
262  :: posvec,ephi
263  REAL :: csinf
264  !------------------------------------------------------------------------!
265  IF (abs(x0).LE.tiny(x0).AND.abs(y0).LE.tiny(y0).AND.abs(z0).LE.tiny(z0)) THEN
266  ! no shift of rotational axis
267  radius(:,:,:) = mesh%radius%bcenter(:,:,:)
268  posvec(:,:,:,:) = mesh%posvec%bcenter(:,:,:,:)
269  ELSE
270  ! axis is assumed to be parallel to the cartesian z-axis
271  ! but shifted in the plane perpendicular to it
272  ! compute curvilinear components of shift vector
273  posvec(:,:,:,1) = x0
274  posvec(:,:,:,2) = y0
275  posvec(:,:,:,3) = 0.0
276  CALL mesh%geometry%Convert2Curvilinear(mesh%bcenter,posvec,posvec)
277  ! subtract the result from the position vector:
278  ! this gives you the curvilinear components of all vectors pointing
279  ! from the point mass to the bary center of any cell on the mesh
280  posvec(:,:,:,:) = mesh%posvec%bcenter(:,:,:,:) - posvec(:,:,:,:)
281  ! compute its absolute value
282  radius(:,:,:) = sqrt(posvec(:,:,:,1)**2+posvec(:,:,:,2)**2+posvec(:,:,:,3)**2)
283  END IF
284  ! distance to axis of rotation
285  dist_axis(:,:,:) = sqrt(posvec(:,:,:,1)**2+posvec(:,:,:,2)**2)
286 
287  ! curvilinear components of azimuthal unit vector
288  ! (maybe with respect to shifted origin)
289  ! from ephi = ez x er = ez x posvec/radius = ez x (rxi*exi + reta*eeta)/r
290  ! = rxi/r*(ez x exi) + reta/r*(ez x eeta) = rxi/r*eeta - reta/r*exi
291  ! because (ez,exi,eeta) is right handed orthonormal set of basis vectors
292  ephi(:,:,:,1) = -posvec(:,:,:,2)/radius(:,:,:)
293  ephi(:,:,:,2) = posvec(:,:,:,1)/radius(:,:,:)
294  ephi(:,:,:,3) = 0.0
295 
296  ! initial condition
297  ! angular velocity
298  domega(:,:,:) = 0.5*vstr/pi*exp(0.5*(1.-(dist_axis(:,:,:)/r0)**2))
299  SELECT TYPE(pvar => timedisc%pvar)
300  TYPE IS(statevector_eulerisotherm) ! isothermal HD
301  ! density
302  pvar%density%data3d(:,:,:) = rhoinf * exp(-0.5*(r0*domega(:,:,:)/csiso)**2)
303  ! velocities
304  DO n=1,physics%VDIM
305  pvar%velocity%data4d(:,:,:,n) = domega(:,:,:)*dist_axis(:,:,:)*ephi(:,:,:,n)
306  END DO
307  TYPE IS(statevector_euler) ! non-isothermal HD
308  csinf = sqrt(gamma*pinf/rhoinf) ! sound speed at infinity (isentropic vortex)
309  ! density
310  ! ATTENTION: there's a factor of 1/PI missing in the density
311  ! formula eq. (3.3) in [1]
312  pvar%density%data3d(:,:,:) = rhoinf * (1.0 - &
313  0.5*(gamma-1.0)*(r0*domega/csinf)**2 )**(1./(gamma-1.))
314  ! pressure
315  pvar%pressure%data1d(:) = pinf * (pvar%density%data1d(:)/rhoinf)**gamma
316  ! velocities
317  DO n=1,physics%VDIM
318  pvar%velocity%data4d(:,:,:,n) = domega(:,:,:)*dist_axis(:,:,:)*ephi(:,:,:,n)
319  END DO
320  END SELECT
321 
322  CALL physics%Convert2Conservative(timedisc%pvar,timedisc%cvar)
323 
324 ! ! compute curvilinear components of constant background velocity field
325 ! ! and add to the vortex velocity field
326 ! IF (ABS(UINF).GT.TINY(UINF).OR.ABS(VINF).GT.TINY(VINF).AND.ABS(WINF).LE.TINY(WINF)) THEN
327 ! v0(:,:,:,1) = UINF
328 ! v0(:,:,:,2) = VINF
329 ! v0(:,:,:,3) = WINF
330 ! CALL Mesh%geometry%Convert2Curvilinear(Mesh%bcenter,v0,v0)
331 ! Timedisc%pvar%data4d(:,:,:,Physics%XVELOCITY:Physics%ZVELOCITY) = &
332 ! Timedisc%pvar%data4d(:,:,:,Physics%XVELOCITY:Physics%ZVELOCITY) + v0(:,:,:,1:3)
333 ! END IF
334 !
335 !
336  CALL mesh%Info(" DATA-----> initial condition: 3D vortex")
337  END SUBROUTINE initdata
338 
339 END PROGRAM vortex3d
Mathematical functions.
Definition: functions.f90:48
pure real function, dimension(size(ephir%data2d, dim=1)) omega(ephir, velocity)
subroutine initdata(Mesh, Physics, Fluxes, Timedisc)
Definition: bondi2d.f90:274
main fosite class
Definition: fosite.f90:71
elemental real function, public asinh(x)
inverse hyperbolic sine function
Definition: functions.f90:100
program vortex3d
Definition: vortex3d.f90:33
subroutine makeconfig(Sim, config)
Definition: bondi2d.f90:165