Spong_3D Subroutine

private subroutine Spong_3D(params, spp)

Arguments

Type IntentOptional AttributesName
type(KORC_PARAMS), intent(in) :: params

Core KORC simulation parameters.

type(SPECIES), intent(inout) :: spp

An instance of the derived type SPECIES containing all the parameters and simulation variables of the different species in the simulation.

An instance of the KORC derived type FIELDS.


Calls

proc~~spong_3d~~CallsGraph proc~spong_3d Spong_3D proc~random_norm~4 random_norm proc~spong_3d->proc~random_norm~4 mpi_barrier mpi_barrier proc~spong_3d->mpi_barrier proc~indicator indicator proc~spong_3d->proc~indicator mpi_scatter mpi_scatter proc~spong_3d->mpi_scatter proc~spong_2d Spong_2D proc~spong_3d->proc~spong_2d proc~psi_rot PSI_ROT proc~spong_3d->proc~psi_rot proc~deg2rad~3 deg2rad proc~spong_2d->proc~deg2rad~3

Contents

Source Code


Source Code

subroutine Spong_3D(params,spp)
  !! @note Subroutine that generates a 2D Gaussian distribution in an 
  !! elliptic torus as the initial spatial condition of a given particle 
  !! species in the simulation. @endnote
  TYPE(KORC_PARAMS), INTENT(IN) 	:: params
  !! Core KORC simulation parameters.
  TYPE(SPECIES), INTENT(INOUT) 		:: spp
  !! An instance of the derived type SPECIES containing all the parameters
  !! and simulation variables of the different species in the simulation.

  !! An instance of the KORC derived type FIELDS.
  REAL(rp), DIMENSION(:), ALLOCATABLE 	:: R_samples
  !! Major radial location of all samples
  REAL(rp), DIMENSION(:), ALLOCATABLE 	:: PHI_samples
  !! Azimuithal angle of all samples
  REAL(rp), DIMENSION(:), ALLOCATABLE 	:: Z_samples
  !! Vertical location of all samples

  REAL(rp), DIMENSION(:), ALLOCATABLE 	:: T_samples
  !! Pitch angle of all samples

  REAL(rp) 				:: psi_max_buff
  !! Value of buffer above desired maximum argument of 2D Gaussian spatial
  !! profile
  REAL(rp) 				:: minmax
  !! Temporary variable used for setting buffers

  !! Minimum domain for momentum sampling including buffer
  REAL(rp) 				:: max_pitch_angle
  !! Maximum domain for pitch angle sampling including buffer
  REAL(rp) 				:: min_pitch_angle
  !! Minimum domain for pitch angle sampling including buffer
  REAL(rp) 				:: theta_rad
  !! Angle of rotation of 2D Gaussian spatial distribution in radians
  REAL(rp) 				:: R_buffer
  !! Previous sample of R location
  REAL(rp) 				:: Z_buffer
  !! Previous sample of Z location
 
  REAL(rp) 				:: T_buffer
  !! Previous sample of pitch angle
  REAL(rp) 				:: R_test
  !! Present sample of R location
  REAL(rp) 				:: Z_test
  !! Present sample of Z location

  REAL(rp) 				:: T_test
  !! Present sample of pitch angle
  REAL(rp) 				:: psi0
  !! Previous value of 2D Gaussian argument based on R_buffer, Z_buffer
  REAL(rp) 				:: psi1
  !! Present value of 2D Gaussian argument based on R_test, Z_test
  REAL(rp) 				:: f0
  !! Evaluation of Avalanche distribution with previous sample
  REAL(rp) 				:: f1
  !! Evaluation of Avalanche distribution with present sample
  REAL(rp) 				:: rand_unif
  !! Uniform random variable [0,1]
  REAL(rp) 				:: ratio
  !! MH selection criteria
  INTEGER				:: nsamples
  !! Total number of samples to be distributed over all mpi processes
  INTEGER 				:: ii
  !! Sample iterator.
  INTEGER 				:: mpierr
  !! mpi error indicator
  
  
  nsamples = spp%ppp*params%mpi_params%nmpi

  psi_max_buff = spp%psi_max*1.1_rp

  theta_rad=C_PI*spp%theta_gauss/180.0_rp


  ! buffer at minimum pitch angle boundary  
  if (spp%etao_lims(1).GE.korc_zero) then
     do ii=1_idef,INT(minmax_buffer_size,idef)
        minmax = spp%etao_lims(1) - REAL(ii,rp)* &
             (spp%etao_lims(2)-spp%etao_lims(1))/100_rp
        if (minmax.GT.0.0_rp) then
           min_pitch_angle = minmax
        end if
     end do
  else
     min_pitch_angle = spp%etao_lims(1)
  end if

  ! buffer at maximum pitch angle boundary
  do ii=1_idef,INT(minmax_buffer_size,idef)
     minmax = spp%etao_lims(2) + REAL(ii,rp)* &
          (spp%etao_lims(2)-spp%etao_lims(1))/100_rp
     if (minmax.LE.180.0_rp) then
        max_pitch_angle = minmax
     end if
  end do

  
  if (params%mpi_params%rank.EQ.0_idef) then
     ALLOCATE(R_samples(nsamples))
     ! Number of samples to distribute among all MPI processes
     ALLOCATE(PHI_samples(nsamples))
     ! Number of samples to distribute among all MPI processes
     ALLOCATE(Z_samples(nsamples))
     ! Number of samples to distribute among all MPI processes
     ALLOCATE(T_samples(nsamples))
     ! Number of samples to distribute among all MPI processes
     
     ! Transient !

     R_buffer = spp%Ro
     Z_buffer = spp%Zo

     
     call RANDOM_NUMBER(rand_unif)
     T_buffer = min_pitch_angle + (max_pitch_angle  &
          - min_pitch_angle)*rand_unif

!     write(output_unit_write,'("length norm: ",E17.10)') params%cpp%length
     
     ii=1_idef
     do while (ii .LE. 1000_idef)

!        write(output_unit_write,'("burn:",I15)') ii
        
        R_test = R_buffer + random_norm(0.0_rp,spp%dR)
        Z_test = Z_buffer + random_norm(0.0_rp,spp%dZ)
        T_test = T_buffer + random_norm(0.0_rp,spp%dth)


        ! Test that pitch angle and momentum are within chosen boundary
        do while ((T_test .GT. spp%etao_lims(2)).OR. &
             (T_test .LT. spp%etao_lims(1)))
           T_test = T_buffer + random_norm(0.0_rp,spp%dth)
        end do

        ! initialize 2D gaussian argument and distribution function, or
        ! copy from previous sample
        if (ii==1) then
           psi0=PSI_ROT(R_buffer,spp%Ro,spp%sigmaR,Z_buffer,spp%Zo, &
                spp%sigmaZ,theta_rad)
           
           f0=Spong_2D(spp%Ro,spp%Spong_b,spp%Spong_w,spp%Spong_dlam, &
                R_buffer,Z_buffer,T_buffer)           
        else
           psi0=psi1
           f0=f1
        end if
        
        psi1=PSI_ROT(R_test,spp%Ro,spp%sigmaR,Z_test,spp%Zo, &
             spp%sigmaZ,theta_rad)       
        
                
        f1=Spong_2D(spp%Ro,spp%Spong_b,spp%Spong_w,spp%Spong_dlam, &
             R_test,Z_test,T_test)    

!        write(output_unit_write,'("psi0: ",E17.10)') psi0
!        write(output_unit_write,'("psi1: ",E17.10)') psi1

!        write(output_unit_write,'("f0: ",E17.10)') f0
!        write(output_unit_write,'("f1: ",E17.10)') f1

        
        ! Calculate acceptance ratio for MH algorithm. fRE function
        ! incorporates p^2 factor of spherical coordinate Jacobian
        ! for velocity phase space, factors of sin(pitch angle) for velocity
        ! phase space and cylindrical coordinate Jacobian R for spatial
        ! phase space incorporated here.
        ratio = indicator(psi1,spp%psi_max)*R_test*EXP(-psi1)*f1/ &
             (R_buffer*EXP(-psi0)*f0)
        
        if (ratio .GE. 1.0_rp) then
           R_buffer = R_test
           Z_buffer = Z_test
           T_buffer = T_test
           ii = ii + 1_idef
        else
           call RANDOM_NUMBER(rand_unif)
           if (rand_unif .LT. ratio) then
              R_buffer = R_test
              Z_buffer = Z_test
              T_buffer = T_test
              ii = ii + 1_idef
           end if
        end if
     end do
     ! Transient !

     ii=1_idef
     do while (ii .LE. nsamples)

!        write(output_unit_write,'("sample:",I15)') ii
        
        if (modulo(ii,10000).eq.0) then
           write(output_unit_write,'("Sample: ",I10)') ii
        end if
        
        R_test = R_buffer + random_norm(0.0_rp,spp%dR)
        Z_test = Z_buffer + random_norm(0.0_rp,spp%dZ)
        T_test = T_buffer + random_norm(0.0_rp,spp%dth)

        ! Selection boundary is set with buffer region
        do while ((T_test .GT. max_pitch_angle).OR. &
             (T_test .LT. min_pitch_angle))
           if (T_test.lt.0) then
              T_test=abs(T_test)
              exit
           end if
           T_test = T_buffer + random_norm(0.0_rp,spp%dth)
        end do


        psi0=psi1
        f0=f1
        
        psi1=PSI_ROT(R_test,spp%Ro,spp%sigmaR,Z_test,spp%Zo, &
             spp%sigmaZ,theta_rad)

        f1=Spong_2D(spp%Ro,spp%Spong_b,spp%Spong_w,spp%Spong_dlam, &
             R_test,Z_test,T_test)
        
        ratio = indicator(psi1,psi_max_buff)*R_test*EXP(-psi1)*f1/ &
             (R_buffer*EXP(-psi0)*f0)

        if (ratio .GE. 1.0_rp) then
           R_buffer = R_test
           Z_buffer = Z_test
           T_buffer = T_test
        else
           call RANDOM_NUMBER(rand_unif)
           if (rand_unif .LT. ratio) then
              R_buffer = R_test
              Z_buffer = Z_test
              T_buffer = T_test
           end if
        end if
        
        ! Only accept sample if it is within desired boundary, but
        ! add to MC above if within buffer. This helps make the boundary
        ! more defined.
        IF ((INT(indicator(psi1,spp%psi_max)).EQ.1).AND. &
             (T_buffer.LE.spp%etao_lims(2)).AND. &
             (T_buffer.GE.spp%etao_lims(1))) THEN
           R_samples(ii) = R_buffer
           Z_samples(ii) = Z_buffer
           T_samples(ii) = T_buffer
           ! Sample phi location uniformly
           call RANDOM_NUMBER(rand_unif)
           PHI_samples(ii) = 2.0_rp*C_PI*rand_unif
           ii = ii + 1_idef 
        END IF

        
     end do

!  if (minval(R_samples(:)).lt.1._rp/params%cpp%length) stop 'error with sample'
!  write(output_unit_write,'("R_sample: ",E17.10)') R_samples(:)*params%cpp%length
  
  end if

  CALL MPI_SCATTER(R_samples*cos(PHI_samples),spp%ppp,MPI_REAL8, &
       spp%vars%X(:,1),spp%ppp,MPI_REAL8,0,MPI_COMM_WORLD,mpierr)
  CALL MPI_SCATTER(R_samples*sin(PHI_samples),spp%ppp,MPI_REAL8, &
       spp%vars%X(:,2),spp%ppp,MPI_REAL8,0,MPI_COMM_WORLD,mpierr)
  CALL MPI_SCATTER(Z_samples,spp%ppp,MPI_REAL8, &
       spp%vars%X(:,3),spp%ppp,MPI_REAL8,0,MPI_COMM_WORLD,mpierr)
!  CALL MPI_SCATTER(T_samples,spp%ppp,MPI_REAL8, &
!       spp%vars%eta,spp%ppp,MPI_REAL8,0,MPI_COMM_WORLD,mpierr)
  
  
  call MPI_BARRIER(MPI_COMM_WORLD,mpierr)

!  write(output_unit_write,'("X_X: ",E17.10)') spp%vars%X(:,1)*params%cpp%length
  
  ! gamma is kept for each particle, not the momentum

  if (params%orbit_model(1:2).eq.'GC') call cart_to_cyl(spp%vars%X,spp%vars%Y)

!  write(output_unit_write,'("Y_R: ",E17.10)') spp%vars%Y(:,1)*params%cpp%length
  
!  if (minval(spp%vars%Y(:,1)).lt.1._rp/params%cpp%length) stop 'error with avalanche'
  
  if (params%mpi_params%rank.EQ.0_idef) then
     DEALLOCATE(R_samples)
     DEALLOCATE(Z_samples)
     DEALLOCATE(PHI_samples)
     DEALLOCATE(T_samples)
  end if
  
  
end subroutine Spong_3D