Add tests for the DMD functions (Reference-LAPACK PR 736)
This commit is contained in:
		
							parent
							
								
									e3039fa7f6
								
							
						
					
					
						commit
						a53a79e059
					
				| 
						 | 
					@ -64,6 +64,8 @@ SEIGTST = schkee.o \
 | 
				
			||||||
   sort03.o ssbt21.o ssgt01.o sslect.o sspt21.o sstt21.o \
 | 
					   sort03.o ssbt21.o ssgt01.o sslect.o sspt21.o sstt21.o \
 | 
				
			||||||
   sstt22.o ssyl01.o ssyt21.o ssyt22.o
 | 
					   sstt22.o ssyl01.o ssyt21.o ssyt22.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SDMDEIGTST = schkdmd.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CEIGTST = cchkee.o \
 | 
					CEIGTST = cchkee.o \
 | 
				
			||||||
   cbdt01.o cbdt02.o cbdt03.o cbdt05.o \
 | 
					   cbdt01.o cbdt02.o cbdt03.o cbdt05.o \
 | 
				
			||||||
   cchkbb.o cchkbd.o cchkbk.o cchkbl.o cchkec.o \
 | 
					   cchkbb.o cchkbd.o cchkbk.o cchkbl.o cchkec.o \
 | 
				
			||||||
| 
						 | 
					@ -81,6 +83,8 @@ CEIGTST = cchkee.o \
 | 
				
			||||||
   csgt01.o cslect.o csyl01.o\
 | 
					   csgt01.o cslect.o csyl01.o\
 | 
				
			||||||
   cstt21.o cstt22.o cunt01.o cunt03.o
 | 
					   cstt21.o cstt22.o cunt01.o cunt03.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CDMDEIGTST = cchkdmd.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DZIGTST = dlafts.o dlahd2.o dlasum.o dlatb9.o dstech.o dstect.o \
 | 
					DZIGTST = dlafts.o dlahd2.o dlasum.o dlatb9.o dstech.o dstect.o \
 | 
				
			||||||
   dsvdch.o dsvdct.o dsxt1.o
 | 
					   dsvdch.o dsvdct.o dsxt1.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,6 +105,8 @@ DEIGTST = dchkee.o \
 | 
				
			||||||
   dort03.o dsbt21.o dsgt01.o dslect.o dspt21.o dstt21.o \
 | 
					   dort03.o dsbt21.o dsgt01.o dslect.o dspt21.o dstt21.o \
 | 
				
			||||||
   dstt22.o dsyl01.o dsyt21.o dsyt22.o
 | 
					   dstt22.o dsyl01.o dsyt21.o dsyt22.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DDMDEIGTST = dchkdmd.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ZEIGTST = zchkee.o \
 | 
					ZEIGTST = zchkee.o \
 | 
				
			||||||
   zbdt01.o zbdt02.o zbdt03.o zbdt05.o \
 | 
					   zbdt01.o zbdt02.o zbdt03.o zbdt05.o \
 | 
				
			||||||
   zchkbb.o zchkbd.o zchkbk.o zchkbl.o zchkec.o \
 | 
					   zchkbb.o zchkbd.o zchkbk.o zchkbl.o zchkec.o \
 | 
				
			||||||
| 
						 | 
					@ -118,27 +124,45 @@ ZEIGTST = zchkee.o \
 | 
				
			||||||
   zsgt01.o zslect.o zsyl01.o\
 | 
					   zsgt01.o zslect.o zsyl01.o\
 | 
				
			||||||
   zstt21.o zstt22.o zunt01.o zunt03.o
 | 
					   zstt21.o zstt22.o zunt01.o zunt03.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ZDMDEIGTST = zchkdmd.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: all
 | 
					.PHONY: all
 | 
				
			||||||
all: single complex double complex16
 | 
					all: single complex double complex16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: single complex double complex16
 | 
					.PHONY: single complex double complex16
 | 
				
			||||||
single: xeigtsts
 | 
					single: xeigtsts xdmdeigtsts
 | 
				
			||||||
complex: xeigtstc
 | 
					complex: xeigtstc xdmdeigtstc
 | 
				
			||||||
double: xeigtstd
 | 
					double: xeigtstd xdmdeigtstd
 | 
				
			||||||
complex16: xeigtstz
 | 
					complex16: xeigtstz xdmdeigtstz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xeigtsts: $(SEIGTST) $(SCIGTST) $(AEIGTST) $(TMGLIB) ../$(LAPACKLIB) $(BLASLIB)
 | 
					xdmdeigtsts: $(SDMDEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
	$(LOADER) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xeigtstc: $(CEIGTST) $(SCIGTST) $(AEIGTST) $(TMGLIB) ../$(LAPACKLIB) $(BLASLIB)
 | 
					xdmdeigtstc: $(CDMDEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
	$(LOADER) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xeigtstd: $(DEIGTST) $(DZIGTST) $(AEIGTST) $(TMGLIB) ../$(LAPACKLIB) $(BLASLIB)
 | 
					xdmdeigtstd: $(DDMDEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
	$(LOADER) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xeigtstz: $(ZEIGTST) $(DZIGTST) $(AEIGTST) $(TMGLIB) ../$(LAPACKLIB) $(BLASLIB)
 | 
					xdmdeigtstz: $(ZDMDEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
	$(LOADER) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xeigtsts: $(SEIGTST) $(SCIGTST) $(AEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xeigtstc: $(CEIGTST) $(SCIGTST) $(AEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xeigtstd: $(DEIGTST) $(DZIGTST) $(AEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xeigtstz: $(ZEIGTST) $(DZIGTST) $(AEIGTST) $(TMGLIB) $(LAPACKLIB) $(BLASLIB)
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS) $(LDFLAGS) -o $@ $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(SDMDEIGTST): $(FRC)
 | 
				
			||||||
 | 
					$(CDMDEIGTST): $(FRC)
 | 
				
			||||||
 | 
					$(DDMDEIGTST): $(FRC)
 | 
				
			||||||
 | 
					$(ZDMDEIGTST): $(FRC)
 | 
				
			||||||
$(AEIGTST): $(FRC)
 | 
					$(AEIGTST): $(FRC)
 | 
				
			||||||
$(SCIGTST): $(FRC)
 | 
					$(SCIGTST): $(FRC)
 | 
				
			||||||
$(DZIGTST): $(FRC)
 | 
					$(DZIGTST): $(FRC)
 | 
				
			||||||
| 
						 | 
					@ -155,7 +179,7 @@ clean: cleanobj cleanexe
 | 
				
			||||||
cleanobj:
 | 
					cleanobj:
 | 
				
			||||||
	rm -f *.o
 | 
						rm -f *.o
 | 
				
			||||||
cleanexe:
 | 
					cleanexe:
 | 
				
			||||||
	rm -f xeigtst*
 | 
						rm -f xeigtst* xdmdeigtst*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
schkee.o: schkee.F
 | 
					schkee.o: schkee.F
 | 
				
			||||||
	$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
| 
						 | 
					@ -165,3 +189,11 @@ cchkee.o: cchkee.F
 | 
				
			||||||
	$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
zchkee.o: zchkee.F
 | 
					zchkee.o: zchkee.F
 | 
				
			||||||
	$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
 | 
					schkdmd.o: schkdmd.f90
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
 | 
					cchkdmd.o: cchkdmd.f90
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
 | 
					dchkdmd.o: dchkdmd.f90
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
 | 
					zchkdmd.o: zchkdmd.f90
 | 
				
			||||||
 | 
						$(FC) $(FFLAGS_DRV) -c -o $@ $<
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,721 @@
 | 
				
			||||||
 | 
					!   This is a test program for checking the implementations of
 | 
				
			||||||
 | 
					!   the implementations of the following subroutines
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!   CGEDMD,  for computation of the
 | 
				
			||||||
 | 
					!            Dynamic Mode Decomposition (DMD)
 | 
				
			||||||
 | 
					!   CGEDMDQ, for computation of a
 | 
				
			||||||
 | 
					!            QR factorization based compressed DMD
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!   Developed and supported by:
 | 
				
			||||||
 | 
					!   ===========================
 | 
				
			||||||
 | 
					!   Developed and coded by Zlatko Drmac, Faculty of Science,
 | 
				
			||||||
 | 
					!   University of Zagreb;  drmac@math.hr
 | 
				
			||||||
 | 
					!   In cooperation with
 | 
				
			||||||
 | 
					!   AIMdyn Inc., Santa Barbara, CA.
 | 
				
			||||||
 | 
					!   ========================================================
 | 
				
			||||||
 | 
					!   How to run the code (compiler, link info)
 | 
				
			||||||
 | 
					!   ========================================================
 | 
				
			||||||
 | 
					!   Compile as FORTRAN 90 (or later) and link with BLAS and
 | 
				
			||||||
 | 
					!   LAPACK libraries.
 | 
				
			||||||
 | 
					!   NOTE: The code is developed and tested on top of the
 | 
				
			||||||
 | 
					!   Intel MKL library (versions 2022.0.3 and 2022.2.0),
 | 
				
			||||||
 | 
					!   using the Intel Fortran compiler.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!   For developers of the C++ implementation
 | 
				
			||||||
 | 
					!   ========================================================
 | 
				
			||||||
 | 
					!   See the LAPACK++ and Template Numerical Toolkit (TNT)
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!   Note on a development of the GPU HP implementation
 | 
				
			||||||
 | 
					!   ========================================================
 | 
				
			||||||
 | 
					!   Work in progress. See CUDA, MAGMA, SLATE.
 | 
				
			||||||
 | 
					!   NOTE: The four SVD subroutines used in this code are
 | 
				
			||||||
 | 
					!   included as a part of R&D and for the completeness.
 | 
				
			||||||
 | 
					!   This was also an opportunity to test those SVD codes.
 | 
				
			||||||
 | 
					!   If the scaling option is used all four are essentially
 | 
				
			||||||
 | 
					!   equally good. For implementations on HP platforms,
 | 
				
			||||||
 | 
					!   one can use whichever SVD is available.
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					      PROGRAM DMD_TEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      use iso_fortran_env
 | 
				
			||||||
 | 
					      IMPLICIT NONE
 | 
				
			||||||
 | 
					      integer, parameter :: WP = real32
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER ::  ONE = 1.0_WP
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER :: ZERO = 0.0_WP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), PARAMETER ::  CONE = ( 1.0_WP, 0.0_WP )
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), PARAMETER :: CZERO = ( 0.0_WP, 0.0_WP )
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:)   :: RES, &
 | 
				
			||||||
 | 
					                     RES1, RESEX, SINGVX, SINGVQX, WORK
 | 
				
			||||||
 | 
					      INTEGER      , ALLOCATABLE, DIMENSION(:)   ::   IWORK
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: WDUMMY(2)
 | 
				
			||||||
 | 
					      INTEGER       :: IDUMMY(4), ISEED(4)
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: ANORM, COND, CONDL, CONDR, EPS,       &
 | 
				
			||||||
 | 
					                       TOL, TOL2, SVDIFF, TMP, TMP_AU,       &
 | 
				
			||||||
 | 
					                       TMP_FQR, TMP_REZ, TMP_REZQ,  TMP_XW, &
 | 
				
			||||||
 | 
					                       TMP_EX
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP) :: CMAX
 | 
				
			||||||
 | 
					      INTEGER :: LCWORK
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), ALLOCATABLE, DIMENSION(:,:) ::  A, AC,  &
 | 
				
			||||||
 | 
					                                 AU, F, F0, F1, S, W,  &
 | 
				
			||||||
 | 
					                                 X, X0, Y, Y0, Y1, Z, Z1
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), ALLOCATABLE, DIMENSION(:)   ::  CDA, CDR, &
 | 
				
			||||||
 | 
					                                       CDL, CEIGS, CEIGSA, CWORK
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP) ::  CDUMMY(22), CDUM2X2(2,2)
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY,  &
 | 
				
			||||||
 | 
					                 LDZ, LIWORK, LWORK, M, N, LLOOP, NRNK
 | 
				
			||||||
 | 
					      INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, j,     &
 | 
				
			||||||
 | 
					                 NFAIL, NFAIL_AU, NFAIL_F_QR, NFAIL_REZ,     &
 | 
				
			||||||
 | 
					                 NFAIL_REZQ, NFAIL_SVDIFF, NFAIL_TOTAL, NFAILQ_TOTAL,  &
 | 
				
			||||||
 | 
					                 NFAIL_Z_XV,  MODE, MODEL, MODER, WHTSVD
 | 
				
			||||||
 | 
					      INTEGER :: iNRNK, iWHTSVD,  K_traj, LWMINOPT
 | 
				
			||||||
 | 
					      CHARACTER :: GRADE, JOBREF, JOBZ, PIVTNG, RSIGN,   &
 | 
				
			||||||
 | 
					                   SCALE, RESIDS, WANTQ, WANTR
 | 
				
			||||||
 | 
					      LOGICAL :: TEST_QRDMD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!..... external subroutines (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL CAXPY, CGEEV, CGEMM, CGEMV, CLASCL
 | 
				
			||||||
 | 
					!.....external subroutines DMD package
 | 
				
			||||||
 | 
					!     subroutines under test
 | 
				
			||||||
 | 
					      EXTERNAL CGEDMD, CGEDMDQ
 | 
				
			||||||
 | 
					!..... external functions (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL         SCNRM2, SLAMCH
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: SCNRM2, SLAMCH
 | 
				
			||||||
 | 
					      EXTERNAL         CLANGE
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: CLANGE
 | 
				
			||||||
 | 
					      EXTERNAL ICAMAX
 | 
				
			||||||
 | 
					      INTEGER  ICAMAX
 | 
				
			||||||
 | 
					      EXTERNAL LSAME
 | 
				
			||||||
 | 
					      LOGICAL  LSAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      INTRINSIC ABS, INT, MIN, MAX, SIGN
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) 'COMPLEX CODE TESTING'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! The test is always in pairs : ( CGEDMD and CGEDMDQ)
 | 
				
			||||||
 | 
					      ! because the test includes comparing the results (in pairs).
 | 
				
			||||||
 | 
					!.....................................................................................
 | 
				
			||||||
 | 
					      ! This code by default performs tests on CGEDMDQ
 | 
				
			||||||
 | 
					      ! Since the QR factorizations based algorithm is designed for
 | 
				
			||||||
 | 
					      ! single trajectory data, only single trajectory tests will
 | 
				
			||||||
 | 
					      ! be performed with xGEDMDQ.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WANTQ = 'Q'
 | 
				
			||||||
 | 
					      WANTR = 'R'
 | 
				
			||||||
 | 
					!.................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      EPS = SLAMCH( 'P' )  ! machine precision WP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Global counters of failures of some particular tests
 | 
				
			||||||
 | 
					      NFAIL      = 0
 | 
				
			||||||
 | 
					      NFAIL_REZ  = 0
 | 
				
			||||||
 | 
					      NFAIL_REZQ = 0
 | 
				
			||||||
 | 
					      NFAIL_Z_XV = 0
 | 
				
			||||||
 | 
					      NFAIL_F_QR = 0
 | 
				
			||||||
 | 
					      NFAIL_AU   = 0
 | 
				
			||||||
 | 
					      NFAIL_SVDIFF = 0
 | 
				
			||||||
 | 
					      NFAIL_TOTAL  = 0
 | 
				
			||||||
 | 
					      NFAILQ_TOTAL = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LLOOP = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) 'L Loop Index = ', LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Set the dimensions of the problem ...
 | 
				
			||||||
 | 
					      READ(*,*) M
 | 
				
			||||||
 | 
					      WRITE(*,*) 'M = ', M
 | 
				
			||||||
 | 
					      ! ... and the number of snapshots.
 | 
				
			||||||
 | 
					      READ(*,*) N
 | 
				
			||||||
 | 
					      WRITE(*,*) 'N = ', N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Test the dimensions
 | 
				
			||||||
 | 
					      IF ( ( MIN(M,N) == 0 ) .OR. ( M < N )  ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Bad dimensions. Required: M >= N > 0.'
 | 
				
			||||||
 | 
					          STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					      ! The seed inside the LLOOP so that each pass can be reproduced easily.
 | 
				
			||||||
 | 
					      ISEED(1) = 4
 | 
				
			||||||
 | 
					      ISEED(2) = 3
 | 
				
			||||||
 | 
					      ISEED(3) = 2
 | 
				
			||||||
 | 
					      ISEED(4) = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LDA  = M
 | 
				
			||||||
 | 
					      LDF  = M
 | 
				
			||||||
 | 
					      LDX  = M
 | 
				
			||||||
 | 
					      LDY  = M
 | 
				
			||||||
 | 
					      LDW  = N
 | 
				
			||||||
 | 
					      LDZ  = M
 | 
				
			||||||
 | 
					      LDAU = M
 | 
				
			||||||
 | 
					      LDS  = N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP_XW  = ZERO
 | 
				
			||||||
 | 
					      TMP_AU   = ZERO
 | 
				
			||||||
 | 
					      TMP_REZ  = ZERO
 | 
				
			||||||
 | 
					      TMP_REZQ = ZERO
 | 
				
			||||||
 | 
					      SVDIFF   = ZERO
 | 
				
			||||||
 | 
					      TMP_EX   = ZERO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( A(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( AC(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( F(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F0(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F1(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( X(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( X0(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y0(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y1(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( AU(LDAU,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( W(LDW,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( S(LDS,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z1(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES1(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RESEX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( CEIGS(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVQX(N) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TOL  = 10*M*EPS
 | 
				
			||||||
 | 
					      TOL2 = 10*M*N*EPS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO K_traj = 1, 2
 | 
				
			||||||
 | 
					      !  Number of intial conditions in the simulation/trajectories (1 or 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COND   = 1.0D4
 | 
				
			||||||
 | 
					      CMAX   = (1.0D1,1.0D1)
 | 
				
			||||||
 | 
					      RSIGN  = 'F'
 | 
				
			||||||
 | 
					      GRADE  = 'N'
 | 
				
			||||||
 | 
					      MODEL  = 6
 | 
				
			||||||
 | 
					      CONDL  = 1.0D1
 | 
				
			||||||
 | 
					      MODER  = 6
 | 
				
			||||||
 | 
					      CONDR  = 1.0D1
 | 
				
			||||||
 | 
					      PIVTNG = 'N'
 | 
				
			||||||
 | 
					      ! Loop over all parameter MODE values for CLATMR (+-1,..,+-6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO MODE = 1, 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( IWORK(2*M) )
 | 
				
			||||||
 | 
					      ALLOCATE( CDA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( CDL(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( CDR(M) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL CLATMR( M, M, 'N', ISEED, 'N', CDA, MODE, COND, &
 | 
				
			||||||
 | 
					                   CMAX, RSIGN, GRADE, CDL, MODEL,  CONDL, &
 | 
				
			||||||
 | 
					                   CDR, MODER, CONDR, PIVTNG, IWORK, M, M, &
 | 
				
			||||||
 | 
					                   ZERO, -ONE, 'N', A, LDA, IWORK(M+1), INFO )
 | 
				
			||||||
 | 
					      DEALLOCATE( CDR )
 | 
				
			||||||
 | 
					      DEALLOCATE( CDL )
 | 
				
			||||||
 | 
					      DEALLOCATE( CDA )
 | 
				
			||||||
 | 
					      DEALLOCATE( IWORK )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LCWORK = MAX(1,2*M)
 | 
				
			||||||
 | 
					      ALLOCATE( CEIGSA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( CWORK(LCWORK) )
 | 
				
			||||||
 | 
					      ALLOCATE( WORK(2*M) )
 | 
				
			||||||
 | 
					      AC(1:M,1:M) = A(1:M,1:M)
 | 
				
			||||||
 | 
					      CALL CGEEV( 'N','N', M, AC, LDA, CEIGSA, CDUM2X2, 2, &
 | 
				
			||||||
 | 
					                  CDUM2X2, 2, CWORK, LCWORK, WORK, INFO ) ! LAPACK CALL
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(CWORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP = ABS(CEIGSA(ICAMAX(M, CEIGSA, 1))) ! The spectral radius of A
 | 
				
			||||||
 | 
					      ! Scale the matrix A to have unit spectral radius.
 | 
				
			||||||
 | 
					      CALL CLASCL( 'G',0, 0, TMP, ONE, M, M, &
 | 
				
			||||||
 | 
					                   A, LDA, INFO )
 | 
				
			||||||
 | 
					      CALL CLASCL( 'G',0, 0, TMP, ONE, M, 1, &
 | 
				
			||||||
 | 
					                   CEIGSA, M, INFO )
 | 
				
			||||||
 | 
					      ANORM = CLANGE( 'F', M, M, A, LDA, WDUMMY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( K_traj == 2 ) THEN
 | 
				
			||||||
 | 
					          ! generate data as two trajectories
 | 
				
			||||||
 | 
					          ! with two inital conditions
 | 
				
			||||||
 | 
					          CALL CLARNV(2, ISEED, M, F(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N/2
 | 
				
			||||||
 | 
					             CALL CGEMV( 'N', M, M, CONE, A, LDA, F(1,i), 1,  &
 | 
				
			||||||
 | 
					                  CZERO, F(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          X0(1:M,1:N/2) = F(1:M,1:N/2)
 | 
				
			||||||
 | 
					          Y0(1:M,1:N/2) = F(1:M,2:N/2+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          CALL CLARNV(2, ISEED, M, F(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N-N/2
 | 
				
			||||||
 | 
					             CALL CGEMV( 'N', M, M, CONE, A, LDA, F(1,i), 1,  &
 | 
				
			||||||
 | 
					                  CZERO, F(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          X0(1:M,N/2+1:N) = F(1:M,1:N-N/2)
 | 
				
			||||||
 | 
					          Y0(1:M,N/2+1:N) = F(1:M,2:N-N/2+1)
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          CALL CLARNV(2, ISEED, M, F(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N
 | 
				
			||||||
 | 
					             CALL CGEMV( 'N', M, M, CONE, A, M, F(1,i), 1,  &
 | 
				
			||||||
 | 
					                  CZERO, F(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          F0(1:M,1:N+1) = F(1:M,1:N+1)
 | 
				
			||||||
 | 
					          X0(1:M,1:N) = F0(1:M,1:N)
 | 
				
			||||||
 | 
					          Y0(1:M,1:N) = F0(1:M,2:N+1)
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE( CEIGSA )
 | 
				
			||||||
 | 
					!........................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBZ = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBZ )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'R'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBZ   = 'F'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              JOBZ   = 'N'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBREF = 1, 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBREF )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBREF = 'R'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBREF = 'E'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBREF = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iSCALE = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iSCALE )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              SCALE = 'S'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              SCALE = 'C'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              SCALE = 'Y'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              SCALE = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iNRNK = -1, -2, -1
 | 
				
			||||||
 | 
					          NRNK   = iNRNK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iWHTSVD = 1,  3
 | 
				
			||||||
 | 
					         ! Check all four options to compute the POD basis
 | 
				
			||||||
 | 
					         ! via the SVD.
 | 
				
			||||||
 | 
					         WHTSVD   = iWHTSVD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LWMINOPT = 1, 2
 | 
				
			||||||
 | 
					         ! Workspace query for the minimal (1) and for the optimal
 | 
				
			||||||
 | 
					         ! (2) workspace lengths determined by workspace query.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! CGEDMD is always tested and its results are also used for
 | 
				
			||||||
 | 
					      ! comparisons with CGEDMDQ.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      X(1:M,1:N) = X0(1:M,1:N)
 | 
				
			||||||
 | 
					      Y(1:M,1:N) = Y0(1:M,1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL CGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,  &
 | 
				
			||||||
 | 
					                M,  N, X, LDX, Y, LDY, NRNK, TOL,  &
 | 
				
			||||||
 | 
					                K, CEIGS, Z, LDZ,  RES,  &
 | 
				
			||||||
 | 
					                AU, LDAU, W,  LDW,   S, LDS,        &
 | 
				
			||||||
 | 
					                CDUMMY, -1, WDUMMY, -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( (INFO .EQ. 2) .OR. ( INFO .EQ. 3 ) &
 | 
				
			||||||
 | 
					                       .OR. ( INFO < 0 ) ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Call to CGEDMD workspace query failed. &
 | 
				
			||||||
 | 
					                   &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					        WRITE(*,*) 'The input parameters were ',      &
 | 
				
			||||||
 | 
					        SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,          &
 | 
				
			||||||
 | 
					        M, N, LDX, LDY, NRNK, TOL, LDZ, LDAU, LDW, LDS
 | 
				
			||||||
 | 
					        STOP
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        !WRITE(*,*) '... done. Workspace length computed.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LCWORK = INT(CDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					      ALLOCATE(CWORK(LCWORK))
 | 
				
			||||||
 | 
					      LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					      ALLOCATE(IWORK(LIWORK))
 | 
				
			||||||
 | 
					      LWORK = INT(WDUMMY(1))
 | 
				
			||||||
 | 
					      ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL CGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,  &
 | 
				
			||||||
 | 
					                   M,  N, X, LDX, Y, LDY, NRNK, TOL,  &
 | 
				
			||||||
 | 
					                   K, CEIGS, Z, LDZ,  RES,  &
 | 
				
			||||||
 | 
					                   AU, LDAU, W,  LDW,   S, LDS,        &
 | 
				
			||||||
 | 
					                   CWORK, LCWORK, WORK, LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					      IF ( INFO /= 0 ) THEN
 | 
				
			||||||
 | 
					           WRITE(*,*) 'Call to CGEDMD failed. &
 | 
				
			||||||
 | 
					           &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					           SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					           M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					           STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      SINGVX(1:N) = WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... CGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBZ,'V')  ) THEN
 | 
				
			||||||
 | 
					          ! Check that Z = X*W, on return from CGEDMD
 | 
				
			||||||
 | 
					          ! This checks that the returned eigenvectors in Z are
 | 
				
			||||||
 | 
					          ! the product of the SVD'POD basis returned in X
 | 
				
			||||||
 | 
					          ! and the eigenvectors of the Rayleigh quotient
 | 
				
			||||||
 | 
					          ! returned in W
 | 
				
			||||||
 | 
					          CALL CGEMM( 'N', 'N', M, K, K, CONE, X, LDX, W, LDW, &
 | 
				
			||||||
 | 
					                      CZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					             CALL CAXPY( M, -CONE, Z(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, SCNRM2( M, Z1(1,i), 1 ) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_XW = MAX(TMP_XW, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP_XW <= TOL ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ' :) .... OK .........CGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_Z_XV = NFAIL_Z_XV + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................CGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      !...... CGEDMD check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBREF,'R') ) THEN
 | 
				
			||||||
 | 
					           ! The matrix A*U is returned for computing refined Ritz vectors.
 | 
				
			||||||
 | 
					           ! Check that A*U is computed correctly using the formula
 | 
				
			||||||
 | 
					           ! A*U = Y * V * inv(SIGMA). This depends on the
 | 
				
			||||||
 | 
					           ! accuracy in the computed singular values and vectors of X.
 | 
				
			||||||
 | 
					           ! See the paper for an error analysis.
 | 
				
			||||||
 | 
					           ! Note that the left singular vectors of the input matrix X
 | 
				
			||||||
 | 
					           ! are returned in the array X.
 | 
				
			||||||
 | 
					           CALL CGEMM( 'N', 'N', M, K, M, CONE, A, LDA, X, LDX, &
 | 
				
			||||||
 | 
					                      CZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					             CALL CAXPY( M, -CONE, AU(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					             TMP = MAX( TMP, SCNRM2( M, Z1(1,i),1 ) * &
 | 
				
			||||||
 | 
					                     SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_AU = MAX( TMP_AU, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ':) .... OK .........CGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_AU = NFAIL_AU + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................CGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL2
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					      ELSEIF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					          ! The unscaled vectors of the Exact DMD are computed.
 | 
				
			||||||
 | 
					          ! This option is included for the sake of completeness,
 | 
				
			||||||
 | 
					          ! for users who prefer the Exact DMD vectors. The
 | 
				
			||||||
 | 
					          ! returned vectors are in the real form, in the same way
 | 
				
			||||||
 | 
					          ! as the Ritz vectors. Here we just save the vectors
 | 
				
			||||||
 | 
					          ! and test them separately using a Matlab script.
 | 
				
			||||||
 | 
					          CALL CGEMM( 'N', 'N', M, K, M, CONE, A, LDA, AU, LDAU, CZERO, Y1, LDY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i=1, K
 | 
				
			||||||
 | 
					             CALL CAXPY( M, -CEIGS(i), AU(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					             RESEX(i) = SCNRM2( M, Y1(1,i), 1) / SCNRM2(M,AU(1,i),1)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      !...... CGEDMD check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					          ! Compare the residuals returned by CGEDMD with the
 | 
				
			||||||
 | 
					          ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					          ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					          CALL CGEMM( 'N', 'N', M, K, M, CONE, A, LDA, Z, LDZ, CZERO, Y1, LDY )
 | 
				
			||||||
 | 
					          ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					          ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					          ! pairs of eigencalues. (See the description of Z in CGEDMD,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i=1, K
 | 
				
			||||||
 | 
					                ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                CALL CAXPY( M, -CEIGS(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                RES1(i) = SCNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                    SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_REZ = MAX( TMP_REZ, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ':) .... OK ..........CGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_REZ = NFAIL_REZ + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( ..................CGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         IF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					            TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES1(i) - RESEX(i))/(RES1(i)+RESEX(i)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_EX = MAX(TMP_EX,TMP)
 | 
				
			||||||
 | 
					         END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(CWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.......................................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( K_traj == 1 ) THEN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          F(1:M,1:N+1) = F0(1:M,1:N+1)
 | 
				
			||||||
 | 
					          CALL CGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, JOBREF, &
 | 
				
			||||||
 | 
					                    WHTSVD, M, N+1, F, LDF,  X, LDX,  Y, LDY,  &
 | 
				
			||||||
 | 
					                    NRNK,  TOL, K, CEIGS, Z, LDZ, RES,  AU,  &
 | 
				
			||||||
 | 
					                    LDAU, W, LDW, S, LDS, CDUMMY, -1,   &
 | 
				
			||||||
 | 
					                    WDUMMY,  -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          LCWORK = INT(CDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					          ALLOCATE(CWORK(LCWORK))
 | 
				
			||||||
 | 
					          LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					          ALLOCATE(IWORK(LIWORK))
 | 
				
			||||||
 | 
					          LWORK = INT(WDUMMY(1))
 | 
				
			||||||
 | 
					          ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          CALL CGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, JOBREF, &
 | 
				
			||||||
 | 
					                        WHTSVD, M, N+1, F, LDF,  X, LDX,  Y, LDY,  &
 | 
				
			||||||
 | 
					                        NRNK,  TOL, KQ, CEIGS, Z, LDZ, RES,  AU,  &
 | 
				
			||||||
 | 
					                        LDAU, W, LDW, S, LDS, CWORK, LCWORK,   &
 | 
				
			||||||
 | 
					                        WORK,  LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					          IF ( INFO /= 0 ) THEN
 | 
				
			||||||
 | 
					                 WRITE(*,*) 'Call to CGEDMDQ failed. &
 | 
				
			||||||
 | 
					                 &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					                 WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					                 WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, WANTQ, WANTR, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					                 STOP
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					          SINGVQX(1:N) =WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... ZGEDMDQ check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, MIN(K, KQ)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, ABS(SINGVX(i)-SINGVQX(i)) / &
 | 
				
			||||||
 | 
					                                   SINGVX(1) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          SVDIFF = MAX( SVDIFF, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					               WRITE(*,*) 'FAILED! Something was wrong with the run.'
 | 
				
			||||||
 | 
					             NFAIL_SVDIFF = NFAIL_SVDIFF + 1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					          !..... CGEDMDQ check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... CGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( LSAME(WANTQ,'Q') .AND. LSAME(WANTR,'R') ) THEN
 | 
				
			||||||
 | 
					             ! Check that the QR factors are computed and returned
 | 
				
			||||||
 | 
					             ! as requested. The residual ||F-Q*R||_F / ||F||_F
 | 
				
			||||||
 | 
					             ! is compared to M*N*EPS.
 | 
				
			||||||
 | 
					             F1(1:M,1:N+1) = F0(1:M,1:N+1)
 | 
				
			||||||
 | 
					             CALL CGEMM( 'N', 'N', M, N+1, MIN(M,N+1), -CONE, F, &
 | 
				
			||||||
 | 
					                         LDF, Y, LDY, CONE, F1, LDF )
 | 
				
			||||||
 | 
					             TMP_FQR = CLANGE( 'F', M, N+1, F1, LDF, WORK ) / &
 | 
				
			||||||
 | 
					                   CLANGE( 'F', M, N+1, F0,  LDF, WORK )
 | 
				
			||||||
 | 
					             IF ( TMP_FQR <= TOL2 ) THEN
 | 
				
			||||||
 | 
					                !WRITE(*,*) ':) CGEDMDQ ........ PASSED.'
 | 
				
			||||||
 | 
					             ELSE
 | 
				
			||||||
 | 
					                WRITE(*,*) ':( CGEDMDQ ........ FAILED.'
 | 
				
			||||||
 | 
					                NFAIL_F_QR = NFAIL_F_QR + 1
 | 
				
			||||||
 | 
					             END IF
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					          !..... ZGEDMDQ checkpoint
 | 
				
			||||||
 | 
					                 !..... ZGEDMDQ checkpoint
 | 
				
			||||||
 | 
					          IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					              ! Compare the residuals returned by ZGEDMDQ with the
 | 
				
			||||||
 | 
					              ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					              ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					              CALL CGEMM( 'N', 'N', M, KQ, M, CONE, A, LDA, Z, LDZ, CZERO, Y1, LDY )
 | 
				
			||||||
 | 
					              ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					              ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					              ! pairs of eigencalues. (See the description of Z in ZGEDMDQ)
 | 
				
			||||||
 | 
					              DO i = 1, KQ
 | 
				
			||||||
 | 
					                    ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                    CALL CAXPY( M, -CEIGS(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                    ! Y(1:M,i) = Y(1:M,i) - REIG(i)*Z(1:M,i)
 | 
				
			||||||
 | 
					                    RES1(i) = SCNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP = ZERO
 | 
				
			||||||
 | 
					              DO i = 1, KQ
 | 
				
			||||||
 | 
					              TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                  SINGVQX(KQ)/(ANORM*SINGVQX(1)) )
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP_REZQ = MAX( TMP_REZQ, TMP )
 | 
				
			||||||
 | 
					              IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					                  !WRITE(*,*) '.... OK ........ CGEDMDQ PASSED.'
 | 
				
			||||||
 | 
					              ELSE
 | 
				
			||||||
 | 
					                  NFAIL_REZQ = NFAIL_REZQ + 1
 | 
				
			||||||
 | 
					                  WRITE(*,*) '................ CGEDMDQ FAILED!', &
 | 
				
			||||||
 | 
					                      'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              END IF
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DEALLOCATE(CWORK)
 | 
				
			||||||
 | 
					          DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					          DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO   ! LWMINOPT
 | 
				
			||||||
 | 
					      !write(*,*) 'LWMINOPT loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iWHTSVD
 | 
				
			||||||
 | 
					      !write(*,*) 'WHTSVD loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iNRNK  -2:-1
 | 
				
			||||||
 | 
					      !write(*,*) 'NRNK loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iSCALE  1:4
 | 
				
			||||||
 | 
					      !write(*,*) 'SCALE loop completed'
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBREF loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iJOBZ
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBZ loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! MODE -6:6
 | 
				
			||||||
 | 
					      !write(*,*) 'MODE loop completed'
 | 
				
			||||||
 | 
					      END DO ! 1 or 2 trajectories
 | 
				
			||||||
 | 
					      !write(*,*) 'trajectories  loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE( A )
 | 
				
			||||||
 | 
					      DEALLOCATE( AC )
 | 
				
			||||||
 | 
					      DEALLOCATE( Z )
 | 
				
			||||||
 | 
					      DEALLOCATE( F )
 | 
				
			||||||
 | 
					      DEALLOCATE( F0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( F1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( X )
 | 
				
			||||||
 | 
					      DEALLOCATE( X0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( Y )
 | 
				
			||||||
 | 
					      DEALLOCATE( Y0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( Y1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( AU )
 | 
				
			||||||
 | 
					      DEALLOCATE( W )
 | 
				
			||||||
 | 
					      DEALLOCATE( S )
 | 
				
			||||||
 | 
					      DEALLOCATE( Z1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( RES )
 | 
				
			||||||
 | 
					      DEALLOCATE( RES1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( RESEX )
 | 
				
			||||||
 | 
					      DEALLOCATE( CEIGS )
 | 
				
			||||||
 | 
					      DEALLOCATE( SINGVX )
 | 
				
			||||||
 | 
					      DEALLOCATE( SINGVQX )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for CGEDMD :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      IF ( NFAIL_Z_XV == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Z - U*V test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Z - U*V test FAILED ', NFAIL_Z_XV, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max error ||Z-U*V||_F was ', TMP_XW
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_z_XV
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_AU == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> A*U test PASSED. '
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'A*U test FAILED ', NFAIL_AU, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max A*U test adjusted error measure was ', TMP_AU
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_AU
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZ == 0 ) THEN
 | 
				
			||||||
 | 
					         WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZ, 'time(s)'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZ
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_REZ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      IF ( NFAIL_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> CGEDMD :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) NFAIL_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>>>>>>>>>>>> CGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for CGEDMDQ :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_SVDIFF == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> CGEDMD and CGEDMDQ computed singular &
 | 
				
			||||||
 | 
					           &values test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'ZGEDMD and ZGEDMDQ discrepancies in &
 | 
				
			||||||
 | 
					            &the singular values unacceptable ', &
 | 
				
			||||||
 | 
					            NFAIL_SVDIFF, ' times. Test FAILED.'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'The maximal discrepancy in the singular values (relative to the norm) was ', SVDIFF
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_SVDIFF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      IF ( NFAIL_F_QR == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> F - Q*R test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'F - Q*R test FAILED ', NFAIL_F_QR, ' time(s)'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'The largest relative residual was ', TMP_FQR
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_F_QR
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZQ == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZQ, 'time(s)'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZQ
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_REZQ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAILQ_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>>>>> CGEDMDQ :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) NFAILQ_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>>>>> CGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) 'Test completed.'
 | 
				
			||||||
 | 
					      STOP
 | 
				
			||||||
 | 
					      END
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,813 @@
 | 
				
			||||||
 | 
					!     This is a test program for checking the implementations of
 | 
				
			||||||
 | 
					!     the implementations of the following subroutines
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     DGEDMD  for computation of the
 | 
				
			||||||
 | 
					!             Dynamic Mode Decomposition (DMD)
 | 
				
			||||||
 | 
					!     DGEDMDQ for computation of a
 | 
				
			||||||
 | 
					!             QR factorization based compressed DMD
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Developed and supported by:
 | 
				
			||||||
 | 
					!     ===========================
 | 
				
			||||||
 | 
					!     Developed and coded by Zlatko Drmac, Faculty of Science,
 | 
				
			||||||
 | 
					!     University of Zagreb;  drmac@math.hr
 | 
				
			||||||
 | 
					!     In cooperation with
 | 
				
			||||||
 | 
					!     AIMdyn Inc., Santa Barbara, CA.
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     How to run the code (compiler, link info)
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Compile as FORTRAN 90 (or later) and link with BLAS and
 | 
				
			||||||
 | 
					!     LAPACK libraries.
 | 
				
			||||||
 | 
					!     NOTE: The code is developed and tested on top of the
 | 
				
			||||||
 | 
					!     Intel MKL library (versions 2022.0.3 and 2022.2.0),
 | 
				
			||||||
 | 
					!     using the Intel Fortran compiler.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     For developers of the C++ implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     See the LAPACK++ and Template Numerical Toolkit (TNT)
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Note on a development of the GPU HP implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Work in progress. See CUDA, MAGMA, SLATE.
 | 
				
			||||||
 | 
					!     NOTE: The four SVD subroutines used in this code are
 | 
				
			||||||
 | 
					!     included as a part of R&D and for the completeness.
 | 
				
			||||||
 | 
					!     This was also an opportunity to test those SVD codes.
 | 
				
			||||||
 | 
					!     If the scaling option is used all four are essentially
 | 
				
			||||||
 | 
					!     equally good. For implementations on HP platforms,
 | 
				
			||||||
 | 
					!     one can use whichever SVD is available.
 | 
				
			||||||
 | 
					!...  .........................................................
 | 
				
			||||||
 | 
					!     NOTE:
 | 
				
			||||||
 | 
					!     When using the Intel MKL 2022.0.3 the subroutine xGESVDQ
 | 
				
			||||||
 | 
					!     (optionally used in xGEDMD) may cause access violation
 | 
				
			||||||
 | 
					!     error for x = S, D, C, Z, but only if called with the
 | 
				
			||||||
 | 
					!     work space query. (At least in our Windows 10 MSVS 2019.)
 | 
				
			||||||
 | 
					!     The problem can be mitigated by downloading the source
 | 
				
			||||||
 | 
					!     code of xGESVDQ from the LAPACK repository and use it
 | 
				
			||||||
 | 
					!     localy instead of the one in the MKL. This seems to
 | 
				
			||||||
 | 
					!     indicate that the problem is indeed in the MKL.
 | 
				
			||||||
 | 
					!     This problem did not appear whith Intel MKL 2022.2.0.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     NOTE:
 | 
				
			||||||
 | 
					!     xGESDD seems to have a problem with workspace. In some
 | 
				
			||||||
 | 
					!     cases the length of the optimal workspace is returned
 | 
				
			||||||
 | 
					!     smaller than the minimal workspace, as specified in the
 | 
				
			||||||
 | 
					!     code. As a precaution, all optimal workspaces are
 | 
				
			||||||
 | 
					!     set as MAX(minimal, optimal).
 | 
				
			||||||
 | 
					!     Latest implementations of complex xGESDD have different
 | 
				
			||||||
 | 
					!     length of the real worksapce. We use max value over
 | 
				
			||||||
 | 
					!     two versions.
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					      PROGRAM DMD_TEST
 | 
				
			||||||
 | 
					      use iso_fortran_env, only: real64
 | 
				
			||||||
 | 
					      IMPLICIT NONE
 | 
				
			||||||
 | 
					      integer, parameter :: WP = real64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER ::  ONE = 1.0_WP
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER :: ZERO = 0.0_WP
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:,:) ::          &
 | 
				
			||||||
 | 
					                     A, AC, EIGA, LAMBDA, LAMBDAQ, F, F1, F2,&
 | 
				
			||||||
 | 
					                     Z, Z1, S, AU, W, VA, X, X0, Y, Y0, Y1
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:)   ::          &
 | 
				
			||||||
 | 
					                     DA, DL, DR, REIG, REIGA, REIGQ, IEIG,   &
 | 
				
			||||||
 | 
					                     IEIGA, IEIGQ,  RES, RES1, RESEX, SINGVX,&
 | 
				
			||||||
 | 
					                     SINGVQX, WORK
 | 
				
			||||||
 | 
					      INTEGER      , ALLOCATABLE, DIMENSION(:)   ::   IWORK
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: AB(2,2),   WDUMMY(2)
 | 
				
			||||||
 | 
					      INTEGER       :: IDUMMY(2), ISEED(4), RJOBDATA(8)
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: ANORM, COND, CONDL, CONDR, DMAX, EPS, &
 | 
				
			||||||
 | 
					                       TOL, TOL2, SVDIFF, TMP, TMP_AU,       &
 | 
				
			||||||
 | 
					                       TMP_FQR, TMP_REZ, TMP_REZQ,  TMP_ZXW, &
 | 
				
			||||||
 | 
					                       TMP_EX, XNORM, YNORM
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY,  &
 | 
				
			||||||
 | 
					                 LDZ, LIWORK, LWORK, M, N, L, LLOOP, NRNK
 | 
				
			||||||
 | 
					      INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, j, KDIFF,  &
 | 
				
			||||||
 | 
					                 NFAIL, NFAIL_AU, NFAIL_F_QR, NFAIL_REZ,     &
 | 
				
			||||||
 | 
					                 NFAIL_REZQ, NFAIL_SVDIFF, NFAIL_TOTAL, NFAILQ_TOTAL, &
 | 
				
			||||||
 | 
					                 NFAIL_Z_XV, MODE, MODEL, MODER, WHTSVD
 | 
				
			||||||
 | 
					      INTEGER    iNRNK, iWHTSVD, K_TRAJ, LWMINOPT
 | 
				
			||||||
 | 
					      CHARACTER(LEN=1) GRADE, JOBREF, JOBZ, PIVTNG, RSIGN,   &
 | 
				
			||||||
 | 
					                       SCALE, RESIDS, WANTQ, WANTR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LOGICAL  TEST_QRDMD
 | 
				
			||||||
 | 
					!..... external subroutines (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL DAXPY,  DGEEV, DGEMM, DGEMV, DLACPY, DLASCL
 | 
				
			||||||
 | 
					      EXTERNAL DLARNV, DLATMR
 | 
				
			||||||
 | 
					!.....external subroutines DMD package, part 1
 | 
				
			||||||
 | 
					!     subroutines under test
 | 
				
			||||||
 | 
					      EXTERNAL DGEDMD, DGEDMDQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!..... external functions (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL         DLAMCH, DLANGE, DNRM2
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: DLAMCH, DLANGE, DNRM2
 | 
				
			||||||
 | 
					      EXTERNAL         LSAME
 | 
				
			||||||
 | 
					      LOGICAL          LSAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      INTRINSIC ABS, INT, MIN, MAX
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! The test is always in pairs : ( DGEDMD and DGEDMDQ )
 | 
				
			||||||
 | 
					      ! because the test includes comparing the results (in pairs).
 | 
				
			||||||
 | 
					!.....................................................................................
 | 
				
			||||||
 | 
					      TEST_QRDMD = .TRUE. ! This code by default performs tests on DGEDMDQ
 | 
				
			||||||
 | 
					                          ! Since the QR factorizations based algorithm is designed for
 | 
				
			||||||
 | 
					                          ! single trajectory data, only single trajectory tests will
 | 
				
			||||||
 | 
					                          ! be performed with xGEDMDQ.
 | 
				
			||||||
 | 
					      WANTQ = 'Q'
 | 
				
			||||||
 | 
					      WANTR = 'R'
 | 
				
			||||||
 | 
					!.................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      EPS = DLAMCH( 'P' )  ! machine precision DP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Global counters of failures of some particular tests
 | 
				
			||||||
 | 
					      NFAIL      = 0
 | 
				
			||||||
 | 
					      NFAIL_REZ  = 0
 | 
				
			||||||
 | 
					      NFAIL_REZQ = 0
 | 
				
			||||||
 | 
					      NFAIL_Z_XV = 0
 | 
				
			||||||
 | 
					      NFAIL_F_QR = 0
 | 
				
			||||||
 | 
					      NFAIL_AU   = 0
 | 
				
			||||||
 | 
					      KDIFF      = 0
 | 
				
			||||||
 | 
					      NFAIL_SVDIFF = 0
 | 
				
			||||||
 | 
					      NFAIL_TOTAL  = 0
 | 
				
			||||||
 | 
					      NFAILQ_TOTAL = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LLOOP = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) 'L Loop Index = ', LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Set the dimensions of the problem ...
 | 
				
			||||||
 | 
					      WRITE(*,*) 'M = '
 | 
				
			||||||
 | 
					      READ(*,*) M
 | 
				
			||||||
 | 
					      WRITE(*,*) M
 | 
				
			||||||
 | 
					      ! ... and the number of snapshots.
 | 
				
			||||||
 | 
					      WRITE(*,*) 'N = '
 | 
				
			||||||
 | 
					      READ(*,*) N
 | 
				
			||||||
 | 
					      WRITE(*,*) N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! ... Test the dimensions
 | 
				
			||||||
 | 
					      IF ( ( MIN(M,N) == 0 ) .OR. ( M < N )  ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Bad dimensions. Required: M >= N > 0.'
 | 
				
			||||||
 | 
					          STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					      ! The seed inside the LLOOP so that each pass can be reproduced easily.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ISEED(1) = 4
 | 
				
			||||||
 | 
					      ISEED(2) = 3
 | 
				
			||||||
 | 
					      ISEED(3) = 2
 | 
				
			||||||
 | 
					      ISEED(4) = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LDA  = M
 | 
				
			||||||
 | 
					      LDF  = M
 | 
				
			||||||
 | 
					      LDX  = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDY  = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDW  = N
 | 
				
			||||||
 | 
					      LDZ  = M
 | 
				
			||||||
 | 
					      LDAU = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDS  = N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP_ZXW  = ZERO
 | 
				
			||||||
 | 
					      TMP_AU   = ZERO
 | 
				
			||||||
 | 
					      TMP_REZ  = ZERO
 | 
				
			||||||
 | 
					      TMP_REZQ = ZERO
 | 
				
			||||||
 | 
					      SVDIFF   = ZERO
 | 
				
			||||||
 | 
					      TMP_EX   = ZERO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !
 | 
				
			||||||
 | 
					      ! Test the subroutines on real data snapshots. All
 | 
				
			||||||
 | 
					      ! computation is done in real arithmetic, even when
 | 
				
			||||||
 | 
					      ! Koopman eigenvalues and modes are real.
 | 
				
			||||||
 | 
					      !
 | 
				
			||||||
 | 
					      ! Allocate memory space
 | 
				
			||||||
 | 
					      ALLOCATE( A(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( AC(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( DA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( DL(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( F(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F1(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F2(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( X(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( X0(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVQX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y0(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y1(M,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z1(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES(N)  )
 | 
				
			||||||
 | 
					      ALLOCATE( RES1(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RESEX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIG(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIG(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIGQ(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIGQ(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIGA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIGA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( VA(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( LAMBDA(N,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( LAMBDAQ(N,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( EIGA(M,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( W(LDW,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( AU(LDAU,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( S(N,N) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TOL  = M*EPS
 | 
				
			||||||
 | 
					      ! This mimics O(M*N)*EPS bound for accumulated roundoff error.
 | 
				
			||||||
 | 
					      ! The factor 10 is somewhat arbitrary.
 | 
				
			||||||
 | 
					      TOL2 = 10*M*N*EPS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO K_TRAJ = 1, 2
 | 
				
			||||||
 | 
					      !  Number of intial conditions in the simulation/trajectories (1 or 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COND = 1.0D8
 | 
				
			||||||
 | 
					      DMAX = 1.0D2
 | 
				
			||||||
 | 
					      RSIGN = 'F'
 | 
				
			||||||
 | 
					      GRADE = 'N'
 | 
				
			||||||
 | 
					      MODEL = 6
 | 
				
			||||||
 | 
					      CONDL = 1.0D2
 | 
				
			||||||
 | 
					      MODER = 6
 | 
				
			||||||
 | 
					      CONDR = 1.0D2
 | 
				
			||||||
 | 
					      PIVTNG = 'N'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Loop over all parameter MODE values for ZLATMR (+1,..,+6)
 | 
				
			||||||
 | 
					      DO MODE = 1, 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( IWORK(2*M) )
 | 
				
			||||||
 | 
					      ALLOCATE(DR(N))
 | 
				
			||||||
 | 
					      CALL DLATMR( M, M, 'S', ISEED, 'N', DA, MODE, COND, &
 | 
				
			||||||
 | 
					                   DMAX, RSIGN, GRADE, DL, MODEL,  CONDL, &
 | 
				
			||||||
 | 
					                   DR, MODER, CONDR, PIVTNG, IWORK, M, M, &
 | 
				
			||||||
 | 
					                   ZERO, -ONE, 'N', A, LDA, IWORK(M+1), INFO )
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(DR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LWORK = 4*M+1
 | 
				
			||||||
 | 
					      ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					      AC  = A
 | 
				
			||||||
 | 
					      CALL DGEEV( 'N','V', M, AC, M, REIGA, IEIGA, VA, M, &
 | 
				
			||||||
 | 
					                  VA, M, WORK, LWORK, INFO ) ! LAPACK CALL
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      TMP = ZERO
 | 
				
			||||||
 | 
					      DO i = 1, M
 | 
				
			||||||
 | 
					         EIGA(i,1) = REIGA(i)
 | 
				
			||||||
 | 
					         EIGA(i,2) = IEIGA(i)
 | 
				
			||||||
 | 
					         TMP = MAX( TMP, SQRT(REIGA(i)**2+IEIGA(i)**2))
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Scale A to have the desirable spectral radius.
 | 
				
			||||||
 | 
					      CALL DLASCL( 'G', 0, 0, TMP, ONE, M, M, A, M, INFO )
 | 
				
			||||||
 | 
					      CALL DLASCL( 'G', 0, 0, TMP, ONE, M, 2, EIGA, M, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Compute the norm of A
 | 
				
			||||||
 | 
					      ANORM = DLANGE( 'F', N, N, A, M, WDUMMY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( K_TRAJ == 2 ) THEN
 | 
				
			||||||
 | 
					          ! generate data with two inital conditions
 | 
				
			||||||
 | 
					      CALL DLARNV(2, ISEED, M, F1(1,1) )
 | 
				
			||||||
 | 
					      F1(1:M,1) = 1.0E-10*F1(1:M,1)
 | 
				
			||||||
 | 
					      DO i = 1, N/2
 | 
				
			||||||
 | 
					         CALL DGEMV( 'N', M, M, ONE, A, M, F1(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F1(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,1:N/2) = F1(1:M,1:N/2)
 | 
				
			||||||
 | 
					      Y0(1:M,1:N/2) = F1(1:M,2:N/2+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL DLARNV(2, ISEED, M, F1(1,1) )
 | 
				
			||||||
 | 
					      DO i = 1, N-N/2
 | 
				
			||||||
 | 
					         CALL DGEMV( 'N', M, M, ONE, A, M, F1(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F1(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,N/2+1:N) = F1(1:M,1:N-N/2)
 | 
				
			||||||
 | 
					      Y0(1:M,N/2+1:N) = F1(1:M,2:N-N/2+1)
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					      CALL DLARNV(2, ISEED, M, F(1,1) )
 | 
				
			||||||
 | 
					      DO i = 1, N
 | 
				
			||||||
 | 
					         CALL DGEMV( 'N', M, M, ONE, A, M, F(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,1:N) = F(1:M,1:N)
 | 
				
			||||||
 | 
					      Y0(1:M,1:N) = F(1:M,2:N+1)
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      XNORM = DLANGE( 'F', M, N, X0, LDX, WDUMMY )
 | 
				
			||||||
 | 
					      YNORM = DLANGE( 'F', M, N, Y0, LDX, WDUMMY )
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBZ = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBZ )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBZ   = 'V' ! Ritz vectors will be computed
 | 
				
			||||||
 | 
					              RESIDS = 'R' ! Residuals will be computed
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBZ   = 'F' ! Ritz vectors in factored form
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              JOBZ   = 'N'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBREF = 1, 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBREF )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBREF = 'R' ! Data for refined Ritz vectors
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBREF = 'E' ! Exact DMD vectors
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBREF = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iSCALE = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iSCALE )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              SCALE = 'S' ! X data normalized
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              SCALE = 'C' ! X normalized, consist. check
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              SCALE = 'Y' ! Y data normalized
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              SCALE = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iNRNK = -1, -2, -1
 | 
				
			||||||
 | 
					          ! Two truncation strategies. The "-2" case for R&D
 | 
				
			||||||
 | 
					          ! purposes only - it uses possibly low accuracy small
 | 
				
			||||||
 | 
					          ! singular values, in which case the formulas used in
 | 
				
			||||||
 | 
					          ! the DMD are highly sensitive.
 | 
				
			||||||
 | 
					          NRNK   = iNRNK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iWHTSVD = 1, 4
 | 
				
			||||||
 | 
					          ! Check all four options to compute the POD basis
 | 
				
			||||||
 | 
					          ! via the SVD.
 | 
				
			||||||
 | 
					          WHTSVD   = iWHTSVD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LWMINOPT = 1, 2
 | 
				
			||||||
 | 
					          ! Workspace query for the minimal (1) and for the optimal
 | 
				
			||||||
 | 
					          ! (2) workspace lengths determined by workspace query.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      X(1:M,1:N) = X0(1:M,1:N)
 | 
				
			||||||
 | 
					      Y(1:M,1:N) = Y0(1:M,1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! DGEDMD: Workspace query and workspace allocation
 | 
				
			||||||
 | 
					      CALL DGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, M, &
 | 
				
			||||||
 | 
					           N, X, LDX, Y, LDY, NRNK, TOL, K, REIG, IEIG, Z, &
 | 
				
			||||||
 | 
					           LDZ, RES, AU, LDAU, W, LDW, S, LDS, WDUMMY, -1, &
 | 
				
			||||||
 | 
					           IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					      ALLOCATE( IWORK(LIWORK) )
 | 
				
			||||||
 | 
					      LWORK = INT(WDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					      ALLOCATE( WORK(LWORK) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! DGEDMD test: CALL DGEDMD
 | 
				
			||||||
 | 
					      CALL DGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, M, &
 | 
				
			||||||
 | 
					           N, X, LDX, Y, LDY, NRNK, TOL, K, REIG, IEIG, Z, &
 | 
				
			||||||
 | 
					           LDZ, RES, AU, LDAU, W, LDW, S, LDS, WORK, LWORK,&
 | 
				
			||||||
 | 
					           IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      SINGVX(1:N) = WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... DGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBZ,'V')  ) THEN
 | 
				
			||||||
 | 
					          ! Check that Z = X*W, on return from DGEDMD
 | 
				
			||||||
 | 
					          ! This checks that the returned aigenvectors in Z are
 | 
				
			||||||
 | 
					          ! the product of the SVD'POD basis returned in X
 | 
				
			||||||
 | 
					          ! and the eigenvectors of the rayleigh quotient
 | 
				
			||||||
 | 
					          ! returned in W
 | 
				
			||||||
 | 
					          CALL DGEMM( 'N', 'N', M, K, K, ONE, X, LDX, W, LDW, &
 | 
				
			||||||
 | 
					                      ZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					             CALL DAXPY( M, -ONE, Z(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, DNRM2( M, Z1(1,i), 1 ) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_ZXW = MAX(TMP_ZXW, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( TMP_ZXW > 10*M*EPS ) THEN
 | 
				
			||||||
 | 
					              NFAIL_Z_XV = NFAIL_Z_XV + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................DGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... DGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBREF,'R') ) THEN
 | 
				
			||||||
 | 
					          ! The matrix A*U is returned for computing refined Ritz vectors.
 | 
				
			||||||
 | 
					          ! Check that A*U is computed correctly using the formula
 | 
				
			||||||
 | 
					          ! A*U = Y * V * inv(SIGMA). This depends on the
 | 
				
			||||||
 | 
					          ! accuracy in the computed singular values and vectors of X.
 | 
				
			||||||
 | 
					          ! See the paper for an error analysis.
 | 
				
			||||||
 | 
					          ! Note that the left singular vectors of the input matrix X
 | 
				
			||||||
 | 
					          ! are returned in the array X.
 | 
				
			||||||
 | 
					          CALL DGEMM( 'N', 'N', M, K, M, ONE, A, LDA, X, LDX, &
 | 
				
			||||||
 | 
					                     ZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					              CALL DAXPY( M, -ONE, AU(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					              TMP = MAX( TMP, DNRM2( M, Z1(1,i),1 ) * &
 | 
				
			||||||
 | 
					                       SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_AU = MAX( TMP_AU, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					              NFAIL_AU = NFAIL_AU + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................DGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ELSEIF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					      ! The unscaled vectors of the Exact DMD are computed.
 | 
				
			||||||
 | 
					      ! This option is included for the sake of completeness,
 | 
				
			||||||
 | 
					      ! for users who prefer the Exact DMD vectors. The
 | 
				
			||||||
 | 
					      ! returned vectors are in the real form, in the same way
 | 
				
			||||||
 | 
					      ! as the Ritz vectors. Here we just save the vectors
 | 
				
			||||||
 | 
					      ! and test them separately using a Matlab script.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       CALL DGEMM( 'N', 'N', M, K, M, ONE, A, LDA, AU, LDAU, ZERO, Y1, M )
 | 
				
			||||||
 | 
					       i=1
 | 
				
			||||||
 | 
					       DO WHILE ( i <= K )
 | 
				
			||||||
 | 
					           IF ( IEIG(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					           ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					           CALL DAXPY( M, -REIG(i), AU(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					           RESEX(i) = DNRM2( M, Y1(1,i), 1) / DNRM2(M,AU(1,i),1)
 | 
				
			||||||
 | 
					           i = i + 1
 | 
				
			||||||
 | 
					           ELSE
 | 
				
			||||||
 | 
					           ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					           ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					           ! Since all computation is done in real
 | 
				
			||||||
 | 
					           ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					           ! is recast for real representation of the
 | 
				
			||||||
 | 
					           ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					           ! description of RES.
 | 
				
			||||||
 | 
					           AB(1,1) =  REIG(i)
 | 
				
			||||||
 | 
					           AB(2,1) = -IEIG(i)
 | 
				
			||||||
 | 
					           AB(1,2) =  IEIG(i)
 | 
				
			||||||
 | 
					           AB(2,2) =  REIG(i)
 | 
				
			||||||
 | 
					           CALL DGEMM( 'N', 'N', M, 2, 2, -ONE, AU(1,i), &
 | 
				
			||||||
 | 
					                       M, AB, 2, ONE, Y1(1,i), M )
 | 
				
			||||||
 | 
					           RESEX(i)   = DLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                        WORK )/ DLANGE( 'F', M, 2, AU(1,i), M, &
 | 
				
			||||||
 | 
					                        WORK )
 | 
				
			||||||
 | 
					           RESEX(i+1) = RESEX(i)
 | 
				
			||||||
 | 
					           i = i + 2
 | 
				
			||||||
 | 
					           END IF
 | 
				
			||||||
 | 
					       END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... DGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					          ! Compare the residuals returned by DGEDMD with the
 | 
				
			||||||
 | 
					          ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					          ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					          CALL DGEMM( 'N', 'N', M, K, M, ONE, A, LDA, Z, LDZ, ZERO, Y1, M )
 | 
				
			||||||
 | 
					          ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					          ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					          ! pairs of eigencalues. (See the description of Z in DGEDMD,)
 | 
				
			||||||
 | 
					          i = 1
 | 
				
			||||||
 | 
					          DO WHILE ( i <= K )
 | 
				
			||||||
 | 
					              IF ( IEIG(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					                  ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                  CALL DAXPY( M, -REIG(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                  RES1(i) = DNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					                  i = i + 1
 | 
				
			||||||
 | 
					              ELSE
 | 
				
			||||||
 | 
					                  ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					                  ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					                  ! Since all computation is done in real
 | 
				
			||||||
 | 
					                  ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					                  ! is recast for real representation of the
 | 
				
			||||||
 | 
					                  ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					                  ! description of RES.
 | 
				
			||||||
 | 
					                  AB(1,1) =  REIG(i)
 | 
				
			||||||
 | 
					                  AB(2,1) = -IEIG(i)
 | 
				
			||||||
 | 
					                  AB(1,2) =  IEIG(i)
 | 
				
			||||||
 | 
					                  AB(2,2) =  REIG(i)
 | 
				
			||||||
 | 
					                  CALL DGEMM( 'N', 'N', M, 2, 2, -ONE, Z(1,i), &
 | 
				
			||||||
 | 
					                              M, AB, 2, ONE, Y1(1,i), M )
 | 
				
			||||||
 | 
					                  RES1(i)   = DLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                                     WORK )
 | 
				
			||||||
 | 
					                  RES1(i+1) = RES1(i)
 | 
				
			||||||
 | 
					                  i = i + 2
 | 
				
			||||||
 | 
					              END IF
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					              TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                        SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_REZ = MAX( TMP_REZ, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					              NFAIL_REZ = NFAIL_REZ + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( ..................DGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					              TMP = ZERO
 | 
				
			||||||
 | 
					              DO i = 1, K
 | 
				
			||||||
 | 
					                  TMP = MAX( TMP, ABS(RES1(i) - RESEX(i))/(RES1(i)+RESEX(i)) )
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP_EX = MAX(TMP_EX,TMP)
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !..... store the results for inspection
 | 
				
			||||||
 | 
					      DO i = 1, K
 | 
				
			||||||
 | 
					          LAMBDA(i,1) = REIG(i)
 | 
				
			||||||
 | 
					          LAMBDA(i,2) = IEIG(i)
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !======================================================================
 | 
				
			||||||
 | 
					      !     Now test the DGEDMDQ
 | 
				
			||||||
 | 
					      !======================================================================
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD .AND. (K_TRAJ == 1) ) THEN
 | 
				
			||||||
 | 
					          RJOBDATA(2) = 1
 | 
				
			||||||
 | 
					          F1 = F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          ! DGEDMDQ test: Workspace query and workspace allocation
 | 
				
			||||||
 | 
					          CALL DGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, &
 | 
				
			||||||
 | 
					               JOBREF, WHTSVD, M, N+1, F1, LDF, X, LDX, Y, &
 | 
				
			||||||
 | 
					               LDY, NRNK, TOL, KQ, REIGQ, IEIGQ, Z, LDZ,   &
 | 
				
			||||||
 | 
					               RES, AU, LDAU, W, LDW, S, LDS, WDUMMY,      &
 | 
				
			||||||
 | 
					               -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					          LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					          ALLOCATE( IWORK(LIWORK) )
 | 
				
			||||||
 | 
					          LWORK = INT(WDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					          ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					          ! DGEDMDQ test: CALL DGEDMDQ
 | 
				
			||||||
 | 
					          CALL DGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, &
 | 
				
			||||||
 | 
					               JOBREF, WHTSVD, M, N+1, F1, LDF, X, LDX, Y, &
 | 
				
			||||||
 | 
					               LDY, NRNK, TOL, KQ, REIGQ, IEIGQ, Z, LDZ,   &
 | 
				
			||||||
 | 
					               RES, AU, LDAU, W, LDW, S, LDS,              &
 | 
				
			||||||
 | 
					               WORK, LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SINGVQX(1:KQ) = WORK(MIN(M,N+1)+1: MIN(M,N+1)+KQ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... DGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( KQ /= K ) THEN
 | 
				
			||||||
 | 
					              KDIFF = KDIFF+1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, MIN(K, KQ)
 | 
				
			||||||
 | 
					              TMP = MAX(TMP, ABS(SINGVX(i)-SINGVQX(i)) / &
 | 
				
			||||||
 | 
					                                    SINGVX(1) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          SVDIFF = MAX( SVDIFF, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP > M*N*EPS ) THEN
 | 
				
			||||||
 | 
					              WRITE(*,*) 'FAILED! Something was wrong with the run.'
 | 
				
			||||||
 | 
					              NFAIL_SVDIFF = NFAIL_SVDIFF + 1
 | 
				
			||||||
 | 
					              DO j =1, 3
 | 
				
			||||||
 | 
					                  write(*,*) j, SINGVX(j), SINGVQX(j)
 | 
				
			||||||
 | 
					                  read(*,*)
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... DGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( LSAME(WANTQ,'Q') .AND. LSAME(WANTR,'R') ) THEN
 | 
				
			||||||
 | 
					              ! Check that the QR factors are computed and returned
 | 
				
			||||||
 | 
					              ! as requested. The residual ||F-Q*R||_F / ||F||_F
 | 
				
			||||||
 | 
					              ! is compared to M*N*EPS.
 | 
				
			||||||
 | 
					              F2 = F
 | 
				
			||||||
 | 
					              CALL DGEMM( 'N', 'N', M, N+1, MIN(M,N+1), -ONE, F1, &
 | 
				
			||||||
 | 
					                          LDF, Y, LDY, ONE, F2, LDF )
 | 
				
			||||||
 | 
					              TMP_FQR = DLANGE( 'F', M, N+1, F2, LDF, WORK ) / &
 | 
				
			||||||
 | 
					                    DLANGE( 'F', M, N+1, F,  LDF, WORK )
 | 
				
			||||||
 | 
					              IF ( TMP_FQR > TOL2 ) THEN
 | 
				
			||||||
 | 
					                  WRITE(*,*) 'FAILED! Something was wrong with the run.'
 | 
				
			||||||
 | 
					                  NFAIL_F_QR = NFAIL_F_QR + 1
 | 
				
			||||||
 | 
					              END IF
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... DGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					              ! Compare the residuals returned by DGEDMDQ with the
 | 
				
			||||||
 | 
					              ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					              ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					              CALL DGEMM( 'N', 'N', M, KQ, M, ONE, A, M, Z, M, ZERO, Y1, M )
 | 
				
			||||||
 | 
					              ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					              ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					              ! pairs of eigencalues. (See the description of Z in DGEDMDQ)
 | 
				
			||||||
 | 
					              i = 1
 | 
				
			||||||
 | 
					              DO WHILE ( i <= KQ )
 | 
				
			||||||
 | 
					                  IF ( IEIGQ(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					                      ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                      CALL DAXPY( M, -REIGQ(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                      ! Y(1:M,i) = Y(1:M,i) - REIG(i)*Z(1:M,i)
 | 
				
			||||||
 | 
					                      RES1(i) = DNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					                      i = i + 1
 | 
				
			||||||
 | 
					                  ELSE
 | 
				
			||||||
 | 
					                     ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					                     ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					                     ! Since all computation is done in real
 | 
				
			||||||
 | 
					                     ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					                     ! is recast for real representation of the
 | 
				
			||||||
 | 
					                     ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					                     ! description of RES.
 | 
				
			||||||
 | 
					                     AB(1,1) =  REIGQ(i)
 | 
				
			||||||
 | 
					                     AB(2,1) = -IEIGQ(i)
 | 
				
			||||||
 | 
					                     AB(1,2) =  IEIGQ(i)
 | 
				
			||||||
 | 
					                     AB(2,2) =  REIGQ(i)
 | 
				
			||||||
 | 
					                     CALL DGEMM( 'N', 'N', M, 2, 2, -ONE, Z(1,i), &
 | 
				
			||||||
 | 
					                                 M, AB, 2, ONE, Y1(1,i), M )             ! BLAS CALL
 | 
				
			||||||
 | 
					                     ! Y(1:M,i:i+1) = Y(1:M,i:i+1) - Z(1:M,i:i+1) * AB   ! INTRINSIC
 | 
				
			||||||
 | 
					                     RES1(i)   = DLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                                        WORK )                           ! LAPACK CALL
 | 
				
			||||||
 | 
					                     RES1(i+1) = RES1(i)
 | 
				
			||||||
 | 
					                     i = i + 2
 | 
				
			||||||
 | 
					                  END IF
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP = ZERO
 | 
				
			||||||
 | 
					              DO i = 1, KQ
 | 
				
			||||||
 | 
					                  TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                      SINGVQX(K)/(ANORM*SINGVQX(1)) )
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP_REZQ = MAX( TMP_REZQ, TMP )
 | 
				
			||||||
 | 
					              IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					                  NFAIL_REZQ = NFAIL_REZQ + 1
 | 
				
			||||||
 | 
					                  WRITE(*,*) '................ DGEDMDQ FAILED!', &
 | 
				
			||||||
 | 
					                      'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					                  STOP
 | 
				
			||||||
 | 
					              END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i = 1, KQ
 | 
				
			||||||
 | 
					              LAMBDAQ(i,1) = REIGQ(i)
 | 
				
			||||||
 | 
					              LAMBDAQ(i,2) = IEIGQ(i)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					          DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      END IF ! TEST_QRDMD
 | 
				
			||||||
 | 
					!======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! LWMINOPT
 | 
				
			||||||
 | 
					      !write(*,*) 'LWMINOPT loop completed'
 | 
				
			||||||
 | 
					      END DO ! WHTSVD LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'WHTSVD loop completed'
 | 
				
			||||||
 | 
					      END DO ! NRNK LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'NRNK loop completed'
 | 
				
			||||||
 | 
					      END DO ! SCALE LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'SCALE loop completed'
 | 
				
			||||||
 | 
					      END DO ! JOBF LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBREF loop completed'
 | 
				
			||||||
 | 
					      END DO ! JOBZ LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBZ loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! MODE -6:6
 | 
				
			||||||
 | 
					      !write(*,*) 'MODE loop completed'
 | 
				
			||||||
 | 
					      END DO ! 1 or 2 trajectories
 | 
				
			||||||
 | 
					      !write(*,*) 'trajectories  loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(A)
 | 
				
			||||||
 | 
					      DEALLOCATE(AC)
 | 
				
			||||||
 | 
					      DEALLOCATE(DA)
 | 
				
			||||||
 | 
					      DEALLOCATE(DL)
 | 
				
			||||||
 | 
					      DEALLOCATE(F)
 | 
				
			||||||
 | 
					      DEALLOCATE(F1)
 | 
				
			||||||
 | 
					      DEALLOCATE(F2)
 | 
				
			||||||
 | 
					      DEALLOCATE(X)
 | 
				
			||||||
 | 
					      DEALLOCATE(X0)
 | 
				
			||||||
 | 
					      DEALLOCATE(SINGVX)
 | 
				
			||||||
 | 
					      DEALLOCATE(SINGVQX)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y0)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y1)
 | 
				
			||||||
 | 
					      DEALLOCATE(Z)
 | 
				
			||||||
 | 
					      DEALLOCATE(Z1)
 | 
				
			||||||
 | 
					      DEALLOCATE(RES)
 | 
				
			||||||
 | 
					      DEALLOCATE(RES1)
 | 
				
			||||||
 | 
					      DEALLOCATE(RESEX)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIG)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIG)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIGQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIGQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(VA)
 | 
				
			||||||
 | 
					      DEALLOCATE(LAMBDA)
 | 
				
			||||||
 | 
					      DEALLOCATE(LAMBDAQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(EIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(W)
 | 
				
			||||||
 | 
					      DEALLOCATE(AU)
 | 
				
			||||||
 | 
					      DEALLOCATE(S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      !     Generate random M-by-M matrix A. Use DLATMR from
 | 
				
			||||||
 | 
					      END DO ! LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for DGEDMD :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      IF ( NFAIL_Z_XV == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Z - U*V test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Z - U*V test FAILED ', NFAIL_Z_XV, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max error ||Z-U*V||_F was ', TMP_ZXW
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_Z_XV
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      IF ( NFAIL_AU == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> A*U test PASSED. '
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'A*U test FAILED ', NFAIL_AU, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max A*U test adjusted error measure was ', TMP_AU
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_AU
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZ == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZ, 'time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZ
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_REZ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> DGEDMD :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) NFAIL_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>>>>>>>>>>>> DGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD ) THEN
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for DGEDMDQ :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_SVDIFF == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> DGEDMD and DGEDMDQ computed singular &
 | 
				
			||||||
 | 
					              &values test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'DGEDMD and DGEDMDQ discrepancies in &
 | 
				
			||||||
 | 
					              &the singular values unacceptable ', &
 | 
				
			||||||
 | 
					              NFAIL_SVDIFF, ' times. Test FAILED.'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'The maximal discrepancy in the singular values (relative to the norm) was ', SVDIFF
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_SVDIFF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_F_QR == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> F - Q*R test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'F - Q*R test FAILED ', NFAIL_F_QR, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'The largest relative residual was ', TMP_FQR
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_F_QR
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZQ == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZQ, 'time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZQ
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_REZQ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAILQ_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>>>>> DGEDMDQ :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					         WRITE(*,*) NFAILQ_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					         WRITE(*,*) '>>>>>>> DGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) 'Test completed.'
 | 
				
			||||||
 | 
					      STOP
 | 
				
			||||||
 | 
					      END
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,792 @@
 | 
				
			||||||
 | 
					!     This is a test program for checking the implementations of
 | 
				
			||||||
 | 
					!     the implementations of the following subroutines
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     SGEDMD  for computation of the
 | 
				
			||||||
 | 
					!             Dynamic Mode Decomposition (DMD)
 | 
				
			||||||
 | 
					!     SGEDMDQ for computation of a
 | 
				
			||||||
 | 
					!             QR factorization based compressed DMD
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Developed and supported by:
 | 
				
			||||||
 | 
					!     ===========================
 | 
				
			||||||
 | 
					!     Developed and coded by Zlatko Drmac, Faculty of Science,
 | 
				
			||||||
 | 
					!     University of Zagreb;  drmac@math.hr
 | 
				
			||||||
 | 
					!     In cooperation with
 | 
				
			||||||
 | 
					!     AIMdyn Inc., Santa Barbara, CA.
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     How to run the code (compiler, link info)
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Compile as FORTRAN 90 (or later) and link with BLAS and
 | 
				
			||||||
 | 
					!     LAPACK libraries.
 | 
				
			||||||
 | 
					!     NOTE: The code is developed and tested on top of the
 | 
				
			||||||
 | 
					!     Intel MKL library (versions 2022.0.3 and 2022.2.0),
 | 
				
			||||||
 | 
					!     using the Intel Fortran compiler.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     For developers of the C++ implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     See the LAPACK++ and Template Numerical Toolkit (TNT)
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Note on a development of the GPU HP implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Work in progress. See CUDA, MAGMA, SLATE.
 | 
				
			||||||
 | 
					!     NOTE: The four SVD subroutines used in this code are
 | 
				
			||||||
 | 
					!     included as a part of R&D and for the completeness.
 | 
				
			||||||
 | 
					!     This was also an opportunity to test those SVD codes.
 | 
				
			||||||
 | 
					!     If the scaling option is used all four are essentially
 | 
				
			||||||
 | 
					!     equally good. For implementations on HP platforms,
 | 
				
			||||||
 | 
					!     one can use whichever SVD is available.
 | 
				
			||||||
 | 
					!...  .........................................................
 | 
				
			||||||
 | 
					!     NOTE:
 | 
				
			||||||
 | 
					!     When using the Intel MKL 2022.0.3 the subroutine xGESVDQ
 | 
				
			||||||
 | 
					!     (optionally used in xGEDMD) may cause access violation
 | 
				
			||||||
 | 
					!     error for x = S, D, C, Z, but only if called with the
 | 
				
			||||||
 | 
					!     work space query. (At least in our Windows 10 MSVS 2019.)
 | 
				
			||||||
 | 
					!     The problem can be mitigated by downloading the source
 | 
				
			||||||
 | 
					!     code of xGESVDQ from the LAPACK repository and use it
 | 
				
			||||||
 | 
					!     localy instead of the one in the MKL. This seems to
 | 
				
			||||||
 | 
					!     indicate that the problem is indeed in the MKL.
 | 
				
			||||||
 | 
					!     This problem did not appear whith Intel MKL 2022.2.0.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     NOTE:
 | 
				
			||||||
 | 
					!     xGESDD seems to have a problem with workspace. In some
 | 
				
			||||||
 | 
					!     cases the length of the optimal workspace is returned
 | 
				
			||||||
 | 
					!     smaller than the minimal workspace, as specified in the
 | 
				
			||||||
 | 
					!     code. As a precaution, all optimal workspaces are
 | 
				
			||||||
 | 
					!     set as MAX(minimal, optimal).
 | 
				
			||||||
 | 
					!     Latest implementations of complex xGESDD have different
 | 
				
			||||||
 | 
					!     length of the real worksapce. We use max value over
 | 
				
			||||||
 | 
					!     two versions.
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					      PROGRAM DMD_TEST
 | 
				
			||||||
 | 
					      use iso_fortran_env, only: real32
 | 
				
			||||||
 | 
					      IMPLICIT NONE
 | 
				
			||||||
 | 
					      integer, parameter :: WP = real32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER ::  ONE = 1.0_WP
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER :: ZERO = 0.0_WP
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:,:) ::          &
 | 
				
			||||||
 | 
					                     A, AC, EIGA, LAMBDA, LAMBDAQ, F, F1, F2,&
 | 
				
			||||||
 | 
					                     Z, Z1, S, AU, W, VA, X, X0, Y, Y0, Y1
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:)   ::          &
 | 
				
			||||||
 | 
					                     DA, DL, DR, REIG, REIGA, REIGQ, IEIG,   &
 | 
				
			||||||
 | 
					                     IEIGA, IEIGQ,  RES, RES1, RESEX, SINGVX,&
 | 
				
			||||||
 | 
					                     SINGVQX, WORK
 | 
				
			||||||
 | 
					      INTEGER      , ALLOCATABLE, DIMENSION(:)   ::   IWORK
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: AB(2,2),   WDUMMY(2)
 | 
				
			||||||
 | 
					      INTEGER       :: IDUMMY(2), ISEED(4), RJOBDATA(8)
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: ANORM, COND, CONDL, CONDR, DMAX, EPS, &
 | 
				
			||||||
 | 
					                       TOL, TOL2, SVDIFF, TMP, TMP_AU,       &
 | 
				
			||||||
 | 
					                       TMP_FQR, TMP_REZ, TMP_REZQ,  TMP_ZXW, &
 | 
				
			||||||
 | 
					                       TMP_EX, XNORM, YNORM
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY,  &
 | 
				
			||||||
 | 
					                 LDZ, LIWORK, LWORK, M, N, L, LLOOP, NRNK
 | 
				
			||||||
 | 
					      INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, KDIFF,     &
 | 
				
			||||||
 | 
					                 NFAIL, NFAIL_AU, NFAIL_F_QR, NFAIL_REZ,     &
 | 
				
			||||||
 | 
					                 NFAIL_REZQ, NFAIL_SVDIFF, NFAIL_TOTAL, NFAILQ_TOTAL, &
 | 
				
			||||||
 | 
					                 NFAIL_Z_XV, MODE, MODEL, MODER, WHTSVD
 | 
				
			||||||
 | 
					      INTEGER    iNRNK, iWHTSVD, K_TRAJ, LWMINOPT
 | 
				
			||||||
 | 
					      CHARACTER(LEN=1) GRADE, JOBREF, JOBZ, PIVTNG, RSIGN,   &
 | 
				
			||||||
 | 
					                       SCALE, RESIDS, WANTQ, WANTR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LOGICAL          TEST_QRDMD
 | 
				
			||||||
 | 
					!..... external subroutines (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL SAXPY,  SGEEV, SGEMM, SGEMV, SLACPY, SLASCL
 | 
				
			||||||
 | 
					      EXTERNAL SLARNV, SLATMR
 | 
				
			||||||
 | 
					!.....external subroutines DMD package, part 1
 | 
				
			||||||
 | 
					!     subroutines under test
 | 
				
			||||||
 | 
					      EXTERNAL SGEDMD, SGEDMDQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!..... external functions (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL         SLAMCH, SLANGE, SNRM2
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: SLAMCH, SLANGE, SNRM2
 | 
				
			||||||
 | 
					      EXTERNAL         LSAME
 | 
				
			||||||
 | 
					      LOGICAL          LSAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      INTRINSIC ABS, INT, MIN, MAX
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! The test is always in pairs : ( SGEDMD and SGEDMDQ )
 | 
				
			||||||
 | 
					      ! because the test includes comparing the results (in pairs).
 | 
				
			||||||
 | 
					!.....................................................................................
 | 
				
			||||||
 | 
					      TEST_QRDMD = .TRUE. ! This code by default performs tests on SGEDMDQ
 | 
				
			||||||
 | 
					                          ! Since the QR factorizations based algorithm is designed for
 | 
				
			||||||
 | 
					                          ! single trajectory data, only single trajectory tests will
 | 
				
			||||||
 | 
					                          ! be performed with xGEDMDQ.
 | 
				
			||||||
 | 
					      WANTQ = 'Q'
 | 
				
			||||||
 | 
					      WANTR = 'R'
 | 
				
			||||||
 | 
					!.................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      EPS = SLAMCH( 'P' )  ! machine precision SP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Global counters of failures of some particular tests
 | 
				
			||||||
 | 
					      NFAIL      = 0
 | 
				
			||||||
 | 
					      NFAIL_REZ  = 0
 | 
				
			||||||
 | 
					      NFAIL_REZQ = 0
 | 
				
			||||||
 | 
					      NFAIL_Z_XV = 0
 | 
				
			||||||
 | 
					      NFAIL_F_QR = 0
 | 
				
			||||||
 | 
					      NFAIL_AU   = 0
 | 
				
			||||||
 | 
					      KDIFF      = 0
 | 
				
			||||||
 | 
					      NFAIL_SVDIFF = 0
 | 
				
			||||||
 | 
					      NFAIL_TOTAL  = 0
 | 
				
			||||||
 | 
					      NFAILQ_TOTAL = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LLOOP = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) 'L Loop Index = ', LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Set the dimensions of the problem ...
 | 
				
			||||||
 | 
					      WRITE(*,*) 'M = '
 | 
				
			||||||
 | 
					      READ(*,*) M
 | 
				
			||||||
 | 
					      WRITE(*,*) M
 | 
				
			||||||
 | 
					      ! ... and the number of snapshots.
 | 
				
			||||||
 | 
					      WRITE(*,*) 'N = '
 | 
				
			||||||
 | 
					      READ(*,*) N
 | 
				
			||||||
 | 
					      WRITE(*,*) N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! ... Test the dimensions
 | 
				
			||||||
 | 
					      IF ( ( MIN(M,N) == 0 ) .OR. ( M < N )  ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Bad dimensions. Required: M >= N > 0.'
 | 
				
			||||||
 | 
					          STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					      ! The seed inside the LLOOP so that each pass can be reproduced easily.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ISEED(1) = 4
 | 
				
			||||||
 | 
					      ISEED(2) = 3
 | 
				
			||||||
 | 
					      ISEED(3) = 2
 | 
				
			||||||
 | 
					      ISEED(4) = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LDA = M
 | 
				
			||||||
 | 
					      LDF = M
 | 
				
			||||||
 | 
					      LDX = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDY = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDW = N
 | 
				
			||||||
 | 
					      LDZ = M
 | 
				
			||||||
 | 
					      LDAU = MAX(M,N+1)
 | 
				
			||||||
 | 
					      LDS = N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP_ZXW  = ZERO
 | 
				
			||||||
 | 
					      TMP_AU   = ZERO
 | 
				
			||||||
 | 
					      TMP_REZ  = ZERO
 | 
				
			||||||
 | 
					      TMP_REZQ = ZERO
 | 
				
			||||||
 | 
					      SVDIFF   = ZERO
 | 
				
			||||||
 | 
					      TMP_EX   = ZERO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !
 | 
				
			||||||
 | 
					      ! Test the subroutines on real data snapshots. All
 | 
				
			||||||
 | 
					      ! computation is done in real arithmetic, even when
 | 
				
			||||||
 | 
					      ! Koopman eigenvalues and modes are real.
 | 
				
			||||||
 | 
					      !
 | 
				
			||||||
 | 
					      ! Allocate memory space
 | 
				
			||||||
 | 
					      ALLOCATE( A(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( AC(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( DA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( DL(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( F(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F1(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( F2(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( X(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( X0(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVQX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y0(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Y1(M,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( Z1(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES(N)  )
 | 
				
			||||||
 | 
					      ALLOCATE( RES1(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RESEX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIG(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIG(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIGQ(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIGQ(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( REIGA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( IEIGA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( VA(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( LAMBDA(N,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( LAMBDAQ(N,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( EIGA(M,2) )
 | 
				
			||||||
 | 
					      ALLOCATE( W(LDW,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( AU(LDAU,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( S(N,N) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TOL  = M*EPS
 | 
				
			||||||
 | 
					      ! This mimics O(M*N)*EPS bound for accumulated roundoff error.
 | 
				
			||||||
 | 
					      ! The factor 10 is somewhat arbitrary.
 | 
				
			||||||
 | 
					      TOL2 = 10*M*N*EPS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO K_TRAJ = 1, 2
 | 
				
			||||||
 | 
					      !  Number of intial conditions in the simulation/trajectories (1 or 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COND = 1.0D8
 | 
				
			||||||
 | 
					      DMAX = 1.0D2
 | 
				
			||||||
 | 
					      RSIGN = 'F'
 | 
				
			||||||
 | 
					      GRADE = 'N'
 | 
				
			||||||
 | 
					      MODEL = 6
 | 
				
			||||||
 | 
					      CONDL = 1.0D2
 | 
				
			||||||
 | 
					      MODER = 6
 | 
				
			||||||
 | 
					      CONDR = 1.0D2
 | 
				
			||||||
 | 
					      PIVTNG = 'N'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Loop over all parameter MODE values for ZLATMR (+1,..,+6)
 | 
				
			||||||
 | 
					      DO MODE = 1, 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( IWORK(2*M) )
 | 
				
			||||||
 | 
					      ALLOCATE(DR(N))
 | 
				
			||||||
 | 
					      CALL SLATMR( M, M, 'S', ISEED, 'N', DA, MODE, COND, &
 | 
				
			||||||
 | 
					                   DMAX, RSIGN, GRADE, DL, MODEL,  CONDL, &
 | 
				
			||||||
 | 
					                   DR, MODER, CONDR, PIVTNG, IWORK, M, M, &
 | 
				
			||||||
 | 
					                   ZERO, -ONE, 'N', A, LDA, IWORK(M+1), INFO )
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(DR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LWORK = 4*M+1
 | 
				
			||||||
 | 
					      ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					      AC  = A
 | 
				
			||||||
 | 
					      CALL SGEEV( 'N','V', M, AC, M, REIGA, IEIGA, VA, M, &
 | 
				
			||||||
 | 
					                  VA, M, WORK, LWORK, INFO ) ! LAPACK CALL
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      TMP = ZERO
 | 
				
			||||||
 | 
					      DO i = 1, M
 | 
				
			||||||
 | 
					          EIGA(i,1) = REIGA(i)
 | 
				
			||||||
 | 
					          EIGA(i,2) = IEIGA(i)
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, SQRT(REIGA(i)**2+IEIGA(i)**2))
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Scale A to have the desirable spectral radius.
 | 
				
			||||||
 | 
					      CALL SLASCL( 'G', 0, 0, TMP, ONE, M, M, A, M, INFO )
 | 
				
			||||||
 | 
					      CALL SLASCL( 'G', 0, 0, TMP, ONE, M, 2, EIGA, M, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Compute the norm of A
 | 
				
			||||||
 | 
					      ANORM = SLANGE( 'F', N, N, A, M, WDUMMY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( K_TRAJ == 2 ) THEN
 | 
				
			||||||
 | 
					          ! generate data with two inital conditions
 | 
				
			||||||
 | 
					      CALL SLARNV(2, ISEED, M, F1(1,1) )
 | 
				
			||||||
 | 
					      F1(1:M,1) = 1.0E-10*F1(1:M,1)
 | 
				
			||||||
 | 
					      DO i = 1, N/2
 | 
				
			||||||
 | 
					         CALL SGEMV( 'N', M, M, ONE, A, M, F1(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F1(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,1:N/2) = F1(1:M,1:N/2)
 | 
				
			||||||
 | 
					      Y0(1:M,1:N/2) = F1(1:M,2:N/2+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL SLARNV(2, ISEED, M, F1(1,1) )
 | 
				
			||||||
 | 
					      DO i = 1, N-N/2
 | 
				
			||||||
 | 
					         CALL SGEMV( 'N', M, M, ONE, A, M, F1(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F1(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,N/2+1:N) = F1(1:M,1:N-N/2)
 | 
				
			||||||
 | 
					      Y0(1:M,N/2+1:N) = F1(1:M,2:N-N/2+1)
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          ! single trajectory
 | 
				
			||||||
 | 
					      CALL SLARNV(2, ISEED, M, F(1,1) )
 | 
				
			||||||
 | 
					      DO i = 1, N
 | 
				
			||||||
 | 
					         CALL SGEMV( 'N', M, M, ONE, A, M, F(1,i), 1, ZERO, &
 | 
				
			||||||
 | 
					              F(1,i+1), 1 )
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      X0(1:M,1:N) = F(1:M,1:N)
 | 
				
			||||||
 | 
					      Y0(1:M,1:N) = F(1:M,2:N+1)
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      XNORM = SLANGE( 'F', M, N, X0, LDX, WDUMMY )
 | 
				
			||||||
 | 
					      YNORM = SLANGE( 'F', M, N, Y0, LDX, WDUMMY )
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBZ = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBZ )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBZ   = 'V' ! Ritz vectors will be computed
 | 
				
			||||||
 | 
					              RESIDS = 'R' ! Residuals will be computed
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBZ   = 'F' ! Ritz vectors in factored form
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              JOBZ   = 'N'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBREF = 1, 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBREF )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBREF = 'R' ! Data for refined Ritz vectors
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBREF = 'E' ! Exact DMD vectors
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBREF = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iSCALE = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iSCALE )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              SCALE = 'S' ! X data normalized
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              SCALE = 'C' ! X normalized, consist. check
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              SCALE = 'Y' ! Y data normalized
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              SCALE = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iNRNK = -1, -2, -1
 | 
				
			||||||
 | 
					          ! Two truncation strategies. The "-2" case for R&D
 | 
				
			||||||
 | 
					          ! purposes only - it uses possibly low accuracy small
 | 
				
			||||||
 | 
					          ! singular values, in which case the formulas used in
 | 
				
			||||||
 | 
					          ! the DMD are highly sensitive.
 | 
				
			||||||
 | 
					          NRNK   = iNRNK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iWHTSVD = 1, 4
 | 
				
			||||||
 | 
					          ! Check all four options to compute the POD basis
 | 
				
			||||||
 | 
					          ! via the SVD.
 | 
				
			||||||
 | 
					          WHTSVD   = iWHTSVD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LWMINOPT = 1, 2
 | 
				
			||||||
 | 
					          ! Workspace query for the minimal (1) and for the optimal
 | 
				
			||||||
 | 
					          ! (2) workspace lengths determined by workspace query.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       X(1:M,1:N) = X0(1:M,1:N)
 | 
				
			||||||
 | 
					       Y(1:M,1:N) = Y0(1:M,1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       ! SGEDMD: Workspace query and workspace allocation
 | 
				
			||||||
 | 
					       CALL SGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, M, &
 | 
				
			||||||
 | 
					            N, X, LDX, Y, LDY, NRNK, TOL, K, REIG, IEIG, Z, &
 | 
				
			||||||
 | 
					            LDZ, RES, AU, LDAU, W, LDW, S, LDS, WDUMMY, -1, &
 | 
				
			||||||
 | 
					            IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					       ALLOCATE( IWORK(LIWORK) )
 | 
				
			||||||
 | 
					       LWORK = INT(WDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					       ALLOCATE( WORK(LWORK) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       ! SGEDMD test: CALL SGEDMD
 | 
				
			||||||
 | 
					       CALL SGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, M, &
 | 
				
			||||||
 | 
					            N, X, LDX, Y, LDY, NRNK, TOL, K, REIG, IEIG, Z, &
 | 
				
			||||||
 | 
					            LDZ, RES, AU, LDAU, W, LDW, S, LDS, WORK, LWORK,&
 | 
				
			||||||
 | 
					            IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       SINGVX(1:N) = WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       !...... SGEDMD check point
 | 
				
			||||||
 | 
					       IF ( LSAME(JOBZ,'V')  ) THEN
 | 
				
			||||||
 | 
					          ! Check that Z = X*W, on return from SGEDMD
 | 
				
			||||||
 | 
					          ! This checks that the returned aigenvectors in Z are
 | 
				
			||||||
 | 
					          ! the product of the SVD'POD basis returned in X
 | 
				
			||||||
 | 
					          ! and the eigenvectors of the rayleigh quotient
 | 
				
			||||||
 | 
					          ! returned in W
 | 
				
			||||||
 | 
					          CALL SGEMM( 'N', 'N', M, K, K, ONE, X, LDX, W, LDW, &
 | 
				
			||||||
 | 
					                      ZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					             CALL SAXPY( M, -ONE, Z(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, SNRM2( M, Z1(1,i), 1 ) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_ZXW = MAX(TMP_ZXW, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( TMP_ZXW > 10*M*EPS ) THEN
 | 
				
			||||||
 | 
					              NFAIL_Z_XV = NFAIL_Z_XV + 1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       !...... SGEDMD check point
 | 
				
			||||||
 | 
					       IF ( LSAME(JOBREF,'R') ) THEN
 | 
				
			||||||
 | 
					           ! The matrix A*U is returned for computing refined Ritz vectors.
 | 
				
			||||||
 | 
					           ! Check that A*U is computed correctly using the formula
 | 
				
			||||||
 | 
					           ! A*U = Y * V * inv(SIGMA). This depends on the
 | 
				
			||||||
 | 
					           ! accuracy in the computed singular values and vectors of X.
 | 
				
			||||||
 | 
					           ! See the paper for an error analysis.
 | 
				
			||||||
 | 
					           ! Note that the left singular vectors of the input matrix X
 | 
				
			||||||
 | 
					           ! are returned in the array X.
 | 
				
			||||||
 | 
					           CALL SGEMM( 'N', 'N', M, K, M, ONE, A, LDA, X, LDX, &
 | 
				
			||||||
 | 
					                      ZERO, Z1, LDZ )
 | 
				
			||||||
 | 
					           TMP = ZERO
 | 
				
			||||||
 | 
					           DO i = 1, K
 | 
				
			||||||
 | 
					              CALL SAXPY( M, -ONE, AU(1,i), 1, Z1(1,i), 1)
 | 
				
			||||||
 | 
					              TMP = MAX( TMP, SNRM2( M, Z1(1,i),1 ) * &
 | 
				
			||||||
 | 
					                       SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					           END DO
 | 
				
			||||||
 | 
					           TMP_AU = MAX( TMP_AU, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					           IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					               NFAIL_AU = NFAIL_AU + 1
 | 
				
			||||||
 | 
					           END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       ELSEIF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					       ! The unscaled vectors of the Exact DMD are computed.
 | 
				
			||||||
 | 
					       ! This option is included for the sake of completeness,
 | 
				
			||||||
 | 
					       ! for users who prefer the Exact DMD vectors. The
 | 
				
			||||||
 | 
					       ! returned vectors are in the real form, in the same way
 | 
				
			||||||
 | 
					       ! as the Ritz vectors. Here we just save the vectors
 | 
				
			||||||
 | 
					       ! and test them separately using a Matlab script.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       CALL SGEMM( 'N', 'N', M, K, M, ONE, A, LDA, AU, LDAU, ZERO, Y1, M )
 | 
				
			||||||
 | 
					       i=1
 | 
				
			||||||
 | 
					       DO WHILE ( i <= K )
 | 
				
			||||||
 | 
					       IF ( IEIG(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					        ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					        CALL SAXPY( M, -REIG(i), AU(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					        RESEX(i) = SNRM2( M, Y1(1,i), 1) / SNRM2(M,AU(1,i),1)
 | 
				
			||||||
 | 
					        i = i + 1
 | 
				
			||||||
 | 
					       ELSE
 | 
				
			||||||
 | 
					       ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					       ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					       ! Since all computation is done in real
 | 
				
			||||||
 | 
					       ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					       ! is recast for real representation of the
 | 
				
			||||||
 | 
					       ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					       ! description of RES.
 | 
				
			||||||
 | 
					       AB(1,1) =  REIG(i)
 | 
				
			||||||
 | 
					       AB(2,1) = -IEIG(i)
 | 
				
			||||||
 | 
					       AB(1,2) =  IEIG(i)
 | 
				
			||||||
 | 
					       AB(2,2) =  REIG(i)
 | 
				
			||||||
 | 
					       CALL SGEMM( 'N', 'N', M, 2, 2, -ONE, AU(1,i), &
 | 
				
			||||||
 | 
					                   M, AB, 2, ONE, Y1(1,i), M )
 | 
				
			||||||
 | 
					       RESEX(i)   = SLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                    WORK )/ SLANGE( 'F', M, 2, AU(1,i), M, &
 | 
				
			||||||
 | 
					                    WORK )
 | 
				
			||||||
 | 
					       RESEX(i+1) = RESEX(i)
 | 
				
			||||||
 | 
					       i = i + 2
 | 
				
			||||||
 | 
					       END IF
 | 
				
			||||||
 | 
					       END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... SGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					          ! Compare the residuals returned by SGEDMD with the
 | 
				
			||||||
 | 
					          ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					          ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					          CALL SGEMM( 'N', 'N', M, K, M, ONE, A, LDA, Z, LDZ, ZERO, Y1, M )
 | 
				
			||||||
 | 
					          ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					          ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					          ! pairs of eigencalues. (See the description of Z in SGEDMD,)
 | 
				
			||||||
 | 
					          i = 1
 | 
				
			||||||
 | 
					          DO WHILE ( i <= K )
 | 
				
			||||||
 | 
					            IF ( IEIG(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					                ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                CALL SAXPY( M, -REIG(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                RES1(i) = SNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					                i = i + 1
 | 
				
			||||||
 | 
					            ELSE
 | 
				
			||||||
 | 
					               ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					               ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					               ! Since all computation is done in real
 | 
				
			||||||
 | 
					               ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					               ! is recast for real representation of the
 | 
				
			||||||
 | 
					               ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					               ! description of RES.
 | 
				
			||||||
 | 
					               AB(1,1) =  REIG(i)
 | 
				
			||||||
 | 
					               AB(2,1) = -IEIG(i)
 | 
				
			||||||
 | 
					               AB(1,2) =  IEIG(i)
 | 
				
			||||||
 | 
					               AB(2,2) =  REIG(i)
 | 
				
			||||||
 | 
					               CALL SGEMM( 'N', 'N', M, 2, 2, -ONE, Z(1,i), &
 | 
				
			||||||
 | 
					                           M, AB, 2, ONE, Y1(1,i), M )
 | 
				
			||||||
 | 
					               RES1(i)   = SLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                                  WORK )
 | 
				
			||||||
 | 
					               RES1(i+1) = RES1(i)
 | 
				
			||||||
 | 
					               i = i + 2
 | 
				
			||||||
 | 
					            END IF
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                    SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_REZ = MAX( TMP_REZ, TMP )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					              NFAIL_REZ = NFAIL_REZ + 1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         IF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					            TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES1(i) - RESEX(i))/(RES1(i)+RESEX(i)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_EX = MAX(TMP_EX,TMP)
 | 
				
			||||||
 | 
					         END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! ... store the results for inspection
 | 
				
			||||||
 | 
					      DO i = 1, K
 | 
				
			||||||
 | 
					          LAMBDA(i,1) = REIG(i)
 | 
				
			||||||
 | 
					          LAMBDA(i,2) = IEIG(i)
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !======================================================================
 | 
				
			||||||
 | 
					      !     Now test the SGEDMDQ, if requested.
 | 
				
			||||||
 | 
					      !======================================================================
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD .AND. (K_TRAJ == 1) ) THEN
 | 
				
			||||||
 | 
					          RJOBDATA(2) = 1
 | 
				
			||||||
 | 
					          F1 = F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          ! SGEDMDQ test: Workspace query and workspace allocation
 | 
				
			||||||
 | 
					          CALL SGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, &
 | 
				
			||||||
 | 
					               JOBREF, WHTSVD, M, N+1, F1, LDF, X, LDX, Y, &
 | 
				
			||||||
 | 
					               LDY, NRNK, TOL, KQ, REIGQ, IEIGQ, Z, LDZ,   &
 | 
				
			||||||
 | 
					               RES, AU, LDAU, W, LDW, S, LDS, WDUMMY,      &
 | 
				
			||||||
 | 
					               -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					          LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					          ALLOCATE( IWORK(LIWORK) )
 | 
				
			||||||
 | 
					          LWORK = INT(WDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					          ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          ! SGEDMDQ test: CALL SGEDMDQ
 | 
				
			||||||
 | 
					          CALL SGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, &
 | 
				
			||||||
 | 
					               JOBREF, WHTSVD, M, N+1, F1, LDF, X, LDX, Y, &
 | 
				
			||||||
 | 
					               LDY, NRNK, TOL, KQ, REIGQ, IEIGQ, Z, LDZ,   &
 | 
				
			||||||
 | 
					               RES, AU, LDAU, W, LDW, S, LDS,              &
 | 
				
			||||||
 | 
					               WORK, LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SINGVQX(1:KQ) = WORK(MIN(M,N+1)+1: MIN(M,N+1)+KQ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... SGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( KQ /= K ) THEN
 | 
				
			||||||
 | 
					             KDIFF = KDIFF+1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, MIN(K, KQ)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, ABS(SINGVX(i)-SINGVQX(i)) / &
 | 
				
			||||||
 | 
					                                   SINGVX(1) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          SVDIFF = MAX( SVDIFF, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP > M*N*EPS ) THEN
 | 
				
			||||||
 | 
					             NFAIL_SVDIFF = NFAIL_SVDIFF + 1
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... SGEDMDQ check point
 | 
				
			||||||
 | 
					          IF ( LSAME(WANTQ,'Q') .AND. LSAME(WANTR,'R') ) THEN
 | 
				
			||||||
 | 
					             ! Check that the QR factors are computed and returned
 | 
				
			||||||
 | 
					             ! as requested. The residual ||F-Q*R||_F / ||F||_F
 | 
				
			||||||
 | 
					             ! is compared to M*N*EPS.
 | 
				
			||||||
 | 
					             F2 = F
 | 
				
			||||||
 | 
					             CALL SGEMM( 'N', 'N', M, N+1, MIN(M,N+1), -ONE, F1, &
 | 
				
			||||||
 | 
					                         LDF, Y, LDY, ONE, F2, LDF )
 | 
				
			||||||
 | 
					             TMP_FQR = SLANGE( 'F', M, N+1, F2, LDF, WORK ) / &
 | 
				
			||||||
 | 
					                   SLANGE( 'F', M, N+1, F,  LDF, WORK )
 | 
				
			||||||
 | 
					             IF ( TMP_FQR > TOL2 ) THEN
 | 
				
			||||||
 | 
					                 NFAIL_F_QR = NFAIL_F_QR + 1
 | 
				
			||||||
 | 
					             END IF
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          !..... SGEDMDQ checkpoint
 | 
				
			||||||
 | 
					          IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					              ! Compare the residuals returned by SGEDMDQ with the
 | 
				
			||||||
 | 
					              ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					              ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					              CALL SGEMM( 'N', 'N', M, KQ, M, ONE, A, M, Z, M, ZERO, Y1, M )
 | 
				
			||||||
 | 
					              ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					              ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					              ! pairs of eigencalues. (See the description of Z in SGEDMDQ)
 | 
				
			||||||
 | 
					              i = 1
 | 
				
			||||||
 | 
					              DO WHILE ( i <= KQ )
 | 
				
			||||||
 | 
					                IF ( IEIGQ(i) == ZERO ) THEN
 | 
				
			||||||
 | 
					                    ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                    CALL SAXPY( M, -REIGQ(i), Z(1,i), 1, Y1(1,i), 1 )
 | 
				
			||||||
 | 
					                    ! Y(1:M,i) = Y(1:M,i) - REIG(i)*Z(1:M,i)
 | 
				
			||||||
 | 
					                    RES1(i) = SNRM2( M, Y1(1,i), 1)
 | 
				
			||||||
 | 
					                    i = i + 1
 | 
				
			||||||
 | 
					                ELSE
 | 
				
			||||||
 | 
					                   ! Have a complex conjugate pair
 | 
				
			||||||
 | 
					                   ! REIG(i) +- sqrt(-1)*IMEIG(i).
 | 
				
			||||||
 | 
					                   ! Since all computation is done in real
 | 
				
			||||||
 | 
					                   ! arithmetic, the formula for the residual
 | 
				
			||||||
 | 
					                   ! is recast for real representation of the
 | 
				
			||||||
 | 
					                   ! complex conjugate eigenpair. See the
 | 
				
			||||||
 | 
					                   ! description of RES.
 | 
				
			||||||
 | 
					                   AB(1,1) =  REIGQ(i)
 | 
				
			||||||
 | 
					                   AB(2,1) = -IEIGQ(i)
 | 
				
			||||||
 | 
					                   AB(1,2) =  IEIGQ(i)
 | 
				
			||||||
 | 
					                   AB(2,2) =  REIGQ(i)
 | 
				
			||||||
 | 
					                   CALL SGEMM( 'N', 'N', M, 2, 2, -ONE, Z(1,i), &
 | 
				
			||||||
 | 
					                               M, AB, 2, ONE, Y1(1,i), M )             ! BLAS CALL
 | 
				
			||||||
 | 
					                   ! Y(1:M,i:i+1) = Y(1:M,i:i+1) - Z(1:M,i:i+1) * AB   ! INTRINSIC
 | 
				
			||||||
 | 
					                   RES1(i)   = SLANGE( 'F', M, 2, Y1(1,i), M, &
 | 
				
			||||||
 | 
					                                      WORK )                           ! LAPACK CALL
 | 
				
			||||||
 | 
					                   RES1(i+1) = RES1(i)
 | 
				
			||||||
 | 
					                   i = i + 2
 | 
				
			||||||
 | 
					                END IF
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP = ZERO
 | 
				
			||||||
 | 
					              DO i = 1, KQ
 | 
				
			||||||
 | 
					              TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                  SINGVQX(K)/(ANORM*SINGVQX(1)) )
 | 
				
			||||||
 | 
					              END DO
 | 
				
			||||||
 | 
					              TMP_REZQ = MAX( TMP_REZQ, TMP )
 | 
				
			||||||
 | 
					              IF ( TMP > TOL2 ) THEN
 | 
				
			||||||
 | 
					                  NFAIL_REZQ = NFAIL_REZQ + 1
 | 
				
			||||||
 | 
					              END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i = 1, KQ
 | 
				
			||||||
 | 
					              LAMBDAQ(i,1) = REIGQ(i)
 | 
				
			||||||
 | 
					              LAMBDAQ(i,2) = IEIGQ(i)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					      END IF            ! TEST_QRDMD
 | 
				
			||||||
 | 
					!======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! LWMINOPT
 | 
				
			||||||
 | 
					      !write(*,*) 'LWMINOPT loop completed'
 | 
				
			||||||
 | 
					      END DO ! WHTSVD LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'WHTSVD loop completed'
 | 
				
			||||||
 | 
					      END DO ! NRNK LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'NRNK loop completed'
 | 
				
			||||||
 | 
					      END DO ! SCALE LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'SCALE loop completed'
 | 
				
			||||||
 | 
					      END DO ! JOBF LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBREF loop completed'
 | 
				
			||||||
 | 
					      END DO ! JOBZ LOOP
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBZ loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! MODE -6:6
 | 
				
			||||||
 | 
					      !write(*,*) 'MODE loop completed'
 | 
				
			||||||
 | 
					      END DO ! 1 or 2 trajectories
 | 
				
			||||||
 | 
					      !write(*,*) 'trajectories  loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(A)
 | 
				
			||||||
 | 
					      DEALLOCATE(AC)
 | 
				
			||||||
 | 
					      DEALLOCATE(DA)
 | 
				
			||||||
 | 
					      DEALLOCATE(DL)
 | 
				
			||||||
 | 
					      DEALLOCATE(F)
 | 
				
			||||||
 | 
					      DEALLOCATE(F1)
 | 
				
			||||||
 | 
					      DEALLOCATE(F2)
 | 
				
			||||||
 | 
					      DEALLOCATE(X)
 | 
				
			||||||
 | 
					      DEALLOCATE(X0)
 | 
				
			||||||
 | 
					      DEALLOCATE(SINGVX)
 | 
				
			||||||
 | 
					      DEALLOCATE(SINGVQX)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y0)
 | 
				
			||||||
 | 
					      DEALLOCATE(Y1)
 | 
				
			||||||
 | 
					      DEALLOCATE(Z)
 | 
				
			||||||
 | 
					      DEALLOCATE(Z1)
 | 
				
			||||||
 | 
					      DEALLOCATE(RES)
 | 
				
			||||||
 | 
					      DEALLOCATE(RES1)
 | 
				
			||||||
 | 
					      DEALLOCATE(RESEX)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIG)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIG)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIGQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIGQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(REIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(IEIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(VA)
 | 
				
			||||||
 | 
					      DEALLOCATE(LAMBDA)
 | 
				
			||||||
 | 
					      DEALLOCATE(LAMBDAQ)
 | 
				
			||||||
 | 
					      DEALLOCATE(EIGA)
 | 
				
			||||||
 | 
					      DEALLOCATE(W)
 | 
				
			||||||
 | 
					      DEALLOCATE(AU)
 | 
				
			||||||
 | 
					      DEALLOCATE(S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      !     Generate random M-by-M matrix A. Use DLATMR from
 | 
				
			||||||
 | 
					      END DO ! LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for SGEDMD :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      IF ( NFAIL_Z_XV == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Z - U*V test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Z - U*V test FAILED ', NFAIL_Z_XV, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max error ||Z-U*V||_F was ', TMP_ZXW
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_Z_XV
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      IF ( NFAIL_AU == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> A*U test PASSED. '
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'A*U test FAILED ', NFAIL_AU, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max A*U test adjusted error measure was ', TMP_AU
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_AU
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZ == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZ, 'time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZ
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_REZ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> SGEDMD :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) NFAIL_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>>>>>>>>>>>> SGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD ) THEN
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for SGEDMDQ :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_SVDIFF == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> SGEDMD and SGEDMDQ computed singular &
 | 
				
			||||||
 | 
					              &values test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'SGEDMD and SGEDMDQ discrepancies in &
 | 
				
			||||||
 | 
					              &the singular values unacceptable ', &
 | 
				
			||||||
 | 
					              NFAIL_SVDIFF, ' times. Test FAILED.'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'The maximal discrepancy in the singular values (relative to the norm) was ', SVDIFF
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_SVDIFF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_F_QR == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> F - Q*R test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'F - Q*R test FAILED ', NFAIL_F_QR, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'The largest relative residual was ', TMP_FQR
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_F_QR
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZQ == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZQ, 'time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZQ
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_REZQ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAILQ_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>>>>> SGEDMDQ :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					         WRITE(*,*) NFAILQ_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					         WRITE(*,*) '>>>>>>> SGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) 'Test completed.'
 | 
				
			||||||
 | 
					      STOP
 | 
				
			||||||
 | 
					      END
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,745 @@
 | 
				
			||||||
 | 
					!     This is a test program for checking the implementations of
 | 
				
			||||||
 | 
					!     the implementations of the following subroutines
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     ZGEDMD,  for computation of the
 | 
				
			||||||
 | 
					!              Dynamic Mode Decomposition (DMD)
 | 
				
			||||||
 | 
					!     ZGEDMDQ, for computation of a
 | 
				
			||||||
 | 
					!              QR factorization based compressed DMD
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Developed and supported by:
 | 
				
			||||||
 | 
					!     ===========================
 | 
				
			||||||
 | 
					!     Developed and coded by Zlatko Drmac, Faculty of Science,
 | 
				
			||||||
 | 
					!     University of Zagreb;  drmac@math.hr
 | 
				
			||||||
 | 
					!     In cooperation with
 | 
				
			||||||
 | 
					!     AIMdyn Inc., Santa Barbara, CA.
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     How to run the code (compiler, link info)
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Compile as FORTRAN 90 (or later) and link with BLAS and
 | 
				
			||||||
 | 
					!     LAPACK libraries.
 | 
				
			||||||
 | 
					!     NOTE: The code is developed and tested on top of the
 | 
				
			||||||
 | 
					!     Intel MKL library (versions 2022.0.3 and 2022.2.0),
 | 
				
			||||||
 | 
					!     using the Intel Fortran compiler.
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     For developers of the C++ implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     See the LAPACK++ and Template Numerical Toolkit (TNT)
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					!     Note on a development of the GPU HP implementation
 | 
				
			||||||
 | 
					!     ========================================================
 | 
				
			||||||
 | 
					!     Work in progress. See CUDA, MAGMA, SLATE.
 | 
				
			||||||
 | 
					!     NOTE: The four SVD subroutines used in this code are
 | 
				
			||||||
 | 
					!     included as a part of R&D and for the completeness.
 | 
				
			||||||
 | 
					!     This was also an opportunity to test those SVD codes.
 | 
				
			||||||
 | 
					!     If the scaling option is used all four are essentially
 | 
				
			||||||
 | 
					!     equally good. For implementations on HP platforms,
 | 
				
			||||||
 | 
					!     one can use whichever SVD is available.
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					      PROGRAM DMD_TEST
 | 
				
			||||||
 | 
					      use iso_fortran_env, only: real64
 | 
				
			||||||
 | 
					      IMPLICIT NONE
 | 
				
			||||||
 | 
					      integer, parameter :: WP = real64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER ::  ONE = 1.0_WP
 | 
				
			||||||
 | 
					      REAL(KIND=WP), PARAMETER :: ZERO = 0.0_WP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), PARAMETER ::  ZONE = ( 1.0_WP, 0.0_WP )
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), PARAMETER :: ZZERO = ( 0.0_WP, 0.0_WP )
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      REAL(KIND=WP), ALLOCATABLE, DIMENSION(:)   :: RES, &
 | 
				
			||||||
 | 
					                     RES1, RESEX, SINGVX, SINGVQX, WORK
 | 
				
			||||||
 | 
					      INTEGER      , ALLOCATABLE, DIMENSION(:)   :: IWORK
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: WDUMMY(2)
 | 
				
			||||||
 | 
					      INTEGER       :: IDUMMY(4), ISEED(4)
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: ANORM, COND, CONDL, CONDR, EPS,       &
 | 
				
			||||||
 | 
					                       TOL, TOL2, SVDIFF, TMP, TMP_AU,       &
 | 
				
			||||||
 | 
					                       TMP_FQR, TMP_REZ, TMP_REZQ,  TMP_ZXW, &
 | 
				
			||||||
 | 
					                       TMP_EX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP) :: ZMAX
 | 
				
			||||||
 | 
					      INTEGER :: LZWORK
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), ALLOCATABLE, DIMENSION(:,:) ::  ZA, ZAC,  &
 | 
				
			||||||
 | 
					                                 ZAU, ZF, ZF0, ZF1, ZS, ZW,       &
 | 
				
			||||||
 | 
					                                 ZX, ZX0, ZY, ZY0, ZY1, ZZ, ZZ1
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP), ALLOCATABLE, DIMENSION(:)   ::  ZDA, ZDR, &
 | 
				
			||||||
 | 
					                                       ZDL, ZEIGS, ZEIGSA, ZWORK
 | 
				
			||||||
 | 
					      COMPLEX(KIND=WP) ::  ZDUMMY(22), ZDUM2X2(2,2)
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					      INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY,  &
 | 
				
			||||||
 | 
					                 LDZ, LIWORK, LWORK, M, N, LLOOP, NRNK, NRNKsp
 | 
				
			||||||
 | 
					      INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, j,     &
 | 
				
			||||||
 | 
					                 NFAIL, NFAIL_AU, NFAIL_F_QR, NFAIL_REZ,     &
 | 
				
			||||||
 | 
					                 NFAIL_REZQ, NFAIL_SVDIFF, NFAIL_TOTAL, NFAILQ_TOTAL,  &
 | 
				
			||||||
 | 
					                 NFAIL_Z_XV,  MODE, MODEL, MODER, WHTSVD,     &
 | 
				
			||||||
 | 
					                 WHTSVDsp
 | 
				
			||||||
 | 
					      INTEGER :: iNRNK, iWHTSVD,  K_TRAJ, LWMINOPT
 | 
				
			||||||
 | 
					      CHARACTER :: GRADE, JOBREF, JOBZ, PIVTNG, RSIGN,   &
 | 
				
			||||||
 | 
					                       SCALE, RESIDS, WANTQ, WANTR
 | 
				
			||||||
 | 
					      LOGICAL :: TEST_QRDMD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.....external subroutines (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL DAXPY,  DGEEV, DGEMM, DGEMV, DLACPY, DLASCL
 | 
				
			||||||
 | 
					      EXTERNAL ZGEEV,  ZGEMV, ZLASCL
 | 
				
			||||||
 | 
					      EXTERNAL ZLARNV, ZLATMR
 | 
				
			||||||
 | 
					      EXTERNAL ZAXPY,  ZGEMM
 | 
				
			||||||
 | 
					!.....external subroutines DMD package, part 1
 | 
				
			||||||
 | 
					!     subroutines under test
 | 
				
			||||||
 | 
					      EXTERNAL ZGEDMD, ZGEDMDQ
 | 
				
			||||||
 | 
					!.....external functions (BLAS and LAPACK)
 | 
				
			||||||
 | 
					      EXTERNAL         DLAMCH,  DZNRM2
 | 
				
			||||||
 | 
					      REAL(KIND=WP) :: DLAMCH,  DZNRM2
 | 
				
			||||||
 | 
					      REAL(KIND=WP) ::          ZLANGE
 | 
				
			||||||
 | 
					      EXTERNAL IZAMAX
 | 
				
			||||||
 | 
					      INTEGER  IZAMAX
 | 
				
			||||||
 | 
					      EXTERNAL LSAME
 | 
				
			||||||
 | 
					      LOGICAL  LSAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      INTRINSIC ABS, INT, MIN, MAX, SIGN
 | 
				
			||||||
 | 
					!............................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! The test is always in pairs : ( ZGEDMD and ZGEDMDQ )
 | 
				
			||||||
 | 
					      ! because the test includes comparing the results (in pairs).
 | 
				
			||||||
 | 
					!.....................................................................................
 | 
				
			||||||
 | 
					      TEST_QRDMD = .TRUE. ! This code by default performs tests on ZGEDMDQ
 | 
				
			||||||
 | 
					                          ! Since the QR factorizations based algorithm is designed for
 | 
				
			||||||
 | 
					                          ! single trajectory data, only single trajectory tests will
 | 
				
			||||||
 | 
					                          ! be performed with xGEDMDQ.
 | 
				
			||||||
 | 
					      WANTQ = 'Q'
 | 
				
			||||||
 | 
					      WANTR = 'R'
 | 
				
			||||||
 | 
					!.................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      EPS = DLAMCH( 'P' )  ! machine precision DP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Global counters of failures of some particular tests
 | 
				
			||||||
 | 
					      NFAIL      = 0
 | 
				
			||||||
 | 
					      NFAIL_REZ  = 0
 | 
				
			||||||
 | 
					      NFAIL_REZQ = 0
 | 
				
			||||||
 | 
					      NFAIL_Z_XV = 0
 | 
				
			||||||
 | 
					      NFAIL_F_QR = 0
 | 
				
			||||||
 | 
					      NFAIL_AU   = 0
 | 
				
			||||||
 | 
					      NFAIL_SVDIFF = 0
 | 
				
			||||||
 | 
					      NFAIL_TOTAL  = 0
 | 
				
			||||||
 | 
					      NFAILQ_TOTAL = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LLOOP = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) 'L Loop Index = ', LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Set the dimensions of the problem ...
 | 
				
			||||||
 | 
					      WRITE(*,*) 'M = '
 | 
				
			||||||
 | 
					      READ(*,*) M
 | 
				
			||||||
 | 
					      WRITE(*,*) M
 | 
				
			||||||
 | 
					      ! ... and the number of snapshots.
 | 
				
			||||||
 | 
					      WRITE(*,*) 'N = '
 | 
				
			||||||
 | 
					      READ(*,*) N
 | 
				
			||||||
 | 
					      WRITE(*,*) N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! ... Test the dimensions
 | 
				
			||||||
 | 
					      IF ( ( MIN(M,N) == 0 ) .OR. ( M < N )  ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Bad dimensions. Required: M >= N > 0.'
 | 
				
			||||||
 | 
					          STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					      ! The seed inside the LLOOP so that each pass can be reproduced easily.
 | 
				
			||||||
 | 
					      ISEED(1) = 4
 | 
				
			||||||
 | 
					      ISEED(2) = 3
 | 
				
			||||||
 | 
					      ISEED(3) = 2
 | 
				
			||||||
 | 
					      ISEED(4) = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LDA  = M
 | 
				
			||||||
 | 
					      LDF  = M
 | 
				
			||||||
 | 
					      LDX  = M
 | 
				
			||||||
 | 
					      LDY  = M
 | 
				
			||||||
 | 
					      LDW  = N
 | 
				
			||||||
 | 
					      LDZ  = M
 | 
				
			||||||
 | 
					      LDAU = M
 | 
				
			||||||
 | 
					      LDS  = N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP_ZXW  = ZERO
 | 
				
			||||||
 | 
					      TMP_AU   = ZERO
 | 
				
			||||||
 | 
					      TMP_REZ  = ZERO
 | 
				
			||||||
 | 
					      TMP_REZQ = ZERO
 | 
				
			||||||
 | 
					      SVDIFF   = ZERO
 | 
				
			||||||
 | 
					      TMP_EX   = ZERO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( ZA(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZAC(LDA,M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZF(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZF0(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZF1(LDF,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZX(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZX0(LDX,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZY(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZY0(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZY1(LDY,N+1) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZAU(LDAU,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZW(LDW,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZS(LDS,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZZ(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZZ1(LDZ,N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RES1(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( RESEX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZEIGS(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVX(N) )
 | 
				
			||||||
 | 
					      ALLOCATE( SINGVQX(N) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TOL  = M*EPS
 | 
				
			||||||
 | 
					      ! This mimics O(M*N)*EPS bound for accumulated roundoff error.
 | 
				
			||||||
 | 
					      ! The factor 10 is somewhat arbitrary.
 | 
				
			||||||
 | 
					      TOL2 = 10*M*N*EPS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO K_TRAJ = 1, 2
 | 
				
			||||||
 | 
					      !  Number of intial conditions in the simulation/trajectories (1 or 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      COND = 1.0D4
 | 
				
			||||||
 | 
					      ZMAX = (1.0D1,1.0D1)
 | 
				
			||||||
 | 
					      RSIGN = 'F'
 | 
				
			||||||
 | 
					      GRADE = 'N'
 | 
				
			||||||
 | 
					      MODEL = 6
 | 
				
			||||||
 | 
					      CONDL = 1.0D1
 | 
				
			||||||
 | 
					      MODER = 6
 | 
				
			||||||
 | 
					      CONDR = 1.0D1
 | 
				
			||||||
 | 
					      PIVTNG = 'N'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! Loop over all parameter MODE values for ZLATMR (+1,..,+6)
 | 
				
			||||||
 | 
					      DO MODE = 1, 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE( IWORK(2*M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZDA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZDL(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZDR(M) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL ZLATMR( M, M, 'N', ISEED, 'N', ZDA, MODE, COND, &
 | 
				
			||||||
 | 
					                   ZMAX, RSIGN, GRADE, ZDL, MODEL,  CONDL, &
 | 
				
			||||||
 | 
					                   ZDR, MODER, CONDR, PIVTNG, IWORK, M, M, &
 | 
				
			||||||
 | 
					                   ZERO, -ONE, 'N', ZA, LDA, IWORK(M+1), INFO )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZDR )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZDL )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZDA )
 | 
				
			||||||
 | 
					      DEALLOCATE( IWORK )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LZWORK = MAX(1,2*M)
 | 
				
			||||||
 | 
					      ALLOCATE( ZEIGSA(M) )
 | 
				
			||||||
 | 
					      ALLOCATE( ZWORK(LZWORK) )
 | 
				
			||||||
 | 
					      ALLOCATE( WORK(2*M) )
 | 
				
			||||||
 | 
					      ZAC(1:M,1:M) = ZA(1:M,1:M)
 | 
				
			||||||
 | 
					      CALL ZGEEV( 'N','N', M, ZAC, LDA, ZEIGSA, ZDUM2X2, 2, &
 | 
				
			||||||
 | 
					                  ZDUM2X2, 2, ZWORK, LZWORK, WORK, INFO ) ! LAPACK CALL
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(ZWORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      TMP = ABS(ZEIGSA(IZAMAX(M, ZEIGSA, 1))) ! The spectral radius of ZA
 | 
				
			||||||
 | 
					      ! Scale the matrix ZA to have unit spectral radius.
 | 
				
			||||||
 | 
					      CALL ZLASCL( 'G',0, 0, TMP, ONE, M, M, &
 | 
				
			||||||
 | 
					                   ZA, LDA, INFO )
 | 
				
			||||||
 | 
					      CALL ZLASCL( 'G',0, 0, TMP, ONE, M, 1, &
 | 
				
			||||||
 | 
					                   ZEIGSA, M, INFO )
 | 
				
			||||||
 | 
					      ANORM = ZLANGE( 'F', M, M, ZA, LDA, WDUMMY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( K_TRAJ == 2 ) THEN
 | 
				
			||||||
 | 
					          ! generate data as two trajectories
 | 
				
			||||||
 | 
					          ! with two inital conditions
 | 
				
			||||||
 | 
					          CALL ZLARNV(2, ISEED, M, ZF(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N/2
 | 
				
			||||||
 | 
					             CALL ZGEMV( 'N', M, M, ZONE, ZA, LDA, ZF(1,i), 1,  &
 | 
				
			||||||
 | 
					                  ZZERO, ZF(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          ZX0(1:M,1:N/2) = ZF(1:M,1:N/2)
 | 
				
			||||||
 | 
					          ZY0(1:M,1:N/2) = ZF(1:M,2:N/2+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          CALL ZLARNV(2, ISEED, M, ZF(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N-N/2
 | 
				
			||||||
 | 
					             CALL ZGEMV( 'N', M, M, ZONE, ZA, LDA, ZF(1,i), 1,  &
 | 
				
			||||||
 | 
					                  ZZERO, ZF(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          ZX0(1:M,N/2+1:N) = ZF(1:M,1:N-N/2)
 | 
				
			||||||
 | 
					          ZY0(1:M,N/2+1:N) = ZF(1:M,2:N-N/2+1)
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          CALL ZLARNV(2, ISEED, M, ZF(1,1) )
 | 
				
			||||||
 | 
					          DO i = 1, N
 | 
				
			||||||
 | 
					             CALL ZGEMV( 'N', M, M, ZONE, ZA, M, ZF(1,i), 1,  &
 | 
				
			||||||
 | 
					                  ZZERO, ZF(1,i+1), 1 )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          ZF0(1:M,1:N+1) = ZF(1:M,1:N+1)
 | 
				
			||||||
 | 
					          ZX0(1:M,1:N) = ZF0(1:M,1:N)
 | 
				
			||||||
 | 
					          ZY0(1:M,1:N) = ZF0(1:M,2:N+1)
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE( ZEIGSA )
 | 
				
			||||||
 | 
					!........................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBZ = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBZ )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'R'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBZ   = 'V'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBZ   = 'F'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              JOBZ   = 'N'
 | 
				
			||||||
 | 
					              RESIDS = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iJOBREF = 1, 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iJOBREF )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              JOBREF = 'R'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              JOBREF = 'E'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              JOBREF = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iSCALE = 1, 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          SELECT CASE ( iSCALE )
 | 
				
			||||||
 | 
					          CASE(1)
 | 
				
			||||||
 | 
					              SCALE = 'S'
 | 
				
			||||||
 | 
					          CASE(2)
 | 
				
			||||||
 | 
					              SCALE = 'C'
 | 
				
			||||||
 | 
					          CASE(3)
 | 
				
			||||||
 | 
					              SCALE = 'Y'
 | 
				
			||||||
 | 
					          CASE(4)
 | 
				
			||||||
 | 
					              SCALE = 'N'
 | 
				
			||||||
 | 
					          END SELECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iNRNK = -1, -2, -1
 | 
				
			||||||
 | 
					         NRNK   = iNRNK
 | 
				
			||||||
 | 
					         NRNKsp = iNRNK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO iWHTSVD = 1,  3
 | 
				
			||||||
 | 
					         ! Check all four options to compute the POD basis
 | 
				
			||||||
 | 
					         ! via the SVD.
 | 
				
			||||||
 | 
					         WHTSVD   = iWHTSVD
 | 
				
			||||||
 | 
					         WHTSVDsp = iWHTSVD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DO LWMINOPT = 1, 2
 | 
				
			||||||
 | 
					         ! Workspace query for the minimal (1) and for the optimal
 | 
				
			||||||
 | 
					         ! (2) workspace lengths determined by workspace query.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ! ZGEDMD is always tested and its results are also used for
 | 
				
			||||||
 | 
					      ! comparisons with ZGEDMDQ.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ZX(1:M,1:N) = ZX0(1:M,1:N)
 | 
				
			||||||
 | 
					      ZY(1:M,1:N) = ZY0(1:M,1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL ZGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,   &
 | 
				
			||||||
 | 
					                   M,  N, ZX, LDX, ZY, LDY, NRNK, TOL,    &
 | 
				
			||||||
 | 
					                   K, ZEIGS, ZZ, LDZ,  RES, ZAU, LDAU,    &
 | 
				
			||||||
 | 
					                   ZW,  LDW, ZS, LDS,  ZDUMMY, -1,        &
 | 
				
			||||||
 | 
					                   WDUMMY, -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					      IF ( (INFO .EQ. 2) .OR. ( INFO .EQ. 3 ) &
 | 
				
			||||||
 | 
					                          .OR. ( INFO < 0 ) ) THEN
 | 
				
			||||||
 | 
					           WRITE(*,*) 'Call to ZGEDMD workspace query failed. &
 | 
				
			||||||
 | 
					                      &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The input parameters were ',      &
 | 
				
			||||||
 | 
					           SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,          &
 | 
				
			||||||
 | 
					           M, N, LDX, LDY, NRNK, TOL, LDZ, LDAU, LDW, LDS
 | 
				
			||||||
 | 
					           STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LZWORK = INT(ZDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					      LWORK  = INT(WDUMMY(1))
 | 
				
			||||||
 | 
					      LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ALLOCATE(ZWORK(LZWORK))
 | 
				
			||||||
 | 
					      ALLOCATE( WORK(LWORK))
 | 
				
			||||||
 | 
					      ALLOCATE(IWORK(LIWORK))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL ZGEDMD( SCALE, JOBZ, RESIDS, JOBREF, WHTSVD,  &
 | 
				
			||||||
 | 
					                   M,  N, ZX, LDX, ZY, LDY, NRNK, TOL,   &
 | 
				
			||||||
 | 
					                   K, ZEIGS, ZZ, LDZ,  RES, ZAU, LDAU,   &
 | 
				
			||||||
 | 
					                   ZW,  LDW,  ZS, LDS, ZWORK,  LZWORK,   &
 | 
				
			||||||
 | 
					                   WORK, LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( INFO /= 0 ) THEN
 | 
				
			||||||
 | 
					           WRITE(*,*) 'Call to ZGEDMD failed. &
 | 
				
			||||||
 | 
					           &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					           WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					           SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					           M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					           STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      SINGVX(1:N) = WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... ZGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBZ,'V')  ) THEN
 | 
				
			||||||
 | 
					          ! Check that Z = X*W, on return from ZGEDMD
 | 
				
			||||||
 | 
					          ! This checks that the returned eigenvectors in Z are
 | 
				
			||||||
 | 
					          ! the product of the SVD'POD basis returned in X
 | 
				
			||||||
 | 
					          ! and the eigenvectors of the rayleigh quotient
 | 
				
			||||||
 | 
					          ! returned in W
 | 
				
			||||||
 | 
					          CALL ZGEMM( 'N', 'N', M, K, K, ZONE, ZX, LDX, ZW, LDW, &
 | 
				
			||||||
 | 
					                      ZZERO, ZZ1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					             CALL ZAXPY( M, -ZONE, ZZ(1,i), 1, ZZ1(1,i), 1)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, DZNRM2( M, ZZ1(1,i), 1 ) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_ZXW = MAX(TMP_ZXW, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP_ZXW <= 10*M*EPS ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ' :) .... OK .........ZGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_Z_XV = NFAIL_Z_XV + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................ZGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !...... ZGEDMD check point
 | 
				
			||||||
 | 
					      IF ( LSAME(JOBREF,'R') ) THEN
 | 
				
			||||||
 | 
					           ! The matrix A*U is returned for computing refined Ritz vectors.
 | 
				
			||||||
 | 
					           ! Check that A*U is computed correctly using the formula
 | 
				
			||||||
 | 
					           ! A*U = Y * V * inv(SIGMA). This depends on the
 | 
				
			||||||
 | 
					           ! accuracy in the computed singular values and vectors of X.
 | 
				
			||||||
 | 
					           ! See the paper for an error analysis.
 | 
				
			||||||
 | 
					           ! Note that the left singular vectors of the input matrix X
 | 
				
			||||||
 | 
					           ! are returned in the array X.
 | 
				
			||||||
 | 
					           CALL ZGEMM( 'N', 'N', M, K, M, ZONE, ZA, LDA, ZX, LDX, &
 | 
				
			||||||
 | 
					                      ZZERO, ZZ1, LDZ )
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					            CALL ZAXPY( M, -ZONE, ZAU(1,i), 1, ZZ1(1,i), 1)
 | 
				
			||||||
 | 
					            TMP = MAX( TMP, DZNRM2( M, ZZ1(1,i),1 ) * &
 | 
				
			||||||
 | 
					                     SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_AU = MAX( TMP_AU, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ':) .... OK .........ZGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_AU = NFAIL_AU + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( .................ZGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					      ELSEIF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					       ! The unscaled vectors of the Exact DMD are computed.
 | 
				
			||||||
 | 
					       ! This option is included for the sake of completeness,
 | 
				
			||||||
 | 
					       ! for users who prefer the Exact DMD vectors. The
 | 
				
			||||||
 | 
					       ! returned vectors are in the real form, in the same way
 | 
				
			||||||
 | 
					       ! as the Ritz vectors. Here we just save the vectors
 | 
				
			||||||
 | 
					       ! and test them separately using a Matlab script.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       CALL ZGEMM( 'N', 'N', M, K, M, ZONE, ZA, LDA, ZAU, LDAU, ZZERO, ZY1, LDY )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               DO i=1, K
 | 
				
			||||||
 | 
					                  ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                CALL ZAXPY( M, -ZEIGS(i), ZAU(1,i), 1, ZY1(1,i), 1 )
 | 
				
			||||||
 | 
					                RESEX(i) = DZNRM2( M, ZY1(1,i), 1) / DZNRM2(M,ZAU(1,i),1)
 | 
				
			||||||
 | 
					               END DO
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      !...... ZGEDMD check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					          ! Compare the residuals returned by ZGEDMD with the
 | 
				
			||||||
 | 
					          ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					          ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					          CALL ZGEMM( 'N', 'N', M, K, M, ZONE, ZA, LDA, ZZ, LDZ, ZZERO, ZY1, LDY )
 | 
				
			||||||
 | 
					          ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					          ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					          ! pairs of eigencalues. (See the description of Z in ZGEDMD,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i=1, K
 | 
				
			||||||
 | 
					                ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                CALL ZAXPY( M, -ZEIGS(i), ZZ(1,i), 1, ZY1(1,i), 1 )
 | 
				
			||||||
 | 
					                RES1(i) = DZNRM2( M, ZY1(1,i), 1)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					                    SINGVX(K)/(ANORM*SINGVX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_REZ = MAX( TMP_REZ, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) ':) .... OK ..........ZGEDMD PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_REZ = NFAIL_REZ + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) ':( ..................ZGEDMD FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					                 SCALE, JOBZ, RESIDS, JOBREF, WHTSVD, &
 | 
				
			||||||
 | 
					                 M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         IF ( LSAME(JOBREF,'E') ) THEN
 | 
				
			||||||
 | 
					            TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, K
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES1(i) - RESEX(i))/(RES1(i)+RESEX(i)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_EX = MAX(TMP_EX,TMP)
 | 
				
			||||||
 | 
					         END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE(ZWORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(WORK)
 | 
				
			||||||
 | 
					      DEALLOCATE(IWORK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD .AND. (K_TRAJ == 1) ) THEN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ZF(1:M,1:N+1) = ZF0(1:M,1:N+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL ZGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, JOBREF, &
 | 
				
			||||||
 | 
					                    WHTSVD, M, N+1, ZF, LDF,  ZX, LDX,  ZY, LDY,  &
 | 
				
			||||||
 | 
					                    NRNK,  TOL, K, ZEIGS, ZZ, LDZ, RES,  ZAU,  &
 | 
				
			||||||
 | 
					                    LDAU, ZW, LDW, ZS, LDS, ZDUMMY, -1,   &
 | 
				
			||||||
 | 
					                    WDUMMY,  -1, IDUMMY, -1, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      LZWORK = INT(ZDUMMY(LWMINOPT))
 | 
				
			||||||
 | 
					      ALLOCATE( ZWORK(LZWORK) )
 | 
				
			||||||
 | 
					      LIWORK = IDUMMY(1)
 | 
				
			||||||
 | 
					      ALLOCATE(IWORK(LIWORK))
 | 
				
			||||||
 | 
					      LWORK = INT(WDUMMY(1))
 | 
				
			||||||
 | 
					      ALLOCATE(WORK(LWORK))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CALL ZGEDMDQ( SCALE, JOBZ, RESIDS, WANTQ, WANTR, JOBREF, &
 | 
				
			||||||
 | 
					                    WHTSVD, M, N+1, ZF, LDF,  ZX, LDX,  ZY, LDY,  &
 | 
				
			||||||
 | 
					                    NRNK,  TOL, KQ, ZEIGS, ZZ, LDZ, RES,  ZAU,  &
 | 
				
			||||||
 | 
					                    LDAU, ZW, LDW, ZS, LDS, ZWORK, LZWORK,   &
 | 
				
			||||||
 | 
					                    WORK,  LWORK, IWORK, LIWORK, INFO )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( INFO /= 0 ) THEN
 | 
				
			||||||
 | 
					             WRITE(*,*) 'Call to ZGEDMDQ failed. &
 | 
				
			||||||
 | 
					             &Check the calling sequence and the code.'
 | 
				
			||||||
 | 
					             WRITE(*,*) 'The error code is ', INFO
 | 
				
			||||||
 | 
					             WRITE(*,*) 'The input parameters were ',&
 | 
				
			||||||
 | 
					             SCALE, JOBZ, RESIDS, WANTQ, WANTR, WHTSVD, &
 | 
				
			||||||
 | 
					             M, N, LDX, LDY, NRNK, TOL
 | 
				
			||||||
 | 
					             STOP
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      SINGVQX(1:N) = WORK(1:N)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !..... ZGEDMDQ check point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          IF ( 1 == 0 ) THEN
 | 
				
			||||||
 | 
					              ! Comparison of ZGEDMD and ZGEDMDQ singular values disabled
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, MIN(K, KQ)
 | 
				
			||||||
 | 
					             TMP = MAX(TMP, ABS(SINGVX(i)-SINGVQX(i)) / &
 | 
				
			||||||
 | 
					                                   SINGVX(1) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          SVDIFF = MAX( SVDIFF, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP > M*N*EPS ) THEN
 | 
				
			||||||
 | 
					             WRITE(*,*) 'FAILED! Something was wrong with the run.'
 | 
				
			||||||
 | 
					             NFAIL_SVDIFF = NFAIL_SVDIFF + 1
 | 
				
			||||||
 | 
					             DO j =1, 3
 | 
				
			||||||
 | 
					                 write(*,*) j, SINGVX(j), SINGVQX(j)
 | 
				
			||||||
 | 
					                 read(*,*)
 | 
				
			||||||
 | 
					             END DO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !..... ZGEDMDQ check point
 | 
				
			||||||
 | 
					      IF ( LSAME(WANTQ,'Q') .AND. LSAME(WANTR,'R') ) THEN
 | 
				
			||||||
 | 
					         ! Check that the QR factors are computed and returned
 | 
				
			||||||
 | 
					         ! as requested. The residual ||F-Q*R||_F / ||F||_F
 | 
				
			||||||
 | 
					         ! is compared to M*N*EPS.
 | 
				
			||||||
 | 
					         ZF1(1:M,1:N+1) = ZF0(1:M,1:N+1)
 | 
				
			||||||
 | 
					         CALL ZGEMM( 'N', 'N', M, N+1, MIN(M,N+1), -ZONE, ZF, &
 | 
				
			||||||
 | 
					                     LDF, ZY, LDY, ZONE, ZF1, LDF )
 | 
				
			||||||
 | 
					         TMP_FQR = ZLANGE( 'F', M, N+1, ZF1, LDF, WORK ) / &
 | 
				
			||||||
 | 
					               ZLANGE( 'F', M, N+1, ZF0,  LDF, WORK )
 | 
				
			||||||
 | 
					         IF ( TMP_FQR > TOL2 ) THEN
 | 
				
			||||||
 | 
					              WRITE(*,*) 'FAILED! Something was wrong with the run.'
 | 
				
			||||||
 | 
					             NFAIL_F_QR = NFAIL_F_QR + 1
 | 
				
			||||||
 | 
					         ELSE
 | 
				
			||||||
 | 
					             !WRITE(*,*) '........ PASSED.'
 | 
				
			||||||
 | 
					         END IF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !..... ZGEDMDQ check point
 | 
				
			||||||
 | 
					      IF ( LSAME(RESIDS, 'R') ) THEN
 | 
				
			||||||
 | 
					          ! Compare the residuals returned by ZGEDMDQ with the
 | 
				
			||||||
 | 
					          ! explicitly computed residuals using the matrix A.
 | 
				
			||||||
 | 
					          ! Compute explicitly Y1 = A*Z
 | 
				
			||||||
 | 
					          CALL ZGEMM( 'N', 'N', M, KQ, M, ZONE, ZA, LDA, ZZ, LDZ, ZZERO, ZY1, LDY )
 | 
				
			||||||
 | 
					          ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
 | 
				
			||||||
 | 
					          ! of the invariant subspaces that correspond to complex conjugate
 | 
				
			||||||
 | 
					          ! pairs of eigencalues. (See the description of Z in ZGEDMDQ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          DO i=1, KQ
 | 
				
			||||||
 | 
					                ! have a real eigenvalue with real eigenvector
 | 
				
			||||||
 | 
					                CALL ZAXPY( M, -ZEIGS(i), ZZ(1,i), 1, ZY1(1,i), 1 )
 | 
				
			||||||
 | 
					                ! Y(1:M,i) = Y(1:M,i) - REIG(i)*Z(1:M,i)
 | 
				
			||||||
 | 
					                RES1(i) = DZNRM2( M, ZY1(1,i), 1)
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP = ZERO
 | 
				
			||||||
 | 
					          DO i = 1, KQ
 | 
				
			||||||
 | 
					          TMP = MAX( TMP, ABS(RES(i) - RES1(i)) * &
 | 
				
			||||||
 | 
					              SINGVQX(KQ)/(ANORM*SINGVQX(1)) )
 | 
				
			||||||
 | 
					          END DO
 | 
				
			||||||
 | 
					          TMP_REZQ = MAX( TMP_REZQ, TMP )
 | 
				
			||||||
 | 
					          IF ( TMP <= TOL2 ) THEN
 | 
				
			||||||
 | 
					              !WRITE(*,*) '.... OK ........ ZGEDMDQ PASSED.'
 | 
				
			||||||
 | 
					          ELSE
 | 
				
			||||||
 | 
					              NFAIL_REZQ = NFAIL_REZQ + 1
 | 
				
			||||||
 | 
					              WRITE(*,*) '................ ZGEDMDQ FAILED!', &
 | 
				
			||||||
 | 
					                  'Check the code for implementation errors.'
 | 
				
			||||||
 | 
					              STOP
 | 
				
			||||||
 | 
					          END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE( ZWORK )
 | 
				
			||||||
 | 
					      DEALLOCATE( WORK  )
 | 
				
			||||||
 | 
					      DEALLOCATE( IWORK )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF ! ZGEDMDQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!.......................................................................................................
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO   ! LWMINOPT
 | 
				
			||||||
 | 
					      !write(*,*) 'LWMINOPT loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iWHTSVD
 | 
				
			||||||
 | 
					      !write(*,*) 'WHTSVD loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iNRNK  -2:-1
 | 
				
			||||||
 | 
					      !write(*,*) 'NRNK loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iSCALE  1:4
 | 
				
			||||||
 | 
					      !write(*,*) 'SCALE loop completed'
 | 
				
			||||||
 | 
					      END DO
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBREF loop completed'
 | 
				
			||||||
 | 
					      END DO   ! iJOBZ
 | 
				
			||||||
 | 
					      !write(*,*) 'JOBZ loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! MODE -6:6
 | 
				
			||||||
 | 
					      !write(*,*) 'MODE loop completed'
 | 
				
			||||||
 | 
					      END DO ! 1 or 2 trajectories
 | 
				
			||||||
 | 
					      !write(*,*) 'trajectories  loop completed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEALLOCATE( ZA )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZAC )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZZ )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZF )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZF0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZF1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZX )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZX0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZY )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZY0 )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZY1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZAU )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZW )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZS )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZZ1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( RES )
 | 
				
			||||||
 | 
					      DEALLOCATE( RES1 )
 | 
				
			||||||
 | 
					      DEALLOCATE( RESEX )
 | 
				
			||||||
 | 
					      DEALLOCATE( ZEIGS )
 | 
				
			||||||
 | 
					      DEALLOCATE( SINGVX )
 | 
				
			||||||
 | 
					      DEALLOCATE( SINGVQX )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END DO ! LLOOP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for ZGEDMD :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      IF ( NFAIL_Z_XV == 0 ) THEN
 | 
				
			||||||
 | 
					         WRITE(*,*) '>>>> Z - U*V test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					         WRITE(*,*) 'Z - U*V test FAILED ', NFAIL_Z_XV, ' time(s)'
 | 
				
			||||||
 | 
					         WRITE(*,*) 'Max error ||Z-U*V||_F was ', TMP_ZXW
 | 
				
			||||||
 | 
					         NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_Z_XV
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					      IF ( NFAIL_AU == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> A*U test PASSED. '
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'A*U test FAILED ', NFAIL_AU, ' time(s)'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Max A*U test adjusted error measure was ', TMP_AU
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_AU
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZ == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZ, 'time(s)'
 | 
				
			||||||
 | 
					        WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZ
 | 
				
			||||||
 | 
					        WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					        NFAIL_TOTAL = NFAIL_TOTAL + NFAIL_REZ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>> ZGEDMD :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					        WRITE(*,*) NFAIL_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					        WRITE(*,*) '>>>>>>>>>>>>>> ZGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( TEST_QRDMD ) THEN
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*) ' Test summary for ZGEDMDQ :'
 | 
				
			||||||
 | 
					      WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_SVDIFF == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> ZGEDMD and ZGEDMDQ computed singular &
 | 
				
			||||||
 | 
					              &values test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					         WRITE(*,*) 'ZGEDMD and ZGEDMDQ discrepancies in &
 | 
				
			||||||
 | 
					             &the singular values unacceptable ', &
 | 
				
			||||||
 | 
					             NFAIL_SVDIFF, ' times. Test FAILED.'
 | 
				
			||||||
 | 
					         WRITE(*,*) 'The maximal discrepancy in the singular values (relative to the norm) was ', SVDIFF
 | 
				
			||||||
 | 
					         WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					         NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_SVDIFF
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_F_QR == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> F - Q*R test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'F - Q*R test FAILED ', NFAIL_F_QR, ' time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'The largest relative residual was ', TMP_FQR
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_F_QR
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAIL_REZQ == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>> Rezidual computation test PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Rezidual computation test FAILED ', NFAIL_REZQ, 'time(s)'
 | 
				
			||||||
 | 
					          WRITE(*,*) 'Max residual computing test adjusted error measure was ', TMP_REZQ
 | 
				
			||||||
 | 
					          WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', EPS
 | 
				
			||||||
 | 
					          NFAILQ_TOTAL = NFAILQ_TOTAL + NFAIL_REZQ
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IF ( NFAILQ_TOTAL == 0 ) THEN
 | 
				
			||||||
 | 
					          WRITE(*,*) '>>>>>>> ZGEDMDQ :: ALL TESTS PASSED.'
 | 
				
			||||||
 | 
					      ELSE
 | 
				
			||||||
 | 
					         WRITE(*,*) NFAILQ_TOTAL, 'FAILURES!'
 | 
				
			||||||
 | 
					         WRITE(*,*) '>>>>>>> ZGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      END IF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      WRITE(*,*)
 | 
				
			||||||
 | 
					      WRITE(*,*) 'Test completed.'
 | 
				
			||||||
 | 
					      STOP
 | 
				
			||||||
 | 
					      END
 | 
				
			||||||
		Loading…
	
		Reference in New Issue