TesiproV – Reliability Analysis Methods for Structural Engineering

Til Lux, Konstantin Nille-Hauf, Tania Feiri, Marcus Ricker

2026-10-28

This document describes how the TesiproV package can be used. The package was developed as part of the “TesiproV” research project (sponsored by BMWi, the German Federal Ministry for Economic Affairs and Energy) and is used for the probabilistic safety assessment of structural components and systems. The source code of the package is freely available as open source.

Introduction

The TesiproV package provides a flexible and extensible framework for probabilistic reliability analysis of structural components and systems.
It enables engineers and researchers to quantify the safety level of structures by evaluating the probability of failure under uncertain loads, material properties and geometric parameters.

In classical deterministic design procedures, reliability is ensured through partial safety factors that implicitly account for uncertainties.
However, such approaches often lack transparency regarding the actual reliability achieved.
Probabilistic methods overcome this limitation by explicitly modelling all relevant sources of uncertainty — e.g., variability in material strength, load effects or model uncertainties — as random variables with defined statistical distributions.

The fundamental concept behind reliability analysis is the limit‑state function \(g(X) = 0\), which separates safe from failed states:

\[ g(X) = R(X) - E(X) = 0 \]

where \(R(X)\) represents the resistance and \(E(X)\) denotes the load effect.
Failure occurs when \(g(X) < 0\). The random vector \(X = [X_1, X_2, …]\) contains all basic variables describing these uncertainties.

The probability of failure can then be expressed as:

\[ P_f = P[g(X) < 0] \]

and converted into a reliability index β via

\[ β = -Φ^{-1}(P_f) \]

where Φ denotes the cumulative standard normal distribution.
Both the reliability index and the probability of failure are measures used to assess and compare reliability. The calculated probability of failure differs from the actual probability of failure, as the governing factor for the failure of a component or structure — human error — is not captured in the analysis.

TesiproV implements several algorithms to estimate these quantities efficiently:

These methods allow both single limit‑state analyses and complex system evaluations involving multiple interacting components.
In addition, TesiproV supports parametric studies where selected input parameters are systematically varied to investigate sensitivity or perform probabilistic optimisation.

Independent of the solution algorithms, the effect of quality control on the distribution of a basic variable can be taken into account. Sampling plans with their operating characteristic (OC) curves are defined by PROB_QUALCON, and the posterior distribution of the controlled variable is derived by Bayesian updating. The updated variable is then used like any other basic variable in the reliability analysis.

Since version 0.9.5 the entire code base has been refactored to improve consistency between probabilistic objects (PROB_BASEVAR, SYS_LSF, SYS_PROB, …), error handling in limit‑state functions ($check()), transformations between mean/standard deviation and native distribution parameters ($prepare()), and parallel execution via the future package was added.

Version 1.0.0 is a consolidated release of the package, based on more than two years of use. It solves single limit-state functions as well as systems of several limit-state functions. Since this version, the influence of quality controls on the distribution of basic variables can also be taken into account (see the section on PROB_QUALCON).

Beyond its computational capabilities, TesiproV aims to provide a transparent educational tool for understanding reliability theory in structural engineering practice.
Its object‑oriented design makes it straightforward to define new limit‑state functions, integrate additional distributions or link external solvers, e.g., for advanced Monte Carlo techniques.

The project was originally initiated at Hochschule Biberach in cooperation with the Institute of Structural Concrete at RWTH Aachen University within a BMWi research program (Allgemeingültiges Verfahren zur Herleitung von Teilsicherheitsbeiwerten im Massivbau auf Basis probabilistischer Verfahren anhand ausgewählter Versagensarten (TesiproV) – Erstellung eines Richtlinienentwurfs, FKZ 03TNK003E) and is now maintained by the Chair of Structural Concrete at TU Dortmund University.

Source code repository: https://gitlab.tu-dortmund.de/ls-massivbau/tesiprov
License: MIT

Installation

Official releases of the R package TesiproV are available on CRAN (https://CRAN.R-project.org/package=TesiproV) and can be installed in R as:

install.packages("TesiproV")

You can install a pre-release version of TesiproV directly from the GitLab server at TU Dortmund University:

remotes::install_gitlab("ls-massivbau/tesiprov", host = "gitlab.tu-dortmund.de")

If you need any permissions, please contact .

Make sure to initialize the TesiproV package before using it:

library("TesiproV")

Conceptual background

Reliability analysis quantifies how likely a structure will perform safely throughout its lifetime despite inherent uncertainties. Typical sources of uncertainty include variations in geometry (e.g., effective depth), material properties (e.g., concrete strength), loading conditions (permanent vs variable actions), environmental influences and modelling simplifications. Within TesiproV every uncertain quantity is represented by an object-oriented random variable definition. Transformation between mean value / standard deviation and native distribution parameters is handled automatically, ensuring consistent probabilistic input even when empirical data are incomplete. System reliability can be evaluated either analytically using bounds (“SimpleBounds”) or numerically via simulation-based approaches. Parallelisation through the parallel (base R) and future backend allows efficient computation even for large-scale Monte-Carlo analyses on multi-core machines.

Basic building blocks

Random variable objects

A basic random variable describes an uncertain quantity used in a limit-state function. It is defined by its statistical distribution type (including parameters) or its statistical moments (mean value (Mean) and standard deviation (Sd)). Supported distributions include:

Distribution Identifier Package Description
Normal "norm" stats Gaussian distribution defined by mean and standard deviation
Lognormal "lnorm" stats Distribution of a variable whose logarithm is normally distributed
Shifted lognormal "slnorm" TesiproV Lognormal distribution shifted by the lower bound x0
Gumbel (Type I extreme value) "gumbel" evd Used for modelling maxima or minima (extreme values)
Gamma "gamma" stats Positive-valued model defined by shape and scale parameters
Exponential "exp" stats Special case of gamma with shape = 1
Beta "beta" stats Bounded on [0,1], often used for proportions or probabilities
Weibull "weibull" stats Flexible positive-valued model for material strength or lifetime data
Student-t "st" TesiproV Heavy-tailed, marginal distribution of a normal variable with uncertain mean and standard deviation
Log-Student-t "lt" TesiproV Heavy-tailed, marginal distribution of a lognormal variable with uncertain parameters
Empirical "emp" EnvStats Empirical distribution based on given data
Binomial "binom" stats Discrete count data, placeholder type
Uniform "unif" stats Constant probability across an interval, placeholder type

Additional placeholders exist for future extensions.

Example – PROB_BASEVAR

var_fck <- PROB_BASEVAR(
  Id = 1,
  Name = "f_ck",
  Description = "Concrete compressive strength",
  DistributionType = "lnorm",
  Mean = 47.35,
  Sd = 5.86
)
  • Id - numeric, for identification purpose
  • Name - Name of the var, must be the same as in the function input
  • Description - Description for the output protocol
  • Package - Packagename, which provides the distribution function (dname,pname,qname,rname; name=DistributionType)
  • DistributionType - Name of the distributionfunction (without the d, p, q or r)
  • Mean - Expected value (first statistical moment)
  • Sd - standard deviation (square root of second statistical moment)
  • Cov - coefficient of variation: Cov = Sd/Mean
  • x0 - location parameter, used for shifted log-normal distribution “slnorm”

Internally TesiproV automatically derives all missing distribution parameters such as shape or scale parameters from the given expected value (mean) and standard deviation (square root of variance) if possible.

Basic variable using the example of concrete compressive strength. As distribution function a logStudentT-distribution adjusted within the package is used. For this distribution a d-, p-, q- and rlt-function is available, therefore Package = “TesiproV”.

var.f_ck <- PROB_BASEVAR(Id = 1, Name = "f_ck", Description = "Concrete compressive strength", Package = "TesiproV", DistributionType = "lt", DistributionParameters = c(3.85, 0.09, 3, 10))

Parametric random variables

To perform parameter studies over varying input values (e.g., different mean strengths or load levels), use PARAM_BASEVAR. It extends PROB_BASEVAR with fields defining which property should vary (ParamType) and which values are tested (ParamValues).

Example – PARAM_BASEVAR

pvar_d <- PARAM_BASEVAR(
  Id = 1,
  Name = "d",
  Description = "Effective depth",
  DistributionType = "norm",
  Sd = 10,
  ParamType = "Mean",
  ParamValues = c(seq(200, 800, 50), seq(1000, 3000, 100)) + 10
)

Deterministic variables

If certain quantities are treated as deterministic constants rather than random variables, they can be modelled using PROB_DETVAR. Internally these are represented as normal distributions with infinitesimal standard deviation so that all algorithms remain compatible.

Example PROB_DETVAR

var.gamma_c <- PROB_DETVAR(Id = 1, Name = "gamma_c", Description = "PSF Concrete", Value = 1.5)

During each iteration of a parametric study the corresponding value from ParamValues is assigned automatically.

Parametric deterministic variables

Frequently, deterministic variables in a parameter calculation also depend on the varying parameter size. In these cases, a parametric deterministic variable can be created. With each iteration of the parametric base variable, the next step of the parametric deterministic variable is also used.

In this case, a normal distribution with infinitesimal standard deviation is also used internally.

Note: Parametric variables are only considered for the parametric system object (SYS_PARAM) while the normal system object (SYS_PROB) only uses the default value.

Example PARAM_DETVAR

var.V_Ed <- PARAM_DETVAR(Id = 1, Name = "V_Ed", Description = "applied shear force", ParamValues = c(1, 2, 3, 4, seq(5, 10, 0.5)))

Quality control and Bayesian updating (PROB_QUALCON)

Quality controls (e.g. the conformity control of concrete or the inspection of dimensions on site) accept or reject a lot. An accepted lot is on average better than the prior assumption. TesiproV quantifies this effect: the object PROB_QUALCON describes the sampling plan and computes its OC curve, and PROB_BASEVAR$updateBasevar() derives the posterior distribution of the controlled basic variable.

Principle

A lot is characterised by its defect fraction \(\theta\), i.e. the share of units that violate a limit value. The OC curve gives the probability that the lot is accepted by the sampling plan:

\[ P_a(\theta) \]

The distribution of the controlled variable is described by a Student-t ("st") or log-Student-t ("lt") distribution with the hyperparameters \(c(m', s', n', v')\), which also express the uncertainty of the distribution parameters. Every parameter combination belongs to one defect fraction \(\theta\) and is therefore weighted with its acceptance probability \(P_a(\theta)\). The result is the outgoing distribution of the accepted lots. It is fitted by a new "st" or "lt" distribution. If the quality of the fit is not sufficient (min_r2 in updateBasevar()), an empirical distribution is returned instead.

The prior variable must therefore be defined with DistributionType = "st" or "lt" and the four hyperparameters in DistributionParameters.

Sampling plans

The plan is chosen with the field ConformityType:

  • "fck_EN-206" with ConformityParam = c(n): variable plan, conformity criterion of EN 206 for the compressive strength. A lot is accepted if the mean of n samples is at least \(f_{ck} + 1.48 s\) and the smallest value at least \(f_{ck} - 4\). The OC curve of this plan is simulated. The Monte Carlo sample size per defect fraction is set with the field NSim (default 100000).
  • "dim_k||n" with ConformityParam = c(n, c_accept): attribute plan with a binomial model. A lot is accepted if at most c_accept of n units are defective. It can be used for any characteristic that is checked against tolerance values, e.g. concrete cover or dimensions.

The fields DefectLimitLower and DefectLimitUpper only define when a single unit counts as defective. They are not the acceptance criterion, which is determined by the sampling plan alone.

  • For "fck_EN-206" the characteristic strength \(f_{ck}\) is given as DefectLimitLower (in the unit of the variable). DefectLimitUpper must stay Inf.
  • For "dim_k||n" at least one of the two limits must be finite. Both limits are freely selectable and do not influence the OC curve, only the update.

Fields and methods:

  • var - the PROB_BASEVAR the plan applies to.
  • NSim - Monte Carlo sample size per defect fraction for the simulation of the OC curve (only for "fck_EN-206", default 100000).
  • theta_grid - defect fractions at which the OC curve is evaluated (default grid from 0.001 to 0.9).
  • Pa_grid - acceptance probabilities for theta_grid, filled by $getOC().
  • $getOC(force = FALSE) - computes the OC curve. An existing curve is only recomputed with force = TRUE.
  • $plot() - plots the OC curve.
  • $isStale() - TRUE if the distribution of var has changed since $getOC() was run (the curve is then outdated), NA if no snapshot exists.
  • $summary() - short printed overview.

If the OC curve of a plan is known from another source, it can be specified manually by passing theta_grid and Pa_grid of the same length. ConformityParam is then not needed. For "fck_EN-206" DefectLimitLower must still be set.

Example - variable plan for the concrete strength

The compressive strength is modelled by a log-Student-t distribution with the hyperparameters \(c(3.75, 0.105, 3, 10)\). The control follows EN 206 with 15 samples for \(f_{ck} = 30\) N/mm².

set.seed(1)
fc <- PROB_BASEVAR(
  Id = 1, Name = "fc", Description = "Concrete compressive strength",
  DistributionType = "lt", DistributionParameters = c(3.75, 0.105, 3, 10)
)

plan <- PROB_QUALCON(
  Name = "EN206_n15", ConformityType = "fck_EN-206",
  ConformityParam = 15, NSim = 20000, DefectLimitLower = 30, var = fc
)
plan$getOC()
plan$plot()

updateBasevar() returns a new PROB_BASEVAR object with the posterior distribution. The prior object stays unchanged. The message printed by updateBasevar() compares the mean value and the standard deviation of prior and posterior. For hyperparameter-defined variables the prior moments are exact for "st" with \(v' > 2\). For "lt" they are not defined analytically and are therefore approximated numerically, which is marked in the message.

fc_post <- fc$updateBasevar(plan)
#> updateBasevar complete.
#>   Prior     : Mean = 42.9141  Sd = 5.8751  (numerical approximation)
#>   Posterior : Mean = 43.3318  Sd = 5.4219

The moments of the posterior are also available as fields of the new object:

c(Mean = fc_post$Mean, Sd = fc_post$Sd)
#>      Mean        Sd 
#> 43.331813  5.421924

Prior and posterior density can be compared with the argument prior:

fc_post$plot(prior = TRUE)

Example - attribute plan for the concrete cover

At most one of ten measured values may be outside the limits 27 mm and 33 mm.

cover <- PROB_BASEVAR(
  Id = 2, Name = "cover", DistributionType = "st",
  DistributionParameters = c(30, 2, 3, 10)
)
plan_cover <- PROB_QUALCON(
  Name = "cover_plan", ConformityType = "dim_k||n", ConformityParam = c(10, 1),
  DefectLimitLower = 27, DefectLimitUpper = 33, var = cover
)
plan_cover$getOC()
cover_post <- cover$updateBasevar(plan_cover)

The mean value remains unchanged, because the limits are symmetric about the prior mean. The standard deviation decreases.

cover_post$plot(prior = TRUE)

Limit-state function object (SYS_LSF)

A limit-state function encapsulates the mathematical definition of failure. It can be provided either as an explicit R function or as an arithmetic expression converted internally into a callable closure.

Variables are used as input values for the functions. The naming in the function header (function(E, R)) must correspond to its use in the function body (function(E,R){R-E}). The naming must also match the name of the variable itself. Therefore, a list() with all used PROB_BASEVAR() objects is passed to the SYS_LSF() object (note: the objects with their variable names, here var1 and var2, are to be passed, not the variable name itself). In the case of multiple limit state functions being used, the function can be given a name to make it easier to assign in printouts later. An objective function() can then be defined via the $func() property. Alternatively, $expr() can be used to assign an expression(R-E). By means of $check() an internal check run is performed, which ensures that all the base variables are complete and suitable.

Example SYS_LSF

var1 <- PROB_BASEVAR(Name = "E", Description = "Effect", DistributionType = "norm", Mean = 10, Sd = 1)
var2 <- PROB_BASEVAR(Name = "R", Description = "Resistance", DistributionType = "norm", Mean = 15, Sd = 1.5)


lsf <- SYS_LSF(vars = list(var1, var2), name = "LSF XY")
lsf$func <- function(E, R) {
  R - E
}
# you can run this check to see if all transformations of the variables worked, all needed data is available and the set of vars fits to the limit state function
lsf$check()

The $check() method validates that all associated variables are consistent before analysis begins.

Reliability algorithms (PROB_MACHINE)

Reliability assessment methods are implemented in modular solver objects called PROB_MACHINE. Each machine defines one algorithm via its field $fCall (e.g., "FORM", "SORM", "MC_CRUDE") together with optional settings stored in $options.

Levels 2 and 3 can be implemented by means of this package (in order to validate Level 1 procedures). The accuracy of the calculated failure probabilities - and ultimately, reliability indexes - increases through the levels.

A solution-oriented approach is always modelled in a so-called PROB_MACHINE(), i.e., an object that stands for a solution algorithm. Over the property fCall, the following reliability assessment methods are available:

Level 2 Methods: * Mean Value First-Order Second Moment (MVFOSM) * Advanced First-Order Reliability Method (FORM) * Second-Order Reliability Method (SORM)

Level 3 Methods: * Crude Monte-Carlo Simulation (MC_CRUDE) * Monte-Carlo Simulation with Importance Sampling (MC_IS) * Monte-Carlo Simulation with Subset Sampling (MC_SubSam)

The property $name serves again for better identification in the later output protocol. A list() object in the $options property can then be used to specify special options according to the methods.

MVFOSM

Options:

  • h - Accuracy of partial derivatives (finite difference method).
  • isExpression - FALSE/TRUE MVFOSM can handle both expressions and functions.

Example:

machine <- PROB_MACHINE(name = "MVFOSM", fCall = "MVFOSM", options = list("isExpression" = FALSE, "h" = 0.1))

FORM

Options:

  • n_optim - max. amount of evaluation runs
  • loctol - local accuracy of the optimisation algorithm (if lower then this threshold, the optim stops)
  • optim_type - solver, one of
    • "auto" (default) - SLSQP, with improved HLRF (iHLRF) as fallback if SLSQP does not converge. The result field fallback shows whether the fallback was used.
    • "slsqp" - sequential quadratic programming (package nloptr), no fallback. Good for low-dimensional spaces
    • "ihlrf" - improved HLRF with line search, no fallback.
    • "rackfies" - Rackwitz-Fiessler iteration (classic HLRF), no fallback.
    • "auglag" - Augmented Lagrange solver (nloptr) with random starts.

Example:

machine <- PROB_MACHINE(name = "FORM Rack.-Fies.", fCall = "FORM", options = list("n_optim" = 20, "loctol" = 0.001, "optim_type" = "rackfies"))

machine <- PROB_MACHINE(name = "FORM Lagrange.", fCall = "FORM", options = list("optim_type" = "auglag"))

SORM

Options:

  • No settings possible

Example:

machine <- PROB_MACHINE(name = "SORM", fCall = "SORM")

MC_Crude

Options:

  • cov_user=0.05 - abort criterion for the CoV.
  • n_batch=10000 - samples per step.
  • n_max=1e7 - abort criterion for the maximum number of samples.
  • use_threads=NULL - number of workers for backend = “parallel” (default 1). Without effect for backend = “future”.
  • backend=NULL - “future” or “parallel”. If not set, the calculation runs sequentially.
  • dataRecord=TRUE - if TRUE, the results per step are returned in data (used for visualization of beta).
  • debug.level=0 - verbosity level (0 = silent, 1 = summary, 2 = detailed).
  • seed - optional integer seed for reproducible random numbers.

Example:

machine <- PROB_MACHINE(name = "MC CoV 0.05", fCall = "MC_CRUDE", options = list("n_max" = 1e6, "cov_user" = 0.05))

MC_IS

Options:

  • cov_user=0.05 - abort criterion for the CoV.
  • n_batch=5000 - samples per step.
  • n_max=1e6 - abort criterion for the maximum number of samples.
  • use_threads=NULL - number of workers for backend = “parallel” (default 1). Without effect for backend = “future”.
  • backend=NULL - “future” or “parallel”. If not set, the calculation runs sequentially.
  • sys_type=“serial” - “serial” or “parallel”, only used for systems.
  • dataRecord=TRUE - if TRUE, the results per step are returned in data (single limit-state function only).
  • dps - optional design points in physical space. If supplied, FORM is skipped (see help("MC_IS") for the format for systems).
  • stability_mode=“robust” - “robust” or “fast”, without influence on the result.
  • debug.level=0 - verbosity level (0 = silent, 1 = summary, 2 = detailed).
  • seed - optional integer seed for reproducible random numbers.

Further options can be found in the documentation of MC_IS. Changing the options is not recommended for inexperienced users.

help("MC_IS")

Example:

machine <- PROB_MACHINE(name = "MC IS", fCall = "MC_IS", options = list("cov_user" = 0.05, "n_max" = 300000))

MC_SubSam

Options:

  • Nsubset=1e5 - number of samples in each simulation level.
  • p0=0.1 - level probability or conditional probability.
  • MaxSubsets=10 - maximum number of simulation levels that are used to terminate the simulation procedure to avoid infinite loop when the target domain cannot be reached.
  • Alpha=0.05 - confidence level.
  • variance=“uniform” - “gaussian” or “uniform”.
  • debug.level - Integer verbosity level (0 = silent, 1 = summary, 2 = detailed).
  • seed - Optional integer seed for reproducible random numbers.

Example:

machine <- PROB_MACHINE(name = "MC Subset Sampling", fCall = "MC_SubSam", options = list("variance" = "uniform"))

System objects

The system object combines all the previous objects and organises the correct calculation of the mathematical model. Two main classes exist:

The SYS_LSF object already contains a list of the required basic variables. However, the system object still requires a list of functions to be calculated and the list of algorithms to be used. In addition, the $sys_type property can be used to specify whether the equations have a series $sys_type="serial" or parallel $sys_type="parallel" relationship.

The calculation process is then triggered with $runMachines(). In the console, the user is informed about the current state of the calculation. After completing the calculation, the results can be retrieved via the SYS_PROB object (in the example below ps). For more information see result interpretation.

You can set a debug.level field of SYS_PROB to 1 or 2, to get more information during the calculation, by default that value is zero.

Example – single problem

var1 <- PROB_BASEVAR(Name = "E", Description = "Effect", DistributionType = "norm", Mean = 10, Sd = 1)
var2 <- PROB_BASEVAR(Name = "R", Description = "Resistance", DistributionType = "norm", Mean = 15, Sd = 1.5)


lsf <- SYS_LSF(vars = list(var1, var2), name = "LSF XY")
lsf$func <- function(E, R) {
  R - E
}
# you can run this check to see if all transformations of the variables worked, all needed data is available and the set of vars fits to the limit state function
lsf$check()


machine <- PROB_MACHINE(name = "FORM Rack.-Fieß.", fCall = "FORM", options = list("n_optim" = 20, "loctol" = 0.001, "optim_type" = "rackfies"))

ps <- SYS_PROB(
  sys_input = list(lsf),
  probMachines = list(machine),
  debug.level = 0
)

ps$runMachines()

Retrieve results

ps$beta_single
#>                    LSF XY
#> FORM Rack.-Fieß. 2.773501

Example – system calculations

For systems consisting of multiple LSFs connected either in series or in parallel:

# System calculation (System of two identical LSFs)
ps_sys <- SYS_PROB(
  sys_input = list(lsf, lsf),
  probMachines = list(machine),
  sys_type = "serial"
)

ps_sys$runMachines()
ps_sys$calculateSystemProbability()

Resulting system reliability indices:

ps_sys$beta_sys
#>                               [,1]
#> SB min (FORM Rack.-Fieß.) 2.540293
#> SB max (FORM Rack.-Fieß.) 2.773501

The method of the system calculation is selected with the argument calcType of $calculateSystemProbability():

  • "simpleBounds" (default) - bounds from the single reliability indices of $runMachines(). The machines can be FORM, SORM or other methods.
  • "MCIS" - importance sampling for serial and parallel systems.
  • "MCC" - crude Monte Carlo simulation of the system limit-state function.
  • "MCSUS" - subset simulation of the system limit-state function.

A system analysis by FORM or SORM is not available. These methods only provide the single results for the simple bounds.

Parametric studies (SYS_PARAM)

Parametric analyses use the class SYS_PARAM. This extends SYS_PROB to iterate over varying input parameters defined by one or more PARAM_BASEVAR objects.

Example:

# Force in kN
pvar_F_mod <- PARAM_BASEVAR(
  Name = "Force", DistributionType = "gumbel", Sd = 2, Package = "evd",
  ParamType = "Mean", ParamValues = c(17, 18, 19, 20) 
)

# yield strength in kN, for Mean the mean of the unshifted distribution must be specified.
fy <- PROB_BASEVAR(
  Name = "fy", DistributionType = "slnorm", Package = "TesiproV", Mean = 265000, Sd = 25000, x0 = 160000
)

# plastic moment of resistance in m³ - considered deterministic in this example
W_pl <- 2.5e-4 
# length of cantilever beam in m - considered deterministic in this example
l    <- 2     

lsf_param <- SYS_LSF(vars = list(pvar_F_mod, fy), name = "Spaethe (1992) - Beispiel 2")
lsf_param$func <- function(Force,fy) {
  return(W_pl*fy-l*Force)
}

machine_form <- PROB_MACHINE(name = "FORM", fCall = "FORM")

ps_param <- SYS_PARAM(
  sys_input = list(lsf_param),
  probMachines = list(machine_form)
)

ps_param$runMachines()
print(ps_param$beta_params)
#> $`Paramrun No. 1. Paramname Force with value(Type): 17.000000 (Mean)`
#>      Spaethe (1992) - Beispiel 2
#> FORM                    3.775581
#> 
#> $`Paramrun No. 2. Paramname Force with value(Type): 18.000000 (Mean)`
#>      Spaethe (1992) - Beispiel 2
#> FORM                     3.61394
#> 
#> $`Paramrun No. 3. Paramname Force with value(Type): 19.000000 (Mean)`
#>      Spaethe (1992) - Beispiel 2
#> FORM                    3.445885
#> 
#> $`Paramrun No. 4. Paramname Force with value(Type): 20.000000 (Mean)`
#>      Spaethe (1992) - Beispiel 2
#> FORM                    3.270672

Results per iteration can be easily visualised:

para_values <- c(17, 18, 19, 20) 
beta_values <- ps_param$beta_params
plot(para_values, beta_values, type = "l", xlab = "Force F [kN]", ylab = "Reliability index β [-]")

Parallelisation in TesiproV

General

TesiproV supports parallel execution for the Monte Carlo-based reliability methods MC_IS() and MC_CRUDE(). MC_SubSam() runs in a single process. The package provides two parallel backends:

  • “parallel” – based on base R’s parallel package
  • “future” – based on the future ecosystem

MC_IS() does not modify the active future plan, users configure parallel execution explicitly. MC_IS() and MC_CRUDE() do not modify the active future plan, users configure parallel execution explicitly.

Reproducibility and Determinism

MC_IS() is designed to be:

  • Deterministic for a fixed seed
  • Independent of the number of worker threads
  • Independent of the selected backend

This means that:

MC_IS(..., seed = 123, use_threads = 1)
MC_IS(..., seed = 123, use_threads = 8)

will produce identical results up to rounding errors.

Determinism is guaranteed by performing all random number generation in the master process. Worker processes do not generate random numbers.

MC_CRUDE() follows the same principle: all random numbers are generated in the master process, so the result for a fixed seed does not depend on the number of workers.

Backend Overview

  1. The “parallel” Backend
  • Uses parallel::mclapply() on Linux/macOS
  • Uses PSOCK clusters on Windows
  • Suitable for high-performance Linux clusters
  • No dependency on future

Example:

MC_IS(..., backend = "parallel", use_threads = 8)
  1. The “future” Backend

Delegates parallelisation to the future framework. TesiproV does not change the global future plan. Users must configure parallel execution explicitly.

Linux / macOS example:

library(future)
plan(multicore, workers = 8)

MC_IS(..., backend = "future")

Windows example:

library(future)
plan(multisession, workers = 8)

MC_IS(..., backend = "future")
# If no future plan is set, execution will be sequential.

Batch Size Selection

Performance improves significantly when n_batch is large enough to amortize parallel overhead.

Typical observations:

  • Small batches -> overhead dominates
  • Medium batches -> optimal performance
  • Very large batches -> memory-bound regime

For HPC workloads, a batch size between:

250,000 -- 500,000

often provides near-optimal performance.

Performance Characteristics

Parallel scaling depends on:

  • LSF computational complexity
  • Memory bandwidth
  • NUMA architecture
  • Batch size

For CPU-intensive LSFs, typical scaling on modern multi-core systems is:

  • 2 threads -> ~1.6x speedup
  • 4 threads -> ~2.8-3.5x
  • 8 threads -> ~4-6×
  • 16 threads -> ~6-9×
  • 32 threads -> often limited by memory bandwidth

HPC Usage Notes

On large Linux clusters (e.g., NUMA systems):

  • future(multicore) typically provides the best performance
  • Avoid very small n_batch values
  • Prefer 8-16 threads for optimal efficiency
  • Use deterministic seeds for reproducible studies

Example HPC workflow:

library(future)
plan(multicore, workers = 16)

res <- MC_IS(
  lsf = my_lsf,
  lDistr = my_distr,
  n_batch = 300000,
  backend = "future",
  seed = 12345
)

Interpretation of results and post processing

After computation each system object contains structured result lists: For regular problems (SYS_PROB):

Here beta_* is the beta values summarised while res_* is the full result output via list(). The list $res_* is structured as follows ps$res_*[[lsf]][[machine]]$value.

For parametric studies (SYS_PARAM):

where the first list level of $res_params corresponds to the parameter iterations. The data can be then processed individually.

In addition, the results can be printed to a file using the command $printResults(filename), where filename corresponds to the file name and the file is stored in the current working directory (see getwd() or setwd()).

The project can also be stored differently to allow later postprocessing in other files. For this, the command $saveProject(level,filename) is used. The following stages describe a different level of detail:

Stages 1 to 3 can be then read back into working memory using the readRDS(filename) command, while Stage 4 is reloaded using load(filename).

Example:

ps <- SYS_PARAM(
  sys_input = list(lsf),
  probMachines = list(machine)
)

ps$runMachines()

local_beta <- ps$beta_params
local_runtime <- ps$res_params[[1]][[1]][[1]]$runtime

# define path with setwd("...")
ps$printResults("result_file") # report file result_file.txt
ps$saveProject(2, "project_file") # results in project_file_res.rds
ps$saveProject(4, "project_file") # workspace in project_file.RData

The results can be reloaded later via:

readRDS("project_file_res.rds")
load("project_file.RData")

Debug output verbosity is controlled by field $debug.level (0=silent … 2=detailed).

Examples

Two normally distributed variables

A limit state equation 20-(x1-x2)^2-8*(x1+x2-4)^3 is to be investigated, where X1 and X2 are normally distributed around the expected value of 0.25 and the standard deviation of 1. The example is taken from the documentation of the UQLab software.

Firstly, two basic variables are created and assigned to the R variables Var1 and Var2. The first variable is named as “X1” and the second as “X2”. These names are then reused in the definition of the limit state function (i.e., to compare the input variables of the function). In addition, both variables receive the indicator “norm” as distribution type (DistributionType) and the mean value defined above or the corresponding standard deviation.

Subsequently, a limit state function object (SYS_LSF) is assigned to the R variable lsf. A list of variables (Var1,Var2) is passed to the object and a name is assigned for later identification. In addition, the corresponding limit state equation is defined via the object property “func”.

The R variable “FORM” is assigned a solution method of the Level 2 (FORM) without any additional parameters.

Finally, the modules are merged in the SYS_PROB object and the R variable “ps” and the calculation is started by means of the $runMachines() method. In the following result log the intermediate results of the individual iteration steps are shown. Using the “ps” object, different results (here, for example, the beta value) can be retrieved after a successful calculation.

Var1 <- PROB_BASEVAR(Id = 1, Name = "X1", DistributionType = "norm", Mean = 0.25, Sd = 1) # kN/m²
Var2 <- PROB_BASEVAR(Id = 2, Name = "X2", DistributionType = "norm", Mean = 0.25, Sd = 1) # m

lsf <- SYS_LSF(vars = list(Var1, Var2), name = "UQLab 2d_hat")
lsf$func <- function(X1, X2) {
  return(20 - (X1 - X2)^2 - 8 * (X1 + X2 - 4)^3)
}

form <- PROB_MACHINE(name = "FORM Rack.-Fieß.", fCall = "FORM")

ps <- SYS_PROB(
  sys_input = list(lsf),
  probMachines = list(form)
)
ps$runMachines()
ps$beta_single
#>                  UQLab 2d_hat
#> FORM Rack.-Fieß.     3.434565

Non-normally distributed basic variable

To demonstrate non-normally distributed basic variables, an example from Nowak & Collins (Example 5.11, Page 127/128) is calculated. Here normally distributed, lognormally distributed as well as gumbel distributed variables are used. While “norm” and “lnorm” are still contained in the standard scope of R (package “stats” belongs to base R) the Gumbel distribution is to be considered on the basis of the EVD-package (EVD := extreme value distributions).

X1 <- PROB_BASEVAR(Id = 1, Name = "Z", DistributionType = "norm", Mean = 100, Cov = 0.04) # kN/m²
X2 <- PROB_BASEVAR(Id = 2, Name = "Fy", DistributionType = "lnorm", Mean = 40, Cov = 0.1) # m
X3 <- PROB_BASEVAR(Id = 2, Name = "M", DistributionType = "gumbel", Package = "evd", Mean = 2000, Cov = 0.1) # m

lsf <- SYS_LSF(vars = list(X1, X2, X3), name = "Nowak & Collins Exp5.11_1")
lsf$func <- function(M, Fy, Z) {
  return(Z * Fy - M)
}

form <- PROB_MACHINE(name = "FORM Rack.-Fieß.", fCall = "FORM")

ps <- SYS_PROB(
  sys_input = list(lsf),
  probMachines = list(form)
)
ps$runMachines()
ps$beta_single
#>                  Nowak & Collins Exp5.11_1
#> FORM Rack.-Fieß.                  4.022115

Multiple limit state functions in one system

Basically, the “SYS_PROB” object can calculate multiple LSF’s using both Level 2 and Level 3 methods. This can be used when a system consists of several limit state functions and when the system reliability is to be determined using SimpleBounds. In this case, the failure probability must first be determined for each individual limit state equation. These results are then used to calculate bounds for the system failure probability. On the other hand, the development of a limit state function often poses several variants in equations or variables, so that by the simultaneous calculation of several equations satisfactory comparability is achieved and a high usability remains granted.

However, if the system failure probability can not to be sufficiently estimated by means of the SimpleBounds, simulation methods (e.g., MC-Crude) can be used to calculate the system failure probability more exactly. Then, the system can also be constructed according to the following scheme.

In this example, the above examples are first determined individually as a system using a FORM calculation and then the system failure probability is determined using different methods.

Var1 <- PROB_BASEVAR(Id = 1, Name = "X1", DistributionType = "norm", Mean = 0.25, Sd = 1) # kN/m²
Var2 <- PROB_BASEVAR(Id = 2, Name = "X2", DistributionType = "norm", Mean = 0.25, Sd = 1) # m

lsf1 <- SYS_LSF(vars = list(Var1, Var2), name = "UQLab 2d_hat")
lsf1$func <- function(X1, X2) {
  return(20 - (X1 - X2)^2 - 8 * (X1 + X2 - 4)^3)
}


X1 <- PROB_BASEVAR(Id = 4, Name = "Z", DistributionType = "norm", Mean = 100, Cov = 0.04) # kN/m²
X2 <- PROB_BASEVAR(Id = 5, Name = "Fy", DistributionType = "lnorm", Mean = 40, Cov = 0.1) # m
X3 <- PROB_BASEVAR(Id = 6, Name = "M", DistributionType = "gumbel", Package = "evd", Mean = 2000, Cov = 0.1) # m

lsf2 <- SYS_LSF(vars = list(X1, X2, X3), name = "Nowak & Collins Exp5.11_1")
lsf2$func <- function(M, Fy, Z) {
  return(Z * Fy - M)
}

form <- PROB_MACHINE(name = "FORM Rack.-Fieß.", fCall = "FORM")

ps <- SYS_PROB(
  sys_input = list(lsf1, lsf2),
  sys_type = "serial",
  probMachines = list(form)
)
ps$runMachines()
ps$beta_single
#>                  UQLab 2d_hat Nowak & Collins Exp5.11_1
#> FORM Rack.-Fieß.     3.434565                  4.022115

ps$calculateSystemProbability()
ps$beta_sys
#>                               [,1]
#> SB min (FORM Rack.-Fieß.) 3.409355
#> SB max (FORM Rack.-Fieß.) 3.434565

The following lines are not executed because the calculation time is several minutes depending on the machine. Results in the range of the above interval are to be expected. The results can be retrieved after the calculation using “$beta_sys”.

params <- list("cov_user" = 0.05, "n_max" = 50000)
ps$calculateSystemProbability("MCC", params)

ps$calculateSystemProbability("MCIS", params)

params_sus <- list("Nsubset" = 10000, "p0" = 0.1)
ps$calculateSystemProbability("MCSUS", params_sus)

Reliability with and without quality control

The posterior variable can be used like any other basic variable. In this example the concrete strength fc from the section on quality control is the resistance and a normally distributed action E (mean 25, standard deviation 3, same unit) is the load effect. The reliability index is calculated with the prior and with the posterior distribution of the strength.

E <- PROB_BASEVAR(Id = 3, Name = "E", Description = "Action effect",
                  DistributionType = "norm", Mean = 25, Sd = 3)

form <- PROB_MACHINE(name = "FORM", fCall = "FORM")

lsf_prior <- SYS_LSF(vars = list(fc, E), name = "Prior")
lsf_prior$func <- function(fc, E) fc - E
lsf_prior$check()

lsf_post <- SYS_LSF(vars = list(fc_post, E), name = "Posterior")
lsf_post$func <- function(fc, E) fc - E
lsf_post$check()

ps <- SYS_PROB(sys_input = list(lsf_prior, lsf_post), probMachines = list(form))
ps$runMachines()
ps$beta_single
#>         Prior Posterior
#> FORM 2.893513  3.155135

The reliability index is higher after the acceptance of the lot. This is the effect of the quality control on the safety level.

Parameterstudy

var.d <- PARAM_BASEVAR(Id = 1, Name = "d", Description = "Effective depth", DistributionType = "norm", Sd = 10, ParamType = "Mean", ParamValues = c(seq(200, 800, 50), seq(1000, 3000, 100)) + 10)
pre.d <- c(seq(200, 800, 50), seq(1000, 3000, 100))

var.f_ck <- PROB_BASEVAR(Id = 2, Name = "f_ck", Description = "Concrete compressive strength", Package = "TesiproV", DistributionType = "lt", DistributionParameters = c(3.85, 0.09, 3, 10))
pre.f_ck <- 35

var.f_ywk <- PROB_BASEVAR(Id = 3, Name = "f_ywk", Description = "Yield strength of shear reinforcement", DistributionType = "norm", Mean = 560, Cov = 0.02)
pre.f_ywk <- 500

var.f_yk <- PROB_BASEVAR(Id = 4, Name = "f_yk", Description = "Yield strength of longitudinal reinforcement", DistributionType = "norm", Mean = 560, Sd = 30)
pre.f_yk <- 500

var.rho_l <- PROB_BASEVAR(Id = 5, Name = "rho_l", Description = "Longitudinal reinforcement ratio", DistributionType = "norm", Mean = 0.01, Cov = 0.02)
pre.rho_l <- var.rho_l$Mean

var.c_D <- PROB_BASEVAR(Id = 6, Name = "c_D", Description = "Column diameter", DistributionType = "norm", Mean = 500 + 0.003 * 500, Sd = 4 + 0.006 * 500)
pre.c_D <- 500

var.theta_c <- PROB_BASEVAR(Id = 7, Name = "theta_c", Description = "Model uncertainty", DistributionType = "lnorm", Mean = 1.0644, Cov = 0.1679)

var.gamma_c <- PROB_DETVAR(Id = 8, Name = "gamma_c", Description = "Partial safety factor concrete", Value = 1.5)
var.gamma_s <- PROB_DETVAR(Id = 9, Name = "gamma_s", Description = "Partial safety factor steel", Value = 1.15)
var.alpha_cc <- PROB_DETVAR(Id = 10, Name = "alpha_cc", Description = "Long-term factor alpha_cc", Value = 0.85)

V_Ed <- c(
  0.6412447, 0.8760515, 1.1424185, 1.4399554, 1.7554079, 2.0188587, 2.3003489, 2.5997038, 2.9167825, 3.2514671, 3.6036567, 3.9732630,
  4.3602076, 6.0800504, 7.0424326, 8.0726216, 9.1702994, 10.3351829, 11.5670173, 12.8655715, 14.2306347, 15.6620132, 17.1595283, 18.7230145,
  20.3523175, 22.0472935, 23.8078076, 25.6337332, 27.5249511, 29.4813487, 31.5028193, 33.5892621, 35.7405811, 37.9566849
)
var.V_Ed <- PARAM_DETVAR(Id = 11, Name = "V_Ed", Description = "Applied shear force", ParamValues = V_Ed)

lsf1 <- SYS_LSF(
  vars = list(
    var.d, var.f_ck, var.f_yk, var.f_ywk, var.rho_l, var.c_D,
    var.theta_c, var.V_Ed, var.gamma_c, var.gamma_s, var.alpha_cc
  ),
  name = "Durchstanzwiderstand ohne Bewehrung"
)
lsf1$func <- function(d, f_ck, f_yk, f_ywk, rho_l, c_D, theta_c, V_Ed, gamma_c, gamma_s, alpha_cc) {
  f_cd <- f_ck * alpha_cc / gamma_c
  f_yd <- f_yk / gamma_s
  f_ywd <- f_ywk / gamma_s

  u_0 <- c_D * pi
  u_1 <- (c_D / 2 + 2 * d) * 2 * pi
  u_0.5 <- (c_D / 2 + 0.5 * d) * 2 * pi

  k <- min(1 + sqrt(200 / d), 2)

  if ((u_0 / d) < 4) {
    C_Rd_c <- 0.18 * (0.1 * u_0 / d + 0.6)
  } else {
    C_Rd_c <- 0.18
  }
  rho_l <- min(rho_l, 0.5 * f_cd / f_yd, 0.02)
  C_Rd_c1 <- C_Rd_c * k * (100 * rho_l * f_ck)^(1 / 3)

  v_Rd_c <- C_Rd_c1
  V_Rd_c <- v_Rd_c * d * u_1 * 1e-6 * theta_c
  return(V_Rd_c - V_Ed)
}

form <- PROB_MACHINE(name = "FORM RF.", fCall = "FORM", options = list("n_optim" = 20, "loctol" = 0.0001, "optim_type" = "rackfies"))

ps <- SYS_PARAM(
  sys_input = list(lsf1),
  probMachines = list(form)
)
ps$runMachines()
d <- pre.d
beta <- unlist(unname(ps$beta_params))
plot(x = d, y = beta, type = "l")

References

  1. JOINT COMMITTEE ON STRUCTURAL SAFETY, JCSS Probabilistic Model Code. URL: https://www.jcss-lc.org/, 2001.

  2. Marelli & Sudret (2014): UQLab: A Framework for Uncertainty Quantification in MATLAB, ICVRAM 2014 Conference Proceedings. DOI:10.1061/9780784413609.257

  3. NOWAK, A. S.; COLLINS, K. R. Reliability of structures. CRC Press, 2012.

  4. DIN EN 1992-1-1: 2011-01: DIN EN 1992-1-1: Design of concrete structures – Part 1-1: General rules and rules for buildings; German version EN 1992-1-1:2004 + AC:2010.

  5. DIN EN 1992-1-1/NA: 2013-04: National Annex – Nationally determined parameters – DIN EN 1992-1-1: Design of concrete structures – Part 1-1: General rules and rules for buildings.

Acknowledgement

The TesiproV package was developed within the framework of the research project “TesiproV”, funded by the German Federal Ministry for Economic Affairs and Energy (BMWi), and the research project “Qualitätskontrollen und Bauwerkszuverlässigkeit im Bauwesen”, funded by the German Institute for Building Technology (DIBt). The authors gratefully acknowledge the financial support provided by these institutions.

Contact & License

For questions, feedback or collaboration requests please contact us at:

TU Dortmund University – Chair of Structural Concrete
August-Schmidt-Strasse 8 · D‑44227 Dortmund · Germany

Email: tesiprov.lmb.ab@tu-dortmund.de

Additional contacts:
* nille-hauf@hochschule-bc.de (konstantin.nille-hauf@googlemail.com)
* tania.feiri@tu-dortmund.de
* marcus.ricker@tu-dortmund.de
* til.lux@tu-dortmund.de


© 2021–2026 K. Nille-Hauf, T. Feiri, M. Ricker, T. Lux – Hochschule Biberach (until 2022), TU Dortmund University – Chair of Structural Concrete (since 2023)

TesiproV is released under the MIT License.
You are free to use, modify and redistribute the software provided that this copyright notice and license information remain included.

For official releases see the CRAN package TesiproV.
Source code repository: https://gitlab.tu-dortmund.de/ls-massivbau/tesiprov