STDMD.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2020-2025 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Class
27  Foam::DMDModels::STDMD
28 
29 Description
30  Streaming Total Dynamic Mode Decomposition (i.e. \c STDMD)
31  is a variant of dynamic mode decomposition.
32 
33  Among other Dynamic Mode Decomposition (DMD) variants, \c STDMD is
34  presumed to provide the general DMD method capabilities alongside
35  economised and feasible memory and CPU usage.
36 
37  The code implementation corresponds to Figs. 15-16 of the first citation
38  below, more broadly to Section 2.4.
39 
40  References:
41  \verbatim
42  DMD and mode-sorting algorithms (tags:K, HRDC, KZ, HWR):
43  Kiewat, M. (2019).
44  Streaming modal decomposition approaches for vehicle aerodynamics.
45  PhD thesis. Munich: Technical University of Munich.
46  URL:mediatum.ub.tum.de/doc/1482652/1482652.pdf
47 
48  Hemati, M. S., Rowley, C. W.,
49  Deem, E. A., & Cattafesta, L. N. (2017).
50  De-biasing the dynamic mode decomposition
51  for applied Koopman spectral analysis of noisy datasets.
52  Theoretical and Computational Fluid Dynamics, 31(4), 349-368.
53  DOI:10.1007/s00162-017-0432-2
54 
55  Kou, J., & Zhang, W. (2017).
56  An improved criterion to select
57  dominant modes from dynamic mode decomposition.
58  European Journal of Mechanics-B/Fluids, 62, 109-129.
59  DOI:10.1016/j.euromechflu.2016.11.015
60 
61  Hemati, M. S., Williams, M. O., & Rowley, C. W. (2014).
62  Dynamic mode decomposition for large and streaming datasets.
63  Physics of Fluids, 26(11), 111701.
64  DOI:10.1063/1.4901016
65 
66  Parallel classical Gram-Schmidt process (tag:Ka):
67  Katagiri, T. (2003).
68  Performance evaluation of parallel
69  Gram-Schmidt re-orthogonalization methods.
70  In: Palma J. M. L. M., Sousa A. A., Dongarra J., Hernández V. (eds)
71  High Performance Computing for Computational Science — VECPAR 2002.
72  Lecture Notes in Computer Science, vol 2565, p. 302-314.
73  Berlin, Heidelberg: Springer.
74  DOI:10.1007/3-540-36569-9_19
75 
76  Parallel direct tall-skinny QR decomposition (tags:BGD, DGHL):
77  Benson, A. R., Gleich, D. F., & Demmel, J. (2013).
78  Direct QR factorizations for
79  tall-and-skinny matrices in MapReduce architectures.
80  2013 IEEE International Conference on Big Data.
81  DOI:10.1109/bigdata.2013.6691583
82 
83  Demmel, J., Grigori, L., Hoemmen, M., & Langou, J. (2012).
84  Communication-optimal parallel
85  and sequential QR and LU factorizations.
86  SIAM Journal on Scientific Computing, 34(1), A206-A239.
87  DOI:10.1137/080731992
88  \endverbatim
89 
90 Usage
91  Minimal example by using \c system/controlDict.functions:
92  \verbatim
93  DMD1
94  {
95  // Mandatory entries
96  DMDModel STDMD;
97 
98  // Conditional mandatory entries
99 
100  // Option-1
101  interval 5.5;
102 
103  // Option-2
104  executeInterval 10;
105 
106  // Optional entries
107  modeSorter kiewat;
108  nGramSchmidt 5;
109  maxRank 50;
110  nModes 50;
111  fMin 0;
112  fMax 1000000000;
113  nAgglomerationProcs 20;
114 
115  // Optional entries (not recommended to change)
116  minBasis 0.00000001;
117  minEVal 0.00000001;
118  sortLimiter 500.0;
119 
120  // Inherited entries
121  ...
122  }
123  \endverbatim
124 
125  where the entries mean:
126  \table
127  Property | Description | Type | Reqd | Deflt
128  DMDModel | Type: STDMD | word | yes | -
129  interval | STDMD time-step size [s] | scalar | cndtnl <!--
130  --> | executeInterval*(current time-step of the simulation)
131  modeSorter | Mode-sorting algorithm model | word | no <!--
132  --> | firstSnapshot
133  nModes | Number of output modes in input frequency range <!--
134  --> | label | no | GREAT
135  maxRank | Max columns in accumulated matrices | label | no | GREAT
136  nGramSchmidt | Number of Gram-Schmidt iterations | label | no | 5
137  fMin | Min (non-negative) output frequency | label | no | 0
138  fMax | Max output frequency | label | no | GREAT
139  nAgglomerationProcs | Number of processors at each agglomeration <!--
140  --> unit during the computation of reduced Koopman <!--
141  --> operator | label | no | 20
142  minBasis | Orthogonal basis expansion threshold | scalar| no | 1e-8
143  minEVal | Min eigenvalue for below eigenvalues are omitted <!--
144  --> | scalar| no | 1e-8
145  sortLimiter | Max allowable magnitude for <!--
146  --> mag(eigenvalue)*(number of DMD steps) to be used in <!--
147  --> modeSorter={kiewat,kouZhang} to avoid overflow errors <!--
148  --> | scalar | no | 500.0
149  \endtable
150 
151  Options for the \c modeSorter entry:
152  \verbatim
153  kiewat | Modified weighted-amplitude scaling method
154  kouZhang | Weighted-amplitude scaling method
155  firstSnapshot | First-snapshot amplitude magnitude method
156  \endverbatim
157 
158 Note
159  - To specify the STDMD time-step size (not necessarily equal to the
160  time step of the simulation), entries of either \c interval or
161  \c executeInterval must be available (highest to lowest precedence). While
162  \c interval allows users to directly specify the STDMD time-step size
163  in seconds, in absence of \c interval, for convenience,
164  \c executeInterval allows users to compute the STDMD time-step internally
165  by multiplying itself with the current time-step size of the simulation.
166  - Limitation: Restart is currently not available since intermediate writing
167  of STDMD matrices are not supported.
168  - Limitation: Non-physical input (e.g. full-zero fields) can upset STDMD.
169  - Warning: In \c modeSorter algorithms of \c kiewat and \c kouZhang, a
170  function of \f$power(x,y)\f$ exists where \c x is the magnitude of an
171  eigenvalue, and \c y is the number of STDMD snapshots. This function poses
172  a risk of overflow errors since, for example, if \c x ends up above 1.5 with
173  500 snapshots or more, this function automatically throws the floating point
174  error meaning overflow. Therefore, the domain-range of this function is
175  heuristically constrained by the optional entry \c sortLimiter which skips
176  the evaluation of this function for a given
177  mag(eigenvalue)*(no. of STDMD steps), i.e. x*y, whose magnitude is larger
178  than \c sortLimiter.
179 
180 See also
181  - Foam::functionObjects::DMD
182  - Foam::DMDModel
183 
184 SourceFiles
185  STDMD.C
186  STDMDTemplates.C
187 
188 \*---------------------------------------------------------------------------*/
189 
190 #ifndef Foam_DMDModels_STDMD_H
191 #define Foam_DMDModels_STDMD_H
192 
193 #include "DMDModel.H"
194 #include "SquareMatrix.H"
195 #include "RectangularMatrix.H"
196 
197 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
198 
199 namespace Foam
200 {
201 namespace DMDModels
202 {
203 
204 /*---------------------------------------------------------------------------*\
205  Class STDMD Declaration
206 \*---------------------------------------------------------------------------*/
207 
208 class STDMD
209 :
210  public DMDModel
211 {
212  typedef SquareMatrix<scalar> SMatrix;
213  typedef RectangularMatrix<scalar> RMatrix;
214  typedef RectangularMatrix<complex> RCMatrix;
215 
216 
217  // Private Enumerations
218 
219  //- Options for the mode-sorting algorithm
220  enum modeSorterType : char
221  {
222  FIRST_SNAPSHOT = 0,
223  KIEWAT,
224  KOU_ZHANG
225  };
226 
227  //- Names for modeSorterType
228  static const Enum<modeSorterType> modeSorterTypeNames;
229 
230 
231  // Private Data
232 
233  //- Mode-sorting algorithm
234  enum modeSorterType modeSorter_;
235 
236  //- Accumulated-in-time unitary similarity matrix produced by the
237  //- orthonormal decomposition of the augmented snapshot matrix 'z'
238  // (K:Eq. 60)
239  RMatrix Q_;
240 
241  //- Accumulated-in-time (squared) upper triangular matrix produced by
242  //- the orthonormal decomposition of the augmented snapshot matrix 'z'
243  // (K:Eq. 64)
244  SMatrix G_;
245 
246  //- Upper half of 'Q'
247  RMatrix Qupper_;
248 
249  //- Lower half of 'Q'
250  RMatrix Qlower_;
251 
252  //- Moore-Penrose pseudo-inverse of 'R' produced by
253  //- the QR decomposition of the last time-step 'Q'
254  RMatrix RxInv_;
255 
256  //- Eigenvalues of modes
257  List<complex> evals_;
258 
259  //- Eigenvectors of modes
260  RCMatrix evecs_;
261 
262  //- (Non-negative) frequencies of modes
263  List<scalar> freqs_;
264 
265  //- Indices of 'freqs' where frequencies are
266  //- non-negative and within ['fMin', 'fMax']
267  DynamicList<label> freqsi_;
268 
269  //- Amplitudes of modes
270  List<complex> amps_;
271 
272  //- (Descending) magnitudes of (complex) amplitudes of modes
273  List<scalar> mags_;
274 
275  //- Indices of 'mags'
276  List<label> magsi_;
277 
278  //- Names of operand patches
279  const wordRes patches_;
280 
281  //- Name of operand field
282  const word fieldName_;
283 
284  //- First-processed snapshot required by the mode-sorting
285  //- algorithms at the final output computations (K:p. 43)
286  word timeName0_;
287 
288  //- Min value to execute orthogonal basis expansion of 'Q' and 'G'
289  scalar minBasis_;
290 
291  //- Min eigenvalue magnitude below where 'evals' are omitted
292  scalar minEval_;
293 
294  //- STDMD time-step size that equals to
295  //- (executeInterval of DMD)*(deltaT of simulation) [s]
296  scalar dt_;
297 
298  //- Maximum allowable magnitude for mag(eigenvalue)*(number of
299  //- STDMD steps) to be used in modeSorter={kiewat,kouZhang} to
300  //- avoid overflow errors
301  scalar sortLimiter_;
302 
303  //- Min frequency: Output only entries corresponding to freqs >= 'fMin'
304  label fMin_;
305 
306  //- Max frequency: Output only entries corresponding to freqs <= 'fMax'
307  label fMax_;
308 
309  //- Number of maximum iterations of the classical
310  //- Gram-Schmidt procedure for the orthonormalisation
311  label nGramSchmidt_;
312 
313  //- Maximum allowable matrix column for 'Q' and 'G'
314  // 'Q' is assumed to always have full-rank, thus 'Q.n() = rank'
315  label maxRank_;
316 
317  //- Current execution-step index of STDMD,
318  //- not necessarily that of the simulation
319  label step_;
320 
321  //- Number of output modes within input frequency range
322  //- starting from the most energetic mode
323  label nModes_;
324 
325  //- Number of processors at each agglomeration unit
326  //- during the computation of reduced Koopman operator
327  label nAgglomerationProcs_;
328 
329  //- (Internal) Flag to tag snapshots which are effectively empty
330  bool empty_;
331 
332 
333  // Private Member Functions
334 
335  // Evaluation
336 
337  //- Return (parallel) L2-norm of a given column vector
338  scalar L2norm(const RMatrix& z) const;
339 
340  //- Execute (parallel) classical Gram-Schmidt
341  //- process to orthonormalise 'ez' (Ka:Fig. 5)
342  RMatrix orthonormalise(RMatrix ez) const;
343 
344  //- Expand orthonormal bases 'Q' and 'G' by stacking a column
345  //- '(ez/ezNorm)' to 'Q', and a row (Zero) and column (Zero)
346  //- to 'G' if '(ezNorm/zNorm > minBasis)'
347  void expand(const RMatrix& ez, const scalar ezNorm);
348 
349  //- Update 'G' before the potential orthonormal basis compression
350  void updateG(const RMatrix& z);
351 
352  //- Compress orthonormal basis for 'Q' and 'G' if '(Q.n()>maxRank)'
353  void compress();
354 
355  //- Return reduced Koopman operator 'Atilde' (K:Eq. 78)
356  // Also fills 'RxInv'.
357  // The function was not divided into subsections to ensure
358  // minimal usage of memory, hence the complexity of the function
359  SMatrix reducedKoopmanOperator();
360 
361  //- Compute eigenvalues and eigenvectors of 'Atilde'
362  // Remove any eigenvalues whose magnitude is smaller than
363  // 'minEVal' while keeping the order of elements the same
364  bool eigendecomposition(SMatrix& Atilde);
365 
366  //- Compute and filter frequencies and its indices (K:Eq. 81)
367  // Indices of 'freqs' where frequencies are
368  // non-negative and within ['fMin', 'fMax']
369  void frequencies();
370 
371  //- Compute amplitudes
372  void amplitudes();
373 
374  //- Compute magnitudes and ordered magnitude indices
375  // Includes advanced sorting methods using
376  // the chosen weighted amplitude scaling method
377  void magnitudes();
378 
379  //- Eigenvalue weighted amplitude scaling (KZ:Eq. 33)
380  //- Modified eigenvalue weighted amplitude scaling (K)
381  scalar sorter
382  (
383  const List<scalar>& weight,
384  const complex& amplitude,
385  const complex& eigenvalue,
386  const scalar modeNorm
387  ) const;
388 
389  //- Compute and write mode dynamics
390  virtual bool dynamics();
391 
392  //- Compute and write modes
393  virtual bool modes();
394 
395  //- Select field type for modes
396  template<class Type>
397  bool modes();
398 
399  //- Compute modes based on input field type
400  template<class GeoFieldType>
401  bool calcModes();
402 
403  //- Compute a mode for a given scalar-based or other input field
404  template<class GeoFieldType>
405  void calcMode
406  (
407  GeoFieldType& modeRe,
408  GeoFieldType& modeIm,
409  const RMatrix& primitiveMode,
410  const label magi,
411  const label rowi = 0
412  );
413 
414 
415  // I-O
416 
417  //- Write objects of dynamics
418  void writeToFile(const word& fileName) const;
419 
420  // Notifying the compiler that we want both writeToFile functions
422 
423  //- Write file header information
424  void writeFileHeader(Ostream& os) const;
425 
426  //- Filter objects of dynamics according to 'freqsi' and 'magsi'
427  void filter();
428 
429  //- Return a new List containing elems of List at 'indices'
430  template<class Type>
431  void filterIndexed
432  (
433  List<Type>& lst,
434  const UList<label>& indices
435  );
436 
437  //- Return a new Matrix containing columns of Matrix at 'indices'
438  template<class MatrixType>
439  void filterIndexed
440  (
441  MatrixType& lst,
442  const UList<label>& indices
443  );
444 
445 
446 public:
447 
448  //- Runtime type information
449  TypeName("STDMD");
450 
451 
452  // Constructors
453 
454  //- Construct from components
455  STDMD
456  (
457  const fvMesh& mesh,
458  const word& name,
459  const dictionary& dict
460  );
461 
462  //- No copy construct
463  STDMD(const STDMD&) = delete;
464 
465  //- No copy assignment
466  void operator=(const STDMD&) = delete;
467 
468 
469  //- Destructor
470  virtual ~STDMD() = default;
471 
472 
473  // Member Functions
474 
475  // Evaluation
476 
477  //- Initialise 'Q' and 'G' (both require the first two snapshots)
478  virtual bool initialise(const RMatrix& z);
479 
480  //- Incremental orthonormal basis update (K:Fig. 15)
481  virtual bool update(const RMatrix& z);
482 
483  //- Compute and write modes and
484  //- mode dynamics of model data members
485  virtual bool fit();
486 
487 
488  // IO
489 
490  //- Read STDMD settings
491  virtual bool read(const dictionary& dict);
492 };
493 
494 
495 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
496 
497 } // End namespace DMDModels
498 } // End namespace Foam
499 
500 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
501 
502 #ifdef NoRepository
503  #include "STDMDTemplates.C"
504 #endif
505 
506 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
507 
508 #endif
509 
510 // ************************************************************************* //
dictionary dict
A class for handling file names.
Definition: fileName.H:72
virtual ~STDMD()=default
Destructor.
virtual bool update(const RMatrix &z)
Incremental orthonormal basis update (K:Fig. 15)
Definition: STDMD.C:1007
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
Streaming Total Dynamic Mode Decomposition (i.e. STDMD) is a variant of dynamic mode decomposition...
Definition: STDMD.H:299
virtual bool fit()
Compute and write modes and mode dynamics of model data members.
Definition: STDMD.C:1041
void operator=(const STDMD &)=delete
No copy assignment.
virtual bool initialise(const RMatrix &z)
Initialise &#39;Q&#39; and &#39;G&#39; (both require the first two snapshots)
Definition: STDMD.C:946
virtual bool read(const dictionary &dict)
Read STDMD settings.
Definition: STDMD.C:859
STDMD(const fvMesh &mesh, const word &name, const dictionary &dict)
Construct from components.
Definition: STDMD.C:804
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
TypeName("STDMD")
Runtime type information.
virtual bool writeToFile() const
Flag to allow writing to file.
Definition: writeFile.C:286
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
OBJstream os(runTime.globalPath()/outputName)
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A complex number, similar to the C++ complex type.
Definition: complex.H:70
Namespace for OpenFOAM.