62 use iso_fortran_env,
only: real64
64 integer,
parameter :: WP = real64
67 REAL(KIND=wp),
PARAMETER :: one = 1.0_wp
68 REAL(KIND=wp),
PARAMETER :: zero = 0.0_wp
70 REAL(KIND=wp),
ALLOCATABLE,
DIMENSION(:,:) :: &
71 a, ac, eiga, lambda, lambdaq, f, f1, f2,&
72 z, z1, s, au, w, va, x, x0, y, y0, y1
73 REAL(KIND=wp),
ALLOCATABLE,
DIMENSION(:) :: &
74 da, dl, dr, reig, reiga, reigq, ieig, &
75 ieiga, ieigq, res, res1, resex, singvx,&
77 INTEGER ,
ALLOCATABLE,
DIMENSION(:) :: IWORK
78 REAL(KIND=wp) :: ab(2,2), wdummy(2)
79 INTEGER :: IDUMMY(2), ISEED(4), RJOBDATA(8)
80 REAL(KIND=wp) :: anorm, cond, condl, condr, dmax, eps, &
81 tol, tol2, svdiff, tmp, tmp_au, &
82 tmp_fqr, tmp_rez, tmp_rezq, tmp_zxw, &
85 INTEGER :: K, KQ, LDF, LDS, LDA, LDAU, LDW, LDX, LDY, &
86 ldz, liwork, lwork, m, n, l, lloop, nrnk
87 INTEGER :: i, iJOBREF, iJOBZ, iSCALE, INFO, j, KDIFF, &
88 nfail, nfail_au, nfail_f_qr, nfail_rez, &
89 nfail_rezq, nfail_svdiff, nfail_total, nfailq_total, &
90 nfail_z_xv, mode, model, moder, whtsvd
91 INTEGER iNRNK, iWHTSVD, K_TRAJ, LWMINOPT
92 CHARACTER(LEN=1) GRADE, JOBREF, JOBZ, PIVTNG, RSIGN, &
93 scale, resids, wantq, wantr
109 INTRINSIC abs, int, min, max
140 WRITE(*,*)
'L Loop Index = ', lloop
152 IF ( ( min(m,n) == 0 ) .OR. ( m < n ) )
THEN
153 WRITE(*,*)
'Bad dimensions. Required: M >= N > 0.'
187 ALLOCATE( ac(lda,m) )
190 ALLOCATE( f(ldf,n+1) )
191 ALLOCATE( f1(ldf,n+1) )
192 ALLOCATE( f2(ldf,n+1) )
194 ALLOCATE( x0(ldx,n) )
195 ALLOCATE( singvx(n) )
196 ALLOCATE( singvqx(n) )
197 ALLOCATE( y(ldy,n+1) )
198 ALLOCATE( y0(ldy,n+1) )
199 ALLOCATE( y1(m,n+1) )
201 ALLOCATE( z1(ldz,n) )
211 ALLOCATE( va(lda,m) )
212 ALLOCATE( lambda(n,2) )
213 ALLOCATE( lambdaq(n,2) )
214 ALLOCATE( eiga(m,2) )
216 ALLOCATE( au(ldau,n) )
242 ALLOCATE( iwork(2*m) )
244 CALL dlatmr( m, m,
'S', iseed,
'N', da, mode, cond, &
245 dmax, rsign, grade, dl, model, condl, &
246 dr, moder, condr, pivtng, iwork, m, m, &
247 zero, -one,
'N', a, lda, iwork(m+1), info )
252 ALLOCATE(work(lwork))
254 CALL dgeev(
'N',
'V', m, ac, m, reiga, ieiga, va, m, &
255 va, m, work, lwork, info )
261 tmp = max( tmp, sqrt(reiga(i)**2+ieiga(i)**2))
265 CALL dlascl(
'G', 0, 0, tmp, one, m, m, a, m, info )
266 CALL dlascl(
'G', 0, 0, tmp, one, m, 2, eiga, m, info )
269 anorm =
dlange(
'F', n, n, a, m, wdummy )
271 IF ( k_traj == 2 )
THEN
273 CALL dlarnv(2, iseed, m, f1(1,1) )
274 f1(1:m,1) = 1.0e-10*f1(1:m,1)
276 CALL dgemv(
'N', m, m, one, a, m, f1(1,i), 1, zero, &
279 x0(1:m,1:n/2) = f1(1:m,1:n/2)
280 y0(1:m,1:n/2) = f1(1:m,2:n/2+1)
282 CALL dlarnv(2, iseed, m, f1(1,1) )
284 CALL dgemv(
'N', m, m, one, a, m, f1(1,i), 1, zero, &
287 x0(1:m,n/2+1:n) = f1(1:m,1:n-n/2)
288 y0(1:m,n/2+1:n) = f1(1:m,2:n-n/2+1)
290 CALL dlarnv(2, iseed, m, f(1,1) )
292 CALL dgemv(
'N', m, m, one, a, m, f(1,i), 1, zero, &
295 x0(1:m,1:n) = f(1:m,1:n)
296 y0(1:m,1:n) = f(1:m,2:n+1)
299 xnorm =
dlange(
'F', m, n, x0, ldx, wdummy )
300 ynorm =
dlange(
'F', m, n, y0, ldx, wdummy )
305 SELECT CASE ( ijobz )
322 SELECT CASE ( ijobref )
333 SELECT CASE ( iscale )
344 DO inrnk = -1, -2, -1
360 x(1:m,1:n) = x0(1:m,1:n)
361 y(1:m,1:n) = y0(1:m,1:n)
364 CALL dgedmd( scale, jobz, resids, jobref, whtsvd, m, &
365 n, x, ldx, y, ldy, nrnk, tol, k, reig, ieig, z, &
366 ldz, res, au, ldau, w, ldw, s, lds, wdummy, -1, &
370 ALLOCATE( iwork(liwork) )
371 lwork = int(wdummy(lwminopt))
372 ALLOCATE( work(lwork) )
375 CALL dgedmd( scale, jobz, resids, jobref, whtsvd, m, &
376 n, x, ldx, y, ldy, nrnk, tol, k, reig, ieig, z, &
377 ldz, res, au, ldau, w, ldw, s, lds, work, lwork,&
378 iwork, liwork, info )
380 singvx(1:n) = work(1:n)
383 IF ( lsame(jobz,
'V') )
THEN
389 CALL dgemm(
'N',
'N', m, k, k, one, x, ldx, w, ldw, &
393 CALL daxpy( m, -one, z(1,i), 1, z1(1,i), 1)
394 tmp = max(tmp,
dnrm2( m, z1(1,i), 1 ) )
396 tmp_zxw = max(tmp_zxw, tmp )
398 IF ( tmp_zxw > 10*m*eps )
THEN
399 nfail_z_xv = nfail_z_xv + 1
400 WRITE(*,*)
':( .................DGEDMD FAILED!', &
401 'Check the code for implementation errors.'
402 WRITE(*,*)
'The input parameters were ',&
403 scale, jobz, resids, jobref, whtsvd, &
404 m, n, ldx, ldy, nrnk, tol
410 IF ( lsame(jobref,
'R') )
THEN
418 CALL dgemm(
'N',
'N', m, k, m, one, a, lda, x, ldx, &
422 CALL daxpy( m, -one, au(1,i), 1, z1(1,i), 1)
423 tmp = max( tmp,
dnrm2( m, z1(1,i),1 ) * &
424 singvx(k)/(anorm*singvx(1)) )
426 tmp_au = max( tmp_au, tmp )
428 IF ( tmp > tol2 )
THEN
429 nfail_au = nfail_au + 1
430 WRITE(*,*)
':( .................DGEDMD FAILED!', &
431 'Check the code for implementation errors.'
432 WRITE(*,*)
'The input parameters were ',&
433 scale, jobz, resids, jobref, whtsvd, &
434 m, n, ldx, ldy, nrnk, tol
437 ELSEIF ( lsame(jobref,
'E') )
THEN
445 CALL dgemm(
'N',
'N', m, k, m, one, a, lda, au, ldau, zero, y1, m
448 IF ( ieig(i) == zero )
THEN
450 CALL daxpy( m, -reig(i), au(1,i), 1, y1(1,i), 1 )
451 resex(i) =
dnrm2( m, y1(1,i), 1) /
dnrm2(m,au(1,i),1)
465 CALL dgemm(
'N',
'N', m, 2, 2, -one, au(1,i), &
466 m, ab, 2, one, y1(1,i), m )
467 resex(i) =
dlange(
'F', m, 2, y1(1,i), m, &
468 work )/
dlange(
'F', m, 2, au(1,i), m, &
470 resex(i+1) = resex(i)
478 IF ( lsame(resids,
'R') )
THEN
482 CALL dgemm(
'N',
'N', m, k, m, one, a, lda, z, ldz, zero, y1, m
488 IF ( ieig(i) == zero )
THEN
490 CALL daxpy( m, -reig(i), z(1,i), 1, y1(1,i), 1 )
491 res1(i) =
dnrm2( m, y1(1,i), 1)
505 CALL dgemm(
'N',
'N', m, 2, 2, -one, z(1,i), &
506 m, ab, 2, one, y1(1,i), m )
507 res1(i) =
dlange(
'F', m, 2, y1(1,i), m, &
515 tmp = max( tmp, abs(res(i) - res1(i)) * &
516 singvx(k)/(anorm*singvx(1)) )
518 tmp_rez = max( tmp_rez, tmp )
520 IF ( tmp > tol2 )
THEN
521 nfail_rez = nfail_rez + 1
522 WRITE(*,*)
':( ..................DGEDMD FAILED!', &
523 'Check the code for implementation errors.'
524 WRITE(*,*)
'The input parameters were ',&
525 scale, jobz, resids, jobref, whtsvd, &
526 m, n, ldx, ldy, nrnk, tol
529 IF ( lsame(jobref,
'E') )
THEN
532 tmp = max( tmp, abs(res1(i) - resex(i))/(res1(i)+resex
534 tmp_ex = max(tmp_ex,tmp)
541 lambda(i,1) = reig(i)
542 lambda(i,2) = ieig(i)
551 IF ( test_qrdmd .AND. (k_traj == 1) )
THEN
556 CALL dgedmdq( scale, jobz, resids, wantq, wantr, &
557 jobref, whtsvd, m, n+1, f1, ldf, x, ldx, y, &
558 ldy, nrnk, tol, kq, reigq, ieigq, z, ldz, &
559 res, au, ldau, w, ldw, s, lds, wdummy, &
560 -1, idummy, -1, info )
562 ALLOCATE( iwork(liwork) )
563 lwork = int(wdummy(lwminopt))
564 ALLOCATE(work(lwork))
566 CALL dgedmdq( scale, jobz, resids, wantq, wantr, &
567 jobref, whtsvd, m, n+1, f1, ldf, x, ldx, y, &
568 ldy, nrnk, tol, kq, reigq, ieigq, z, ldz, &
569 res, au, ldau, w, ldw, s, lds, &
570 work, lwork, iwork, liwork, info )
572 singvqx(1:kq) = work(min(m,n+1)+1: min(m,n+1)+kq)
581 tmp = max(tmp, abs(singvx(i)-singvqx(i)) / &
584 svdiff = max( svdiff, tmp )
585 IF ( tmp > m*n*eps )
THEN
586 WRITE(*,*)
'FAILED! Something was wrong with the run.'
587 nfail_svdiff = nfail_svdiff + 1
589 write(*,*) j, singvx(j), singvqx(j)
595 IF ( lsame(wantq,
'Q') .AND. lsame(wantr,
'R') )
THEN
600 CALL dgemm(
'N',
'N', m, n+1, min(m,n+1), -one, f1, &
601 ldf, y, ldy, one, f2, ldf )
602 tmp_fqr =
dlange(
'F', m, n+1, f2, ldf, work ) / &
603 dlange(
'F', m, n+1, f, ldf, work )
604 IF ( tmp_fqr > tol2 )
THEN
605 WRITE(*,*)
'FAILED! Something was wrong with the run.'
606 nfail_f_qr = nfail_f_qr + 1
611 IF ( lsame(resids,
'R') )
THEN
615 CALL dgemm(
'N',
'N', m, kq, m, one, a, m, z, m, zero, y1,
621 IF ( ieigq(i) == zero )
THEN
623 CALL daxpy( m, -reigq(i), z(1,i), 1, y1(1,i), 1 )
625 res1(i) =
dnrm2( m, y1(1,i), 1)
639 CALL dgemm(
'N',
'N', m, 2, 2, -one, z(1,i), &
640 m, ab, 2, one, y1(1,i), m )
642 res1(i) =
dlange(
'F', m, 2, y1(1,i), m, &
650 tmp = max( tmp, abs(res(i) - res1(i)) * &
651 singvqx(k)/(anorm*singvqx(1)) )
653 tmp_rezq = max( tmp_rezq, tmp )
654 IF ( tmp > tol2 )
THEN
655 nfail_rezq = nfail_rezq + 1
656 WRITE(*,*)
'................ DGEDMDQ FAILED!', &
657 'Check the code for implementation errors.'
664 lambdaq(i,1) = reigq(i)
665 lambdaq(i,2) = ieigq(i)
728 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
729 WRITE(*,*)
' Test summary for DGEDMD :'
730 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
732 IF ( nfail_z_xv == 0 )
THEN
733 WRITE(*,*)
'>>>> Z - U*V test PASSED.'
735 WRITE(*,*)
'Z - U*V test FAILED ', nfail_z_xv,
' time(s)'
736 WRITE(*,*)
'Max error ||Z-U*V||_F was ', tmp_zxw
737 nfail_total = nfail_total + nfail_z_xv
739 IF ( nfail_au == 0 )
THEN
740 WRITE(*,*)
'>>>> A*U test PASSED. '
742 WRITE(*,*)
'A*U test FAILED ', nfail_au,
' time(s)'
743 WRITE(*,*)
'Max A*U test adjusted error measure was ', tmp_au
744 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
745 nfail_total = nfail_total + nfail_au
748 IF ( nfail_rez == 0 )
THEN
749 WRITE(*,*)
'>>>> Rezidual computation test PASSED.'
751 WRITE(*,*)
'Rezidual computation test FAILED ', nfail_rez,
'time(s)'
752 WRITE(*,*)
'Max residual computing test adjusted error measure was '
753 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
754 nfail_total = nfail_total + nfail_rez
757 IF ( nfail_total == 0 )
THEN
758 WRITE(*,*)
'>>>> DGEDMD :: ALL TESTS PASSED.'
760 WRITE(*,*) nfail_total,
'FAILURES!'
761 WRITE(*,*)
'>>>>>>>>>>>>>> DGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
764 IF ( test_qrdmd )
THEN
766 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
767 WRITE(*,*)
' Test summary for DGEDMDQ :'
768 WRITE(*,*)
'>>>>>>>>>>>>>>>>>>>>>>>>>>'
771 IF ( nfail_svdiff == 0 )
THEN
772 WRITE(*,*)
'>>>> DGEDMD and DGEDMDQ computed singular &
773 &values test PASSED.'
775 WRITE(*,*)
'DGEDMD and DGEDMDQ discrepancies in &
776 &the singular values unacceptable ', &
777 nfail_svdiff,
' times. Test FAILED.'
778 WRITE(*,*)
'The maximal discrepancy in the singular values (relative to the norm) was '
779 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
780 nfailq_total = nfailq_total + nfail_svdiff
783 IF ( nfail_f_qr == 0 )
THEN
784 WRITE(*,*)
'>>>> F - Q*R test PASSED.'
786 WRITE(*,*)
'F - Q*R test FAILED ', nfail_f_qr,
' time(s)'
787 WRITE(*,*)
'The largest relative residual was ', tmp_fqr
788 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
789 nfailq_total = nfailq_total + nfail_f_qr
792 IF ( nfail_rezq == 0 )
THEN
793 WRITE(*,*)
'>>>> Rezidual computation test PASSED.'
795 WRITE(*,*)
'Rezidual computation test FAILED ', nfail_rezq,
'time(s)'
796 WRITE(*,*)
'Max residual computing test adjusted error measure was '
797 WRITE(*,*)
'It should be up to O(M*N) times EPS, EPS = ', eps
798 nfailq_total = nfailq_total + nfail_rezq
801 IF ( nfailq_total == 0 )
THEN
802 WRITE(*,*)
'>>>>>>> DGEDMDQ :: ALL TESTS PASSED.'
804 WRITE(*,*) nfailq_total,
'FAILURES!'
805 WRITE(*,*)
'>>>>>>> DGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
811 WRITE(*,*)
'Test completed.'
subroutine dlatmr(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)
DLATMR
subroutine daxpy(n, da, dx, incx, dy, incy)
DAXPY
subroutine dgedmdq(jobs, jobz, jobr, jobq, jobt, jobf, whtsvd, m, n, f, ldf, x, ldx, y, ldy, nrnk, tol, k, reig, imeig, z, ldz, res, b, ldb, v, ldv, s, lds, work, lwork, iwork, liwork, info)
DGEDMDQ computes the Dynamic Mode Decomposition (DMD) for a pair of data snapshot matrices.
subroutine dgedmd(jobs, jobz, jobr, jobf, whtsvd, m, n, x, ldx, y, ldy, nrnk, tol, k, reig, imeig, z, ldz, res, b, ldb, w, ldw, s, lds, work, lwork, iwork, liwork, info)
DGEDMD 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 dgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
DGEMM
subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
DGEMV
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 dlange(norm, m, n, a, lda, work)
DLANGE returns the value of the 1-norm, Frobenius norm, infinity-norm, or the largest absolute value ...
subroutine dlarnv(idist, iseed, n, x)
DLARNV returns a vector of random numbers from a uniform or normal distribution.
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 dnrm2(n, x, incx)
DNRM2