├── .gitattributes ├── .gitignore ├── 01_LICENSE.txt ├── 02_TODO.txt ├── BhTomoPy.ai ├── BhTomoPy.png ├── Icons ├── triangle_down.png └── triangle_right.png ├── README.md ├── bh_tomo.py ├── borehole.py ├── borehole_ui.py ├── covar.py ├── covar_ui.py ├── cutils ├── csegy.c ├── csegy.h ├── csegy.pxd ├── segy.c ├── segy.cp35-win_amd64.pyd ├── segy.cp36-win_amd64.pyd ├── segy.cpython-34m.so ├── segy.cpython-35m-darwin.so ├── segy.cpython-35m-x86_64-linux-gnu.so └── segy.pyx ├── database.db ├── database.py ├── database_ui.py ├── events_ui.py ├── grid.py ├── interp_ui.py ├── inversion.py ├── inversion_ui.py ├── manual_amp_ui.py ├── manual_tt_ui.py ├── model.py ├── model_ui.py ├── mog.py ├── mog_ui.py ├── requirements.txt ├── semi_auto_tt_ui.py ├── setup.py ├── testData ├── air_shots │ ├── ap0102b.rad │ ├── ap0102b.rd3 │ ├── ap0102b.tlf │ ├── ap0302.rad │ ├── ap0302.rd3 │ ├── ap0302.tlf │ ├── av0102.rad │ ├── av0102.rd3 │ ├── av0102.tlf │ ├── av0102b.rad │ ├── av0102b.rd3 │ ├── av0102b.tlf │ ├── av0302.rad │ ├── av0302.rd3 │ └── av0302.tlf ├── coord_forages.txt ├── formats │ └── ramac │ │ ├── t0102.rad │ │ ├── t0102.rd3 │ │ ├── t0102.tlf │ │ ├── t0102_no_tlf.rad │ │ ├── t0102_no_tlf.rd3 │ │ ├── t0102b.rad │ │ ├── t0102b.rd3 │ │ ├── t0102b.tlf │ │ ├── t0302.rad │ │ ├── t0302.rd3 │ │ └── t0302.tlf ├── stlambert │ ├── p18p17_0001_A1.rad │ ├── p18p17_0001_A1.rd3 │ ├── p18p17_0002_A1.rad │ ├── p18p17_0002_A1.rd3 │ ├── p18p17_0003_A1.rad │ ├── p18p17_0003_A1.rd3 │ ├── p18p17_0004_A1.rad │ ├── p18p17_0004_A1.rd3 │ ├── p18p17_0005_A1.rad │ ├── p18p17_0005_A1.rd3 │ ├── p18p17_0006_A1.rad │ ├── p18p17_0006_A1.rd3 │ ├── p18p17_0007_A1.rad │ ├── p18p17_0007_A1.rd3 │ ├── p18p17_0008_A1.rad │ ├── p18p17_0008_A1.rd3 │ ├── p18p17_0009_A1.rad │ ├── p18p17_0009_A1.rd3 │ ├── p18p17_0010_A1.rad │ ├── p18p17_0010_A1.rd3 │ ├── p18p17_0011_A1.rad │ ├── p18p17_0011_A1.rd3 │ ├── p18p17_0012_A1.rad │ ├── p18p17_0012_A1.rd3 │ ├── p18p17_0013_A1.rad │ ├── p18p17_0013_A1.rd3 │ ├── p18p17_0014_A1.rad │ ├── p18p17_0014_A1.rd3 │ ├── p18p17_0015_A1.rad │ ├── p18p17_0015_A1.rd3 │ ├── p18p17_0016_A1.rad │ ├── p18p17_0016_A1.rd3 │ ├── p18p17_0017_A1.rad │ ├── p18p17_0017_A1.rd3 │ ├── p18p17_0018_A1.rad │ ├── p18p17_0018_A1.rd3 │ ├── p18p17_0019_A1.rad │ ├── p18p17_0019_A1.rd3 │ ├── p18p17_0020_A1.rad │ ├── p18p17_0020_A1.rd3 │ ├── p18p17_0021_A1.rad │ ├── p18p17_0021_A1.rd3 │ ├── p18p17_0022_A1.rad │ ├── p18p17_0022_A1.rd3 │ ├── p18p17_0023_A1.rad │ ├── p18p17_0023_A1.rd3 │ ├── p18p17_0024_A1.rad │ ├── p18p17_0024_A1.rd3 │ ├── p18p17_0025_A1.rad │ ├── p18p17_0025_A1.rd3 │ ├── p18p17_0026_A1.rad │ ├── p18p17_0026_A1.rd3 │ ├── p18p17_0027_A1.rad │ └── p18p17_0027_A1.rd3 ├── t0102_tt.dat ├── t0302_tt.dat ├── testConstraints │ ├── F1.xyz │ ├── F2.xyz │ ├── F3.xyz │ ├── F3_vel.con │ ├── F4.xyz │ ├── F5.xyz │ ├── F6.xyz │ └── test1_vel.con └── tt.dat ├── test_db.h5 ├── test_segy.py ├── utils.py └── utils_ui.py /.gitattributes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/.gitattributes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | build/ 4 | .project 5 | .pydevproject 6 | .settings/ 7 | .DS_Store 8 | cutils/*.so 9 | -------------------------------------------------------------------------------- /02_TODO.txt: -------------------------------------------------------------------------------- 1 | As of June 30th 2017... 2 | 3 | Covar_ui is close to done: 4 | 5 | - Some validation tests for amplitude covariance are still missing (for instance, curved rays must be loaded to access that functionality); 6 | - No tests were made on the interface for 3D grids; 7 | - Experimental covariance isn't implemented; 8 | - No tests were run on anisotropic covariance models. 9 | 10 | In order to successfully create a covariance model, some preliminary steps are required. First, on must create the model in database_ui 11 | and add at least one mog to it. The latter must have boreholes associated with it. Second, one should create the model's grid (N.B.: don't 12 | forget clicking on 'Done' on the grid editor). Finally, one must also indicate the arrival times for each of the traces from the manual_tt_ui 13 | (which can be achieved easily by importing testData\tt.dat). Every feature of covar_ui should then be accessible. 14 | 15 | Random tasks: 16 | 17 | - Model.getModelData seems to be missing supported types (for instance, 'tt' is supported, but 'amp' isn't). These exist in Model.m 18 | within the Matlab code; 19 | - Model.getModelData also doesn't support an upper limit velocity ('vlim'); 20 | - All dependencies from object to object should be cleared once it refers to a deleted object. One should study how the 'relationships' 21 | are implemented between the Borehole, Mog, AirShots and Model classes in order to achieve this; 22 | - Data management is not fully viable: whenever a stored class' attribute's name is modified, the database is deprecated, which 23 | is quite a problem. One could solve this issue by completing 'convert_database' from the module 'database', although this is neither urgent 24 | nor easy to do. Some resources on this subject might exist on the web. 25 | 26 | Data management through SQLAlchemy has been fully implemented in database_ui and covar_ui, and the main submodules. 27 | Some other modules still lack this implementation, though. One should consider close to every *.bh, *.mog, *.model and 28 | *.air attributes deprecated if applied to a user interface. Those should be replaced by a call into the database by 29 | the means of .session.query(). 30 | 31 | Quite often, a specific class's attribute may fail to save. This is due to the issue described in database.save_as's documentation. 32 | One should consider solving this issue as soon as possible, as the errors it causes are hard to debug, and the solving of this 33 | issue would result in much less confusing code. 34 | 35 | Be wary of the tools such as auto_create_scrollbar() and lay() in utils_ui, as they provide a way of reducing the 36 | quantity of code for a specified task and improving readability. 37 | 38 | Arguments unpacking is used thoroughly in covar_ui and utils_ui, so one should become comfortable with this functionality 39 | of Python. The star ('*') is used to separate an iterable into different arguments. Therefore, 'print(*['a', 'b', 'c'])' reads 40 | as 'print('a', 'b', 'c')'. 41 | 42 | The code is fully PEP 8 compatible, exception made for the extra spaces before and after operators and for lines too long, 43 | which are ignored for the purpose of readability. (Full list of ignored errors: E202, E221, E241, E501, E722, E741) 44 | 45 | Finally, one should refer to the TODO annotations for specific tasks. Those may require a better understanding of BhTomoPy, though. -------------------------------------------------------------------------------- /BhTomoPy.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/BhTomoPy.ai -------------------------------------------------------------------------------- /BhTomoPy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/BhTomoPy.png -------------------------------------------------------------------------------- /Icons/triangle_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/Icons/triangle_down.png -------------------------------------------------------------------------------- /Icons/triangle_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/Icons/triangle_right.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BhTomoPy 2 | Borehole radar/seismic tomography package in python 3 | 4 | This is ongoing work to port the Matlab bh_tomo package to python. *BhTomoPy is not ready yet, it should be used only for testing* 5 | 6 | 7 | BhTomoPy is coded in python 3 and is currently being developped on systems running python 3.6 8 | -------------------------------------------------------------------------------- /bh_tomo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import os 23 | import sys 24 | 25 | from PyQt5 import QtGui, QtCore, QtWidgets 26 | 27 | from database_ui import DatabaseUI 28 | from manual_tt_ui import ManualttUI 29 | from covar_ui import CovarUI 30 | from inversion_ui import InversionUI 31 | from interp_ui import InterpretationUI 32 | from semi_auto_tt_ui import SemiAutottUI 33 | from manual_amp_ui import ManualAmpUI 34 | 35 | 36 | class BhTomoPy(QtWidgets.QWidget): 37 | 38 | def __init__(self, parent=None): 39 | super(BhTomoPy, self).__init__(parent) 40 | self.setWindowTitle("BhTomoPy") 41 | 42 | self.dbname = '' 43 | self.database = DatabaseUI() 44 | self.manual_tt = ManualttUI() 45 | self.semi_tt = SemiAutottUI() 46 | self.covar = CovarUI() 47 | self.inv = InversionUI() 48 | self.interp = InterpretationUI() 49 | self.manual_amp = ManualAmpUI() 50 | self.init_UI() 51 | 52 | self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, 53 | QtWidgets.QSizePolicy.Minimum) 54 | 55 | def choose_db(self): 56 | filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Choose Database')[0] 57 | if filename: 58 | self.dbname = filename 59 | self.current_db.setText(os.path.basename(filename)) 60 | 61 | def show(self): 62 | super(BhTomoPy, self).show() 63 | 64 | # Gets initial geometry of the widget 65 | qr = self.frameGeometry() 66 | 67 | # Shows it at the center of the screen 68 | cp = QtWidgets.QDesktopWidget().availableGeometry().center() 69 | 70 | # Moves the window's center at the center of the screen 71 | qr.moveCenter(cp) 72 | 73 | # Then moves it at the top left 74 | translation = qr.topLeft() 75 | 76 | self.move(translation) 77 | 78 | self.setFixedSize(self.size()) 79 | self.__h1 = self.size().height() 80 | self.__h2 = self.tt_tool.size().height() + self.tl_tool.size().height() 81 | 82 | def init_UI(self): 83 | 84 | # ------- Widgets ------- # 85 | # --- Actions --- # 86 | ChooseDbAction = QtWidgets.QAction('Choose Database', self) 87 | ChooseDbAction.setShortcut('Ctrl+O') 88 | ChooseDbAction.triggered.connect(self.choose_db) 89 | 90 | ConvertDbAction = QtWidgets.QAction('Convert Database', self) 91 | ConvertDbAction.setShortcut('Ctrl+C') 92 | 93 | # --- Menubar --- # 94 | self.menu = QtWidgets.QMenuBar() 95 | filemenu = self.menu.addMenu('&File') 96 | editmenu = self.menu.addMenu('&Edit') 97 | filemenu.addAction(ChooseDbAction) 98 | editmenu.addAction(ConvertDbAction) 99 | 100 | # --- Buttons --- # 101 | btn_Database = QtWidgets.QPushButton("Database") 102 | btn_Automatic_Traveltime_Picking = QtWidgets.QPushButton("Automatic (AIC-CWT)") 103 | btn_Semi_Automatic_Traveltime_Picking = QtWidgets.QPushButton("Semi-Automatic (x-corr)") 104 | btn_Manual_Traveltime_Picking = QtWidgets.QPushButton("Manual") 105 | btn_Manual_Amplitude_Picking = QtWidgets.QPushButton("Manual Amplitude Picking") 106 | btn_Cov_Mod = QtWidgets.QPushButton("Covariance Model") 107 | btn_Inversion = QtWidgets.QPushButton("Inversion") 108 | btn_Interpretation = QtWidgets.QPushButton("Interpretation (GPR)") 109 | btn_Time_Lapse_Inversion = QtWidgets.QPushButton("Inversion") 110 | btn_Time_Lapse_Visualisation = QtWidgets.QPushButton("Visualisation") 111 | btn_Nano_Fluid = QtWidgets.QPushButton("Magnetic Nano Fluid Saturation") 112 | 113 | # - Buttons Disposition - # 114 | btn_Automatic_Traveltime_Picking.setDisabled(True) 115 | btn_Time_Lapse_Inversion.setDisabled(True) 116 | btn_Time_Lapse_Visualisation.setDisabled(True) 117 | # btn_Nano_Fluid.setDisabled(True) 118 | 119 | # - Buttons Actions - # 120 | btn_Database.clicked.connect(lambda: self.database.show(self.dbname)) 121 | btn_Manual_Traveltime_Picking.clicked.connect(lambda: self.manual_tt.show(self.dbname)) 122 | btn_Semi_Automatic_Traveltime_Picking.clicked.connect(lambda: self.semi_tt.show(self.dbname)) 123 | btn_Cov_Mod.clicked.connect(lambda: self.covar.show(self.dbname)) 124 | btn_Inversion.clicked.connect(lambda: self.inv.show(self.dbname)) 125 | btn_Interpretation.clicked.connect(lambda: self.interp.show(self.dbname)) 126 | btn_Manual_Amplitude_Picking.clicked.connect(lambda: self.manual_amp.show(self.dbname)) 127 | 128 | # --- Image --- # 129 | pic = QtGui.QPixmap(os.getcwd() + "/BhTomoPy.png") 130 | image_label = QtWidgets.QLabel() 131 | image_label.setPixmap(pic) 132 | image_label.setAlignment(QtCore.Qt.AlignCenter) 133 | 134 | # # --- Title --- # 135 | # Title = QtWidgets.QLabel( 136 | # 'BH TOMO \n Borehole Radar/Seismic Data Processing Center') 137 | # Title.setAlignment(QtCore.Qt.AlignHCenter) 138 | # Title.setContentsMargins(10, 10, 10, 30) 139 | # Title.setStyleSheet('color: Darkcyan') 140 | # serifFont = QtGui.QFont("Times", 10, QtGui.QFont.Bold) 141 | # Title.setFont(serifFont) 142 | 143 | # --- Edit --- # 144 | # Edit to hold the chosen database's name 145 | self.current_db = QtWidgets.QLineEdit() 146 | 147 | # - Edit Disposition - # 148 | self.current_db.setReadOnly(True) 149 | self.current_db.setAlignment(QtCore.Qt.AlignHCenter) 150 | 151 | # --- Image SubWidget --- # 152 | sub_image_widget = QtWidgets.QWidget() 153 | sub_image_grid = QtWidgets.QGridLayout() 154 | sub_image_grid.addWidget(image_label, 0, 0) 155 | sub_image_grid.setContentsMargins(20, 0, 20, 0) 156 | sub_image_widget.setLayout(sub_image_grid) 157 | 158 | # --- Traveltime ToolBox --- # 159 | travel_time_tool = QtWidgets.QWidget() 160 | travel_time_grid = QtWidgets.QGridLayout() 161 | travel_time_grid.addWidget(btn_Manual_Traveltime_Picking, 0, 0) 162 | travel_time_grid.addWidget(btn_Semi_Automatic_Traveltime_Picking, 1, 0) 163 | travel_time_grid.addWidget(btn_Automatic_Traveltime_Picking, 2, 0) 164 | travel_time_tool.setLayout(travel_time_grid) 165 | 166 | # --- Time Lapse Tool --- # 167 | time_lapse_tool = QtWidgets.QWidget() 168 | time_lapse_grid = QtWidgets.QGridLayout() 169 | time_lapse_grid.addWidget(btn_Time_Lapse_Inversion, 0, 0) 170 | time_lapse_grid.addWidget(btn_Time_Lapse_Visualisation, 1, 0) 171 | time_lapse_tool.setLayout(time_lapse_grid) 172 | 173 | # --- Traveltime ToolBox --- # 174 | tt_tool = MyQToolBox() 175 | tt_tool.setIcons(QtGui.QIcon('Icons/triangle_right.png'), 176 | QtGui.QIcon('Icons/triangle_down.png')) 177 | tt_tool.addItem(travel_time_tool, 'Travel Time Picking') 178 | tt_tool.sizeChanged.connect(self.fit_height) 179 | self.tt_tool = tt_tool 180 | 181 | # --- Time Lapse ToolBox --- # 182 | tl_tool = MyQToolBox() 183 | tl_tool.setIcons(QtGui.QIcon('Icons/triangle_right.png'), 184 | QtGui.QIcon('Icons/triangle_down.png')) 185 | tl_tool.addItem(time_lapse_tool, 'Time Lapse') 186 | tl_tool.sizeChanged.connect(self.fit_height) 187 | self.tl_tool = tl_tool 188 | 189 | # --- Connecting mutual closing --- # 190 | tl_tool.toolboxOpened.connect(tt_tool.closeAll) 191 | tt_tool.toolboxOpened.connect(tl_tool.closeAll) 192 | 193 | # --- Buttons SubWidget --- # 194 | Sub_button_widget = QtWidgets.QGroupBox() 195 | sub_button_grid = QtWidgets.QGridLayout() 196 | sub_button_grid.addWidget(btn_Database, 0, 0) 197 | sub_button_grid.addWidget(tt_tool, 1, 0) 198 | sub_button_grid.addWidget(btn_Manual_Amplitude_Picking, 2, 0) 199 | sub_button_grid.addWidget(btn_Cov_Mod, 3, 0) 200 | sub_button_grid.addWidget(btn_Inversion, 4, 0) 201 | sub_button_grid.addWidget(tl_tool, 5, 0) 202 | sub_button_grid.addWidget(btn_Interpretation, 6, 0) 203 | sub_button_grid.addWidget(btn_Nano_Fluid, 7, 0) 204 | sub_button_grid.setRowStretch(8, 100) 205 | Sub_button_widget.setLayout(sub_button_grid) 206 | 207 | # --- Main Widget--- # 208 | master_grid = QtWidgets.QGridLayout() 209 | master_grid.addWidget(self.menu, 0, 0, 1, 4) 210 | master_grid.addWidget(sub_image_widget, 1, 0, 1, 4) 211 | master_grid.addWidget(self.current_db, 2, 1, 1, 2) 212 | master_grid.addWidget(Sub_button_widget, 3, 0, 1, 4) 213 | sub_button_grid.setRowStretch(0, 0) 214 | sub_button_grid.setRowStretch(1, 0) 215 | master_grid.setContentsMargins(0, 0, 0, 0) 216 | master_grid.setVerticalSpacing(3) 217 | 218 | self.setLayout(master_grid) 219 | 220 | def fit_height(self, x): 221 | # shrink or expand height to fit the toolbox 222 | h = self.__h1 + x - self.__h2 223 | self.setFixedHeight(h) 224 | 225 | 226 | class MyQToolBox(QtWidgets.QWidget): 227 | 228 | """ 229 | A custom widget that mimicks the behavior of the "Tools" sidepanel in 230 | Adobe Acrobat. It is derived from a QToolBox with the following variants: 231 | 232 | 1. Only one tool can be displayed at a time. 233 | 2. Unlike the stock QToolBox widget, it is possible to hide all the tools. 234 | 3. It is also possible to hide the current displayed tool by clicking on 235 | its header. 236 | 4. Closed and Expanded arrows can be set from custom icons. 237 | 5. The tools that are hidden are marked by a right-arrow icon, while the 238 | tool that is currently displayed is marked with a down-arrow icon. 239 | """ 240 | # ============================================================================= 241 | 242 | sizeChanged = QtCore.pyqtSignal(float) 243 | toolboxOpened = QtCore.pyqtSignal() 244 | 245 | def __init__(self, parent=None): 246 | super(MyQToolBox, self).__init__(parent) 247 | 248 | self.__iclosed = QtWidgets.QWidget().style().standardIcon( 249 | QtWidgets.QStyle.SP_ToolBarHorizontalExtensionButton) 250 | self.__iexpand = QtWidgets.QWidget().style().standardIcon( 251 | QtWidgets.QStyle.SP_ToolBarVerticalExtensionButton) 252 | 253 | self.setLayout(QtWidgets.QGridLayout()) 254 | self.layout().setContentsMargins(0, 0, 0, 0) 255 | 256 | self.__currentIndex = -1 257 | 258 | def setIcons(self, ar_right, ar_down): # ================================= 259 | self.__iclosed = ar_right 260 | self.__iexpand = ar_down 261 | 262 | def addItem(self, tool, text): # ========================================= 263 | 264 | N = self.layout().rowCount() 265 | 266 | # ---- Add Header ---- 267 | 268 | head = QtWidgets.QPushButton(text) 269 | head.setIcon(self.__iclosed) 270 | head.clicked.connect(self.__isClicked__) 271 | head.setStyleSheet("QPushButton {text-align:left;}") 272 | head.sizeHint().height() 273 | 274 | self.layout().addWidget(head, N - 1, 0) 275 | 276 | # ---- Add Item in a ScrollArea ---- 277 | 278 | scrollarea = QtWidgets.QScrollArea() 279 | scrollarea.setFrameStyle(0) 280 | scrollarea.hide() 281 | scrollarea.setStyleSheet("QScrollArea {background-color:transparent;}") 282 | scrollarea.setWidgetResizable(True) 283 | 284 | tool.setObjectName("myViewport") 285 | tool.setStyleSheet("#myViewport {background-color:transparent;}") 286 | scrollarea.setWidget(tool) 287 | 288 | self.layout().addWidget(scrollarea, N, 0) 289 | 290 | def __isClicked__(self): # =============================================== 291 | 292 | for row in range(0, self.layout().rowCount() - 1, 2): 293 | 294 | head = self.layout().itemAtPosition(0, 0).widget() 295 | tool = self.layout().itemAtPosition(row + 1, 0).widget() 296 | 297 | if head == self.sender(): 298 | if self.__currentIndex == row: 299 | # if clicked tool is open, closes it 300 | head.setIcon(self.__iclosed) 301 | tool.hide() 302 | self.__currentIndex = -1 303 | self.sizeChanged.emit(self.sizeHint().height() + head.sizeHint().height()) 304 | 305 | else: 306 | # if clicked tool is closed, expands it 307 | head.setIcon(self.__iexpand) 308 | tool.show() 309 | self.__currentIndex = row 310 | self.toolboxOpened.emit() 311 | self.sizeChanged.emit(self.sizeHint().height() + head.sizeHint().height()) 312 | 313 | def closeAll(self): # ==================================================== 314 | 315 | # allows opening only one toolbox at a time using the 'toolboxOpened' signal 316 | 317 | for row in range(0, self.layout().rowCount() - 1, 2): 318 | 319 | head = self.layout().itemAtPosition(0, 0).widget() 320 | tool = self.layout().itemAtPosition(row + 1, 0).widget() 321 | 322 | if self.__currentIndex == row: 323 | 324 | head.setIcon(self.__iclosed) 325 | tool.hide() 326 | self.__currentIndex = -1 327 | self.sizeChanged.emit(self.sizeHint().height() + head.sizeHint().height()) 328 | 329 | 330 | if __name__ == '__main__': 331 | 332 | app = QtWidgets.QApplication(sys.argv) 333 | 334 | bh_tomo = BhTomoPy() 335 | bh_tomo.show() 336 | 337 | sys.exit(app.exec_()) 338 | -------------------------------------------------------------------------------- /borehole.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import numpy as np 23 | 24 | 25 | class Borehole: 26 | """ 27 | Class holding borehole data 28 | """ 29 | 30 | def __init__(self, name=''): 31 | 32 | self.name = name 33 | self.X = 0.0 34 | self.Y = 0.0 35 | self.Z = 0.0 36 | self.Xmax = 0.0 37 | self.Ymax = 0.0 38 | self.Zmax = 0.0 39 | self.Z_surf = 0.0 40 | self.Z_water = 0.0 41 | self.scont = np.array([]) 42 | self.acont = np.array([]) 43 | self.fdata = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]) 44 | self.modified = True 45 | 46 | @staticmethod 47 | def project(fdata, ldepth): 48 | """ 49 | Project measurement points on borehole trajectory 50 | 51 | INPUT: 52 | 53 | fdata: matrix(n, 3) where the 3 columns represent the x, y and z coordinates 54 | of the BH's trajectory for a single n value. 55 | The n are sorted in growing order, from the top to the bottom of the borehole. 56 | 57 | ldepth: vector(1,m) which reprensents the position of the m measurement points (from top to bottom) 58 | 59 | Note: the discrete points of the BH's trajectory are not the same as the discrete points of the ldepth 60 | that's why we do this function; to determine the projection of the ldepth point on the fdata trajectory. 61 | 62 | OUTPUT: 63 | 64 | x: x coordinates of all measurement points 65 | y: y coordinates of all measurement points 66 | z: z coordinates of all measurement points 67 | c: direction of cosines at measurements points which point downwards 68 | """ 69 | 70 | npts = ldepth.size 71 | # the x,y and z coordinates are initially a matrix which contains as much 0 as the number of measurement points 72 | # we can see the c value as the combination of the three cartesian coordinates in unitary form 73 | x = np.zeros((npts, 1)) 74 | y = np.zeros((npts, 1)) 75 | z = np.zeros((npts, 1)) 76 | c = np.zeros((npts, 3)) 77 | 78 | depthBH = np.append(np.array([[0]]), np.cumsum(np.sqrt(np.sum(np.diff(fdata, n=1, axis=0) ** 2, axis=1)))) 79 | 80 | # Knowing that de BH's depth is a matrix which contains the distance between every points of fdata, and that 81 | # ldepth contains the points where the data was taken,we need to first make sure that every points taken in 82 | # charge by ldepth is in the range of the BH's depth. As a matter of fact, we verify if each points of ldepth 83 | # is contained in between the volume (i.e. between X and Xmax and the same for Y and Z). If so, we take the 84 | # closest point under our point of interest (i.e. i2[0]) and the closest point above our point of interest 85 | # (i.e. i1[-1]). So you can anticipate that these points will change for every index of the ldepth vector. 86 | 87 | for n in range(npts): 88 | i1, = np.nonzero(ldepth[n] >= depthBH) 89 | i2, = np.nonzero(ldepth[n] < depthBH) 90 | if i1.size == 0 or i2.size == 0: 91 | x = np.zeros((npts, 1)) 92 | y = np.zeros((npts, 1)) 93 | z = np.zeros((npts, 1)) 94 | c = np.zeros((npts, 3)) 95 | raise ValueError('Depth data outside trajectory range') 96 | i1 = i1[-1] 97 | i2 = i2[0] 98 | 99 | # Here we calculate the distance between the points which have the same index than the closest points above 100 | # and under 101 | d = np.sqrt(np.sum((fdata[i2, :] - fdata[i1, :]) ** 2)) 102 | l = (fdata[i2, :] - fdata[i1, :]) / d 103 | # the l value represents the direction cosine for every dimension 104 | 105 | d2 = ldepth[n] - depthBH[i1] 106 | 107 | x[n] = fdata[i1, 0] + d2 * l[0] 108 | y[n] = fdata[i1, 1] + d2 * l[1] 109 | z[n] = fdata[i1, 2] + d2 * l[2] 110 | c[n, :] = l 111 | 112 | # We represent the ldepth's point of interest coordinates by adding the direction cosine of every dimension 113 | # to the closest upper point's coordinates 114 | return x, y, z, c 115 | 116 | 117 | if __name__ == '__main__': 118 | fdatatest = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5]], dtype=np.float64) 119 | ldepthtest = np.array([1, 2, 3, 4, 5], dtype=np.float64) 120 | bh1 = Borehole('BH1') 121 | bh1.fdata = fdatatest 122 | x, y, z, c = Borehole.project(fdatatest, ldepthtest) 123 | print(x) 124 | print(y) 125 | print(z) 126 | print(c) 127 | -------------------------------------------------------------------------------- /borehole_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | import os 22 | import re 23 | import sys 24 | from PyQt5 import QtCore, QtWidgets 25 | import numpy as np 26 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg 27 | from matplotlib.figure import Figure 28 | from mpl_toolkits.mplot3d import axes3d # @UnusedImport 29 | import vtk 30 | 31 | from borehole import Borehole 32 | from utils_ui import MyQLabel 33 | from database import BhTomoDb 34 | 35 | 36 | class BoreholeUI(QtWidgets.QWidget): 37 | # ------- Signals ------- # 38 | bhlogSignal = QtCore.pyqtSignal(str) 39 | bhUpdateSignal = QtCore.pyqtSignal( 40 | list) # this signal sends the information to update the Tx and Rx comboboxes in MogUI 41 | bhInfoSignal = QtCore.pyqtSignal( 42 | int) # this signal sends the information to update the number of boreholes in infoUI 43 | 44 | def __init__(self, db, parent=None): 45 | super(BoreholeUI, self).__init__(parent) 46 | self.db = db 47 | self.setWindowTitle("BhTomoPy/Borehole") 48 | self.init_UI() 49 | self.update_list_widget() 50 | self.update_list_edits() 51 | 52 | def import_borehole(self): 53 | """ 54 | This method opens a QFileDialog, takes the name that the user has selected and 55 | updates the borehole's informations 56 | """ 57 | filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Import Borehole')[0] 58 | try: 59 | if filename: 60 | self.load_borehole(filename) 61 | except: 62 | self.bhlogSignal.emit('Error: Borehole file must have *.xyz extension') 63 | 64 | def export_boreholes(self): 65 | filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Export boreholes', '', 'VTK file (*.vtp)', '') 66 | if filename != '': 67 | pts = vtk.vtkPoints() 68 | for bh in self.db.boreholes: 69 | for n in range(bh.fdata.shape[0]): 70 | pts.InsertNextPoint(bh.fdata[n, 0], bh.fdata[n, 1], bh.fdata[n, 2]) 71 | polydata = vtk.vtkPolyData() 72 | polydata.SetPoints(pts) 73 | cellarray = vtk.vtkCellArray() 74 | npts = 0 75 | for bh in self.db.boreholes: 76 | line = vtk.vtkPolyLine() 77 | line.GetPointIds().SetNumberOfIds(bh.fdata.shape[0]) 78 | for n in range(bh.fdata.shape[0]): 79 | line.GetPointIds().SetId(n, npts) 80 | npts += 1 81 | cellarray.InsertNextCell(line) 82 | polydata.SetLines(cellarray) 83 | writer = vtk.vtkXMLPolyDataWriter() 84 | writer.SetFileName(filename) 85 | writer.SetInputData(polydata) 86 | writer.SetDataModeToBinary() 87 | writer.Update() 88 | 89 | def load_borehole(self, filename): 90 | 91 | rname = os.path.basename(filename) 92 | rname = rname.strip('.xyz') 93 | bh = Borehole(str(rname)) 94 | self.db.boreholes.append(bh) 95 | bh.fdata = np.loadtxt(filename) 96 | bh.X = bh.fdata[0, 0] 97 | bh.Y = bh.fdata[0, 1] 98 | bh.Z = bh.fdata[0, 2] 99 | bh.Xmax = bh.fdata[-1, 0] 100 | bh.Ymax = bh.fdata[-1, 1] 101 | bh.Zmax = bh.fdata[-1, 2] 102 | self.update_list_widget() 103 | self.bh_list.setCurrentRow(len(self.db.boreholes) - 1) 104 | self.update_list_edits() 105 | self.bhlogSignal.emit("{}.xyz has been loaded successfully".format(rname)) 106 | 107 | def add_borehole(self): 108 | """ 109 | This method will create an instance of Borehole and initialize it, while showing the value of all its 110 | attributes in the coordinates edits 111 | """ 112 | name, ok = QtWidgets.QInputDialog.getText(self, "Borehole creation", "Borehole name") 113 | if ok: 114 | bh = Borehole(str(name)) 115 | try: 116 | self.db.boreholes.append(bh) 117 | except ValueError: 118 | QtWidgets.QMessageBox.warning(self, 'Error', 'Borehole name already used', 119 | buttons=QtWidgets.QMessageBox.Ok) 120 | return 121 | self.update_list_widget() 122 | self.bh_list.setCurrentRow(len(self.db.boreholes) - 1) 123 | self.update_list_edits() 124 | self.bhlogSignal.emit("{} borehole has been added successfully".format(name)) 125 | 126 | def update_list_widget(self): 127 | """ 128 | Updates the information in the bh_list, then emits the instances contained in boreholes and the 129 | length of bh_list to DatabaseUI 130 | """ 131 | self.bh_list.clear() 132 | for bh in self.db.boreholes: 133 | self.bh_list.addItem(bh.name) 134 | self.bhInfoSignal.emit(len(self.bh_list)) 135 | self.bhUpdateSignal.emit(self.db.boreholes) # TODO rework 136 | 137 | def update_list_edits(self): 138 | """ 139 | Updates the coordinates edits information with the attributes of the Borehole class instance 140 | """ 141 | bh = self.current_borehole() 142 | if bh: 143 | self.X_edit.setText(str(bh.X)) 144 | self.Y_edit.setText(str(bh.Y)) 145 | self.Z_edit.setText(str(bh.Z)) 146 | self.Xmax_edit.setText(str(bh.Xmax)) 147 | self.Ymax_edit.setText(str(bh.Ymax)) 148 | self.Zmax_edit.setText(str(bh.Zmax)) 149 | self.Z_surf_edit.setText(str(bh.Z_surf)) 150 | if bh.Z_water is None: 151 | self.Z_water_edit.setText('') 152 | else: 153 | self.Z_water_edit.setText(str(bh.Z_water)) 154 | else: 155 | self.X_edit.setText('0.0') 156 | self.Y_edit.setText('0.0') 157 | self.Z_edit.setText('0.0') 158 | self.Xmax_edit.setText('0.0') 159 | self.Ymax_edit.setText('0.0') 160 | self.Zmax_edit.setText('0.0') 161 | self.Z_surf_edit.setText('0.0') 162 | self.Z_water_edit.setText('') 163 | 164 | def current_borehole(self): 165 | 166 | row = self.bh_list.currentRow() 167 | if row != -1: 168 | return self.db.boreholes[row] 169 | 170 | def delete_borehole(self): 171 | """ 172 | Deletes a borehole instance from boreholes 173 | """ 174 | item = self.current_borehole() 175 | if item: 176 | # check if borehole is used by mogs 177 | for mog in self.db.mogs: 178 | if mog.Tx is item or mog.Rx is item: 179 | QtWidgets.QMessageBox.warning(self, 'Warning', 180 | 'Borehole {0:s} used by MOG {1:s}'.format(item.name, mog.name), 181 | buttons=QtWidgets.QMessageBox.Ok) 182 | break 183 | else: 184 | self.db.boreholes.remove(item) 185 | self.bhlogSignal.emit("{} has been deleted".format(item.name)) 186 | if len(self.db.boreholes) > 0: 187 | self.bh_list.setCurrentRow(0) 188 | else: 189 | self.bh_list.setCurrentRow(-1) 190 | self.update_list_widget() 191 | self.update_list_edits() 192 | 193 | def update_borehole_data(self): 194 | """ 195 | Updates the borehole's attributes from the coordinates edits 196 | """ 197 | 198 | exp = re.compile("^-?[0-9]+([\.,][0-9]+)?$") # float number, with or without decimals, and allowing negatives 199 | 200 | for item in ( 201 | self.X_edit, self.Y_edit, self.Z_edit, self.Xmax_edit, self.Ymax_edit, self.Zmax_edit, self.Z_surf_edit, 202 | self.Z_water_edit): 203 | 204 | if item.text() != '' and not exp.match(item.text()): 205 | self.bhlogSignal.emit("Error: Some edited information is incorrect.") 206 | item.setFocus() 207 | QtWidgets.QMessageBox.warning(self, 'Warning', 208 | "Some edited information is incorrect. Edit fields cannot contain letters or special characters.", 209 | buttons=QtWidgets.QMessageBox.Ok) 210 | self.updateHandler = False 211 | return 212 | 213 | item.setText(item.text().replace(',', '.')) 214 | 215 | self.updateHandler = False 216 | 217 | item = self.current_borehole() 218 | if item: 219 | bh = item 220 | bh.X = float(self.X_edit.text()) 221 | bh.Y = float(self.Y_edit.text()) 222 | bh.Z = float(self.Z_edit.text()) 223 | bh.Xmax = float(self.Xmax_edit.text()) 224 | bh.Ymax = float(self.Ymax_edit.text()) 225 | bh.Zmax = float(self.Zmax_edit.text()) 226 | bh.Z_surf = float(self.Z_surf_edit.text()) 227 | if self.Z_water_edit.text() == '': 228 | bh.Z_water = None 229 | else: 230 | bh.Z_water = float(self.Z_water_edit.text()) 231 | bh.fdata[0, 0] = bh.X 232 | bh.fdata[0, 1] = bh.Y 233 | bh.fdata[0, 2] = bh.Z 234 | bh.fdata[-1, 0] = bh.Xmax 235 | bh.fdata[-1, 1] = bh.Ymax 236 | bh.fdata[-1, 2] = bh.Zmax 237 | bh.modified = True 238 | 239 | def plot(self): 240 | """ 241 | Plots all the Borehole instances in boreholes 242 | """ 243 | if len(self.db.boreholes) != 0: 244 | self.bholeFig = BoreholeFig() 245 | self.bholeFig.plot_bholes(self.db.boreholes) 246 | 247 | for bh in self.db.boreholes: 248 | self.bhlogSignal.emit("{}'s trajectory has been plotted".format(bh.name)) 249 | self.bholeFig.show() 250 | 251 | def attenuation_constraints(self): 252 | """ 253 | Knowing the values of attenuation depending on elevation, we can define the attenuation on the borehole's trajectory 254 | with the project method and then associate an exactitude value (covariance) to each of them if it is given in the *.con file. 255 | We then associate the Cont instance to the borehole's acont attribute 256 | """ 257 | item = self.current_borehole() 258 | if item: 259 | acont = Cont() 260 | filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File')[0] 261 | rname = os.path.basename(filename) 262 | rname = rname[:-4] 263 | if ".con" in filename: 264 | bh = item 265 | cont = np.loadtxt(filename) 266 | 267 | acont.x, acont.y, acont.z, _ = bh.project(bh.fdata, cont[:, 0]) 268 | 269 | acont.x = acont.x.flatten() 270 | acont.y = acont.y.flatten() 271 | acont.z = acont.z.flatten() 272 | acont.valeur = cont[:, 1] 273 | 274 | if np.size(cont, axis=1) == 3: 275 | acont.variance = cont[:, 2] 276 | else: 277 | acont.variance = np.zeros(len(cont[:, 1])) 278 | 279 | bh.acont = acont 280 | self.bhlogSignal.emit( 281 | "{} Attenuation Constraints have been applied to Borehole {} ".format(rname, bh.name)) 282 | bh.modified = True 283 | else: 284 | self.bhlogSignal.emit("Error: the file's extension must be *.con") 285 | 286 | def slowness_constraints(self): 287 | """ 288 | Practically the same method as attenuation_constraints but reversed 289 | """ 290 | bh = self.current_borehole() 291 | scont = Cont() 292 | if bh: 293 | filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File')[0] 294 | rname = os.path.basename(filename) 295 | rname = rname[:-4] 296 | if ".con" in filename: 297 | cont = np.loadtxt(filename) 298 | 299 | scont.x, scont.y, scont.z, _ = bh.project(bh.fdata, cont[:, 0]) 300 | 301 | scont.x = scont.x.flatten() 302 | scont.y = scont.y.flatten() 303 | scont.z = scont.z.flatten() 304 | scont.valeur = 1 / cont[:, 1] 305 | 306 | if np.size(cont, axis=1) == 3: 307 | # inversion of a random variable http://math.stackexchange.com/questions/269216/inverse-of-random-variable 308 | scont.variance = cont[:, 2] / (cont[:, 1] ** 4) 309 | else: 310 | scont.variance = np.zeros(len(cont[:, 1])) 311 | 312 | bh.scont = scont 313 | self.bhlogSignal.emit( 314 | "{} Slowness Constraints have been applied to Borehole {} ".format(rname, bh.name)) 315 | bh.modified = True 316 | else: 317 | self.bhlogSignal.emit("Error: the file's extension must be *.con") 318 | 319 | def init_UI(self): 320 | 321 | # ------- Widget Creation ------- # 322 | # --- Buttons Set--- # 323 | btn_Add = QtWidgets.QPushButton("Add") 324 | btn_Remove = QtWidgets.QPushButton("Remove") 325 | btn_Import = QtWidgets.QPushButton("Import") 326 | btn_Plot = QtWidgets.QPushButton("Plot") 327 | btn_Constraints_veloc = QtWidgets.QPushButton("Constraints Veloc.") 328 | btn_Constraints_atten = QtWidgets.QPushButton("Constraints Atten.") 329 | 330 | # --- list --- # 331 | self.bh_list = QtWidgets.QListWidget() 332 | 333 | # --- Labels --- # 334 | Coord_label = MyQLabel('Coordinates', ha='center') 335 | Collar_label = MyQLabel('Collar', ha='center') 336 | Bottom_label = MyQLabel('Bottom', ha='center') 337 | X_label = MyQLabel('X:', ha='right') 338 | Y_label = MyQLabel('Y:', ha='right') 339 | Elev_label = MyQLabel('Elevation:', ha='right') 340 | Elev_surf_label = QtWidgets.QLabel("Elevation at surface:") 341 | Elev_water_label = MyQLabel('Water elevation:', ha='right') 342 | 343 | # --- Edits --- # 344 | self.X_edit = QtWidgets.QLineEdit() 345 | self.Y_edit = QtWidgets.QLineEdit() 346 | self.Z_edit = QtWidgets.QLineEdit() 347 | self.Xmax_edit = QtWidgets.QLineEdit() 348 | self.Ymax_edit = QtWidgets.QLineEdit() 349 | self.Zmax_edit = QtWidgets.QLineEdit() 350 | self.Z_surf_edit = QtWidgets.QLineEdit() 351 | self.Z_water_edit = QtWidgets.QLineEdit() 352 | 353 | # --- List Actions --- # 354 | self.bh_list.itemSelectionChanged.connect(self.update_list_edits) 355 | 356 | # --- Edits Actions --- # 357 | self.X_edit.editingFinished.connect(self.update_borehole_data) 358 | self.Y_edit.editingFinished.connect(self.update_borehole_data) 359 | self.Z_edit.editingFinished.connect(self.update_borehole_data) 360 | self.Xmax_edit.editingFinished.connect(self.update_borehole_data) 361 | self.Ymax_edit.editingFinished.connect(self.update_borehole_data) 362 | self.Zmax_edit.editingFinished.connect(self.update_borehole_data) 363 | self.Z_surf_edit.editingFinished.connect(self.update_borehole_data) 364 | self.Z_water_edit.editingFinished.connect(self.update_borehole_data) 365 | 366 | # --- Buttons Actions --- # 367 | btn_Add.clicked.connect(self.add_borehole) 368 | btn_Remove.clicked.connect(self.delete_borehole) 369 | btn_Import.clicked.connect(self.import_borehole) 370 | btn_Plot.clicked.connect(self.plot) 371 | btn_Constraints_atten.clicked.connect(self.attenuation_constraints) 372 | btn_Constraints_veloc.clicked.connect(self.slowness_constraints) 373 | 374 | # --- SubWidgets --- # 375 | # --- Edits and Labels SubWidgets --- # 376 | sub_E_and_L_widget = QtWidgets.QWidget() 377 | sub_E_and_L_grid = QtWidgets.QGridLayout() 378 | sub_E_and_L_grid.addWidget(Coord_label, 0, 0, 1, 2) 379 | sub_E_and_L_grid.addWidget(Collar_label, 0, 2, 1, 2) 380 | sub_E_and_L_grid.addWidget(Bottom_label, 0, 4, 1, 2) 381 | sub_E_and_L_grid.addWidget(X_label, 1, 0, 1, 2) 382 | sub_E_and_L_grid.addWidget(self.X_edit, 1, 2, 1, 2) 383 | sub_E_and_L_grid.addWidget(self.Xmax_edit, 1, 4, 1, 2) 384 | sub_E_and_L_grid.addWidget(Y_label, 2, 0, 1, 2) 385 | sub_E_and_L_grid.addWidget(self.Y_edit, 2, 2, 1, 2) 386 | sub_E_and_L_grid.addWidget(self.Ymax_edit, 2, 4, 1, 2) 387 | sub_E_and_L_grid.addWidget(Elev_label, 3, 0, 1, 2) 388 | sub_E_and_L_grid.addWidget(self.Z_edit, 3, 2, 1, 2) 389 | sub_E_and_L_grid.addWidget(self.Zmax_edit, 3, 4, 1, 2) 390 | sub_E_and_L_grid.addWidget(Elev_surf_label, 4, 1, 1, 2) 391 | sub_E_and_L_grid.addWidget(self.Z_surf_edit, 4, 3, 1, 2) 392 | sub_E_and_L_grid.addWidget(Elev_water_label, 5, 1, 1, 2) 393 | sub_E_and_L_grid.addWidget(self.Z_water_edit, 5, 3, 1, 2) 394 | sub_E_and_L_widget.setLayout(sub_E_and_L_grid) 395 | 396 | # --- Upper Buttons --- # 397 | sub_upper_buttons_widget = QtWidgets.QWidget() 398 | sub_upper_buttons_Grid = QtWidgets.QGridLayout() 399 | sub_upper_buttons_Grid.addWidget(btn_Add, 0, 0) 400 | sub_upper_buttons_Grid.addWidget(btn_Remove, 0, 1) 401 | sub_upper_buttons_Grid.addWidget(btn_Import, 0, 2) 402 | sub_upper_buttons_Grid.addWidget(btn_Plot, 0, 4) 403 | sub_upper_buttons_Grid.setContentsMargins(0, 0, 0, 0) 404 | sub_upper_buttons_widget.setLayout(sub_upper_buttons_Grid) 405 | 406 | # --- Lower Buttons --- # 407 | sub_lower_buttons_widget = QtWidgets.QWidget() 408 | sub_lower_buttons_Grid = QtWidgets.QGridLayout() 409 | sub_lower_buttons_Grid.addWidget(btn_Constraints_veloc, 0, 0) 410 | sub_lower_buttons_Grid.addWidget(btn_Constraints_atten, 0, 1) 411 | sub_lower_buttons_Grid.setContentsMargins(0, 0, 0, 0) 412 | sub_lower_buttons_widget.setLayout(sub_lower_buttons_Grid) 413 | 414 | # ------- Grid Disposition ------- # 415 | master_grid = QtWidgets.QGridLayout() 416 | master_grid.addWidget(sub_upper_buttons_widget, 0, 0) 417 | master_grid.addWidget(self.bh_list, 1, 0) 418 | master_grid.addWidget(sub_E_and_L_widget, 2, 0) 419 | master_grid.addWidget(sub_lower_buttons_widget, 4, 0) 420 | master_grid.setContentsMargins(0, 0, 0, 0) 421 | 422 | # ------- set Layout ------- # 423 | self.setLayout(master_grid) 424 | 425 | 426 | class BoreholeFig(FigureCanvasQTAgg): 427 | 428 | def __init__(self): 429 | """ 430 | Here we create a 3D figure in which we will plot the Borehole instances' trajectory (i.e. their respective fdata) 431 | """ 432 | 433 | fig_width, fig_height = 6, 8 434 | fig = Figure(figsize=(fig_width, fig_height), facecolor='white') 435 | super(BoreholeFig, self).__init__(fig) 436 | self.init_figure() 437 | 438 | def init_figure(self): 439 | ax = self.figure.add_axes([0.05, 0.05, 0.9, 0.9], projection='3d') 440 | ax.set_axisbelow(True) 441 | 442 | def plot_bholes(self, bhole_list): 443 | ax = self.figure.axes[0] 444 | ax.cla() 445 | for bhole in bhole_list: 446 | ax.plot(bhole.fdata[:, 0], bhole.fdata[:, 1], bhole.fdata[:, 2], label=bhole.name) 447 | 448 | l = ax.legend(ncol=1, bbox_to_anchor=(0, 1), loc='upper left', borderpad=0) 449 | l.draw_frame(False) 450 | 451 | self.draw() 452 | 453 | 454 | class Cont(object): 455 | """ 456 | This class represents either the slowness constraints(i.e. bh.scont) or the attenuation constraints(i.e. bh.acont). 457 | We created a class for Cont because it has its own attributes. 458 | """ 459 | 460 | def __init__(self): 461 | self.x = np.array([]) 462 | self.y = np.array([]) 463 | self.z = np.array([]) 464 | self.valeur = np.array([]) 465 | self.variance = np.array([]) 466 | 467 | 468 | if __name__ == '__main__': 469 | app = QtWidgets.QApplication(sys.argv) 470 | 471 | db = BhTomoDb('/tmp/test_db.h5') 472 | db.load() 473 | bh_ui = BoreholeUI(db) 474 | bh_ui.show() 475 | 476 | sys.exit(app.exec_()) 477 | -------------------------------------------------------------------------------- /cutils/csegy.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _CSEGY_H_ 3 | #define _CSEGY_H_ 4 | 5 | #include "string.h" 6 | 7 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 8 | #include "Python.h" 9 | #include "numpy/ndarrayobject.h" 10 | 11 | 12 | 13 | int read_segy_b_header(const char*, PyObject*); 14 | int read_segy_tr_headers(const char*, PyObject*, PyObject*, PyObject*, PyObject*, PyObject*); 15 | PyObject* read_segy_data(const char*, PyObject*); 16 | 17 | #endif -------------------------------------------------------------------------------- /cutils/csegy.pxd: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Aug 5 09:00:30 2016 4 | 5 | @author: giroux 6 | """ 7 | 8 | cdef extern from "csegy.h": 9 | int read_segy_b_header(const char*, object) 10 | int read_segy_tr_headers(const char*, object, object, object, object, object) 11 | object read_segy_data(const char*, object) 12 | 13 | -------------------------------------------------------------------------------- /cutils/segy.cp35-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/cutils/segy.cp35-win_amd64.pyd -------------------------------------------------------------------------------- /cutils/segy.cp36-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/cutils/segy.cp36-win_amd64.pyd -------------------------------------------------------------------------------- /cutils/segy.cpython-34m.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/cutils/segy.cpython-34m.so -------------------------------------------------------------------------------- /cutils/segy.cpython-35m-darwin.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/cutils/segy.cpython-35m-darwin.so -------------------------------------------------------------------------------- /cutils/segy.cpython-35m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/cutils/segy.cpython-35m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /cutils/segy.pyx: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Copyright 2016 Bernard Giroux 5 | email: bernard.giroux@ete.inrs.ca 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU 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 program 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 General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | """ 20 | import numpy as np 21 | cimport numpy as np 22 | 23 | cimport csegy 24 | 25 | #cdef struct c_bin_header: 26 | # int jobid 27 | # int lino 28 | # int reno 29 | # short ntrpr 30 | # short nart 31 | # unsigned short hdt 32 | # unsigned short dto 33 | # unsigned short hns 34 | # unsigned short nso 35 | # short format 36 | # short fold 37 | # short tsort 38 | # short vscode 39 | # short hsfs 40 | # short hsfe 41 | # short hslen 42 | # short hstyp 43 | # short schn 44 | # short hstas 45 | # short hstae 46 | # short htatyp 47 | # short hcorr 48 | # short bgrcv 49 | # short rcvm 50 | # short mfeet 51 | # short polyt 52 | # short vpol 53 | # unsigned short rev 54 | # short fixl 55 | # short extfh 56 | 57 | 58 | class Segy_data(): 59 | """ 60 | Class to hold SEG-Y data 61 | 62 | Attributes are: 63 | bh: Dictionnary containing binary header data (integer) 64 | keys are: 65 | (bytes in file) 66 | jobid 3201-3204 67 | lino 3205-3208 68 | reno 3209-3212 69 | ntrpr 3213-3214 70 | nart 3215-3216 71 | hdt 3217-3218 72 | dto 3219-3220 73 | hns 3221-3222 74 | nso 3223-3224 75 | format 3225-3226 76 | 77 | fold 3227-3228 78 | tsort 3229-3230 79 | vscode 3231-3232 80 | hsfs 3233-3234 81 | hsfe 3235-3236 82 | hslen 3237-3238 83 | hstyp 3239-3240 84 | schn 3241-3242 85 | hstas 3243-3244 86 | hstae 3245-3246 87 | 88 | htatyp 3247-3248 89 | hcorr 3249-3250 90 | bgrcv 3251-3252 91 | rcvm 3253-3254 92 | mfeet 3255-3256 93 | polyt 3257-3258 94 | vpol 3259-3260 95 | 96 | rev 3501-3502 97 | fixl 3503-3504 98 | extfh 3505-3506 99 | 100 | th: Dictionnary containing traces header data (numpy arrays) 101 | keys are (unless custom dictionary given to read_segy) 102 | 103 | (bytes in header) 104 | tracl - 1-4 105 | tracr - 5-8 106 | fldr - 9-12 107 | tracf - 13-16 108 | ep - 17-20 109 | cdp - 21-24 110 | cdpt - 25-28 111 | trid - 29-30 112 | nvs - 31-32 113 | nhs - 33-34 114 | 115 | duse - 35-36 116 | offset - 37-40 117 | gelev - 41-44 118 | selev - 45-48 119 | sdepth - 49-52 120 | gdel - 53-56 121 | sdel - 57-60 122 | swdep - 61-64 123 | gwdep - 65-68 124 | scalel - 69-70 125 | 126 | scalco - 71-72 127 | sx - 73-76 128 | sy - 77-80 129 | gx - 81-84 130 | gy - 85-88 131 | counit - 89-90 132 | wevel - 91-92 133 | swevel - 93-94 134 | sut - 95-96 135 | gut - 97-98 136 | 137 | sstat - 99-100 138 | gstat - 101-102 139 | tstat - 103-104 140 | laga - 105-106 141 | lagb - 107-108 142 | delrt - 109-110 143 | muts - 111-112 144 | mute - 113-114 145 | ns - 115-116 146 | dt - 117-118 147 | 148 | gain - 119-120 149 | igc - 121-122 150 | igi - 123-124 151 | corr - 125-126 152 | sfs - 127-128 153 | sfe - 129-130 154 | slen - 131-132 155 | styp - 133-134 156 | stas - 135-136 157 | stae - 137-138 158 | 159 | tatyp - 139-140 160 | afilf - 141-142 161 | afils - 143-144 162 | nofilf - 145-146 163 | nofils - 147-148 164 | lcf - 149-150 165 | hcf - 151-152 166 | lcs - 153-154 167 | hcs - 155-156 168 | year - 157-158 169 | 170 | day - 159-160 171 | hour - 161-162 172 | minute - 163-164 173 | sec - 165-166 174 | timbas - 167-168 175 | trwf - 169-170 176 | grnors - 171-172 177 | grnofr - 173-174 178 | grnlof - 175-176 179 | gaps - 177-178 180 | 181 | otrav - 179-180 182 | xcdp - 181-184 183 | ycdp - 185-188 184 | ilineno - 189-192 185 | clineno - 193-196 186 | shotno - 197-200 187 | scalsn - 201-202 188 | tvmunit - 203-204 189 | tdcst - 205-210 190 | tdunit - 211-212 191 | 192 | trid - 213-214 193 | scalt - 215-216 194 | styp - 217-218 195 | sdir - 219-224 196 | smeas - 225-230 197 | smunit - 231-232 198 | unass - 233-240 199 | 200 | data: the actual traces (numpy array of size nsamples x ntraces) 201 | 202 | """ 203 | bh=0 # binary header 204 | th=0 # trace headers 205 | data=0 # traces 206 | 207 | def read_segy(segyfile, traceNo=None, fields=None, thDict=None, wordLength=None): 208 | """ 209 | READ_SEGY - read the content of a SEG-Y file 210 | s = read_segy(segyfile, traces, fields, dict, word_length) 211 | 212 | Input: 213 | segyfile (mandatory) : name of SEG-Y file 214 | traces (optional) : list of desired traces within the file 215 | fields (optional) : list of indices or names of trace header word to retrieve 216 | dict (optional) : custom dictionary for trace header (list of strings) 217 | word_length (optional) : word length in bytes for trace header (list of int) 218 | (mandatory if dict given) 219 | - sum(word_length) must be less than 241 220 | - numel(word_length) must equal numel(dict) 221 | - 4-byte IBM float words are handled by setting word_length=5 222 | 223 | Output: 224 | s : instance of a class with the following attributes 225 | - the binary header data (s.bh) 226 | - the trace header data (s.th) 227 | - the trace data (s.data) 228 | 229 | Caveat: 230 | Text headers are not read 231 | Traces of variable length are not handled (results unpredictable) 232 | 233 | """ 234 | s = Segy_data() 235 | s.bh = dict() 236 | s.th = dict() 237 | 238 | cdef bytes py_bytes = segyfile.encode() 239 | cdef char* filename = py_bytes 240 | 241 | cdef int retval = 0 242 | 243 | retval = csegy.read_segy_b_header(filename, s.bh) 244 | 245 | if retval == 1: 246 | raise IOError('Problem opening segy file') 247 | elif retval == 2: 248 | raise RuntimeError('Problem parsing binary header') 249 | 250 | if traceNo is None: 251 | traceNo = list() 252 | else: 253 | traceNo = list(traceNo) 254 | 255 | if fields is not None: 256 | fields = list(fields) # make sure we have list instances 257 | if thDict is None: 258 | thDict = list() 259 | else: 260 | thDict = list(thDict) 261 | if wordLength is None: 262 | wordLength = list() 263 | else: 264 | wordLength = list(wordLength) 265 | retval = csegy.read_segy_tr_headers(filename, traceNo, fields, thDict, wordLength, s.th) 266 | 267 | if retval == 1: 268 | raise IOError('Problem opening segy file') 269 | elif retval == 2: 270 | raise RuntimeError('Problem parsing trace headers') 271 | 272 | s.data = csegy.read_segy_data(filename, traceNo) 273 | if type(s.data) is int: 274 | retval = s.data 275 | else: 276 | retval = 0 277 | 278 | if retval == 1: 279 | raise IOError('Problem opening segy file') 280 | elif retval == 2: 281 | raise RuntimeError('Problem parsing trace data') 282 | 283 | return s 284 | -------------------------------------------------------------------------------- /database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/database.db -------------------------------------------------------------------------------- /database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | import os 22 | import re 23 | import shutil 24 | 25 | import h5py 26 | import numpy as np 27 | from ttcrpy import rgrid 28 | 29 | from borehole import Borehole 30 | from grid import Grid2D 31 | from model import Model 32 | from mog import MogData, Mog, AirShots 33 | 34 | 35 | class DbList(list): 36 | def __init__(self, *args): 37 | list.__init__(self, *args) 38 | self.modified = False 39 | 40 | def append(self, item): 41 | for obj in self: 42 | if obj.name == item.name: 43 | raise ValueError('Two items cannot share the same name in a DbList') 44 | super(DbList, self).append(item) 45 | self.modified = True 46 | 47 | def remove(self, item): 48 | super(DbList, self).remove(item) 49 | self.modified = True 50 | 51 | 52 | class BhTomoDb(): 53 | def __init__(self, fname=''): 54 | self.filename = fname 55 | self.air_shots = DbList() 56 | self.boreholes = DbList() 57 | self.mogs = DbList() 58 | self.models = DbList() 59 | 60 | # prepare for special cases 61 | # Mog.av 62 | # Mog.ap 63 | # Mog.Tx 64 | # Mog.Rx 65 | # Model.mogs 66 | self.p = re.compile('/mogs/.*/(av|ap|Tx|Rx)$') 67 | self.p2 = re.compile('/mogs/.*/(av|ap|Tx|Rx)') 68 | self.p3 = re.compile('/models/.*/_list_mogs') 69 | 70 | @property 71 | def filename(self): 72 | return self._filename 73 | 74 | @filename.setter 75 | def filename(self, fname): 76 | # TODO: check if db is modified before making the change 77 | if fname != '': 78 | try: 79 | self.f = h5py.File(fname, 'a') 80 | # we must reset modified to True otherwise nothing will be saved in new file 81 | for obj in self.boreholes + self.air_shots + self.mogs + self.models: 82 | obj.modified = True 83 | except Exception as e: 84 | raise e 85 | self._filename = fname 86 | 87 | @property 88 | def name(self): 89 | return os.path.basename(self._filename) 90 | 91 | @property 92 | def modified(self): 93 | modified = self.air_shots.modified or self.boreholes.modified or self.mogs.modified\ 94 | or self.models.modified 95 | for obj in self.boreholes + self.air_shots + self.mogs + self.models: 96 | modified = modified or obj.modified 97 | return modified 98 | 99 | def save(self, fname=None, obj=None): 100 | if fname is not None: 101 | self.filename = fname 102 | 103 | # if empty file, create 4 main groups 104 | self.f.require_group('/boreholes') 105 | self.f.require_group('/mogs') 106 | self.f.require_group('/models') 107 | self.f.require_group('/air_shots') 108 | 109 | if obj is not None: 110 | # obj should be an instance of either a Borehole, Mog, Model or AirShot 111 | if type(obj) is Borehole: 112 | group = self.f.require_group('/boreholes/'+obj.name) 113 | elif type(obj) is Mog: 114 | group = self.f.require_group('/mogs/'+obj.name) 115 | elif type(obj) is Model: 116 | group = self.f.require_group('/models/'+obj.name) 117 | elif type(obj) is AirShots: 118 | group = self.f.require_group('/air_shots/'+obj.name) 119 | else: 120 | raise TypeError 121 | 122 | self._save_object(obj, group) 123 | self.f.flush() 124 | 125 | else: 126 | # save everything 127 | g = self.f.require_group('/boreholes') 128 | self._save_list(self.boreholes, g) 129 | if self.boreholes.modified: 130 | self._cleanup_list(self.boreholes, g) 131 | 132 | g = self.f.require_group('/air_shots') 133 | self._save_list(self.air_shots, g) 134 | if self.air_shots.modified: 135 | self._cleanup_list(self.air_shots, g) 136 | 137 | g = self.f.require_group('/mogs') 138 | self._save_list(self.mogs, g) 139 | if self.mogs.modified: 140 | self._cleanup_list(self.mogs, g) 141 | 142 | g = self.f.require_group('/models') 143 | self._save_list(self.models, g) 144 | if self.models.modified: 145 | self._cleanup_list(self.models, g) 146 | 147 | self.f.flush() 148 | self.boreholes.modified = False 149 | self.mogs.modified = False 150 | self.models.modified = False 151 | self.air_shots.modified = False 152 | 153 | def save_mog(self, mog): 154 | # TODO: make sure all boreholes and air_shots held in Tx, Rx, av & ap are in db 155 | group = self.f.require_group('/mogs/'+mog.name) 156 | self._save_object(mog, group) 157 | self.f.flush() 158 | 159 | def save_model(self, model): 160 | # TODO: make sure all mogs held in model.mogs are in db 161 | group = self.f.require_group('/models/'+model.name) 162 | self._save_object(model, group) 163 | self.f.flush() 164 | 165 | def load(self, fname=None): 166 | if fname is not None: 167 | self.filename = fname 168 | 169 | # make sure we load boreholes & air_shots before mogs, and mogs before models 170 | self.load_boreholes() 171 | self.load_air_shots() 172 | self.load_mogs() 173 | self.load_models() 174 | 175 | def get_boreholes(self): 176 | boreholes = DbList() 177 | gr = self.f['/boreholes'] 178 | for k in gr.keys(): 179 | b = Borehole(gr[k].attrs['name']) 180 | for kk in gr[k].attrs.keys(): 181 | b.__dict__[kk] = gr[k].attrs[kk] 182 | for kk in gr[k].keys(): 183 | b.__dict__[kk] = np.asarray(gr[k][kk]) 184 | boreholes.append(b) 185 | return boreholes 186 | 187 | def load_boreholes(self): 188 | self.boreholes = self.get_boreholes() 189 | 190 | def get_mogs(self): 191 | mogs = DbList() 192 | gr = self.f['/mogs'] 193 | for k in gr.keys(): 194 | m = self._load_mog(gr[k]) 195 | mogs.append(m) 196 | return mogs 197 | 198 | def load_mogs(self): 199 | self.mogs = self.get_mogs() 200 | 201 | def get_mog(self, name): 202 | group = self.f['/mogs/'+name] 203 | return self._load_mog(group) 204 | 205 | def get_models(self): 206 | models = DbList() 207 | gr = self.f['/models'] 208 | for k in gr.keys(): 209 | m = self._load_model(gr[k]) 210 | models.append(m) 211 | return models 212 | 213 | def load_models(self): 214 | self.models = self.get_models() 215 | 216 | def get_model(self, name): 217 | group = self.f['/models/'+name] 218 | return self._load_model(group) 219 | 220 | def get_air_shots(self): 221 | air_shots = DbList() 222 | gr = self.f['/air_shots'] 223 | for k in gr.keys(): 224 | m = AirShots() 225 | for kk in gr[k].attrs.keys(): 226 | m.__dict__[kk] = gr[k].attrs[kk] 227 | for kk in gr[k].keys(): 228 | if type(gr[k][kk]) is h5py._hl.dataset.Dataset: # @UndefinedVariable 229 | if gr[k][kk].dtype is np.dtype('int8'): 230 | m.__dict__[kk] = np.asarray(gr[k][kk]).astype(bool) 231 | else: 232 | m.__dict__[kk] = np.asarray(gr[k][kk]) 233 | elif type(gr[k][kk]) is h5py._hl.group.Group: # @UndefinedVariable 234 | # we have either a list or a custom class 235 | gr2 = gr[k][kk] 236 | # if '_list_' in gr2.name: 237 | # m.__dict__[kk] = self._load_list(gr2) 238 | # else: 239 | # m.__dict__[kk] = self._load_object(gr2) 240 | m.__dict__[kk] = self._load_object(gr2) 241 | air_shots.append(m) 242 | return air_shots 243 | 244 | def load_air_shots(self): 245 | self.air_shots = self.get_air_shots() 246 | 247 | def get_mog_names(self): 248 | gr = self.f['/mogs'] 249 | return [gr[k].attrs['name'] for k in gr.keys()] 250 | 251 | def get_model_names(self): 252 | gr = self.f['/models'] 253 | return [gr[k].attrs['name'] for k in gr.keys()] 254 | 255 | def _save_object(self, obj, group): 256 | 257 | # check if special case 258 | if self.p.match(group.name) or self.p3.match(group.name): 259 | # store name 260 | group.attrs['name'] = obj.name 261 | return 262 | elif self.p2.match(group.name): 263 | # skip 264 | return 265 | 266 | if 'modified' in obj.__dict__.keys(): 267 | if not obj.modified: 268 | # no need to save 269 | return 270 | else: 271 | # reset to False before saving 272 | obj.modified = False 273 | 274 | # loop over attributes 275 | for k in obj.__dict__.keys(): 276 | # print(k, type(obj.__dict__[k]), obj.__dict__[k]) 277 | if obj.__dict__[k] is None: 278 | continue 279 | if type(obj.__dict__[k]) is rgrid.Grid2d: 280 | continue 281 | elif type(obj.__dict__[k]) is str: 282 | group.attrs[k] = obj.__dict__[k] 283 | elif type(obj.__dict__[k]) is bool or type(obj.__dict__[k]) is np.bool_: 284 | group.attrs[k] = obj.__dict__[k] 285 | elif type(obj.__dict__[k]) is float: 286 | group.attrs[k] = obj.__dict__[k] 287 | elif type(obj.__dict__[k]) is int: 288 | group.attrs[k] = obj.__dict__[k] 289 | elif type(obj.__dict__[k]) is np.float64: 290 | group.attrs[k] = obj.__dict__[k] 291 | elif type(obj.__dict__[k]) is np.int8: 292 | group.attrs[k] = obj.__dict__[k] 293 | elif type(obj.__dict__[k]) is np.int64: 294 | group.attrs[k] = obj.__dict__[k] 295 | elif type(obj.__dict__[k]) is np.ndarray: 296 | try: 297 | if group[k].shape != obj.__dict__[k].shape: 298 | # we have to delete previous dataset because new one is not same size 299 | del(group[k]) 300 | #group[k] = obj.__dict__[k] 301 | if obj.__dict__[k].dtype is np.dtype('bool'): 302 | # for some reason, bools are not stored in file, so we cast to int8 instead 303 | group.create_dataset(k, data=obj.__dict__[k].astype(np.int8), compression='gzip') 304 | else: 305 | group.create_dataset(k, data=obj.__dict__[k], compression='gzip') 306 | else: 307 | if obj.__dict__[k].dtype is np.dtype('bool'): 308 | group[k][...] = obj.__dict__[k].astype(np.int8) 309 | else: 310 | group[k][...] = obj.__dict__[k] 311 | except: 312 | #group[k] = obj.__dict__[k] 313 | if obj.__dict__[k].dtype is np.dtype('bool'): 314 | group.create_dataset(k, data=obj.__dict__[k].astype(np.int8), compression='gzip') 315 | else: 316 | group.create_dataset(k, data=obj.__dict__[k], compression='gzip') 317 | elif type(obj.__dict__[k]) is list: 318 | g = group.require_group('_list_'+k) 319 | self._save_list(obj.__dict__[k], g) 320 | else: 321 | # must be one of BhTomoPy class 322 | g = group.require_group(k) 323 | g.attrs['BhTomoPyClassName'] = obj.__dict__[k].__class__.__name__ 324 | self._save_object(obj.__dict__[k], g) 325 | 326 | def _save_list(self, lst, group): 327 | for n in range(len(lst)): 328 | # group name in index in list 329 | g = group.require_group(lst[n].name) 330 | self._save_object(lst[n], g) 331 | 332 | def _cleanup_list(self, lst, group): 333 | names = [obj.name for obj in lst] 334 | for k in group.keys(): 335 | if k not in names: 336 | del(group[k]) # TODO: limitation in h5py/hdf5 -> group is removed, but space is not reclaimed from file 337 | 338 | def _load_object(self, group, caller=None): 339 | 340 | if caller is not None: 341 | # check if special case 342 | if self.p.match(group.name): 343 | name = group.attrs['name'] 344 | p = re.compile('/mogs/.*/([apvTRx]*)') 345 | tmp = p.match(group.name) 346 | if tmp: 347 | # air_shots 348 | att_name = group.name[tmp.regs[1][0]:tmp.regs[1][1]] 349 | if att_name == 'av' or att_name == 'ap': 350 | for obj in self.air_shots: 351 | if obj.name == name: 352 | break 353 | else: 354 | # air_shots not loaded 355 | air_shots = self.get_air_shots() 356 | for obj in air_shots: 357 | if obj.name == name: 358 | break 359 | 360 | elif att_name == 'Tx' or att_name == 'Rx': 361 | for obj in self.boreholes: 362 | if obj.name == name: 363 | break 364 | else: 365 | boreholes = self.get_boreholes() 366 | for obj in boreholes: 367 | if obj.name == name: 368 | break 369 | return obj 370 | else: 371 | raise ValueError('Problem reading Mog attribute') 372 | return 373 | elif self.p3.match(group.name): 374 | name = group.attrs['name'] 375 | for mog in self.mogs: 376 | if mog.name == name: 377 | break 378 | else: 379 | mogs = self.get_mogs() 380 | for mog in mogs: 381 | if mog.name == name: 382 | break 383 | caller.mogs.append(mog) 384 | return 385 | 386 | klass = globals()[group.attrs['BhTomoPyClassName']] 387 | obj = klass() 388 | for k in group.attrs.keys(): 389 | obj.__dict__[k] = group.attrs[k] 390 | for k in group.keys(): 391 | if type(group[k]) is h5py._hl.dataset.Dataset: # @UndefinedVariable 392 | if group[k].dtype is np.dtype('int8'): 393 | obj.__dict__[k] = np.asarray(group[k]).astype(bool) 394 | else: 395 | obj.__dict__[k] = np.asarray(group[k]) 396 | elif type(group[k]) is h5py._hl.group.Group: # @UndefinedVariable 397 | # if '_list_' in group[k].name: 398 | # obj.__dict__[k] = self._load_list(group[k]) 399 | # else: 400 | # obj.__dict__[k] = self._load_object(group[k]) 401 | obj.__dict__[k] = self._load_object(group[k]) 402 | return obj 403 | 404 | def _load_list(self, group, caller=None): 405 | lst = [] 406 | for k in group.keys(): 407 | lst.append(self._load_object(group[k], caller)) 408 | return lst 409 | 410 | def _load_mog(self, group): 411 | m = Mog() 412 | for kk in group.attrs.keys(): 413 | m.__dict__[kk] = group.attrs[kk] 414 | for kk in group.keys(): 415 | if type(group[kk]) is h5py._hl.dataset.Dataset: # @UndefinedVariable 416 | if group[kk].dtype is np.dtype('int8'): 417 | m.__dict__[kk] = np.asarray(group[kk]).astype(bool) 418 | else: 419 | m.__dict__[kk] = np.asarray(group[kk]) 420 | elif type(group[kk]) is h5py._hl.group.Group: # @UndefinedVariable 421 | gr2 = group[kk] 422 | # if '_list_' in gr2.name: 423 | # m.__dict__[kk] = self._load_list(gr2) 424 | # else: 425 | # m.__dict__[kk] = self._load_object(gr2, m) 426 | m.__dict__[kk] = self._load_object(gr2, m) 427 | return m 428 | 429 | def _load_model(self, group): 430 | m = Model() 431 | for kk in group.attrs.keys(): 432 | m.__dict__[kk] = group.attrs[kk] 433 | for kk in group.keys(): 434 | if type(group[kk]) is h5py._hl.dataset.Dataset: # @UndefinedVariable 435 | if group[kk].dtype is np.dtype('int8'): 436 | m.__dict__[kk] = np.asarray(group[kk]).astype(bool) 437 | else: 438 | m.__dict__[kk] = np.asarray(group[kk]) 439 | elif type(group[kk]) is h5py._hl.group.Group: # @UndefinedVariable 440 | # we have either a list or a custom class 441 | gr2 = group[kk] 442 | if '_list_' in gr2.name: 443 | self._load_list(gr2, m) 444 | else: 445 | m.__dict__[kk] = self._load_object(gr2) 446 | return m 447 | 448 | 449 | if __name__ == '__main__': 450 | 451 | if os.path.isfile('/tmp/test_db.h5'): 452 | os.remove('/tmp/test_db.h5') 453 | db = BhTomoDb() 454 | db.filename = '/tmp/test_db.h5' 455 | db.boreholes.append(Borehole('BH1')) 456 | db.boreholes.append(Borehole('BH2')) 457 | bh3 = Borehole('BH3') 458 | db.boreholes.append(bh3) 459 | 460 | md = MogData() 461 | md.readRAMAC('testData/formats/ramac/t0302') 462 | db.mogs.append(Mog('mog1', md)) 463 | db.mogs.append(Mog('mog2', md)) 464 | 465 | db.models.append(Model('model1')) 466 | db.air_shots.append(AirShots('air1')) 467 | db.air_shots[0].data.readRAMAC('testData/air_shots/av0302') 468 | db.air_shots.append(AirShots('air2')) 469 | db.air_shots[1].data.readRAMAC('testData/air_shots/ap0302') 470 | 471 | db.mogs[0].Tx = db.boreholes[0] 472 | db.mogs[0].Rx = db.boreholes[1] 473 | db.mogs[0].av = db.air_shots[0] 474 | db.mogs[0].ap = db.air_shots[1] 475 | db.mogs[1].av = db.air_shots[0] 476 | db.mogs[1].ap = db.air_shots[1] 477 | 478 | db.models[0].mogs.append(db.mogs[0]) 479 | db.models[0].mogs.append(db.mogs[1]) 480 | 481 | g = Grid2D(np.arange(10), np.arange(20)) 482 | db.models[0].grid = g 483 | 484 | g.raytrace(np.ones((g.getNumberOfCells(),)), np.array([[0.5, 0.0, 0.5]]), np.array([[8.5, 0.0, 15.5]])) 485 | 486 | print(db.modified) 487 | 488 | db.save() 489 | db.f.close() 490 | shutil.copyfile('/tmp/test_db.h5', '/tmp/test_db2.h5') 491 | 492 | db.filename = '/tmp/test_db.h5' 493 | db.boreholes.remove(bh3) 494 | 495 | print(db.modified) 496 | db.save() 497 | print(db.modified) 498 | 499 | db.filename = '/tmp/test_db3.h5' 500 | db.save() 501 | 502 | del(db) 503 | print('Done') 504 | 505 | db2 = BhTomoDb() 506 | db2.filename = '/tmp/test_db.h5' 507 | # db2.load() 508 | names = db2.get_model_names() 509 | print(names) 510 | mod = db2.get_model(names[0]) 511 | print(mod.mogs[0].data.ntrace) 512 | print(db2.get_mog_names()) 513 | mod.modified = True 514 | db2.save_model(mod) 515 | 516 | mog = db2.get_mog(mod.mogs[0].name) 517 | mog.modified = True 518 | db2.save_mog(mog) 519 | 520 | db2.load() 521 | for bh in db2.boreholes: 522 | print(bh.name) 523 | 524 | for m in db2.models: 525 | print(m.name) 526 | 527 | for m in db2.mogs: 528 | print(m.name) 529 | -------------------------------------------------------------------------------- /database_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import time 23 | import os 24 | import sys 25 | 26 | from PyQt5 import QtGui, QtWidgets, QtCore 27 | from borehole_ui import BoreholeUI 28 | from database import BhTomoDb 29 | from model_ui import ModelUI 30 | from mog_ui import MOGUI, MergeMog 31 | from utils_ui import MyQLabel, auto_create_scrollbar, save_warning 32 | 33 | 34 | class DatabaseUI(QtWidgets.QWidget): 35 | def __init__(self, parent=None): 36 | super(DatabaseUI, self).__init__(parent) 37 | self.setWindowTitle("BhTomoPy/Database") 38 | # --- Other Modules Instances --- # 39 | self.db = BhTomoDb() 40 | self.bh = BoreholeUI(self.db) 41 | self.mog = MOGUI(self.db) 42 | self.model = ModelUI(self.db) 43 | self.info = InfoUI() 44 | self.mergemog = MergeMog(self.mog) 45 | self.init_UI() 46 | self.action_list = [] 47 | 48 | # DatabaseUI receives the signals, which were emitted by different modules, and transmits the signal to the other 49 | # modules in order to update them 50 | 51 | self.bh.bhUpdateSignal.connect(self.update_MogUI) 52 | self.bh.bhInfoSignal.connect(self.update_borehole_info) 53 | self.mog.mogInfoSignal.connect(self.update_mog_info) 54 | self.mog.ntraceSignal.connect(self.update_trace_info) 55 | self.model.modelInfoSignal.connect(self.update_model_info) 56 | self.mergemog.mergemoglogSignal.connect(self.update_log) 57 | self.bh.bhlogSignal.connect(self.update_log) 58 | self.mog.moglogSignal.connect(self.update_log) 59 | self.model.modellogSignal.connect(self.update_log) 60 | 61 | def update_spectra(self, Tx_list): 62 | self.mog.update_spectra_Tx_num_combo(Tx_list) 63 | self.mog.update_spectra_Tx_elev_value_label(Tx_list) 64 | 65 | def update_MogUI(self, list_bh): 66 | self.mog.update_Tx_and_Rx_Widget(list_bh) 67 | 68 | def update_database_info(self, name): 69 | self.info.update_database(name) 70 | 71 | def update_borehole_info(self, num): 72 | self.info.update_borehole(num) 73 | 74 | def update_mog_info(self, num): 75 | self.info.update_mog(num) 76 | 77 | def update_model_info(self, num): 78 | self.info.update_model(num) 79 | 80 | def update_trace_info(self, num): 81 | self.info.update_trace(num) 82 | 83 | def update_log(self, action): 84 | # Clears the log to make sure any action is not written more than once 85 | self.log.clear() 86 | 87 | # Appends the time and the action that was done 88 | self.action_list.append("[{}] {} ".format(time.asctime()[11:16], action)) 89 | 90 | # Shows the Error messages in red and the others in black 91 | for item in self.action_list: 92 | 93 | if "Error:" in item: 94 | self.log.setTextColor(QtGui.QColor(QtCore.Qt.red)) 95 | self.log.append(item) 96 | 97 | else: 98 | self.log.setTextColor(QtGui.QColor(QtCore.Qt.black)) 99 | self.log.append(item) 100 | 101 | def update_widgets(self): 102 | 103 | self.bh.update_list_widget() 104 | self.bh.bh_list.setCurrentRow(0) 105 | self.bh.update_list_edits() 106 | 107 | self.mog.update_list_widget() 108 | self.mog.update_edits() 109 | self.mog.MOG_list.setCurrentRow(0) 110 | self.mog.update_spectra_and_coverage_Tx_num_list() 111 | self.mog.update_spectra_and_coverage_Tx_elev_value_label() 112 | self.mog.update_edits() 113 | self.mog.update_prune_edits_info() 114 | self.mog.update_prune_info() 115 | 116 | self.model.update_model_list() 117 | self.model.update_model_mog_list() 118 | 119 | self.update_database_info(self.db.name) 120 | 121 | def show(self, dbname): 122 | super(DatabaseUI, self).show() 123 | if dbname != '': 124 | try: 125 | self.db.load(dbname) 126 | except Exception as e: 127 | QtWidgets.QMessageBox.warning(self, 'Error', str(e)) 128 | 129 | # Gets initial geometry of the widget: 130 | qr = self.frameGeometry() 131 | 132 | # Shows it at the center of the screen 133 | cp = QtWidgets.QDesktopWidget().availableGeometry().center() 134 | 135 | # Moves the window's center at the center of the screen 136 | qr.moveCenter(cp) 137 | 138 | # Then moves it at the top left 139 | translation = qr.topLeft() 140 | 141 | self.move(translation) 142 | 143 | self.update_widgets() 144 | 145 | def openfile(self): # TODO: On Windows, access to folders containing special characters fails. May be due to the fact that Windows doesn't use Unicode. 146 | 147 | if save_warning(self.db): 148 | filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open Database','','Database (*.h5)')[0] 149 | 150 | if filename: 151 | self.db.load(filename) 152 | self.update_database_info(os.path.basename(filename)) 153 | self.update_widgets() 154 | self.update_log("Database '{}' was loaded successfully".format(os.path.basename(filename))) 155 | 156 | def savefile(self): 157 | 158 | try: 159 | if self.db.filename == '': 160 | self.saveasfile() 161 | return 162 | 163 | self.db.save() 164 | 165 | self.update_log("Database was saved successfully") 166 | QtWidgets.QMessageBox.information(self, 'Success', "Database was saved successfully", 167 | buttons=QtWidgets.QMessageBox.Ok) 168 | 169 | except Exception as e: 170 | QtWidgets.QMessageBox.warning(self, 'Warning', "Database could not be saved : " + str(e), 171 | buttons=QtWidgets.QMessageBox.Ok) 172 | 173 | def saveasfile(self): 174 | filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Save Database as ...', 175 | filter='Database (*.h5)', )[0] 176 | 177 | if filename: 178 | self.db.save(filename) 179 | 180 | self.update_database_info(os.path.basename(filename)) 181 | self.update_log("Database '{}' was saved successfully".format(os.path.basename(filename))) 182 | 183 | 184 | def init_UI(self): 185 | 186 | # --- Log Widget --- # 187 | self.log = QtWidgets.QTextEdit() 188 | self.log.setReadOnly(True) 189 | self.log.setLineWrapMode(0) 190 | 191 | # --- Actions --- # 192 | openAction = QtWidgets.QAction('Open', self) 193 | openAction.setShortcut('Ctrl+O') 194 | openAction.triggered.connect(self.openfile) 195 | 196 | saveAction = QtWidgets.QAction('Save', self) 197 | saveAction.setShortcut('Ctrl+S') 198 | saveAction.triggered.connect(self.savefile) 199 | 200 | saveasAction = QtWidgets.QAction('Save as', self) 201 | saveasAction.setShortcut('Ctrl+A') 202 | saveasAction.triggered.connect(self.saveasfile) 203 | 204 | exportBHAction = QtWidgets.QAction('Export boreholes', self) 205 | exportBHAction.setShortcut('Ctrl+B') 206 | exportBHAction.triggered.connect(self.bh.export_boreholes) 207 | 208 | # --- Menubar --- # 209 | self.menu = QtWidgets.QMenuBar() 210 | filemenu = self.menu.addMenu('&File') 211 | filemenu.addAction(openAction) 212 | filemenu.addAction(saveAction) 213 | filemenu.addAction(saveasAction) 214 | filemenu.addAction(exportBHAction) 215 | 216 | # --- GroupBoxes --- # 217 | # - Boreholes GroupBox - # 218 | bh_GroupBox = QtWidgets.QGroupBox("Boreholes") 219 | bh_Sub_Grid = QtWidgets.QGridLayout() 220 | bh_Sub_Grid.addWidget(self.bh) 221 | bh_GroupBox.setLayout(bh_Sub_Grid) 222 | 223 | # - MOGs GroupBox - # 224 | MOGs_GroupBox = QtWidgets.QGroupBox("MOGs") 225 | MOGs_Sub_Grid = QtWidgets.QGridLayout() 226 | MOGs_Sub_Grid.addWidget(self.mog) 227 | MOGs_GroupBox.setLayout(MOGs_Sub_Grid) 228 | 229 | # - Models GroupBox - # 230 | Models_GroupBox = QtWidgets.QGroupBox("Models") 231 | Models_Sub_Grid = QtWidgets.QGridLayout() 232 | Models_Sub_Grid.addWidget(self.model) 233 | Models_GroupBox.setLayout(Models_Sub_Grid) 234 | 235 | # - Info GroupBox - # 236 | Info_GroupBox = QtWidgets.QGroupBox("Infos") 237 | Info_Sub_Grid = QtWidgets.QGridLayout() 238 | Info_Sub_Grid.addWidget(self.info) 239 | Info_GroupBox.setLayout(Info_Sub_Grid) 240 | 241 | # - Big SubWidget - # 242 | sub_big_widget = QtWidgets.QWidget() 243 | sub_big_grid = QtWidgets.QGridLayout() 244 | sub_big_grid.addWidget(bh_GroupBox, 0, 0, 1, 1) 245 | sub_big_grid.addWidget(MOGs_GroupBox, 0, 1, 1, 3) 246 | sub_big_grid.addWidget(Models_GroupBox, 1, 0, 2, 2) 247 | sub_big_grid.addWidget(Info_GroupBox, 1, 2, 2, 3) 248 | sub_big_grid.setColumnStretch(0, 1) 249 | sub_big_grid.setColumnStretch(1, 1) 250 | sub_big_grid.setColumnStretch(2, 1) 251 | sub_big_widget.setLayout(sub_big_grid) 252 | 253 | # - Scroll bar - # 254 | 255 | scrollbar = auto_create_scrollbar(sub_big_widget) 256 | 257 | # --- Grid --- # 258 | master_grid = QtWidgets.QGridLayout() 259 | master_grid.addWidget(self.menu, 0, 0, 1, 3) 260 | master_grid.addWidget(scrollbar, 1, 0, 1, 3) 261 | master_grid.addWidget(self.log, 2, 0, 2, 3) 262 | master_grid.setContentsMargins(0, 0, 0, 0) 263 | master_grid.setVerticalSpacing(5) 264 | 265 | self.setLayout(master_grid) 266 | 267 | 268 | class InfoUI(QtWidgets.QFrame): 269 | def __init__(self, parent=None): 270 | super(InfoUI, self).__init__() 271 | self.setWindowTitle("BhTomoPy/Info") 272 | self.init_UI() 273 | 274 | # ------- Updating the information ------- # 275 | def update_database(self, name): 276 | self.live_database_label.setText(name) 277 | 278 | def update_borehole(self, value): 279 | self.num_boreholes_label.setText(str(value)) 280 | 281 | def update_mog(self, value): 282 | self.num_mogs_label.setText(str(value)) 283 | 284 | def update_model(self, value): 285 | self.num_models_label.setText(str(value)) 286 | 287 | def update_trace(self, value): 288 | self.num_traces_label.setText(str(value)) 289 | 290 | def init_UI(self): 291 | 292 | # --- Widget --- # 293 | self.database_label = QtWidgets.QLabel("Database : ") 294 | self.live_database_label = MyQLabel('', ha='left') 295 | self.boreholes_label = QtWidgets.QLabel(" Borehole(s)") 296 | self.num_boreholes_label = MyQLabel('0', ha='right') 297 | self.mogs_label = QtWidgets.QLabel(" MOG(s)") 298 | self.num_mogs_label = MyQLabel('0', ha='right') 299 | self.models_label = QtWidgets.QLabel(" Model(s)") 300 | self.num_models_label = MyQLabel('0', ha='right') 301 | self.traces_label = QtWidgets.QLabel(" Traces") 302 | self.num_traces_label = MyQLabel('0', ha='right') 303 | 304 | # --- Grid --- # 305 | master_grid = QtWidgets.QGridLayout() 306 | master_grid.addWidget(self.database_label, 0, 0) 307 | master_grid.addWidget(self.live_database_label, 0, 1) 308 | master_grid.addWidget(self.num_boreholes_label, 2, 0) 309 | master_grid.addWidget(self.boreholes_label, 2, 1) 310 | master_grid.addWidget(self.num_mogs_label, 3, 0) 311 | master_grid.addWidget(self.mogs_label, 3, 1) 312 | master_grid.addWidget(self.num_models_label, 4, 0) 313 | master_grid.addWidget(self.models_label, 4, 1) 314 | master_grid.addWidget(self.num_traces_label, 6, 0) 315 | master_grid.addWidget(self.traces_label, 6, 1) 316 | master_grid.setAlignment(QtCore.Qt.AlignCenter) 317 | self.setLayout(master_grid) 318 | 319 | 320 | class MyLogWidget(QtWidgets.QTextEdit): 321 | def __init__(self, parent=None): 322 | super(MyLogWidget, self).__init__(parent) 323 | 324 | def append(self, txt): 325 | super(MyLogWidget, self).append(txt) 326 | 327 | bottom = self.verticalScrollBar().maximum() 328 | self.verticalScrollBar().setValue(bottom) 329 | 330 | 331 | if __name__ == '__main__': 332 | 333 | app = QtWidgets.QApplication(sys.argv) 334 | 335 | Database_ui = DatabaseUI() 336 | Database_ui.show('/Users/giroux/Desktop/sussargues2D.h5') 337 | 338 | # Database_ui.update_log("Welcome to BH TOMO Python Edition's Database") 339 | # Database_ui.bh.load_borehole('testData/testConstraints/F3.xyz') 340 | # Database_ui.bh.load_borehole('testData/testConstraints/F2.xyz') 341 | # Database_ui.mog.load_file_MOG('testData/formats/ramac/t0302.rad') 342 | # Database_ui.mog.load_file_MOG('testData/formats/ramac/t0102.rad') 343 | # Database_ui.model.load_model("t0302's model") 344 | # Database_ui.model.load_model("test") 345 | # Database_ui.model.load_model("test2") 346 | # Database_ui.mog.plot_spectra() 347 | # Database_ui.mog.plot_zop() 348 | 349 | # Database_ui.saveasfile() 350 | 351 | sys.exit(app.exec_()) 352 | -------------------------------------------------------------------------------- /events_ui.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on august 31st, 2016 3 | 4 | @author: giroux 5 | ''' 6 | 7 | from PyQt5.QtCore import QEvent 8 | 9 | 10 | # Boreholes 11 | class BoreholeAdded(QEvent): 12 | _type = QEvent.registerEventType() 13 | 14 | def __init__(self): 15 | super(BoreholeAdded, self).__init__(BoreholeAdded._type) 16 | 17 | 18 | class BoreholeDeleted(QEvent): 19 | _type = QEvent.registerEventType() 20 | 21 | def __init__(self): 22 | super(BoreholeDeleted, self).__init__(BoreholeDeleted._type) 23 | 24 | 25 | class BoreholeEdited(QEvent): 26 | _type = QEvent.registerEventType() 27 | 28 | def __init__(self): 29 | super(BoreholeEdited, self).__init__(BoreholeEdited._type) 30 | 31 | 32 | # Covariance 33 | class CovarianceEdited(QEvent): 34 | _type = QEvent.registerEventType() 35 | 36 | def __init__(self): 37 | super(CovarianceEdited, self).__init__(CovarianceEdited._type) 38 | 39 | 40 | # Grid 41 | class GridEdited(QEvent): 42 | _type = QEvent.registerEventType() 43 | 44 | def __init__(self): 45 | super(GridEdited, self).__init__(GridEdited._type) 46 | 47 | 48 | # Models 49 | class ModelAdded(QEvent): 50 | _type = QEvent.registerEventType() 51 | 52 | def __init__(self): 53 | super(ModelAdded, self).__init__(ModelAdded._type) 54 | 55 | 56 | class ModelDeleted(QEvent): 57 | _type = QEvent.registerEventType() 58 | 59 | def __init__(self): 60 | super(ModelDeleted, self).__init__(ModelDeleted._type) 61 | 62 | 63 | class ModelEdited(QEvent): 64 | _type = QEvent.registerEventType() 65 | 66 | def __init__(self): 67 | super(ModelEdited, self).__init__(ModelEdited._type) 68 | 69 | 70 | # Mogs 71 | class MogAdded(QEvent): 72 | _type = QEvent.registerEventType() 73 | 74 | def __init__(self): 75 | super(MogAdded, self).__init__(MogAdded._type) 76 | 77 | 78 | class MogDeleted(QEvent): 79 | _type = QEvent.registerEventType() 80 | 81 | def __init__(self): 82 | super(MogDeleted, self).__init__(MogDeleted._type) 83 | 84 | 85 | class MogEdited(QEvent): 86 | _type = QEvent.registerEventType() 87 | 88 | def __init__(self): 89 | super(MogEdited, self).__init__(MogEdited._type) 90 | 91 | 92 | if __name__ == '__main__': 93 | 94 | e = MogAdded() 95 | print(e.type()) 96 | 97 | print(MogAdded._type == e.type()) 98 | 99 | e = BoreholeAdded() 100 | print(e.type()) 101 | 102 | print(BoreholeAdded._type == e.type()) 103 | print(MogAdded._type == e.type()) 104 | -------------------------------------------------------------------------------- /interp_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import sys 23 | from PyQt5 import QtGui, QtWidgets, QtCore 24 | import matplotlib as mpl 25 | from unicodedata import * 26 | 27 | from utils_ui import MyQLabel 28 | 29 | class InterpretationUI(QtWidgets.QFrame): 30 | def __init__(self, parent=None): 31 | super(InterpretationUI, self).__init__() 32 | self.setWindowTitle("BhTomoPy/Inversion") 33 | self.init_UI() 34 | 35 | def init_UI(self): 36 | 37 | # --- Importation of the greek letters --- # 38 | char1 = lookup("GREEK SMALL LETTER ALPHA") 39 | char2 = lookup("GREEK SMALL LETTER THETA") 40 | char3 = lookup("GREEK SMALL LETTER EPSILON") 41 | char4 = lookup("GREEK SMALL LETTER KAPPA") 42 | char5 = lookup("GREEK SMALL LETTER SIGMA") 43 | char6 = lookup("GREEK SMALL LETTER RHO") 44 | char7 = lookup("GREEK SMALL LETTER DELTA") 45 | 46 | # --- Color for the labels --- # 47 | palette = QtGui.QPalette() 48 | palette.setColor(QtGui.QPalette.Foreground, QtCore.Qt.red) 49 | 50 | # ------- Widgets Creation ------- # 51 | 52 | # --- Label --- # 53 | Min_labeli = MyQLabel("Min :", ha='right') 54 | Max_labeli = MyQLabel("Max :", ha='right') 55 | slow_label = QtWidgets.QLabel("Slowness") 56 | atten_label = QtWidgets.QLabel("Attentuation") 57 | type_label = QtWidgets.QLabel("Type") 58 | freq_label = MyQLabel("Frequency[MHz]", ha='right') 59 | 60 | # --- Edits --- # 61 | Min_editi = QtWidgets.QLineEdit() 62 | Max_editi = QtWidgets.QLineEdit() 63 | freq_edit = QtWidgets.QLineEdit("100") 64 | 65 | # --- Checkbox --- # 66 | set_color_checkbox = QtWidgets.QCheckBox("Set Color Limits") 67 | 68 | # --- Text Edits --- # 69 | futur_Graph1 = QtWidgets.QTextEdit() 70 | futur_Graph1.setReadOnly(True) 71 | 72 | # --- combobox --- # 73 | slow_combo = QtWidgets.QComboBox() 74 | atten_combo = QtWidgets.QComboBox() 75 | type_combo = QtWidgets.QComboBox() 76 | phys_combo = QtWidgets.QComboBox() 77 | petro_combo = QtWidgets.QComboBox() 78 | fig_combo = QtWidgets.QComboBox() 79 | 80 | # --- Items in the comboboxes --- # 81 | # --- Type Combobox's Items --- # 82 | type_combo.addItem("Cokriging") 83 | type_combo.addItem("Cosimulation") 84 | 85 | # --- Physical Property Combobox's Items --- # 86 | phys_combo.addItem("Velocity") 87 | phys_combo.addItem("Slowness") 88 | phys_combo.addItem("Attenuation {}".format(char1)) 89 | phys_combo.addItem("Volumetric Water Content {}".format(char2)) 90 | phys_combo.addItem("Dielectric Permittivity {}".format(char3)) 91 | phys_combo.addItem("Dielectric constant {}".format(char4)) 92 | phys_combo.addItem("Electric conductivity {}".format(char5)) 93 | phys_combo.addItem("Electric resistivity {}".format(char6)) 94 | phys_combo.addItem("VLoss tangent {}".format(char7)) 95 | 96 | # --- Petrophysical Combobox's Items --- # 97 | petro_combo.addItem("Topp") 98 | petro_combo.addItem("CRIM") 99 | petro_combo.addItem("Hanai-Brugemann") 100 | 101 | # --- Figure Combobox's Items --- # 102 | fig_combo.addItem("cmr") 103 | fig_combo.addItem("polarmap") 104 | fig_combo.addItem("parula") 105 | fig_combo.addItem("jet") 106 | fig_combo.addItem("hsv") 107 | fig_combo.addItem("hot") 108 | fig_combo.addItem("cool") 109 | fig_combo.addItem("autumn") 110 | fig_combo.addItem("spring") 111 | fig_combo.addItem("winter") 112 | fig_combo.addItem("summer") 113 | fig_combo.addItem("gray") 114 | fig_combo.addItem("bone") 115 | fig_combo.addItem("copper") 116 | fig_combo.addItem("pink") 117 | fig_combo.addItem("prism") 118 | fig_combo.addItem("flag") 119 | fig_combo.addItem("colorcube") 120 | fig_combo.addItem("lines") 121 | 122 | # ------- Groupboxes ------- # 123 | # --- Tomograms Groupbox --- # 124 | Tomo_groupbox = QtWidgets.QGroupBox("Tomograms") 125 | Tomo_grid = QtWidgets.QGridLayout() 126 | Tomo_grid.addWidget(slow_label, 0, 0) 127 | Tomo_grid.addWidget(slow_combo, 1, 0, 1, 2) 128 | Tomo_grid.addWidget(atten_label, 2, 0) 129 | Tomo_grid.addWidget(atten_combo, 3, 0, 1, 2) 130 | Tomo_grid.addWidget(type_label, 4, 0) 131 | Tomo_grid.addWidget(type_combo, 5, 0, 1, 2) 132 | Tomo_groupbox.setLayout(Tomo_grid) 133 | 134 | # --- Physical Property Groupbox --- # 135 | Phys_groupbox = QtWidgets.QGroupBox("Physical Property") 136 | Phys_grid = QtWidgets.QGridLayout() 137 | Phys_grid.addWidget(phys_combo, 0, 0, 1, 2) 138 | Phys_grid.addWidget(freq_label, 1, 0) 139 | Phys_grid.addWidget(freq_edit, 1, 1) 140 | Phys_groupbox.setLayout(Phys_grid) 141 | 142 | # --- Petrophysical Model Groupbox --- # 143 | Petro_groupbox = QtWidgets.QGroupBox("Parameters") 144 | Petro_grid = QtWidgets.QGridLayout() 145 | Petro_grid.addWidget(petro_combo, 0, 0) 146 | Petro_groupbox.setLayout(Petro_grid) 147 | 148 | # --- Figures Groupbox --- # 149 | fig_groupbox = QtWidgets.QGroupBox("Figures") 150 | fig_grid = QtWidgets.QGridLayout() 151 | fig_grid.addWidget(set_color_checkbox, 0, 0) 152 | fig_grid.addWidget(Min_labeli, 0, 1) 153 | fig_grid.addWidget(Min_editi, 0, 2) 154 | fig_grid.addWidget(Max_labeli, 0, 3) 155 | fig_grid.addWidget(Max_editi, 0, 4) 156 | fig_grid.addWidget(fig_combo, 0, 5) 157 | fig_grid.setColumnStretch(6, 100) 158 | fig_groupbox.setLayout(fig_grid) 159 | 160 | # ------- Sub Widgets ------- # 161 | # --- Right Part SubWidget --- # 162 | # The Right part SubWidget is created in order to have a more uniform disposition of the Figure Groupbox 163 | Sub_right_Widget = QtWidgets.QWidget() 164 | Sub_right_Grid = QtWidgets.QGridLayout() 165 | Sub_right_Grid.addWidget(fig_groupbox, 0, 0) 166 | Sub_right_Grid.setContentsMargins(0, 0, 0, 0) 167 | Sub_right_Widget.setLayout(Sub_right_Grid) 168 | 169 | # ------- Master Grid Disposition ------- # 170 | master_grid = QtWidgets.QGridLayout() 171 | master_grid.addWidget(Tomo_groupbox, 0, 0, 3, 1) 172 | master_grid.addWidget(Phys_groupbox, 3, 0, 3, 1) 173 | master_grid.addWidget(Petro_groupbox, 6, 0) 174 | master_grid.addWidget(Sub_right_Widget, 0, 1) 175 | master_grid.addWidget(futur_Graph1, 1, 1, 7, 2) 176 | master_grid.setColumnStretch(2, 100) 177 | master_grid.setRowStretch(7, 100) 178 | self.setLayout(master_grid) 179 | 180 | 181 | if __name__ == '__main__': 182 | 183 | app = QtWidgets.QApplication(sys.argv) 184 | 185 | Model_ui = InterpretationUI() 186 | Model_ui.show() 187 | 188 | sys.exit(app.exec_()) 189 | -------------------------------------------------------------------------------- /inversion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import numpy as np 23 | import scipy as spy 24 | from scipy.sparse import linalg 25 | 26 | 27 | class InvLSQRParams(object): 28 | def __init__(self): 29 | self.tomoAtt = 0 30 | self.selectedMogs = [] 31 | self.numItStraight = 0 32 | self.numItCurved = 0 33 | self.saveInvData = 1 34 | self.useCont = 0 35 | self.tol = 0 36 | self.wCont = 0 37 | self.alphax = 0 38 | self.alphay = 0 39 | self.alphaz = 0 40 | self.order = 1 41 | self.nbreiter = 0 42 | self.dv_max = 0 43 | 44 | def invGeostat(params, data, idata, grid, cm, L, app=None, ui=None): 45 | """ 46 | Input: 47 | params: Instance of lsqrParams class whose parameters have been 48 | edited in InversionUI or manually 49 | 50 | data: (m, 15) array : 51 | - data[:, 3] == Tx(i.e. Tx_x, Tx_y, Tx_z) 52 | - data[:, 3:6] == Rx(i.e. Rx_x, Rx_y, Rx_z) 53 | - data[:, 6:9] == data from model(i.e. tt, et, trace_num) 54 | - data[:, 9:12] == TxCosDir 55 | - data[:, 12:15] == RxCosDir 56 | 57 | idata: (n,) bool array: 58 | - Values at a one index of this vector will be True if the mog.in_vect is True and mog.tt vector does not 59 | equal -1.0 at this same index 60 | 61 | ex: 62 | mog.tt = np.array([ -1.0, 87.341, 79.649, -1.0]) 63 | mog.in_vect = np.array([ 1, 1, 0, 0]) 64 | 65 | idata = np.array([ False, True, False, False]) 66 | 67 | grid: instance of Grid class 68 | 69 | cm : Covar model used 70 | 71 | L: 72 | First iteration: 73 | - Sparse matrix which contains the trajectory of straight rays. 74 | Rays are straight because we assume to have a homogeneous slowness/velocity model. 75 | 76 | Second iteration and more: 77 | - Sparse matrix which contains the tracjectory of curved rays. 78 | Rays are now curved because we've been able to build our 79 | slowness/velocity model from the scipy.sparse.linalg.lsqr method. 80 | 81 | app: 82 | if using Bh_Tomo/InversionUI: 83 | The application which contains the InversionUI QWidget. 84 | We need it to process the ui events such as the resfresh of the invFig 85 | 86 | if not using Bh_Tomo/InversionUI:: 87 | app is set to none 88 | 89 | ui: the InversionUI QWidget 90 | """ 91 | 92 | # First we call a Tomo class instance. It will hold the data we will process along the way. 93 | tomo = Tomo() 94 | 95 | if data.shape[1] >= 9: 96 | tomo.no_trace = data[:, 8] 97 | 98 | if np.all(L == 0): 99 | # We get the straights rays for the first iteration 100 | L = grid.getForwardStraightRays(idata) 101 | 102 | tomo.x = 0.5 * (grid.grx[0:-1] + grid.grx[1:]) 103 | tomo.z = 0.5 * (grid.grz[0:-1] + grid.grz[1:]) 104 | 105 | if not np.all(grid.gry == 0): 106 | tomo.y = 0.5 * (grid.gry[0:-2] + grid.gry[1:-1]) 107 | else: 108 | tomo.y = np.array([]) 109 | 110 | cont = np.array([]) 111 | 112 | xc = grid.getCellCenter() 113 | Cm = cm.compute(xc,xc) 114 | 115 | # TODO : Test, indices may not work 116 | if cont.size > 0 and params.useCont == 1: 117 | indc = grid.getContIndices(cont,xc) 118 | Cm0 = Cm[indc,:] 119 | Cmc = Cm[indc,indc] 120 | Cmc = Cmc+np.diag(cont[:,-1]) 121 | 122 | c0=np.array([]); 123 | if np.size(data[0,:])>7 and cm.use_c0==1: 124 | if (data[:,7] != 0).all(): 125 | c0=data[:,7]**2 126 | 127 | for noIter in range(params.numItCurved + params.numItStraight + 1): 128 | if noIter == 1: 129 | l_moy = np.mean(data[:,6]/np.sum(L.A,axis = 1)) 130 | else: 131 | l_moy = np.mean(tomo.s) 132 | mta = np.sum(L.A*l_moy,axis =1) 133 | dt = data[:,6] - mta 134 | 135 | #TODO: Add Simulation param 136 | doSim = 0 137 | #if params.doSim==1 and noIter==(params.numItStraight+params.numItCurved): 138 | # doSim = 1 139 | 140 | if np.size(c0) == 0: 141 | Cd = L*Cm*L.T + cm.nugget_data*np.eye(np.size(L.A[:,0])) 142 | else: 143 | Cd = L*Cm*L.T + cm.nugget_data*np.diag(c0) 144 | 145 | Cdm = L*Cm 146 | 147 | if doSim == 0: 148 | 149 | # TODO : Fix and test this part 150 | if np.size(cont) > 0 and params.useCont == 1: 151 | scont = cont[:,-2]-l_moy 152 | C = np.concatenate((np.concatenate(Cmc, Cdm[:,indc].T),np.concatenate(Cdm[:,indc],Cd))) 153 | C = C+np.eye(np.size(C))*1e-6 154 | # dual cokriging (see Gloaguen et al 2005) 155 | Gamma = np.linalg(C,np.concatenate((scont,dt))).reshape(-1, 1).T 156 | m = Gamma.dot(np.concatenate((Cm0,Cdm))).T 157 | else: 158 | Gamma = np.linalg.solve(Cd,dt).reshape(-1, 1).T 159 | m = Gamma.dot(Cdm).T 160 | 161 | if params.tomoAtt == 1: 162 | #neative attenuation set to zero 163 | m[m<-l_moy] = -l_moy 164 | 165 | tomo.s = m+l_moy 166 | # TODO : Implement simulation 167 | #else: 168 | # 169 | 170 | if params.tomoAtt ==0 and noIter>=params.numItStraight and params.numItCurved > 0: 171 | if np.any(tomo.s<0): 172 | print("Negative Slownesses: Change Inversion Parameters") 173 | #tomo = np.array([]) 174 | _,L,tomo.rays = grid.raytrace(tomo.s,data[:,0:3],data[:,3:6]) 175 | 176 | if params.saveInvData == 1: 177 | tt = L.dot(tomo.s) 178 | tomo.invData.res = data[:,6]-tt 179 | tomo.invData.s = tomo.s 180 | 181 | if ui is not None: 182 | ui.InvIterationDone.emit(noIter + 1,tomo.s, "Geostatistic") 183 | 184 | tomo.L = L 185 | 186 | if ui is not None: 187 | ui.InvDone.emit(noIter, "Geostatistic") 188 | else: 189 | print('Geostatistic Inversion - Finished, {} Iterations Done'.format(noIter)) 190 | 191 | return tomo 192 | 193 | 194 | def invLSQR(params, data, idata, grid, L=None, app=None, ui=None): 195 | """ 196 | Input: 197 | params: Instance of lsqrParams class whose parameters have been 198 | edited in InversionUI or manually 199 | 200 | data: (m, 15) array : 201 | - data[:, 3] == Tx(i.e. Tx_x, Tx_y, Tx_z) 202 | - data[:, 3:6] == Rx(i.e. Rx_x, Rx_y, Rx_z) 203 | - data[:, 6:9] == data from model(i.e. tt, et, trace_num) 204 | - data[:, 9:12] == TxCosDir 205 | - data[:, 12:15] == RxCosDir 206 | 207 | idata: (n,) bool array: 208 | - Values at a one index of this vector will be True if the mog.in_vect is True and mog.tt vector does not 209 | equal -1.0 at this same index 210 | 211 | ex: 212 | mog.tt = np.array([ -1.0, 87.341, 79.649, -1.0]) 213 | mog.in_vect = np.array([ 1, 1, 0, 0]) 214 | 215 | idata = np.array([ False, True, False, False]) 216 | 217 | grid: instance of Grid class 218 | 219 | L: 220 | First iteration: 221 | - Sparse matrix which contains the trajectory of straight rays. 222 | Rays are straight because we assume to have a homogeneous slowness/velocity model. 223 | 224 | Second iteration and more: 225 | - Sparse matrix which contains the tracjectory of curved rays. 226 | Rays are now curved because we've been able to build our 227 | slowness/velocity model from the scipy.sparse.linalg.lsqr method. 228 | 229 | app: 230 | if using Bh_Tomo/InversionUI: 231 | The application which contains the InversionUI QWidget. 232 | We need it to process the ui events such as the resfresh of the invFig 233 | 234 | if not using Bh_Tomo/InversionUI:: 235 | app is set to none 236 | 237 | ui: the InversionUI QWidget 238 | """ 239 | 240 | # First we call a Tomo class instance. It will hold the data we will process along the way. 241 | tomo = Tomo() 242 | 243 | if data.shape[1] >= 9: 244 | tomo.no_trace = data[:, 8] 245 | 246 | if L is None: 247 | # We get the straights rays for the first iteration 248 | L = grid.getForwardStraightRays(idata) 249 | 250 | tomo.x = 0.5 * (grid.grx[0:-2] + grid.grx[1:-1]) 251 | tomo.z = 0.5 * (grid.grz[0:-2] + grid.grz[1:-1]) 252 | 253 | if not np.all(grid.gry == 0): 254 | tomo.y = 0.5 * (grid.gry[0:-2] + grid.gry[1:-1]) 255 | else: 256 | tomo.y = np.array([]) 257 | 258 | cont = np.array([]) 259 | # TODO: Ajouter les conditions par rapport au contraintes de v�locit� appliqu�es dans grid editor 260 | 261 | # Getting our spatial derivative elements 262 | # These will smoothen the subsequent slowness/velocity model 263 | Dx, Dy, Dz = grid.derivative(params.order) 264 | 265 | for noIter in range(params.numItCurved + params.numItStraight): 266 | if ui is not None and app is not None: 267 | ui.gv.noIter = noIter 268 | app.processEvents() 269 | 270 | if ui is not None: 271 | ui.InvIterationDone.emit(noIter,tomo.s, "LSQR") 272 | else: 273 | print('LSQR Inversion - Ray Tracing, Iteration {}'.format(noIter + 1)) 274 | 275 | if noIter == 0: 276 | # Calculating the mean slowness from the picked tts and the ray lenghts 277 | mean_s = np.mean(data[:, 6] / L.sum(axis=1)) 278 | mta = L.sum(axis=1) * mean_s 279 | else: 280 | mean_s = np.mean(tomo.s) 281 | mta = L @ tomo.s 282 | 283 | dt = data[:, 6] - mta.flatten() 284 | 285 | if noIter == 0: 286 | s_o = mean_s * np.ones(L.shape[1]).T 287 | 288 | A = spy.sparse.vstack([L, Dx * params.alphax, Dz * params.alphaz]) 289 | 290 | b = np.concatenate((dt.T, np.zeros(Dx.shape[0]+Dz.shape[0]).reshape((-1,1)))).flatten() 291 | 292 | if not np.all(cont == 0) and params.useCont == 1: 293 | # TODO: faire les modifications aux matrices A et b avec les contraintes 294 | pass 295 | 296 | ans = linalg.lsqr(A, b, atol=params.tol, btol=params.tol, iter_lim=params.nbreiter) 297 | # See http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.linalg.lsqr.html for documentation 298 | x = ans[0] 299 | 300 | if noIter == 0: 301 | tomo.res[0] = ans[3] 302 | else: 303 | np.append(tomo.res, ans[3]) 304 | 305 | if max(abs(s_o / (x + mean_s) - 1)) > params.dv_max: 306 | fac = min(abs((s_o / (params.dv_max + 1) - mean_s) / x)) 307 | x = fac * x 308 | s_o = x + mean_s 309 | 310 | tomo.s = x + mean_s 311 | 312 | if params.saveInvData == 1: 313 | tt = L @ tomo.s 314 | if noIter == 0: 315 | tomo.invData.res = np.array([data[:, 6] - tt]).T 316 | tomo.invData.s = np.array([tomo.s]).T 317 | 318 | else: 319 | tomo.invData.res = np.concatenate((tomo.invData.res, np.array([data[:, 6] - tt]).T), axis=1) 320 | tomo.invData.s = np.concatenate((tomo.invData.s, np.array([tomo.s]).T), axis=1) 321 | 322 | # Applying the resulting model to Tx and Rx to get new tt and L and the trajectory of curved rays 323 | tt, tomo.rays, L = grid.raytrace(tomo.s, data[:, 0:3:2], data[:, 3:6:2]) 324 | 325 | tomo.L = L 326 | 327 | # Results: 328 | # tomo.invData.res: 329 | # - shape: (m, noIter+1) 330 | # - values: residuals from comparison between original tt (i.e. data[:, 6]) 331 | # and tt calculated from the slowness model and the L sparse matrix 332 | # 333 | # tomo.invData.res: 334 | # - shape: (n, noIter+1) 335 | # - values: slowness models from ech iterations 336 | 337 | if ui is not None: 338 | ui.InvDone.emit(noIter, "LSQR") 339 | else: 340 | print('LSQR Inversion - Finished, {} Iterations Done'.format(noIter + 1)) 341 | 342 | return tomo 343 | 344 | 345 | class Tomo(object): 346 | def __init__(self): 347 | self.rays = np.array([]) 348 | self.L = np.array([]) 349 | self.invData = invData() 350 | self.no_trace = np.array([]) 351 | self.x = np.array([]) 352 | self.y = np.array([]) 353 | self.z = np.array([]) 354 | self.s = 0 355 | self.res = np.array([0]) 356 | self.var_res = np.array([]) 357 | 358 | 359 | class invData(object): 360 | def __init__(self): 361 | self.res = np.array([0]) 362 | self.s = np.array([0]) 363 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import numpy as np 23 | 24 | 25 | class Model: 26 | def __init__(self, name=''): 27 | self.name = name 28 | self.grid = None 29 | self.tt_covar = None 30 | self.amp_covar = None 31 | self.mogs = [] 32 | self.inv_res = [] # TODO: use DbList for this attribute 33 | self.tlinv_res = None 34 | self.modified = True 35 | 36 | @property 37 | def boreholes(self): 38 | """ 39 | Returns a list of all the boreholes contained in the mogs of a model, without duplicates. 40 | """ 41 | boreholes = [] 42 | 43 | for mog in self.mogs: 44 | for borehole in mog.Tx, mog.Rx: 45 | if borehole is not None: 46 | if borehole not in boreholes: # guarantees there is no duplicate 47 | boreholes.append(borehole) 48 | 49 | return boreholes 50 | 51 | @staticmethod 52 | def getModelData(model, selected_mogs, type1, vlim=0, type2=''): 53 | data = np.array([]) 54 | ind = np.array([]) 55 | 56 | tt = np.array([]) 57 | et = np.array([]) 58 | in_vect = np.array([]) 59 | mogs = [] 60 | for i in selected_mogs: 61 | mogs.append(model.mogs[i]) 62 | 63 | if type1 == 'tt': 64 | fac_dt = 1 65 | 66 | mog = mogs[0] 67 | ind = np.not_equal(mog.tt, -1).T 68 | tt, t0 = mog.getCorrectedTravelTimes() 69 | tt = tt.T 70 | et = fac_dt * mog.f_et * mog.et.T 71 | in_vect = mog.in_vect.T 72 | no = np.arange(mog.data.ntrace).T 73 | 74 | if len(mogs) > 1: 75 | for n in range(1, len(model.mogs)): 76 | mog = mogs[n] 77 | ind = np.concatenate((ind, np.not_equal(mog.tt, -1).T), axis=0) 78 | tt = np.concatenate((tt, mog.getCorrectedTravelTimes()[0].T), axis=0) 79 | et = np.concatenate((et, fac_dt * mog.et * mog.f_et.T), axis=0) 80 | in_vect = np.concatenate((in_vect, mog.in_vect.T), axis=0) 81 | no = np.concatenate((no, np.arange(mog.ntrace + 1).T), axis=0) 82 | 83 | elif type1 == "amp": 84 | mog = mogs[0] 85 | ind = np.not_equal(mog.tauApp, -1).T 86 | tt = mog.tauApp.T 87 | et = mog.tauApp_et.T * mog.f_et 88 | in_vect = mog.in_vect.T 89 | no = np.arange(mog.data.ntrace).T 90 | 91 | if len(mogs) > 1: 92 | for n in range(1, len(model.mogs)): 93 | mog = mogs[n] 94 | ind = np.concatenate((ind, np.not_equal(mog.tauApp, -1).T), axis=0) 95 | tt = np.concatenate((tt, mog.tauApp.T), axis=0) 96 | et = np.concatenate((et, mog.tauApp_et.T * mog.f_et), axis=0) 97 | in_vect = np.concatenate((in_vect, mog.in_vect.T), axis=0) 98 | no = np.concatenate((no, np.arange(mog.ntrace + 1).T), axis=0) 99 | 100 | elif type1 == "fce": 101 | mog = mogs[0] 102 | ind = np.not_equal(mog.tauFce, -1).T 103 | tt = mog.tauFce.T 104 | et = mog.tauFce_et.T * mog.f_et 105 | in_vect = mog.in_vect.T 106 | no = np.arange(mog.data.ntrace).T 107 | 108 | if len(mogs) > 1: 109 | for n in range(1, len(model.mogs)): 110 | mog = mogs[n] 111 | ind = np.concatenate((ind, np.not_equal(mog.tauFce, -1).T), axis=0) 112 | tt = np.concatenate((tt, mog.tauFce.T), axis=0) 113 | et = np.concatenate((et, mog.tauFce_et.T * mog.f_et), axis=0) 114 | in_vect = np.concatenate((in_vect, mog.in_vect.T), axis=0) 115 | no = np.concatenate((no, np.arange(mog.ntrace + 1).T), axis=0) 116 | 117 | elif type1 == "hyb": 118 | mog = mogs[0] 119 | ind = np.not_equal(mog.tauHyb, -1).T 120 | tt = mog.tauHyb.T 121 | et = mog.tauHyb_et.T * mog.f_et 122 | in_vect = mog.in_vect.T 123 | no = np.arange(mog.data.ntrace).T 124 | 125 | if len(mogs) > 1: 126 | for n in range(1, len(model.mogs)): 127 | mog = mogs[n] 128 | ind = np.concatenate((ind, np.not_equal(mog.tauHyb, -1).T), axis=0) 129 | tt = np.concatenate((tt, mog.tauHyb.T), axis=0) 130 | et = np.concatenate((et, mog.tauHyb_et.T * mog.f_et), axis=0) 131 | in_vect = np.concatenate((in_vect, mog.in_vect.T), axis=0) 132 | no = np.concatenate((no, np.arange(mog.ntrace + 1).T), axis=0) 133 | 134 | elif type1 == 'depth': 135 | if type2 == '': 136 | return data, ind 137 | 138 | _, ind = Model.getModelData(model, selected_mogs, type2) # @UndefinedVariable 139 | mog = mogs[0] 140 | tt = mog.Tx_z_orig.T 141 | et = mog.Rx_z_orig.T 142 | in_vect = mog.in_vect.T 143 | if len(mogs) > 1: 144 | for n in (1, len(mogs)): 145 | tt = np.concatenate((tt, mogs[n].Tx_z_orig.T), axis=0) 146 | et = np.concatenate((et, mogs[n].Rx_z_orig.T), axis=0) 147 | in_vect = np.concatenate((in_vect, mogs[n].in_vect.T), axis=0) 148 | else: 149 | raise ValueError 150 | 151 | if vlim != 0: 152 | l = np.sqrt(np.sum((model.grid.Tx-model.grid.Rx)**2, axis=1)).T 153 | vapp = l/tt 154 | in2 = vapp=1.19.4 2 | h5py>=3.0.0 3 | matplotlib>=3.3.0 4 | scipy>=1.5.4 5 | ttcrpy>=0.4.8 6 | pyFFTW>=0.12.0 7 | Cython>=0.29.21 8 | spectrum>=0.7.6 9 | psutil>=5.7.3 10 | vtk>=8.2.0 -------------------------------------------------------------------------------- /semi_auto_tt_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import sys 23 | from PyQt5 import QtWidgets, QtCore 24 | from matplotlib.figure import Figure 25 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT 26 | 27 | from utils_ui import MyQLabel 28 | 29 | class SemiAutottUI(QtWidgets.QWidget): 30 | def __init__(self, parent=None): 31 | super(SemiAutottUI, self).__init__() 32 | self.setWindowTitle("BhTomoPy/Semi Automatic Traveltime Picking") 33 | self.init_UI() 34 | 35 | def init_UI(self): 36 | 37 | # ------ Creation of the Manager for the Upper figure ------- # 38 | self.Fig = Fig() 39 | self.tool = NavigationToolbar2QT(self.Fig, self) 40 | self.manager = QtWidgets.QWidget() 41 | managergrid = QtWidgets.QGridLayout() 42 | managergrid.addWidget(self.tool, 0, 0) 43 | managergrid.addWidget(self.Fig, 1, 0) 44 | managergrid.setContentsMargins(0, 0, 0, 0) 45 | managergrid.setVerticalSpacing(3) 46 | self.manager.setLayout(managergrid) 47 | # ------- Widgets ------- # 48 | # --- Labels --- # 49 | Z_min_label = MyQLabel(('Z min'), ha='center') 50 | Z_max_label = MyQLabel(('Z max'), ha='center') 51 | Tx_label = MyQLabel(('Tx'), ha='center') 52 | Rx_label = MyQLabel(('Rx'), ha='center') 53 | self.percent_label = MyQLabel((''), ha='center') 54 | Bin_label = MyQLabel(('Bin width [°]'), ha='center') 55 | self.bin_value_label = MyQLabel(('0'), ha='center') 56 | sn_threshold_process_label = MyQLabel(('S/N threshold - 1st Cycle processing'), ha='right') 57 | threshold_label = MyQLabel(('Selection threshold, 1st Cycle'), ha='right') 58 | weight_label = MyQLabel(('Weight - Traces 1st Cycle'), ha='right') 59 | sn_threshold_freq_label = MyQLabel(('S/N threshold - Dom freq scaling'), ha='right') 60 | Dom_freq_min_label = MyQLabel(('Dom freq - acceptable min freq'), ha='right') 61 | Dom_freq_max_label = MyQLabel(('Dom freq - acceptable max freq'), ha='right') 62 | iteration_label = MyQLabel(('Iteration No'), ha='center') 63 | self.iteration_num_label = MyQLabel(('0'), ha='center') 64 | t_label = MyQLabel(('t '), ha='right') 65 | t_min_label = MyQLabel(('min'), ha='center') 66 | t_max_label = MyQLabel(('max'), ha='center') 67 | A_label = MyQLabel(('A '), ha='right') 68 | A_min_label = MyQLabel(('min'), ha='center') 69 | A_max_label = MyQLabel(('max'), ha='center') 70 | computation_label = MyQLabel(('Window - S/N computation'), ha='right') 71 | self.time_units_label = MyQLabel(('[]'), ha='center') 72 | 73 | # --- Edits --- # 74 | self.Tx_Zmin_edit = QtWidgets.QLineEdit() 75 | self.Tx_Zmax_edit = QtWidgets.QLineEdit() 76 | self.Rx_Zmin_edit = QtWidgets.QLineEdit() 77 | self.Rx_Zmax_edit = QtWidgets.QLineEdit() 78 | self.bin_width_edit = QtWidgets.QLineEdit() 79 | self.sn_threshold_process_edit = QtWidgets.QLineEdit() 80 | self.threshold_edit = QtWidgets.QLineEdit() 81 | self.weight_edit = QtWidgets.QLineEdit() 82 | self.sn_threshold_freq_edit = QtWidgets.QLineEdit() 83 | self.Dom_freq_min_edit = QtWidgets.QLineEdit() 84 | self.Dom_freq_max_edit = QtWidgets.QLineEdit() 85 | self.t_min_edit = QtWidgets.QLineEdit() 86 | self.t_max_edit = QtWidgets.QLineEdit() 87 | self.A_min_edit = QtWidgets.QLineEdit() 88 | self.A_max_edit = QtWidgets.QLineEdit() 89 | self.time_step_edit = QtWidgets.QLineEdit() 90 | 91 | # - Edits Dispotion - # 92 | self.Tx_Zmin_edit.setFixedWidth(80) 93 | self.Tx_Zmax_edit.setFixedWidth(80) 94 | self.Rx_Zmin_edit.setFixedWidth(80) 95 | self.Rx_Zmax_edit.setFixedWidth(80) 96 | self.bin_width_edit.setFixedWidth(80) 97 | self.t_min_edit.setFixedWidth(50) 98 | self.t_max_edit.setFixedWidth(50) 99 | self.A_min_edit.setFixedWidth(50) 100 | self.A_max_edit.setFixedWidth(50) 101 | self.time_step_edit.setFixedWidth(50) 102 | self.sn_threshold_process_edit.setFixedWidth(50) 103 | self.threshold_edit.setFixedWidth(50) 104 | self.weight_edit.setFixedWidth(50) 105 | self.sn_threshold_freq_edit.setFixedWidth(50) 106 | self.Dom_freq_min_edit.setFixedWidth(50) 107 | self.Dom_freq_max_edit.setFixedWidth(50) 108 | 109 | # --- Buttons --- # 110 | self.btn_prev_bin = QtWidgets.QPushButton('Previous') 111 | self.btn_next_bin = QtWidgets.QPushButton('Next') 112 | self.btn_prep = QtWidgets.QPushButton('Prepare') 113 | self.btn_show = QtWidgets.QPushButton('Show') 114 | self.btn_remove = QtWidgets.QPushButton('Remove') 115 | self.btn_reinit = QtWidgets.QPushButton('Reinit') 116 | self.btn_align = QtWidgets.QPushButton('Align Traces') 117 | self.btn_pick = QtWidgets.QPushButton('Pick mean Trace') 118 | self.btn_corr = QtWidgets.QPushButton('Pick Traces using Cross correlation') 119 | # --- Action for Menubar --- # 120 | saveAction = QtWidgets.QAction('Save', self) 121 | saveAction.setShortcut('Ctrl+S') 122 | 123 | chooseAction = QtWidgets.QAction('Choose MOG', self) 124 | chooseAction.setShortcut('Ctrl+O') 125 | # chooseAction.triggered.connect(self.openmain.show) 126 | 127 | reiniAction = QtWidgets.QAction('Reinitialize', self) 128 | 129 | usedetrendAction = QtWidgets.QAction('Use Detrend', self) 130 | usedetrendAction.setCheckable(True) 131 | usedetrendAction.setChecked(True) 132 | 133 | alignAction = QtWidgets.QAction('Align Traces', self) 134 | alignAction.setShortcut('Ctrl+A') 135 | 136 | pointAction = QtWidgets.QAction('Point the average Trace', self) 137 | pointAction.setShortcut('Ctrl+P') 138 | 139 | prevAction = QtWidgets.QAction('Previous Group', self) 140 | prevAction.setShortcut('Ctrl+P') 141 | 142 | nextAction = QtWidgets.QAction('Next Group', self) 143 | nextAction.setShortcut('Ctrl+F') 144 | 145 | averAction = QtWidgets.QAction('Show average Traces', self) 146 | 147 | # --- Menubar --- # 148 | self.menu = QtWidgets.QMenuBar() 149 | 150 | # - Menus - # 151 | filemenu = self.menu.addMenu('&File') 152 | editmenu = self.menu.addMenu('&Edit') 153 | actionmenu = self.menu.addMenu('&Action') 154 | 155 | # - Menus Actions - # 156 | filemenu.addAction(chooseAction) 157 | filemenu.addAction(saveAction) 158 | 159 | editmenu.addAction(reiniAction) 160 | editmenu.addAction(usedetrendAction) 161 | 162 | actionmenu.addAction(alignAction) 163 | actionmenu.addAction(pointAction) 164 | actionmenu.addAction(prevAction) 165 | actionmenu.addAction(nextAction) 166 | actionmenu.addAction(nextAction) 167 | actionmenu.addAction(averAction) 168 | 169 | # --- Checkboxes --- # 170 | self.work_check = QtWidgets.QCheckBox('Work with 1st Cycle') 171 | self.dom_freq_check = QtWidgets.QCheckBox('Dominant frequency scaling') 172 | self.orig_check = QtWidgets.QCheckBox('Display original Traces') 173 | self.show_check = QtWidgets.QCheckBox('Show Picks') 174 | 175 | # ------- SubWidgets ------- # 176 | # --- Edits and Labels SubWidget --- # 177 | Sub_E_and_L_widget = QtWidgets.QWidget() 178 | Sub_E_and_L_grid = QtWidgets.QGridLayout() 179 | Sub_E_and_L_grid.addWidget(sn_threshold_process_label, 0, 1) 180 | Sub_E_and_L_grid.addWidget(self.sn_threshold_process_edit, 0, 2) 181 | Sub_E_and_L_grid.addWidget(threshold_label, 1, 1) 182 | Sub_E_and_L_grid.addWidget(self.threshold_edit, 1, 2) 183 | Sub_E_and_L_grid.addWidget(weight_label, 2, 1) 184 | Sub_E_and_L_grid.addWidget(self.weight_edit, 2, 2) 185 | Sub_E_and_L_grid.addWidget(sn_threshold_freq_label, 3, 1) 186 | Sub_E_and_L_grid.addWidget(self.sn_threshold_freq_edit, 3, 2) 187 | Sub_E_and_L_grid.addWidget(Dom_freq_min_label, 4, 1) 188 | Sub_E_and_L_grid.addWidget(self.Dom_freq_min_edit, 4, 2) 189 | Sub_E_and_L_grid.addWidget(Dom_freq_max_label, 5, 1) 190 | Sub_E_and_L_grid.addWidget(self.Dom_freq_max_edit, 5, 2) 191 | Sub_E_and_L_grid.setVerticalSpacing(0) 192 | Sub_E_and_L_grid.setContentsMargins(0, 0, 0, 0) 193 | Sub_E_and_L_grid.setColumnStretch(0, 100) 194 | Sub_E_and_L_widget.setFixedWidth(250) 195 | Sub_E_and_L_widget.setLayout(Sub_E_and_L_grid) 196 | 197 | # --- Lower Buttons SubWidget --- # 198 | Sub_lower_widget = QtWidgets.QWidget() 199 | Sub_lower_grid = QtWidgets.QGridLayout() 200 | Sub_lower_grid.addWidget(self.btn_show, 0, 0) 201 | Sub_lower_grid.addWidget(self.btn_remove, 0, 1) 202 | Sub_lower_grid.addWidget(self.btn_reinit, 0, 2) 203 | Sub_lower_grid.setHorizontalSpacing(3) 204 | Sub_lower_grid.setContentsMargins(0, 0, 0, 0) 205 | Sub_lower_widget.setLayout(Sub_lower_grid) 206 | 207 | # --- trace SubWidget --- # 208 | Sub_trace_widget = QtWidgets.QWidget() 209 | Sub_trace_grid = QtWidgets.QGridLayout() 210 | Sub_trace_grid.addWidget(self.btn_align, 0, 0) 211 | Sub_trace_grid.addWidget(iteration_label, 0, 1) 212 | Sub_trace_grid.addWidget(self.iteration_num_label, 0, 2) 213 | Sub_trace_grid.addWidget(self.btn_pick, 1, 0, 1, 3) 214 | Sub_trace_grid.setContentsMargins(0, 0, 0, 0) 215 | Sub_trace_widget.setLayout(Sub_trace_grid) 216 | 217 | # --- Time and Amplitude Subwidget --- # 218 | Sub_T_and_A_widget = QtWidgets.QWidget() 219 | Sub_T_and_A_grid = QtWidgets.QGridLayout() 220 | Sub_T_and_A_grid.addWidget(t_min_label, 0, 1) 221 | Sub_T_and_A_grid.addWidget(t_max_label, 0, 2) 222 | Sub_T_and_A_grid.addWidget(A_min_label, 0, 4) 223 | Sub_T_and_A_grid.addWidget(A_max_label, 0, 5) 224 | Sub_T_and_A_grid.addWidget(t_label, 1, 0) 225 | Sub_T_and_A_grid.addWidget(self.t_min_edit, 1, 1) 226 | Sub_T_and_A_grid.addWidget(self.t_max_edit, 1, 2) 227 | Sub_T_and_A_grid.addWidget(A_label, 1, 3) 228 | Sub_T_and_A_grid.addWidget(self.A_min_edit, 1, 4) 229 | Sub_T_and_A_grid.addWidget(self.A_max_edit, 1, 5) 230 | Sub_T_and_A_grid.addWidget(computation_label, 2, 1, 1, 3) 231 | Sub_T_and_A_grid.addWidget(self.time_units_label, 2, 4) 232 | Sub_T_and_A_grid.addWidget(self.time_step_edit, 2, 5) 233 | Sub_T_and_A_grid.setHorizontalSpacing(5) 234 | Sub_T_and_A_grid.setContentsMargins(0, 0, 0, 0) 235 | Sub_T_and_A_widget.setLayout(Sub_T_and_A_grid) 236 | 237 | # ------- GroupBoxes -------- # 238 | # --- Station GroupBox --- # 239 | station_group = QtWidgets.QGroupBox('Stations Tx-Rx') 240 | station_grid = QtWidgets.QGridLayout() 241 | station_grid.addWidget(Tx_label, 0, 1) 242 | station_grid.addWidget(Rx_label, 0, 2) 243 | station_grid.addWidget(Z_min_label, 1, 0) 244 | station_grid.addWidget(self.Tx_Zmin_edit, 1, 1) 245 | station_grid.addWidget(self.Rx_Zmin_edit, 1, 2) 246 | station_grid.addWidget(self.percent_label, 1, 3) 247 | station_grid.addWidget(Z_max_label, 2, 0) 248 | station_grid.addWidget(self.Tx_Zmax_edit, 2, 1) 249 | station_grid.addWidget(self.Rx_Zmax_edit, 2, 2) 250 | station_group.setLayout(station_grid) 251 | station_group.setFixedWidth(300) 252 | 253 | # --- Bin GroupBox --- # 254 | bin_group = QtWidgets.QGroupBox('Bin') 255 | bin_grid = QtWidgets.QGridLayout() 256 | bin_grid.addWidget(Bin_label, 0, 0) 257 | bin_grid.addWidget(self.bin_width_edit, 0, 1) 258 | bin_grid.addWidget(self.btn_prev_bin, 1, 0) 259 | bin_grid.addWidget(self.bin_value_label, 1, 1) 260 | bin_grid.addWidget(self.btn_next_bin, 1, 2) 261 | bin_group.setLayout(bin_grid) 262 | bin_group.setFixedWidth(300) 263 | 264 | # --- No Name GroupBox --- # 265 | no_group = QtWidgets.QGroupBox() 266 | no_grid = QtWidgets.QGridLayout() 267 | no_grid.addWidget(self.work_check, 0, 0) 268 | no_grid.addWidget(self.dom_freq_check, 1, 0) 269 | no_grid.addWidget(self.orig_check, 2, 0) 270 | no_grid.addWidget(self.btn_prep, 3, 0) 271 | no_grid.addWidget(Sub_E_and_L_widget, 4, 0) 272 | no_grid.addWidget(Sub_lower_widget, 5, 0) 273 | no_group.setLayout(no_grid) 274 | 275 | # --- Traces GroupBox --- # 276 | traces_group = QtWidgets.QGroupBox('Traces') 277 | traces_grid = QtWidgets.QGridLayout() 278 | traces_grid.addWidget(no_group, 0, 0) 279 | traces_grid.addWidget(Sub_trace_widget, 1, 0) 280 | traces_grid.addWidget(Sub_T_and_A_widget, 2, 0) 281 | traces_group.setLayout(traces_grid) 282 | traces_group.setFixedWidth(300) 283 | 284 | # --- Automatic Picking GroupBox --- # 285 | auto_group = QtWidgets.QGroupBox('Automatic Picking') 286 | auto_grid = QtWidgets.QGridLayout() 287 | auto_grid.addWidget(self.show_check, 0, 0) 288 | auto_grid.addWidget(self.btn_pick, 1, 0, 1, 2) 289 | auto_group.setLayout(auto_grid) 290 | auto_group.setFixedWidth(300) 291 | 292 | # ------- Master Grid ------- # 293 | master_grid = QtWidgets.QGridLayout() 294 | master_grid.addWidget(self.menu, 0, 0, 1, 5) 295 | master_grid.addWidget(self.manager, 1, 0, 5, 4) 296 | master_grid.addWidget(station_group, 2, 4) 297 | master_grid.addWidget(bin_group, 3, 4) 298 | master_grid.addWidget(traces_group, 4, 4) 299 | master_grid.addWidget(auto_group, 5, 4) 300 | master_grid.setColumnStretch(0, 100) 301 | master_grid.setVerticalSpacing(0) 302 | master_grid.setContentsMargins(0, 0, 0, 0) 303 | self.setLayout(master_grid) 304 | 305 | 306 | class Fig(FigureCanvasQTAgg): 307 | def __init__(self): 308 | fig = Figure(facecolor='white') 309 | super(Fig, self).__init__(fig) 310 | self.init_figure() 311 | 312 | def init_figure(self): 313 | ax1 = self.figure.add_axes([0.08, 0.45, 0.85, 0.5]) 314 | ax2 = self.figure.add_axes([0.08, 0.06, 0.85, 0.3]) 315 | ax1.yaxis.set_ticks_position('left') 316 | ax1.set_axisbelow(True) 317 | 318 | 319 | if __name__ == '__main__': 320 | 321 | app = QtWidgets.QApplication(sys.argv) 322 | 323 | Semi_ui = SemiAutottUI() 324 | Semi_ui.show() 325 | 326 | sys.exit(app.exec_()) 327 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Copyright 2017 Bernard Giroux, Elie Dumas-Lefebvre, Jerome Simon 4 | email: Bernard.Giroux@ete.inrs.ca 5 | 6 | This file is part of BhTomoPy. 7 | 8 | BhTomoPy is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | # 23 | # python setup.py build_ext --inplace 24 | 25 | import platform 26 | import numpy as np 27 | from distutils.core import setup 28 | from distutils.extension import Extension 29 | from Cython.Build import cythonize 30 | 31 | include_dirs = ['./cutils/', np.get_include()] 32 | if platform.system() == 'Darwin': 33 | extra_compile_args = ['-std=c++11', '-stdlib=libc++', '-O3'] 34 | extra_compile_argsC = ['-O3'] 35 | include_dirs.append('/opt/local/include') # for boost 36 | elif platform.system() == 'Windows': 37 | extra_compile_args = ['/O2'] 38 | extra_compile_argsC = ['/O2'] 39 | include_dirs=['./cutils/', np.get_include(), 40 | 'C:\\Users\\giroux\OneDrive\Documents\\boost_1_66_0'] 41 | elif platform.system() == 'Linux': 42 | extra_compile_args = ['-std=c++11', '-O3'] 43 | extra_compile_argsC = ['-O3'] 44 | 45 | extensions = [ 46 | Extension('cutils.segy', 47 | sources=['./cutils/segy.pyx', './cutils/csegy.c'], # additional source file(s) 48 | include_dirs=include_dirs, 49 | extra_compile_args=extra_compile_argsC,), 50 | ] 51 | 52 | setup( 53 | name='cutils', 54 | ext_modules=cythonize(extensions, include_path=['./cutils/', ]), 55 | ) 56 | -------------------------------------------------------------------------------- /testData/air_shots/ap0102b.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:10 24 | STOP POSITION:0.00 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:2.700 37 | -------------------------------------------------------------------------------- /testData/air_shots/ap0102b.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/air_shots/ap0102b.rd3 -------------------------------------------------------------------------------- /testData/air_shots/ap0102b.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 0 0.00 0.00 0.00 3 | 1 1 0.00 0.00 0.30 4 | 2 2 0.00 0.00 0.60 5 | 3 3 0.00 0.00 0.90 6 | 4 4 0.00 0.00 1.20 7 | 5 5 0.00 0.00 1.50 8 | 6 6 0.00 0.00 1.80 9 | 7 7 0.00 0.00 2.10 10 | 8 8 0.00 0.00 2.40 11 | 9 9 0.00 0.00 2.70 12 | -------------------------------------------------------------------------------- /testData/air_shots/ap0302.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.371321 5 | RAW SIGNAL POSITION:48693 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:13 24 | STOP POSITION:0.00 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:3.600 37 | -------------------------------------------------------------------------------- /testData/air_shots/ap0302.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/air_shots/ap0302.rd3 -------------------------------------------------------------------------------- /testData/air_shots/ap0302.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 0 0.00 0.00 0.00 3 | 1 1 0.00 0.00 0.30 4 | 2 2 0.00 0.00 0.60 5 | 3 3 0.00 0.00 0.90 6 | 4 4 0.00 0.00 1.20 7 | 5 5 0.00 0.00 1.50 8 | 6 6 0.00 0.00 1.80 9 | 7 7 0.00 0.00 2.10 10 | 8 8 0.00 0.00 2.40 11 | 9 9 0.00 0.00 2.70 12 | 10 10 0.00 0.00 3.00 13 | 11 11 0.00 0.00 3.30 14 | 12 12 0.00 0.00 3.60 15 | -------------------------------------------------------------------------------- /testData/air_shots/av0102.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:10 24 | STOP POSITION:0.00 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:2.700 37 | -------------------------------------------------------------------------------- /testData/air_shots/av0102.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/air_shots/av0102.rd3 -------------------------------------------------------------------------------- /testData/air_shots/av0102.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 0 0.00 0.00 0.00 3 | 1 1 0.00 0.00 0.30 4 | 2 2 0.00 0.00 0.60 5 | 3 3 0.00 0.00 0.90 6 | 4 4 0.00 0.00 1.20 7 | 5 5 0.00 0.00 1.50 8 | 6 6 0.00 0.00 1.80 9 | 7 7 0.00 0.00 2.10 10 | 8 8 0.00 0.00 2.40 11 | 9 9 0.00 0.00 2.70 12 | -------------------------------------------------------------------------------- /testData/air_shots/av0102b.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:10 24 | STOP POSITION:0.00 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:2.700 37 | -------------------------------------------------------------------------------- /testData/air_shots/av0102b.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/air_shots/av0102b.rd3 -------------------------------------------------------------------------------- /testData/air_shots/av0102b.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 0 0.00 0.00 0.00 3 | 1 1 0.00 0.00 0.30 4 | 2 2 0.00 0.00 0.60 5 | 3 3 0.00 0.00 0.90 6 | 4 4 0.00 0.00 1.20 7 | 5 5 0.00 0.00 1.50 8 | 6 6 0.00 0.00 1.80 9 | 7 7 0.00 0.00 2.10 10 | 8 8 0.00 0.00 2.40 11 | 9 9 0.00 0.00 2.70 12 | -------------------------------------------------------------------------------- /testData/air_shots/av0302.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.371321 5 | RAW SIGNAL POSITION:48693 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:10 24 | STOP POSITION:0.00 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:2.700 37 | -------------------------------------------------------------------------------- /testData/air_shots/av0302.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/air_shots/av0302.rd3 -------------------------------------------------------------------------------- /testData/air_shots/av0302.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 0 0.00 0.00 0.00 3 | 1 1 0.00 0.00 0.30 4 | 2 2 0.00 0.00 0.60 5 | 3 3 0.00 0.00 0.90 6 | 4 4 0.00 0.00 1.20 7 | 5 5 0.00 0.00 1.50 8 | 6 6 0.00 0.00 1.80 9 | 7 7 0.00 0.00 2.10 10 | 8 8 0.00 0.00 2.40 11 | 9 9 0.00 0.00 2.70 12 | -------------------------------------------------------------------------------- /testData/coord_forages.txt: -------------------------------------------------------------------------------- 1 | 0 0 0 2 | 0.253316900403028 2.96491898936936 0.130000000000000 3 | 0.859758711842723 5.74900091965682 0.160000000000000 4 | 4.84799121423705 3.02128577382876 0.130000000000000 5 | 7.74009983204746 6.29389096728768 0.170000000000000 6 | 9.37200502186476 2.93432364925112 0.150000000000000 7 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0102.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:2068 24 | STOP POSITION:13.51 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:13.500 37 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0102.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/formats/ramac/t0102.rd3 -------------------------------------------------------------------------------- /testData/formats/ramac/t0102.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 45 0.00 13.50 0.00 3 | 46 91 13.50 0.00 0.30 4 | 92 137 0.00 13.50 0.60 5 | 138 183 13.50 0.00 0.90 6 | 184 229 0.00 13.50 1.20 7 | 230 275 13.50 -0.01 1.50 8 | 276 321 -0.01 13.50 1.80 9 | 322 367 13.50 0.00 2.10 10 | 368 413 0.00 13.50 2.40 11 | 414 459 13.50 -0.01 2.70 12 | 460 505 -0.01 13.50 3.00 13 | 506 551 13.50 0.00 3.30 14 | 552 597 0.00 13.50 3.60 15 | 598 643 13.50 0.00 3.90 16 | 644 689 0.00 13.50 4.20 17 | 690 735 13.50 0.00 4.50 18 | 736 781 0.00 13.50 4.80 19 | 782 827 13.50 0.00 5.10 20 | 828 873 0.00 13.50 5.40 21 | 874 919 13.50 0.00 5.70 22 | 920 965 0.00 13.40 6.00 23 | 966 1010 13.40 0.01 6.30 24 | 1011 1056 0.01 13.50 6.60 25 | 1057 1102 13.50 0.00 6.90 26 | 1103 1148 0.00 13.40 7.20 27 | 1149 1193 13.40 0.00 7.50 28 | 1194 1239 0.00 13.40 7.80 29 | 1240 1284 13.40 0.00 8.10 30 | 1285 1330 0.00 13.51 8.40 31 | 1331 1376 13.51 0.01 8.70 32 | 1377 1422 0.01 13.51 9.00 33 | 1423 1468 13.51 -0.01 9.30 34 | 1469 1514 -0.01 13.50 9.60 35 | 1515 1560 13.50 0.00 9.90 36 | 1561 1606 0.00 13.50 10.20 37 | 1607 1652 13.50 0.00 10.50 38 | 1653 1698 0.00 13.50 10.80 39 | 1699 1744 13.50 -0.01 11.10 40 | 1745 1790 -0.01 13.50 11.40 41 | 1791 1836 13.50 0.00 11.70 42 | 1837 1882 0.00 13.50 12.00 43 | 1883 1928 13.50 0.00 12.30 44 | 1929 1974 0.00 13.50 12.60 45 | 1975 2020 13.50 0.00 12.90 46 | 2021 2066 0.00 13.51 13.20 47 | 2067 2067 13.51 13.51 13.50 48 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0102_no_tlf.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:2068 24 | STOP POSITION:13.51 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:13.500 37 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0102_no_tlf.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/formats/ramac/t0102_no_tlf.rd3 -------------------------------------------------------------------------------- /testData/formats/ramac/t0102b.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.348309 5 | RAW SIGNAL POSITION:47706 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:322 24 | STOP POSITION:13.50 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:1 35 | FIXED MOVES DOWN:0 36 | FIXED POSITION:11.400 37 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0102b.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/formats/ramac/t0102b.rd3 -------------------------------------------------------------------------------- /testData/formats/ramac/t0102b.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 45 0.00 13.50 13.20 3 | 46 91 13.50 0.00 12.90 4 | 92 137 0.00 13.51 12.60 5 | 138 183 13.51 0.00 12.30 6 | 184 229 0.00 13.50 12.00 7 | 230 275 13.50 0.00 11.70 8 | 276 321 0.00 13.50 11.40 9 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0302.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:550 2 | FREQUENCY:2042.383769 3 | FREQUENCY STEPS:21 4 | SIGNAL POSITION:-0.371321 5 | RAW SIGNAL POSITION:48693 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL:0.100000 11 | DISTANCE INTERVAL:0.299980 12 | OPERATOR: 13 | CUSTOMER: 14 | SITE: 15 | ANTENNAS:BH100 MHz 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION:0.600000 18 | COMMENT: 19 | TIMEWINDOW:269.293170 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.176000 23 | LAST TRACE:2254 24 | STOP POSITION:-0.16 25 | SYSTEM CALIBRATION:0.0000233154 26 | START POSITION:0.00 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:5 32 | LOW:15 33 | FIXED INCREMENT:0.300 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:13.500 37 | -------------------------------------------------------------------------------- /testData/formats/ramac/t0302.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/formats/ramac/t0302.rd3 -------------------------------------------------------------------------------- /testData/formats/ramac/t0302.tlf: -------------------------------------------------------------------------------- 1 | #First trace Last trace First pos Last pos Fixed pos 2 | 0 48 0.00 14.40 0.00 3 | 49 97 14.40 0.00 0.30 4 | 98 146 0.00 14.40 0.60 5 | 147 195 14.40 0.00 0.90 6 | 196 244 0.00 14.40 1.20 7 | 245 293 14.40 0.00 1.50 8 | 294 342 0.00 14.40 1.80 9 | 343 391 14.40 0.00 2.10 10 | 392 440 0.00 14.40 2.40 11 | 441 489 14.40 -0.01 2.70 12 | 490 538 -0.01 14.40 3.00 13 | 539 587 14.40 0.06 3.30 14 | 588 636 0.06 14.40 3.60 15 | 637 685 14.40 0.00 3.90 16 | 686 734 0.00 14.40 4.20 17 | 735 783 14.40 0.00 4.50 18 | 784 832 0.00 14.40 4.80 19 | 833 881 14.40 0.00 5.10 20 | 882 930 0.00 14.41 5.40 21 | 931 979 14.41 0.00 5.70 22 | 980 1028 0.00 14.40 6.00 23 | 1029 1077 14.40 0.00 6.30 24 | 1078 1126 0.00 14.40 6.60 25 | 1127 1175 14.40 0.00 6.90 26 | 1176 1224 0.00 14.40 7.20 27 | 1225 1273 14.40 0.00 7.50 28 | 1274 1322 0.00 14.40 7.80 29 | 1323 1371 14.40 0.01 8.10 30 | 1372 1420 0.01 14.40 8.40 31 | 1421 1469 14.40 0.00 8.70 32 | 1470 1518 0.00 14.40 9.00 33 | 1519 1567 14.40 0.00 9.30 34 | 1568 1616 0.00 14.40 9.60 35 | 1617 1665 14.40 0.00 9.90 36 | 1666 1714 0.00 14.39 10.20 37 | 1715 1763 14.39 0.00 10.50 38 | 1764 1812 0.00 14.40 10.80 39 | 1813 1861 14.40 0.00 11.10 40 | 1862 1910 0.00 14.40 11.40 41 | 1911 1959 14.40 0.00 11.70 42 | 1960 2008 0.00 14.40 12.00 43 | 2009 2057 14.40 0.01 12.30 44 | 2058 2106 0.01 14.40 12.60 45 | 2107 2155 14.40 0.00 12.90 46 | 2156 2204 0.00 14.40 13.20 47 | 2205 2253 14.40 -0.13 13.50 48 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0001_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0001_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0001_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0002_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0002_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0002_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0003_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0003_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0003_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0004_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0004_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0004_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0005_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0005_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0005_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0006_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0006_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0006_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0007_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0007_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0007_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0008_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0008_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0008_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0009_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0009_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0009_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0010_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0010_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0010_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0011_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0011_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0011_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0012_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0012_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0012_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0013_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0013_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0013_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0014_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0014_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0014_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0015_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0015_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0015_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0016_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0016_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0016_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0017_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0017_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0017_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0018_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0018_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0018_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0019_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0019_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0019_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0020_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0020_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0020_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0021_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0021_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0021_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0022_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0022_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0022_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0023_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0023_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0023_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0024_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0024_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0024_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0025_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0025_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0025_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0026_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0026_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0026_A1.rd3 -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0027_A1.rad: -------------------------------------------------------------------------------- 1 | SAMPLES:512 2 | FREQUENCY:1248.145264 3 | FREQUENCY STEPS:31 4 | SIGNAL POSITION:373.664118 5 | RAW SIGNAL POSITION:51077 6 | DISTANCE FLAG:1 7 | TIME FLAG:0 8 | PROGRAM FLAG:0 9 | EXTERNAL FLAG:0 10 | TIME INTERVAL: 0.000000 11 | DISTANCE INTERVAL: 0.249346 12 | OPERATOR:_ 13 | CUSTOMER:_ 14 | SITE:_ 15 | ANTENNAS:100 MHz Borehole 16 | ANTENNA ORIENTATION:NOT VALID FIELD 17 | ANTENNA SEPARATION: 2.750000 18 | COMMENT: 19 | TIMEWINDOW:410.208666 20 | STACKS:32 21 | STACK EXPONENT:5 22 | STACKING TIME:0.048000 23 | LAST TRACE:40 24 | STOP POSITION: 9.973859 25 | SYSTEM CALIBRATION:0.0000258448 26 | START POSITION:0.000000 27 | SHORT FLAG:0 28 | INTERMEDIATE FLAG:1 29 | LONG FLAG:0 30 | PREPROCESSING:0 31 | HIGH:0 32 | LOW:0 33 | FIXED INCREMENT:0.300000 34 | FIXED MOVES UP:0 35 | FIXED MOVES DOWN:1 36 | FIXED POSITION:0.000000 37 | WHEEL CALIBRATION:497.300000 38 | POSITIVE DIRECTION:1 39 | -------------------------------------------------------------------------------- /testData/stlambert/p18p17_0027_A1.rd3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/testData/stlambert/p18p17_0027_A1.rd3 -------------------------------------------------------------------------------- /testData/testConstraints/F1.xyz: -------------------------------------------------------------------------------- 1 | 0.00 0.00 0.00 2 | 0.00 0.00 -16.00 3 | -------------------------------------------------------------------------------- /testData/testConstraints/F2.xyz: -------------------------------------------------------------------------------- 1 | 0.2533 2.9649 0.1300 2 | 0.2533 2.9649 -16.0000 3 | -------------------------------------------------------------------------------- /testData/testConstraints/F3.xyz: -------------------------------------------------------------------------------- 1 | 0.8598 5.7490 0.1600 2 | 0.8598 5.7490 -16.0000 3 | -------------------------------------------------------------------------------- /testData/testConstraints/F3_vel.con: -------------------------------------------------------------------------------- 1 | 1 0.09 2 | 2 0.09 3 | 3 0.10 4 | 4 0.10 5 | 5 0.095 6 | 6 0.10 7 | 7 0.09 8 | 8 0.10 9 | 9 0.11 10 | 10 0.10 11 | 11 0.095 12 | 12 0.095 13 | 13 0.105 14 | 14 0.11 15 | 15 0.095 16 | 16 0.095 17 | -------------------------------------------------------------------------------- /testData/testConstraints/F4.xyz: -------------------------------------------------------------------------------- 1 | 4.8480 3.0213 0.1300 2 | 4.8480 3.0213 -16.0000 3 | -------------------------------------------------------------------------------- /testData/testConstraints/F5.xyz: -------------------------------------------------------------------------------- 1 | 7.7401 6.2939 0.1700 2 | 7.7401 6.2939 -16.0000 3 | -------------------------------------------------------------------------------- /testData/testConstraints/F6.xyz: -------------------------------------------------------------------------------- 1 | 9.3720 2.9343 0.1500 2 | 9.3720 2.9343 -16.0000 3 | -------------------------------------------------------------------------------- /testData/testConstraints/test1_vel.con: -------------------------------------------------------------------------------- 1 | 0.5 4.0 -1.0 0.11 0.0 2 | 1.0 4.0 -1.0 0.11 0.0 3 | 0.0 2.0 -1.0 0.1 0.0 4 | -------------------------------------------------------------------------------- /test_db.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/groupeLIAMG/BhTomoPy/df12d21fa8d72723ae03d626583cb59f3694d2be/test_db.h5 -------------------------------------------------------------------------------- /test_segy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Aug 5 12:54:52 2016 4 | 5 | @author: giroux 6 | """ 7 | 8 | from cutils import segy 9 | 10 | filename = '/Users/giroux/CloudStation/Projets/Frio/donnees_brutes/pre-xwell-all.sgy' 11 | 12 | d = segy.read_segy(filename, fields=['sx', 'sy', 'gx', 'gy', 'selev']) # @UndefinedVariable 13 | 14 | for k in d.bh: 15 | print(k, d.bh[k]) 16 | 17 | for k in d.th: 18 | print(k, d.th[k][1]) 19 | 20 | print(d.data.shape) 21 | print(d.data[:50, 0]) 22 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jun 21 20:55:29 2016 4 | 5 | @author: giroux 6 | 7 | Copyright 2017 Bernard Giroux, Jerome Simon 8 | email: Bernard.Giroux@ete.inrs.ca 9 | 10 | This file is part of BhTomoPy. 11 | 12 | BhTomoPy is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this program. If not, see . 24 | """ 25 | import sys 26 | import inspect 27 | import dis 28 | import numpy as np 29 | import scipy.signal 30 | from PyQt5.QtCore import QThread 31 | 32 | class ComputeThread(QThread): # Class that simplify the threading of a function. Simply create a thread for a giving function 33 | def __init__(self, function_to_compute, *args): 34 | QThread.__init__(self) 35 | self.compute = function_to_compute 36 | self.args = args 37 | 38 | def run(self): 39 | self.compute(*self.args) 40 | 41 | def Hook(Type, value, traceback): # PyQt5 overrides Eclipse's exception catching. 'Hook' solves this issue. 42 | initial_ctx = traceback.tb_next 43 | while initial_ctx is not None: 44 | initial_ctx = initial_ctx.tb_next 45 | sys.__excepthook__(Type, value, traceback) 46 | 47 | 48 | sys.excepthook = Hook 49 | 50 | 51 | 52 | def nargout(): 53 | """ 54 | Returns how many values the caller is expecting 55 | 56 | taken from 57 | http://stackoverflow.com/questions/16488872/python-check-for-the-number-of-output-arguments-a-function-is-called-with 58 | """ 59 | if sys.version_info[1] > 5: 60 | off = 1 61 | else: 62 | off = 0 63 | f = inspect.currentframe() 64 | f = f.f_back.f_back 65 | c = f.f_code 66 | i = f.f_lasti 67 | bytecode = c.co_code 68 | instruction = bytecode[i + 3 - off] 69 | if instruction == dis.opmap['UNPACK_SEQUENCE']: 70 | howmany = bytecode[i + 4 - off] 71 | return howmany 72 | elif instruction == dis.opmap['POP_TOP']: 73 | return 0 74 | return 1 75 | 76 | 77 | def set_tick_arrangement(grid): 78 | start = min(grid.grx[0],grid.grx[-1]) 79 | end = max(grid.grx[0],grid.grx[-1]) 80 | 81 | nticks = 4 82 | tickstep = np.round((end-start)/nticks) 83 | 84 | return np.arange(np.round(start), end, tickstep) 85 | 86 | 87 | def detrend_rad(traces): 88 | # TODO: fill this fct 89 | return traces 90 | 91 | 92 | def compute_SNR(mog): 93 | SNR = np.ones(mog.data.ntrace) 94 | 95 | max_amps = np.amax(np.abs(detrend_rad(mog.data.rdata))) 96 | i = np.nonzero(np.abs(detrend_rad(mog.data.rdata)) == max_amps)[0] 97 | 98 | width = 60 99 | 100 | i1 = i - width / 2 101 | i2 = i + width / 2 102 | i1[i1 < 1] = 1 103 | i2[i2 > mog.data.nptsptrc] = mog.data.nptsptrc 104 | 105 | for n in range(mog.data.ntrace): 106 | SNR[n] = np.std(mog.data.rdata[i1[n]:i2[n], n]) / np.std(mog.data.rdata[:width, n]) 107 | 108 | return SNR 109 | 110 | 111 | def data_select(data, freq, dt, L=100, threshold=5, medfilt_len=10): 112 | 113 | shape = np.shape(data) 114 | M = shape[1] 115 | std_sig = np.zeros(M).T 116 | ind_data_select = np.zeros(M, dtype=bool).T 117 | ind_max = np.zeros(M).T 118 | nb_p = np.round(1 / (dt * freq)) 119 | width = 60 120 | if medfilt_len > 0: 121 | data = scipy.signal.medfilt(data) 122 | 123 | for i in range(M): 124 | ind1 = np.argmax(data[:, i]) 125 | ind_max[i] = ind1 126 | ind = np.arange(ind1 - nb_p, ind1 + 2 * nb_p + 1) 127 | 128 | if ind[0] < 1: 129 | ind = np.arange(1, ind1 + width) 130 | elif ind[-1] < 1: 131 | ind = np.arange(ind1 - width, ind1) 132 | 133 | std_sig[i] = np.std(data[int(ind[0]):int(ind[-1]), i]) 134 | 135 | std_noise = np.std(data[-1 - L: -1, :]) 136 | SNR = std_sig / std_noise 137 | ind_data_select[SNR > threshold] = True 138 | 139 | return SNR 140 | 141 | 142 | 143 | if __name__ == "__main__": 144 | 145 | def f(): # test 146 | nout = nargout() 147 | print(nout) 148 | if nout == 1: 149 | return 1 150 | elif nout == 2: 151 | return 1, 2 152 | 153 | f() 154 | a = f() 155 | a, b = f() 156 | --------------------------------------------------------------------------------