Surface NMR processing and inversion GUI
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

akvoGUI.py 72KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626
  1. #/usr/bin/env python
  2. import sys
  3. import matplotlib
  4. matplotlib.use("QT5Agg")
  5. from PyQt5 import QtCore, QtGui, QtWidgets #, uic
  6. import numpy as np
  7. import time
  8. import os
  9. from copy import deepcopy
  10. from matplotlib.backends.backend_qt4 import NavigationToolbar2QT #as NavigationToolbar
  11. import datetime, time
  12. import pkg_resources # part of setuptools
  13. from collections import OrderedDict
  14. from ruamel import yaml
  15. from akvo.gui.main_ui import Ui_MainWindow
  16. from akvo.gui.addCircularLoop_ui import Ui_circularLoopAdd
  17. from akvo.gui.addFigure8Loop_ui import Ui_figure8LoopAdd
  18. from akvo.gui.addPolygonalLoop_ui import Ui_polygonalLoopAdd
  19. from akvo.tressel import mrsurvey
  20. from pyLemma import LemmaCore
  21. from pyLemma import FDEM1D
  22. from pyLemma import Merlin
  23. VERSION = pkg_resources.require("Akvo")[0].version
  24. # Writes out numpy arrays into Eigen vectors as serialized by Lemma
  25. class MatrixXr(yaml.YAMLObject):
  26. yaml_tag = u'MatrixXr'
  27. def __init__(self, rows, cols, data):
  28. self.rows = rows
  29. self.cols = cols
  30. self.data = np.zeros((rows,cols))
  31. def __repr__(self):
  32. return "%s(rows=%r, cols=%r, data=%r)" % (self.__class__.__name__, self.rows, self.cols, self.data)
  33. class VectorXr(yaml.YAMLObject):
  34. yaml_tag = r'VectorXr'
  35. def __init__(self, array):
  36. self.size = np.shape(array)[0]
  37. self.data = array.tolist()
  38. def __repr__(self):
  39. # Converts to numpy array on import
  40. return "np.array(%r)" % (self.data)
  41. def setup_yaml():
  42. """ https://stackoverflow.com/a/8661021 """
  43. represent_dict_order = lambda self, data: self.represent_mapping('tag:yaml.org,2002:map', data.items())
  44. yaml.add_representer(OrderedDict, represent_dict_order)
  45. setup_yaml()
  46. class AkvoYamlNode(yaml.YAMLObject):
  47. yaml_tag = u'AkvoData'
  48. def __init__(self):
  49. self.Akvo_VERSION = VERSION
  50. self.Import = OrderedDict() # {}
  51. self.Processing = [] # OrderedDict()
  52. self.Stacking = OrderedDict()
  53. self.META = OrderedDict()
  54. def __repr__(self):
  55. return "%s(name=%r, Akvo_VERSION=%r, Import=%r, Processing=%r, self.Stacking=%r, self.META=%r)" % (
  56. self.__class__.__name__, self.Akvo_VERSION, self.Import, self.Processing, self.Stacking, self.META )
  57. try:
  58. import thread
  59. except ImportError:
  60. import _thread as thread #Py3K compatibility
  61. class MyPopup(QtWidgets.QWidget):
  62. def __init__(self, name):
  63. super().__init__()
  64. self.name = name
  65. self.initUI()
  66. def initUI(self):
  67. lblName = QtWidgets.QLabel(self.name, self)
  68. class ApplicationWindow(QtWidgets.QMainWindow):
  69. def __init__(self):
  70. super().__init__()
  71. #QtWidgets.QMainWindow.__init__(self)
  72. self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
  73. # alternative to calling pyuic
  74. #self.ui = uic.loadUi('main.ui', self)
  75. self.ui = Ui_MainWindow()
  76. self.ui.setupUi(self)
  77. self.RAWDataProc = None
  78. self.YamlNode = AkvoYamlNode()
  79. # initialise some stuff
  80. self.ui.lcdNumberTauPulse2.setEnabled(0)
  81. self.ui.lcdNumberTauPulse1.setEnabled(0)
  82. self.ui.lcdNumberNuTx.setEnabled(0)
  83. self.ui.lcdNumberTuneuF.setEnabled(0)
  84. self.ui.lcdNumberSampFreq.setEnabled(0)
  85. self.ui.lcdNumberTauDelay.setEnabled(0)
  86. self.ui.lcdNumberNQ.setEnabled(0)
  87. self.logText = []
  88. #######################
  89. ##################### #
  90. ## Make connections # #
  91. ##################### #
  92. #######################
  93. ##############
  94. # Menu items #
  95. ##############
  96. self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset)
  97. self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess)
  98. self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess)
  99. self.ui.actionExport_Preprocessed_Dataset.setEnabled(False)
  100. self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess)
  101. self.ui.actionAboutAkvo.triggered.connect(self.about)
  102. ###########
  103. # Buttons #
  104. ###########
  105. self.ui.loadDataPushButton.pressed.connect(self.loadRAW)
  106. self.ui.sumDataGO.pressed.connect( self.sumDataChans )
  107. self.ui.bandPassGO.pressed.connect( self.bandPassFilter )
  108. self.ui.filterDesignPushButton.pressed.connect( self.designFilter )
  109. self.ui.fdDesignPushButton.pressed.connect( self.designFDFilter )
  110. self.ui.downSampleGO.pressed.connect( self.downsample )
  111. self.ui.windowFilterGO.pressed.connect( self.windowFilter )
  112. self.ui.adaptGO.pressed.connect( self.adaptFilter )
  113. self.ui.adaptFDGO.pressed.connect( self.adaptFilterFD )
  114. self.ui.qdGO.pressed.connect( self.quadDet )
  115. self.ui.gateIntegrateGO.pressed.connect( self.gateIntegrate )
  116. self.ui.calcQGO.pressed.connect( self.calcQ )
  117. self.ui.FDSmartStackGO.pressed.connect( self.FDSmartStack )
  118. self.ui.harmonicGO.pressed.connect( self.harmonicModel )
  119. self.ui.f0K1Spin.valueChanged.connect( self.LCDHarmonics )
  120. self.ui.f0KNSpin.valueChanged.connect( self.LCDHarmonics )
  121. self.ui.f0KsSpin.valueChanged.connect( self.LCDHarmonics )
  122. self.ui.f0Spin.valueChanged.connect( self.LCDHarmonics )
  123. self.ui.NHarmonicsFreqsSpin.valueChanged.connect( self.LCDHarmonics2 )
  124. self.ui.f1K1Spin.valueChanged.connect( self.LCDHarmonics2 )
  125. self.ui.f1KNSpin.valueChanged.connect( self.LCDHarmonics2 )
  126. self.ui.f1KsSpin.valueChanged.connect( self.LCDHarmonics2 )
  127. self.ui.f1Spin.valueChanged.connect( self.LCDHarmonics2 )
  128. self.ui.plotQD.setEnabled(False)
  129. self.ui.plotQD.pressed.connect( self.plotQD )
  130. self.ui.plotGI.setEnabled(False)
  131. self.ui.plotGI.pressed.connect( self.plotGI )
  132. # META
  133. self.ui.locEdit.editingFinished.connect( self.logSite )
  134. self.ui.UTMzone.currentIndexChanged.connect( self.logSite )
  135. self.ui.latBand.currentIndexChanged.connect( self.logSite )
  136. self.ui.ellipsoid.currentIndexChanged.connect( self.logSite )
  137. self.ui.incSpinBox.valueChanged.connect( self.logSite )
  138. self.ui.decSpinBox.valueChanged.connect( self.logSite )
  139. self.ui.intensitySpinBox.valueChanged.connect( self.logSite )
  140. self.ui.tempSpinBox.valueChanged.connect( self.logSite )
  141. self.ui.timeEdit.timeChanged.connect( self.logSite )
  142. self.ui.dateEdit.dateChanged.connect( self.logSite )
  143. # this may call the yaml stuff too often...
  144. self.ui.txtComments.textChanged.connect( self.logSite )
  145. self.ui.plotLoops.pressed.connect( self.plotLoops2 )
  146. self.ui.removeLoopButton.pressed.connect( self.removeLoop )
  147. # Loops
  148. self.ui.addLoopButton.pressed.connect( self.loopAdd )
  149. self.loops = {}
  150. # hide header info box
  151. #self.ui.headerFileBox.setVisible(False)
  152. self.ui.headerFileBox.clicked.connect( self.headerBoxShrink )
  153. self.ui.headerBox2.setVisible(False)
  154. # Clean up the tab widget
  155. self.ui.actionPreprocessing.triggered.connect(self.addPreProc)
  156. self.ui.actionModelling.triggered.connect(self.addModelling)
  157. self.ui.actionInversion.triggered.connect(self.addInversion)
  158. # tabs
  159. #self.ui.ProcTabs.tabCloseRequested.connect( self.closeTabs )
  160. #self.ui.ProcTabs.tabBar().setTabButton(7, QtWidgets.QTabBar.RightSide,None)
  161. self.ui.ProcTabs.removeTab(4)
  162. self.ui.ProcTabs.removeTab(4)
  163. self.ui.ProcTabs.removeTab(4)
  164. self.ui.ProcTabs.removeTab(4)
  165. #self.ui.LoadTab.close( )
  166. # Add progressbar to statusbar
  167. self.ui.barProgress = QtWidgets.QProgressBar()
  168. self.ui.statusbar.addPermanentWidget(self.ui.barProgress, 0);
  169. self.ui.barProgress.setMaximumSize(100, 16777215);
  170. self.ui.barProgress.hide();
  171. self.ui.mplwidget_navigator.setCanvas(self.ui.mplwidget)
  172. #self.ui.mplwidget_navigator_2.setCanvas(self.ui.mplwidget)
  173. self.ui.txRxTable.setColumnCount(4)
  174. self.ui.txRxTable.setRowCount(0)
  175. self.ui.txRxTable.setHorizontalHeaderLabels( ["Label", "Geom.","Turns","Tx/Rx"] )
  176. ##########################################################################
  177. # layer Table
  178. self.ui.layerTableWidget.setRowCount(80)
  179. self.ui.layerTableWidget.setColumnCount(3)
  180. self.ui.layerTableWidget.setHorizontalHeaderLabels( [r"top [m]", r"bottom [m]", "σ [ Ωm]" ] )
  181. # do we want this
  182. self.ui.layerTableWidget.setDragDropOverwriteMode(False)
  183. self.ui.layerTableWidget.setDragEnabled(True)
  184. self.ui.layerTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  185. pCell = QtWidgets.QTableWidgetItem()
  186. pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  187. pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  188. self.ui.layerTableWidget.setItem(0, 1, pCell)
  189. for ir in range(1, self.ui.layerTableWidget.rowCount() ):
  190. for ic in range(0, self.ui.layerTableWidget.columnCount() ):
  191. pCell = QtWidgets.QTableWidgetItem()
  192. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  193. pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  194. pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  195. self.ui.layerTableWidget.setItem(ir, ic, pCell)
  196. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  197. def LCDHarmonics(self):
  198. self.ui.lcdH1F.setEnabled(True)
  199. self.ui.lcdH1F.display( self.ui.f0Spin.value() * self.ui.f0K1Spin.value() )
  200. self.ui.lcdHNF.setEnabled(True)
  201. self.ui.lcdHNF.display( self.ui.f0Spin.value() * self.ui.f0KNSpin.value() )
  202. self.ui.lcdf0NK.setEnabled(True)
  203. self.ui.lcdf0NK.display( (self.ui.f0KNSpin.value()+1-self.ui.f0K1Spin.value()) * self.ui.f0KsSpin.value() )
  204. def LCDHarmonics2(self):
  205. if self.ui.NHarmonicsFreqsSpin.value() == 2:
  206. self.ui.lcdH1F2.setEnabled(True)
  207. self.ui.lcdH1F2.display( self.ui.f1Spin.value() * self.ui.f1K1Spin.value() )
  208. self.ui.lcdHNF2.setEnabled(True)
  209. self.ui.lcdHNF2.display( self.ui.f1Spin.value() * self.ui.f1KNSpin.value() )
  210. self.ui.lcdf0NK2.setEnabled(True)
  211. self.ui.lcdf0NK2.display( (self.ui.f1KNSpin.value()+1-self.ui.f1K1Spin.value()) * self.ui.f1KsSpin.value() )
  212. else:
  213. self.ui.lcdH1F2.setEnabled(False)
  214. self.ui.lcdHNF2.setEnabled(False)
  215. self.ui.lcdf0NK2.setEnabled(False)
  216. def closeTabs(self):
  217. #self.ui.ProcTabs.removeTab(idx)
  218. self.ui.ProcTabs.clear( )
  219. def addPreProc(self):
  220. if self.ui.actionPreprocessing.isChecked():
  221. self.ui.actionModelling.setChecked(False)
  222. self.ui.actionInversion.setChecked(False)
  223. self.ui.ProcTabs.clear( )
  224. self.ui.ProcTabs.insertTab( 0, self.ui.LoadTab, "Load" )
  225. self.ui.ProcTabs.insertTab( 1, self.ui.NCTab, "NC" )
  226. self.ui.ProcTabs.insertTab( 2, self.ui.QCTab, "QC" )
  227. self.ui.ProcTabs.insertTab( 3, self.ui.METATab, "META" )
  228. self.ui.ProcTabs.insertTab( 4, self.ui.LogTab, "Log" )
  229. else:
  230. self.ui.ProcTabs.removeTab(0)
  231. self.ui.ProcTabs.removeTab(0)
  232. self.ui.ProcTabs.removeTab(0)
  233. self.ui.ProcTabs.removeTab(0)
  234. def addModelling(self):
  235. if self.ui.actionModelling.isChecked():
  236. self.ui.actionPreprocessing.setChecked(False)
  237. self.ui.actionInversion.setChecked(False)
  238. self.ui.ProcTabs.clear( )
  239. self.ui.ProcTabs.insertTab( 0, self.ui.KernTab, "Kernel" )
  240. self.ui.ProcTabs.insertTab( 1, self.ui.ModelTab, "Modelling" )
  241. self.ui.ProcTabs.insertTab( 2, self.ui.LogTab, "Log" )
  242. else:
  243. self.ui.ProcTabs.removeTab(0)
  244. self.ui.ProcTabs.removeTab(0)
  245. def addInversion(self, idx):
  246. if self.ui.actionInversion.isChecked():
  247. self.ui.actionPreprocessing.setChecked(False)
  248. self.ui.actionModelling.setChecked(False)
  249. self.ui.ProcTabs.clear( )
  250. self.ui.ProcTabs.insertTab( 0, self.ui.InvertTab, "Inversion" )
  251. self.ui.ProcTabs.insertTab( 1, self.ui.AppraiseTab, "Appraisal" )
  252. self.ui.ProcTabs.insertTab( 2, self.ui.LogTab, "Log" )
  253. else:
  254. self.ui.ProcTabs.removeTab(0)
  255. self.ui.ProcTabs.removeTab(0)
  256. def loopAdd(self):
  257. #print(self.ui.loopLabel.text())
  258. #print(self.ui.loopGeom.currentText())
  259. #print(self.ui.loopType.currentText())
  260. #print( "label len", len(self.ui.loopLabel.text()) )
  261. if len(self.ui.loopLabel.text().strip()) == 0:
  262. Error = QtWidgets.QMessageBox()
  263. Error.setWindowTitle("Error!")
  264. Error.setText("Loop label cannot be blank or repeated")
  265. Error.setDetailedText("Each loop label must be unique and comprise at least one character. Leading and trailing whitespace will be trimmed.")
  266. Error.exec_()
  267. else:
  268. ### Circular loop
  269. if self.ui.loopGeom.currentText() == "Circular":
  270. dialog = QtWidgets.QDialog()
  271. dialog.ui = Ui_circularLoopAdd()
  272. dialog.ui.setupUi(dialog)
  273. dialog.exec_()
  274. dialog.show()
  275. if dialog.result():
  276. cn = dialog.ui.centreNorth.value()
  277. ce = dialog.ui.centreEast.value()
  278. ht = dialog.ui.loopHeight.value()
  279. rad = dialog.ui.loopRadius.value()
  280. turns = dialog.ui.loopTurns.value()
  281. ns = dialog.ui.segments.value()
  282. cwise = dialog.ui.cwiseBox.currentIndex()
  283. print("cwise", cwise)
  284. #dip = dialog.ui.dip.value()
  285. #azimuth = dialog.ui.az.value()
  286. self.loops[self.ui.loopLabel.text()] = FDEM1D.PolygonalWireAntenna()
  287. self.loops[self.ui.loopLabel.text()].SetNumberOfPoints( dialog.ui.segments.value() + 1 )
  288. self.loops[self.ui.loopLabel.text()].SetNumberOfTurns( dialog.ui.loopTurns.value() )
  289. points = np.linspace(0, 2*np.pi, dialog.ui.segments.value()+1)
  290. for iseg, ipt in enumerate(points):
  291. if cwise == 0:
  292. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( cn+rad*np.sin(ipt), ce+rad*np.cos(ipt), ht) )
  293. else:
  294. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( -cn+rad*np.sin(ipt), ce+rad*np.cos(ipt), ht) )
  295. self.loops[self.ui.loopLabel.text()].SetNumberOfFrequencies(1)
  296. self.loops[self.ui.loopLabel.text()].SetCurrent(1.)
  297. if self.ui.loopGeom.currentText() == "figure-8":
  298. dialog = QtWidgets.QDialog()
  299. dialog.ui = Ui_figure8LoopAdd()
  300. dialog.ui.setupUi(dialog)
  301. dialog.exec_()
  302. dialog.show()
  303. if dialog.result():
  304. cn1 = dialog.ui.centreNorth1.value()
  305. ce1 = dialog.ui.centreEast1.value()
  306. cn2 = dialog.ui.centreNorth2.value()
  307. ce2 = dialog.ui.centreEast2.value()
  308. ht = dialog.ui.loopHeight.value()
  309. rad = dialog.ui.loopRadius.value()
  310. turns = dialog.ui.loopTurns.value()
  311. ns = dialog.ui.segments.value()
  312. #cwise = dialog.ui.cwiseBox.currentIndex()
  313. print(cn1, ce1, cn2, ce2, ht, rad, turns, ns)
  314. if self.ui.loopGeom.currentText() == "polygon":
  315. dialog = QtWidgets.QDialog()
  316. dialog.ui = Ui_polygonalLoopAdd()
  317. dialog.ui.setupUi(dialog)
  318. ##########################################################################
  319. # Loop Table
  320. dialog.ui.loopTableWidget.setRowCount(80)
  321. dialog.ui.loopTableWidget.setColumnCount(3)
  322. #dialog.ui.loopTableWidget.horizontalHeader().setSectionResizeMode(0, QtGui.Qt.QHeaderView.Stretch)
  323. dialog.ui.loopTableWidget.setHorizontalHeaderLabels( \
  324. ["Northing [m]","Easting [m]","Height [m]"])
  325. for ir in range(0, dialog.ui.loopTableWidget.rowCount() ):
  326. for ic in range(0, 3): #dialog.ui.loopTableWidget.columnCount() ):
  327. pCell = QtWidgets.QTableWidgetItem()
  328. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  329. #pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  330. #pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  331. dialog.ui.loopTableWidget.setItem(ir, ic, pCell)
  332. #dialog.ui.loopTableWidget.cellChanged.connect(self.loopCellChanged)
  333. #dialog.ui.loopTableWidget.itemClicked.connect(self.loopCellClicked)
  334. #self.ui.loopTableWidget.cellPressed.connect(self.loopCellChanged)
  335. #self.ui.loopTableWidget.cellPressed.connect(self.loopCellClicked)
  336. dialog.ui.loopTableWidget.setDragDropOverwriteMode(False)
  337. dialog.ui.loopTableWidget.setDragEnabled(False)
  338. #self.ui.loopTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  339. dialog.ui.loopTableWidget.resizeColumnsToContents()
  340. dialog.exec_()
  341. dialog.show()
  342. if dialog.result():
  343. self.loops[self.ui.loopLabel.text()] = FDEM1D.PolygonalWireAntenna()
  344. self.loops[self.ui.loopLabel.text()].SetNumberOfTurns( dialog.ui.loopTurns.value() )
  345. npts = 0
  346. for ir in range(0, dialog.ui.loopTableWidget.rowCount() ):
  347. if len(dialog.ui.loopTableWidget.item(ir, 0).text()) == 0:
  348. break
  349. npts += 1
  350. self.loops[self.ui.loopLabel.text()].SetNumberOfPoints( npts )
  351. for ir in range( 0, npts ):
  352. self.loops[self.ui.loopLabel.text()].SetPoint(ir, eval(dialog.ui.loopTableWidget.item(ir, 0).text()), \
  353. eval(dialog.ui.loopTableWidget.item(ir, 1).text()), \
  354. eval(dialog.ui.loopTableWidget.item(ir, 2).text()) \
  355. )
  356. self.loops[self.ui.loopLabel.text()].SetNumberOfFrequencies(1)
  357. self.loops[self.ui.loopLabel.text()].SetCurrent(1.)
  358. # general across all types
  359. if dialog.result():
  360. yml = open( self.ui.loopLabel.text() + ".yml", 'w' )
  361. print( self.loops[self.ui.loopLabel.text()], file=yml)
  362. # update the table
  363. self.ui.txRxTable.setRowCount( len(self.loops.keys()) )
  364. pCell = QtWidgets.QTableWidgetItem()
  365. pCell.setText( self.ui.loopLabel.text() )
  366. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
  367. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 0, pCell)
  368. gCell = QtWidgets.QTableWidgetItem()
  369. gCell.setText( self.ui.loopGeom.currentText() )
  370. gCell.setFlags( QtCore.Qt.ItemIsEnabled )
  371. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 1, gCell)
  372. tCell = QtWidgets.QTableWidgetItem()
  373. tCell.setText( str(dialog.ui.loopTurns.value()) )
  374. tCell.setFlags( QtCore.Qt.ItemIsEnabled )
  375. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 2, tCell)
  376. txCell = QtWidgets.QTableWidgetItem()
  377. txCell.setText( str(self.ui.loopType.currentText()) )
  378. txCell.setFlags( QtCore.Qt.ItemIsEnabled )
  379. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 3, txCell)
  380. def headerBoxShrink(self):
  381. #self.ui.headerFileBox.setVisible(False)
  382. if self.ui.headerFileBox.isChecked( ):
  383. #self.ui.headerFileBox.setMinimumSize(460,250)
  384. self.ui.headerBox2.setVisible(True)
  385. else:
  386. #self.ui.headerFileBox.setMinimumSize(460,50)
  387. self.ui.headerBox2.setVisible(False)
  388. def sigmaCellChanged(self):
  389. self.ui.layerTableWidget.cellChanged.disconnect(self.sigmaCellChanged)
  390. # TODO consider building the model whenever this is called. Would be nice to be able to
  391. # do that. Would require instead dist of T2 I guess.
  392. jj = self.ui.layerTableWidget.currentColumn()
  393. ii = self.ui.layerTableWidget.currentRow()
  394. val = "class 'NoneType'>"
  395. try:
  396. val = eval (str( self.ui.layerTableWidget.item(ii, jj).text() ))
  397. except:
  398. #if jj != 0:
  399. # Error = QtWidgets.QMessageBox()
  400. # Error.setWindowTitle("Error!")
  401. # Error.setText("Non-numeric value encountered")
  402. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  403. return
  404. if jj == 1:
  405. #item.setFlags(QtCore.Qt.ItemIsEnabled)
  406. pCell = self.ui.layerTableWidget.item(ii, jj)
  407. pCell.setBackground( QtGui.QColor("white"))
  408. pCell = self.ui.layerTableWidget.item(ii+1, jj-1)
  409. if str(type(pCell)) == "<class 'NoneType'>":
  410. pCell = QtWidgets.QTableWidgetItem()
  411. pCell.setFlags(QtCore.Qt.ItemIsEnabled)
  412. self.ui.layerTableWidget.setItem(ii+1, jj-1, pCell)
  413. if ii == 0:
  414. pCell.setText(str(val))
  415. #pCell3 = self.ui.layerTableWidget.item(ii+1, jj)
  416. #print ("setting", ii, jj, type(pCell3))
  417. #print ( "setting", ii, jj, type(pCell3))
  418. #pCell3.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  419. #pCell3.setFlags( QtCore.Qt.ItemIsEditable )
  420. elif ii > 0:
  421. val2 = eval (str( self.ui.layerTableWidget.item(ii-1, jj).text() ))
  422. #print ("val2", val2, val, type(val))
  423. #if str(type(pCell)) == "<class 'NoneType'>":
  424. if type(val) == str or val > val2:
  425. pCell.setText(str(val))
  426. else:
  427. Error = QtWidgets.QMessageBox()
  428. Error.setWindowTitle("Error!")
  429. Error.setText("Non-increasing layer detected")
  430. Error.setDetailedText("Each layer interface must be below the one above it.")
  431. Error.exec_()
  432. #err_msg = "Quadrature detection has already been done!"
  433. #reply =QtWidgets.QMessageBox.critical(self, 'Error',
  434. # err_msg)
  435. pCell2 = self.ui.layerTableWidget.item(ii, jj)
  436. pCell2.setText(str(""))
  437. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  438. return
  439. # enable next layer
  440. pCell4 = self.ui.layerTableWidget.item(ii+1, jj)
  441. pCell4.setBackground( QtGui.QColor("lightblue") ) #.lighter(110))
  442. pCell4.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  443. pCell5 = self.ui.layerTableWidget.item(ii+1, jj+1)
  444. pCell5.setBackground( QtGui.QColor("white"))
  445. pCell5.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  446. print("ii", ii, "jj", jj)
  447. if ii == 0 and jj == 0:
  448. pCell = self.ui.layerTableWidget.item(0, 1)
  449. pCell.setBackground( QtGui.QColor("lightblue")) #.lighter(110) )
  450. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  451. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  452. def plotLoops2(self):
  453. self.ui.mplwidget.reAxH(1)
  454. for loop in self.loops:
  455. POINTS = self.loops[loop].GetPoints().T
  456. self.ui.mplwidget.ax1.plot( POINTS[:,1], POINTS[:,0], label=loop )
  457. self.ui.mplwidget.ax1.spines['right'].set_visible(False)
  458. self.ui.mplwidget.ax1.spines['top'].set_visible(False)
  459. self.ui.mplwidget.ax1.set_xlabel("easting (m)")
  460. self.ui.mplwidget.ax1.set_ylabel("northing (m)")
  461. self.ui.mplwidget.ax1.legend()
  462. self.ui.mplwidget.ax1.set_aspect('equal') #, adjustable='box')
  463. self.ui.mplwidget.draw()
  464. def removeLoop(self):
  465. del self.loops[ self.ui.txRxTable.item( self.ui.txRxTable.currentRow(), 0).text() ]
  466. self.ui.txRxTable.removeRow(self.ui.txRxTable.currentRow())
  467. def about(self):
  468. # TODO proper popup with info
  469. #self.w = MyPopup("""About Akvo \n
  470. # Akvo is an open source project developed primarily by Trevor Irons.
  471. #""")
  472. #self.w.setGeometry(100, 100, 400, 200)
  473. #self.w.show()
  474. #print("ABOUT")
  475. # Just a splash screen for now
  476. logo = pkg_resources.resource_filename(__name__, 'akvo-about.png')
  477. pixmap = QtGui.QPixmap(logo)
  478. self.splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  479. self.splash.show()
  480. def connectGMRDataProcessor(self):
  481. self.RAWDataProc = mrsurvey.GMRDataProcessor()
  482. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  483. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  484. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  485. self.RAWDataProc.updateProcTrigger.connect(self.updateProc)
  486. def openGMRRAWDataset(self):
  487. """ Opens a GMR header file
  488. """
  489. try:
  490. with open('.gmr.last.path') as f:
  491. fpath = f.readline()
  492. pass
  493. except IOError as e:
  494. fpath = '.'
  495. self.headerstr = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', fpath)[0] # arg2 = File Type 'All Files (*)'
  496. self.ui.headerFileTextBrowser.clear()
  497. self.ui.headerFileTextBrowser.append(self.headerstr)
  498. if len(self.headerstr) == 0:
  499. return
  500. # clear the processing log
  501. self.ui.logTextBrowser.clear()
  502. self.logText = [] #MAK 20170126
  503. path,filen=os.path.split(str(self.headerstr))
  504. f = open('.gmr.last.path', 'w')
  505. f.write( str(self.headerstr) ) # prompt last file
  506. self.connectGMRDataProcessor()
  507. self.RAWDataProc.readHeaderFile(str(self.headerstr))
  508. # If we got this far, enable all the widgets
  509. self.ui.lcdNumberTauPulse1.setEnabled(True)
  510. self.ui.lcdNumberNuTx.setEnabled(True)
  511. self.ui.lcdNumberTuneuF.setEnabled(True)
  512. self.ui.lcdNumberSampFreq.setEnabled(True)
  513. self.ui.lcdNumberNQ.setEnabled(True)
  514. self.ui.headerFileBox.setEnabled(True)
  515. self.ui.headerFileBox.setChecked( True )
  516. self.ui.headerBox2.setVisible(True)
  517. self.ui.inputRAWParametersBox.setEnabled(True)
  518. self.ui.loadDataPushButton.setEnabled(True)
  519. # make plots as you import the dataset
  520. self.ui.plotImportCheckBox.setEnabled(True)
  521. self.ui.plotImportCheckBox.setChecked(True)
  522. # Update info from the header into the GUI
  523. self.ui.pulseTypeTextBrowser.clear()
  524. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  525. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  526. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  527. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  528. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  529. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  530. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  531. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  532. if self.RAWDataProc.pulseType != "FID":
  533. self.ui.lcdNumberTauPulse2.setEnabled(1)
  534. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  535. self.ui.lcdNumberTauDelay.setEnabled(1)
  536. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  537. self.ui.FIDProcComboBox.clear()
  538. if self.RAWDataProc.pulseType == "4PhaseT1" or self.RAWDataProc.pulseType == "T1":
  539. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  540. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2")
  541. self.ui.FIDProcComboBox.insertItem(2, "Both")
  542. self.ui.FIDProcComboBox.setCurrentIndex (1)
  543. elif self.RAWDataProc.pulseType == "FID":
  544. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  545. self.ui.FIDProcComboBox.setCurrentIndex (0)
  546. def ExportPreprocess(self):
  547. """ This method exports to YAML
  548. """
  549. try:
  550. with open('.akvo.last.yaml.path') as f:
  551. fpath = f.readline()
  552. pass
  553. except IOError as e:
  554. fpath = '.'
  555. fdir = os.path.dirname(fpath)
  556. # Pickle the preprocessed data dictionary
  557. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Processed data (*.yaml)")[0]
  558. spath,filen=os.path.split(str(SaveStr))
  559. f = open('.akvo.last.yaml.path', 'w')
  560. f.write( str(spath) ) # prompt last file
  561. INFO = {}
  562. INFO["headerstr"] = str(self.headerstr)
  563. INFO["pulseType"] = self.RAWDataProc.pulseType
  564. INFO["transFreq"] = self.RAWDataProc.transFreq.tolist()
  565. INFO["pulseLength"] = self.RAWDataProc.pulseLength.tolist()
  566. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance.tolist()
  567. #INFO["samp"] = self.RAWDataProc.samp
  568. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  569. #INFO["deadTime"] = self.RAWDataProc.deadTime
  570. INFO["processed"] = "Akvo v. 1.0, on " + time.strftime("%d/%m/%Y")
  571. # Pulse current info
  572. ip = 0
  573. INFO["Pulses"] = {}
  574. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  575. qq = []
  576. qv = []
  577. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  578. #for istack in self.RAWDataProc.DATADICT["stacks"]:
  579. # print ("stack q", self.RAWDataProc.DATADICT[pulse]["Q"][ipm,istack-1])
  580. qq.append(np.mean( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]) )
  581. qv.append(np.std( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]/self.RAWDataProc.pulseLength[ip] ))
  582. qq = np.array(qq)
  583. qv = np.array(qv)
  584. iQ = np.argsort(np.array(qq))
  585. qq = np.array(qq)[iQ]
  586. print("qq", qq, iQ)
  587. qv = np.array(qv)[iQ]
  588. INFO["Pulses"][pulse] = {}
  589. INFO["Pulses"][pulse]["units"] = "A"
  590. INFO["Pulses"][pulse]["current"] = VectorXr(qq/self.RAWDataProc.pulseLength[ip])
  591. INFO["Pulses"][pulse]["variance"] = VectorXr(qv)
  592. ip += 1
  593. # Data
  594. if self.RAWDataProc.gated == True:
  595. INFO["Gated"] = {}
  596. INFO["Gated"]["abscissa units"] = "ms"
  597. INFO["Gated"]["data units"] = "nT"
  598. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  599. INFO["Gated"][pulse] = {}
  600. INFO["Gated"][pulse]["abscissa"] = VectorXr( self.RAWDataProc.GATEDABSCISSA )
  601. INFO["Gated"][pulse]["windows"] = VectorXr( self.RAWDataProc.GATEDWINDOW )
  602. for ichan in self.RAWDataProc.DATADICT[pulse]["chan"]:
  603. INFO["Gated"][pulse]["Chan. " + str(ichan)] = {}
  604. INFO["Gated"][pulse]["Chan. " + str(ichan)]["STD"] = VectorXr( np.std(self.RAWDataProc.GATED[ichan]["NR"], axis=0) )
  605. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  606. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " CA"] = VectorXr(self.RAWDataProc.GATED[ichan]["CA"][ipm])
  607. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " RE"] = VectorXr(self.RAWDataProc.GATED[ichan]["RE"][ipm])
  608. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IM"] = VectorXr(self.RAWDataProc.GATED[ichan]["IM"][ipm])
  609. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IP"] = VectorXr(self.RAWDataProc.GATED[ichan]["IP"][ipm])
  610. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " NR"] = VectorXr(self.RAWDataProc.GATED[ichan]["NR"][ipm])
  611. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " STD" ] = VectorXr(self.RAWDataProc.GATED[ichan]["SIGMA"][ipm])
  612. # we have gated data
  613. # Window edges
  614. # Window centres
  615. with open(SaveStr, 'w') as outfile:
  616. #for line in self.logText:
  617. # outfile.write(line+"\n")
  618. yaml.dump(self.YamlNode, outfile)
  619. yaml.dump(INFO, outfile) #, default_flow_style=False)
  620. def SavePreprocess(self):
  621. #if "Saved" not in self.YamlNode.Processing.keys():
  622. # self.YamlNode.Processing["Saved"] = []
  623. #self.YamlNode.Processing["Saved"].append(datetime.datetime.now().isoformat())
  624. #self.Log()
  625. import pickle, os
  626. try:
  627. with open('.akvo.last.path') as f:
  628. fpath = f.readline()
  629. pass
  630. except IOError as e:
  631. fpath = '.'
  632. fdir = os.path.dirname(fpath)
  633. # Pickle the preprocessed data dictionary
  634. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Pickle (*.dmp)")
  635. print(SaveStr)
  636. spath,filen=os.path.split(str(SaveStr[0]))
  637. f = open('.akvo.last.path', 'w')
  638. f.write( str(spath) ) # prompt last file
  639. save = open(SaveStr[0], 'wb')
  640. # Add some extra info
  641. INFO = {}
  642. INFO["pulseType"] = self.RAWDataProc.pulseType
  643. INFO["prePulseDelay"] = self.RAWDataProc.prePulseDelay
  644. INFO["interpulseDelay"] = self.RAWDataProc.interpulseDelay
  645. INFO["transFreq"] = self.RAWDataProc.transFreq
  646. INFO["pulseLength"] = self.RAWDataProc.pulseLength
  647. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance
  648. INFO["samp"] = self.RAWDataProc.samp
  649. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  650. INFO["deadTime"] = self.RAWDataProc.deadTime
  651. INFO["transFreq"] = self.RAWDataProc.transFreq
  652. INFO["headerstr"] = str(self.headerstr)
  653. INFO["nDAQVersion"] = self.RAWDataProc.nDAQVersion
  654. INFO["log"] = yaml.dump( self.YamlNode )
  655. TXRX = []
  656. for ir in range(0, self.ui.txRxTable.rowCount() ):
  657. txrx = []
  658. for ic in range(0, self.ui.txRxTable.columnCount() ):
  659. txrx.append( self.ui.txRxTable.item(ir, ic).text() )
  660. TXRX.append(txrx)
  661. INFO["TXRX"] = TXRX
  662. self.RAWDataProc.DATADICT["INFO"] = INFO
  663. print ("TXRX", TXRX)
  664. pickle.dump(self.RAWDataProc.DATADICT, save)
  665. save.close()
  666. # Export XML file suitable for USGS ScienceBase Data Release
  667. def ExportXML(self):
  668. """ This is a filler function for use by USGS collaborators
  669. """
  670. return 42
  671. def OpenPreprocess(self):
  672. import pickle
  673. try:
  674. with open('.akvo.last.path') as f:
  675. fpath = f.readline()
  676. pass
  677. except IOError as e:
  678. fpath = '.'
  679. #filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', '.')
  680. fpath = QtWidgets.QFileDialog.getOpenFileName(self, 'Open preprocessed file', fpath, r"Pickle Files (*.dmp)")[0]
  681. f = open('.akvo.last.path', 'w')
  682. f.write( str(fpath) ) # prompt last file
  683. self.ui.logTextBrowser.clear()
  684. self.logText = []
  685. if len(fpath) == 0:
  686. return
  687. pfile = open(fpath,'rb')
  688. unpickle = pickle.Unpickler(pfile)
  689. self.connectGMRDataProcessor()
  690. self.RAWDataProc.DATADICT = unpickle.load()
  691. # This line causes Akvo to crash, if the header file is no longer there. We don't need to load the
  692. # file. TODO, need to disable "Load Data" in Load command though, as that is no longer possible.
  693. #self.RAWDataProc.readHeaderFile(self.RAWDataProc.DATADICT["INFO"]["headerstr"])
  694. self.headerstr = self.RAWDataProc.DATADICT["INFO"]["headerstr"]
  695. self.RAWDataProc.pulseType = self.RAWDataProc.DATADICT["INFO"]["pulseType"]
  696. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  697. self.RAWDataProc.pulseLength = self.RAWDataProc.DATADICT["INFO"]["pulseLength"]
  698. self.RAWDataProc.TuneCapacitance = self.RAWDataProc.DATADICT["INFO"]["TuneCapacitance"]
  699. self.RAWDataProc.samp = self.RAWDataProc.DATADICT["INFO"]["samp"]
  700. self.RAWDataProc.nPulseMoments = self.RAWDataProc.DATADICT["INFO"]["nPulseMoments"]
  701. self.RAWDataProc.deadTime = self.RAWDataProc.DATADICT["INFO"]["deadTime"]
  702. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  703. self.RAWDataProc.nDAQVersion = self.RAWDataProc.DATADICT["INFO"]["nDAQVersion"]
  704. #self.RAWDataProc.prePulseDelay = self.RAWDataProc.DATADICT["INFO"]["prePulseDelay"]
  705. self.RAWDataProc.dt = 1./self.RAWDataProc.samp
  706. self.dataChan = self.RAWDataProc.DATADICT[ self.RAWDataProc.DATADICT["PULSES"][0] ]["chan"]
  707. # Keep backwards compatibility with prior saved pickles???
  708. #self.ui.logTextBrowser.clear()
  709. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  710. #for a in self.logText:
  711. # self.ui.logTextBrowser.append(str(a))
  712. #self.ui.logTextBrowser
  713. #self.ui.logTextBrowser.clear()
  714. #print ( self.RAWDataProc.DATADICT["INFO"]["log"] )
  715. if "TXRX" in self.RAWDataProc.DATADICT["INFO"].keys():
  716. TXRX = self.RAWDataProc.DATADICT["INFO"]["TXRX"]
  717. self.ui.txRxTable.setRowCount( len(TXRX))
  718. for irow, row in enumerate(TXRX):
  719. for icol, val in enumerate(row):
  720. pCell = QtWidgets.QTableWidgetItem()
  721. pCell.setText( val )
  722. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
  723. self.ui.txRxTable.setItem(irow, icol, pCell)
  724. self.logText = self.RAWDataProc.DATADICT["INFO"]["log"] # YAML
  725. self.YamlNode = AkvoYamlNode( ) #self.logText )
  726. self.YamlNode.Akvo_VERSION = (yaml.load( self.logText, Loader=yaml.Loader )).Akvo_VERSION
  727. AKVO_VERSION = np.array(self.YamlNode.Akvo_VERSION.split("."), dtype=int)
  728. if AKVO_VERSION[0] >= 1 and AKVO_VERSION[1] >= 2 and AKVO_VERSION[2] >= 3:
  729. self.RAWDataProc.interpulseDelay = self.RAWDataProc.DATADICT["INFO"]["interpulseDelay"]
  730. self.YamlNode.Import = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Import)
  731. self.YamlNode.Processing = list((yaml.load( self.logText, Loader=yaml.Loader )).Processing)
  732. self.YamlNode.Stacking = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).Stacking)
  733. self.YamlNode.META = OrderedDict((yaml.load( self.logText, Loader=yaml.Loader )).META)
  734. self.Log()
  735. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  736. #except KeyError:
  737. # pass
  738. # Remove "Saved" and "Loaded" from processing flow
  739. #if "Loaded" not in self.YamlNode.Processing.keys():
  740. # self.YamlNode.Processing["Loaded"] = []
  741. #self.YamlNode.Processing["Loaded"].append(datetime.datetime.now().isoformat())
  742. #self.Log()
  743. # If we got this far, enable all the widgets
  744. self.ui.lcdNumberTauPulse1.setEnabled(True)
  745. self.ui.lcdNumberNuTx.setEnabled(True)
  746. self.ui.lcdNumberTuneuF.setEnabled(True)
  747. self.ui.lcdNumberSampFreq.setEnabled(True)
  748. self.ui.lcdNumberNQ.setEnabled(True)
  749. self.ui.headerFileBox.setEnabled(True)
  750. self.ui.headerFileBox.setChecked( True )
  751. self.headerBoxShrink()
  752. #self.ui.headerBox2.setVisible(True)
  753. self.ui.inputRAWParametersBox.setEnabled(False)
  754. self.ui.loadDataPushButton.setEnabled(True)
  755. # make plots as you import the datasetmost
  756. self.ui.plotImportCheckBox.setEnabled(True)
  757. self.ui.plotImportCheckBox.setChecked(True)
  758. # enable the LCDs
  759. self.ui.lcdNumberFID1Length.setEnabled(1)
  760. self.ui.lcdNumberFID2Length.setEnabled(1)
  761. self.ui.lcdNumberResampFreq.setEnabled(1)
  762. self.ui.lcdTotalDeadTime.setEnabled(1)
  763. # enable META tab
  764. self.ui.METATab.setEnabled(1)
  765. self.ui.siteBox.setEnabled(1)
  766. #self.ui.lcdTotalDeadTime.display( 1e3*self.RAWDataProc.DATADICT["INFO"]["deadTime"] )
  767. self.ui.headerFileTextBrowser.clear( )
  768. self.ui.headerFileTextBrowser.append( self.RAWDataProc.DATADICT["INFO"]["headerstr"] )
  769. if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
  770. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  771. self.ui.lcdTotalDeadTime.display( round(1e3*(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1]), 3) )
  772. print("CALC DEAD", (1e3*(self.RAWDataProc.prePulseDelay))) # - (self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1])), 3) )
  773. if u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
  774. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  775. self.ui.lcdTotalDeadTime.display( 1e3 * (self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 2"]["PULSE_TIMES"][-1]) )
  776. # Update info from the header into the GUI
  777. self.ui.pulseTypeTextBrowser.clear()
  778. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  779. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  780. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  781. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  782. self.ui.lcdNumberResampFreq.display(self.RAWDataProc.samp)
  783. self.ui.lcdNumberSampFreq.display(50000) # TODO, if non GMR is supported, query
  784. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  785. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  786. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  787. if self.RAWDataProc.pulseType != "FID":
  788. self.ui.lcdNumberTauPulse2.setEnabled(1)
  789. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  790. self.ui.lcdNumberTauDelay.setEnabled(1)
  791. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  792. self.ui.FIDProcComboBox.clear()
  793. if self.RAWDataProc.pulseType == "4PhaseT1" or self.RAWDataProc.pulseType == "T1":
  794. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  795. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") #, const QVariant & userData = QVariant() )
  796. self.ui.FIDProcComboBox.insertItem(2, "Both") #, const QVariant & userData = QVariant() )
  797. if len( self.RAWDataProc.DATADICT["PULSES"]) == 2:
  798. self.ui.FIDProcComboBox.setCurrentIndex (2)
  799. elif self.RAWDataProc.DATADICT["PULSES"][0] == "Pulse 1":
  800. self.ui.FIDProcComboBox.setCurrentIndex (0)
  801. else:
  802. self.ui.FIDProcComboBox.setCurrentIndex (1)
  803. elif self.RAWDataProc.pulseType == "FID":
  804. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  805. self.ui.FIDProcComboBox.setCurrentIndex (0)
  806. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  807. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  808. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  809. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  810. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  811. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  812. self.enableAll()
  813. def loadRAW(self):
  814. #################################################
  815. # Check to make sure we are ready to process
  816. # Header
  817. if self.RAWDataProc == None:
  818. err_msg = "You need to load a header first."
  819. reply = QtGui.QMessageBox.critical(self, 'Error',
  820. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  821. return
  822. # Stacks
  823. try:
  824. self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]"))
  825. except:
  826. err_msg = "You need to set your stacks correctly.\n" + \
  827. "This should be a Python Numpy interpretable list\n" + \
  828. "of stack indices. For example 1:24 or 1:4,8:24"
  829. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  830. return
  831. # Data Channels
  832. #Chan = np.arange(0,9,1)
  833. try:
  834. self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]"))
  835. except:
  836. #QMessageBox messageBox;
  837. #messageBox.critical(0,"Error","An error has occured !");
  838. #messageBox.setFixedSize(500,200);
  839. #quit_msg = "Are you sure you want to exit the program?"
  840. #reply = QtGui.QMessageBox.question(self, 'Message',
  841. # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  842. err_msg = "You need to set your data channels correctly.\n" + \
  843. "This should be a Python Numpy interpretable list\n" + \
  844. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  845. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  846. "1:3 is not inclusive of 3 and is the same as 1,2 "
  847. reply = QtGui.QMessageBox.critical(self, 'Error',
  848. err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
  849. return
  850. #############################
  851. # Reference Channels
  852. # TODO make sure no overlap between data and ref channels
  853. self.refChan = np.array( () )
  854. if str(self.ui.refChanLineEdit.text()): # != "none":
  855. try:
  856. self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]"))
  857. except:
  858. err_msg = "You need to set your reference channels correctly.\n" + \
  859. "This should be a Python Numpy interpretable list\n" + \
  860. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  861. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  862. "1:3 is not inclusive of 3 and is the same as 1,2 "
  863. QtGui.QMessageBox.critical(self, 'Error', err_msg)
  864. return
  865. #####################################################
  866. # Load data
  867. self.lock("loading RAW GMR dataset")
  868. if self.RAWDataProc.pulseType == "FID":
  869. self.procThread = thread.start_new_thread(self.RAWDataProc.loadFIDData, \
  870. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  871. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  872. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  873. elif self.RAWDataProc.pulseType == "4PhaseT1":
  874. self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  875. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  876. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  877. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  878. elif self.RAWDataProc.pulseType == "T1":
  879. self.procThread = thread.start_new_thread(self.RAWDataProc.loadT1Data, \
  880. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  881. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  882. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  883. #self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  884. # (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  885. # str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  886. # 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  887. self.YamlNode.Import["GMR Header"] = self.headerstr
  888. self.YamlNode.Import["opened"] = datetime.datetime.now().isoformat()
  889. self.YamlNode.Import["pulse Type"] = str(self.RAWDataProc.pulseType)
  890. self.YamlNode.Import["stacks"] = self.procStacks.tolist()
  891. self.YamlNode.Import["data channels"] = self.dataChan.tolist()
  892. self.YamlNode.Import["reference channels"] = self.refChan.tolist()
  893. self.YamlNode.Import["pulse records"] = str(self.ui.FIDProcComboBox.currentText())
  894. self.YamlNode.Import["instrument dead time"] = (1e-3 * self.ui.DeadTimeSpinBox.value( ))
  895. self.Log ( )
  896. # enable META tab
  897. self.ui.METATab.setEnabled(1)
  898. self.ui.siteBox.setEnabled(1)
  899. # should be already done
  900. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  901. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  902. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  903. #self.ui.ProcessedBox.setEnabled(True)
  904. self.ui.lcdNumberFID1Length.setEnabled(1)
  905. self.ui.lcdNumberFID2Length.setEnabled(1)
  906. self.ui.lcdNumberResampFreq.setEnabled(1)
  907. self.ui.lcdTotalDeadTime.setEnabled(1)
  908. self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) )
  909. #self.ui.lcdTotalDeadTime.display( round(1e3*(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1]), 3) )
  910. #self.ui.lcdNumberFID1Length.display(0)
  911. #self.ui.lcdNumberFID2Length.display(0)
  912. #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  913. self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget)
  914. self.ui.mplwidget.draw()
  915. def Log(self):
  916. #for line in yaml.dump(self.YamlNode, default_flow_style=False):
  917. #for line in nlogText:
  918. # self.ui.logTextBrowser.append( line )
  919. # self.logText.append( line )
  920. self.ui.logTextBrowser.clear()
  921. self.ui.logTextBrowser.append( yaml.dump(self.YamlNode ))
  922. def disable(self):
  923. self.ui.inputRAWParametersBox.setEnabled(False)
  924. self.ui.BandPassBox.setEnabled(False)
  925. self.ui.downSampleGroupBox.setEnabled(False)
  926. self.ui.windowFilterGroupBox.setEnabled(False)
  927. self.ui.harmonicBox.setEnabled(False)
  928. # self.ui.despikeGroupBox.setEnabled(False)
  929. self.ui.adaptBox.setEnabled(False)
  930. self.ui.adaptFDBox.setEnabled(False)
  931. self.ui.qCalcGroupBox.setEnabled(False)
  932. self.ui.FDSmartStackGroupBox.setEnabled(False)
  933. self.ui.sumDataBox.setEnabled(False)
  934. self.ui.qdGroupBox.setEnabled(False)
  935. self.ui.gateBox.setEnabled(False)
  936. def enableAll(self):
  937. self.enableDSP()
  938. self.enableQC()
  939. def enableDSP(self):
  940. # Bandpass filter
  941. self.ui.BandPassBox.setEnabled(True)
  942. self.ui.BandPassBox.setChecked(True)
  943. self.ui.bandPassGO.setEnabled(False) # need to design first
  944. self.ui.plotBP.setEnabled(True)
  945. self.ui.plotBP.setChecked(True)
  946. # downsample
  947. self.ui.downSampleGroupBox.setEnabled(True)
  948. self.ui.downSampleGroupBox.setChecked(True)
  949. # window
  950. self.ui.windowFilterGroupBox.setEnabled(True)
  951. self.ui.windowFilterGroupBox.setChecked(True)
  952. # Despike
  953. # self.ui.despikeGroupBox.setEnabled(True)
  954. # self.ui.despikeGroupBox.setChecked(False)
  955. # Adaptive filtering
  956. self.ui.adaptBox.setEnabled(True)
  957. self.ui.adaptBox.setChecked(True)
  958. # FD Adaptive filtering
  959. self.ui.adaptFDBox.setEnabled(True)
  960. self.ui.adaptFDBox.setChecked(False)
  961. # Harmonic
  962. self.ui.harmonicBox.setEnabled(True)
  963. self.ui.harmonicBox.setChecked(True)
  964. self.LCDHarmonics()
  965. self.LCDHarmonics2()
  966. # sum group box
  967. try:
  968. if len(self.dataChan) > 1:
  969. self.ui.sumDataBox.setEnabled(True)
  970. self.ui.sumDataBox.setChecked(False)
  971. except:
  972. pass
  973. # Quadrature Detect
  974. self.ui.qdGroupBox.setEnabled(True)
  975. self.ui.qdGroupBox.setChecked(True)
  976. self.enableQC()
  977. def enableQC(self):
  978. # Q calc
  979. self.ui.qCalcGroupBox.setEnabled(True)
  980. self.ui.qCalcGroupBox.setChecked(True)
  981. # FD SmartStack
  982. self.ui.FDSmartStackGroupBox.setEnabled(True)
  983. self.ui.FDSmartStackGroupBox.setChecked(True)
  984. # Quadrature detect
  985. try:
  986. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  987. np.shape(self.RAWDataProc.DATADICT[pulse]["Q"])
  988. self.RAWDataProc.DATADICT["stack"]
  989. self.ui.qdGroupBox.setEnabled(True)
  990. self.ui.qdGroupBox.setChecked(True)
  991. except:
  992. self.ui.qdGroupBox.setEnabled(False)
  993. self.ui.qdGroupBox.setChecked(False)
  994. # Gating
  995. try:
  996. self.RAWDataProc.DATADICT["CA"]
  997. self.ui.gateBox.setEnabled(True)
  998. self.ui.gateBox.setChecked(True)
  999. except:
  1000. self.ui.gateBox.setEnabled(False)
  1001. self.ui.gateBox.setChecked(False)
  1002. def despikeFilter(self):
  1003. self.lock("despike filter")
  1004. thread.start_new_thread(self.RAWDataProc.despike, \
  1005. (self.ui.windowSpinBox.value(), \
  1006. self.ui.thresholdSpinBox.value(), \
  1007. str(self.ui.replComboBox.currentText()), \
  1008. self.ui.rollOnSpinBox.value(), \
  1009. self.ui.despikeInterpWinSpinBox.value(),
  1010. self.ui.mplwidget))
  1011. def calcQ(self):
  1012. if "Calc Q" not in self.YamlNode.Stacking.keys():
  1013. #print("In CalcQ", yaml.dump(self.YamlNode.Processing) )
  1014. self.YamlNode.Stacking["Calc Q"] = True
  1015. #print( yaml.dump(self.YamlNode.Processing) )
  1016. self.Log()
  1017. else:
  1018. err_msg = "Q values have already been calculated"
  1019. reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1020. err_msg)
  1021. return
  1022. self.lock("pulse moment calculation")
  1023. thread.start_new_thread(self.RAWDataProc.effectivePulseMoment, \
  1024. (self.ui.CentralVSpinBox.value(), \
  1025. self.ui.mplwidget))
  1026. def harmonicModel(self):
  1027. self.lock("harmonic noise modelling")
  1028. Harm = OrderedDict()
  1029. Harm["STEP"] = "Harmonic modelling"
  1030. Harm["NF"] = str( self.ui.NHarmonicsFreqsSpin.value() )
  1031. Harm["Segments"] = str( self.ui.NSegments.value() )
  1032. Harm["Proc. ref."] = self.ui.harmRef.isChecked()
  1033. if self.ui.searchAll.currentText() == "All":
  1034. Harm["search"] = self.ui.searchAll.currentText()
  1035. Search = False
  1036. else:
  1037. #Harm["search"] = self.ui.searchAll.currentText()
  1038. Harm["search"] = str(self.ui.Nsearch.value())
  1039. Search = self.ui.Nsearch.value()
  1040. if self.ui.boundsCheck.isChecked():
  1041. Harm["Bounds"] = str(self.ui.bounds.value())
  1042. Bounds = self.ui.bounds.value()
  1043. else:
  1044. Harm["Bounds"] = self.ui.boundsCheck.isChecked()
  1045. Bounds = 0
  1046. Harm["f0K1"] = str( self.ui.f0K1Spin.value() )
  1047. Harm["f0KN"] = str( self.ui.f0KNSpin.value() )
  1048. Harm["f0Ks"] = str( self.ui.f0KsSpin.value() )
  1049. Harm["f0"] = str( self.ui.f0Spin.value() )
  1050. if self.ui.NHarmonicsFreqsSpin.value() > 1:
  1051. Harm["f1K1"] = str( self.ui.f1K1Spin.value() )
  1052. Harm["f1KN"] = str( self.ui.f1KNSpin.value() )
  1053. Harm["f1Ks"] = str( self.ui.f1KsSpin.value() )
  1054. Harm["f1"] = str( self.ui.f1Spin.value() )
  1055. self.YamlNode.Processing.append(Harm)
  1056. self.Log()
  1057. thread.start_new_thread(self.RAWDataProc.harmonicModel, \
  1058. ( \
  1059. self.ui.NHarmonicsFreqsSpin.value(), \
  1060. self.ui.f0Spin.value(), \
  1061. self.ui.f0K1Spin.value(), \
  1062. self.ui.f0KNSpin.value(), \
  1063. self.ui.f0KsSpin.value(), \
  1064. self.ui.NSegments.value(), \
  1065. self.ui.f1Spin.value(), \
  1066. self.ui.f1K1Spin.value(), \
  1067. self.ui.f1KNSpin.value(), \
  1068. self.ui.f1KsSpin.value(), \
  1069. Search, \
  1070. Bounds, \
  1071. self.ui.harmRef.isChecked(), \
  1072. self.ui.plotHarmonic.isChecked(), \
  1073. self.ui.mplwidget \
  1074. ) \
  1075. )
  1076. def FDSmartStack(self):
  1077. if "TD stack" not in self.YamlNode.Stacking.keys():
  1078. self.YamlNode.Stacking["TD stack"] = {}
  1079. self.YamlNode.Stacking["TD stack"]["outlier"] = str( self.ui.outlierTestCB.currentText() )
  1080. self.YamlNode.Stacking["TD stack"]["cutoff"] = str( self.ui.MADCutoff.value() )
  1081. self.Log()
  1082. else:
  1083. err_msg = "TD noise cancellation has already been applied!"
  1084. reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1085. err_msg)
  1086. return
  1087. self.lock("time-domain smart stack")
  1088. thread.start_new_thread(self.RAWDataProc.TDSmartStack, \
  1089. (str(self.ui.outlierTestCB.currentText()), \
  1090. self.ui.MADCutoff.value(),
  1091. self.ui.mplwidget))
  1092. def adaptFilter(self):
  1093. self.lock("TD noise cancellation filter")
  1094. # Log processing
  1095. Adapt = OrderedDict()
  1096. Adapt["STEP"] = "TD noise cancellation"
  1097. #print(Adapt)
  1098. Adapt["n_Taps"] = str(self.ui.MTapsSpinBox.value())
  1099. Adapt["lambda"] = str(self.ui.adaptLambdaSpinBox.value())
  1100. Adapt["truncate"] = str(self.ui.adaptTruncateSpinBox.value())
  1101. Adapt["mu"] = str(self.ui.adaptMuSpinBox.value())
  1102. Adapt["PCA"] = str(self.ui.PCAComboBox.currentText())
  1103. #print(Adapt)
  1104. self.YamlNode.Processing.append(Adapt)
  1105. self.Log( )
  1106. thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
  1107. (self.ui.MTapsSpinBox.value(), \
  1108. self.ui.adaptLambdaSpinBox.value(), \
  1109. self.ui.adaptTruncateSpinBox.value(), \
  1110. self.ui.adaptMuSpinBox.value(), \
  1111. str(self.ui.PCAComboBox.currentText()), \
  1112. self.ui.mplwidget))
  1113. def sumDataChans(self):
  1114. self.lock("Summing data channels")
  1115. Sum = OrderedDict()
  1116. Sum["STEP"] = "Channel sum"
  1117. self.YamlNode.Processing.append(Sum)
  1118. self.Log( )
  1119. self.dataChan = [self.dataChan[0]]
  1120. self.ui.sumDataBox.setEnabled(False)
  1121. thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) )
  1122. def adaptFilterFD(self):
  1123. self.lock("FD noise cancellation filter")
  1124. thread.start_new_thread(self.RAWDataProc.adaptiveFilterFD, \
  1125. (str(self.ui.windowTypeComboBox.currentText()), \
  1126. self.ui.windowBandwidthSpinBox.value(), \
  1127. self.ui.CentralVSpinBox.value(), \
  1128. self.ui.mplwidget))
  1129. def logSite(self):
  1130. self.YamlNode.META["Location"] = self.ui.locEdit.text()
  1131. self.YamlNode.META["Coordinates"] = OrderedDict()
  1132. self.YamlNode.META["Coordinates"]["UTM"] = self.ui.UTMzone.currentText()
  1133. self.YamlNode.META["Coordinates"]["LatBand"] = self.ui.latBand.currentText()
  1134. self.YamlNode.META["Coordinates"]["ellipsoid"] = self.ui.ellipsoid.currentText()
  1135. self.YamlNode.META["DateTime"] = self.ui.dateEdit.date().toString("yyyy-MM-dd") + "T" + str( self.ui.timeEdit.time().toString("hh:mm") )
  1136. self.YamlNode.META["Temp"] = self.ui.tempSpinBox.value()
  1137. self.YamlNode.META["B_0"] = OrderedDict()
  1138. self.YamlNode.META["B_0"]["inc"] = self.ui.incSpinBox.value()
  1139. self.YamlNode.META["B_0"]["dec"] = self.ui.decSpinBox.value()
  1140. self.YamlNode.META["B_0"]["intensity"] = self.ui.intensitySpinBox.value()
  1141. self.YamlNode.META["Field Notes"] = self.ui.txtComments.toPlainText()
  1142. self.YamlNode.META["Loops"] = OrderedDict()
  1143. for loop in self.loops:
  1144. print(self.loops[loop])
  1145. self.YamlNode.META["Loops"][loop] = loop + ".yml"
  1146. self.Log()
  1147. def bandPassFilter(self):
  1148. self.lock("bandpass filter")
  1149. # Log processing
  1150. Band = OrderedDict()
  1151. Band["STEP"] = "Bandpass filter"
  1152. Band["central_nu"] = str(self.ui.CentralVSpinBox.value())
  1153. Band["passband"] = str(self.ui.passBandSpinBox.value())
  1154. Band["stopband"] = str(self.ui.stopBandSpinBox.value())
  1155. Band["gpass"] = str(self.ui.gpassSpinBox.value())
  1156. Band["gstop"] = str(self.ui.gstopSpinBox.value())
  1157. Band["type"] = str(self.ui.fTypeComboBox.currentText())
  1158. self.YamlNode.Processing.append(Band)
  1159. self.Log( )
  1160. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
  1161. self.ui.lcdTotalDeadTime.display( nv )
  1162. thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
  1163. (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
  1164. def downsample(self):
  1165. self.lock("resampling")
  1166. # Log processing
  1167. Resample = OrderedDict()
  1168. Resample["STEP"] = "Resample"
  1169. Resample["downsample factor"] = str(self.ui.downSampleSpinBox.value())
  1170. Resample["truncate length"] = str(self.ui.truncateSpinBox.value())
  1171. self.YamlNode.Processing.append(Resample)
  1172. self.Log( )
  1173. thread.start_new_thread(self.RAWDataProc.downsample, \
  1174. (self.ui.truncateSpinBox.value(), \
  1175. self.ui.downSampleSpinBox.value(), \
  1176. self.ui.dsPlot.isChecked(), \
  1177. self.ui.mplwidget))
  1178. def quadDet(self):
  1179. method = ['trf','dogbox','lm'][int(self.ui.QDMethod.currentIndex())]
  1180. loss = ['linear','soft_l1','cauchy','huber'][int(self.ui.QDLoss.currentIndex())]
  1181. # allow overwrite of Quad Det.
  1182. self.YamlNode.Stacking["Quadrature detection"] = {}
  1183. self.YamlNode.Stacking["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1184. self.YamlNode.Stacking["Quadrature detection"]["method"] = method
  1185. self.YamlNode.Stacking["Quadrature detection"]["loss"] = loss
  1186. self.Log()
  1187. #if "Quadrature detection" not in self.YamlNode.Processing.keys():
  1188. # self.YamlNode.Processing["Quadrature detection"] = {}
  1189. # self.YamlNode.Processing["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1190. # self.Log()
  1191. #else:
  1192. # self.YamlNode.Processing["Quadrature detection"] = {}
  1193. # self.YamlNode.Processing["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1194. # self.Log()
  1195. #err_msg = "Quadrature detection has already been done!"
  1196. #reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1197. # err_msg)
  1198. #return
  1199. self.lock("quadrature detection")
  1200. thread.start_new_thread(self.RAWDataProc.quadDet, \
  1201. (self.ui.trimSpin.value(), method, loss, self.ui.mplwidget))
  1202. self.ui.plotQD.setEnabled(True)
  1203. def plotQD(self):
  1204. self.lock("plot QD")
  1205. thread.start_new_thread(self.RAWDataProc.plotQuadDet, \
  1206. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget))
  1207. def gateIntegrate(self):
  1208. if "Gate integrate" not in self.YamlNode.Stacking.keys():
  1209. self.YamlNode.Stacking["Gate integrate"] = {}
  1210. self.YamlNode.Stacking["Gate integrate"]["gpd"] = str(self.ui.GPDspinBox.value( ) )
  1211. self.Log()
  1212. self.lock("gate integration")
  1213. thread.start_new_thread(self.RAWDataProc.gateIntegrate, \
  1214. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), self.ui.mplwidget))
  1215. self.ui.actionExport_Preprocessed_Dataset.setEnabled(True)
  1216. self.ui.plotGI.setEnabled(True)
  1217. def plotGI(self):
  1218. self.lock("plot gate integrate")
  1219. thread.start_new_thread(self.RAWDataProc.plotGateIntegrate, \
  1220. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), \
  1221. self.ui.QDType_2.currentIndex(), self.ui.mplwidget))
  1222. def designFilter(self):
  1223. [bord, fe] = self.RAWDataProc.designFilter( \
  1224. self.ui.CentralVSpinBox.value(), \
  1225. self.ui.passBandSpinBox.value(), \
  1226. self.ui.stopBandSpinBox.value(), \
  1227. self.ui.gpassSpinBox.value(), \
  1228. self.ui.gstopSpinBox.value(), \
  1229. str(self.ui.fTypeComboBox.currentText()),
  1230. self.ui.mplwidget
  1231. )
  1232. self.ui.lcdNumberFilterOrder.display(bord)
  1233. self.ui.lcdNumberFTauDead.display(1e3*fe)
  1234. self.ui.bandPassGO.setEnabled(1)
  1235. ################################################################
  1236. # Hack for MacOS to force refresh of group box and plot
  1237. # this has an undesirable effect that it causes the groupbox to 'jump' up
  1238. # TODO come up with a better solution
  1239. self.ui.mplwidget.hide()
  1240. self.ui.mplwidget.show()
  1241. self.ui.BandPassBox.hide()
  1242. self.ui.BandPassBox.show()
  1243. def windowFilter(self):
  1244. self.lock("window filter")
  1245. # Log processing
  1246. Window = OrderedDict()
  1247. Window["STEP"] = "Window filter"
  1248. Window["type"] = str(self.ui.windowTypeComboBox.currentText())
  1249. Window["width"] = str(self.ui.windowBandwidthSpinBox.value())
  1250. Window["centre"] = str(self.ui.CentralVSpinBox.value() )
  1251. Window["trim"] = str(self.ui.windowTrim.isChecked())
  1252. self.YamlNode.Processing.append(Window)
  1253. self.Log( )
  1254. if self.ui.windowTrim.isChecked():
  1255. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdWinDead.value()
  1256. self.ui.lcdTotalDeadTime.display( nv )
  1257. thread.start_new_thread(self.RAWDataProc.windowFilter, \
  1258. (str(self.ui.windowTypeComboBox.currentText()), \
  1259. self.ui.windowBandwidthSpinBox.value(), \
  1260. self.ui.CentralVSpinBox.value(), \
  1261. self.ui.windowTrim.isChecked(), \
  1262. self.ui.mplwidget))
  1263. def designFDFilter(self):
  1264. mPulse = "None"
  1265. if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
  1266. mPulse = u"Pulse 1"
  1267. elif u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
  1268. mPulse = u"Pulse 2"
  1269. a,b,c,d,dead,ndead = self.RAWDataProc.computeWindow( \
  1270. mPulse,
  1271. self.ui.windowBandwidthSpinBox.value(), \
  1272. self.ui.CentralVSpinBox.value(), \
  1273. str(self.ui.windowTypeComboBox.currentText()), \
  1274. self.ui.mplwidget )
  1275. self.ui.lcdWinDead.display(dead)
  1276. ################################################################
  1277. # Hack for MacOS to force refresh of group box and plot
  1278. # this has an undesirable effect that it causes the groupbox to 'jump' up
  1279. # TODO come up with a better solution
  1280. self.ui.mplwidget.hide()
  1281. self.ui.mplwidget.show()
  1282. self.ui.windowFilterGroupBox.hide()
  1283. self.ui.windowFilterGroupBox.show()
  1284. def updateProgressBar(self, percent):
  1285. self.ui.barProgress.setValue(percent)
  1286. def updateProc(self):
  1287. if str(self.ui.FIDProcComboBox.currentText()) == "Pulse 1":
  1288. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  1289. elif str(self.ui.FIDProcComboBox.currentText()) == "Pulse 2":
  1290. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  1291. else:
  1292. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  1293. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  1294. self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  1295. def doneStatus(self): # unlocks GUI
  1296. self.ui.statusbar.clearMessage ( )
  1297. self.ui.barProgress.hide()
  1298. self.updateProc()
  1299. self.enableAll()
  1300. def lock(self, string):
  1301. self.ui.statusbar.showMessage ( string )
  1302. self.ui.barProgress.show()
  1303. self.ui.barProgress.setValue(0)
  1304. self.disable()
  1305. def unlock(self):
  1306. self.ui.statusbar.clearMessage ( )
  1307. self.ui.barProgress.hide()
  1308. self.enableAll()
  1309. def done(self):
  1310. self.ui.statusbar.showMessage ( "" )
  1311. ################################################################
  1312. ################################################################
  1313. # Boiler plate main function
  1314. import pkg_resources
  1315. from pkg_resources import resource_string
  1316. import matplotlib.image as mpimg
  1317. import matplotlib.pyplot as plt
  1318. from akvo.gui.logo import plotLogo
  1319. def main():
  1320. # splash screen logo
  1321. logo = pkg_resources.resource_filename(__name__, 'akvo.png')
  1322. logo2 = pkg_resources.resource_filename(__name__, 'akvo2.png')
  1323. qApp = QtWidgets.QApplication(sys.argv)
  1324. ssplash = True
  1325. if ssplash:
  1326. pixmap = QtGui.QPixmap(logo)
  1327. splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  1328. splash.show()
  1329. aw = ApplicationWindow()
  1330. #img=mpimg.imread(logo)
  1331. for ax in [ aw.ui.mplwidget ]:
  1332. ax.fig.clear()
  1333. subplot = ax.fig.add_subplot(211)
  1334. # old logo plot
  1335. ax.fig.patch.set_facecolor( None )
  1336. ax.fig.patch.set_alpha( .0 )
  1337. #subplot.imshow(img)
  1338. #ax.fig.patch.set_visible(False)
  1339. subplot.axis('off')
  1340. plotLogo(subplot)
  1341. subplot.xaxis.set_major_locator(plt.NullLocator())
  1342. subplot.yaxis.set_major_locator(plt.NullLocator())
  1343. subplot2 = ax.fig.add_subplot(212)
  1344. subplot2.text(0.5, 1.,'surface NMR workbench',
  1345. horizontalalignment='center',
  1346. verticalalignment='center',
  1347. size=22,
  1348. transform = subplot2.transAxes)
  1349. subplot2.xaxis.set_major_locator(plt.NullLocator())
  1350. subplot2.yaxis.set_major_locator(plt.NullLocator())
  1351. subplot2.axis('off')
  1352. ax.draw()
  1353. if ssplash:
  1354. splash.showMessage("Loading modules")
  1355. splash.finish(aw)
  1356. #time.sleep(1)
  1357. aw.setWindowTitle("Akvo v"+str(VERSION))
  1358. aw.show()
  1359. qApp.setWindowIcon(QtGui.QIcon(logo2))
  1360. sys.exit(qApp.exec_())
  1361. if __name__ == "__main__":
  1362. main()