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

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
DSMC_Neutrals PPartiC
mod/ mod/
obj/ obj/
doc/user_manual/ doc/user_manual/

View file

@ -12,20 +12,24 @@ JSONINC := $(JSONDIR)/include
INCDIR := INCDIR :=
INCDIR += $(JSONINC) INCDIR += $(JSONINC)
VAR := ""
# compile flags # compile flags
FCFLAGS := -fopenmp -Ofast -J $(MODDIR) -I $(INCDIR) -Wall -fno-stack-arrays -g FCFLAGS := -fopenmp -Ofast -J $(MODDIR) -I $(INCDIR) -Wall -g
#Output file #Output file
OUTPUT = DSMC_Neutrals OUTPUT = PPartiC
export export
$(OUTPUT): src.o all: $(OUTPUT)
$(OUTPUT): src.o
src.o: src.o:
@mkdir -p $(MODDIR) @mkdir -p $(MODDIR)
@mkdir -p $(OBJDIR) @mkdir -p $(OBJDIR)
$(MAKE) -C src all $(MAKE) -C src $(OUTPUT)
clean: clean:
rm -f $(OUTPUT) rm -f $(OUTPUT)

View file

@ -24,14 +24,15 @@
{"name": "Nozzle", "species": "Argon", "flow": 10.0, "units": "sccm", "v": 300.0, "T": [300.0, 300.0, 300.0], "n": [1, 0, 0], "physicalSurface": 1} {"name": "Nozzle", "species": "Argon", "flow": 10.0, "units": "sccm", "v": 300.0, "T": [300.0, 300.0, 300.0], "n": [1, 0, 0], "physicalSurface": 1}
], ],
"reference": { "reference": {
"density": 1.0e20, "density": 1.0e20,
"mass": 6.633e-26, "mass": 6.633e-26,
"temperature": 300.0, "temperature": 300.0,
"radius": 1.88e-10 "radius": 1.88e-10
}, },
"case": { "case": {
"tau": 6.e-7, "tau": 6.0e-7,
"time": 3.e-3 "time": 3.0e-3,
"solver": "2DCylNeutral"
}, },
"interactions": { "interactions": {
"folderCollisions": "./data/collisions/", "folderCollisions": "./data/collisions/",

View file

@ -1,5 +1,5 @@
! PPartiC neutral DSMC main program. ! PPartiC neutral PIC main program.
PROGRAM DSMC_Neutrals PROGRAM PPartiC
USE moduleInput USE moduleInput
USE moduleErrors USE moduleErrors
USE OMP_LIB USE OMP_LIB
@ -10,28 +10,32 @@ PROGRAM DSMC_Neutrals
USE moduleMesh USE moduleMesh
IMPLICIT NONE IMPLICIT NONE
! t = time step; n = number of particle; e = number of element; i = number of inject ! t = time step
INTEGER:: t = 0 INTEGER:: t = 0
! arg1 = Input argument 1 (input file)
CHARACTER(200):: arg1 CHARACTER(200):: arg1
! inputFile = path+name of input file
CHARACTER(:), ALLOCATABLE:: inputFile CHARACTER(:), ALLOCATABLE:: inputFile
tStep = omp_get_wtime() tStep = omp_get_wtime()
!Gets the input file !Gets the input file
CALL getarg(1, arg1) CALL getarg(1, arg1)
inputFile = TRIM(arg1) inputFile = TRIM(arg1)
!If no input file is declared, a critical error is called !If no input file is declared, a critical error is called
IF (inputFile == "") CALL criticalError("No input file provided", "DSMC_Neutrals") IF (inputFile == "") CALL criticalError("No input file provided", "PPartiC")
!Reads the json configuration file !Reads the json configuration file
CALL readConfig(inputFile) CALL readConfig(inputFile)
CALL verboseError("Calculating initial EM field...")
CALL doEMField()
tStep = omp_get_wtime() - tStep tStep = omp_get_wtime() - tStep
!Output initial state !Output initial state
CALL doOutput(t) CALL doOutput(t)
CALL verboseError('Starting main loop...') CALL verboseError('Starting main loop...')
!$OMP PARALLEL PRIVATE(t) DEFAULT(SHARED) !$OMP PARALLEL DEFAULT(SHARED)
DO t = 1, tmax DO t = 1, tmax
!Insert new particles and push them !Insert new particles and push them
!$OMP SINGLE !$OMP SINGLE
@ -46,18 +50,18 @@ PROGRAM DSMC_Neutrals
!$OMP SINGLE !$OMP SINGLE
tPush = omp_get_wtime() - tPush tPush = omp_get_wtime() - tPush
!Collisions
tColl = omp_get_wtime() tColl = omp_get_wtime()
!$OMP END SINGLE !$OMP END SINGLE
!Collisions
CALL doCollisions() CALL doCollisions()
!$OMP SINGLE !$OMP SINGLE
tColl = omp_get_wtime() - tColl tColl = omp_get_wtime() - tColl
!Reset particles
tReset = omp_get_wtime() tReset = omp_get_wtime()
!$OMP END SINGLE !$OMP END SINGLE
!Reset particles
CALL doReset() CALL doReset()
!$OMP SINGLE !$OMP SINGLE
@ -71,6 +75,13 @@ PROGRAM DSMC_Neutrals
!$OMP SINGLE !$OMP SINGLE
tWeight = omp_get_wtime() - tWeight tWeight = omp_get_wtime() - tWeight
tEMField = omp_get_wtime()
!$OMP END SINGLE
CALL doEMField()
!$OMP SINGLE
tEMField = omp_get_wtime() - tEMField
tStep = omp_get_wtime() - tStep tStep = omp_get_wtime() - tStep
!Output data !Output data
CALL doOutput(t) CALL doOutput(t)
@ -79,5 +90,5 @@ PROGRAM DSMC_Neutrals
END DO END DO
!$OMP END PARALLEL !$OMP END PARALLEL
END PROGRAM DSMC_Neutrals END PROGRAM PPartiC

View file

@ -1,17 +1,16 @@
OBJECTS = $(OBJDIR)/$(OUTPUT).o \ OBJECTS = $(OBJDIR)/moduleMesh.o $(OBJDIR)/moduleCompTime.o $(OBJDIR)/moduleSolver.o \
$(OBJDIR)/moduleMesh.o $(OBJDIR)/moduleCompTime.o $(OBJDIR)/moduleSolver.o \
$(OBJDIR)/moduleSpecies.o $(OBJDIR)/moduleInject.o $(OBJDIR)/moduleInput.o \ $(OBJDIR)/moduleSpecies.o $(OBJDIR)/moduleInject.o $(OBJDIR)/moduleInput.o \
$(OBJDIR)/moduleErrors.o $(OBJDIR)/moduleList.o $(OBJDIR)/moduleOutput.o \ $(OBJDIR)/moduleErrors.o $(OBJDIR)/moduleList.o $(OBJDIR)/moduleOutput.o \
$(OBJDIR)/moduleMeshCyl.o $(OBJDIR)/moduleMeshCylRead.o $(OBJDIR)/moduleMeshCylBoundary.o \ $(OBJDIR)/moduleMeshCyl.o $(OBJDIR)/moduleMeshCylRead.o $(OBJDIR)/moduleMeshCylBoundary.o \
$(OBJDIR)/moduleBoundary.o $(OBJDIR)/moduleCaseParam.o $(OBJDIR)/moduleRefParam.o \ $(OBJDIR)/moduleBoundary.o $(OBJDIR)/moduleCaseParam.o $(OBJDIR)/moduleRefParam.o \
$(OBJDIR)/moduleCollisions.o $(OBJDIR)/moduleTable.o $(OBJDIR)/moduleParallel.o $(OBJDIR)/moduleCollisions.o $(OBJDIR)/moduleTable.o $(OBJDIR)/moduleParallel.o \
$(OBJDIR)/moduleEM.o
all: $(OUTPUT) all: $(OUTPUT)
$(FC) $(FCFLAGS) -o $(TOPDIR)/$(OUTPUT) $(OBJECTS) $(JSONLIB)
$(OUTPUT): modules.o $(OUTPUT).f95 $(OUTPUT): modules.o $(OUTPUT).f95
$(FC) $(FCFLAGS) -o $(OBJDIR)/$(OUTPUT).o -c $(OUTPUT).f95 $(FC) $(FCFLAGS) -o $(OBJDIR)/$(OUTPUT).o -c $(OUTPUT).f95
$(FC) $(FCFLAGS) -o $(TOPDIR)/$(OUTPUT) $(OBJECTS) $(OBJDIR)/$(OUTPUT).o $(JSONLIB) -L/usr/local/lib -llapack -lopenblas
modules.o: modules.o:
$(MAKE) -C modules all $(MAKE) -C modules all

View file

@ -1,9 +1,9 @@
OBJS = moduleCaseParam.o moduleCompTime.o moduleList.o\ OBJS = moduleCaseParam.o moduleCompTime.o moduleList.o\
moduleMesh.o moduleMeshCyl.o moduleMeshCylBoundary.o\ moduleMesh.o moduleMeshCyl.o moduleMeshCylBoundary.o\
moduleMeshCylRead.o moduleOutput.o moduleInput.o \ moduleMeshCylRead.o moduleOutput.o moduleInput.o \
moduleSolver.o moduleCollisions.o moduleTable.o \ moduleSolver.o moduleCollisions.o moduleTable.o \
moduleParallel.o moduleParallel.o moduleEM.o
all: $(OBJS) all: $(OBJS)
@ -40,11 +40,14 @@ moduleRefParam.o: moduleConstParam.o moduleRefParam.f95
moduleSpecies.o: moduleCaseParam.o moduleSpecies.f95 moduleSpecies.o: moduleCaseParam.o moduleSpecies.f95
$(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@ $(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@
moduleSolver.o: moduleSpecies.o moduleRefParam.o moduleMesh.o moduleOutput.o moduleSolver.f95 moduleSolver.o: moduleEM.o moduleSpecies.o moduleRefParam.o moduleMesh.o moduleOutput.o moduleSolver.f95
$(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@ $(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@
moduleTable.o: moduleErrors.o moduleTable.f95 moduleTable.o: moduleErrors.o moduleTable.f95
$(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@ $(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@
moduleEM.o: moduleSpecies.o moduleMesh.o moduleEM.f95
$(FC) $(FCFLAGS) -c $(subst .o,.f95,$@) -o $(OBJDIR)/$@
%.o: %.f95 %.o: %.f95
$(FC) $(FCFLAGS) -c $< -o $(OBJDIR)/$@ $(FC) $(FCFLAGS) -c $< -o $(OBJDIR)/$@

View file

@ -5,6 +5,7 @@ MODULE moduleCompTime
REAL(8):: tReset=0.D0 REAL(8):: tReset=0.D0
REAL(8):: tColl=0.D0 REAL(8):: tColl=0.D0
REAL(8):: tWeight=0.D0 REAL(8):: tWeight=0.D0
REAL(8):: tEMField=0.D0
END MODULE moduleCompTime END MODULE moduleCompTime

View file

@ -6,9 +6,10 @@ MODULE moduleConstParam
REAL(8), PARAMETER:: PI = 4.D0*DATAN(1.D0) !number pi REAL(8), PARAMETER:: PI = 4.D0*DATAN(1.D0) !number pi
REAL(8), PARAMETER:: sccm2atomPerS = 4.5D17 !sccm to atom s^-1 REAL(8), PARAMETER:: sccm2atomPerS = 4.5D17 !sccm to atom s^-1
REAL(8), PARAMETER:: eV2J = 1.60217662D-19 !Electron volt to Joule (elementary charge) REAL(8), PARAMETER:: qe = 1.60217662D-19 !Elementary charge
REAL(8), PARAMETER:: kb = 1.38064852D-23 !Boltzmann constants SI REAL(8), PARAMETER:: kb = 1.38064852D-23 !Boltzmann constants SI
! REAL(8), PARAMETER:: eps_0 = 8.8542D-12 !Epsilon_0 (Not used in Neutrals) REAL(8), PARAMETER:: eV2J = qe !Electron volt to Joule conversion
REAL(8), PARAMETER:: eps_0 = 8.8542D-12 !Epsilon_0
END MODULE moduleConstParam END MODULE moduleConstParam

133
src/modules/moduleEM.f95 Normal file
View file

@ -0,0 +1,133 @@
!Module to solve the electromagnetic field
MODULE moduleEM
IMPLICIT NONE
TYPE:: boundaryEM
CHARACTER(:), ALLOCATABLE:: typeEM
INTEGER:: physicalSurface
REAL(8):: potential
CONTAINS
PROCEDURE, PASS:: apply
END TYPE boundaryEM
INTEGER:: nBoundaryEM
TYPE(boundaryEM), ALLOCATABLE:: boundEM(:)
!Information of charge and reference parameters for rho vector
REAL(8), ALLOCATABLE:: qSpecies(:)
CONTAINS
SUBROUTINE apply(self, edge)
USE moduleMesh
IMPLICIT NONE
CLASS(boundaryEM), INTENT(in):: self
CLASS(meshEdge):: edge
INTEGER, ALLOCATABLE:: nodes(:)
INTEGER:: n
nodes = edge%getNodes()
DO n = 1, SIZE(nodes)
SELECT CASE(self%typeEM)
CASE ("dirichlet")
mesh%K(nodes(n), :) = 0.D0
mesh%K(nodes(n), nodes(n)) = 1.D0
mesh%nodes(nodes(n))%obj%emData%type = self%typeEM
mesh%nodes(nodes(n))%obj%emData%phi = self%potential
END SELECT
END DO
END SUBROUTINE
PURE FUNCTION gatherElecField(part) RESULT(elField)
USE moduleSpecies
USE moduleMesh
IMPLICIT NONE
TYPE(particle), INTENT(in):: part
REAl(8):: xi(1:3) !Logical coordinates of particle in element
REAL(8):: elField(1:3)
elField = 0.D0
xi = part%xLog
elField = mesh%vols(part%e_p)%obj%gatherEF(xi)
END FUNCTION gatherElecField
SUBROUTINE assembleSourceVector(vectorF)
USE moduleMesh
USE moduleRefParam
IMPLICIT NONE
REAL(8), INTENT(out):: vectorF(1:mesh%numNodes)
REAL(8), ALLOCATABLE:: localF(:)
INTEGER, ALLOCATABLE:: nodes(:)
REAL(8), ALLOCATABLE:: rho(:)
INTEGER:: nNodes
INTEGER:: e, i, ni
CLASS(meshNode), POINTER:: node
!$OMP SINGLE
vectorF = 0.D0
!$OMP END SINGLE
!$OMP SINGLE
DO e = 1, mesh%numVols
nodes = mesh%vols(e)%obj%getNodes()
nNodes = SIZE(nodes)
!Calculates charge density (rho) in element nodes
ALLOCATE(rho(1:nNodes))
rho = 0.D0
DO i = 1, nNodes
ni = nodes(i)
node => mesh%nodes(ni)%obj
rho(i) = DOT_PRODUCT(qSpecies(:), node%output(:)%den/(vol_ref*node%v*n_ref))
END DO
!If there is charge in the nodes, compute the local F vector
IF (ANY(rho > 0.D0)) THEN
!Calculates local F vector
localF = mesh%vols(e)%obj%elemF(rho)
!Assign local F to global F
DO i = 1, nNodes
ni = nodes(i)
vectorF(ni) = vectorF(ni) + localF(i)
END DO
DEALLOCATE(localF)
END IF
DEALLOCATE(nodes, rho)
END DO
!$OMP END SINGLE
!Apply boundary conditions
!$OMP DO
DO i = 1, mesh%numNodes
node => mesh%nodes(i)%obj
SELECT CASE(node%emData%type)
CASE ("dirichlet")
vectorF(i) = node%emData%phi
END SELECT
END DO
!$OMP END DO
END SUBROUTINE assembleSourceVector
END MODULE moduleEM

View file

@ -37,7 +37,6 @@ MODULE moduleErrors
errorMsg = msg errorMsg = msg
WRITE (*, '(A)') errorMsg WRITE (*, '(A)') errorMsg
WRITE (*, *)
END SUBROUTINE verboseError END SUBROUTINE verboseError

View file

@ -25,24 +25,14 @@ MODULE moduleInject
TYPE(injectGeneric), ALLOCATABLE:: inject(:) TYPE(injectGeneric), ALLOCATABLE:: inject(:)
CONTAINS CONTAINS
!Injection of particles !Initialize an injection of particles
SUBROUTINE doInjects() SUBROUTINE initInject(self, i, v, n, T, flow, units, pt, physicalSurface)
IMPLICIT NONE
INTEGER:: i
DO i=1, nInject
CALL inject(i)%addParticles()
END DO
END SUBROUTINE doInjects
SUBROUTINE initInject(self, i, v, n, T, flow, pt, physicalSurface)
USE moduleMesh USE moduleMesh
USE moduleMeshCyl USE moduleMeshCyl
USE moduleRefParam USE moduleRefParam
USE moduleConstParam USE moduleConstParam
USE moduleSpecies USE moduleSpecies
USE moduleErrors
IMPLICIT NONE IMPLICIT NONE
CLASS(injectGeneric), INTENT(inout):: self CLASS(injectGeneric), INTENT(inout):: self
@ -50,6 +40,7 @@ MODULE moduleInject
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):: pt, physicalSurface INTEGER, INTENT(in):: pt, physicalSurface
REAL(8), INTENT(in):: flow REAL(8), INTENT(in):: flow
CHARACTER(:), ALLOCATABLE, INTENT(in):: units
INTEGER:: e, et INTEGER:: e, et
INTEGER:: phSurface(1:mesh%numEdges) INTEGER:: phSurface(1:mesh%numEdges)
@ -57,8 +48,21 @@ MODULE moduleInject
self%vMod = v/v_ref self%vMod = v/v_ref
self%n = n self%n = n
self%T = T/T_ref self%T = T/T_ref
self%nParticles = INT(flow*sccm2atomPerS*tau*ti_ref/species(pt)%obj%weight) SELECT CASE(units)
self%pt = pt CASE ("sccm")
!Standard cubic centimeter per minute
self%nParticles = INT(flow*sccm2atomPerS*tau*ti_ref/species(pt)%obj%weight)
CASE ("A")
!Input current in Ampers
self%nParticles = INT(flow*tau*ti_ref/(qe*species(pt)%obj%weight))
CASE DEFAULT
CALL criticalError("No support for units: " // units, 'initInject')
END SELECT
IF (self%nParticles == 0) CALL criticalError("The number of particles for inject is 0.", 'initInject')
self%pt = pt
self%v = self%v * self%n self%v = self%v * self%n
self%vTh = DSQRT(self%T/species(self%pt)%obj%m) self%vTh = DSQRT(self%T/species(self%pt)%obj%m)
@ -92,6 +96,19 @@ MODULE moduleInject
END SUBROUTINE END SUBROUTINE
!Injection of particles
SUBROUTINE doInjects()
IMPLICIT NONE
INTEGER:: i
DO i=1, nInject
CALL inject(i)%addParticles()
END DO
END SUBROUTINE doInjects
!Random velocity from maxwellian distribution !Random velocity from maxwellian distribution
REAL(8) FUNCTION vBC(u, vth) REAL(8) FUNCTION vBC(u, vth)
USE moduleConstParam, ONLY: PI USE moduleConstParam, ONLY: PI
@ -119,18 +136,28 @@ MODULE moduleInject
CLASS(injectGeneric), INTENT(in):: self CLASS(injectGeneric), INTENT(in):: self
REAL(8):: randomX REAL(8):: randomX
INTEGER:: j INTEGER:: j
REAL(8):: randomPos INTEGER, SAVE:: nMin, nMax !Min and Max index in partInj array
INTEGER:: nMin, nMax !Min and Max index in partInj array
INTEGER:: n INTEGER:: n
CLASS(meshEdge), POINTER:: randomEdge CLASS(meshEdge), POINTER:: randomEdge
!Insert particles !Insert particles
!$OMP SINGLE
nMin = SUM(inject(1:(self%id-1))%nParticles) + 1 nMin = SUM(inject(1:(self%id-1))%nParticles) + 1
nMax = nMin + self%nParticles nMax = nMin + self%nParticles - 1
!Assign particle type !Assign particle type
partInj(nMin:nMax)%pt = self%pt partInj(nMin:nMax)%pt = self%pt
!Assign weight to particle. !Assign weight to particle.
partInj(nMin:nMax)%weight = species(self%pt)%obj%weight partInj(nMin:nMax)%weight = species(self%pt)%obj%weight
!Particle is considered to be outside the domain
partInj(nMin:nMax)%n_in = .FALSE.
!Assign charge/mass to charged particle.
SELECT TYPE(sp => species(self%pt)%obj)
TYPE IS(speciesCharged)
partInj(nMin:nMax)%qm = sp%qm
END SELECT
!$OMP END SINGLE
!$OMP DO !$OMP DO
DO n = nMin, nMax DO n = nMin, nMax
!Select edge randomly from which inject particle !Select edge randomly from which inject particle
@ -143,8 +170,7 @@ MODULE moduleInject
randomEdge => mesh%edges(self%edges(j))%obj randomEdge => mesh%edges(self%edges(j))%obj
!Random position in edge !Random position in edge
randomPos = RAND() partInj(n)%r = randomEdge%randPos()
partInj(n)%r = randomEdge%randPos(randomPos)
!Volume associated to the edge: !Volume associated to the edge:
IF (DOT_PRODUCT(self%n, randomEdge%normal) >= 0.D0) THEN IF (DOT_PRODUCT(self%n, randomEdge%normal) >= 0.D0) THEN
partInj(n)%e_p = randomEdge%e1%n partInj(n)%e_p = randomEdge%e1%n
@ -159,7 +185,7 @@ MODULE moduleInject
vBC(self%v(3), self%vTh(3)) /) vBC(self%v(3), self%vTh(3)) /)
!Push new particle !Push new particle
CALL push(partInj(n)) CALL solver%push(partInj(n))
!Assign cell to new particle !Assign cell to new particle
CALL mesh%vols(partInj(n)%e_p)%obj%findCell(partInj(n)) CALL mesh%vols(partInj(n)%e_p)%obj%findCell(partInj(n))

View file

@ -44,6 +44,9 @@ MODULE moduleInput
CALL verboseError('Reading Geometry...') CALL verboseError('Reading Geometry...')
CALL readGeometry(config) CALL readGeometry(config)
!Read boundary for EM field
CALL readEMBoundary(config)
!Read injection of particles !Read injection of particles
CALL verboseError('Reading Interactions between species...') CALL verboseError('Reading Interactions between species...')
CALL readInject(config) CALL readInject(config)
@ -63,7 +66,7 @@ MODULE moduleInput
IMPLICIT NONE IMPLICIT NONE
TYPE(json_file), INTENT(inout):: config TYPE(json_file), INTENT(inout):: config
LOGICAL:: found LOGICAL:: found, found_r
CHARACTER(:), ALLOCATABLE:: object CHARACTER(:), ALLOCATABLE:: object
object = 'reference' object = 'reference'
@ -77,15 +80,25 @@ MODULE moduleInput
CALL config%get(object // '.temperature', T_ref, found) CALL config%get(object // '.temperature', T_ref, found)
IF (.NOT. found) CALL criticalError('Reference temperature not found','readReference') IF (.NOT. found) CALL criticalError('Reference temperature not found','readReference')
CALL config%get(object // '.radius', r_ref, found) CALL config%get(object // '.radius', r_ref, found_r)
IF (.NOT. found) CALL criticalError('Reference radius not found','readReference')
!Derived parameters !Derived parameters
v_ref = DSQRT(kb*T_ref/m_ref) !reference velocity v_ref = DSQRT(kb*T_ref/m_ref) !reference velocity
sigma_ref = PI*(r_ref+r_ref)**2 !reference cross section !TODO: Make this solver dependent
L_ref = 1.D0/(sigma_ref*n_ref) !mean free path 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 ti_ref = L_ref/v_ref !reference time
Vol_ref = L_ref**3 !reference volume 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 END SUBROUTINE readReference
@ -94,6 +107,7 @@ MODULE moduleInput
USE moduleRefParam USE moduleRefParam
USE moduleErrors USE moduleErrors
USE moduleCaseParam USE moduleCaseParam
USE moduleSolver
USE json_module USE json_module
IMPLICIT NONE IMPLICIT NONE
@ -101,6 +115,7 @@ MODULE moduleInput
LOGICAL:: found LOGICAL:: found
CHARACTER(:), ALLOCATABLE:: object CHARACTER(:), ALLOCATABLE:: object
REAL(8):: time !simulation time in [t] REAL(8):: time !simulation time in [t]
CHARACTER(:), ALLOCATABLE:: solverType
object = 'case' object = 'case'
!Time parameters !Time parameters
@ -110,6 +125,21 @@ MODULE moduleInput
CALL config%get(object // '.time', time, found) CALL config%get(object // '.time', time, found)
IF (.NOT. found) CALL criticalError('Required parameter time not found','readCase') 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 !Convert simulation time to number of iterations
tmax = INT(time/tau) tmax = INT(time/tau)
@ -149,6 +179,7 @@ MODULE moduleInput
CALL config%get(object // '.cpuTime', timeOutput, found) CALL config%get(object // '.cpuTime', timeOutput, found)
CALL config%get(object // '.numColl', collOutput, found) CALL config%get(object // '.numColl', collOutput, found)
CALL config%get(object // '.EMField', emOutput, found)
END SUBROUTINE readOutput END SUBROUTINE readOutput
@ -164,12 +195,12 @@ MODULE moduleInput
CHARACTER(2):: iString CHARACTER(2):: iString
CHARACTER(:), ALLOCATABLE:: object CHARACTER(:), ALLOCATABLE:: object
CHARACTER(:), ALLOCATABLE:: speciesType CHARACTER(:), ALLOCATABLE:: speciesType
REAL(8):: mass REAL(8):: mass, charge
LOGICAL:: found LOGICAL:: found
INTEGER:: i INTEGER:: i
!Gets the number of species !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 !Zero species means critical error
IF (nSpecies == 0) CALL criticalError("No species found", "configRead") IF (nSpecies == 0) CALL criticalError("No species found", "configRead")
@ -180,21 +211,28 @@ MODULE moduleInput
WRITE(iString, '(I2)') i WRITE(iString, '(I2)') i
object = 'species(' // TRIM(iString) // ')' object = 'species(' // TRIM(iString) // ')'
CALL config%get(object // '.type', speciesType, found) 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) SELECT CASE(speciesType)
CASE ("neutral") CASE ("neutral")
ALLOCATE(species(i)%obj, source=speciesNeutral()) ALLOCATE(species(i)%obj, source=speciesNeutral())
!TODO: move to subroutine
CALL config%get(object // '.name', species(i)%obj%name, found) CASE ("charged")
CALL config%get(object // '.mass', mass, found) CALL config%get(object // '.charge', charge, found)
CALL config%get(object // '.weight', species(i)%obj%weight, found) ALLOCATE(species(i)%obj, source=speciesCharged(q = charge, &
species(i)%obj%pt = i qm = charge/mass))
species(i)%obj%m = mass/m_ref
CASE DEFAULT CASE DEFAULT
CALL warningError("Species " // speciesType // " not supported yet") CALL warningError("Species " // speciesType // " not supported yet")
END SELECT 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 END DO
@ -217,29 +255,30 @@ MODULE moduleInput
CHARACTER(:), ALLOCATABLE:: species_i, species_j CHARACTER(:), ALLOCATABLE:: species_i, species_j
CHARACTER(:), ALLOCATABLE:: crossSecFile CHARACTER(:), ALLOCATABLE:: crossSecFile
CHARACTER(:), ALLOCATABLE:: crossSecFilePath CHARACTER(:), ALLOCATABLE:: crossSecFilePath
LOGICAL:: found
INTEGER:: nInteractions, nCollisions INTEGER:: nInteractions, nCollisions
INTEGER:: i, k, ij INTEGER:: i, k, ij
INTEGER:: pt_i, pt_j INTEGER:: pt_i, pt_j
CALL initInteractionMatrix(interactionMatrix) 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 DO i = 1, nInteractions
WRITE(iString, '(I2)') i WRITE(iString, '(I2)') i
object = 'interactions.collisions(' // TRIM(iString) // ')' 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) 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) 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) ij = interactionIndex(pt_i,pt_j)
CALL interactionMatrix(ij)%init(nCollisions) CALL interactionMatrix(ij)%init(nCollisions)
DO k = 1, nCollisions DO k = 1, nCollisions
WRITE (kString, '(I2)') k WRITE (kString, '(I2)') k
CALL config%get(object // '.crossSections(' // TRIM(kString)// ')', crossSecFile) CALL config%get(object // '.crossSections(' // TRIM(kString)// ')', crossSecFile, found)
crossSecFilePath = pathCollisions // crossSecFile crossSecFilePath = pathCollisions // crossSecFile
CALL interactionMatrix(ij)%collisions(k)%obj%init(crossSecFilePath, species(pt_i)%obj%m, species(pt_j)%obj%m) 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 DO
END SUBROUTINE readInteractions END SUBROUTINE readInteractions
!Reads boundary conditions for the mesh !Reads boundary conditions for the mesh
@ -263,7 +301,7 @@ MODULE moduleInput
LOGICAL:: found LOGICAL:: found
INTEGER:: i INTEGER:: i
CALL config%info('boundary', n_children = nBoundary) CALL config%info('boundary', found, n_children = nBoundary)
ALLOCATE(boundary(1:nBoundary)) ALLOCATE(boundary(1:nBoundary))
DO i = 1, nBoundary DO i = 1, nBoundary
WRITE(istring, '(i2)') i WRITE(istring, '(i2)') i
@ -322,6 +360,85 @@ MODULE moduleInput
END SUBROUTINE readGeometry 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 !Reads the injection of particles from the boundaries
SUBROUTINE readInject(config) SUBROUTINE readInject(config)
USE moduleSpecies USE moduleSpecies
@ -340,10 +457,11 @@ MODULE moduleInput
REAL(8):: v REAL(8):: v
REAL(8), ALLOCATABLE:: T(:), normal(:) REAL(8), ALLOCATABLE:: T(:), normal(:)
REAL(8):: flow REAL(8):: flow
CHARACTER(:), ALLOCATABLE:: units
INTEGER:: physicalSurface INTEGER:: physicalSurface
INTEGER:: pt INTEGER:: pt
CALL config%info('inject', n_children = nInject) CALL config%info('inject', found, n_children = nInject)
ALLOCATE(inject(1:nInject)) ALLOCATE(inject(1:nInject))
nPartInj = 0 nPartInj = 0
DO i = 1, nInject DO i = 1, nInject
@ -359,11 +477,13 @@ MODULE moduleInput
CALL config%get(object // '.T', T, found) CALL config%get(object // '.T', T, found)
CALL config%get(object // '.n', normal, found) CALL config%get(object // '.n', normal, found)
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 // '.physicalSurface', physicalSurface, 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 END DO
PRINT *, inject(:)%nParticles
!Allocate array for injected particles !Allocate array for injected particles
IF (nPartInj > 0) THEN IF (nPartInj > 0) THEN

View file

@ -2,7 +2,6 @@
MODULE moduleMesh MODULE moduleMesh
USE moduleList USE moduleList
USE moduleOutput USE moduleOutput
USE OMP_LIB
IMPLICIT NONE IMPLICIT NONE
!Parent of Node element !Parent of Node element
@ -13,6 +12,7 @@ MODULE moduleMesh
REAL(8):: v = 0.D0 REAL(8):: v = 0.D0
!Output values !Output values
TYPE(outputNode), ALLOCATABLE:: output(:) TYPE(outputNode), ALLOCATABLE:: output(:)
TYPE(emNode):: emData
CONTAINS CONTAINS
PROCEDURE(initNode_interface), DEFERRED, PASS:: init PROCEDURE(initNode_interface), DEFERRED, PASS:: init
PROCEDURE(getCoord_interface), DEFERRED, PASS:: getCoordinates PROCEDURE(getCoord_interface), DEFERRED, PASS:: getCoordinates
@ -58,15 +58,17 @@ MODULE moduleMesh
!id for boundary condition !id for boundary condition
INTEGER:: bt = 0 INTEGER:: bt = 0
CONTAINS CONTAINS
PROCEDURE(initEdge_interface), DEFERRED, PASS:: init PROCEDURE(initEdge_interface), DEFERRED, PASS:: init
PROCEDURE(boundary_interface), DEFERRED, PASS:: fBoundary PROCEDURE(boundary_interface), DEFERRED, PASS:: fBoundary
PROCEDURE(randPos_interface), DEFERRED, PASS:: randPos PROCEDURE(getNodesEdge_interface), DEFERRED, PASS:: getNodes
PROCEDURE(randPos_interface), DEFERRED, PASS:: randPos
END TYPE meshEdge END TYPE meshEdge
ABSTRACT INTERFACE ABSTRACT INTERFACE
SUBROUTINE initEdge_interface(self, n, p, bt, physicalSurface) SUBROUTINE initEdge_interface(self, n, p, bt, physicalSurface)
IMPORT:: meshEdge IMPORT:: meshEdge
CLASS(meshEdge), INTENT(out):: self CLASS(meshEdge), INTENT(out):: self
INTEGER, INTENT(in):: n INTEGER, INTENT(in):: n
INTEGER, INTENT(in):: p(:) INTEGER, INTENT(in):: p(:)
@ -84,10 +86,16 @@ MODULE moduleMesh
END SUBROUTINE END SUBROUTINE
PURE FUNCTION randPos_interface(self, rnd) RESULT(r) PURE FUNCTION getNodesEdge_interface(self) RESULT(n)
IMPORT:: meshEdge
CLASS(meshEdge), INTENT(in):: self
INTEGER, ALLOCATABLE:: n(:)
END FUNCTION
FUNCTION randPos_interface(self) RESULT(r)
IMPORT:: meshEdge IMPORT:: meshEdge
CLASS(meshEdge), INTENT(in):: self CLASS(meshEdge), INTENT(in):: self
REAL(8), INTENT(in):: rnd
REAL(8):: r(1:3) REAL(8):: r(1:3)
END FUNCTION randPos_interface END FUNCTION randPos_interface
@ -119,6 +127,9 @@ MODULE moduleMesh
CONTAINS CONTAINS
PROCEDURE(initVol_interface), DEFERRED, PASS:: init PROCEDURE(initVol_interface), DEFERRED, PASS:: init
PROCEDURE(scatter_interface), DEFERRED, PASS:: scatter PROCEDURE(scatter_interface), DEFERRED, PASS:: scatter
PROCEDURE(gatherEF_interface), DEFERRED, PASS:: gatherEF
PROCEDURE(getNodesVol_interface), DEFERRED, PASS:: getNodes
PROCEDURE(elemF_interface), DEFERRED, PASS:: elemF
PROCEDURE(collision_interface), DEFERRED, PASS:: collision PROCEDURE(collision_interface), DEFERRED, PASS:: collision
PROCEDURE(findCell_interface), DEFERRED, PASS:: findCell PROCEDURE(findCell_interface), DEFERRED, PASS:: findCell
PROCEDURE(resetOutput_interface), DEFERRED, PASS:: resetOutput PROCEDURE(resetOutput_interface), DEFERRED, PASS:: resetOutput
@ -143,6 +154,32 @@ MODULE moduleMesh
END SUBROUTINE scatter_interface END SUBROUTINE scatter_interface
PURE FUNCTION gatherEF_interface(self, xi) RESULT(EF)
IMPORT:: meshVol
CLASS(meshVol), INTENT(in):: self
REAL(8), INTENT(in):: xi(1:3)
REAL(8):: EF(1:3)
END FUNCTION gatherEF_interface
PURE FUNCTION getNodesVol_interface(self) RESULT(n)
IMPORT:: meshVol
CLASS(meshVol), INTENT(in):: self
INTEGER, ALLOCATABLE:: n(:)
END FUNCTION getNodesVol_interface
PURE FUNCTION elemF_interface(self, source) RESULT(localF)
IMPORT:: meshVol
CLASS(meshVol), INTENT(in):: self
REAL(8), INTENT(in):: source(1:)
REAL(8), ALLOCATABLE:: localF(:)
END FUNCTION elemF_interface
SUBROUTINE collision_interface(self) SUBROUTINE collision_interface(self)
IMPORT:: meshVol IMPORT:: meshVol
CLASS(meshVol), INTENT(inout):: self CLASS(meshVol), INTENT(inout):: self
@ -184,13 +221,14 @@ MODULE moduleMesh
TYPE(meshVolCont), ALLOCATABLE:: vols(:) TYPE(meshVolCont), ALLOCATABLE:: vols(:)
!Global stiffness matrix !Global stiffness matrix
REAL(8), ALLOCATABLE, DIMENSION(:,:):: K REAL(8), ALLOCATABLE, DIMENSION(:,:):: K
!Global load vector !Permutation matrix for P L U factorization
REAL(8), ALLOCATABLE, DIMENSION(:):: F INTEGER, ALLOCATABLE, DIMENSION(:,:):: IPIV
CONTAINS CONTAINS
PROCEDURE(readMesh_interface), PASS, DEFERRED:: readMesh PROCEDURE(readMesh_interface), PASS, DEFERRED:: readMesh
PROCEDURE(printOutput_interface), PASS, DEFERRED:: printOutput PROCEDURE(printOutput_interface), PASS, DEFERRED:: printOutput
PROCEDURE(printColl_interface), PASS, DEFERRED:: printColl PROCEDURE(printColl_interface), PASS, DEFERRED:: printColl
PROCEDURE(printEM_interface), PASS, DEFERRED:: printEM
END TYPE meshGeneric END TYPE meshGeneric
@ -213,7 +251,7 @@ MODULE moduleMesh
END SUBROUTINE printOutput_interface END SUBROUTINE printOutput_interface
!Prints unmber of collisions !Prints number of collisions
SUBROUTINE printColl_interface(self, t) SUBROUTINE printColl_interface(self, t)
IMPORT meshGeneric IMPORT meshGeneric
@ -222,6 +260,14 @@ MODULE moduleMesh
END SUBROUTINE printColl_interface END SUBROUTINE printColl_interface
!Prints EM info
SUBROUTINE printEM_interface(self, t)
IMPORT meshGeneric
CLASS(meshGeneric), INTENT(in):: self
INTEGER, INTENT(in):: t
END SUBROUTINE printEM_interface
END INTERFACE END INTERFACE
!Generic mesh !Generic mesh

View file

@ -25,8 +25,9 @@ MODULE moduleMeshCyl
!Connectivity to nodes !Connectivity to nodes
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL() CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL()
CONTAINS CONTAINS
PROCEDURE, PASS:: init => initEdgeCyl PROCEDURE, PASS:: init => initEdgeCyl
PROCEDURE, PASS:: randPos => randPosCyl PROCEDURE, PASS:: getNodes => getNodesCyl
PROCEDURE, PASS:: randPos => randPosCyl
END TYPE meshEdgeCyl END TYPE meshEdgeCyl
@ -43,22 +44,20 @@ MODULE moduleMeshCyl
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL(), n3 => NULL(), n4 => NULL() CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL(), n3 => NULL(), n4 => NULL()
!Connectivity to adjacent elements !Connectivity to adjacent elements
CLASS(*), POINTER:: e1 => NULL(), e2 => NULL(), e3 => NULL(), e4 => NULL() CLASS(*), POINTER:: e1 => NULL(), e2 => NULL(), e3 => NULL(), e4 => NULL()
!Maximum collision rate
!TODO: Move to other more appropiate section
REAL(8):: phi(1:4) = 0.D0
REAL(8):: Ke(1:4,1:4) = 0.D0
REAL(8):: arNodes(1:4) = 0.D0 REAL(8):: arNodes(1:4) = 0.D0
CONTAINS CONTAINS
PROCEDURE, PASS:: init => initVolQuadCyl PROCEDURE, PASS:: init => initVolQuadCyl
PROCEDURE, PASS:: locKe => localKeQuad PROCEDURE, PASS:: elemK => elemKQuad
PROCEDURE, PASS:: elemF => elemFQuad
PROCEDURE, PASS:: detJac => detJQuad PROCEDURE, PASS:: detJac => detJQuad
PROCEDURE, PASS:: invJ => invJQuad PROCEDURE, PASS:: invJ => invJQuad
PROCEDURE, PASS:: area => areaQuad PROCEDURE, PASS:: area => areaQuad
PROCEDURE, NOPASS:: weight => weightQuad PROCEDURE, NOPASS:: weight => weightQuad
PROCEDURE, NOPASS:: inside => insideQuad PROCEDURE, NOPASS:: inside => insideQuad
PROCEDURE, PASS:: dVal => dValQuad
PROCEDURE, PASS:: scatter => scatterQuad PROCEDURE, PASS:: scatter => scatterQuad
PROCEDURE, PASS:: gatherEF => gatherEFQuad
PROCEDURE, PASS:: getNodes => getNodesQuad
PROCEDURE, PASS:: phy2log => phy2logQuad PROCEDURE, PASS:: phy2log => phy2logQuad
PROCEDURE, PASS:: findCell => findCellCylQuad PROCEDURE, PASS:: findCell => findCellCylQuad
PROCEDURE, PASS:: resetOutput => resetOutputQuad PROCEDURE, PASS:: resetOutput => resetOutputQuad
@ -78,8 +77,8 @@ MODULE moduleMeshCyl
REAL(8), INTENT(in):: r(1:3) REAL(8), INTENT(in):: r(1:3)
self%n = n self%n = n
self%r = r(1)/L_ref
self%z = r(2)/L_ref self%z = r(2)/L_ref
self%r = r(1)/L_ref
!Node volume, to be determined in mesh !Node volume, to be determined in mesh
self%v = 0.D0 self%v = 0.D0
@ -128,13 +127,25 @@ MODULE moduleMeshCyl
END SUBROUTINE initEdgeCyl END SUBROUTINE initEdgeCyl
PURE FUNCTION getNodesCyl(self) RESULT(n)
IMPLICIT NONE
PURE FUNCTION randPosCyl(self, rnd) RESULT(r)
CLASS(meshEdgeCyl), INTENT(in):: self CLASS(meshEdgeCyl), INTENT(in):: self
REAL(8), INTENT(in):: rnd INTEGER, ALLOCATABLE:: n(:)
ALLOCATE(n(1:2))
n = (/self%n1%n, self%n2%n /)
END FUNCTION getNodesCyl
FUNCTION randPosCyl(self) RESULT(r)
CLASS(meshEdgeCyl), INTENT(in):: self
REAL(8):: rnd
REAL(8):: r(1:3) REAL(8):: r(1:3)
REAL(8):: p1(1:2), p2(1:2) REAL(8):: p1(1:2), p2(1:2)
rnd = RAND()
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) /)
r(1:2) = (1.D0 - rnd)*p1 + rnd*p2 r(1:2) = (1.D0 - rnd)*p1 + rnd*p2
@ -173,15 +184,14 @@ MODULE moduleMeshCyl
self%n3%v = self%n3%v + self%arNodes(3) self%n3%v = self%n3%v + self%arNodes(3)
self%n4%v = self%n4%v + self%arNodes(4) self%n4%v = self%n4%v + self%arNodes(4)
CALL self%locKe()
self%sigmaVrelMax = sigma_ref/L_ref**2 self%sigmaVrelMax = sigma_ref/L_ref**2
CALL OMP_INIT_LOCK(self%lock) CALL OMP_INIT_LOCK(self%lock)
END SUBROUTINE initVolQuadCyl END SUBROUTINE initVolQuadCyl
FUNCTION fpsi(xi1,xi2) RESULT(psi) !TODO: MAKE ELEMENT DEPENDENT
PURE FUNCTION fpsi(xi1,xi2) RESULT(psi)
IMPLICIT NONE IMPLICIT NONE
REAL(8),INTENT(in):: xi1,xi2 REAL(8),INTENT(in):: xi1,xi2
@ -195,7 +205,8 @@ MODULE moduleMeshCyl
END FUNCTION fpsi END FUNCTION fpsi
!Derivative element function (xi1) !Derivative element function (xi1)
FUNCTION dpsiXi1(xi2) RESULT(psiXi1) !TODO: MAKE ELEMENT DEPENDENT
PURE FUNCTION dpsiXi1(xi2) RESULT(psiXi1)
IMPLICIT NONE IMPLICIT NONE
REAL(8),INTENT(in):: xi2 REAL(8),INTENT(in):: xi2
@ -209,7 +220,8 @@ MODULE moduleMeshCyl
END FUNCTION dpsiXi1 END FUNCTION dpsiXi1
!Derivative element function (xi2) !Derivative element function (xi2)
FUNCTION dpsiXi2(xi1) RESULT(psiXi2) !TODO: MAKE ELEMENT DEPENDENT
PURE FUNCTION dpsiXi2(xi1) RESULT(psiXi2)
IMPLICIT NONE IMPLICIT NONE
REAL(8),INTENT(in):: xi1 REAL(8),INTENT(in):: xi1
@ -223,12 +235,13 @@ MODULE moduleMeshCyl
END FUNCTION dpsiXi2 END FUNCTION dpsiXi2
!Transforms physical coordinates to element coordinates !Transforms physical coordinates to element coordinates
FUNCTION phy2logQuad(this,r) RESULT(xN) PURE FUNCTION phy2logQuad(self,r) RESULT(xN)
IMPLICIT NONE IMPLICIT NONE
CLASS(meshVolCylQuad):: this CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8):: r(1:2) REAL(8), INTENT(in):: r(1:3)
REAL(8):: xN(1:2), xO(1:2), dPsi(1:2,1:4), detJ, j(1:2,1:2), psi(1:4), f(1:2) REAL(8):: xN(1:3)
REAL(8):: xO(1:3), dPsi(1:2,1:4), detJ, j(1:2,1:2), psi(1:4), f(1:2)
REAL(8):: conv REAL(8):: conv
!Iterative newton method to transform coordinates !Iterative newton method to transform coordinates
@ -238,12 +251,12 @@ MODULE moduleMeshCyl
DO WHILE(conv>1.D-4) DO WHILE(conv>1.D-4)
dPsi(1,:) = dpsiXi1(xO(2)) dPsi(1,:) = dpsiXi1(xO(2))
dPsi(2,:) = dpsiXi2(xO(1)) dPsi(2,:) = dpsiXi2(xO(1))
j = this%invJ(xO(1),xO(2),dPsi) j = self%invJ(xO, dPsi)
psi = fpsi(xO(1), xO(2)) psi = fpsi(xO(1), xO(2))
f(1) = DOT_PRODUCT(psi,this%z)-r(1) f(1) = DOT_PRODUCT(psi,self%z)-r(1)
f(2) = DOT_PRODUCT(psi,this%r)-r(2) f(2) = DOT_PRODUCT(psi,self%r)-r(2)
detJ = this%detJac(xO(1),xO(2),dPsi) detJ = self%detJac(xO,dPsi)
xN=xO - MATMUL(j, f)/detJ xN(1:2)=xO(1:2) - MATMUL(j, f)/detJ
conv=MAXVAL(DABS(xN-xO),1) conv=MAXVAL(DABS(xN-xO),1)
xO=xN xO=xN
@ -252,106 +265,139 @@ MODULE moduleMeshCyl
END FUNCTION phy2logQuad END FUNCTION phy2logQuad
!Computes element local stiffness matrix !Computes element local stiffness matrix
SUBROUTINE localKeQuad(this) PURE FUNCTION elemKQuad(self) RESULT(ke)
USE moduleConstParam USE moduleConstParam
IMPLICIT NONE IMPLICIT NONE
CLASS(meshVolCylQuad):: this CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8):: r, xi1, xi2, dPsi(1:2,1:4) REAL(8):: r, xi(1:3), dPsi(1:2,1:4)
REAL(8):: ke(1:4,1:4)
REAL(8):: j(1:2,1:2), detJ REAL(8):: j(1:2,1:2), detJ
INTEGER:: l, m INTEGER:: l, m
this%Ke=0.D0 ke=0.D0
!Start 2D Gauss Quad Integral !Start 2D Gauss Quad Integral
DO l=1, 3 DO l=1, 3
xi(1) = cor(l)
dPsi(2,:) = dpsiXi2(xi(1))
DO m = 1, 3 DO m = 1, 3
xi1 = cor(l) xi(2) = cor(m)
xi2 = cor(m) dPsi(1,:) = dpsiXi1(xi(2))
dPsi(1,:) = dpsiXi1(xi2) detJ = self%detJac(xi,dPsi)
dPsi(2,:) = dpsiXi2(xi1) j = self%invJ(xi,dPsi)
detJ = this%detJac(xi1,xi2,dPsi) r = DOT_PRODUCT(fpsi(xi(1),xi(2)),self%r)
j = this%invJ(xi1,xi2,dPsi) ke = ke + MATMUL(TRANSPOSE(MATMUL(j,dPsi)),MATMUL(j,dPsi))*r*w(l)*w(m)/detJ
r = DOT_PRODUCT(fpsi(xi1,xi2),this%r)
this%Ke = this%Ke + MATMUL(TRANSPOSE(MATMUL(j,dPsi)),MATMUL(j,dPsi))*r*w(l)*w(m)/detJ
END DO END DO
END DO END DO
this%Ke = this%Ke*2.D0*PI ke = ke*2.D0*PI
END SUBROUTINE localKeQuad END FUNCTION elemKQuad
!Computes element Jacobian determinant !Computes the local source vector for a force f
FUNCTION detJQuad(this,xi1,xi2,dPsi_in) RESULT(dJ) PURE FUNCTION elemFQuad(self, source) RESULT(localF)
USE moduleConstParam
IMPLICIT NONE IMPLICIT NONE
REAL(8),OPTIONAL:: dPsi_in(1:2,1:4) CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8), INTENT(in):: source(1:)
REAL(8), ALLOCATABLE:: localF(:)
REAL(8):: r, xi(1:3), psi(1:4)
REAL(8):: detJ, f
INTEGER:: l, m
ALLOCATE(localF(1:4))
localF = 0.D0
xi = 0.D0
DO l=1, 3
DO m = 1, 3
xi(1) = cor(l)
xi(2) = cor(m)
detJ = self%detJac(xi)
psi = fpsi(xi(1),xi(2))
r = DOT_PRODUCT(psi,self%r)
f = DOT_PRODUCT(psi,source)
localF = localF + r*f*psi*w(l)*w(m)*detJ
END DO
END DO
localF = localF*2.D0*PI
END FUNCTION elemFQuad
!Computes element Jacobian determinant
PURE FUNCTION detJQuad(self,xi,dPsi_in) RESULT(dJ)
IMPLICIT NONE
CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8), INTENT(in):: xi(1:3)
REAL(8), INTENT(in), OPTIONAL:: dPsi_in(1:2,1:4)
REAL(8):: dJ
REAL(8):: dPsi(1:2,1:4) REAL(8):: dPsi(1:2,1:4)
REAL(8):: dz(1:2), dr(1:2) REAL(8):: dz(1:2), dr(1:2)
REAL(8):: xi1,xi2, dJ
CLASS(meshVolCylQuad):: this
IF(PRESENT(dPsi_in)) THEN IF(PRESENT(dPsi_in)) THEN
dPsi=dPsi_in dPsi=dPsi_in
ELSE ELSE
dPsi(1,:) = dpsiXi1(xi2) dPsi(1,:) = dpsiXi1(xi(2))
dPsi(2,:) = dpsiXi2(xi1) dPsi(2,:) = dpsiXi2(xi(1))
END IF END IF
dz(1) = DOT_PRODUCT(dPsi(1,:),this%z) dz(1) = DOT_PRODUCT(dPsi(1,:),self%z)
dz(2) = DOT_PRODUCT(dPsi(2,:),this%z) dz(2) = DOT_PRODUCT(dPsi(2,:),self%z)
dr(1) = DOT_PRODUCT(dPsi(1,:),this%r) dr(1) = DOT_PRODUCT(dPsi(1,:),self%r)
dr(2) = DOT_PRODUCT(dPsi(2,:),this%r) dr(2) = DOT_PRODUCT(dPsi(2,:),self%r)
dJ = dz(1)*dr(2)-dz(2)*dr(1) dJ = dz(1)*dr(2)-dz(2)*dr(1)
END FUNCTION detJQuad END FUNCTION detJQuad
FUNCTION invJQuad(this,xi1,xi2,dPsi_in) RESULT(j) !Computes element Jacobian inverse matrix (without determinant) PURE FUNCTION invJQuad(self,xi,dPsi_in) RESULT(j) !Computes element Jacobian inverse matrix (without determinant)
IMPLICIT NONE IMPLICIT NONE
REAL(8),OPTIONAL:: dpsi_in(1:2,1:4) CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8), INTENT(in):: xi(1:3)
REAL(8), INTENT(in), OPTIONAL:: dpsi_in(1:2,1:4)
REAL(8):: dPsi(1:2,1:4) REAL(8):: dPsi(1:2,1:4)
REAL(8):: dz(1:2), dr(1:2) REAL(8):: dz(1:2), dr(1:2)
REAL(8):: xi1,xi2, j(1:2,1:2) REAL(8):: j(1:2,1:2)
CLASS(meshVolCylQuad):: this
IF(PRESENT(dPsi_in)) THEN IF(PRESENT(dPsi_in)) THEN
dPsi=dPsi_in dPsi=dPsi_in
ELSE ELSE
dPsi(1,:) = dpsiXi1(xi2) dPsi(1,:) = dpsiXi1(xi(2))
dPsi(2,:) = dpsiXi2(xi1) dPsi(2,:) = dpsiXi2(xi(1))
END IF END IF
dz(1) = DOT_PRODUCT(dPsi(1,:),this%z) dz(1) = DOT_PRODUCT(dPsi(1,:),self%z)
dz(2) = DOT_PRODUCT(dPsi(2,:),this%z) dz(2) = DOT_PRODUCT(dPsi(2,:),self%z)
dr(1) = DOT_PRODUCT(dPsi(1,:),this%r) dr(1) = DOT_PRODUCT(dPsi(1,:),self%r)
dr(2) = DOT_PRODUCT(dPsi(2,:),this%r) dr(2) = DOT_PRODUCT(dPsi(2,:),self%r)
j(1,:) = (/ dr(2), -dz(2) /) j(1,:) = (/ dr(2), -dz(2) /)
j(2,:) = (/ -dr(1), dz(1) /) j(2,:) = (/ -dr(1), dz(1) /)
END FUNCTION invJQuad END FUNCTION invJQuad
SUBROUTINE areaQuad(this)!Computes element area SUBROUTINE areaQuad(self)!Computes element area
USE moduleConstParam USE moduleConstParam
IMPLICIT NONE IMPLICIT NONE
CLASS(meshVolCylQuad):: this CLASS(meshVolCylQuad):: self
REAL(8):: r, xi1, xi2 REAL(8):: r, xi(1:3)
REAL(8):: detJ, fpsi0(1:4) REAL(8):: detJ, fpsi0(1:4)
this%volume = 0.D0 self%volume = 0.D0
this%arNodes = 0.D0 self%arNodes = 0.D0
!2D 1 point Gauss Quad Integral !2D 1 point Gauss Quad Integral
xi1 = 0.D0 xi = 0.D0
xi2 = 0.D0 detJ = self%detJac(xi)*8.D0*PI !4*2*pi
detJ = this%detJac(xi1,xi2)*8.D0*PI !4*2*pi fpsi0 = fpsi(xi(1),xi(2))
fpsi0 = fpsi(xi1,xi2) r = DOT_PRODUCT(fpsi0,self%r)
r = DOT_PRODUCT(fpsi0,this%r) self%volume = r*detJ
this%volume = r*detJ self%arNodes = fpsi0*r*detJ
this%arNodes = fpsi0*r*detJ
END SUBROUTINE areaQuad END SUBROUTINE areaQuad
@ -376,24 +422,6 @@ MODULE moduleMeshCyl
END FUNCTION insideQuad END FUNCTION insideQuad
FUNCTION dValQuad(this,xi1,xi2) RESULT(EF)!Computes electric field in xi1,xi2
IMPLICIT NONE
CLASS(meshVolCylQuad):: this
REAL(8):: xi1, xi2, dPsi(1:2,1:4)
REAL(8):: j(1:2,1:2), detJ
REAL(8):: EF(1:3)
dPsi(1,:) = dpsiXi1(xi2)
dPsi(2,:) = dpsiXi2(xi1)
detJ = this%detJac(xi1,xi2,dPsi)
j = this%invJ(xi1,xi2,dPsi)
EF(1) = -DOT_PRODUCT(dPsi(1,:), this%phi)*j(2,2)/detJ
EF(2) = -DOT_PRODUCT(dPsi(2,:), this%phi)*j(1,1)/detJ
EF(3) = 0.D0
END FUNCTION dValQuad
SUBROUTINE scatterQuad(self, part) SUBROUTINE scatterQuad(self, part)
USE moduleOutput USE moduleOutput
USE moduleSpecies USE moduleSpecies
@ -428,29 +456,65 @@ MODULE moduleMeshCyl
vertex%mom(:) = vertex%mom(:) + part%weight*w_p(4)*part%v(:) vertex%mom(:) = vertex%mom(:) + part%weight*w_p(4)*part%v(:)
vertex%tensorS(:,:) = vertex%tensorS(:,:) + part%weight*w_p(4)*tensorS vertex%tensorS(:,:) = vertex%tensorS(:,:) + part%weight*w_p(4)*tensorS
END SUBROUTINE scatterQuad END SUBROUTINE scatterQuad
PURE FUNCTION gatherEFQuad(self,xi) RESULT(EF)!Computes electric field inside element
IMPLICIT NONE
CLASS(meshVolCylQuad), INTENT(in):: self
REAL(8), INTENT(in):: xi(1:3)
REAL(8):: dPsi(1:2,1:4)
REAL(8):: j(1:2,1:2), detJ
REAL(8):: phi(1:4)
REAL(8):: EF(1:3)
phi = (/self%n1%emData%phi, &
self%n2%emData%phi, &
self%n3%emData%phi, &
self%n4%emData%phi /)
dPsi(1,:) = dpsiXi1(xi(2))
dPsi(2,:) = dpsiXi2(xi(1))
detJ = self%detJac(xi,dPsi)
j = self%invJ(xi,dPsi)
EF(1) = -DOT_PRODUCT(dPsi(1,:), phi)*j(2,2)/detJ
EF(2) = -DOT_PRODUCT(dPsi(2,:), phi)*j(1,1)/detJ
EF(3) = 0.D0
END FUNCTION gatherEFQuad
PURE FUNCTION getNodesQuad(self) RESULT(n)
IMPLICIT NONE
CLASS(meshVolCylQuad), INTENT(in):: self
INTEGER, ALLOCATABLE:: n(:)
ALLOCATE(n(1:4))
n = (/self%n1%n, self%n2%n, self%n3%n, self%n4%n /)
END FUNCTION getNodesQuad
RECURSIVE SUBROUTINE findCellCylQuad(self, part, oldCell) RECURSIVE SUBROUTINE findCellCylQuad(self, part, oldCell)
USE moduleSpecies USE moduleSpecies
USE OMP_LIB
IMPLICIT NONE IMPLICIT NONE
CLASS(meshVolCylQuad), INTENT(inout):: self CLASS(meshVolCylQuad), INTENT(inout):: self
CLASS(meshVol), OPTIONAL, INTENT(in):: oldCell CLASS(meshVol), OPTIONAL, INTENT(in):: oldCell
CLASS(particle), INTENT(inout), TARGET:: part CLASS(particle), INTENT(inout), TARGET:: part
REAL(8):: xLog(1:2) REAL(8):: xLog(1:3)
REAL(8):: xLogArray(1:4) REAL(8):: xLogArray(1:4)
CLASS(*), POINTER:: nextElement CLASS(*), POINTER:: nextElement
INTEGER:: nextInt INTEGER:: nextInt
xLog = self%phy2log(part%r(1:2)) xLog = self%phy2log(part%r)
!Checks if particle is inside of current cell
IF (self%inside(xLog(1), xLog(2))) THEN IF (self%inside(xLog(1), xLog(2))) THEN
!Checks if particle is inside of current cell ! IF (PRESENT(oldCell)) THEN
IF (PRESENT(oldCell)) THEN ! !If oldCell, recalculate particle weight, as particle has entered a new cell.
!If oldCell, recalculate particle weight, as particle has entered a new cell. ! part%weight = part%weight*oldCell%volume/self%volume
part%weight = part%weight*oldCell%volume/self%volume !
! END IF
END IF
part%e_p = self%n part%e_p = self%n
part%xLog = xLog part%xLog = xLog
part%n_in = .TRUE. part%n_in = .TRUE.

View file

@ -74,8 +74,6 @@ MODULE moduleMeshCylBoundary
CLASS(meshEdgeCylAxis), INTENT(inout):: self CLASS(meshEdgeCylAxis), INTENT(inout):: self
CLASS(particle), INTENT(inout):: part CLASS(particle), INTENT(inout):: part
!Do to the 2D Cyl pusher, this function should never be called.
END SUBROUTINE symmetryAxis END SUBROUTINE symmetryAxis

View file

@ -8,6 +8,7 @@ MODULE moduleMeshCylRead
PROCEDURE, PASS:: readMesh => readMeshCyl PROCEDURE, PASS:: readMesh => readMeshCyl
PROCEDURE, PASS:: printOutput => printOutputCyl PROCEDURE, PASS:: printOutput => printOutputCyl
PROCEDURE, PASS:: printColl => printCollisionsCyl PROCEDURE, PASS:: printColl => printCollisionsCyl
PROCEDURE, PASS:: printEM => printEMCyl
END TYPE END TYPE
@ -41,8 +42,10 @@ MODULE moduleMeshCylRead
READ(10, *) self%numNodes READ(10, *) self%numNodes
!Allocate required matrices and vectors !Allocate required matrices and vectors
ALLOCATE(self%nodes(1:self%numNodes)) ALLOCATE(self%nodes(1:self%numNodes))
! ALLOCATE(self%K(1:numNodes,1:numNodes)) ALLOCATE(self%K(1:self%numNodes,1:self%numNodes))
! ALLOCATE(self%F(1:numNodes)) ALLOCATE(self%IPIV(1:self%numNodes,1:self%numNodes))
self%K = 0.D0
self%IPIV = 0
!Read nodes cartesian coordinates (x=z, y=r, z=null) !Read nodes cartesian coordinates (x=z, y=r, z=null)
DO e=1, self%numNodes DO e=1, self%numNodes
READ(10, *) n, z, r READ(10, *) n, z, r
@ -123,24 +126,10 @@ MODULE moduleMeshCylRead
END DO END DO
END DO !Constructs the global K matrix
CALL constructGlobalK(self%K, self%vols(e)%obj)
! !Compute global stiffness matrix END DO
! GlobalK=0.D0
! DO e=1, numElem
! DO i=1, 4
! DO j=1, 4
! GlobalK(elems(e)%p(i),elems(e)%p(j)) = GlobalK(elems(e)%p(i),elems(e)%p(j)) + elems(e)%Ke(i,j)
! END DO
! END DO
! END DO
! ! Apply Dirichlet boundary conditions to GlobalK
! DO n=1, numNodes
! IF (nodes(n)%bound == 1) THEN
! GlobalK(n,:)=0.D0
! GlobalK(n,n)=1.D0
! END IF
! END DO
END SUBROUTINE END SUBROUTINE
@ -298,6 +287,41 @@ MODULE moduleMeshCylRead
END SUBROUTINE connectedQuadEdge END SUBROUTINE connectedQuadEdge
SUBROUTINE constructGlobalK(K, elem)
IMPLICIT NONE
REAL(8), INTENT(inout):: K(1:,1:)
CLASS(meshVol), INTENT(in):: elem
REAL(8), ALLOCATABLE:: localK(:,:)
INTEGER:: nNodes, i, j
INTEGER, ALLOCATABLE:: n(:)
SELECT TYPE(elem)
TYPE IS(meshVolCylQuad)
nNodes = 4
ALLOCATE(localK(1:nNodes,1:nNodes))
localK = elem%elemK()
ALLOCATE(n(1:nNodes))
n = (/ elem%n1%n, elem%n2%n, &
elem%n3%n, elem%n4%n /)
CLASS DEFAULT
nNodes = 0
ALLOCATE(localK(1:1, 1:1))
localK = 0.D0
ALLOCATE(n(1:1))
n = 0
END SELECT
DO i = 1, nNodes
DO j = 1, nNodes
K(n(i), n(j)) = K(n(i), n(j)) + localK(i, j)
END DO
END DO
END SUBROUTINE constructGlobalK
SUBROUTINE printOutputCyl(self, t) SUBROUTINE printOutputCyl(self, t)
USE moduleRefParam USE moduleRefParam
USE moduleSpecies USE moduleSpecies
@ -425,4 +449,60 @@ MODULE moduleMeshCylRead
END SUBROUTINE printCollisionsCyl END SUBROUTINE printCollisionsCyl
SUBROUTINE printEMCyl(self, t)
USE moduleRefParam
USE moduleCaseParam
USE moduleOutput
IMPLICIT NONE
CLASS(meshCylGeneric), INTENT(in):: self
INTEGER, INTENT(in):: t
INTEGER:: n, e
REAL(8):: time
CHARACTER(:), ALLOCATABLE:: fileName
CHARACTER (LEN=6):: tstring !TODO: Review to allow any number of iterations
IF (emOutput) THEN
time = DBLE(t)*tau*ti_ref
WRITE(tstring, '(I6.6)') t
fileName='OUTPUT_' // tstring// '_EMField.msh'
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
OPEN (20, file = path // folder // '/' // fileName)
WRITE(20, "(A)") '$MeshFormat'
WRITE(20, "(A)") '2.2 0 8'
WRITE(20, "(A)") '$EndMeshFormat'
WRITE(20, "(A)") '$NodeData'
WRITE(20, "(A)") '1'
WRITE(20, "(A)") '"Potential (V)"'
WRITE(20, *) 1
WRITE(20, *) time
WRITE(20, *) 3
WRITE(20, *) t
WRITE(20, *) 1
WRITE(20, *) self%numNodes
DO n=1, self%numNodes
WRITE(20, *) n, self%nodes(n)%obj%emData%phi*Volt_ref
END DO
WRITE(20, "(A)") '$EndNodeData'
WRITE(20, "(A)") '$ElementData'
WRITE(20, "(A)") '1'
WRITE(20, "(A)") '"Electric Field (V/m)"'
WRITE(20, *) 1
WRITE(20, *) time
WRITE(20, *) 3
WRITE(20, *) t
WRITE(20, *) 3
WRITE(20, *) self%numVols
DO e=1, self%numVols
WRITE(20, *) e+self%numEdges, self%vols(e)%obj%gatherEF((/0.D0, 0.D0, 0.D0/))*EF_ref
END DO
WRITE(20, "(A)") '$EndElementData'
CLOSE(20)
END IF
END SUBROUTINE printEMCyl
END MODULE moduleMeshCylRead END MODULE moduleMeshCylRead

View file

@ -7,6 +7,13 @@ MODULE moduleOutput
END TYPE END TYPE
!Type for EM data in node
TYPE emNode
CHARACTER(:), ALLOCATABLE:: type
REAL(8):: phi
END TYPE emNode
!Output in dimensional units to print !Output in dimensional units to print
TYPE outputFormat TYPE outputFormat
REAL(8):: density, velocity(1:3), pressure, temperature REAL(8):: density, velocity(1:3), pressure, temperature
@ -18,6 +25,7 @@ MODULE moduleOutput
INTEGER:: triggerOutput, counterOutput INTEGER:: triggerOutput, counterOutput
LOGICAL:: timeOutput = .FALSE. LOGICAL:: timeOutput = .FALSE.
LOGICAL:: collOutput = .FALSE. LOGICAL:: collOutput = .FALSE.
LOGICAL:: emOutput = .FALSE.
CONTAINS CONTAINS
FUNCTION outerProduct(a,b) RESULT(s) FUNCTION outerProduct(a,b) RESULT(s)
@ -42,6 +50,7 @@ MODULE moduleOutput
END FUNCTION tensorTrace END FUNCTION tensorTrace
SUBROUTINE calculateOutput(rawValues, formatValues, nodeVol, speciesIn) SUBROUTINE calculateOutput(rawValues, formatValues, nodeVol, speciesIn)
USE moduleConstParam
USE moduleRefParam USE moduleRefParam
USE moduleSpecies USE moduleSpecies
IMPLICIT NONE IMPLICIT NONE

View file

@ -1,10 +1,9 @@
!Reference parameters !Reference parameters
MODULE moduleRefParam MODULE moduleRefParam
USE moduleConstParam
!Parameters that define the problem (inputs) !Parameters that define the problem (inputs)
REAL(8):: n_ref, m_ref, T_ref, r_ref, sigma_ref!, q_ref=1.6022D-19 REAL(8):: n_ref, m_ref, T_ref, r_ref, debye_ref, sigma_ref
!Reference parameters for non-dimensional problem !Reference parameters for non-dimensional problem
REAL(8):: L_ref, v_ref, ti_ref, Vol_ref REAL(8):: L_ref, v_ref, ti_ref, Vol_ref, EF_ref, Volt_ref
END MODULE moduleRefParam END MODULE moduleRefParam

View file

@ -1,5 +1,44 @@
MODULE moduleSolver 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 CONTAINS
SUBROUTINE doPushes() SUBROUTINE doPushes()
USE moduleSpecies USE moduleSpecies
@ -10,7 +49,9 @@ MODULE moduleSolver
!$OMP DO !$OMP DO
DO n=1, nPartOld 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)) CALL mesh%vols(partOld(n)%e_p)%obj%findCell(partOld(n))
END DO END DO
@ -18,16 +59,15 @@ MODULE moduleSolver
END SUBROUTINE doPushes END SUBROUTINE doPushes
!Push one particle. Boris pusher for 2D Cyl !Push one particle. Boris pusher for 2D Cyl Neutral particle
!TODO: make general for any pusher PURE SUBROUTINE pushCylNeutral(part)
PURE SUBROUTINE push(part)
USE moduleSpecies USE moduleSpecies
USE moduleMesh
IMPLICIT NONE IMPLICIT NONE
TYPE(particle), INTENT(inout):: part TYPE(particle), INTENT(inout):: part
REAL(8):: v_p_oh_star(2:3) REAL(8):: v_p_oh_star(2:3)
TYPE(particle):: part_temp 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 part_temp = part
!z !z
@ -40,8 +80,6 @@ MODULE moduleSolver
y_new = v_p_oh_star(3)*tau y_new = v_p_oh_star(3)*tau
r = DSQRT(x_new**2+y_new**2) r = DSQRT(x_new**2+y_new**2)
part_temp%r(2) = r 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 IF (r > 0.D0) THEN
sin_alpha = y_new/r sin_alpha = y_new/r
cos_alpha = x_new/r cos_alpha = x_new/r
@ -57,7 +95,47 @@ MODULE moduleSolver
!Copy temporal particle to particle !Copy temporal particle to particle
part=part_temp 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 !Do the collisions in all the cells
SUBROUTINE doCollisions() SUBROUTINE doCollisions()
@ -153,6 +231,64 @@ MODULE moduleSolver
END SUBROUTINE doScatter 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) SUBROUTINE doOutput(t)
USE moduleMesh USE moduleMesh
USE moduleOutput USE moduleOutput
@ -172,8 +308,9 @@ MODULE moduleSolver
CALL mesh%printOutput(t) CALL mesh%printOutput(t)
CALL printTime(t, t == 0) CALL printTime(t, t == 0)
CALL mesh%printColl(t) CALL mesh%printColl(t)
WRITE(*, "(5X,A21,I10,A1,I8)") "t/tmax: ", t, "/", tmax CALL mesh%printEM(t)
WRITE(*, "(5X,A21,I10)") "Particles: ", nPartOld WRITE(*, "(5X,A21,I10,A1,I10)") "t/tmax: ", t, "/", tmax
WRITE(*, "(5X,A21,I10)") "Particles: ", nPartOld
IF (t == 0) THEN IF (t == 0) THEN
WRITE(*, "(5X,A21,F8.1,A2)") " init time: ", 1.D3*tStep, "ms" WRITE(*, "(5X,A21,F8.1,A2)") " init time: ", 1.D3*tStep, "ms"
@ -183,7 +320,7 @@ MODULE moduleSolver
END IF END IF
IF (nPartOld > 0) THEN 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 END IF
WRITE(*,*) WRITE(*,*)

View file

@ -31,9 +31,10 @@ MODULE moduleSpecies
REAL(8):: v(1:3) !Velocity REAL(8):: v(1:3) !Velocity
INTEGER:: pt !Particle species id INTEGER:: pt !Particle species id
INTEGER:: e_p !Index of element in which the particle is located INTEGER:: e_p !Index of element in which the particle is located
REAL(8):: xLog(1:2) !Logical coordinates of particle in element e_p. REAL(8):: xLog(1:3) !Logical coordinates of particle in element e_p.
LOGICAL:: n_in !Flag that indicates if a particle is in the domain LOGICAL:: n_in !Flag that indicates if a particle is in the domain
REAL(8):: weight=0.D0 REAL(8):: weight=0.D0 !weight of particle
REAL(8):: qm = 0.D0 !charge over mass
END TYPE particle END TYPE particle