Merge branch 'issue/injection2DCyl' into 'development'

Rework of injection of particles with a special focus in 2DCyl to ensure an homogeneous distribution.

See merge request JorgeGonz/fpakc!51
This commit is contained in:
Jorge Gonzalez 2024-07-11 16:51:42 +00:00
commit 065bb1d13e
17 changed files with 220 additions and 142 deletions

View file

@ -6,6 +6,7 @@
*.aux *.aux
*.ps *.ps
bibliography.bib.bak bibliography.bib.bak
bibliography.bib.sav
*.bbl *.bbl
*.blg *.blg
*.out *.out

Binary file not shown.

View file

@ -611,7 +611,7 @@ make
\begin{itemize} \begin{itemize}
\item \textbf{A}: Ampere. \item \textbf{A}: Ampere.
\item \textbf{Am2}: Ampere per square meter. \item \textbf{Am2}: Ampere per square meter.
This value will be multiplied by the square of the reference length to convert to A, it will not consider the surface area of injection. This value will be multiplied by the surface of injection.
\item \textbf{sccm}: Standard cubic centimetre. \item \textbf{sccm}: Standard cubic centimetre.
\item \textbf{part/s}: Particles (real) per second. \item \textbf{part/s}: Particles (real) per second.
\end{itemize} \end{itemize}
@ -638,6 +638,11 @@ make
Temperature in each direction. Temperature in each direction.
\item \textbf{physicalSurface}: Integer. \item \textbf{physicalSurface}: Integer.
Identification of the edge in the mesh file. Identification of the edge in the mesh file.
\item \textbf{particlesPerEdge}: Integer.
Optional.
Number of particles to be injected by each edge in the numerical domain.
The weight of the particles for each edge will modified by the surface of the edge to ensure the right flux is injected.
If no value is provided, the number of particles to inject per edge will be calculated with the species weight and the surface of the edge respect to the total one.
\end{itemize} \end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{reference} \subsection{reference}
@ -713,6 +718,10 @@ make
The file format must be the same as in \textbf{geometry.meshType} The file format must be the same as in \textbf{geometry.meshType}
Initial particles are assumed to have a Maxwellian distribution. Initial particles are assumed to have a Maxwellian distribution.
File must be located at \textbf{output.path}. File must be located at \textbf{output.path}.
\item \textbf{particlesPerCell}: Integer.
Optional.
Initial number of particles per cell.
If not, the number of particles per cell will be assigned based on the species weight and the cell volume.
\end{itemize} \end{itemize}
\end{itemize} \end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -40,10 +40,10 @@ MODULE moduleRandom
INTEGER:: rnd INTEGER:: rnd
REAL(8):: rnd01 REAL(8):: rnd01
rnd = 0.D0 rnd = 0
CALL RANDOM_NUMBER(rnd01) CALL RANDOM_NUMBER(rnd01)
rnd = INT(REAL(b - a) * rnd01) + 1 rnd = a + FLOOR((b+1-a)*rnd01)
END FUNCTION randomIntAB END FUNCTION randomIntAB

View file

@ -308,7 +308,7 @@ MODULE moduleInput
LOGICAL:: found LOGICAL:: found
CHARACTER(:), ALLOCATABLE:: object CHARACTER(:), ALLOCATABLE:: object
INTEGER:: nInitial INTEGER:: nInitial
INTEGER:: i, j, p, e INTEGER:: i, p, e
CHARACTER(LEN=2):: iString CHARACTER(LEN=2):: iString
CHARACTER(:), ALLOCATABLE:: spName CHARACTER(:), ALLOCATABLE:: spName
INTEGER:: sp INTEGER:: sp
@ -324,7 +324,8 @@ MODULE moduleInput
REAL(8):: densityCen REAL(8):: densityCen
!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
REAL(8):: weight = 0.D0
CLASS(meshCell), POINTER:: cell CLASS(meshCell), POINTER:: cell
TYPE(particle), POINTER:: partNew TYPE(particle), POINTER:: partNew
REAL(8):: vTh REAL(8):: vTh
@ -343,6 +344,9 @@ MODULE moduleInput
!Reads node values at the nodes !Reads node values at the nodes
filename = path // spFile filename = path // spFile
CALL mesh%readInitial(filename, density, velocity, temperature) CALL mesh%readInitial(filename, density, velocity, temperature)
!Check if initial number of particles is given
CALL config%get(object // '.particlesPerCell', nNewPart, found)
!For each volume in the node, create corresponding particles !For each volume in the node, create corresponding particles
DO e = 1, mesh%numCells DO e = 1, mesh%numCells
!Scale variables !Scale variables
@ -355,7 +359,11 @@ MODULE moduleInput
densityCen = mesh%cells(e)%obj%gatherF((/ 0.D0, 0.D0, 0.D0 /), nNodes, sourceScalar) densityCen = mesh%cells(e)%obj%gatherF((/ 0.D0, 0.D0, 0.D0 /), nNodes, sourceScalar)
!Calculate number of particles !Calculate number of particles
nNewPart = INT(densityCen * (mesh%cells(e)%obj%volume*Vol_ref) / species(sp)%obj%weight) IF (.NOT. found) THEN
nNewPart = FLOOR(densityCen * (mesh%cells(e)%obj%volume*Vol_ref) / species(sp)%obj%weight)
END IF
weight = densityCen * (mesh%cells(e)%obj%volume*Vol_ref) / REAL(nNewPart)
!Allocate new particles !Allocate new particles
DO p = 1, nNewPart DO p = 1, nNewPart
@ -392,7 +400,7 @@ MODULE moduleInput
partNew%n_in = .TRUE. partNew%n_in = .TRUE.
partNew%weight = species(sp)%obj%weight partNew%weight = weight
!Assign particle to temporal list of particles !Assign particle to temporal list of particles
CALL partInitial%add(partNew) CALL partInitial%add(partNew)
@ -915,7 +923,6 @@ MODULE moduleInput
LOGICAL:: found LOGICAL:: found
CHARACTER(:), ALLOCATABLE:: meshFormat, meshFile CHARACTER(:), ALLOCATABLE:: meshFormat, meshFile
REAL(8):: volume REAL(8):: volume
CHARACTER(:), ALLOCATABLE:: meshFileVTU !Temporary to test VTU OUTPUT
object = 'geometry' object = 'geometry'
@ -1228,6 +1235,7 @@ MODULE moduleInput
REAL(8):: flow REAL(8):: flow
CHARACTER(:), ALLOCATABLE:: units CHARACTER(:), ALLOCATABLE:: units
INTEGER:: physicalSurface INTEGER:: physicalSurface
INTEGER:: particlesPerEdge
INTEGER:: sp INTEGER:: sp
CALL config%info('inject', found, n_children = nInject) CALL config%info('inject', found, n_children = nInject)
@ -1252,8 +1260,10 @@ MODULE moduleInput
CALL config%get(object // '.flow', flow, found) CALL config%get(object // '.flow', flow, found)
CALL config%get(object // '.units', units, found) CALL config%get(object // '.units', units, found)
CALL config%get(object // '.physicalSurface', physicalSurface, found) CALL config%get(object // '.physicalSurface', physicalSurface, found)
particlesPerEdge = 0
CALL config%get(object // '.particlesPerEdge', particlesPerEdge, found)
CALL inject(i)%init(i, v, normal, T, flow, units, sp, physicalSurface) CALL inject(i)%init(i, v, normal, T, flow, units, sp, physicalSurface, particlesPerEdge)
CALL readVelDistr(config, inject(i), object) CALL readVelDistr(config, inject(i), object)

View file

@ -104,6 +104,7 @@ MODULE moduleMesh1DCart
USE moduleSpecies USE moduleSpecies
USE moduleBoundary USE moduleBoundary
USE moduleErrors USE moduleErrors
USE moduleRefParam, ONLY: L_ref
IMPLICIT NONE IMPLICIT NONE
CLASS(meshEdge1DCart), INTENT(out):: self CLASS(meshEdge1DCart), INTENT(out):: self
@ -122,6 +123,8 @@ MODULE moduleMesh1DCart
self%x = r1(1) self%x = r1(1)
self%surface = 1.D0 / L_ref**2
self%normal = (/ 1.D0, 0.D0, 0.D0 /) self%normal = (/ 1.D0, 0.D0, 0.D0 /)
!Boundary index !Boundary index

View file

@ -104,6 +104,7 @@ MODULE moduleMesh1DRad
USE moduleSpecies USE moduleSpecies
USE moduleBoundary USE moduleBoundary
USE moduleErrors USE moduleErrors
USE moduleRefParam, ONLY: L_ref
IMPLICIT NONE IMPLICIT NONE
CLASS(meshEdge1DRad), INTENT(out):: self CLASS(meshEdge1DRad), INTENT(out):: self
@ -122,6 +123,8 @@ MODULE moduleMesh1DRad
self%r = r1(1) self%r = r1(1)
self%surface = 1.D0 / L_ref**2
self%normal = (/ 1.D0, 0.D0, 0.D0 /) self%normal = (/ 1.D0, 0.D0, 0.D0 /)
!Boundary index !Boundary index

View file

@ -144,6 +144,7 @@ MODULE moduleMesh2DCart
USE moduleSpecies USE moduleSpecies
USE moduleBoundary USE moduleBoundary
USE moduleErrors USE moduleErrors
USE moduleRefParam, ONLY: L_ref
IMPLICIT NONE IMPLICIT NONE
CLASS(meshEdge2DCart), INTENT(out):: self CLASS(meshEdge2DCart), INTENT(out):: self
@ -163,7 +164,7 @@ MODULE moduleMesh2DCart
r2 = self%n2%getCoordinates() r2 = self%n2%getCoordinates()
self%x = (/r1(1), r2(1)/) self%x = (/r1(1), r2(1)/)
self%y = (/r1(2), r2(2)/) self%y = (/r1(2), r2(2)/)
self%weight = 1.D0 self%surface = SQRT((self%x(2) - self%x(1))**2 + (self%y(2) - self%y(1))**2) / L_ref
!Normal vector !Normal vector
self%normal = (/ -(self%y(2)-self%y(1)), & self%normal = (/ -(self%y(2)-self%y(1)), &
self%x(2)-self%x(1) , & self%x(2)-self%x(1) , &
@ -556,6 +557,7 @@ MODULE moduleMesh2DCart
!Compute element volume !Compute element volume
PURE SUBROUTINE volumeQuad(self) PURE SUBROUTINE volumeQuad(self)
USE moduleRefParam, ONLY: L_ref
IMPLICIT NONE IMPLICIT NONE
CLASS(meshCell2DCartQuad), INTENT(inout):: self CLASS(meshCell2DCartQuad), INTENT(inout):: self
@ -573,7 +575,7 @@ MODULE moduleMesh2DCart
fPsi = self%fPsi(Xi, 4) fPsi = self%fPsi(Xi, 4)
!Compute total volume of the cell !Compute total volume of the cell
self%volume = detJ*4.D0 self%volume = detJ*4.D0/L_ref
!Compute volume per node !Compute volume per node
self%n1%v = self%n1%v + fPsi(1)*self%volume self%n1%v = self%n1%v + fPsi(1)*self%volume
self%n2%v = self%n2%v + fPsi(2)*self%volume self%n2%v = self%n2%v + fPsi(2)*self%volume

View file

@ -144,6 +144,7 @@ MODULE moduleMesh2DCyl
USE moduleSpecies USE moduleSpecies
USE moduleBoundary USE moduleBoundary
USE moduleErrors USE moduleErrors
USE moduleConstParam, ONLY: PI
IMPLICIT NONE IMPLICIT NONE
CLASS(meshEdge2DCyl), INTENT(out):: self CLASS(meshEdge2DCyl), INTENT(out):: self
@ -163,7 +164,15 @@ MODULE moduleMesh2DCyl
r2 = self%n2%getCoordinates() r2 = self%n2%getCoordinates()
self%z = (/r1(1), r2(1)/) self%z = (/r1(1), r2(1)/)
self%r = (/r1(2), r2(2)/) self%r = (/r1(2), r2(2)/)
self%weight = DABS(self%r(2)**2 - self%r(1)**2) !Edge surface
IF (self%z(2) /= self%z(1)) THEN
self%surface = ABS(self%r(2) + self%r(1))*ABS(self%z(2) - self%z(1))
ELSE
self%surface = ABS(self%r(2)**2 - self%r(1)**2)
END IF
self%surface = self%surface * PI
!Normal vector !Normal vector
self%normal = (/ -(self%r(2)-self%r(1)), & self%normal = (/ -(self%r(2)-self%r(1)), &
self%z(2)-self%z(1) , & self%z(2)-self%z(1) , &
@ -226,11 +235,6 @@ MODULE moduleMesh2DCyl
REAL(8):: p1(1:2), p2(1:2) REAL(8):: p1(1:2), p2(1:2)
rnd = random() rnd = random()
IF (self%r(1) == 0.D0 .OR. &
self%r(2) == 0.D0) THEN
rnd = rnd**(1.D0/3.D0)
END IF
p1 = (/self%z(1), self%r(1) /) p1 = (/self%z(1), self%r(1) /)
p2 = (/self%z(2), self%r(2) /) p2 = (/self%z(2), self%r(2) /)
@ -243,7 +247,6 @@ MODULE moduleMesh2DCyl
!QUAD FUNCTIONS !QUAD FUNCTIONS
!Init element !Init element
SUBROUTINE initCellQuad2DCyl(self, n, p, nodes) SUBROUTINE initCellQuad2DCyl(self, n, p, nodes)
USE moduleRefParam
IMPLICIT NONE IMPLICIT NONE
CLASS(meshCell2DCylQuad), INTENT(out):: self CLASS(meshCell2DCylQuad), INTENT(out):: self
@ -589,12 +592,20 @@ MODULE moduleMesh2DCyl
fPsi = self%fPsi(Xi, 4) fPsi = self%fPsi(Xi, 4)
r = DOT_PRODUCT(fPsi,self%r) r = DOT_PRODUCT(fPsi,self%r)
!Computes total volume of the cell !Computes total volume of the cell
self%volume = r*detJ*PI8 !4*2*pi self%volume = r*detJ*PI8 !2*pi * 4 (weight of 1 point 2D-Gaussian integral)
!Computes volume per node !Computes volume per node. Change the radius point to calculate the area to improve accuracy near the axis.
self%n1%v = self%n1%v + fPsi(1)*self%volume Xi = (/-5.D-1, -0.25D0, 0.D0/)
self%n2%v = self%n2%v + fPsi(2)*self%volume r = self%gatherF(Xi, 4, self%r)
self%n3%v = self%n3%v + fPsi(3)*self%volume self%n1%v = self%n1%v + fPsi(1)*r*detJ*PI8
self%n4%v = self%n4%v + fPsi(4)*self%volume Xi = (/ 5.D-1, -0.25D0, 0.D0/)
r = self%gatherF(Xi, 4, self%r)
self%n2%v = self%n2%v + fPsi(2)*r*detJ*PI8
Xi = (/ 5.D-1, 0.75D0, 0.D0/)
r = self%gatherF(Xi, 4, self%r)
self%n3%v = self%n3%v + fPsi(3)*r*detJ*PI8
Xi = (/-5.D-1, 0.75D0, 0.D0/)
r = self%gatherF(Xi, 4, self%r)
self%n4%v = self%n4%v + fPsi(4)*r*detJ*PI8
END SUBROUTINE volumeQuad END SUBROUTINE volumeQuad

View file

@ -109,6 +109,7 @@ MODULE moduleMesh3DCart
USE moduleBoundary USE moduleBoundary
USE moduleErrors USE moduleErrors
USE moduleMath USE moduleMath
USE moduleRefParam, ONLY: L_ref
IMPLICIT NONE IMPLICIT NONE
CLASS(meshEdge3DCartTria), INTENT(out):: self CLASS(meshEdge3DCartTria), INTENT(out):: self
@ -142,6 +143,8 @@ MODULE moduleMesh3DCart
self%normal = crossProduct(vec1, vec2) self%normal = crossProduct(vec1, vec2)
self%normal = normalize(self%normal) self%normal = normalize(self%normal)
self%surface = 1.D0/L_ref**2 !TODO: FIX THIS WHEN MOVING TO 3D
!Boundary index !Boundary index
self%boundary => boundary(bt) self%boundary => boundary(bt)
ALLOCATE(self%fBoundary(1:nSpecies)) ALLOCATE(self%fBoundary(1:nSpecies))

View file

@ -108,6 +108,7 @@ MODULE moduleMeshInputGmsh2
READ(10, *) totalNumElem READ(10, *) totalNumElem
!Count edges and volume elements !Count edges and volume elements
numEdges = 0
SELECT TYPE(self) SELECT TYPE(self)
TYPE IS(meshParticles) TYPE IS(meshParticles)
self%numEdges = 0 self%numEdges = 0
@ -328,7 +329,7 @@ MODULE moduleMeshInputGmsh2
DO i = 1, numNodes DO i = 1, numNodes
!Reads the density !Reads the density
READ(10, *), e, density(i) READ(10, *) e, density(i)
END DO END DO
@ -339,7 +340,7 @@ MODULE moduleMeshInputGmsh2
DO i = 1, numNodes DO i = 1, numNodes
!Reads the velocity !Reads the velocity
READ(10, *), e, velocity(i, 1:3) READ(10, *) e, velocity(i, 1:3)
END DO END DO

View file

@ -275,6 +275,7 @@ MODULE moduleMeshInputVTU
END DO END DO
!Count the number of edges !Count the number of edges
numEdges = 0
SELECT CASE(self%dimen) SELECT CASE(self%dimen)
CASE(3) CASE(3)
!Edges are triangles, type 5 in VTK !Edges are triangles, type 5 in VTK

View file

@ -315,9 +315,8 @@ MODULE moduleMeshOutputVTU
CLASS(meshParticles), INTENT(in):: self CLASS(meshParticles), INTENT(in):: self
INTEGER, INTENT(in):: t INTEGER, INTENT(in):: t
INTEGER:: n, i, fileID INTEGER:: i, fileID
CHARACTER(:), ALLOCATABLE:: fileName, fileNameCollection CHARACTER(:), ALLOCATABLE:: fileName, fileNameCollection
TYPE(outputFormat):: output(1:self%numNodes)
fileID = 60 fileID = 60
@ -352,10 +351,9 @@ MODULE moduleMeshOutputVTU
CLASS(meshGeneric), INTENT(in):: self CLASS(meshGeneric), INTENT(in):: self
INTEGER, INTENT(in):: t INTEGER, INTENT(in):: t
INTEGER:: n, i, fileID INTEGER:: fileID
CHARACTER(:), ALLOCATABLE:: fileName, fileNameCollection CHARACTER(:), ALLOCATABLE:: fileName, fileNameCollection
CHARACTER (LEN=iterationDigits):: tstring CHARACTER (LEN=iterationDigits):: tstring
TYPE(outputFormat):: output(1:self%numNodes)
fileID = 62 fileID = 62
@ -424,9 +422,8 @@ MODULE moduleMeshOutputVTU
IMPLICIT NONE IMPLICIT NONE
CLASS(meshParticles), INTENT(in):: self CLASS(meshParticles), INTENT(in):: self
INTEGER:: n, i, fileIDMean, fileIDDeviation INTEGER:: i, fileIDMean, fileIDDeviation
CHARACTER(:), ALLOCATABLE:: fileNameMean, fileNameDeviation CHARACTER(:), ALLOCATABLE:: fileNameMean, fileNameDeviation
TYPE(outputFormat):: output(1:self%numNodes)
fileIDMean = 66 fileIDMean = 66
fileIDDeviation = 67 fileIDDeviation = 67

View file

@ -76,8 +76,8 @@ MODULE moduleMesh
CLASS(meshCell), POINTER:: eColl => NULL() CLASS(meshCell), POINTER:: eColl => NULL()
!Normal vector !Normal vector
REAL(8):: normal(1:3) REAL(8):: normal(1:3)
!Weight for random injection of particles ! Surface of edge
REAL(8):: weight = 1.D0 REAL(8):: surface = 0.D0
!Pointer to boundary type !Pointer to boundary type
TYPE(boundaryCont), POINTER:: boundary TYPE(boundaryCont), POINTER:: boundary
!Array of functions for boundary conditions !Array of functions for boundary conditions
@ -613,6 +613,7 @@ MODULE moduleMesh
INTEGER:: sp INTEGER:: sp
INTEGER:: i INTEGER:: i
CLASS(meshNode), POINTER:: node CLASS(meshNode), POINTER:: node
REAL(8):: pFraction !Particle fraction
cellNodes = self%getNodes(nNodes) cellNodes = self%getNodes(nNodes)
fPsi = self%fPsi(part%Xi, nNodes) fPsi = self%fPsi(part%Xi, nNodes)
@ -623,10 +624,11 @@ MODULE moduleMesh
DO i = 1, nNodes DO i = 1, nNodes
node => mesh%nodes(cellNodes(i))%obj node => mesh%nodes(cellNodes(i))%obj
pFraction = fPsi(i)*part%weight
CALL OMP_SET_LOCK(node%lock) CALL OMP_SET_LOCK(node%lock)
node%output(sp)%den = node%output(sp)%den + part%weight*fPsi(i) node%output(sp)%den = node%output(sp)%den + pFraction
node%output(sp)%mom(:) = node%output(sp)%mom(:) + part%weight*fPsi(i)*part%v(:) node%output(sp)%mom(:) = node%output(sp)%mom(:) + pFraction*part%v(:)
node%output(sp)%tensorS(:,:) = node%output(sp)%tensorS(:,:) + part%weight*fPsi(i)*tensorS node%output(sp)%tensorS(:,:) = node%output(sp)%tensorS(:,:) + pFraction*tensorS
CALL OMP_UNSET_LOCK(node%lock) CALL OMP_UNSET_LOCK(node%lock)
END DO END DO
@ -1023,6 +1025,9 @@ MODULE moduleMesh
ALLOCATE(deltaV_ij(1:cell%listPart_in(i)%amount, 1:3)) ALLOCATE(deltaV_ij(1:cell%listPart_in(i)%amount, 1:3))
ALLOCATE(p_ij(1:cell%listPart_in(i)%amount, 1:3)) ALLOCATE(p_ij(1:cell%listPart_in(i)%amount, 1:3))
ALLOCATE(mass_ij(1:cell%listPart_in(i)%amount)) ALLOCATE(mass_ij(1:cell%listPart_in(i)%amount))
deltaV_ij = 0.D0
p_ij = 0.D0
mass_ij = 0.D0
!Loop over particles of species_i !Loop over particles of species_i
partTemp => cell%listPart_in(i)%head partTemp => cell%listPart_in(i)%head
p = 1 p = 1
@ -1107,6 +1112,9 @@ MODULE moduleMesh
ALLOCATE(deltaV_ji(1:cell%listPart_in(j)%amount, 1:3)) ALLOCATE(deltaV_ji(1:cell%listPart_in(j)%amount, 1:3))
ALLOCATE(p_ji(1:cell%listPart_in(j)%amount, 1:3)) ALLOCATE(p_ji(1:cell%listPart_in(j)%amount, 1:3))
ALLOCATE(mass_ji(1:cell%listPart_in(j)%amount)) ALLOCATE(mass_ji(1:cell%listPart_in(j)%amount))
deltaV_ji = 0.D0
p_ji = 0.D0
mass_ji = 0.D0
!Loop over particles of species_j !Loop over particles of species_j
partTemp => cell%listPart_in(j)%head partTemp => cell%listPart_in(j)%head
p = 1 p = 1

View file

@ -61,8 +61,9 @@ MODULE moduleInject
CLASS(speciesGeneric), POINTER:: species !Species of injection CLASS(speciesGeneric), POINTER:: species !Species of injection
INTEGER:: nEdges INTEGER:: nEdges
INTEGER, ALLOCATABLE:: edges(:) !Array with edges INTEGER, ALLOCATABLE:: edges(:) !Array with edges
REAL(8), ALLOCATABLE:: cumWeight(:) !Array of cummulative probability INTEGER, ALLOCATABLE:: particlesPerEdge(:) ! Particles per edge
REAL(8):: sumWeight REAL(8), ALLOCATABLE:: weightPerEdge(:) ! Weight per edge
REAL(8):: surface ! Total surface of injection
TYPE(velDistCont):: v(1:3) !Velocity distribution function in each direction TYPE(velDistCont):: v(1:3) !Velocity distribution function in each direction
CONTAINS CONTAINS
PROCEDURE, PASS:: init => initInject PROCEDURE, PASS:: init => initInject
@ -75,7 +76,7 @@ MODULE moduleInject
CONTAINS CONTAINS
!Initialize an injection of particles !Initialize an injection of particles
SUBROUTINE initInject(self, i, v, n, T, flow, units, sp, physicalSurface) SUBROUTINE initInject(self, i, v, n, T, flow, units, sp, physicalSurface, particlesPerEdge)
USE moduleMesh USE moduleMesh
USE moduleRefParam USE moduleRefParam
USE moduleConstParam USE moduleConstParam
@ -87,52 +88,28 @@ MODULE moduleInject
CLASS(injectGeneric), INTENT(inout):: self CLASS(injectGeneric), INTENT(inout):: self
INTEGER, INTENT(in):: i INTEGER, INTENT(in):: i
REAL(8), INTENT(in):: v, n(1:3), T(1:3) REAL(8), INTENT(in):: v, n(1:3), T(1:3)
INTEGER, INTENT(in):: sp, physicalSurface INTEGER, INTENT(in):: sp, physicalSurface, particlesPerEdge
REAL(8):: tauInject REAL(8):: tauInject
REAL(8), INTENT(in):: flow REAL(8), INTENT(in):: flow
CHARACTER(:), ALLOCATABLE, INTENT(in):: units CHARACTER(:), ALLOCATABLE, INTENT(in):: units
INTEGER:: e, et INTEGER:: e, et
INTEGER:: phSurface(1:mesh%numEdges) INTEGER:: phSurface(1:mesh%numEdges)
INTEGER:: nVolColl INTEGER:: nVolColl
REAL(8):: fluxPerStep = 0.D0
self%id = i self%id = i
self%vMod = v / v_ref self%vMod = v / v_ref
self%n = n / NORM2(n) self%n = n / NORM2(n)
self%T = T / T_ref self%T = T / T_ref
self%species => species(sp)%obj
tauInject = tau(self%species%n)
SELECT CASE(units)
CASE ("sccm")
!Standard cubic centimeter per minute
self%nParticles = INT(flow*sccm2atomPerS*tauInject*ti_ref/species(sp)%obj%weight)
CASE ("A")
!Input current in Ampers
self%nParticles = INT(flow*tauInject*ti_ref/(qe*species(sp)%obj%weight))
CASE ("Am2")
!Input current in Ampers per square meter
self%nParticles = INT(flow*tauInject*ti_ref*L_ref**2/(qe*species(sp)%obj%weight))
CASE ("part/s")
!Input current in Ampers
self%nParticles = INT(flow*tauInject*ti_ref/species(sp)%obj%weight)
CASE DEFAULT
CALL criticalError("No support for units: " // units, 'initInject')
END SELECT
!Scale particles for different species steps
IF (self%nParticles == 0) CALL criticalError("The number of particles for inject is 0.", 'initInject')
!Gets the edge elements from which particles are injected !Gets the edge elements from which particles are injected
DO e = 1, mesh%numEdges DO e = 1, mesh%numEdges
phSurface(e) = mesh%edges(e)%obj%physicalSurface phSurface(e) = mesh%edges(e)%obj%physicalSurface
END DO END DO
self%nEdges = COUNT(phSurface == physicalSurface) self%nEdges = COUNT(phSurface == physicalSurface)
ALLOCATE(inject(i)%edges(1:self%nEdges)) ALLOCATE(self%edges(1:self%nEdges))
ALLOCATE(self%particlesPerEdge(1:self%nEdges))
ALLOCATE(self%weightPerEdge(1:self%nEdges))
et = 0 et = 0
DO e=1, mesh%numEdges DO e=1, mesh%numEdges
IF (mesh%edges(e)%obj%physicalSurface == physicalSurface) THEN IF (mesh%edges(e)%obj%physicalSurface == physicalSurface) THEN
@ -164,15 +141,63 @@ MODULE moduleInject
END DO END DO
!Calculates cumulative probability !Calculates total area
ALLOCATE(self%cumWeight(1:self%nEdges)) self%surface = 0.D0
et = 1 DO et = 1, self%nEdges
self%cumWeight(1) = mesh%edges(self%edges(et))%obj%weight self%surface = self%surface + mesh%edges(self%edges(et))%obj%surface
DO et = 2, self%nEdges
self%cumWeight(et) = mesh%edges(self%edges(et))%obj%weight + self%cumWeight(et-1)
END DO END DO
self%sumWeight = self%cumWeight(self%nEdges)
! Information about species and flux
self%species => species(sp)%obj
tauInject = tau(self%species%n)
! Convert units
SELECT CASE(units)
CASE ("sccm")
!Standard cubic centimeter per minute
fluxPerStep = flow*sccm2atomPerS
CASE ("A")
!Current in Ampers
fluxPerStep = flow/qe
CASE ("Am2")
!Input current in Ampers per square meter
fluxPerStep = flow*self%surface*L_ref**2/qe
CASE ("part/s")
!Input current in Ampers
fluxPerStep = flow
CASE DEFAULT
CALL criticalError("No support for units: " // units, 'initInject')
END SELECT
fluxPerStep = fluxPerStep * tauInject * ti_ref / self%surface
!Assign particles per edge
IF (particlesPerEdge > 0) THEN
! Particles per edge defined by the user
self%particlesPerEdge = particlesPerEdge
DO et = 1, self%nEdges
self%weightPerEdge(et) = fluxPerStep*mesh%edges(self%edges(et))%obj%surface / REAL(particlesPerEdge)
END DO
ELSE
! No particles assigned per edge, use the species weight
self%weightPerEdge = self%species%weight
DO et = 1, self%nEdges
self%particlesPerEdge(et) = FLOOR(fluxPerStep*mesh%edges(self%edges(et))%obj%surface /self%species%weight)
END DO
END IF
self%nParticles = SUM(self%particlesPerEdge)
!Scale particles for different species steps
IF (self%nParticles == 0) CALL criticalError("The number of particles for inject is 0.", 'initInject')
END SUBROUTINE initInject END SUBROUTINE initInject
@ -286,9 +311,8 @@ MODULE moduleInject
IMPLICIT NONE IMPLICIT NONE
CLASS(injectGeneric), INTENT(in):: self CLASS(injectGeneric), INTENT(in):: self
INTEGER:: randomX INTEGER, SAVE:: nMin
INTEGER, SAVE:: nMin, nMax !Min and Max index in partInj array INTEGER:: i, e
INTEGER:: i
INTEGER:: n, sp INTEGER:: n, sp
CLASS(meshEdge), POINTER:: randomEdge CLASS(meshEdge), POINTER:: randomEdge
REAL(8):: direction(1:3) REAL(8):: direction(1:3)
@ -303,21 +327,23 @@ MODULE moduleInject
END IF END IF
END DO END DO
nMin = nMin + 1 nMin = nMin + 1
nMax = nMin + self%nParticles - 1
!Particle is considered to be outside the domain
partInj(nMin:nMax)%n_in = .FALSE.
!$OMP END SINGLE !$OMP END SINGLE
!$OMP DO !$OMP DO
DO n = nMin, nMax DO e = 1, self%nEdges
randomX = randomWeighted(self%cumWeight, self%sumWeight) ! Select edge for injection
randomEdge => mesh%edges(self%edges(randomX))%obj randomEdge => mesh%edges(self%edges(e))%obj
! Inject particles in edge
DO i = 1, self%particlesPerEdge(e)
! Index in the global partInj array
n = nMin - 1 + SUM(self%particlesPerEdge(1:e-1)) + i
!Particle is considered to be outside the domain
partInj(n)%n_in = .FALSE.
!Random position in edge !Random position in edge
partInj(n)%r = randomEdge%randPos() partInj(n)%r = randomEdge%randPos()
!Assign weight to particle. !Assign weight to particle.
partInj(n)%weight = self%species%weight partInj(n)%weight = self%weightPerEdge(e)
!Volume associated to the edge: !Volume associated to the edge:
IF (ASSOCIATED(randomEdge%e1)) THEN IF (ASSOCIATED(randomEdge%e1)) THEN
partInj(n)%cell = randomEdge%e1%n partInj(n)%cell = randomEdge%e1%n
@ -357,6 +383,8 @@ MODULE moduleInject
CALL solver%updateParticleCell(partInj(n)) CALL solver%updateParticleCell(partInj(n))
END DO END DO
END DO
!$OMP END DO !$OMP END DO
END SUBROUTINE addParticles END SUBROUTINE addParticles

View file

@ -101,7 +101,7 @@ MODULE moduleProbe
!Maximum radius !Maximum radius
!TODO: Make this an input parameter !TODO: Make this an input parameter
self%maxR = 1.D0 self%maxR = 1.D-2/L_ref
!Init the probe lock !Init the probe lock
CALL OMP_INIT_LOCK(self%lock) CALL OMP_INIT_LOCK(self%lock)
@ -148,7 +148,7 @@ MODULE moduleProbe
deltaR = NORM2(self%r - part%r) deltaR = NORM2(self%r - part%r)
!Only include particle if it is inside the maximum radius !Only include particle if it is inside the maximum radius
IF (deltaR < self%maxR) THEN ! IF (deltaR < self%maxR) THEN
!find lower index for all dimensions !find lower index for all dimensions
CALL self%findLowerIndex(part%v, i, j, k, inside) CALL self%findLowerIndex(part%v, i, j, k, inside)
@ -162,28 +162,28 @@ MODULE moduleProbe
fk = self%vk(k+1) - part%v(3) fk = self%vk(k+1) - part%v(3)
fk1 = part%v(3) - self%vk(k) fk1 = part%v(3) - self%vk(k)
! weight = part%weight * DEXP(deltaR/self%maxR) weight = part%weight * DEXP(-deltaR/self%maxR)
weight = part%weight ! weight = part%weight
!Lock the probe !Lock the probe
CALL OMP_SET_LOCK(self%lock) CALL OMP_SET_LOCK(self%lock)
!Assign particle weight to distribution function !Assign particle weight to distribution function
self%f(i , j , k ) = fi * fj * fk * weight self%f(i , j , k ) = self%f(i , j , k ) + fi * fj * fk * weight
self%f(i+1, j , k ) = fi1 * fj * fk * weight self%f(i+1, j , k ) = self%f(i+1, j , k ) + fi1 * fj * fk * weight
self%f(i , j+1, k ) = fi * fj1 * fk * weight self%f(i , j+1, k ) = self%f(i , j+1, k ) + fi * fj1 * fk * weight
self%f(i+1, j+1, k ) = fi1 * fj1 * fk * weight self%f(i+1, j+1, k ) = self%f(i+1, j+1, k ) + fi1 * fj1 * fk * weight
self%f(i , j , k+1) = fi * fj * fk1 * weight self%f(i , j , k+1) = self%f(i , j , k+1) + fi * fj * fk1 * weight
self%f(i+1, j , k+1) = fi1 * fj * fk1 * weight self%f(i+1, j , k+1) = self%f(i+1, j , k+1) + fi1 * fj * fk1 * weight
self%f(i , j+1, k+1) = fi * fj1 * fk1 * weight self%f(i , j+1, k+1) = self%f(i , j+1, k+1) + fi * fj1 * fk1 * weight
self%f(i+1, j+1, k+1) = fi1 * fj1 * fk1 * weight self%f(i+1, j+1, k+1) = self%f(i+1, j+1, k+1) + fi1 * fj1 * fk1 * weight
!Unlock the probe !Unlock the probe
CALL OMP_UNSET_LOCK(self%lock) CALL OMP_UNSET_LOCK(self%lock)
END IF END IF
END IF ! END IF
END IF END IF

View file

@ -30,6 +30,7 @@ MODULE moduleEM
INTEGER, ALLOCATABLE:: nodes(:) INTEGER, ALLOCATABLE:: nodes(:)
INTEGER:: n INTEGER:: n
nNodes = 1
nNodes = edge%nNodes nNodes = edge%nNodes
nodes = edge%getNodes(nNodes) nodes = edge%getNodes(nNodes)