gravity_sboxspectral.f90
Go to the documentation of this file.
1 !#############################################################################
2 !# #
3 !# fosite - 3D hydrodynamical simulation program #
4 !# module: gravity_sboxspectral.f90 #
5 !# #
6 !# Copyright (C) 2015-2019 #
7 !# Jannes Klee <jklee@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 !#############################################################################
34 !----------------------------------------------------------------------------!
50 !
51 !! \todo Remove unnecessary allocations like ip_den, etc. At the moment there
52 !! are certainly possibilities to save memory, because for every task
53 !! a new array is allocated.
54 !
55 !! \attention The parallel version with this module needs a pencil decomposition
56 !! of Mesh%INUM X Mesh%JNUM/nprocs for each process, in order to use
57 !! the FFT-method with period boundaries in one direction.
58 !!
59 !! References:
60 !!
61 !! \cite gammie2001 , \cite gammiecode, \cite frigo2005, \cite mathkeisan2018
62 !!
63 !! \extends gravity_spectral
64 !! \ingroup gravity
65 !----------------------------------------------------------------------------!
70  USE fluxes_base_mod
72  USE mesh_base_mod
74  USE marray_base_mod
76  USE common_dict
77  USE fftw
78 #ifdef PARALLEL
79 #ifdef HAVE_MPI_MOD
80  USE mpi
81 #endif
82 #endif
83  IMPLICIT NONE
84 #ifdef PARALLEL
85 #ifdef HAVE_MPIF_H
86  include 'mpif.h'
87 #endif
88 #endif
89  !--------------------------------------------------------------------------!
90  PRIVATE
91  REAL, PARAMETER :: sqrttwopi &
92  = 2.50662827463100050241576528481104525300698674
93 
95 #ifdef HAVE_FFTW
96 
98  REAL(C_DOUBLE), POINTER :: mass2d(:,:)
99  COMPLEX(C_DOUBLE_COMPLEX), POINTER &
100  :: fmass2d(:,:)
101  REAL, DIMENSION(:,:,:), POINTER :: fmass2d_real
102  INTEGER(C_INTPTR_T) :: local_joff
103  REAL,DIMENSION(:), POINTER :: kx
104  REAL,DIMENSION(:), POINTER :: ky
105  REAL :: shiftconst
106  REAL, DIMENSION(:), POINTER :: joff, jrem
107  INTEGER :: order
108  LOGICAL :: calc_fmass2d
109 #ifdef PARALLEL
110  INTEGER(C_INTPTR_T) :: c_inum, c_jnum
111  INTEGER(C_INTPTR_T) :: alloc_local, local_jnum
112  TYPE(c_ptr) :: mass2d_pointer
113  TYPE(c_ptr) :: fmass2d_pointer
114 #endif
115 #endif
116 
117  CONTAINS
118 
120  PROCEDURE :: updategravity_single
121  PROCEDURE :: infogravity
123  PROCEDURE :: finalize
124 #ifdef HAVE_FFTW
125  PROCEDURE :: calcpotential
126  PROCEDURE :: fft_forward
127  PROCEDURE :: fft_backward
128  PROCEDURE :: fieldshift
129 #endif
130  END TYPE
131 
132  !--------------------------------------------------------------------------!
133  PUBLIC :: &
134  ! types
136  !--------------------------------------------------------------------------!
137 
138  CONTAINS
139 
147  SUBROUTINE initgravity_sboxspectral(this,Mesh,Physics,config,IO)
149  IMPLICIT NONE
150  !------------------------------------------------------------------------!
151  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
152  CLASS(mesh_base), INTENT(IN) :: Mesh
153  CLASS(physics_base), INTENT(IN) :: Physics
154  TYPE(Dict_TYP), POINTER :: config,IO
155  !------------------------------------------------------------------------!
156  INTEGER :: gravity_number
157  INTEGER :: err, valwrite, i
158 #if defined(HAVE_FFTW) && defined(PARALLEL)
159  INTEGER(C_INTPTR_T) :: C_INUM,C_JNUM
160  INTEGER(C_INTPTR_T) :: alloc_local, local_JNUM, local_joff
161  INTEGER :: nprocs
162 #endif
163  !------------------------------------------------------------------------!
164  CALL this%InitGravity(mesh,physics,"shearingbox spectral solver",config,io)
165 
166  !-------------- checks & warnings for initial conditions ----------------!
167 #if !defined(HAVE_FFTW)
168  CALL this%Error("InitGravity_sboxspectral", &
169  "No fftw package could be loaded.")
170 #else
171  CALL getattr(config, "order", this%order, 2)
172 
173 #ifdef PARALLEL
174  CALL fftw_mpi_init()
175  c_inum = mesh%INUM
176  c_jnum = mesh%JNUM
177 #endif
178 
179  ! rotational symmetry is not allowed
180  IF (mesh%ROTSYM.NE.0) &
181  CALL this%Error("InitGravity_sboxspectral", &
182  "Rotational symmetry not supported.")
183 
184  ! 1D simulations are not allowed
185  IF (mesh%NDIMS.EQ.1) &
186  CALL this%Error("InitGravity_sboxspectral", &
187  "Only 2D (shearingsheet) and 3D (shearingbox) simulations allowed with this module.")
188 
189  ! check physics
190  SELECT TYPE (phys => physics)
191  CLASS IS(physics_eulerisotherm)
192  ! do nothing
193  CLASS DEFAULT
194  CALL this%Error("InitGravity_sboxspectral", &
195  "Physics modules with density necessary for this module.")
196  END SELECT
197 
198  ! Check even number of cells
199  IF(.NOT.(mod(mesh%JMAX-mesh%JMIN+1,2)==0)) THEN
200  CALL this%Error("InitGravity_sboxspectral", &
201  "The spectral poisson solver needs an even number of "// &
202  "cells in the phi direction due to the discrete cosinus "// &
203  "transform.")
204  END IF
205  !------------------------------------------------------------------------!
206 
207  ! check the dimensions if fftw should be used in parallel in order to
208  ! know how to allocate the local arrays
209 #ifdef PARALLEL
210  CALL mpi_comm_size(mpi_comm_world, nprocs, err)
211  IF (nprocs.GT.1 .AND. mesh%shear_dir.EQ.2) THEN
212  CALL this%Error("InitGravity_sboxspectral", &
213  "Execution of the parallel Fourier solver is only possible with pencil "// &
214  "decomposition. The first dimension should be fully accessible by the "//&
215  "first core. The shear thereto needs to vary along the second " // &
216  "dimension. In order to achieve this set the boundaries accordingly. "// &
217  "Check InitBoundary where the shear direction is set.")
218  END IF
219  IF (mesh%dims(1).GT.1 .AND. mesh%shear_dir.EQ.1) THEN
220  CALL this%Error("InitGravity_sboxspectral", &
221  "The first dimension needs to be fully accessible by each process. "// &
222  "Please change domain decomposition to pencil decompositon. " // &
223  "This needs to be done during initialization. In the Mesh dictionary " // &
224  "use the key 'decompositon' and the value (/ 1,-1, 1/) to force decomposition " // &
225  "along second direction")
226  END IF
227 #endif
228  ALLOCATE( &
229  this%phi(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JGMAX,mesh%KGMIN:mesh%KGMAX), &
230 #if !defined(PARALLEL)
231  this%mass2D(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX), &
232  this%Fmass2D(mesh%IMIN:mesh%IMAX/2+1,mesh%JMIN:mesh%JMAX), &
233 #else
234  ! initialization handled by FFTW (see below)
235 #endif
236  this%Fmass2D_real(mesh%IMIN:mesh%IMAX+2,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX), &
237  this%kx(mesh%INUM), &
238  this%ky(mesh%JNUM), &
239  this%joff(mesh%IMIN:mesh%IMAX), &
240  this%jrem(mesh%IMIN:mesh%IMAX), &
241  this%den_ip(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX), &
242  stat=err)
243  IF (err.NE.0) &
244  CALL this%Error("InitGravity_sboxspectral","Memory allocation failed.")
245 
246  this%local_joff = 0
247 
248  ! use special allocation pattern from fftw when using MPI in order to
249  ! assure good alignment
250 #if defined(PARALLEL)
251  this%alloc_local = fftw_mpi_local_size_2d(c_jnum, c_inum, &
252  mpi_comm_world, this%local_JNUM, this%local_joff)
253  this%mass2D_pointer = fftw_alloc_real(2*this%alloc_local)
254  this%Fmass2D_pointer = fftw_alloc_complex(this%alloc_local)
255  call c_f_pointer(this%mass2D_pointer,this%mass2D, &
256  [2*(c_inum/2+1),this%local_JNUM])
257  call c_f_pointer(this%Fmass2D_pointer,this%Fmass2D, &
258  [c_inum/2+1,this%local_JNUM])
259 #endif
260 
261  !------------------- create plans for fftw ------------------------------!
262  ! Pay attention to the argument order of the dimension (JNUM and INUM !
263  ! are switched because of C -> row-major, Fortran -> column-major), !
264  ! BUT ONLY in modern Fortran UNLIKE the legacy version !
265  ! ------------ plans are allocated in dictionary ------------------------!
266 #if !defined(PARALLEL)
267  this%plan_r2c = fftw_plan_dft_r2c_2d(mesh%JMAX-mesh%JMIN+1, &
268  mesh%IMAX-mesh%IMIN+1,this%mass2D, &
269  this%Fmass2D,fftw_measure)
270  this%plan_c2r = fftw_plan_dft_c2r_2d(mesh%JMAX-mesh%JMIN+1, &
271  mesh%IMAX-mesh%IMIN+1, this%Fmass2D, &
272  this%mass2D, fftw_measure)
273  IF ((.NOT. c_associated(this%plan_r2c)) .OR. (.NOT. c_associated(this%plan_c2r))) THEN
274  CALL this%Error("InitGravity_sboxspectral","FFT plan could not be created.")
275  END IF
276 #elif defined(PARALLEL)
277  this%plan_r2c = fftw_mpi_plan_dft_r2c_2d(c_jnum,c_inum, &
278  this%mass2D,this%Fmass2D, &
279  mpi_comm_world, fftw_measure)
280  this%plan_c2r = fftw_mpi_plan_dft_c2r_2d(c_jnum,c_inum, &
281  this%Fmass2D,this%mass2D, &
282  mpi_comm_world, fftw_measure)
283 #endif
284  !------------------------------------------------------------------------!
285  ! set potential and acceleration to zero
286  this%phi(:,:,:) = 0.
287  this%mass2D(:,:) = 0.
288  this%Fmass2D(:,:) = cmplx(0.,0)
289  this%Fmass2D_real(:,:,:) = 0.
290  this%joff(:) = 0.
291  this%jrem(:) = 0.
292  this%kx(:) = 0.
293  this%ky(:) = 0.
294  ! nullify not used potential explicitely
295  NULLIFY(this%pot)
296 
297  ! precompute wavenumbers
298  this%kx = cshift((/(i-(mesh%INUM+1)/2,i=0,mesh%INUM-1)/), &
299  +(mesh%INUM+1)/2)*2.*pi/(mesh%XMAX-mesh%XMIN)
300  this%ky = cshift((/(i-(mesh%JNUM+1)/2,i=0,mesh%JNUM-1)/), &
301  +(mesh%JNUM+1)/2)*2.*pi/(mesh%YMAX-mesh%YMIN)
302 
303  ! precompute shift constant
304  IF(mesh%shear_dir.EQ.2) THEN
305  this%shiftconst = mesh%Q*mesh%OMEGA*(mesh%xmax-mesh%xmin)/mesh%dy
306  ELSE IF (mesh%shear_dir.EQ.1) THEN
307  this%shiftconst = mesh%Q*mesh%OMEGA*(mesh%ymax-mesh%ymin)/mesh%dx
308  ELSE
309  CALL this%Error("InitGravity_sboxspectral", &
310  "Either WE_shear or SN_shear need to be applied.")
311  END IF
312 
313  !------------------------------- output ---------------------------------!
314  valwrite = 0
315  CALL getattr(config, "output/phi", valwrite, 0)
316  IF (valwrite .EQ. 1) &
317  CALL setattr(io, "phi", &
318  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX))
319  valwrite = 0
320  this%calc_Fmass2D = .false.
321  CALL getattr(config, "output/Fmass2D", valwrite, 0)
322  IF (valwrite .EQ. 1) THEN
323  CALL setattr(io, "Fmass2D_real", &
324  this%Fmass2D_real(mesh%IMIN:mesh%IMAX+2,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX))
325  this%calc_Fmass2D = .true.
326  END IF
327 
328 #endif
329  END SUBROUTINE initgravity_sboxspectral
330 
338  SUBROUTINE updategravity_single(this,Mesh,Physics,Fluxes,pvar,time,dt)
339  IMPLICIT NONE
340  !------------------------------------------------------------------------!
341  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
342  CLASS(mesh_base), INTENT(IN) :: Mesh
343  CLASS(physics_base), INTENT(IN) :: Physics
344  CLASS(fluxes_base), INTENT(IN) :: Fluxes
345  CLASS(marray_compound), INTENT(INOUT) :: pvar
346  REAL, INTENT(IN) :: time,dt
347  !------------------------------------------------------------------------!
348  INTEGER :: i,j,k
349  REAL :: w1,w2
350  !------------------------------------------------------------------------!
351 #ifdef HAVE_FFTW
352  ! calc potential first
353  CALL this%CalcPotential(mesh,physics,time,pvar)
354 
355  IF (this%order.EQ.2) THEN
356 !NEC$ ivdep
357  DO k = mesh%KMIN,mesh%KMAX
358 !NEC$ ivdep
359  DO j = mesh%JMIN,mesh%JMAX
360 !NEC$ ivdep
361  DO i = mesh%IMIN,mesh%IMAX
362  ! second order approximation
363  this%accel%data4d(i,j,k,1) = -1.0*(this%phi(i+1,j,k)-this%phi(i-1,j,k))/ &
364  (2*mesh%dlx%data3d(i,j,k))
365  this%accel%data4d(i,j,k,2) = -1.0*(this%phi(i,j+1,k)-this%phi(i,j-1,k))/ &
366  (2*mesh%dly%data3d(i,j,k))
367  END DO
368  END DO
369  END DO
370  ELSE IF (this%order.EQ.4) THEN
371  w1 = 3./48.
372  w2 = 30./48.
373 !NEC$ ivdep
374  DO k = mesh%KMIN,mesh%KMAX
375 !NEC$ ivdep
376  DO j = mesh%JMIN,mesh%JMAX
377 !NEC$ ivdep
378  DO i = mesh%IMIN,mesh%IMAX
379  ! fourth order
380  this%accel%data4d(i,j,k,1) = -1.0*(w1*this%phi(i-2,j,k)-w2*this%phi(i-1,j,k)+ &
381  w2*this%phi(i+1,j,k)-w1*this%phi(i+2,j,k))/ &
382  (mesh%dlx%data3d(i,j,k))
383  this%accel%data4d(i,j,k,2) = -1.0*(w1*this%phi(i,j-2,k)-w2*this%phi(i,j-1,k)+ &
384  w2*this%phi(i,j+1,k)-w1*this%phi(i,j+2,k)) / &
385  (mesh%dly%data3d(i,j,k))
386  END DO
387  END DO
388  END DO
389  ELSE
390  CALL this%Error("InitGravity_sboxspectral", &
391  "The chosen order approximation does not exist (only 2 and 3).")
392  END IF
393 #endif
394  END SUBROUTINE updategravity_single
395 
431 #ifdef HAVE_FFTW
432  SUBROUTINE calcpotential(this,Mesh,Physics,time,pvar)
434  IMPLICIT NONE
435  !------------------------------------------------------------------------!
436  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
437  CLASS(mesh_base), INTENT(IN) :: Mesh
438  CLASS(physics_base), INTENT(IN) :: Physics
439  REAL, INTENT(IN) :: time
440  CLASS(marray_compound), INTENT(INOUT) :: pvar
441  !------------------------------------------------------------------------!
442  INTEGER :: i,j,k
443  REAL :: K2max,K2,KO
444  REAL :: joff2,jrem2,delt,time0
445  INTEGER :: nprocs
446 #ifdef PARALLEL
447  INTEGER :: status(MPI_STATUS_SIZE),ierror,ier
448  REAL :: mpi_buf(Mesh%IMIN:Mesh%IMAX,Mesh%GJNUM,Mesh%KMIN:Mesh%KMAX) !TODO: ONLY 2D
449 #endif
450  !------------------------------------------------------------------------!
451  !---------------- fourier transformation of density ---------------------!
452  ! calculate the shift of the indice at time t !
453  ! shift density to pretend periodic behavior with interpolation !
454  nprocs=1
455 #ifdef PARALLEL
456  CALL mpi_comm_size(mpi_comm_world, nprocs, ier)
457 #endif
458 
459  IF (mesh%OMEGA .EQ. 0) THEN
460  time0 = 0.0
461  ELSE IF (mesh%shear_dir.EQ.2) THEN
462  time0 = nint(time*mesh%Q*mesh%OMEGA*(mesh%xmax-mesh%xmin)/ &
463  (mesh%ymax-mesh%ymin))*(mesh%ymax-mesh%ymin)/(mesh%Q*mesh%OMEGA &
464  *(mesh%xmax-mesh%xmin))
465  ELSE IF (mesh%shear_dir.EQ.1) THEN
466  time0 = nint(time*mesh%Q*mesh%OMEGA*(mesh%ymax-mesh%ymin)/ &
467  (mesh%xmax-mesh%xmin))*(mesh%xmax-mesh%xmin)/(mesh%Q*mesh%OMEGA &
468  *(mesh%ymax-mesh%ymin))
469  END IF
470  delt = time - time0
471 
472  !----------------- shift field to periodic point ------------------------!
473  SELECT TYPE(p => pvar)
474  CLASS IS(statevector_eulerisotherm)
475  CALL this%FieldShift(mesh,physics,delt, &
476  p%density%data3d(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JGMAX,mesh%KGMIN:mesh%KGMAX), &
477  this%den_ip(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX))
478  CLASS DEFAULT
479  CALL this%Error("gravity_sboxspectral::CalcPotential","unsupported state vector")
480  END SELECT
481 
482 
483 #if defined(PARALLEL)
484  this%mass2D(1:mesh%INUM,1:this%local_JNUM) = &
485  reshape(this%den_ip(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX), (/ mesh%INUM,mesh%JNUM/nprocs /))
486 #else
487  this%mass2D(1:mesh%INUM,1:mesh%JNUM/nprocs) = &
488  reshape(this%den_ip(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX), (/ mesh%INUM,mesh%JNUM/nprocs /))
489 #endif
490 
491  !-------------- fourier transform (forward) of shifted density ----------!
492 ! for performance checks
493 #ifdef _FTRACE
494 CALL ftrace_region_begin("forward_fft")
495 #endif
496 
500  CALL this%FFT_Forward(mesh,physics)
501 
502 ! performance checks
503 #ifdef _FTRACE
504 CALL ftrace_region_end("forward_fft")
505 #endif
506 
507  !------------- calculate potential in fourier domain --------------------!
508  IF (mesh%dx .GT. mesh%dy) THEN
509  k2max = 0.5*pi**2/(mesh%dx**2)
510  ELSE
511  k2max = 0.5*pi**2/(mesh%dy**2)
512  END IF
513 
514  IF (mesh%shear_dir.EQ.2) THEN
515 !NEC$ IVDEP
516  DO j = mesh%JMIN,mesh%JMAX
517 !NEC$ IVDEP
518  DO i = mesh%IMIN,mesh%IMAX/2+1
519  k2 = (this%kx(i) + mesh%Q*mesh%OMEGA*this%ky(j)*delt)**2 + this%ky(j)**2
520  ko = sqrt(k2)
521  IF ((k2 .LT. k2max) .AND. (k2 .GT. 0)) THEN
522  this%Fmass2D(i,j-this%local_joff) = -2.*pi*physics%Constants%GN* &
523  this%Fmass2D(i,j-this%local_joff)/ko
524  ELSE
525  this%Fmass2D(i,j-this%local_joff) = 0.0
526  END IF
527  END DO
528  END DO
529  ELSE IF (mesh%shear_dir.EQ.1) THEN
530 !NEC$ IVDEP
531  DO j = mesh%JMIN,mesh%JMAX
532 !NEC$ IVDEP
533  DO i = mesh%IMIN,mesh%IMAX/2+1
534  k2 = this%kx(i)**2 + (this%ky(j)-mesh%Q*mesh%OMEGA*this%kx(i)*delt)**2
535  ko = sqrt(k2)
536  IF ((k2 .LT. k2max) .AND. (k2 .GT. 0)) THEN
537  this%Fmass2D(i,j-this%local_joff) = -2.*pi*physics%Constants%GN* &
538  this%Fmass2D(i,j-this%local_joff)/ko
539  ELSE
540  this%Fmass2D(i,j-this%local_joff) = 0.0
541  END IF
542  END DO
543  END DO
544  END IF
545 
546  !----------- fourier transform (backward) of shifted density -----------!
547 #ifdef _FTRACE
548 CALL ftrace_region_begin("backward_fft")
549 #endif
550 
554  CALL this%FFT_Backward(mesh,physics)
555 
556 #ifdef _FTRACE
557 CALL ftrace_region_end("backward_fft")
558 #endif
559 
560  !------ calculate final potential with backshift and normalization ------!
561 !NEC$ IVDEP
562  DO k = mesh%KMIN,mesh%KMAX
563 !NEC$ IVDEP
564  DO j = mesh%JMIN,mesh%JMAX
565 !NEC$ IVDEP
566  DO i = mesh%IMIN,mesh%IMAX
567  this%phi(i,j,k) = this%mass2D(i,j-this%local_joff)/ &
568  (mesh%JNUM*mesh%INUM) ! no norm. by FFTW !
569  END DO
570  END DO
571  END DO
572  !-------------------------- shift field back ----------------------------!
573 !!NEC$ IEXPAND
574  CALL this%FieldShift(mesh,physics,-delt, &
575  this%phi(mesh%IGMIN:mesh%IGMAX,mesh%JGMIN:mesh%JGMAX,mesh%KGMIN:mesh%KGMAX), &
576  this%den_ip(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX))
577 
578 !NEC$ IVDEP
579  DO k = mesh%KMIN,mesh%KMAX
580 !NEC$ IVDEP
581  DO j = mesh%JMIN,mesh%JMAX
582 !NEC$ IVDEP
583  DO i = mesh%IMIN,mesh%IMAX
584  this%phi(i,j,k) = this%den_ip(i,j,k)
585  END DO
586  END DO
587  END DO
588 
589  !----- copy values to boundaries in order to calculate acceleration -----!
590  IF(mesh%shear_dir.EQ.2) THEN
591 !NEC$ SHORTLOOP
592  DO j = 1,mesh%GJNUM
593  ! southern northern (periodic)
594  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN-j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX-j+1,mesh%KMIN:mesh%KMAX)
595  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN+j-1,mesh%KMIN:mesh%KMAX)
596  END DO
597  joff2 = -this%shiftconst*delt
598  jrem2 = joff2 - floor(joff2)
599 !NEC$ SHORTLOOP
600  DO i = 1,mesh%GINUM
601  ! western (periodic)
602  this%phi(mesh%IMIN-i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMAX-i+1,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX)
603  ! western integer shift
604  this%phi(mesh%IMIN-i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = &
605  cshift(this%phi(mesh%IMIN-i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX),floor(joff2))
606  ! western residual shift
607  this%phi(mesh%IMIN-i,mesh%JMAX+1,:) = this%phi(mesh%IMIN-i,mesh%JMIN,:)
608  DO k=mesh%KMIN,mesh%KMAX
609  DO j=mesh%JMIN,mesh%JMAX
610  this%phi(mesh%IMIN-i,j,k) = &
611  (1.0 - jrem2)*this%phi(mesh%IMIN-i,j,k) + jrem2*this%phi(mesh%IMIN-i,j+1,k)
612  END DO
613  END DO
614  END DO
615  joff2 = this%shiftconst*delt
616  jrem2 = joff2 - floor(joff2)
617 !NEC$ SHORTLOOP
618  DO i = 1,mesh%GINUM
619  ! eastern (periodic)
620  this%phi(mesh%IMAX+i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN+i-1,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX)
621  ! eastern integer shift
622  this%phi(mesh%IMAX+i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = &
623  cshift(this%phi(mesh%IMAX+i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX),floor(joff2))
624  ! eastern residual shift
625  this%phi(mesh%IMAX+i,mesh%JMAX+1,:) = this%phi(mesh%IMAX+i,mesh%JMIN,:)
626  DO k=mesh%KMIN,mesh%KMAX
627  DO j=mesh%JMIN,mesh%JMAX
628  this%phi(mesh%IMAX+i,j,k) = &
629  (1.0 - jrem2)*this%phi(mesh%IMAX+i,j,k) + jrem2*this%phi(mesh%IMAX+i,j+1,k)
630  END DO
631  END DO
632  END DO
633 ! Only north-south direction has parallelization allowed
634 ! Attention: The order of the copies plays a role. First the non-shifted direction needs to be
635 ! copied, afterwards the shifted.
636  ELSE IF(mesh%shear_dir.EQ.1) THEN
637 !NEC$ SHORTLOOP
638  DO i = 1,mesh%GINUM
639  ! western and eastern (always periodic)
640  this%phi(mesh%IMIN-i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMAX-i+1,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX)
641  this%phi(mesh%IMAX+i,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN+i-1,mesh%JMIN:mesh%JMAX,mesh%KMIN:mesh%KMAX)
642  END DO
643 #ifdef PARALLEL
644  IF(mesh%dims(2).GT.1) THEN
645  mpi_buf(mesh%IMIN:mesh%IMAX,1:mesh%GJNUM,mesh%KMIN:mesh%KMAX) = &
646  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX-mesh%GJNUM+1:mesh%JMAX,mesh%KMIN:mesh%KMAX)
647  CALL mpi_sendrecv_replace(&
648  mpi_buf,&
649  2*(mesh%IMAX-mesh%IMIN+1), &
651  mesh%neighbor(north), 53+north, &
652  mesh%neighbor(south), mpi_any_tag, &
653  mesh%comm_cart, status, ierror)
654  this%phi(mesh%IMIN:mesh%IMAX,mesh%JGMIN:mesh%JMIN-1,mesh%KMIN:mesh%KMAX) = &
655  mpi_buf(mesh%IMIN:mesh%IMAX,1:mesh%GJNUM,mesh%KMIN:mesh%KMAX)
656 
657  mpi_buf(mesh%IMIN:mesh%IMAX,1:mesh%GJNUM,mesh%KMIN:mesh%KMAX) = &
658  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN:mesh%JMIN+mesh%GJNUM-1,mesh%KMIN:mesh%KMAX)
659  CALL mpi_sendrecv_replace(&
660  mpi_buf,&
661  2*(mesh%IMAX-mesh%IMIN+1), &
663  mesh%neighbor(south), 53+south, &
664  mesh%neighbor(north), mpi_any_tag, &
665  mesh%comm_cart, status, ierror)
666  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+1:mesh%JGMAX,mesh%KMIN:mesh%KMAX) = &
667  mpi_buf(mesh%IMIN:mesh%IMAX,1:mesh%GJNUM,mesh%KMIN:mesh%KMAX)
668  ELSE
669 !NEC$ SHORTLOOP
670  DO j = 1,mesh%GJNUM
671  ! southern northern (periodic in first step - further shift-treatment below)
672  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN-j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX-j+1,mesh%KMIN:mesh%KMAX)
673  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN+j-1,mesh%KMIN:mesh%KMAX)
674  END DO
675  END IF
676 #endif
677 
678 #ifdef PARALLEL
679  IF (mesh%mycoords(2).EQ.0) THEN
680 #endif
681 !NEC$ SHORTLOOP
682  DO j = 1,mesh%GJNUM
683  ! southern (shorn periodic) - residual and integer shift
684 #ifndef PARALLEL
685  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN-j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX-j+1,mesh%KMIN:mesh%KMAX)
686 #endif
687  joff2 = this%shiftconst*delt
688  jrem2 = joff2 - floor(joff2)
689  !------- integral shift ---------------------------------------------!
690  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN-j,mesh%KMIN:mesh%KMAX) = &
691  cshift(this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN-j,mesh%KMIN:mesh%KMAX),floor(joff2))
692  !------- residual shift ---------------------------------------------!
693  this%phi(mesh%IMAX+1,mesh%JMIN-j,:) = this%phi(mesh%IMIN,mesh%JMIN-j,:)
694  DO k = mesh%KMIN,mesh%KMAX
695  DO i=mesh%IMIN,mesh%IMAX
696  this%phi(i,mesh%JMIN-j,k) = &
697  (1.0 - jrem2)*this%phi(i,mesh%JMIN-j,k) + jrem2*this%phi(i+1,mesh%JMIN-j,k)
698  END DO
699  END DO
700  END DO
701 #ifdef PARALLEL
702  END IF
703 #endif
704 
705 #ifdef PARALLEL
706  IF (mesh%mycoords(2).EQ.mesh%dims(2)-1) THEN
707 #endif
708 !NEC$ SHORTLOOP
709  DO j = 1,mesh%GJNUM
710 #ifndef PARALLEL
711  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+j,mesh%KMIN:mesh%KMAX) = this%phi(mesh%IMIN:mesh%IMAX,mesh%JMIN+j-1,mesh%KMIN:mesh%KMAX)
712 #endif
713  ! northern (shorn periodic) - residual and integer shift
714  joff2 = -this%shiftconst*delt
715  jrem2 = joff2 - floor(joff2)
716  !------- integral shift ---------------------------------------------!
717  this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+j,mesh%KMIN:mesh%KMAX) = &
718  cshift(this%phi(mesh%IMIN:mesh%IMAX,mesh%JMAX+j,mesh%KMIN:mesh%KMAX),floor(joff2))
719  !------- residual shift ---------------------------------------------!
720  this%phi(mesh%IMAX+1,mesh%JMAX+j,:) = this%phi(mesh%IMIN,mesh%JMAX+j,:)
721  DO k = mesh%KMIN,mesh%KMAX
722  DO i = mesh%IMIN,mesh%IMAX
723  this%phi(i,mesh%JMAX+j,k) = &
724  (1.0 - jrem2)*this%phi(i,mesh%JMAX+j,k) + jrem2*this%phi(i+1,mesh%JMAX+j,k)
725  END DO
726  END DO
727  END DO
728 #ifdef PARALLEL
729  END IF
730 #endif
731  END IF
732  END SUBROUTINE calcpotential
733 
734 
736  SUBROUTINE fft_forward(this,Mesh,Physics)
737  IMPLICIT NONE
738  !------------------------------------------------------------------------!
739  CLASS(gravity_sboxspectral), INTENT(INOUT):: this
740  CLASS(mesh_base), INTENT(IN) :: Mesh
741  CLASS(physics_base), INTENT(IN) :: Physics
742  !------------------------------------------------------------------------!
743  INTEGER :: i,j,k
744 #ifdef PARALLEL
745  INTEGER :: nprocs,status(MPI_STATUS_SIZE)
746  INTEGER :: ier
747 #endif
748  !------------------------------------------------------------------------!
749 #ifdef PARALLEL
750  CALL mpi_comm_size(mpi_comm_world, nprocs, ier)
751 #endif
752 
753 #ifdef _FTRACE
754 CALL ftrace_region_begin("forward FFT")
755 #endif
756 
757 #if !defined(PARALLEL)
758  CALL fftw_execute_dft_r2c(this%plan_r2c, this%mass2D, this%Fmass2D)
759 #else
760  CALL fftw_mpi_execute_dft_r2c(this%plan_r2c,this%mass2D, this%Fmass2D)
761 #endif
762 
763  IF (this%calc_Fmass2D) THEN
764 !NEC$ IVDEP
765  DO k = mesh%KMIN,mesh%KMAX
766 !NEC$ IVDEP
767  DO j = mesh%JMIN,mesh%JMAX
768 !NEC$ IVDEP
769  DO i = mesh%IMIN,mesh%IMAX/2+1
770  this%Fmass2D_real(2*i-1,j,k) = REAL(REAL(this%Fmass2D(i,j-this%local_joff)))
771  this%Fmass2D_real(2*i,j,k) = REAL(AIMAG(this%Fmass2D(i,j-this%local_joff)))
772  END DO
773  END DO
774  END DO
775  END IF
776 
777 #ifdef _FTRACE
778 CALL ftrace_region_end("foward FFT")
779 #endif
780 
781  END SUBROUTINE
782 
783 
785  SUBROUTINE fft_backward(this,Mesh,Physics)
786  IMPLICIT NONE
787  !------------------------------------------------------------------------!
788  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
789  CLASS(mesh_base), INTENT(IN) :: Mesh
790  CLASS(physics_base), INTENT(IN) :: Physics
791  !------------------------------------------------------------------------!
792 #ifdef PARALLEL
793  INTEGER :: nprocs,status(MPI_STATUS_SIZE)
794  INTEGER :: ier
795 #endif
796  !------------------------------------------------------------------------!
797 #ifdef PARALLEL
798  CALL mpi_comm_size(mpi_comm_world, nprocs, ier)
799 #endif
800 
801 #if defined(PARALLEL)
802  CALL fftw_mpi_execute_dft_c2r(this%plan_c2r,this%Fmass2D, this%mass2D)
803 #else
804  CALL fftw_execute_dft_c2r(this%plan_c2r, this%Fmass2D, this%mass2D)
805 #endif
806  END SUBROUTINE
807 #endif
808 
809 
838  SUBROUTINE calcdiskheight_single(this,Mesh,Physics,pvar,bccsound,h_ext,height)
839  IMPLICIT NONE
840  !------------------------------------------------------------------------!
841  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
842  CLASS(mesh_base), INTENT(IN) :: Mesh
843  CLASS(physics_base), INTENT(IN) :: Physics
844  CLASS(marray_compound), INTENT(INOUT) :: pvar
845  TYPE(marray_base), INTENT(INOUT) :: bccsound,h_ext,height
846  !------------------------------------------------------------------------!
847  INTEGER :: i,j,k
848  REAL :: cs2,p,q
849  !------------------------------------------------------------------------!
850 #ifdef HAVE_FFTW
851  ! pure self-gravitating shearing sheet with external point mass potential
852 !NEC$ COLLAPSE
853  DO k=mesh%KGMIN,mesh%KGMAX
854 !NEC$ IVDEP
855  DO j=mesh%JGMIN,mesh%JGMAX
856 !NEC$ IVDEP
857  DO i=mesh%IGMIN,mesh%IGMAX
858  cs2 = bccsound%data3d(i,j,k)*bccsound%data3d(i,j,k)
859  p = -sqrttwopi*physics%Constants%GN*pvar%data4d(i,j,k,physics%DENSITY) &
860  /mesh%OMEGA**2.
861  q = cs2/mesh%OMEGA**2.
862  ! return the new disk height
863  height%data3d(i,j,k) = p+sqrt(q+p*p)
864  END DO
865  END DO
866  END DO
867 #endif
868  END SUBROUTINE calcdiskheight_single
869 
871  SUBROUTINE infogravity(this,Mesh)
872  IMPLICIT NONE
873  !------------------------------------------------------------------------!
874  CLASS(gravity_sboxspectral), INTENT(IN) :: this
875  CLASS(mesh_base), INTENT(IN) :: Mesh
876  !------------------------------------------------------------------------!
877 #ifdef HAVE_FFTW
878  CALL this%Info( " FFT-Package: FFTW " // &
879 #if defined(PARALLEL)
880  "- parallel mode")
881 #else
882  "- serial mode")
883 #endif
884  CALL this%Info(" .. done initializing")
885 #endif
886  END SUBROUTINE infogravity
887 
897 #ifdef HAVE_FFTW
898  SUBROUTINE fieldshift(this,Mesh,Physics,delt,field,mass2D)
899  IMPLICIT NONE
900  !------------------------------------------------------------------------!
901  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
902  CLASS(mesh_base), INTENT(IN) :: Mesh
903  CLASS(physics_base), INTENT(IN) :: Physics
904  REAL, DIMENSION(Mesh%IGMIN:Mesh%IGMAX,Mesh%JGMIN:Mesh%JGMAX,Mesh%KGMIN:Mesh%KGMAX), &
905  INTENT(IN) :: field
906 #if defined(PARALLEL)
907  REAL, DIMENSION(1:Mesh%INUM,1:this%local_JNUM), &
908  INTENT(OUT) :: mass2D
909 #else
910  REAL, DIMENSION(Mesh%IMIN:Mesh%IMAX,Mesh%JMIN:Mesh%JMAX), &
911  INTENT(OUT) :: mass2D
912 #endif
913  !------------------------------------------------------------------------!
914  INTEGER :: i,j,k,local_joff
915  REAL :: delt
916  !------------------------------------------------------------------------!
917  local_joff = this%local_joff
918 
919  IF (mesh%shear_dir.EQ.1) THEN
920 !NEC$ IVDEP
921  DO k = mesh%KMIN,mesh%KMAX
922 !NEC$ IVDEP
923  DO j = mesh%JMIN,mesh%JMAX
924  this%joff(j) = mesh%Q*mesh%OMEGA*mesh%bcenter(mesh%IMIN,j,k,2)* &
925  delt/mesh%dx
926  this%jrem(j) = this%joff(j) - floor(this%joff(j))
927 !NEC$ IVDEP
928  DO i = mesh%IMIN,mesh%IMAX
929  mass2d(i,j-local_joff) = &
930  (1.0-this%jrem(j))*field(1+modulo(i-1+floor(this%joff(j)), &
931  mesh%IMAX-mesh%IMIN+1),j,k) + this%jrem(j)*field(1+modulo(i+ &
932  floor(this%joff(j)),mesh%IMAX-mesh%IMIN+1),j,k)
933  END DO
934  END DO
935  END DO
936  ELSE IF (mesh%shear_dir.EQ.2) THEN
937 !NEC$ IVDEP
938  DO k = mesh%KMIN,mesh%KMAX
939 !NEC$ IVDEP
940  DO i = mesh%IMIN,mesh%IMAX
941  this%joff(i) = -mesh%Q*mesh%OMEGA*mesh%bcenter(i,mesh%JMIN,k,1)* &
942  delt/mesh%dy
943  this%jrem(i) = this%joff(i) - floor(this%joff(i))
944  END DO
945  DO j = mesh%JMIN,mesh%JMAX
946 !NEC$ IVDEP
947  DO i = mesh%IMIN,mesh%IMAX
948  mass2d(i,j) = &
949  (1.0-this%jrem(i))*field(i,1+modulo(j-1+floor(this%joff(i)), &
950  mesh%JMAX-mesh%JMIN+1),k) + this%jrem(i)*field(i,1+modulo(j+ &
951  floor(this%joff(i)),mesh%JMAX-mesh%JMIN+1),k)
952  END DO
953  END DO
954  END DO
955  END IF
956  END SUBROUTINE fieldshift
957 #endif
958 
959  SUBROUTINE finalize(this)
960  IMPLICIT NONE
961  !------------------------------------------------------------------------!
962  CLASS(gravity_sboxspectral), INTENT(INOUT) :: this
963  !------------------------------------------------------------------------!
964 #ifdef HAVE_FFTW
965  CALL fftw_destroy_plan(this%plan_r2c)
966  CALL fftw_destroy_plan(this%plan_c2r)
967 #if defined(PARALLEL)
968  CALL fftw_free(this%mass2D_pointer)
969  CALL fftw_free(this%Fmass2D_pointer)
970 #else
971  DEALLOCATE(this%mass2D,this%Fmass2D)
972 #endif
973  ! Free memory
974  DEALLOCATE(&
975  this%phi, &
976  this%Fmass2D_real, &
977  this%kx, this%ky, &
978  this%joff, &
979  this%jrem, &
980  this%den_ip &
981  )
982 #endif
983  END SUBROUTINE finalize
984 
985 END MODULE gravity_sboxspectral_mod
subroutine calcdiskheight_single(this, Mesh, Physics, pvar, bccsound, h_ext, height)
Compute disk pressure scale height for geometrically thin self-gravitating shearingsheet.
subroutine finalize(this)
Destructor of common class.
integer, save default_mpi_real
default real type for MPI
2D poisson solver using spectral methods for direct integration
Poisson solver via spectral methods within the shearingsheet.
derived class for compound of mesh arrays
base class for mesh arrays
Definition: marray_base.f90:36
subroutine fieldshift(this, Mesh, Physics, delt, field, mass2D)
Shifts the whole field to the next periodic point.
subroutine initgravity_sboxspectral(this, Mesh, Physics, config, IO)
Constructor of gravity sboxspectral module.
subroutine updategravity_single(this, Mesh, Physics, Fluxes, pvar, time, dt)
Calculates the acceleration from potential.
Basic fosite module.
fftw module
Definition: fftw.f90:29
subroutine fft_backward(this, Mesh, Physics)
Calculates the FFT backward transformation.
generic gravity terms module providing functionaly common to all gravity terms
subroutine calcpotential(this, Mesh, Physics, time, pvar)
Computes the potential with FFT method within a shearingsheet.
physics module for 1D,2D and 3D isothermal Euler equations
Basic physics module.
Dictionary for generic data types.
Definition: common_dict.f90:61
subroutine infogravity(this, Mesh)
Prints out information.
base module for numerical flux functions
Definition: fluxes_base.f90:39
subroutine fft_forward(this, Mesh, Physics)
Calculates the FFT forward.