Surface NMR processing and inversion GUI
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

akvoGUI.py 71KB

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