A new option has been added in which MCC are computed with its own time step. If no time is provided, then the minimum time step of the simulation is employed.
536 lines
17 KiB
Fortran
536 lines
17 KiB
Fortran
MODULE moduleCollisions
|
|
USE moduleSpecies
|
|
USE moduleTable
|
|
|
|
!Integer for when collisions are computed
|
|
INTEGER:: everyColl
|
|
|
|
!Abstract type for collision between two particles
|
|
TYPE, ABSTRACT:: collisionBinary
|
|
REAL(8):: rMass !Reduced mass
|
|
REAL(8):: sMassInv !Summed mass
|
|
TYPE(table1D):: crossSec !cross section of collision
|
|
CONTAINS
|
|
PROCEDURE(collideBinary_interface), PASS, DEFERRED:: collide
|
|
|
|
END TYPE collisionBinary
|
|
|
|
ABSTRACT INTERFACE
|
|
SUBROUTINE collideBinary_interface(self, sigmaVRelMax, sigmaVrelMaxNew, part_i, part_j)
|
|
USE moduleSpecies
|
|
IMPORT:: collisionBinary
|
|
|
|
CLASS(collisionBinary), INTENT(in):: self
|
|
REAL(8), INTENT(in):: sigmaVrelMax
|
|
REAL(8), INTENT(inout):: sigmaVrelMaxNew
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
|
|
END SUBROUTINE
|
|
|
|
END INTERFACE
|
|
|
|
!Container for binary collisions
|
|
TYPE:: collisionCont
|
|
CLASS(collisionBinary), ALLOCATABLE:: obj
|
|
|
|
END TYPE collisionCont
|
|
|
|
!Binary elastic interaction
|
|
TYPE, EXTENDS(collisionBinary):: collisionBinaryElastic
|
|
CONTAINS
|
|
PROCEDURE, PASS:: collide => collideBinaryElastic
|
|
|
|
END TYPE collisionBinaryElastic
|
|
|
|
!Ionization binary interaction
|
|
TYPE, EXTENDS(collisionBinary):: collisionBinaryIonization
|
|
REAL(8):: eThreshold !Minimum energy (non-dimensional units) required for ionization
|
|
REAL(8):: deltaV !Change in velocity due to exchange of eThreshold
|
|
CLASS(speciesCharged), POINTER:: electron !Pointer to species considerer as electrons
|
|
CONTAINS
|
|
PROCEDURE, PASS:: collide => collideBinaryIonization
|
|
|
|
END TYPE collisionBinaryIonization
|
|
|
|
TYPE, EXTENDS(collisionBinary):: collisionBinaryRecombination
|
|
REAL(8):: eBinding !binding energy of free electron in recombining ion
|
|
REAL(8):: deltaV !Change in velocity due to energy exchange
|
|
CLASS(speciesCharged), POINTER:: electron !Pointer to species considerer as electrons
|
|
CONTAINS
|
|
PROCEDURE, PASS:: collide => collideBinaryRecombination
|
|
|
|
END TYPE collisionBinaryRecombination
|
|
|
|
!Resonant charge-exchange
|
|
TYPE, EXTENDS(collisionBinary):: collisionBinaryChargeExchange
|
|
CONTAINS
|
|
PROCEDURE, PASS:: collide => collideBinaryChargeExchange
|
|
|
|
END TYPE collisionBinaryChargeExchange
|
|
|
|
!Type for interaction matrix
|
|
TYPE:: interactionsBinary
|
|
INTEGER:: amount
|
|
TYPE(collisionCont), ALLOCATABLE:: collisions(:)
|
|
CONTAINS
|
|
PROCEDURE, PASS:: init => initInteractionBinary
|
|
|
|
END TYPE interactionsBinary
|
|
|
|
!Collision 'Matrix'. A symmetric 2D matrix put into a 1D array to save memory
|
|
TYPE(interactionsBinary), ALLOCATABLE, TARGET:: interactionMatrix(:)
|
|
!Folder for collision cross section tables
|
|
CHARACTER(:), ALLOCATABLE:: pathCollisions
|
|
|
|
CONTAINS
|
|
!Velocity of center of mass of two particles
|
|
PURE FUNCTION velocityCM(m_i, v_i, m_j, v_j) RESULT(vCM)
|
|
IMPLICIT NONE
|
|
|
|
REAL(8), INTENT(in):: m_i, m_j
|
|
REAL(8), INTENT(in), DIMENSION(1:3):: v_i, v_j
|
|
REAL(8):: vCM(1:3)
|
|
|
|
vCM = (m_i*v_i + m_j*v_j)/(m_i + m_j)
|
|
|
|
END FUNCTION velocityCM
|
|
|
|
!Random direction for hard sphere collisions
|
|
FUNCTION randomDirectionVHS() RESULT(n)
|
|
USE moduleConstParam
|
|
USE moduleRandom
|
|
IMPLICIT NONE
|
|
|
|
REAL(8):: n(1:3)
|
|
REAL(8):: cosXii, sinXii, eps
|
|
|
|
cosXii = random(-1.D0, 1.D0)
|
|
sinXii = DSQRT(1.D0 - cosXii**2)
|
|
eps = random(0.D0, PI2)
|
|
|
|
n = (/ cosXii, sinXii*DCOS(eps), sinXii*DSIN(eps) /)
|
|
|
|
END FUNCTION randomDirectionVHS
|
|
|
|
!Inits the interaction matrix
|
|
SUBROUTINE initInteractionMatrix(interactionMatrix)
|
|
USE moduleSpecies
|
|
IMPLICIT NONE
|
|
|
|
TYPE(interactionsBinary), INTENT(inout), ALLOCATABLE:: interactionMatrix(:)
|
|
INTEGER:: nInteractions
|
|
|
|
nInteractions = (nSpecies*(nSpecies+1))/2
|
|
ALLOCATE(interactionMatrix(1:nInteractions))
|
|
|
|
END SUBROUTINE initInteractionMatrix
|
|
|
|
!Gets the interaction index from the collision matrix from index i,j
|
|
FUNCTION interactionIndex(i,j) RESULT(k)
|
|
|
|
INTEGER:: i, j
|
|
INTEGER:: p
|
|
INTEGER:: k
|
|
|
|
k = i + j
|
|
p = (k + ABS(i - j))/2
|
|
k = k + (p*(p-3))/2
|
|
|
|
END FUNCTION interactionIndex
|
|
|
|
!Inits the binary interaction
|
|
SUBROUTINE initInteractionBinary(self, amount)
|
|
IMPLICIT NONE
|
|
|
|
CLASS(interactionsBinary), INTENT(inout):: self
|
|
INTEGER, INTENT(in):: amount
|
|
|
|
self%amount = amount
|
|
|
|
ALLOCATE(self%collisions(1:self%amount))
|
|
|
|
END SUBROUTINE initInteractionBinary
|
|
|
|
!ELASTIC COLLISIONS
|
|
!Inits binary elastic collision
|
|
SUBROUTINE initBinaryElastic(collision, crossSectionFilename, mass_i, mass_j)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
REAL(8), INTENT(in):: mass_i, mass_j
|
|
|
|
ALLOCATE(collisionBinaryElastic:: collision)
|
|
|
|
!Reads data from file
|
|
CALL collision%crossSec%init(crossSectionFilename)
|
|
|
|
!Convert to no-dimensional units
|
|
CALL collision%crossSec%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
|
|
|
!Calculates reduced mass
|
|
collision%sMassInv = 1.D0/(mass_i+mass_j)
|
|
collision%rMass = (mass_i*mass_j)*collision%sMassInv
|
|
|
|
END SUBROUTINE initBinaryElastic
|
|
|
|
!Binary elastic process
|
|
SUBROUTINE collideBinaryElastic(self, sigmaVrelMax, sigmaVrelMaxNew, &
|
|
part_i, part_j)
|
|
USE moduleSpecies
|
|
USE moduleConstParam
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryElastic), INTENT(in):: self
|
|
REAL(8), INTENT(in):: sigmaVrelMax
|
|
REAL(8), INTENT(inout):: sigmaVrelMaxNew
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
REAL(8):: sigmaVrel
|
|
REAL(8):: vRel !relative velocity
|
|
REAL(8):: eRel !relative energy
|
|
REAL(8):: m_i, m_j
|
|
REAL(8), DIMENSION(1:3):: vCM
|
|
REAL(8):: vp(1:3)
|
|
|
|
vRel = NORM2(part_i%v-part_j%v)
|
|
eRel = self%rMass*vRel**2
|
|
sigmaVrel = self%crossSec%get(eRel)*vRel
|
|
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
|
|
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
|
|
m_i = part_i%species%m
|
|
m_j = part_j%species%m
|
|
!Applies the collision
|
|
vCM = velocityCM(m_i, part_i%v, m_j, part_j%v)
|
|
vp = vRel*randomDirectionVHS()
|
|
|
|
!Assign velocities to particles
|
|
part_i%v = vCM + m_j*vp*self%sMassInv
|
|
part_j%v = vCM - m_i*vp*self%sMassInv
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryElastic
|
|
|
|
!ELECTRON IMPACT IONIZATION
|
|
!Inits electron impact ionization
|
|
SUBROUTINE initBinaryIonization(collision, crossSectionFilename, energyThreshold, mass_i, mass_j, electron)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
REAL(8), INTENT(in):: energyThreshold
|
|
REAL(8), INTENT(in):: mass_i, mass_j
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: electron
|
|
INTEGER:: electronIndex
|
|
|
|
ALLOCATE(collisionBinaryIonization:: collision)
|
|
|
|
!Reads data from file
|
|
CALL collision%crossSec%init(crossSectionFilename)
|
|
|
|
!Convert to no-dimensional units
|
|
CALL collision%crossSec%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
|
|
|
!Calculates reduced mass
|
|
collision%sMassInv = 1.D0/(mass_i+mass_j)
|
|
collision%rMass = (mass_i*mass_j)*collision%sMassInv
|
|
|
|
!Specific parameters for ionization collision
|
|
SELECT TYPE(collision)
|
|
TYPE IS(collisionBinaryIonization)
|
|
!Assign the energy threshold
|
|
!Input energy is in eV. Convert to J with ev2J and then to
|
|
!non-dimensional units.
|
|
collision%eThreshold = energyThreshold*eV2J/(m_ref*v_ref**2)
|
|
electronIndex = speciesName2Index(electron)
|
|
SELECT TYPE(sp => species(electronIndex)%obj)
|
|
TYPE IS(speciesCharged)
|
|
collision%electron => sp
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError("Species " // sp%name // " chosen for ionization is not a charged species", 'initBinaryIonization')
|
|
|
|
END SELECT
|
|
|
|
END SELECT
|
|
|
|
END SUBROUTINE initBinaryIonization
|
|
|
|
!Binary electron impact ionization process
|
|
SUBROUTINE collideBinaryIonization(self, sigmaVrelMax, sigmaVrelMaxNew, &
|
|
part_i, part_j)
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
USE moduleList
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
USE OMP_LIB
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryIonization), INTENT(in):: self
|
|
REAL(8), INTENT(in):: sigmaVrelMax
|
|
REAL(8), INTENT(inout):: sigmaVrelMaxNew
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
TYPE(particle), POINTER:: electron => NULL(), neutral => NULL()
|
|
TYPE(particle), POINTER:: newElectron
|
|
REAL(8):: vRel, eRel
|
|
REAL(8):: sigmaVrel
|
|
REAL(8), DIMENSION(1:3):: vp_e, vp_n
|
|
|
|
!eRel (in units of [m][L]^2[t]^-2
|
|
vRel = NORM2(part_i%v-part_j%v)
|
|
eRel = self%rMass*vRel**2
|
|
!Relative energy must be higher than threshold
|
|
IF (eRel > self%eThreshold) THEN
|
|
sigmaVrel = self%crossSec%get(eRel)*vRel
|
|
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
|
|
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
|
|
!Find which particle is the ionizing electron
|
|
IF (ASSOCIATED(part_i%species, self%electron)) THEN
|
|
electron => part_i
|
|
neutral => part_j
|
|
|
|
ELSEIF(ASSOCIATED(part_j%species, self%electron)) THEN
|
|
electron => part_j
|
|
neutral => part_i
|
|
|
|
ELSE
|
|
CALL criticalError("No matching between input particles and ionizing species", 'collideBinaryIonization')
|
|
|
|
END IF
|
|
|
|
!Exchange energy between
|
|
vp_e = electron%v*(1.D0 - self%deltaV/NORM2(electron%v))
|
|
vp_n = neutral%v* (1.D0 + self%deltaV/NORM2(neutral%v) )
|
|
|
|
!Changes velocity of impacting electron
|
|
electron%v = vp_e
|
|
|
|
!Creates a new electron from ionization
|
|
ALLOCATE(newElectron)
|
|
newElectron%species => electron%species
|
|
newElectron%v = vp_n
|
|
newElectron%r = neutral%r
|
|
newElectron%xi = neutral%xi
|
|
newElectron%n_in = .TRUE.
|
|
newElectron%vol = neutral%vol
|
|
newElectron%volColl = neutral%volColl
|
|
newElectron%weight = neutral%weight
|
|
newElectron%qm = electron%qm
|
|
|
|
!Ionize neutral particle
|
|
SELECT TYPE(sp => neutral%species)
|
|
TYPE IS(speciesNeutral)
|
|
CALL sp%ionize(neutral)
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError(sp%name // " is not a neutral", 'collideBinaryIonization')
|
|
|
|
END SELECT
|
|
|
|
!Adds new electron to list of new particles from collisions
|
|
CALL OMP_SET_LOCK(lockCollisions)
|
|
CALL partCollisions%add(newElectron)
|
|
CALL OMP_UNSET_LOCK(lockCollisions)
|
|
|
|
END IF
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryIonization
|
|
|
|
!ELECTRON ION RESONANT RECOMBINATION
|
|
!Inits electron ion recombination
|
|
SUBROUTINE initBinaryRecombination(collision, crossSectionFilename, energyBinding, mass_i, mass_j, electron)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
REAL(8), INTENT(in):: energyBinding
|
|
REAL(8), INTENT(in):: mass_i, mass_j
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: electron
|
|
INTEGER:: electronIndex
|
|
|
|
ALLOCATE(collisionBinaryRecombination:: collision)
|
|
|
|
!Reads data from file
|
|
CALL collision%crossSec%init(crossSectionFilename)
|
|
|
|
!Convert to no-dimensional units
|
|
CALL collision%crossSec%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
|
|
|
!Calculates reduced mass
|
|
collision%sMassInv = 1.D0/(mass_i+mass_j)
|
|
collision%rMass = (mass_i*mass_j)*collision%sMassInv
|
|
|
|
!Specific parameters for ionization collision
|
|
SELECT TYPE(collision)
|
|
TYPE IS(collisionBinaryRecombination)
|
|
!Assign the energy threshold
|
|
!Input energy is in eV. Convert to J with ev2J and then to
|
|
!non-dimensional units.
|
|
collision%eBinding = energyBinding*eV2J/(m_ref*v_ref**2)
|
|
electronIndex = speciesName2Index(electron)
|
|
SELECT TYPE(sp => species(electronIndex)%obj)
|
|
TYPE IS(speciesCharged)
|
|
collision%electron => sp
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError("Species " // sp%name // " chosen for ionization is not a charged species", 'initBinaryIonization')
|
|
|
|
END SELECT
|
|
|
|
END SELECT
|
|
|
|
END SUBROUTINE initBinaryRecombination
|
|
|
|
!Binary electron impact ionization process
|
|
SUBROUTINE collideBinaryRecombination(self, sigmaVrelMax, sigmaVrelMaxNew, &
|
|
part_i, part_j)
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
USE moduleList
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryRecombination), INTENT(in):: self
|
|
REAL(8), INTENT(in):: sigmaVrelMax
|
|
REAL(8), INTENT(inout):: sigmaVrelMaxNew
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
TYPE(particle), POINTER:: electron => NULL(), ion => NULL()
|
|
REAL(8):: vRel, eRel
|
|
REAL(8):: sigmaVrel
|
|
REAL(8), DIMENSION(1:3):: vp_i
|
|
|
|
!eRel (in units of [m][L]^2[t]^-2
|
|
vRel = NORM2(part_i%v-part_j%v)
|
|
eRel = self%rMass*vRel**2
|
|
!Relative energy must be higher than threshold
|
|
sigmaVrel = self%crossSec%get(eRel)*vRel
|
|
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
|
|
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
|
|
!Find which particle is the ionizing electron
|
|
IF (ASSOCIATED(part_i%species, self%electron)) THEN
|
|
electron => part_i
|
|
ion => part_j
|
|
|
|
ELSEIF(ASSOCIATED(part_j%species, self%electron)) THEN
|
|
electron => part_j
|
|
ion => part_i
|
|
|
|
ELSE
|
|
CALL criticalError("No matching between input particles and ionizing species", 'collideBinaryIonization')
|
|
|
|
END IF
|
|
|
|
!Excess energy
|
|
!TODO: This energy should be transformed into photons
|
|
vp_i = ion%v* (1.D0 - (vRel + self%deltaV)/NORM2(ion%v))
|
|
|
|
!Remove electron from simulation
|
|
electron%n_in = .FALSE.
|
|
|
|
!Neutralize ion particle
|
|
SELECT TYPE(sp => ion%species)
|
|
TYPE IS(speciesCharged)
|
|
CALL sp%neutralize(ion)
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError(sp%name // " is not a charge", 'collideBinaryRecombination')
|
|
|
|
END SELECT
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryRecombination
|
|
|
|
!RESONANT CHARGE EXCHANGE
|
|
!Inits resonant charge exchange
|
|
SUBROUTINE initBinaryChargeExchange(collision, crossSectionFilename, mass_i, mass_j)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
REAL(8), INTENT(in):: mass_i, mass_j
|
|
|
|
ALLOCATE(collisionBinaryChargeExchange:: collision)
|
|
|
|
!Reads data from file
|
|
CALL collision%crossSec%init(crossSectionFilename)
|
|
|
|
!Convert to no-dimensional units
|
|
CALL collision%crossSec%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
|
|
|
!Calculates reduced mass
|
|
collision%sMassInv = 1.D0/(mass_i+mass_j)
|
|
collision%rMass = (mass_i*mass_j)/collision%sMassInv
|
|
|
|
END SUBROUTINE initBinaryChargeExchange
|
|
|
|
SUBROUTINE collideBinaryChargeExchange(self, sigmaVrelMax, sigmaVrelMaxNew, &
|
|
part_i, part_j)
|
|
USE moduleSpecies
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryChargeExchange), INTENT(in):: self
|
|
REAL(8), INTENT(in):: sigmaVrelMax
|
|
REAL(8), INTENT(inout):: sigmaVrelMaxNew
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
REAL(8):: sigmaVrel
|
|
REAL(8):: vRel !relative velocity
|
|
REAL(8):: eRel !relative energy
|
|
|
|
!eRel (in units of [m][L]^2[t]^-2
|
|
vRel = NORM2(part_i%v-part_j%v)
|
|
eRel = self%rMass*vRel**2
|
|
sigmaVrel = self%crossSec%get(eRel)*vRel
|
|
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
|
|
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
|
|
SELECT TYPE(sp => part_i%species)
|
|
TYPE IS (speciesNeutral)
|
|
!Species i is neutral, ionize particle i
|
|
CALL sp%ionize(part_i)
|
|
|
|
TYPE IS (speciesCharged)
|
|
!Species i is charged, neutralize particle i
|
|
CALL sp%neutralize(part_i)
|
|
|
|
END SELECT
|
|
|
|
SELECT TYPE(sp => part_j%species)
|
|
TYPE IS (speciesNeutral)
|
|
!Species j is neutral, ionize particle j
|
|
CALL sp%ionize(part_j)
|
|
|
|
TYPE IS (speciesCharged)
|
|
!Species j is charged, neutralize particle j
|
|
CALL sp%neutralize(part_j)
|
|
|
|
END SELECT
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryChargeExchange
|
|
|
|
END MODULE moduleCollisions
|