You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

dgedmdq.f90 32 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. SUBROUTINE DGEDMDQ( JOBS, JOBZ, JOBR, JOBQ, JOBT, JOBF, &
  2. WHTSVD, M, N, F, LDF, X, LDX, Y, &
  3. LDY, NRNK, TOL, K, REIG, IMEIG, &
  4. Z, LDZ, RES, B, LDB, V, LDV, &
  5. S, LDS, WORK, LWORK, IWORK, LIWORK, INFO )
  6. ! March 2023
  7. !.....
  8. USE iso_fortran_env
  9. IMPLICIT NONE
  10. INTEGER, PARAMETER :: WP = real64
  11. !.....
  12. ! Scalar arguments
  13. CHARACTER, INTENT(IN) :: JOBS, JOBZ, JOBR, JOBQ, &
  14. JOBT, JOBF
  15. INTEGER, INTENT(IN) :: WHTSVD, M, N, LDF, LDX, &
  16. LDY, NRNK, LDZ, LDB, LDV, &
  17. LDS, LWORK, LIWORK
  18. INTEGER, INTENT(OUT) :: INFO, K
  19. REAL(KIND=WP), INTENT(IN) :: TOL
  20. ! Array arguments
  21. REAL(KIND=WP), INTENT(INOUT) :: F(LDF,*)
  22. REAL(KIND=WP), INTENT(OUT) :: X(LDX,*), Y(LDY,*), &
  23. Z(LDZ,*), B(LDB,*), &
  24. V(LDV,*), S(LDS,*)
  25. REAL(KIND=WP), INTENT(OUT) :: REIG(*), IMEIG(*), &
  26. RES(*)
  27. REAL(KIND=WP), INTENT(OUT) :: WORK(*)
  28. INTEGER, INTENT(OUT) :: IWORK(*)
  29. !.....
  30. ! Purpose
  31. ! =======
  32. ! DGEDMDQ computes the Dynamic Mode Decomposition (DMD) for
  33. ! a pair of data snapshot matrices, using a QR factorization
  34. ! based compression of the data. For the input matrices
  35. ! X and Y such that Y = A*X with an unaccessible matrix
  36. ! A, DGEDMDQ computes a certain number of Ritz pairs of A using
  37. ! the standard Rayleigh-Ritz extraction from a subspace of
  38. ! range(X) that is determined using the leading left singular
  39. ! vectors of X. Optionally, DGEDMDQ returns the residuals
  40. ! of the computed Ritz pairs, the information needed for
  41. ! a refinement of the Ritz vectors, or the eigenvectors of
  42. ! the Exact DMD.
  43. ! For further details see the references listed
  44. ! below. For more details of the implementation see [3].
  45. !
  46. ! References
  47. ! ==========
  48. ! [1] P. Schmid: Dynamic mode decomposition of numerical
  49. ! and experimental data,
  50. ! Journal of Fluid Mechanics 656, 5-28, 2010.
  51. ! [2] Z. Drmac, I. Mezic, R. Mohr: Data driven modal
  52. ! decompositions: analysis and enhancements,
  53. ! SIAM J. on Sci. Comp. 40 (4), A2253-A2285, 2018.
  54. ! [3] Z. Drmac: A LAPACK implementation of the Dynamic
  55. ! Mode Decomposition I. Technical report. AIMDyn Inc.
  56. ! and LAPACK Working Note 298.
  57. ! [4] J. Tu, C. W. Rowley, D. M. Luchtenburg, S. L.
  58. ! Brunton, N. Kutz: On Dynamic Mode Decomposition:
  59. ! Theory and Applications, Journal of Computational
  60. ! Dynamics 1(2), 391 -421, 2014.
  61. !
  62. ! Developed and supported by:
  63. ! ===========================
  64. ! Developed and coded by Zlatko Drmac, Faculty of Science,
  65. ! University of Zagreb; drmac@math.hr
  66. ! In cooperation with
  67. ! AIMdyn Inc., Santa Barbara, CA.
  68. ! and supported by
  69. ! - DARPA SBIR project "Koopman Operator-Based Forecasting
  70. ! for Nonstationary Processes from Near-Term, Limited
  71. ! Observational Data" Contract No: W31P4Q-21-C-0007
  72. ! - DARPA PAI project "Physics-Informed Machine Learning
  73. ! Methodologies" Contract No: HR0011-18-9-0033
  74. ! - DARPA MoDyL project "A Data-Driven, Operator-Theoretic
  75. ! Framework for Space-Time Analysis of Process Dynamics"
  76. ! Contract No: HR0011-16-C-0116
  77. ! Any opinions, findings and conclusions or recommendations
  78. ! expressed in this material are those of the author and
  79. ! do not necessarily reflect the views of the DARPA SBIR
  80. ! Program Office.
  81. !============================================================
  82. ! Distribution Statement A:
  83. ! Approved for Public Release, Distribution Unlimited.
  84. ! Cleared by DARPA on September 29, 2022
  85. !============================================================
  86. !......................................................................
  87. ! Arguments
  88. ! =========
  89. ! JOBS (input) CHARACTER*1
  90. ! Determines whether the initial data snapshots are scaled
  91. ! by a diagonal matrix. The data snapshots are the columns
  92. ! of F. The leading N-1 columns of F are denoted X and the
  93. ! trailing N-1 columns are denoted Y.
  94. ! 'S' :: The data snapshots matrices X and Y are multiplied
  95. ! with a diagonal matrix D so that X*D has unit
  96. ! nonzero columns (in the Euclidean 2-norm)
  97. ! 'C' :: The snapshots are scaled as with the 'S' option.
  98. ! If it is found that an i-th column of X is zero
  99. ! vector and the corresponding i-th column of Y is
  100. ! non-zero, then the i-th column of Y is set to
  101. ! zero and a warning flag is raised.
  102. ! 'Y' :: The data snapshots matrices X and Y are multiplied
  103. ! by a diagonal matrix D so that Y*D has unit
  104. ! nonzero columns (in the Euclidean 2-norm)
  105. ! 'N' :: No data scaling.
  106. !.....
  107. ! JOBZ (input) CHARACTER*1
  108. ! Determines whether the eigenvectors (Koopman modes) will
  109. ! be computed.
  110. ! 'V' :: The eigenvectors (Koopman modes) will be computed
  111. ! and returned in the matrix Z.
  112. ! See the description of Z.
  113. ! 'F' :: The eigenvectors (Koopman modes) will be returned
  114. ! in factored form as the product Z*V, where Z
  115. ! is orthonormal and V contains the eigenvectors
  116. ! of the corresponding Rayleigh quotient.
  117. ! See the descriptions of F, V, Z.
  118. ! 'Q' :: The eigenvectors (Koopman modes) will be returned
  119. ! in factored form as the product Q*Z, where Z
  120. ! contains the eigenvectors of the compression of the
  121. ! underlying discretized operator onto the span of
  122. ! the data snapshots. See the descriptions of F, V, Z.
  123. ! Q is from the initial QR factorization.
  124. ! 'N' :: The eigenvectors are not computed.
  125. !.....
  126. ! JOBR (input) CHARACTER*1
  127. ! Determines whether to compute the residuals.
  128. ! 'R' :: The residuals for the computed eigenpairs will
  129. ! be computed and stored in the array RES.
  130. ! See the description of RES.
  131. ! For this option to be legal, JOBZ must be 'V'.
  132. ! 'N' :: The residuals are not computed.
  133. !.....
  134. ! JOBQ (input) CHARACTER*1
  135. ! Specifies whether to explicitly compute and return the
  136. ! orthogonal matrix from the QR factorization.
  137. ! 'Q' :: The matrix Q of the QR factorization of the data
  138. ! snapshot matrix is computed and stored in the
  139. ! array F. See the description of F.
  140. ! 'N' :: The matrix Q is not explicitly computed.
  141. !.....
  142. ! JOBT (input) CHARACTER*1
  143. ! Specifies whether to return the upper triangular factor
  144. ! from the QR factorization.
  145. ! 'R' :: The matrix R of the QR factorization of the data
  146. ! snapshot matrix F is returned in the array Y.
  147. ! See the description of Y and Further details.
  148. ! 'N' :: The matrix R is not returned.
  149. !.....
  150. ! JOBF (input) CHARACTER*1
  151. ! Specifies whether to store information needed for post-
  152. ! processing (e.g. computing refined Ritz vectors)
  153. ! 'R' :: The matrix needed for the refinement of the Ritz
  154. ! vectors is computed and stored in the array B.
  155. ! See the description of B.
  156. ! 'E' :: The unscaled eigenvectors of the Exact DMD are
  157. ! computed and returned in the array B. See the
  158. ! description of B.
  159. ! 'N' :: No eigenvector refinement data is computed.
  160. ! To be useful on exit, this option needs JOBQ='Q'.
  161. !.....
  162. ! WHTSVD (input) INTEGER, WHSTVD in { 1, 2, 3, 4 }
  163. ! Allows for a selection of the SVD algorithm from the
  164. ! LAPACK library.
  165. ! 1 :: DGESVD (the QR SVD algorithm)
  166. ! 2 :: DGESDD (the Divide and Conquer algorithm; if enough
  167. ! workspace available, this is the fastest option)
  168. ! 3 :: DGESVDQ (the preconditioned QR SVD ; this and 4
  169. ! are the most accurate options)
  170. ! 4 :: DGEJSV (the preconditioned Jacobi SVD; this and 3
  171. ! are the most accurate options)
  172. ! For the four methods above, a significant difference in
  173. ! the accuracy of small singular values is possible if
  174. ! the snapshots vary in norm so that X is severely
  175. ! ill-conditioned. If small (smaller than EPS*||X||)
  176. ! singular values are of interest and JOBS=='N', then
  177. ! the options (3, 4) give the most accurate results, where
  178. ! the option 4 is slightly better and with stronger
  179. ! theoretical background.
  180. ! If JOBS=='S', i.e. the columns of X will be normalized,
  181. ! then all methods give nearly equally accurate results.
  182. !.....
  183. ! M (input) INTEGER, M >= 0
  184. ! The state space dimension (the number of rows of F).
  185. !.....
  186. ! N (input) INTEGER, 0 <= N <= M
  187. ! The number of data snapshots from a single trajectory,
  188. ! taken at equidistant discrete times. This is the
  189. ! number of columns of F.
  190. !.....
  191. ! F (input/output) REAL(KIND=WP) M-by-N array
  192. ! > On entry,
  193. ! the columns of F are the sequence of data snapshots
  194. ! from a single trajectory, taken at equidistant discrete
  195. ! times. It is assumed that the column norms of F are
  196. ! in the range of the normalized floating point numbers.
  197. ! < On exit,
  198. ! If JOBQ == 'Q', the array F contains the orthogonal
  199. ! matrix/factor of the QR factorization of the initial
  200. ! data snapshots matrix F. See the description of JOBQ.
  201. ! If JOBQ == 'N', the entries in F strictly below the main
  202. ! diagonal contain, column-wise, the information on the
  203. ! Householder vectors, as returned by DGEQRF. The
  204. ! remaining information to restore the orthogonal matrix
  205. ! of the initial QR factorization is stored in WORK(1:N).
  206. ! See the description of WORK.
  207. !.....
  208. ! LDF (input) INTEGER, LDF >= M
  209. ! The leading dimension of the array F.
  210. !.....
  211. ! X (workspace/output) REAL(KIND=WP) MIN(M,N)-by-(N-1) array
  212. ! X is used as workspace to hold representations of the
  213. ! leading N-1 snapshots in the orthonormal basis computed
  214. ! in the QR factorization of F.
  215. ! On exit, the leading K columns of X contain the leading
  216. ! K left singular vectors of the above described content
  217. ! of X. To lift them to the space of the left singular
  218. ! vectors U(:,1:K)of the input data, pre-multiply with the
  219. ! Q factor from the initial QR factorization.
  220. ! See the descriptions of F, K, V and Z.
  221. !.....
  222. ! LDX (input) INTEGER, LDX >= N
  223. ! The leading dimension of the array X.
  224. !.....
  225. ! Y (workspace/output) REAL(KIND=WP) MIN(M,N)-by-(N-1) array
  226. ! Y is used as workspace to hold representations of the
  227. ! trailing N-1 snapshots in the orthonormal basis computed
  228. ! in the QR factorization of F.
  229. ! On exit,
  230. ! If JOBT == 'R', Y contains the MIN(M,N)-by-N upper
  231. ! triangular factor from the QR factorization of the data
  232. ! snapshot matrix F.
  233. !.....
  234. ! LDY (input) INTEGER , LDY >= N
  235. ! The leading dimension of the array Y.
  236. !.....
  237. ! NRNK (input) INTEGER
  238. ! Determines the mode how to compute the numerical rank,
  239. ! i.e. how to truncate small singular values of the input
  240. ! matrix X. On input, if
  241. ! NRNK = -1 :: i-th singular value sigma(i) is truncated
  242. ! if sigma(i) <= TOL*sigma(1)
  243. ! This option is recommended.
  244. ! NRNK = -2 :: i-th singular value sigma(i) is truncated
  245. ! if sigma(i) <= TOL*sigma(i-1)
  246. ! This option is included for R&D purposes.
  247. ! It requires highly accurate SVD, which
  248. ! may not be feasible.
  249. ! The numerical rank can be enforced by using positive
  250. ! value of NRNK as follows:
  251. ! 0 < NRNK <= N-1 :: at most NRNK largest singular values
  252. ! will be used. If the number of the computed nonzero
  253. ! singular values is less than NRNK, then only those
  254. ! nonzero values will be used and the actually used
  255. ! dimension is less than NRNK. The actual number of
  256. ! the nonzero singular values is returned in the variable
  257. ! K. See the description of K.
  258. !.....
  259. ! TOL (input) REAL(KIND=WP), 0 <= TOL < 1
  260. ! The tolerance for truncating small singular values.
  261. ! See the description of NRNK.
  262. !.....
  263. ! K (output) INTEGER, 0 <= K <= N
  264. ! The dimension of the SVD/POD basis for the leading N-1
  265. ! data snapshots (columns of F) and the number of the
  266. ! computed Ritz pairs. The value of K is determined
  267. ! according to the rule set by the parameters NRNK and
  268. ! TOL. See the descriptions of NRNK and TOL.
  269. !.....
  270. ! REIG (output) REAL(KIND=WP) (N-1)-by-1 array
  271. ! The leading K (K<=N) entries of REIG contain
  272. ! the real parts of the computed eigenvalues
  273. ! REIG(1:K) + sqrt(-1)*IMEIG(1:K).
  274. ! See the descriptions of K, IMEIG, Z.
  275. !.....
  276. ! IMEIG (output) REAL(KIND=WP) (N-1)-by-1 array
  277. ! The leading K (K<N) entries of REIG contain
  278. ! the imaginary parts of the computed eigenvalues
  279. ! REIG(1:K) + sqrt(-1)*IMEIG(1:K).
  280. ! The eigenvalues are determined as follows:
  281. ! If IMEIG(i) == 0, then the corresponding eigenvalue is
  282. ! real, LAMBDA(i) = REIG(i).
  283. ! If IMEIG(i)>0, then the corresponding complex
  284. ! conjugate pair of eigenvalues reads
  285. ! LAMBDA(i) = REIG(i) + sqrt(-1)*IMAG(i)
  286. ! LAMBDA(i+1) = REIG(i) - sqrt(-1)*IMAG(i)
  287. ! That is, complex conjugate pairs have consequtive
  288. ! indices (i,i+1), with the positive imaginary part
  289. ! listed first.
  290. ! See the descriptions of K, REIG, Z.
  291. !.....
  292. ! Z (workspace/output) REAL(KIND=WP) M-by-(N-1) array
  293. ! If JOBZ =='V' then
  294. ! Z contains real Ritz vectors as follows:
  295. ! If IMEIG(i)=0, then Z(:,i) is an eigenvector of
  296. ! the i-th Ritz value.
  297. ! If IMEIG(i) > 0 (and IMEIG(i+1) < 0) then
  298. ! [Z(:,i) Z(:,i+1)] span an invariant subspace and
  299. ! the Ritz values extracted from this subspace are
  300. ! REIG(i) + sqrt(-1)*IMEIG(i) and
  301. ! REIG(i) - sqrt(-1)*IMEIG(i).
  302. ! The corresponding eigenvectors are
  303. ! Z(:,i) + sqrt(-1)*Z(:,i+1) and
  304. ! Z(:,i) - sqrt(-1)*Z(:,i+1), respectively.
  305. ! If JOBZ == 'F', then the above descriptions hold for
  306. ! the columns of Z*V, where the columns of V are the
  307. ! eigenvectors of the K-by-K Rayleigh quotient, and Z is
  308. ! orthonormal. The columns of V are similarly structured:
  309. ! If IMEIG(i) == 0 then Z*V(:,i) is an eigenvector, and if
  310. ! IMEIG(i) > 0 then Z*V(:,i)+sqrt(-1)*Z*V(:,i+1) and
  311. ! Z*V(:,i)-sqrt(-1)*Z*V(:,i+1)
  312. ! are the eigenvectors of LAMBDA(i), LAMBDA(i+1).
  313. ! See the descriptions of REIG, IMEIG, X and V.
  314. !.....
  315. ! LDZ (input) INTEGER , LDZ >= M
  316. ! The leading dimension of the array Z.
  317. !.....
  318. ! RES (output) REAL(KIND=WP) (N-1)-by-1 array
  319. ! RES(1:K) contains the residuals for the K computed
  320. ! Ritz pairs.
  321. ! If LAMBDA(i) is real, then
  322. ! RES(i) = || A * Z(:,i) - LAMBDA(i)*Z(:,i))||_2.
  323. ! If [LAMBDA(i), LAMBDA(i+1)] is a complex conjugate pair
  324. ! then
  325. ! RES(i)=RES(i+1) = || A * Z(:,i:i+1) - Z(:,i:i+1) *B||_F
  326. ! where B = [ real(LAMBDA(i)) imag(LAMBDA(i)) ]
  327. ! [-imag(LAMBDA(i)) real(LAMBDA(i)) ].
  328. ! It holds that
  329. ! RES(i) = || A*ZC(:,i) - LAMBDA(i) *ZC(:,i) ||_2
  330. ! RES(i+1) = || A*ZC(:,i+1) - LAMBDA(i+1)*ZC(:,i+1) ||_2
  331. ! where ZC(:,i) = Z(:,i) + sqrt(-1)*Z(:,i+1)
  332. ! ZC(:,i+1) = Z(:,i) - sqrt(-1)*Z(:,i+1)
  333. ! See the description of Z.
  334. !.....
  335. ! B (output) REAL(KIND=WP) MIN(M,N)-by-(N-1) array.
  336. ! IF JOBF =='R', B(1:N,1:K) contains A*U(:,1:K), and can
  337. ! be used for computing the refined vectors; see further
  338. ! details in the provided references.
  339. ! If JOBF == 'E', B(1:N,1;K) contains
  340. ! A*U(:,1:K)*W(1:K,1:K), which are the vectors from the
  341. ! Exact DMD, up to scaling by the inverse eigenvalues.
  342. ! In both cases, the content of B can be lifted to the
  343. ! original dimension of the input data by pre-multiplying
  344. ! with the Q factor from the initial QR factorization.
  345. ! Here A denotes a compression of the underlying operator.
  346. ! See the descriptions of F and X.
  347. ! If JOBF =='N', then B is not referenced.
  348. !.....
  349. ! LDB (input) INTEGER, LDB >= MIN(M,N)
  350. ! The leading dimension of the array B.
  351. !.....
  352. ! V (workspace/output) REAL(KIND=WP) (N-1)-by-(N-1) array
  353. ! On exit, V(1:K,1:K) contains the K eigenvectors of
  354. ! the Rayleigh quotient. The eigenvectors of a complex
  355. ! conjugate pair of eigenvalues are returned in real form
  356. ! as explained in the description of Z. The Ritz vectors
  357. ! (returned in Z) are the product of X and V; see
  358. ! the descriptions of X and Z.
  359. !.....
  360. ! LDV (input) INTEGER, LDV >= N-1
  361. ! The leading dimension of the array V.
  362. !.....
  363. ! S (output) REAL(KIND=WP) (N-1)-by-(N-1) array
  364. ! The array S(1:K,1:K) is used for the matrix Rayleigh
  365. ! quotient. This content is overwritten during
  366. ! the eigenvalue decomposition by DGEEV.
  367. ! See the description of K.
  368. !.....
  369. ! LDS (input) INTEGER, LDS >= N-1
  370. ! The leading dimension of the array S.
  371. !.....
  372. ! WORK (workspace/output) REAL(KIND=WP) LWORK-by-1 array
  373. ! On exit,
  374. ! WORK(1:MIN(M,N)) contains the scalar factors of the
  375. ! elementary reflectors as returned by DGEQRF of the
  376. ! M-by-N input matrix F.
  377. ! WORK(MIN(M,N)+1:MIN(M,N)+N-1) contains the singular values of
  378. ! the input submatrix F(1:M,1:N-1).
  379. ! If the call to DGEDMDQ is only workspace query, then
  380. ! WORK(1) contains the minimal workspace length and
  381. ! WORK(2) is the optimal workspace length. Hence, the
  382. ! length of work is at least 2.
  383. ! See the description of LWORK.
  384. !.....
  385. ! LWORK (input) INTEGER
  386. ! The minimal length of the workspace vector WORK.
  387. ! LWORK is calculated as follows:
  388. ! Let MLWQR = N (minimal workspace for DGEQRF[M,N])
  389. ! MLWDMD = minimal workspace for DGEDMD (see the
  390. ! description of LWORK in DGEDMD) for
  391. ! snapshots of dimensions MIN(M,N)-by-(N-1)
  392. ! MLWMQR = N (minimal workspace for
  393. ! DORMQR['L','N',M,N,N])
  394. ! MLWGQR = N (minimal workspace for DORGQR[M,N,N])
  395. ! Then
  396. ! LWORK = MAX(N+MLWQR, N+MLWDMD)
  397. ! is updated as follows:
  398. ! if JOBZ == 'V' or JOBZ == 'F' THEN
  399. ! LWORK = MAX( LWORK, MIN(M,N)+N-1+MLWMQR )
  400. ! if JOBQ == 'Q' THEN
  401. ! LWORK = MAX( LWORK, MIN(M,N)+N-1+MLWGQR)
  402. ! If on entry LWORK = -1, then a workspace query is
  403. ! assumed and the procedure only computes the minimal
  404. ! and the optimal workspace lengths for both WORK and
  405. ! IWORK. See the descriptions of WORK and IWORK.
  406. !.....
  407. ! IWORK (workspace/output) INTEGER LIWORK-by-1 array
  408. ! Workspace that is required only if WHTSVD equals
  409. ! 2 , 3 or 4. (See the description of WHTSVD).
  410. ! If on entry LWORK =-1 or LIWORK=-1, then the
  411. ! minimal length of IWORK is computed and returned in
  412. ! IWORK(1). See the description of LIWORK.
  413. !.....
  414. ! LIWORK (input) INTEGER
  415. ! The minimal length of the workspace vector IWORK.
  416. ! If WHTSVD == 1, then only IWORK(1) is used; LIWORK >=1
  417. ! Let M1=MIN(M,N), N1=N-1. Then
  418. ! If WHTSVD == 2, then LIWORK >= MAX(1,8*MIN(M1,N1))
  419. ! If WHTSVD == 3, then LIWORK >= MAX(1,M1+N1-1)
  420. ! If WHTSVD == 4, then LIWORK >= MAX(3,M1+3*N1)
  421. ! If on entry LIWORK = -1, then a workspace query is
  422. ! assumed and the procedure only computes the minimal
  423. ! and the optimal workspace lengths for both WORK and
  424. ! IWORK. See the descriptions of WORK and IWORK.
  425. !.....
  426. ! INFO (output) INTEGER
  427. ! -i < 0 :: On entry, the i-th argument had an
  428. ! illegal value
  429. ! = 0 :: Successful return.
  430. ! = 1 :: Void input. Quick exit (M=0 or N=0).
  431. ! = 2 :: The SVD computation of X did not converge.
  432. ! Suggestion: Check the input data and/or
  433. ! repeat with different WHTSVD.
  434. ! = 3 :: The computation of the eigenvalues did not
  435. ! converge.
  436. ! = 4 :: If data scaling was requested on input and
  437. ! the procedure found inconsistency in the data
  438. ! such that for some column index i,
  439. ! X(:,i) = 0 but Y(:,i) /= 0, then Y(:,i) is set
  440. ! to zero if JOBS=='C'. The computation proceeds
  441. ! with original or modified data and warning
  442. ! flag is set with INFO=4.
  443. !.............................................................
  444. !.............................................................
  445. ! Parameters
  446. ! ~~~~~~~~~~
  447. REAL(KIND=WP), PARAMETER :: ONE = 1.0_WP
  448. REAL(KIND=WP), PARAMETER :: ZERO = 0.0_WP
  449. !
  450. ! Local scalars
  451. ! ~~~~~~~~~~~~~
  452. INTEGER :: IMINWR, INFO1, MLWDMD, MLWGQR, &
  453. MLWMQR, MLWORK, MLWQR, MINMN, &
  454. OLWDMD, OLWGQR, OLWMQR, OLWORK, &
  455. OLWQR
  456. LOGICAL :: LQUERY, SCCOLX, SCCOLY, WANTQ, &
  457. WNTTRF, WNTRES, WNTVEC, WNTVCF, &
  458. WNTVCQ, WNTREF, WNTEX
  459. CHARACTER(LEN=1) :: JOBVL
  460. !
  461. ! Local array
  462. ! ~~~~~~~~~~~
  463. REAL(KIND=WP) :: RDUMMY(2)
  464. !
  465. ! External functions (BLAS and LAPACK)
  466. ! ~~~~~~~~~~~~~~~~~
  467. LOGICAL LSAME
  468. EXTERNAL LSAME
  469. !
  470. ! External subroutines (BLAS and LAPACK)
  471. ! ~~~~~~~~~~~~~~~~~~~~
  472. EXTERNAL DGEMM
  473. EXTERNAL DGEQRF, DLACPY, DLASET, DORGQR, &
  474. DORMQR, XERBLA
  475. ! External subroutines
  476. ! ~~~~~~~~~~~~~~~~~~~~
  477. EXTERNAL DGEDMD
  478. ! Intrinsic functions
  479. ! ~~~~~~~~~~~~~~~~~~~
  480. INTRINSIC MAX, MIN, INT
  481. !..........................................................
  482. !
  483. ! Test the input arguments
  484. WNTRES = LSAME(JOBR,'R')
  485. SCCOLX = LSAME(JOBS,'S') .OR. LSAME( JOBS, 'C' )
  486. SCCOLY = LSAME(JOBS,'Y')
  487. WNTVEC = LSAME(JOBZ,'V')
  488. WNTVCF = LSAME(JOBZ,'F')
  489. WNTVCQ = LSAME(JOBZ,'Q')
  490. WNTREF = LSAME(JOBF,'R')
  491. WNTEX = LSAME(JOBF,'E')
  492. WANTQ = LSAME(JOBQ,'Q')
  493. WNTTRF = LSAME(JOBT,'R')
  494. MINMN = MIN(M,N)
  495. INFO = 0
  496. LQUERY = ( ( LWORK == -1 ) .OR. ( LIWORK == -1 ) )
  497. !
  498. IF ( .NOT. (SCCOLX .OR. SCCOLY .OR. &
  499. LSAME(JOBS,'N')) ) THEN
  500. INFO = -1
  501. ELSE IF ( .NOT. (WNTVEC .OR. WNTVCF .OR. WNTVCQ &
  502. .OR. LSAME(JOBZ,'N')) ) THEN
  503. INFO = -2
  504. ELSE IF ( .NOT. (WNTRES .OR. LSAME(JOBR,'N')) .OR. &
  505. ( WNTRES .AND. LSAME(JOBZ,'N') ) ) THEN
  506. INFO = -3
  507. ELSE IF ( .NOT. (WANTQ .OR. LSAME(JOBQ,'N')) ) THEN
  508. INFO = -4
  509. ELSE IF ( .NOT. ( WNTTRF .OR. LSAME(JOBT,'N') ) ) THEN
  510. INFO = -5
  511. ELSE IF ( .NOT. (WNTREF .OR. WNTEX .OR. &
  512. LSAME(JOBF,'N') ) ) THEN
  513. INFO = -6
  514. ELSE IF ( .NOT. ((WHTSVD == 1).OR.(WHTSVD == 2).OR. &
  515. (WHTSVD == 3).OR.(WHTSVD == 4)) ) THEN
  516. INFO = -7
  517. ELSE IF ( M < 0 ) THEN
  518. INFO = -8
  519. ELSE IF ( ( N < 0 ) .OR. ( N > M+1 ) ) THEN
  520. INFO = -9
  521. ELSE IF ( LDF < M ) THEN
  522. INFO = -11
  523. ELSE IF ( LDX < MINMN ) THEN
  524. INFO = -13
  525. ELSE IF ( LDY < MINMN ) THEN
  526. INFO = -15
  527. ELSE IF ( .NOT. (( NRNK == -2).OR.(NRNK == -1).OR. &
  528. ((NRNK >= 1).AND.(NRNK <=N ))) ) THEN
  529. INFO = -16
  530. ELSE IF ( ( TOL < ZERO ) .OR. ( TOL >= ONE ) ) THEN
  531. INFO = -17
  532. ELSE IF ( LDZ < M ) THEN
  533. INFO = -22
  534. ELSE IF ( (WNTREF.OR.WNTEX ).AND.( LDB < MINMN ) ) THEN
  535. INFO = -25
  536. ELSE IF ( LDV < N-1 ) THEN
  537. INFO = -27
  538. ELSE IF ( LDS < N-1 ) THEN
  539. INFO = -29
  540. END IF
  541. !
  542. IF ( WNTVEC .OR. WNTVCF .OR. WNTVCQ ) THEN
  543. JOBVL = 'V'
  544. ELSE
  545. JOBVL = 'N'
  546. END IF
  547. IF ( INFO == 0 ) THEN
  548. ! Compute the minimal and the optimal workspace
  549. ! requirements. Simulate running the code and
  550. ! determine minimal and optimal sizes of the
  551. ! workspace at any moment of the run.
  552. IF ( ( N == 0 ) .OR. ( N == 1 ) ) THEN
  553. ! All output except K is void. INFO=1 signals
  554. ! the void input. In case of a workspace query,
  555. ! the minimal workspace lengths are returned.
  556. IF ( LQUERY ) THEN
  557. IWORK(1) = 1
  558. WORK(1) = 2
  559. WORK(2) = 2
  560. ELSE
  561. K = 0
  562. END IF
  563. INFO = 1
  564. RETURN
  565. END IF
  566. MLWQR = MAX(1,N) ! Minimal workspace length for DGEQRF.
  567. MLWORK = MINMN + MLWQR
  568. IF ( LQUERY ) THEN
  569. CALL DGEQRF( M, N, F, LDF, WORK, RDUMMY, -1, &
  570. INFO1 )
  571. OLWQR = INT(RDUMMY(1))
  572. OLWORK = MIN(M,N) + OLWQR
  573. END IF
  574. CALL DGEDMD( JOBS, JOBVL, JOBR, JOBF, WHTSVD, MINMN,&
  575. N-1, X, LDX, Y, LDY, NRNK, TOL, K, &
  576. REIG, IMEIG, Z, LDZ, RES, B, LDB, &
  577. V, LDV, S, LDS, WORK, -1, IWORK, &
  578. LIWORK, INFO1 )
  579. MLWDMD = INT(WORK(1))
  580. MLWORK = MAX(MLWORK, MINMN + MLWDMD)
  581. IMINWR = IWORK(1)
  582. IF ( LQUERY ) THEN
  583. OLWDMD = INT(WORK(2))
  584. OLWORK = MAX(OLWORK, MINMN+OLWDMD)
  585. END IF
  586. IF ( WNTVEC .OR. WNTVCF ) THEN
  587. MLWMQR = MAX(1,N)
  588. MLWORK = MAX(MLWORK,MINMN+N-1+MLWMQR)
  589. IF ( LQUERY ) THEN
  590. CALL DORMQR( 'L','N', M, N, MINMN, F, LDF, &
  591. WORK, Z, LDZ, WORK, -1, INFO1 )
  592. OLWMQR = INT(WORK(1))
  593. OLWORK = MAX(OLWORK,MINMN+N-1+OLWMQR)
  594. END IF
  595. END IF
  596. IF ( WANTQ ) THEN
  597. MLWGQR = N
  598. MLWORK = MAX(MLWORK,MINMN+N-1+MLWGQR)
  599. IF ( LQUERY ) THEN
  600. CALL DORGQR( M, MINMN, MINMN, F, LDF, WORK, &
  601. WORK, -1, INFO1 )
  602. OLWGQR = INT(WORK(1))
  603. OLWORK = MAX(OLWORK,MINMN+N-1+OLWGQR)
  604. END IF
  605. END IF
  606. IMINWR = MAX( 1, IMINWR )
  607. MLWORK = MAX( 2, MLWORK )
  608. IF ( LWORK < MLWORK .AND. (.NOT.LQUERY) ) INFO = -31
  609. IF ( LIWORK < IMINWR .AND. (.NOT.LQUERY) ) INFO = -33
  610. END IF
  611. IF( INFO /= 0 ) THEN
  612. CALL XERBLA( 'DGEDMDQ', -INFO )
  613. RETURN
  614. ELSE IF ( LQUERY ) THEN
  615. ! Return minimal and optimal workspace sizes
  616. IWORK(1) = IMINWR
  617. WORK(1) = MLWORK
  618. WORK(2) = OLWORK
  619. RETURN
  620. END IF
  621. !.....
  622. ! Initial QR factorization that is used to represent the
  623. ! snapshots as elements of lower dimensional subspace.
  624. ! For large scale computation with M >>N , at this place
  625. ! one can use an out of core QRF.
  626. !
  627. CALL DGEQRF( M, N, F, LDF, WORK, &
  628. WORK(MINMN+1), LWORK-MINMN, INFO1 )
  629. !
  630. ! Define X and Y as the snapshots representations in the
  631. ! orthogonal basis computed in the QR factorization.
  632. ! X corresponds to the leading N-1 and Y to the trailing
  633. ! N-1 snapshots.
  634. CALL DLASET( 'L', MINMN, N-1, ZERO, ZERO, X, LDX )
  635. CALL DLACPY( 'U', MINMN, N-1, F, LDF, X, LDX )
  636. CALL DLACPY( 'A', MINMN, N-1, F(1,2), LDF, Y, LDY )
  637. IF ( M >= 3 ) THEN
  638. CALL DLASET( 'L', MINMN-2, N-2, ZERO, ZERO, &
  639. Y(3,1), LDY )
  640. END IF
  641. !
  642. ! Compute the DMD of the projected snapshot pairs (X,Y)
  643. CALL DGEDMD( JOBS, JOBVL, JOBR, JOBF, WHTSVD, MINMN, &
  644. N-1, X, LDX, Y, LDY, NRNK, TOL, K, &
  645. REIG, IMEIG, Z, LDZ, RES, B, LDB, V, &
  646. LDV, S, LDS, WORK(MINMN+1), LWORK-MINMN, &
  647. IWORK, LIWORK, INFO1 )
  648. IF ( INFO1 == 2 .OR. INFO1 == 3 ) THEN
  649. ! Return with error code. See DGEDMD for details.
  650. INFO = INFO1
  651. RETURN
  652. ELSE
  653. INFO = INFO1
  654. END IF
  655. !
  656. ! The Ritz vectors (Koopman modes) can be explicitly
  657. ! formed or returned in factored form.
  658. IF ( WNTVEC ) THEN
  659. ! Compute the eigenvectors explicitly.
  660. IF ( M > MINMN ) CALL DLASET( 'A', M-MINMN, K, ZERO, &
  661. ZERO, Z(MINMN+1,1), LDZ )
  662. CALL DORMQR( 'L','N', M, K, MINMN, F, LDF, WORK, Z, &
  663. LDZ, WORK(MINMN+N), LWORK-(MINMN+N-1), INFO1 )
  664. ELSE IF ( WNTVCF ) THEN
  665. ! Return the Ritz vectors (eigenvectors) in factored
  666. ! form Z*V, where Z contains orthonormal matrix (the
  667. ! product of Q from the initial QR factorization and
  668. ! the SVD/POD_basis returned by DGEDMD in X) and the
  669. ! second factor (the eigenvectors of the Rayleigh
  670. ! quotient) is in the array V, as returned by DGEDMD.
  671. CALL DLACPY( 'A', N, K, X, LDX, Z, LDZ )
  672. IF ( M > N ) CALL DLASET( 'A', M-N, K, ZERO, ZERO, &
  673. Z(N+1,1), LDZ )
  674. CALL DORMQR( 'L','N', M, K, MINMN, F, LDF, WORK, Z, &
  675. LDZ, WORK(MINMN+N), LWORK-(MINMN+N-1), INFO1 )
  676. END IF
  677. !
  678. ! Some optional output variables:
  679. !
  680. ! The upper triangular factor R in the initial QR
  681. ! factorization is optionally returned in the array Y.
  682. ! This is useful if this call to DGEDMDQ is to be
  683. ! followed by a streaming DMD that is implemented in a
  684. ! QR compressed form.
  685. IF ( WNTTRF ) THEN ! Return the upper triangular R in Y
  686. CALL DLASET( 'A', MINMN, N, ZERO, ZERO, Y, LDY )
  687. CALL DLACPY( 'U', MINMN, N, F, LDF, Y, LDY )
  688. END IF
  689. !
  690. ! The orthonormal/orthogonal factor Q in the initial QR
  691. ! factorization is optionally returned in the array F.
  692. ! Same as with the triangular factor above, this is
  693. ! useful in a streaming DMD.
  694. IF ( WANTQ ) THEN ! Q overwrites F
  695. CALL DORGQR( M, MINMN, MINMN, F, LDF, WORK, &
  696. WORK(MINMN+N), LWORK-(MINMN+N-1), INFO1 )
  697. END IF
  698. !
  699. RETURN
  700. !
  701. END SUBROUTINE DGEDMDQ