POD-ESN model¶
POD_ESN combines Proper Orthogonal Decomposition with an Echo State Network. It provides
a reduced-order forecast model for high-dimensional fields, with sensor placement available
through the projector interface.
romda.models.data_driven.pod_esn.POD_ESN(data, dt, plot_case=False, pdf_file=None, skip_sensor_placement=False, train_ESN=True, domain_of_measurement=None, down_sample_measurement=None, **kwargs)
¶
POD-projected echo state network: a POD
decomposition reduces the (spatial) field to a handful of temporal
coefficients, and an ESN_model is
trained to forecast those coefficients in time.
Following the POD convention (see its
docstring), writing \(\mathbf{Q} = \mathbf{X} - \bar{\mathbf{Q}}\) for the
zero-mean data, the field is approximated as
with \(\boldsymbol{\Psi}\) (Psi) the orthonormal spatial modes and
\(\boldsymbol{\Phi}\) (Phi) the temporal coefficients
(\(\boldsymbol{\Phi} = \boldsymbol{\Psi}^\mathrm{T}\mathbf{Q}\), already scaled by the
singular values Sigma). POD_ESN.__init__ runs the POD decomposition first,
then trains the ESN on \(\boldsymbol{\Phi}\) (transposed to the
(L, Nt, N_modes) layout ESN_model expects) to forecast the temporal
coefficients forward in time; get_observables maps the ESN's closed-loop
Phi forecast back to physical sensor readings (decode) or returns the modal
coefficients directly if measure_modes.
Run the POD decomposition, train the ESN on the resulting temporal coefficients, and select sensor locations for observation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
Data for the POD decomposition and ESN training, shape
|
required |
dt
|
float
|
Time step of |
required |
plot_case
|
bool
|
Whether to plot the POD modes/spectrum/reconstruction (and the ESN
training process, if |
False
|
pdf_file
|
str
|
If given (and |
None
|
skip_sensor_placement
|
bool
|
If True, skip sensor placement and observe the POD modes directly
(equivalent to |
False
|
train_ESN
|
bool
|
Whether to train the ESN on the POD temporal coefficients. Default True. |
True
|
domain_of_measurement
|
list
|
Sub-domain |
None
|
down_sample_measurement
|
int or (int, int)
|
Grid down-sampling factor(s) applied to the measurement domain before sensor selection. |
None
|
**kwargs
|
Additional keyword arguments to configure the parent Model/ESN/POD
classes, e.g. |
{}
|
Source code in src/models/data_driven/pod_esn.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
obs_labels
property
¶
list of str: LaTeX labels for the observed quantities -- POD coefficients
\(\Phi_1, \dots, \Phi_{N_\mathrm{modes}}\) if measure_modes, otherwise the
sensor readings' \(u_x\)/\(u_y\) components.
state_labels
property
¶
list of str: LaTeX labels for the state vector, \(\Phi_1, \dots,
\Phi_{N_\mathrm{modes}}\) (POD temporal coefficients, if update_state)
followed by \(r_1, \dots, r_{N_\mathrm{units}}\) (reservoir units, if
update_reservoir).
N_sensors
property
¶
int: Number of sensor locations per velocity component (\(u_x\) or \(u_y\)),
i.e. Nq // 2 (each location contributes 2 observables); 0 if
measure_modes.
sensor_rows
property
¶
np.ndarray or None: Rows of Psi/Q_mean corresponding to
sensor_locations (cached after first access; invalidated by
select_sensors). sensor_locations are raw-grid indices
(var * Nx * Ny + g), whereas the POD basis rows follow the masked flat
ordering -- this property maps between the two, via
grid_index_to_flat_rows. None if sensor_locations is None.
domain_of_measurement
property
writable
¶
list: Sub-domain [x0, x1, y0, y1] sensors may be placed in. Defaults
to the full domain if never set.
down_sample_measurement
property
writable
¶
list of int or None: Grid down-sampling factors [step_x, step_y]
applied to the measurement grid before sensor placement. None (no
down-sampling) if never set.
grid_of_measurement
property
¶
np.ndarray: Flat-grid indices (fluid cells only, all velocity
components) eligible for sensor placement, i.e. domain_of_measurement
down-sampled by down_sample_measurement and intersected with
fluid_mask_flat.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
get_POD_coefficients(Nt=1)
¶
Read the forecasted POD temporal coefficients off the state history.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
Nt
|
int
|
Number of trailing history steps to return. Default 1. |
1
|
Returns:
| Type | Description |
|---|---|
ndarray
|
\(\boldsymbol{\Phi}\)-block of |
Source code in src/models/data_driven/pod_esn.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | |
get_observables(Nt=1, Phi=None, **kwargs)
¶
Map the (forecasted) POD coefficients to observables: the coefficients
themselves if measure_modes, otherwise physical-space sensor readings
obtained via decode at sensor_rows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
Nt
|
int
|
Number of trailing history steps to return. Default 1. |
1
|
Phi
|
ndarray
|
POD coefficients to decode, shape |
None
|
**kwargs
|
Unused; accepted for interface compatibility. |
{}
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Observables, shape |
Source code in src/models/data_driven/pod_esn.py
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | |
reset_case(reset_POD=False, reset_ESN=False, Phi0=None, **kwargs)
¶
Optionally rerun the POD decomposition and/or reset (retrain) the ESN.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reset_POD
|
bool
|
If True, rerun the POD decomposition ( |
False
|
reset_ESN
|
bool
|
If True, reset the |
False
|
Phi0
|
ndarray
|
Passed to |
None
|
**kwargs
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
|
Source code in src/models/data_driven/pod_esn.py
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
select_sensors(measure_modes=False, domain_of_measurement=None, down_sample_measurement=None, N_sensors=None, qr_selection=False)
¶
(Re)configure how the model is observed: either the raw POD coefficients
(measure_modes) or physical-space point sensors placed by define_sensors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
measure_modes
|
bool
|
If True, observe the POD coefficients directly ( |
False
|
domain_of_measurement
|
list
|
Sub-domain |
None
|
down_sample_measurement
|
int or (int, int)
|
Grid down-sampling factor(s) for the measurement domain. |
None
|
N_sensors
|
int
|
Number of sensor locations to place. Defaults to |
None
|
qr_selection
|
bool
|
Whether to use QR-pivoting sensor placement ( |
False
|
Returns:
| Type | Description |
|---|---|
None
|
Sets |
Source code in src/models/data_driven/pod_esn.py
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | |
define_sensors(N_sensors=None, plot=False)
¶
Choose sensor grid locations within grid_of_measurement.
If qr_selection, uses column-pivoted QR on the (physical-grid) spatial
modes Psi restricted to the candidate locations, so the chosen sensors
best condition the mode-reconstruction problem (a greedy, deterministic
sensor-placement heuristic); otherwise picks N_sensors random locations
(rng).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
N_sensors
|
int
|
Number of sensor locations to place. Defaults to |
None
|
plot
|
bool
|
Show the debug scatter of grid/measurement domain/sensors (blocks in interactive backends). Default False. |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Flat-grid sensor indices, one block per velocity component, shape
|
Source code in src/models/data_driven/pod_esn.py
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | |
plot_case(case, datasets=None, num_modes=None)
staticmethod
¶
Plot the POD modes, temporal coefficients, spectrum and (if datasets
is given) flow/reconstruction/error fields with sensor locations overlaid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
case
|
POD_ESN
|
Instance to plot. |
required |
datasets
|
dict
|
Named fields to pass to |
None
|
num_modes
|
int
|
Number of POD modes to show. Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
None
|
|
Source code in src/models/data_driven/pod_esn.py
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | |