!moduleMesh: General module for Finite Element mesh MODULE moduleMesh USE moduleList USE moduleOutput USE moduleBoundary USE moduleCollisions IMPLICIT NONE !Generic mesh element TYPE, PUBLIC, ABSTRACT:: meshElement !Index INTEGER:: n = 0 CONTAINS END TYPE meshElement !Parent of Node element TYPE, PUBLIC, ABSTRACT, EXTENDS(meshElement):: meshNode !Node volume REAL(8):: v = 0.D0 !Output values TYPE(outputNode), ALLOCATABLE:: output(:) TYPE(emNode):: emData !Lock indicator for scattering INTEGER(KIND=OMP_LOCK_KIND):: lock CONTAINS PROCEDURE(initNode_interface), DEFERRED, PASS:: init PROCEDURE(getCoord_interface), DEFERRED, PASS:: getCoordinates PROCEDURE, PASS:: resetOutput END TYPE meshNode ABSTRACT INTERFACE !Interface of init a node (3D generic coordinates) SUBROUTINE initNode_interface(self, n, r) IMPORT:: meshNode CLASS(meshNode), INTENT(out):: self INTEGER, INTENT(in):: n REAL(8), INTENT(in):: r(1:3) END SUBROUTINE initNode_interface !Interface to get coordinates from node PURE FUNCTION getCoord_interface(self) RESULT(r) IMPORT:: meshNode CLASS(meshNode), INTENT(in):: self REAL(8):: r(1:3) END FUNCTION getCoord_interface END INTERFACE !Containers for nodes in the mesh TYPE:: meshNodeCont CLASS(meshNode), ALLOCATABLE:: obj CONTAINS END TYPE meshNodeCont !Type for array of boundary functions (one per species) TYPE, PUBLIC:: fBoundaryGeneric PROCEDURE(boundary_interface), POINTER, NOPASS:: apply => NULL() CONTAINS END TYPE !Parent of Edge element TYPE, PUBLIC, ABSTRACT, EXTENDS(meshElement):: meshEdge !Connectivity to vols CLASS(meshVol), POINTER:: e1 => NULL(), e2 => NULL() !Connectivity to vols in meshColl CLASS(meshVol), POINTER:: eColl => NULL() !Normal vector REAL(8):: normal(1:3) !Weight for random injection of particles REAL(8):: weight = 1.D0 !Pointer to boundary type TYPE(boundaryCont), POINTER:: boundary !Array of functions for boundary conditions TYPE(fBoundaryGeneric), ALLOCATABLE:: fBoundary(:) !Physical surface for the edge INTEGER:: physicalSurface CONTAINS PROCEDURE(initEdge_interface), DEFERRED, PASS:: init PROCEDURE(getNodesEdge_interface), DEFERRED, PASS:: getNodes PROCEDURE(intersectionEdge_interface), DEFERRED, PASS:: intersection PROCEDURE(randPosEdge_interface), DEFERRED, PASS:: randPos END TYPE meshEdge ABSTRACT INTERFACE !Inits the edge parameters SUBROUTINE initEdge_interface(self, n, p, bt, physicalSurface) IMPORT:: meshEdge CLASS(meshEdge), INTENT(out):: self INTEGER, INTENT(in):: n INTEGER, INTENT(in):: p(:) INTEGER, INTENT(in):: bt INTEGER, INTENT(in):: physicalSurface END SUBROUTINE initEdge_interface !Get nodes index from node PURE FUNCTION getNodesEdge_interface(self) RESULT(n) IMPORT:: meshEdge CLASS(meshEdge), INTENT(in):: self INTEGER, ALLOCATABLE:: n(:) END FUNCTION getNodesEdge_interface !Returns the intersecction between an edge and a line defined by point r0 PURE FUNCTION intersectionEdge_interface(self, r0) RESULT(r) IMPORT:: meshEdge CLASS(meshEdge), INTENT(in):: self REAL(8), INTENT(in), DIMENSION(1:3):: r0 REAL(8):: r(1:3) END FUNCTION intersectionEdge_interface !Returns a random position in the edge FUNCTION randPosEdge_interface(self) RESULT(r) IMPORT:: meshEdge CLASS(meshEdge), INTENT(in):: self REAL(8):: r(1:3) END FUNCTION randPosEdge_interface END INTERFACE INTERFACE SUBROUTINE boundary_interface(edge, part) USE moduleSpecies IMPORT:: meshEdge CLASS (meshEdge), INTENT(inout):: edge CLASS (particle), INTENT(inout):: part END SUBROUTINE END INTERFACE !Containers for edges in the mesh TYPE:: meshEdgeCont CLASS(meshEdge), ALLOCATABLE:: obj END TYPE meshEdgeCont !Parent of Volume element TYPE, PUBLIC, ABSTRACT, EXTENDS(meshElement):: meshVol !Maximum collision rate REAL(8), ALLOCATABLE:: sigmaVrelMax(:) !Arrays for counting number of collisions TYPE(tallyCollisions), ALLOCATABLE:: tallyColl(:) !Volume REAL(8):: volume = 0.D0 !List of particles inside the volume TYPE(listNode), ALLOCATABLE:: listPart_in(:) !Lock indicator for listPart_in INTEGER(KIND=OMP_LOCK_KIND):: lock !Total weight of particles inside cell REAL(8), ALLOCATABLE:: totalWeight(:) CONTAINS PROCEDURE(initVol_interface), DEFERRED, PASS:: init PROCEDURE(getNodesVol_interface), DEFERRED, PASS:: getNodes PROCEDURE(randPosVol_interface), DEFERRED, PASS:: randPos PROCEDURE(fPsi_interface), DEFERRED, NOPASS:: fPsi PROCEDURE, PASS:: scatter PROCEDURE(gatherEF_interface), DEFERRED, PASS:: gatherEF PROCEDURE(gatherMF_interface), DEFERRED, PASS:: gatherMF PROCEDURE(elemK_interface), DEFERRED, PASS:: elemK PROCEDURE(elemF_interface), DEFERRED, PASS:: elemF PROCEDURE, PASS:: findCell PROCEDURE(phy2log_interface), DEFERRED, PASS:: phy2log PROCEDURE(inside_interface), DEFERRED, NOPASS:: inside PROCEDURE(nextElement_interface), DEFERRED, PASS:: nextElement END TYPE meshVol ABSTRACT INTERFACE SUBROUTINE initVol_interface(self, n, p, nodes) IMPORT:: meshVol IMPORT meshNodeCont CLASS(meshVol), INTENT(out):: self INTEGER, INTENT(in):: n INTEGER, INTENT(in):: p(:) TYPE(meshNodeCont), INTENT(in), TARGET:: nodes(:) END SUBROUTINE initVol_interface PURE FUNCTION gatherEF_interface(self, xi) RESULT(EF) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8), INTENT(in):: xi(1:3) REAL(8):: EF(1:3) END FUNCTION gatherEF_interface PURE FUNCTION gatherMF_interface(self, xi) RESULT(MF) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8), INTENT(in):: xi(1:3) REAL(8):: MF(1:3) END FUNCTION gatherMF_interface PURE FUNCTION getNodesVol_interface(self) RESULT(n) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self INTEGER, ALLOCATABLE:: n(:) END FUNCTION getNodesVol_interface PURE FUNCTION fPsi_interface(xi) RESULT(fPsi) REAL(8), INTENT(in):: xi(1:3) REAL(8), ALLOCATABLE:: fPsi(:) END FUNCTION fPsi_interface PURE FUNCTION elemK_interface(self) RESULT(localK) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8), ALLOCATABLE:: localK(:,:) END FUNCTION elemK_interface PURE FUNCTION elemF_interface(self, source) RESULT(localF) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8), INTENT(in):: source(1:) REAL(8), ALLOCATABLE:: localF(:) END FUNCTION elemF_interface SUBROUTINE nextElement_interface(self, xi, nextElement) IMPORT:: meshVol, meshElement CLASS(meshVol), INTENT(in):: self REAL(8), INTENT(in):: xi(1:3) CLASS(meshElement), POINTER, INTENT(out):: nextElement END SUBROUTINE nextElement_interface PURE FUNCTION phy2log_interface(self,r) RESULT(xN) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8), INTENT(in):: r(1:3) REAL(8):: xN(1:3) END FUNCTION phy2log_interface PURE FUNCTION inside_interface(xi) RESULT(ins) IMPORT:: meshVol REAL(8), INTENT(in):: xi(1:3) LOGICAL:: ins END FUNCTION inside_interface FUNCTION randPosVol_interface(self) RESULT(r) IMPORT:: meshVol CLASS(meshVol), INTENT(in):: self REAL(8):: r(1:3) END FUNCTION randPosVol_interface END INTERFACE !Containers for volumes in the mesh TYPE:: meshVolCont CLASS(meshVol), ALLOCATABLE:: obj END TYPE meshVolCont !Generic mesh type TYPE, ABSTRACT:: meshGeneric !Dimension of the mesh INTEGER:: dimen !Geometry of the mesh CHARACTER(:), ALLOCATABLE:: geometry !Number of elements INTEGER:: numNodes, numVols !Array of nodes TYPE(meshNodeCont), ALLOCATABLE:: nodes(:) !Array of volume elements TYPE(meshVolCont), ALLOCATABLE:: vols(:) PROCEDURE(readMesh_interface), POINTER, PASS:: readMesh => NULL() PROCEDURE(readInitial_interface), POINTER, NOPASS:: readInitial => NULL() PROCEDURE(connectMesh_interface), POINTER, PASS:: connectMesh => NULL() PROCEDURE(printColl_interface), POINTER, PASS:: printColl => NULL() CONTAINS PROCEDURE, PASS:: doCollisions END TYPE meshGeneric ABSTRACT INTERFACE !Reads the mesh from a file SUBROUTINE readMesh_interface(self, filename) IMPORT meshGeneric CLASS(meshGeneric), INTENT(inout):: self CHARACTER(:), ALLOCATABLE, INTENT(in):: filename END SUBROUTINE readMesh_interface SUBROUTINE readInitial_interface(sp, filename, density, velocity, temperature) INTEGER, INTENT(in):: sp CHARACTER(:), ALLOCATABLE, INTENT(in):: filename REAL(8), ALLOCATABLE, INTENT(out), DIMENSION(:):: density REAL(8), ALLOCATABLE, INTENT(out), DIMENSION(:,:):: velocity REAL(8), ALLOCATABLE, INTENT(out), DIMENSION(:):: temperature END SUBROUTINE readInitial_interface !Connects volume and edges to the mesh SUBROUTINE connectMesh_interface(self) IMPORT meshGeneric CLASS(meshGeneric), INTENT(inout):: self END SUBROUTINE connectMesh_interface !Prints number of collisions in each volume SUBROUTINE printColl_interface(self, t) IMPORT meshGeneric CLASS(meshGeneric), INTENT(inout):: self INTEGER, INTENT(in):: t END SUBROUTINE printColl_interface END INTERFACE !Particle mesh TYPE, EXTENDS(meshGeneric), PUBLIC:: meshParticles INTEGER:: numEdges !Array of boundary elements TYPE(meshEdgeCont), ALLOCATABLE:: edges(:) !Global stiffness matrix REAL(8), ALLOCATABLE, DIMENSION(:,:):: K !Permutation matrix for P L U factorization INTEGER, ALLOCATABLE, DIMENSION(:,:):: IPIV PROCEDURE(printOutput_interface), POINTER, PASS:: printOutput => NULL() PROCEDURE(printEM_interface), POINTER, PASS:: printEM => NULL() PROCEDURE(doCoulomb_interface), POINTER, PASS:: doCoulomb => NULL() PROCEDURE(printAverage_interface), POINTER, PASS:: printAverage => NULL() CONTAINS PROCEDURE, PASS:: constructGlobalK END TYPE meshParticles ABSTRACT INTERFACE !Perform Coulomb Scattering SUBROUTINE doCoulomb_interface(self) IMPORT meshParticles CLASS(meshParticles), INTENT(inout):: self END SUBROUTINE doCoulomb_interface !Prints Species data SUBROUTINE printOutput_interface(self, t) IMPORT meshParticles CLASS(meshParticles), INTENT(in):: self INTEGER, INTENT(in):: t END SUBROUTINE printOutput_interface !Prints EM info SUBROUTINE printEM_interface(self, t) IMPORT meshParticles CLASS(meshParticles), INTENT(in):: self INTEGER, INTENT(in):: t END SUBROUTINE printEM_interface !Prints average values SUBROUTINE printAverage_interface(self) IMPORT meshParticles CLASS(meshParticles), INTENT(in):: self END SUBROUTINE printAverage_interface END INTERFACE TYPE(meshParticles), TARGET:: mesh !Collision (MCC) mesh TYPE, EXTENDS(meshGeneric):: meshCollisions CONTAINS END TYPE meshCollisions TYPE(meshCollisions), TARGET:: meshColl ABSTRACT INTERFACE SUBROUTINE readMeshColl_interface(self, filename) IMPORT meshCollisions CLASS(meshCollisions), INTENT(inout):: self CHARACTER(:), ALLOCATABLE, INTENT(in):: filename END SUBROUTINE readMeshColl_interface SUBROUTINE connectMeshColl_interface(self) IMPORT meshParticles CLASS(meshParticles), INTENT(inout):: self END SUBROUTINE connectMeshColl_interface END INTERFACE !Pointer to mesh used for MC collisions CLASS(meshGeneric), POINTER:: meshForMCC => NULL() !Procedure to find a volume for a particle in meshColl PROCEDURE(findCellColl_interface), POINTER:: findCellColl => NULL() ABSTRACT INTERFACE SUBROUTINE findCellColl_interface(part) USE moduleSpecies TYPE(particle), INTENT(inout):: part END SUBROUTINE findCellColl_interface END INTERFACE !Logical to indicate if an specific mesh for MC Collisions is used LOGICAL:: doubleMesh !Complete path for the two meshes CHARACTER(:), ALLOCATABLE:: pathMeshColl, pathMeshParticle CONTAINS !Constructs the global K matrix SUBROUTINE constructGlobalK(self) IMPLICIT NONE CLASS(meshParticles), INTENT(inout):: self INTEGER:: e INTEGER, ALLOCATABLE:: n(:) REAL(8), ALLOCATABLE:: localK(:,:) INTEGER:: nNodes, i, j DO e = 1, self%numVols n = self%vols(e)%obj%getNodes() localK = self%vols(e)%obj%elemK() nNodes = SIZE(n) DO i = 1, nNodes DO j = 1, nNodes self%K(n(i), n(j)) = self%K(n(i), n(j)) + localK(i, j) END DO END DO END DO END SUBROUTINE constructGlobalK !Reset the output of node PURE SUBROUTINE resetOutput(self) USE moduleSpecies USE moduleOutput IMPLICIT NONE CLASS(meshNode), INTENT(inout):: self INTEGER:: k DO k = 1, nSpecies self%output(k)%den = 0.D0 self%output(k)%mom = 0.D0 self%output(k)%tensorS = 0.D0 END DO END SUBROUTINE resetOutput !Scatters particle properties into vol nodes SUBROUTINE scatter(self, part) USE moduleMath USE moduleSpecies USE OMP_LIB IMPLICIT NONE CLASS(meshVol), INTENT(inout):: self CLASS(particle), INTENT(in):: part REAL(8), ALLOCATABLE:: fPsi(:) INTEGER, ALLOCATABLE:: volNodes(:) REAL(8):: tensorS(1:3, 1:3) INTEGER:: sp INTEGER:: i, nNodes CLASS(meshNode), POINTER:: node fPsi = self%fPsi(part%xi) tensorS = outerProduct(part%v, part%v) sp = part%species%n volNodes = self%getNodes() nNodes = SIZE(volNodes) DO i = 1, nNodes node => mesh%nodes(volNodes(i))%obj CALL OMP_SET_LOCK(node%lock) node%output(sp)%den = node%output(sp)%den + part%weight*fPsi(i) node%output(sp)%mom(:) = node%output(sp)%mom(:) + part%weight*fPsi(i)*part%v(:) node%output(sp)%tensorS(:,:) = node%output(sp)%tensorS(:,:) + part%weight*fPsi(i)*tensorS CALL OMP_UNSET_LOCK(node%lock) END DO END SUBROUTINE scatter !Find next cell for particle RECURSIVE SUBROUTINE findCell(self, part, oldCell) USE moduleSpecies USE moduleErrors USE OMP_LIB IMPLICIT NONE CLASS(meshVol), INTENT(inout):: self CLASS(particle), INTENT(inout), TARGET:: part 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 IF (self%inside(xi)) THEN part%vol = self%n part%xi = xi part%n_in = .TRUE. !Assign particle to listPart_in CALL OMP_SET_LOCK(self%lock) 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 !If not, searches for a neighbour and repeats the process. CALL self%nextElement(xi, nextElement) !Defines the next step SELECT TYPE(nextElement) CLASS IS(meshVol) !Particle moved to new cell, repeat find procedure CALL nextElement%findCell(part, self) CLASS IS (meshEdge) !Particle encountered a surface, apply boundary CALL nextElement%fBoundary(part%species%n)%apply(nextElement,part) !If particle is still inside the domain, call findCell IF (part%n_in) THEN IF(PRESENT(oldCell)) THEN CALL self%findCell(part, oldCell) ELSE CALL self%findCell(part) END IF END IF CLASS DEFAULT WRITE (*, "(A, I6)") "Element = ", self%n CALL criticalError("No connectivity found for element", "findCell") END SELECT END IF END SUBROUTINE findCell !If Coll and Particle are the same, simply copy the part%vol into part%volColl SUBROUTINE findCellSameMesh(part) USE moduleSpecies IMPLICIT NONE TYPE(particle), INTENT(inout):: part part%volColl = part%vol END SUBROUTINE findCellSameMesh !TODO: try to combine this with the findCell for a regular mesh !Find the volume in which particle reside in the mesh for collisions !No boundary interaction taken into account SUBROUTINE findCellCollMesh(part) USE moduleSpecies IMPLICIT NONE TYPE(particle), INTENT(inout):: part LOGICAL:: found CLASS(meshVol), POINTER:: vol REAL(8), DIMENSION(1:3):: xii CLASS(meshElement), POINTER:: nextElement INTEGER:: sp found = .FALSE. vol => meshColl%vols(part%volColl)%obj DO WHILE(.NOT. found) xii = vol%phy2log(part%r) IF (vol%inside(xii)) THEN part%volColl = vol%n CALL OMP_SET_LOCK(vol%lock) 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. ELSE CALL vol%nextElement(xii, nextElement) SELECT TYPE(nextElement) CLASS IS(meshVol) !Try next element vol => nextElement CLASS DEFAULT !Should never happend, but just in case, stops loops found = .TRUE. END SELECT END IF END DO END SUBROUTINE findCellCollMesh !Returns index of volume associated to a position (if any) !If no voulme is found, returns 0 !WARNING: This function is slow and should only be used in initialization phase FUNCTION findCellBrute(self, r) RESULT(nVol) USE moduleSpecies IMPLICIT NONE CLASS(meshGeneric), INTENT(in):: self REAL(8), DIMENSION(1:3), INTENT(in):: r INTEGER:: nVol INTEGER:: e REAL(8), DIMENSION(1:3):: xii !Inits RESULT nVol = 0 DO e = 1, self%numVols xii = self%vols(e)%obj%phy2log(r) IF(self%vols(e)%obj%inside(xii)) THEN nVol = self%vols(e)%obj%n EXIT END IF END DO END FUNCTION findCellBrute !Computes collisions in element SUBROUTINE doCollisions(self, t) USE moduleCollisions USE moduleSpecies USE moduleList use moduleRefParam USE moduleRandom USE moduleOutput USE moduleMath IMPLICIT NONE CLASS(meshGeneric), INTENT(inout), TARGET:: self INTEGER, INTENT(in):: t INTEGER:: e CLASS(meshVol), POINTER:: vol INTEGER:: k, i, j INTEGER:: nPart_i, nPart_j, nPart!Number of particles inside the cell REAL(8):: pMax !Maximum probability of collision INTEGER:: nColl TYPE(pointerArray), ALLOCATABLE:: partTemp_i(:), partTemp_j(:) TYPE(particle), POINTER:: part_i, part_j INTEGER:: n, c REAL(8):: vRel, rMass, eRel REAL(8):: sigmaVrelTotal REAL(8), ALLOCATABLE:: sigmaVrel(:), probabilityColl(:) REAL(8):: rnd !Random number for collision IF (MOD(t, everyColl) == 0) THEN !Collisions need to be performed in this iteration !$OMP DO SCHEDULE(DYNAMIC) PRIVATE(part_i, part_j, partTemp_i, partTemp_j) DO e=1, self%numVols vol => self%vols(e)%obj !TODO: Simplify this, to many sublevels !Iterate over the number of pairs DO k = 1, nCollPairs !Reset tally of collisions IF (collOutput) THEN vol%tallyColl(k)%tally = 0 END IF 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 !Number of particles per species in the collision pair nPart_i = vol%listPart_in(i)%amount nPart_j = vol%listPart_in(j)%amount IF (nPart_i > 0 .AND. nPart_j > 0) THEN !Total number of particles for the collision pair nPart = nPart_i + nPart_j !Resets the number of collisions in the cell nColl = 0 !Probability of collision for pair i-j pMax = (vol%totalWeight(i) + vol%totalWeight(j))*vol%sigmaVrelMax(k)*tauColl/vol%volume !Number of collisions in the cell nColl = NINT(REAL(nPart)*pMax*0.5D0) !Converts the list of particles to an array for easy access IF (nColl > 0) THEN partTemp_i = vol%listPart_in(i)%convert2Array() partTemp_j = vol%listPart_in(j)%convert2Array() END IF DO n = 1, 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 END IF !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. Maybe check new 'k' and use that for the collision, maybe? IF (part_i%species%n /= i .OR. & part_j%species%n /= j) THEN CYCLE 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) rMass = reducedMass(part_i%weight*part_i%species%m, part_j%weight*part_j%species%m) eRel = rMass*vRel**2 CALL interactionMatrix(k)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel) !Update maximum sigma*v_rel IF (sigmaVrelTotal > vol%sigmaVrelMax(k)) THEN vol%sigmaVrelMax(k) = sigmaVrelTotal END IF ALLOCATE(probabilityColl(0:interactionMatrix(k)%amount)) probabilityColl = 0.0 DO c = 1, interactionMatrix(k)%amount probabilityColl(c) = sigmaVrel(c)/vol%sigmaVrelMax(k) + SUM(probabilityColl(0:c-1)) END DO !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(k)) THEN !Loop over collisions DO c = 1, interactionMatrix(k)%amount IF (rnd <= probabilityColl(c)) THEN CALL interactionMatrix(k)%collisions(c)%obj%collide(part_i, part_j, vRel) !If collisions are gonna be output, count the collision IF (collOutput) THEN vol%tallyColl(k)%tally(c) = vol%tallyColl(k)%tally(c) + 1 END IF !A collision has ocurred, exit the loop EXIT END IF END DO END IF !Deallocate arrays for next collision DEALLOCATE(sigmaVrel, probabilityColl) !End loop collisions in cell END DO END IF END IF !End loop collision pairs END DO !End loop volumes END DO !$OMP END DO END IF END SUBROUTINE doCollisions SUBROUTINE doCoulomb(self) IMPLICIT NONE CLASS(meshParticles), INTENT(inout):: self END SUBROUTINE doCoulomb END MODULE moduleMesh