583 lines
18 KiB
Fortran
583 lines
18 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
|
|
TYPE(table1D):: crossSec !cross section of collision
|
|
CONTAINS
|
|
PROCEDURE(collideBinary_interface), PASS, DEFERRED:: collide
|
|
|
|
END TYPE collisionBinary
|
|
|
|
ABSTRACT INTERFACE
|
|
SUBROUTINE collideBinary_interface(self, part_i, part_j, vRel)
|
|
USE moduleSpecies
|
|
IMPORT:: collisionBinary
|
|
|
|
CLASS(collisionBinary), INTENT(in):: self
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
REAL(8), INTENT(in):: vRel
|
|
|
|
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
|
|
CLASS(speciesCharged), POINTER:: electronSecondary !Pointer to species considerer as secondary electron
|
|
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
|
|
CLASS(speciesGeneric), POINTER:: sp_i
|
|
CLASS(speciesGeneric), POINTER:: sp_j
|
|
INTEGER:: amount
|
|
TYPE(collisionCont), ALLOCATABLE:: collisions(:)
|
|
CONTAINS
|
|
PROCEDURE, PASS:: init => initInteractionBinary
|
|
PROCEDURE, PASS:: getSigmaVrel => getSigmaVrelBinary
|
|
|
|
END TYPE interactionsBinary
|
|
|
|
!Type to count number of collisions
|
|
TYPE:: tallyCollisions
|
|
INTEGER, ALLOCATABLE:: tally(:)
|
|
|
|
END TYPE
|
|
|
|
!Number of collision pairs (nSpecies*(nSpecies+1)/2)
|
|
INTEGER:: nCollPairs = 0
|
|
!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):: cosXi, sinXi, eps
|
|
|
|
cosXi = random(-1.D0, 1.D0)
|
|
sinXi = DSQRT(1.D0 - cosXi**2)
|
|
eps = random(0.D0, PI2)
|
|
|
|
n = (/ cosXi, sinXi*DCOS(eps), sinXi*DSIN(eps) /)
|
|
|
|
END FUNCTION randomDirectionVHS
|
|
|
|
!Inits the interaction matrix
|
|
SUBROUTINE initInteractionMatrix(matrix)
|
|
USE moduleSpecies
|
|
IMPLICIT NONE
|
|
|
|
TYPE(interactionsBinary), INTENT(inout), ALLOCATABLE:: matrix(:)
|
|
|
|
nCollPairs = (nSpecies*(nSpecies+1))/2
|
|
ALLOCATE(matrix(1:nCollPairs))
|
|
|
|
matrix(:)%amount = 0
|
|
|
|
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, i, j)
|
|
USE moduleMath
|
|
USE moduleSpecies
|
|
IMPLICIT NONE
|
|
|
|
CLASS(interactionsBinary), INTENT(inout):: self
|
|
INTEGER, INTENT(in):: amount
|
|
INTEGER, INTENT(in):: i, j
|
|
REAL(8):: mass_i, mass_j
|
|
|
|
self%sp_i => species(i)%obj
|
|
self%sp_j => species(j)%obj
|
|
|
|
self%amount = amount
|
|
|
|
mass_i = species(i)%obj%m
|
|
mass_j = species(j)%obj%m
|
|
|
|
ALLOCATE(self%collisions(1:self%amount))
|
|
|
|
END SUBROUTINE initInteractionBinary
|
|
|
|
SUBROUTINE getSigmaVrelBinary (self, vRel, eRel, sigmaVrelTotal, sigmaVrel)
|
|
IMPLICIT NONE
|
|
|
|
CLASS(interactionsBinary), INTENT(in):: self
|
|
REAL(8), INTENT(in):: vRel, eRel
|
|
REAL(8), INTENT(out):: sigmaVrelTotal
|
|
REAL(8), INTENT(out), ALLOCATABLE:: sigmaVrel(:)
|
|
INTEGER:: c
|
|
|
|
sigmaVrelTotal = 0.D0
|
|
|
|
ALLOCATE(sigmaVrel(1:self%amount))
|
|
|
|
DO c = 1, self%amount
|
|
sigmaVrel(c) = self%collisions(c)%obj%crossSec%get(eRel)*vRel
|
|
|
|
END DO
|
|
sigmaVrelTotal = SUM(sigmaVrel)
|
|
|
|
END SUBROUTINE getSigmaVrelBinary
|
|
|
|
!ELASTIC COLLISIONS
|
|
!Inits binary elastic collision
|
|
SUBROUTINE initBinaryElastic(collision, crossSectionFilename)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
|
|
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)
|
|
|
|
END SUBROUTINE initBinaryElastic
|
|
|
|
!Binary elastic process
|
|
SUBROUTINE collideBinaryElastic(self, part_i, part_j, vRel)
|
|
USE moduleSpecies
|
|
USE moduleConstParam
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryElastic), INTENT(in):: self
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
REAL(8), INTENT(in):: vRel
|
|
REAL(8):: m_i, m_j
|
|
REAL(8), DIMENSION(1:3):: vCM, vp
|
|
|
|
m_i = part_i%species%m
|
|
m_j = part_j%species%m
|
|
!Applies the collision
|
|
vCM = velocityCM(part_i%weight*m_i, part_i%v, part_j%weight*m_j, part_j%v)
|
|
vp = vRel*randomDirectionVHS()
|
|
|
|
!Assign velocities to particles
|
|
part_i%v = vCM + m_j*vp / (m_i + m_j)
|
|
part_j%v = vCM - m_i*vp / (m_i + m_j)
|
|
|
|
END SUBROUTINE collideBinaryElastic
|
|
|
|
!ELECTRON IMPACT IONIZATION
|
|
!Inits electron impact ionization
|
|
SUBROUTINE initBinaryIonization(collision, crossSectionFilename, energyThreshold, electron, electronSecondary)
|
|
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
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: electron
|
|
CHARACTER(:), ALLOCATABLE, OPTIONAL, INTENT(in):: electronSecondary
|
|
INTEGER:: electronIndex, electronSecondaryIndex
|
|
|
|
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)
|
|
|
|
!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)
|
|
!species for impacting electron
|
|
electronIndex = speciesName2Index(electron)
|
|
SELECT TYPE(sp => species(electronIndex)%obj)
|
|
TYPE IS(speciesCharged)
|
|
collision%electron => sp
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError("Species " // sp%name // " chosen for " // &
|
|
"impacting electron is not a charged species", 'initBinaryIonization')
|
|
|
|
END SELECT
|
|
|
|
IF (PRESENT(electronSecondary)) THEN
|
|
electronSecondaryIndex = speciesName2Index(electronSecondary)
|
|
SELECT TYPE(sp => species(electronSecondaryIndex)%obj)
|
|
TYPE IS(speciesCharged)
|
|
collision%electronSecondary => sp
|
|
|
|
CLASS DEFAULT
|
|
CALL criticalError("Species " // sp%name // " chosen for " // &
|
|
"secondary electron is not a charged species", 'initBinaryIonization')
|
|
|
|
END SELECT
|
|
|
|
ELSE
|
|
collision%electronSecondary => NULL()
|
|
|
|
END IF
|
|
|
|
!momentum change per ionization process
|
|
collision%deltaV = sqrt(collision%eThreshold / collision%electron%m)
|
|
|
|
END SELECT
|
|
|
|
END SUBROUTINE initBinaryIonization
|
|
|
|
!Binary electron impact ionization process
|
|
SUBROUTINE collideBinaryIonization(self, part_i, part_j, vRel)
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
USE moduleList
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
USE OMP_LIB
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryIonization), INTENT(in):: self
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
REAL(8), INTENT(in):: vRel
|
|
REAL(8):: rMass, eRel
|
|
TYPE(particle), POINTER:: electron => NULL(), neutral => NULL()
|
|
REAL(8), DIMENSION(1:3):: vChange
|
|
TYPE(particle), POINTER:: newElectron => NULL(), remainingNeutral => NULL()
|
|
|
|
rMass = reducedMass(part_i%weight*part_i%species%m, part_j%weight*part_j%species%m)
|
|
eRel = rMass*vRel**2
|
|
!Relative energy must be higher than threshold
|
|
IF (eRel > self%eThreshold) THEN
|
|
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 of velocity between particles
|
|
vChange = self%deltaV*randomDirectionVHS()
|
|
|
|
!Energy is loss by the primary electron
|
|
electron%v = electron%v - vChange
|
|
|
|
!Creates a new electron from ionization
|
|
ALLOCATE(newElectron)
|
|
|
|
!Copy basic information from primary electron
|
|
newElectron = electron
|
|
|
|
!If secondary electron species indicates, convert
|
|
IF (ASSOCIATED(self%electronSecondary)) THEN
|
|
newElectron%species => self%electronSecondary
|
|
|
|
END IF
|
|
|
|
!Secondary electorn gains energy from ionization
|
|
newElectron%v = vChange
|
|
|
|
!Correct the weight of the particles
|
|
IF (electron%weight >= neutral%weight) THEN
|
|
!If primary electron is hevier than neutral, reduce weight to secondary electron
|
|
newElectron%weight = neutral%weight
|
|
|
|
ELSEIF (electron%weight < neutral%weight) THEN
|
|
!If primary electron is ligther than neutral, change weight of neutral and create new neutral
|
|
ALLOCATE(remainingNeutral)
|
|
|
|
remainingNeutral = neutral
|
|
|
|
remainingNeutral%weight = neutral%weight - electron%weight
|
|
|
|
neutral%weight = electron%weight
|
|
|
|
END IF
|
|
|
|
!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')
|
|
RETURN
|
|
|
|
END SELECT
|
|
|
|
!Adds new particles to the list
|
|
CALL partCollisions%setLock()
|
|
CALL partCollisions%add(newElectron)
|
|
IF (ASSOCIATED(remainingNeutral)) THEN
|
|
CALL partCollisions%add(remainingNeutral)
|
|
|
|
END IF
|
|
CALL partCollisions%unsetLock()
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryIonization
|
|
|
|
!ELECTRON ION RESONANT RECOMBINATION
|
|
!Inits electron ion recombination
|
|
SUBROUTINE initBinaryRecombination(collision, crossSectionFilename, energyBinding, 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
|
|
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)
|
|
|
|
!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 recombination is not a charged species", &
|
|
'initBinaryRecombination')
|
|
|
|
END SELECT
|
|
|
|
END SELECT
|
|
|
|
END SUBROUTINE initBinaryRecombination
|
|
|
|
!Binary recombination
|
|
SUBROUTINE collideBinaryRecombination(self, part_i, part_j, vRel)
|
|
USE moduleSpecies
|
|
USE moduleErrors
|
|
USE moduleList
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryRecombination), INTENT(in):: self
|
|
REAL(8), INTENT(in):: vRel
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
TYPE(particle), POINTER:: electron => NULL(), ion => NULL()
|
|
REAL(8), DIMENSION(1:3):: vp_i
|
|
TYPE(particle), POINTER:: remainingIon => NULL()
|
|
|
|
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))
|
|
|
|
IF (electron%weight > ion%weight) THEN
|
|
!Reduce weight of primary electron but particle continues
|
|
electron%weight = electron%weight - ion%weight
|
|
|
|
ELSE
|
|
!Remove electron from simulation
|
|
electron%n_in = .FALSE.
|
|
|
|
!There is some ion remaining
|
|
IF (electron%weight < ion%weight) THEN
|
|
ALLOCATE(remainingIon)
|
|
|
|
remainingIon = ion
|
|
|
|
remainingIon%weight = ion%weight - electron%weight
|
|
|
|
ion%weight = electron%weight
|
|
|
|
END IF
|
|
|
|
END IF
|
|
|
|
!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
|
|
|
|
!Adds new particles to the list
|
|
IF (ASSOCIATED(remainingIon)) THEN
|
|
CALL partCollisions%setLock()
|
|
CALL partCollisions%add(remainingIon)
|
|
CALL partCollisions%unsetLock()
|
|
END IF
|
|
|
|
END SUBROUTINE collideBinaryRecombination
|
|
|
|
!RESONANT CHARGE EXCHANGE
|
|
!Inits resonant charge exchange
|
|
SUBROUTINE initBinaryChargeExchange(collision, crossSectionFilename)
|
|
USE moduleTable
|
|
USE moduleRefParam
|
|
USE moduleConstParam
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinary), INTENT(out), ALLOCATABLE:: collision
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSectionFilename
|
|
|
|
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)
|
|
|
|
END SUBROUTINE initBinaryChargeExchange
|
|
|
|
SUBROUTINE collideBinaryChargeExchange(self, part_i, part_j, vRel)
|
|
USE moduleSpecies
|
|
USE moduleRandom
|
|
USE moduleMath
|
|
IMPLICIT NONE
|
|
|
|
CLASS(collisionBinaryChargeExchange), INTENT(in):: self
|
|
REAL(8), INTENT(in):: vRel ! NOTE: Required by itnerface but unused
|
|
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
|
|
|
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 SUBROUTINE collideBinaryChargeExchange
|
|
|
|
END MODULE moduleCollisions
|