LAPACK 3.12.0
LAPACK: Linear Algebra PACKage
Loading...
Searching...
No Matches
dchkdmd.f90
Go to the documentation of this file.
1! This is a test program for checking the implementations of
2! the implementations of the following subroutines
3!
4! DGEDMD for computation of the
5! Dynamic Mode Decomposition (DMD)
6! DGEDMDQ for computation of a
7! QR factorization based compressed DMD
8!
9! Developed and supported by:
10! ===========================
11! Developed and coded by Zlatko Drmac, Faculty of Science,
12! University of Zagreb; drmac@math.hr
13! In cooperation with
14! AIMdyn Inc., Santa Barbara, CA.
15! ========================================================
16! How to run the code (compiler, link info)
17! ========================================================
18! Compile as FORTRAN 90 (or later) and link with BLAS and
19! LAPACK libraries.
20! NOTE: The code is developed and tested on top of the
21! Intel MKL library (versions 2022.0.3 and 2022.2.0),
22! using the Intel Fortran compiler.
23!
24! For developers of the C++ implementation
25! ========================================================
26! See the LAPACK++ and Template Numerical Toolkit (TNT)
27!
28! Note on a development of the GPU HP implementation
29! ========================================================
30! Work in progress. See CUDA, MAGMA, SLATE.
31! NOTE: The four SVD subroutines used in this code are
32! included as a part of R&D and for the completeness.
33! This was also an opportunity to test those SVD codes.
34! If the scaling option is used all four are essentially
35! equally good. For implementations on HP platforms,
36! one can use whichever SVD is available.
37!... .........................................................
38! NOTE:
39! When using the Intel MKL 2022.0.3 the subroutine xGESVDQ
40! (optionally used in xGEDMD) may cause access violation
41! error for x = S, D, C, Z, but only if called with the
42! work space query. (At least in our Windows 10 MSVS 2019.)
43! The problem can be mitigated by downloading the source
44! code of xGESVDQ from the LAPACK repository and use it
45! localy instead of the one in the MKL. This seems to
46! indicate that the problem is indeed in the MKL.
47! This problem did not appear whith Intel MKL 2022.2.0.
48!
49! NOTE:
50! xGESDD seems to have a problem with workspace. In some
51! cases the length of the optimal workspace is returned
52! smaller than the minimal workspace, as specified in the
53! code. As a precaution, all optimal workspaces are
54! set as MAX(minimal, optimal).
55! Latest implementations of complex xGESDD have different
56! length of the real worksapce. We use max value over
57! two versions.
58!............................................................
59!............................................................
60!
61 PROGRAM dmd_test
62 use iso_fortran_env, only: real64
63 IMPLICIT NONE
64 integer, parameter :: WP = real64
65
66!............................................................
67 REAL(KIND=wp), PARAMETER :: one = 1.0_wp
68 REAL(KIND=wp), PARAMETER :: zero = 0.0_wp
69!............................................................
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,&
76 singvqx, work
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, &
83 tmp_ex, xnorm, ynorm
84!............................................................
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
94
95 LOGICAL TEST_QRDMD
96!..... external subroutines (BLAS and LAPACK)
97 EXTERNAL daxpy, dgeev, dgemm, dgemv, dlacpy, dlascl
98 EXTERNAL dlarnv, dlatmr
99!.....external subroutines DMD package, part 1
100! subroutines under test
101 EXTERNAL dgedmd, dgedmdq
102
103!..... external functions (BLAS and LAPACK)
104 EXTERNAL dlamch, dlange, dnrm2
105 REAL(KIND=wp) :: dlamch, dlange, dnrm2
106 EXTERNAL lsame
107 LOGICAL LSAME
108
109 INTRINSIC abs, int, min, max
110!............................................................
111
112 ! The test is always in pairs : ( DGEDMD and DGEDMDQ )
113 ! because the test includes comparing the results (in pairs).
114!.....................................................................................
115 test_qrdmd = .true. ! This code by default performs tests on DGEDMDQ
116 ! Since the QR factorizations based algorithm is designed for
117 ! single trajectory data, only single trajectory tests will
118 ! be performed with xGEDMDQ.
119 wantq = 'Q'
120 wantr = 'R'
121!.................................................................................
122
123 eps = dlamch( 'P' ) ! machine precision DP
124
125 ! Global counters of failures of some particular tests
126 nfail = 0
127 nfail_rez = 0
128 nfail_rezq = 0
129 nfail_z_xv = 0
130 nfail_f_qr = 0
131 nfail_au = 0
132 kdiff = 0
133 nfail_svdiff = 0
134 nfail_total = 0
135 nfailq_total = 0
136
137
138 DO lloop = 1, 4
139
140 WRITE(*,*) 'L Loop Index = ', lloop
141
142 ! Set the dimensions of the problem ...
143 WRITE(*,*) 'M = '
144 READ(*,*) m
145 WRITE(*,*) m
146 ! ... and the number of snapshots.
147 WRITE(*,*) 'N = '
148 READ(*,*) n
149 WRITE(*,*) n
150
151 ! ... Test the dimensions
152 IF ( ( min(m,n) == 0 ) .OR. ( m < n ) ) THEN
153 WRITE(*,*) 'Bad dimensions. Required: M >= N > 0.'
154 stop
155 END IF
156!.............
157 ! The seed inside the LLOOP so that each pass can be reproduced easily.
158
159 iseed(1) = 4
160 iseed(2) = 3
161 iseed(3) = 2
162 iseed(4) = 1
163
164 lda = m
165 ldf = m
166 ldx = max(m,n+1)
167 ldy = max(m,n+1)
168 ldw = n
169 ldz = m
170 ldau = max(m,n+1)
171 lds = n
172
173 tmp_zxw = zero
174 tmp_au = zero
175 tmp_rez = zero
176 tmp_rezq = zero
177 svdiff = zero
178 tmp_ex = zero
179
180 !
181 ! Test the subroutines on real data snapshots. All
182 ! computation is done in real arithmetic, even when
183 ! Koopman eigenvalues and modes are real.
184 !
185 ! Allocate memory space
186 ALLOCATE( a(lda,m) )
187 ALLOCATE( ac(lda,m) )
188 ALLOCATE( da(m) )
189 ALLOCATE( dl(m) )
190 ALLOCATE( f(ldf,n+1) )
191 ALLOCATE( f1(ldf,n+1) )
192 ALLOCATE( f2(ldf,n+1) )
193 ALLOCATE( x(ldx,n) )
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) )
200 ALLOCATE( z(ldz,n) )
201 ALLOCATE( z1(ldz,n) )
202 ALLOCATE( res(n) )
203 ALLOCATE( res1(n) )
204 ALLOCATE( resex(n) )
205 ALLOCATE( reig(n) )
206 ALLOCATE( ieig(n) )
207 ALLOCATE( reigq(n) )
208 ALLOCATE( ieigq(n) )
209 ALLOCATE( reiga(m) )
210 ALLOCATE( ieiga(m) )
211 ALLOCATE( va(lda,m) )
212 ALLOCATE( lambda(n,2) )
213 ALLOCATE( lambdaq(n,2) )
214 ALLOCATE( eiga(m,2) )
215 ALLOCATE( w(ldw,n) )
216 ALLOCATE( au(ldau,n) )
217 ALLOCATE( s(n,n) )
218
219 tol = m*eps
220 ! This mimics O(M*N)*EPS bound for accumulated roundoff error.
221 ! The factor 10 is somewhat arbitrary.
222 tol2 = 10*m*n*eps
223
224!.............
225
226 DO k_traj = 1, 2
227 ! Number of intial conditions in the simulation/trajectories (1 or 2)
228
229 cond = 1.0d8
230 dmax = 1.0d2
231 rsign = 'F'
232 grade = 'N'
233 model = 6
234 condl = 1.0d2
235 moder = 6
236 condr = 1.0d2
237 pivtng = 'N'
238
239 ! Loop over all parameter MODE values for ZLATMR (+1,..,+6)
240 DO mode = 1, 6
241
242 ALLOCATE( iwork(2*m) )
243 ALLOCATE(dr(n))
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 )
248 DEALLOCATE(iwork)
249 DEALLOCATE(dr)
250
251 lwork = 4*m+1
252 ALLOCATE(work(lwork))
253 ac = a
254 CALL dgeev( 'N','V', m, ac, m, reiga, ieiga, va, m, &
255 va, m, work, lwork, info ) ! LAPACK CALL
256 DEALLOCATE(work)
257 tmp = zero
258 DO i = 1, m
259 eiga(i,1) = reiga(i)
260 eiga(i,2) = ieiga(i)
261 tmp = max( tmp, sqrt(reiga(i)**2+ieiga(i)**2))
262 END DO
263
264 ! Scale A to have the desirable spectral radius.
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 )
267
268 ! Compute the norm of A
269 anorm = dlange( 'F', n, n, a, m, wdummy )
270
271 IF ( k_traj == 2 ) THEN
272 ! generate data with two inital conditions
273 CALL dlarnv(2, iseed, m, f1(1,1) )
274 f1(1:m,1) = 1.0e-10*f1(1:m,1)
275 DO i = 1, n/2
276 CALL dgemv( 'N', m, m, one, a, m, f1(1,i), 1, zero, &
277 f1(1,i+1), 1 )
278 END DO
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)
281
282 CALL dlarnv(2, iseed, m, f1(1,1) )
283 DO i = 1, n-n/2
284 CALL dgemv( 'N', m, m, one, a, m, f1(1,i), 1, zero, &
285 f1(1,i+1), 1 )
286 END DO
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)
289 ELSE
290 CALL dlarnv(2, iseed, m, f(1,1) )
291 DO i = 1, n
292 CALL dgemv( 'N', m, m, one, a, m, f(1,i), 1, zero, &
293 f(1,i+1), 1 )
294 END DO
295 x0(1:m,1:n) = f(1:m,1:n)
296 y0(1:m,1:n) = f(1:m,2:n+1)
297 END IF
298
299 xnorm = dlange( 'F', m, n, x0, ldx, wdummy )
300 ynorm = dlange( 'F', m, n, y0, ldx, wdummy )
301!............................................................
302
303 DO ijobz = 1, 4
304
305 SELECT CASE ( ijobz )
306 CASE(1)
307 jobz = 'V' ! Ritz vectors will be computed
308 resids = 'R' ! Residuals will be computed
309 CASE(2)
310 jobz = 'V'
311 resids = 'N'
312 CASE(3)
313 jobz = 'F' ! Ritz vectors in factored form
314 resids = 'N'
315 CASE(4)
316 jobz = 'N'
317 resids = 'N'
318 END SELECT
319
320 DO ijobref = 1, 3
321
322 SELECT CASE ( ijobref )
323 CASE(1)
324 jobref = 'R' ! Data for refined Ritz vectors
325 CASE(2)
326 jobref = 'E' ! Exact DMD vectors
327 CASE(3)
328 jobref = 'N'
329 END SELECT
330
331 DO iscale = 1, 4
332
333 SELECT CASE ( iscale )
334 CASE(1)
335 scale = 'S' ! X data normalized
336 CASE(2)
337 scale = 'C' ! X normalized, consist. check
338 CASE(3)
339 scale = 'Y' ! Y data normalized
340 CASE(4)
341 scale = 'N'
342 END SELECT
343
344 DO inrnk = -1, -2, -1
345 ! Two truncation strategies. The "-2" case for R&D
346 ! purposes only - it uses possibly low accuracy small
347 ! singular values, in which case the formulas used in
348 ! the DMD are highly sensitive.
349 nrnk = inrnk
350
351 DO iwhtsvd = 1, 4
352 ! Check all four options to compute the POD basis
353 ! via the SVD.
354 whtsvd = iwhtsvd
355
356 DO lwminopt = 1, 2
357 ! Workspace query for the minimal (1) and for the optimal
358 ! (2) workspace lengths determined by workspace query.
359
360 x(1:m,1:n) = x0(1:m,1:n)
361 y(1:m,1:n) = y0(1:m,1:n)
362
363 ! DGEDMD: Workspace query and workspace allocation
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, &
367 idummy, -1, info )
368
369 liwork = idummy(1)
370 ALLOCATE( iwork(liwork) )
371 lwork = int(wdummy(lwminopt))
372 ALLOCATE( work(lwork) )
373
374 ! DGEDMD test: CALL DGEDMD
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 )
379
380 singvx(1:n) = work(1:n)
381
382 !...... DGEDMD check point
383 IF ( lsame(jobz,'V') ) THEN
384 ! Check that Z = X*W, on return from DGEDMD
385 ! This checks that the returned aigenvectors in Z are
386 ! the product of the SVD'POD basis returned in X
387 ! and the eigenvectors of the rayleigh quotient
388 ! returned in W
389 CALL dgemm( 'N', 'N', m, k, k, one, x, ldx, w, ldw, &
390 zero, z1, ldz )
391 tmp = zero
392 DO i = 1, k
393 CALL daxpy( m, -one, z(1,i), 1, z1(1,i), 1)
394 tmp = max(tmp, dnrm2( m, z1(1,i), 1 ) )
395 END DO
396 tmp_zxw = max(tmp_zxw, tmp )
397
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
405 END IF
406
407 END IF
408
409 !...... DGEDMD check point
410 IF ( lsame(jobref,'R') ) THEN
411 ! The matrix A*U is returned for computing refined Ritz vectors.
412 ! Check that A*U is computed correctly using the formula
413 ! A*U = Y * V * inv(SIGMA). This depends on the
414 ! accuracy in the computed singular values and vectors of X.
415 ! See the paper for an error analysis.
416 ! Note that the left singular vectors of the input matrix X
417 ! are returned in the array X.
418 CALL dgemm( 'N', 'N', m, k, m, one, a, lda, x, ldx, &
419 zero, z1, ldz )
420 tmp = zero
421 DO i = 1, k
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)) )
425 END DO
426 tmp_au = max( tmp_au, tmp )
427
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
435 END IF
436
437 ELSEIF ( lsame(jobref,'E') ) THEN
438 ! The unscaled vectors of the Exact DMD are computed.
439 ! This option is included for the sake of completeness,
440 ! for users who prefer the Exact DMD vectors. The
441 ! returned vectors are in the real form, in the same way
442 ! as the Ritz vectors. Here we just save the vectors
443 ! and test them separately using a Matlab script.
444
445 CALL dgemm( 'N', 'N', m, k, m, one, a, lda, au, ldau, zero, y1, m )
446 i=1
447 DO WHILE ( i <= k )
448 IF ( ieig(i) == zero ) THEN
449 ! have a real eigenvalue with real eigenvector
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)
452 i = i + 1
453 ELSE
454 ! Have a complex conjugate pair
455 ! REIG(i) +- sqrt(-1)*IMEIG(i).
456 ! Since all computation is done in real
457 ! arithmetic, the formula for the residual
458 ! is recast for real representation of the
459 ! complex conjugate eigenpair. See the
460 ! description of RES.
461 ab(1,1) = reig(i)
462 ab(2,1) = -ieig(i)
463 ab(1,2) = ieig(i)
464 ab(2,2) = reig(i)
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, &
469 work )
470 resex(i+1) = resex(i)
471 i = i + 2
472 END IF
473 END DO
474
475 END IF
476
477 !...... DGEDMD check point
478 IF ( lsame(resids, 'R') ) THEN
479 ! Compare the residuals returned by DGEDMD with the
480 ! explicitly computed residuals using the matrix A.
481 ! Compute explicitly Y1 = A*Z
482 CALL dgemm( 'N', 'N', m, k, m, one, a, lda, z, ldz, zero, y1, m )
483 ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
484 ! of the invariant subspaces that correspond to complex conjugate
485 ! pairs of eigencalues. (See the description of Z in DGEDMD,)
486 i = 1
487 DO WHILE ( i <= k )
488 IF ( ieig(i) == zero ) THEN
489 ! have a real eigenvalue with real eigenvector
490 CALL daxpy( m, -reig(i), z(1,i), 1, y1(1,i), 1 )
491 res1(i) = dnrm2( m, y1(1,i), 1)
492 i = i + 1
493 ELSE
494 ! Have a complex conjugate pair
495 ! REIG(i) +- sqrt(-1)*IMEIG(i).
496 ! Since all computation is done in real
497 ! arithmetic, the formula for the residual
498 ! is recast for real representation of the
499 ! complex conjugate eigenpair. See the
500 ! description of RES.
501 ab(1,1) = reig(i)
502 ab(2,1) = -ieig(i)
503 ab(1,2) = ieig(i)
504 ab(2,2) = reig(i)
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, &
508 work )
509 res1(i+1) = res1(i)
510 i = i + 2
511 END IF
512 END DO
513 tmp = zero
514 DO i = 1, k
515 tmp = max( tmp, abs(res(i) - res1(i)) * &
516 singvx(k)/(anorm*singvx(1)) )
517 END DO
518 tmp_rez = max( tmp_rez, tmp )
519
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
527 END IF
528
529 IF ( lsame(jobref,'E') ) THEN
530 tmp = zero
531 DO i = 1, k
532 tmp = max( tmp, abs(res1(i) - resex(i))/(res1(i)+resex(i)) )
533 END DO
534 tmp_ex = max(tmp_ex,tmp)
535 END IF
536
537 END IF
538
539 !..... store the results for inspection
540 DO i = 1, k
541 lambda(i,1) = reig(i)
542 lambda(i,2) = ieig(i)
543 END DO
544
545 DEALLOCATE(iwork)
546 DEALLOCATE(work)
547
548 !======================================================================
549 ! Now test the DGEDMDQ
550 !======================================================================
551 IF ( test_qrdmd .AND. (k_traj == 1) ) THEN
552 rjobdata(2) = 1
553 f1 = f
554
555 ! DGEDMDQ test: Workspace query and workspace allocation
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 )
561 liwork = idummy(1)
562 ALLOCATE( iwork(liwork) )
563 lwork = int(wdummy(lwminopt))
564 ALLOCATE(work(lwork))
565 ! DGEDMDQ test: CALL DGEDMDQ
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 )
571
572 singvqx(1:kq) = work(min(m,n+1)+1: min(m,n+1)+kq)
573
574 !..... DGEDMDQ check point
575 IF ( kq /= k ) THEN
576 kdiff = kdiff+1
577 END IF
578
579 tmp = zero
580 DO i = 1, min(k, kq)
581 tmp = max(tmp, abs(singvx(i)-singvqx(i)) / &
582 singvx(1) )
583 END DO
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
588 DO j =1, 3
589 write(*,*) j, singvx(j), singvqx(j)
590 read(*,*)
591 END DO
592 END IF
593
594 !..... DGEDMDQ check point
595 IF ( lsame(wantq,'Q') .AND. lsame(wantr,'R') ) THEN
596 ! Check that the QR factors are computed and returned
597 ! as requested. The residual ||F-Q*R||_F / ||F||_F
598 ! is compared to M*N*EPS.
599 f2 = f
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
607 END IF
608 END IF
609
610 !..... DGEDMDQ check point
611 IF ( lsame(resids, 'R') ) THEN
612 ! Compare the residuals returned by DGEDMDQ with the
613 ! explicitly computed residuals using the matrix A.
614 ! Compute explicitly Y1 = A*Z
615 CALL dgemm( 'N', 'N', m, kq, m, one, a, m, z, m, zero, y1, m )
616 ! ... and then A*Z(:,i) - LAMBDA(i)*Z(:,i), using the real forms
617 ! of the invariant subspaces that correspond to complex conjugate
618 ! pairs of eigencalues. (See the description of Z in DGEDMDQ)
619 i = 1
620 DO WHILE ( i <= kq )
621 IF ( ieigq(i) == zero ) THEN
622 ! have a real eigenvalue with real eigenvector
623 CALL daxpy( m, -reigq(i), z(1,i), 1, y1(1,i), 1 )
624 ! Y(1:M,i) = Y(1:M,i) - REIG(i)*Z(1:M,i)
625 res1(i) = dnrm2( m, y1(1,i), 1)
626 i = i + 1
627 ELSE
628 ! Have a complex conjugate pair
629 ! REIG(i) +- sqrt(-1)*IMEIG(i).
630 ! Since all computation is done in real
631 ! arithmetic, the formula for the residual
632 ! is recast for real representation of the
633 ! complex conjugate eigenpair. See the
634 ! description of RES.
635 ab(1,1) = reigq(i)
636 ab(2,1) = -ieigq(i)
637 ab(1,2) = ieigq(i)
638 ab(2,2) = reigq(i)
639 CALL dgemm( 'N', 'N', m, 2, 2, -one, z(1,i), &
640 m, ab, 2, one, y1(1,i), m ) ! BLAS CALL
641 ! Y(1:M,i:i+1) = Y(1:M,i:i+1) - Z(1:M,i:i+1) * AB ! INTRINSIC
642 res1(i) = dlange( 'F', m, 2, y1(1,i), m, &
643 work ) ! LAPACK CALL
644 res1(i+1) = res1(i)
645 i = i + 2
646 END IF
647 END DO
648 tmp = zero
649 DO i = 1, kq
650 tmp = max( tmp, abs(res(i) - res1(i)) * &
651 singvqx(k)/(anorm*singvqx(1)) )
652 END DO
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.'
658 stop
659 END IF
660
661 END IF
662
663 DO i = 1, kq
664 lambdaq(i,1) = reigq(i)
665 lambdaq(i,2) = ieigq(i)
666 END DO
667
668 DEALLOCATE(work)
669 DEALLOCATE(iwork)
670 END IF ! TEST_QRDMD
671!======================================================================
672
673 END DO ! LWMINOPT
674 !write(*,*) 'LWMINOPT loop completed'
675 END DO ! WHTSVD LOOP
676 !write(*,*) 'WHTSVD loop completed'
677 END DO ! NRNK LOOP
678 !write(*,*) 'NRNK loop completed'
679 END DO ! SCALE LOOP
680 !write(*,*) 'SCALE loop completed'
681 END DO ! JOBF LOOP
682 !write(*,*) 'JOBREF loop completed'
683 END DO ! JOBZ LOOP
684 !write(*,*) 'JOBZ loop completed'
685
686 END DO ! MODE -6:6
687 !write(*,*) 'MODE loop completed'
688 END DO ! 1 or 2 trajectories
689 !write(*,*) 'trajectories loop completed'
690
691 DEALLOCATE(a)
692 DEALLOCATE(ac)
693 DEALLOCATE(da)
694 DEALLOCATE(dl)
695 DEALLOCATE(f)
696 DEALLOCATE(f1)
697 DEALLOCATE(f2)
698 DEALLOCATE(x)
699 DEALLOCATE(x0)
700 DEALLOCATE(singvx)
701 DEALLOCATE(singvqx)
702 DEALLOCATE(y)
703 DEALLOCATE(y0)
704 DEALLOCATE(y1)
705 DEALLOCATE(z)
706 DEALLOCATE(z1)
707 DEALLOCATE(res)
708 DEALLOCATE(res1)
709 DEALLOCATE(resex)
710 DEALLOCATE(reig)
711 DEALLOCATE(ieig)
712 DEALLOCATE(reigq)
713 DEALLOCATE(ieigq)
714 DEALLOCATE(reiga)
715 DEALLOCATE(ieiga)
716 DEALLOCATE(va)
717 DEALLOCATE(lambda)
718 DEALLOCATE(lambdaq)
719 DEALLOCATE(eiga)
720 DEALLOCATE(w)
721 DEALLOCATE(au)
722 DEALLOCATE(s)
723
724!............................................................
725 ! Generate random M-by-M matrix A. Use DLATMR from
726 END DO ! LLOOP
727
728 WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
729 WRITE(*,*) ' Test summary for DGEDMD :'
730 WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
731 WRITE(*,*)
732 IF ( nfail_z_xv == 0 ) THEN
733 WRITE(*,*) '>>>> Z - U*V test PASSED.'
734 ELSE
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
738 END IF
739 IF ( nfail_au == 0 ) THEN
740 WRITE(*,*) '>>>> A*U test PASSED. '
741 ELSE
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
746 END IF
747
748 IF ( nfail_rez == 0 ) THEN
749 WRITE(*,*) '>>>> Rezidual computation test PASSED.'
750 ELSE
751 WRITE(*,*) 'Rezidual computation test FAILED ', nfail_rez, 'time(s)'
752 WRITE(*,*) 'Max residual computing test adjusted error measure was ', tmp_rez
753 WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', eps
754 nfail_total = nfail_total + nfail_rez
755 END IF
756
757 IF ( nfail_total == 0 ) THEN
758 WRITE(*,*) '>>>> DGEDMD :: ALL TESTS PASSED.'
759 ELSE
760 WRITE(*,*) nfail_total, 'FAILURES!'
761 WRITE(*,*) '>>>>>>>>>>>>>> DGEDMD :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
762 END IF
763
764 IF ( test_qrdmd ) THEN
765 WRITE(*,*)
766 WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
767 WRITE(*,*) ' Test summary for DGEDMDQ :'
768 WRITE(*,*) '>>>>>>>>>>>>>>>>>>>>>>>>>>'
769 WRITE(*,*)
770
771 IF ( nfail_svdiff == 0 ) THEN
772 WRITE(*,*) '>>>> DGEDMD and DGEDMDQ computed singular &
773 &values test PASSED.'
774 ELSE
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 ', svdiff
779 WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', eps
780 nfailq_total = nfailq_total + nfail_svdiff
781 END IF
782
783 IF ( nfail_f_qr == 0 ) THEN
784 WRITE(*,*) '>>>> F - Q*R test PASSED.'
785 ELSE
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
790 END IF
791
792 IF ( nfail_rezq == 0 ) THEN
793 WRITE(*,*) '>>>> Rezidual computation test PASSED.'
794 ELSE
795 WRITE(*,*) 'Rezidual computation test FAILED ', nfail_rezq, 'time(s)'
796 WRITE(*,*) 'Max residual computing test adjusted error measure was ', tmp_rezq
797 WRITE(*,*) 'It should be up to O(M*N) times EPS, EPS = ', eps
798 nfailq_total = nfailq_total + nfail_rezq
799 END IF
800
801 IF ( nfailq_total == 0 ) THEN
802 WRITE(*,*) '>>>>>>> DGEDMDQ :: ALL TESTS PASSED.'
803 ELSE
804 WRITE(*,*) nfailq_total, 'FAILURES!'
805 WRITE(*,*) '>>>>>>> DGEDMDQ :: TESTS FAILED. CHECK THE IMPLEMENTATION.'
806 END IF
807
808 END IF
809
810 WRITE(*,*)
811 WRITE(*,*) 'Test completed.'
812 stop
813 END
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
Definition dlatmr.f:471
subroutine daxpy(n, da, dx, incx, dy, incy)
DAXPY
Definition daxpy.f:89
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.
Definition dgedmdq.f90:576
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.
Definition dgedmd.f90:536
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
Definition dgeev.f:192
subroutine dgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
DGEMM
Definition dgemm.f:188
subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
DGEMV
Definition dgemv.f:158
subroutine dlacpy(uplo, m, n, a, lda, b, ldb)
DLACPY copies all or part of one two-dimensional array to another.
Definition dlacpy.f:103
double precision function dlamch(cmach)
DLAMCH
Definition dlamch.f:69
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 ...
Definition dlange.f:114
subroutine dlarnv(idist, iseed, n, x)
DLARNV returns a vector of random numbers from a uniform or normal distribution.
Definition dlarnv.f:97
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.
Definition dlascl.f:143
logical function lsame(ca, cb)
LSAME
Definition lsame.f:48
real(wp) function dnrm2(n, x, incx)
DNRM2
Definition dnrm2.f90:89