First version with possibility for charged particles to be included.

Now, the solver needs to be an input parameter of the case, to select if
it is for charged or neutral particles.

Resolution of Poisson equation with Dirichlet boundary conditions is
possible. The source vector is the charge density. This resolution is
done in two steps to save computational time:
  1. When reading the mesh, the PLU factorization of the K matrix is
  computed.
  2. In each iteration, the system K*u = f is solved, in which f is the
  source vector (charge density) and u is the solution (potential) in
  each node.

No case has been added to the repository. This will be done in next
commit.

The 'non-analog' scheme has been commented. It still needs to split
the particle to avoid 'overweight' particles.
This commit is contained in:
Jorge Gonzalez 2020-11-15 21:16:02 +01:00
commit c82279f5c5
20 changed files with 859 additions and 227 deletions

View file

@ -1,5 +1,44 @@
MODULE moduleSolver
TYPE, PUBLIC, ABSTRACT:: solverGeneric
CONTAINS
PROCEDURE(push_interafece), DEFERRED, NOPASS:: push
PROCEDURE(solveEM_interface), DEFERRED, NOPASS:: solveEMField
END TYPE solverGeneric
ABSTRACT INTERFACE
!Push a particle
PURE SUBROUTINE push_interafece(part)
USE moduleSpecies
TYPE(particle), INTENT(inout):: part
END SUBROUTINE push_interafece
!Solve the electromagnetic field
SUBROUTINE solveEM_interface()
END SUBROUTINE solveEM_interface
END INTERFACE
TYPE, PUBLIC, EXTENDS(solverGeneric):: solverCylNeutral
CONTAINS
PROCEDURE, NOPASS:: push => pushCylNeutral
PROCEDURE, NOPASS:: solveEMField => noEMField
END TYPE solverCylNeutral
TYPE, PUBLIC, EXTENDS(solverGeneric):: solverCylCharged
CONTAINS
PROCEDURE, NOPASS:: push => pushCylCharged
PROCEDURE, NOPASS:: solveEMField => solveElecField
END TYPE solverCylCharged
CLASS(solverGeneric), ALLOCATABLE:: solver
CONTAINS
SUBROUTINE doPushes()
USE moduleSpecies
@ -10,7 +49,9 @@ MODULE moduleSolver
!$OMP DO
DO n=1, nPartOld
CALL push(partOld(n))
!Push particle
CALL solver%push(partOld(n))
!Find cell in wich particle reside
CALL mesh%vols(partOld(n)%e_p)%obj%findCell(partOld(n))
END DO
@ -18,16 +59,15 @@ MODULE moduleSolver
END SUBROUTINE doPushes
!Push one particle. Boris pusher for 2D Cyl
!TODO: make general for any pusher
PURE SUBROUTINE push(part)
!Push one particle. Boris pusher for 2D Cyl Neutral particle
PURE SUBROUTINE pushCylNeutral(part)
USE moduleSpecies
USE moduleMesh
IMPLICIT NONE
TYPE(particle), INTENT(inout):: part
REAL(8):: v_p_oh_star(2:3)
TYPE(particle):: part_temp
REAL(8):: x_new, y_new, r, sin_alpha, cos_alpha, alpha
REAL(8):: x_new, y_new, r, sin_alpha, cos_alpha
part_temp = part
!z
@ -40,8 +80,6 @@ MODULE moduleSolver
y_new = v_p_oh_star(3)*tau
r = DSQRT(x_new**2+y_new**2)
part_temp%r(2) = r
alpha = 0.D0!ATAN2(y_new,x_new) !0 in 2D problem
part_temp%r(3) = part%r(3) + alpha
IF (r > 0.D0) THEN
sin_alpha = y_new/r
cos_alpha = x_new/r
@ -57,7 +95,47 @@ MODULE moduleSolver
!Copy temporal particle to particle
part=part_temp
END SUBROUTINE push
END SUBROUTINE pushCylNeutral
!Push one particle. Boris pusher for 2D Cyl Charged particle
PURE SUBROUTINE pushCylCharged(part)
USE moduleSpecies
USE moduleEM
IMPLICIT NONE
TYPE(particle), INTENT(inout):: part
REAL(8):: v_p_oh_star(2:3)
TYPE(particle):: part_temp
REAL(8):: x_new, y_new, r, sin_alpha, cos_alpha
REAL(8):: qmEFt(1:3)!charge*tau*EF/mass
part_temp = part
!Get electric field at particle position
qmEFt = part_temp%qm*gatherElecField(part_temp)*tau
!z
part_temp%v(1) = part%v(1) + qmEFt(1)
part_temp%r(1) = part%r(1) + part_temp%v(1)*tau
!r,theta
v_p_oh_star(2) = part%v(2) + qmEFt(2)
x_new = part%r(2) + v_p_oh_star(2)*tau
v_p_oh_star(3) = part%v(3) + qmEFt(3)
y_new = v_p_oh_star(3)*tau
r = DSQRT(x_new**2+y_new**2)
part_temp%r(2) = r
IF (r > 0.D0) THEN
sin_alpha = y_new/r
cos_alpha = x_new/r
ELSE
sin_alpha = 0.D0
cos_alpha = 1.D0
END IF
part_temp%v(2) = cos_alpha*v_p_oh_star(2)+sin_alpha*v_p_oh_star(3)
part_temp%v(3) = -sin_alpha*v_p_oh_star(2)+cos_alpha*v_p_oh_star(3)
part_temp%n_in = .FALSE. !Assume particle is outside until cell is found
!Copy temporal particle to particle
part=part_temp
END SUBROUTINE pushCylCharged
!Do the collisions in all the cells
SUBROUTINE doCollisions()
@ -153,6 +231,64 @@ MODULE moduleSolver
END SUBROUTINE doScatter
SUBROUTINE doEMField()
IMPLICIT NONE
CALL solver%solveEMField()
END SUBROUTINE doEMField
!Solving the Poisson equation for electrostatic potential
SUBROUTINE solveElecField()
USE moduleEM
USE moduleMesh
USE moduleErrors
IMPLICIT NONE
INTEGER, SAVE:: INFO
INTEGER:: n
REAL(8), ALLOCATABLE, SAVE:: tempF(:)
EXTERNAL:: dgetrs
!$OMP SINGLE
ALLOCATE(tempF(1:mesh%numNodes))
!$OMP END SINGLE
CALL assembleSourceVector(tempF)
!$OMP SINGLE
CALL dgetrs('N', mesh%numNodes, 1, mesh%K, mesh%numNodes, &
mesh%IPIV, tempF, mesh%numNodes, info)
!$OMP END SINGLE
IF (info == 0) THEN
!Suscessful resolution of Poission equation
!$OMP DO
DO n = 1, mesh%numNodes
mesh%nodes(n)%obj%emData%phi = tempF(n)
END DO
!$OMP END DO
ELSE
!$OMP SINGLE
CALL criticalError('Poisson equation failed', 'solveElecField')
!$OMP END SINGLE
END IF
!$OMP SINGLE
DEALLOCATE(tempF)
!$OMP END SINGLE
END SUBROUTINE solveElecField
!Empty module that does no computation of EM field for neutral cases
SUBROUTINE noEMField()
IMPLICIT NONE
END SUBROUTINE noEMField
SUBROUTINE doOutput(t)
USE moduleMesh
USE moduleOutput
@ -172,8 +308,9 @@ MODULE moduleSolver
CALL mesh%printOutput(t)
CALL printTime(t, t == 0)
CALL mesh%printColl(t)
WRITE(*, "(5X,A21,I10,A1,I8)") "t/tmax: ", t, "/", tmax
WRITE(*, "(5X,A21,I10)") "Particles: ", nPartOld
CALL mesh%printEM(t)
WRITE(*, "(5X,A21,I10,A1,I10)") "t/tmax: ", t, "/", tmax
WRITE(*, "(5X,A21,I10)") "Particles: ", nPartOld
IF (t == 0) THEN
WRITE(*, "(5X,A21,F8.1,A2)") " init time: ", 1.D3*tStep, "ms"
@ -183,7 +320,7 @@ MODULE moduleSolver
END IF
IF (nPartOld > 0) THEN
WRITE(*, "(5X,A21,F8.1,A2)") "avg t/particle: ", 1.D9*(tPush+tReset+tColl+tWeight)/DBLE(nPartOld), "ns"
WRITE(*, "(5X,A21,F8.1,A2)") "avg t/particle: ", 1.D9*tStep/DBLE(nPartOld), "ns"
END IF
WRITE(*,*)