Bias estimators¶
Summary¶
File: src/bias_estimators/bias.py
Base class for observation-bias estimators. Mixes in HistoryTracker. Wraps a forecaster model to produce bias corrections at each assimilation step.
Key attributes: innovation, dt, forecaster, Nq, N_dim, upsample, biased_observations
Subclasses must implement:
- init_forecaster(**kwargs) — build/train the internal forecasting model
- state_derivative() — return the Jacobian J = db/dy used by bias-aware filters
Bias
├── ESN_bias
└── ConstantBias
└── NoBias
| Class | File | Notes |
|---|---|---|
ESN_bias |
src/bias_estimators/esn.py |
Correlation-based training; biased_observations = True |
ConstantBias |
src/bias_estimators/constantbias.py |
Persistent bias, reset to the latest innovation each analysis step |
NoBias |
src/bias_estimators/constantbias.py |
ConstantBias fixed at zero; unbiased-limit placeholder |
Forecaster¶
The forecaster attribute of a Bias instance is a Model subclass — typically a data-driven model trained on the residual between observations and model output.
Bias instance
.forecaster → Model instance (usually ESN_model)
The forecaster is initialised inside init_forecaster() and stepped forward in sync with the main model during Estimator.forecast_step(). Its output is the predicted bias b(t), which enters the analysis step as a correction to the observation.
romda.bias_estimators.Bias(innovation, t, dt, **kwargs)
¶
Base class for the model-bias estimators used in bias-aware data assimilation.
A bias estimator provides three things to the assimilation loop:
- a forecast of the bias between analyses (
time_integrate), driven by its internal forecaster (an ESN, a constant map, a linear model, ...); - the Jacobian of the bias with respect to the observables
(
state_derivative), \(\mathbf{J} = \mathrm{d}\mathbf{b}/\mathrm{d}\mathbf{q}\), required by the regularized bias-aware EnKF; - an update rule from the analysis innovation
(
update_state_from_innovation), optionally Bayesian (an internal EnSRKF on the bias state).
The estimator state has \(N_\mathrm{dim}\) components: \([\mathbf{b}]\) if the
observations are unbiased, or \([\mathbf{b}; \mathbf{i}]\) (bias and innovations,
\(N_\mathrm{dim} = 2 N_q\)) if biased_observations is set. Child classes may add
hidden components (e.g., the ESN reservoir).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
innovation
|
ndarray
|
Initial innovation/bias estimate, used to set the observable dimension \(N_q\). |
required |
t
|
float
|
Initial time. |
required |
dt
|
float
|
Time step of the output history. |
required |
**kwargs
|
Class-attribute overrides (see Attributes) and forecaster options. |
{}
|
Attributes:
| Name | Type | Description |
|---|---|---|
upsample |
int
|
Upsampling factor of the internal forecaster time step relative to |
L |
int
|
Number of trajectories in the training dataset (data-driven estimators). |
augment_data |
bool or int
|
Whether (and how much) to augment the training data. |
bayesian_update |
bool
|
If True, the innovation update is a Bayesian (EnSRKF) update of the full estimator state; otherwise the innovation is assigned directly. |
biased_observations |
bool
|
If True, the observations themselves are assumed biased and the estimator tracks bias and innovations separately. |
force_retrain |
bool
|
If True, retrain the forecaster even if a cached configuration exists. |
Source code in src/bias_estimators/bias.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
initialize_bias_state
property
¶
Only used at initialization. If the forecaster is a model, this should be handled by the child class. The state has N_dim components: [bias] if the observations are unbiased, or [bias; innovations] if the observations are biased (N_dim = 2 * Nq).
integrator
property
¶
This is the integrator used by the model of the bias. E.g., DiscreteIntegrator if using ESN_model as forecaster.
washout_data
property
writable
¶
Returns the washout data used for initializing the bias model, which is typically obtained from the washout phase using the validation data. This property can be used to access the washout data for further processing or analysis.
Returns:
| Type | Description |
|---|---|
Tuple of (washout_data, washout_time) where:
|
|
hist
property
¶
Returns only the valid (non-empty) portion of the history buffer.
hist_t
property
¶
Returns only the valid portion of the time history.
current_state
property
¶
Returns the current state (last entry in history).
current_time
property
¶
Returns the current time (last entry in time history).
current_bias
property
¶
Returns the current (ensemble-mean) bias computed from the current state. Shape: (Nq, 1) -- the bias is defined on the ensemble mean.
current_innovations
property
¶
Returns the current (ensemble-mean) innovations computed from the current state. Shape: (Nq, 1).
DA_method
property
¶
Cached measurement operator M for the Bayesian innovation update (_ensrkf_update).
init_forecaster(**kwargs)
¶
.....
Source code in src/bias_estimators/bias.py
232 233 234 235 236 | |
state_derivative()
¶
Returns the derivative of the bias state, which is used for time integration. This is computed by the forecaster model.
Source code in src/bias_estimators/bias.py
238 239 240 241 242 243 | |
washout_phase(d_wash, t_wash, **kwargs)
¶
Optional method to initialize the bias model if needed, e.g., by running a washout phase with given data. By default, does nothing, but can be implemented in child classes if needed.
Source code in src/bias_estimators/bias.py
245 246 247 248 249 250 | |
update_history_aux(**kwargs)
¶
Auxiliary method to update any additional history attributes in child classes if needed.
Source code in src/bias_estimators/bias.py
383 384 385 | |
update_state_from_innovation(input_innovation)
¶
Optional method to perform a Bayesian update to the state using the bias model. This can be implemented in child classes if needed, e.g., for ESN bias model. By default, does nothing, but can be implemented in child classes if needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_innovation
|
ndarray
|
Analysis innovation ensemble, shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Updated estimator state, shape |
Source code in src/bias_estimators/bias.py
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | |
close()
¶
Close any resources used by the bias model, e.g., forecaster model.
Source code in src/bias_estimators/bias.py
471 472 473 474 | |
romda.bias_estimators.ESN_bias(rom, reference_data=None, **kwargs)
¶
Bases: Bias
Echo-state-network bias estimator.
An ESN_model forecasts the model bias
(and, if biased_observations, the innovations) in closed loop between analyses,
and its open-loop linearization provides the Jacobian
\(\mathbf{J} = \mathrm{d}\mathbf{b}/\mathrm{d}\mathbf{q}\) used by the
regularized bias-aware EnKF. The network is trained offline on synthetic
innovation data generated by perturbing the low-order model (see
create_bias_training_dataset);
trained configurations are cached on disk and reloaded when the configuration
hash matches (unless force_retrain).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rom
|
Model
|
The (biased) low-order forecast model whose bias is estimated. |
required |
reference_data
|
Observations or list of Observations
|
Reference data used to build the training dataset if no cached forecaster or dataset is found. |
None
|
**kwargs
|
ESN hyperparameters ( |
{}
|
References
Nóvoa, Racca & Magri (2023). Inferring unknown unknowns: Regularized bias-aware ensemble Kalman filter. Comput. Methods Appl. Mech. Eng., 418, 116502. DOI: 10.1016/j.cma.2023.116502.
Source code in src/bias_estimators/esn.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
initialize_bias_state
property
¶
Initialize the ESN reservoir state from the validation data.
Called during Bias.__init__ to set the initial state of the ESN_model
forecaster from its validation data, which improves training and
closed-loop performance relative to a zero/random initial state.
Returns:
| Type | Description |
|---|---|
ndarray
|
Initialized reservoir state for the |
washout_phase(d_wash, t_wash, **kwargs)
¶
Run an open-loop washout to initialize the reservoir from real data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d_wash
|
ndarray
|
Washout data used to initialize the bias model, shape |
required |
t_wash
|
ndarray
|
Time points corresponding to |
required |
Returns:
| Name | Type | Description |
|---|---|---|
psi |
ndarray
|
Bias state trajectory after washout (excluding the initial state). |
t_wash |
ndarray
|
Time points of |
Source code in src/bias_estimators/esn.py
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 | |
init_forecaster(training_data_filename=None, **kwargs)
¶
Load or create the ESN_model forecaster and store it as self.forecaster.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
training_data_filename
|
str
|
Path to load/save the bias-training dataset (see
|
None
|
**kwargs
|
ESN hyperparameters and other options, forwarded to
|
{}
|
Source code in src/bias_estimators/esn.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
load_or_create_forecaster(hash=None, reference_data=None, rom=None, **kwargs)
¶
Load a cached ESN_model forecaster from disk, or train a new one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hash
|
str
|
Hash identifying the |
None
|
reference_data
|
Observations or list of Observations
|
Reference data used to build the training dataset if no cached
forecaster/dataset is found. Required (with |
None
|
rom
|
Model
|
The (biased) low-order model to sample training states from. Required
(with |
None
|
**kwargs
|
ESN hyperparameters and dataset options, used both to compute the
configuration hash and (if training) to construct the new |
{}
|
Returns:
| Type | Description |
|---|---|
ESN_model
|
A trained forecaster, either loaded from cache or newly trained. |
Source code in src/bias_estimators/esn.py
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 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 | |
load_or_create_bias_training_dataset(training_data_filename=None, rom=None, reference_data=None, std_phi=None, std_alpha=None)
¶
Load the bias-training dataset from disk, or create and cache a new one.
Delegates to load_bias_training_dataset / create_bias_training_dataset
(defined in romda.bias_estimators.aux), which handle preprocessing,
augmentation, and formatting for training the bias model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
training_data_filename
|
str
|
Filename to load/save the training dataset. |
None
|
rom
|
Model
|
ROM to sample states from, if the dataset needs to be created. |
None
|
reference_data
|
Observations or list of Observations
|
Reference data, if the dataset needs to be created. |
None
|
std_phi
|
float
|
Standard deviation for sampling initial conditions, if the dataset needs
to be created; see |
None
|
std_alpha
|
float or dict
|
Standard deviation for sampling parameters, if the dataset needs to be
created; see |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
Training-data dictionary; see |
Source code in src/bias_estimators/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 313 314 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 | |
romda.bias_estimators.ConstantBias(innovation, t, dt, k=None, **kwargs)
¶
Bases: Bias
Constant (persistent) bias estimator.
The bias is held constant between analysis steps, i.e., the forecast model of the
bias is \(\dot{\mathbf{b}} = \mathbf{0}\). At each analysis step, the bias state is
reset to the latest innovation (see Bias.update_state_from_innovation). This is
the classic persistent-bias assumption.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
innovation
|
ndarray
|
Initial innovation/bias estimate, shape (Nq,), (Nq, N_ens) or (1, Nq, N_ens). |
required |
t
|
float
|
Initial time. |
required |
dt
|
float
|
Time step of the output history. |
required |
k
|
float or ndarray
|
If provided, the initial bias state is set to the constant value(s) k instead of the provided innovation. |
None
|
Source code in src/bias_estimators/constantbias.py
33 34 35 36 37 38 39 40 | |
init_forecaster(**kwargs)
¶
Constant forecaster: no underlying model, the state is simply held in time.
Source code in src/bias_estimators/constantbias.py
65 66 67 68 69 70 71 72 73 74 75 | |
romda.bias_estimators.NoBias(innovation, t, dt, **kwargs)
¶
Bases: ConstantBias
Placeholder bias estimator that always returns zero bias. Useful to run the bias-aware machinery in its unbiased limit.
Source code in src/bias_estimators/constantbias.py
84 85 86 | |
romda.bias_estimators.aux.create_bias_training_dataset(config, rom, reference_data, minimum_training_steps, L, correlation_based_training, augment_data_length, biased_observations, std_phi=None, std_alpha=None)
¶
Build a training dataset for the bias model from ROM samples and reference data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict
|
Configuration for creating the training dataset; echoed into the returned dictionary. |
required |
rom
|
Model
|
The reduced-order model to sample states from. |
required |
reference_data
|
Observations or list of Observations
|
Reference data to prepare for training. |
required |
minimum_training_steps
|
int
|
Minimum number of time steps required for training the bias model. |
required |
L
|
int
|
Number of samples to generate from the ROM. |
required |
correlation_based_training
|
bool
|
If True, correlate the model-generated data with the raw observations (via
|
required |
augment_data_length
|
int
|
Number of augmented samples per observed variable: 1 uses only the best lag/direct pairing; 2 adds a mid-point (or scaled) sample; 3 also adds the worst lag (or oppositely-scaled) sample. |
required |
biased_observations
|
bool
|
Whether to also include the model bias (true minus model-generated data) in the training dataset, alongside the innovations. |
required |
std_phi
|
float
|
Standard deviation for sampling initial conditions; see |
None
|
std_alpha
|
float or dict
|
Standard deviation for sampling parameters; see |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
Training data for the bias model, plus the entries of
|
Source code in src/bias_estimators/aux.py
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 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | |
romda.bias_estimators.aux.sample_model_states(rom, L, minimum_training_steps, std_phi=None, std_alpha=None)
¶
Sample model states from the ROM to build a training dataset for the bias model.
- Initializes the ROM with an ensemble of states (sampled initial conditions and, if specified, parameters).
- Integrates the ROM forward in time to generate model data.
- Processes this data into a training dataset for the bias model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rom
|
Model
|
The reduced-order model to sample states from. |
required |
L
|
int
|
Number of samples (ensemble members) to generate. |
required |
minimum_training_steps
|
int
|
Minimum number of time steps to integrate the ROM for, to generate enough data for training the bias model. |
required |
std_phi
|
float
|
Standard deviation for sampling the initial conditions. If None (default), the standard deviation of the ROM's current state is used. |
None
|
std_alpha
|
float or dict
|
Standard deviation for sampling the parameters. A float is used as a
multiplier on the current-state standard deviation, giving a
|
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Observable history of the (re-)integrated ROM ensemble, used as the model data for training. |
Source code in src/bias_estimators/aux.py
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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | |
romda.bias_estimators.plot_train_data(truth, bias_data, t_CR)
¶
Plot the observable and bias training samples against the truth.
Shows one window before the first observation, colouring each training sample
(of bias_data) by its bias RMS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
truth
|
Observations
|
Reference truth used to select the plotting window and overlay the true observable/bias signals. |
required |
bias_data
|
dict
|
Training-data dictionary as returned by |
required |
t_CR
|
float
|
Characteristic (e.g. oscillation) time scale, used to set the plotting window length. |
required |
Source code in src/bias_estimators/aux.py
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 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 | |