I should've commited before, but I wanted to make things compile. The big change is that I've added a global time step so the parameter does not need to be passed in each function. This is useful as we are moving towards using time profiles for boundary conditions and injection of particles (not in this branch, but in the future and the procedure will be quite similar)
285 lines
8 KiB
Fortran
285 lines
8 KiB
Fortran
MODULE moduleProbe
|
|
USE moduleSpecies
|
|
|
|
TYPE:: probeDistFunc
|
|
INTEGER:: id
|
|
REAL(8), DIMENSION(1:3):: r
|
|
CLASS(speciesGeneric), POINTER:: species
|
|
REAL(8), ALLOCATABLE, DIMENSION(:):: vi, vj, vk
|
|
REAL(8), ALLOCATABLE, DIMENSION(:,:,:):: f
|
|
INTEGER, DIMENSION(1:3):: nv
|
|
REAL(8), DIMENSION(1:3):: vrange
|
|
REAL(8):: dvInv
|
|
INTEGER:: every
|
|
LOGICAL:: update
|
|
INTEGER(KIND=OMP_LOCK_KIND):: lock
|
|
REAL(8):: maxR
|
|
CONTAINS
|
|
PROCEDURE, PASS:: init
|
|
PROCEDURE, PASS:: findLowerIndex
|
|
PROCEDURE, PASS:: calculate
|
|
PROCEDURE, PASS:: output
|
|
|
|
END TYPE probeDistFunc
|
|
|
|
INTEGER:: nProbes = 0
|
|
TYPE(probeDistFunc), ALLOCATABLE:: probe(:)
|
|
|
|
CONTAINS
|
|
!Functions for probeDistFunc type
|
|
SUBROUTINE init(self, id, speciesName, r, v1, v2, v3, points, everyTimeStep)
|
|
USE moduleCaseParam
|
|
USE moduleRefParam
|
|
USE moduleSpecies
|
|
USE moduleMesh
|
|
USE moduleErrors
|
|
IMPLICIT NONE
|
|
|
|
CLASS(probeDistFunc), INTENT(out):: self
|
|
INTEGER, INTENT(in):: id
|
|
CHARACTER(:), ALLOCATABLE, INTENT(in):: speciesName
|
|
REAL(8), INTENT(in):: r(1:3)
|
|
REAL(8), INTENT(in):: v1(1:2), v2(1:2), v3(1:2)
|
|
INTEGER, INTENT(in):: points(1:3)
|
|
REAL(8), INTENT(in):: everyTimeStep
|
|
INTEGER:: sp, i
|
|
REAL(8):: dv(1:3)
|
|
|
|
!Assign id
|
|
self%id = id
|
|
|
|
!Get species
|
|
sp = speciesName2Index(speciesName)
|
|
self%species => species(sp)%obj
|
|
|
|
!Find cell
|
|
self%r = r/L_ref
|
|
|
|
!Allocates velocity grid
|
|
self%nv = points
|
|
ALLOCATE(self%vi(1:self%nv(1)))
|
|
ALLOCATE(self%vj(1:self%nv(2)))
|
|
ALLOCATE(self%vk(1:self%nv(3)))
|
|
|
|
self%vrange(1) = (v1(2) - v1(1))/v_ref
|
|
self%vrange(2) = (v2(2) - v2(1))/v_ref
|
|
self%vrange(3) = (v3(2) - v3(1))/v_ref
|
|
|
|
!Creates grid
|
|
dv = self%vrange / REAL(self%nv - 1)
|
|
|
|
self%dvInv = 1.D0/(dv(1)*dv(2)*dv(3))
|
|
|
|
DO i = 1, self%nv(1)
|
|
self%vi(i) = dv(1)*REAL(i - 1) + v1(1)/v_ref
|
|
|
|
END DO
|
|
|
|
DO i = 1, self%nv(2)
|
|
self%vj(i) = dv(2)*REAL(i - 1) + v2(1)/v_ref
|
|
|
|
END DO
|
|
|
|
DO i = 1, self%nv(3)
|
|
self%vk(i) = dv(3)*REAL(i - 1) + v3(1)/v_ref
|
|
|
|
END DO
|
|
|
|
!Allocates distribution function
|
|
ALLOCATE(self%f(1:self%nv(1), &
|
|
1:self%nv(2), &
|
|
1:self%nv(3)))
|
|
|
|
!Number of iterations between output
|
|
IF (everyTimeStep == 0.D0) THEN
|
|
self%every = 1
|
|
|
|
ELSE
|
|
self%every = NINT(everyTimeStep/ tauMin / ti_ref)
|
|
|
|
END IF
|
|
|
|
!Maximum radius
|
|
!TODO: Make this an input parameter
|
|
self%maxR = 1.D-2/L_ref
|
|
|
|
!Init the probe lock
|
|
CALL OMP_INIT_LOCK(self%lock)
|
|
|
|
END SUBROUTINE init
|
|
|
|
SUBROUTINE findLowerIndex(self, vp, i, j, k, inside)
|
|
IMPLICIT NONE
|
|
|
|
CLASS(probeDistFunc), INTENT(in):: self
|
|
REAL(8), INTENT(in):: vp(1:3)
|
|
INTEGER, INTENT(out):: i, j, k
|
|
LOGICAL, INTENT(out):: inside
|
|
|
|
inside = .TRUE.
|
|
|
|
i = FLOOR((vp(1) - self%vi(1))/self%vrange(1)*(REAL(self%nv(1) - 1)) + 1.D0)
|
|
IF (i >= self%nv(1) .OR. i < 1) inside = .FALSE.
|
|
j = FLOOR((vp(2) - self%vj(1))/self%vrange(2)*(REAL(self%nv(2) - 1)) + 1.D0)
|
|
IF (j >= self%nv(2) .OR. j < 1) inside = .FALSE.
|
|
k = FLOOR((vp(3) - self%vk(1))/self%vrange(3)*(REAL(self%nv(3) - 1)) + 1.D0)
|
|
IF (k >= self%nv(3) .OR. k < 1) inside = .FALSE.
|
|
|
|
END SUBROUTINE findLowerIndex
|
|
|
|
SUBROUTINE calculate(self, part)
|
|
USE moduleSpecies
|
|
USE moduleList
|
|
IMPLICIT NONE
|
|
|
|
CLASS(probeDistFunc), INTENT(inout):: self
|
|
TYPE(particle), INTENT(in):: part
|
|
REAL(8):: deltaR
|
|
INTEGER:: i, j, k
|
|
LOGICAL:: inside
|
|
REAL(8):: weight
|
|
REAL(8):: fi, fi1
|
|
REAL(8):: fj, fj1
|
|
REAL(8):: fk, fk1
|
|
|
|
!If particle is of desired type, include in the distribution function
|
|
IF (part%species%n == self%species%n) THEN
|
|
!Calculate distance between particle and probe
|
|
deltaR = NORM2(self%r - part%r)
|
|
|
|
!Only include particle if it is inside the maximum radius
|
|
! IF (deltaR < self%maxR) THEN
|
|
!find lower index for all dimensions
|
|
CALL self%findLowerIndex(part%v, i, j, k, inside)
|
|
|
|
!If particle is inside the velocity grid, add it to the distribution function
|
|
IF (inside) THEN
|
|
!Calculate weights
|
|
fi = self%vi(i+1) - part%v(1)
|
|
fi1 = part%v(1) - self%vi(i)
|
|
fj = self%vj(j+1) - part%v(2)
|
|
fj1 = part%v(2) - self%vj(j)
|
|
fk = self%vk(k+1) - part%v(3)
|
|
fk1 = part%v(3) - self%vk(k)
|
|
|
|
weight = part%weight * DEXP(-deltaR/self%maxR)
|
|
! weight = part%weight
|
|
|
|
!Lock the probe
|
|
CALL OMP_SET_LOCK(self%lock)
|
|
|
|
!Assign particle weight to distribution function
|
|
self%f(i , j , k ) = self%f(i , j , k ) + fi * fj * fk * weight
|
|
self%f(i+1, j , k ) = self%f(i+1, j , k ) + fi1 * fj * fk * weight
|
|
self%f(i , j+1, k ) = self%f(i , j+1, k ) + fi * fj1 * fk * weight
|
|
self%f(i+1, j+1, k ) = self%f(i+1, j+1, k ) + fi1 * fj1 * fk * weight
|
|
self%f(i , j , k+1) = self%f(i , j , k+1) + fi * fj * fk1 * weight
|
|
self%f(i+1, j , k+1) = self%f(i+1, j , k+1) + fi1 * fj * fk1 * weight
|
|
self%f(i , j+1, k+1) = self%f(i , j+1, k+1) + fi * fj1 * fk1 * weight
|
|
self%f(i+1, j+1, k+1) = self%f(i+1, j+1, k+1) + fi1 * fj1 * fk1 * weight
|
|
|
|
!Unlock the probe
|
|
CALL OMP_UNSET_LOCK(self%lock)
|
|
|
|
END IF
|
|
|
|
! END IF
|
|
|
|
END IF
|
|
|
|
END SUBROUTINE calculate
|
|
|
|
SUBROUTINE output(self)
|
|
USE moduleOutput
|
|
USE moduleRefParam
|
|
USE moduleCaseParam, ONLY: timeStep
|
|
IMPLICIT NONE
|
|
|
|
CLASS(probeDistFunc), INTENT(inout):: self
|
|
CHARACTER (LEN=iterationDigits):: tstring
|
|
CHARACTER (LEN=3):: pstring
|
|
CHARACTER(:), ALLOCATABLE:: filename
|
|
INTEGER:: i, j, k
|
|
|
|
!Divide by the velocity cube volume
|
|
self%f = self%f * self%dvInv
|
|
|
|
WRITE(tstring, iterationFormat) timeStep
|
|
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)
|
|
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"
|
|
WRITE(10, "(A1, A19, 3(A20))") "#", "v1 (m s^-1)", "v2 (m s^-1)", "v3 (m s^-1)", "f"
|
|
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)
|
|
|
|
END DO
|
|
WRITE(10, *)
|
|
|
|
END DO
|
|
|
|
END DO
|
|
|
|
CLOSE(10)
|
|
|
|
!Reset distribution function
|
|
self%f = 0.D0
|
|
|
|
END SUBROUTINE output
|
|
|
|
SUBROUTINE doProbes(part)
|
|
IMPLICIT NONE
|
|
|
|
TYPE(particle), INTENT(in):: part
|
|
INTEGER:: i
|
|
|
|
!Do it so they are only calculated when output
|
|
DO i = 1, nProbes
|
|
IF (probe(i)%update) THEN
|
|
CALL probe(i)%calculate(part)
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
END SUBROUTINE doProbes
|
|
|
|
SUBROUTINE outputProbes()
|
|
USE moduleCaseParam, ONLY: timeStep
|
|
IMPLICIT NONE
|
|
|
|
INTEGER:: i
|
|
|
|
DO i = 1, nProbes
|
|
IF (probe(i)%update) THEN
|
|
CALL probe(i)%output()
|
|
|
|
END IF
|
|
|
|
END DO
|
|
|
|
END SUBROUTINE outputProbes
|
|
|
|
SUBROUTINE resetProbes()
|
|
USE moduleCaseParam, ONLY: timeStep
|
|
IMPLICIT NONE
|
|
|
|
INTEGER:: i
|
|
|
|
DO i = 1, nProbes
|
|
probe(i)%f = 0.D0
|
|
probe(i)%update = timeStep == tFinal .OR. timeStep == tInitial .OR. MOD(timeStep, probe(i)%every) == 0
|
|
|
|
END DO
|
|
|
|
END SUBROUTINE resetProbes
|
|
|
|
END MODULE moduleProbe
|