Merge, but I have to recover the outflow boundary condition
This commit is contained in:
commit
6828f1ef96
554 changed files with 1714358 additions and 41895 deletions
|
|
@ -45,6 +45,9 @@ PROGRAM fpakc
|
|||
|
||||
!$OMP SINGLE
|
||||
CALL verboseError("Calculating initial EM field...")
|
||||
! Update EM boundary models
|
||||
call boundariesEM_update()
|
||||
|
||||
!$OMP END SINGLE
|
||||
CALL doEMField()
|
||||
!$OMP END PARALLEL
|
||||
|
|
@ -62,6 +65,12 @@ PROGRAM fpakc
|
|||
! Update global time step index
|
||||
timeStep = t
|
||||
|
||||
! Update Particle boundary models
|
||||
call boundariesParticle_update()
|
||||
|
||||
! Update EM boundary models
|
||||
call boundariesEM_update()
|
||||
|
||||
!Checks if a species needs to me moved in this iteration
|
||||
CALL solver%updatePushSpecies()
|
||||
|
||||
|
|
|
|||
11
src/makefile
11
src/makefile
|
|
@ -1,15 +1,15 @@
|
|||
OBJECTS = $(OBJDIR)/moduleMesh.o $(OBJDIR)/moduleMeshBoundary.o $(OBJDIR)/moduleCompTime.o \
|
||||
OBJECTS = $(OBJDIR)/moduleMesh.o $(OBJDIR)/moduleMeshCommon.o $(OBJDIR)/moduleCompTime.o \
|
||||
$(OBJDIR)/moduleMesh@elements.o $(OBJDIR)/moduleMesh@boundaryEM.o $(OBJDIR)/moduleMesh@boundaryParticle.o $(OBJDIR)/moduleMesh@surfaces.o \
|
||||
$(OBJDIR)/moduleSpecies.o $(OBJDIR)/moduleInject.o $(OBJDIR)/moduleInput.o \
|
||||
$(OBJDIR)/moduleErrors.o $(OBJDIR)/moduleList.o $(OBJDIR)/moduleOutput.o \
|
||||
$(OBJDIR)/moduleBoundary.o $(OBJDIR)/moduleCaseParam.o $(OBJDIR)/moduleRefParam.o \
|
||||
$(OBJDIR)/moduleCaseParam.o $(OBJDIR)/moduleRefParam.o \
|
||||
$(OBJDIR)/moduleCollisions.o $(OBJDIR)/moduleTable.o $(OBJDIR)/moduleParallel.o \
|
||||
$(OBJDIR)/moduleEM.o $(OBJDIR)/moduleRandom.o $(OBJDIR)/moduleMath.o \
|
||||
$(OBJDIR)/moduleProbe.o $(OBJDIR)/moduleAverage.o $(OBJDIR)/moduleCoulomb.o \
|
||||
$(OBJDIR)/moduleMeshInoutCommon.o \
|
||||
$(OBJDIR)/moduleMeshInputVTU.o $(OBJDIR)/moduleMeshOutputVTU.o \
|
||||
$(OBJDIR)/moduleMeshInputGmsh2.o $(OBJDIR)/moduleMeshOutputGmsh2.o \
|
||||
$(OBJDIR)/moduleMeshInput0D.o $(OBJDIR)/moduleMeshOutput0D.o \
|
||||
$(OBJDIR)/moduleMeshInputText.o $(OBJDIR)/moduleMeshOutputText.o \
|
||||
$(OBJDIR)/moduleMeshInputText.o $(OBJDIR)/moduleMeshOutputText.o \
|
||||
$(OBJDIR)/moduleMesh3DCart.o \
|
||||
$(OBJDIR)/moduleMesh2DCyl.o \
|
||||
$(OBJDIR)/moduleMesh2DCart.o \
|
||||
|
|
@ -17,7 +17,8 @@ OBJECTS = $(OBJDIR)/moduleMesh.o $(OBJDIR)/moduleMeshBoundary.o $(OBJDIR)/module
|
|||
$(OBJDIR)/moduleMesh1DCart.o \
|
||||
$(OBJDIR)/moduleMesh0D.o \
|
||||
$(OBJDIR)/moduleSolver.o \
|
||||
$(OBJDIR)/modulePusher.o
|
||||
$(OBJDIR)/modulePusher.o \
|
||||
$(OBJDIR)/velocityDistribution.o
|
||||
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
OBJS = moduleCompTime.o moduleCaseParam.o moduleConstParam.o \
|
||||
moduleErrors.o moduleMath.o moduleParallel.o \
|
||||
moduleRandom.o moduleRefParam.o moduleTable.o
|
||||
moduleRandom.o moduleRefParam.o moduleTable.o \
|
||||
velocityDistribution.o
|
||||
|
||||
all: $(OBJS)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ MODULE moduleConstParam
|
|||
REAL(8), PARAMETER:: PI8 = 8.D0*PI !8*pi
|
||||
REAL(8), PARAMETER:: sccm2atomPerS = 4.5D17 !sccm to atom s^-1
|
||||
REAL(8), PARAMETER:: qe = 1.60217662D-19 !Elementary charge
|
||||
real(8), parameter:: me = 9.1093837d-31 !electron mass
|
||||
REAL(8), PARAMETER:: kb = 1.38064852D-23 !Boltzmann constants SI
|
||||
REAL(8), PARAMETER:: eV2J = qe !Electron volt to Joule conversion
|
||||
REAL(8), PARAMETER:: eps_0 = 8.8542D-12 !Epsilon_0
|
||||
|
|
|
|||
88
src/modules/common/velocityDistribution.f90
Normal file
88
src/modules/common/velocityDistribution.f90
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
! Functions that return a random velocity based on the distribution function
|
||||
module velocityDistribution
|
||||
use moduleRandom
|
||||
!Generic type for velocity distribution function
|
||||
type, abstract:: velDistGeneric
|
||||
contains
|
||||
!Returns random velocity from distribution function
|
||||
procedure(randomVel_interface), deferred, pass:: randomVel
|
||||
|
||||
end type velDistGeneric
|
||||
|
||||
abstract interface
|
||||
function randomVel_interface(self) result(v)
|
||||
import velDistGeneric
|
||||
|
||||
class(velDistGeneric), intent(in):: self
|
||||
real(8):: v
|
||||
|
||||
end function randomVel_interface
|
||||
|
||||
end interface
|
||||
|
||||
!Container for velocity distributions
|
||||
type:: velDistCont
|
||||
class(velDistGeneric), allocatable:: obj
|
||||
|
||||
end type velDistCont
|
||||
|
||||
!Maxwellian distribution function
|
||||
type, extends(velDistGeneric):: velDistMaxwellian
|
||||
real(8):: vTh !Thermal Velocity
|
||||
contains
|
||||
procedure, pass:: randomVel => randomVelMaxwellian
|
||||
|
||||
end type velDistMaxwellian
|
||||
|
||||
type, extends(velDistGeneric):: velDistHalfMaxwellian
|
||||
real(8):: vTh !Thermal Velocity
|
||||
contains
|
||||
procedure, pass:: randomVel => randomVelHalfMaxwellian
|
||||
|
||||
end type velDistHalfMaxwellian
|
||||
|
||||
!Dirac's delta distribution function
|
||||
type, extends(velDistGeneric):: velDistDelta
|
||||
contains
|
||||
procedure, pass:: randomVel => randomVelDelta
|
||||
|
||||
end type velDistDelta
|
||||
|
||||
contains
|
||||
!Random velocity from Maxwellian distribution
|
||||
function randomVelMaxwellian(self) result (v)
|
||||
use moduleRandom
|
||||
implicit none
|
||||
|
||||
class(velDistMaxwellian), intent(in):: self
|
||||
real(8):: v
|
||||
v = 0.D0
|
||||
|
||||
v = self%vTh*randomMaxwellian()/sqrt(2.d0)
|
||||
|
||||
end function randomVelMaxwellian
|
||||
|
||||
!Random velocity from Half Maxwellian distribution
|
||||
function randomVelHalfMaxwellian(self) result (v)
|
||||
implicit none
|
||||
|
||||
class(velDistHalfMaxwellian), intent(in):: self
|
||||
real(8):: v
|
||||
v = 0.D0
|
||||
|
||||
v = self%vTh*randomHalfMaxwellian()
|
||||
|
||||
end function randomVelHalfMaxwellian
|
||||
|
||||
!Random velocity from Dirac's delta distribution
|
||||
PURE function randomVelDelta(self) result(v)
|
||||
implicit none
|
||||
|
||||
class(velDistDelta), intent(in):: self
|
||||
real(8):: v
|
||||
|
||||
v = 0.D0
|
||||
|
||||
end function randomVelDelta
|
||||
|
||||
end module velocityDistribution
|
||||
|
|
@ -8,7 +8,6 @@ MODULE moduleInput
|
|||
SUBROUTINE readConfig(inputFile)
|
||||
USE json_module
|
||||
USE moduleErrors
|
||||
USE moduleBoundary
|
||||
USE moduleOutput
|
||||
USE moduleMesh
|
||||
IMPLICIT NONE
|
||||
|
|
@ -39,10 +38,20 @@ MODULE moduleInput
|
|||
CALL readSpecies(config)
|
||||
CALL checkStatus(config, "readSpecies")
|
||||
|
||||
!Read boundaries
|
||||
CALL verboseError('Reading boundary conditions...')
|
||||
CALL readBoundary(config)
|
||||
CALL checkStatus(config, "readBoundary")
|
||||
!Read particle boundaries
|
||||
CALL verboseError('Reading particle boundary conditions...')
|
||||
CALL readBoundaryParticle(config)
|
||||
CALL checkStatus(config, "readBoundaryParticle")
|
||||
|
||||
! read EM boundaries
|
||||
CALL verboseError('Reading EM boundary conditions...')
|
||||
CALL readBoundaryEM(config)
|
||||
CALL checkStatus(config, "readBoundaryEM")
|
||||
|
||||
! Read Physical Surfaces
|
||||
call verboseError('Reading Physical Surfaces...')
|
||||
call readPhysicalSurfaces(config)
|
||||
call checkStatus(config, 'readPhysicalSurfaces')
|
||||
|
||||
!Read Geometry
|
||||
CALL verboseError('Reading Geometry...')
|
||||
|
|
@ -255,17 +264,7 @@ MODULE moduleInput
|
|||
IF (found) THEN
|
||||
CALL solver%initEM(EMType)
|
||||
SELECT CASE(EMType)
|
||||
CASE("Electrostatic")
|
||||
!Read BC
|
||||
CALL readEMBoundary(config)
|
||||
|
||||
CASE("ElectrostaticBoltzmann")
|
||||
!Read BC
|
||||
CALL readEMBoundary(config)
|
||||
|
||||
CASE("ConstantB")
|
||||
!Read BC
|
||||
CALL readEMBoundary(config)
|
||||
!Read constant magnetic field
|
||||
DO i = 1, 3
|
||||
WRITE(iString, '(i2)') i
|
||||
|
|
@ -288,9 +287,6 @@ MODULE moduleInput
|
|||
|
||||
END DO
|
||||
|
||||
CASE DEFAULT
|
||||
CALL criticalError('EM Solver ' // EMType // ' not found', 'readSolver')
|
||||
|
||||
END SELECT
|
||||
|
||||
END IF
|
||||
|
|
@ -495,7 +491,8 @@ MODULE moduleInput
|
|||
|
||||
CALL config%get(object // '.cpuTime', timeOutput, found)
|
||||
CALL config%get(object // '.numColl', collOutput, found)
|
||||
CALL config%get(object // '.EMField', emOutput, found)
|
||||
CALL config%get(object // '.EMField', emOutput, found)
|
||||
call config%get(object // '.boundariesParticle', boundaryParticleOutput, found)
|
||||
|
||||
CALL config%get(object // '.triggerCPUTime', triggerCPUTime, found)
|
||||
IF (.NOT. found) THEN
|
||||
|
|
@ -513,6 +510,7 @@ MODULE moduleInput
|
|||
USE moduleRefParam
|
||||
USE moduleList
|
||||
USE json_module
|
||||
use moduleMesh, only: qSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(json_file), INTENT(inout):: config
|
||||
|
|
@ -521,7 +519,7 @@ MODULE moduleInput
|
|||
CHARACTER(:), ALLOCATABLE:: speciesType
|
||||
REAL(8):: mass, charge
|
||||
LOGICAL:: found
|
||||
INTEGER:: i
|
||||
INTEGER:: s
|
||||
CHARACTER(:), ALLOCATABLE:: linkName
|
||||
INTEGER:: linkID
|
||||
|
||||
|
|
@ -533,8 +531,8 @@ MODULE moduleInput
|
|||
ALLOCATE(species(1:nSpecies))
|
||||
|
||||
!Reads information of individual species
|
||||
DO i = 1, nSpecies
|
||||
WRITE(iString, '(I2)') i
|
||||
DO s = 1, nSpecies
|
||||
WRITE(iString, '(I2)') s
|
||||
object = 'species(' // TRIM(iString) // ')'
|
||||
CALL config%get(object // '.type', speciesType, found)
|
||||
CALL config%get(object // '.mass', mass, found)
|
||||
|
|
@ -543,12 +541,12 @@ MODULE moduleInput
|
|||
!Allocate species depending on type and assign specific parameters
|
||||
SELECT CASE(speciesType)
|
||||
CASE ("neutral")
|
||||
ALLOCATE(species(i)%obj, source=speciesNeutral())
|
||||
ALLOCATE(species(s)%obj, source=speciesNeutral())
|
||||
|
||||
CASE ("charged")
|
||||
CALL config%get(object // '.charge', charge, found)
|
||||
IF (.NOT. found) CALL criticalError("Required parameter charge not found for species " // object, 'readSpecies')
|
||||
ALLOCATE(species(i)%obj, source=speciesCharged(q = charge, &
|
||||
ALLOCATE(species(s)%obj, source=speciesCharged(q = charge, &
|
||||
qm = charge/mass))
|
||||
|
||||
CASE DEFAULT
|
||||
|
|
@ -556,18 +554,32 @@ MODULE moduleInput
|
|||
|
||||
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%n = i
|
||||
species(i)%obj%m = mass
|
||||
CALL config%get(object // '.name', species(s)%obj%name, found)
|
||||
CALL config%get(object // '.weight', species(s)%obj%weight, found)
|
||||
species(s)%obj%n = s
|
||||
species(s)%obj%m = mass
|
||||
|
||||
END DO
|
||||
|
||||
! Allocate the vector with the species charges for calculating the EM field
|
||||
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
|
||||
|
||||
!Read relations between species
|
||||
DO i = 1, nSpecies
|
||||
WRITE(iString, '(I2)') i
|
||||
DO s = 1, nSpecies
|
||||
WRITE(iString, '(I2)') s
|
||||
object = 'species(' // TRIM(iString) // ')'
|
||||
SELECT TYPE(sp => species(i)%obj)
|
||||
SELECT TYPE(sp => species(s)%obj)
|
||||
TYPE IS (speciesNeutral)
|
||||
!Get species linked ion
|
||||
CALL config%get(object // '.ion', linkName, found)
|
||||
|
|
@ -792,48 +804,48 @@ MODULE moduleInput
|
|||
END SUBROUTINE readInteractions
|
||||
|
||||
!Reads boundary conditions for the mesh
|
||||
SUBROUTINE readBoundary(config)
|
||||
USE moduleBoundary
|
||||
SUBROUTINE readBoundaryParticle(config)
|
||||
use moduleMesh
|
||||
USE moduleErrors
|
||||
USE moduleSpecies
|
||||
USE moduleRefParam
|
||||
USE moduleList, ONLY: partSurfaces
|
||||
use moduleRefParam, only: m_ref
|
||||
use moduleConstParam, only: me
|
||||
USE json_module
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(json_file), INTENT(inout):: config
|
||||
INTEGER:: i, s
|
||||
CHARACTER(2):: iString, sString
|
||||
CHARACTER(:), ALLOCATABLE:: object, bType
|
||||
REAL(8):: Tw, cw !Wall temperature and specific heat
|
||||
!Neutral Properties
|
||||
REAL(8):: m0, n0, T0
|
||||
REAL(8), DIMENSION(:), ALLOCATABLE:: v0
|
||||
REAL(8):: effTime
|
||||
REAL(8):: eThreshold !Energy threshold
|
||||
INTEGER:: speciesID, electronSecondaryID
|
||||
CHARACTER(:), ALLOCATABLE:: speciesName, crossSection, electronSecondary
|
||||
integer:: b
|
||||
character(2):: bString
|
||||
character(:), allocatable:: object
|
||||
LOGICAL:: found
|
||||
INTEGER:: nTypes
|
||||
character(:), allocatable:: bType
|
||||
real(8):: Tw, cw !Wall temperature and specific heat
|
||||
!neutral Properties
|
||||
real(8):: m0, n0, T0
|
||||
real(8), dimension(:), allocatable:: v0
|
||||
real(8):: effTime
|
||||
real(8):: eThreshold !Energy threshold
|
||||
integer:: speciesID, electronSecondaryID
|
||||
character(:), allocatable:: speciesName, crossSection, electronSecondary
|
||||
integer:: s_incident
|
||||
|
||||
CALL config%info('boundary', found, n_children = nBoundary)
|
||||
ALLOCATE(boundary(1:nBoundary))
|
||||
DO i = 1, nBoundary
|
||||
WRITE(iString, '(i2)') i
|
||||
object = 'boundary(' // TRIM(iString) // ')'
|
||||
! Read models of particles
|
||||
object = 'boundaries.particles'
|
||||
CALL config%info(object, found, n_children = nBoundariesParticle)
|
||||
allocate(boundariesParticle(1:nBoundariesParticle))
|
||||
DO b = 1, nBoundariesParticle
|
||||
WRITE(bString, '(i2)') b
|
||||
object = 'boundaries.particles(' // trim(bString) // ')'
|
||||
|
||||
boundary(i)%n = i
|
||||
CALL config%get(object // '.name', boundary(i)%name, found)
|
||||
CALL config%get(object // '.physicalSurface', boundary(i)%physicalSurface, found)
|
||||
CALL config%info(object // '.bTypes', found, n_children = nTypes)
|
||||
IF (nTypes /= nSpecies) CALL criticalError('Not enough boundary types defined in ' // object, 'readBoundary')
|
||||
ALLOCATE(boundary(i)%bTypes(1:nSpecies))
|
||||
DO s = 1, nSpecies
|
||||
associate(bound => boundary(i)%bTypes(s)%obj)
|
||||
WRITE(sString,'(i2)') s
|
||||
object = 'boundary(' // TRIM(iString) // ').bTypes(' // TRIM(sString) // ')'
|
||||
CALL config%get(object // '.type', bType, found)
|
||||
SELECT CASE(bType)
|
||||
CALL config%get(object // '.type', bType, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "type" for particle boundary condition not found', &
|
||||
'initBoundaryParticle')
|
||||
|
||||
end if
|
||||
|
||||
associate(bound => boundariesParticle(b)%obj)
|
||||
SELECT CASE(bType)
|
||||
CASE('reflection')
|
||||
ALLOCATE(boundaryReflection:: bound)
|
||||
|
||||
|
|
@ -860,55 +872,186 @@ MODULE moduleInput
|
|||
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) THEN
|
||||
m0 = species(s)%obj%m*m_ref
|
||||
END IF
|
||||
IF (.NOT. found) CALL criticalError("missing parameter 'mass' for neutrals in ionization", 'readBoundary')
|
||||
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 // '.electronSecondary', electronSecondary, found)
|
||||
IF (found) THEN
|
||||
electronSecondaryID = speciesName2Index(electronSecondary)
|
||||
CALL initIonization(bound, me/m_ref, m0, n0, v0, T0, &
|
||||
speciesID, effTime, crossSection, eThreshold, electronSecondaryID)
|
||||
ELSE
|
||||
CALL initIonization(bound, me/m_ref, m0, n0, v0, T0, &
|
||||
speciesID, effTime, crossSection, eThreshold)
|
||||
|
||||
CALL config%get(object // '.effectiveTime', effTime, found)
|
||||
IF (.NOT. found) CALL criticalError("missing parameter 'effectiveTime' for ionization", 'readBoundary')
|
||||
|
||||
END IF
|
||||
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')
|
||||
case('quasiNeutrality')
|
||||
call config%get(object // '.incident', speciesName, found)
|
||||
if (.not. found) call criticalError("Incident species name not found for quasiNeutrality boundary model", 'readBoundary')
|
||||
|
||||
CALL config%get(object // '.electronSecondary', electronSecondary, found)
|
||||
electronSecondaryID = speciesName2Index(electronSecondary)
|
||||
IF (found) THEN
|
||||
CALL initIonization(bound, species(s)%obj%m, m0, n0, v0, T0, &
|
||||
speciesID, effTime, crossSection, eThreshold,electronSecondaryID)
|
||||
s_incident = speciesName2Index(speciesName)
|
||||
|
||||
ELSE
|
||||
CALL initIonization(bound, species(s)%obj%m, m0, n0, v0, T0, &
|
||||
speciesID, effTime, crossSection, eThreshold)
|
||||
|
||||
END IF
|
||||
|
||||
case('outflowAdaptive')
|
||||
allocate(boundaryOutflowAdaptive:: bound)
|
||||
call initQuasiNeutrality(bound, s_incident)
|
||||
|
||||
CASE DEFAULT
|
||||
CALL criticalError('Boundary type ' // bType // ' undefined', 'readBoundary')
|
||||
|
||||
END SELECT
|
||||
END SELECT
|
||||
|
||||
end associate
|
||||
bound%n = b
|
||||
|
||||
END DO
|
||||
CALL config%get(object // '.name', bound%name, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "name" for particle boundary condition not found', &
|
||||
'initBoundaryParticle')
|
||||
|
||||
end if
|
||||
|
||||
end associate
|
||||
|
||||
END DO
|
||||
|
||||
!Init the list of particles from surfaces
|
||||
CALL OMP_INIT_LOCK(partSurfaces%lock)
|
||||
|
||||
END SUBROUTINE readBoundary
|
||||
END SUBROUTINE readBoundaryParticle
|
||||
|
||||
SUBROUTINE readBoundaryEM(config)
|
||||
USE moduleMesh
|
||||
USE moduleOutput
|
||||
USE moduleErrors
|
||||
USE moduleEM
|
||||
USE json_module
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(json_file), INTENT(inout):: config
|
||||
CHARACTER(:), ALLOCATABLE:: object
|
||||
LOGICAL:: found
|
||||
INTEGER:: b
|
||||
CHARACTER(2):: bString
|
||||
character(:), allocatable:: bType
|
||||
|
||||
CALL config%info('boundaries.EM', found, n_children = nBoundariesEM)
|
||||
|
||||
IF (found) THEN
|
||||
ALLOCATE(boundariesEM(1:nBoundariesEM))
|
||||
|
||||
END IF
|
||||
|
||||
do b = 1, nBoundariesEM
|
||||
write(bString, '(I2)') b
|
||||
object = 'boundaries.EM(' // TRIM(bString) // ')'
|
||||
|
||||
associate(self => boundariesEM(b)%obj)
|
||||
call config%get(object // '.type', bType, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "type" for EM boundary condition not found', &
|
||||
'initBoundaryEM')
|
||||
|
||||
end if
|
||||
|
||||
select case(bType)
|
||||
case ("dirichlet")
|
||||
! Allocate boundary edge
|
||||
allocate(boundaryEMDirichlet:: self)
|
||||
|
||||
CALL initDirichlet(self, config, object)
|
||||
|
||||
case ("dirichlettime")
|
||||
! Allocate boundary edge
|
||||
allocate(boundaryEMDirichletTime:: self)
|
||||
|
||||
call initDirichletTime(self, config, object)
|
||||
|
||||
case default
|
||||
call criticalError('Boundary type ' // bType // ' not supported', 'readBoundaryEM')
|
||||
|
||||
end select
|
||||
|
||||
self%n = b
|
||||
allocate(self%nodes(0))
|
||||
|
||||
call config%get(object // '.name', self%name, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "name" for EM boundary condition not found', &
|
||||
'initBoundaryEM')
|
||||
|
||||
end if
|
||||
|
||||
end associate
|
||||
|
||||
end do
|
||||
|
||||
END SUBROUTINE readBoundaryEM
|
||||
|
||||
subroutine readPhysicalSurfaces(config)
|
||||
use json_module
|
||||
use moduleMesh
|
||||
use moduleErrors
|
||||
implicit none
|
||||
|
||||
type(json_file), intent(inout):: config
|
||||
character(:), allocatable:: object
|
||||
logical:: found
|
||||
integer:: ps
|
||||
character(2):: psString, sSTring
|
||||
integer:: nParticleModels
|
||||
character(:), allocatable:: particleModel
|
||||
character(:), allocatable:: EMModel
|
||||
integer:: s, boundaryIndex
|
||||
|
||||
call config%info('physicalSurfaces', found, n_children = nPhysicalSurfaces)
|
||||
if (found) then
|
||||
allocate(physicalSurfaces(1:nPhysicalSurfaces))
|
||||
|
||||
end if
|
||||
|
||||
do ps = 1, nPhysicalSurfaces
|
||||
write(psString, '(I2)') ps
|
||||
object = 'physicalSurfaces(' // trim(psString) // ')'
|
||||
|
||||
allocate(physicalSurfaces(ps)%nodes(0))
|
||||
allocate(physicalSurfaces(ps)%edges(0))
|
||||
call config%get(object // '.index', physicalSurfaces(ps)%index, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Physical surface index not found', 'readPhysicalSurfaces')
|
||||
|
||||
end if
|
||||
|
||||
! Link models for particles
|
||||
call config%info(object // '.particles', found, n_children = nParticleModels)
|
||||
if ((.not. found) .or. &
|
||||
(nParticleModels /= nSpecies)) then
|
||||
call criticalError('Not enough models for particles provided', 'readPhysicalSurfaces')
|
||||
|
||||
end if
|
||||
allocate(physicalSurfaces(ps)%particles(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
write(sString, '(I2)') s
|
||||
call config%get(object // '.particles(' // trim(sSTring) // ')', particleModel, found)
|
||||
boundaryIndex = boundaryParticleName_to_Index(particleModel)
|
||||
physicalSurfaces(ps)%particles(s)%obj => boundariesParticle(boundaryIndex)%obj
|
||||
|
||||
end do
|
||||
|
||||
! Link electromagnetic boundary condition
|
||||
call config%get(object // '.EM', EMModel, found)
|
||||
if (found) then
|
||||
boundaryIndex = boundaryEMName_to_Index(EMModel)
|
||||
physicalSurfaces(ps)%EM => boundariesEM(boundaryIndex)%obj
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end subroutine readPhysicalSurfaces
|
||||
|
||||
!Read the geometry (mesh) for the case
|
||||
SUBROUTINE readGeometry(config)
|
||||
|
|
@ -934,6 +1077,9 @@ MODULE moduleInput
|
|||
LOGICAL:: found
|
||||
CHARACTER(:), ALLOCATABLE:: meshFormat, meshFile
|
||||
REAL(8):: volume
|
||||
integer:: b, ps, s
|
||||
integer:: e
|
||||
integer:: nVolColl
|
||||
|
||||
object = 'geometry'
|
||||
|
||||
|
|
@ -1102,18 +1248,101 @@ MODULE moduleInput
|
|||
|
||||
END SELECT
|
||||
|
||||
!Builds the K matrix for the Particles mesh
|
||||
CALL mesh%constructGlobalK()
|
||||
|
||||
!Assign the procedure to find a volume for meshColl
|
||||
!Assign the procedure to find a cell for meshColl
|
||||
IF (doubleMesh) THEN
|
||||
findCellColl => findCellCollMesh
|
||||
! Link edges with cells in meshColl
|
||||
DO e=1, mesh%numEdges
|
||||
nVolColl = findCellBrute(meshColl, mesh%edges(e)%obj%center())
|
||||
IF (nVolColl > 0) THEN
|
||||
mesh%edges(e)%obj%eColl => meshColl%cells(nVolColl)%obj
|
||||
|
||||
ELSE
|
||||
CALL criticalError("No connection between edge and meshColl", "readGeometry")
|
||||
|
||||
END IF
|
||||
|
||||
end do
|
||||
|
||||
ELSE
|
||||
findCellColl => findCellSameMesh
|
||||
! Link edges with cells in meshColl
|
||||
DO e=1, mesh%numEdges
|
||||
IF (ASSOCIATED(mesh%edges(e)%obj%e1)) THEN
|
||||
mesh%edges(e)%obj%eColl => mesh%edges(e)%obj%e1
|
||||
|
||||
ELSE
|
||||
mesh%edges(e)%obj%eColl => mesh%edges(e)%obj%e2
|
||||
|
||||
END IF
|
||||
|
||||
end do
|
||||
|
||||
END IF
|
||||
|
||||
! If needed, add nodes and edges to boundary models
|
||||
! Particle boundaries
|
||||
do b = 1, nBoundariesParticle
|
||||
select type(bound => boundariesParticle(b)%obj)
|
||||
type is(boundaryQuasiNeutrality)
|
||||
! Loop over all physical surfaces
|
||||
do ps = 1, nPhysicalSurfaces
|
||||
! Loop over all species
|
||||
do s = 1, nSpecies
|
||||
! If the boundary for the species is linked to the one analysing, add the edges
|
||||
if (associated(physicalSurfaces(ps)%particles(s)%obj, bound)) then
|
||||
bound%edges = [bound%edges, physicalSurfaces(ps)%edges]
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end do
|
||||
|
||||
allocate(bound%alpha(1:mesh%numEdges)) ! TODO: Change this so only the edges associated to the boundary are here
|
||||
bound%alpha = 0.d0
|
||||
|
||||
end select
|
||||
|
||||
end do
|
||||
|
||||
! EM Boundaries
|
||||
do b = 1, nBoundariesEM
|
||||
associate(bound => boundariesEM(b)%obj)
|
||||
select type(bound)
|
||||
type is(boundaryEMDirichlet)
|
||||
! Loop over all physical surfaces
|
||||
do ps = 1, nPhysicalSurfaces
|
||||
! If the boundary for the species is linked to the one analysing, add the edges
|
||||
if (associated(physicalSurfaces(ps)%EM, bound)) then
|
||||
bound%nodes = [bound%nodes, physicalSurfaces(ps)%nodes]
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
type is(boundaryEMDirichletTime)
|
||||
! Loop over all physical surfaces
|
||||
do ps = 1, nPhysicalSurfaces
|
||||
! If the boundary for the species is linked to the one analysing, add the edges
|
||||
if (associated(physicalSurfaces(ps)%EM, bound)) then
|
||||
bound%nodes = [bound%nodes, physicalSurfaces(ps)%nodes]
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end select
|
||||
|
||||
bound%nNodes = size(bound%nodes)
|
||||
|
||||
end associate
|
||||
|
||||
end do
|
||||
|
||||
if (mesh%dimen > 0) then
|
||||
! Builds the K matrix for the Particles mesh
|
||||
call mesh%constructGlobalK()
|
||||
|
||||
end if
|
||||
|
||||
END SUBROUTINE readGeometry
|
||||
|
||||
SUBROUTINE readProbes(config)
|
||||
|
|
@ -1157,134 +1386,6 @@ MODULE moduleInput
|
|||
|
||||
END SUBROUTINE readProbes
|
||||
|
||||
SUBROUTINE readEMBoundary(config)
|
||||
USE moduleMesh
|
||||
USE moduleOutput
|
||||
USE moduleErrors
|
||||
USE moduleEM
|
||||
USE moduleSpecies
|
||||
USE json_module
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(json_file), INTENT(inout):: config
|
||||
CHARACTER(:), ALLOCATABLE:: object
|
||||
LOGICAL:: found
|
||||
CHARACTER(:), ALLOCATABLE:: typeEM
|
||||
REAL(8):: potential
|
||||
INTEGER:: physicalSurface
|
||||
CHARACTER(:), ALLOCATABLE:: temporalProfile, temporalProfilePath
|
||||
INTEGER:: b, s, n, ni
|
||||
CHARACTER(2):: bString
|
||||
INTEGER:: info
|
||||
EXTERNAL:: dgetrf
|
||||
|
||||
CALL config%info('boundaryEM', found, n_children = nBoundaryEM)
|
||||
|
||||
IF (found) THEN
|
||||
ALLOCATE(boundaryEM(1:nBoundaryEM))
|
||||
|
||||
END IF
|
||||
|
||||
DO b = 1, nBoundaryEM
|
||||
WRITE(bString, '(I2)') b
|
||||
object = 'boundaryEM(' // TRIM(bString) // ')'
|
||||
|
||||
CALL config%get(object // '.type', typeEM, found)
|
||||
|
||||
SELECT CASE(typeEM)
|
||||
CASE ("dirichlet")
|
||||
CALL config%get(object // '.potential', potential, found)
|
||||
IF (.NOT. found) THEN
|
||||
CALL criticalError('Required parameter "potential" for Dirichlet boundary condition not found', 'readEMBoundary')
|
||||
|
||||
END IF
|
||||
|
||||
CALL config%get(object // '.physicalSurface', physicalSurface, found)
|
||||
IF (.NOT. found) THEN
|
||||
CALL criticalError('Required parameter "physicalSurface" for Dirichlet boundary condition not found', &
|
||||
'readEMBoundary')
|
||||
|
||||
END IF
|
||||
|
||||
CALL initDirichlet(boundaryEM(b)%obj, physicalSurface, potential)
|
||||
|
||||
CASE ("dirichletTime")
|
||||
CALL config%get(object // '.potential', potential, found)
|
||||
IF (.NOT. found) THEN
|
||||
CALL criticalError('Required parameter "potential" for Dirichlet Time boundary condition not found', &
|
||||
'readEMBoundary')
|
||||
|
||||
END IF
|
||||
|
||||
CALL config%get(object // '.temporalProfile', temporalProfile, found)
|
||||
IF (.NOT. found) THEN
|
||||
CALL criticalError('Required parameter "temporalProfile" for Dirichlet Time boundary condition not found', &
|
||||
'readEMBoundary')
|
||||
|
||||
END IF
|
||||
temporalProfilePath = path // temporalProfile
|
||||
|
||||
CALL config%get(object // '.physicalSurface', physicalSurface, found)
|
||||
IF (.NOT. found) THEN
|
||||
CALL criticalError('Required parameter "physicalSurface" for Dirichlet Time boundary condition not found', &
|
||||
'readEMBoundary')
|
||||
|
||||
END IF
|
||||
|
||||
CALL initDirichletTime(boundaryEM(b)%obj, physicalSurface, potential, temporalProfilePath)
|
||||
|
||||
CASE DEFAULT
|
||||
CALL criticalError('Boundary type ' // 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
|
||||
|
||||
! Modify K matrix due to boundary conditions
|
||||
DO b = 1, nBoundaryEM
|
||||
SELECT TYPE(boundary => boundaryEM(b)%obj)
|
||||
TYPE IS(boundaryEMDirichlet)
|
||||
DO n = 1, boundary%nNodes
|
||||
ni = boundary%nodes(n)%obj%n
|
||||
mesh%K(ni, :) = 0.D0
|
||||
mesh%K(ni, ni) = 1.D0
|
||||
|
||||
END DO
|
||||
|
||||
TYPE IS(boundaryEMDirichletTime)
|
||||
DO n = 1, boundary%nNodes
|
||||
ni = boundary%nodes(n)%obj%n
|
||||
mesh%K(ni, :) = 0.D0
|
||||
mesh%K(ni, ni) = 1.D0
|
||||
|
||||
END DO
|
||||
|
||||
END SELECT
|
||||
|
||||
END DO
|
||||
|
||||
!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) THEN
|
||||
CALL criticalError('Factorization of K matrix failed', 'readEMBoundary')
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE readEMBoundary
|
||||
|
||||
!Reads the injection of particles from the boundaries
|
||||
SUBROUTINE readInject(config)
|
||||
USE moduleSpecies
|
||||
|
|
@ -1460,35 +1561,29 @@ MODULE moduleInput
|
|||
END SUBROUTINE readParallel
|
||||
|
||||
SUBROUTINE initOutput(inputFile)
|
||||
USE moduleRefParam
|
||||
USE moduleMesh, ONLY: mesh, doubleMesh, pathMeshParticle, pathMeshColl
|
||||
USE moduleOutput, ONLY: path, folder
|
||||
USE moduleOutput, ONLY: createOutputFolder, writeReference, copyFileToOutput, writeCommit
|
||||
IMPLICIT NONE
|
||||
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: inputFile
|
||||
INTEGER:: fileReference = 30
|
||||
!If everything is correct, creates the output folder
|
||||
CALL EXECUTE_COMMAND_LINE('mkdir ' // path // folder )
|
||||
call createOutputFolder()
|
||||
!Copies input file to output folder
|
||||
CALL EXECUTE_COMMAND_LINE('cp ' // inputFile // ' ' // path // folder)
|
||||
call copyFileToOutput(inputFile)
|
||||
!Copies particle mesh
|
||||
IF (mesh%dimen > 0) THEN
|
||||
CALL EXECUTE_COMMAND_LINE('cp ' // pathMeshParticle // ' ' // path // folder)
|
||||
call copyFileToOutput(pathMeshParticle)
|
||||
IF (doubleMesh) THEN
|
||||
CALL EXECUTE_COMMAND_LINE('cp ' // pathMeshColl // ' ' // path // folder)
|
||||
call copyFileToOutput(pathMeshColl)
|
||||
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
! Write commit of fpakc
|
||||
CALL SYSTEM('git rev-parse HEAD > ' // path // folder // '/' // 'fpakc_commit.txt')
|
||||
call writeCommit()
|
||||
|
||||
! Write file with reference values
|
||||
OPEN (fileReference, file=path // folder // '/' // 'reference.txt')
|
||||
WRITE(fileReference, "(7(1X,A20))") 'L_ref', 'v_ref', 'ti_ref', 'Vol_ref', 'EF_ref', 'Volt_ref', 'B_ref'
|
||||
WRITE(fileReference, "(7(1X,ES20.6E3))") L_ref, v_ref, ti_ref, Vol_ref, EF_ref, Volt_ref, B_ref
|
||||
CLOSE(fileReference)
|
||||
call writeReference()
|
||||
|
||||
END SUBROUTINE initOutput
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
OBJS = common.o output.o mesh.o solver.o init.o \
|
||||
moduleBoundary.o moduleCollisions.o moduleInject.o \
|
||||
moduleCollisions.o moduleInject.o \
|
||||
moduleList.o moduleProbe.o moduleCoulomb.o \
|
||||
moduleSpecies.o
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ common.o:
|
|||
output.o: moduleSpecies.o common.o
|
||||
$(MAKE) -C output all
|
||||
|
||||
mesh.o: moduleCollisions.o moduleCoulomb.o moduleBoundary.o output.o common.o
|
||||
mesh.o: moduleList.o moduleSpecies.o moduleCollisions.o moduleCoulomb.o output.o common.o
|
||||
$(MAKE) -C mesh all
|
||||
|
||||
solver.o: moduleSpecies.o moduleProbe.o common.o output.o mesh.o
|
||||
|
|
@ -20,9 +20,6 @@ solver.o: moduleSpecies.o moduleProbe.o common.o output.o mesh.o
|
|||
init.o: common.o solver.o moduleInject.o
|
||||
$(MAKE) -C init all
|
||||
|
||||
moduleBoundary.o: common.o moduleBoundary.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
|
||||
moduleCollisions.o: moduleList.o moduleSpecies.o common.o moduleCollisions.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
|
||||
|
|
@ -38,6 +35,9 @@ moduleProbe.o: mesh.o moduleProbe.f90
|
|||
moduleSpecies.o: common.o moduleSpecies.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
|
||||
moduleInject.o: common.o moduleInject.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
|
||||
%.o: %.f90
|
||||
$(FC) $(FCFLAGS) -c $< -o $(OBJDIR)/$@
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ MODULE moduleMesh0D
|
|||
|
||||
CLASS(meshNode0D), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
REAL(8), INTENT(in):: r(1:3) !Unused variable
|
||||
REAL(8), INTENT(in):: r(1:3) ! NOTE: Required by interface but unused
|
||||
|
||||
self%n = n
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ MODULE moduleMesh0D
|
|||
PURE FUNCTION fPsi0D(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
REAL(8), INTENT(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ MODULE moduleMesh0D
|
|||
PURE FUNCTION dPsi0D(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
REAL(8), INTENT(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ MODULE moduleMesh0D
|
|||
CLASS(meshCell0D), INTENT(in):: self
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8), INTENT(in):: dPsi(1:3,1:nNodes)
|
||||
REAL(8):: pDer(1:3, 1:3)
|
||||
REAL(8):: pDer(1:3, 1:3) ! NOTE: Required by interface but unused
|
||||
|
||||
pDer = 0.D0
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ MODULE moduleMesh0D
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell0D), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: r(1:3)
|
||||
REAL(8), INTENT(in):: r(1:3) ! NOTE: Required by interface but unused
|
||||
REAL(8):: xN(1:3)
|
||||
|
||||
xN = 0.D0
|
||||
|
|
@ -215,7 +215,7 @@ MODULE moduleMesh0D
|
|||
PURE FUNCTION inside0D(Xi) RESULT(ins)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
REAL(8), INTENT(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
LOGICAL:: ins
|
||||
|
||||
ins = .TRUE.
|
||||
|
|
@ -226,7 +226,7 @@ MODULE moduleMesh0D
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell0D), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
REAL(8), INTENT(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
CLASS(meshElement), POINTER, INTENT(out):: neighbourElement
|
||||
|
||||
neighbourElement => NULL()
|
||||
|
|
@ -237,7 +237,7 @@ MODULE moduleMesh0D
|
|||
PURE FUNCTION detJ0D(pDer) RESULT(dJ)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: pDer(1:3, 1:3)
|
||||
REAL(8), INTENT(in):: pDer(1:3, 1:3) ! NOTE: Required by interface but unused
|
||||
REAL(8):: dJ
|
||||
|
||||
dJ = 0.D0
|
||||
|
|
@ -247,7 +247,7 @@ MODULE moduleMesh0D
|
|||
PURE FUNCTION invJ0D(pDer) RESULT(invJ)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: pDer(1:3, 1:3)
|
||||
REAL(8), INTENT(in):: pDer(1:3, 1:3) ! NOTE: Required by interface but unused
|
||||
REAL(8):: invJ(1:3,1:3)
|
||||
|
||||
invJ = 0.D0
|
||||
|
|
|
|||
|
|
@ -4,12 +4,9 @@
|
|||
! z == unused
|
||||
MODULE moduleMesh1DCart
|
||||
USE moduleMesh
|
||||
USE moduleMeshBoundary
|
||||
use moduleMeshCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), PARAMETER:: corSeg(1:3) = (/ -DSQRT(3.D0/5.D0), 0.D0, DSQRT(3.D0/5.D0) /)
|
||||
REAL(8), PARAMETER:: wSeg(1:3) = (/ 5.D0/9.D0 , 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode1DCart
|
||||
!Element coordinates
|
||||
REAL(8):: x = 0.D0
|
||||
|
|
@ -27,10 +24,13 @@ MODULE moduleMesh1DCart
|
|||
CLASS(meshNode), POINTER:: n1 => NULL()
|
||||
CONTAINS
|
||||
!meshEdge DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: init => initEdge1DCart
|
||||
PROCEDURE, PASS:: getNodes => getNodes1DCart
|
||||
PROCEDURE, PASS:: intersection => intersection1DCart
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
PROCEDURE, PASS:: init => initEdge1DCart
|
||||
PROCEDURE, PASS:: getNodes => getNodes1DCart
|
||||
PROCEDURE, PASS:: intersection => intersection1DCart
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
procedure, pass:: center => centerEdgePoint
|
||||
procedure, nopass:: centerXi => centerXiPoint
|
||||
procedure, nopass:: fPsi => fPsiPoint
|
||||
|
||||
END TYPE meshEdge1DCart
|
||||
|
||||
|
|
@ -100,17 +100,16 @@ MODULE moduleMesh1DCart
|
|||
|
||||
!EDGE FUNCTIONS
|
||||
!Init edge element
|
||||
SUBROUTINE initEdge1DCart(self, n, p, bt, physicalSurface)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
SUBROUTINE initEdge1DCart(self, n, p, ps)
|
||||
USE moduleSpecies, only: nSpecies
|
||||
USE moduleErrors
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge1DCart), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
INTEGER, INTENT(in):: p(:)
|
||||
INTEGER, INTENT(in):: bt
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
INTEGER, INTENT(in):: ps
|
||||
integer:: ps_index
|
||||
REAL(8), DIMENSION(1:3):: r1
|
||||
INTEGER:: s
|
||||
|
||||
|
|
@ -126,19 +125,21 @@ MODULE moduleMesh1DCart
|
|||
|
||||
self%normal = (/ 1.D0, 0.D0, 0.D0 /)
|
||||
|
||||
!Boundary index
|
||||
self%boundary => boundary(bt)
|
||||
ALLOCATE(self%fboundary(1:nSpecies))
|
||||
!Assign functions to boundary
|
||||
DO s = 1, nSpecies
|
||||
CALL pointBoundaryFunction(self, s)
|
||||
! Get Physical Surface index based on input numering
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
END DO
|
||||
! Add elements to physical surface
|
||||
call meshEdgePointer_add(physicalSurfaces(ps_index)%edges, self%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n1%n)
|
||||
|
||||
!Physical Surface
|
||||
self%physicalSurface = physicalSurface
|
||||
! Link edge to particle boundaries
|
||||
allocate(self%boundariesParticle(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
self%boundariesParticle(s)%obj => physicalSurfaces(ps_index)%particles(s)%obj
|
||||
|
||||
END SUBROUTINE initEdge1DCart
|
||||
end do
|
||||
|
||||
end subroutine initEdge1DCart
|
||||
|
||||
!Get nodes from edge
|
||||
PURE FUNCTION getNodes1DCart(self, nNodes) RESULT(n)
|
||||
|
|
@ -156,7 +157,7 @@ MODULE moduleMesh1DCart
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge1DCart), INTENT(in):: self
|
||||
REAL(8), DIMENSION(1:3), INTENT(in):: r0
|
||||
REAL(8), DIMENSION(1:3), INTENT(in):: r0 ! NOTE: Required by interface but unused
|
||||
REAL(8), DIMENSION(1:3):: r
|
||||
|
||||
r = (/ self%x, 0.D0, 0.D0 /)
|
||||
|
|
@ -165,6 +166,8 @@ MODULE moduleMesh1DCart
|
|||
|
||||
!Calculate a 'random' position in edge
|
||||
FUNCTION randPosEdge(self) RESULT(r)
|
||||
implicit none
|
||||
|
||||
CLASS(meshEdge1DCart), INTENT(in):: self
|
||||
REAL(8):: r(1:3)
|
||||
|
||||
|
|
@ -172,7 +175,17 @@ MODULE moduleMesh1DCart
|
|||
|
||||
END FUNCTION randPosEdge
|
||||
|
||||
!VOLUME FUNCTIONS
|
||||
function centerEdgePoint(self) RESULT(r)
|
||||
implicit none
|
||||
|
||||
class(meshEdge1DCart), intent(in):: self
|
||||
real(8):: r(1:3)
|
||||
|
||||
r = (/ self%x, 0.D0, 0.D0 /)
|
||||
|
||||
end function centerEdgePoint
|
||||
|
||||
!CELL FUNCTIONS
|
||||
!SEGMENT FUNCTIONS
|
||||
!Init element
|
||||
SUBROUTINE initCell1DCartSegm(self, n, p, nodes)
|
||||
|
|
@ -236,35 +249,6 @@ MODULE moduleMesh1DCart
|
|||
|
||||
END FUNCTION randPos1DCartSegm
|
||||
|
||||
!Compute element functions at point Xi
|
||||
PURE FUNCTION fPsiSegm(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = (/ 1.D0 - Xi(1), &
|
||||
1.D0 + Xi(1) /)
|
||||
|
||||
fPsi = fPsi * 0.50D0
|
||||
|
||||
END FUNCTION fPsiSegm
|
||||
|
||||
!Derivative element function at coordinates Xi
|
||||
PURE FUNCTION dPsiSegm(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:2) = (/ -5.D-1, 5.D-1 /)
|
||||
|
||||
END FUNCTION dPsiSegm
|
||||
|
||||
!Partial derivative in global coordinates
|
||||
PURE FUNCTION partialDerSegm(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
@ -446,7 +430,7 @@ MODULE moduleMesh1DCart
|
|||
|
||||
END SUBROUTINE volumeSegm
|
||||
|
||||
!COMMON FUNCTIONS FOR 1D VOLUME ELEMENTS
|
||||
!COMMON FUNCTIONS FOR 1D CELL ELEMENTS
|
||||
!Compute element Jacobian determinant
|
||||
PURE FUNCTION detJ1DCart(pDer) RESULT(dJ)
|
||||
IMPLICIT NONE
|
||||
|
|
|
|||
|
|
@ -4,12 +4,9 @@
|
|||
! z == unused
|
||||
MODULE moduleMesh1DRad
|
||||
USE moduleMesh
|
||||
USE moduleMeshBoundary
|
||||
use moduleMeshCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), PARAMETER:: corSeg(1:3) = (/ -DSQRT(3.D0/5.D0), 0.D0, DSQRT(3.D0/5.D0) /)
|
||||
REAL(8), PARAMETER:: wSeg(1:3) = (/ 5.D0/9.D0 , 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode1DRad
|
||||
!Element coordinates
|
||||
REAL(8):: r = 0.D0
|
||||
|
|
@ -27,10 +24,13 @@ MODULE moduleMesh1DRad
|
|||
CLASS(meshNode), POINTER:: n1 => NULL()
|
||||
CONTAINS
|
||||
!meshEdge DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: init => initEdge1DRad
|
||||
PROCEDURE, PASS:: getNodes => getNodes1DRad
|
||||
PROCEDURE, PASS:: intersection => intersection1DRad
|
||||
PROCEDURE, PASS:: randPos => randPos1DRad
|
||||
PROCEDURE, PASS:: init => initEdge1DRad
|
||||
PROCEDURE, PASS:: getNodes => getNodes1DRad
|
||||
PROCEDURE, PASS:: intersection => intersection1DRad
|
||||
PROCEDURE, PASS:: randPos => randPos1DRad
|
||||
procedure, pass:: center => centerEdgePoint
|
||||
procedure, nopass:: centerXi => centerXiPoint
|
||||
procedure, nopass:: fPsi => fPsiPoint
|
||||
|
||||
END TYPE meshEdge1DRad
|
||||
|
||||
|
|
@ -100,18 +100,16 @@ MODULE moduleMesh1DRad
|
|||
|
||||
!EDGE FUNCTIONS
|
||||
!Init edge element
|
||||
SUBROUTINE initEdge1DRad(self, n, p, bt, physicalSurface)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
SUBROUTINE initEdge1DRad(self, n, p, ps)
|
||||
USE moduleSpecies, only:nSpecies
|
||||
USE moduleErrors
|
||||
USE moduleRefParam, ONLY: L_ref
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge1DRad), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
INTEGER, INTENT(in):: p(:)
|
||||
INTEGER, INTENT(in):: bt
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
INTEGER, INTENT(in):: ps
|
||||
integer:: ps_index
|
||||
REAL(8), DIMENSION(1:3):: r1
|
||||
INTEGER:: s
|
||||
|
||||
|
|
@ -127,19 +125,21 @@ MODULE moduleMesh1DRad
|
|||
|
||||
self%normal = (/ 1.D0, 0.D0, 0.D0 /)
|
||||
|
||||
!Boundary index
|
||||
self%boundary => boundary(bt)
|
||||
ALLOCATE(self%fboundary(1:nSpecies))
|
||||
!Assign functions to boundary
|
||||
DO s = 1, nSpecies
|
||||
CALL pointBoundaryFunction(self, s)
|
||||
! Get Physical Surface index based on input numering
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
END DO
|
||||
! Add elements to physical surface
|
||||
call meshEdgePointer_add(physicalSurfaces(ps_index)%edges, self%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n1%n)
|
||||
|
||||
!Physical Surface
|
||||
self%physicalSurface = physicalSurface
|
||||
! Link edge to particle boundaries
|
||||
allocate(self%boundariesParticle(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
self%boundariesParticle(s)%obj => physicalSurfaces(ps_index)%particles(s)%obj
|
||||
|
||||
END SUBROUTINE initEdge1DRad
|
||||
end do
|
||||
|
||||
end subroutine initEdge1DRad
|
||||
|
||||
!Get nodes from edge
|
||||
PURE FUNCTION getNodes1DRad(self, nNodes) RESULT(n)
|
||||
|
|
@ -157,7 +157,7 @@ MODULE moduleMesh1DRad
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge1DRad), INTENT(in):: self
|
||||
REAL(8), DIMENSION(1:3), INTENT(in):: r0
|
||||
REAL(8), DIMENSION(1:3), INTENT(in):: r0 ! NOTE: Required by interface but unused
|
||||
REAL(8), DIMENSION(1:3):: r
|
||||
|
||||
r = (/ self%r, 0.D0, 0.D0 /)
|
||||
|
|
@ -173,7 +173,15 @@ MODULE moduleMesh1DRad
|
|||
|
||||
END FUNCTION randPos1DRad
|
||||
|
||||
!VOLUME FUNCTIONS
|
||||
function centerEdgePoint(self) RESULT(r)
|
||||
class(meshEdge1DRad), intent(in):: self
|
||||
real(8):: r(1:3)
|
||||
|
||||
r = (/ self%r, 0.D0, 0.D0 /)
|
||||
|
||||
end function centerEdgePoint
|
||||
|
||||
!CELL FUNCTIONS
|
||||
!SEGMENT FUNCTIONS
|
||||
!Init element
|
||||
SUBROUTINE initCell1DRadSegm(self, n, p, nodes)
|
||||
|
|
@ -237,35 +245,6 @@ MODULE moduleMesh1DRad
|
|||
|
||||
END FUNCTION randPos1DRadSegm
|
||||
|
||||
!Compute element functions at point Xi
|
||||
PURE FUNCTION fPsiSegm(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = (/ 1.D0 - Xi(1), &
|
||||
1.D0 + Xi(1) /)
|
||||
|
||||
fPsi = fPsi * 0.50D0
|
||||
|
||||
END FUNCTION fPsiSegm
|
||||
|
||||
!Derivative element function at coordinates Xi
|
||||
PURE FUNCTION dPsiSegm(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:2) = (/ -5.D-1, 5.D-1 /)
|
||||
|
||||
END FUNCTION dPsiSegm
|
||||
|
||||
!Partial derivative in global coordinates
|
||||
PURE FUNCTION partialDerSegm(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
@ -462,7 +441,7 @@ MODULE moduleMesh1DRad
|
|||
|
||||
END SUBROUTINE volumeSegm
|
||||
|
||||
!COMMON FUNCTIONS FOR 1D VOLUME ELEMENTS
|
||||
!COMMON FUNCTIONS FOR 1D CELL ELEMENTS
|
||||
!Compute element Jacobian determinant
|
||||
PURE FUNCTION detJ1DRad(pDer) RESULT(dJ)
|
||||
IMPLICIT NONE
|
||||
|
|
|
|||
|
|
@ -4,17 +4,9 @@
|
|||
! z == unused
|
||||
MODULE moduleMesh2DCart
|
||||
USE moduleMesh
|
||||
USE moduleMeshBoundary
|
||||
use moduleMeshCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
!Values for Gauss integral
|
||||
REAL(8), PARAMETER:: corQuad(1:3) = (/ -DSQRT(3.D0/5.D0), 0.D0, DSQRT(3.D0/5.D0) /)
|
||||
REAL(8), PARAMETER:: wQuad(1:3) = (/ 5.D0/9.D0, 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
REAL(8), PARAMETER:: Xi1Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 3.D0/5.D0, 1.D0/5.D0 /)
|
||||
REAL(8), PARAMETER:: Xi2Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 1.D0/5.D0, 3.D0/5.D0 /)
|
||||
REAL(8), PARAMETER:: wTria(1:4) = (/ -27.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0 /)
|
||||
|
||||
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode2DCart
|
||||
!Element coordinates
|
||||
REAL(8):: x = 0.D0, y = 0.D0
|
||||
|
|
@ -32,10 +24,13 @@ MODULE moduleMesh2DCart
|
|||
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL()
|
||||
CONTAINS
|
||||
!meshEdge DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: init => initEdge2DCart
|
||||
PROCEDURE, PASS:: getNodes => getNodes2DCart
|
||||
PROCEDURE, PASS:: intersection => intersection2DCartEdge
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
PROCEDURE, PASS:: init => initEdge2DCart
|
||||
PROCEDURE, PASS:: getNodes => getNodes2DCart
|
||||
PROCEDURE, PASS:: intersection => intersection2DCartEdge
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
procedure, pass:: center => centerEdgeSegm
|
||||
procedure, nopass:: centerXi => centerXiSegm
|
||||
procedure, nopass:: fPsi => fPsiSegm
|
||||
|
||||
END TYPE meshEdge2DCart
|
||||
|
||||
|
|
@ -140,17 +135,16 @@ MODULE moduleMesh2DCart
|
|||
|
||||
!EDGE FUNCTIONS
|
||||
!Init edge element
|
||||
SUBROUTINE initEdge2DCart(self, n, p, bt, physicalSurface)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
SUBROUTINE initEdge2DCart(self, n, p, ps)
|
||||
USE moduleSpecies, only:nSpecies
|
||||
USE moduleErrors
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge2DCart), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
INTEGER, INTENT(in):: p(:)
|
||||
INTEGER, INTENT(in):: bt
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
INTEGER, INTENT(in):: ps
|
||||
integer:: ps_index
|
||||
REAL(8), DIMENSION(1:3):: r1, r2
|
||||
INTEGER:: s
|
||||
|
||||
|
|
@ -170,17 +164,20 @@ MODULE moduleMesh2DCart
|
|||
0.D0 /)
|
||||
self%normal = self%normal/NORM2(self%normal)
|
||||
|
||||
!Boundary index
|
||||
self%boundary => boundary(bt)
|
||||
ALLOCATE(self%fboundary(1:nSpecies))
|
||||
!Assign functions to boundary
|
||||
DO s = 1, nSpecies
|
||||
CALL pointBoundaryFunction(self, s)
|
||||
! Get Physical Surface index based on input numering
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
END DO
|
||||
! Add elements to physical surface
|
||||
call meshEdgePointer_add(physicalSurfaces(ps_index)%edges, self%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n1%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n2%n)
|
||||
|
||||
!Physical surface
|
||||
self%physicalSurface = physicalSurface
|
||||
! Link edge to particle boundaries
|
||||
allocate(self%boundariesParticle(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
self%boundariesParticle(s)%obj => physicalSurfaces(ps_index)%particles(s)%obj
|
||||
|
||||
end do
|
||||
|
||||
END SUBROUTINE initEdge2DCart
|
||||
|
||||
|
|
@ -221,19 +218,37 @@ MODULE moduleMesh2DCart
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge2DCart), INTENT(in):: self
|
||||
REAL(8):: rnd
|
||||
REAL(8):: r(1:3)
|
||||
REAL(8):: p1(1:2), p2(1:2)
|
||||
real(8):: Xi(1:3)
|
||||
real(8):: r(1:3)
|
||||
real(8):: fPsi(1:2)
|
||||
|
||||
rnd = random()
|
||||
Xi = 0.d0
|
||||
Xi(1) = random()
|
||||
|
||||
p1 = (/self%x(1), self%y(1) /)
|
||||
p2 = (/self%x(2), self%y(2) /)
|
||||
r(1:2) = (1.D0 - rnd)*p1 + rnd*p2
|
||||
r(3) = 0.D0
|
||||
fPsi = self%fPsi(Xi, 2)
|
||||
|
||||
r = (/dot_product(fPsi, self%x), &
|
||||
dot_product(fPsi, self%y), &
|
||||
0.d0/)
|
||||
|
||||
END FUNCTION randPosEdge
|
||||
|
||||
function centerEdgeSegm(self) result(r)
|
||||
use moduleMeshCommon, only: cenSeg
|
||||
implicit none
|
||||
|
||||
class(meshEdge2DCart), intent(in):: self
|
||||
real(8):: r(1:3)
|
||||
real(8):: fPsi(1:2)
|
||||
|
||||
fPsi = self%fPsi(cenSeg, 2)
|
||||
|
||||
r = (/dot_product(fPsi, self%x), &
|
||||
dot_product(fPsi, self%y), &
|
||||
0.d0/)
|
||||
|
||||
end function centerEdgeSegm
|
||||
|
||||
!VOLUME FUNCTIONS
|
||||
!QUAD FUNCTIONS
|
||||
!Init element
|
||||
|
|
@ -310,49 +325,6 @@ MODULE moduleMesh2DCart
|
|||
|
||||
END FUNCTION randPosCellQuad
|
||||
|
||||
!Compute element functions in point Xi
|
||||
PURE FUNCTION fPsiQuad(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = 0.D0
|
||||
|
||||
fPsi = (/ (1.D0 - Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 + Xi(2)), &
|
||||
(1.D0 - Xi(1)) * (1.D0 + Xi(2)) /)
|
||||
|
||||
fPsi = fPsi * 0.25D0
|
||||
|
||||
END FUNCTION fPsiQuad
|
||||
|
||||
!Derivative element function at coordinates Xi
|
||||
PURE FUNCTION dPsiQuad(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:4) = (/ -(1.D0 - Xi(2)), &
|
||||
(1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(2)), &
|
||||
-(1.D0 + Xi(2)) /)
|
||||
|
||||
dPsi(2, 1:4) = (/ -(1.D0 - Xi(1)), &
|
||||
-(1.D0 + Xi(1)), &
|
||||
(1.D0 + Xi(1)), &
|
||||
(1.D0 - Xi(1)) /)
|
||||
|
||||
dPsi = dPsi * 0.25D0
|
||||
|
||||
END FUNCTION dPsiQuad
|
||||
|
||||
!Partial derivative in global coordinates
|
||||
PURE FUNCTION partialDerQuad(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
@ -488,9 +460,13 @@ MODULE moduleMesh2DCart
|
|||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
LOGICAL:: ins
|
||||
real(8):: eps
|
||||
|
||||
ins = (Xi(1) >= -1.D0 .AND. Xi(1) <= 1.D0) .AND. &
|
||||
(Xi(2) >= -1.D0 .AND. Xi(2) <= 1.D0)
|
||||
eps = 1.0d-10
|
||||
|
||||
|
||||
ins = (Xi(1) >= -1.D0-eps .AND. Xi(1) <= 1.D0+eps) .AND. &
|
||||
(Xi(2) >= -1.D0-eps .AND. Xi(2) <= 1.D0+eps)
|
||||
|
||||
END FUNCTION insideQuad
|
||||
|
||||
|
|
@ -656,35 +632,6 @@ MODULE moduleMesh2DCart
|
|||
|
||||
END FUNCTION randPosCellTria
|
||||
|
||||
!Compute element functions in point Xi
|
||||
PURE FUNCTION fPsiTria(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
|
||||
END FUNCTION fPsiTria
|
||||
|
||||
!Compute element derivative functions in point Xi
|
||||
PURE FUNCTION dPsiTria(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1,1:3) = (/ -1.D0, 1.D0, 0.D0 /)
|
||||
dPsi(2,1:3) = (/ -1.D0, 0.D0, 1.D0 /)
|
||||
|
||||
END FUNCTION dPsiTria
|
||||
|
||||
!Compute the derivatives in global coordinates
|
||||
PURE FUNCTION partialDerTria(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
|
|||
|
|
@ -4,17 +4,9 @@
|
|||
! z == theta (unused)
|
||||
MODULE moduleMesh2DCyl
|
||||
USE moduleMesh
|
||||
USE moduleMeshBoundary
|
||||
use moduleMeshCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
!Values for Gauss integral
|
||||
REAL(8), PARAMETER:: corQuad(1:3) = (/ -DSQRT(3.D0/5.D0), 0.D0, DSQRT(3.D0/5.D0) /)
|
||||
REAL(8), PARAMETER:: wQuad(1:3) = (/ 5.D0/9.D0, 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
REAL(8), PARAMETER:: Xi1Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 3.D0/5.D0, 1.D0/5.D0 /)
|
||||
REAL(8), PARAMETER:: Xi2Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 1.D0/5.D0, 3.D0/5.D0 /)
|
||||
REAL(8), PARAMETER:: wTria(1:4) = (/ -27.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0 /)
|
||||
|
||||
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode2DCyl
|
||||
!Element coordinates
|
||||
REAL(8):: r = 0.D0, z = 0.D0
|
||||
|
|
@ -32,10 +24,13 @@ MODULE moduleMesh2DCyl
|
|||
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL()
|
||||
CONTAINS
|
||||
!meshEdge DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: init => initEdge2DCyl
|
||||
PROCEDURE, PASS:: getNodes => getNodes2DCyl
|
||||
PROCEDURE, PASS:: intersection => intersection2DCylEdge
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
PROCEDURE, PASS:: init => initEdge2DCyl
|
||||
PROCEDURE, PASS:: getNodes => getNodes2DCyl
|
||||
PROCEDURE, PASS:: intersection => intersection2DCylEdge
|
||||
PROCEDURE, PASS:: randPos => randPosEdge
|
||||
procedure, pass:: center => centerEdgeSegm
|
||||
procedure, nopass:: centerXi => centerXiSegm
|
||||
procedure, nopass:: fPsi => fPsiSegm
|
||||
|
||||
END TYPE meshEdge2DCyl
|
||||
|
||||
|
|
@ -140,9 +135,8 @@ MODULE moduleMesh2DCyl
|
|||
|
||||
!EDGE FUNCTIONS
|
||||
!Init edge element
|
||||
SUBROUTINE initEdge2DCyl(self, n, p, bt, physicalSurface)
|
||||
SUBROUTINE initEdge2DCyl(self, n, p, ps)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
USE moduleErrors
|
||||
USE moduleConstParam, ONLY: PI
|
||||
IMPLICIT NONE
|
||||
|
|
@ -150,8 +144,8 @@ MODULE moduleMesh2DCyl
|
|||
CLASS(meshEdge2DCyl), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
INTEGER, INTENT(in):: p(:)
|
||||
INTEGER, INTENT(in):: bt
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
INTEGER, INTENT(in):: ps
|
||||
integer:: ps_index
|
||||
REAL(8), DIMENSION(1:3):: r1, r2
|
||||
INTEGER:: s
|
||||
|
||||
|
|
@ -179,17 +173,20 @@ MODULE moduleMesh2DCyl
|
|||
0.D0 /)
|
||||
self%normal = self%normal/NORM2(self%normal)
|
||||
|
||||
!Boundary index
|
||||
self%boundary => boundary(bt)
|
||||
ALLOCATE(self%fboundary(1:nSpecies))
|
||||
!Assign functions to boundary
|
||||
DO s = 1, nSpecies
|
||||
CALL pointBoundaryFunction(self, s)
|
||||
! Get Physical Surface index based on input numering
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
END DO
|
||||
! Add elements to physical surface
|
||||
call meshEdgePointer_add(physicalSurfaces(ps_index)%edges, self%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n1%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n2%n)
|
||||
|
||||
!Physical surface
|
||||
self%physicalSurface = physicalSurface
|
||||
! Link edge to particle boundaries
|
||||
allocate(self%boundariesParticle(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
self%boundariesParticle(s)%obj => physicalSurfaces(ps_index)%particles(s)%obj
|
||||
|
||||
end do
|
||||
|
||||
END SUBROUTINE initEdge2DCyl
|
||||
|
||||
|
|
@ -230,20 +227,38 @@ MODULE moduleMesh2DCyl
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge2DCyl), INTENT(in):: self
|
||||
REAL(8):: rnd
|
||||
REAL(8):: r(1:3)
|
||||
REAL(8):: p1(1:2), p2(1:2)
|
||||
real(8):: Xi(1:3)
|
||||
real(8):: r(1:3)
|
||||
real(8):: fPsi(1:2)
|
||||
|
||||
rnd = random()
|
||||
Xi = 0.d0
|
||||
Xi(1) = random()
|
||||
|
||||
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
|
||||
fPsi = self%fPsi(Xi, 2)
|
||||
|
||||
r = (/dot_product(fPsi, self%z), &
|
||||
dot_product(fPsi, self%r), &
|
||||
0.d0/)
|
||||
|
||||
END FUNCTION randPosEdge
|
||||
|
||||
!VOLUME FUNCTIONS
|
||||
function centerEdgeSegm(self) result(r)
|
||||
use moduleMeshCommon, only: cenSeg
|
||||
implicit none
|
||||
|
||||
class(meshEdge2DCyl), intent(in):: self
|
||||
real(8):: r(1:3)
|
||||
real(8):: fPsi(1:2)
|
||||
|
||||
fPsi = self%fPsi(cenSeg, 2)
|
||||
|
||||
r = (/dot_product(fPsi, self%z), &
|
||||
dot_product(fPsi, self%r), &
|
||||
0.d0/)
|
||||
|
||||
end function centerEdgeSegm
|
||||
|
||||
!CELL FUNCTIONS
|
||||
!QUAD FUNCTIONS
|
||||
!Init element
|
||||
SUBROUTINE initCellQuad2DCyl(self, n, p, nodes)
|
||||
|
|
@ -318,49 +333,6 @@ MODULE moduleMesh2DCyl
|
|||
|
||||
END FUNCTION randPosCellQuad
|
||||
|
||||
!Computes element functions in point Xi
|
||||
PURE FUNCTION fPsiQuad(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = 0.D0
|
||||
|
||||
fPsi = (/ (1.D0 - Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 + Xi(2)), &
|
||||
(1.D0 - Xi(1)) * (1.D0 + Xi(2)) /)
|
||||
|
||||
fPsi = fPsi * 0.25D0
|
||||
|
||||
END FUNCTION fPsiQuad
|
||||
|
||||
!Derivative element function at coordinates Xi
|
||||
PURE FUNCTION dPsiQuad(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:4) = (/ -(1.D0 - Xi(2)), &
|
||||
(1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(2)), &
|
||||
-(1.D0 + Xi(2)) /)
|
||||
|
||||
dPsi(2, 1:4) = (/ -(1.D0 - Xi(1)), &
|
||||
-(1.D0 + Xi(1)), &
|
||||
(1.D0 + Xi(1)), &
|
||||
(1.D0 - Xi(1)) /)
|
||||
|
||||
dPsi = dPsi * 0.25D0
|
||||
|
||||
END FUNCTION dPsiQuad
|
||||
|
||||
!Partial derivative in global coordinates
|
||||
PURE FUNCTION partialDerQuad(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
@ -504,9 +476,12 @@ MODULE moduleMesh2DCyl
|
|||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
LOGICAL:: ins
|
||||
real(8):: eps
|
||||
|
||||
ins = (Xi(1) >= -1.D0 .AND. Xi(1) <= 1.D0) .AND. &
|
||||
(Xi(2) >= -1.D0 .AND. Xi(2) <= 1.D0)
|
||||
eps = 1.0d-10
|
||||
|
||||
ins = (Xi(1) >= -1.D0-eps .AND. Xi(1) <= 1.D0+eps) .AND. &
|
||||
(Xi(2) >= -1.D0-eps .AND. Xi(2) <= 1.D0+eps)
|
||||
|
||||
END FUNCTION insideQuad
|
||||
|
||||
|
|
@ -683,35 +658,6 @@ MODULE moduleMesh2DCyl
|
|||
|
||||
END FUNCTION randPosCellTria
|
||||
|
||||
!Compute element functions in point Xi
|
||||
PURE FUNCTION fPsiTria(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
|
||||
END FUNCTION fPsiTria
|
||||
|
||||
!Compute element derivative functions in point Xi
|
||||
PURE FUNCTION dPsiTria(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1,1:3) = (/ -1.D0, 1.D0, 0.D0 /)
|
||||
dPsi(2,1:3) = (/ -1.D0, 0.D0, 1.D0 /)
|
||||
|
||||
END FUNCTION dPsiTria
|
||||
|
||||
!Compute the derivatives in global coordinates
|
||||
PURE FUNCTION partialDerTria(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
@ -929,7 +875,7 @@ MODULE moduleMesh2DCyl
|
|||
|
||||
END SUBROUTINE volumeTria
|
||||
|
||||
!COMMON FUNCTIONS FOR CYLINDRICAL VOLUME ELEMENTS
|
||||
!COMMON FUNCTIONS FOR CYLINDRICAL CELL ELEMENTS
|
||||
!Compute element Jacobian determinant
|
||||
PURE FUNCTION detJ2DCyl(pDer) RESULT(dJ)
|
||||
IMPLICIT NONE
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
! z == z
|
||||
MODULE moduleMesh3DCart
|
||||
USE moduleMesh
|
||||
USE moduleMeshBoundary
|
||||
use moduleMeshCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode3DCart
|
||||
|
|
@ -25,12 +25,14 @@ MODULE moduleMesh3DCart
|
|||
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL(), n3 => NULL()
|
||||
CONTAINS
|
||||
!meshEdge DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: init => initEdge3DCartTria
|
||||
PROCEDURE, PASS:: getNodes => getNodes3DCartTria
|
||||
PROCEDURE, PASS:: intersection => intersection3DCartTria
|
||||
PROCEDURE, PASS:: randPos => randPosEdgeTria
|
||||
PROCEDURE, PASS:: init => initEdge3DCartTria
|
||||
PROCEDURE, PASS:: getNodes => getNodes3DCartTria
|
||||
PROCEDURE, PASS:: intersection => intersection3DCartTria
|
||||
PROCEDURE, PASS:: randPos => randPosEdgeTria
|
||||
procedure, pass:: center => centerEdgeTria
|
||||
!PARTICULAR PROCEDURES
|
||||
PROCEDURE, NOPASS, PRIVATE:: fPsi => fPsiEdgeTria
|
||||
procedure, nopass:: centerXi => centerXiTria
|
||||
PROCEDURE, NOPASS:: fPsi => fPsiTria
|
||||
|
||||
END TYPE meshEdge3DCartTria
|
||||
|
||||
|
|
@ -104,9 +106,8 @@ MODULE moduleMesh3DCart
|
|||
|
||||
!EDGE FUNCTIONS
|
||||
!Init surface element
|
||||
SUBROUTINE initEdge3DCartTria(self, n, p, bt, physicalSurface)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
SUBROUTINE initEdge3DCartTria(self, n, p, ps)
|
||||
USE moduleSpecies, only: nSpecies
|
||||
USE moduleErrors
|
||||
USE moduleMath
|
||||
USE moduleRefParam, ONLY: L_ref
|
||||
|
|
@ -115,8 +116,8 @@ MODULE moduleMesh3DCart
|
|||
CLASS(meshEdge3DCartTria), INTENT(out):: self
|
||||
INTEGER, INTENT(in):: n
|
||||
INTEGER, INTENT(in):: p(:)
|
||||
INTEGER, INTENT(in):: bt
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
INTEGER, INTENT(in):: ps
|
||||
integer:: ps_index
|
||||
REAL(8), DIMENSION(1:3):: r1, r2, r3
|
||||
REAL(8), DIMENSION(1:3):: vec1, vec2
|
||||
INTEGER:: s
|
||||
|
|
@ -145,17 +146,21 @@ MODULE moduleMesh3DCart
|
|||
|
||||
self%surface = 1.D0/L_ref**2 !TODO: FIX THIS WHEN MOVING TO 3D
|
||||
|
||||
!Boundary index
|
||||
self%boundary => boundary(bt)
|
||||
ALLOCATE(self%fBoundary(1:nSpecies))
|
||||
!Assign functions to boundary
|
||||
DO s = 1, nSpecies
|
||||
CALL pointBoundaryFunction(self, s)
|
||||
! Get Physical Surface index based on input numering
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
END DO
|
||||
! Add elements to physical surface
|
||||
call meshEdgePointer_add(physicalSurfaces(ps_index)%edges, self%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n1%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n2%n)
|
||||
call meshNodePointer_add(physicalSurfaces(ps_index)%nodes, self%n3%n)
|
||||
|
||||
!Physical surface
|
||||
self%physicalSurface = physicalSurface
|
||||
! Link edge to particle boundaries
|
||||
allocate(self%boundariesParticle(1:nSpecies))
|
||||
do s = 1, nSpecies
|
||||
self%boundariesParticle(s)%obj => physicalSurfaces(ps_index)%particles(s)%obj
|
||||
|
||||
end do
|
||||
|
||||
END SUBROUTINE initEdge3DCartTria
|
||||
|
||||
|
|
@ -204,25 +209,28 @@ MODULE moduleMesh3DCart
|
|||
Xi(2) = random( 0.D0, 1.D0 - Xi(1))
|
||||
Xi(3) = 0.D0
|
||||
|
||||
fPsi = self%fPsi(Xi)
|
||||
fPsi = self%fPsi(Xi, 3)
|
||||
r = (/DOT_PRODUCT(fPsi, self%x), &
|
||||
DOT_PRODUCT(fPsi, self%y), &
|
||||
DOT_PRODUCT(fPsi, self%z)/)
|
||||
|
||||
END FUNCTION randPosEdgeTria
|
||||
|
||||
!Shape functions for triangular surface
|
||||
PURE FUNCTION fPsiEdgeTria(Xi) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
function centerEdgeTria(self) result(r)
|
||||
use moduleMeshCommon, only: cenTria
|
||||
implicit none
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
REAL(8):: fPsi(1:3)
|
||||
class(meshEdge3DCartTria), intent(in):: self
|
||||
real(8):: r(1:3)
|
||||
real(8):: fPsi(1:3)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
fPsi = self%fPsi(cenTria, 3)
|
||||
|
||||
END FUNCTION fPsiEdgeTria
|
||||
r = (/dot_product(fPsi, self%x), &
|
||||
dot_product(fPsi, self%y), &
|
||||
dot_product(fPsi, self%z)/)
|
||||
|
||||
end function centerEdgeTria
|
||||
|
||||
!VOLUME FUNCTIONS
|
||||
!TETRA FUNCTIONS
|
||||
|
|
@ -301,37 +309,6 @@ MODULE moduleMesh3DCart
|
|||
|
||||
END FUNCTION randPosCellTetra
|
||||
|
||||
!Compute element functions in point Xi
|
||||
PURE FUNCTION fPsiTetra(Xi, nNodes) RESULT(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2) - Xi(3)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
fPsi(4) = Xi(3)
|
||||
|
||||
END FUNCTION fPsiTetra
|
||||
|
||||
!Compute element derivative functions in point Xi
|
||||
PURE FUNCTION dPsiTetra(Xi, nNodes) RESULT(dPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8):: dPsi(1:3, 1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1,1:4) = (/ -1.D0, 1.D0, 0.D0, 0.D0 /)
|
||||
dPsi(2,1:4) = (/ -1.D0, 0.D0, 1.D0, 0.D0 /)
|
||||
dPsi(3,1:4) = (/ -1.D0, 0.D0, 0.D0, 1.D0 /)
|
||||
|
||||
END FUNCTION dPsiTetra
|
||||
|
||||
!Compute the derivatives in global coordinates
|
||||
PURE FUNCTION partialDerTetra(self, nNodes, dPsi) RESULT(pDer)
|
||||
IMPLICIT NONE
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ MODULE moduleMeshInput0D
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(inout):: self
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: filename !Dummy file, not used
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: filename ! NOTE: Required by interface but unused
|
||||
REAL(8):: r(1:3)
|
||||
|
||||
!Allocates one node
|
||||
|
|
|
|||
|
|
@ -15,22 +15,24 @@ MODULE moduleMeshOutput0D
|
|||
CHARACTER(:), ALLOCATABLE:: fileName
|
||||
|
||||
DO i = 1, nSpecies
|
||||
fileName='OUTPUT_' // species(i)%obj%name // '.dat'
|
||||
fileName = formatFileName('Output', species(i)%obj%name, 'csv')
|
||||
IF (timeStep == 0) THEN
|
||||
OPEN(20, file = path // folder // '/' // fileName, action = 'write')
|
||||
WRITE(20, "(A1, 14X, A5, A20, 40X, A20, 2(A20))") "#","t (s)","density (m^-3)", "velocity (m/s)", &
|
||||
"pressure (Pa)", "temperature (K)"
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN(20, file = generateFilePath(fileName), action = 'write')
|
||||
WRITE(20, "(*("//fmtColStr//"))")'"t (s)"','"density (m^-3)"', &
|
||||
'"velocity (m/s):0"', '"velocity (m/s):1"', '"velocity (m/s):2"', &
|
||||
'"pressure (Pa)"', &
|
||||
'"temperature (K)"'
|
||||
call informFileCreation(fileName)
|
||||
CLOSE(20)
|
||||
|
||||
END IF
|
||||
|
||||
OPEN(20, file = path // folder // '/' // fileName, position = 'append', action = 'write')
|
||||
OPEN(20, file = generateFilePath(fileName), position = 'append', action = 'write')
|
||||
CALL calculateOutput(self%nodes(1)%obj%output(i), output, self%nodes(1)%obj%v, species(i)%obj)
|
||||
WRITE(20, "(7(ES20.6E3))") REAL(timeStep)*tauMin*ti_ref, output%density, &
|
||||
output%velocity, &
|
||||
output%pressure, &
|
||||
output%temperature
|
||||
WRITE(20, "(*("//fmtColReal//"))") REAL(timeStep)*tauMin*ti_ref, output%density, &
|
||||
output%velocity, &
|
||||
output%pressure, &
|
||||
output%temperature
|
||||
CLOSE(20)
|
||||
|
||||
END DO
|
||||
|
|
@ -49,17 +51,22 @@ MODULE moduleMeshOutput0D
|
|||
CHARACTER(:), ALLOCATABLE:: fileName
|
||||
INTEGER:: k
|
||||
|
||||
fileName='OUTPUT_Collisions.dat'
|
||||
fileName = formatFileName('Output', 'Collisions', 'csv')
|
||||
IF (timeStep == tInitial) THEN
|
||||
OPEN(20, file = path // folder // '/' // fileName, action = 'write')
|
||||
WRITE(20, "(A1, 14X, A5, A20)") "#","t (s)","collisions"
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN(20, file = generateFilePath(fileName), action = 'write')
|
||||
call informFileCreation(fileName)
|
||||
WRITE(20, "(A,A)", advance='no') "t (s)", ','
|
||||
do k = 1, nCollPairs-1
|
||||
write(20, '(A,A,I3,A,A)', advance='no') '"',"pair", k, '"', ','
|
||||
|
||||
end do
|
||||
write(20, "(A,A,I3,A)", advance='no') '"',"pair",k, '"'
|
||||
CLOSE(20)
|
||||
|
||||
END IF
|
||||
|
||||
OPEN(20, file = path // folder // '/' // fileName, position = 'append', action = 'write')
|
||||
WRITE(20, "(ES20.6E3, 10I20)") REAL(timeStep)*tauMin*ti_ref, (self%cells(1)%obj%tallyColl(k)%tally, k=1,nCollPairs)
|
||||
OPEN(20, file = generateFilePath(fileName), position = 'append', action = 'write')
|
||||
WRITE(20, "("//fmtColReal//", *("//fmtColInt//"))") REAL(timeStep)*tauMin*ti_ref, (self%cells(1)%obj%tallyColl(k)%tally, k=1,nCollPairs)
|
||||
CLOSE(20)
|
||||
|
||||
END SUBROUTINE printColl0D
|
||||
|
|
|
|||
|
|
@ -30,14 +30,13 @@ MODULE moduleMeshInputGmsh2
|
|||
USE moduleMesh2DCart
|
||||
USE moduleMesh1DRad
|
||||
USE moduleMesh1DCart
|
||||
USE moduleBoundary
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(inout):: self
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: filename
|
||||
REAL(8):: r(1:3) !3 generic coordinates
|
||||
INTEGER, ALLOCATABLE:: p(:) !Array for nodes
|
||||
INTEGER:: e = 0, n = 0, eTemp = 0, elemType = 0, bt = 0
|
||||
INTEGER:: e = 0, n = 0, eTemp = 0, elemType = 0
|
||||
INTEGER:: totalNumElem
|
||||
INTEGER:: numEdges
|
||||
INTEGER:: boundaryType
|
||||
|
|
@ -161,9 +160,6 @@ MODULE moduleMeshInputGmsh2
|
|||
READ(10, *) n, elemType, eTemp, boundaryType
|
||||
BACKSPACE(10)
|
||||
|
||||
!Associate boundary condition procedure.
|
||||
bt = getBoundaryID(boundaryType)
|
||||
|
||||
SELECT CASE(elemType)
|
||||
CASE(2)
|
||||
!Triangular surface
|
||||
|
|
@ -178,8 +174,6 @@ MODULE moduleMeshInputGmsh2
|
|||
CASE (2)
|
||||
ALLOCATE(p(1:2))
|
||||
READ(10,*) n, elemType, eTemp, boundaryType, eTemp, p(1:2)
|
||||
!Associate boundary condition procedure.
|
||||
bt = getBoundaryId(boundaryType)
|
||||
|
||||
SELECT CASE(self%geometry)
|
||||
CASE("Cyl")
|
||||
|
|
@ -193,8 +187,6 @@ MODULE moduleMeshInputGmsh2
|
|||
CASE(1)
|
||||
ALLOCATE(p(1:1))
|
||||
READ(10, *) n, elemType, eTemp, boundaryType, eTemp, p(1)
|
||||
!Associate boundary condition
|
||||
bt = getBoundaryId(boundaryType)
|
||||
SELECT CASE(self%geometry)
|
||||
CASE("Rad")
|
||||
ALLOCATE(meshEdge1DRad:: self%edges(e)%obj)
|
||||
|
|
@ -206,8 +198,13 @@ MODULE moduleMeshInputGmsh2
|
|||
|
||||
END SELECT
|
||||
|
||||
CALL self%edges(e)%obj%init(n, p, bt, boundaryType)
|
||||
DEALLOCATE(p)
|
||||
! If an edge was found, init it
|
||||
if (allocated(p)) then
|
||||
call self%edges(e)%obj%init(n, p, boundaryType)
|
||||
|
||||
deallocate(p)
|
||||
|
||||
end if
|
||||
|
||||
END DO
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ MODULE moduleMeshOutputGmsh2
|
|||
!Node data subroutines
|
||||
!Header
|
||||
SUBROUTINE writeGmsh2HeaderNodeData(fileID, title, iteration, time, dimensions, nNodes)
|
||||
use moduleOutput
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER, INTENT(in):: fileID
|
||||
|
|
@ -25,14 +26,14 @@ MODULE moduleMeshOutputGmsh2
|
|||
|
||||
|
||||
WRITE(fileID, "(A)") '$NodeData'
|
||||
WRITE(fileID, "(I10)") 1
|
||||
WRITE(fileID, "("//fmtInt//")") 1
|
||||
WRITE(fileID, "(A1, A, A1)") '"' , title , '"'
|
||||
WRITE(fileID, "(I10)") 1
|
||||
WRITE(fileID, "(ES20.6E3)") time
|
||||
WRITE(fileID, "(I10)") 3
|
||||
WRITE(fileID, "(I10)") iteration
|
||||
WRITE(fileID, "(I10)") dimensions
|
||||
WRITE(fileID, "(I10)") nNodes
|
||||
WRITE(fileID, "("//fmtInt//")") 1
|
||||
WRITE(fileID, "("//fmtReal//")") time
|
||||
WRITE(fileID, "("//fmtInt//")") 3
|
||||
WRITE(fileID, "("//fmtInt//")") iteration
|
||||
WRITE(fileID, "("//fmtInt//")") dimensions
|
||||
WRITE(fileID, "("//fmtInt//")") nNodes
|
||||
|
||||
END SUBROUTINE writeGmsh2HeaderNodeData
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ MODULE moduleMeshOutputGmsh2
|
|||
!Element data subroutines
|
||||
!Header
|
||||
SUBROUTINE writeGmsh2HeaderElementData(fileID, title, iteration, time, dimensions, nVols)
|
||||
use moduleOutput
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER, INTENT(in):: fileID
|
||||
|
|
@ -58,14 +60,14 @@ MODULE moduleMeshOutputGmsh2
|
|||
|
||||
|
||||
WRITE(fileID, "(A)") '$ElementData'
|
||||
WRITE(fileID, "(I10)") 1
|
||||
WRITE(fileID, "("//fmtInt//")") 1
|
||||
WRITE(fileID, "(A1, A, A1)") '"' , title , '"'
|
||||
WRITE(fileID, "(I10)") 1
|
||||
WRITE(fileID, "(ES20.6E3)") time
|
||||
WRITE(fileID, "(I10)") 3
|
||||
WRITE(fileID, "(I10)") iteration
|
||||
WRITE(fileID, "(I10)") dimensions
|
||||
WRITE(fileID, "(I10)") nVols
|
||||
WRITE(fileID, "("//fmtInt//")") 1
|
||||
WRITE(fileID, "("//fmtReal//")") time
|
||||
WRITE(fileID, "("//fmtInt//")") 3
|
||||
WRITE(fileID, "("//fmtInt//")") iteration
|
||||
WRITE(fileID, "("//fmtInt//")") dimensions
|
||||
WRITE(fileID, "("//fmtInt//")") nVols
|
||||
|
||||
END SUBROUTINE writeGmsh2HeaderElementData
|
||||
|
||||
|
|
@ -85,7 +87,6 @@ MODULE moduleMeshOutputGmsh2
|
|||
USE moduleRefParam
|
||||
USE moduleSpecies
|
||||
USE moduleOutput
|
||||
USE moduleMeshInoutCommon
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
|
|
@ -99,33 +100,33 @@ MODULE moduleMeshOutputGmsh2
|
|||
|
||||
DO i = 1, nSpecies
|
||||
fileName = formatFileName(prefix, species(i)%obj%name, 'msh', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (60, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (60, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeGmsh2HeaderMesh(60)
|
||||
|
||||
CALL writeGmsh2HeaderNodeData(60, species(i)%obj%name // ' density (m^-3)', timeStep, time, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
CALL calculateOutput(self%nodes(n)%obj%output(i), output(n), self%nodes(n)%obj%v, species(i)%obj)
|
||||
WRITE(60, "(I6,ES20.6E3)") n, output(n)%density
|
||||
WRITE(60, "(I6,"//fmtReal//")") n, output(n)%density
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(60)
|
||||
|
||||
CALL writeGmsh2HeaderNodeData(60, species(i)%obj%name // ' velocity (m s^-1)', timeStep, time, 3, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(60, "(I6,3(ES20.6E3))") n, output(n)%velocity
|
||||
WRITE(60, "(I6,3("//fmtReal//"))") n, output(n)%velocity
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(60)
|
||||
|
||||
CALL writeGmsh2HeaderNodeData(60, species(i)%obj%name // ' Pressure (Pa)', timeStep, time, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(60, "(I6,3(ES20.6E3))") n, output(n)%pressure
|
||||
WRITE(60, "(I6,3("//fmtReal//"))") n, output(n)%pressure
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(60)
|
||||
|
||||
CALL writeGmsh2HeaderNodeData(60, species(i)%obj%name // ' Temperature (K)', timeStep, time, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(60, "(I6,3(ES20.6E3))") n, output(n)%temperature
|
||||
WRITE(60, "(I6,3("//fmtReal//"))") n, output(n)%temperature
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(60)
|
||||
CLOSE (60)
|
||||
|
|
@ -141,7 +142,6 @@ MODULE moduleMeshOutputGmsh2
|
|||
USE moduleCaseParam
|
||||
USE moduleCollisions
|
||||
USE moduleOutput
|
||||
USE moduleMeshInoutCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(in):: self
|
||||
|
|
@ -169,8 +169,8 @@ MODULE moduleMeshOutputGmsh2
|
|||
time = DBLE(timeStep)*tauMin*ti_ref
|
||||
|
||||
fileName = formatFileName(prefix, 'Collisions', 'msh', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (60, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (60, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeGmsh2HeaderMesh(60)
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ MODULE moduleMeshOutputGmsh2
|
|||
title = '"Pair ' // interactionMatrix(k)%sp_i%name // '-' // interactionMatrix(k)%sp_j%name // ' collision ' // cString
|
||||
CALL writeGmsh2HeaderElementData(60, title, timeStep, time, 1, self%numCells)
|
||||
DO n=1, self%numCells
|
||||
WRITE(60, "(I6,I10)") n + numEdges, self%cells(n)%obj%tallyColl(k)%tally(c)
|
||||
WRITE(60, "(I6,"//fmtInt//")") n + numEdges, self%cells(n)%obj%tallyColl(k)%tally(c)
|
||||
END DO
|
||||
CALL writeGmsh2FooterElementData(60)
|
||||
|
||||
|
|
@ -200,7 +200,6 @@ MODULE moduleMeshOutputGmsh2
|
|||
USE moduleRefParam
|
||||
USE moduleCaseParam
|
||||
USE moduleOutput
|
||||
USE moduleMeshInoutCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshParticles), INTENT(in):: self
|
||||
|
|
@ -215,8 +214,8 @@ MODULE moduleMeshOutputGmsh2
|
|||
time = DBLE(timeStep)*tauMin*ti_ref
|
||||
|
||||
fileName = formatFileName(prefix, 'EMField', 'msh', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (20, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (20, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeGmsh2HeaderMesh(20)
|
||||
|
||||
|
|
@ -251,7 +250,6 @@ MODULE moduleMeshOutputGmsh2
|
|||
USE moduleSpecies
|
||||
USE moduleOutput
|
||||
USE moduleAverage
|
||||
USE moduleMeshInoutCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshParticles), INTENT(in):: self
|
||||
|
|
@ -262,12 +260,12 @@ MODULE moduleMeshOutputGmsh2
|
|||
|
||||
DO i = 1, nSpecies
|
||||
fileName = formatFileName('Average_mean', species(i)%obj%name, 'msh')
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (fileMean, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (fileMean, file = generateFilePath(fileName))
|
||||
|
||||
fileName = formatFileName('Average_deviation', species(i)%obj%name, 'msh')
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (filedeviation, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (filedeviation, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeGmsh2HeaderMesh(fileMean)
|
||||
CALL writeGmsh2HeaderMesh(fileDeviation)
|
||||
|
|
@ -276,9 +274,9 @@ MODULE moduleMeshOutputGmsh2
|
|||
CALL writeGmsh2HeaderNodeData(fileDeviation, species(i)%obj%name // ' density, sd (m^-3)', 0, 0.D0, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
CALL calculateOutput(averageScheme(n)%mean%output(i), outputMean(n), self%nodes(n)%obj%v, species(i)%obj)
|
||||
WRITE(fileMean, "(I6,ES20.6E3)") n, outputMean(n)%density
|
||||
WRITE(fileMean, "(I6,"//fmtReal//")") n, outputMean(n)%density
|
||||
CALL calculateOutput(averageScheme(n)%deviation%output(i), outputDeviation(n), self%nodes(n)%obj%v, species(i)%obj)
|
||||
WRITE(fileDeviation, "(I6,ES20.6E3)") n, outputDeviation(n)%density
|
||||
WRITE(fileDeviation, "(I6,"//fmtReal//")") n, outputDeviation(n)%density
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(fileMean)
|
||||
CALL writeGmsh2FooterNodeData(fileDeviation)
|
||||
|
|
@ -286,8 +284,8 @@ MODULE moduleMeshOutputGmsh2
|
|||
CALL writeGmsh2HeaderNodeData(fileMean, species(i)%obj%name // ' velocity, mean (m s^-1)', 0, 0.D0, 3, self%numNodes)
|
||||
CALL writeGmsh2HeaderNodeData(fileDeviation, species(i)%obj%name // ' velocity, sd (m s^-1)', 0, 0.D0, 3, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(fileMean, "(I6,3(ES20.6E3))") n, outputMean(n)%velocity
|
||||
WRITE(fileDeviation, "(I6,3(ES20.6E3))") n, outputDeviation(n)%velocity
|
||||
WRITE(fileMean, "(I6,3("//fmtReal//"))") n, outputMean(n)%velocity
|
||||
WRITE(fileDeviation, "(I6,3("//fmtReal//"))") n, outputDeviation(n)%velocity
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(fileMean)
|
||||
CALL writeGmsh2FooterNodeData(fileDeviation)
|
||||
|
|
@ -295,8 +293,8 @@ MODULE moduleMeshOutputGmsh2
|
|||
CALL writeGmsh2HeaderNodeData(fileMean, species(i)%obj%name // ' Pressure, mean (Pa)', 0, 0.D0, 1, self%numNodes)
|
||||
CALL writeGmsh2HeaderNodeData(fileDeviation, species(i)%obj%name // ' Pressure, sd (Pa)', 0, 0.D0, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(fileMean, "(I6,3(ES20.6E3))") n, outputMean(n)%pressure
|
||||
WRITE(fileDeviation, "(I6,3(ES20.6E3))") n, outputDeviation(n)%pressure
|
||||
WRITE(fileMean, "(I6,3("//fmtReal//"))") n, outputMean(n)%pressure
|
||||
WRITE(fileDeviation, "(I6,3("//fmtReal//"))") n, outputDeviation(n)%pressure
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(fileMean)
|
||||
CALL writeGmsh2FooterNodeData(fileDeviation)
|
||||
|
|
@ -304,8 +302,8 @@ MODULE moduleMeshOutputGmsh2
|
|||
CALL writeGmsh2HeaderNodeData(fileMean, species(i)%obj%name // ' Temperature, mean (K)', 0, 0.D0, 1, self%numNodes)
|
||||
CALL writeGmsh2HeaderNodeData(fileDeviation, species(i)%obj%name // ' Temperature, sd (K)', 0, 0.D0, 1, self%numNodes)
|
||||
DO n=1, self%numNodes
|
||||
WRITE(fileMean, "(I6,3(ES20.6E3))") n, outputMean(n)%temperature
|
||||
WRITE(fileDeviation, "(I6,3(ES20.6E3))") n, outputDeviation(n)%temperature
|
||||
WRITE(fileMean, "(I6,3("//fmtReal//"))") n, outputMean(n)%temperature
|
||||
WRITE(fileDeviation, "(I6,3("//fmtReal//"))") n, outputDeviation(n)%temperature
|
||||
END DO
|
||||
CALL writeGmsh2FooterNodeData(fileMean)
|
||||
CALL writeGmsh2FooterNodeData(fileDeviation)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
all: vtu.o gmsh2.o 0D.o text.o
|
||||
|
||||
vtu.o: moduleMeshInoutCommon.o
|
||||
vtu.o:
|
||||
$(MAKE) -C vtu all
|
||||
|
||||
gmsh2.o:
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
MODULE moduleMeshInoutCommon
|
||||
|
||||
CHARACTER(LEN=4):: prefix = 'Step'
|
||||
|
||||
CONTAINS
|
||||
PURE FUNCTION formatFileName(prefix, suffix, extension, timeStep) RESULT(fileName)
|
||||
USE moduleOutput
|
||||
IMPLICIT NONE
|
||||
|
||||
CHARACTER(*), INTENT(in):: prefix, suffix, extension
|
||||
INTEGER, INTENT(in), OPTIONAL:: timeStep
|
||||
CHARACTER (LEN=iterationDigits):: tString
|
||||
CHARACTER(:), ALLOCATABLE:: fileName
|
||||
|
||||
IF (PRESENT(timeStep)) THEN
|
||||
WRITE(tString, iterationFormat) timeStep
|
||||
fileName = prefix // '_' // tString // '_' // suffix // '.' // extension
|
||||
|
||||
ELSE
|
||||
fileName = prefix // '_' // suffix // '.' // extension
|
||||
|
||||
END IF
|
||||
|
||||
END FUNCTION formatFileName
|
||||
|
||||
|
||||
END MODULE moduleMeshInoutCommon
|
||||
|
|
@ -47,7 +47,6 @@ module moduleMeshInputText
|
|||
integer:: physicalID
|
||||
integer:: n, c
|
||||
integer, allocatable:: p(:)
|
||||
integer:: bt
|
||||
|
||||
fileID = 10
|
||||
|
||||
|
|
@ -141,8 +140,9 @@ module moduleMeshInputText
|
|||
|
||||
allocate(p(1))
|
||||
p(1) = n
|
||||
bt = getBoundaryId(physicalID)
|
||||
call self%edges(physicalID)%obj%init(physicalID, p, physicalID, physicalID)
|
||||
|
||||
call self%edges(physicalID)%obj%init(physicalID, p, physicalID)
|
||||
|
||||
deallocate(p)
|
||||
|
||||
end if
|
||||
|
|
@ -197,6 +197,7 @@ module moduleMeshInputText
|
|||
fileID = 10
|
||||
|
||||
open(fileID, file=trim(filename))
|
||||
nNodes = 0
|
||||
|
||||
do
|
||||
read(fileID, *, iostat=reason) line
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ module moduleMeshOutputText
|
|||
subroutine writeCollOutput(self, fileID)
|
||||
use moduleMesh
|
||||
use moduleCollisions
|
||||
use moduleRefParam, only: L_ref
|
||||
implicit none
|
||||
|
||||
class(meshGeneric), intent(in):: self
|
||||
|
|
@ -122,7 +121,6 @@ module moduleMeshOutputText
|
|||
subroutine printOutputText(self)
|
||||
use moduleMesh
|
||||
use moduleSpecies
|
||||
use moduleMeshInoutCommon
|
||||
use moduleCaseParam, ONLY: timeStep
|
||||
implicit none
|
||||
|
||||
|
|
@ -135,13 +133,13 @@ module moduleMeshOutputText
|
|||
|
||||
do s = 1, nSpecies
|
||||
fileName = formatFileName(prefix, species(s)%obj%name, 'csv', timeStep)
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
open (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
open (fileID, file = generateFilePath(fileName))
|
||||
|
||||
write(fileID, '(5(A,","),A)') 'Position (m)', &
|
||||
'Density (m^-3)', &
|
||||
'Velocity (m s^-1):0', 'Velocity (m s^-1):1', 'Velocity (m s^-1):2', &
|
||||
'Temperature (K)'
|
||||
write(fileID, '(5(A,","),A)') '"Position (m)"', &
|
||||
'"Density (m^-3)"', &
|
||||
'"Velocity (m s^-1):0"', 'Velocity (m s^-1):1"', 'Velocity (m s^-1):2"', &
|
||||
'"Temperature (K)"'
|
||||
|
||||
call writeSpeciesOutput(self, fileID, s)
|
||||
|
||||
|
|
@ -154,7 +152,6 @@ module moduleMeshOutputText
|
|||
subroutine printCollText(self)
|
||||
use moduleMesh
|
||||
use moduleOutput
|
||||
use moduleMeshInoutCommon
|
||||
use moduleCaseParam, only: timeStep
|
||||
implicit none
|
||||
|
||||
|
|
@ -168,8 +165,8 @@ module moduleMeshOutputText
|
|||
|
||||
if (collOutput) then
|
||||
fileName = formatFileName(prefix, 'Collisions', 'csv', timeStep)
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
open (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
open (fileID, file = generateFilePath(fileName))
|
||||
|
||||
write(fileID, '(A)', advance='no') "Cell"
|
||||
do k = 1, nCollPairs
|
||||
|
|
@ -192,7 +189,6 @@ module moduleMeshOutputText
|
|||
|
||||
subroutine printEMText(self)
|
||||
use moduleMesh
|
||||
use moduleMeshInoutCommon
|
||||
use moduleCaseParam, only: timeStep
|
||||
implicit none
|
||||
|
||||
|
|
@ -204,13 +200,13 @@ module moduleMeshOutputText
|
|||
|
||||
if (emOutput) then
|
||||
fileName = formatFileName(prefix, 'EMField', 'csv', timeStep)
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
open (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
open (fileID, file = generateFilePath(fileName))
|
||||
|
||||
write(fileID, '(8(A,","),A)') 'Position (m)', &
|
||||
'Potential (V)', &
|
||||
'Electric Field (V m^-1):0', 'Electric Field (V m^-1):1', 'Electric Field (V m^-1):2', &
|
||||
'Magnetic Field (T):0', 'Magnetic Field (T):1', 'Magnetic Field (T):2'
|
||||
write(fileID, '(8(A,","),A)') '"Position (m)"', &
|
||||
'"Potential (V)"', &
|
||||
'"Electric Field (V m^-1):0"', 'Electric Field (V m^-1):1"', 'Electric Field (V m^-1):2"', &
|
||||
'"Magnetic Field (T):0"', 'Magnetic Field (T):1"', 'Magnetic Field (T):2"'
|
||||
|
||||
call writeEMOutput(self, fileID)
|
||||
|
||||
|
|
@ -223,7 +219,6 @@ module moduleMeshOutputText
|
|||
subroutine printAverageText(self)
|
||||
use moduleMesh
|
||||
use moduleSpecies
|
||||
use moduleMeshInoutCommon
|
||||
implicit none
|
||||
|
||||
class(meshParticles), intent(in):: self
|
||||
|
|
@ -235,23 +230,23 @@ module moduleMeshOutputText
|
|||
fileIDDeviation = 67
|
||||
|
||||
do s = 1, nSpecies
|
||||
fileNameMean = formatFileName('Average_mean', species(s)%obj%name, 'csv', timeStep)
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileNameMean
|
||||
open (fileIDMean, file = path // folder // '/' // fileNameMean)
|
||||
fileNameMean = formatFileName('Average_mean', species(s)%obj%name, 'csv')
|
||||
call informFileCreation(fileNameMean)
|
||||
open (fileIDMean, file = generateFilePath(fileNameMean))
|
||||
|
||||
write(fileIDMean, '(5(A,","),A)') 'Position (m)', &
|
||||
'Density, mean (m^-3)', &
|
||||
'Velocity, mean (m s^-1):0', 'Velocity (m s^-1):1', 'Velocity (m s^-1):2', &
|
||||
'Temperature, mean (K)'
|
||||
write(fileIDMean, '(5(A,","),A)') '"Position (m)"', &
|
||||
'"Density, mean (m^-3)"', &
|
||||
'"Velocity, mean (m s^-1):0"', '"Velocity (m s^-1):1"', '"Velocity (m s^-1):2"', &
|
||||
'"Temperature, mean (K)"'
|
||||
|
||||
fileNameDeviation = formatFileName('Average_deviation', species(s)%obj%name, 'csv', timeStep)
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileNameDeviation
|
||||
open (fileIDDeviation, file = path // folder // '/' // fileNameDeviation)
|
||||
fileNameDeviation = formatFileName('Average_deviation', species(s)%obj%name, 'csv')
|
||||
call informFileCreation(fileNameDeviation)
|
||||
open (fileIDDeviation, file = generateFilePath(fileNameDeviation))
|
||||
|
||||
write(fileIDDeviation, '(5(A,","),A)') 'Position (m)', &
|
||||
'Density, deviation (m^-3)', &
|
||||
'Velocity, deviation (m s^-1):0', 'Velocity (m s^-1):1', 'Velocity (m s^-1):2', &
|
||||
'Temperature, deviation (K)'
|
||||
write(fileIDDeviation, '(5(A,","),A)') '"Position (m)"', &
|
||||
'"Density, deviation (m^-3)"', &
|
||||
'"Velocity, deviation (m s^-1):0"', 'Velocity (m s^-1):1"', 'Velocity (m s^-1):2"', &
|
||||
'"Temperature, deviation (K)"'
|
||||
|
||||
call writeAverage(self, fileIDMean, fileIDDeviation, s)
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,6 @@ MODULE moduleMeshInputVTU
|
|||
USE moduleMesh2DCart
|
||||
USE moduleMesh1DRad
|
||||
USE moduleMesh1DCart
|
||||
USE moduleBoundary
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(inout):: self
|
||||
|
|
@ -174,7 +173,6 @@ MODULE moduleMeshInputVTU
|
|||
REAL(8), ALLOCATABLE, DIMENSION(:):: coordinates
|
||||
INTEGER:: n, e, c
|
||||
INTEGER, ALLOCATABLE:: p(:)
|
||||
INTEGER:: bt
|
||||
|
||||
fileID = 10
|
||||
|
||||
|
|
@ -321,16 +319,9 @@ MODULE moduleMeshInputVTU
|
|||
p(2) = connectivity(offsets(n) - 1)
|
||||
p(3) = connectivity(offsets(n))
|
||||
|
||||
!Associate boundary condition procedure.
|
||||
bt = getBoundaryId(entitiesID(n))
|
||||
|
||||
!Allocate edge
|
||||
ALLOCATE(meshEdge3DCartTria:: self%edges(e)%obj)
|
||||
|
||||
!Init edge
|
||||
CALL self%edges(e)%obj%init(n, p, bt, entitiesID(n))
|
||||
DEALLOCATE(p)
|
||||
|
||||
END IF
|
||||
|
||||
CASE(2)
|
||||
|
|
@ -340,9 +331,6 @@ MODULE moduleMeshInputVTU
|
|||
p(1) = connectivity(offsets(n) - 1)
|
||||
p(2) = connectivity(offsets(n))
|
||||
|
||||
!Associate boundary condition procedure.
|
||||
bt = getBoundaryId(entitiesID(n))
|
||||
|
||||
!Allocate edge
|
||||
SELECT CASE(self%geometry)
|
||||
CASE("Cyl")
|
||||
|
|
@ -353,10 +341,6 @@ MODULE moduleMeshInputVTU
|
|||
|
||||
END SELECT
|
||||
|
||||
!Init edge
|
||||
CALL self%edges(e)%obj%init(n, p, bt, entitiesID(n))
|
||||
DEALLOCATE(p)
|
||||
|
||||
END IF
|
||||
|
||||
CASE(1)
|
||||
|
|
@ -365,9 +349,6 @@ MODULE moduleMeshInputVTU
|
|||
ALLOCATE(p(1:1))
|
||||
p(1) = connectivity(offsets(n))
|
||||
|
||||
!Associate boundary condition procedure.
|
||||
bt = getBoundaryId(entitiesID(n))
|
||||
|
||||
!Allocate edge
|
||||
SELECT CASE(self%geometry)
|
||||
CASE("Rad")
|
||||
|
|
@ -378,14 +359,18 @@ MODULE moduleMeshInputVTU
|
|||
|
||||
END SELECT
|
||||
|
||||
!Init edge
|
||||
CALL self%edges(e)%obj%init(n, p, bt, entitiesID(n))
|
||||
DEALLOCATE(p)
|
||||
|
||||
END IF
|
||||
|
||||
END SELECT
|
||||
|
||||
! If an edge was found, init it
|
||||
if (allocated(p)) then
|
||||
call self%edges(e)%obj%init(n, p, entitiesID(n))
|
||||
|
||||
deallocate(p)
|
||||
|
||||
end if
|
||||
|
||||
END DO
|
||||
|
||||
END SELECT
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ MODULE moduleMeshOutputVTU
|
|||
WRITE(fileID,"(A)") '<?xml version="1.0"?>'
|
||||
WRITE(fileID,"(2X, A)") '<VTKFile type="UnstructuredGrid">'
|
||||
WRITE(fileID,"(4X, A)") '<UnstructuredGrid>'
|
||||
WRITE(fileID,"(6X, A, I10, A, I10, A)") '<Piece NumberOfPoints="', nNodes, '" NumberOfCells="', nCells, '">'
|
||||
WRITE(fileID,"(6X, A, "//fmtInt//", A, "//fmtInt//", A)") '<Piece NumberOfPoints="', nNodes, '" NumberOfCells="', nCells, '">'
|
||||
|
||||
END SUBROUTINE writeHeader
|
||||
|
||||
|
|
@ -87,14 +87,14 @@ MODULE moduleMeshOutputVTU
|
|||
!Write nodes coordinates
|
||||
WRITE(fileID, "(8X, A)") '<Points>'
|
||||
WRITE(fileID, "(10X,A)") '<DataArray type="Float32" NumberOfComponents="3" format="ascii">'
|
||||
WRITE(fileID, "(6(ES20.6E3))") (self%nodes(e)%obj%getCoordinates()*L_ref, e = 1, self%numNodes)
|
||||
WRITE(fileID, "(6("//fmtReal//"))") (self%nodes(e)%obj%getCoordinates()*L_ref, e = 1, self%numNodes)
|
||||
WRITE(fileID, "(10X, A)") '</DataArray>'
|
||||
WRITE(fileID, "(8X, A)") '</Points>'
|
||||
|
||||
WRITE(fileID, "(8X, A)") '<Cells>'
|
||||
!Write nodes connectivity of each cell
|
||||
WRITE(fileID, "(10X,A)") '<DataArray type="Int32" Name="connectivity" format="ascii">'
|
||||
WRITE(fileID, "(6(I10))") (self%cells(e)%obj%getNodes(self%cells(e)%obj%nNodes) - 1, e = 1, self%numCells) !Array starts on 0
|
||||
WRITE(fileID, "(6("//fmtInt//"))") (self%cells(e)%obj%getNodes(self%cells(e)%obj%nNodes) - 1, e = 1, self%numCells) !Array starts on 0
|
||||
WRITE(fileID, "(10X, A)") '</DataArray>'
|
||||
!Write offset of each cell
|
||||
offset(1) = self%cells(1)%obj%nNodes
|
||||
|
|
@ -103,7 +103,7 @@ MODULE moduleMeshOutputVTU
|
|||
offset(e) = offset(e - 1) + self%cells(e)%obj%nNodes
|
||||
|
||||
END DO
|
||||
WRITE(fileID, "(6(I10))") offset
|
||||
WRITE(fileID, "(6("//fmtInt//"))") offset
|
||||
WRITE(fileID, "(10X, A)") '</DataArray>'
|
||||
!Write type of each cell
|
||||
WRITE(fileID, "(10X,A)") '<DataArray type="Int32" Name="types" format="ascii">'
|
||||
|
|
@ -111,7 +111,7 @@ MODULE moduleMeshOutputVTU
|
|||
types(e) = getCellType(self%cells(e)%obj)
|
||||
|
||||
END DO
|
||||
WRITE(fileID, "(6(I10))") types
|
||||
WRITE(fileID, "(6("//fmtInt//"))") types
|
||||
WRITE(fileID, "(10X, A)") '</DataArray>'
|
||||
WRITE(fileID, "(8X, A)") '</Cells>'
|
||||
|
||||
|
|
@ -137,19 +137,19 @@ MODULE moduleMeshOutputVTU
|
|||
WRITE(fileID,"(8X,A)") '<PointData>'
|
||||
!Write density
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Density (m^-3)" NumberOfComponents="1">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (output(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (output(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
!Write velocity
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Velocity (m s^-1)" NumberOfComponents="3">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (output(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (output(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
!Write pressure
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Pressure (Pa)" NumberOfComponents="1">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (output(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (output(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
!Write temperature
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Temperature (K)" NumberOfComponents="1">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (output(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (output(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
!End node data
|
||||
WRITE(fileID,"(8X,A)") '</PointData>'
|
||||
|
|
@ -173,7 +173,7 @@ MODULE moduleMeshOutputVTU
|
|||
WRITE(cString, "(I2)") c
|
||||
title = 'Pair ' // interactionMatrix(k)%sp_i%name // '-' // interactionMatrix(k)%sp_j%name // ' collision ' // cString
|
||||
WRITE(fileID,"(10X,A, A, A)") '<DataArray type="Float64" Name="',title, '" NumberOfComponents="1">'
|
||||
WRITE(fileID, "(6(I10))") (self%cells(n)%obj%tallyColl(k)%tally(c), n = 1, self%numCells)
|
||||
WRITE(fileID, "(6("//fmtInt//"))") (self%cells(n)%obj%tallyColl(k)%tally(c), n = 1, self%numCells)
|
||||
WRITE(fileID, "(10X, A)") '</DataArray>'
|
||||
|
||||
END DO
|
||||
|
|
@ -196,11 +196,11 @@ MODULE moduleMeshOutputVTU
|
|||
WRITE(fileID,"(8X,A)") '<PointData>'
|
||||
!Electric potential
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Potential (V)" NumberOfComponents="1">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (self%nodes(n)%obj%emData%phi*Volt_ref, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (self%nodes(n)%obj%emData%phi*Volt_ref, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
!Magnetic Field
|
||||
WRITE(fileID,"(10X,A)") '<DataArray type="Float64" Name="Magnetic Field (T)" NumberOfComponents="3">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (self%nodes(n)%obj%emData%B*B_ref, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (self%nodes(n)%obj%emData%B*B_ref, n = 1, self%numNodes)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
WRITE(fileID,"(8X,A)") '</PointData>'
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ MODULE moduleMeshOutputVTU
|
|||
WRITE(fileID,"(8X,A)") '<CellData>'
|
||||
!Electric field
|
||||
WRITE(fileID,"(10X,A, A, A)") '<DataArray type="Float64" Name="Electric Field (V m^-1)" NumberOfComponents="3">'
|
||||
WRITE(fileID,"(6(ES20.6E3))") (self%cells(n)%obj%gatherElectricField(Xi)*EF_ref, n = 1, self%numCells)
|
||||
WRITE(fileID,"(6("//fmtReal//"))") (self%cells(n)%obj%gatherElectricField(Xi)*EF_ref, n = 1, self%numCells)
|
||||
WRITE(fileID,"(10X,A)") '</DataArray>'
|
||||
WRITE(fileID,"(8X,A)") '</CellData>'
|
||||
|
||||
|
|
@ -221,30 +221,31 @@ MODULE moduleMeshOutputVTU
|
|||
USE moduleRefParam
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER:: fileID
|
||||
CHARACTER(*):: fileNameStep, fileNameCollection
|
||||
INTEGER, intent(in):: fileID
|
||||
CHARACTER(*), intent(in):: fileNameStep, fileNameCollection
|
||||
|
||||
IF (timeStep == tInitial) THEN
|
||||
!Create collection file
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileNameCollection
|
||||
OPEN (fileID + 1, file = path // folder // '/' // fileNameCollection)
|
||||
call informFileCreation(fileNameCollection)
|
||||
OPEN (fileID + 1, file = generateFilePath(fileNameCollection))
|
||||
WRITE (fileID + 1, "(A)") '<VTKFile type="Collection">'
|
||||
WRITE (fileID + 1, "(2X, A)") '<Collection>'
|
||||
CLOSE(fileID + 1)
|
||||
|
||||
else
|
||||
OPEN (fileID + 1, file = generateFilePath(fileNameCollection), ACCESS='APPEND')
|
||||
! Append removing the last two lines that close the <tags>
|
||||
backspace(fileID + 1)
|
||||
backspace(fileID + 1)
|
||||
|
||||
END IF
|
||||
|
||||
!Write iteration file in collection
|
||||
OPEN (fileID + 1, file = path // folder // '/' // fileNameCollection, ACCESS='APPEND')
|
||||
WRITE(fileID + 1, "(4X, A, ES20.6E3, A, A, A)") &
|
||||
WRITE(fileID + 1, "(4X, A, "//fmtReal//", A, A, A)") &
|
||||
'<DataSet timestep="', DBLE(timeStep)*tauMin*ti_ref,'" file="', fileNameStep,'"/>'
|
||||
|
||||
!Close collection file
|
||||
IF (timeStep == tFinal) THEN
|
||||
WRITE (fileID + 1, "(2X, A)") '</Collection>'
|
||||
WRITE (fileID + 1, "(A)") '</VTKFile>'
|
||||
WRITE (fileID + 1, "(2X, A)") '</Collection>'
|
||||
WRITE (fileID + 1, "(A)") '</VTKFile>'
|
||||
|
||||
END IF
|
||||
CLOSE(fileID + 1)
|
||||
|
||||
END SUBROUTINE writeCollection
|
||||
|
|
@ -276,29 +277,29 @@ MODULE moduleMeshOutputVTU
|
|||
!Write density
|
||||
WRITE(fileIDMean, "(10X,A)") '<DataArray type="Float64" Name="Density, mean (m^-3)" NumberOfComponents="1">'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '<DataArray type="Float64" Name="Density, deviation (m^-3)" NumberOfComponents="1">'
|
||||
WRITE(fileIDMean, "(6(ES20.6E3))") (outputMean(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6(ES20.6E3))") (outputDeviation(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(6("//fmtReal//"))") (outputMean(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6("//fmtReal//"))") (outputDeviation(n)%density, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean,"(10X,A)") '</DataArray>'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '</DataArray>'
|
||||
!Write velocity
|
||||
WRITE(fileIDMean, "(10X,A)") '<DataArray type="Float64" Name="Velocity, mean (m s^-1)" NumberOfComponents="3">'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '<DataArray type="Float64" Name="Velocity, deviation (m s^-1)" NumberOfComponents="3">'
|
||||
WRITE(fileIDMean, "(6(ES20.6E3))") (outputMean(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6(ES20.6E3))") (outputDeviation(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(6("//fmtReal//"))") (outputMean(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6("//fmtReal//"))") (outputDeviation(n)%velocity, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(10X,A)") '</DataArray>'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '</DataArray>'
|
||||
!Write pressure
|
||||
WRITE(fileIDMean, "(10X,A)") '<DataArray type="Float64" Name="Pressure, mean (Pa)" NumberOfComponents="1">'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '<DataArray type="Float64" Name="Pressure, deviation (Pa)" NumberOfComponents="1">'
|
||||
WRITE(fileIDMean, "(6(ES20.6E3))") (outputMean(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6(ES20.6E3))") (outputDeviation(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(6("//fmtReal//"))") (outputMean(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6("//fmtReal//"))") (outputDeviation(n)%pressure, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(10X,A)") '</DataArray>'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '</DataArray>'
|
||||
!Write temperature
|
||||
WRITE(fileIDMean, "(10X,A)") '<DataArray type="Float64" Name="Temperature, mean (K)" NumberOfComponents="1">'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '<DataArray type="Float64" Name="Temperature, deviation (K)" NumberOfComponents="1">'
|
||||
WRITE(fileIDMean, "(6(ES20.6E3))") (outputMean(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6(ES20.6E3))") (outputDeviation(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(6("//fmtReal//"))") (outputMean(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileIDDeviation,"(6("//fmtReal//"))") (outputDeviation(n)%temperature, n = 1, self%numNodes)
|
||||
WRITE(fileIDMean, "(10X,A)") '</DataArray>'
|
||||
WRITE(fileIDDeviation,"(10X,A)") '</DataArray>'
|
||||
!End node data
|
||||
|
|
@ -310,7 +311,6 @@ MODULE moduleMeshOutputVTU
|
|||
SUBROUTINE printOutputVTU(self)
|
||||
USE moduleMesh
|
||||
USE moduleSpecies
|
||||
USE moduleMeshInoutCommon
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
|
|
@ -322,8 +322,8 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
DO i = 1, nSpecies
|
||||
fileName = formatFileName(prefix, species(i)%obj%name, 'vtu', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (fileID, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeHeader(self%numNodes, self%numCells, fileID)
|
||||
|
||||
|
|
@ -346,7 +346,6 @@ MODULE moduleMeshOutputVTU
|
|||
SUBROUTINE printCollVTU(self)
|
||||
USE moduleMesh
|
||||
USE moduleOutput
|
||||
USE moduleMeshInoutCommon
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
|
|
@ -358,8 +357,8 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
IF (collOutput) THEN
|
||||
fileName = formatFileName(prefix, 'Collisions', 'vtu', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (fileID, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeHeader(self%numNodes, self%numCells, fileID)
|
||||
|
||||
|
|
@ -381,7 +380,6 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
SUBROUTINE printEMVTU(self)
|
||||
USE moduleMesh
|
||||
USE moduleMeshInoutCommon
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
|
|
@ -393,8 +391,8 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
IF (emOutput) THEN
|
||||
fileName = formatFileName(prefix, 'EMField', 'vtu', timeStep)
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (fileID, file = path // folder // '/' // fileName)
|
||||
call informFileCreation(fileName)
|
||||
OPEN (fileID, file = generateFilePath(fileName))
|
||||
|
||||
CALL writeHeader(self%numNodes, self%numCells, fileID)
|
||||
|
||||
|
|
@ -416,8 +414,8 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
SUBROUTINE printAverageVTU(self)
|
||||
USE moduleMesh
|
||||
use moduleOutput
|
||||
USE moduleSpecies
|
||||
USE moduleMeshInoutCommon
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshParticles), INTENT(in):: self
|
||||
|
|
@ -429,12 +427,12 @@ MODULE moduleMeshOutputVTU
|
|||
|
||||
DO i = 1, nSpecies
|
||||
fileNameMean = formatFileName('Average_mean', species(i)%obj%name, 'vtu')
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileNameMean
|
||||
OPEN (fileIDMean, file = path // folder // '/' // fileNameMean)
|
||||
call informFileCreation(fileNameMean)
|
||||
OPEN (fileIDMean, file = generateFilePath(fileNameMean))
|
||||
|
||||
fileNameDeviation = formatFileName('Average_deviation', species(i)%obj%name, 'vtu')
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileNameDeviation
|
||||
OPEN (fileIDDeviation, file = path // folder // '/' // fileNameDeviation)
|
||||
call informFileCreation(fileNameDeviation)
|
||||
OPEN (fileIDDeviation, file = generateFilePath(fileNameDeviation))
|
||||
|
||||
CALL writeHeader(self%numNodes, self%numCells, fileIDMean)
|
||||
CALL writeHeader(self%numNodes, self%numCells, fileIDDeviation)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
all: moduleMesh.o moduleMeshBoundary.o inout.o 3DCart.o 2DCyl.o 2DCart.o 1DRad.o 1DCart.o 0D.o
|
||||
all: moduleMesh.o inout.o 3DCart.o 2DCyl.o 2DCart.o 1DRad.o 1DCart.o 0D.o
|
||||
|
||||
3DCart.o: moduleMesh.o
|
||||
$(MAKE) -C 3DCart all
|
||||
|
|
@ -18,11 +18,12 @@ all: moduleMesh.o moduleMeshBoundary.o inout.o 3DCart.o 2DCyl.o 2DCart.o 1DRad.o
|
|||
0D.o: moduleMesh.o
|
||||
$(MAKE) -C 0D all
|
||||
|
||||
moduleMesh.o: moduleMesh.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
|
||||
moduleMeshBoundary.o: moduleMesh.o moduleMeshBoundary.f90
|
||||
moduleMesh.o: moduleMeshCommon.o moduleMesh.f90
|
||||
$(FC) $(FCFLAGS) -c $(subst .o,.f90,$@) -o $(OBJDIR)/$@
|
||||
$(FC) $(FCFLAGS) -c moduleMesh@elements.f90 -o $(OBJDIR)/moduleMesh@elements.o
|
||||
$(FC) $(FCFLAGS) -c moduleMesh@boundaryParticle.f90 -o $(OBJDIR)/moduleMesh@boundaryParticle.o
|
||||
$(FC) $(FCFLAGS) -c moduleMesh@boundaryEM.f90 -o $(OBJDIR)/moduleMesh@boundaryEM.o
|
||||
$(FC) $(FCFLAGS) -c moduleMesh@surfaces.f90 -o $(OBJDIR)/moduleMesh@surfaces.o
|
||||
|
||||
inout.o: 3DCart.o 2DCyl.o 2DCart.o 1DRad.o 1DCart.o 0D.o
|
||||
$(MAKE) -C inout all
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
161
src/modules/mesh/moduleMesh@boundaryEM.f90
Normal file
161
src/modules/mesh/moduleMesh@boundaryEM.f90
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
submodule(moduleMesh) boundaryEM
|
||||
CONTAINS
|
||||
module function boundaryEMName_to_Index(boundaryName) result(bp)
|
||||
use moduleErrors
|
||||
implicit none
|
||||
|
||||
character(:), allocatable:: boundaryName
|
||||
integer:: bp
|
||||
integer:: b
|
||||
|
||||
bp = 0
|
||||
do b = 1, nBoundariesEM
|
||||
if (boundaryName == boundariesEM(b)%obj%name) then
|
||||
bp = boundariesEM(b)%obj%n
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
if (bp == 0) then
|
||||
call criticalError('Boundary ' // boundaryName // ' not found', 'boundaryEMName_to_Index')
|
||||
|
||||
end if
|
||||
|
||||
end function boundaryEMName_to_Index
|
||||
|
||||
! Initialize Dirichlet boundary condition
|
||||
module SUBROUTINE initDirichlet(self, config, object)
|
||||
use json_module
|
||||
USE moduleRefParam, ONLY: Volt_ref
|
||||
use moduleErrors
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMGeneric), ALLOCATABLE, INTENT(inout):: self
|
||||
type(json_file), intent(inout):: config
|
||||
character(:), allocatable, intent(in):: object
|
||||
REAL(8):: potential
|
||||
logical:: found
|
||||
|
||||
select type(self)
|
||||
type is(boundaryEMDirichlet)
|
||||
call config%get(object // '.potential', potential, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "potential" for Dirichlet boundary condition not found', 'readBoundaryEM')
|
||||
|
||||
end if
|
||||
|
||||
self%potential = potential / Volt_ref
|
||||
|
||||
end select
|
||||
|
||||
end subroutine initDirichlet
|
||||
|
||||
! Initialize Dirichlet boundary condition
|
||||
module subroutine initDirichletTime(self, config, object)
|
||||
use json_module
|
||||
use moduleRefParam, ONLY: Volt_ref, ti_ref
|
||||
use moduleErrors
|
||||
implicit none
|
||||
|
||||
class(boundaryEMGeneric), allocatable, intent(inout):: self
|
||||
type(json_file), intent(inout):: config
|
||||
character(:), allocatable, intent(in):: object
|
||||
real(8):: potential
|
||||
character(:), allocatable:: temporalProfile
|
||||
logical:: found
|
||||
character(:), allocatable:: temporalProfilePath
|
||||
|
||||
select type(self)
|
||||
type is(boundaryEMDirichletTime)
|
||||
call config%get(object // '.potential', potential, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "potential" for Dirichlet Time boundary condition not found', &
|
||||
'readBoundaryEM')
|
||||
|
||||
end if
|
||||
|
||||
call config%get(object // '.temporalProfile', temporalProfile, found)
|
||||
if (.not. found) then
|
||||
call criticalError('Required parameter "temporalProfile" for Dirichlet Time boundary condition not found', &
|
||||
'readBoundaryEM')
|
||||
|
||||
end if
|
||||
temporalProfilePath = path // temporalProfile
|
||||
|
||||
self%potential = potential / Volt_ref
|
||||
|
||||
call self%temporalProfile%init(temporalProfile)
|
||||
|
||||
call self%temporalProfile%convert(1.D0/ti_ref, 1.D0)
|
||||
|
||||
self%update => updateDirichletTime
|
||||
|
||||
end select
|
||||
|
||||
END SUBROUTINE initDirichletTime
|
||||
|
||||
!Apply Dirichlet boundary condition to the poisson equation
|
||||
module SUBROUTINE applyDirichlet(self, vectorF)
|
||||
USE moduleMesh
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMDirichlet), INTENT(in):: self
|
||||
REAL(8), INTENT(inout):: vectorF(:)
|
||||
integer:: n
|
||||
|
||||
DO n = 1, self%nNodes
|
||||
self%nodes(n)%obj%emData%phi = self%potential
|
||||
vectorF(self%nodes(n)%obj%n) = self%nodes(n)%obj%emData%phi
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE applyDirichlet
|
||||
|
||||
!Apply Dirichlet boundary condition with time temporal profile
|
||||
module SUBROUTINE applyDirichletTime(self, vectorF)
|
||||
USE moduleMesh
|
||||
USE moduleCaseParam, ONLY: timeStep, tauMin
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMDirichletTime), INTENT(in):: self
|
||||
REAL(8), INTENT(inout):: vectorF(:)
|
||||
integer:: n
|
||||
|
||||
DO n = 1, self%nNodes
|
||||
self%nodes(n)%obj%emData%phi = self%potential * self%timeFactor
|
||||
vectorF(self%nodes(n)%obj%n) = self%nodes(n)%obj%emData%phi
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE applyDirichletTime
|
||||
|
||||
module subroutine updateDirichletTime(self)
|
||||
implicit none
|
||||
|
||||
class(boundaryEMGeneric), intent(inout):: self
|
||||
|
||||
select type(self)
|
||||
type is(boundaryEMDirichletTime)
|
||||
self%timeFactor = self%temporalProfile%get(DBLE(timeStep)*tauMin)
|
||||
|
||||
end select
|
||||
|
||||
end subroutine updateDirichletTime
|
||||
|
||||
module subroutine boundariesEM_update()
|
||||
implicit none
|
||||
|
||||
integer:: b
|
||||
|
||||
do b = 1, nBoundariesEM
|
||||
if (associated(boundariesEM(b)%obj%update)) then
|
||||
call boundariesEM(b)%obj%update
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end subroutine boundariesEM_update
|
||||
|
||||
end submodule boundaryEM
|
||||
574
src/modules/mesh/moduleMesh@boundaryParticle.f90
Normal file
574
src/modules/mesh/moduleMesh@boundaryParticle.f90
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
!moduleMeshBoundary: Boundary functions for the mesh edges
|
||||
submodule(moduleMesh) boundaryParticle
|
||||
contains
|
||||
! Returns the array index of the boundary based on the name
|
||||
module function boundaryParticleName_to_Index(boundaryName) result(bp)
|
||||
use moduleErrors
|
||||
implicit none
|
||||
|
||||
character(:), allocatable:: boundaryName
|
||||
integer:: bp
|
||||
integer:: b
|
||||
|
||||
bp = 0
|
||||
do b = 1, nBoundariesParticle
|
||||
if (boundaryName == boundariesParticle(b)%obj%name) then
|
||||
bp = boundariesParticle(b)%obj%n
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
if (bp == 0) then
|
||||
call criticalError('Boundary ' // boundaryName // ' not found', 'boundaryParticleName_to_Index')
|
||||
|
||||
end if
|
||||
|
||||
end function boundaryParticleName_to_Index
|
||||
|
||||
module SUBROUTINE reflection(self, edge, part)
|
||||
USE moduleCaseParam
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryReflection), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
!rp = intersection between particle and edge
|
||||
!rpp = final position of particle
|
||||
!vpp = final velocity of particle
|
||||
REAL(8), DIMENSION(1:3):: rp, vpp
|
||||
|
||||
!Reflect particle velocity
|
||||
vpp = part%v - 2.D0*DOT_PRODUCT(part%v, edge%normal)*edge%normal
|
||||
part%v = vpp
|
||||
|
||||
rp = edge%intersection(part%r)
|
||||
|
||||
part%r = 2.D0*(rp - part%r) + part%r
|
||||
|
||||
!particle is assumed to be inside
|
||||
part%n_in = .TRUE.
|
||||
|
||||
END SUBROUTINE reflection
|
||||
|
||||
!Absoption in a surface
|
||||
module SUBROUTINE absorption(self, edge, part)
|
||||
USE moduleCaseParam
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryAbsorption), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
REAL(8):: rpp(1:3) !Position of particle projected to the edge
|
||||
REAL(8):: d !Distance from particle to edge
|
||||
|
||||
rpp = edge%intersection(part%r)
|
||||
|
||||
d = NORM2(rpp - part%r)
|
||||
|
||||
IF (d >= 0.D0) THEN
|
||||
part%weight = part%weight/d
|
||||
|
||||
END IF
|
||||
|
||||
!Assign new position to particle
|
||||
part%r = rpp
|
||||
!Remove particle from the domain
|
||||
part%n_in = .FALSE.
|
||||
|
||||
!Scatter particle in associated volume
|
||||
IF (ASSOCIATED(edge%e1)) THEN
|
||||
CALL edge%e1%scatter(edge%e1%nNodes, part)
|
||||
|
||||
ELSE
|
||||
CALL edge%e2%scatter(edge%e2%nNodes, part)
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE absorption
|
||||
|
||||
!Transparent boundary condition
|
||||
module SUBROUTINE transparent(self, edge, part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryTransparent), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
|
||||
!Removes particle from domain
|
||||
part%n_in = .FALSE.
|
||||
|
||||
END SUBROUTINE transparent
|
||||
|
||||
!Symmetry axis. Reflects particles.
|
||||
!Although this function should never be called, it is set as a reflective boundary
|
||||
!to properly deal with possible particles reaching a corner and selecting this boundary.
|
||||
module SUBROUTINE symmetryAxis(self, edge, part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryAxis), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
|
||||
CALL genericReflection(edge, part)
|
||||
|
||||
END SUBROUTINE symmetryAxis
|
||||
|
||||
! wallTemperature
|
||||
! During the collision, the boundary transfers part of the energy to the incident particle
|
||||
! Init
|
||||
module SUBROUTINE initWallTemperature(boundary, T, c)
|
||||
USE moduleRefParam
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryParticleGeneric), ALLOCATABLE, INTENT(inout):: boundary
|
||||
REAL(8), INTENT(in):: T, c !Wall temperature and specific heat
|
||||
REAL(8):: vTh
|
||||
|
||||
vTh = DSQRT(c * T) / v_ref
|
||||
allocate(boundaryWallTemperature:: boundary)
|
||||
|
||||
select type(boundary)
|
||||
type is(boundaryWallTemperature)
|
||||
boundary%vTh = vTh
|
||||
|
||||
end select
|
||||
|
||||
END SUBROUTINE initWallTemperature
|
||||
|
||||
! Apply
|
||||
module SUBROUTINE wallTemperature(self, edge, part)
|
||||
USE moduleSpecies
|
||||
USE moduleRandom
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryWallTemperature), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
INTEGER:: i
|
||||
|
||||
!Modifies particle velocity according to wall temperature
|
||||
DO i = 1, 3
|
||||
part%v(i) = part%v(i) + self%vTh*randomMaxwellian()
|
||||
|
||||
END DO
|
||||
|
||||
CALL genericReflection(edge, part)
|
||||
|
||||
END SUBROUTINE wallTemperature
|
||||
|
||||
! ionization
|
||||
! An electron will pass through the surface and create a series of ion-electron pairs based on a neutral background
|
||||
!init
|
||||
module SUBROUTINE initIonization(boundary, mImpact, m0, n0, v0, T0, ion, effTime, crossSection, eThreshold, electronSecondary)
|
||||
use moduleRefParam
|
||||
use moduleSpecies
|
||||
use moduleCaseParam
|
||||
use moduleConstParam
|
||||
use moduleErrors, only: criticalError
|
||||
use omp_lib, only: omp_init_lock
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), allocatable, intent(inout):: boundary
|
||||
real(8), intent(in):: mImpact
|
||||
real(8), intent(in):: m0, n0, v0(1:3), T0 !Neutral properties
|
||||
integer, intent(in):: ion
|
||||
real(8), intent(in):: effTime
|
||||
character(:), allocatable, intent(in):: crossSection
|
||||
real(8), intent(in):: eThreshold
|
||||
integer, optional, intent(in):: electronSecondary
|
||||
|
||||
ALLOCATE(boundaryIonization:: boundary)
|
||||
|
||||
SELECT TYPE(boundary)
|
||||
TYPE IS(boundaryIonization)
|
||||
boundary%m0 = m0 / m_ref
|
||||
boundary%n0 = n0 * Vol_ref
|
||||
boundary%v0 = v0 / v_ref
|
||||
boundary%vTh = DSQRT(kb*T0/m0)/v_ref
|
||||
boundary%species => species(ion)%obj
|
||||
IF (PRESENT(electronSecondary)) THEN
|
||||
SELECT TYPE(sp => species(electronSecondary)%obj)
|
||||
TYPE IS(speciesCharged)
|
||||
boundary%electronSecondary => sp
|
||||
|
||||
CLASS DEFAULT
|
||||
CALL criticalError("Species " // sp%name // " chosen for " // &
|
||||
"secondary electron is not a charged species", 'initIonization')
|
||||
|
||||
END SELECT
|
||||
|
||||
ELSE
|
||||
boundary%electronSecondary => NULL()
|
||||
|
||||
END IF
|
||||
boundary%effectiveTime = effTime / ti_ref
|
||||
CALL boundary%crossSection%init(crossSection)
|
||||
CALL boundary%crossSection%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
||||
boundary%eThreshold = eThreshold*eV2J/(m_ref*v_ref**2)
|
||||
boundary%deltaV = DSQRT(boundary%eThreshold/mImpact)
|
||||
|
||||
boundary%update => ionization_resetTally
|
||||
boundary%print => ionization_print
|
||||
|
||||
boundary%tally = 0
|
||||
call omp_init_lock(boundary%tally_lock)
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE initIonization
|
||||
|
||||
! Apply
|
||||
module SUBROUTINE ionization(self, edge, part)
|
||||
USE moduleList
|
||||
USE moduleSpecies
|
||||
USE moduleMesh
|
||||
USE moduleRefParam
|
||||
USE moduleRandom
|
||||
USE moduleMath
|
||||
use omp_lib, only: omp_set_lock, omp_unset_lock
|
||||
IMPLICIT NONE
|
||||
|
||||
class(boundaryIonization), intent(inout):: self
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
REAL(8):: vRel, eRel, mRel !relative velocity, energy and mass
|
||||
INTEGER:: nIonizations !Number of ionizations based on eRel
|
||||
REAL(8):: pIonization !Probability of ionization of each event
|
||||
INTEGER:: p
|
||||
REAL(8):: v0(1:3) !random velocity of neutral
|
||||
TYPE(particle), POINTER:: newElectron
|
||||
TYPE(particle), POINTER:: newIon
|
||||
|
||||
mRel = reducedMass(self%m0, part%species%m)
|
||||
vRel = SUM(DABS(part%v-self%v0))
|
||||
eRel = mRel*vRel**2*5.D-1
|
||||
|
||||
!Maximum number of possible ionizations based on relative energy
|
||||
nIonizations = FLOOR(eRel/self%eThreshold)
|
||||
|
||||
DO p = 1, nIonizations
|
||||
!Get probability of ionization
|
||||
pIonization = 1.D0 - DEXP(-self%n0*self%crossSection%get(eRel)*vRel*self%effectiveTime/REAL(nIonizations))
|
||||
|
||||
!If a random number is below the probability of ionization, create new pair of ion-electron
|
||||
IF (random() < pIonization) THEN
|
||||
!Assign random velocity to the neutral
|
||||
v0(1) = self%v0(1) + self%vTh*randomMaxwellian()
|
||||
v0(2) = self%v0(2) + self%vTh*randomMaxwellian()
|
||||
v0(3) = self%v0(3) + self%vTh*randomMaxwellian()
|
||||
|
||||
!Allocates the new particles
|
||||
ALLOCATE(newElectron)
|
||||
ALLOCATE(newIon)
|
||||
|
||||
IF (ASSOCIATED(self%electronSecondary)) THEN
|
||||
newElectron%species => self%electronSecondary
|
||||
|
||||
ELSE
|
||||
newElectron%species => part%species
|
||||
|
||||
END IF
|
||||
newIon%species => self%species
|
||||
|
||||
newElectron%v = v0 + (1.D0 + self%deltaV*v0/NORM2(v0))
|
||||
newIon%v = v0
|
||||
|
||||
newElectron%r = edge%randPos()
|
||||
newIon%r = newElectron%r
|
||||
|
||||
IF (ASSOCIATED(edge%e1)) THEN
|
||||
newElectron%cell = edge%e1%n
|
||||
|
||||
ELSEIF (ASSOCIATED(edge%e2)) THEN
|
||||
newElectron%cell = edge%e2%n
|
||||
|
||||
END IF
|
||||
newIon%cell = newElectron%cell
|
||||
|
||||
newElectron%Xi = mesh%cells(part%cell)%obj%phy2log(newElectron%r)
|
||||
newIon%Xi = newElectron%Xi
|
||||
|
||||
newElectron%weight = part%weight
|
||||
newIon%weight = newElectron%weight
|
||||
|
||||
newElectron%n_in = .TRUE.
|
||||
newIon%n_in = .TRUE.
|
||||
|
||||
!Add particles to list
|
||||
CALL partSurfaces%setLock()
|
||||
CALL partSurfaces%add(newElectron)
|
||||
CALL partSurfaces%add(newIon)
|
||||
CALL partSurfaces%unsetLock()
|
||||
|
||||
!Electron loses energy due to ionization
|
||||
eRel = eRel - self%eThreshold
|
||||
vRel = 2.D0*DSQRT(eRel)/mRel
|
||||
|
||||
!Reduce number of possible ionizations
|
||||
nIonizations = nIonizations - 1
|
||||
|
||||
! Increase the tally
|
||||
call omp_set_lock(self%tally_lock)
|
||||
self%tally = self%tally + 1
|
||||
call omp_unset_lock(self%tally_lock)
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
!Removes ionizing electron regardless the number of pair created
|
||||
part%n_in = .FALSE.
|
||||
|
||||
END SUBROUTINE ionization
|
||||
|
||||
! Update
|
||||
subroutine ionization_resetTally(self)
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), intent(inout):: self
|
||||
|
||||
select type(self)
|
||||
type is(boundaryIonization)
|
||||
self%tally = 0
|
||||
|
||||
end select
|
||||
|
||||
end subroutine ionization_resetTally
|
||||
|
||||
! Print
|
||||
subroutine ionization_print(self, fileID)
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), intent(inout):: self
|
||||
integer, intent(in):: fileID
|
||||
|
||||
write(fileID, '(A)') self%name
|
||||
select type(self)
|
||||
type is(boundaryIonization)
|
||||
write(fileID, '(A)') 'Number of successful ionization events per iteration'
|
||||
write(fileID, '('//fmtInt//')') self%tally
|
||||
|
||||
end select
|
||||
|
||||
end subroutine ionization_print
|
||||
|
||||
! quasiNeutrality
|
||||
! Maintains n_incident = n_rest by modifying the reflection parameter of the edge.
|
||||
! Init
|
||||
module subroutine initQuasiNeutrality(boundary, s_incident)
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), allocatable, intent(inout):: boundary
|
||||
integer, intent(in):: s_incident
|
||||
|
||||
allocate(boundaryQuasiNeutrality:: boundary)
|
||||
|
||||
select type(boundary)
|
||||
type is(boundaryQuasiNeutrality)
|
||||
allocate(boundary%edges(0))
|
||||
|
||||
boundary%s_incident = s_incident
|
||||
|
||||
boundary%update => quasiNeutrality_update
|
||||
boundary%print => quasiNeutrality_print
|
||||
|
||||
end select
|
||||
|
||||
end subroutine initQuasiNeutrality
|
||||
|
||||
! Apply
|
||||
module subroutine quasiNeutrality(self, edge, part)
|
||||
use moduleRandom
|
||||
implicit none
|
||||
|
||||
class(boundaryQuasiNeutrality), intent(inout):: self
|
||||
class(meshEdge), intent(inout):: edge
|
||||
class(particle), intent(inout):: part
|
||||
|
||||
if (random() <= self%alpha(edge%n)) then
|
||||
call genericReflection(edge, part)
|
||||
|
||||
else
|
||||
call genericTransparent(edge, part)
|
||||
|
||||
end if
|
||||
|
||||
end subroutine quasiNeutrality
|
||||
|
||||
! Update
|
||||
subroutine quasiNeutrality_update(self)
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), intent(inout):: self
|
||||
integer:: e, n, s
|
||||
integer, allocatable:: nodes(:)
|
||||
class(meshEdge), pointer:: edge
|
||||
real(8), allocatable:: density_nodes(:)
|
||||
class(meshNode), pointer:: node
|
||||
real(8):: density_incident, density_rest
|
||||
real(8):: alpha
|
||||
|
||||
select type(self)
|
||||
type is(boundaryQuasiNeutrality)
|
||||
do e = 1, size(self%edges)
|
||||
edge => mesh%edges(e)%obj
|
||||
|
||||
density_incident = 0.d0
|
||||
density_rest = 0.d0
|
||||
|
||||
nodes = edge%getNodes(edge%nNodes)
|
||||
allocate(density_nodes(1:edge%nNodes))
|
||||
do s = 1, nSpecies
|
||||
do n = 1, edge%nNodes
|
||||
node => mesh%nodes(n)%obj
|
||||
density_nodes(n) = node%output(s)%den
|
||||
|
||||
end do
|
||||
|
||||
if (s == self%s_incident) then
|
||||
density_incident = edge%gatherF(edge%centerXi(), edge%nNodes, density_nodes)
|
||||
|
||||
else
|
||||
density_rest = density_rest + edge%gatherF(edge%centerXi(), edge%nNodes, density_nodes)
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
! Correction for this time step
|
||||
if (density_rest > 1.0d-10) then
|
||||
! If there is a rest population, correct
|
||||
alpha = 1.d0 - density_incident/density_rest
|
||||
|
||||
else
|
||||
! If not, alpha is assumed unchaged
|
||||
alpha = 0.d0
|
||||
|
||||
end if
|
||||
|
||||
! Apply correction with a factor of 0.1 to avoid fast changes
|
||||
self%alpha(edge%n) = self%alpha(edge%n) + 1.0d-2 * alpha
|
||||
|
||||
! Limit alpha between 0 and 1
|
||||
self%alpha(edge%n) = min(self%alpha(edge%n), 1.d0)
|
||||
self%alpha(edge%n) = max(self%alpha(edge%n), 0.d0)
|
||||
|
||||
deallocate(density_nodes)
|
||||
|
||||
end do
|
||||
|
||||
end select
|
||||
|
||||
end subroutine quasiNeutrality_update
|
||||
|
||||
! Print output
|
||||
subroutine quasiNeutrality_print(self, fileID)
|
||||
implicit none
|
||||
|
||||
class(boundaryParticleGeneric), intent(inout):: self
|
||||
integer, intent(in):: fileID
|
||||
integer:: e
|
||||
|
||||
write(fileID, '(A)') self%name
|
||||
select type(self)
|
||||
type is(boundaryQuasiNeutrality)
|
||||
write(fileID, '(A,",",A)') '"Edge id"', '"alpha"'
|
||||
do e = 1, size(self%edges)
|
||||
write(fileID, '('//fmtColInt//','//fmtReal//')') self%edges(e)%obj%n, self%alpha(self%edges(e)%obj%n)
|
||||
|
||||
end do
|
||||
|
||||
end select
|
||||
|
||||
end subroutine quasiNeutrality_print
|
||||
|
||||
! Generic boundary conditions for internal use
|
||||
! reflection
|
||||
module subroutine genericReflection(edge, part)
|
||||
use moduleCaseParam
|
||||
use moduleSpecies
|
||||
implicit none
|
||||
|
||||
class(meshEdge), intent(inout):: edge
|
||||
class(particle), intent(inout):: part
|
||||
!rp = intersection between particle and edge
|
||||
!rpp = final position of particle
|
||||
!vpp = final velocity of particle
|
||||
real(8), dimension(1:3):: rp, vpp
|
||||
|
||||
!Reflect particle velocity
|
||||
vpp = part%v - 2.D0*dot_product(part%v, edge%normal)*edge%normal
|
||||
part%v = vpp
|
||||
|
||||
rp = edge%intersection(part%r)
|
||||
|
||||
part%r = 2.D0*(rp - part%r) + part%r
|
||||
|
||||
!particle is assumed to be inside
|
||||
part%n_in = .TRUE.
|
||||
|
||||
end subroutine genericReflection
|
||||
|
||||
! transparent
|
||||
module subroutine genericTransparent(edge, part)
|
||||
use moduleSpecies
|
||||
implicit none
|
||||
|
||||
class(meshEdge), intent(inout):: edge
|
||||
class(particle), intent(inout):: part
|
||||
|
||||
!Removes particle from domain
|
||||
part%n_in = .FALSE.
|
||||
|
||||
end subroutine genericTransparent
|
||||
|
||||
! Updates the boundary condition values when %update procedure is associated
|
||||
module subroutine boundariesParticle_update()
|
||||
implicit none
|
||||
|
||||
integer:: b
|
||||
|
||||
do b = 1, nBoundariesParticle
|
||||
if (associated(boundariesParticle(b)%obj%update)) then
|
||||
call boundariesParticle(b)%obj%update
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end subroutine boundariesParticle_update
|
||||
|
||||
! Writes the output into the Step_XXXXX_boundaryParticles file when the %print procedure is associated
|
||||
module subroutine boundariesParticle_write()
|
||||
use moduleCaseparam, only: timeStep
|
||||
use moduleOutput, only:fileID_boundaryParticle, formatFileName, informFileCreation
|
||||
implicit none
|
||||
|
||||
integer:: b
|
||||
character(:), allocatable:: fileName
|
||||
|
||||
if (boundaryParticleOutput) then
|
||||
fileName = formatFileName(prefix, 'boundariesParticle', 'csv', timeStep)
|
||||
call informFileCreation(fileName)
|
||||
open(fileID_boundaryParticle, file = path // folder // '/' // fileName)
|
||||
|
||||
do b = 1, nBoundariesParticle
|
||||
if (associated(boundariesParticle(b)%obj%print)) then
|
||||
call boundariesParticle(b)%obj%print(fileID_boundaryParticle)
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
close(fileID_boundaryParticle)
|
||||
|
||||
end if
|
||||
|
||||
end subroutine boundariesParticle_write
|
||||
|
||||
end submodule boundaryParticle
|
||||
933
src/modules/mesh/moduleMesh@elements.f90
Normal file
933
src/modules/mesh/moduleMesh@elements.f90
Normal file
|
|
@ -0,0 +1,933 @@
|
|||
submodule(moduleMesh) elements
|
||||
CONTAINS
|
||||
!Reset the output of node
|
||||
PURE module SUBROUTINE resetOutput(self)
|
||||
USE moduleSpecies
|
||||
USE moduleOutput
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshNode), INTENT(inout):: self
|
||||
INTEGER:: k
|
||||
|
||||
DO k = 1, nSpecies
|
||||
self%output(k)%den = 0.D0
|
||||
self%output(k)%mom = 0.D0
|
||||
self%output(k)%tensorS = 0.D0
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE resetOutput
|
||||
|
||||
module subroutine meshNodePointer_add(self, node)
|
||||
implicit none
|
||||
|
||||
class(meshNodePointer), allocatable, intent(inout):: self(:)
|
||||
integer, intent(in):: node
|
||||
integer:: n
|
||||
logical:: inArray
|
||||
type(meshNodePointer):: nodeToAdd
|
||||
|
||||
|
||||
nodeToAdd%obj => mesh%nodes(node)%obj
|
||||
inArray = .false.
|
||||
! I cannot use the procedure 'any' for this
|
||||
do n = 1 , size(self)
|
||||
IF (self(n) == nodeToAdd) THEN
|
||||
! Node already in array
|
||||
inArray = .true.
|
||||
exit
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
if (.not. inArray) then
|
||||
! If not, add element to array of nodes
|
||||
self = [self, nodeToAdd]
|
||||
|
||||
end if
|
||||
|
||||
end subroutine meshNodePointer_add
|
||||
|
||||
module function meshNodePointer_equal_type_type(self, other) result(isEqual)
|
||||
implicit none
|
||||
|
||||
class(meshNodePointer), intent(in):: self, other
|
||||
logical:: isEqual
|
||||
|
||||
isEqual = self%obj%n == other%obj%n
|
||||
|
||||
end function meshNodePointer_equal_type_type
|
||||
|
||||
module function meshNodePointer_equal_type_int(self, other) result(isEqual)
|
||||
implicit none
|
||||
|
||||
class(meshNodePointer), intent(in):: self
|
||||
integer, intent(in):: other
|
||||
logical:: isEqual
|
||||
|
||||
isEqual = self%obj%n == other
|
||||
|
||||
end function meshNodePointer_equal_type_int
|
||||
|
||||
module function meshEdgePointer_equal_type_type(self, other) result(isEqual)
|
||||
implicit none
|
||||
|
||||
class(meshEdgePointer), intent(in):: self, other
|
||||
logical:: isEqual
|
||||
|
||||
isEqual = self%obj%n == other%obj%n
|
||||
|
||||
end function meshEdgePointer_equal_type_type
|
||||
|
||||
module subroutine meshEdgePointer_add(self, edge)
|
||||
implicit none
|
||||
|
||||
class(meshEdgePointer), allocatable, intent(inout):: self(:)
|
||||
integer, intent(in):: edge
|
||||
integer:: n
|
||||
logical:: inArray
|
||||
type(meshEdgePointer):: edgeToAdd
|
||||
|
||||
|
||||
edgeToAdd%obj => mesh%edges(edge)%obj
|
||||
inArray = .false.
|
||||
! I cannot use the procedure 'any' for this
|
||||
do n = 1 , size(self)
|
||||
IF (self(n) == edgeToAdd) THEN
|
||||
! Node already in array
|
||||
inArray = .true.
|
||||
exit
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
if (.not. inArray) then
|
||||
! If not, add element to array of nodes
|
||||
self = [self, edgeToAdd]
|
||||
|
||||
end if
|
||||
|
||||
end subroutine meshEdgePointer_add
|
||||
|
||||
module function meshEdgePointer_equal_type_int(self, other) result(isEqual)
|
||||
implicit none
|
||||
|
||||
class(meshEdgePointer), intent(in):: self
|
||||
integer, intent(in):: other
|
||||
logical:: isEqual
|
||||
|
||||
isEqual = self%obj%n == other
|
||||
|
||||
end function meshEdgePointer_equal_type_int
|
||||
|
||||
!Constructs the global K matrix
|
||||
module SUBROUTINE constructGlobalK(self)
|
||||
use moduleErrors, only: criticalError
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshParticles), INTENT(inout):: self
|
||||
INTEGER:: c
|
||||
INTEGER, ALLOCATABLE:: nodes(:)
|
||||
REAL(8), ALLOCATABLE:: localK(:,:)
|
||||
INTEGER:: i, j
|
||||
integer:: n, b, ni
|
||||
INTEGER:: info
|
||||
EXTERNAL:: dgetrf
|
||||
|
||||
DO c = 1, self%numCells
|
||||
associate(nNodes => self%cells(c)%obj%nNodes)
|
||||
ALLOCATE(nodes(1:nNodes))
|
||||
ALLOCATE(localK(1:nNodes, 1:nNodes))
|
||||
nodes = self%cells(c)%obj%getNodes(nNodes)
|
||||
localK = self%cells(c)%obj%elemK(nNodes)
|
||||
|
||||
DO i = 1, nNodes
|
||||
DO j = 1, nNodes
|
||||
self%K(nodes(i), nodes(j)) = self%K(nodes(i), nodes(j)) + localK(i, j)
|
||||
|
||||
END DO
|
||||
|
||||
END DO
|
||||
|
||||
DEALLOCATE(nodes, localK)
|
||||
|
||||
end associate
|
||||
|
||||
END DO
|
||||
|
||||
! Modify K matrix due to EM boundary conditions
|
||||
DO b = 1, nBoundariesEM
|
||||
SELECT TYPE(boundary => boundariesEM(b)%obj)
|
||||
TYPE IS(boundaryEMDirichlet)
|
||||
DO n = 1, boundary%nNodes
|
||||
ni = boundary%nodes(n)%obj%n
|
||||
self%K(ni, :) = 0.D0
|
||||
self%K(ni, ni) = 1.D0
|
||||
|
||||
END DO
|
||||
|
||||
TYPE IS(boundaryEMDirichletTime)
|
||||
DO n = 1, boundary%nNodes
|
||||
ni = boundary%nodes(n)%obj%n
|
||||
self%K(ni, :) = 0.D0
|
||||
self%K(ni, ni) = 1.D0
|
||||
|
||||
END DO
|
||||
|
||||
END SELECT
|
||||
|
||||
END DO
|
||||
|
||||
!Compute the PLU factorization of K once boundary conditions have been read
|
||||
CALL dgetrf(self%numNodes, self%numNodes, self%K, self%numNodes, self%IPIV, info)
|
||||
IF (info /= 0) THEN
|
||||
CALL criticalError('Factorization of K matrix failed', 'constructGlobalK')
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE constructGlobalK
|
||||
|
||||
! Gather the value of valNodes at position Xi of an edge
|
||||
pure module function gatherF_edge_scalar(self, Xi, nNodes, valNodes) RESULT(f)
|
||||
implicit none
|
||||
|
||||
class(meshEdge), intent(in):: self
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8), intent(in):: valNodes(1:nNodes)
|
||||
real(8):: f
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = self%fPsi(Xi, nNodes)
|
||||
f = dot_product(fPsi, valNodes)
|
||||
|
||||
end function gatherF_edge_scalar
|
||||
|
||||
!Gather the value of valNodes (scalar) at position Xi
|
||||
PURE module FUNCTION gatherF_cell_scalar(self, Xi, nNodes, valNodes) RESULT(f)
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8), INTENT(in):: valNodes(1:nNodes)
|
||||
REAL(8):: f
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = self%fPsi(Xi, nNodes)
|
||||
f = DOT_PRODUCT(fPsi, valNodes)
|
||||
|
||||
END FUNCTION gatherF_cell_scalar
|
||||
|
||||
!Gather the value of valNodes (array) at position Xi
|
||||
PURE module FUNCTION gatherF_cell_array(self, Xi, nNodes, valNodes) RESULT(f)
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8), INTENT(in):: valNodes(1:nNodes, 1:3)
|
||||
REAL(8):: f(1:3)
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = self%fPsi(Xi, nNodes)
|
||||
f = MATMUL(fPsi, valNodes)
|
||||
|
||||
END FUNCTION gatherF_cell_array
|
||||
|
||||
!Gather the spatial derivative of valNodes (scalar) at position Xi
|
||||
PURE module FUNCTION gatherDF_cell_scalar(self, Xi, nNodes, valNodes) RESULT(df)
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: Xi(1:3)
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
REAL(8), INTENT(in):: valNodes(1:nNodes)
|
||||
REAL(8):: df(1:3)
|
||||
REAL(8):: dPsi(1:3, 1:nNodes)
|
||||
REAL(8):: pDer(1:3,1:3)
|
||||
REAL(8):: dPsiR(1:3, 1:nNodes)
|
||||
REAL(8):: invJ(1:3, 1:3), detJ
|
||||
|
||||
dPsi = self%dPsi(Xi, nNodes)
|
||||
pDer = self%partialDer(nNodes, dPsi)
|
||||
detJ = self%detJac(pDer)
|
||||
invJ = self%invJac(pDer)
|
||||
dPsiR = MATMUL(invJ, dPsi)/detJ
|
||||
df = (/ DOT_PRODUCT(dPsiR(1,:), valNodes), &
|
||||
DOT_PRODUCT(dPsiR(2,:), valNodes), &
|
||||
DOT_PRODUCT(dPsiR(3,:), valNodes) /)
|
||||
|
||||
END FUNCTION gatherDF_cell_scalar
|
||||
|
||||
!Scatters particle properties into cell nodes
|
||||
module SUBROUTINE scatter(self, nNodes, part)
|
||||
USE moduleMath
|
||||
USE moduleSpecies
|
||||
USE OMP_LIB
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell), INTENT(inout):: self
|
||||
INTEGER, INTENT(in):: nNodes
|
||||
CLASS(particle), INTENT(in):: part
|
||||
REAL(8):: fPsi(1:nNodes)
|
||||
INTEGER:: cellNodes(1:nNodes)
|
||||
REAL(8):: tensorS(1:3, 1:3)
|
||||
INTEGER:: sp
|
||||
INTEGER:: i
|
||||
CLASS(meshNode), POINTER:: node
|
||||
REAL(8):: pFraction !Particle fraction
|
||||
|
||||
cellNodes = self%getNodes(nNodes)
|
||||
fPsi = self%fPsi(part%Xi, nNodes)
|
||||
|
||||
tensorS = outerProduct(part%v, part%v)
|
||||
|
||||
sp = part%species%n
|
||||
|
||||
DO i = 1, nNodes
|
||||
node => mesh%nodes(cellNodes(i))%obj
|
||||
pFraction = fPsi(i)*part%weight
|
||||
CALL OMP_SET_LOCK(node%lock)
|
||||
node%output(sp)%den = node%output(sp)%den + pFraction
|
||||
node%output(sp)%mom(:) = node%output(sp)%mom(:) + pFraction*part%v(:)
|
||||
node%output(sp)%tensorS(:,:) = node%output(sp)%tensorS(:,:) + pFraction*tensorS
|
||||
CALL OMP_UNSET_LOCK(node%lock)
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE scatter
|
||||
|
||||
!Find next cell for particle
|
||||
RECURSIVE SUBROUTINE findCell(self, part, oldCell)
|
||||
USE moduleSpecies
|
||||
USE moduleErrors
|
||||
USE OMP_LIB
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshCell), INTENT(inout):: self
|
||||
CLASS(particle), INTENT(inout), TARGET:: part
|
||||
CLASS(meshCell), OPTIONAL, INTENT(in):: oldCell
|
||||
REAL(8):: Xi(1:3)
|
||||
CLASS(meshElement), POINTER:: neighbourElement
|
||||
INTEGER:: sp
|
||||
|
||||
Xi = self%phy2log(part%r)
|
||||
!Checks if particle is inside 'self' cell
|
||||
IF (self%inside(Xi)) THEN
|
||||
part%cell = self%n
|
||||
part%Xi = Xi
|
||||
part%n_in = .TRUE.
|
||||
!Assign particle to listPart_in
|
||||
IF (listInCells) THEN
|
||||
CALL OMP_SET_LOCK(self%lock)
|
||||
sp = part%species%n
|
||||
CALL self%listPart_in(sp)%add(part)
|
||||
self%totalWeight(sp) = self%totalWeight(sp) + part%weight
|
||||
CALL OMP_UNSET_LOCK(self%lock)
|
||||
|
||||
END IF
|
||||
|
||||
ELSE
|
||||
!If not, searches for a neighbour and repeats the process.
|
||||
CALL self%neighbourElement(Xi, neighbourElement)
|
||||
!Defines the next step
|
||||
SELECT TYPE(neighbourElement)
|
||||
CLASS IS(meshCell)
|
||||
!Particle moved to new cell, repeat find procedure
|
||||
CALL neighbourElement%findCell(part, self)
|
||||
|
||||
CLASS IS (meshEdge)
|
||||
!Particle encountered a surface, apply boundary
|
||||
CALL neighbourElement%boundariesParticle(part%species%n)%obj%apply(neighbourElement,part)
|
||||
|
||||
!If particle is still inside the domain, call findCell
|
||||
IF (part%n_in) THEN
|
||||
IF(PRESENT(oldCell)) THEN
|
||||
CALL self%findCell(part, oldCell)
|
||||
|
||||
ELSE
|
||||
CALL self%findCell(part)
|
||||
|
||||
END IF
|
||||
END IF
|
||||
|
||||
CLASS DEFAULT
|
||||
WRITE (*, "(A, I6)") "Element = ", self%n
|
||||
CALL criticalError("No connectivity found for element", "findCell")
|
||||
|
||||
END SELECT
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE findCell
|
||||
|
||||
!If Coll and Particle are the same, simply copy the part%cell into part%cellColl
|
||||
SUBROUTINE findCellSameMesh(part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(particle), INTENT(inout):: part
|
||||
|
||||
part%cellColl = part%cell
|
||||
|
||||
END SUBROUTINE findCellSameMesh
|
||||
|
||||
!TODO: try to combine this with the findCell for a regular mesh
|
||||
!Find the volume in which particle reside in the mesh for collisions
|
||||
!No boundary interaction taken into account
|
||||
SUBROUTINE findCellCollMesh(part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(particle), INTENT(inout):: part
|
||||
LOGICAL:: found
|
||||
CLASS(meshCell), POINTER:: cell
|
||||
REAL(8), DIMENSION(1:3):: Xi
|
||||
CLASS(meshElement), POINTER:: neighbourElement
|
||||
INTEGER:: sp
|
||||
|
||||
found = .FALSE.
|
||||
|
||||
cell => meshColl%cells(part%cellColl)%obj
|
||||
DO WHILE(.NOT. found)
|
||||
Xi = cell%phy2log(part%r)
|
||||
IF (cell%inside(Xi)) THEN
|
||||
part%cellColl = cell%n
|
||||
IF (listInCells) THEN
|
||||
CALL OMP_SET_LOCK(cell%lock)
|
||||
sp = part%species%n
|
||||
CALL cell%listPart_in(sp)%add(part)
|
||||
cell%totalWeight(sp) = cell%totalWeight(sp) + part%weight
|
||||
CALL OMP_UNSET_LOCK(cell%lock)
|
||||
|
||||
END IF
|
||||
found = .TRUE.
|
||||
|
||||
ELSE
|
||||
CALL cell%neighbourElement(Xi, neighbourElement)
|
||||
SELECT TYPE(neighbourElement)
|
||||
CLASS IS(meshCell)
|
||||
!Try next element
|
||||
cell => neighbourElement
|
||||
|
||||
CLASS DEFAULT
|
||||
!Should never happend, but just in case, stops loops
|
||||
found = .TRUE.
|
||||
|
||||
END SELECT
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE findCellCollMesh
|
||||
|
||||
!Returns index of volume associated to a position (if any)
|
||||
!If no voulme is found, returns 0
|
||||
!WARNING: This function is slow and should only be used in initialization phase
|
||||
FUNCTION findCellBrute(self, r) RESULT(nVol)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(in):: self
|
||||
REAL(8), DIMENSION(1:3), INTENT(in):: r
|
||||
INTEGER:: nVol
|
||||
INTEGER:: e
|
||||
REAL(8), DIMENSION(1:3):: Xi
|
||||
|
||||
!Inits RESULT
|
||||
nVol = 0
|
||||
|
||||
DO e = 1, self%numCells
|
||||
Xi = self%cells(e)%obj%phy2log(r)
|
||||
IF(self%cells(e)%obj%inside(Xi)) THEN
|
||||
nVol = self%cells(e)%obj%n
|
||||
EXIT
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
END FUNCTION findCellBrute
|
||||
|
||||
!Computes collisions in element
|
||||
SUBROUTINE doCollisions(self)
|
||||
USE moduleCollisions
|
||||
USE moduleSpecies
|
||||
USE moduleList
|
||||
use moduleRefParam
|
||||
USE moduleRandom
|
||||
USE moduleOutput
|
||||
USE moduleMath
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshGeneric), INTENT(inout), TARGET:: self
|
||||
INTEGER:: e
|
||||
CLASS(meshCell), POINTER:: cell
|
||||
INTEGER:: k, i, j
|
||||
INTEGER:: nPart_i, nPart_j, nPart!Number of particles inside the cell
|
||||
REAL(8):: pMax !Maximum probability of collision
|
||||
INTEGER:: nColl
|
||||
TYPE(pointerArray), ALLOCATABLE:: partTemp_i(:), partTemp_j(:)
|
||||
TYPE(particle), POINTER:: part_i, part_j
|
||||
INTEGER:: n, c
|
||||
REAL(8):: vRel, rMass, eRel
|
||||
REAL(8):: sigmaVrelTotal
|
||||
REAL(8), ALLOCATABLE:: sigmaVrel(:), probabilityColl(:)
|
||||
REAL(8):: rnd_real !Random number for collision
|
||||
INTEGER:: rnd_int !Random number for collision
|
||||
|
||||
IF (MOD(timeStep, everyColl) == 0) THEN
|
||||
!Collisions need to be performed in this iteration
|
||||
!$OMP DO SCHEDULE(DYNAMIC) PRIVATE(part_i, part_j, partTemp_i, partTemp_j)
|
||||
DO e=1, self%numCells
|
||||
|
||||
cell => self%cells(e)%obj
|
||||
|
||||
!TODO: Simplify this, to many sublevels
|
||||
!Iterate over the number of pairs
|
||||
DO k = 1, nCollPairs
|
||||
!Reset tally of collisions
|
||||
IF (collOutput) THEN
|
||||
cell%tallyColl(k)%tally = 0
|
||||
|
||||
END IF
|
||||
|
||||
IF (interactionMatrix(k)%amount > 0) THEN
|
||||
!Select the species for the collision pair
|
||||
i = interactionMatrix(k)%sp_i%n
|
||||
j = interactionMatrix(k)%sp_j%n
|
||||
|
||||
!Number of particles per species in the collision pair
|
||||
nPart_i = cell%listPart_in(i)%amount
|
||||
nPart_j = cell%listPart_in(j)%amount
|
||||
|
||||
IF (nPart_i > 0 .AND. nPart_j > 0) THEN
|
||||
!Total number of particles for the collision pair
|
||||
nPart = nPart_i + nPart_j
|
||||
|
||||
!Resets the number of collisions in the cell
|
||||
nColl = 0
|
||||
|
||||
!Probability of collision for pair i-j
|
||||
pMax = (cell%totalWeight(i) + cell%totalWeight(j))*cell%sigmaVrelMax(k)*tauColl/cell%volume
|
||||
|
||||
!Number of collisions in the cell
|
||||
nColl = NINT(REAL(nPart)*pMax*0.5D0)
|
||||
|
||||
!Converts the list of particles to an array for easy access
|
||||
IF (nColl > 0) THEN
|
||||
partTemp_i = cell%listPart_in(i)%convert2Array()
|
||||
partTemp_j = cell%listPart_in(j)%convert2Array()
|
||||
|
||||
END IF
|
||||
|
||||
DO n = 1, nColl
|
||||
!Select random particles
|
||||
part_i => NULL()
|
||||
part_j => NULL()
|
||||
rnd_int = random(1, nPart_i)
|
||||
part_i => partTemp_i(rnd_int)%part
|
||||
rnd_int = random(1, nPart_j)
|
||||
part_j => partTemp_j(rnd_int)%part
|
||||
!If they are the same particle, skip
|
||||
!TODO: Maybe try to improve this
|
||||
IF (ASSOCIATED(part_i, part_j)) THEN
|
||||
CYCLE
|
||||
|
||||
END IF
|
||||
|
||||
!If particles do not belong to the species, skip collision
|
||||
!This can happen, for example, if particle has been previously ionized or removed
|
||||
!TODO: Try to find a way to not lose these collisions. Maybe check new 'k' and use that for the collision?
|
||||
IF (part_i%species%n /= i .OR. &
|
||||
part_j%species%n /= j) THEN
|
||||
CYCLE
|
||||
|
||||
END IF
|
||||
!Obtain the cross sections for the different processes
|
||||
!TODO: From here it might be a procedure in interactionMatrix
|
||||
vRel = NORM2(part_i%v-part_j%v)
|
||||
rMass = reducedMass(part_i%weight*part_i%species%m, part_j%weight*part_j%species%m)
|
||||
eRel = rMass*vRel**2
|
||||
CALL interactionMatrix(k)%getSigmaVrel(vRel, eRel, sigmaVrelTotal, sigmaVrel)
|
||||
|
||||
!Update maximum sigma*v_rel
|
||||
IF (sigmaVrelTotal > cell%sigmaVrelMax(k)) THEN
|
||||
cell%sigmaVrelMax(k) = sigmaVrelTotal
|
||||
|
||||
END IF
|
||||
|
||||
ALLOCATE(probabilityColl(0:interactionMatrix(k)%amount))
|
||||
probabilityColl = 0.0
|
||||
DO c = 1, interactionMatrix(k)%amount
|
||||
probabilityColl(c) = sigmaVrel(c)/cell%sigmaVrelMax(k) + SUM(probabilityColl(0:c-1))
|
||||
|
||||
END DO
|
||||
|
||||
!Selects random number between 0 and 1
|
||||
rnd_real = random()
|
||||
|
||||
!If the random number is below the total probability of collision, collide particles
|
||||
IF (rnd_real < sigmaVrelTotal / cell%sigmaVrelMax(k)) THEN
|
||||
|
||||
!Loop over collisions
|
||||
DO c = 1, interactionMatrix(k)%amount
|
||||
IF (rnd_real <= probabilityColl(c)) THEN
|
||||
!$OMP CRITICAL
|
||||
CALL interactionMatrix(k)%collisions(c)%obj%collide(part_i, part_j, vRel)
|
||||
!$OMP END CRITICAL
|
||||
|
||||
!If collisions are gonna be output, count the collision
|
||||
IF (collOutput) THEN
|
||||
cell%tallyColl(k)%tally(c) = cell%tallyColl(k)%tally(c) + 1
|
||||
|
||||
END IF
|
||||
|
||||
!A collision has ocurred, exit the loop
|
||||
EXIT
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
!Deallocate arrays for next collision
|
||||
DEALLOCATE(sigmaVrel, probabilityColl)
|
||||
|
||||
!End loop collisions in cell
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
!End loop collision pairs
|
||||
END DO
|
||||
|
||||
!End loop volumes
|
||||
END DO
|
||||
!$OMP END DO
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE doCollisions
|
||||
|
||||
SUBROUTINE doCoulomb(self)
|
||||
USE moduleCoulomb
|
||||
USE moduleRandom
|
||||
USE moduleOutput
|
||||
USE moduleList
|
||||
USE moduleMath
|
||||
USE moduleRefParam
|
||||
USE moduleConstParam
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshParticles), INTENT(in), TARGET:: self
|
||||
CLASS(meshCell), POINTER:: cell
|
||||
TYPE(interactionsCoulomb):: pair
|
||||
INTEGER:: e
|
||||
INTEGER:: k
|
||||
INTEGER:: i, j
|
||||
INTEGER:: n
|
||||
INTEGER:: p
|
||||
TYPE(lNode), POINTER:: partTemp
|
||||
INTEGER(8), ALLOCATABLE:: cellNodes(:)
|
||||
CLASS(meshNode), POINTER:: node
|
||||
TYPE(outputFormat):: output
|
||||
REAL(8), ALLOCATABLE:: densityNodes(:), velocityNodes(:,:), temperatureNodes(:) !values in node
|
||||
REAL(8):: density, velocity(1:3), temperature!values at particle position
|
||||
REAL(8):: C(1:3), C_per, W(1:3) !relative velocity and velocity in the relative frame of reference
|
||||
REAL(8):: l, lW, l2
|
||||
REAL(8):: GlW, HlW
|
||||
REAL(8):: normC
|
||||
REAL(8):: cosThe, sinThe
|
||||
REAL(8):: cosPhi, sinPhi
|
||||
REAL(8):: rotation(1:3,1:3) !Rotation matrix to go back to laboratory frame
|
||||
REAL(8):: A, AW
|
||||
REAL(8):: deltaW_par, deltaW_par_square, deltaW_per_square !Increments of W
|
||||
REAL(8):: theta_per !Random angle for perpendicular direction
|
||||
REAL(8):: eps = 1.D-12
|
||||
REAL(8), ALLOCATABLE, DIMENSION(:,:):: deltaV_ij, p_ij
|
||||
REAL(8), ALLOCATABLE, DIMENSION(:):: mass_ij
|
||||
REAL(8):: massSum_ij
|
||||
REAL(8), ALLOCATABLE, DIMENSION(:,:):: deltaV_ji, p_ji
|
||||
REAL(8), ALLOCATABLE, DIMENSION(:):: mass_ji
|
||||
REAL(8):: massSum_ji
|
||||
REAL(8):: alpha_num, alpha_den, alpha, beta(1:3)
|
||||
|
||||
|
||||
!$OMP DO SCHEDULE(DYNAMIC) PRIVATE(partTemp)
|
||||
DO e = 1, self%numCells
|
||||
cell => self%cells(e)%obj
|
||||
cellNodes = cell%getNodes(cell%nNodes)
|
||||
|
||||
ALLOCATE(densityNodes(1:cell%nNodes), &
|
||||
velocityNodes(1:cell%nNodes, 1:3), &
|
||||
temperatureNodes(1:cell%nNodes))
|
||||
|
||||
DO k=1, nCoulombPairs
|
||||
pair = coulombMatrix(k)
|
||||
i = pair%sp_i%n
|
||||
j = pair%sp_j%n
|
||||
|
||||
!Do scattering of particles from species_i due to species j
|
||||
!Compute background properties of species_j
|
||||
DO n = 1, cell%nNodes
|
||||
node => self%nodes(cellNodes(n))%obj
|
||||
CALL calculateOutput(node%output(j), output, node%v, pair%sp_j)
|
||||
densityNodes(n) = output%density/n_ref
|
||||
velocityNodes(n,1:3) = output%velocity(1:3)/v_ref
|
||||
temperatureNodes(n) = output%temperature/T_ref
|
||||
|
||||
END DO
|
||||
|
||||
ALLOCATE(deltaV_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))
|
||||
deltaV_ij = 0.D0
|
||||
p_ij = 0.D0
|
||||
mass_ij = 0.D0
|
||||
!Loop over particles of species_i
|
||||
partTemp => cell%listPart_in(i)%head
|
||||
p = 1
|
||||
DO WHILE(ASSOCIATED(partTemp))
|
||||
density = cell%gatherF(partTemp%part%Xi, cell%nNodes, densityNodes)
|
||||
velocity = cell%gatherF(partTemp%part%Xi, cell%nNodes, velocityNodes)
|
||||
temperature = cell%gatherF(partTemp%part%Xi, cell%nNodes, temperatureNodes)
|
||||
|
||||
!If cell temperature is too low, skip particle to avoid division by zero
|
||||
IF (temperature>eps) THEN
|
||||
l2 = pair%l2_j/temperature
|
||||
l = SQRT(l2)
|
||||
|
||||
ELSE
|
||||
partTemp => partTemp%next
|
||||
|
||||
CYCLE
|
||||
|
||||
END IF
|
||||
|
||||
A = pair%A_i*density
|
||||
|
||||
C = partTemp%part%v - velocity
|
||||
normC = NORM2(C)
|
||||
|
||||
!C_3 = z; C_1, C2 = x, y (per)
|
||||
C_per = NORM2(C(1:2))
|
||||
cosPhi = C(1) / C_per
|
||||
sinPhi = C(2) / C_per
|
||||
cosThe = C(3) / normC
|
||||
sinThe = C_per / normC
|
||||
|
||||
!Rotation matrix to go from W to C
|
||||
rotation = RESHAPE((/ cosThe*cosPhi, cosThe*sinPhi, -sinThe, & !First column
|
||||
-sinPhi, cosPhi, 0.D0, & !Second column
|
||||
sinThe*cosPhi, sinThe*sinPhi, cosThe /), & !Third column
|
||||
(/ 3, 3 /))
|
||||
|
||||
!W at start is = (0, 0, normC), so normW = normC
|
||||
lW = l * normC
|
||||
GlW = G(lW)
|
||||
HlW = H(lW)
|
||||
AW = A / normC
|
||||
|
||||
!Calculate changes in W due to collision process
|
||||
deltaW_par = - A * pair%one_plus_massRatio_ij * l2 * GlW * tauMin
|
||||
deltaW_par_square = SQRT(AW * GlW * tauMin)*randomMaxwellian()
|
||||
deltaW_per_square = SQRT(AW * HlW * tauMin)*randomMaxwellian()
|
||||
|
||||
!Random angle to distribute perpendicular change in velocity
|
||||
theta_per = PI2*random()
|
||||
|
||||
!Change W
|
||||
W(1) = deltaW_per_square * COS(theta_per)
|
||||
W(2) = deltaW_per_square * SIN(theta_per)
|
||||
W(3) = normC + deltaW_par + deltaW_par_square
|
||||
|
||||
!Compute changes in velocity for each particle
|
||||
deltaV_ij(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v
|
||||
mass_ij(p) = pair%sp_i%m*partTemp%part%weight
|
||||
p_ij(p,1:3) = mass_ij(p)*partTemp%part%v
|
||||
|
||||
!Move to the next particle in the list
|
||||
partTemp => partTemp%next
|
||||
p = p + 1
|
||||
|
||||
END DO
|
||||
|
||||
!Do corresponding collisions
|
||||
IF (i /= j) THEN
|
||||
!Do scattering of particles from species_j due to species i
|
||||
!Compute background properties of species_i
|
||||
DO n = 1, cell%nNodes
|
||||
node => self%nodes(cellNodes(n))%obj
|
||||
CALL calculateOutput(node%output(i), output, node%v, pair%sp_i)
|
||||
densityNodes(n) = output%density/n_ref
|
||||
velocityNodes(n,1:3) = output%velocity(1:3)/v_ref
|
||||
temperatureNodes(n) = output%temperature/T_ref
|
||||
|
||||
END DO
|
||||
|
||||
ALLOCATE(deltaV_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))
|
||||
deltaV_ji = 0.D0
|
||||
p_ji = 0.D0
|
||||
mass_ji = 0.D0
|
||||
!Loop over particles of species_j
|
||||
partTemp => cell%listPart_in(j)%head
|
||||
p = 1
|
||||
DO WHILE(ASSOCIATED(partTemp))
|
||||
density = cell%gatherF(partTemp%part%Xi, cell%nNodes, densityNodes)
|
||||
velocity = cell%gatherF(partTemp%part%Xi, cell%nNodes, velocityNodes)
|
||||
temperature = cell%gatherF(partTemp%part%Xi, cell%nNodes, temperatureNodes)
|
||||
|
||||
!If cell temperature is too low, skip particle to avoid division by zero
|
||||
IF (temperature>eps) THEN
|
||||
l2 = pair%l2_i/temperature
|
||||
l = SQRT(l2)
|
||||
|
||||
ELSE
|
||||
partTemp => partTemp%next
|
||||
|
||||
CYCLE
|
||||
|
||||
END IF
|
||||
A = pair%A_j*density
|
||||
|
||||
C = partTemp%part%v - velocity
|
||||
normC = NORM2(C)
|
||||
|
||||
!C_3 = z; C_1, C2 = x, y (per)
|
||||
C_per = NORM2(C(1:2))
|
||||
cosPhi = C(1) / C_per
|
||||
sinPhi = C(2) / C_per
|
||||
cosThe = C(3) / normC
|
||||
sinThe = C_per / normC
|
||||
|
||||
!Rotation matrix to go from W to C
|
||||
rotation = RESHAPE((/ cosThe*cosPhi, cosThe*sinPhi, -sinThe, & !First column
|
||||
-sinPhi, cosPhi, 0.D0, & !Second column
|
||||
sinThe*cosPhi, sinThe*sinPhi, cosThe /), & !Third column
|
||||
(/ 3, 3 /))
|
||||
|
||||
!W at start is = (0, 0, normC), so normW = normC
|
||||
lW = l * normC
|
||||
GlW = G(lW)
|
||||
HlW = H(lW)
|
||||
AW = A / normC
|
||||
|
||||
!Calculate changes in W due to collision process
|
||||
deltaW_par = - A * pair%one_plus_massRatio_ij * l2 * GlW * tauMin
|
||||
deltaW_par_square = SQRT(AW * GlW * tauMin)*randomMaxwellian()
|
||||
deltaW_per_square = SQRT(AW * HlW * tauMin)*randomMaxwellian()
|
||||
|
||||
!Random angle to distribute perpendicular change in velocity
|
||||
theta_per = PI2*random()
|
||||
|
||||
!Change W
|
||||
W(1) = deltaW_per_square * COS(theta_per)
|
||||
W(2) = deltaW_per_square * SIN(theta_per)
|
||||
W(3) = normC + deltaW_par + deltaW_par_square
|
||||
|
||||
!Compute changes in velocity for each particle
|
||||
deltaV_ji(p,1:3) = MATMUL(rotation, W) + velocity - partTemp%part%v
|
||||
mass_ji(p) = pair%sp_j%m*partTemp%part%weight
|
||||
p_ji(p,1:3) = mass_ji(p)*partTemp%part%v
|
||||
|
||||
!Move to the next particle in the list
|
||||
partTemp => partTemp%next
|
||||
p = p + 1
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
!Calculate correction
|
||||
!Total mass
|
||||
massSum_ij = SUM(mass_ij)
|
||||
massSum_ji = 0.D0
|
||||
|
||||
!Beta
|
||||
beta = 0.D0
|
||||
DO p = 1, cell%listPart_in(i)%amount
|
||||
beta = beta + mass_ij(p) * deltaV_ij(p,1:3)
|
||||
|
||||
END DO
|
||||
|
||||
IF (i /= j) THEN
|
||||
massSum_ji = SUM(mass_ji)
|
||||
DO p = 1, cell%listPart_in(j)%amount
|
||||
beta = beta + mass_ji(p) * deltaV_ji(p,1:3)
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
beta = beta / (massSum_ij + massSum_ji)
|
||||
|
||||
!Alpha
|
||||
alpha_num = 0.D0
|
||||
alpha_den = 0.D0
|
||||
DO p =1, cell%listPart_in(i)%amount
|
||||
alpha_num = alpha_num + DOT_PRODUCT(p_ij(p,1:3), deltav_ij(p,1:3) - beta(1:3))
|
||||
alpha_den = alpha_den + mass_ij(p) * NORM2(deltav_ij(p,1:3) - beta(1:3))**2
|
||||
|
||||
END DO
|
||||
|
||||
IF (i /= j) THEN
|
||||
DO p = 1, cell%listPart_in(j)%amount
|
||||
alpha_num = alpha_num + DOT_PRODUCT(p_ji(p,1:3), deltav_ji(p,1:3) - beta(1:3))
|
||||
alpha_den = alpha_den + mass_ji(p) * NORM2(deltav_ji(p,1:3) - beta(1:3))**2
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
alpha = -2.D0*alpha_num / alpha_den
|
||||
|
||||
!Apply correction to particles velocity
|
||||
partTemp => cell%listPart_in(i)%head
|
||||
p = 1
|
||||
DO WHILE(ASSOCIATED(partTemp))
|
||||
partTemp%part%v = partTemp%part%v + alpha * (deltaV_ij(p,1:3) - beta(1:3))
|
||||
partTemp => partTemp%next
|
||||
p = p + 1
|
||||
|
||||
END DO
|
||||
|
||||
IF (i /= j) THEN
|
||||
partTemp => cell%listPart_in(j)%head
|
||||
p = 1
|
||||
DO WHILE(ASSOCIATED(partTemp))
|
||||
partTemp%part%v = partTemp%part%v + alpha * (deltaV_ji(p,1:3) - beta(1:3))
|
||||
partTemp => partTemp%next
|
||||
p = p + 1
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
DEALLOCATE(deltaV_ij, p_ij, mass_ij)
|
||||
|
||||
IF (i /= j) THEN
|
||||
DEALLOCATE(deltaV_ji, p_ji, mass_ji)
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
DEALLOCATE(densityNodes, velocityNodes, temperatureNodes, cellNodes)
|
||||
|
||||
END DO
|
||||
!$OMP END DO
|
||||
|
||||
END SUBROUTINE doCoulomb
|
||||
|
||||
end submodule elements
|
||||
22
src/modules/mesh/moduleMesh@surfaces.f90
Normal file
22
src/modules/mesh/moduleMesh@surfaces.f90
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
submodule(moduleMesh) surfaces
|
||||
contains
|
||||
module function physicalSurface_to_index(ps) result(index)
|
||||
implicit none
|
||||
|
||||
integer:: ps
|
||||
integer:: index
|
||||
integer:: i
|
||||
|
||||
index = 0
|
||||
do i = 1, nPhysicalSurfaces
|
||||
if (physicalSurfaces(i)%index == ps) then
|
||||
index = i
|
||||
exit
|
||||
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end function physicalSurface_to_index
|
||||
|
||||
end submodule surfaces
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
!moduleMeshBoundary: Boundary functions for the mesh edges
|
||||
MODULE moduleMeshBoundary
|
||||
USE moduleMesh
|
||||
|
||||
CONTAINS
|
||||
SUBROUTINE reflection(edge, part)
|
||||
USE moduleCaseParam
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
!rp = intersection between particle and edge
|
||||
!rpp = final position of particle
|
||||
!vpp = final velocity of particle
|
||||
REAL(8), DIMENSION(1:3):: rp, vpp
|
||||
|
||||
!Reflect particle velocity
|
||||
vpp = part%v - 2.D0*DOT_PRODUCT(part%v, edge%normal)*edge%normal
|
||||
part%v = vpp
|
||||
|
||||
rp = edge%intersection(part%r)
|
||||
|
||||
part%r = 2.D0*(rp - part%r) + part%r
|
||||
|
||||
!particle is assumed to be inside
|
||||
part%n_in = .TRUE.
|
||||
|
||||
END SUBROUTINE reflection
|
||||
|
||||
!Absoption in a surface
|
||||
SUBROUTINE absorption(edge, part)
|
||||
USE moduleCaseParam
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
REAL(8):: rpp(1:3) !Position of particle projected to the edge
|
||||
REAL(8):: d !Distance from particle to edge
|
||||
|
||||
rpp = edge%intersection(part%r)
|
||||
|
||||
d = NORM2(rpp - part%r)
|
||||
|
||||
IF (d >= 0.D0) THEN
|
||||
part%weight = part%weight/d
|
||||
|
||||
END IF
|
||||
|
||||
!Assign new position to particle
|
||||
part%r = rpp
|
||||
!Remove particle from the domain
|
||||
part%n_in = .FALSE.
|
||||
|
||||
!Scatter particle in associated volume
|
||||
IF (ASSOCIATED(edge%e1)) THEN
|
||||
CALL edge%e1%scatter(edge%e1%nNodes, part)
|
||||
|
||||
ELSE
|
||||
CALL edge%e2%scatter(edge%e2%nNodes, part)
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE absorption
|
||||
|
||||
!Transparent boundary condition
|
||||
SUBROUTINE transparent(edge, part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
|
||||
!Removes particle from domain
|
||||
part%n_in = .FALSE.
|
||||
|
||||
END SUBROUTINE transparent
|
||||
|
||||
!Symmetry axis. Reflects particles.
|
||||
!Although this function should never be called, it is set as a reflective boundary
|
||||
!to properly deal with possible particles reaching a corner and selecting this boundary.
|
||||
SUBROUTINE symmetryAxis(edge, part)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
|
||||
CALL reflection(edge, part)
|
||||
|
||||
END SUBROUTINE symmetryAxis
|
||||
|
||||
!Wall with temperature
|
||||
SUBROUTINE wallTemperature(edge, part)
|
||||
USE moduleSpecies
|
||||
USE moduleBoundary
|
||||
USE moduleRandom
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
INTEGER:: i
|
||||
|
||||
!Modifies particle velocity according to wall temperature
|
||||
SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj)
|
||||
TYPE IS(boundaryWallTemperature)
|
||||
DO i = 1, 3
|
||||
part%v(i) = part%v(i) + bound%vTh*randomMaxwellian()
|
||||
|
||||
END DO
|
||||
|
||||
END SELECT
|
||||
|
||||
CALL reflection(edge, part)
|
||||
|
||||
END SUBROUTINE wallTemperature
|
||||
|
||||
!Ionization surface: an electron will pass through the surface
|
||||
! and create an ion-electron pair based on a neutral background
|
||||
SUBROUTINE ionization(edge, part)
|
||||
USE moduleList
|
||||
USE moduleSpecies
|
||||
USE moduleMesh
|
||||
USE moduleRefParam
|
||||
USE moduleRandom
|
||||
USE moduleMath
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
CLASS(particle), INTENT(inout):: part
|
||||
REAL(8):: vRel, eRel, mRel !relative velocity, energy and mass
|
||||
INTEGER:: nIonizations !Number of ionizations based on eRel
|
||||
REAL(8):: pIonization !Probability of ionization of each event
|
||||
INTEGER:: p
|
||||
REAL(8):: v0(1:3) !random velocity of neutral
|
||||
TYPE(particle), POINTER:: newElectron
|
||||
TYPE(particle), POINTER:: newIon
|
||||
|
||||
SELECT TYPE(bound => edge%boundary%bTypes(part%species%n)%obj)
|
||||
TYPE IS(boundaryIonization)
|
||||
mRel = reducedMass(bound%m0, part%species%m)
|
||||
vRel = SUM(DABS(part%v-bound%v0))
|
||||
eRel = mRel*vRel**2*5.D-1
|
||||
|
||||
!Maximum number of possible ionizations based on relative energy
|
||||
nIonizations = FLOOR(eRel/bound%eThreshold)
|
||||
|
||||
DO p = 1, nIonizations
|
||||
!Get probability of ionization
|
||||
pIonization = 1.D0 - DEXP(-bound%n0*bound%crossSection%get(eRel)*vRel*bound%effectiveTime/REAL(nIonizations))
|
||||
|
||||
!If a random number is below the probability of ionization, create new pair of ion-electron
|
||||
IF (random() < pIonization) THEN
|
||||
!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)
|
||||
|
||||
IF (ASSOCIATED(bound%electronSecondary)) THEN
|
||||
newElectron%species => bound%electronSecondary
|
||||
|
||||
ELSE
|
||||
newElectron%species => part%species
|
||||
|
||||
END IF
|
||||
newIon%species => bound%species
|
||||
|
||||
newElectron%v = v0 + (1.D0 + bound%deltaV*v0/NORM2(v0))
|
||||
newIon%v = v0
|
||||
|
||||
newElectron%r = edge%randPos()
|
||||
newIon%r = newElectron%r
|
||||
|
||||
IF (ASSOCIATED(edge%e1)) THEN
|
||||
newElectron%cell = edge%e1%n
|
||||
|
||||
ELSEIF (ASSOCIATED(edge%e2)) THEN
|
||||
newElectron%cell = edge%e2%n
|
||||
|
||||
END IF
|
||||
newIon%cell = newElectron%cell
|
||||
|
||||
newElectron%Xi = mesh%cells(part%cell)%obj%phy2log(newElectron%r)
|
||||
newIon%Xi = newElectron%Xi
|
||||
|
||||
newElectron%weight = part%weight
|
||||
newIon%weight = newElectron%weight
|
||||
|
||||
newElectron%n_in = .TRUE.
|
||||
newIon%n_in = .TRUE.
|
||||
|
||||
!Add particles to list
|
||||
CALL partSurfaces%setLock()
|
||||
CALL partSurfaces%add(newElectron)
|
||||
CALL partSurfaces%add(newIon)
|
||||
CALL partSurfaces%unsetLock()
|
||||
|
||||
!Electron loses energy due to ionization
|
||||
eRel = eRel - bound%eThreshold
|
||||
vRel = 2.D0*DSQRT(eRel)/mRel
|
||||
|
||||
!Reduce number of possible ionizations
|
||||
nIonizations = nIonizations - 1
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
END SELECT
|
||||
|
||||
!Removes ionizing electron regardless the number of pair created
|
||||
part%n_in = .FALSE.
|
||||
|
||||
END SUBROUTINE ionization
|
||||
|
||||
subroutine outflowAdaptive(edge, part)
|
||||
use moduleRandom
|
||||
use moduleRefParam, only: v_ref
|
||||
implicit none
|
||||
|
||||
class(meshEdge), intent(inout):: edge
|
||||
class(particle), intent(inout):: part
|
||||
real(8):: v_cut
|
||||
|
||||
v_cut = 2.d0 * 40.d3/v_ref !This will be the drag velocity of the ions in the future
|
||||
|
||||
select type(bound => edge%boundary%bTypes(part%species%n)%obj)
|
||||
type is(boundaryOutflowAdaptive)
|
||||
if (dot_product(part%v,-edge%normal) > v_cut) then
|
||||
part%v = part%v + v_cut*edge%normal
|
||||
call reflection(edge, part)
|
||||
|
||||
else
|
||||
call transparent(edge, part)
|
||||
|
||||
end if
|
||||
|
||||
end select
|
||||
|
||||
end subroutine outflowAdaptive
|
||||
|
||||
!Points the boundary function to specific type
|
||||
SUBROUTINE pointBoundaryFunction(edge, s)
|
||||
USE moduleErrors
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(meshEdge), INTENT(inout):: edge
|
||||
INTEGER, INTENT(in):: s !Species index
|
||||
|
||||
SELECT TYPE(obj => edge%boundary%bTypes(s)%obj)
|
||||
TYPE IS(boundaryAbsorption)
|
||||
edge%fBoundary(s)%apply => absorption
|
||||
|
||||
TYPE IS(boundaryReflection)
|
||||
edge%fBoundary(s)%apply => reflection
|
||||
|
||||
TYPE IS(boundaryTransparent)
|
||||
edge%fBoundary(s)%apply => transparent
|
||||
|
||||
TYPE IS(boundaryAxis)
|
||||
edge%fBoundary(s)%apply => symmetryAxis
|
||||
|
||||
TYPE IS(boundaryWallTemperature)
|
||||
edge%fBoundary(s)%apply => wallTemperature
|
||||
|
||||
TYPE IS(boundaryIonization)
|
||||
edge%fBoundary(s)%apply => ionization
|
||||
|
||||
type is(boundaryOutflowAdaptive)
|
||||
edge%fBoundary(s)%apply => outflowAdaptive
|
||||
|
||||
CLASS DEFAULT
|
||||
CALL criticalError("Boundary type not defined in this geometry", 'pointBoundaryFunction')
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE pointBoundaryFunction
|
||||
|
||||
END MODULE moduleMeshBoundary
|
||||
227
src/modules/mesh/moduleMeshCommon.f90
Normal file
227
src/modules/mesh/moduleMeshCommon.f90
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
! Common subroutines and parameters for mesh elements
|
||||
module moduleMeshCommon
|
||||
! values for integration gauss integral
|
||||
! Segment
|
||||
real(8), parameter:: corSeg(1:3) = (/ -dsqrt(3.D0/5.D0), 0.D0, dsqrt(3.D0/5.D0) /)
|
||||
real(8), parameter:: wSeg(1:3) = (/ 5.D0/9.D0, 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
! tria
|
||||
real(8), parameter:: Xi1Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 3.D0/5.D0, 1.D0/5.D0 /)
|
||||
real(8), parameter:: Xi2Tria(1:4) = (/ 1.D0/3.D0, 1.D0/5.D0, 1.D0/5.D0, 3.D0/5.D0 /)
|
||||
real(8), parameter:: wTria(1:4) = (/ -27.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0, 25.D0/96.D0 /)
|
||||
|
||||
! Quad
|
||||
real(8), parameter:: corQuad(1:3) = (/ -dsqrt(3.D0/5.D0), 0.D0, dsqrt(3.D0/5.D0) /)
|
||||
real(8), parameter:: wQuad(1:3) = (/ 5.D0/9.D0, 8.D0/9.D0, 5.D0/9.D0 /)
|
||||
|
||||
! Center point in natural coordinates
|
||||
! Point
|
||||
real(8), parameter:: cenPoint(1:3) = (/ 0.0d0, 0.0d0, 0.0d0 /)
|
||||
! Segment
|
||||
real(8), parameter:: cenSeg(1:3) = (/ 0.0d0, 0.0d0, 0.0d0 /)
|
||||
! Tria
|
||||
real(8), parameter:: cenTria(1:3) = (/ 1.0d0/3.0d0, 1.0d0/3.0d0, 0.0d0 /)
|
||||
! Quad
|
||||
real(8), parameter:: cenQuad(1:3) = (/ 0.0d0, 0.0d0, 0.0d0 /)
|
||||
! Tetra
|
||||
real(8), parameter:: cenTetra(1:3) = (/ 1.0d0/3.0d0, 1.0d0/3.0d0, 1.d0/3.d0 /)
|
||||
|
||||
contains
|
||||
! RETURN CENTER IN NATURAL COORDINATES
|
||||
! Point
|
||||
pure function centerXiPoint() result(Xi)
|
||||
implicit none
|
||||
|
||||
real(8):: Xi(1:3)
|
||||
|
||||
Xi = cenPoint
|
||||
|
||||
end function centerXiPoint
|
||||
|
||||
! Segment
|
||||
pure function centerXiSegm() result(Xi)
|
||||
implicit none
|
||||
|
||||
real(8):: Xi(1:3)
|
||||
|
||||
Xi = cenSeg
|
||||
|
||||
end function centerXiSegm
|
||||
|
||||
! Tria
|
||||
pure function centerXiTria() result(Xi)
|
||||
implicit none
|
||||
|
||||
real(8):: Xi(1:3)
|
||||
|
||||
Xi = cenTria
|
||||
|
||||
end function centerXiTria
|
||||
|
||||
! Quad
|
||||
pure function centerXiQuad() result(Xi)
|
||||
implicit none
|
||||
|
||||
real(8):: Xi(1:3)
|
||||
|
||||
Xi = cenQuad
|
||||
|
||||
end function centerXiQuad
|
||||
|
||||
! Quad
|
||||
pure function centerXiTetra() result(Xi)
|
||||
implicit none
|
||||
|
||||
real(8):: Xi(1:3)
|
||||
|
||||
Xi = cenTetra
|
||||
|
||||
end function centerXiTetra
|
||||
|
||||
! ELEMENT FUNCTIONS
|
||||
! Point
|
||||
pure function fPsiPoint(Xi, nNodes) RESULT(fPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = (/ 1.D0 /)
|
||||
|
||||
end function fPsiPoint
|
||||
|
||||
! Segment
|
||||
pure function fPsiSegm(Xi, nNodes) result(fPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = (/ 1.D0 - Xi(1), &
|
||||
1.D0 + Xi(1) /)
|
||||
|
||||
fPsi = fPsi * 0.50D0
|
||||
|
||||
end function fPsiSegm
|
||||
|
||||
! Quad
|
||||
pure function fPsiQuad(Xi, nNodes) result(fPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi = 0.D0
|
||||
|
||||
fPsi = (/ (1.D0 - Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(1)) * (1.D0 + Xi(2)), &
|
||||
(1.D0 - Xi(1)) * (1.D0 + Xi(2)) /)
|
||||
|
||||
fPsi = fPsi * 0.25D0
|
||||
|
||||
end function fPsiQuad
|
||||
|
||||
! Tria
|
||||
pure function fPsiTria(Xi, nNodes) result(fPsi)
|
||||
IMPLICIT NONE
|
||||
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
|
||||
end function fPsiTria
|
||||
|
||||
! Tetra
|
||||
pure function fPsiTetra(Xi, nNodes) result(fPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: fPsi(1:nNodes)
|
||||
|
||||
fPsi(1) = 1.D0 - Xi(1) - Xi(2) - Xi(3)
|
||||
fPsi(2) = Xi(1)
|
||||
fPsi(3) = Xi(2)
|
||||
fPsi(4) = Xi(3)
|
||||
|
||||
end function fPsiTetra
|
||||
|
||||
! DERIVATIVE FOR ELEMENT FUNCTIONS
|
||||
! Segment
|
||||
pure function dPsiSegm(Xi, nNodes) result(dPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:2) = (/ -5.D-1, 5.D-1 /)
|
||||
|
||||
end function dPsiSegm
|
||||
|
||||
! Quad
|
||||
pure function dPsiQuad(Xi, nNodes) result(dPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3)
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1, 1:4) = (/ -(1.D0 - Xi(2)), &
|
||||
(1.D0 - Xi(2)), &
|
||||
(1.D0 + Xi(2)), &
|
||||
-(1.D0 + Xi(2)) /)
|
||||
|
||||
dPsi(2, 1:4) = (/ -(1.D0 - Xi(1)), &
|
||||
-(1.D0 + Xi(1)), &
|
||||
(1.D0 + Xi(1)), &
|
||||
(1.D0 - Xi(1)) /)
|
||||
|
||||
dPsi = dPsi * 0.25D0
|
||||
|
||||
end function dPsiQuad
|
||||
|
||||
! Tria
|
||||
pure function dPsiTria(Xi, nNodes) result(dPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: dPsi(1:3,1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1,1:3) = (/ -1.D0, 1.D0, 0.D0 /)
|
||||
dPsi(2,1:3) = (/ -1.D0, 0.D0, 1.D0 /)
|
||||
|
||||
end function dPsiTria
|
||||
|
||||
!Compute element derivative functions in point Xi
|
||||
pure function dPsiTetra(Xi, nNodes) result(dPsi)
|
||||
implicit none
|
||||
|
||||
real(8), intent(in):: Xi(1:3) ! NOTE: Required by interface but unused
|
||||
integer, intent(in):: nNodes
|
||||
real(8):: dPsi(1:3, 1:nNodes)
|
||||
|
||||
dPsi = 0.D0
|
||||
|
||||
dPsi(1,1:4) = (/ -1.D0, 1.D0, 0.D0, 0.D0 /)
|
||||
dPsi(2,1:4) = (/ -1.D0, 0.D0, 1.D0, 0.D0 /)
|
||||
dPsi(3,1:4) = (/ -1.D0, 0.D0, 0.D0, 1.D0 /)
|
||||
|
||||
end function dPsiTetra
|
||||
|
||||
end module moduleMeshCommon
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
MODULE moduleBoundary
|
||||
USE moduleTable
|
||||
USE moduleSpecies
|
||||
|
||||
!Generic type for boundaries
|
||||
TYPE, PUBLIC:: boundaryGeneric
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryGeneric
|
||||
|
||||
!Reflecting boundary
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryReflection
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryReflection
|
||||
|
||||
!Absorption boundary
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryAbsorption
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryAbsorption
|
||||
|
||||
!Transparent boundary
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryTransparent
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryTransparent
|
||||
|
||||
!Symmetry axis
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryAxis
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryAxis
|
||||
|
||||
!Wall Temperature boundary
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryWallTemperature
|
||||
!Thermal velocity of the wall: square root(Wall temperature X specific heat)
|
||||
REAL(8):: vTh
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryWallTemperature
|
||||
|
||||
!Ionization boundary
|
||||
TYPE, PUBLIC, EXTENDS(boundaryGeneric):: boundaryIonization
|
||||
REAL(8):: m0, n0, v0(1:3), vTh !Properties of background neutrals.
|
||||
CLASS(speciesGeneric), POINTER:: species !Ion species
|
||||
CLASS(speciesCharged), POINTER:: electronSecondary !Pointer to species considerer as secondary electron
|
||||
TYPE(table1D):: crossSection
|
||||
REAL(8):: effectiveTime
|
||||
REAL(8):: eThreshold
|
||||
REAL(8):: deltaV
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryIonization
|
||||
|
||||
!Boundary for quasi-neutral outflow adjusting reflection coefficient
|
||||
type, public, extends(boundaryGeneric):: boundaryOutflowAdaptive
|
||||
real(8):: outflowCurrent
|
||||
real(8):: reflectionFraction
|
||||
contains
|
||||
|
||||
end type boundaryOutflowAdaptive
|
||||
|
||||
!Wrapper for boundary types (one per species)
|
||||
TYPE:: bTypesCont
|
||||
CLASS(boundaryGeneric), ALLOCATABLE:: obj
|
||||
CONTAINS
|
||||
|
||||
END TYPE bTypesCont
|
||||
|
||||
!Wrapper for boundary conditions
|
||||
TYPE:: boundaryCont
|
||||
INTEGER:: n = 0
|
||||
CHARACTER(:), ALLOCATABLE:: name
|
||||
INTEGER:: physicalSurface = 0 !Physical surface as defined in the mesh file
|
||||
CLASS(bTypesCont), ALLOCATABLE:: bTypes(:) !Array for boundary per species
|
||||
CONTAINS
|
||||
|
||||
END TYPE boundaryCont
|
||||
|
||||
!Number of boundaries
|
||||
INTEGER:: nBoundary = 0
|
||||
!Array for boundaries
|
||||
TYPE(boundaryCont), ALLOCATABLE, TARGET:: boundary(:)
|
||||
|
||||
CONTAINS
|
||||
FUNCTION getBoundaryId(physicalSurface) RESULT(id)
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER:: physicalSurface
|
||||
INTEGER:: id
|
||||
INTEGER:: i
|
||||
|
||||
id = 0
|
||||
DO i = 1, nBoundary
|
||||
IF (physicalSurface == boundary(i)%physicalSurface) id = boundary(i)%n
|
||||
|
||||
END DO
|
||||
|
||||
END FUNCTION getBoundaryId
|
||||
|
||||
SUBROUTINE initWallTemperature(boundary, T, c)
|
||||
USE moduleRefParam
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryGeneric), ALLOCATABLE, INTENT(out):: boundary
|
||||
REAL(8), INTENT(in):: T, c !Wall temperature and specific heat
|
||||
REAL(8):: vTh
|
||||
|
||||
vTh = DSQRT(c * T) / v_ref
|
||||
boundary = boundaryWallTemperature(vTh = vTh)
|
||||
|
||||
END SUBROUTINE initWallTemperature
|
||||
|
||||
SUBROUTINE initIonization(boundary, me, m0, n0, v0, T0, ion, effTime, crossSection, eThreshold, electronSecondary)
|
||||
USE moduleRefParam
|
||||
USE moduleSpecies
|
||||
USE moduleCaseParam
|
||||
USE moduleConstParam
|
||||
USE moduleErrors
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryGeneric), ALLOCATABLE, INTENT(out):: boundary
|
||||
REAL(8), INTENT(in):: me !Electron mass
|
||||
REAL(8), INTENT(in):: m0, n0, v0(1:3), T0 !Neutral properties
|
||||
INTEGER, INTENT(in):: ion
|
||||
INTEGER, OPTIONAL, INTENT(in):: electronSecondary
|
||||
REAL(8):: effTime
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: crossSection
|
||||
REAL(8), INTENT(in):: eThreshold
|
||||
|
||||
ALLOCATE(boundaryIonization:: boundary)
|
||||
|
||||
SELECT TYPE(boundary)
|
||||
TYPE IS(boundaryIonization)
|
||||
boundary%m0 = m0 / m_ref
|
||||
boundary%n0 = n0 * Vol_ref
|
||||
boundary%v0 = v0 / v_ref
|
||||
boundary%vTh = DSQRT(kb*T0/m0)/v_ref
|
||||
boundary%species => species(ion)%obj
|
||||
IF (PRESENT(electronSecondary)) THEN
|
||||
SELECT TYPE(sp => species(electronSecondary)%obj)
|
||||
TYPE IS(speciesCharged)
|
||||
boundary%electronSecondary => sp
|
||||
|
||||
CLASS DEFAULT
|
||||
CALL criticalError("Species " // sp%name // " chosen for " // &
|
||||
"secondary electron is not a charged species", 'initIonization')
|
||||
|
||||
END SELECT
|
||||
|
||||
ELSE
|
||||
boundary%electronSecondary => NULL()
|
||||
|
||||
END IF
|
||||
boundary%effectiveTime = effTime / ti_ref
|
||||
CALL boundary%crossSection%init(crossSection)
|
||||
CALL boundary%crossSection%convert(eV2J/(m_ref*v_ref**2), 1.D0/L_ref**2)
|
||||
boundary%eThreshold = eThreshold*eV2J/(m_ref*v_ref**2)
|
||||
boundary%deltaV = DSQRT(boundary%eThreshold/me)
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE initIonization
|
||||
|
||||
END MODULE moduleBoundary
|
||||
|
|
@ -123,16 +123,16 @@ MODULE moduleCollisions
|
|||
END FUNCTION randomDirectionVHS
|
||||
|
||||
!Inits the interaction matrix
|
||||
SUBROUTINE initInteractionMatrix(interactionMatrix)
|
||||
SUBROUTINE initInteractionMatrix(matrix)
|
||||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(interactionsBinary), INTENT(inout), ALLOCATABLE:: interactionMatrix(:)
|
||||
TYPE(interactionsBinary), INTENT(inout), ALLOCATABLE:: matrix(:)
|
||||
|
||||
nCollPairs = (nSpecies*(nSpecies+1))/2
|
||||
ALLOCATE(interactionMatrix(1:nCollPairs))
|
||||
ALLOCATE(matrix(1:nCollPairs))
|
||||
|
||||
interactionMatrix(:)%amount = 0
|
||||
matrix(:)%amount = 0
|
||||
|
||||
END SUBROUTINE initInteractionMatrix
|
||||
|
||||
|
|
@ -553,7 +553,7 @@ MODULE moduleCollisions
|
|||
IMPLICIT NONE
|
||||
|
||||
CLASS(collisionBinaryChargeExchange), INTENT(in):: self
|
||||
REAL(8), INTENT(in):: vRel
|
||||
REAL(8), INTENT(in):: vRel ! NOTE: Required by itnerface but unused
|
||||
TYPE(particle), INTENT(inout), TARGET:: part_i, part_j
|
||||
|
||||
SELECT TYPE(sp => part_i%species)
|
||||
|
|
|
|||
|
|
@ -1,53 +1,8 @@
|
|||
!injection of particles
|
||||
MODULE moduleInject
|
||||
USE moduleSpecies
|
||||
|
||||
!Generic type for velocity distribution function
|
||||
TYPE, ABSTRACT:: velDistGeneric
|
||||
CONTAINS
|
||||
!Returns random velocity from distribution function
|
||||
PROCEDURE(randomVel_interface), DEFERRED, PASS:: randomVel
|
||||
|
||||
END TYPE velDistGeneric
|
||||
|
||||
ABSTRACT INTERFACE
|
||||
FUNCTION randomVel_interface(self) RESULT(v)
|
||||
IMPORT velDistGeneric
|
||||
|
||||
CLASS(velDistGeneric), INTENT(in):: self
|
||||
REAL(8):: v
|
||||
|
||||
END FUNCTION randomVel_interface
|
||||
|
||||
END INTERFACE
|
||||
|
||||
!Container for velocity distributions
|
||||
TYPE:: velDistCont
|
||||
CLASS(velDistGeneric), ALLOCATABLE:: obj
|
||||
|
||||
END TYPE velDistCont
|
||||
|
||||
!Maxwellian distribution function
|
||||
TYPE, EXTENDS(velDistGeneric):: velDistMaxwellian
|
||||
REAL(8):: vTh !Thermal Velocity
|
||||
CONTAINS
|
||||
PROCEDURE, PASS:: randomVel => randomVelMaxwellian
|
||||
|
||||
END TYPE velDistMaxwellian
|
||||
|
||||
TYPE, EXTENDS(velDistGeneric):: velDistHalfMaxwellian
|
||||
REAL(8):: vTh !Thermal Velocity
|
||||
CONTAINS
|
||||
PROCEDURE, PASS:: randomVel => randomVelHalfMaxwellian
|
||||
|
||||
END TYPE velDistHalfMaxwellian
|
||||
|
||||
!Dirac's delta distribution function
|
||||
TYPE, EXTENDS(velDistGeneric):: velDistDelta
|
||||
CONTAINS
|
||||
PROCEDURE, PASS:: randomVel => randomVelDelta
|
||||
|
||||
END TYPE velDistDelta
|
||||
use velocityDistribution
|
||||
use moduleMesh, only: meshEdgePointer
|
||||
|
||||
!Generic injection of particles
|
||||
TYPE:: injectGeneric
|
||||
|
|
@ -60,7 +15,7 @@ MODULE moduleInject
|
|||
INTEGER:: nParticles !Number of particles to introduce each time step
|
||||
CLASS(speciesGeneric), POINTER:: species !Species of injection
|
||||
INTEGER:: nEdges
|
||||
INTEGER, ALLOCATABLE:: edges(:) !Array with edges
|
||||
type(meshEdgePointer), allocatable:: edges(:)
|
||||
INTEGER, ALLOCATABLE:: particlesPerEdge(:) ! Particles per edge
|
||||
REAL(8), ALLOCATABLE:: weightPerEdge(:) ! Weight per edge
|
||||
REAL(8):: surface ! Total surface of injection
|
||||
|
|
@ -76,7 +31,7 @@ MODULE moduleInject
|
|||
|
||||
CONTAINS
|
||||
!Initialize an injection of particles
|
||||
SUBROUTINE initInject(self, i, v, n, temperature, flow, units, sp, physicalSurface, particlesPerEdge)
|
||||
SUBROUTINE initInject(self, i, v, n, temperature, flow, units, sp, ps, particlesPerEdge)
|
||||
USE moduleMesh
|
||||
USE moduleRefParam
|
||||
USE moduleConstParam
|
||||
|
|
@ -88,63 +43,33 @@ MODULE moduleInject
|
|||
CLASS(injectGeneric), INTENT(inout):: self
|
||||
INTEGER, INTENT(in):: i
|
||||
REAL(8), INTENT(in):: v, n(1:3), temperature(1:3)
|
||||
INTEGER, INTENT(in):: sp, physicalSurface, particlesPerEdge
|
||||
INTEGER, INTENT(in):: sp, ps, particlesPerEdge
|
||||
integer:: ps_index
|
||||
REAL(8):: tauInject
|
||||
REAL(8), INTENT(in):: flow
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: units
|
||||
INTEGER:: e, et
|
||||
INTEGER:: phSurface(1:mesh%numEdges)
|
||||
INTEGER:: nVolColl
|
||||
INTEGER:: e
|
||||
REAL(8):: fluxPerStep = 0.D0
|
||||
|
||||
self%id = i
|
||||
self%vMod = v / v_ref
|
||||
self%n = n / NORM2(n)
|
||||
self%temperature = temperature / T_ref
|
||||
!Gets the edge elements from which particles are injected
|
||||
DO e = 1, mesh%numEdges
|
||||
phSurface(e) = mesh%edges(e)%obj%physicalSurface
|
||||
|
||||
END DO
|
||||
self%nEdges = COUNT(phSurface == physicalSurface)
|
||||
ALLOCATE(self%edges(1:self%nEdges))
|
||||
ALLOCATE(self%particlesPerEdge(1:self%nEdges))
|
||||
ALLOCATE(self%weightPerEdge(1:self%nEdges))
|
||||
et = 0
|
||||
DO e=1, mesh%numEdges
|
||||
IF (mesh%edges(e)%obj%physicalSurface == physicalSurface) THEN
|
||||
et = et + 1
|
||||
self%edges(et) = mesh%edges(e)%obj%n
|
||||
!Assign connectivity between injection edge and meshColl volume
|
||||
IF (doubleMesh) THEN
|
||||
nVolColl = findCellBrute(meshColl, mesh%edges(e)%obj%randPos())
|
||||
IF (nVolColl > 0) THEN
|
||||
mesh%edges(e)%obj%eColl => meshColl%cells(nVolColl)%obj
|
||||
!Get array index of physical surface for inject
|
||||
ps_index = physicalSurface_to_index(ps)
|
||||
|
||||
ELSE
|
||||
CALL criticalError("No connection between edge and meshColl", "initInject")
|
||||
! Copy array of edges
|
||||
self%edges = physicalSurfaces(ps_index)%edges
|
||||
self%nEdges = size(self%edges)
|
||||
|
||||
END IF
|
||||
|
||||
ELSE
|
||||
IF (ASSOCIATED(mesh%edges(e)%obj%e1)) THEN
|
||||
mesh%edges(e)%obj%eColl => mesh%edges(e)%obj%e1
|
||||
|
||||
ELSE
|
||||
mesh%edges(e)%obj%eColl => mesh%edges(e)%obj%e2
|
||||
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
allocate(self%particlesPerEdge(1:self%nEdges))
|
||||
allocate(self%weightPerEdge(1:self%nEdges))
|
||||
|
||||
!Calculates total area
|
||||
self%surface = 0.D0
|
||||
DO et = 1, self%nEdges
|
||||
self%surface = self%surface + mesh%edges(self%edges(et))%obj%surface
|
||||
DO e = 1, self%nEdges
|
||||
self%surface = self%surface + self%edges(e)%obj%surface
|
||||
|
||||
END DO
|
||||
|
||||
|
|
@ -194,8 +119,8 @@ MODULE moduleInject
|
|||
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)
|
||||
DO e = 1, self%nEdges
|
||||
self%weightPerEdge(e) = fluxPerStep * self%edges(e)%obj%surface / real(particlesPerEdge)
|
||||
|
||||
END DO
|
||||
|
||||
|
|
@ -204,8 +129,8 @@ MODULE moduleInject
|
|||
ELSE
|
||||
! No particles assigned per edge, use the species weight
|
||||
self%weightPerEdge = self%species%weight
|
||||
DO et = 1, self%nEdges
|
||||
self%particlesPerEdge(et) = max(1,FLOOR(fluxPerStep*mesh%edges(self%edges(et))%obj%surface / self%species%weight))
|
||||
DO e = 1, self%nEdges
|
||||
self%particlesPerEdge(e) = max(1,FLOOR(fluxPerStep*self%edges(e)%obj%surface / self%species%weight))
|
||||
END DO
|
||||
|
||||
self%nParticles = SUM(self%particlesPerEdge)
|
||||
|
|
@ -280,43 +205,6 @@ MODULE moduleInject
|
|||
|
||||
END SUBROUTINE initVelDistDelta
|
||||
|
||||
!Random velocity from Maxwellian distribution
|
||||
FUNCTION randomVelMaxwellian(self) RESULT (v)
|
||||
USE moduleRandom
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(velDistMaxwellian), INTENT(in):: self
|
||||
REAL(8):: v
|
||||
v = 0.D0
|
||||
|
||||
v = self%vTh*randomMaxwellian()/sqrt(2.d0)
|
||||
|
||||
END FUNCTION randomVelMaxwellian
|
||||
|
||||
!Random velocity from Half Maxwellian distribution
|
||||
FUNCTION randomVelHalfMaxwellian(self) RESULT (v)
|
||||
USE moduleRandom
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(velDistHalfMaxwellian), INTENT(in):: self
|
||||
REAL(8):: v
|
||||
v = 0.D0
|
||||
|
||||
v = self%vTh*randomHalfMaxwellian()/sqrt(2.d0)
|
||||
|
||||
END FUNCTION randomVelHalfMaxwellian
|
||||
|
||||
!Random velocity from Dirac's delta distribution
|
||||
PURE FUNCTION randomVelDelta(self) RESULT(v)
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(velDistDelta), INTENT(in):: self
|
||||
REAL(8):: v
|
||||
|
||||
v = 0.D0
|
||||
|
||||
END FUNCTION randomVelDelta
|
||||
|
||||
!Add particles for the injection
|
||||
SUBROUTINE addParticles(self)
|
||||
USE moduleSpecies
|
||||
|
|
@ -349,7 +237,7 @@ MODULE moduleInject
|
|||
!$OMP DO
|
||||
DO e = 1, self%nEdges
|
||||
! Select edge for injection
|
||||
randomEdge => mesh%edges(self%edges(e))%obj
|
||||
randomEdge => self%edges(e)%obj
|
||||
! Inject particles in edge
|
||||
DO i = 1, self%particlesPerEdge(e)
|
||||
! Index in the global partInj array
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ MODULE moduleProbe
|
|||
WRITE(pstring, "(I3.3)") self%id
|
||||
fileName='Probe_' // tstring// '_f_' // pstring // '.dat'
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
OPEN (10, file = path // folder // '/' // fileName)
|
||||
OPEN (10, file = generateFilePath(fileName))
|
||||
WRITE(10, "(A1, 1X, A)") "# ", self%species%name
|
||||
WRITE(10, "(A6, 3(ES15.6E3), A2)") "# r = ", self%r(:)*L_ref, " m"
|
||||
WRITE(10, "(A6, ES15.6E3, A2)") "# t = ", REAL(timeStep)*tauMin*ti_ref, " s"
|
||||
|
|
@ -216,10 +216,10 @@ MODULE moduleProbe
|
|||
DO i = 1, self%nv(1)
|
||||
DO j = 1, self%nv(2)
|
||||
DO k = 1, self%nv(3)
|
||||
WRITE(10, "(4(ES20.6E3))") self%vi(i)*v_ref, &
|
||||
self%vj(j)*v_ref, &
|
||||
self%vk(k)*v_ref, &
|
||||
self%f(i, j, k)
|
||||
WRITE(10, "(4("//fmtReal//"))") self%vi(i)*v_ref, &
|
||||
self%vj(j)*v_ref, &
|
||||
self%vk(k)*v_ref, &
|
||||
self%f(i, j, k)
|
||||
|
||||
END DO
|
||||
WRITE(10, *)
|
||||
|
|
@ -253,7 +253,6 @@ MODULE moduleProbe
|
|||
END SUBROUTINE doProbes
|
||||
|
||||
SUBROUTINE outputProbes()
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER:: i
|
||||
|
|
|
|||
|
|
@ -1,6 +1,40 @@
|
|||
!Contains information about output
|
||||
MODULE moduleOutput
|
||||
IMPLICIT NONE
|
||||
! Path and folder for the output
|
||||
CHARACTER(:), ALLOCATABLE:: path
|
||||
CHARACTER(:), ALLOCATABLE:: folder
|
||||
! Number of digits for step files
|
||||
INTEGER:: iterationDigits
|
||||
CHARACTER(:), ALLOCATABLE:: iterationFormat
|
||||
! Triggers and counters for output
|
||||
INTEGER:: triggerOutput, counterOutput = 0
|
||||
INTEGER:: triggerCPUTime, counterCPUTime = 0
|
||||
! logicals to activate file output
|
||||
LOGICAL:: timeOutput = .FALSE.
|
||||
LOGICAL:: collOutput = .FALSE.
|
||||
LOGICAL:: emOutput = .FALSE.
|
||||
logical:: boundaryParticleOutput = .false.
|
||||
|
||||
! Prefix for iteration files
|
||||
character(len=*), parameter:: prefix = 'Step'
|
||||
|
||||
! Column separator
|
||||
character(len=*), parameter:: colSep = '","'
|
||||
|
||||
! General format for file outputs
|
||||
character(len=*), parameter:: fmtColReal = 'ES0.6E3,:,'//colSep ! Column with real
|
||||
character(len=*), parameter:: fmtColInt = 'I0,:,'//colSep ! Column with integer
|
||||
character(len=*), parameter:: fmtColStr = 'A,:,'//colSep ! Column with text
|
||||
character(len=*), parameter:: fmtReal = 'ES14.6E3' ! Fixed size real
|
||||
character(len=*), parameter:: fmtInt = 'I14' ! Fixed size real
|
||||
|
||||
! File IDs for different input/output
|
||||
integer, parameter:: fileID_mesh = 10 ! Base id for mesh files
|
||||
integer, parameter:: fileID_output = 20 ! Base id for species/collisions/EM output
|
||||
integer, parameter:: fileID_boundaryParticle = 30 ! Particle boundaries
|
||||
integer, parameter:: fileID_boundaryEM = 31 ! EM boundaries
|
||||
integer, parameter:: fileID_reference = 40 ! Reference values
|
||||
integer, parameter:: fileID_time =50 ! Computation time
|
||||
|
||||
!Output for each node
|
||||
TYPE, PUBLIC:: outputNode
|
||||
|
|
@ -33,17 +67,68 @@ MODULE moduleOutput
|
|||
|
||||
END TYPE
|
||||
|
||||
CHARACTER(:), ALLOCATABLE:: path
|
||||
CHARACTER(:), ALLOCATABLE:: folder
|
||||
INTEGER:: iterationDigits
|
||||
CHARACTER(:), ALLOCATABLE:: iterationFormat
|
||||
INTEGER:: triggerOutput, counterOutput = 0
|
||||
INTEGER:: triggerCPUTime, counterCPUTime = 0
|
||||
LOGICAL:: timeOutput = .FALSE.
|
||||
LOGICAL:: collOutput = .FALSE.
|
||||
LOGICAL:: emOutput = .FALSE.
|
||||
|
||||
CONTAINS
|
||||
PURE FUNCTION formatFileName(pref, suff, extension, timeStep) RESULT(fileName)
|
||||
IMPLICIT NONE
|
||||
|
||||
CHARACTER(*), INTENT(in):: pref, suff, extension
|
||||
INTEGER, INTENT(in), OPTIONAL:: timeStep
|
||||
CHARACTER (LEN=iterationDigits):: tString
|
||||
CHARACTER(:), ALLOCATABLE:: fileName
|
||||
|
||||
IF (PRESENT(timeStep)) THEN
|
||||
WRITE(tString, iterationFormat) timeStep
|
||||
fileName = pref // '_' // tString // '_' // suff // '.' // extension
|
||||
|
||||
ELSE
|
||||
fileName = pref // '_' // suff // '.' // extension
|
||||
|
||||
END IF
|
||||
|
||||
END FUNCTION formatFileName
|
||||
|
||||
subroutine createOutputFolder()
|
||||
implicit none
|
||||
|
||||
call execute_command_line('mkdir ' // path // folder )
|
||||
|
||||
end subroutine createOutputFolder
|
||||
|
||||
subroutine copyFileToOutput(fileName)
|
||||
implicit none
|
||||
|
||||
character(*), intent(in):: fileName
|
||||
|
||||
call execute_command_line('cp ' // fileName // ' ' // path // folder)
|
||||
|
||||
end subroutine copyFileToOutput
|
||||
|
||||
subroutine writeCommit()
|
||||
implicit none
|
||||
|
||||
call system('git rev-parse HEAD > ' // path // folder // '/' // 'fpakc_commit.txt')
|
||||
|
||||
end subroutine writeCommit
|
||||
|
||||
pure function generateFilePath(filename) result(completePath)
|
||||
implicit none
|
||||
|
||||
character(*), intent(in):: fileName
|
||||
character(:), allocatable:: completePath
|
||||
|
||||
completePath = path // folder // '/' // fileName
|
||||
|
||||
end function generateFilePath
|
||||
|
||||
subroutine informFileCreation(filename)
|
||||
implicit none
|
||||
|
||||
character(*), intent(in):: fileName
|
||||
|
||||
write(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
|
||||
end subroutine informFileCreation
|
||||
|
||||
PURE SUBROUTINE outputNode_equal_outputNode(self, from)
|
||||
IMPLICIT NONE
|
||||
|
||||
|
|
@ -159,7 +244,7 @@ MODULE moduleOutput
|
|||
|
||||
END SUBROUTINE calculateOutput
|
||||
|
||||
SUBROUTINE printTime(first)
|
||||
SUBROUTINE writeTime(first)
|
||||
USE moduleSpecies
|
||||
USE moduleCompTime
|
||||
USE moduleCaseParam, ONLY: timeStep
|
||||
|
|
@ -168,31 +253,43 @@ MODULE moduleOutput
|
|||
LOGICAL, INTENT(in), OPTIONAL:: first
|
||||
CHARACTER(:), ALLOCATABLE:: fileName
|
||||
|
||||
fileName = 'cpuTime.dat'
|
||||
fileName = 'cpuTime.csv'
|
||||
|
||||
IF (timeOutput) THEN
|
||||
IF (PRESENT(first)) THEN
|
||||
IF (first) THEN
|
||||
OPEN(20, file = path // folder // '/' // fileName, action = 'write')
|
||||
WRITE(20, "(A1, 8X, A1, 9X, A1, 7(A20))") "#","t","n","total (s)","push (s)","reset (s)", &
|
||||
"collision (s)","coulomb (s)", &
|
||||
"weighting (s)","EMField (s)"
|
||||
WRITE(*, "(6X,A15,A)") "Creating file: ", fileName
|
||||
CLOSE(20)
|
||||
OPEN(fileID_time, file = generateFilePath(fileName), action = 'write')
|
||||
WRITE(fileID_time, "(*("//fmtColStr//"))") "t","n","total (s)","push (s)","reset (s)", &
|
||||
"collision (s)","coulomb (s)", &
|
||||
"weighting (s)","EMField (s)"
|
||||
call informFileCreation(fileName)
|
||||
CLOSE(fileID_time)
|
||||
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
OPEN(20, file = path // folder // '/' // fileName, position = 'append', action = 'write')
|
||||
OPEN(fileID_time, file = generateFilePath(fileName), position = 'append', action = 'write')
|
||||
|
||||
WRITE (20, "(I10, I10, 7(ES20.6E3))") timeStep, nPartOld, tStep, tPush, tReset, tColl, tCoul, tWeight, tEMField
|
||||
WRITE (fileID_time, "(*("//fmtColInt//"),*("//fmtColReal//"))") timeStep, nPartOld, tStep, tPush, tReset, tColl, tCoul, tWeight, tEMField
|
||||
|
||||
CLOSE(20)
|
||||
CLOSE(fileID_time)
|
||||
|
||||
END IF
|
||||
|
||||
END SUBROUTINE printTime
|
||||
END SUBROUTINE writeTime
|
||||
|
||||
! Write file with reference values
|
||||
subroutine writeReference()
|
||||
use moduleRefParam
|
||||
implicit none
|
||||
|
||||
open (fileID_reference, file=generateFilePath('reference.csv'))
|
||||
write(fileID_reference, "(*("//fmtColStr//"))") '"L_ref"','"v_ref"','"ti_ref"','"Vol_ref"','"EF_ref"','"Volt_ref"','"B_ref"'
|
||||
write(fileID_reference, "(*("//fmtColReal//"))") L_ref, v_ref, ti_ref, Vol_ref, EF_ref, Volt_ref, B_ref
|
||||
close(fileID_reference)
|
||||
|
||||
end subroutine writeReference
|
||||
|
||||
END MODULE moduleOutput
|
||||
|
||||
|
|
|
|||
|
|
@ -4,197 +4,7 @@ MODULE moduleEM
|
|||
USE moduleTable
|
||||
IMPLICIT NONE
|
||||
|
||||
! Generic type for electromagnetic boundary conditions
|
||||
TYPE, PUBLIC, ABSTRACT:: boundaryEMGeneric
|
||||
INTEGER:: nNodes
|
||||
TYPE(meshNodePointer), ALLOCATABLE:: nodes(:)
|
||||
|
||||
CONTAINS
|
||||
PROCEDURE(applyEM_interface), DEFERRED, PASS:: apply
|
||||
|
||||
END TYPE boundaryEMGeneric
|
||||
|
||||
ABSTRACT INTERFACE
|
||||
! Apply boundary condition to the load vector for the Poission equation
|
||||
SUBROUTINE applyEM_interface(self, vectorF)
|
||||
IMPORT boundaryEMGeneric
|
||||
CLASS(boundaryEMGeneric), INTENT(in):: self
|
||||
REAL(8), INTENT(inout):: vectorF(:)
|
||||
|
||||
END SUBROUTINE applyEM_interface
|
||||
|
||||
END INTERFACE
|
||||
|
||||
TYPE, EXTENDS(boundaryEMGeneric):: boundaryEMDirichlet
|
||||
REAL(8):: potential
|
||||
|
||||
CONTAINS
|
||||
! boundaryEMGeneric DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: apply => applyDirichlet
|
||||
|
||||
END TYPE boundaryEMDirichlet
|
||||
|
||||
TYPE, EXTENDS(boundaryEMGeneric):: boundaryEMDirichletTime
|
||||
REAL(8):: potential
|
||||
TYPE(table1D):: temporalProfile
|
||||
|
||||
CONTAINS
|
||||
! boundaryEMGeneric DEFERRED PROCEDURES
|
||||
PROCEDURE, PASS:: apply => applyDirichletTime
|
||||
|
||||
END TYPE boundaryEMDirichletTime
|
||||
|
||||
! Container for boundary conditions
|
||||
TYPE:: boundaryEMCont
|
||||
CLASS(boundaryEMGeneric), ALLOCATABLE:: obj
|
||||
|
||||
END TYPE boundaryEMCont
|
||||
|
||||
INTEGER:: nBoundaryEM
|
||||
TYPE(boundaryEMCont), ALLOCATABLE:: boundaryEM(:)
|
||||
|
||||
!Information of charge and reference parameters for rho vector
|
||||
REAL(8), ALLOCATABLE:: qSpecies(:)
|
||||
|
||||
CONTAINS
|
||||
SUBROUTINE findNodes(self, physicalSurface)
|
||||
USE moduleMesh
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMGeneric), INTENT(inout):: self
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
CLASS(meshEdge), POINTER:: edge
|
||||
INTEGER, ALLOCATABLE:: nodes(:), nodesEdge(:)
|
||||
INTEGER:: nNodes, nodesNew
|
||||
INTEGER:: e, n
|
||||
|
||||
!Temporal array to hold nodes
|
||||
ALLOCATE(nodes(0))
|
||||
|
||||
! Loop thorugh the edges and identify those that are part of the boundary
|
||||
DO e = 1, mesh%numEdges
|
||||
edge => mesh%edges(e)%obj
|
||||
IF (edge%physicalSurface == physicalSurface) THEN
|
||||
! Edge is of the right boundary index
|
||||
! Get nodes in the edge
|
||||
nNodes = edge%nNodes
|
||||
nodesEdge = edge%getNodes(nNodes)
|
||||
! Collect all nodes that are not already in the temporal array
|
||||
DO n = 1, nNodes
|
||||
IF (ANY(nodes == nodesEdge(n))) THEN
|
||||
! Node already in array, skip
|
||||
CYCLE
|
||||
|
||||
ELSE
|
||||
! If not, add element to array of nodes
|
||||
nodes = [nodes, nodesEdge(n)]
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
END IF
|
||||
|
||||
END DO
|
||||
|
||||
! Point boundary to nodes
|
||||
nNodes = SIZE(nodes)
|
||||
ALLOCATE(self%nodes(nNodes))
|
||||
self%nNodes = nNodes
|
||||
DO n = 1, nNodes
|
||||
self%nodes(n)%obj => mesh%nodes(nodes(n))%obj
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE findNodes
|
||||
|
||||
! Initialize Dirichlet boundary condition
|
||||
SUBROUTINE initDirichlet(self, physicalSurface, potential)
|
||||
USE moduleRefParam, ONLY: Volt_ref
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMGeneric), ALLOCATABLE, INTENT(out):: self
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
REAL(8), INTENT(in):: potential
|
||||
|
||||
! Allocate boundary edge
|
||||
ALLOCATE(boundaryEMDirichlet:: self)
|
||||
|
||||
SELECT TYPE(self)
|
||||
TYPE IS(boundaryEMDirichlet)
|
||||
self%potential = potential / Volt_ref
|
||||
|
||||
CALL findNodes(self, physicalSurface)
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE initDirichlet
|
||||
|
||||
! Initialize Dirichlet boundary condition
|
||||
SUBROUTINE initDirichletTime(self, physicalSurface, potential, temporalProfile)
|
||||
USE moduleRefParam, ONLY: Volt_ref, ti_ref
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMGeneric), ALLOCATABLE, INTENT(out):: self
|
||||
INTEGER, INTENT(in):: physicalSurface
|
||||
REAL(8), INTENT(in):: potential
|
||||
CHARACTER(:), ALLOCATABLE, INTENT(in):: temporalProfile
|
||||
|
||||
! Allocate boundary edge
|
||||
ALLOCATE(boundaryEMDirichletTime:: self)
|
||||
|
||||
SELECT TYPE(self)
|
||||
TYPE IS(boundaryEMDirichletTime)
|
||||
self%potential = potential / Volt_ref
|
||||
|
||||
CALL findNodes(self, physicalSurface)
|
||||
|
||||
CALL self%temporalProfile%init(temporalProfile)
|
||||
|
||||
CALL self%temporalProfile%convert(1.D0/ti_ref, 1.D0)
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE initDirichletTime
|
||||
|
||||
!Apply Dirichlet boundary condition to the poisson equation
|
||||
SUBROUTINE applyDirichlet(self, vectorF)
|
||||
USE moduleMesh
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMDirichlet), INTENT(in):: self
|
||||
REAL(8), INTENT(inout):: vectorF(:)
|
||||
INTEGER:: n, ni
|
||||
|
||||
DO n = 1, self%nNodes
|
||||
self%nodes(n)%obj%emData%phi = self%potential
|
||||
vectorF(self%nodes(n)%obj%n) = self%nodes(n)%obj%emData%phi
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE applyDirichlet
|
||||
|
||||
!Apply Dirichlet boundary condition with time temporal profile
|
||||
SUBROUTINE applyDirichletTime(self, vectorF)
|
||||
USE moduleMesh
|
||||
USE moduleCaseParam, ONLY: timeStep, tauMin
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(boundaryEMDirichletTime), INTENT(in):: self
|
||||
REAL(8), INTENT(inout):: vectorF(:)
|
||||
REAL(8):: timeFactor
|
||||
INTEGER:: n, ni
|
||||
|
||||
timeFactor = self%temporalProfile%get(DBLE(timeStep)*tauMin)
|
||||
|
||||
DO n = 1, self%nNodes
|
||||
self%nodes(n)%obj%emData%phi = self%potential * timeFactor
|
||||
vectorF(self%nodes(n)%obj%n) = self%nodes(n)%obj%emData%phi
|
||||
|
||||
END DO
|
||||
|
||||
END SUBROUTINE applyDirichletTime
|
||||
|
||||
contains
|
||||
!Assemble the source vector based on the charge density to solve Poisson's equation
|
||||
SUBROUTINE assembleSourceVector(vectorF, n_e)
|
||||
USE moduleMesh
|
||||
|
|
@ -250,8 +60,8 @@ MODULE moduleEM
|
|||
|
||||
!Apply boundary conditions
|
||||
!$OMP SINGLE
|
||||
do b = 1, nBoundaryEM
|
||||
call boundaryEM(b)%obj%apply(vectorF)
|
||||
do b = 1, nBoundariesEM
|
||||
call boundariesEM(b)%obj%apply(vectorF)
|
||||
|
||||
end do
|
||||
!$OMP END SINGLE
|
||||
|
|
@ -311,7 +121,6 @@ MODULE moduleEM
|
|||
REAL(8), INTENT(in):: phi(1:n)
|
||||
REAL(8):: n_e(1:n)
|
||||
REAL(8):: n_e0 = 1.0D16, phi_0 = -500.0D0, T_e = 11604.0
|
||||
INTEGER:: i
|
||||
|
||||
n_e = n_e0 / n_ref * exp(qe * (phi*Volt_ref - phi_0) / (kb * T_e))
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ MODULE moduleSolver
|
|||
|
||||
SUBROUTINE initEM(self, EMType)
|
||||
USE moduleEM
|
||||
USE moduleErrors, only: criticalError
|
||||
IMPLICIT NONE
|
||||
|
||||
CLASS(solverGeneric), INTENT(inout):: self
|
||||
|
|
@ -141,6 +142,9 @@ MODULE moduleSolver
|
|||
CASE('ElectrostaticBoltzmann')
|
||||
self%solveEM => solveElecFieldBoltzmann
|
||||
|
||||
CASE DEFAULT
|
||||
CALL criticalError('EM Solver ' // EMType // ' not found', 'readSolver')
|
||||
|
||||
END SELECT
|
||||
|
||||
END SUBROUTINE initEM
|
||||
|
|
@ -531,6 +535,10 @@ MODULE moduleSolver
|
|||
CALL mesh%printOutput()
|
||||
IF (ASSOCIATED(meshForMCC)) CALL meshForMCC%printColl()
|
||||
CALL mesh%printEM()
|
||||
|
||||
! Output of boundaries
|
||||
call boundariesParticle_write()
|
||||
|
||||
WRITE(*, "(5X,A21,I10,A1,I10)") "t/tFinal: ", timeStep, "/", tFinal
|
||||
WRITE(*, "(5X,A21,I10)") "Particles: ", nPartOld
|
||||
IF (timeStep == 0) THEN
|
||||
|
|
@ -556,7 +564,7 @@ MODULE moduleSolver
|
|||
!Reset CPU Time counter
|
||||
counterCPUTime = 0
|
||||
|
||||
CALL printTime(timeStep == 0)
|
||||
CALL writeTime(timeStep == 0)
|
||||
|
||||
END IF
|
||||
|
||||
|
|
|
|||
|
|
@ -231,8 +231,8 @@ MODULE modulePusher
|
|||
USE moduleSpecies
|
||||
IMPLICIT NONE
|
||||
|
||||
TYPE(particle), INTENT(inout):: part
|
||||
REAL(8), INTENT(in):: tauIn
|
||||
TYPE(particle), INTENT(inout):: part ! NOTE: Required by interface but unused
|
||||
REAL(8), INTENT(in):: tauIn ! NOTE: Required by interface but unused
|
||||
|
||||
END SUBROUTINE push0D
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue