!moduleMeshBoundary: Boundary functions for the mesh edges MODULE moduleMeshBoundary USE moduleMesh CONTAINS SUBROUTINE reflection(edge, part) USE moduleCaseParam USE moduleSpecies IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part !rp = intersection between particle and edge !rpp = final position of particle !vpp = final velocity of particle REAL(8), DIMENSION(1:3):: rp, vpp !Reflect particle velocity vpp = part%v - 2.D0*DOT_PRODUCT(part%v, edge%normal)*edge%normal part%v = vpp rp = edge%intersection(part%r) part%r = 2.D0*(rp - part%r) + part%r !particle is assumed to be inside part%n_in = .TRUE. END SUBROUTINE reflection !Absoption in a surface SUBROUTINE absorption(edge, part) USE moduleCaseParam USE moduleSpecies IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part REAL(8):: rpp(1:3) !Position of particle projected to the edge REAL(8):: d !Distance from particle to edge rpp = edge%intersection(part%r) d = NORM2(rpp - part%r) IF (d >= 0.D0) THEN part%weight = part%weight/d END IF !Assign new position to particle part%r = rpp !Remove particle from the domain part%n_in = .FALSE. !Scatter particle in associated volume IF (ASSOCIATED(edge%e1)) THEN CALL edge%e1%scatter(edge%e1%nNodes, part) ELSE CALL edge%e2%scatter(edge%e2%nNodes, part) END IF END SUBROUTINE absorption !Transparent boundary condition SUBROUTINE transparent(edge, part) USE moduleSpecies IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part !Removes particle from domain part%n_in = .FALSE. END SUBROUTINE transparent !Symmetry axis. Reflects particles. !Although this function should never be called, it is set as a reflective boundary !to properly deal with possible particles reaching a corner and selecting this boundary. SUBROUTINE symmetryAxis(edge, part) USE moduleSpecies IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part CALL reflection(edge, part) END SUBROUTINE symmetryAxis !Wall with temperature SUBROUTINE wallTemperature(edge, part) USE moduleSpecies USE moduleBoundary USE moduleRandom IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part INTEGER:: i !Modifies particle velocity according to wall temperature SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj) TYPE IS(boundaryWallTemperature) DO i = 1, 3 part%v(i) = part%v(i) + bound%vTh*randomMaxwellian() END DO END SELECT CALL reflection(edge, part) END SUBROUTINE wallTemperature !Ionization surface: an electron will pass through the surface ! and create an ion-electron pair based on a neutral background SUBROUTINE ionization(edge, part) USE moduleList USE moduleSpecies USE moduleMesh USE moduleRefParam USE moduleRandom USE moduleMath IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge CLASS(particle), INTENT(inout):: part REAL(8):: vRel, eRel, mRel !relative velocity, energy and mass INTEGER:: nIonizations !Number of ionizations based on eRel REAL(8):: pIonization !Probability of ionization of each event INTEGER:: p REAL(8):: v0(1:3) !random velocity of neutral TYPE(particle), POINTER:: newElectron TYPE(particle), POINTER:: newIon SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj) TYPE IS(boundaryIonization) mRel = reducedMass(bound%m0, part%species%m) vRel = SUM(DABS(part%v-bound%v0)) eRel = mRel*vRel**2*5.D-1 !Maximum number of possible ionizations based on relative energy nIonizations = FLOOR(eRel/bound%eThreshold) DO p = 1, nIonizations !Get probability of ionization pIonization = 1.D0 - DEXP(-bound%n0*bound%crossSection%get(eRel)*vRel*bound%effectiveTime/REAL(nIonizations)) !If a random number is below the probability of ionization, create new pair of ion-electron IF (random() < pIonization) THEN !Assign random velocity to the neutral v0(1) = bound%v0(1) + bound%vTh*randomMaxwellian() v0(2) = bound%v0(2) + bound%vTh*randomMaxwellian() v0(3) = bound%v0(3) + bound%vTh*randomMaxwellian() !Allocates the new particles ALLOCATE(newElectron) ALLOCATE(newIon) IF (ASSOCIATED(bound%electronSecondary)) THEN newElectron%species => bound%electronSecondary ELSE newElectron%species => part%species END IF newIon%species => bound%species newElectron%v = v0 + (1.D0 + bound%deltaV*v0/NORM2(v0)) newIon%v = v0 newElectron%r = edge%randPos() newIon%r = newElectron%r IF (ASSOCIATED(edge%e1)) THEN newElectron%cell = edge%e1%n ELSEIF (ASSOCIATED(edge%e2)) THEN newElectron%cell = edge%e2%n END IF newIon%cell = newElectron%cell newElectron%Xi = mesh%cells(part%cell)%obj%phy2log(newElectron%r) newIon%Xi = newElectron%Xi newElectron%weight = part%weight newIon%weight = newElectron%weight newElectron%n_in = .TRUE. newIon%n_in = .TRUE. !Add particles to list CALL partSurfaces%setLock() CALL partSurfaces%add(newElectron) CALL partSurfaces%add(newIon) CALL partSurfaces%unsetLock() !Electron loses energy due to ionization eRel = eRel - bound%eThreshold vRel = 2.D0*DSQRT(eRel)/mRel !Reduce number of possible ionizations nIonizations = nIonizations - 1 END IF END DO END SELECT !Removes ionizing electron regardless the number of pair created part%n_in = .FALSE. END SUBROUTINE ionization subroutine outflowAdaptive(edge, part) use moduleRandom implicit none class(meshEdge), intent(inout):: edge class(particle), intent(inout):: part select type(bound => edge%boundary%bTypes(part%species%n)%obj) type is(boundaryOutflowAdaptive) if (random() < 0.844d0) then call reflection(edge, part) else call transparent(edge, part) end if end select end subroutine outflowAdaptive !Points the boundary function to specific type SUBROUTINE pointBoundaryFunction(edge, s) USE moduleErrors IMPLICIT NONE CLASS(meshEdge), INTENT(inout):: edge INTEGER, INTENT(in):: s !Species index SELECT TYPE(obj => edge%boundary%bTypes(s)%obj) TYPE IS(boundaryAbsorption) edge%fBoundary(s)%apply => absorption TYPE IS(boundaryReflection) edge%fBoundary(s)%apply => reflection TYPE IS(boundaryTransparent) edge%fBoundary(s)%apply => transparent TYPE IS(boundaryAxis) edge%fBoundary(s)%apply => symmetryAxis TYPE IS(boundaryWallTemperature) edge%fBoundary(s)%apply => wallTemperature TYPE IS(boundaryIonization) edge%fBoundary(s)%apply => ionization type is(boundaryOutflowAdaptive) edge%fBoundary(s)%apply => outflowAdaptive CLASS DEFAULT CALL criticalError("Boundary type not defined in this geometry", 'pointBoundaryFunction') END SELECT END SUBROUTINE pointBoundaryFunction END MODULE moduleMeshBoundary