From e84a81a4bba706f2c48913c553128a547c5eb941 Mon Sep 17 00:00:00 2001 From: Antoine Hoffmann <antoine.hoffmann@epfl.ch> Date: Fri, 5 May 2023 16:09:16 +0200 Subject: [PATCH] monomial closure done, no convincing results --- Makefile | 3 +- fort.90 | 2 +- src/CLA_mod.F90 | 190 ++++++++++++++++++++++++++++---------------- src/closure_mod.F90 | 98 ++++++++++++++++++----- src/diagnose.F90 | 6 +- 5 files changed, 207 insertions(+), 92 deletions(-) diff --git a/Makefile b/Makefile index 1316ceff..06b6ca82 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,6 @@ test_svd: F90 = mpif90 test_svd: F90FLAGS = -DTEST_SVD -O3 test_svd: EXEC = $(BINDIR)/gyacomo23_test_svd test_svd: dirs src/srcinfo.h -test_svd: dirs src/srcinfo.h test_svd: compile # subroutines dirs: @@ -148,7 +147,7 @@ $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o $(OBJDIR)/CLA_mod.o $(OBJDIR)/closure_mod.o : src/closure_mod.F90 \ $(OBJDIR)/model_mod.o $(OBJDIR)/basic_mod.o $(OBJDIR)/grid_mod.o \ - $(OBJDIR)/array_mod.o $(OBJDIR)/fields_mod.o + $(OBJDIR)/array_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/CLA_mod.o $(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/closure_mod.F90 -o $@ $(OBJDIR)/collision_mod.o : src/collision_mod.F90 \ diff --git a/fort.90 b/fort.90 index b3a5e9fa..88f8dbfb 100644 --- a/fort.90 +++ b/fort.90 @@ -8,7 +8,7 @@ &GRID pmax = 4 jmax = 2 - Nx = 128 + Nx = 64 Lx = 200 Ny = 48 Ly = 60 diff --git a/src/CLA_mod.F90 b/src/CLA_mod.F90 index 16acc115..0729a947 100644 --- a/src/CLA_mod.F90 +++ b/src/CLA_mod.F90 @@ -5,8 +5,9 @@ module CLA ! closure USE prec_const USE parallel + USE FMZM ! For factorial implicit none - ! LOCAL VARIABLES + ! local variables for DLRA and SVD COMPLEX(xp), DIMENSION(:,:), ALLOCATABLE :: A_buff,Bf,Br ! buffer and full/reduced rebuilt matrices COMPLEX(xp), DIMENSION(:,:), ALLOCATABLE :: U ! basis REAL(xp), DIMENSION(:), ALLOCATABLE :: Sf, Sr ! full and reduced singular values @@ -15,103 +16,158 @@ module CLA COMPLEX(xp), DIMENSION(:), ALLOCATABLE :: work REAL(xp), DIMENSION(:), ALLOCATABLE :: rwork - REAL(xp), DIMENSION(:), ALLOCATABLE :: ln ! Laguerre coefficients - REAL(xp), DIMENSION(:), ALLOCATABLE :: hn ! Hermite coefficients + ! local variables for monomial truncation (Hermite and Laguerre coeff) + ! Coeff for the linear combination of the monomial truncation scheme + REAL(xp), PUBLIC, PROTECTED, DIMENSION(:), ALLOCATABLE :: c_Pp1, c_Pp2, c_Jp1 + #ifdef TEST_SVD ! These routines are meant for testing SVD filtering PUBLIC :: init_CLA, filter_sv_moments_ky_pj, test_SVD #endif - PUBLIC :: invert_utr_matrix, build_hermite_matrix, build_laguerre_matrix + PUBLIC :: set_monomial_trunc_coeff CONTAINS !--------------Routines to compute coeff for monomial truncation---------- - ! Invert an upper triangular matrix - SUBROUTINE invert_utr_matrix(U,invU) + SUBROUTINE set_monomial_trunc_coeff(Pmax,Jmax) IMPLICIT NONE - REAL(xp), DIMENSION(:,:), INTENT(IN) :: U ! Matrix to invert - REAL(xp), DIMENSION(:,:), INTENT(OUT) :: invU! Result + INTEGER, INTENT(IN) :: Pmax,Jmax ! truncation degree (p,j>d are not evolved) + REAL(xp), DIMENSION(Pmax+3,Pmax+3) :: HH, iHH ! Hermite matrix to invert (+1 dim for p=0 and +2 dim for coeff P+1,P+2) + REAL(xp), DIMENSION(Jmax+2,Jmax+2) :: LL, iLL ! Laguerre matrix to invert (+1 dim for j=0 and +1 dim for coeff J+1) + INTEGER :: i,n + ! Hermite + HH = 0._dp + DO i = 1,Pmax+3 + n = i-1 !poly. degree + HH(1:i,i) = get_hermite_coeffs(n) + ENDDO + CALL inverse_triangular(Pmax+3,HH,iHH) + + ! Laguerre + LL = 0._dp + DO i = 1,Jmax+2 + n = i-1 !poly. degree + LL(1:i,i) = get_laguerre_coeffs(n) + ENDDO + CALL inverse_triangular(Jmax+2,LL,iLL) + + ! Allocate and fill the monomial truncation coefficients + ALLOCATE(c_Pp1(Pmax+1)) + DO i = 1,Pmax+1 + c_Pp1(i) = -iHH(i,Pmax+2)/iHH(Pmax+2,Pmax+2) + ENDDO + ALLOCATE(c_Pp2(Pmax+1)) + DO i = 1,Pmax+1 + c_Pp2(i) = -iHH(i,Pmax+3)/iHH(Pmax+3,Pmax+3) + ENDDO + ALLOCATE(c_Jp1(Jmax+1)) + DO i = 1,Jmax+1 + c_Jp1(i) = 0*iLL(i,Jmax+2)/iLL(Jmax+2,Jmax+2) + ENDDO END SUBROUTINE - SUBROUTINE build_hermite_matrix(d,U) + ! Invert an upper triangular matrix + SUBROUTINE inverse_triangular(N,U,invU) IMPLICIT NONE - INTEGER, INTENT(IN) :: d - REAL(xp), DIMENSION(d,d), INTENT(OUT) :: U + INTEGER, INTENT(in) :: N ! size of the matrix + REAL(xp), DIMENSION(N,N), INTENT(IN) :: U ! Matrix to invert + REAL(xp), DIMENSION(N,N), INTENT(OUT) :: invU! Result + ! local variables + INTEGER :: info + invU = U +#ifdef SINGLE_PRECISION + CALL STRTRI('U','N',N,invU,N,info) +#else + CALL DTRTRI('U','N',N,invU,N,info) +#endif + IF (info .LT. 0) THEN + print*, info + ERROR STOP "STOP, LAPACK TRTRI: illegal value at index" + ELSEIF(info .GT. 0) THEN + ERROR STOP "STOP, LAPACK TRTRI: singular matrix" + ENDIF END SUBROUTINE - SUBROUTINE build_laguerre_matrix(d,U) + ! Compute the kth coefficient of the nth degree Hermite + ! adapted from LaguerrePoly.m by David Terr, Raytheon, 5-10-04 + FUNCTION get_hermite_coeffs(n) RESULT(hn) IMPLICIT NONE - INTEGER, INTENT(IN) :: d - REAL(xp), DIMENSION(d,d), INTENT(OUT) :: U - - - END SUBROUTINE + INTEGER, INTENT(IN) :: n ! Polyn. Deg. and index + REAL(xp), DIMENSION(n+1) :: hn ! Hermite coefficients + REAL(xp), DIMENSION(n+1) :: hnm2, hnm1, tmp + INTEGER :: k, e, factn + IF (n .EQ. 0) THEN + hn = 1._xp + ELSEIF (n .EQ. 1) THEN + hn = [2._xp, 0._xp] + ELSE + hnm2 = 0._xp + hnm2(n+1) = 1._xp + hnm1 = 0._xp + hnm1(n) = 2._xp + DO k = 2,n + hn = 0._xp + DO e = n-k+1,n,2 + hn(e) = REAL(2*(hnm1(e+1) - (k-1)*hnm2(e)),xp) + END DO + hn(n+1) = REAL(-2*(k-1)*hnm2(n+1),xp) + IF (k .LT. n) THEN + hnm2 = hnm1 + hnm1 = hn + END IF + END DO + END IF + ! Normalize the polynomials + factn = 1 + DO k = 1,n + factn = k*factn + ENDDO + hn = hn/SQRT(REAL(2**n*factn,xp)) + ! reverse order + tmp = hn + DO k = 1,n+1 + hn(n+1-(k-1)) = tmp(k) + ENDDO + END FUNCTION ! Compute the kth coefficient of the nth degree Laguerre ! adapted from LaguerrePoly.m by David Terr, Raytheon, 5-11-04 ! lnk = (-1)^k/k! binom(n,k), s.t. Ln(x) = sum_k lnk x^k - SUBROUTINE set_laguerre_coeffs(n) + FUNCTION get_laguerre_coeffs(n) RESULT(ln) IMPLICIT NONE - INTEGER, INTENT(IN) :: n ! Polyn. Deg. and index - INTEGER, DIMENSION(n+1) :: lnm2, lnm1 + INTEGER, INTENT(IN) :: n ! Polyn. Deg. and index + REAL(xp), DIMENSION(n+1) :: ln ! Laguerre coefficients + REAL(xp), DIMENSION(n+1) :: lnm2, lnm1, tmp INTEGER :: k, e - ALLOCATE(ln(n+1)) - IF (n == 0) THEN - ln = 1 - ELSEIF (n == 1) THEN - ln = [-1, 1] + IF (n .EQ. 0) THEN + ln = 1._xp + ELSEIF (n .EQ. 1) THEN + ln = [-1._xp, 1._xp] ELSE - lnm2 = 0.0 - lnm2(n+1) = 1 - lnm1 = 0.0 - lnm1(n) = -1 - lnm1(n+1) = 1 + lnm2 = 0._xp + lnm2(n+1) = 1._xp + lnm1 = 0._xp + lnm1(n) =-1._xp + lnm1(n+1) = 1._xp DO k = 2, n - ln = 0.0 + ln = 0 DO e = n-k+1, n - ln(e) = (2*k-1)*lnm1(e) - lnm1(e+1) + (1-k)*lnm2(e) + ln(e) = REAL((2*k-1)*lnm1(e) - lnm1(e+1) + (1-k)*lnm2(e),xp) END DO - ln(n+1) = (2*k-1)*lnm1(n+1) + (1-k)*lnm2(n+1) - ln = ln/k + ln(n+1) = REAL((2*k-1)*lnm1(n+1) + (1-k)*lnm2(n+1),xp) + ln = ln/REAL(k,xp) IF (k < n) THEN lnm2 = lnm1 lnm1 = ln END IF END DO END IF - END SUBROUTINE - - ! Compute the kth coefficient of the nth degree hermite - ! (-1)^k/k! binom(j,k) - SUBROUTINE set_hermite_coeffs(n) - IMPLICIT NONE - INTEGER, INTENT(IN) :: n ! Polyn. Deg. and index - INTEGER, DIMENSION(n+1) :: hnm2, hnm1 - INTEGER :: k, e - ALLOCATE(hn(n+1)) - IF (n .EQ. 0) THEN - hn = 1 - ELSEIF (n .EQ. 1) THEN - hn = [2, 0] - ELSE - hnm2 = 0 - hnm2(n+1) = 1 - hnm1 = 0 - hnm1(n) = 2 - - DO k = 2, n - hn = 0 - DO e = n-k+1, 2, -2 - hn(e) = 2*(hnm1(e+1) - (k-1)*hnm2(e)) - END DO - hn(n+1) = -2*(k-1)*hnm2(n+1) - IF (k < n) THEN - hnm2 = hnm1 - hnm1 = hn - END IF - END DO - END IF - END SUBROUTINE + ! reverse order + tmp = ln + DO k = 1,n+1 + ln(n+1-(k-1)) = tmp(k) + ENDDO + END FUNCTION !--------------Routines to test singular value filtering ----------------- #ifdef TEST_SVD diff --git a/src/closure_mod.F90 b/src/closure_mod.F90 index a27cd910..299fc626 100644 --- a/src/closure_mod.F90 +++ b/src/closure_mod.F90 @@ -23,8 +23,9 @@ END SUBROUTINE SUBROUTINE set_closure_model USE basic, ONLY: speak - USE grid, ONLY: local_np, ngp, local_nj, ngj, parray, jarray,& - pmax, jmax + USE grid, ONLY: local_np, ngp, local_nj, ngj, parray, jarray,& + pmax, jmax + USE CLA, ONLY: set_monomial_trunc_coeff IMPLICIT NONE INTEGER :: ip,ij ! adapt the dmax if it is set <0 @@ -36,7 +37,14 @@ SUBROUTINE set_closure_model ! set the evolve mom array ALLOCATE(evolve_mom(local_np+ngp,local_nj+ngj)) SELECT CASE(hierarchy_closure) - CASE('truncation','monomial') + CASE('truncation') + DO ip = 1,local_np+ngp + DO ij = 1, local_nj+ngj + evolve_mom(ip,ij) = ((parray(ip).GE.0) .AND. (jarray(ij).GE.0)) & + .AND. (parray(ip).LE.pmax) .AND. (jarray(ij).LE.jmax) + ENDDO + ENDDO + CASE('monomial') DO ip = 1,local_np+ngp DO ij = 1, local_nj+ngj evolve_mom(ip,ij) = ((parray(ip).GE.0) .AND. (jarray(ij).GE.0)) & @@ -51,8 +59,14 @@ SUBROUTINE set_closure_model ENDDO ENDDO CASE DEFAULT - ERROR STOP "closure scheme not recognized (avail: truncation,max_degree)" + ERROR STOP "closure scheme not recognized (avail: truncation,max_degree,monomial)" END SELECT + ! If monomial truncation, setup the coefficients required + SELECT CASE(hierarchy_closure) + CASE('monomial') + CALL set_monomial_trunc_coeff(pmax,jmax) + END SELECT + ! Set the nonlinear closure scheme (truncation of sum over n in Sapj) ALLOCATE(nmaxarray(local_nj)) SELECT CASE(nonlinear_closure) @@ -74,31 +88,79 @@ SUBROUTINE set_closure_model CASE DEFAULT ERROR STOP "nonlinear closure scheme not recognized (avail: truncation,anti_laguerre_aliasing,full_sum)" END SELECT - - ! If monomial truncation, setup the coefficients required - SELECT CASE(nonlinear_closure) - CASE('monomial') - END SELECT - END SUBROUTINE set_closure_model ! Positive Oob indices are approximated with a model SUBROUTINE apply_closure_model USE prec_const, ONLY: xp - USE grid, ONLY: local_nj,ngj,local_np,ngp,local_na + USE grid, ONLY: local_nj,ngj,local_np,ngp,local_na,deltap USE fields, ONLY: moments USE time_integration, ONLY: updatetlevel + USE CLA, ONLY: c_Pp1, c_Pp2, c_Jp1 + USE parallel, ONLY: num_procs_p IMPLICIT NONE - INTEGER ::ij,ip,ia + INTEGER ::ij,ip,ia, ipi, iji, ipmax, ijmax, iq, ik, iqi, iki + ! Set to zero all non evolving moments + DO ij = 1, local_nj+ngj + DO ip = 1,local_np+ngp + DO ia = 1,local_na + IF(.NOT. evolve_mom(ip,ij))& + moments(ia,ip,ij,:,:,:,updatetlevel) = 0._xp + ENDDO + ENDDO + ENDDO SELECT CASE (hierarchy_closure) CASE('truncation','max_degree') - DO ij = 1, local_nj+ngj - DO ip = 1,local_np+ngp - DO ia = 1,local_na - IF(.NOT. evolve_mom(ip,ij))& - moments(ia,ip,ij,:,:,:,updatetlevel) = 0._xp + ! do nothing + CASE('monomial') + IF(num_procs_p .GT. 1) ERROR STOP "STOP: monomial closure is not parallelized in p" + ! + ipmax = local_np+ngp/2 + ijmax = local_nj+ngj/2 + DO ia = 1,local_na + IF(deltap .EQ. 1) THEN ! We solve for every Hermite + !! P+1 truncation : NaP+1,j = sum_{q=0}^P c^{P+1}_q Nqj + DO ij = 1, local_nj + iji = ij + ngj/2 + moments(ia,ipmax+1,iji,:,:,:,updatetlevel) = 0._xp + DO iq = 1, local_np + iqi = iq + ngp/2 + moments(ia,ipmax+1,iji,:,:,:,updatetlevel) = moments(ia,ipmax+1,iji,:,:,:,updatetlevel) & + + c_Pp1(iq) * moments(ia,iqi,iji,:,:,:,updatetlevel) + ENDDO + ENDDO + !! P+2 truncation : NaP+2,j = sum_{q=0}^P c^{P+2}_q Nqj + DO ij = 1, local_nj + iji = ij + ngj/2 + moments(ia,ipmax+2,iji,:,:,:,updatetlevel) = 0._xp + DO iq = 1, local_np + iqi = iq + ngp/2 + moments(ia,ipmax+2,iji,:,:,:,updatetlevel) = moments(ia,ipmax+2,iji,:,:,:,updatetlevel) & + + c_Pp2(iq) * moments(ia,iqi,iji,:,:,:,updatetlevel) + ENDDO + ENDDO + ELSE + !! P+2 truncation only : NaP+2,j = sum_{q=0}^P c^{P+2}_q Nqj + DO ij = 1, local_nj + iji = ij + ngj/2 + moments(ia,ipmax+1,iji,:,:,:,updatetlevel) = 0._xp + DO iq = 1, local_np + iqi = iq + ngp/2 + moments(ia,ipmax+1,iji,:,:,:,updatetlevel) = moments(ia,ipmax+1,iji,:,:,:,updatetlevel) & + + c_Pp2(2*(iq-1)+1) * moments(ia,iqi,iji,:,:,:,updatetlevel) + ENDDO + ENDDO + ENDIF + !! J+1 truncation : Nap,J+1 = sum_{k=0}^J c^{J+1}_k Npk + DO ip = 1, local_np + ipi = ip + ngp/2 + moments(ia,ipi,ijmax+1,:,:,:,updatetlevel) = 0._xp + DO ik = 1, local_nj + iki = ik + ngj/2 + moments(ia,iki,ijmax+1,:,:,:,updatetlevel) = moments(ia,iki,ijmax+1,:,:,:,updatetlevel) & + + c_Jp1(ik) * moments(ia,ipi,iki,:,:,:,updatetlevel) ENDDO - ENDDO + ENDDO ENDDO CASE DEFAULT ERROR STOP "closure scheme not recognized" diff --git a/src/diagnose.F90 b/src/diagnose.F90 index f9e3aa8d..d5aca960 100644 --- a/src/diagnose.F90 +++ b/src/diagnose.F90 @@ -96,7 +96,6 @@ SUBROUTINE diagnose_full(kstep) USE basic, ONLY: speak,chrono_runt,& cstep,iframe0d,iframe3d,iframe5d,crashed USE grid, ONLY: & - local_nj,local_nky,local_nkx,local_nz,ngj,ngz,& parray_full,pmax,jarray_full,jmax,& kyarray_full,kxarray_full,zarray_full USE diagnostics_par @@ -105,7 +104,6 @@ SUBROUTINE diagnose_full(kstep) USE model, ONLY: EM USE parallel, ONLY: my_id, comm0 USE collision, ONLY: coll_outputinputs - USE geometry, ONLY: gxx,gxy,gyy,gxz,gyz,gzz,hatR,hatZ,hatB,dBdx,dBdy,dBdz,Jacobian,gradz_coeff,Ckxky IMPLICIT NONE INTEGER, INTENT(in) :: kstep INTEGER, parameter :: BUFSIZE = 2 @@ -282,7 +280,7 @@ SUBROUTINE diagnose_txtonly(kstep) IMPLICIT NONE INTEGER, INTENT(in) :: kstep INTEGER, parameter :: BUFSIZE = 2 - INTEGER :: rank = 0, ierr + INTEGER :: rank = 0 INTEGER :: dims(1) = (/0/) IF (kstep .GE. 0) THEN ! output the transport in a txt file @@ -507,7 +505,7 @@ SUBROUTINE diagnose_5d CONTAINS SUBROUTINE write_field5d(field, text) - USE basic, ONLY: GATHERV_OUTPUT, jobnum, dt + USE basic, ONLY: jobnum, dt USE futils, ONLY: attach, putarr!, putarrnd USE parallel, ONLY: gather_pjxyz, num_procs USE prec_const, ONLY: xp -- GitLab