1 // -*- C++ -*-
2 /**
3 * @brief Approximation algorithm for system events based on FORM
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "openturns/SystemFORM.hxx"
23 #include "openturns/PersistentObjectFactory.hxx"
24 #include "openturns/FORM.hxx"
25 #include "openturns/IntersectionEvent.hxx"
26 #include "openturns/UnionEvent.hxx"
27 #include "openturns/Normal.hxx"
28
29 BEGIN_NAMESPACE_OPENTURNS
30
31 CLASSNAMEINIT(SystemFORM);
32
33 static Factory<SystemFORM> Factory_SystemFORM;
34
SystemFORM()35 SystemFORM::SystemFORM()
36 : Analytical()
37 {
38 // Nothing to do
39 }
40
SystemFORM(const OptimizationAlgorithm & nearestPointAlgorithm,const RandomVector & event,const Point & physicalStartingPoint)41 SystemFORM::SystemFORM(const OptimizationAlgorithm & nearestPointAlgorithm,
42 const RandomVector & event,
43 const Point & physicalStartingPoint)
44 : Analytical()
45 {
46 setNearestPointAlgorithm(nearestPointAlgorithm);
47 setPhysicalStartingPoint(physicalStartingPoint);
48 setEvent(event);
49 }
50
51 /* Virtual constructor */
clone() const52 SystemFORM * SystemFORM::clone() const
53 {
54 return new SystemFORM(*this);
55 }
56
57 /* Result accessor */
getResult() const58 MultiFORMResult SystemFORM::getResult() const
59 {
60 return multiFORMResult_;
61 }
62
63
64 /* String converter */
__repr__() const65 String SystemFORM::__repr__() const
66 {
67 OSS oss;
68 oss << "class=" << SystemFORM::GetClassName()
69 << " " << Analytical::__repr__()
70 << " result=" << multiFORMResult_;
71 return oss;
72 }
73
setEvent(const RandomVector & event)74 void SystemFORM::setEvent(const RandomVector & event)
75 {
76 // check that the event is in disjunctive normal form (union of intersections)
77 const UnionEvent *unionEvent = dynamic_cast<UnionEvent*>(event.getImplementation().get());
78 Collection<RandomVector> unionCollection;
79 if (unionEvent)
80 unionCollection = unionEvent->getEventCollection();
81 else // just a single intersection
82 unionCollection.add(event);
83 for (UnsignedInteger i = 0; i < unionCollection.getSize(); ++ i)
84 {
85 if (unionCollection[i].getImplementation()->getClassName() == "IntersectionEvent")
86 {
87 const IntersectionEvent *intersectionEvent = dynamic_cast<IntersectionEvent*>(unionCollection[i].getImplementation().get());
88 Collection<RandomVector> intersectionCollection(intersectionEvent->getEventCollection());
89 for (UnsignedInteger j = 0; j < intersectionCollection.getSize(); ++ j)
90 if (intersectionCollection[j].getImplementation()->getClassName() != "ThresholdEventImplementation")
91 throw InvalidArgumentException(HERE) << "Event is not in disjunctive normal form";
92 }
93 else if (unionCollection[i].getImplementation()->getClassName() != "ThresholdEventImplementation")
94 throw InvalidArgumentException(HERE) << "Event is not in disjunctive normal form";
95 }
96 Analytical::setEvent(event);
97 }
98
99 /* Run */
run()100 void SystemFORM::run()
101 {
102 // Collect the flat list of leaf events from the DNF event and the the lists of ids for each parallel region
103 Collection<RandomVector> leafEventCollection;
104 const UnionEvent *unionEvent = dynamic_cast<UnionEvent*>(getEvent().getImplementation().get());
105 Collection<RandomVector> unionCollection;
106 if (unionEvent)
107 unionCollection = unionEvent->getEventCollection();
108 else // just a single intersection
109 unionCollection.add(getEvent());
110 Collection<Indices> parallelRegionIdCollection;
111 for (UnsignedInteger i = 0; i < unionCollection.getSize(); ++ i)
112 {
113 if (unionCollection[i].getImplementation()->getClassName() == "IntersectionEvent")
114 {
115 const IntersectionEvent *intersectionEvent = dynamic_cast<IntersectionEvent*>(unionCollection[i].getImplementation().get());
116 Collection<RandomVector> intersectionCollection(intersectionEvent->getEventCollection());
117 leafEventCollection.add(intersectionCollection);
118 Indices parallelRegionId(intersectionCollection.getSize());
119 for (UnsignedInteger j = 0; j < intersectionCollection.getSize(); ++ j)
120 {
121 parallelRegionId[j] = intersectionCollection[j].getId();
122 }
123 parallelRegionIdCollection.add(parallelRegionId);
124 }
125 else
126 {
127 // single event in parallel region
128 leafEventCollection.add(unionCollection[i]);
129 parallelRegionIdCollection.add(Indices(1, unionCollection[i].getId()));
130 }
131 }
132
133 // for each leaf events perform FORM
134 std::map<UnsignedInteger, Scalar> idToBetaMap;
135 std::map<UnsignedInteger, Point> idToAlphaMap;
136 Collection<FORMResult> formResultCollection;
137 for (UnsignedInteger i = 0; i < leafEventCollection.getSize(); ++ i)
138 {
139 const UnsignedInteger id = leafEventCollection[i].getId();
140 if (idToBetaMap.find(id) == idToBetaMap.end()) // if not already computed for this event
141 {
142 FORM algo(getNearestPointAlgorithm(), leafEventCollection[i], getPhysicalStartingPoint());
143 algo.run();
144
145 const FORMResult result(algo.getResult());
146 const Scalar beta = result.getGeneralisedReliabilityIndex();
147 idToBetaMap[id] = beta;
148 idToAlphaMap[id] = result.getStandardSpaceDesignPoint() * (1.0 / beta);
149 formResultCollection.add(result);
150 LOGINFO(OSS() << "SystemFORM: event=" << id << " beta=" << result.getGeneralisedReliabilityIndex());
151 }
152 }
153
154 // generate all poincarre terms
155 Collection<Indices> poincarreRegion;
156 UnsignedInteger numberOfPoincarreTerms = 0;
157 for (UnsignedInteger k = 0; k < unionCollection.getSize(); ++ k)
158 {
159 // retrieve region
160 const Indices region(parallelRegionIdCollection[k]);
161
162 // recursive expansion of the Poincarre formula
163 for (UnsignedInteger i = 0; i < numberOfPoincarreTerms; ++ i)
164 {
165 // intersection of region / poincarreRegion[i]
166 Indices intersection(region);
167 const UnsignedInteger poincarreRegionSize = poincarreRegion[i].getSize();
168 for (UnsignedInteger j = 0; j < poincarreRegionSize; ++ j)
169 if (!region.contains(poincarreRegion[i][j]))
170 intersection.add(poincarreRegion[i][j]);
171 poincarreRegion.add(intersection);
172 }
173 poincarreRegion.add(region);
174
175 // update number of poincarre terms (=2^n-1)
176 numberOfPoincarreTerms = 2 * numberOfPoincarreTerms + 1;
177 }
178
179 Scalar eventProbability = 0.0;
180 for (UnsignedInteger k = 0; k < numberOfPoincarreTerms; ++ k)
181 {
182 // retrieve region
183 const Indices region(poincarreRegion[k]);
184 const UnsignedInteger regionSize = region.getSize();
185
186 // set region beta
187 Point regionBeta(regionSize);
188 for (UnsignedInteger i = 0; i < regionSize; ++ i)
189 regionBeta[i] = idToBetaMap[region[i]];
190
191 // set the correlation matrix C
192 CovarianceMatrix C(regionSize);
193 for (UnsignedInteger i = 0; i < regionSize; ++ i)
194 for (UnsignedInteger j = 0; j < i; ++ j)
195 C(i, j) = idToAlphaMap[region[i]].dot(idToAlphaMap[region[j]]);
196
197 // Regularize C
198 Scalar cumulatedScaling = 0.0;
199 const Scalar startingScaling = ResourceMap::GetAsScalar("SystemFORM-StartingScaling");
200 const Scalar maximalScaling = ResourceMap::GetAsScalar("SystemFORM-MaximalScaling");
201 Scalar scaling = startingScaling;
202 while (!C.isPositiveDefinite())
203 {
204 cumulatedScaling += scaling;
205 for (UnsignedInteger index = 0; index < regionSize; ++index)
206 C(index, index) += scaling;
207 scaling *= 2.0;
208
209 // No reasonable regularization succeeded
210 if (cumulatedScaling >= maximalScaling)
211 throw InvalidArgumentException(HERE) << "Could not regularize, scaling up to " << cumulatedScaling << " was not enough";
212 }
213
214 // compute the parallel region probability
215 const Point mu(regionSize, 0.0);
216 const Normal normal(mu, C);
217 const Scalar poincarreProbability = normal.computeCDF(-1.0 * regionBeta);
218
219 LOGINFO(OSS() << "SystemFORM: poincarre probability [" << k << "]=" << poincarreProbability);
220
221 // trick to update the poincarre sum
222 // we invert the sign of each consecutive term to follow the order of our recursive expansion of the Poincarre formula
223 eventProbability = -eventProbability + poincarreProbability;
224 }
225
226 // store results
227 multiFORMResult_ = MultiFORMResult(formResultCollection);
228 multiFORMResult_.setEventProbability(eventProbability);
229 }
230
231
232 /* Method save() stores the object through the StorageManager */
save(Advocate & adv) const233 void SystemFORM::save(Advocate & adv) const
234 {
235 Analytical::save(adv);
236 adv.saveAttribute("multiFORMResult_", multiFORMResult_);
237 }
238
239
240 /* Method load() reloads the object from the StorageManager */
load(Advocate & adv)241 void SystemFORM::load(Advocate & adv)
242 {
243 Analytical::load(adv);
244 adv.loadAttribute("multiFORMResult_", multiFORMResult_);
245 }
246
247 END_NAMESPACE_OPENTURNS
248