summaryrefslogtreecommitdiff
path: root/Dragon/src/SNFBH3.F
diff options
context:
space:
mode:
authorstainer_t <thomas.stainer@oecd-nea.org>2025-09-08 13:48:49 +0200
committerstainer_t <thomas.stainer@oecd-nea.org>2025-09-08 13:48:49 +0200
commit7dfcc480ba1e19bd3232349fc733caef94034292 (patch)
tree03ee104eb8846d5cc1a981d267687a729185d3f3 /Dragon/src/SNFBH3.F
Initial commit from Polytechnique Montreal
Diffstat (limited to 'Dragon/src/SNFBH3.F')
-rw-r--r--Dragon/src/SNFBH3.F793
1 files changed, 793 insertions, 0 deletions
diff --git a/Dragon/src/SNFBH3.F b/Dragon/src/SNFBH3.F
new file mode 100644
index 0000000..cc7b8d7
--- /dev/null
+++ b/Dragon/src/SNFBH3.F
@@ -0,0 +1,793 @@
+*DECK SNFBH3
+ SUBROUTINE SNFBH3(NUN,NGEFF,IMPX,INCONV,NGIND,NHEX,LZ,ISPLH,SIDE,
+ 1 IELEM,NM,NMX,NMY,NMZ,NMAT,NPQ,NSCT,MAT,VOL,TOTAL,NCODE,ZCODE,
+ 2 QEXT,LFIXUP,DU,DE,DZ,W,MRMZ,DC,DB,DA,MN,DN,WX,WY,WZ,CST,ISADPT,
+ 3 LOZSWP,COORDMAP,FUNKNO)
+*
+*-----------------------------------------------------------------------
+*
+*Purpose:
+* Perform one inner iteration for solving SN equations in 3D Cartesian
+* geometry for the HODD method. Energy-angle multithreading. Albedo
+* boundary conditions on top/bottom, Void on sides. Boltzmann (BTE)
+* discretization.
+*
+*Copyright:
+* Copyright (C) 2025 Ecole Polytechnique de Montreal
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version
+*
+*Author(s): A. Hebert, A. A. Calloo and C. Bienvenue
+*
+*Parameters: input
+* NUN total number of unknowns in vector FUNKNO.
+* NGEFF number of energy groups processed in parallel.
+* IMPX print flag (equal to zero for no print).
+* INCONV energy group convergence flag (set to .FALSE. if converged).
+* NGIND energy group indices assign to the NGEFF set.
+* NHEX number of hexagons in X-Y plane.
+* ISPLH splitting option for hexagons.
+* SIDE side of an hexagon.
+* LZ number of meshes along Z axis.
+* IELEM measure of order of the spatial approximation polynomial:
+* =1 constant - default for HODD;
+* =2 linear - default for DG;
+* >3 higher orders.
+* NM number of moments in space for flux components
+* NMX number of moments for X axis boundaries components
+* NMY number of moments for Y axis boundaries components
+* NMZ number of moments for Z axis boundaries components
+* NMAT number of material mixtures.
+* NPQ number of SN directions in height octants.
+* NSCT maximum number of spherical harmonics moments of the flux.
+* MAT material mixture index in each region.
+* VOL volumes of each region.
+* TOTAL macroscopic total cross sections.
+* ESTOPW stopping power.
+* NCODE boundary condition indices.
+* ZCODE albedos.
+* DELTAE energy group width in MeV.
+* QEXT Legendre components of the fixed source.
+* LFIXUP flag to enable negative flux fixup.
+* DU first direction cosines ($\\mu$).
+* DE second direction cosines ($\\eta$).
+* DZ third direction cosines ($\\xi$).
+* W weights.
+* MRMZ quadrature index.
+* DC diamond-scheme parameter.
+* DB diamond-scheme parameter.
+* DA diamond-scheme parameter.
+* MN moment-to-discrete matrix.
+* DN discrete-to-moment matrix.
+* WX spatial X axis closure relation weighting factors.
+* WY spatial Y axis closure relation weighting factors.
+* WZ spatial Z axis closure relation weighting factors.
+* CST constants for the polynomial approximations.
+* ISADPT flag to enable/disable adaptive flux calculations.
+* LOZSWP lozenge sweep order depending on direction.
+* COORDMAP coordinate map - mapping the hexagons from the indices
+* within the DRAGON geometry to a Cartesian axial coordinate
+* array (see redblobgames.com website).
+*
+*Parameters: input/output
+* FUNKNO Legendre components of the flux and boundary fluxes.
+*
+*Comments:
+* 1. The direction of the axes I, J and D for the surface boundary
+* fluxes are shown in the diagram below. This means that
+* i) lozenge A has I- and D-boundaries (instead of I and J)
+* i) lozenge B has I- and J-boundaries
+* i) lozenge C has D- and J-boundaries (instead of I and J)
+*
+* ^
+* j-axis |
+* | ^
+* _________ / d-axis
+* / / \ /
+* / B / \
+* / / \
+* (-------( A )
+* \ \ /
+* \ C \ /
+* \_______\_/ \
+* \ i-axis
+* ^
+*
+*-----------------------------------------------------------------------
+*
+#if defined(_OPENMP)
+ USE omp_lib
+#endif
+*----
+* SUBROUTINE ARGUMENTS
+*----
+ INTEGER NUN,NGEFF,IMPX,NGIND(NGEFF),NHEX,LZ,ISPLH,IELEM,NM,NMX,
+ 1 NMY,NMZ,NMAT,NPQ,NSCT,MAT(ISPLH,ISPLH,3,NHEX,LZ),NCODE(6),
+ 2 MRMZ(NPQ),LOZSWP(3,6),COORDMAP(3,NHEX)
+ LOGICAL INCONV(NGEFF)
+ REAL SIDE,VOL(ISPLH,ISPLH,3,NHEX,LZ),TOTAL(0:NMAT,NGEFF),ZCODE(6),
+ 1 QEXT(NUN,NGEFF),DU(NPQ),DE(NPQ),DZ(NPQ),W(NPQ),
+ 2 DC(ISPLH*ISPLH*3*NHEX,1,NPQ),DB(ISPLH*ISPLH*3*NHEX,LZ,NPQ),
+ 3 DA(1,LZ,NPQ),FUNKNO(NUN,NGEFF),WX(IELEM+1),WY(IELEM+1),
+ 4 WZ(IELEM+1),CST(IELEM),MN(NPQ,NSCT),DN(NSCT,NPQ)
+ LOGICAL LFIXUP,ISADPT(3)
+*----
+* LOCAL VARIABLES
+*----
+ INTEGER :: NPQD(12),IIND(12),P,DCOORD
+ REAL :: JAC(2,2,3),MUH,ETAH,XIH,AAA,BBB,CCC,DDD,MUHTEMP,ETAHTEMP,
+ 1 WX0(IELEM+1),WY0(IELEM+1),WZ0(IELEM+1)
+ DOUBLE PRECISION :: V,Q(NM),Q2(NM,NM+1),THETA,XNI(NMX),
+ > XNJ(NMY),XNK(NMZ)
+ PARAMETER(IUNOUT=6,RLOG=1.0E-8,PI=3.141592654)
+ LOGICAL ISFIX(3),LHEX(NHEX)
+*----
+* ALLOCATABLE ARRAYS
+*----
+ INTEGER, ALLOCATABLE, DIMENSION(:,:) :: INDANG
+ INTEGER, ALLOCATABLE, DIMENSION(:,:,:,:,:,:) :: TMPMAT
+ DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:,:,:,:) :: FLUX
+ DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:,:,:,:,:) :: FLUX_G
+ DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:,:) :: TMPXNI,
+ > TMPXNJ, TMPXND
+ DOUBLE PRECISION,ALLOCATABLE, DIMENSION(:,:,:,:,:) :: TMPXNK
+*----
+* MAP MATERIAL VALUES TO CARTESIAN AXIAL COORDINATE MAP
+*----
+ NRINGS=INT((SQRT( REAL((4*NHEX-1)/3) )+1.)/2.)
+ NCOL=2*NRINGS -1
+ ALLOCATE(TMPMAT(ISPLH,ISPLH,3,NCOL,NCOL,LZ))
+ TMPMAT(:,:,:,:,:,:) = -1
+ DO K=1,LZ
+ DO IHEX_XY=1,NHEX
+ TMPMAT(:,:,:,COORDMAP(1,IHEX_XY),COORDMAP(2,IHEX_XY),K) =
+ > MAT(:,:,:,IHEX_XY,K)
+ ENDDO
+ ENDDO
+*----
+* SCRATCH STORAGE ALLOCATION
+*----
+ ALLOCATE(INDANG(NPQ,12))
+ ALLOCATE(FLUX(NM,NSCT,3*ISPLH**2,NHEX,LZ))
+ ALLOCATE(FLUX_G(NM,NSCT,3*ISPLH**2,NHEX,LZ,NGEFF))
+ ALLOCATE(TMPXNI(NMX,ISPLH,NCOL))
+ ALLOCATE(TMPXNJ(NMY,ISPLH,NCOL))
+ ALLOCATE(TMPXND(NMX,ISPLH,NCOL))
+ ALLOCATE(TMPXNK(NMZ,ISPLH,ISPLH,3,NHEX))
+*----
+* CONSTRUCT JACOBIAN MATRIX FOR EACH LOZENGE
+*----
+ JAC = RESHAPE((/ 1., -SQRT(3.), 1., SQRT(3.), 2., 0., 1.,
+ > SQRT(3.), 2., 0., -1., SQRT(3.) /), SHAPE(JAC))
+ JAC = (SIDE/2.)*JAC
+*----
+* LENGTH OF FUNKNO COMPONENTS (IN ORDER)
+*----
+ LFLX=3*NM*(ISPLH**2)*NHEX*LZ*NSCT
+ L5=3*NMZ*(ISPLH**2)*NHEX
+*----
+* SET DODECANT SWAPPING ORDER.
+*----
+ NPQD(:12)=0
+ INDANG(:NPQ,:12)=0
+ IIND(:12)=0
+ DO M=1,NPQ
+ VU=DU(M)
+ VE=DE(M)
+ VZ=DZ(M)
+ IF(W(M).EQ.0) CYCLE
+ THETA=0.0D0
+ IF(VE.GT.0.0)THEN
+ IF(VU.EQ.0.0)THEN
+ THETA = PI/2
+ ELSEIF(VU.GT.0.0)THEN
+ THETA = ATAN(ABS(VE/VU))
+ ELSEIF(VU.LT.0.0)THEN
+ THETA = PI - ATAN(ABS(VE/VU))
+ ENDIF
+ ELSEIF(VE.LT.0.0)THEN
+ IF(VU.EQ.0.0)THEN
+ THETA = 3*PI/2
+ ELSEIF(VU.LT.0.0)THEN
+ THETA = PI + ATAN(ABS(VE/VU))
+ ELSEIF(VU.GT.0.0)THEN
+ THETA = 2.*PI - ATAN(ABS(VE/VU))
+ ENDIF
+ ENDIF
+ ! UNFOLD DODECANTS
+ IND=0
+ IF(VZ.GE.0.0)THEN
+ IF((THETA.GT.0.0).AND.(THETA.LT.(PI/3.)))THEN
+ IND=1
+ ELSEIF((THETA.GT.(PI/3.)).AND.(THETA.LT.(2.*PI/3.)))THEN
+ IND=2
+ ELSEIF((THETA.GT.(2.*PI/3.)).AND.(THETA.LT.(PI)))THEN
+ IND=3
+ ELSEIF((THETA.GT.(PI)).AND.(THETA.LT.(4.*PI/3.)))THEN
+ IND=4
+ ELSEIF((THETA.GT.(4.*PI/3.)).AND.(THETA.LT.(5.*PI/3.)))THEN
+ IND=5
+ ELSEIF((THETA.GT.(5.*PI/3.)).AND.(THETA.LT.(2.*PI)))THEN
+ IND=6
+ ENDIF
+ ELSEIF(VZ.LT.0.0)THEN
+ IF((THETA.GT.0.0).AND.(THETA.LT.(PI/3.)))THEN
+ IND=7
+ ELSEIF((THETA.GT.(PI/3.)).AND.(THETA.LT.(2.*PI/3.)))THEN
+ IND=8
+ ELSEIF((THETA.GT.(2.*PI/3.)).AND.(THETA.LT.(PI)))THEN
+ IND=9
+ ELSEIF((THETA.GT.(PI)).AND.(THETA.LT.(4.*PI/3.)))THEN
+ IND=10
+ ELSEIF((THETA.GT.(4.*PI/3.)).AND.(THETA.LT.(5.*PI/3.)))THEN
+ IND=11
+ ELSEIF((THETA.GT.(5.*PI/3.)).AND.(THETA.LT.(2.*PI)))THEN
+ IND=12
+ ENDIF
+ ENDIF
+ ! Assume IIND(I)=I in hexagonal geometry
+ IIND(IND)=IND
+ NPQD(IND)=NPQD(IND)+1
+ INDANG(NPQD(IND),IND)=M
+ ENDDO
+*----
+* MAIN LOOP OVER DODECANTS.
+*----
+
+ FLUX_G(:NM,:NSCT,:3*ISPLH**2,:NHEX,:LZ,:NGEFF)=0.0D0
+ WX0=WX
+ WY0=WY
+ WZ0=WZ
+
+ DO JND=1,12
+ IND=IIND(JND)
+ IND_XY=MOD(IND-1,6)+1
+ ! Needed because of S2 LS (8 dir. for 12 dodecants)
+ IF(IND.EQ.0) CYCLE
+*----
+* PRELIMINARY LOOPS FOR SETTING BOUNDARY CONDITIONS.
+*----
+
+ IF((NCODE(5).NE.1).or.(NCODE(6).NE.1))THEN
+*$OMP PARALLEL DO
+*$OMP+ PRIVATE(M,IG,VZ,M1,IOF,JOF,IPQD)
+*$OMP+ SHARED(FUNKNO) COLLAPSE(2)
+
+ DO IG=1,NGEFF
+ DO IPQD=1,NPQD(IND)
+ IF(.NOT.INCONV(IG)) CYCLE
+ M=INDANG(IPQD,IND)
+
+ VZ=DZ(M)
+ ! Z-BOUNDARY
+ IF(VZ.GT.0.0)THEN
+ M1=MRMZ(M)
+ IF(NCODE(5).NE.4)THEN
+ IOF=(M-1)*(L5)
+ JOF=(M1-1)*(L5)
+ FUNKNO(LFLX+IOF+1:LFLX+IOF+L5,IG)=
+ > FUNKNO(LFLX+JOF+1:LFLX+JOF+L5,IG)
+ ENDIF
+ ELSEIF(VZ.LT.0.0)THEN
+ M1=MRMZ(M)
+ IF(NCODE(6).NE.4)THEN
+ IOF=(M-1)*(L5)
+ JOF=(M1-1)*(L5)
+ FUNKNO(LFLX+IOF+1:LFLX+IOF+L5,IG)=
+ > FUNKNO(LFLX+JOF+1:LFLX+JOF+L5,IG)
+ ENDIF
+ ENDIF
+*
+ ENDDO
+ ENDDO
+
+*$OMP END PARALLEL DO
+ ENDIF
+
+ ! CALL XABORT('SNFBH3: testing 1 ')
+*----
+* MAIN SWAPPING LOOPS FOR SN FLUX CALCULATION
+* LOOP OVER ENERGY AND ANGLES
+*----
+
+*$OMP PARALLEL DO
+*$OMP+ PRIVATE(ITID,FLUX,M,IG,XNI,XNJ,XNK,Q,Q2,IOF,IER,II,JJ,I,J,K,K0)
+*$OMP+ PRIVATE(IPQD,IBM,SIGMA,V,ISFIX,IX,JX,IY,JY,IZ,JZ,AAA,BBB,CCC,DDD)
+*$OMP+ PRIVATE(IIX,IIY,IIZ,P,IEL)
+*$OMP+ PRIVATE(LHEX,IHEX_XY,IIHEX,DCOORD,ILOZLOOP,ILOZ,IL,I2,JL,J2)
+*$OMP+ PRIVATE(MUHTEMP,MUH,ETAHTEMP,ETAH,XIH,I3,I_FETCH,III,JJJ,IIM,JIM)
+*$OMP+ PRIVATE(TMPXNI,TMPXNJ,TMPXND,TMPXNK)
+*$OMP+ FIRSTPRIVATE(WX,WY,WZ,WX0,WY0,WZ0) SHARED(FUNKNO,IND)
+*$OMP+ REDUCTION(+:FLUX_G) COLLAPSE(2)
+ ! LOOP FOR GROUPS TO EXECUTE IN PARALLEL
+ DO IG=1,NGEFF
+
+ ! LOOP OVER ALL DIRECTIONS
+ DO IPQD=1,NPQD(IND)
+ IF(.NOT.INCONV(IG)) CYCLE
+ M=INDANG(IPQD,IND)
+ IF(W(M).EQ.0.0) CYCLE
+
+ ! GET AND PRINT THREAD NUMBER
+#if defined(_OPENMP)
+ ITID=omp_get_thread_num()
+#else
+ ITID=0
+#endif
+ IF(IMPX.GT.5) WRITE(IUNOUT,500) ITID,NGIND(IG),IPQD
+
+ ! INITIALIZE FLUX AND Z-BOUNDARY FLUXES
+ FLUX(:NM,:NSCT,:3*ISPLH**2,:NHEX,:LZ)=0.0D0
+ TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)=0.0D0
+
+ ! PICK UP BOUNDARY ELEMENTS
+ IF((NCODE(5).NE.1).or.(NCODE(6).NE.1))THEN
+ IOF=(M-1)*(L5) + 1
+ TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)=
+ > RESHAPE(FUNKNO(LFLX+IOF:LFLX+IOF+L5,IG),
+ > (/NMZ,ISPLH,ISPLH,3,NHEX/))
+ ENDIF
+ ! ACCOUNT FOR ALBEDO IN BOUNDARY ELEMENTS
+ IF(IND.LT.7) THEN
+ TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)=
+ > TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)*ZCODE(5)
+ ELSE
+ TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)=
+ > TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)*ZCODE(6)
+ ENDIF
+
+*----
+* LOOP OVER Z-AXIS PLANES
+*----
+
+ DO K0=1,LZ
+ K=K0
+ IF(IND.GE.7) K=LZ+1-K0
+
+ ! INITIALIZE I,J,D-BOUNDARY FLUXES
+ TMPXNI(:NMX,:ISPLH,:NCOL)=0.0D0
+ TMPXNJ(:NMY,:ISPLH,:NCOL)=0.0D0
+ TMPXND(:NMX,:ISPLH,:NCOL)=0.0D0
+
+*----
+* LOOP OVER CARTESIAN MAP OF HEXAGONAL DOMAIN
+*----
+
+ DO JJJ=1,NCOL
+ JIM=JJJ
+ ! Account for different sweep direction depending on angle
+ IF((IND_XY.EQ.1).OR.(IND_XY.EQ.2).OR.(IND_XY.EQ.3)) JIM=NCOL+1-JIM
+
+ DO III=1,NCOL
+ IIM=III
+ ! Account for different sweep direction depending on angle
+ IF((IND_XY.EQ.2).OR.(IND_XY.EQ.3).OR.(IND_XY.EQ.4)) IIM=NCOL+1-IIM
+
+ ! For IND_XY 3 or 6, Cartesian axial coordinate map is swept
+ ! vertically instead of horizontally. IM suffix is for 'IMmutable'
+ I=IIM
+ J=JIM
+ IF((IND_XY.EQ.3).OR.(IND_XY.EQ.6))THEN
+ I=JIM
+ J=IIM
+ ENDIF
+
+ ! If within corners of Cartesian axial coordinate map (where
+ ! there are no hexagons), skip loop
+ IF(TMPMAT(1,1,1,I,J,K).EQ.-1) CYCLE
+
+ ! Find in X-Y plane DRAGON geometry hexagonal index using I and J
+ LHEX=(COORDMAP(1,:).EQ.I .AND. COORDMAP(2,:).EQ.J)
+ IHEX_XY=0
+ DO IIHEX=1,NHEX
+ IF(LHEX(IIHEX)) THEN
+ IHEX_XY=IIHEX
+ EXIT
+ ENDIF
+ ENDDO
+ IF(IHEX_XY.EQ.0) CALL XABORT('SNFBH3: IHEX_XY FAILURE.')
+ ! Find D coordinate
+ DCOORD = ABS(COORDMAP(3,IHEX_XY))-NRINGS
+
+*----
+* LOOP OVER LOZENGES
+*----
+
+ DO ILOZLOOP=1,3
+ ILOZ=LOZSWP(ILOZLOOP,IND_XY)
+
+ ! Get Jacobian elements values
+ AAA = JAC(1,1,ILOZ)
+ BBB = JAC(1,2,ILOZ)
+ CCC = JAC(2,1,ILOZ)
+ DDD = JAC(2,2,ILOZ)
+
+ ! CALL XABORT('SNFBH3: testing 19 ')
+*----
+* LOOP OVER SUBMESH WITHIN EACH LOZENGE
+*----
+ DO IL=1,ISPLH
+ I2=IL
+ ! Account for different sweep direction depending on angle
+ IF((ILOZ.EQ.1).OR.(ILOZ.EQ.2))THEN
+ IF((IND_XY.EQ.2).OR.(IND_XY.EQ.3).OR.(IND_XY.EQ.4))I2=ISPLH+1-I2
+ ELSEIF(ILOZ.EQ.3)THEN
+ IF((IND_XY.EQ.3).OR.(IND_XY.EQ.4).OR.(IND_XY.EQ.5))I2=ISPLH+1-I2
+ ENDIF
+
+ DO JL=1,ISPLH
+ J2=JL
+ ! Account for different sweep direction depending on angle
+ IF((ILOZ.EQ.2).OR.(ILOZ.EQ.3))THEN
+ IF((IND_XY.EQ.4).OR.(IND_XY.EQ.5).OR.(IND_XY.EQ.6))J2=ISPLH+1-J2
+ ELSEIF(ILOZ.EQ.1)THEN
+ IF((IND_XY.EQ.3).OR.(IND_XY.EQ.4).OR.(IND_XY.EQ.5))J2=ISPLH+1-J2
+ ENDIF
+ ! READ IN XNI AND XNJ DEPENDING ON LOZENGE
+ I_FETCH=0
+ IF((ILOZ.EQ.1))THEN
+ ! Read boundary fluxes in reverse for lozenge A since affine
+ ! transformation of lozenges causes the D and I directions
+ ! of lozenges C and A respectively to be reversed
+ I_FETCH=ISPLH+1-I2
+ XNI(:) = TMPXNI(:,J2,J)
+ XNJ(:) = TMPXND(:,I_FETCH,DCOORD)
+ ELSEIF((ILOZ.EQ.2))THEN
+ XNI(:) = TMPXNI(:,J2,J)
+ XNJ(:) = TMPXNJ(:,I2,I)
+ ELSEIF((ILOZ.EQ.3))THEN
+ XNI(:) = TMPXND(:,J2,DCOORD)
+ XNJ(:) = TMPXNJ(:,I2,I)
+ ENDIF
+ XNK(:) = TMPXNK(:,I2,J2,ILOZ,IHEX_XY)
+
+ ! DATA
+ IBM=MAT(I2,J2,ILOZ,IHEX_XY,K)
+ ! Skip loop if virtual element
+ IF(IBM.EQ.0) CYCLE
+ SIGMA=TOTAL(IBM,IG)
+ V=VOL(I2,J2,ILOZ,IHEX_XY,K)
+
+ ! COMPUTE ADJUSTED DIRECTION COSINES
+ MUHTEMP = DA(1,K,M)
+ ETAHTEMP = DB(1,K,M)
+ MUH = (MUHTEMP*DDD) - (ETAHTEMP*BBB)
+ ETAH = (-MUHTEMP*CCC) + (ETAHTEMP*AAA)
+ XIH = DC(1,1,M)
+
+ ! IF(IND.EQ.12) CALL XABORT('SNFBH3: testing 60 ')
+ ! WRITE(*,*) (((((((K-1)*NHEX+(IHEX_XY-1))*3+(ILOZ-1))*ISPLH+
+ ! > (J2-1))*ISPLH+(I2-1))*NSCT+(2-1))*NM)+1
+ ! WRITE(*,*) K, NHEX, IHEX_XY, ILOZ, ISPLH, J2, I2, NSCT, NM
+ ! CALL XABORT('SNFBH3: testing 2')
+ ! SOURCE DENSITY TERM
+ DO IEL=1,NM
+ Q(IEL)=0.0D0
+ DO P=1,NSCT
+ IOF=(((((((K-1)*NHEX+(IHEX_XY-1))*3+(ILOZ-1))*ISPLH+(J2-1))*
+ > ISPLH+(I2-1))*NSCT+(P-1))*NM)+IEL
+ Q(IEL)=Q(IEL)+QEXT(IOF,IG)*MN(M,P)
+ ENDDO
+ ENDDO
+
+ ! CALL XABORT('SNFBH3: testing 17 ')
+ ISFIX=.FALSE.
+ DO WHILE (.NOT.ALL(ISFIX)) ! LOOP FOR ADAPTIVE CALCULATION
+
+ ! FLUX MOMENT COEFFICIENTS MATRIX
+ Q2(:NM,:NM+1)=0.0D0
+ DO IZ=1,IELEM
+ DO JZ=1,IELEM
+ DO IY=1,IELEM
+ DO JY=1,IELEM
+ DO IX=1,IELEM
+ DO JX=1,IELEM
+
+ II=IELEM**2*(IZ-1)+IELEM*(IY-1)+IX
+ JJ=IELEM**2*(JZ-1)+IELEM*(JY-1)+JX
+
+ ! IF(IPQD.EQ.3) CALL XABORT('SNFBH3: testing 69 ')
+ ! CALL XABORT('SNFBH3: testing 17 ')
+ ! DIAGONAL TERMS
+ IF(II.EQ.JJ) THEN
+ Q2(II,JJ)=SIGMA*V
+ 1 +CST(IX)**2*WX(JX+1)*ABS(MUH)
+ 2 +CST(IY)**2*WY(JY+1)*ABS(ETAH)
+ 3 +CST(IZ)**2*WZ(JZ+1)*ABS(XIH)
+
+ ! IF(IND.EQ.12) CALL XABORT('SNFBH3: testing 70 ')
+ ! CALL XABORT('SNFBH3: testing 191 ')
+ ! UPPER DIAGONAL TERMS
+ ELSEIF(II.LT.JJ) THEN
+ ! CALL XABORT('SNFBH3: testing 1919 ')
+ IF(IZ.EQ.JZ) THEN
+ IF(IY.EQ.JY) THEN
+ ! X-SPACE TERMS
+ IF(MOD(IX+JX,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*MUH
+ ELSE
+ Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*ABS(MUH)
+ ENDIF
+ ELSEIF(IX.EQ.JX) THEN
+ ! Y-SPACE TERMS
+ IF(MOD(IY+JY,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*ETAH
+ ELSE
+ Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*ABS(ETAH)
+ ENDIF
+ ENDIF
+ ELSEIF(IY.EQ.JY.AND.IX.EQ.JX) THEN
+ ! Z-SPACE TERMS
+ IF(MOD(IZ+JZ,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IZ)*CST(JZ)*WZ(JZ+1)*XIH
+ ELSE
+ Q2(II,JJ)=CST(IZ)*CST(JZ)*WZ(JZ+1)*ABS(XIH)
+ ENDIF
+ ENDIF
+ ! IF(IND.EQ.12) CALL XABORT('SNFBH3: testing 75 ')
+ ! CALL XABORT('SNFBH3: testing 19 ')
+
+ ! UNDER DIAGONAL TERMS
+ ELSE
+ ! CALL XABORT('SNFBH3: testing 1920 ')
+ IF(IZ.EQ.JZ) THEN
+ IF(IY.EQ.JY) THEN
+ ! X-SPACE TERMS
+ IF(MOD(IX+JX,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IX)*CST(JX)*(WX(JX+1)-2)*MUH
+ ELSE
+ Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*ABS(MUH)
+ ENDIF
+ ELSEIF(IX.EQ.JX) THEN
+ ! Y-SPACE TERMS
+ IF(MOD(IY+JY,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IY)*CST(JY)*(WY(JY+1)-2)*ETAH
+ ELSE
+ Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*ABS(ETAH)
+ ENDIF
+ ENDIF
+ ELSEIF(IY.EQ.JY.AND.IX.EQ.JX) THEN
+ ! Z-SPACE TERMS
+ IF(MOD(IZ+JZ,2).EQ.1) THEN
+ Q2(II,JJ)=CST(IZ)*CST(JZ)*(WZ(JZ+1)-2)*XIH
+ ELSE
+ Q2(II,JJ)=CST(IZ)*CST(JZ)*WZ(JZ+1)*ABS(XIH)
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDDO
+ ENDDO
+ ENDDO
+ ENDDO
+ ENDDO
+ ENDDO
+
+ ! FLUX SOURCE VECTOR
+ DO IZ=1,IELEM
+ DO IY=1,IELEM
+ DO IX=1,IELEM
+ II=IELEM**2*(IZ-1)+IELEM*(IY-1)+IX
+ IIX=IELEM*(IZ-1)+IY
+ IIY=IELEM*(IZ-1)+IX
+ IIZ=IELEM*(IY-1)+IX
+ Q2(II,NM+1)=Q(II)*V
+ ! X-SPACE TERMS
+ IF(MOD(IX,2).EQ.1) THEN
+ Q2(II,NM+1)=Q2(II,NM+1)+CST(IX)*(1-WX(1))
+ 1 *XNI(IIX)*ABS(MUH)
+ ELSE
+ Q2(II,NM+1)=Q2(II,NM+1)-CST(IX)*(1+WX(1))
+ 1 *XNI(IIX)*MUH
+ ENDIF
+ ! Y-SPACE TERMS
+ IF(MOD(IY,2).EQ.1) THEN
+ Q2(II,NM+1)=Q2(II,NM+1)+CST(IY)*(1-WY(1))
+ 1 *XNJ(IIY)*ABS(ETAH)
+ ELSE
+ Q2(II,NM+1)=Q2(II,NM+1)-CST(IY)*(1+WY(1))
+ 1 *XNJ(IIY)*ETAH
+ ENDIF
+ ! Z-SPACE TERMS
+ IF(MOD(IZ,2).EQ.1) THEN
+ Q2(II,NM+1)=Q2(II,NM+1)+CST(IZ)*(1-WZ(1))
+ 1 *XNK(IIZ)*ABS(XIH)
+ ELSE
+ Q2(II,NM+1)=Q2(II,NM+1)-CST(IZ)*(1+WZ(1))
+ 1 *XNK(IIZ)*XIH
+ ENDIF
+ ENDDO
+ ENDDO
+ ENDDO
+
+ CALL ALSBD(NM,1,Q2,IER,NM)
+ IF(IER.NE.0) CALL XABORT('SNFBH3: SINGULAR MATRIX.')
+
+ ! ADAPTIVE CORRECTION OF WEIGHTING PARAMETERS
+ IF(ANY(ISADPT)) THEN
+ IF(ISADPT(1)) THEN
+ CALL SNADPT(IELEM,NM,IELEM**2,Q2(1:IELEM:1,NM+1),
+ 1 XNI(:NMX),1.0,WX,ISFIX(1))
+ ELSE
+ ISFIX(1)=.TRUE.
+ ENDIF
+ IF(ISADPT(2)) THEN
+ CALL SNADPT(IELEM,NM,IELEM**2,Q2(1:IELEM**2:IELEM,NM+1),
+ 1 XNJ(:NMY),1.0,WY,ISFIX(2))
+ ELSE
+ ISFIX(2)=.TRUE.
+ ENDIF
+ IF(ISADPT(3)) THEN
+ CALL SNADPT(IELEM,NM,IELEM**2,Q2(1:NM:IELEM**2,NM+1),
+ 1 XNK(:NMZ),1.0,WZ,ISFIX(3))
+ ELSE
+ ISFIX(3)=.TRUE.
+ ENDIF
+ ELSE
+ ISFIX=.TRUE.
+ ENDIF
+
+ END DO ! END OF ADAPTIVE LOOP
+
+ ! CLOSURE RELATIONS
+ IF(IELEM.EQ.1.AND.LFIXUP.AND.(Q2(1,2).LE.RLOG)) Q2(1,2)=0.0
+ ! Read XNI/XNI/XNK into TMPXNI/J/D/K
+ IF((ILOZ.EQ.1).OR.(ILOZ.EQ.2))THEN
+ TMPXNI(:NMX,J2,J)=WX(1)*XNI(:NMX)
+ ELSE
+ TMPXND(:NMX,J2,DCOORD)=WX(1)*XNI(:NMX)
+ ENDIF
+ IF((ILOZ.EQ.2).OR.(ILOZ.EQ.3))THEN
+ TMPXNJ(:NMY,I2,I)=WY(1)*XNJ(:NMY)
+ ELSE
+ I3=I_FETCH
+ TMPXND(:NMY,I3,DCOORD)=WY(1)*XNJ(:NMY)
+ ENDIF
+ TMPXNK(:NMZ,I2,J2,ILOZ,IHEX_XY)=WZ(1)*XNK(:NMZ)
+ DO IZ=1,IELEM
+ DO IY=1,IELEM
+ DO IX=1,IELEM
+ II=IELEM**2*(IZ-1)+IELEM*(IY-1)+IX
+ IIX=IELEM*(IZ-1)+IY
+ IIY=IELEM*(IZ-1)+IX
+ IIZ=IELEM*(IY-1)+IX
+ ! X-SPACE
+ ! Assign I-boundary fluxes if lozenges A or B
+ IF((ILOZ.EQ.1).OR.(ILOZ.EQ.2))THEN
+ IF(MOD(IX,2).EQ.1) THEN
+ TMPXNI(IIX,J2,J)=TMPXNI(IIX,J2,J)+CST(IX)*WX(IX+1)
+ 1 *Q2(II,NM+1)
+ ELSE
+ TMPXNI(IIX,J2,J)=TMPXNI(IIX,J2,J)+CST(IX)*WX(IX+1)
+ 1 *Q2(II,NM+1)*SIGN(1.0,MUH)
+ ENDIF
+ ENDIF
+ ! Y-SPACE
+ ! Assign J-boundary fluxes if lozenges B or C
+ IF((ILOZ.EQ.2).OR.(ILOZ.EQ.3))THEN
+ IF(MOD(IY,2).EQ.1) THEN
+ TMPXNJ(IIY,I2,I)=TMPXNJ(IIY,I2,I)+CST(IY)*WY(IY+1)
+ 1 *Q2(II,NM+1)
+ ELSE
+ TMPXNJ(IIY,I2,I)=TMPXNJ(IIY,I2,I)+CST(IY)*WY(IY+1)
+ 1 *Q2(II,NM+1)*SIGN(1.0,ETAH)
+ ENDIF
+ ENDIF
+ ! D-SPACE
+ ! Assign D-boundary fluxes if lozenge A using XNJ
+ IF((ILOZ.EQ.1))THEN
+ I3=I_FETCH
+ IF(MOD(IY,2).EQ.1) THEN
+ TMPXND(IIY,I3,DCOORD)=TMPXND(IIY,I3,DCOORD)+CST(IY)*WY(IY+1)
+ 1 *Q2(II,NM+1)
+ ELSE
+ TMPXND(IIY,I3,DCOORD)=TMPXND(IIY,I3,DCOORD)+CST(IY)*WY(IY+1)
+ 1 *Q2(II,NM+1)*SIGN(1.0,ETAH)
+ ENDIF
+ ENDIF
+ ! Assign D-boundary fluxes if lozenge C using XNI
+ IF((ILOZ.EQ.3))THEN
+ IF(MOD(IX,2).EQ.1) THEN
+ TMPXND(IIX,J2,DCOORD)=TMPXND(IIX,J2,DCOORD)+CST(IX)*WX(IX+1)
+ 1 *Q2(II,NM+1)
+ ELSE
+ TMPXND(IIX,J2,DCOORD)=TMPXND(IIX,J2,DCOORD)+CST(IX)*WX(IX+1)
+ 1 *Q2(II,NM+1)*SIGN(1.0,MUH)
+ ENDIF
+ ENDIF
+ ! Z-SPACE
+ IF(MOD(IZ,2).EQ.1) THEN
+ TMPXNK(IIZ,I2,J2,ILOZ,IHEX_XY)=TMPXNK(IIZ,I2,J2,ILOZ,IHEX_XY)
+ 1 +CST(IZ)*WZ(IZ+1)*Q2(II,NM+1)
+ ELSE
+ TMPXNK(IIZ,I2,J2,ILOZ,IHEX_XY)=TMPXNK(IIZ,I2,J2,ILOZ,IHEX_XY)
+ 1 +CST(IZ)*WZ(IZ+1)*Q2(II,NM+1)*SIGN(1.0,XIH)
+ ENDIF
+ ENDDO
+ ENDDO
+ ENDDO
+ ! FLIP GRADIENTS IF NECESSARY
+ DO IZ=1,IELEM
+ DO IY=1,IELEM
+ IIX=IELEM*(IZ-1)+IY
+ IF((MOD(IY,2).EQ.0).AND.(ILOZ.EQ.3).AND.(IL.EQ.ISPLH))
+ 1 TMPXND(IIX,J2,DCOORD)=TMPXND(IIX,J2,DCOORD)*(-1)
+ ENDDO
+ ENDDO
+ I3=I_FETCH
+ DO IZ=1,IELEM
+ DO IX=1,IELEM
+ IIY=IELEM*(IZ-1)+IX
+ IF((MOD(IX,2).EQ.0).AND.(ILOZ.EQ.1).AND.(JL.EQ.ISPLH))
+ 1 TMPXND(IIY,I3,DCOORD)=TMPXND(IIY,I3,DCOORD)*(-1)
+ ENDDO
+ ENDDO
+ ! LFIXUP
+ IF(IELEM.EQ.1.AND.LFIXUP)THEN
+ IF((ILOZ.EQ.1).OR.(ILOZ.EQ.2))THEN
+ IF(TMPXNI(1,J2,J).LE.RLOG) TMPXNI(1,J2,J)=0.0
+ ELSE
+ IF(TMPXND(1,J2,DCOORD).LE.RLOG) TMPXND(1,J2,DCOORD)=0.0
+ ENDIF
+ IF((ILOZ.EQ.2).OR.(ILOZ.EQ.3))THEN
+ IF(TMPXNJ(1,I2,I).LE.RLOG) TMPXNJ(1,I2,I)=0.0
+ ELSE
+ I3=I_FETCH
+ IF(TMPXND(1,I3,DCOORD).LE.RLOG) TMPXND(1,I3,DCOORD)=0.0
+ ENDIF
+ IF(TMPXNK(1,I2,J2,ILOZ,IHEX_XY).LE.RLOG)
+ 1 TMPXNK(1,I2,J2,ILOZ,IHEX_XY)=0.0
+ ENDIF
+ WX=WX0
+ WY=WY0
+ WZ=WZ0
+
+ ! SAVE LEGENDRE MOMENT OF THE FLUX
+ IOF=((ILOZ-1)*ISPLH+(J2-1))*ISPLH+I2
+ DO P=1,NSCT
+ DO IEL=1,NM
+ FLUX(IEL,P,IOF,IHEX_XY,K) = FLUX(IEL,P,IOF,IHEX_XY,K)
+ 1 +Q2(IEL,NM+1)*DN(P,M)
+ ENDDO
+ ENDDO
+
+ ENDDO ! END OF WITHIN LOZENGE J-LOOP
+ ENDDO ! END OF WITHIN LOZENGE I-LOOP
+
+ ENDDO ! END OF LOZENGE LOOP
+
+ ENDDO ! END OF I COLUMNS OF CARTESIAN MAP LOOP
+ ENDDO ! END OF J COLUMNS OF CARTESIAN MAP LOOP
+ ENDDO ! END OF Z-LOOP
+
+ ! SAVE FLUX INFORMATION
+ FLUX_G(:,:,:,:,:,IG)=FLUX_G(:,:,:,:,:,IG)+FLUX(:,:,:,:,:)
+
+ ! SAVE K-BOUNDARY CONDITIONS IF NOT VOID B.C.
+ IF((NCODE(5).NE.1).or.(NCODE(6).NE.1))THEN
+ IOF=(M-1)*(L5)
+ FUNKNO(LFLX+IOF+1:LFLX+IOF+L5,IG)=
+ > RESHAPE(REAL(TMPXNK(:NMZ,:ISPLH,:ISPLH,:3,:NHEX)),
+ > (/L5/))
+ ENDIF
+
+ ENDDO ! END OF DIRECTION LOOP
+ ENDDO ! END OF ENERGY LOOP
+*$OMP END PARALLEL DO
+ ENDDO ! END OF OCTANT LOOP
+
+ ! SAVE FLUX INFORMATION
+ DO IG=1,NGEFF
+ IF(.NOT.INCONV(IG)) CYCLE
+ FUNKNO(:LFLX,IG)=
+ 1 RESHAPE(REAL(FLUX_G(:NM,:NSCT,:3*ISPLH**2,:NHEX,:LZ,IG)),
+ 2 (/LFLX/))
+ ENDDO
+*----
+* SCRATCH STORAGE DEALLOCATION
+*----
+ DEALLOCATE(FLUX_G,FLUX,INDANG,TMPXNI,TMPXNJ,TMPXND,TMPXNK,TMPMAT)
+ RETURN
+ 500 FORMAT(16H SNFBH3: thread=,I8,12H --->(group=,I4,7H angle=,I4,1H))
+ END