fpakc/src/modules/moduleCollisions.f90
Jorge Gonzalez ac2965621a Structure for 3D Cartesian Grid created.
Unification of boundary conditions into one file.

Some changes to input file for reference cases. This should have been
done in another branch but I wanto to commit to save progress and I
don't want to deal with tswitching branches right now, I'm very busy
watching Futurama.
2021-02-27 16:24:44 +01:00

530 lines
17 KiB
Fortran

MODULE moduleCollisions
USE moduleSpecies
USE moduleTable
!Abstract type for collision between two particles
TYPE, ABSTRACT:: collisionBinary
REAL(8):: rMass !Reduced mass
REAL(8):: sMass !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%sMass = mass_i+mass_j
collision%rMass = (mass_i*mass_j)/collision%sMass
END SUBROUTINE initBinaryElastic
!Binary elastic process
SUBROUTINE collideBinaryElastic(self, sigmaVrelMax, sigmaVrelMaxNew, &
part_i, part_j)
USE moduleSpecies
USE moduleConstParam
USE moduleRandom
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)
!eRel (in units of [m][L]^2[t]^-2
vRel = SUM(DABS(part_i%v-part_j%v)) !TODO make function of norm1
eRel = self%rMass*vRel**2
sigmaVrel = self%crossSec%get(eRel)*vRel
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
m_i = species(part_i%sp)%obj%m
m_j = species(part_j%sp)%obj%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%sMass
part_j%v = vCM - m_i*vp/self%sMass
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%sMass = mass_i+mass_j
collision%rMass = (mass_i*mass_j)/collision%sMass
!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 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 = SUM(DABS(part_i%v-part_j%v)) !TODO make function of norm1
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 (part_i%sp == self%electron%sp) THEN
electron => part_i
neutral => part_j
ELSEIF(part_j%sp == self%electron%sp) 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%sp = electron%sp
newElectron%v = vp_n
newElectron%r = neutral%r
newElectron%xi = neutral%xi
newElectron%n_in = .TRUE.
newElectron%vol = neutral%vol
newElectron%weight = neutral%weight
newElectron%qm = electron%qm
!Ionize neutral particle
SELECT TYPE(sp => species(neutral%sp)%obj)
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%sMass = mass_i+mass_j
collision%rMass = (mass_i*mass_j)/collision%sMass
!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 OMP_LIB
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 = SUM(DABS(part_i%v-part_j%v)) !TODO make function of norm1
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 (part_i%sp == self%electron%sp) THEN
electron => part_i
ion => part_j
ELSEIF(part_j%sp == self%electron%sp) 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 => species(ion%sp)%obj)
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%sMass = mass_i+mass_j
collision%rMass = (mass_i*mass_j)/collision%sMass
END SUBROUTINE initBinaryChargeExchange
SUBROUTINE collideBinaryChargeExchange(self, sigmaVrelMax, sigmaVrelMaxNew, &
part_i, part_j)
USE moduleSpecies
USE moduleRandom
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 = SUM(DABS(part_i%v-part_j%v)) !TODO make function of norm1
eRel = self%rMass*vRel**2
sigmaVrel = self%crossSec%get(eRel)*vRel
sigmaVrelMaxNew = sigmaVrelMaxNew + sigmaVrel
IF (sigmaVrelMaxNew/sigmaVrelMax > random()) THEN
SELECT TYPE(sp => species(part_i%sp)%obj)
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 => species(part_j%sp)%obj)
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