File: plot_multi_form.py

package info (click to toggle)
openturns 1.26-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 67,708 kB
  • sloc: cpp: 261,605; python: 67,030; ansic: 4,378; javascript: 406; sh: 185; xml: 164; makefile: 101
file content (142 lines) | stat: -rw-r--r-- 5,023 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Use the FORM algorithm in case of several design points
=======================================================
"""

# %%
# Abstract
# --------
#
# In this example we showcase the :class:`~openturns.MultiFORM` class which can perform a FORM analysis with several
# design points.

# %%
import openturns as ot
import openturns.viewer as otv

# %%
# We consider a standard bivariate Gaussian random vector :math:`X = (X_1, X_2)`:
dim = 2
dist = ot.Normal(dim)

# %%
# We can draw the bidimensional PDF of the distribution `dist` over :math:`[-5,5] \times [-5,5]`:
ot.ResourceMap.SetAsUnsignedInteger("Contour-DefaultLevelsNumber", 8)
graphPDF = dist.drawPDF([-5, -5], [5, 5])
graphPDF.setTitle(r"2D-PDF of the input variables $(X_1, X_2)$")
graphPDF.setXTitle(r"$x_1$")
graphPDF.setYTitle(r"$x_2$")
graphPDF.setLegendPosition("lower right")
view = otv.View(graphPDF, contour_kw={"norm": "log"})

# %%
# We then define a model :math:`f` which maps a 2D-vector X = (X_1,X_2) to a
# scalar output `Y = f(X)`.
f = ot.SymbolicFunction(["x0", "x1"], ["5.0-x1-0.5*(x0-0.1)^2"])
graphModel = f.draw([-8.0, -8.0], [8.0, 8.0])
graphModel.setXTitle(r"$x_1$")
graphModel.setXTitle(r"$x_2$")
graphModel.setTitle(r"Isolines of the model : $Y = f(X)$")
view = otv.View(graphModel)


# %%
# We create random vectors for the input and output variables:
X = ot.RandomVector(dist)
Y = ot.CompositeRandomVector(f, X)


# %%
# The failure domain :math:`\mathcal{D}` is :math:`\mathcal{D} = \{ x=(x_1, x_2) \in \mathbb{R}^2 / f(x) < 0 \}`
failureEvent = ot.ThresholdEvent(Y, ot.Less(), 0.0)


# %%
# We shall represent the failure domain event using a :class:`~openturns.Contour` object.
nx, ny = 25, 25
xx = ot.Box([nx], ot.Interval([-8.0], [8.0])).generate()
yy = ot.Box([ny], ot.Interval([-8.0], [8.0])).generate()
inputData = ot.Box([nx, ny], ot.Interval([-8.0, -8.0], [8.0, 8.0])).generate()
outputData = f(inputData)
mycontour = ot.Contour(xx, yy, outputData)
mycontour.setLevels([0.0])
mycontour.setLabels(["0.0"])
mycontour.setColor("black")
mycontour.setLineStyle("dashed")
graphModel.add(mycontour)
view = otv.View(graphModel)

# %%
# In the physical space the failure domain boundary is the dashed black curve. We recall that one of
# the steps of the FORM method is to find the closest point of the failure domain boundary to the origin.
# Here we see that the symmetry of the domain implies that two points exist;
# one in the :math:`x_1 \geq 0` half-space and the other in the :math:`x_1 \leq 0` half-space.


# %%
# We build the :class:`~openturns.MultiFORM` algorithm in a similar fashion as the :class:`~openturns.FORM` algorithm.
# We choose an optimization solver, here the Cobyla solver, and a starting point, the mean of the distribution `dist`.
solver = ot.Cobyla()
solver.setStartingPoint(dist.getMean())
algo = ot.MultiFORM(solver, failureEvent)


# %%
# We are ready to run the algorithm and store the result in the :class:`~openturns.MultiFORM` class:
algo.run()
result = algo.getResult()

# %%
# We have access to the results with the getFORMResultCollection method which produces a collection of :class:`~openturns.FORMResult`:
coll = result.getFORMResultCollection()

# %%
# The length of this collection is the number of design points:
n_design_pts = len(coll)
print("Number of design points :", n_design_pts)


# %%
# We have access to the design points with the getPhysicalSpaceDesignPoint method
# for each element of the collection `coll`.
designPointPhysicalSpace1 = coll[0].getPhysicalSpaceDesignPoint()
designPointPhysicalSpace2 = coll[1].getPhysicalSpaceDesignPoint()
print(coll[0].getPhysicalSpaceDesignPoint())
print(coll[1].getPhysicalSpaceDesignPoint())

# %%
# We visualize them on the previous graph with red circle dots.
cloud = ot.Cloud([designPointPhysicalSpace1[0]], [designPointPhysicalSpace1[1]])
cloud.setColor("red")
cloud.setPointStyle("fcircle")
cloud.setLegend("design point no. 1")
graphModel.add(cloud)

cloud = ot.Cloud([designPointPhysicalSpace2[0]], [designPointPhysicalSpace2[1]])
cloud.setColor("red")
cloud.setPointStyle("fcircle")
cloud.setLegend("design point no. 2")
graphModel.add(cloud)
graphModel.setLegendPosition("")
view = otv.View(graphModel)

# %%
# We recall that the FORM approximate is based on the substitution of the failure domain by the half-space defined by the tangent at the design point.
# Here we can clearly see that this would miss half of the information. That is why both design points are needed.

# %%
# For each design point we have a probability associated to the approximation by the half-space:
pf1 = coll[0].getEventProbability()
pf2 = coll[1].getEventProbability()

# %%
# The probability of failure is the given by the :meth:`~openturns.MultiFORMResult.getEventProbability`
# which is the sum of the two previous probabilities `pf1` and `pf2`:
pf = result.getEventProbability()
print("Probability of failure : ", pf)
print("    wrt design point 1 : ", pf1)
print("    wrt design point 2 : ", pf2)

# %%
# Display the figures
otv.View.ShowAll()