Newer
Older
Antoine Cyril David Hoffmann
committed
MODULE calculus
! Routine to evaluate gradients, interpolation schemes and integrals
USE prec_const, ONLY: dp
Antoine Cyril David Hoffmann
committed
IMPLICIT NONE
REAL(dp), dimension(-2:2) :: dz_usu = &
(/ 1._dp/12._dp, -2._dp/3._dp, 0._dp, 2._dp/3._dp, -1._dp/12._dp /) ! fd4 centered stencil
Antoine Cyril David Hoffmann
committed
REAL(dp), dimension(-2:1) :: dz_o2e = &
(/ 1._dp/24._dp,-9._dp/8._dp, 9._dp/8._dp,-1._dp/24._dp /) ! fd4 odd to even stencil
Antoine Cyril David Hoffmann
committed
REAL(dp), dimension(-1:2) :: dz_e2o = &
(/ 1._dp/24._dp,-9._dp/8._dp, 9._dp/8._dp,-1._dp/24._dp /) ! fd4 odd to even stencil
REAL(dp), dimension(-2:2) :: dz2_usu = &
(/-1._dp/12._dp, 4._dp/3._dp, -5._dp/2._dp, 4._dp/3._dp, -1._dp/12._dp /)! 2th derivative, 4th order (for parallel hypdiff)
REAL(dp), dimension(-2:2) :: dz4_usu = &
(/ 1._dp, -4._dp, 6._dp, -4._dp, 1._dp /) ! 4th derivative, 2nd order (for parallel hypdiff)
REAL(dp), dimension(-2:1) :: iz_o2e = &
(/ -1._dp/16._dp, 9._dp/16._dp, 9._dp/16._dp, -1._dp/16._dp /) ! grid interpolation, 4th order, odd to even
REAL(dp), dimension(-1:2) :: iz_e2o = &
(/ -1._dp/16._dp, 9._dp/16._dp, 9._dp/16._dp, -1._dp/16._dp /) ! grid interpolation, 4th order, even to odd
PUBLIC :: simpson_rule_z, interp_z, grad_z, grad_z4
Antoine Cyril David Hoffmann
committed
CONTAINS
SUBROUTINE grad_z(target,local_nz,ngz,inv_deltaz,f,ddzf)
Antoine Cyril David Hoffmann
committed
implicit none
! Compute the periodic boundary condition 4 points centered finite differences
! formula among staggered grid or not.
! not staggered : the derivative results must be on the same grid as the field
! staggered : the derivative is computed from a grid to the other
REAL(dp), INTENT(IN) :: inv_deltaz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: f
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: ddzf
INTEGER :: iz
IF(ngz .GT. 3) THEN ! Cannot apply four points stencil on less than four points grid
SELECT CASE(TARGET)
CASE(1)
CASE DEFAULT ! No staggered grid -> usual centered finite differences
ddzf(iz) = dz_usu(-2)*f(iz ) + dz_usu(-1)*f(iz+1) &
+dz_usu( 0)*f(iz+2) &
+dz_usu( 1)*f(iz+3) + dz_usu( 2)*f(iz+4)
Antoine Cyril David Hoffmann
committed
ENDDO
ddzf(:) = ddzf(:) * inv_deltaz
Antoine Cyril David Hoffmann
committed
ELSE
ddzf = 0._dp
Antoine Cyril David Hoffmann
committed
ENDIF
SUBROUTINE grad_z_o2e(local_nz,ngz,inv_deltaz,fo,ddzfe) ! Paruta 2018 eq (27)
! gives the gradient of a field from the odd grid to the even one
implicit none
REAL(dp), INTENT(IN) :: inv_deltaz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: fo
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: ddzfe !
INTEGER :: iz
ddzfe(iz) = dz_o2e(-2)*fo(iz ) + dz_o2e(-1)*fo(iz+1) &
+dz_o2e( 0)*fo(iz+2) + dz_o2e( 1)*fo(iz+3)
ENDDO
ddzfe(:) = ddzfe(:) * inv_deltaz
END SUBROUTINE grad_z_o2e
Antoine Cyril David Hoffmann
committed
SUBROUTINE grad_z_e2o(local_nz,ngz,inv_deltaz,fe,ddzfo) ! n2v for Paruta 2018 eq (28)
! gives the gradient of a field from the even grid to the odd one
implicit none
REAL(dp), INTENT(IN) :: inv_deltaz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: fe
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: ddzfo
INTEGER :: iz
ddzfo(iz) = dz_e2o(-1)*fe(iz+1) + dz_e2o(0)*fe(iz+2) &
+dz_e2o( 1)*fe(iz+3) + dz_e2o(2)*fe(iz+4)
ENDDO
ddzfo(:) = ddzfo(:) * inv_deltaz
END SUBROUTINE grad_z_e2o
END SUBROUTINE grad_z
Antoine Cyril David Hoffmann
committed
! Compute the second order fourth derivative for periodic boundary condition
implicit none
REAL(dp), INTENT(IN) :: inv_deltaz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: f
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: ddz2f
INTEGER :: iz
IF(ngz .GT. 3) THEN ! Cannot apply four points stencil on less than four points grid
ddz2f(iz) = dz2_usu(-2)*f(iz ) + dz2_usu(-1)*f(iz+1) &
+dz2_usu( 0)*f(iz+2)&
+dz2_usu( 1)*f(iz+3) + dz2_usu( 2)*f(iz+4)
ENDDO
ELSE
ddz2f = 0._dp
ENDIF
ddz2f = ddz2f * inv_deltaz**2
END SUBROUTINE grad_z2
SUBROUTINE grad_z4(local_nz,ngz,inv_deltaz,f,ddz4f)
! Compute the second order fourth derivative for periodic boundary condition
implicit none
REAL(dp), INTENT(IN) :: inv_deltaz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: f
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: ddz4f
INTEGER :: iz
IF(ngz .GT. 3) THEN ! Cannot apply four points stencil on less than four points grid
ddz4f(iz) = dz4_usu(-2)*f(iz ) + dz4_usu(-1)*f(iz+1) &
+dz4_usu( 0)*f(iz+2)&
+dz4_usu( 1)*f(iz+3) + dz4_usu( 2)*f(iz+4)
ENDDO
ELSE
ddz4f = 0._dp
ENDIF
ddz4f = ddz4f * inv_deltaz**4
END SUBROUTINE grad_z4
Antoine Cyril David Hoffmann
committed
SUBROUTINE interp_z(target,local_nz,ngz,f_in,f_out)
Antoine Cyril David Hoffmann
committed
! Function meant to interpolate one field defined on a even/odd z into
! the other odd/even z grid.
! If Staggered Grid flag (SG) is false, returns identity
implicit none
Antoine Cyril David Hoffmann
committed
INTEGER, intent(in) :: target ! target grid : 0 for even grid, 1 for odd
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: f_in
COMPLEX(dp),dimension(local_nz), INTENT(OUT) :: f_out
SELECT CASE(TARGET)
CASE(1) ! output on even grid
CASE(2) ! output on odd grid
CASE DEFAULT ! No staggered grid -> usual centered finite differences
! gives the value of a field from the odd grid to the even one
implicit none
INTEGER, INTENT(IN) :: local_nz, ngz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: fo
INTEGER :: iz
! 4th order interp
fe(iz) = iz_o2e(-2)*fo(iz ) + iz_o2e(-1)*fo(iz+1) &
+ iz_o2e( 0)*fo(iz+2) + iz_o2e( 1)*fo(iz+3)
ENDDO
END SUBROUTINE interp_o2e_z
Antoine Cyril David Hoffmann
committed
! gives the value of a field from the even grid to the odd one
implicit none
INTEGER, INTENT(IN) :: local_nz, ngz
COMPLEX(dp),dimension(local_nz+ngz), INTENT(IN) :: fe
INTEGER :: iz
! 4th order interp
fo(iz) = iz_e2o(-1)*fe(iz+1) + iz_e2o( 0)*fe(iz+2) &
+ iz_e2o( 1)*fe(iz+3) + iz_e2o( 2)*fe(iz+4)
ENDDO
END SUBROUTINE interp_e2o_z
Antoine Cyril David Hoffmann
committed
END SUBROUTINE interp_z
Antoine Cyril David Hoffmann
committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
! integrate f(z) over z using the simpon's rule. Assume periodic boundary conditions (f(ize+1) = f(izs))
!from molix BJ Frei
USE prec_const, ONLY: dp, onethird
USE parallel, ONLY: num_procs_z, rank_z, comm_z, manual_0D_bcast
USE mpi
implicit none
INTEGER, INTENT(IN) :: local_nz
REAL(dp),INTENT(IN) :: dz
complex(dp),dimension(local_nz), intent(in) :: f
COMPLEX(dp), intent(out) :: intf
COMPLEX(dp) :: buffer, local_int
INTEGER :: root, i_, iz, ierr
! Buil local sum using the weights of composite Simpson's rule
local_int = 0._dp
DO iz = 1,local_nz
IF(MODULO(iz,2) .EQ. 1) THEN ! odd iz
local_int = local_int + 2._dp*onethird*dz*f(iz)
ELSE ! even iz
local_int = local_int + 4._dp*onethird*dz*f(iz)
ENDIF
ENDDO
buffer = local_int
root = 0
!Gather manually among the rank_z=0 processes and perform the sum
intf = 0._dp
IF (num_procs_z .GT. 1) THEN
!! Everyone sends its local_sum to root = 0
IF (rank_z .NE. root) THEN
CALL MPI_SEND(buffer, 1 , MPI_DOUBLE_COMPLEX, root, 5678, comm_z, ierr)
ELSE
! Recieve from all the other processes
DO i_ = 0,num_procs_z-1
IF (i_ .NE. rank_z) &
CALL MPI_RECV(buffer, 1 , MPI_DOUBLE_COMPLEX, i_, 5678, comm_z, MPI_STATUS_IGNORE, ierr)
intf = intf + buffer
ENDDO
ENDIF
CALL manual_0D_bcast(intf)
ELSE
intf = local_int
ENDIF
END SUBROUTINE simpson_rule_z
Antoine Cyril David Hoffmann
committed
END MODULE calculus