gravity_spectral.f90
Go to the documentation of this file.
1!#############################################################################
2!# #
3!# fosite - 3D hydrodynamical simulation program #
4!# module: gravity_spectral.f90 #
5!# #
6!# Copyright (C) 2011-2024 #
7!# Manuel Jung <mjung@astrophysik.uni-kiel.de> #
8!# Jannes Klee <jklee@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!#############################################################################
31!----------------------------------------------------------------------------!
44!----------------------------------------------------------------------------!
53 USE functions
54 USE common_dict
55 USE fftw
56#ifdef PARALLEL
57 USE mpi
58#endif
59 IMPLICIT NONE
60 !--------------------------------------------------------------------------!
61 PRIVATE
62 REAL, PARAMETER :: sqrttwopi &
63 = 2.50662827463100050241576528481104525300698674
64
66#if defined(HAVE_FFTW)
67
69 TYPE(c_ptr) :: pfdensity, pfphi
70 TYPE(c_ptr) :: plan_r2c
71 TYPE(c_ptr) :: plan_c2r
72 REAL(c_double), DIMENSION(:,:), POINTER &
73 :: fdensity,fphi,block
74 COMPLEX(C_DOUBLE_COMPLEX), DIMENSION(:,:), POINTER &
75 :: cfdensity, cfphi, cblock
77 REAL(c_double), DIMENSION(:,:,:), POINTER &
78 :: fi
79 COMPLEX(C_DOUBLE_COMPLEX), DIMENSION(:,:,:), POINTER &
80 :: cfi
81 TYPE(c_ptr) :: p_fi
82 REAL, DIMENSION(:,:,:), POINTER :: phi
83 REAL, DIMENSION(:,:), POINTER :: tmp2d
84 REAL, DIMENSION(:,:), POINTER :: phi2d
85 REAL, DIMENSION(:), POINTER :: height1d
86 INTEGER :: green
87 REAL :: sigma, ecut
88 INTEGER, DIMENSION(:), POINTER :: sizes
89 INTEGER, POINTER :: mcut
90 INTEGER :: inum,knum
91 INTEGER :: mnum
92 INTEGER :: imax, kmax
94#if defined(PARALLEL)
95
96 INTEGER,DIMENSION(:), POINTER :: displ, num
97 INTEGER :: mpi_error
98 REAL,DIMENSION(:,:), POINTER :: sbuf1,sbuf2,& !< send buffers
99 rbuf1,rbuf2
100#endif
101#endif
102 CONTAINS
104 PROCEDURE :: setoutput
107 final :: finalize
108#ifdef HAVE_FFTW
109 PROCEDURE :: calcpotential
110 PROCEDURE :: precomputei
111 PROCEDURE :: calcmcut
112#endif
113 END TYPE
114 !--------------------------------------------------------------------------!
115 PUBLIC :: &
116 ! types
118 !--------------------------------------------------------------------------!
119 CONTAINS
120
121 SUBROUTINE initgravity_spectral(this,Mesh,Physics,config,IO)
122 IMPLICIT NONE
123 !------------------------------------------------------------------------!
124 CLASS(gravity_spectral), INTENT(INOUT) :: this
125 CLASS(mesh_base), INTENT(IN) :: Mesh
126 CLASS(physics_base), INTENT(IN) :: Physics
127 TYPE(dict_typ), POINTER :: config,IO
128 !------------------------------------------------------------------------!
129 INTEGER :: err, valwrite
130 CHARACTER(LEN=32) :: info_str
131 !------------------------------------------------------------------------!
132 CALL this%InitGravity(mesh,physics,"spectral",config,io)
133
134#if !defined(HAVE_FFTW)
135 CALL this%Error("InitGravity_spectral", &
136 "Mandatory requirement fft has not been enabled. "//&
137 "Please add --with-fftw=$FFTWDIR or similar to configure call.")
138#endif
139#if defined(HAVE_FFTW)
140#ifdef PARALLEL
141 ! Check domains a annular rings
142 IF(.NOT.(mesh%dims(2).EQ.1)) &
143 CALL this%Error("InitGravity_spectral", &
144 "Only domains shaped as annular rings are allowed (N x 1 decompositions).")
145#endif
146
147! IF(.NOT.(GetType(Boundary(NORTH)).EQ.PERIODIC .AND. &
148! GetType(Boundary(SOUTH)).EQ.PERIODIC)) THEN
149! CALL this%Error(,"InitGravity_spectral", &
150! "The boundary conditions in north and south direction have " // &
151! "to be periodic! Don't forget: This kind of " // &
152! "self-gravitation only works for polar-like coordinate " // &
153! "systems.")
154! END IF
155
156
157 IF(.NOT.(mod(mesh%JNUM,2)==0)) THEN
158 CALL this%Error("InitGravity_spectral", &
159 "The spectral poisson solver needs an even number of cells " // &
160 "in the phi direction due to the discrete cosinus transform.")
161 END IF
162
163
164! If this is the innermost domain include 1 ghost cell,
165! if this is the outermost domain include also 1 ghost cell.
166#ifdef PARALLEL
167 IF(mesh%IMAX.EQ.mesh%INUM) THEN
168 this%IMAX = mesh%IMAX+1
169 ELSE
170 this%IMAX = mesh%IMAX
171 END IF
172#else
173 !always innermost and outermost domain
174 this%IMAX = mesh%IMAX+1
175#endif
176
177 this%INUM = this%IMAX - mesh%IMIN + 1
178
179 ! number of fourier modes
180 this%MNUM = mesh%JNUM/2+1
181
182 ALLOCATE(this%phi2D(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JGMAX), &
183 this%tmp2D(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JGMAX), &
184 this%pot, &
185 this%height1D(1:mesh%INUM), &
186 this%sizes(1),&
187 this%mcut, &
188#ifdef PARALLEL
189 this%sbuf1(mesh%GNUM,mesh%JNUM), &
190 this%rbuf1(mesh%GNUM,mesh%JNUM), &
191 this%sbuf2(mesh%GNUM,mesh%JNUM), &
192 this%rbuf2(mesh%GNUM,mesh%JNUM), &
193 this%displ(0:this%GetNumProcs()-1),&
194 this%num(0:this%GetNumProcs()-1),&
195#endif
196 stat=err)
197
198 IF (err.NE.0) &
199 CALL this%Error("gravity_spectral::InitGravity_spectral","memory allocation failed")
200
201 ! initialize potential
202 this%pot = marray_base(4)
203 this%pot%data1d(:) = 0.0
204
205 CALL getattr(config, "green", this%green, 1)
206 SELECT CASE(this%green)
207 CASE(1,2,3)
208 ! ok -> do nothing
209 CASE DEFAULT
210 CALL this%Error("gravity_spectral::InitGravity_spectral","type of Green's function should be one of 1,2,3")
211 END SELECT
212
213 CALL getattr(config, "sigma", this%sigma, 0.05)
214 this%height1D(:) = this%sigma
215
216 ! mode cut off.
217 ! 0: disabled
218 ! >0: constant cutoff number
219 ! (can be overwritten by ecut>0.)
220 CALL getattr(config, "mcut", this%mcut, this%MNUM)
221 this%mcut = min(this%mcut,this%MNUM)
222
223 ! mode cutoff relative error boundary
224 ! <=0: no automatic cutoff calculation
225 ! >0 : automatic setting of mcut
226 CALL getattr(config, "ecut", this%ecut, 0.)
227
228 CALL this%Info(" Initializing")
229
230 WRITE (info_str, '(I8)') this%green
231 CALL this%Info(" green-fn type: " // trim(info_str))
232 WRITE (info_str, '(ES8.2)') this%sigma
233 CALL this%Info(" sigma: " // trim(info_str))
234
235
236 !\todo only 2D variables
237 this%p_FI = fftw_alloc_real(int(2*this%MNUM * (this%INUM)*(mesh%INUM), c_size_t))
238 CALL c_f_pointer(this%p_FI, this%FI, &
239 [2*this%MNUM,this%INUM,mesh%INUM])
240 CALL c_f_pointer(this%p_FI, this%cFI, &
241 [this%MNUM,this%INUM,mesh%INUM])
242
243
244 this%pFdensity = fftw_alloc_real(int(2*this%MNUM*mesh%INUM, c_size_t))
245 CALL c_f_pointer(this%pFdensity, this%Fdensity, &
246 [2*this%MNUM,mesh%INUM])
247 CALL c_f_pointer(this%pFdensity, this%cFdensity, &
248 [mesh%JNUM/2+1,mesh%INUM])
249
250 this%pFphi = fftw_alloc_real(int(2*this%MNUM*this%INUM,c_size_t))
251 CALL c_f_pointer(this%pFphi, this%Fphi, &
252 [2*this%MNUM, this%INUM])
253 CALL c_f_pointer(this%pFphi, this%cFphi, &
254 [mesh%JNUM/2+1, this%INUM])
255
256 IF (err.NE.0) &
257 CALL this%Error("InitGravity_spectral","Memory allocation failed.")
258
259 this%block => this%Fdensity(:,mesh%IMIN:mesh%IMAX)
260 this%cblock => this%cFdensity(:,mesh%IMIN:mesh%IMAX)
261
262 this%phi2D(:,:) = 0.
263 this%tmp2D(:,:) = 0.
264
265 ! Create plans for fftw
266
267 ! Use FFTW_MEASURE for calculating the fastest plan, but this
268 ! costs some extra seconds
269 this%sizes(1) = mesh%JNUM
270 this%plan_r2c = fftw_plan_many_dft_r2c(1, this%sizes, (mesh%IMAX-mesh%IMIN+1),&
271 this%block, this%sizes, &
272 1, 2*this%MNUM, &
273 this%cblock, this%sizes, &
274 1, this%MNUM, &
275 fftw_measure)
276
277 this%sizes(1) = mesh%JNUM
278 this%plan_c2r = fftw_plan_many_dft_c2r(1, this%sizes, this%INUM, &
279 this%cFphi, this%sizes, &
280 1, this%MNUM, &
281 this%Fphi, this%sizes, &
282 1, 2*this%MNUM, &
283 fftw_measure)
284
285 IF(this%ecut.GT.0.) &
286 CALL setattr(io, "mcut",ref(this%mcut))
287
288#ifdef PARALLEL
289 this%displ((this%GetRank())) = (mesh%IMIN-1)*2*this%mcut
290 this%num((this%GetRank())) = (mesh%IMAX-mesh%IMIN+1)*2*this%mcut
291 CALL mpi_allgather(mpi_in_place, 0, mpi_datatype_null, &
292 this%displ, 1, mpi_integer, mpi_comm_world, this%mpi_error)
293 CALL mpi_allgather(mpi_in_place, 0, mpi_datatype_null, &
294 this%num, 1, mpi_integer, mpi_comm_world, this%mpi_error)
295
296#endif
297
298 CALL this%PrecomputeI(mesh, physics)
299
300 CALL this%Info(" .. done initializing")
301#endif
302
303 END SUBROUTINE initgravity_spectral
304
305 SUBROUTINE setoutput(this,Mesh,Physics,config,IO)
306 IMPLICIT NONE
307 !------------------------------------------------------------------------!
308 CLASS(gravity_spectral), INTENT(INOUT) :: this
309 CLASS(mesh_base), INTENT(IN) :: Mesh
310 CLASS(physics_base), INTENT(IN) :: Physics
311 TYPE(dict_typ), POINTER :: config,IO
312 !------------------------------------------------------------------------!
313 INTEGER :: valwrite
314 !------------------------------------------------------------------------!
315 valwrite = 0
316 CALL getattr(config, "output/potential", valwrite, 0)
317 IF (valwrite .EQ. 1.AND.ALLOCATED(this%pot)) THEN
318 IF (ASSOCIATED(this%pot%data4d)) &
319 CALL setattr(io, "potential", &
320 this%pot%data4d(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX,4))
321 END IF
322 END SUBROUTINE setoutput
323
324
325#ifdef HAVE_FFTW
326 FUNCTION calcmcut(this,Mesh) RESULT(res)
327 IMPLICIT NONE
328 !------------------------------------------------------------------------!
329 CLASS(gravity_spectral) :: this
330 CLASS(mesh_base), INTENT(IN) :: mesh
331 INTEGER :: res
332 !------------------------------------------------------------------------!
333 INTEGER :: m,i
334#ifdef PARALLEL
335 INTEGER :: ier
336#endif
337 REAL :: cumsum(this%mnum)
338 INTEGER :: mcut(mesh%imin:mesh%imax)
339 !------------------------------------------------------------------------!
340 DO i=mesh%IMIN,mesh%IMAX
341 cumsum(1) = this%Fdensity(2*1-1,i)**2 + this%Fdensity(2*1,i)**2
342 DO m=2,this%MNUM
343 cumsum(m) = cumsum(m-1) + this%Fdensity(2*m-1,i)**2 + this%Fdensity(2*m,i)**2
344 END DO
345 DO m=1,this%MNUM
346 IF(abs(cumsum(m)/cumsum(this%MNUM)-1.).LT.this%ecut) THEN
347 mcut(i) = m
348 EXIT
349 END IF
350 END DO
351 END DO
352 res = maxval(mcut)
353
354#ifdef PARALLEL
355 CALL mpi_allreduce(mpi_in_place,res,1,mpi_integer,mpi_max,mpi_comm_world,ier)
356#endif
357 END FUNCTION calcmcut
358#endif
359
360#if defined(HAVE_FFTW)
361 SUBROUTINE calcpotential(this,Mesh,Physics,time,pvar)
363 IMPLICIT NONE
364 !------------------------------------------------------------------------!
365 CLASS(gravity_spectral), INTENT(INOUT):: this
366 CLASS(mesh_base), INTENT(IN) :: Mesh
367 CLASS(physics_base), INTENT(IN) :: Physics
368 CLASS(marray_compound), INTENT(INOUT) :: pvar
369 REAL, INTENT(IN) :: time
370 !------------------------------------------------------------------------!
371 INTEGER :: i,k,m,i0,oldmcut
372#ifdef PARALLEL
373 INTEGER :: status(MPI_STATUS_SIZE)
374#endif
375 !------------------------------------------------------------------------!
376 ! Fourier transform the density with respect to Phi
377 SELECT TYPE(p => pvar)
379 DO k=mesh%KMIN, mesh%KMAX
380 DO i=mesh%IMIN, mesh%IMAX
381 this%Fdensity(1:mesh%JNUM,i) = p%density%data3d(i,mesh%JMIN:mesh%JMAX,k)
382 END DO
383 END DO
384 CLASS DEFAULT
385 CALL this%Error("gravity_spectral::CalcPotential","unsupported state vector")
386 END SELECT
387
388 CALL fftw_execute_dft_r2c(this%plan_r2c, this%block, this%cblock)
389
390 IF(this%ecut.GT.0.) THEN
391 oldmcut = this%mcut
392
393 this%mcut = this%CalcMcut(mesh)
394
395#ifdef PARALLEL
396 this%displ = this%displ / oldmcut * this%mcut
397 this%num = this%num / oldmcut * this%mcut
398#endif
399 END IF
400
401#ifdef PARALLEL
402 ! Distribute Fdensity to all processes
403 CALL mpi_allgatherv(mpi_in_place, 0, mpi_datatype_null,&
404 this%Fdensity(1:2*this%mcut,1:mesh%INUM), &
405 this%num, this%displ, default_mpi_real, &
406 mpi_comm_world, this%mpi_error)
407#endif
408
409 ! Integrate in radial direction by numerical quadrature
410 ! Fphi_m(t,r) = int_rmin^rmax Fdensity_m(t,r') * I_m(r,r') dr'
411 ! dr' is already multiplicated into FI.
412
413 ! Direct summation and multiplication with complex numbers:
414 !DO m=1, this%MNUM
415 ! ! integrate
416 ! DO i=1, this%INUM
417 ! this%cFPhi(m,i) = SUM(this%cFdensity(m,:) * this%cFI(m,i,:))
418 ! END DO
419 !END DO
420
421 ! or with real numbers, real and imaginary part seperate:
422 this%FPhi(:,:) = 0.
423!NEC$ IVDEP
424 DO i0=1,mesh%INUM
425!NEC$ IVDEP
426 DO i=1,this%INUM
427!NEC$ IVDEP
428 DO m=1,this%mcut
429 ! real part
430 this%FPhi(2*m-1,i) = this%FPhi(2*m-1,i) &
431 + this%Fdensity(2*m-1,i0) * this%FI(2*m-1,i,i0)
432 ! imag part
433 this%FPhi(2*m,i) = this%FPhi(2*m,i) &
434 + this%Fdensity(2*m,i0) * this%FI(2*m-1,i,i0)
435 END DO
436 END DO
437 END DO
438
439 ! Inverse fourier transform Fphi with respect to Phi
440 CALL fftw_execute_dft_c2r(this%plan_c2r, this%cFphi, this%Fphi)
441
442 DO i=1,this%INUM
443 this%phi2D(i+mesh%IMIN-1,mesh%JMIN:mesh%JMAX) = this%FPhi(1:mesh%JNUM,i)
444 END DO
445
446 ! calculate boundary data (only one ghost cell is enough)
447#ifdef PARALLEL
448 ! send boundary data to western and receive from eastern neighbor
449 IF (mesh%neighbor(west).NE.mpi_proc_null) &
450 this%sbuf1 = this%phi2D(mesh%IMIN:mesh%IMIN+mesh%GNUM-1,mesh%JMIN:mesh%JMAX)
451 CALL mpi_sendrecv(this%sbuf1,mesh%GNUM*mesh%JNUM, &
452 default_mpi_real,mesh%neighbor(west),10+west,this%rbuf1, &
453 mesh%GNUM*mesh%JNUM,default_mpi_real,mesh%neighbor(east), &
454 mpi_any_tag,mesh%comm_cart,status,this%mpi_error)
455 IF (mesh%neighbor(east).NE.mpi_proc_null) &
456 this%phi2D(mesh%IMAX+1:mesh%IGMAX,mesh%JMIN:mesh%JMAX) = this%rbuf1
457 ! send boundary data to western and receive from eastern neighbor
458 IF (mesh%neighbor(east).NE.mpi_proc_null) &
459 this%sbuf2 = this%phi2D(mesh%IMAX-mesh%GNUM+1:mesh%IMAX,mesh%JMIN:mesh%JMAX)
460 CALL mpi_sendrecv(this%sbuf2,mesh%GNUM*mesh%JNUM, &
461 default_mpi_real,mesh%neighbor(east),10+east,this%rbuf2, &
462 mesh%GNUM*mesh%JNUM,default_mpi_real,mesh%neighbor(west), &
463 mpi_any_tag,mesh%comm_cart,status,this%mpi_error)
464 IF (mesh%neighbor(west).NE.mpi_proc_null) &
465 this%phi2D(mesh%IGMIN:mesh%IMIN-1,mesh%JMIN:mesh%JMAX) = this%rbuf2
466#endif
467 this%phi2D(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JMIN-1) &
468 = this%phi2D(mesh%IGMIN:mesh%IGMAX,mesh%JMAX-mesh%GNUM+1:mesh%JMAX)
469 this%phi2D(mesh%IGMIN:mesh%IGMAX,mesh%JMAX+1:mesh%JGMAX) &
470 = this%phi2D(mesh%IGMIN:mesh%IGMAX,mesh%JMIN:mesh%JMIN+mesh%GNUM-1)
471
472 END SUBROUTINE calcpotential
473#endif
474
496#ifdef HAVE_FFTW
497 ELEMENTAL FUNCTION greenfunction(dr2, green, sigma) RESULT(G)
498 IMPLICIT NONE
499 !------------------------------------------------------------------------!
500 REAL, INTENT(IN) :: dr2
501 INTEGER, INTENT(IN) :: green
502 REAL, INTENT(IN) :: sigma
503 REAL :: g
504 !------------------------------------------------------------------------!
505 SELECT CASE(green)
506 CASE(1) ! Razor sharp disc
507 g = -1.0/sqrt(dr2)
508 CASE(2) ! gaussian spheres
509 g = -1.0 * bessel_k0e(dr2/(4.0*sigma*sigma)) &
510 / (sqrttwopi*sigma)
511 CASE(3) ! Used for the orbiting cylinder example
512 g = log(dr2)
513 CASE DEFAULT
514 ! should never happen
515 g = 0.0
516 END SELECT
517 END FUNCTION greenfunction
518#endif
519
527#ifdef HAVE_FFTW
528 SUBROUTINE precomputei(this, Mesh, Physics)
529 IMPLICIT NONE
530 !------------------------------------------------------------------------!
531 CLASS(gravity_spectral) :: this
532 CLASS(mesh_base), INTENT(IN) :: Mesh
533 CLASS(physics_base) :: Physics
534 !------------------------------------------------------------------------!
535 TYPE(c_ptr) :: plan_r2c
536 INTEGER :: i1, i, j, k
537 REAL :: r0, notzero
538 CHARACTER(LEN=128) :: str
539 REAL, DIMENSION(Mesh%JMIN:Mesh%JMAX) &
540 :: phi
541 REAL, DIMENSION(1:Mesh%INUM+1) :: r,hx,hy
542 REAL, DIMENSION(Mesh%JMIN:Mesh%JMAX,Mesh%IMIN:this%IMAX) :: dr2
543 INTEGER :: rank, howmany, istride, idist, ostride, odist
544 INTEGER, DIMENSION(1) &
545 :: n
546#ifdef PARALLEL
547 INTEGER, DIMENSION(0:(this%GetNumProcs())-1) :: num,displ
548#endif
549 !------------------------------------------------------------------------!
550 n(1) = mesh%JNUM
551 rank = 1
552 howmany = this%INUM * mesh%INUM
553 istride = 1
554 idist = 2*this%MNUM
555 ostride = istride
556 odist = this%MNUM
557 plan_r2c = fftw_plan_many_dft_r2c(rank, n, howmany, &
558 this%FI, n, &
559 istride, idist, &
560 this%cFI, n, &
561 ostride, odist, &
562 fftw_measure &
563 )
564
565 phi = mesh%curv%center(mesh%IMIN,mesh%JMIN:mesh%JMAX,mesh%KMIN,2)&
566 - mesh%curv%center(mesh%IMIN,mesh%JMIN,mesh%KMIN,2)
567
568 r(mesh%IMIN:this%IMAX) = mesh%radius%bcenter(mesh%IMIN:this%IMAX,mesh%JMIN,mesh%KMIN)
569 hx(mesh%IMIN:this%IMAX) = mesh%hx%bcenter(mesh%IMIN:this%IMAX,mesh%JMIN,mesh%KMIN)
570 hy(mesh%IMIN:this%IMAX) = mesh%hy%bcenter(mesh%IMIN:this%IMAX,mesh%JMIN,mesh%KMIN)
571#ifdef PARALLEL
572 displ(this%GetRank()) = (mesh%IMIN-1)
573 num(this%GetRank()) = this%INUM
574 CALL mpi_allgather(mpi_in_place, 0, mpi_datatype_null, &
575 displ, 1, mpi_integer, mpi_comm_world, this%mpi_error)
576 CALL mpi_allgather(mpi_in_place, 0, mpi_datatype_null, &
577 num, 1, mpi_integer, mpi_comm_world, this%mpi_error)
578 CALL mpi_allgatherv(mpi_in_place, 0, mpi_datatype_null, &
579 r, num, displ, &
580 default_mpi_real, mpi_comm_world, this%mpi_error)
581 CALL mpi_allgatherv(mpi_in_place, 0, mpi_datatype_null, &
582 hx, num, displ, &
583 default_mpi_real, mpi_comm_world, this%mpi_error)
584 CALL mpi_allgatherv(mpi_in_place, 0, mpi_datatype_null, &
585 hy, num, displ, &
586 default_mpi_real, mpi_comm_world, this%mpi_error)
587#endif
588
589 DO k=mesh%KMIN,mesh%KMAX
590 DO i1=1,mesh%INUM
591!NEC$ IVDEP
592 DO i=mesh%IMIN,this%IMAX
593 DO j=mesh%JMIN,mesh%JMAX
594 r0 = mesh%radius%faces(i,j,k,1)
595 dr2(j,i) = r(i1)**2 + r0**2 - 2.*r(i1)*r0*cos(phi(j))
596 END DO
597 END DO
598
599 this%FI(1:mesh%JNUM,1:this%INUM,i1) &
600 = 2.0 * pi * hx(i1) * hy(i1) * mesh%dx &
601 * physics%Constants%GN &
602 * greenfunction(dr2(:,:),this%green,this%height1D(i1)) &
603 / (mesh%JNUM)**2
604 END DO
605 END DO
606
607 CALL fftw_execute_dft_r2c(plan_r2c, this%FI, this%cFI)
608
609 ! Free plan_r2c
610 CALL fftw_destroy_plan(plan_r2c)
611
612 ! I has an even symmetry around 0. Normally a cosinus tranform (r2r)
613 ! would be sufficent. But this is not available on all platforms. There-
614 ! fore do a standard r2c dft and ditch the imaginary part of the result,
615 ! which is approx zero numerically (and exactly zero analytically).
616 !this%cFI = REAL(this%cFI)
617 notzero = sum(abs(this%FI(2:2*this%MNUM:2,:,:)))/(this%MNUM*mesh%JNUM*this%INUM)
618#ifdef PARALLEL
619 CALL mpi_allreduce(mpi_in_place, notzero, 1, default_mpi_real, &
620 mpi_max, &
621 mpi_comm_world, this%mpi_error)
622#endif
623 IF(notzero.GT.1.) THEN
624 WRITE(str,'(A,ES12.4,A)')"Imag(FI) should be zero, but ",notzero,&
625 " > 1."
626 CALL this%Warning("ProcomputeI_spectral",trim(str))
627 END IF
628
629 this%FI(2:2*this%MNUM:2,:,:) = 0.
630 END SUBROUTINE precomputei
631#endif
632
634 SUBROUTINE updategravity_single(this,Mesh,Physics,Fluxes,pvar,time,dt)
635 IMPLICIT NONE
636 !------------------------------------------------------------------------!
637 CLASS(gravity_spectral), INTENT(INOUT) :: this
638 CLASS(mesh_base), INTENT(IN) :: Mesh
639 CLASS(physics_base), INTENT(IN) :: Physics
640 CLASS(fluxes_base), INTENT(IN) :: Fluxes
641 CLASS(marray_compound), INTENT(INOUT) :: pvar
642 REAL, INTENT(IN) :: time,dt
643 !------------------------------------------------------------------------!
644 INTEGER :: i, j, k
645 !------------------------------------------------------------------------!
646#ifdef HAVE_FFTW
647 ! calc potential first
648 CALL this%CalcPotential(mesh,physics,time,pvar)
649
650 ! compute gravitational acceleration using the gradient of the potential
651 ! ATTENTION: ghost cell values and any other component of the gravitational
652 ! acceleration are set to zero in InitGravity_spectral
653 ! \todo This difference quotient is still 2D and only the third component is
654 ! added. It will not work in 3D.
655!NEC$ IVDEP
656 DO k = mesh%KMIN,mesh%KMAX
657!NEC$ IVDEP
658 DO j = mesh%JMIN-mesh%JP1,mesh%JMAX+mesh%JP1
659!NEC$ IVDEP
660 DO i = mesh%IMIN-mesh%IP1,mesh%IMAX
661 this%accel%data4d(i,j,k,1) = -1.0*(this%phi2D(i+1,j)-this%phi2D(i,j))/mesh%dlx%data3d(i,j,k)
662 this%accel%data4d(i,j,k,2) = -1.0*(this%phi2D(i+1,j+1)+this%phi2D(i,j+1) &
663 -this%phi2D(i+1,j-1)-this%phi2D(i,j-1))&
664 /(4.0*mesh%dly%data3d(i,j,k))
665 this%pot%data4d(i,j,k,1) = 0.5*(this%phi2D(i,j)+this%phi2D(i+1,j))
666 this%pot%data4d(i,j,k,2) = this%phi2D(i+1,j)
667 this%pot%data4d(i,j,k,3) = 0.25*(this%phi2D(i,j)+this%phi2D(i+1,j)+this%phi2D(i,j+1)+this%phi2D(i+1,j+1))
668 END DO
669 END DO
670 END DO
671#endif
672 END SUBROUTINE updategravity_single
673
674
714 SUBROUTINE calcdiskheight_single(this,Mesh,Physics,pvar,bccsound,h_ext,height)
715 IMPLICIT NONE
716 !------------------------------------------------------------------------!
717 CLASS(gravity_spectral), INTENT(INOUT) :: this
718 CLASS(mesh_base), INTENT(IN) :: Mesh
719 CLASS(physics_base), INTENT(IN) :: Physics
720 CLASS(marray_compound), INTENT(INOUT) :: pvar
721 TYPE(marray_base), INTENT(INOUT) :: bccsound,h_ext,height
722 !------------------------------------------------------------------------!
723 REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,2) &
724 :: phi
725 INTEGER :: i,j,k
726 REAL :: cs2,p,q
727 !------------------------------------------------------------------------!
728#ifdef HAVE_FFTW
729 ! compute the laplacian of the gravitational potential in the disks
730 ! equatorial plane; gravity_generic updates the gravitational acceleration
731 DO k=mesh%KMIN-mesh%KP1,mesh%KMAX
732 DO j=mesh%JMIN-mesh%JP1,mesh%JMAX
733 DO i=mesh%IMIN-mesh%IP1,mesh%IMAX
734 phi(i,j,1) = mesh%hy%faces(i,j,k,2)*mesh%hz%faces(i,j,k,2)/mesh%hx%faces(i,j,k,2)&
735 * this%pot%data4d(i,j,k,2)
736 phi(i,j,2) = mesh%hx%faces(i,j,k,4)*mesh%hz%faces(i,j,k,4)/mesh%hy%faces(i,j,k,4)&
737 * this%pot%data4d(i,j,k,3)
738 END DO
739 END DO
740 END DO
741 ! div(-grad(phi)))
742 DO k=mesh%KMIN,mesh%KMAX
743 DO j=mesh%JMIN,mesh%JMAX
744 DO i=mesh%IMIN,mesh%IMAX
745 this%tmp2D(i,j) = - 1./mesh%sqrtg%bcenter(i,j,k) &
746 * ( (phi(i,j,1) - phi(i-1,j,1)) / mesh%dlx%data3d(i,j,k) &
747 + (phi(i,j,2) - phi(i,j-1,2)) / mesh%dly%data3d(i,j,k))
748 END DO
749 END DO
750 END DO
751
752 IF (ASSOCIATED(h_ext%data1d).AND.(h_ext.match.height).AND. &
753 (minval(h_ext%data1d,mask=mesh%without_ghost_zones%mask1d(:)).GT.0.0)) THEN
754 ! disk height with external potential
755 DO k=mesh%KGMIN,mesh%KGMAX
756 DO j=mesh%JGMIN,mesh%JGMAX
757 DO i=mesh%IGMIN,mesh%IGMAX
758 cs2 = bccsound%data3d(i,j,k)**2
759 p = sqrttwopi*physics%Constants%GN*pvar%data4d(i,j,k,physics%DENSITY)*h_ext%data3d(i,j,k)/cs2
760 q = 1. + this%tmp2D(i,j)*h_ext%data3d(i,j,k)**2/cs2
761 ! return the new disk height
762 height%data3d(i,j,k) = h_ext%data3d(i,j,k) / (p+sqrt(q+p*p))
763 END DO
764 END DO
765 END DO
766 ELSE
767 ! pure self-gravitating disk without external potential
768 DO k=mesh%KGMIN,mesh%KGMAX
769 DO j=mesh%JGMIN,mesh%JGMAX
770 DO i=mesh%IGMIN,mesh%IGMAX
771 cs2 = bccsound%data3d(i,j,k)**2
772 p = sqrttwopi*physics%Constants%GN*pvar%data4d(i,j,k,physics%DENSITY)*mesh%radius%bcenter(i,j,k)/cs2
773 q = this%tmp2D(i,j)*h_ext%data3d(i,j,k)**2/cs2
774 ! return the new disk height
775 height%data3d(i,j,k) = mesh%radius%bcenter(i,j,k) / (p+sqrt(q+p*p))
776 END DO
777 END DO
778 END DO
779 END IF
780#endif
781 END SUBROUTINE calcdiskheight_single
782
783
784 SUBROUTINE finalize(this)
785 IMPLICIT NONE
786 !------------------------------------------------------------------------!
787 TYPE(gravity_spectral), INTENT(INOUT) :: this
788 !------------------------------------------------------------------------!
789#if defined(HAVE_FFTW)
790 ! Destroy plans
791 CALL fftw_destroy_plan(this%plan_r2c)
792 CALL fftw_destroy_plan(this%plan_c2r)
793
794 ! Free memomry
795 DEALLOCATE(&
796#ifdef PARALLEL
797 this%sbuf1, &
798 this%rbuf1, &
799 this%sbuf2, &
800 this%rbuf2, &
801 this%displ,this%num,&
802#endif
803 this%phi2D, &
804 this%pot, &
805 this%tmp2D, &
806 this%sizes, &
807 this%mcut &
808 )
809
810 CALL fftw_free(this%p_FI)
811 CALL fftw_free(this%pFdensity)
812 CALL fftw_free(this%pFphi)
813
814 ! Free all temporary memory of FFTW
815 CALL fftw_cleanup()
816#endif
817 IF (ALLOCATED(this%pot)) DEALLOCATE(this%pot)
818 CALL this%Finalize_base()
819 END SUBROUTINE finalize
820
821END MODULE gravity_spectral_mod
Dictionary for generic data types.
Definition: common_dict.f90:61
type(logging_base), save this
fftw module
Definition: fftw.f90:29
base module for numerical flux functions
Definition: fluxes_base.f90:39
Mathematical functions.
Definition: functions.f90:48
elemental real function, public bessel_k0e(x)
Compute the exponential scaled modified Bessel function of the second kind e.g. K0e = EXP(x) * K0(x) ...
Definition: functions.f90:692
real, parameter pi
Definition: functions.f90:52
generic gravity terms module providing functionaly common to all gravity terms
2D poisson solver using spectral methods for direct integration
subroutine updategravity_single(this, Mesh, Physics, Fluxes, pvar, time, dt)
elemental real function greenfunction(dr2, green, sigma)
Green's function.
subroutine calcpotential(this, Mesh, Physics, time, pvar)
subroutine initgravity_spectral(this, Mesh, Physics, config, IO)
real, parameter sqrttwopi
integer function calcmcut(this, Mesh)
subroutine precomputei(this, Mesh, Physics)
Precomputes the fourier transform.
subroutine calcdiskheight_single(this, Mesh, Physics, pvar, bccsound, h_ext, height)
compute disk pressure scale height for geometrically thin self-gravitating disks
Basic fosite module.
subroutine finalize(this)
Destructor of logging_base class.
integer, save default_mpi_real
default real type for MPI
base class for mesh arrays
Definition: marray_base.f90:36
integer, save knum
array sizes
Definition: marray_base.f90:45
integer, save inum
Definition: marray_base.f90:45
derived class for compound of mesh arrays
basic mesh module
Definition: mesh_base.f90:72
integer, parameter east
named constant for eastern boundary
Definition: mesh_base.f90:101
subroutine setoutput(this, config, IO)
Setup mesh fields for i/o.
Definition: mesh_base.f90:828
integer, parameter west
named constant for western boundary
Definition: mesh_base.f90:101
Basic physics module.
physics module for 1D,2D and 3D isothermal Euler equations
basic mesh array class
Definition: marray_base.f90:69
mesh data structure
Definition: mesh_base.f90:122