383 lines
11 KiB
Fortran
383 lines
11 KiB
Fortran
!================================================================================
|
|
!================================================================================
|
|
! Initialization of passive scalars
|
|
!================================================================================
|
|
|
|
subroutine init_scalars
|
|
|
|
use m_parameters
|
|
use m_io
|
|
use m_fields
|
|
use x_fftw, only : ialias
|
|
|
|
implicit none
|
|
|
|
integer :: n_scalar, i, j, k
|
|
|
|
write(out,*) 'Generating scalars'
|
|
call flush(out)
|
|
|
|
do n_scalar = 1,n_scalars
|
|
call init_scalar(n_scalar)
|
|
end do
|
|
|
|
write(out,*) "Generated the scalars."
|
|
call flush(out)
|
|
|
|
! now making sure that the scalars do not have any high
|
|
! Fourier harmonics by zeroing out everything that has a wavenumber
|
|
! that potentially can produce aliasing
|
|
do k = 1, nz
|
|
do j = 1, ny
|
|
do i = 1, nx+2
|
|
if (ialias(i,j,k).gt.0) fields(i,j,k,4:3+n_scalars) = zip
|
|
end do
|
|
end do
|
|
end do
|
|
|
|
return
|
|
|
|
end subroutine init_scalars
|
|
|
|
!================================================================================
|
|
!================================================================================
|
|
|
|
subroutine init_scalar(n_scalar)
|
|
|
|
use m_parameters
|
|
use m_io
|
|
use m_fields
|
|
|
|
implicit none
|
|
|
|
integer :: n_scalar, ic_type, sc_type
|
|
|
|
write(out,*) 'Generating scalar #', n_scalar
|
|
call flush(out)
|
|
|
|
sc_type = scalar_type(n_scalar)
|
|
ic_type = sc_type - (sc_type/100)*100
|
|
|
|
if (ic_type.eq.0) then
|
|
! gradient source - no need for initial conditions
|
|
! thus making the initial scalar field zero
|
|
write(out,*) "The scalar type = 0, nothing to generate"
|
|
call flush(out)
|
|
fields(:,:,:,n_scalar+3) = zip
|
|
|
|
elseif (ic_type.lt.10) then
|
|
! if the last two digits of the scalar type are less than 10,
|
|
! the scalar initial conditions are generated based on the
|
|
! particular spectrum of the scalar
|
|
call init_scalar_spectrum(n_scalar)
|
|
|
|
else
|
|
! if the last two digits are bigger than 10, the scalar is generated
|
|
! in physical space and then transformed in the Fourier space
|
|
call init_scalar_space(n_scalar)
|
|
|
|
end if
|
|
return
|
|
end subroutine init_scalar
|
|
!================================================================================
|
|
!================================================================================
|
|
subroutine init_scalar_spectrum(n_scalar)
|
|
!================================================================================
|
|
|
|
use m_openmpi
|
|
use m_parameters
|
|
use m_io
|
|
use m_fields
|
|
use m_work
|
|
use x_fftw
|
|
use m_rand_knuth
|
|
use RANDu
|
|
|
|
implicit none
|
|
|
|
integer :: i, j, k, n, n_scalar
|
|
integer *8 :: i8
|
|
|
|
real*8, allocatable :: e_spec(:), e_spec1(:), rr(:)
|
|
integer *8, allocatable :: hits(:), hits1(:)
|
|
|
|
integer :: n_shell
|
|
real*8 :: sc_rad1, sc_rad2
|
|
|
|
real*8 :: wmag, wmag2, ratio, fac, fac2
|
|
|
|
!--------------------------------------------------------------------------------
|
|
write(out,*) " Generating scalar # ",n_scalar
|
|
call flush(out)
|
|
|
|
! Initializing the random sequence with the seed RN2
|
|
fac = random(-RN2)
|
|
|
|
! allocate work arrays
|
|
allocate( e_spec(kmax), e_spec1(kmax), hits(kmax), hits1(kmax), &
|
|
rr(nx+2), stat=ierr)
|
|
|
|
! bringing the processors to their own places in the random sequence
|
|
! ("2" is there because we're generating two random number fields
|
|
! for each scalar field
|
|
! using i8 because it's int*8
|
|
do i8 = 1,myid*(nx+2)*ny*nz*2
|
|
fac = random(RN2)
|
|
end do
|
|
|
|
! now filling the arrays wrk1, wrk2
|
|
do n = 1,2
|
|
do k = 1,nz
|
|
do j = 1,ny
|
|
do i = 1,nx+2
|
|
wrk(i,j,k,n) = random(RN2)
|
|
end do
|
|
end do
|
|
end do
|
|
end do
|
|
|
|
! bringing the random numbers to the same
|
|
! point in the sequence again
|
|
do i8 = 1,(numprocs-myid-1)*(nx+2)*ny*nz*2
|
|
fac = random(RN2)
|
|
end do
|
|
|
|
! making random array with Gaussian PDF
|
|
! out of the two arrays that we generated
|
|
wrk(:,:,:,3) = sqrt(-two*log(wrk(:,:,:,1))) * sin(TWO_PI*wrk(:,:,:,2))
|
|
|
|
! go to Fourier space
|
|
call xFFT3d(1,3)
|
|
|
|
!-------------------------------------------------------------------------------
|
|
! Calculating the scalar spectrum
|
|
!-------------------------------------------------------------------------------
|
|
|
|
! need this normalization factor because the FFT is unnormalized
|
|
fac = one / real(nx*ny*nz_all)**2
|
|
|
|
e_spec1 = zip
|
|
e_spec = zip
|
|
hits = 0
|
|
hits1 = 0
|
|
|
|
! assembling the scalar energy in each shell and number of hits in each shell
|
|
do k = 1,nz
|
|
do j = 1,ny
|
|
do i = 1,nx
|
|
|
|
n_shell = nint(sqrt(real(akx(i)**2 + aky(k)**2 + akz(j)**2, 4)))
|
|
if (n_shell .gt. 0 .and. n_shell .le. kmax) then
|
|
fac2 = fac * wrk(i,j,k,3)**2
|
|
if (akx(i).eq.0.d0) fac2 = fac2 * 0.5d0
|
|
e_spec1(n_shell) = e_spec1(n_shell) + fac2
|
|
end if
|
|
end do
|
|
end do
|
|
end do
|
|
|
|
! reducing the number of hits and energy to two arrays on master node
|
|
count = kmax
|
|
call MPI_REDUCE(e_spec1,e_spec,count,MPI_REAL8,MPI_SUM,0,MPI_COMM_TASK,mpi_err)
|
|
! broadcasting the spectrum
|
|
count = kmax
|
|
call MPI_BCAST(e_spec,count,MPI_REAL8,0,MPI_COMM_TASK,mpi_err)
|
|
|
|
!-------------------------------------------------------------------------------
|
|
! Now make the spectrum to be as desired
|
|
!-------------------------------------------------------------------------------
|
|
! first, define the desired spectrum
|
|
do k = 1,kmax
|
|
|
|
wmag = real(k, 8)
|
|
ratio = wmag / peak_wavenum_sc(n_scalar)
|
|
|
|
if (scalar_type(n_scalar).eq.0) then
|
|
! Plain Kolmogorov spectrum
|
|
e_spec1(k) = wmag**(-5.d0/3.d0)
|
|
|
|
else if (scalar_type(n_scalar).eq.1 .or. scalar_type(n_scalar).eq.3) then
|
|
! Exponential spectrum
|
|
e_spec1(k) = ratio**3 / peak_wavenum_sc(n_scalar) * exp(-3.0D0*ratio)
|
|
|
|
else if (scalar_type(n_scalar).eq.2) then
|
|
! Von Karman spectrum
|
|
fac = two * PI * ratio
|
|
e_spec1(k) = fac**4 / (one + fac**2)**3
|
|
|
|
else
|
|
write(out,*) "INIT_SCALARS: WRONG INITIAL SPECTRUM TYPE: ",scalar_type(n_scalar)
|
|
call flush(out)
|
|
stop
|
|
|
|
end if
|
|
end do
|
|
|
|
! normalize it so it has the unit total energy
|
|
e_spec1 = e_spec1 / sum(e_spec1(1:kmax))
|
|
|
|
! now go over all Fourier shells and multiply the velocities in a shell by
|
|
! the sqrt of ratio of the resired to the current spectrum
|
|
fields(:,:,:,3+n_scalar) = zip
|
|
|
|
do k = 1,nz
|
|
do j = 1,ny
|
|
do i = 1,nx+2
|
|
|
|
n_shell = nint(sqrt(real(akx(i)**2 + aky(k)**2 + akz(j)**2, 4)))
|
|
if (n_shell .gt. 0 .and. n_shell .le. kmax .and. e_spec(n_shell) .gt. zip) then
|
|
fields(i,j,k,3+n_scalar) = wrk(i,j,k,3) * sqrt(e_spec1(n_shell)/e_spec(n_shell))
|
|
else
|
|
fields(i,j,k,3+n_scalar) = zip
|
|
end if
|
|
|
|
end do
|
|
end do
|
|
end do
|
|
|
|
!-------------------------------------------------------------------------------
|
|
! Creating scalars with double-delta PDF
|
|
!-------------------------------------------------------------------------------
|
|
|
|
if (scalar_type(n_scalar).eq.3) then
|
|
wrk(:,:,:,0) = fields(:,:,:,3+n_scalar)
|
|
call xFFT3d(-1,0)
|
|
|
|
! making it double-delta (0.9 and -0.9)
|
|
wrk(:,:,:,0) = sign(one,wrk(:,:,:,0)) * 0.9d0
|
|
call xFFT3d(1,0)
|
|
|
|
! smoothing it by zeroing out high harmonics
|
|
do k = 1,nz
|
|
do j = 1,ny
|
|
do i = 1,nx+2
|
|
n_shell = nint(sqrt(real(akx(i)**2 + aky(k)**2 + akz(j)**2, 4)))
|
|
if (n_shell .eq. 0 .or. n_shell .ge. kmax*2/3) then
|
|
wrk(i,j,k,0) = zip
|
|
end if
|
|
end do
|
|
end do
|
|
end do
|
|
fields(:,:,:,3+n_scalar) = wrk(:,:,:,0)
|
|
|
|
end if
|
|
|
|
! deallocate work arrays
|
|
deallocate(e_spec, e_spec1, rr, hits, hits1, stat=ierr)
|
|
|
|
return
|
|
end subroutine init_scalar_spectrum
|
|
|
|
!================================================================================
|
|
!================================================================================
|
|
!================================================================================
|
|
!================================================================================
|
|
subroutine init_scalar_space(n_scalar)
|
|
!================================================================================
|
|
|
|
use m_openmpi
|
|
use m_io
|
|
use m_parameters
|
|
use m_fields
|
|
use m_work
|
|
use x_fftw
|
|
|
|
implicit none
|
|
|
|
integer :: i, k, n_scalar, sc_type, ic_type, nfi
|
|
real*8 :: zloc, sctmp, h, xx
|
|
|
|
nfi = 3 + n_scalar
|
|
|
|
write(out,*) " Generating scalar # ", n_scalar
|
|
call flush(out)
|
|
|
|
sc_type = scalar_type(n_scalar)
|
|
ic_type = sc_type - (sc_type/100)*100
|
|
|
|
select case (ic_type)
|
|
|
|
!---------------------------------------------------
|
|
! single slab of the scalar
|
|
!---------------------------------------------------
|
|
case(11)
|
|
|
|
! how much to smear out the interface
|
|
! the minimum interface length is set to 2*dz
|
|
! the maximum is set to 2*PI/(peak wavenumber for the scalar, taken from
|
|
! the .in file)
|
|
h = max(2.*dz, two*PI/peak_wavenum_sc(n_scalar))
|
|
|
|
! creating array of scalar
|
|
do k = 1,nz
|
|
zloc = dble(myid*nz + k-1) * dz
|
|
sctmp = tanh((zloc-PI*0.5)/h) - tanh((zloc-PI*1.5)/h) - one
|
|
wrk(:,:,k,0) = sctmp
|
|
end do
|
|
|
|
! FFT of the scalar
|
|
call xFFT3d(1,0)
|
|
|
|
! putting it into the scalar array
|
|
fields(:,:,:, 3+n_scalar) = wrk(:,:,:,0)
|
|
if (iammaster) fields(1,1,1,3+n_scalar) = zip
|
|
|
|
!---------------------------------------------------
|
|
! two slabs of the scalar
|
|
!---------------------------------------------------
|
|
case(12)
|
|
|
|
write(out,*) "-- Double-slab scalar in real space"
|
|
call flush(out)
|
|
|
|
! how much to smear out the interface
|
|
h = max(8.*dz, PI/8.d0)
|
|
|
|
! creating array of scalar
|
|
do i = 1,nx
|
|
xx = dble(i-1) * dx
|
|
sctmp = tanh((xx-PI*0.25)/h) - tanh((xx-PI*0.75)/h) + tanh((xx-PI*1.25)/h) - tanh((xx-PI*1.75)/h)
|
|
wrk(i,:,:,0) = sctmp - one
|
|
! now it is between -1 and 1
|
|
end do
|
|
|
|
! FFT of the scalar
|
|
call xFFT3d(1,0)
|
|
|
|
! putting it into the scalar array
|
|
fields(:,:,:, 3+n_scalar) = wrk(:,:,:,0)
|
|
|
|
! making sure that the mean is ero
|
|
if (iammaster) fields(1,1,1,3+n_scalar) = zip
|
|
|
|
!---------------------------------------------------
|
|
! N slabs of the scalar
|
|
! actually more like N sinusoidal waves
|
|
!---------------------------------------------------
|
|
case(13)
|
|
write(out,*) "-- Multi-slab scalar in real space"
|
|
call flush(out)
|
|
|
|
! making sure that we can support the desired numberof waves with our FFT
|
|
peak_wavenum_sc(n_scalar) = min(peak_wavenum_sc(n_scalar),real(nx/8))
|
|
|
|
! definition of initial scalar
|
|
fields(:,:,:,nfi) = zip
|
|
do i = 1, nx
|
|
fields(i,:,:,nfi) = sin(peak_wavenum_sc(n_scalar) * dx * real(i-1))
|
|
end do
|
|
call xFFT3d_fields(1,nfi)
|
|
|
|
|
|
case default
|
|
write(out,*) "INIT_SCALARS: UNEXPECTED SCALAR TYPE: ", scalar_type(n_scalar)
|
|
call flush(out)
|
|
stop
|
|
end select
|
|
|
|
write(out,*) "Initialized the scalars."
|
|
call flush(out)
|
|
|
|
return
|
|
|
|
end subroutine init_scalar_space
|