*DECK SNFBC2 SUBROUTINE SNFBC2(NUN,NGEFF,IMPX,INCONV,NGIND,LX,LY,IELEM,NM,NMX, 1 NMY,NMAT,NPQ,NSCT,MAT,VOL,TOTAL,NCODE,ZCODE,QEXT,LFIXUP,DU,DE,W, 2 MRM,MRMY,DB,DA,MN,DN,WX,WY,CST,ISADPT,ISBS,NBS,ISBSM,BS,MAXL, 3 FUNKNO) * *----------------------------------------------------------------------- * *Purpose: * Perform one inner iteration for solving SN equations in 2D Cartesian * geometry for the HODD method. Energy-angle multithreading. Albedo * boundary conditions. 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. * LX number of meshes along X axis. * LY number of meshes along Y 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 and energy for flux components * NMX number of moments for X axis boundaries components * NMY number of moments for Y axis boundaries components * NMAT number of material mixtures. * NPQ number of SN directions in four octants (including zero-weight * directions). * 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. * NCODE boundary condition indices. * ZCODE albedos. * QEXT Legendre components of the fixed source. * LFIXUP flag to enable negative flux fixup. * DU first direction cosines ($\\mu$). * DE second direction cosines ($\\eta$). * W weights. * MRM quadrature index. * MRMY quadrature index. * DB diamond-scheme parameter. * DA diamond-scheme parameter. * MN moment-to-discrete matrix. * DN discrete-to-moment matrix. * ISBS flag to indicate the presence or not of boundary fixed * sources. * NBS number of boundary fixed sources. * ISBSM flag array to indicate the presence or not of boundary fixed * source in each unit surface. * BS boundary source array with their intensities. * MAXL maximum size of boundary source array. * WX spatial X axis closure relation weighting factors. * WY spatial Y axis closure relation weighting factors. * CST constants for the polynomial approximations. * ISADPT flag to enable/disable adaptive flux calculations.\ * *Parameters: input/output * FUNKNO Legendre components of the flux and boundary fluxes. * FLUXC flux at the cutoff energy. * *----------------------------------------------------------------------- #if defined(_OPENMP) USE omp_lib #endif * *---- * SUBROUTINE ARGUMENTS *---- INTEGER NUN,NGEFF,IMPX,NGIND(NGEFF),LX,LY,IELEM,NM,NMX,NMY,NMAT, 1 NPQ,NSCT,MAT(LX,LY),NCODE(4),MRM(NPQ),MRMY(NPQ),ISBS,NBS, 2 ISBSM(4*ISBS,NPQ*ISBS,NGEFF*ISBS),MAXL LOGICAL INCONV(NGEFF) REAL VOL(LX,LY),TOTAL(0:NMAT,NGEFF),ZCODE(4),QEXT(NUN,NGEFF), 1 DU(NPQ),DE(NPQ),W(NPQ),DB(LX,NPQ),DA(LX,LY,NPQ), 2 FUNKNO(NUN,NGEFF),BS(MAXL*ISBS,NBS*ISBS),WX(IELEM+1), 3 WY(IELEM+1),CST(IELEM),MN(NPQ,NSCT),DN(NSCT,NPQ) LOGICAL LFIXUP,ISADPT(2) *---- * LOCAL VARIABLES *---- INTEGER NPQD(4),IIND(4),P REAL WX0(IELEM+1),WY0(IELEM+1) DOUBLE PRECISION Q(NM),Q2(NM,NM+1),XNJ(NMY),V PARAMETER(IUNOUT=6,RLOG=1.0E-8,PI=3.141592654) LOGICAL ISFIX(2) *---- * ALLOCATABLE ARRAYS *---- INTEGER, ALLOCATABLE, DIMENSION(:,:) :: INDANG DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:,:,:) :: FLUX DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:,:,:,:) :: FLUX_G DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:) :: XNI *---- * SCRATCH STORAGE ALLOCATION *---- ALLOCATE(INDANG(NPQ,4)) ALLOCATE(XNI(NMX,LY),FLUX(NM,NSCT,LX,LY)) ALLOCATE(FLUX_G(NM,NSCT,LX,LY,NGEFF)) *---- * LENGTH OF FUNKNO COMPONENTS (IN ORDER) *---- LFLX=NM*LX*LY*NSCT LXNI=NMX*LY*NPQ LXNJ=NMY*LX*NPQ *---- * SET OCTANT SWAPPING ORDER. *---- NPQD(:4)=0 INDANG(:NPQ,:4)=0 IIND(:)=0 DO M=1,NPQ VU=DU(M) VE=DE(M) IF(W(M).EQ.0) CYCLE IF((VU.GE.0.0).AND.(VE.GE.0.0)) THEN IND=1 JND=4 ELSE IF((VU.LE.0.0).AND.(VE.GE.0.0)) THEN IND=2 JND=3 ELSE IF((VU.LE.0.0).AND.(VE.LE.0.0)) THEN IND=3 JND=1 ELSE IND=4 JND=2 ENDIF IIND(JND)=IND NPQD(IND)=NPQD(IND)+1 INDANG(NPQD(IND),IND)=M ENDDO *---- * MAIN LOOP OVER OCTANTS. *---- FLUX_G(:NM,:NSCT,:LX,:LY,:NGEFF)=0.0D0 WX0=WX WY0=WY DO 190 JND=1,4 IND=IIND(JND) *---- * PRELIMINARY LOOPS FOR SETTING BOUNDARY CONDITIONS. *---- *$OMP PARALLEL DO *$OMP+ PRIVATE(M,IG,VU,VE,M1,IOF,JOF,IEL,I,J,IPQD) *$OMP+ SHARED(FUNKNO) COLLAPSE(2) DO 70 IG=1,NGEFF DO 60 IPQD=1,NPQD(IND) IF(.NOT.INCONV(IG)) GO TO 60 M=INDANG(IPQD,IND) VU=DU(M) VE=DE(M) ! X-BOUNDARY IF(VU.GT.0.0)THEN M1=MRM(M) IF((NCODE(1).NE.4))THEN DO IEL=1,NMX DO J=1,LY IOF=((M-1)*LY+(J-1))*NMX+IEL JOF=((M1-1)*LY+(J-1))*NMX+IEL FUNKNO(LFLX+IOF,IG)=FUNKNO(LFLX+JOF,IG) ENDDO ENDDO ENDIF ELSEIF(VU.LT.0.0)THEN M1=MRM(M) IF((NCODE(2).NE.4))THEN DO IEL=1,NMX DO J=1,LY IOF=((M-1)*LY+(J-1))*NMX+IEL JOF=((M1-1)*LY+(J-1))*NMX+IEL FUNKNO(LFLX+IOF,IG)=FUNKNO(LFLX+JOF,IG) ENDDO ENDDO ENDIF ENDIF ! Y-BOUNDARY IF(VE.GT.0.0)THEN M1=MRMY(M) IF((NCODE(3).NE.4))THEN DO IEL=1,NMY DO I=1,LX IOF=((M-1)*LX+(I-1))*NMY+IEL JOF=((M1-1)*LX+(I-1))*NMY+IEL FUNKNO(LFLX+LXNI+IOF,IG)= > FUNKNO(LFLX+LXNI+JOF,IG) ENDDO ENDDO ENDIF ELSEIF(VE.LT.0.0)THEN M1=MRMY(M) IF((NCODE(4).NE.4))THEN DO IEL=1,NMY DO I=1,LX IOF=((M-1)*LX+(I-1))*NMY+IEL JOF=((M1-1)*LX+(I-1))*NMY+IEL FUNKNO(LFLX+LXNI+IOF,IG)= > FUNKNO(LFLX+LXNI+JOF,IG) ENDDO ENDDO ENDIF ENDIF 60 CONTINUE 70 CONTINUE *OMP END PARALLEL DO *---- * MAIN SWAPPING LOOPS FOR SN FLUX CALCULATION *---- *$OMP PARALLEL DO *$OMP+ PRIVATE(ITID,FLUX,M,IG,XNI,XNJ,Q,Q2,IOF,IER,II,JJ,IEL,I,J,P) *$OMP+ PRIVATE(IPQD,I0,J0,IBM,SIGMA,V,ISFIX,IX,JX,IY,JY) *$OMP+ FIRSTPRIVATE(WX,WY,WX0,WY0) SHARED(FUNKNO) *$OMP+ REDUCTION(+:FLUX_G) COLLAPSE(2) ! LOOP FOR GROUPS TO EXECUTE IN PARALLEL DO 180 IG=1,NGEFF ! LOOP OVER ALL DIRECTIONS DO 170 IPQD=1,NPQD(IND) IF(.NOT.INCONV(IG)) GO TO 170 M=INDANG(IPQD,IND) IF(W(M).EQ.0.0) GO TO 170 ! GET AND PRINT THREAD NUMBER #if defined(_OPENMP) ITID=omp_get_thread_num() #else ITID=0 #endif IF(IMPX.GT.5) WRITE(IUNOUT,400) ITID,NGIND(IG),IPQD ! INITIALIZE FLUXES FLUX(:NM,:NSCT,:LX,:LY)=0.0D0 *---- * LOOP OVER X- AND Y-DIRECTED AXES. *---- ! X-AXIS LOOP DO 155 I0=1,LX I=I0 IF((IND.EQ.2).OR.(IND.EQ.3)) I=LX+1-I ! Y-BOUNDARIES CONDITIONS XNJ=0.0 DO IEL=1,NMY IOF=(M-1)*NMY*LX+(I-1)*NMY+IEL IF((IND.EQ.1).OR.(IND.EQ.2)) THEN XNJ(IEL)=FUNKNO(LFLX+LXNI+IOF,IG)*ZCODE(3) ELSE XNJ(IEL)=FUNKNO(LFLX+LXNI+IOF,IG)*ZCODE(4) ENDIF ENDDO ! Y-BOUNDARIES FIXED SOURCES IF(ISBS.EQ.1) THEN IF((IND.EQ.3.OR.IND.EQ.4).AND.ISBSM(4,M,IG).NE.0) THEN XNJ(1)=XNJ(1)+BS(I,ISBSM(4,M,IG)) ELSE IF((IND.EQ.1.OR.IND.EQ.2).AND.ISBSM(3,M,IG).NE.0) THEN XNJ(1)=XNJ(1)+BS(I,ISBSM(3,M,IG)) ENDIF ENDIF ! Y-AXIS LOOP DO 140 J0=1,LY J=J0 IF((IND.EQ.3).OR.(IND.EQ.4)) J=LY+1-J ! X-BOUNDARIES CONDITIONS IF(I0.EQ.1) THEN XNI(:NMX,J)=0.0 DO IEL=1,NMX IOF=(M-1)*NMX*LY+(J-1)*NMX+IEL IF((IND.EQ.1).OR.(IND.EQ.4)) THEN XNI(IEL,J)=FUNKNO(LFLX+IOF,IG)*ZCODE(1) ELSE XNI(IEL,J)=FUNKNO(LFLX+IOF,IG)*ZCODE(2) ENDIF ENDDO ENDIF ! X-BOUNDARIES FIXED SOURCES IF(ISBS.EQ.1.AND.I0.EQ.1) THEN IF((IND.EQ.2.OR.IND.EQ.3).AND.ISBSM(2,M,IG).NE.0) THEN XNI(1,J)=XNI(1,J)+BS(J,ISBSM(2,M,IG)) ELSE IF((IND.EQ.1.OR.IND.EQ.4).AND.ISBSM(1,M,IG).NE.0) THEN XNI(1,J)=XNI(1,J)+BS(J,ISBSM(1,M,IG)) ENDIF ENDIF ! DATA IBM=MAT(I,J) IF(IBM.EQ.0) GO TO 140 SIGMA=TOTAL(IBM,IG) V=VOL(I,J) ! SOURCE DENSITY TERM DO IEL=1,NM Q(IEL)=0.0D0 DO P=1,NSCT IOF=((J-1)*LX*NSCT+(I-1)*NSCT+(P-1))*NM+IEL Q(IEL)=Q(IEL)+QEXT(IOF,IG)*MN(M,P) ENDDO ENDDO ISFIX=.FALSE. DO WHILE (.NOT.ALL(ISFIX)) ! LOOP FOR ADAPTIVE CALCULATION ! FLUX MOMENT COEFFICIENTS MATRIX Q2(:NM,:NM+1)=0.0D0 DO IY=1,IELEM DO JY=1,IELEM DO IX=1,IELEM DO JX=1,IELEM II=IELEM*(IY-1)+IX JJ=IELEM*(JY-1)+JX ! DIAGONAL TERMS IF(II.EQ.JJ) THEN Q2(II,JJ)=SIGMA*V 1 +CST(IX)**2*WX(JX+1)*ABS(DA(I,J,M)) 2 +CST(IY)**2*WY(JY+1)*ABS(DB(I,M)) ! UPPER DIAGONAL TERMS ELSEIF(II.LT.JJ) THEN ! X-SPACE TERMS IF(IY.EQ.JY) THEN IF(MOD(IX+JX,2).EQ.1) THEN Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*DA(I,J,M) ELSE Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*ABS(DA(I,J,M)) ENDIF ! Y-SPACE TERMS ELSEIF(IX.EQ.JX) THEN IF(MOD(IY+JY,2).EQ.1) THEN Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*DB(I,M) ELSE Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*ABS(DB(I,M)) ENDIF ENDIF ! UNDER DIAGONAL TERMS ELSE ! X-SPACE TERMS IF(IY.EQ.JY) THEN IF(MOD(IX+JX,2).EQ.1) THEN Q2(II,JJ)=CST(IX)*CST(JX)*(WX(JX+1)-2)*DA(I,J,M) ELSE Q2(II,JJ)=CST(IX)*CST(JX)*WX(JX+1)*ABS(DA(I,J,M)) ENDIF ! Y-SPACE TERMS ELSEIF(IX.EQ.JX) THEN IF(MOD(IY+JY,2).EQ.1) THEN Q2(II,JJ)=CST(IY)*CST(JY)*(WY(JY+1)-2)*DB(I,M) ELSE Q2(II,JJ)=CST(IY)*CST(JY)*WY(JY+1)*ABS(DB(I,M)) ENDIF ENDIF ENDIF ENDDO ENDDO ENDDO ENDDO ! FLUX SOURCE VECTOR DO IY=1,IELEM DO IX=1,IELEM II=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(IY,J)*ABS(DA(I,J,M)) ELSE Q2(II,NM+1)=Q2(II,NM+1)-CST(IX)*(1+WX(1)) 1 *XNI(IY,J)*DA(I,J,M) 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(IX)*ABS(DB(I,M)) ELSE Q2(II,NM+1)=Q2(II,NM+1)-CST(IY)*(1+WY(1)) 1 *XNJ(IX)*DB(I,M) ENDIF ENDDO ENDDO CALL ALSBD(NM,1,Q2,IER,NM) IF(IER.NE.0) CALL XABORT('SNFBC2: SINGULAR MATRIX.') ! ADAPTIVE CORRECTION OF WEIGHTING PARAMETERS IF(ANY(ISADPT)) THEN IF(ISADPT(1)) THEN CALL SNADPT(IELEM,NM,IELEM,Q2(1:IELEM:1,NM+1), 1 XNI(:NMX,J),1.0,WX,ISFIX(1)) ELSE ISFIX(1)=.TRUE. ENDIF IF(ISADPT(2)) THEN CALL SNADPT(IELEM,NM,IELEM,Q2(1:NM:IELEM,NM+1), 1 XNJ,1.0,WY,ISFIX(2)) ELSE ISFIX(2)=.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 XNI(:NMX,J)=WX(1)*XNI(:NMX,J) XNJ(:NMY)=WY(1)*XNJ(:NMY) DO IY=1,IELEM DO IX=1,IELEM II=IELEM*(IY-1)+IX ! X-SPACE IF(MOD(IX,2).EQ.1) THEN XNI(IY,J)=XNI(IY,J)+CST(IX)*WX(IX+1) 1 *Q2(II,NM+1) ELSE XNI(IY,J)=XNI(IY,J)+CST(IX)*WX(IX+1) 1 *Q2(II,NM+1)*SIGN(1.0,DA(I,J,M)) ENDIF ! Y-SPACE IF(MOD(IY,2).EQ.1) THEN XNJ(IX)=XNJ(IX)+CST(IY)*WY(IY+1) 1 *Q2(II,NM+1) ELSE XNJ(IX)=XNJ(IX)+CST(IY)*WY(IY+1) 1 *Q2(II,NM+1)*SIGN(1.0,DB(I,M)) ENDIF ENDDO ENDDO IF(IELEM.EQ.1.AND.LFIXUP.AND.(XNI(1,J).LE.RLOG)) XNI(1,J)=0.0 IF(IELEM.EQ.1.AND.LFIXUP.AND.(XNJ(1).LE.RLOG)) XNJ(1)=0.0 WX=WX0 WY=WY0 ! SAVE LEGENDRE MOMENT OF THE FLUX DO P=1,NSCT DO IEL=1,NM FLUX(IEL,P,I,J)=FLUX(IEL,P,I,J)+Q2(IEL,NM+1)*DN(P,M) ENDDO ENDDO 140 CONTINUE ! END OF Y-LOOP ! SAVE Y-BOUNDARY CONDITIONS DO IEL=1,NMY IOF=(M-1)*NMY*LX+(I-1)*NMY+IEL FUNKNO(LFLX+LXNI+IOF,IG)=REAL(XNJ(IEL)) ENDDO 155 CONTINUE ! END OF X-LOOP ! SAVE X-BOUNDARY CONDITIONS DO J=1,LY DO IEL=1,NMX IOF=(M-1)*NMX*LY+(J-1)*NMX+IEL FUNKNO(LFLX+IOF,IG)=REAL(XNI(IEL,J)) ENDDO ENDDO ! SAVE FLUX INFORMATION FLUX_G(:,:,:,:,IG)=FLUX_G(:,:,:,:,IG)+FLUX(:,:,:,:) 170 CONTINUE ! END OF DIRECTION LOOP 180 CONTINUE ! END OF ENERGY LOOP *$OMP END PARALLEL DO 190 CONTINUE ! END OF OCTANT LOOP ! SAVE FLUX INFORMATION DO 200 IG=1,NGEFF IF(.NOT.INCONV(IG)) GO TO 200 FUNKNO(:LFLX,IG)= 1 RESHAPE(REAL(FLUX_G(:NM,:NSCT,:LX,:LY,IG)), 2 (/ LFLX /) ) 200 CONTINUE ! CALL XABORT('SNFBC2: testing') *---- * SCRATCH STORAGE DEALLOCATION *---- DEALLOCATE(XNI,FLUX_G,FLUX,INDANG) RETURN 400 FORMAT(16H SNFBC2: thread=,I8,12H --->(group=,I4,7H angle=,I4,1H)) END