43 use iso_fortran_env,
only: real64
45 integer,
parameter :: WP = real64
48 REAL(KIND=wp),
PARAMETER :: one = 1.0_wp
49 REAL(KIND=wp),
PARAMETER :: zero = 0.0_wp
51 COMPLEX(KIND=WP),
PARAMETER :: ZONE = ( 1.0_wp, 0.0_wp )
52 COMPLEX(KIND=WP),
PARAMETER :: ZZERO = ( 0.0_wp, 0.0_wp )
54 REAL(KIND=wp),
ALLOCATABLE,
DIMENSION(:) :: res, &
55 res1, resex, singvx, singvqx, work
56 INTEGER ,
ALLOCATABLE,
DIMENSION(:) :: IWORK
57 REAL(KIND=wp) :: wdummy(2)
58 INTEGER :: IDUMMY(4), ISEED(4)
59 REAL(KIND=wp) :: anorm, cond, condl, condr, eps, &
60 tol, tol2, svdiff, tmp, tmp_au, &
61 tmp_fqr, tmp_rez, tmp_rezq, tmp_zxw, &
65 COMPLEX(KIND=WP) :: ZMAX
67 COMPLEX(KIND=WP),
ALLOCATABLE,
DIMENSION(:,:) :: ZA, ZAC, &
68 zau, zf, zf0, zf1, zs, zw, &
69 zx, zx0, zy, zy0, zy1, zz, zz1
70 COMPLEX(KIND=WP),
ALLOCATABLE,
DIMENSION(:) :: ZDA, ZDR, &
71 zdl, zeigs, zeigsa, zwork
72 COMPLEX(KIND=WP) :: ZDUMMY(22), ZDUM2X2(2,2)
74 INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY, &
75 ldz, liwork, lwork, m, n, lloop, nrnk, nrnksp
76 INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, j, &
77 nfail, nfail_au, nfail_f_qr, nfail_rez, &
78 nfail_rezq, nfail_svdiff, nfail_total, nfailq_total, &
79 nfail_z_xv, mode, model, moder, whtsvd, &
81 INTEGER :: iNRNK, iWHTSVD, K_TRAJ, LWMINOPT
82 CHARACTER :: GRADE, JOBREF, JOBZ, PIVTNG, RSIGN, &
83 scale, resids, wantq, wantr
103 INTRINSIC abs, int, min, max, sign
132 WRITE(*,*)
'L Loop Index = ', lloop
144 IF ( ( min(m,n) == 0 ) .OR. ( m < n ) )
THEN
145 WRITE(*,*)
'Bad dimensions. Required: M >= N > 0.'
171 ALLOCATE( za(lda,m) )
172 ALLOCATE( zac(lda,m) )
173 ALLOCATE( zf(ldf,n+1) )
174 ALLOCATE( zf0(ldf,n+1) )
175 ALLOCATE( zf1(ldf,n+1) )
176 ALLOCATE( zx(ldx,n) )
177 ALLOCATE( zx0(ldx,n) )
178 ALLOCATE( zy(ldy,n+1) )
179 ALLOCATE( zy0(ldy,n+1) )
180 ALLOCATE( zy1(ldy,n+1) )
181 ALLOCATE( zau(ldau,n) )
182 ALLOCATE( zw(ldw,n) )
183 ALLOCATE( zs(lds,n) )
184 ALLOCATE( zz(ldz,n) )
185 ALLOCATE( zz1(ldz,n) )
190 ALLOCATE( singvx(n) )
191 ALLOCATE( singvqx(n) )
216 ALLOCATE( iwork(2*m) )
221 CALL zlatmr( m, m,
'N', iseed,
'N', zda, mode, cond, &
222 zmax, rsign, grade, zdl, model, condl, &
223 zdr, moder, condr, pivtng, iwork, m, m, &
224 zero, -one,
'N', za, lda, iwork(m+1), info )
231 ALLOCATE( zeigsa(m) )
232 ALLOCATE( zwork(lzwork) )
233 ALLOCATE( work(2*m) )
234 zac(1:m,1:m) = za(1:m,1:m)
235 CALL zgeev(
'N',
'N', m, zac, lda, zeigsa, zdum2x2, 2, &
236 zdum2x2, 2, zwork, lzwork, work, info )
240 tmp = abs(zeigsa(izamax(m, zeigsa, 1)))
242 CALL zlascl(
'G',0, 0, tmp, one, m, m, &
244 CALL zlascl(
'G',0, 0, tmp, one, m, 1, &
246 anorm =
zlange(
'F', m, m, za, lda, wdummy )
248 IF ( k_traj == 2 )
THEN
251 CALL zlarnv(2, iseed, m, zf(1,1) )
253 CALL zgemv(
'N', m, m, zone, za, lda, zf(1,i), 1, &
254 zzero, zf(1,i+1), 1 )
256 zx0(1:m,1:n/2) = zf(1:m,1:n/2)
257 zy0(1:m,1:n/2) = zf(1:m,2:n/2+1)
259 CALL zlarnv(2, iseed, m, zf(1,1) )
261 CALL zgemv(
'N', m, m, zone, za, lda, zf(1,i), 1, &
262 zzero, zf(1,i+1), 1 )
264 zx0(1:m,n/2+1:n) = zf(1:m,1:n-n/2)
265 zy0(1:m,n/2+1:n) = zf(1:m,2:n-n/2+1)
267 CALL zlarnv(2, iseed, m, zf(1,1) )
269 CALL zgemv(
'N', m, m, zone, za, m, zf(1,i), 1, &
270 zzero, zf(1,i+1), 1 )
272 zf0(1:m,1:n+1) = zf(1:m,1:n+1)
273 zx0(1:m,1:n) = zf0(1:m,1:n)
274 zy0(1:m,1:n) = zf0(1:m,2:n+1)
282 SELECT CASE ( ijobz )
299 SELECT CASE ( ijobref )
310 SELECT CASE ( iscale )
321 DO inrnk = -1, -2, -1
338 zx(1:m,1:n) = zx0(1:m,1:n)
339 zy(1:m,1:n) = zy0(1:m,1:n)
341 CALL zgedmd( scale, jobz, resids, jobref, whtsvd, &
342 m, n, zx, ldx, zy, ldy, nrnk, tol, &
343 k, zeigs, zz, ldz, res, zau, ldau, &
344 zw, ldw, zs, lds, zdummy, -1, &
345 wdummy, -1, idummy, -1, info )
346 IF ( (info .EQ. 2) .OR. ( info .EQ. 3 ) &
347 .OR. ( info < 0 ) )
THEN
348 WRITE(*,*)
'Call to ZGEDMD workspace query failed. &
349 &Check the calling sequence and the code.'
350 WRITE(*,*)
'The error code is ', info
351 WRITE(*,*)
'The input parameters were ', &
352 scale, jobz, resids, jobref, whtsvd, &
353 m, n, ldx, ldy, nrnk, tol, ldz, ldau, ldw, lds
357 lzwork = int(zdummy(lwminopt))
358 lwork = int(wdummy(1))
361 ALLOCATE(zwork(lzwork))
362 ALLOCATE( work(lwork))
363 ALLOCATE(iwork(liwork))
365 CALL zgedmd( scale, jobz, resids, jobref, whtsvd, &
366 m, n, zx, ldx, zy, ldy, nrnk, tol, &
367 k, zeigs, zz, ldz, res, zau, ldau, &
368 zw, ldw, zs, lds, zwork, lzwork, &
369 work, lwork, iwork, liwork, info )
371 IF ( info /= 0 )
THEN
372 WRITE(*,*)
'Call to ZGEDMD failed. &
373 &Check the calling sequence and the code.'
374 WRITE(*,*)
'The error code is ', info
375 WRITE(*,*)
'The input parameters were ',&
376 scale, jobz, resids, jobref, whtsvd, &
377 m, n, ldx, ldy, nrnk, tol
381 singvx(1:n) = work(1:n)
384 IF ( lsame(jobz,
'V') )
THEN
390 CALL zgemm(
'N',
'N', m, k, k, zone, zx, ldx, zw, ldw, &
394 CALL zaxpy( m, -zone, zz(1,i), 1, zz1(1,i), 1)
395 tmp = max(tmp,
dznrm2( m, zz1(1,i), 1 ) )
397 tmp_zxw = max(tmp_zxw, tmp )
398 IF ( tmp_zxw <= 10*m*eps )
THEN
401 nfail_z_xv = nfail_z_xv + 1
402 WRITE(*,*)
':( .................ZGEDMD FAILED!', &
403 'Check the code for implementation errors.'
404 WRITE(*,*)
'The input parameters were ',&
405 scale, jobz, resids, jobref, whtsvd, &
406 m, n, ldx, ldy, nrnk, tol
412 IF ( lsame(jobref,
'R') )
THEN
420 CALL zgemm(
'N',
'N', m, k, m, zone, za, lda, zx, ldx, &
424 CALL zaxpy( m, -zone, zau(1,i), 1, zz1(1,i), 1)
425 tmp = max( tmp,
dznrm2( m, zz1(1,i),1 ) * &
426 singvx(k)/(anorm*singvx(1)) )
428 tmp_au = max( tmp_au, tmp )
429 IF ( tmp <= tol2 )
THEN
432 nfail_au = nfail_au + 1
433 WRITE(*,*)
':( .................ZGEDMD FAILED!', &
434 'Check the code for implementation errors.'
435 WRITE(*,*)
'The input parameters were ',&
436 scale, jobz, resids, jobref, whtsvd, &
437 m, n, ldx, ldy, nrnk, tol
439 ELSEIF ( lsame(jobref,
'E') )
THEN
448 CALL zgemm(
'N',
'N', m, k, m, zone, za, lda, zau, ldau, zzero, zy1
452 CALL zaxpy( m, -zeigs(i), zau(1,i), 1, zy1(1,i), 1 )
453 resex(i) =
dznrm2( m, zy1(1,i), 1) /
dznrm2(m,zau(1,i),1
458 IF ( lsame(resids,
'R') )
THEN
462 CALL zgemm(
'N',
'N', m, k, m, zone, za, lda, zz, ldz, zzero, zy1
469 CALL zaxpy( m, -zeigs(i), zz(1,i), 1, zy1(1,i), 1 )
470 res1(i) =
dznrm2( m, zy1(1,i), 1)
474 tmp = max( tmp, abs(res(i) - res1(i)) * &
475 singvx(k)/(anorm*singvx(1)) )
477 tmp_rez = max( tmp_rez, tmp )
478 IF ( tmp <= tol2 )
THEN
481 nfail_rez = nfail_rez + 1
482 WRITE(*,*)
':( ..................ZGEDMD FAILED!', &
483 'Check the code for implementation errors.'
484 WRITE(*,*)
'The input parameters were ',&
485 scale, jobz, resids, jobref, whtsvd, &
486 m, n, ldx, ldy, nrnk, tol
490 IF ( lsame(jobref,
'E') )
THEN
493 tmp = max( tmp, abs(res1(i) - resex(i))/(res1(i)+resex(i)) )
495 tmp_ex = max(tmp_ex,tmp)
504 IF ( test_qrdmd .AND. (k_traj == 1) )
THEN
506 zf(1:m,1:n+1) = zf0(1:m,1:n+1)
508 CALL zgedmdq( scale, jobz, resids, wantq, wantr, jobref, &
509 whtsvd, m, n+1, zf, ldf, zx, ldx, zy, ldy, &
510 nrnk, tol, k, zeigs, zz, ldz, res, zau, &
511 ldau, zw, ldw, zs, lds, zdummy, -1, &
512 wdummy, -1, idummy, -1, info )
514 lzwork = int(zdummy(lwminopt))
515 ALLOCATE( zwork(lzwork) )
517 ALLOCATE(iwork(liwork))
518 lwork = int(wdummy(1))
519 ALLOCATE(work(lwork))
521 CALL zgedmdq( scale, jobz, resids, wantq, wantr, jobref, &
522 whtsvd, m, n+1, zf, ldf, zx, ldx, zy, ldy, &
523 nrnk, tol, kq, zeigs, zz, ldz, res, zau, &
524 ldau, zw, ldw, zs, lds, zwork, lzwork, &
525 work, lwork, iwork, liwork, info )
527 IF ( info /= 0 )
THEN
528 WRITE(*,*)
'Call to ZGEDMDQ failed. &
529 &Check the calling sequence and the code.'
530 WRITE(*,*)
'The error code is ', info
531 WRITE(*,*)
'The input parameters were ',&
532 scale, jobz, resids, wantq, wantr, whtsvd, &
533 m, n, ldx, ldy, nrnk, tol
536 singvqx(1:n) = work(1:n)
544 tmp = max(tmp, abs(singvx(i)-singvqx(i)) / &
547 svdiff = max( svdiff, tmp )
548 IF ( tmp > m*n*eps )
THEN
549 WRITE(*,*)
'FAILED! Something was wrong with the run.'
550 nfail_svdiff = nfail_svdiff + 1
552 write(*,*) j, singvx(j), singvqx(j)
560 IF ( lsame(wantq,
'Q') .AND. lsame(wantr,
'R') )
THEN
564 zf1(1:m,1:n+1) = zf0(1:m,1:n+1)
565 CALL zgemm(
'N',
'N', m, n+1, min(m,n+1), -zone, zf, &
566 ldf, zy, ldy, zone, zf1, ldf )
567 tmp_fqr =
zlange(
'F', m, n+1, zf1, ldf, work ) / &
568 zlange(
'F', m, n+1, zf0, ldf, work )
569 IF ( tmp_fqr > tol2 )
THEN
570 WRITE(*,*)
'FAILED! Something was wrong with the run.'
571 nfail_f_qr = nfail_f_qr + 1
578 IF ( lsame(resids,
'R') )
THEN
582 CALL zgemm(
'N',
'N', m, kq, m, zone, za, lda, zz, ldz, zzero,
589 CALL zaxpy( m, -zeigs(i), zz(1,i), 1, zy1(1,i), 1 )
591 res1(i) =
dznrm2( m, zy1(1,i), 1)
595 tmp = max( tmp, abs(res(i) - res1(i)) * &
596 singvqx(kq)/(anorm*singvqx(1)) )
598 tmp_rezq = max( tmp_rezq, tmp )
599 IF ( tmp <= tol2 )
THEN
602 nfail_rezq = nfail_rezq + 1
603 WRITE(*,*)
'................ ZGEDMDQ FAILED!', &
604 'Check the code for implementation errors.'
656 DEALLOCATE( singvqx )
660 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
661 WRITE(*,*)
' Test summary for ZGEDMD :'
662 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
664 IF ( nfail_z_xv == 0 )
THEN
665 WRITE(*,*)
'>>>> Z - U*V test PASSED.'
667 WRITE(*,*)
'Z - U*V test FAILED ', nfail_z_xv,
' time(s)'
668 WRITE(*,*)
'Max error ||Z-U*V||_F was ', tmp_zxw
669 nfail_total = nfail_total + nfail_z_xv
671 IF ( nfail_au == 0 )
THEN
672 WRITE(*,*)
'>>>> A*U test PASSED. '
674 WRITE(*,*)
'A*U test FAILED ', nfail_au,
' time(s)'
675 WRITE(*,*)
'Max A*U test adjusted error measure was ', tmp_au
676 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
677 nfail_total = nfail_total + nfail_au
680 IF ( nfail_rez == 0 )
THEN
681 WRITE(*,*)
'>>>> Rezidual computation test PASSED.'
683 WRITE(*,*)
'Rezidual computation test FAILED ', nfail_rez,
'time(s)'
684 WRITE(*,*)
'Max residual computing test adjusted error measure was '
685 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
686 nfail_total = nfail_total + nfail_rez
689 IF ( nfail_total == 0 )
THEN
690 WRITE(*,*)
'>>>> ZGEDMD :: ALL TESTS PASSED.'
692 WRITE(*,*) nfail_total,
'FAILURES!'
693 WRITE(*,*)
'>>>>>>>>>>>>>> ZGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
696 IF ( test_qrdmd )
THEN
698 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
699 WRITE(*,*)
' Test summary for ZGEDMDQ :'
700 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
703 IF ( nfail_svdiff == 0 )
THEN
704 WRITE(*,*)
'>>>> ZGEDMD and ZGEDMDQ computed singular &
705 &values test PASSED.'
707 WRITE(*,*)
'ZGEDMD and ZGEDMDQ discrepancies in &
708 &the singular values unacceptable ', &
709 nfail_svdiff,
' times. Test FAILED.'
710 WRITE(*,*)
'The maximal discrepancy in the singular values (relative to the norm) was '
711 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
712 nfailq_total = nfailq_total + nfail_svdiff
715 IF ( nfail_f_qr == 0 )
THEN
716 WRITE(*,*)
'>>>> F - Q*R test PASSED.'
718 WRITE(*,*)
'F - Q*R test FAILED ', nfail_f_qr,
' time(s)'
719 WRITE(*,*)
'The largest relative residual was ', tmp_fqr
720 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
721 nfailq_total = nfailq_total + nfail_f_qr
724 IF ( nfail_rezq == 0 )
THEN
725 WRITE(*,*)
'>>>> Rezidual computation test PASSED.'
727 WRITE(*,*)
'Rezidual computation test FAILED ', nfail_rezq,
'time(s)'
728 WRITE(*,*)
'Max residual computing test adjusted error measure was '
729 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
730 nfailq_total = nfailq_total + nfail_rezq
733 IF ( nfailq_total == 0 )
THEN
734 WRITE(*,*)
'>>>>>>> ZGEDMDQ :: ALL TESTS PASSED.'
736 WRITE(*,*) nfailq_total,
'FAILURES!'
737 WRITE(*,*)
'>>>>>>> ZGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
743 WRITE(*,*)
'Test completed.'
subroutine daxpy(n, da, dx, incx, dy, incy)
DAXPY
subroutine zaxpy(n, za, zx, incx, zy, incy)
ZAXPY
subroutine zgedmdq(jobs, jobz, jobr, jobq, jobt, jobf, whtsvd, m, n, f, ldf, x, ldx, y, ldy, nrnk, tol, k, eigs, z, ldz, res, b, ldb, v, ldv, s, lds, zwork, lzwork, work, lwork, iwork, liwork, info)
ZGEDMDQ computes the Dynamic Mode Decomposition (DMD) for a pair of data snapshot matrices.
subroutine zgedmd(jobs, jobz, jobr, jobf, whtsvd, m, n, x, ldx, y, ldy, nrnk, tol, k, eigs, z, ldz, res, b, ldb, w, ldw, s, lds, zwork, lzwork, rwork, lrwork, iwork, liwork, info)
ZGEDMD computes the Dynamic Mode Decomposition (DMD) for a pair of data snapshot matrices.
subroutine dgeev(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info)
DGEEV computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matrices
subroutine zgeev(jobvl, jobvr, n, a, lda, w, vl, ldvl, vr, ldvr, work, lwork, rwork, info)
ZGEEV computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matrices
subroutine dgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
DGEMM
subroutine zgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
ZGEMM
subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
DGEMV
subroutine zgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
ZGEMV
integer function izamax(n, zx, incx)
IZAMAX
subroutine dlacpy(uplo, m, n, a, lda, b, ldb)
DLACPY copies all or part of one two-dimensional array to another.
double precision function dlamch(cmach)
DLAMCH
double precision function zlange(norm, m, n, a, lda, work)
ZLANGE returns the value of the 1-norm, Frobenius norm, infinity-norm, or the largest absolute value ...
subroutine zlarnv(idist, iseed, n, x)
ZLARNV returns a vector of random numbers from a uniform or normal distribution.
subroutine zlascl(type, kl, ku, cfrom, cto, m, n, a, lda, info)
ZLASCL multiplies a general rectangular matrix by a real scalar defined as cto/cfrom.
subroutine dlascl(type, kl, ku, cfrom, cto, m, n, a, lda, info)
DLASCL multiplies a general rectangular matrix by a real scalar defined as cto/cfrom.
logical function lsame(ca, cb)
LSAME
real(wp) function dznrm2(n, x, incx)
DZNRM2
subroutine zlatmr(m, n, dist, iseed, sym, d, mode, cond, dmax, rsign, grade, dl, model, condl, dr, moder, condr, pivtng, ipivot, kl, ku, sparse, anorm, pack, a, lda, iwork, info)
ZLATMR