Note
Go to the end to download the full example code.
Uncertainty quantification#
Every hydro-geophysical number carries the uncertainty of the petrophysical
assumptions behind it. MonteCarloHydro propagates
priors on the rock-physics parameters (pore-water resistivity, cementation
exponent, …) through the whole workflow, producing P10/P50/P90 maps and
profiles instead of single values. This example quantifies the uncertainty
on the synthetic section’s aquifer properties.
Monte-Carlo propagation#
UncertaintyBounds sets the prior ranges; each
draw re-runs the hydro model, and run aggregates the ensemble into an
UncertaintyResult with percentile maps and
coefficient-of-variation fields.
from _interp_data import demo_model
from pycsamt.interp import (
MonteCarloHydro,
PetrophysicalConfig,
UncertaintyBounds,
)
# Use the uncertainty section (2nd figure) as the card thumbnail.
rm = demo_model()
cfg = PetrophysicalConfig(rho_w=20.0, porosity_prior=0.25)
bounds = UncertaintyBounds(rho_w_range=(10.0, 60.0), m_range=(1.6, 2.2))
unc = MonteCarloHydro(rm, cfg, bounds, n_samples=200).run()
import numpy as np
print("worst-case CV of K:", round(float(np.nanmax(unc.cv_K)), 2))
print(
"water-table P10-P90 spread (m), first 5:",
np.round((unc.p90_wt - unc.p10_wt)[:5], 1),
)
worst-case CV of K: 0.89
water-table P10-P90 spread (m), first 5: [0. 0. 0. 0. 0.]
Uncertainty section#
PlotUncertaintySection pairs the P50 estimate
(top) with its spread (bottom) for a chosen quantity — so a confident,
high-K aquifer cell is visibly distinct from a high-K cell that is
merely a lucky draw.
from pycsamt.interp.plot import (
PlotUncertaintyHistogram,
PlotUncertaintyProfile,
PlotUncertaintySection,
)
PlotUncertaintySection(unc, quantity="K").plot()
![Uncertainty section — K [ N=200], P50 estimate, Uncertainty spread](../../_images/sphx_glr_plot_8_uncertainty_001.png)
<Figure size 1300x800 with 4 Axes>
Water-table and transmissivity with error bands#
PlotUncertaintyProfile is the water-table /
transmissivity profile from Hydro-geophysics: aquifer properties, now with
P10-P90 envelopes — the honest version of a well-siting figure.
PlotUncertaintyProfile(unc, reference_depth=20.0).plot()
![WT & T uncertainty profile [ N=200]](../../_images/sphx_glr_plot_8_uncertainty_002.png)
<Figure size 1300x600 with 2 Axes>
Distribution of a target property#
PlotUncertaintyHistogram shows the full
ensemble distribution of a scalar target (e.g. peak transmissivity),
making the shape of the uncertainty — skew, multi-modality — explicit
rather than collapsing it to a single error bar.
PlotUncertaintyHistogram(unc).plot()
![Posterior histogram — water table [N=200], S00, S07, S014, S021, S028, S035](../../_images/sphx_glr_plot_8_uncertainty_003.png)
<Figure size 1200x700 with 6 Axes>
Reading it. Uncertainty is largest where the aquifer is thin or its resistivity sits near a unit boundary, and smallest in the thick clean sand — so report calibrated P10-P90 ranges, not point values, whenever the interpretation feeds a drilling or management decision. This closes the interpretation workflow: model -> lithology -> hydrogeology -> properties -> calibration -> monitoring -> uncertainty.
Total running time of the script: (0 minutes 8.550 seconds)