iam-git / WellMet (public) (License: MIT) (since 2021-08-31) (hash sha1)
WellMet is pure Python framework for spatial structural reliability analysis. Or, more specifically, for "failure probability estimation and detection of failure surfaces by adaptive sequential decomposition of the design domain".
List of commits:
Subject Hash Author Date (UTC)
qt_plot.SimplexErrorGraph: finish 6fce1097d34c86c9b30c749e5b8cc2e4d8e7541d I am 2021-01-26 11:36:13
stm_df: finish get_tri_data_frame() 454bd2725a75f5a3f3851998693c4f85630fb30b I am 2021-01-22 20:43:36
stm_df: WIP bd99b8f3b8623a65c0bf0e3c22d9e67d8bce6a2c Alex 2021-01-21 15:27:11
stm_df: WIP f61a963c04764066bdd2bb9a363c51ec1c4fb389 Alex 2021-01-18 10:01:23
dicebox.Chrt: add design support 7426717fe5b3bbf299e44a92b2aca2672b752042 Alex 2021-01-15 09:30:28
design_proof_of_concept a1c9fc6ce6739e745382bdc1bfc6183a8c2a2f16 Alex 2021-01-14 22:58:01
estimation: rework simplex estimations, add cubature and design support 01dc64d5fa9afeda8326b90a71af71ede46fd8f8 Alex 2021-01-14 21:41:12
simplex.Triangulation: WIP 44bdae7876aac717f3d34c4bc6c818fc4ec65169 Alex 2021-01-13 10:43:59
simplex.Triangulation: WIP 47fe5e817878bc6bfd43db208d256a60ee573f9c Alex 2021-01-12 15:41:32
simplex.Triangulation: WIP 57f90b4ae9608d3f2fb5bc081934fa17523998f5 Alex 2021-01-10 11:12:30
simplex.get_failure_ratio() added 65e2940cfa549236cfb09a0e7cadb576a471070f Alex 2021-01-09 09:40:12
simplex.Shull: design support added fe2c0c6b23b32ce99aaa0f824424b32694978615 Alex 2021-01-07 14:22:58
IS_stat: add IS_norm() method 6d1d11c4591143a26c92551ec3f722ea642711ae Alex 2021-01-07 05:33:21
misc: add comment 3d735585d49ac9d5f831b860cf95d3f41fd0d93e I am 2021-01-04 10:29:24
stm_df added (as is for now) 55402101bfabf4b9fe7d70fbd8f1469aea401bc7 Alex 2020-12-26 01:26:17
qt_plot.Isocurves: Isocurves-isolevels reworked 330b3387cfe46f75be6bf70f41c3f289303bdba2 I am 2020-12-23 02:36:39
qt_plot.Isocurves: infs issue fix 276a727723579be523e43b9748b7d36f6d151b0d I am 2020-12-18 00:14:14
qt_plot.Isocurves: extendEdge fix (there was an issue in P and U) 6a836879cc5d280862f4534dc824be86d34bfb4c I am 2020-12-17 23:49:44
qt_plot.Isocurves: bias fix 7c13581235e8e1bac726381b22db46057d1ac188 I am 2020-12-17 14:42:39
qt_plot: Isocurves nan check added + simplex error graph committed (as is) 3b2882661f7af4bb51e518bcd3a37dba6c67f7b2 I am 2020-12-17 03:55:44
Commit 6fce1097d34c86c9b30c749e5b8cc2e4d8e7541d - qt_plot.SimplexErrorGraph: finish
Author: I am
Author date (UTC): 2021-01-26 11:36
Committer name: I am
Committer date (UTC): 2021-01-26 11:36
Parent(s): 454bd2725a75f5a3f3851998693c4f85630fb30b
Signer:
Signing key:
Signing status: N
Tree: 405e06eea16cebcd874e9830f20709000a014e3c
File Lines added Lines deleted
qt_plot.py 151 74
stm_df.py 20 9
File qt_plot.py changed (mode: 100644) (index f4ef829..758936d)
... ... import pandas as pd # required for estimation graph
12 12
13 13 from . import estimation as stm from . import estimation as stm
14 14 from . import misc from . import misc
15
15 from . import stm_df
16 16
17 17 def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs): def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs):
18 18 """ """
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
188 188 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
189 189
190 190 dock = QtGui.QDockWidget("Simplex error graph", self) dock = QtGui.QDockWidget("Simplex error graph", self)
191 dock.setWidget(SimplexErrorGraph(self.sample_box, self, dock))
191 dock.setWidget(SimplexErrorGraph(self.simplex_data, dock))
192 192 self.dockables.append(dock) self.dockables.append(dock)
193 193 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
194 194
 
... ... class Isocurves:
624 624 self.on_space_changed() self.on_space_changed()
625 625
626 626 def on_space_changed(self): def on_space_changed(self):
627 points = getattr(self.f, self.w.space)
627 if self.contour_item.checkState() or self.isocurve_item.checkState():
628 points = getattr(self.f, self.w.space)
629
630 #č valčím s nekoněčno
631 mask = np.all(np.isfinite(points), axis=1)
628 632
629 #č valčím s nekoněčno
630 mask = np.all(np.isfinite(points), axis=1)
631
632 self.max = np.max(points[mask], axis=0)
633 self.min = np.min(points[mask], axis=0)
634
635 ngrid = self.ngrid
636 grid = np.mgrid[0:ngrid,0:ngrid].T.reshape(-1, 2)
637 # scale
638 grid = self.grid_scale(grid)
633 self.max = np.max(points[mask], axis=0)
634 self.min = np.min(points[mask], axis=0)
639 635
640 f_model = self.w.sample_box.f_model
641 self.pdf = f_model.sample_pdf(grid, space=self.w.space)
642 #č pokud tam budou nanka, pak nikdo nic nedostane
643 #č u současných f_modelů však nemají být
644 self.pdf = np.nan_to_num(self.pdf, copy=False)
645 #č reshape, flip a rot90 dle dokumentaci vracej view
646 #č povede-li to numpy, data nebudou žrat další místo v paměti
647 self.data = self.pdf.reshape((ngrid, ngrid))
648 #č bůhví co ta pomocná funkce očekává za vstup
649 #č a co je zvykem u těch borců co pracujou s obrázky
650 #č zkrátka, empiricky - buď zde flipnout a pootočit
651 #č nebo tam dále prohodit souřadnice
652 self.data = np.flip(self.data, axis=0)
653 self.data = np.rot90(self.data, k=-1)
636 ngrid = self.ngrid
637 grid = np.mgrid[0:ngrid,0:ngrid].T.reshape(-1, 2)
638 # scale
639 grid = self.grid_scale(grid)
654 640
641 f_model = self.w.sample_box.f_model
642 self.pdf = f_model.sample_pdf(grid, space=self.w.space)
643 #č pokud tam budou nanka, pak nikdo nic nedostane
644 #č u současných f_modelů však nemají být
645 self.pdf = np.nan_to_num(self.pdf, copy=False)
646 #č reshape, flip a rot90 dle dokumentaci vracej view
647 #č povede-li to numpy, data nebudou žrat další místo v paměti
648 self.data = self.pdf.reshape((ngrid, ngrid))
649 #č bůhví co ta pomocná funkce očekává za vstup
650 #č a co je zvykem u těch borců co pracujou s obrázky
651 #č zkrátka, empiricky - buď zde flipnout a pootočit
652 #č nebo tam dále prohodit souřadnice
653 self.data = np.flip(self.data, axis=0)
654 self.data = np.rot90(self.data, k=-1)
655 655
656 self.plot()
656
657 self.plot()
657 658
658 659
659 660 def show_slot(self, item): def show_slot(self, item):
 
... ... class SimplexEstimationData(QtCore.QObject):
1037 1038
1038 1039 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu) self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
1039 1040 self.simplex_chk.setCheckable(True) self.simplex_chk.setCheckable(True)
1040 #self.simplex_chk.setChecked(True)
1041 self.simplex_chk.setChecked(True)
1041 1042 self.simplex_chk.triggered.connect(self.recalculate) self.simplex_chk.triggered.connect(self.recalculate)
1042 1043 self.TRI_menu.addAction(self.simplex_chk) self.TRI_menu.addAction(self.simplex_chk)
1043 1044
1044 # hope, it is temporary
1045 self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
1046 self.sources_action_group.addAction(self.TRI_overall_chk)
1047 self.sources_action_group.addAction(self.simplex_chk)
1045 # year, it was
1046 ## hope, it is temporary
1047 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
1048 #self.sources_action_group.addAction(self.TRI_overall_chk)
1049 #self.sources_action_group.addAction(self.simplex_chk)
1048 1050
1049 1051 self.TRI_menu.addSeparator() self.TRI_menu.addSeparator()
1050 1052
1051 1053 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu) self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
1052 1054 self.proxy_chk.setCheckable(True) self.proxy_chk.setCheckable(True)
1055 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
1053 1056 self.proxy_chk.triggered.connect(self.recalculate) self.proxy_chk.triggered.connect(self.recalculate)
1054 1057 self.TRI_menu.addAction(self.proxy_chk) self.TRI_menu.addAction(self.proxy_chk)
1055 1058
 
... ... class SimplexEstimationData(QtCore.QObject):
1073 1076 proposal_filename += '.xlsx' proposal_filename += '.xlsx'
1074 1077 else: else:
1075 1078 proposal_filename = self.dice_box.gm_signature + '.xlsx' proposal_filename = self.dice_box.gm_signature + '.xlsx'
1076 filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
1079 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
1077 1080 proposal_filename, initialFilter='*.xlsx') proposal_filename, initialFilter='*.xlsx')
1078 1081 self.df.to_excel(filename) self.df.to_excel(filename)
1079 1082 except BaseException as e: except BaseException as e:
 
... ... class SimplexEstimationData(QtCore.QObject):
1081 1084
1082 1085
1083 1086 def recalculate(self): def recalculate(self):
1084 if self.simplex_chk.isChecked():
1085 tri_estimation = dict()
1086 try: # тут всё что угодно может пойти не так
1087 # kruci, ještě navic i generovať pokažde znovu...
1088
1089 # new-style: šecko leží dohromady a každý si z toho
1090 # bere co chce a jak chce
1091 # ne že by to bylo nějak šetrný
1092 # estimation je slovníkem
1093 for estimation in self.dice_box.estimations:
1094 # nsim musí mäť každej odhad
1095 # pokud nemá - je třeba jej prostě opravit
1096 nsim = estimation['nsim']
1097 try:
1098 tri_estimation[nsim] = estimation['TRI_estimation']
1099 except KeyError as e:
1100 pass #print(self.__class__.__name__ + ":", repr(e))
1101
1102 #č neotravuj uživatele chybovejma hlaškama
1103 if tri_estimation:
1104 # it can be effectively done with pandas
1105 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1106 # -1 = 'out', 0=success, 1=failure, 2=mix
1107 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1108 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1109 df.sort_values('nsim', inplace=True)
1110
1111 self._pens_data_update()
1087 try:
1088 # sources=['box', 'user']
1089 sources = list()
1090 if self.TRI_overall_chk.isChecked():
1091 sources.append('box')
1092 if self.simplex_chk.isChecked():
1093 sources.append('user')
1112 1094
1113 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1114 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1115 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1116
1117 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1118 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1119 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1120 except:
1121 pass
1122 self.simplex_estimation_updated.emit()
1095 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
1096 apply_proxy=self.proxy_chk.isChecked())
1097 self.simplex_estimation_updated.emit()
1098
1099 except BaseException as e:
1100 print(self.__class__.__name__ + ":", repr(e))
1101
1123 1102
1124 1103
1125 1104 class SimplexEstimationGraph(pg.PlotWidget): class SimplexEstimationGraph(pg.PlotWidget):
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
1370 1349
1371 1350
1372 1351
1373 class SimplexErrorGraph(SimplexEstimationGraph):
1374 pass
1352 class SimplexErrorGraph(pg.PlotWidget):
1353 def __init__(self, simplex_data, parent=None, *args, **kwargs):
1354 super().__init__(parent, *args, **kwargs)
1355 self.simplex_data = simplex_data
1356 self.simplex_data.simplex_estimation_updated.connect(self.redraw)
1357
1358 self.setup_context_menu()
1359 self.setup()
1360
1361 def setup_context_menu(self):
1362 # creates instance of LegendItem
1363 # and saves it into plotItem.legend
1364 self.legend = self.addLegend()
1365
1366 self.plotItem.ctrl.xGridCheck.setChecked(True)
1367 self.plotItem.ctrl.yGridCheck.setChecked(True)
1368
1369 # menu of SimplexEstimationData
1370 self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
1371
1372 #č já se bojím. radší to uložím
1373 self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
1374
1375 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1376 self.legend_chk.setCheckable(True)
1377 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1378 self.custom_menu.addAction(self.legend_chk)
1379 # apply custom menu option
1380 self.legend.setVisible(self.legend_chk.isChecked())
1381
1382 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1383 self.laction.triggered.connect(self.show_labels)
1384 self.custom_menu.addAction(self.laction)
1385
1386
1387 def show_labels(self):
1388 self.setLabel('left', "Failure probability estimation error")
1389 self.setLabel('bottom', "Number of simulations")
1390
1391
1392 def setup(self, *args, **kwargs):
1393 self.clear()
1394 self.setBackground('w')
1395 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1396
1397 # We will use logMode by default
1398 self.setLogMode(y=True)
1399
1400 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1401 #red = (253, 0, 17, 96)
1402
1403 #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1404 #self.pen_f.setZValue(-100)
1405
1406
1407 pen = pg.mkPen(color='m', width=2)
1408 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1409 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1410 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1411
1412
1413
1414 #č když se někde objeví nula se zapnutým LogModem -
1415 #č qtpygraph hned spadne a není možne ten pad zachytit
1416 def zerosafe(self, x, y, fallback_y=None):
1417 x = np.array(x)
1418 y = np.array(y)
1419 if fallback_y is None:
1420 fallback_y = y
1421 y = np.where(y > 0, y, fallback_y)
1422 mask = y > 0
1423 return x[mask], y[mask]
1424
1425
1426 def redraw(self):
1427 #č neotravujme uživatele chybovejma hlaškama
1428 if hasattr(self.simplex_data.dice_box, 'pf_exact'):
1429 try: #ё тут всё что угодно может пойти не так
1430 pf_exact = self.simplex_data.dice_box.pf_exact
1431
1432 df = self.simplex_data.df
1433 #č zapíšeme do data rámu, snad nikomu nebude vadit
1434 df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
1435 df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
1436
1437 v = df['vertex_estimation_error'].abs()
1438 wv = df['weighted_vertex_estimation_error'].abs()
1439
1440 x, y = self.zerosafe(v.index, v.to_numpy())
1441 self.pen_vertex.setData(x, y)
1442
1443 x, y = self.zerosafe(wv.index, wv.to_numpy())
1444 self.pen_weighted_vertex.setData(x, y)
1445
1446
1447 except BaseException as e:
1448 print(self.__class__.__name__ + ":", repr(e))
1449
1450
1451
1375 1452
1376 1453
1377 1454
File stm_df.py changed (mode: 100644) (index b1c9dca..408e989)
5 5 tohle je mezivrstva mezi simplexovymi odhady v boxu a grafy v qt_plot tohle je mezivrstva mezi simplexovymi odhady v boxu a grafy v qt_plot
6 6 (Kdybych věřil, že je to jen pro qt_plot, tak ten modul nevytvařím) (Kdybych věřil, že je to jen pro qt_plot, tak ten modul nevytvařím)
7 7
8 Podle kódu pyqtgraph a matplotlib už je jasný, že musím vracet 2 numpy vektory.
9 Asi nebudu zahrnovat .zerosafe() - je to jen zvlaštnost pyqtgraph
10 Není úplně jasně, zda mám dělat třídu (stateful),
11 nebo mám se omezit jen na funkci (stateless)
12 Minule přišel jsem na potřebu stateful,
13 ale už si nepamatuji proč.
8 #Podle kódu pyqtgraph a matplotlib už je jasný, že musím vracet 2 numpy vektory.
9 #Asi nebudu zahrnovat .zerosafe() - je to jen zvlaštnost pyqtgraph
10 #Není úplně jasně, zda mám dělat třídu (stateful),
11 #nebo mám se omezit jen na funkci (stateless)
12 #Minule přišel jsem na potřebu stateful,
13 #ale už si nepamatuji proč.
14 14
15 není aktuální, ale ty estimátory furt nemám promyšlený.
16 Podstata problému spočívá v tom, že současný DiceBox
17 ukladá odhady dvěma různejma způsoby, přičemž
18 TRI odhady jsou ukladány jako slovníky (strukturováně).
19 Pro ty strukturovaná data Pandas (aj obecně tabulka)
20 není ideální volba. Na druhou stranu chceme jednoduše
21 všechno co máme nakreslit a vyexportovat do Excelu.
15 22 """ """
16 23
17 24 import numpy as np import numpy as np
18 import pandas as pd
25 #č právě kvůli pandas davam tohle do separatního modulu
26 #č normálně kód WellMet pandas nevyžaduje
27 import pandas as pd
19 28
20 29
21 30 def get_estimation_data(estimations, metric): def get_estimation_data(estimations, metric):
 
... ... def get_tri_data_frame(dice_box, sources=['box', 'user'], apply_proxy=False):
81 90
82 91 #č předbežně: #č předbežně:
83 92 #č nejdřív concat (spojime zdroje dohromady) #č nejdřív concat (spojime zdroje dohromady)
84 df = pd.concat((df_box, df_user))
93 df = pd.concat((df_box, df_user), sort=False)
85 94
86 95 #č pak deduplicate #č pak deduplicate
87 96 #č (aby se převzaly odhady se stejným nsim z posledního zdroje) #č (aby se převzaly odhady se stejným nsim z posledního zdroje)
 
... ... def get_tri_data_frame(dice_box, sources=['box', 'user'], apply_proxy=False):
98 107 #č oboje nsim a nsim_proxy jsou pro lide, aby zahrivalo srdce #č oboje nsim a nsim_proxy jsou pro lide, aby zahrivalo srdce
99 108 #č předpokladá se, že volající kód bude použivat index #č předpokladá se, že volající kód bude použivat index
100 109 df.insert(loc=0, column='nsim (proxy)', value=nsim_proxy) df.insert(loc=0, column='nsim (proxy)', value=nsim_proxy)
110 #č nahradit index, pak vyhodit ďupy
101 111 df.index = nsim_proxy df.index = nsim_proxy
112 df = df.groupby(level=0).last()
102 113
103 114 #č když ne - tak jenom nahradíme index a vypadneme otsuď #č když ne - tak jenom nahradíme index a vypadneme otsuď
104 115 #č Alexi, co? vždyť ten index už nemusíme řešit, ten musí bejt v pořádku! #č Alexi, co? vždyť ten index už nemusíme řešit, ten musí bejt v pořádku!
 
... ... def get_tri_box_df(dice_box, tri_estimation_name='TRI_overall_estimations'):
116 127 data = dice_box.guessbox.estimations[tri_estimation_name] data = dice_box.guessbox.estimations[tri_estimation_name]
117 128 nsim, tri_data = data nsim, tri_data = data
118 129 # it can be effectively done with pandas # it can be effectively done with pandas
119 self.df = df = pd.DataFrame(tri_data, index=nsim)
130 df = pd.DataFrame(tri_data, index=nsim)
120 131 # -1 = 'out', 0=success, 1=failure, 2=mix # -1 = 'out', 0=success, 1=failure, 2=mix
121 132 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True) df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
122 133 df.insert(loc=0, column='nsim', value=nsim) df.insert(loc=0, column='nsim', value=nsim)
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/iam-git/WellMet

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/iam-git/WellMet

Clone this repository using git:
git clone git://git.rocketgit.com/user/iam-git/WellMet

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main