Download notebook · Download runnable bundle
Dependencies: PySTRA core.
Distribution adapters and analysis cost#
Compare the cost of the same SORM analysis using PySTRA distributions and equivalent SciPy distribution adapters. Timings depend on the machine, dependency versions and solver settings; the measured ratios below are observations for this run.
Before you start: the introductory and SciPy-distribution tutorials. NumPy and SciPy are included in the core installation.
[1]:
import pystra as ra
from scipy.stats import norm, lognorm, uniform
import numpy as np
import timeit
Define a reasonably complex limit-state function
[2]:
def lsf(r, X1, X2, X3):
g = r - X2 * (1000 * X3) ** (-1) - (X1 * (200 * X3) ** (-1)) ** 2
return g
Define some objects common to both sets of analyses:
[3]:
limit_state = ra.LimitState(lsf)
options = ra.FORMOptions()
The analysis using the distributions built in to PySTRA:
[4]:
def run_builtin():
"""
The basic example using built-in distributions
"""
stochastic_model = ra.StochasticModel()
stochastic_model.add_variable(ra.Lognormal("X1", 500, 100))
stochastic_model.add_variable(ra.Normal("X2", 2000, 400))
stochastic_model.add_variable(ra.Uniform("X3", 5, 0.5))
stochastic_model.add_variable(ra.Constant("r", 1))
stochastic_model.set_correlation(
ra.CorrelationMatrix([[1.0, 0.3, 0.2], [0.3, 1.0, 0.2], [0.2, 0.2, 1.0]])
)
sorm = ra.SORM(
model=stochastic_model,
limit_state=limit_state,
options=ra.SORMOptions(form=options),
)
sorm_result = sorm.run()
assert sorm_result.converged
return sorm_result.approximations["breitung"]
The analysis using the equivalent distributions in SciPy
[5]:
def run_scipy():
"""
The basic example using Scipy distributions
"""
stochastic_model = ra.StochasticModel()
# Lognormal
zeta = (np.log(1 + (100 / 500) ** 2)) ** 0.5
lamb = np.log(500) - 0.5 * zeta**2
stochastic_model.add_variable(
ra.ScipyDist("X1", lognorm(s=zeta, scale=np.exp(lamb)))
)
# Normal
stochastic_model.add_variable(ra.ScipyDist("X2", norm(loc=2000, scale=400)))
## Uniform
a_b = (0.5**2 * 12) ** (1 / 2)
a = (2 * 5 - a_b) / 2
stochastic_model.add_variable(ra.ScipyDist("X3", uniform(loc=a, scale=a_b)))
# Constant
stochastic_model.add_variable(ra.Constant("r", 1))
stochastic_model.set_correlation(
ra.CorrelationMatrix([[1.0, 0.3, 0.2], [0.3, 1.0, 0.2], [0.2, 0.2, 1.0]])
)
sorm = ra.SORM(
model=stochastic_model,
limit_state=limit_state,
options=ra.SORMOptions(form=options),
)
sorm_result = sorm.run()
assert sorm_result.converged
return sorm_result.approximations["breitung"]
Check agreement and measure execution time#
Check the two implementations before comparing their speed. This isolates distribution-adapter overhead; it does not predict the cost of an external structural model.
[6]:
builtin_probability = run_builtin()
scipy_probability = run_scipy()
np.testing.assert_allclose(builtin_probability, scipy_probability, rtol=1e-4)
number = 100
time_builtin = timeit.timeit(stmt=run_builtin, number=number)
time_scipy = timeit.timeit(stmt=run_scipy, number=number)
print("Total time taken (s)")
print(f"Built-in: {time_builtin}; Scipy: {time_scipy}")
print("Average time per call (s):")
print(f"Built-in: {time_builtin/number}; Scipy: {time_scipy/number}")
print(f"Built-in speed-up: {time_scipy/time_builtin:.2f}")
Total time taken (s)
Built-in: 1.4266015900000184; Scipy: 6.354021983999985
Average time per call (s):
Built-in: 0.014266015900000184; Scipy: 0.06354021983999986
Built-in speed-up: 4.45
Interpretation#
Use the numerical agreement check before drawing performance conclusions. For an expensive structural model, model-evaluation cost can dominate the distribution overhead measured here.
Continue: User guide · API reference · Theory