---
title: "TesiproV – Reliability Analysis Methods for Structural Engineering"
author: "Konstantin Nille-Hauf, Tania Feiri, Marcus Ricker, Til Lux"
date: "`r format(Sys.Date(), '%Y-%m-%d')`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{TesiproV – Reliability Analysis Methods for Structural Engineering}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

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:

- **MVFOSM** — Mean Value First Order Second Moment method; fast linear approximation based on moment statistics.
- **FORM** — First Order Reliability Method; iterative search for design point on failure surface.
- **SORM** — Second Order Reliability Method; curvature correction around design point.
- **Monte Carlo simulations** — direct numerical evaluation using random sampling or importance/subset sampling schemes.

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.

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.

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 Institue 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](https://opensource.org/licenses/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: 

```{r, eval = FALSE}
install.packages("TesiproV")
```

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

```{r, eval = FALSE}
remotes::install_gitlab("ls-massivbau/tesiprov", host = "gitlab.tu-dortmund.de")
```

If you need any permissions, please contact <tesiprov.lmb.ab@tu-dortmund.de>.

Make sure to initialize the TesiproV package before using it:

```{r}
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 |
| Lognormal | `"slnorm"` | brms | shifted lognormal distribution |
| Gumbel (Type I extreme value)  | `"gumbel"`  | evd  | Used for modeling 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 internal| heavy-tailed continuous; useful for sensitivity analyses|
|"Log-Student-t"| `"lt"`|TesiproV internal| extended heavy-tailed log-scale distribution|
|"Empirical"| `"emp"`| evd | 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

```{r}
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 - cofficient of variation: Cov = Mean/Sd
* 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".

```{r}
var.f_ck <- PROB_BASEVAR(Id = 1, Name = "f_ck", Description = "Char. Betondruckfestigkeit", 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

```{r}
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
)
```

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

## Determistic 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

```{r}
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

```{r}
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)))
```


## 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

```{r}
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`.

* Level 1 (partial safety factors)
* Level 2 (MVFOSM, FORM, SORM)
* Level 3 (MC_CRUDE, MCIS, MC_SubSam)

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:

```{r}
machine <- PROB_MACHINE(name = "MVFOSM", fCall = "MVFOSM", options = list("isExpression" = FALSE, "h" = 0.1))
```
### FORM

Options:

* n_optim - max. amount of evaulation runs
* loctol - local accuracy of the optimisation algorithm (if lower then this threshold, the optim stops)
* OptimType - Algorithms one can choose: Rackwitz-Fiessler Algorithmus "rackfies" (quite stable) or Augmented Lagrange Solver "auglag" (fast but sometimes difficult)

Example:

```{r}
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:

```{r}
machine <- PROB_MACHINE(name = "SORM", fCall = "SORM")
```
### MC_Crude

Options:

* cov_user=0.025 - abort criterion for Cov.
* n_batch=100 - evaulations each step.
* n_max=1e7 - abort cirterion for max cycles of evaluation
* use_threads=6 - amount of threads for parallel computing (1 = single core calculation)
* backend - parallel backend, eather "future" or "parallel", use "future" on Windows
* dataRecord=TRUE - if true, there is a list() with all the data per calculation step in the result (used for visualization of beta)
* debug.level=0 - Integer verbosity level (0 = silent, 1 = summary, 2 = detailed).
* seed - Optional integer seed for reproducible rondom numbers. 

Example:

```{r}
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.025 - abort criterion for cov.
* n_batch=100 - evaulations each step.
* n_max=1e7 - abort criterion for maximum cycles of evaluation
* use_threads=4 - amount of cores for parallel computing (1 = single core calculation).
* backend=NULL - parallel backend, either "future" or "parallel", use "future" on Windows.
* sys_type="serial" - Character string, either "serial" or "parallel", specifying system configuration.
* dataRecord=TRUE - If true, there is a list() with all the data per calculation step in the result (used for visualization of beta).
* beta_l=100 - optional threshold; limit states with β > beta_l may be excluded in system analysis.
* density Type - Sampling density type (currently "norm" supported).
* dps - Optional vector of design points in physical space; if supplied, FORM analysis is skipped.
* debug.level - Integer verbosity level (0 = silent, 1 = summary, 2 = detailed).
* seed - Optional integer seed for reproducible rondom numbers. 

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

```{r, eval = FALSE}
help("MC_IS")
```

Example:

```{r}
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 rondom numbers. 

Example:

```{r}
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:

* `SYS_PROB` – classical probabilistic system analysis; may contain several LSFs,
* `SYS_PARAM` – parametric sweep over one LSF using varying input parameters.

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 `$run_machines()`. 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

```{r, results="hide"}
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

```{r}
ps$beta_single
```

### Example – system calculations

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

```{r}
# Systemberechnungn (System aus zwei gleichen LSF´s)
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:

```{r}
ps_sys$beta_sys
```

## 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:

```{r}
# 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 = "brms", 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)
```

Results per iteration can be easily visualised:

```{r}
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 Monte Carlo-based reliability methods, including `MC_IS()` and `MC_CRUDE()`. The package provides two parallel backends:

* "parallel" -- based on base R's parallel package  
* "future" -- based on the future ecosystem

TesiproV does not modify the active future plan. Users are responsible for configuring parallel execution explicitly.

### Reproducibility and Determinism
All Monte Carlo simulations in TesiproV are designed to be:

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

This means that:
```{r, eval=FALSE}
MC_IS(..., seed = 123, use_threads = 1)
MC_IS(..., seed = 123, use_threads = 8)
```

will produce identical results.

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

### 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:

```{r, eval=FALSE}
MC_IS(..., backend = "parallel", use_threads = 8)
```

2. 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:
```{r, eval=FALSE}
library(future)
plan(multicore, workers = 8)

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

Windows example:
```{r, eval=FALSE}
library(future)
plan(multisession, workers = 8)

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

### Recommended Parallel Settings

Parallel efficiency depends strongly on the computational cost of the limit-state function (LSF).

| Problem Type               | Recommended Threads | Backend Recommendation      | Suggested `n_batch`      |
|----------------------------|--------------------|-----------------------------|--------------------------|
| Very simple LSF           | 1-2                | `"future"` or `"parallel"`  | 50,000 - 100,000         |
| Moderately expensive LSF  | 4-8                | `future(multicore)`         | 100,000 - 250,000        |
| Expensive LSF             | 8-16               | `future(multicore)`         | 250,000 - 500,000        |
| Very expensive LSF        | ~16                | `future(multicore)`         | ~500,000                 |


Using more than 16 threads on large shared-memory systems often leads to memory-bandwidth saturation.

### 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:

```{r, eval=FALSE}
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:
```{r, eval=FALSE}
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`):

* Single calculations -> `$beta_single`, `$res_single`,
* System calculations -> `$beta_sys`, `$res_sys`.

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`):

* Parameter iterations -> `$beta_params`, `$res_params`.

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:

* 1. Only the beta values are stored.
* 2. The `$res_*` object is saved.
* 3. The entire `ps` object is stored.
* 4. An image of the current working memory is created, which can be reloaded later.

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:

```{r, eval = FALSE}
ps <- SYS_PARAM(
  sys_input = list(lsf),
  probMachines = list(machine)
)

ps$runMachines()

local_beta <- ps$beta
local_runtime <- ps$res_single[[1]][[1]]$runtime

# define path with setwd("...")
ps$printResults("result_file") # Prints a report file in .txt format with all informations about the calculation
ps$saveProject(4, "project_file") # stores the project in a file
```

The results can be reloaded later via:

```{r, eval = FALSE}
readRDS("example_proj_res.rds")
load("example_proj.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.


```{r, results="hide"}
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()
```

```{r}
ps$beta_single
```

## 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).

```{r, results ='hide'}
library("evd")
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()
```

```{r}
ps$beta_single
```



## 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.



```{r, results="hide"}
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()
```

```{r}
ps$beta_single

ps$calculateSystemProbability()
ps$beta_sys
```


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".
```{r, eval = FALSE}
params <- list("cov_user" = 0.05, "n_max" = 50000)
ps$calculateSystemProbability("MC", params)

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

ps$calculateSystemProbability("MCSUS", params)
```

## Parameterstudy

* Punching according to DIN EN 1992-1 + NA(D)
* Effective depth (var.d) is parameterised (cf. vector at "ParamValues")
* Additional parametric deterministic variable "var.V_Ed" which depends on "pre.d
* Calculation by FORM and postprocessing see below.


```{r, results="hide", warning=FALSE}
var.d <- PARAM_BASEVAR(Id = 1, Name = "d", Description = "Stat. Nutzhöhe", 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 = "Char.Betondruckfestigkeit", 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 = "Zugfestigkeit Bügelbewehrung", DistributionType = "norm", Mean = 560, Cov = 0.02)
pre.f_ywk <- 500

var.f_yk <- PROB_BASEVAR(Id = 4, Name = "f_yk", Description = "Zugfestigkeit Längsbewehrung", DistributionType = "norm", Mean = 560, Sd = 30)
pre.f_yk <- 500

var.rho_l <- PROB_BASEVAR(Id = 5, Name = "rho_l", Description = "Biegebewehrungsgrad", 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 = "Stützendurchmesser", 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 = "Modellunsicherheit c nach DIBT", DistributionType = "lnorm", Mean = 1.0644, Cov = 0.1679)

var.gamma_c <- PROB_DETVAR(Id = 8, Name = "gamma_c", Description = "TSB Beton", Value = 1.5)
var.gamma_s <- PROB_DETVAR(Id = 9, Name = "gamma_s", Description = "TSB Stahl", Value = 1.15)
var.alpha_cc <- PROB_DETVAR(Id = 10, Name = "alpha_cc", Description = "Langzeitfaktor AlphaCC", 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 = "Einwirkende Querkraft", 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()
```

```{r, results="hide", warning=FALSE}
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. 

# Aknowledgement 

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 Engineering**  
August-Schmidt-Strasse 8 · D‑44227 Dortmund · Germany  

Email: [tesiprov.lmb.ab@tu-dortmund.de](mailto:tesiprov.lmb.ab@tu-dortmund.de)  

Additional contacts:  
* [nille-hauf@hochschule-bc.de](mailto:nille-hauf@hochschule-bc.de) ([konstantin.nille-hauf@googlemail.com](mailto:konstantin.nille-hauf@googlemail.com))  
* [tania.feiri@tu-dortmund.de](mailto:tania.feiri@tu-dortmund.de)  
* [marcus.ricker@tu-dortmund.de](mailto:marcus.ricker@tu-dortmund.de)  
* [til.lux@tu-dortmund.de](mailto: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](https://opensource.org/licenses/MIT).  
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](https://CRAN.R-project.org/package=TesiproV).  
Source code repository: <https://gitlab.tu-dortmund.de/ls-massivbau/tesiprov>
