Merge branch 'feature/collisionPairs' into feature/electromagnetic

Merging branches and fixing a number of important issues:

- Initial particles were not being assigned to the list of particles.

- List of particles was being erased every iteration, even if species
  was not pushed.

These caused issues with the calculation of collisions when a species
was frozen.

Now, things should work properly. All particles are properly added to
the volume list and the list is erased ONLY if the species has been
updated.

I hope that collisions are now properly accounted for per species pair.
This commit is contained in:
Jorge Gonzalez 2022-04-23 20:48:34 +02:00
commit cbb5fe0bf2
12 changed files with 179 additions and 81 deletions

View file

@ -152,13 +152,13 @@ MODULE moduleMesh
!Volume
REAL(8):: volume = 0.D0
!List of particles inside the volume
TYPE(listNode):: listPart_in
TYPE(listNode), ALLOCATABLE:: listPart_in(:)
!Lock indicator for listPart_in
INTEGER(KIND=OMP_LOCK_KIND):: lock
!Number of collisions per volume
INTEGER:: nColl = 0
!Total weight of particles inside cell
REAL(8):: totalWeight = 0.D0
REAL(8), ALLOCATABLE:: totalWeight(:)
CONTAINS
PROCEDURE(initVol_interface), DEFERRED, PASS:: init
PROCEDURE(getNodesVol_interface), DEFERRED, PASS:: getNodes
@ -516,6 +516,7 @@ MODULE moduleMesh
CLASS(meshVol), OPTIONAL, INTENT(in):: oldCell
REAL(8):: xi(1:3)
CLASS(meshElement), POINTER:: nextElement
INTEGER:: sp
xi = self%phy2log(part%r)
!Checks if particle is inside 'self' cell
@ -525,8 +526,9 @@ MODULE moduleMesh
part%n_in = .TRUE.
!Assign particle to listPart_in
CALL OMP_SET_LOCK(self%lock)
CALL self%listPart_in%add(part)
self%totalWeight = self%totalWeight + part%weight
sp = part%species%n
CALL self%listPart_in(sp)%add(part)
self%totalWeight(sp) = self%totalWeight(sp) + part%weight
CALL OMP_UNSET_LOCK(self%lock)
ELSE
@ -586,6 +588,7 @@ MODULE moduleMesh
CLASS(meshVol), POINTER:: vol
REAL(8), DIMENSION(1:3):: xii
CLASS(meshElement), POINTER:: nextElement
INTEGER:: sp
found = .FALSE.
@ -595,8 +598,9 @@ MODULE moduleMesh
IF (vol%inside(xii)) THEN
part%volColl = vol%n
CALL OMP_SET_LOCK(vol%lock)
CALL vol%listPart_in%add(part)
vol%totalWeight = vol%totalWeight + part%weight
sp = part%species%n
CALL vol%listPart_in(sp)%add(part)
vol%totalWeight(sp) = vol%totalWeight(sp) + part%weight
CALL OMP_UNSET_LOCK(vol%lock)
found = .TRUE.
@ -660,13 +664,12 @@ MODULE moduleMesh
INTEGER, INTENT(in):: t
INTEGER:: e
CLASS(meshVol), POINTER:: vol
INTEGER:: nPart !Number of particles inside the cell
INTEGER:: k, nPairs, i, j
INTEGER:: nPart_i, nPart_j, nPart!Number of particles inside the cell
REAL(8):: pMax !Maximum probability of collision
TYPE(pointerArray), ALLOCATABLE:: partTemp(:)
INTEGER:: i, j !random particle indexes
TYPE(pointerArray), ALLOCATABLE:: partTemp_i(:), partTemp_j(:)
TYPE(particle), POINTER:: part_i, part_j
INTEGER:: n !collision
INTEGER:: ij, k
INTEGER:: n, c
REAL(8):: vRel, eRel
REAL(8):: sigmaVrelTotal
REAL(8), ALLOCATABLE:: sigmaVrel(:), probabilityColl(:)
@ -681,80 +684,111 @@ MODULE moduleMesh
realCollisions = 0
vol => self%vols(e)%obj
nPart = vol%listPart_in%amount
!Resets the number of collisions
vol%nColl = 0
!TODO: Simplify this, to many sublevels
!Iterate over the number of pairs
nPairs = SIZE(interactionMatrix) !TODO: This does not change, make a variable in a module
DO k = 1, nPairs
IF (interactionMatrix(k)%amount > 0) THEN
!Select the species for the collision pair
i = interactionMatrix(k)%sp_i%n
j = interactionMatrix(k)%sp_j%n
!Calculates number of collisions if there is more than one particle in the cell
IF (nPart > 1) THEN
!Probability of collision
pMax = vol%totalWeight*vol%sigmaVrelMax*tauColl/vol%volume
!Number of particles per species in the collision pair
nPart_i = vol%listPart_in(i)%amount
nPart_j = vol%listPart_in(j)%amount
!Number of collisions in the cell
vol%nColl = NINT(REAL(nPart)*pMax*0.5D0)
IF (nPart_i > 0 .AND. nPart_j > 0) THEN
!Total number of particles for the collision pair
nPart = nPart_i + nPart_j
IF (vol%nColl > 0) THEN
!Converts the list of particles to an array for easy access
partTemp = vol%listPart_in%convert2Array()
!Resets the number of collisions in the cell
vol%nColl = 0
END IF
!Probability of collision for pair i-j
pMax = (vol%totalWeight(i) + vol%totalWeight(j))*vol%sigmaVrelMax*tauColl/vol%volume
DO n = 1, vol%nColl
!Select random different particles
i = 0
j = 0
DO WHILE (i == j)
i = random(1, nPart)
j = random(1, nPart)
END DO
part_i => partTemp(i)%part
part_j => partTemp(j)%part
!TODO: I think that from here forward it can be passed to a procedure in interactionMatrix
ij = interactionIndex(part_i%species%n, part_j%species%n)
!Number of collisions in the cell
vol%nColl = NINT(REAL(nPart)*pMax*0.5D0)
IF (interactionMatrix(ij)%amount > 0) THEN
!Obtain the cross sections for the different processes
vRel = NORM2(part_i%v-part_j%v)
eRel = interactionMatrix(ij)%rMass*vRel**2
CALL interactionMatrix(ij)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel)
!Update maximum sigma*v_rel
IF (sigmaVrelTotal > vol%sigmaVrelMax) THEN
vol%sigmaVrelMax = sigmaVrelTotal
!Converts the list of particles to an array for easy access
IF (vol%nColl > 0) THEN
partTemp_i = vol%listPart_in(i)%convert2Array()
partTemp_j = vol%listPart_in(j)%convert2Array()
END IF
ALLOCATE(probabilityColl(0:interactionMatrix(ij)%amount))
probabilityColl(0) = 0.0
probabilityColl(1:interactionMatrix(ij)%amount) = sigmaVrel/vol%sigmaVrelMax
DO n = 1, vol%nColl
!Select random particles
part_i => NULL()
part_j => NULL()
rnd = random(1, nPart_i)
part_i => partTemp_i(rnd)%part
rnd = random(1, nPart_j)
part_j => partTemp_j(rnd)%part
!If they are the same particle, skip
!TODO: Maybe try to improve this
IF (ASSOCIATED(part_i, part_j)) THEN
CYCLE
!Selects random number between 0 and 1
rnd = random()
END IF
!If the random number is below the total probability of collision, do collisions
IF (rnd < sigmaVrelTotal / vol%sigmaVrelMax) THEN
!If particles do not belong to the species, skip collision
!This can happen, for example, if particle has been previously ionized or removed
!TODO: Try to find a way to no lose these collisions. Check new 'k' and use that for the collision, maybe?
IF (part_i%species%n /= i .OR. &
part_j%species%n /= j) THEN
CYCLE
!Loop over collisions
DO k = 1, interactionMatrix(ij)%amount
IF (SUM(probabilityColl(0:k-1)) + rnd <= probabilityColl(k)) THEN
CALL interactionMatrix(ij)%collisions(k)%obj%collide(part_i, part_j, vRel)
realCollisions = realCollisions + 1
END IF
END IF
!Obtain the cross sections for the different processes
!TODO: From here it might be a procedure in interactionMatrix
vRel = NORM2(part_i%v-part_j%v)
eRel = interactionMatrix(k)%rMass*vRel**2
CALL interactionMatrix(k)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel)
END DO
!Update maximum sigma*v_rel
IF (sigmaVrelTotal > vol%sigmaVrelMax) THEN
vol%sigmaVrelMax = sigmaVrelTotal
END IF
END IF
ALLOCATE(probabilityColl(0:interactionMatrix(k)%amount))
probabilityColl(0) = 0.0
probabilityColl(1:interactionMatrix(k)%amount) = sigmaVrel/vol%sigmaVrelMax
!Selects random number between 0 and 1
rnd = random()
!If the random number is below the total probability of collision, collide particles
IF (rnd < sigmaVrelTotal / vol%sigmaVrelMax) THEN
!Loop over collisions
DO c = 1, interactionMatrix(k)%amount
IF (SUM(probabilityColl(0:c-1)) + rnd <= probabilityColl(c)) THEN
CALL interactionMatrix(k)%collisions(c)%obj%collide(part_i, part_j, vRel)
realCollisions = realCollisions + 1
!A collision has ocurred, exit the loop
EXIT
END IF
END DO
END IF
!Deallocate arrays for next collision
DEALLOCATE(sigmaVrel, probabilityColl)
!Deallocate arrays for next collision
DEALLOCATE(sigmaVrel, probabilityColl)
END DO
END IF
END DO
END IF
END IF
END DO
vol%nColl = realCollisions