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

@ -44,6 +44,9 @@ MODULE moduleInput
CALL verboseError('Reading Geometry...')
CALL readGeometry(config)
!Read boundary for EM field
CALL readEMBoundary(config)
!Read injection of particles
CALL verboseError('Reading Interactions between species...')
CALL readInject(config)
@ -63,7 +66,7 @@ MODULE moduleInput
IMPLICIT NONE
TYPE(json_file), INTENT(inout):: config
LOGICAL:: found
LOGICAL:: found, found_r
CHARACTER(:), ALLOCATABLE:: object
object = 'reference'
@ -77,15 +80,25 @@ MODULE moduleInput
CALL config%get(object // '.temperature', T_ref, found)
IF (.NOT. found) CALL criticalError('Reference temperature not found','readReference')
CALL config%get(object // '.radius', r_ref, found)
IF (.NOT. found) CALL criticalError('Reference radius not found','readReference')
CALL config%get(object // '.radius', r_ref, found_r)
!Derived parameters
v_ref = DSQRT(kb*T_ref/m_ref) !reference velocity
sigma_ref = PI*(r_ref+r_ref)**2 !reference cross section
L_ref = 1.D0/(sigma_ref*n_ref) !mean free path
!TODO: Make this solver dependent
IF (found_r) THEN
L_ref = 1.D0/(sigma_ref*n_ref) !mean free path
sigma_ref = PI*(r_ref+r_ref)**2 !reference cross section
ELSE
L_ref = DSQRT(kb*T_ref*eps_0/n_ref)/qe !Debye length
!TODO: Obtain right sigma_ref for PIC case
sigma_ref = PI*(4.D-10)**2 !reference cross section
END IF
ti_ref = L_ref/v_ref !reference time
Vol_ref = L_ref**3 !reference volume
EF_ref = qe*n_ref*L_ref/eps_0 !reference electric field
Volt_ref = EF_ref*L_ref !reference voltage
END SUBROUTINE readReference
@ -94,6 +107,7 @@ MODULE moduleInput
USE moduleRefParam
USE moduleErrors
USE moduleCaseParam
USE moduleSolver
USE json_module
IMPLICIT NONE
@ -101,6 +115,7 @@ MODULE moduleInput
LOGICAL:: found
CHARACTER(:), ALLOCATABLE:: object
REAL(8):: time !simulation time in [t]
CHARACTER(:), ALLOCATABLE:: solverType
object = 'case'
!Time parameters
@ -110,6 +125,21 @@ MODULE moduleInput
CALL config%get(object // '.time', time, found)
IF (.NOT. found) CALL criticalError('Required parameter time not found','readCase')
CALL config%get(object // '.solver', solverType, found)
IF (.NOT. found) CALL criticalError('Required parameter solver not found','readCase')
!Allocate the type of solver
SELECT CASE(solverType)
CASE('2DCylNeutral')
!Allocate the solver for neutral pusher 2D Cylindrical
ALLOCATE(solver, source=solverCylNeutral())
CASE('2DCylCharged')
!Allocate the solver for charged pusher 2D Cylindrical
ALLOCATE(solver, source=solverCylCharged())
END SELECT
!Convert simulation time to number of iterations
tmax = INT(time/tau)
@ -149,6 +179,7 @@ MODULE moduleInput
CALL config%get(object // '.cpuTime', timeOutput, found)
CALL config%get(object // '.numColl', collOutput, found)
CALL config%get(object // '.EMField', emOutput, found)
END SUBROUTINE readOutput
@ -164,12 +195,12 @@ MODULE moduleInput
CHARACTER(2):: iString
CHARACTER(:), ALLOCATABLE:: object
CHARACTER(:), ALLOCATABLE:: speciesType
REAL(8):: mass
REAL(8):: mass, charge
LOGICAL:: found
INTEGER:: i
!Gets the number of species
CALL config%info('species', n_children = nSpecies)
CALL config%info('species', found, n_children = nSpecies)
!Zero species means critical error
IF (nSpecies == 0) CALL criticalError("No species found", "configRead")
@ -180,21 +211,28 @@ MODULE moduleInput
WRITE(iString, '(I2)') i
object = 'species(' // TRIM(iString) // ')'
CALL config%get(object // '.type', speciesType, found)
CALL config%get(object // '.mass', mass, found)
mass = mass/m_ref
!Allocate species depending on type and assign specific parameters
SELECT CASE(speciesType)
CASE ("neutral")
ALLOCATE(species(i)%obj, source=speciesNeutral())
!TODO: move to subroutine
CALL config%get(object // '.name', species(i)%obj%name, found)
CALL config%get(object // '.mass', mass, found)
CALL config%get(object // '.weight', species(i)%obj%weight, found)
species(i)%obj%pt = i
species(i)%obj%m = mass/m_ref
CASE ("charged")
CALL config%get(object // '.charge', charge, found)
ALLOCATE(species(i)%obj, source=speciesCharged(q = charge, &
qm = charge/mass))
CASE DEFAULT
CALL warningError("Species " // speciesType // " not supported yet")
END SELECT
!Assign shared parameters for all species
CALL config%get(object // '.name', species(i)%obj%name, found)
CALL config%get(object // '.weight', species(i)%obj%weight, found)
species(i)%obj%pt = i
species(i)%obj%m = mass
END DO
@ -217,29 +255,30 @@ MODULE moduleInput
CHARACTER(:), ALLOCATABLE:: species_i, species_j
CHARACTER(:), ALLOCATABLE:: crossSecFile
CHARACTER(:), ALLOCATABLE:: crossSecFilePath
LOGICAL:: found
INTEGER:: nInteractions, nCollisions
INTEGER:: i, k, ij
INTEGER:: pt_i, pt_j
CALL initInteractionMatrix(interactionMatrix)
CALL config%get('interactions.folderCollisions', pathCollisions)
CALL config%get('interactions.folderCollisions', pathCollisions, found)
CALL config%info('interactions.collisions', n_children = nInteractions)
CALL config%info('interactions.collisions', found, n_children = nInteractions)
DO i = 1, nInteractions
WRITE(iString, '(I2)') i
object = 'interactions.collisions(' // TRIM(iString) // ')'
CALL config%get(object // '.species_i', species_i)
CALL config%get(object // '.species_i', species_i, found)
pt_i = speciesName2Index(species_i)
CALL config%get(object // '.species_j', species_j)
CALL config%get(object // '.species_j', species_j, found)
pt_j = speciesName2Index(species_j)
CALL config%info(object // '.crossSections', n_children = nCollisions)
CALL config%info(object // '.crossSections', found, n_children = nCollisions)
ij = interactionIndex(pt_i,pt_j)
CALL interactionMatrix(ij)%init(nCollisions)
DO k = 1, nCollisions
WRITE (kString, '(I2)') k
CALL config%get(object // '.crossSections(' // TRIM(kString)// ')', crossSecFile)
CALL config%get(object // '.crossSections(' // TRIM(kString)// ')', crossSecFile, found)
crossSecFilePath = pathCollisions // crossSecFile
CALL interactionMatrix(ij)%collisions(k)%obj%init(crossSecFilePath, species(pt_i)%obj%m, species(pt_j)%obj%m)
@ -247,7 +286,6 @@ MODULE moduleInput
END DO
END SUBROUTINE readInteractions
!Reads boundary conditions for the mesh
@ -263,7 +301,7 @@ MODULE moduleInput
LOGICAL:: found
INTEGER:: i
CALL config%info('boundary', n_children = nBoundary)
CALL config%info('boundary', found, n_children = nBoundary)
ALLOCATE(boundary(1:nBoundary))
DO i = 1, nBoundary
WRITE(istring, '(i2)') i
@ -322,6 +360,85 @@ MODULE moduleInput
END SUBROUTINE readGeometry
SUBROUTINE readEMBoundary(config)
USE moduleMesh
USE moduleOutput
USE moduleErrors
USE moduleEM
USE moduleRefParam
USE moduleSpecies
USE json_module
IMPLICIT NONE
TYPE(json_file), INTENT(inout):: config
CHARACTER(:), ALLOCATABLE:: object
LOGICAL:: found
CHARACTER(2):: istring
INTEGER:: i, e, s
INTEGER:: info
EXTERNAL:: dgetrf
CALL config%info('boundaryEM', found, n_children = nBoundaryEM)
IF (found) ALLOCATE(boundEM(1:nBoundaryEM))
DO i = 1, nBoundaryEM
WRITE(istring, '(i2)') i
object = 'boundaryEM(' // trim(istring) // ')'
CALL config%get(object // '.type', boundEM(i)%typeEM, found)
SELECT CASE(boundEM(i)%typeEM)
CASE ("dirichlet")
CALL config%get(object // '.potential', boundEM(i)%potential, found)
IF (.NOT. found) &
CALL criticalError('Required parameter "potential" for Dirichlet boundary condition not found', 'readEMBoundary')
boundEM(i)%potential = boundEM(i)%potential/Volt_ref
CALL config%get(object // '.physicalSurface', boundEM(i)%physicalSurface, found)
IF (.NOT. found) &
CALL criticalError('Required parameter "physicalSurface" for Dirichlet boundary condition not found', 'readEMBoundary')
CASE DEFAULT
CALL criticalError('Boundary type ' // boundEM(i)%typeEM // ' not yet supported', 'readEMBoundary')
END SELECT
END DO
ALLOCATE(qSpecies(1:nSpecies))
DO s = 1, nSpecies
SELECT TYPE(sp => species(s)%obj)
TYPE IS (speciesCharged)
qSpecies(s) = sp%q
CLASS DEFAULT
qSpecies(s) = 0.D0
END SELECT
END DO
!TODO: Improve this
IF (ALLOCATED(boundEM)) THEN
DO e = 1, mesh%numEdges
IF (ANY(mesh%edges(e)%obj%physicalSurface == boundEM(:)%physicalSurface)) THEN
DO i = 1, nBoundaryEM
IF (mesh%edges(e)%obj%physicalSurface == boundEM(i)%physicalSurface) THEN
CALL boundEM(i)%apply(mesh%edges(e)%obj)
END IF
END DO
END IF
END DO
END IF
!Compute the PLU factorization of K once boundary conditions have been read
CALL dgetrf(mesh%numNodes, mesh%numNodes, mesh%K, mesh%numNodes, mesh%IPIV, info)
IF (info /= 0) CALL criticalError('Factorization of K matrix failed', 'readEMBoundary')
END SUBROUTINE readEMBoundary
!Reads the injection of particles from the boundaries
SUBROUTINE readInject(config)
USE moduleSpecies
@ -340,10 +457,11 @@ MODULE moduleInput
REAL(8):: v
REAL(8), ALLOCATABLE:: T(:), normal(:)
REAL(8):: flow
CHARACTER(:), ALLOCATABLE:: units
INTEGER:: physicalSurface
INTEGER:: pt
CALL config%info('inject', n_children = nInject)
CALL config%info('inject', found, n_children = nInject)
ALLOCATE(inject(1:nInject))
nPartInj = 0
DO i = 1, nInject
@ -359,11 +477,13 @@ MODULE moduleInput
CALL config%get(object // '.T', T, found)
CALL config%get(object // '.n', normal, found)
CALL config%get(object // '.flow', flow, found)
CALL config%get(object // '.units', units, found)
CALL config%get(object // '.physicalSurface', physicalSurface, found)
CALL inject(i)%init(i, v, normal, T, flow, pt, physicalSurface)
CALL inject(i)%init(i, v, normal, T, flow, units, pt, physicalSurface)
END DO
PRINT *, inject(:)%nParticles
!Allocate array for injected particles
IF (nPartInj > 0) THEN