Avalanche_4D Subroutine

private subroutine Avalanche_4D(params, spp, P, F)

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.

type(PROFILES), intent(in) :: P

An instance of the KORC derived type PROFILES.

type(FIELDS), intent(in) :: F

An instance of the KORC derived type FIELDS.


Calls

proc~~avalanche_4d~~CallsGraph proc~avalanche_4d Avalanche_4D proc~indicator~2 indicator proc~avalanche_4d->proc~indicator~2 mpi_barrier mpi_barrier proc~avalanche_4d->mpi_barrier proc~update_avalanche_params update_avalanche_params proc~avalanche_4d->proc~update_avalanche_params proc~get_profiles get_profiles proc~avalanche_4d->proc~get_profiles proc~fre~3 fRE proc~avalanche_4d->proc~fre~3 mpi_scatter mpi_scatter proc~avalanche_4d->mpi_scatter proc~random_norm~5 random_norm proc~avalanche_4d->proc~random_norm~5 proc~deg2rad~3 deg2rad proc~avalanche_4d->proc~deg2rad~3 proc~psi_rot~2 PSI_ROT proc~avalanche_4d->proc~psi_rot~2 proc~cart_to_cyl cart_to_cyl proc~get_profiles->proc~cart_to_cyl proc~get_analytical_profiles get_analytical_profiles proc~get_profiles->proc~get_analytical_profiles proc~uniform_profiles uniform_profiles proc~get_profiles->proc~uniform_profiles proc~cart_to_tor_check_if_confined cart_to_tor_check_if_confined proc~get_profiles->proc~cart_to_tor_check_if_confined proc~interp_profiles interp_profiles proc~get_profiles->proc~interp_profiles proc~cyl_to_cart cyl_to_cart proc~get_profiles->proc~cyl_to_cart proc~check_if_in_profiles_domain check_if_in_profiles_domain proc~interp_profiles->proc~check_if_in_profiles_domain proc~interp_3d_profiles interp_3D_profiles proc~interp_profiles->proc~interp_3d_profiles proc~korc_abort korc_abort proc~interp_profiles->proc~korc_abort proc~interp_2d_profiles interp_2D_profiles proc~interp_profiles->proc~interp_2d_profiles proc~get_fio_profile get_fio_profile proc~interp_profiles->proc~get_fio_profile ezspline_error ezspline_error proc~interp_3d_profiles->ezspline_error mpi_abort mpi_abort proc~korc_abort->mpi_abort proc~interp_2d_profiles->ezspline_error interface~fio_eval_field fio_eval_field proc~get_fio_profile->interface~fio_eval_field

Called by

proc~~avalanche_4d~~CalledByGraph proc~avalanche_4d Avalanche_4D proc~get_avalanche_4d get_Avalanche_4D proc~get_avalanche_4d->proc~avalanche_4d

Contents

Source Code


Source Code

subroutine Avalanche_4D(params,spp,P,F)
  !! @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.
  TYPE(PROFILES), INTENT(IN)            :: P
  !! An instance of the KORC derived type PROFILES.
  TYPE(FIELDS), INTENT(IN)                                   :: F
  !! 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 	:: P_samples
  !! Magnitude of momentum of all samples
  REAL(rp), DIMENSION(:), ALLOCATABLE 	:: T_samples
  !! Pitch angle of all samples
  REAL(rp), DIMENSION(:), ALLOCATABLE   :: mom
  !! Magnitude of momentum of samples on individual mpi process
  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
  REAL(rp) 				:: max_p
  !! Maximum domain for momentum sampling including buffer
  REAL(rp) 				:: min_p
  !! 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) 				:: P_buffer
  !! Previous sample of momentum
  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) 				:: P_test
  !! Present sample of momentum
  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) 				:: fRE0
  !! Evaluation of Avalanche distribution with previous sample
  REAL(rp) 				:: fRE1
  !! 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
  
  ALLOCATE(mom(spp%ppp))
  
  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 p boundary
  do ii=1_idef,INT(minmax_buffer_size,idef)
     minmax = aval_params%min_p - REAL(ii,rp)*(aval_params%max_p- &
       aval_params%min_p)/100_rp
     if (minmax.GT.0.0_rp) then
        min_p = minmax
     end if
  end do

  ! buffer at maximum p boundary
  max_p = aval_params%max_p + minmax_buffer_size*(aval_params%max_p- &
       aval_params%min_p)/100_rp

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

  ! buffer at maximum pitch angle boundary
  do ii=1_idef,INT(minmax_buffer_size,idef)
     minmax = aval_params%max_pitch_angle + REAL(ii,rp)* &
          (aval_params%max_pitch_angle-aval_params%min_pitch_angle)/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(P_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

     call RANDOM_NUMBER(rand_unif)
     P_buffer = min_p + (max_p - min_p)*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,aval_params%dR)
        Z_test = Z_buffer + random_norm(0.0_rp,aval_params%dZ)
        P_test = P_buffer + random_norm(0.0_rp,aval_params%dp)
        T_test = T_buffer + random_norm(0.0_rp,aval_params%dth)


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

        do while ((P_test.LT.aval_params%min_p).OR. &
             (P_test.GT.aval_params%max_p))
           P_test = P_buffer + random_norm(0.0_rp,aval_params%dp)
        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)

           ! Repetedly put location of sample into first entry of spp%vars%Y,
           ! beacause spp%vas%X isn't filled until the end of this subrouting.
           ! This allows us to use the machinery for calling PSPLINES
           ! interpolation routines here also.
           spp%vars%Y(1,1)=R_buffer
           spp%vars%Y(1,2)=0
           spp%vars%Y(1,3)=Z_buffer

           call get_profiles(params,spp%vars,P,F)          

!           write(output_unit_write,'("ne",E17.10)') spp%vars%ne(1)
!           write(output_unit_write,'("Te",E17.10)') spp%vars%Te(1)
!           write(output_unit_write,'("Zeff",E17.10)') spp%vars%Zeff(1)
           
           ! Update avalanche parameters with interpolated fields to be used
           ! in call to avalanche distribution function
           call update_avalanche_params(params,spp%vars)
           
           fRE0=fRE(cos(deg2rad(T_buffer)),P_buffer)          
        else
           psi0=psi1
           fRE0=fRE1
        end if
        
        psi1=PSI_ROT(R_test,spp%Ro,spp%sigmaR,Z_test,spp%Zo, &
             spp%sigmaZ,theta_rad)       
        
        spp%vars%Y(1,1)=R_test
        spp%vars%Y(1,2)=0
        spp%vars%Y(1,3)=Z_test
        
        call get_profiles(params,spp%vars,P,F)

        call update_avalanche_params(params,spp%vars)
        
        fRE1=fRE(COS(deg2rad(T_test)),P_test)

!        write(output_unit_write,'("psi0: ",E17.10)') psi0
!        write(output_unit_write,'("psi1: ",E17.10)') psi1
        
        ! 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)* &
             sin(deg2rad(T_test))*fRE1/(R_buffer*EXP(-psi0)* &
             sin(deg2rad(T_buffer))*fRE0)
        
        if (ratio .GE. 1.0_rp) then
           R_buffer = R_test
           Z_buffer = Z_test
           P_buffer = P_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
              P_buffer = P_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,aval_params%dR)
        Z_test = Z_buffer + random_norm(0.0_rp,aval_params%dZ)
        P_test = P_buffer + random_norm(0.0_rp,aval_params%dp)
        T_test = T_buffer + random_norm(0.0_rp,aval_params%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,aval_params%dth)
        end do

        do while ((P_test.LT.min_p).OR.(P_test.GT.max_p))
           if (P_test.lt.0) then
              P_test=abs(P_test)
              exit
           end if
           P_test = P_buffer + random_norm(0.0_rp,aval_params%dp)
        end do

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

        spp%vars%Y(1,1)=R_test
        spp%vars%Y(1,2)=0
        spp%vars%Y(1,3)=Z_test

        call get_profiles(params,spp%vars,P,F)

        call update_avalanche_params(params,spp%vars)
        
        fRE1=fRE(COS(deg2rad(T_test)),P_test)
        
        ratio = indicator(psi1,psi_max_buff)*R_test*EXP(-psi1)* &
             sin(deg2rad(T_test))*fRE1/(R_buffer*EXP(-psi0)* &
             sin(deg2rad(T_buffer))*fRE0)

        if (ratio .GE. 1.0_rp) then
           R_buffer = R_test
           Z_buffer = Z_test
           P_buffer = P_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
              P_buffer = P_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. &
             (P_buffer.LE.aval_params%max_p).AND. &
             (P_buffer.GE.aval_params%min_p).AND. &
             (T_buffer.LE.aval_params%max_pitch_angle).AND. &
             (T_buffer.GE.aval_params%min_pitch_angle)) THEN
           R_samples(ii) = R_buffer
           Z_samples(ii) = Z_buffer
           P_samples(ii) = P_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(P_samples,spp%ppp,MPI_REAL8, &
       mom,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
  spp%vars%g = SQRT(1.0_rp + mom**2)

  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'
  
  DEALLOCATE(mom)
  if (params%mpi_params%rank.EQ.0_idef) then
     DEALLOCATE(R_samples)
     DEALLOCATE(Z_samples)
     DEALLOCATE(PHI_samples)
     DEALLOCATE(P_samples)
     DEALLOCATE(T_samples)
  end if
  
  
end subroutine Avalanche_4D