Ionization boundary condition fully tested.

Documentation updated properly.

3D Cartesian geometry also tested.
Documentation updated properly.

Added weighting probability in the injection of particles.
This commit is contained in:
Jorge Gonzalez 2021-03-27 11:38:18 +01:00
commit 2a843547b8
8 changed files with 128 additions and 24 deletions

Binary file not shown.

View file

@ -123,6 +123,10 @@
Velocity and position are updated according to the old particle values and the external forces.
All the push routines for the different geometries can be found in \lstinline|moduleSolver|.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{3D Cartesian pusher}
Moving particles in a simple 3D Cartesian space.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{2D Cylindrical}
When a 2D cylindrical geometry is used ($z$, $r$), a Boris solver\cite{boris1970relativistic} is used to move particles accounting for the effect of the symmetry axis.
@ -151,7 +155,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Variable Weighting Scheme\label{sec:weightingScheme}}
One of the issues in particle simulations, specially for axisymmetrical cases, is that due to the disparate volume of cells, specially close to the axis, the statistics in some cells is usually poor.
One of the issues in particle simulations, specially for axial-symmetrical cases, is that due to the disparate volume of cells, specially close to the axis, the statistics in some cells is usually poor.
To try to fix that, the possibility to include a Variable Weighting Scheme in the simulations is available in \Gls{fpakc}.
This schemes detect when a particle change cells and modify its weight accordingly.
To avoid particles having a larger weight than the rest, particle can be split in multiple particles if weight become too large.
@ -341,6 +345,8 @@ make
Type of geometry.
Current accepted vaules are
\begin{itemize}
\item \textbf{3DCart}: Three-dimensional grid ($x \hyphen y \hyphen z$) in Cartesian coordinates..
For \Gls{gmsh} mesh format, the coordinates $x$, $y$ and $z$ correspond to $x$, $y$ and $z$ respectively.
\item \textbf{2DCyl}: Two-dimensional grid ($z \hyphen r$) with symmetry axis at $r = 0$.
For \Gls{gmsh} mesh format, the coordinates $x$ and $y$ correspond to $z$ and $r$ respectively.
\item \textbf{2DCart}: Two-dimensional grid ($x \hyphen y$) in Cartesian coordinates..
@ -401,8 +407,61 @@ make
\item \textbf{absorption}: Particle is eliminated from the domain.
The particle is first moved into the edge and its properties are scattered among the edge nodes.
\item \textbf{transparent}: Particle abandon the numerical domain.
\item \textbf{wallTemperature}: Reflective wall with cosntant temperature that exchange heat with particles.
Required parameters are:
\begin{itemize}
\item \textbf{temperature}: Real.
Units of $\unit{K}$.
Temperature wall.
\item \textbf{specificHeat}: Real.
Units of $\unit{J kg^{-1} K^{-1}}$.
Specific heat capacity of the material.
\end{itemize}
\item \textbf{ionization}: Per each particle crossing the surface with this type of boundary, a number of ionization events are calculated.
A pair of ion-electron is generated for each ionization event taking as a reference a neutral background.
Secondary electron is taken as same type as incident particle.
The available input is:
\begin{itemize}
\item \textbf{neutral}: Object.
Information about the neutral background.
Required parameters are:
\begin{itemize}
\item \textbf{ion}: Character.
Species name of the ion generated as defined in object \textbf{species}.
Required parameter.
\item \textbf{mass}: Real.
Units in $\unit{kg}$.
Mass of neutral species.
If missing, the mass of the ion is ussed
\item \textbf{density}: Real.
Units in $\unit{m^{-3}}$.
Density of neutral background.
Required parameter.
\item \textbf{velocity}: Real.
Units in $\unit{m^{-3}}$.
Array of dimension $3$.
Mean velocity of neutral background.
Required parameter.
\item \textbf{temperature}: Real.
Units in $\unit{K}$.
Temperature of neutral background.
Required parameter.
\end{itemize}
\item \textbf{effectiveTime}: Real.
Units in $\unit{s}$.
As the particle is no longer simulated once it crossed the boundary, this time represent the effective time in which the particle produces ionization processes in the neutral background.
Required parameter.
\item \textbf{energyThreashold}: Real.
Units in $\unit{eV}$.
Ionization energy threshold for the simulated process.
Required parameter.
\item \textbf{crossSection}: Character.
Complete path to the cross section data for the ionization process.
\end{itemize}
\item \textbf{axis}: Identifies the symmetry axis for 2D cylindrical simulations.
It has no actual function.
If for some reason a particle interact with this axis, it is reflected.
\end{itemize}
\item \textbf{physicalSurface}: Integer.
Identification of the edge in the mesh file.
@ -499,14 +558,16 @@ make
Array dimension 'number of species'.
Indicates the type of pusher used for each species:
\begin{itemize}
\item \textbf{2DCylNeutral}: Pushes particles in a 2D cylindrical space ($z \hyphen r$) without any external force.
\item \textbf{2DCylCharged}: Pushes particles in a 2D cylindrical space ($z \hyphen r$) including the effect of the electrostatic field.
\item \textbf{2DCartNeutral}: Pushes particles in a 2D Cartesian space ($x \hyphen y$) without any external force.
\item \textbf{2DCartCharged}: Pushes particles in a 2D Cartesian space ($x \hyphen y$) including the effect of the electrostatic field.
\item \textbf{1DRadNeutral}: Pushes particles in a 1D cylindrical space ($r$) without any external force.
\item \textbf{1DRadCharged}: Pushes particles in a 1D cylindrical space ($r$) accounting the the electrostatic field.
\item \textbf{1DCartNeutral}: Pushes particles in a 1D Cartesian space ($x$) without any external force.
\item \textbf{1DCartCharged}: Pushes particles in a 1D Cartesian space ($x$) accounting the the electrostatic field.
\item \textbf{3DCartNeutral}: Pushes particles in a 3D Cartesian space ($x \hyphen y \hyphen z$) without any external force.
\item \textbf{3DCartCharged}: Pushes particles in a 3D Cartesian space ($x \hyphen y \hyphen z$) including the effect of the electrostatic field.
\item \textbf{2DCylNeutral}: Pushes particles in a 2D cylindrical space ($z \hyphen r$) without any external force.
\item \textbf{2DCylCharged}: Pushes particles in a 2D cylindrical space ($z \hyphen r$) including the effect of the electrostatic field.
\item \textbf{2DCartNeutral}: Pushes particles in a 2D Cartesian space ($x \hyphen y$) without any external force.
\item \textbf{2DCartCharged}: Pushes particles in a 2D Cartesian space ($x \hyphen y$) including the effect of the electrostatic field.
\item \textbf{1DRadNeutral}: Pushes particles in a 1D cylindrical space ($r$) without any external force.
\item \textbf{1DRadCharged}: Pushes particles in a 1D cylindrical space ($r$) accounting the the electrostatic field.
\item \textbf{1DCartNeutral}: Pushes particles in a 1D Cartesian space ($x$) without any external force.
\item \textbf{1DCartCharged}: Pushes particles in a 1D Cartesian space ($x$) accounting the the electrostatic field.
\end{itemize}
\item \textbf{WeightingScheme}: Character.
Indicates the variable weighting scheme to be used in the simulation.

View file

@ -190,6 +190,7 @@ MODULE moduleMesh2DCyl
r2 = self%n2%getCoordinates()
self%z = (/r1(1), r2(1)/)
self%r = (/r1(2), r2(2)/)
self%weight = SUM(self%r)*5.D-1
!Normal vector
self%normal = (/ -(self%r(2)-self%r(1)), &
self%z(2)-self%z(1) , &
@ -247,14 +248,22 @@ MODULE moduleMesh2DCyl
CLASS(meshEdge2DCyl), INTENT(in):: self
REAL(8):: rnd
REAL(8):: dr, dz
REAL(8):: r(1:3)
REAL(8):: p1(1:2), p2(1:2)
rnd = random()
dr = self%r(2) - self%r(1)
dz = self%z(2) - self%z(1)
IF (dr /= 0.D0) THEN
r(2) = dr*DSQRT(rnd) + self%r(1)
r(1) = dz * (r(2) - self%r(1))/dr + self%z(1)
ELSE
r(2) = self%r(1)
r(1) = dz * rnd + self%z(1)
END IF
p1 = (/self%z(1), self%r(1) /)
p2 = (/self%z(2), self%r(2) /)
r(1:2) = (1.D0 - rnd)*p1 + rnd*p2
r(3) = 0.D0
END FUNCTION randPosEdge

View file

@ -61,6 +61,8 @@ MODULE moduleMesh
CLASS(meshVol), POINTER:: e1 => NULL(), e2 => NULL()
!Normal vector
REAL(8):: normal(1:3)
!Weight for random injection of particles
REAL(8):: weight = 1.D0
!Pointer to boundary element
TYPE(boundaryCont), POINTER:: boundary
!Array of functions for boundary conditions

View file

@ -137,14 +137,15 @@ MODULE moduleMeshBoundary
!Create the new pair of particles
DO p = 1, ionizationPair
ALLOCATE(newElectron)
ALLOCATE(newIon)
!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)
newElectron%sp = part%sp
newIon%sp = bound%sp

View file

@ -54,6 +54,8 @@ MODULE moduleInject
INTEGER:: sp !Species of injection
INTEGER:: nEdges
INTEGER, ALLOCATABLE:: edges(:) !Array with edges
REAL(8), ALLOCATABLE:: cumWeight(:) !Array of cummulative probability
REAL(8):: sumWeight
TYPE(velDistCont):: v(1:3) !Velocity distribution function in each direction
CONTAINS
PROCEDURE, PASS:: init => initInject
@ -121,12 +123,21 @@ MODULE moduleInject
DO e=1, mesh%numEdges
IF (mesh%edges(e)%obj%physicalSurface == physicalSurface) THEN
et = et + 1
self%edges(et) = mesh%edges(e)%obj%n
self%edges(et) = mesh%edges(e)%obj%n
END IF
END DO
!Calculates cumulative probability
ALLOCATE(self%cumWeight(1:self%nEdges))
self%cumWeight(1) = mesh%edges(self%edges(et))%obj%weight
DO et = 2, self%nEdges
self%cumWeight(et) = mesh%edges(self%edges(et))%obj%weight + self%cumWeight(et-1)
END DO
self%sumWeight = self%cumWeight(self%nEdges)
nPartInj = nPartInj + self%nParticles
END SUBROUTINE initInject
@ -229,7 +240,7 @@ MODULE moduleInject
!$OMP DO
DO n = nMin, nMax
randomX = random(1, self%nEdges)
randomX = randomWeighted(self%cumWeight, self%sumWeight)
randomEdge => mesh%edges(self%edges(randomX))%obj
!Random position in edge

View file

@ -636,21 +636,27 @@ MODULE moduleInput
ALLOCATE(boundaryTransparent:: boundary(i)%bTypes(s)%obj)
CASE('ionization')
CALL config%get(object // '.neutral.name', speciesName, found)
IF (.NOT. found) CALL criticalError("missing parameter 'name' for neutrals in ionization", 'readBoundary')
!Neutral parameters
CALL config%get(object // '.neutral.ion', speciesName, found)
IF (.NOT. found) CALL criticalError("missing parameter 'ion' for neutrals in ionization", 'readBoundary')
speciesID = speciesName2Index(speciesName)
CALL config%get(object // '.neutral.mass', m0, found)
IF (.NOT. found) CALL criticalError("missing parameter 'mass' for neutrals in ionization", 'readBoundary')
IF (.NOT. found) THEN
m0 = species(s)%obj%m*m_ref
END IF
CALL config%get(object // '.neutral.density', n0, found)
IF (.NOT. found) CALL criticalError("missing parameter 'density' for neutrals in ionization", 'readBoundary')
CALL config%get(object // '.neutral.velocity', v0, found)
IF (.NOT. found) CALL criticalError("missing parameter 'velocity' for neutrals in ionization", 'readBoundary')
CALL config%get(object // '.neutral.temperature', T0, found)
IF (.NOT. found) CALL criticalError("missing parameter 'temperature' for neutrals in ionization", 'readBoundary')
CALL config%get(object // '.effectiveTime', effTime, found)
IF (.NOT. found) CALL criticalError("missing parameter 'effectiveTime' for neutrals in ionization", 'readBoundary')
IF (.NOT. found) CALL criticalError("missing parameter 'effectiveTime' for ionization", 'readBoundary')
CALL config%get(object // '.energyThreshold', eThreshold, found)
IF (.NOT. found) CALL criticalError("missing parameter 'eThreshold' in ionization", 'readBoundary')
CALL config%get(object // '.crossSection', crossSection, found)
IF (.NOT. found) CALL criticalError("missing parameter 'crossSection' for neutrals in ionization", 'readBoundary')

View file

@ -66,4 +66,18 @@ MODULE moduleRandom
END FUNCTION randomMaxwellian
!Returns a random number weighted with the cumWeight array
FUNCTION randomWeighted(cumWeight, sumWeight) RESULT(rnd)
IMPLICIT NONE
REAL(8), INTENT(in):: cumWeight(1:)
REAL(8), INTENT(in):: sumWeight
REAL(8):: rnd0b
INTEGER:: rnd
rnd0b = random(0.D0, sumWeight)
rnd = MINLOC(DABS(rnd0b - cumWeight), 1)
END FUNCTION randomWeighted
END MODULE moduleRandom