Compare commits

...
Sign in to create a new pull request.

10 commits

Author SHA1 Message Date
0c49723848 NOT WORKING
I need to fix something in another place and make some test, so this
commit does not comile.
2023-11-21 09:23:18 +01:00
286e858d66 Intermediate push
I still have to figure out how to do this properly, but I am tired of
working on my laptop.
2023-09-22 18:18:46 +02:00
b73c8531e8 Fix an issue with different time steps
Sometimes the division between number of steps and time step was not
giving the right results.

Nevertheless, this just indicates that the species have to be in
separated arrays so that the assignment of particles in list, pushing
and scattering can be dealt independently.

Thus, this is the first step in creating separate arrays of particles
per species.
2023-08-06 19:45:48 +02:00
541a6ff97a Correction to injection velocity
Small correction to injection velocity. Still not fully satisfied with
it. I have to find a way to ensure that velocity is injected in the
right direction and fulfills the distribution functions in each
direction regardless the direction of injection, mean velocity or
distribution function.
2023-07-30 12:55:52 +02:00
e1009a21df Correction due to angle
Moving forward to a complete model for SEE. Now the yield has a
correction for the incident angle on the surface (still to check if this
 is correct)

Velocity distribution is still a dummy one.
2023-07-18 15:35:16 +02:00
cc3e28e5e7 Input done
The input is done and testing.

WARNING: Velocity of secondary electrons is still a dummy one!
2023-07-17 22:48:52 +02:00
38fa37c995 Dummy velocity for testing
I have set the velocity of the particle to be a dummy Maxwellian
distribution to start testing things.

Also I added a constant yield table for testing.

Next step is to do the user input and run some tests.
2023-07-17 16:29:52 +02:00
0f7d9919ec Ignore backups of bibliography
Sorry that this change is in this branch, but I just noticed that the
backups from jabref were not being ignored.
2023-07-17 16:18:51 +02:00
e369bccf78 Function to create electrons
Still required to assign velocity:
  - In the direction normal to the surface
  - Which energy?
2023-07-17 13:58:57 +02:00
21184e91d3 Type for SEE
Implementation of the type for Secondary Electron Emission (SEE)
2023-07-17 12:02:24 +02:00
15 changed files with 372 additions and 154 deletions

View file

@ -0,0 +1,4 @@
#Relative energy (eV) yield ()
0.000 1.000E-01
1.000 1.000E-01

View file

@ -19,3 +19,4 @@ fpakc_UserManual-blx.bib
*.gls *.gls
*.ist *.ist
fpakc_UserManual.run.xml fpakc_UserManual.run.xml
*.bib.sav

View file

@ -66,6 +66,24 @@ MODULE moduleRandom
END FUNCTION randomMaxwellian END FUNCTION randomMaxwellian
FUNCTION randomHalfMaxwellian() RESULT(rnd)
USE moduleConstParam, ONLY: PI
IMPLICIT NONE
REAL(8):: rnd
REAL(8):: x, y
rnd = 0.D0
x = 0.D0
DO WHILE (x == 0.D0)
CALL RANDOM_NUMBER(x)
END DO
y = random(-PI, PI)
rnd = DSQRT(-2.D0*DLOG(x))*DCOS(y)
END FUNCTION randomHalfMaxwellian
!Returns a random number weighted with the cumWeight array !Returns a random number weighted with the cumWeight array
FUNCTION randomWeighted(cumWeight, sumWeight) RESULT(rnd) FUNCTION randomWeighted(cumWeight, sumWeight) RESULT(rnd)
IMPLICIT NONE IMPLICIT NONE

View file

@ -30,6 +30,8 @@ MODULE moduleTable
READ(id, '(A)', iostat = stat) dummy READ(id, '(A)', iostat = stat) dummy
!If EOF or error, exit file !If EOF or error, exit file
IF (stat /= 0) EXIT IF (stat /= 0) EXIT
!If empty line, exit file
IF (dummy == "") EXIT
!Skip comment !Skip comment
IF (INDEX(dummy,'#') /= 0) CYCLE IF (INDEX(dummy,'#') /= 0) CYCLE
!Add row !Add row
@ -55,6 +57,7 @@ MODULE moduleTable
!TODO: Make this a function !TODO: Make this a function
IF (INDEX(dummy,'#') /= 0) CYCLE IF (INDEX(dummy,'#') /= 0) CYCLE
IF (stat /= 0) EXIT IF (stat /= 0) EXIT
IF (dummy == "") EXIT
!Add data !Add data
!TODO: substitute with extracting information from dummy !TODO: substitute with extracting information from dummy
BACKSPACE(id) BACKSPACE(id)

View file

@ -339,10 +339,9 @@ MODULE moduleInput
!Mean velocity and temperature at particle position !Mean velocity and temperature at particle position
REAL(8):: velocityXi(1:3), temperatureXi REAL(8):: velocityXi(1:3), temperatureXi
INTEGER:: nNewPart = 0.D0 INTEGER:: nNewPart = 0.D0
CLASS(meshCell), POINTER:: cell
TYPE(particle), POINTER:: partNew TYPE(particle), POINTER:: partNew
CLASS(meshCell), POINTER:: cell
REAL(8):: vTh REAL(8):: vTh
TYPE(lNode), POINTER:: partCurr, partNext
CALL config%info('solver.initial', found, n_children = nInitial) CALL config%info('solver.initial', found, n_children = nInitial)
@ -371,9 +370,12 @@ MODULE moduleInput
!Calculate number of particles !Calculate number of particles
nNewPart = INT(densityCen * (mesh%cells(e)%obj%volume*Vol_ref) / species(sp)%obj%weight) nNewPart = INT(densityCen * (mesh%cells(e)%obj%volume*Vol_ref) / species(sp)%obj%weight)
!Allocate new particles !Allocate array of particles for this species
ALLOCATE(partOld(sp)%p(1:nNewPart))
!Create new particles
DO p = 1, nNewPart DO p = 1, nNewPart
ALLOCATE(partNew) partNew = partOld(sp)%p(p)
partNew%species => species(sp)%obj partNew%species => species(sp)%obj
partNew%r = mesh%cells(e)%obj%randPos() partNew%r = mesh%cells(e)%obj%randPos()
partNew%Xi = mesh%cells(e)%obj%phy2log(partNew%r) partNew%Xi = mesh%cells(e)%obj%phy2log(partNew%r)
@ -408,9 +410,6 @@ MODULE moduleInput
partNew%weight = species(sp)%obj%weight partNew%weight = species(sp)%obj%weight
!Assign particle to temporal list of particles
CALL partInitial%add(partNew)
!Assign particle to list in volume !Assign particle to list in volume
IF (listInCells) THEN IF (listInCells) THEN
cell => meshforMCC%cells(partNew%cellColl)%obj cell => meshforMCC%cells(partNew%cellColl)%obj
@ -430,30 +429,10 @@ MODULE moduleInput
END DO END DO
nPartOld(sp) = SIZE(partOld(sp)%p)
END DO END DO
!Convert temporal list of particles into initial partOld array
!Deallocate the list of initial particles
nNewPart = partInitial%amount
IF (nNewPart > 0) THEN
ALLOCATE(partOld(1:nNewPart))
partCurr => partInitial%head
DO p = 1, nNewPart
partNext => partCurr%next
partOld(p) = partCurr%part
DEALLOCATE(partCurr)
partCurr => partNext
END DO
IF (ASSOCIATED(partInitial%head)) NULLIFY(partInitial%head)
IF (ASSOCIATED(partInitial%tail)) NULLIFY(partInitial%tail)
partInitial%amount = 0
END IF
nPartOld = SIZE(partOld)
END IF END IF
END SUBROUTINE readInitial END SUBROUTINE readInitial
@ -600,7 +579,10 @@ MODULE moduleInput
END DO END DO
!Allocate the wrapper array that contains particles
ALLOCATE(partOld(1:nSpecies))
!Set number of particles to 0 for init state !Set number of particles to 0 for init state
ALLOCATE(nPartOld(1:nSpecies))
nPartOld = 0 nPartOld = 0
!Initialize the lock for the non-analogue (NA) list of particles !Initialize the lock for the non-analogue (NA) list of particles
@ -806,7 +788,7 @@ MODULE moduleInput
REAL(8):: effTime REAL(8):: effTime
REAL(8):: eThreshold !Energy threshold REAL(8):: eThreshold !Energy threshold
INTEGER:: speciesID INTEGER:: speciesID
CHARACTER(:), ALLOCATABLE:: speciesName, crossSection CHARACTER(:), ALLOCATABLE:: speciesName, crossSection, yield
LOGICAL:: found LOGICAL:: found
INTEGER:: nTypes INTEGER:: nTypes
@ -872,6 +854,15 @@ MODULE moduleInput
CALL initWallTemperature(boundary(i)%bTypes(s)%obj, Tw, cw) CALL initWallTemperature(boundary(i)%bTypes(s)%obj, Tw, cw)
CASE('secondaryEmission')
CALL config%get(object // '.yield', yield, found)
IF (.NOT. found) CALL criticalError("missing parameter 'yield' for secondary emission", 'readBoundary')
CALL config%get(object // '.electron', speciesName, found)
IF (.NOT. found) CALL criticalError("missing parameter 'electron' for secondary emission", 'readBoundary')
speciesID = speciesName2Index(speciesName)
CALL initSEE(boundary(i)%bTypes(s)%obj, yield, speciesID)
CASE('axis') CASE('axis')
ALLOCATE(boundaryAxis:: boundary(i)%bTypes(s)%obj) ALLOCATE(boundaryAxis:: boundary(i)%bTypes(s)%obj)

View file

@ -816,9 +816,8 @@ MODULE moduleMesh
IF (MOD(t, everyColl) == 0) THEN IF (MOD(t, everyColl) == 0) THEN
!Collisions need to be performed in this iteration !Collisions need to be performed in this iteration
!$OMP DO SCHEDULE(DYNAMIC) PRIVATE(part_i, part_j, partTemp_i, partTemp_j) !$OMP DO SCHEDULE(DYNAMIC) PRIVATE(part_i, part_j, partTemp_i, partTemp_j, cell)
DO e=1, self%numCells DO e=1, self%numCells
cell => self%cells(e)%obj cell => self%cells(e)%obj
!TODO: Simplify this, to many sublevels !TODO: Simplify this, to many sublevels
@ -885,7 +884,7 @@ MODULE moduleMesh
!Obtain the cross sections for the different processes !Obtain the cross sections for the different processes
!TODO: From here it might be a procedure in interactionMatrix !TODO: From here it might be a procedure in interactionMatrix
vRel = NORM2(part_i%v-part_j%v) vRel = NORM2(part_i%v-part_j%v)
rMass = reducedMass(part_i%weight*part_i%species%m, part_j%weight*part_j%species%m) rMass = reducedMass(part_i%weight*part_i%species%mass, part_j%weight*part_j%species%mass)
eRel = rMass*vRel**2 eRel = rMass*vRel**2
CALL interactionMatrix(k)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel) CALL interactionMatrix(k)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel)
@ -1080,7 +1079,7 @@ MODULE moduleMesh
!Compute changes in velocity for each particle !Compute changes in velocity for each particle
deltaV_ij(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v deltaV_ij(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v
mass_ij(p) = pair%sp_i%m*partTemp%part%weight mass_ij(p) = pair%sp_i%mass*partTemp%part%weight
p_ij(p,1:3) = mass_ij(p)*partTemp%part%v p_ij(p,1:3) = mass_ij(p)*partTemp%part%v
!Move to the next particle in the list !Move to the next particle in the list
@ -1163,7 +1162,7 @@ MODULE moduleMesh
!Compute changes in velocity for each particle !Compute changes in velocity for each particle
deltaV_ji(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v deltaV_ji(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v
mass_ji(p) = pair%sp_j%m*partTemp%part%weight mass_ji(p) = pair%sp_j%mass*partTemp%part%weight
p_ji(p,1:3) = mass_ji(p)*partTemp%part%v p_ji(p,1:3) = mass_ji(p)*partTemp%part%v
!Move to the next particle in the list !Move to the next particle in the list

View file

@ -125,7 +125,7 @@ MODULE moduleMeshBoundary
SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj) SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj)
TYPE IS(boundaryIonization) TYPE IS(boundaryIonization)
mRel = reducedMass(bound%m0, part%species%m) mRel = reducedMass(bound%m0, part%species%mass)
vRel = SUM(DABS(part%v-bound%v0)) vRel = SUM(DABS(part%v-bound%v0))
eRel = mRel*vRel**2*5.D-1 eRel = mRel*vRel**2*5.D-1
@ -193,7 +193,7 @@ MODULE moduleMeshBoundary
END SELECT END SELECT
!Removes ionizing electron regardless the number of pair created !Removes ionizing electron regardless the number of pairs created
part%n_in = .FALSE. part%n_in = .FALSE.
END SUBROUTINE ionization END SUBROUTINE ionization
@ -212,6 +212,116 @@ MODULE moduleMeshBoundary
END SUBROUTINE symmetryAxis END SUBROUTINE symmetryAxis
!Secondary emission of electrons by impacting particle.
SUBROUTINE secondaryEmission(edge, part)
USE moduleSpecies
USE moduleRandom
USE moduleConstParam
IMPLICIT NONE
CLASS(meshEdge), INTENT(inout):: edge
CLASS(particle), INTENT(inout):: part
REAL(8):: vRel, eRel
REAL(8), DIMENSION(1:3):: rElectron, XiElectron!Position of new electrons (impacting particle)
REAL(8), DIMENSION(1:3):: rIncident !Vector from imapcting particle position to particle position
REAL(8):: theta !incident angle
REAL(8):: yield
REAL(8):: energy !incident energy corrected by threshold and
INTEGER:: nNewElectrons
REAL(8), ALLOCATABLE:: weight(:)
INTEGER:: p
INTEGER:: cell
TYPE(particle), POINTER:: secondaryElectron
SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj)
TYPE IS(boundarySEE)
!Get relative velocity
vRel = NORM2(part%v)
!Convert to relative energy
eRel = part%species%mass*vRel**2*5.D-1
!If energy is abound threshold calculate secondary electrons
IF (eRel >= bound%energyThreshold) THEN
!position of impacting ion
rElectron = edge%intersection(part%r)
XiElectron = mesh%cells(part%cell)%obj%phy2log(rElectron)
!Calculate incident angle
rIncident = part%r - rElectron
theta = ACOS(DOT_PRODUCT(rIncident, edge%normal) / (NORM2(rIncident) * NORM2(edge%normal)))
!Calculate incident energy
energy = (eRel - bound%energyThreshold) * PI2 / (PI2 + theta**2) + bound%energyThreshold
!Get number of secondary electrons particles
yield = part%weight*bound%yield%get(eRel) * (1.D0 * theta**2 / PI2) !Check equation!
!Convert the number to macro-particles
nNewElectrons = FLOOR(yield / bound%electron%weight)
!If the weight of new macro-particles is below the yield, correct adding a particle
IF (REAL(nNewElectrons) * bound%electron%weight < yield) THEN
nNewElectrons = nNewElectrons + 1
ALLOCATE(weight(1:nNewElectrons))
weight(1:nNewElectrons-1) = bound%electron%weight
weight(nNewElectrons) = yield - SUM(weight(1:nNewElectrons-1))
ELSE
ALLOCATE(weight(1:nNewElectrons))
weight(1:nNewElectrons) = bound%electron%weight
END IF
!New cell of origin
IF (ASSOCIATED(edge%e1)) THEN
cell = edge%e1%n
ELSEIF (ASSOCIATED(edge%e2)) THEN
cell = edge%e2%n
END IF
!Create the new electron macro-particles
DO p = 1, nNewElectrons
!Create new macro-particle
ALLOCATE(secondaryElectron)
!Assign species to electron
secondaryElectron%species => bound%electron
!Assign position to particle
secondaryElectron%r = rElectron
secondaryElectron%Xi = XiElectron
!Assign cell to electron
secondaryElectron%cell = cell
!Assign weight
secondaryElectron%weight = weight(p)
!Assume particle is inside the numerical domain
secondaryElectron%n_in = .TRUE.
!Assign velocity
secondaryElectron%v = 2.D0 * edge%normal + 1.D-1 * (/ randomMaxwellian(), randomMaxwellian(), randomMaxwellian() /)
!Add particle to list
CALL partSurfaces%setLock()
CALL partSurfaces%add(secondaryElectron)
CALL partSurfaces%unsetLock()
END DO
END IF
!Absorb impacting particle
CALL absorption(edge, part)
END SELECT
END SUBROUTINE secondaryEmission
!Points the boundary function to specific type !Points the boundary function to specific type
SUBROUTINE pointBoundaryFunction(edge, s) SUBROUTINE pointBoundaryFunction(edge, s)
USE moduleErrors USE moduleErrors
@ -239,6 +349,9 @@ MODULE moduleMeshBoundary
TYPE IS(boundaryAxis) TYPE IS(boundaryAxis)
edge%fBoundary(s)%apply => symmetryAxis edge%fBoundary(s)%apply => symmetryAxis
TYPE IS(boundarySEE)
edge%fBoundary(s)%apply => secondaryEmission
CLASS DEFAULT CLASS DEFAULT
CALL criticalError("Boundary type not defined in this geometry", 'pointBoundaryFunction') CALL criticalError("Boundary type not defined in this geometry", 'pointBoundaryFunction')

View file

@ -46,6 +46,16 @@ MODULE moduleBoundary
END TYPE boundaryIonization END TYPE boundaryIonization
!Secondary electron emission (by ion impact)
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundarySEE
!Yield as a function of ion energy
TYPE(table1D):: yield
CLASS(speciesGeneric), POINTER:: electron !Electron species for secondary emission
REAL(8):: energyThreshold
CONTAINS
END TYPE boundarySEE
!Symmetry axis !Symmetry axis
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryAxis TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryAxis
CONTAINS CONTAINS
@ -137,4 +147,36 @@ MODULE moduleBoundary
END SUBROUTINE initIonization END SUBROUTINE initIonization
SUBROUTINE initSEE(boundary, tableFile, speciesID)
USE moduleRefParam
USE moduleConstParam
USE moduleSpecies
IMPLICIT NONE
CLASS(boundaryGeneric), ALLOCATABLE, INTENT(out):: boundary
CHARACTER(:), ALLOCATABLE, INTENT(in):: tableFile
INTEGER:: speciesID
INTEGER:: i
ALLOCATE(boundarySEE:: boundary)
SELECT TYPE(boundary)
TYPE IS(boundarySEE)
CALL boundary%yield%init(tableFile)
CALL boundary%yield%convert(eV2J/(m_ref*v_ref**2), 1.D0)
boundary%electron => species(speciesID)%obj
!Search for the threshold energy in the table
DO i = 1, SIZE(boundary%yield%f)
IF (boundary%yield%f(i) > 0.D0) THEN
boundary%energyThreshold = boundary%yield%x(i)
EXIT
END IF
END DO
END SELECT
END SUBROUTINE initSEE
END MODULE moduleBoundary END MODULE moduleBoundary

View file

@ -164,8 +164,8 @@ MODULE moduleCollisions
self%amount = amount self%amount = amount
mass_i = species(i)%obj%m mass_i = species(i)%obj%mass
mass_j = species(j)%obj%m mass_j = species(j)%obj%mass
ALLOCATE(self%collisions(1:self%amount)) ALLOCATE(self%collisions(1:self%amount))
@ -227,8 +227,8 @@ MODULE moduleCollisions
REAL(8):: m_i, m_j REAL(8):: m_i, m_j
REAL(8), DIMENSION(1:3):: vCM, vp REAL(8), DIMENSION(1:3):: vCM, vp
m_i = part_i%species%m m_i = part_i%species%mass
m_j = part_j%species%m m_j = part_j%species%mass
!Applies the collision !Applies the collision
vCM = velocityCM(part_i%weight*m_i, part_i%v, part_j%weight*m_j, part_j%v) vCM = velocityCM(part_i%weight*m_i, part_i%v, part_j%weight*m_j, part_j%v)
vp = vRel*randomDirectionVHS() vp = vRel*randomDirectionVHS()
@ -283,7 +283,7 @@ MODULE moduleCollisions
END SELECT END SELECT
!momentum change per ionization process !momentum change per ionization process
collision%deltaV = sqrt(collision%eThreshold / collision%electron%m) collision%deltaV = sqrt(collision%eThreshold / collision%electron%mass)
END SELECT END SELECT
@ -307,7 +307,7 @@ MODULE moduleCollisions
REAL(8), DIMENSION(1:3):: vChange REAL(8), DIMENSION(1:3):: vChange
TYPE(particle), POINTER:: newElectron => NULL(), remainingNeutral => NULL() TYPE(particle), POINTER:: newElectron => NULL(), remainingNeutral => NULL()
rMass = reducedMass(part_i%weight*part_i%species%m, part_j%weight*part_j%species%m) rMass = reducedMass(part_i%weight*part_i%species%mass, part_j%weight*part_j%species%mass)
eRel = rMass*vRel**2 eRel = rMass*vRel**2
!Relative energy must be higher than threshold !Relative energy must be higher than threshold
IF (eRel > self%eThreshold) THEN IF (eRel > self%eThreshold) THEN

View file

@ -61,7 +61,7 @@ MODULE moduleCoulomb
self%sp_i => species(i)%obj self%sp_i => species(i)%obj
self%sp_j => species(j)%obj self%sp_j => species(j)%obj
self%one_plus_massRatio_ij = 1.D0 + self%sp_i%m/self%sp_j%m self%one_plus_massRatio_ij = 1.D0 + self%sp_i%mass/self%sp_j%mass
Z_i = 0.D0 Z_i = 0.D0
Z_j = 0.D0 Z_j = 0.D0
@ -87,11 +87,11 @@ MODULE moduleCoulomb
scaleFactor = (n_ref * qe**4 * ti_ref) / (eps_0**2 * m_ref**2 * v_ref**3) scaleFactor = (n_ref * qe**4 * ti_ref) / (eps_0**2 * m_ref**2 * v_ref**3)
self%A_i = Z_i**2*Z_j**2*self%lnCoulomb / (2.D0 * PI**2 * self%sp_i%m**2) * scaleFactor !Missing density because it's cell dependent self%A_i = Z_i**2*Z_j**2*self%lnCoulomb / (2.D0 * PI**2 * self%sp_i%mass**2) * scaleFactor !Missing density because it's cell dependent
self%A_j = Z_j**2*Z_i**2*self%lnCoulomb / (2.D0 * PI**2 * self%sp_j%m**2) * scaleFactor !Missing density because it's cell dependent self%A_j = Z_j**2*Z_i**2*self%lnCoulomb / (2.D0 * PI**2 * self%sp_j%mass**2) * scaleFactor !Missing density because it's cell dependent
self%l2_j = self%sp_j%m / 2.D0 !Missing temperature because it's cell dependent self%l2_j = self%sp_j%mass / 2.D0 !Missing temperature because it's cell dependent
self%l2_i = self%sp_i%m / 2.D0 !Missing temperature because it's cell dependent self%l2_i = self%sp_i%mass / 2.D0 !Missing temperature because it's cell dependent
END SUBROUTINE initInteractionCoulomb END SUBROUTINE initInteractionCoulomb

View file

@ -179,16 +179,21 @@ MODULE moduleInject
IMPLICIT NONE IMPLICIT NONE
INTEGER:: i INTEGER:: i
INTEGER, DIMENSION(1:nInject):: nMin, nMax
!$OMP SINGLE !$OMP SINGLE
nPartInj = 0 nPartInj = 0
DO i = 1, nInject DO i = 1, nInject
IF (solver%pusher(inject(i)%species%n)%pushSpecies) THEN IF (solver%pusher(inject(i)%species%n)%pushSpecies) THEN
nMin(i) = nPartInj + 1
nPartInj = nPartInj + inject(i)%nParticles nPartInj = nPartInj + inject(i)%nParticles
nMax(i) = nPartInj
END IF END IF
END DO END DO
PRINT *, nMin
PRINT *, nMax
IF (ALLOCATED(partInj)) DEALLOCATE(partInj) IF (ALLOCATED(partInj)) DEALLOCATE(partInj)
ALLOCATE(partInj(1:nPartInj)) ALLOCATE(partInj(1:nPartInj))
@ -196,7 +201,7 @@ MODULE moduleInject
DO i=1, nInject DO i=1, nInject
IF (solver%pusher(inject(i)%species%n)%pushSpecies) THEN IF (solver%pusher(inject(i)%species%n)%pushSpecies) THEN
CALL inject(i)%addParticles() CALL inject(i)%addParticles(nMin(i), nMax(i))
END IF END IF
END DO END DO
@ -254,10 +259,7 @@ MODULE moduleInject
REAL(8):: v REAL(8):: v
v = 0.D0 v = 0.D0
DO WHILE (v <= 0.D0) v = self%vTh*randomHalfMaxwellian()
v = self%vTh*randomMaxwellian()
END DO
END FUNCTION randomVelHalfMaxwellian END FUNCTION randomVelHalfMaxwellian
@ -282,8 +284,8 @@ MODULE moduleInject
IMPLICIT NONE IMPLICIT NONE
CLASS(injectGeneric), INTENT(in):: self CLASS(injectGeneric), INTENT(in):: self
INTEGER, INTENT(in):: nMin, nMax !Min and Max index in partInj array
INTEGER:: randomX INTEGER:: randomX
INTEGER, SAVE:: nMin, nMax !Min and Max index in partInj array
INTEGER:: i INTEGER:: i
INTEGER:: n, sp INTEGER:: n, sp
CLASS(meshEdge), POINTER:: randomEdge CLASS(meshEdge), POINTER:: randomEdge
@ -291,17 +293,6 @@ MODULE moduleInject
!Insert particles !Insert particles
!$OMP SINGLE !$OMP SINGLE
nMin = 0
DO i = 1, self%id -1
IF (solver%pusher(inject(i)%species%n)%pushSpecies) THEN
nMin = nMin + inject(i)%nParticles
END IF
END DO
nMin = nMin + 1
nMax = nMin + self%nParticles - 1
!Assign weight to particle. !Assign weight to particle.
partInj(nMin:nMax)%weight = self%species%weight partInj(nMin:nMax)%weight = self%species%weight
!Particle is considered to be outside the domain !Particle is considered to be outside the domain
@ -334,17 +325,19 @@ MODULE moduleInject
direction = self%n direction = self%n
partInj(n)%v = 0.D0 !Sample initial velocity
partInj(n)%v = self%vMod*direction + (/ self%v(1)%obj%randomVel(), & partInj(n)%v = self%vMod*direction + (/ self%v(1)%obj%randomVel(), &
self%v(2)%obj%randomVel(), & self%v(2)%obj%randomVel(), &
self%v(3)%obj%randomVel() /) self%v(3)%obj%randomVel() /)
!If velocity is not in the right direction, invert it !For each direction, velocities have to agree with the direction of injection
IF (DOT_PRODUCT(direction, partInj(n)%v) < 0.D0) THEN DO i = 1, 3
partInj(n)%v = - partInj(n)%v DO WHILE (partInj(n)%v(i)*direction(i) < 0)
partInj(n)%v(i) = self%vMod*direction(i) + self%v(i)%obj%randomVel()
END IF END DO
END DO
!Obtain natural coordinates of particle in cell !Obtain natural coordinates of particle in cell
partInj(n)%Xi = mesh%cells(partInj(n)%cell)%obj%phy2log(partInj(n)%r) partInj(n)%Xi = mesh%cells(partInj(n)%cell)%obj%phy2log(partInj(n)%r)

View file

@ -4,12 +4,54 @@ MODULE moduleSpecies
USE OMP_LIB USE OMP_LIB
IMPLICIT NONE IMPLICIT NONE
!Basic type that defines a macro-particle
TYPE:: particle
REAL(8):: r(1:3) !Position
REAL(8):: v(1:3) !Velocity
CLASS(speciesGeneric), POINTER:: species !Pointer to particle's species
INTEGER:: cell !Index of element in which the particle is located TODO: Make these pointers
INTEGER:: cellColl !Index of element in which the particle is located in the Collision Mesh
REAL(8):: Xi(1:3) !Logical coordinates of particle in cell
LOGICAL:: n_in !Flag that indicates if a particle is in the domain
REAL(8):: weight=0.D0 !weight of particle
END TYPE particle
!Wrapper to store the particles per species
TYPE:: particleArray
TYPE(particle), ALLOCATABLE, DIMENSION(:):: p
END TYPE particleArray
!Array of pointers for the particles to be pushed
TYPE:: particlePointer
TYPE(particle), POINTER:: p
END TYPE particlePointer
!Arrays that contain the particles
TYPE(particleArray), ALLOCATABLE, TARGET, DIMENSION(:):: particles !array of particles in the domain
TYPE(particle), ALLOCATABLE, TARGET, DIMENSION(:):: particlesInjection !array of inject particles
TYPE(particlePointer), ALLOCATABLE, DIMENSION(:):: particlesToPush !particles pushed in each iteration
!Integers to track number of particles in domain
INTEGER, ALLOCATABLE, DIMENSION(:):: nParticles
INTEGER:: nParticlesTotal
!Number of injected particles
INTEGER, ALLOCATABLE, DIMENSION(:):: nParticlesInject
INTEGER:: nPariclesInjectTotal
!Generic species type
TYPE, ABSTRACT:: speciesGeneric TYPE, ABSTRACT:: speciesGeneric
CHARACTER(:), ALLOCATABLE:: name INTEGER:: n=0 !Index of species
REAL(8):: m=0.D0, weight=0.D0, qm=0.D0 CHARACTER(:), ALLOCATABLE:: name !Name of species
INTEGER:: n=0 !Mass, default weight of species and charge over mass
REAL(8):: mass=0.D0, weight=0.D0, qm=0.D0
INTEGER:: every !How many interations between advancing the species
LOGICAL:: pushSpecies !Boolean to indicate if the species is moved in the iteration
END TYPE speciesGeneric END TYPE speciesGeneric
!Neutral species
TYPE, EXTENDS(speciesGeneric):: speciesNeutral TYPE, EXTENDS(speciesGeneric):: speciesNeutral
CLASS(speciesGeneric), POINTER:: ion => NULL() CLASS(speciesGeneric), POINTER:: ion => NULL()
CONTAINS CONTAINS
@ -17,6 +59,7 @@ MODULE moduleSpecies
END TYPE speciesNeutral END TYPE speciesNeutral
!Charged species
TYPE, EXTENDS(speciesGeneric):: speciesCharged TYPE, EXTENDS(speciesGeneric):: speciesCharged
REAL(8):: q=0.D0 REAL(8):: q=0.D0
CLASS(speciesGeneric), POINTER:: ion => NULL(), neutral => NULL() CLASS(speciesGeneric), POINTER:: ion => NULL(), neutral => NULL()
@ -26,34 +69,17 @@ MODULE moduleSpecies
END TYPE speciesCharged END TYPE speciesCharged
!Wrapper for species
TYPE:: speciesCont TYPE:: speciesCont
CLASS(speciesGeneric), ALLOCATABLE:: obj CLASS(speciesGeneric), ALLOCATABLE:: obj
END TYPE END TYPE
!Number of species
INTEGER:: nSpecies INTEGER:: nSpecies
!Array for species
TYPE(speciesCont), ALLOCATABLE, TARGET:: species(:) TYPE(speciesCont), ALLOCATABLE, TARGET:: species(:)
TYPE particle
REAL(8):: r(1:3) !Position
REAL(8):: v(1:3) !Velocity
CLASS(speciesGeneric), POINTER:: species !Pointer to species associated with this particle
INTEGER:: cell !Index of element in which the particle is located
INTEGER:: cellColl !Index of element in which the particle is located in the Collision Mesh
REAL(8):: Xi(1:3) !Logical coordinates of particle in element e_p.
LOGICAL:: n_in !Flag that indicates if a particle is in the domain
REAL(8):: weight=0.D0 !weight of particle
END TYPE particle
!Number of old particles
INTEGER:: nPartOld
!Number of injected particles
INTEGER:: nPartInj
!Arrays that contain the particles
TYPE(particle), ALLOCATABLE, DIMENSION(:), TARGET:: partOld !array of particles from previous iteration
TYPE(particle), ALLOCATABLE, DIMENSION(:), TARGET:: partInj !array of inject particles
CONTAINS CONTAINS
FUNCTION speciesName2Index(speciesName) RESULT(sp) FUNCTION speciesName2Index(speciesName) RESULT(sp)
USE moduleErrors USE moduleErrors

View file

@ -148,8 +148,8 @@ MODULE moduleOutput
formatValues%density = rawValues%den*tempVol formatValues%density = rawValues%den*tempVol
formatValues%velocity(:) = tempVel formatValues%velocity(:) = tempVel
IF (tensorTrace(tensorTemp) > 0.D0) THEN IF (tensorTrace(tensorTemp) > 0.D0) THEN
formatValues%pressure = speciesIn%m*tensorTrace(tensorTemp)*tempVol/3.D0 formatValues%pressure = speciesIn%mass*tensorTrace(tensorTemp)*tempVol/3.D0
formatValues%temperature = formatValues%pressure/(formatValues%density*kb) formatValues%temperature = formatValues%pressure/(formatValues%density*kb)
END IF END IF
END IF END IF
@ -187,7 +187,7 @@ MODULE moduleOutput
OPEN(20, file = path // folder // '/' // fileName, position = 'append', action = 'write') OPEN(20, file = path // folder // '/' // fileName, position = 'append', action = 'write')
WRITE (20, "(I10, I10, 7(ES20.6E3))") t, nPartOld, tStep, tPush, tReset, tColl, tCoul, tWeight, tEMField WRITE (20, "(I10, I10, 7(ES20.6E3))") t, nParticlesTotal, tStep, tPush, tReset, tColl, tCoul, tWeight, tEMField
CLOSE(20) CLOSE(20)

View file

@ -3,7 +3,7 @@ MODULE moduleSolver
!Generic type for pusher of particles !Generic type for pusher of particles
TYPE, PUBLIC:: pusherGeneric TYPE, PUBLIC:: pusherGeneric
PROCEDURE(push_interafece), POINTER, NOPASS:: pushParticle => NULL() PROCEDURE(push_interface), POINTER, NOPASS:: pushParticle => NULL()
!Boolean to indicate if the species is moved in the iteration !Boolean to indicate if the species is moved in the iteration
LOGICAL:: pushSpecies LOGICAL:: pushSpecies
!How many interations between advancing the species !How many interations between advancing the species
@ -29,13 +29,13 @@ MODULE moduleSolver
INTERFACE INTERFACE
!Push a particle !Push a particle
PURE SUBROUTINE push_interafece(part, tauIn) PURE SUBROUTINE push_interface(part, tauIn)
USE moduleSpecies USE moduleSpecies
TYPE(particle), INTENT(inout):: part TYPE(particle), INTENT(inout):: part
REAL(8), INTENT(in):: tauIn REAL(8), INTENT(in):: tauIn
END SUBROUTINE push_interafece END SUBROUTINE push_interface
!Solve the electromagnetic field !Solve the electromagnetic field
SUBROUTINE solveEM_interface() SUBROUTINE solveEM_interface()
@ -123,7 +123,12 @@ MODULE moduleSolver
END SELECT END SELECT
self%pushSpecies = .FALSE. self%pushSpecies = .FALSE.
self%every = INT(tauSp/tau) self%every = FLOOR(tauSp/tau)
!Correct value if not fulfilled
IF (tau*REAL(self%every) < tauSp) THEN
self%every = self%every + 1
END IF
END SUBROUTINE initPusher END SUBROUTINE initPusher
@ -164,24 +169,75 @@ MODULE moduleSolver
USE moduleMesh USE moduleMesh
IMPLICIT NONE IMPLICIT NONE
INTEGER:: n INTEGER:: p
INTEGER:: sp INTEGER:: s, sp
INTEGER:: e
!$OMP DO !$OMP SINGLE
DO n = 1, nPartOld !Allocate the array of particles to push
!Select species type nSpeciesToPush = COUNT(solver%pusher(:)%pushSpecies)
sp = partOld(n)%species%n ALLOCATE(particlesToPush(1:nSpeciesToPush))
ALLOCATE(nPartOldToPush(1:nSpeciesToPush))
!Point the arrays to the location of the particles
sp = 0
DO s = 1, nSpecies
!Checks if the species sp is update this iteration !Checks if the species sp is update this iteration
IF (solver%pusher(sp)%pushSpecies) THEN IF (solver%pusher(sp)%pushSpecies) THEN
!Push particle sp = sp + 1
CALL solver%pusher(sp)%pushParticle(partOld(n), tau(sp)) particlesToPush(sp)%p = partOld(s)%p
!Find cell in wich particle reside nPartOldToPush(sp) = nPartOld(s)
CALL solver%updateParticleCell(partOld(n))
END IF END IF
END DO END DO
!$OMP END DO
!Delete list of particles in cells for collisions if the particle is pushed
IF (listInCells) THEN
DO e = 1, mesh%numCells
DO s = 1, nSpecies
IF (solver%pusher(s)%pushSpecies) THEN
CALL mesh%cells(e)%obj%listPart_in(s)%erase()
mesh%cells(e)%obj%totalWeight(s) = 0.D0
END IF
END DO
END DO
END IF
!Erase the list of particles inside the cell in coll mesh if the particle is pushed
IF (doubleMesh) THEN
DO e = 1, meshColl%numCells
DO s = 1, nSpecies
IF (solver%pusher(s)%pushSpecies) THEN
CALL meshColl%cells(e)%obj%listPart_in(s)%erase()
meshColl%cells(e)%obj%totalWeight(s) = 0.D0
END IF
END DO
END DO
END IF
!$OMP END SINGLE
!Now, push particles
!$OMP DO
DO sp = 1, nSpeciesToPush
DO p = 1, nPartOldToPush(sp)
!Push particle
CALL solver%pusher(sp)%pushParticle(particlesToPush(sp)%p(p), tau(sp))
!Find cell in which particle reside
CALL solver%updateParticleCell(particlesToPush(sp)%p(p))
END DO
END DO
!$END OMP DO
END SUBROUTINE doPushes END SUBROUTINE doPushes
@ -242,7 +298,10 @@ MODULE moduleSolver
!$OMP SECTION !$OMP SECTION
nOldIn = 0 nOldIn = 0
IF (ALLOCATED(partOld)) THEN IF (ALLOCATED(partOld)) THEN
nOldIn = COUNT(partOld%n_in) DO s = 1, nSpecies
nOldIn = nOldin + COUNT(partOld(s)%p(:)%n_in)
END DO
END IF END IF
!$OMP SECTION !$OMP SECTION
@ -319,40 +378,6 @@ MODULE moduleSolver
END DO END DO
!$OMP SECTION
!Erase the list of particles inside the cell if particles have been pushed
IF (listInCells) THEN
DO s = 1, nSpecies
DO e = 1, mesh%numCells
IF (solver%pusher(s)%pushSpecies) THEN
CALL mesh%cells(e)%obj%listPart_in(s)%erase()
mesh%cells(e)%obj%totalWeight(s) = 0.D0
END IF
END DO
END DO
END IF
!$OMP SECTION
!Erase the list of particles inside the cell in coll mesh
IF (doubleMesh) THEN
DO s = 1, nSpecies
DO e = 1, meshColl%numCells
IF (solver%pusher(s)%pushSpecies) THEN
CALL meshColl%cells(e)%obj%listPart_in(s)%erase()
meshColl%cells(e)%obj%totalWeight(s) = 0.D0
END IF
END DO
END DO
END IF
!$OMP END SECTIONS !$OMP END SECTIONS
!$OMP SINGLE !$OMP SINGLE
@ -367,14 +392,17 @@ MODULE moduleSolver
USE moduleMesh USE moduleMesh
IMPLICIT NONE IMPLICIT NONE
INTEGER:: n INTEGER:: n, sp
CLASS(meshCell), POINTER:: cell CLASS(meshCell), POINTER:: cell
!Loops over the particles to scatter them !Loops over the particles to scatter them
!$OMP DO !$OMP DO
DO n = 1, nPartOld DO sp = 1, nSpeciesToPush
cell => mesh%cells(partOld(n)%cell)%obj DO n = 1, nPartOldToPush(sp)
CALL cell%scatter(cell%nNodes, partOld(n)) cell => mesh%cells(particlesToPush(sp)%p(n)%cell)%obj
CALL cell%scatter(cell%nNodes, particlesToPush(sp)%p(n))
END DO
END DO END DO
!$OMP END DO !$OMP END DO
@ -544,8 +572,8 @@ MODULE moduleSolver
END IF END IF
IF (nPartOld > 0) THEN IF (nPartOldTotal > 0) THEN
WRITE(*, "(5X,A21,F8.1,A2)") "avg t/particle: ", 1.D9*tStep/DBLE(nPartOld), "ns" WRITE(*, "(5X,A21,F8.1,A2)") "avg t/particle: ", 1.D9*tStep/DBLE(nPartOldTotal), "ns"
END IF END IF
WRITE(*,*) WRITE(*,*)

View file

@ -14,7 +14,7 @@ MODULE modulePusher
END SUBROUTINE pushCartNeutral END SUBROUTINE pushCartNeutral
PURE SUBROUTINE pushCartElectrostatic(part, tauIn) PURE SUBROUTINE pushCartElectrostatic(part, tauIn)
USE moduleSPecies USE moduleSpecies
USE moduleMesh USE moduleMesh
IMPLICIT NONE IMPLICIT NONE