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 98KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228
  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_qt5 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.gui.redirect_ui import Ui_callScript
  20. from akvo.gui.callScript import callScript
  21. from akvo.tressel import mrsurvey
  22. from pyLemma import LemmaCore
  23. from pyLemma import FDEM1D
  24. from pyLemma import Merlin
  25. VERSION = pkg_resources.require("Akvo")[0].version
  26. GAMMAH = 42.577478518 * 1e-3 # Hz nT
  27. # Writes out numpy arrays into Eigen vectors as serialized by Lemma
  28. class MatrixXr(yaml.YAMLObject):
  29. yaml_tag = u'MatrixXr'
  30. def __init__(self, rows, cols, data):
  31. self.rows = rows
  32. self.cols = cols
  33. self.data = np.zeros((rows,cols))
  34. def __repr__(self):
  35. return "%s(rows=%r, cols=%r, data=%r)" % (self.__class__.__name__, self.rows, self.cols, self.data)
  36. class VectorXr(yaml.YAMLObject):
  37. yaml_tag = r'VectorXr'
  38. def __init__(self, array):
  39. self.size = np.shape(array)[0]
  40. self.data = array.tolist()
  41. def __repr__(self):
  42. # Converts to numpy array on import
  43. return "np.array(%r)" % (self.data)
  44. def setup_yaml():
  45. """ https://stackoverflow.com/a/8661021 """
  46. represent_dict_order = lambda self, data: self.represent_mapping('tag:yaml.org,2002:map', data.items())
  47. yaml.add_representer(OrderedDict, represent_dict_order)
  48. setup_yaml()
  49. class AkvoYamlNode(yaml.YAMLObject):
  50. yaml_tag = u'AkvoData'
  51. def __init__(self):
  52. self.Akvo_VERSION = VERSION
  53. self.Import = OrderedDict() # {}
  54. self.Processing = [] # OrderedDict()
  55. self.Stacking = OrderedDict()
  56. self.META = OrderedDict()
  57. def __repr__(self):
  58. return "%s(name=%r, Akvo_VERSION=%r, Import=%r, Processing=%r, self.Stacking=%r, self.META=%r)" % (
  59. self.__class__.__name__, self.Akvo_VERSION, self.Import, self.Processing, self.Stacking, self.META )
  60. try:
  61. import thread
  62. except ImportError:
  63. import _thread as thread #Py3K compatibility
  64. class MyPopup(QtWidgets.QWidget):
  65. def __init__(self, name):
  66. super().__init__()
  67. self.name = name
  68. self.initUI()
  69. def initUI(self):
  70. lblName = QtWidgets.QLabel(self.name, self)
  71. class ApplicationWindow(QtWidgets.QMainWindow):
  72. def __init__(self):
  73. super().__init__()
  74. #QtWidgets.QMainWindow.__init__(self)
  75. self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
  76. # alternative to calling pyuic
  77. #self.ui = uic.loadUi('main.ui', self)
  78. self.ui = Ui_MainWindow()
  79. self.ui.setupUi(self)
  80. self.RAWDataProc = None
  81. self.YamlNode = AkvoYamlNode()
  82. # initialise some stuff
  83. self.ui.lcdNumberTauPulse2.setEnabled(0)
  84. self.ui.lcdNumberTauPulse1.setEnabled(0)
  85. self.ui.lcdNumberNuTx.setEnabled(0)
  86. self.ui.lcdNumberTuneuF.setEnabled(0)
  87. self.ui.lcdNumberSampFreq.setEnabled(0)
  88. self.ui.lcdNumberTauDelay.setEnabled(0)
  89. self.ui.lcdNumberNQ.setEnabled(0)
  90. self.logText = []
  91. #######################
  92. ##################### #
  93. ## Make connections # #
  94. ##################### #
  95. #######################
  96. ##############
  97. # Menu items #
  98. ##############
  99. self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset)
  100. self.ui.actionLoad_MIDI.triggered.connect(self.loadMIDI2Dataset)
  101. self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess)
  102. self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess)
  103. self.ui.actionExport_Preprocessed_Dataset.setEnabled(False)
  104. self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess)
  105. self.ui.actionAboutAkvo.triggered.connect(self.about)
  106. ###########
  107. # Buttons #
  108. ###########
  109. #self.ui.loadDataPushButton.pressed.connect(self.loadRAW)
  110. self.ui.sumDataGO.pressed.connect( self.sumDataChans )
  111. self.ui.bandPassGO.pressed.connect( self.bandPassFilter )
  112. self.ui.filterDesignPushButton.pressed.connect( self.designFilter )
  113. self.ui.fdDesignPushButton.pressed.connect( self.designFDFilter )
  114. self.ui.downSampleGO.pressed.connect( self.downsample )
  115. self.ui.windowFilterGO.pressed.connect( self.windowFilter )
  116. self.ui.adaptGO.pressed.connect( self.adaptFilter )
  117. self.ui.adaptFDGO.pressed.connect( self.adaptFilterFD )
  118. self.ui.qdGO.pressed.connect( self.quadDet )
  119. self.ui.gateIntegrateGO.pressed.connect( self.gateIntegrate )
  120. self.ui.calcQGO.pressed.connect( self.calcQ )
  121. self.ui.FDSmartStackGO.pressed.connect( self.FDSmartStack )
  122. self.ui.harmonicGO.pressed.connect( self.harmonicModel )
  123. self.ui.K0Data.pressed.connect( self.K0DataSelect )
  124. self.ui.invDataButton.pressed.connect( self.invDataSelect )
  125. self.ui.invKernelButton.pressed.connect( self.invKernelSelect )
  126. self.ui.f0K1Spin.valueChanged.connect( self.LCDHarmonics )
  127. self.ui.f0KNSpin.valueChanged.connect( self.LCDHarmonics )
  128. self.ui.f0KsSpin.valueChanged.connect( self.LCDHarmonics )
  129. self.ui.f0Spin.valueChanged.connect( self.LCDHarmonics )
  130. self.ui.NHarmonicsFreqsSpin.valueChanged.connect( self.LCDHarmonics2 )
  131. self.ui.f1K1Spin.valueChanged.connect( self.LCDHarmonics2 )
  132. self.ui.f1KNSpin.valueChanged.connect( self.LCDHarmonics2 )
  133. self.ui.f1KsSpin.valueChanged.connect( self.LCDHarmonics2 )
  134. self.ui.f1Spin.valueChanged.connect( self.LCDHarmonics2 )
  135. self.ui.plotQD.setEnabled(False)
  136. self.ui.plotQD.pressed.connect( self.plotQD )
  137. self.ui.plotGI.setEnabled(False)
  138. self.ui.plotGI.pressed.connect( self.plotGI )
  139. # balance the Larmor frequency info and Tx off resonance info
  140. self.ui.intensitySpinBox.valueChanged.connect( self.adjustLarmor )
  141. self.ui.txv.valueChanged.connect( self.adjustB0 )
  142. self.ui.larmorv.valueChanged.connect( self.adjustB02 )
  143. # Kernel
  144. self.ui.calcK0.pressed.connect( self.calcK0 )
  145. # Inversion
  146. self.ui.invertButton.pressed.connect( self.QTInv )
  147. # META
  148. self.ui.locEdit.editingFinished.connect( self.logSite )
  149. self.ui.UTMzone.currentIndexChanged.connect( self.logSite )
  150. self.ui.latBand.currentIndexChanged.connect( self.logSite )
  151. self.ui.ellipsoid.currentIndexChanged.connect( self.logSite )
  152. self.ui.incSpinBox.valueChanged.connect( self.logSite )
  153. self.ui.decSpinBox.valueChanged.connect( self.logSite )
  154. self.ui.intensitySpinBox.valueChanged.connect( self.logSite )
  155. self.ui.tempSpinBox.valueChanged.connect( self.logSite )
  156. self.ui.timeEdit.timeChanged.connect( self.logSite )
  157. self.ui.dateEdit.dateChanged.connect( self.logSite )
  158. # this may call the yaml stuff too often...
  159. self.ui.txtComments.textChanged.connect( self.logSite )
  160. self.ui.plotLoops.pressed.connect( self.plotLoops2 )
  161. self.ui.removeLoopButton.pressed.connect( self.removeLoop )
  162. # Loops
  163. self.ui.addLoopButton.pressed.connect( self.loopAdd )
  164. self.loops = {}
  165. # hide header info box
  166. #self.ui.headerFileBox.setVisible(False)
  167. self.ui.headerFileBox.clicked.connect( self.headerBoxShrink )
  168. self.ui.headerBox2.setVisible(False)
  169. # Clean up the tab widget
  170. self.ui.actionPreprocessing.triggered.connect(self.addPreProc)
  171. self.ui.actionModelling.triggered.connect(self.addModelling)
  172. self.ui.actionInversion.triggered.connect(self.addInversion)
  173. # tabs
  174. #self.ui.ProcTabs.tabCloseRequested.connect( self.closeTabs )
  175. #self.ui.ProcTabs.tabBar().setTabButton(7, QtWidgets.QTabBar.RightSide,None)
  176. self.ui.ProcTabs.removeTab(4)
  177. self.ui.ProcTabs.removeTab(4)
  178. self.ui.ProcTabs.removeTab(4)
  179. self.ui.ProcTabs.removeTab(4)
  180. #self.ui.LoadTab.close( )
  181. # Add progressbar to statusbar
  182. self.ui.barProgress = QtWidgets.QProgressBar()
  183. self.ui.statusbar.addPermanentWidget(self.ui.barProgress, 0);
  184. self.ui.barProgress.setMaximumSize(100, 16777215);
  185. self.ui.barProgress.hide();
  186. self.ui.mplwidget_navigator.setCanvas(self.ui.mplwidget)
  187. #self.ui.mplwidget_navigator_2.setCanvas(self.ui.mplwidget)
  188. self.ui.txRxTable.setColumnCount(4)
  189. self.ui.txRxTable.setRowCount(0)
  190. self.ui.txRxTable.setHorizontalHeaderLabels( ["Label", "Geom.","Turns","Tx/Rx"] )
  191. ##########################################################################
  192. # layer Table
  193. self.ui.layerTableWidget.setRowCount(80)
  194. self.ui.layerTableWidget.setColumnCount(3)
  195. self.ui.layerTableWidget.setHorizontalHeaderLabels( [r"top [m]", r"bottom [m]", "ρ [Ωm]" ] )
  196. # do we want this
  197. self.ui.layerTableWidget.setDragDropOverwriteMode(False)
  198. self.ui.layerTableWidget.setDragEnabled(True)
  199. self.ui.layerTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  200. pCell0 = QtWidgets.QTableWidgetItem()
  201. pCell0.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  202. pCell0.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  203. pCell0.setForeground( QtGui.QColor("black") )
  204. pCell0.setText(str("0"))
  205. self.ui.layerTableWidget.setItem(0, 0, pCell0)
  206. pCell1 = QtWidgets.QTableWidgetItem()
  207. #pCell1.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  208. pCell1.setBackground( QtGui.QColor("lightblue") ) #.lighter(110) )
  209. pCell1.setForeground( QtGui.QColor("black") )
  210. self.ui.layerTableWidget.setItem(0, 1, pCell1)
  211. pCell2 = QtWidgets.QTableWidgetItem()
  212. #pCell1.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  213. pCell2.setBackground( QtGui.QColor("white") ) #.lighter(110) )
  214. pCell2.setForeground( QtGui.QColor("black") )
  215. self.ui.layerTableWidget.setItem(0, 2, pCell2)
  216. for ir in range(1, self.ui.layerTableWidget.rowCount() ):
  217. for ic in range(0, self.ui.layerTableWidget.columnCount() ):
  218. pCell = QtWidgets.QTableWidgetItem()
  219. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  220. pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  221. pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  222. pCell.setForeground( QtGui.QColor("black"))
  223. self.ui.layerTableWidget.setItem(ir, ic, pCell)
  224. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  225. def LCDHarmonics(self):
  226. self.ui.lcdH1F.setEnabled(True)
  227. self.ui.lcdH1F.display( self.ui.f0Spin.value() * self.ui.f0K1Spin.value() )
  228. self.ui.lcdHNF.setEnabled(True)
  229. self.ui.lcdHNF.display( self.ui.f0Spin.value() * self.ui.f0KNSpin.value() )
  230. self.ui.lcdf0NK.setEnabled(True)
  231. self.ui.lcdf0NK.display( (self.ui.f0KNSpin.value()+1-self.ui.f0K1Spin.value()) * self.ui.f0KsSpin.value() )
  232. def LCDHarmonics2(self):
  233. if self.ui.NHarmonicsFreqsSpin.value() == 2:
  234. self.ui.lcdH1F2.setEnabled(True)
  235. self.ui.lcdH1F2.display( self.ui.f1Spin.value() * self.ui.f1K1Spin.value() )
  236. self.ui.lcdHNF2.setEnabled(True)
  237. self.ui.lcdHNF2.display( self.ui.f1Spin.value() * self.ui.f1KNSpin.value() )
  238. self.ui.lcdf0NK2.setEnabled(True)
  239. self.ui.lcdf0NK2.display( (self.ui.f1KNSpin.value()+1-self.ui.f1K1Spin.value()) * self.ui.f1KsSpin.value() )
  240. else:
  241. self.ui.lcdH1F2.setEnabled(False)
  242. self.ui.lcdHNF2.setEnabled(False)
  243. self.ui.lcdf0NK2.setEnabled(False)
  244. def adjustLarmor(self):
  245. """ Triggers when the B0 intensity spin box is cycled
  246. """
  247. self.ui.larmorv.setValue( self.ui.intensitySpinBox.value() * GAMMAH )
  248. self.ui.txv.setValue( self.RAWDataProc.transFreq - self.ui.larmorv.value() )
  249. def adjustB0(self):
  250. """ Triggers when tx frequency offset is cycled
  251. """
  252. self.ui.intensitySpinBox.setValue( (self.RAWDataProc.transFreq - self.ui.txv.value()) / GAMMAH )
  253. def adjustB02(self):
  254. """ Triggers when Larmor frequency spin box is cycled o
  255. """
  256. self.ui.intensitySpinBox.setValue( (self.ui.larmorv.value()) / GAMMAH )
  257. def closeTabs(self):
  258. #self.ui.ProcTabs.removeTab(idx)
  259. self.ui.ProcTabs.clear( )
  260. def addPreProc(self):
  261. if self.ui.actionPreprocessing.isChecked():
  262. self.ui.actionModelling.setChecked(False)
  263. self.ui.actionInversion.setChecked(False)
  264. self.ui.ProcTabs.clear( )
  265. self.ui.ProcTabs.insertTab( 0, self.ui.LoadTab, "Load" )
  266. self.ui.ProcTabs.insertTab( 1, self.ui.NCTab, "Noise removal" )
  267. self.ui.ProcTabs.insertTab( 2, self.ui.QCTab, "QC" )
  268. self.ui.ProcTabs.insertTab( 3, self.ui.METATab, "META" )
  269. self.ui.ProcTabs.insertTab( 4, self.ui.LogTab, "Log" )
  270. else:
  271. self.ui.ProcTabs.removeTab(0)
  272. self.ui.ProcTabs.removeTab(0)
  273. self.ui.ProcTabs.removeTab(0)
  274. self.ui.ProcTabs.removeTab(0)
  275. def addModelling(self):
  276. if self.ui.actionModelling.isChecked():
  277. self.ui.actionPreprocessing.setChecked(False)
  278. self.ui.actionInversion.setChecked(False)
  279. self.ui.ProcTabs.clear( )
  280. self.ui.ProcTabs.insertTab( 0, self.ui.KernTab, "Kernel" )
  281. self.ui.ProcTabs.insertTab( 1, self.ui.ModelTab, "Modelling" )
  282. #self.ui.ProcTabs.insertTab( 2, self.ui.LogTab, "Log" )
  283. else:
  284. self.ui.ProcTabs.removeTab(0)
  285. self.ui.ProcTabs.removeTab(0)
  286. def addInversion(self, idx):
  287. if self.ui.actionInversion.isChecked():
  288. self.ui.actionPreprocessing.setChecked(False)
  289. self.ui.actionModelling.setChecked(False)
  290. self.ui.ProcTabs.clear( )
  291. self.ui.ProcTabs.insertTab( 0, self.ui.InvertTab, "QT Inversion" )
  292. self.ui.ProcTabs.insertTab( 1, self.ui.AppraiseTab, "Appraisal" )
  293. #self.ui.ProcTabs.insertTab( 2, self.ui.LogTab, "Log" )
  294. else:
  295. self.ui.ProcTabs.removeTab(0)
  296. self.ui.ProcTabs.removeTab(0)
  297. def invDataSelect(self):
  298. try:
  299. with open('.akvo.last.path') as f:
  300. fpath = f.readline()
  301. pass
  302. except IOError as e:
  303. fpath = '.'
  304. self.akvoDataFile = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Datafile File', fpath, r"Akvo datafiles (*.akvoProcData *.yaml)")[0]
  305. self.ui.dataText.clear()
  306. self.ui.dataText.append( self.akvoDataFile )
  307. def K0DataSelect(self):
  308. try:
  309. with open('.akvo.last.path') as f:
  310. fpath = f.readline()
  311. pass
  312. except IOError as e:
  313. fpath = '.'
  314. self.K0akvoDataFile = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Datafile File', fpath, r"Akvo datafiles (*.akvoProcData *.yaml)")[0]
  315. # populate combo box with loops
  316. if os.path.isfile( self.K0akvoDataFile ):
  317. self.ui.K0DataText.clear()
  318. self.ui.K0DataText.append( self.K0akvoDataFile )
  319. with open(self.K0akvoDataFile) as f:
  320. parse = yaml.load( f, Loader=yaml.Loader )
  321. self.ui.txListWidget.clear()
  322. self.ui.rxListWidget.clear()
  323. for loop in parse.META["Loops"]:
  324. print(loop)
  325. self.ui.txListWidget.addItem( parse.META["Loops"][loop] )
  326. self.ui.rxListWidget.addItem( parse.META["Loops"][loop] )
  327. # TODO, why are these necessary
  328. self.ui.txListWidget.setCurrentRow(0)
  329. self.ui.rxListWidget.setCurrentRow(0)
  330. # else do nothing
  331. def invKernelSelect(self):
  332. try:
  333. with open('.akvo.last.path') as f:
  334. fpath = f.readline()
  335. pass
  336. except IOError as e:
  337. fpath = '.'
  338. self.K0file = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Kernel File', fpath, r"Akvo kernels (*.akvoK0)")[0]
  339. self.ui.kernelText.clear()
  340. self.ui.kernelText.append(self.K0file)
  341. def QTInv(self):
  342. print("Big RED INVERT BUTTON")
  343. try:
  344. with open('.akvo.last.path') as f:
  345. fpath = f.readline()
  346. pass
  347. except IOError as e:
  348. fpath = '.'
  349. #K0file = self.ui.kernelText.text()
  350. #akvoDataFile = self.ui.dataText.text()
  351. T2lo = self.ui.T2low.value()
  352. T2hi = self.ui.T2hi.value()
  353. NT2 = self.ui.NT2.value()
  354. dataChan = self.ui.invChan.currentText()
  355. t2Obj = self.ui.T2Objective.currentText()
  356. depthObj = self.ui.depthObjective.currentText()
  357. alpha_0 = self.ui.initialAlpha.value()
  358. invDict = dict()
  359. invDict["data"] = dict()
  360. invDict["data"] = dict()
  361. invDict["data"][self.akvoDataFile] = dict()
  362. invDict["data"][self.akvoDataFile]["channels"] = [dataChan,]
  363. invDict["K0"] = [self.K0file,]
  364. invDict["T2Bins"] = dict()
  365. invDict["T2Bins"]["low"] = T2lo
  366. invDict["T2Bins"]["high"] = T2hi
  367. invDict["T2Bins"]["number"] = NT2
  368. invDict["NonLinearRefinement"] = self.ui.NLButton.isChecked()
  369. invDict["CalcDOI"] = self.ui.DOIButton.isChecked()
  370. node = yaml.YAML()
  371. kpo = open( "invert.yml", 'w' )
  372. node.dump(invDict, kpo)
  373. callBox = callScript( ) #QtWidgets.QDialog()
  374. callBox.ui = Ui_callScript()
  375. callBox.ui.setupUi( callBox )
  376. callBox.setupQTInv( "invert.yml" )
  377. callBox.exec_()
  378. callBox.show()
  379. def calcK0(self):
  380. try:
  381. with open('.akvo.last.path') as f:
  382. fpath = f.readline()
  383. pass
  384. except IOError as e:
  385. fpath = '.'
  386. #self.K0akvoDataFile = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Datafile File', fpath, r"Akvo datafiles (*.yaml)")[0]
  387. #akvoData = QtWidgets.QFileDialog.getOpenFileName(self, 'Open Datafile File', fpath, r"Akvo datafiles (*.yaml)")[0]
  388. txCoilList = self.ui.txListWidget.selectedItems() #currentItem().text()
  389. txCoils = []
  390. for txCoil in txCoilList:
  391. print("txCoil", txCoil.text())
  392. txCoils.append(txCoil.text())
  393. rxCoilList = self.ui.txListWidget.selectedItems() #currentItem().text()
  394. rxCoils = []
  395. for rxCoil in rxCoilList:
  396. print("rxCoil", rxCoil.text())
  397. rxCoils.append(rxCoil.text())
  398. saveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save kernel as", fpath, r"Merlin KernelV0 (*.akvoK0)")[0]
  399. intDict = dict()
  400. intDict["origin_n"] = self.ui.originN.value()
  401. intDict["origin_e"] = self.ui.originE.value()
  402. intDict["origin_d"] = self.ui.originD.value()
  403. intDict["size_n"] = self.ui.sizeN.value()
  404. intDict["size_e"] = self.ui.sizeE.value()
  405. intDict["size_d"] = self.ui.sizeD.value()
  406. intDict["nLay"] = self.ui.NLayers.value()
  407. intDict["thick1"] = self.ui.thick1.value()
  408. intDict["thickN"] = self.ui.thickN.value()
  409. intDict["Lspacing"] = self.ui.layerSpacing.currentText()
  410. intDict["minLevel"] = self.ui.minLevel.value()
  411. intDict["maxLevel"] = self.ui.maxLevel.value()
  412. intDict["branchTol"] = self.ui.branchTol.value()
  413. intDict["txCoils"] = txCoils
  414. intDict["rxCoils"] = rxCoils
  415. # conductivity model...
  416. #tops = self.ui.layerTableWidget.col(0)
  417. #print("Tops", tops)
  418. tops = []
  419. itop = 0
  420. while self.ui.layerTableWidget.item(itop, 0).text():
  421. tops.append( float(self.ui.layerTableWidget.item(itop,0).text()) )
  422. itop += 1
  423. bots = []
  424. ibot = 0
  425. while self.ui.layerTableWidget.item(ibot, 1).text():
  426. bots.append( float(self.ui.layerTableWidget.item(ibot, 1).text()) )
  427. ibot += 1
  428. sigs = []
  429. isig = 0
  430. while self.ui.layerTableWidget.item(isig, 2).text():
  431. sigs.append( 1./float(self.ui.layerTableWidget.item(isig, 2).text()) )
  432. isig += 1
  433. intDict["tops"] = tops
  434. intDict["bots"] = bots
  435. intDict["sigs"] = sigs
  436. node = yaml.YAML()
  437. kpo = open( "kparams.yml", 'w' )
  438. node.dump(intDict, kpo)
  439. callBox = callScript( ) #QtWidgets.QDialog()
  440. callBox.ui = Ui_callScript()
  441. callBox.ui.setupUi( callBox )
  442. callBox.setupCB( self.K0akvoDataFile, "kparams.yml", saveStr )
  443. callBox.exec_()
  444. callBox.show()
  445. def loopAdd(self):
  446. #print(self.ui.loopLabel.text())
  447. #print(self.ui.loopGeom.currentText())
  448. #print(self.ui.loopType.currentText())
  449. #print( "label len", len(self.ui.loopLabel.text()) )
  450. if len(self.ui.loopLabel.text().strip()) == 0:
  451. Error = QtWidgets.QMessageBox()
  452. Error.setWindowTitle("Error!")
  453. Error.setText("Loop label cannot be blank or repeated")
  454. Error.setDetailedText("Each loop label must be unique and comprise at least one character. Leading and trailing whitespace will be trimmed.")
  455. Error.exec_()
  456. else:
  457. ### Circular loop
  458. if self.ui.loopGeom.currentText() == "Circular":
  459. dialog = QtWidgets.QDialog()
  460. dialog.ui = Ui_circularLoopAdd()
  461. dialog.ui.setupUi(dialog)
  462. dialog.exec_()
  463. dialog.show()
  464. if dialog.result():
  465. cn = dialog.ui.centreNorth.value()
  466. ce = dialog.ui.centreEast.value()
  467. ht = dialog.ui.loopHeight.value()
  468. rad = dialog.ui.loopRadius.value()
  469. turns = dialog.ui.loopTurns.value()
  470. ns = dialog.ui.segments.value()
  471. cwise = dialog.ui.cwiseBox.currentIndex()
  472. #print("cwise", cwise)
  473. #dip = dialog.ui.dip.value()
  474. #azimuth = dialog.ui.az.value()
  475. self.loops[self.ui.loopLabel.text()] = FDEM1D.PolygonalWireAntenna()
  476. self.loops[self.ui.loopLabel.text()].SetNumberOfPoints( dialog.ui.segments.value() + 1 )
  477. self.loops[self.ui.loopLabel.text()].SetNumberOfTurns( dialog.ui.loopTurns.value() )
  478. points = np.linspace(0, 2*np.pi, dialog.ui.segments.value()+1)
  479. for iseg, ipt in enumerate(points):
  480. if cwise == 0:
  481. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( cn+rad*np.sin(ipt), ce+rad*np.cos(ipt), ht) )
  482. else:
  483. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( cn-rad*np.sin(ipt), ce+rad*np.cos(ipt), ht) )
  484. self.loops[self.ui.loopLabel.text()].SetNumberOfFrequencies(1)
  485. self.loops[self.ui.loopLabel.text()].SetCurrent(1.)
  486. if self.ui.loopGeom.currentText() == "figure-8":
  487. dialog = QtWidgets.QDialog()
  488. dialog.ui = Ui_figure8LoopAdd()
  489. dialog.ui.setupUi(dialog)
  490. dialog.exec_()
  491. dialog.show()
  492. if dialog.result():
  493. cn1 = dialog.ui.centreNorth1.value()
  494. ce1 = dialog.ui.centreEast1.value()
  495. cn2 = dialog.ui.centreNorth2.value()
  496. ce2 = dialog.ui.centreEast2.value()
  497. ht = dialog.ui.loopHeight.value()
  498. rad = dialog.ui.loopRadius.value()
  499. turns = dialog.ui.loopTurns.value()
  500. ns = dialog.ui.segments.value()
  501. cwise = dialog.ui.cwiseBox.currentIndex()
  502. self.loops[self.ui.loopLabel.text()] = FDEM1D.PolygonalWireAntenna()
  503. self.loops[self.ui.loopLabel.text()].SetNumberOfPoints( 2*dialog.ui.segments.value() + 1 )
  504. self.loops[self.ui.loopLabel.text()].SetNumberOfTurns( dialog.ui.loopTurns.value() )
  505. # first loop
  506. points = np.linspace(0, 2*np.pi, dialog.ui.segments.value())
  507. ptsL = []
  508. for iseg, ipt in enumerate(points):
  509. ptsL.append( np.array( [cn1+rad*np.sin(ipt), ce1+rad*np.cos(ipt)] ))
  510. lenP = len(points)
  511. # search for closest point, ugly and not efficient, but it's not critical here
  512. closest = 1e8
  513. iclosest = -1
  514. for iseg, ipt in enumerate(points):
  515. p2 = np.array([cn2-rad*np.sin(ipt), ce2-rad*np.cos(ipt)])
  516. for p1 in ptsL:
  517. dist = np.linalg.norm(p1-p2)
  518. if dist < closest:
  519. closest = dist
  520. iclosest = iseg
  521. points = np.concatenate([points[iclosest::],points[0:iclosest]])
  522. # Fill first loop
  523. point1 = False
  524. for iseg, ipt in enumerate(points):
  525. if cwise == 0:
  526. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( cn1+rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht) )
  527. pointlast = ( cn1+rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht)
  528. if not point1:
  529. point1 = ( cn1+rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht)
  530. else:
  531. self.loops[self.ui.loopLabel.text()].SetPoint(iseg, ( cn1-rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht) )
  532. if not point1:
  533. point1 = ( cn1-rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht)
  534. pointlast = ( cn1-rad*np.sin(ipt), ce1+rad*np.cos(ipt), ht)
  535. lenP = len(points)
  536. # reorder points again to find nearest point in second loop
  537. closest = 99999
  538. iclosest = -1
  539. for iseg, ipt in enumerate(points):
  540. if cwise == 0:
  541. p2 = np.array([cn2-rad*np.sin(ipt), ce2+rad*np.cos(ipt)])
  542. else:
  543. p2 = np.array([cn2+rad*np.sin(ipt), ce2+rad*np.cos(ipt)])
  544. for p1 in ptsL:
  545. dist = np.linalg.norm(np.array(pointlast[0:2])-p2)
  546. if dist < closest:
  547. closest = dist
  548. iclosest = iseg
  549. points = np.concatenate([points[iclosest::],points[0:iclosest]])
  550. # fill second loop
  551. for iseg, ipt in enumerate(points):
  552. if cwise == 0:
  553. self.loops[self.ui.loopLabel.text()].SetPoint(lenP+iseg, ( cn2-rad*np.sin(ipt), ce2+rad*np.cos(ipt), ht) )
  554. else:
  555. self.loops[self.ui.loopLabel.text()].SetPoint(lenP+iseg, ( cn2+rad*np.sin(ipt), ce2+rad*np.cos(ipt), ht) )
  556. # close loop
  557. self.loops[self.ui.loopLabel.text()].SetPoint(lenP+iseg+1, point1)
  558. self.loops[self.ui.loopLabel.text()].SetNumberOfFrequencies(1)
  559. self.loops[self.ui.loopLabel.text()].SetCurrent(1.)
  560. if self.ui.loopGeom.currentText() == "polygon":
  561. dialog = QtWidgets.QDialog()
  562. dialog.ui = Ui_polygonalLoopAdd()
  563. dialog.ui.setupUi(dialog)
  564. ##########################################################################
  565. # Loop Table
  566. dialog.ui.loopTableWidget.setRowCount(80)
  567. dialog.ui.loopTableWidget.setColumnCount(3)
  568. #dialog.ui.loopTableWidget.horizontalHeader().setSectionResizeMode(0, QtGui.Qt.QHeaderView.Stretch)
  569. dialog.ui.loopTableWidget.setHorizontalHeaderLabels( \
  570. ["Northing [m]","Easting [m]","Height [m]"])
  571. for ir in range(0, dialog.ui.loopTableWidget.rowCount() ):
  572. for ic in range(0, 3): #dialog.ui.loopTableWidget.columnCount() ):
  573. pCell = QtWidgets.QTableWidgetItem()
  574. #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
  575. #pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable
  576. #pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) )
  577. dialog.ui.loopTableWidget.setItem(ir, ic, pCell)
  578. #dialog.ui.loopTableWidget.cellChanged.connect(self.loopCellChanged)
  579. #dialog.ui.loopTableWidget.itemClicked.connect(self.loopCellClicked)
  580. #self.ui.loopTableWidget.cellPressed.connect(self.loopCellChanged)
  581. #self.ui.loopTableWidget.cellPressed.connect(self.loopCellClicked)
  582. dialog.ui.loopTableWidget.setDragDropOverwriteMode(False)
  583. dialog.ui.loopTableWidget.setDragEnabled(False)
  584. #self.ui.loopTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
  585. dialog.ui.loopTableWidget.resizeColumnsToContents()
  586. dialog.exec_()
  587. dialog.show()
  588. if dialog.result():
  589. self.loops[self.ui.loopLabel.text()] = FDEM1D.PolygonalWireAntenna()
  590. self.loops[self.ui.loopLabel.text()].SetNumberOfTurns( dialog.ui.loopTurns.value() )
  591. npts = 0
  592. for ir in range(0, dialog.ui.loopTableWidget.rowCount() ):
  593. if len(dialog.ui.loopTableWidget.item(ir, 0).text()) == 0:
  594. break
  595. npts += 1
  596. self.loops[self.ui.loopLabel.text()].SetNumberOfPoints( npts )
  597. for ir in range( 0, npts ):
  598. self.loops[self.ui.loopLabel.text()].SetPoint(ir, eval(dialog.ui.loopTableWidget.item(ir, 0).text()), \
  599. eval(dialog.ui.loopTableWidget.item(ir, 1).text()), \
  600. eval(dialog.ui.loopTableWidget.item(ir, 2).text()) \
  601. )
  602. self.loops[self.ui.loopLabel.text()].SetNumberOfFrequencies(1)
  603. self.loops[self.ui.loopLabel.text()].SetCurrent(1.)
  604. # general across all types
  605. if dialog.result():
  606. yml = open( self.ui.loopLabel.text() + ".pwa", 'w' )
  607. print( self.loops[self.ui.loopLabel.text()], file=yml)
  608. # update the table
  609. self.ui.txRxTable.setRowCount( len(self.loops.keys()) )
  610. pCell = QtWidgets.QTableWidgetItem()
  611. pCell.setText( self.ui.loopLabel.text() )
  612. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
  613. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 0, pCell)
  614. gCell = QtWidgets.QTableWidgetItem()
  615. gCell.setText( self.ui.loopGeom.currentText() )
  616. gCell.setFlags( QtCore.Qt.ItemIsEnabled )
  617. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 1, gCell)
  618. tCell = QtWidgets.QTableWidgetItem()
  619. tCell.setText( str(dialog.ui.loopTurns.value()) )
  620. tCell.setFlags( QtCore.Qt.ItemIsEnabled )
  621. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 2, tCell)
  622. txCell = QtWidgets.QTableWidgetItem()
  623. txCell.setText( str(self.ui.loopType.currentText()) )
  624. txCell.setFlags( QtCore.Qt.ItemIsEnabled )
  625. self.ui.txRxTable.setItem( len(self.loops.keys())-1, 3, txCell)
  626. def headerBoxShrink(self):
  627. #self.ui.headerFileBox.setVisible(False)
  628. if self.ui.headerFileBox.isChecked( ):
  629. #self.ui.headerFileBox.setMinimumSize(460,250)
  630. self.ui.headerBox2.setVisible(True)
  631. else:
  632. #self.ui.headerFileBox.setMinimumSize(460,50)
  633. self.ui.headerBox2.setVisible(False)
  634. def sigmaCellChanged(self):
  635. self.ui.layerTableWidget.cellChanged.disconnect(self.sigmaCellChanged)
  636. # TODO consider building the model whenever this is called. Would be nice to be able to
  637. # do that. Would require instead dist of T2 I guess.
  638. jj = self.ui.layerTableWidget.currentColumn()
  639. ii = self.ui.layerTableWidget.currentRow()
  640. val = "class 'NoneType'>"
  641. try:
  642. val = eval (str( self.ui.layerTableWidget.item(ii, jj).text() ))
  643. except:
  644. #if jj != 0:
  645. # Error = QtWidgets.QMessageBox()
  646. # Error.setWindowTitle("Error!")
  647. # Error.setText("Non-numeric value encountered")
  648. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  649. return
  650. if jj == 1:
  651. #item.setFlags(QtCore.Qt.ItemIsEnabled)
  652. pCell = self.ui.layerTableWidget.item(ii, jj)
  653. pCell.setBackground( QtGui.QColor("white"))
  654. pCell = self.ui.layerTableWidget.item(ii+1, jj-1)
  655. if str(type(pCell)) == "<class 'NoneType'>":
  656. pCell = QtWidgets.QTableWidgetItem()
  657. pCell.setFlags(QtCore.Qt.ItemIsEnabled)
  658. self.ui.layerTableWidget.setItem(ii+1, jj-1, pCell)
  659. if ii == 0:
  660. pCell.setText(str(val))
  661. #pCell3 = self.ui.layerTableWidget.item(ii+1, jj)
  662. #print ("setting", ii, jj, type(pCell3))
  663. #print ( "setting", ii, jj, type(pCell3))
  664. #pCell3.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  665. #pCell3.setFlags( QtCore.Qt.ItemIsEditable )
  666. elif ii > 0:
  667. val2 = eval (str( self.ui.layerTableWidget.item(ii-1, jj).text() ))
  668. #print ("val2", val2, val, type(val))
  669. #if str(type(pCell)) == "<class 'NoneType'>":
  670. if type(val) == str or val > val2:
  671. pCell.setText(str(val))
  672. else:
  673. Error = QtWidgets.QMessageBox()
  674. Error.setWindowTitle("Error!")
  675. Error.setText("Non-increasing layer detected")
  676. Error.setDetailedText("Each layer interface must be below the one above it.")
  677. Error.exec_()
  678. #err_msg = "Quadrature detection has already been done!"
  679. #reply =QtWidgets.QMessageBox.critical(self, 'Error',
  680. # err_msg)
  681. pCell2 = self.ui.layerTableWidget.item(ii, jj)
  682. pCell2.setText(str(""))
  683. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  684. return
  685. # enable next layer
  686. pCell4 = self.ui.layerTableWidget.item(ii+1, jj)
  687. pCell4.setBackground( QtGui.QColor("lightblue") ) #.lighter(110))
  688. pCell4.setForeground( QtGui.QColor("black"))
  689. pCell4.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  690. pCell5 = self.ui.layerTableWidget.item(ii+1, jj+1)
  691. pCell5.setBackground( QtGui.QColor("white"))
  692. pCell5.setForeground( QtGui.QColor("black"))
  693. pCell5.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  694. if ii == 0 and jj == 0:
  695. pCell = self.ui.layerTableWidget.item(0, 1)
  696. pCell.setBackground(QtGui.QColor("lightblue")) #.lighter(110) )
  697. pCell.setForeground( QtGui.QColor("black"))
  698. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled )
  699. self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged)
  700. def plotLoops2(self):
  701. self.ui.mplwidget.reAxH(1)
  702. for loop in self.loops:
  703. POINTS = self.loops[loop].GetPoints().T
  704. self.ui.mplwidget.ax1.plot( POINTS[:,1], POINTS[:,0], label=loop )
  705. self.ui.mplwidget.ax1.spines['right'].set_visible(False)
  706. self.ui.mplwidget.ax1.spines['top'].set_visible(False)
  707. self.ui.mplwidget.ax1.set_xlabel("easting (m)")
  708. self.ui.mplwidget.ax1.set_ylabel("northing (m)")
  709. self.ui.mplwidget.ax1.legend()
  710. self.ui.mplwidget.ax1.set_aspect('equal') #, adjustable='box')
  711. self.ui.mplwidget.draw()
  712. def removeLoop(self):
  713. del self.loops[ self.ui.txRxTable.item( self.ui.txRxTable.currentRow(), 0).text() ]
  714. self.ui.txRxTable.removeRow(self.ui.txRxTable.currentRow())
  715. def about(self):
  716. # TODO proper popup with info
  717. #self.w = MyPopup("""About Akvo \n
  718. # Akvo is an open source project developed primarily by Trevor Irons.
  719. #""")
  720. #self.w.setGeometry(100, 100, 400, 200)
  721. #self.w.show()
  722. #print("ABOUT")
  723. # Just a splash screen for now
  724. logo = pkg_resources.resource_filename(__name__, 'akvo-about.png')
  725. pixmap = QtGui.QPixmap(logo)
  726. self.splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  727. self.splash.show()
  728. def connectGMRDataProcessor(self):
  729. self.RAWDataProc = mrsurvey.GMRDataProcessor()
  730. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  731. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  732. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  733. self.RAWDataProc.updateProcTrigger.connect(self.updateProc)
  734. def loadMIDI2Dataset (self):
  735. """ Opens a MIDI file and extracts header info
  736. """
  737. try:
  738. with open('.midi2.last.path') as f:
  739. fpath = f.readline()
  740. pass
  741. except IOError as e:
  742. fpath = '.'
  743. self.headerstr = QtWidgets.QFileDialog.getExistingDirectory(self, 'Load MIDI 2 Directory', fpath)
  744. self.ui.headerFileTextBrowser.clear()
  745. self.ui.headerFileTextBrowser.append(self.headerstr)
  746. if len(self.headerstr) == 0:
  747. return
  748. # TODO, should rename this class, use MIDI path
  749. self.connectGMRDataProcessor()
  750. self.RAWDataProc.readMIDI2Header(str(self.headerstr))
  751. # look in the directory for all the files
  752. self.ui.loadDataPushButton.pressed.connect(self.loadMIDI2)
  753. # If we got this far, enable all the widgets
  754. self.ui.lcdNumberTauPulse1.setEnabled(True)
  755. self.ui.lcdNumberNuTx.setEnabled(True)
  756. self.ui.lcdNumberTuneuF.setEnabled(True)
  757. self.ui.lcdNumberSampFreq.setEnabled(True)
  758. self.ui.lcdNumberNQ.setEnabled(True)
  759. self.ui.headerFileBox.setEnabled(True)
  760. self.ui.headerFileBox.setChecked( True )
  761. self.ui.headerBox2.setVisible(True)
  762. self.ui.inputRAWParametersBox.setEnabled(True)
  763. self.ui.loadDataPushButton.setEnabled(True)
  764. # make plots as you import the dataset
  765. self.ui.plotImportCheckBox.setEnabled(True)
  766. self.ui.plotImportCheckBox.setChecked(True)
  767. # Update info from the header into the GUI
  768. self.ui.pulseTypeTextBrowser.clear()
  769. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  770. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  771. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  772. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  773. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  774. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  775. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  776. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  777. # set the B0 field according to Tx as an initial guess
  778. self.ui.intensitySpinBox.setValue( self.RAWDataProc.transFreq/GAMMAH )
  779. if self.RAWDataProc.pulseType != "FID":
  780. self.ui.lcdNumberTauPulse2.setEnabled(1)
  781. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  782. self.ui.lcdNumberTauDelay.setEnabled(1)
  783. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  784. self.ui.FIDProcComboBox.clear()
  785. if self.RAWDataProc.pulseType == "4PhaseT1" or self.RAWDataProc.pulseType == "T1":
  786. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  787. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2")
  788. self.ui.FIDProcComboBox.insertItem(2, "Both")
  789. self.ui.FIDProcComboBox.setCurrentIndex (1)
  790. elif self.RAWDataProc.pulseType == "FID":
  791. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  792. self.ui.FIDProcComboBox.setCurrentIndex (0)
  793. def openGMRRAWDataset(self):
  794. """ Opens a GMR header file
  795. """
  796. try:
  797. with open('.gmr.last.path') as f:
  798. fpath = f.readline()
  799. pass
  800. except IOError as e:
  801. fpath = '.'
  802. self.headerstr = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', fpath)[0] # arg2 = File Type 'All Files (*)'
  803. self.ui.headerFileTextBrowser.clear()
  804. self.ui.headerFileTextBrowser.append(self.headerstr)
  805. if len(self.headerstr) == 0:
  806. return
  807. # clear the processing log
  808. self.ui.logTextBrowser.clear()
  809. self.logText = [] #MAK 20170126
  810. path,filen=os.path.split(str(self.headerstr))
  811. f = open('.gmr.last.path', 'w')
  812. f.write( str(self.headerstr) ) # prompt last file
  813. self.connectGMRDataProcessor()
  814. self.RAWDataProc.readHeaderFile(str(self.headerstr))
  815. # make sure we will use GMR path
  816. self.ui.loadDataPushButton.pressed.connect(self.loadRAW)
  817. # If we got this far, enable all the widgets
  818. self.ui.lcdNumberTauPulse1.setEnabled(True)
  819. self.ui.lcdNumberNuTx.setEnabled(True)
  820. self.ui.lcdNumberTuneuF.setEnabled(True)
  821. self.ui.lcdNumberSampFreq.setEnabled(True)
  822. self.ui.lcdNumberNQ.setEnabled(True)
  823. self.ui.headerFileBox.setEnabled(True)
  824. self.ui.headerFileBox.setChecked( True )
  825. self.ui.headerBox2.setVisible(True)
  826. self.ui.inputRAWParametersBox.setEnabled(True)
  827. self.ui.loadDataPushButton.setEnabled(True)
  828. # make plots as you import the dataset
  829. self.ui.plotImportCheckBox.setEnabled(True)
  830. self.ui.plotImportCheckBox.setChecked(True)
  831. # Update info from the header into the GUI
  832. self.ui.pulseTypeTextBrowser.clear()
  833. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  834. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  835. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  836. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  837. self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp)
  838. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  839. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  840. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  841. # set the B0 field according to Tx as an initial guess
  842. self.ui.intensitySpinBox.setValue( self.RAWDataProc.transFreq/GAMMAH )
  843. if self.RAWDataProc.pulseType != "FID":
  844. self.ui.lcdNumberTauPulse2.setEnabled(1)
  845. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  846. self.ui.lcdNumberTauDelay.setEnabled(1)
  847. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  848. self.ui.FIDProcComboBox.clear()
  849. if self.RAWDataProc.pulseType == "4PhaseT1" or self.RAWDataProc.pulseType == "T1":
  850. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  851. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2")
  852. self.ui.FIDProcComboBox.insertItem(2, "Both")
  853. self.ui.FIDProcComboBox.setCurrentIndex (1)
  854. elif self.RAWDataProc.pulseType == "FID":
  855. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1")
  856. self.ui.FIDProcComboBox.setCurrentIndex (0)
  857. def ExportPreprocess(self):
  858. """ This method exports to YAML
  859. """
  860. try:
  861. with open('.akvo.last.yaml.path') as f:
  862. fpath = f.readline()
  863. pass
  864. except IOError as e:
  865. fpath = '.'
  866. fdir = os.path.dirname(fpath)
  867. # Pickle the preprocessed data dictionary
  868. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Processed data (*.akvoProcData)")[0]
  869. spath,filen=os.path.split(str(SaveStr))
  870. f = open('.akvo.last.yaml.path', 'w')
  871. f.write( str(spath) ) # prompt last file
  872. INFO = {}
  873. INFO["headerstr"] = str(self.headerstr)
  874. INFO["pulseType"] = self.RAWDataProc.pulseType
  875. INFO["transFreq"] = np.array(self.RAWDataProc.transFreq).tolist() # numpy is for MIDI datasets
  876. INFO["pulseLength"] = np.array(self.RAWDataProc.pulseLength).tolist()
  877. INFO["TuneCapacitance"] = np.array(self.RAWDataProc.TuneCapacitance).tolist()
  878. #INFO["samp"] = self.RAWDataProc.samp
  879. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  880. #INFO["deadTime"] = self.RAWDataProc.deadTime
  881. INFO["processed"] = "Akvo v" + VERSION + ", on " + time.strftime("%d/%m/%Y")
  882. # Pulse current info
  883. ip = 0
  884. INFO["Pulses"] = {}
  885. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  886. qq = []
  887. qv = []
  888. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  889. #for ipm in self.pulseMoments:
  890. #for istack in self.RAWDataProc.DATADICT["stacks"]:
  891. # print ("stack q", self.RAWDataProc.DATADICT[pulse]["Q"][ipm,istack-1])
  892. qq.append(np.mean( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]) )
  893. qv.append(np.std( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]/self.RAWDataProc.pulseLength[ip] ))
  894. qq = np.array(qq)
  895. qv = np.array(qv)
  896. iQ = np.argsort(np.array(qq))
  897. qq = np.array(qq)[iQ]
  898. qv = np.array(qv)[iQ]
  899. INFO["Pulses"][pulse] = {}
  900. INFO["Pulses"][pulse]["units"] = "A"
  901. INFO["Pulses"][pulse]["current"] = VectorXr(qq/self.RAWDataProc.pulseLength[ip])
  902. INFO["Pulses"][pulse]["variance"] = VectorXr(qv)
  903. ip += 1
  904. # Data
  905. if self.RAWDataProc.gated == True:
  906. INFO["Gated"] = {}
  907. INFO["Gated"]["abscissa units"] = "ms"
  908. INFO["Gated"]["data units"] = "nT"
  909. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  910. INFO["Gated"][pulse] = {}
  911. INFO["Gated"][pulse]["abscissa"] = VectorXr( self.RAWDataProc.GATEDABSCISSA )
  912. INFO["Gated"][pulse]["windows"] = VectorXr( self.RAWDataProc.GATEDWINDOW )
  913. for ichan in self.RAWDataProc.DATADICT[pulse]["chan"]:
  914. INFO["Gated"][pulse]["Chan. " + str(ichan)] = {}
  915. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["STD"] = VectorXr( np.std(self.RAWDataProc.GATED[ichan]["NR"], axis=0) )
  916. INFO["Gated"][pulse]["Chan. " + str(ichan)]["STD"] = VectorXr( np.average(self.RAWDataProc.GATED[ichan]["BN"], axis=0) )
  917. for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]):
  918. #for ipm in self.pulseMoments:
  919. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " CA"] = VectorXr(self.RAWDataProc.GATED[ichan]["CA"][ipm])
  920. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " RE"] = VectorXr(self.RAWDataProc.GATED[ichan]["RE"][ipm])
  921. INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IM"] = VectorXr(self.RAWDataProc.GATED[ichan]["IM"][ipm])
  922. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IP"] = VectorXr(self.RAWDataProc.GATED[ichan]["IP"][ipm])
  923. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " NR"] = VectorXr(self.RAWDataProc.GATED[ichan]["NR"][ipm])
  924. #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " STD" ] = VectorXr(self.RAWDataProc.GATED[ichan]["SIGMA"][ipm])
  925. # we have gated data
  926. # Window edges
  927. # Window centres
  928. with open(SaveStr, 'w') as outfile:
  929. #for line in self.logText:
  930. # outfile.write(line+"\n")
  931. yaml.dump(self.YamlNode, outfile)
  932. yaml.dump(INFO, outfile) #, default_flow_style=False)
  933. def SavePreprocess(self):
  934. #if "Saved" not in self.YamlNode.Processing.keys():
  935. # self.YamlNode.Processing["Saved"] = []
  936. #self.YamlNode.Processing["Saved"].append(datetime.datetime.now().isoformat())
  937. #self.Log()
  938. import pickle, os
  939. try:
  940. with open('.akvo.last.path') as f:
  941. fpath = f.readline()
  942. pass
  943. except IOError as e:
  944. fpath = '.'
  945. fdir = os.path.dirname(fpath)
  946. # Pickle the preprocessed data dictionary
  947. SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Pickle (*.dmp)")
  948. spath,filen=os.path.split(str(SaveStr[0]))
  949. f = open('.akvo.last.path', 'w')
  950. f.write( str(spath) ) # prompt last file
  951. save = open(SaveStr[0], 'wb')
  952. # Add some extra info
  953. INFO = {}
  954. INFO["pulseType"] = self.RAWDataProc.pulseType
  955. INFO["prePulseDelay"] = self.RAWDataProc.prePulseDelay
  956. INFO["interpulseDelay"] = self.RAWDataProc.interpulseDelay
  957. INFO["transFreq"] = self.RAWDataProc.transFreq
  958. INFO["pulseLength"] = self.RAWDataProc.pulseLength
  959. INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance
  960. INFO["samp"] = self.RAWDataProc.samp
  961. INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments
  962. INFO["deadTime"] = self.RAWDataProc.deadTime
  963. INFO["transFreq"] = self.RAWDataProc.transFreq
  964. INFO["headerstr"] = str(self.headerstr)
  965. INFO["nDAQVersion"] = self.RAWDataProc.nDAQVersion
  966. INFO["log"] = yaml.dump( self.YamlNode )
  967. # 1.6.4 and on
  968. INFO["Instrument"] = self.RAWDataProc.Instrument
  969. if self.RAWDataProc.Instrument == "MIDI 2":
  970. INFO["MIDIGain"] = self.RAWDataProc.MIDIGain
  971. INFO["datadir"] = self.RAWDataProc.datadir
  972. TXRX = []
  973. for ir in range(0, self.ui.txRxTable.rowCount() ):
  974. txrx = []
  975. for ic in range(0, self.ui.txRxTable.columnCount() ):
  976. txrx.append( self.ui.txRxTable.item(ir, ic).text() )
  977. TXRX.append(txrx)
  978. INFO["TXRX"] = TXRX
  979. if "Stacking" in self.YamlNode.Stacking.keys():
  980. INFO["sigma"] = self.RawDataProc.sigma
  981. if "Gate integrate" in self.YamlNode.Stacking.keys():
  982. INFO["GATED"] = self.RAWDataProc.GATED
  983. #print("META SAVE")
  984. #print("INFO log", INFO["log"])
  985. self.RAWDataProc.DATADICT["INFO"] = INFO
  986. pickle.dump(self.RAWDataProc.DATADICT, save)
  987. #pickle.dump(self.RAWDataProc, save) # doesn't work :-(
  988. save.close()
  989. # Export XML file suitable for USGS ScienceBase Data Release
  990. def ExportXML(self):
  991. """ This is a filler function for use by USGS collaborators
  992. """
  993. return 42
  994. def OpenPreprocess(self):
  995. import pickle
  996. try:
  997. with open('.akvo.last.path') as f:
  998. fpath = f.readline()
  999. pass
  1000. except IOError as e:
  1001. fpath = '.'
  1002. #filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', '.')
  1003. fpath = QtWidgets.QFileDialog.getOpenFileName(self, 'Open preprocessed file', fpath, r"Pickle Files (*.dmp)")[0]
  1004. f = open('.akvo.last.path', 'w')
  1005. f.write( str(fpath) ) # prompt last file
  1006. self.ui.logTextBrowser.clear()
  1007. self.logText = []
  1008. if len(fpath) == 0:
  1009. return
  1010. pfile = open(fpath,'rb')
  1011. unpickle = pickle.Unpickler(pfile)
  1012. self.connectGMRDataProcessor()
  1013. self.RAWDataProc.DATADICT = unpickle.load()
  1014. # This line causes Akvo to crash, if the header file is no longer there. We don't need to load the
  1015. # file. TODO, need to disable "Load Data" in Load command though, as that is no longer possible.
  1016. #self.RAWDataProc.readHeaderFile(self.RAWDataProc.DATADICT["INFO"]["headerstr"])
  1017. self.headerstr = self.RAWDataProc.DATADICT["INFO"]["headerstr"]
  1018. self.RAWDataProc.pulseType = self.RAWDataProc.DATADICT["INFO"]["pulseType"]
  1019. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  1020. self.RAWDataProc.pulseLength = self.RAWDataProc.DATADICT["INFO"]["pulseLength"]
  1021. self.RAWDataProc.TuneCapacitance = self.RAWDataProc.DATADICT["INFO"]["TuneCapacitance"]
  1022. self.RAWDataProc.samp = self.RAWDataProc.DATADICT["INFO"]["samp"]
  1023. self.RAWDataProc.nPulseMoments = self.RAWDataProc.DATADICT["INFO"]["nPulseMoments"]
  1024. self.RAWDataProc.deadTime = self.RAWDataProc.DATADICT["INFO"]["deadTime"]
  1025. self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"]
  1026. self.RAWDataProc.nDAQVersion = self.RAWDataProc.DATADICT["INFO"]["nDAQVersion"]
  1027. #self.RAWDataProc.prePulseDelay = self.RAWDataProc.DATADICT["INFO"]["prePulseDelay"]
  1028. self.RAWDataProc.dt = 1./self.RAWDataProc.samp
  1029. self.RAWDataProc.Instrument = self.RAWDataProc.DATADICT["INFO"]["Instrument"]
  1030. if self.RAWDataProc.DATADICT["INFO"]["Instrument"] == "MIDI 2":
  1031. self.RAWDataProc.Instrument = "MIDI 2"
  1032. self.RAWDataProc.MIDIGain = self.RAWDataProc.DATADICT["INFO"]["MIDIGain"]
  1033. self.RAWDataProc.datadir = self.RAWDataProc.DATADICT["INFO"]["datadir"]
  1034. self.dataChan = self.RAWDataProc.DATADICT[ self.RAWDataProc.DATADICT["PULSES"][0] ]["chan"]
  1035. # Keep backwards compatibility with prior saved pickles???
  1036. #self.ui.logTextBrowser.clear()
  1037. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  1038. #for a in self.logText:
  1039. # self.ui.logTextBrowser.append(str(a))
  1040. #self.ui.logTextBrowser
  1041. #self.ui.logTextBrowser.clear()
  1042. #print ( self.RAWDataProc.DATADICT["INFO"]["log"] )
  1043. if "TXRX" in self.RAWDataProc.DATADICT["INFO"].keys():
  1044. TXRX = self.RAWDataProc.DATADICT["INFO"]["TXRX"]
  1045. self.ui.txRxTable.setRowCount( len(TXRX))
  1046. for irow, row in enumerate(TXRX):
  1047. for icol, val in enumerate(row):
  1048. pCell = QtWidgets.QTableWidgetItem()
  1049. pCell.setText( val )
  1050. pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
  1051. self.ui.txRxTable.setItem(irow, icol, pCell)
  1052. self.logText = self.RAWDataProc.DATADICT["INFO"]["log"] # YAML
  1053. parse = yaml.load( self.logText, Loader=yaml.Loader )
  1054. self.YamlNode = AkvoYamlNode( ) #self.logText )
  1055. self.YamlNode.Akvo_VERSION = (yaml.load( self.logText, Loader=yaml.Loader )).Akvo_VERSION
  1056. AKVO_VERSION = np.array(self.YamlNode.Akvo_VERSION.split("."), dtype=int)
  1057. if AKVO_VERSION[0] >= 1 and AKVO_VERSION[1] >= 2 and AKVO_VERSION[2] >= 3:
  1058. self.RAWDataProc.interpulseDelay = self.RAWDataProc.DATADICT["INFO"]["interpulseDelay"]
  1059. self.YamlNode.Import = OrderedDict(parse.Import)
  1060. self.YamlNode.Processing = list(parse.Processing)
  1061. self.YamlNode.Stacking = OrderedDict(parse.Stacking)
  1062. self.YamlNode.META = OrderedDict(parse.META)
  1063. self.logGUI()
  1064. self.Log()
  1065. #self.ui.logTextBrowser.append( yaml.dump(self.YamlNode)) #, default_flow_style=False) )
  1066. #except KeyError:
  1067. # pass
  1068. # Remove "Saved" and "Loaded" from processing flow
  1069. #if "Loaded" not in self.YamlNode.Processing.keys():
  1070. # self.YamlNode.Processing["Loaded"] = []
  1071. #self.YamlNode.Processing["Loaded"].append(datetime.datetime.now().isoformat())
  1072. #self.Log()
  1073. if "Stacking" in self.YamlNode.Stacking.keys():
  1074. self.RAWDataProc.sigma = self.RAWDataProc.DATADICT["sigma"]
  1075. # check to see if gate integration has been done, and it's ready to send to Merlin
  1076. if "Gate integrate" in self.YamlNode.Stacking.keys():
  1077. self.RAWDataProc.GATED = self.RAWDataProc.DATADICT["GATED"]
  1078. self.ui.actionExport_Preprocessed_Dataset.setEnabled(True)
  1079. #self.ui.plotGI.setEnabled(True)
  1080. # If we got this far, enable all the widgets
  1081. self.ui.lcdNumberTauPulse1.setEnabled(True)
  1082. self.ui.lcdNumberNuTx.setEnabled(True)
  1083. self.ui.lcdNumberTuneuF.setEnabled(True)
  1084. self.ui.lcdNumberSampFreq.setEnabled(True)
  1085. self.ui.lcdNumberNQ.setEnabled(True)
  1086. self.ui.headerFileBox.setEnabled(True)
  1087. self.ui.headerFileBox.setChecked( True )
  1088. self.headerBoxShrink()
  1089. #self.ui.headerBox2.setVisible(True)
  1090. self.ui.inputRAWParametersBox.setEnabled(False)
  1091. self.ui.loadDataPushButton.setEnabled(True)
  1092. # make plots as you import the datasetmost
  1093. self.ui.plotImportCheckBox.setEnabled(True)
  1094. self.ui.plotImportCheckBox.setChecked(True)
  1095. # enable the LCDs
  1096. self.ui.lcdNumberFID1Length.setEnabled(1)
  1097. self.ui.lcdNumberFID2Length.setEnabled(1)
  1098. self.ui.lcdNumberResampFreq.setEnabled(1)
  1099. self.ui.lcdTotalDeadTime.setEnabled(1)
  1100. # enable META tab
  1101. self.ui.METATab.setEnabled(1)
  1102. self.ui.siteBox.setEnabled(1)
  1103. #self.ui.lcdTotalDeadTime.display( 1e3*self.RAWDataProc.DATADICT["INFO"]["deadTime"] )
  1104. self.ui.headerFileTextBrowser.clear( )
  1105. self.ui.headerFileTextBrowser.append( self.RAWDataProc.DATADICT["INFO"]["headerstr"] )
  1106. if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
  1107. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  1108. self.ui.lcdTotalDeadTime.display( round(1e3*(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1]), 3) )
  1109. #print("CALC DEAD", (1e3*(self.RAWDataProc.prePulseDelay))) # - (self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1])), 3) )
  1110. if u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
  1111. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  1112. self.ui.lcdTotalDeadTime.display( 1e3 * (self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 2"]["PULSE_TIMES"][-1]) )
  1113. # Update info from the header into the GUI
  1114. self.ui.pulseTypeTextBrowser.clear()
  1115. self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType)
  1116. self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq)
  1117. self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0])
  1118. self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance)
  1119. self.ui.lcdNumberResampFreq.display(self.RAWDataProc.samp)
  1120. self.ui.lcdNumberSampFreq.display(50000) # TODO, if non GMR is supported, query
  1121. self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments)
  1122. self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime)
  1123. self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq )
  1124. if self.RAWDataProc.pulseType != "FID":
  1125. self.ui.lcdNumberTauPulse2.setEnabled(1)
  1126. self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1])
  1127. self.ui.lcdNumberTauDelay.setEnabled(1)
  1128. self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay)
  1129. self.ui.FIDProcComboBox.clear()
  1130. if self.RAWDataProc.pulseType == "4PhaseT1" or self.RAWDataProc.pulseType == "T1":
  1131. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  1132. self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") #, const QVariant & userData = QVariant() )
  1133. self.ui.FIDProcComboBox.insertItem(2, "Both") #, const QVariant & userData = QVariant() )
  1134. if len( self.RAWDataProc.DATADICT["PULSES"]) == 2:
  1135. self.ui.FIDProcComboBox.setCurrentIndex (2)
  1136. elif self.RAWDataProc.DATADICT["PULSES"][0] == "Pulse 1":
  1137. self.ui.FIDProcComboBox.setCurrentIndex (0)
  1138. else:
  1139. self.ui.FIDProcComboBox.setCurrentIndex (1)
  1140. elif self.RAWDataProc.pulseType == "FID":
  1141. self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() )
  1142. self.ui.FIDProcComboBox.setCurrentIndex (0)
  1143. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  1144. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  1145. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  1146. self.RAWDataProc.progressTrigger.connect(self.updateProgressBar)
  1147. self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP)
  1148. self.RAWDataProc.doneTrigger.connect(self.doneStatus)
  1149. self.enableAll()
  1150. def loadMIDI2(self):
  1151. #################################################
  1152. # Check to make sure we are ready to process
  1153. # Header
  1154. if self.RAWDataProc == None:
  1155. err_msg = "You need to load a header first."
  1156. reply = QtWidgets.QMessageBox.critical(self, 'Error',
  1157. err_msg) #, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1158. return
  1159. # Stacks
  1160. try:
  1161. self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]"))
  1162. except:
  1163. err_msg = "You need to set your stacks correctly.\n" + \
  1164. "This should be a Python Numpy interpretable list\n" + \
  1165. "of stack indices. For example 1:24 or 1:4,8:24"
  1166. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1167. return
  1168. ######################
  1169. # Qs
  1170. #####################
  1171. #print("text", self.ui.QLineEdit.text())
  1172. if self.ui.QLineEdit.text() == "":
  1173. self.pulseMoments = [-1]
  1174. print("Setting pulse moments to [-1]")
  1175. else:
  1176. try:
  1177. self.pulseMoments = np.array(eval(str("np.r_["+self.ui.QLineEdit.text())+"]"))
  1178. except:
  1179. err_msg = "You need to set your pulse moments correctly.\n" + \
  1180. "This should be a Python Numpy interpretable list\n" + \
  1181. "of stack indices. For example 1:24 or 1:4,8:24"
  1182. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1183. ###################
  1184. # Data Channels
  1185. ###################
  1186. try:
  1187. self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]"))
  1188. except:
  1189. #QMessageBox messageBox;
  1190. #messageBox.critical(0,"Error","An error has occured !");
  1191. #messageBox.setFixedSize(500,200);
  1192. #quit_msg = "Are you sure you want to exit the program?"
  1193. #reply = QtWidgets.QMessageBox.question(self, 'Message',
  1194. # quit_msg, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1195. err_msg = "You need to set your data channels correctly.\n" + \
  1196. "This should be a Python Numpy interpretable list\n" + \
  1197. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  1198. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  1199. "1:3 is not inclusive of 3 and is the same as 1,2 "
  1200. reply = QtWidgets.QMessageBox.critical(self, 'Error',
  1201. err_msg) #, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1202. return
  1203. #############################
  1204. # Reference Channels
  1205. # TODO make sure no overlap between data and ref channels
  1206. self.refChan = np.array( () )
  1207. if str(self.ui.refChanLineEdit.text()): # != "none":
  1208. try:
  1209. self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]"))
  1210. except:
  1211. err_msg = "You need to set your reference channels correctly.\n" + \
  1212. "This should be a Python Numpy interpretable list\n" + \
  1213. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  1214. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  1215. "1:3 is not inclusive of 3 and is the same as 1,2 "
  1216. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1217. return
  1218. #####################################################
  1219. # Load data
  1220. self.lock("loading MIDI 2 dataset")
  1221. self.procThread = thread.start_new_thread(self.RAWDataProc.loadMIDI2, \
  1222. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  1223. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  1224. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.pulseMoments,
  1225. self.ui.plotImportCheckBox.isChecked() )) #, self))
  1226. self.YamlNode.Import["MIDI Header"] = self.headerstr
  1227. self.YamlNode.Import["opened"] = datetime.datetime.now().isoformat()
  1228. self.YamlNode.Import["pulse Type"] = str(self.RAWDataProc.pulseType)
  1229. self.YamlNode.Import["stacks"] = self.procStacks.tolist()
  1230. self.YamlNode.Import["data channels"] = self.dataChan.tolist()
  1231. self.YamlNode.Import["reference channels"] = self.refChan.tolist()
  1232. self.YamlNode.Import["pulse records"] = str(self.ui.FIDProcComboBox.currentText())
  1233. self.YamlNode.Import["instrument dead time"] = (1e-3 * self.ui.DeadTimeSpinBox.value( ))
  1234. self.Log ( )
  1235. # enable META tab
  1236. self.ui.METATab.setEnabled(1)
  1237. self.ui.siteBox.setEnabled(1)
  1238. # should be already done
  1239. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  1240. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  1241. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  1242. #self.ui.ProcessedBox.setEnabled(True)
  1243. self.ui.lcdNumberFID1Length.setEnabled(1)
  1244. self.ui.lcdNumberFID2Length.setEnabled(1)
  1245. self.ui.lcdNumberResampFreq.setEnabled(1)
  1246. self.ui.lcdTotalDeadTime.setEnabled(1)
  1247. self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) )
  1248. #self.ui.lcdTotalDeadTime.display( round(1e3*(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1]), 3) )
  1249. #self.ui.lcdNumberFID1Length.display(0)
  1250. #self.ui.lcdNumberFID2Length.display(0)
  1251. #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  1252. self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget)
  1253. self.ui.mplwidget.draw()
  1254. def loadRAW(self):
  1255. #################################################
  1256. # Check to make sure we are ready to process
  1257. # Header
  1258. if self.RAWDataProc == None:
  1259. err_msg = "You need to load a header first."
  1260. reply = QtWidgets.QMessageBox.critical(self, 'Error',
  1261. err_msg) #, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1262. return
  1263. # Stacks
  1264. try:
  1265. self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]"))
  1266. except:
  1267. err_msg = "You need to set your stacks correctly.\n" + \
  1268. "This should be a Python Numpy interpretable list\n" + \
  1269. "of stack indices. For example 1:24 or 1:4,8:24"
  1270. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1271. return
  1272. # Qs
  1273. #print("pulse moment text", len(self.ui.QLineEdit.text()))
  1274. if self.ui.QLineEdit.text() == "":
  1275. self.pulseMoments = [-1]
  1276. else:
  1277. try:
  1278. self.pulseMoments = np.array(eval(str("np.r_["+self.ui.QLineEdit.text())+"]"))
  1279. except:
  1280. err_msg = "You need to set your pulse moments correctly.\n" + \
  1281. "This should be a Python Numpy interpretable list\n" + \
  1282. "of stack indices. For example 1:24 or 1:4,8:25"
  1283. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1284. # Data Channels
  1285. #Chan = np.arange(0,9,1)
  1286. try:
  1287. self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]"))
  1288. except:
  1289. #QMessageBox messageBox;
  1290. #messageBox.critical(0,"Error","An error has occured !");
  1291. #messageBox.setFixedSize(500,200);
  1292. #quit_msg = "Are you sure you want to exit the program?"
  1293. #reply = QtWidgets.QMessageBox.question(self, 'Message',
  1294. # quit_msg, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1295. err_msg = "You need to set your data channels correctly.\n" + \
  1296. "This should be a Python Numpy interpretable list\n" + \
  1297. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  1298. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  1299. "1:3 is not inclusive of 3 and is the same as 1,2 "
  1300. reply = QtWidgets.QMessageBox.critical(self, 'Error',
  1301. err_msg) #, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
  1302. return
  1303. #############################
  1304. # Reference Channels
  1305. # TODO make sure no overlap between data and ref channels
  1306. self.refChan = np.array( () )
  1307. if str(self.ui.refChanLineEdit.text()): # != "none":
  1308. try:
  1309. self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]"))
  1310. except:
  1311. err_msg = "You need to set your reference channels correctly.\n" + \
  1312. "This should be a Python Numpy interpretable list\n" + \
  1313. "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \
  1314. "valid GMR data channels fall between 1 and 8. Note that\n" +\
  1315. "1:3 is not inclusive of 3 and is the same as 1,2 "
  1316. QtWidgets.QMessageBox.critical(self, 'Error', err_msg)
  1317. return
  1318. #####################################################
  1319. # Load data
  1320. self.lock("loading RAW GMR dataset")
  1321. if self.RAWDataProc.pulseType == "FID":
  1322. self.procThread = thread.start_new_thread(self.RAWDataProc.loadFIDData, \
  1323. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  1324. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  1325. 1e-3 * self.ui.DeadTimeSpinBox.value( ),
  1326. self.ui.plotImportCheckBox.isChecked() )) #, self))
  1327. elif self.RAWDataProc.pulseType == "4PhaseT1":
  1328. self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  1329. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  1330. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  1331. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  1332. elif self.RAWDataProc.pulseType == "T1":
  1333. self.procThread = thread.start_new_thread(self.RAWDataProc.loadT1Data, \
  1334. (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  1335. str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  1336. 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  1337. #self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \
  1338. # (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \
  1339. # str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \
  1340. # 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self))
  1341. self.YamlNode.Import["GMR Header"] = self.headerstr
  1342. self.YamlNode.Import["opened"] = datetime.datetime.now().isoformat()
  1343. self.YamlNode.Import["pulse Type"] = str(self.RAWDataProc.pulseType)
  1344. self.YamlNode.Import["stacks"] = self.procStacks.tolist()
  1345. self.YamlNode.Import["data channels"] = self.dataChan.tolist()
  1346. self.YamlNode.Import["reference channels"] = self.refChan.tolist()
  1347. self.YamlNode.Import["pulse records"] = str(self.ui.FIDProcComboBox.currentText())
  1348. self.YamlNode.Import["instrument dead time"] = (1e-3 * self.ui.DeadTimeSpinBox.value( ))
  1349. self.Log ( )
  1350. # enable META tab
  1351. self.ui.METATab.setEnabled(1)
  1352. self.ui.siteBox.setEnabled(1)
  1353. # should be already done
  1354. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  1355. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  1356. # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  1357. #self.ui.ProcessedBox.setEnabled(True)
  1358. self.ui.lcdNumberFID1Length.setEnabled(1)
  1359. self.ui.lcdNumberFID2Length.setEnabled(1)
  1360. self.ui.lcdNumberResampFreq.setEnabled(1)
  1361. self.ui.lcdTotalDeadTime.setEnabled(1)
  1362. self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) )
  1363. #self.ui.lcdTotalDeadTime.display( round(1e3*(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]-self.RAWDataProc.DATADICT["Pulse 1"]["PULSE_TIMES"][-1]), 3) )
  1364. #self.ui.lcdNumberFID1Length.display(0)
  1365. #self.ui.lcdNumberFID2Length.display(0)
  1366. #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  1367. self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget)
  1368. self.ui.mplwidget.draw()
  1369. def Log(self):
  1370. #for line in yaml.dump(self.YamlNode, default_flow_style=False):
  1371. #for line in nlogText:
  1372. # self.ui.logTextBrowser.append( line )
  1373. # self.logText.append( line )
  1374. self.ui.logTextBrowser.clear()
  1375. self.ui.logTextBrowser.append( yaml.dump(self.YamlNode ))
  1376. def disable(self):
  1377. self.ui.inputRAWParametersBox.setEnabled(False)
  1378. self.ui.BandPassBox.setEnabled(False)
  1379. self.ui.downSampleGroupBox.setEnabled(False)
  1380. self.ui.windowFilterGroupBox.setEnabled(False)
  1381. self.ui.harmonicBox.setEnabled(False)
  1382. # self.ui.despikeGroupBox.setEnabled(False)
  1383. self.ui.adaptBox.setEnabled(False)
  1384. self.ui.adaptFDBox.setEnabled(False)
  1385. self.ui.qCalcGroupBox.setEnabled(False)
  1386. self.ui.FDSmartStackGroupBox.setEnabled(False)
  1387. self.ui.sumDataBox.setEnabled(False)
  1388. self.ui.qdGroupBox.setEnabled(False)
  1389. self.ui.gateBox.setEnabled(False)
  1390. def enableAll(self):
  1391. self.enableDSP()
  1392. self.enableQC()
  1393. def enableDSP(self):
  1394. # Bandpass filter
  1395. self.ui.BandPassBox.setEnabled(True)
  1396. self.ui.BandPassBox.setChecked(True)
  1397. self.ui.bandPassGO.setEnabled(False) # need to design first
  1398. self.ui.plotBP.setEnabled(True)
  1399. self.ui.plotBP.setChecked(True)
  1400. # downsample
  1401. self.ui.downSampleGroupBox.setEnabled(True)
  1402. self.ui.downSampleGroupBox.setChecked(True)
  1403. # window
  1404. self.ui.windowFilterGroupBox.setEnabled(True)
  1405. self.ui.windowFilterGroupBox.setChecked(True)
  1406. # Despike
  1407. # self.ui.despikeGroupBox.setEnabled(True)
  1408. # self.ui.despikeGroupBox.setChecked(False)
  1409. # Adaptive filtering
  1410. self.ui.adaptBox.setEnabled(True)
  1411. self.ui.adaptBox.setChecked(True)
  1412. self.ui.plotRLS.setEnabled(True)
  1413. # FD Adaptive filtering
  1414. self.ui.adaptFDBox.setEnabled(True)
  1415. self.ui.adaptFDBox.setChecked(False)
  1416. # Harmonic
  1417. self.ui.harmonicBox.setEnabled(True)
  1418. self.ui.harmonicBox.setChecked(True)
  1419. self.LCDHarmonics()
  1420. self.LCDHarmonics2()
  1421. # sum group box
  1422. try:
  1423. if len(self.dataChan) > 1:
  1424. self.ui.sumDataBox.setEnabled(True)
  1425. self.ui.sumDataBox.setChecked(False)
  1426. except:
  1427. pass
  1428. # Quadrature Detect
  1429. self.ui.qdGroupBox.setEnabled(True)
  1430. self.ui.qdGroupBox.setChecked(True)
  1431. self.enableQC()
  1432. def enableQC(self):
  1433. # Q calc
  1434. self.ui.qCalcGroupBox.setEnabled(True)
  1435. self.ui.qCalcGroupBox.setChecked(True)
  1436. # FD SmartStack
  1437. self.ui.FDSmartStackGroupBox.setEnabled(True)
  1438. self.ui.FDSmartStackGroupBox.setChecked(True)
  1439. # Quadrature detect
  1440. try:
  1441. for pulse in self.RAWDataProc.DATADICT["PULSES"]:
  1442. np.shape(self.RAWDataProc.DATADICT[pulse]["Q"])
  1443. self.RAWDataProc.DATADICT["stack"]
  1444. self.ui.qdGroupBox.setEnabled(True)
  1445. self.ui.qdGroupBox.setChecked(True)
  1446. except:
  1447. self.ui.qdGroupBox.setEnabled(False)
  1448. self.ui.qdGroupBox.setChecked(False)
  1449. # Gating
  1450. try:
  1451. self.RAWDataProc.DATADICT["CA"]
  1452. self.ui.gateBox.setEnabled(True)
  1453. self.ui.gateBox.setChecked(True)
  1454. except:
  1455. self.ui.gateBox.setEnabled(False)
  1456. self.ui.gateBox.setChecked(False)
  1457. def despikeFilter(self):
  1458. self.lock("despike filter")
  1459. thread.start_new_thread(self.RAWDataProc.despike, \
  1460. (self.ui.windowSpinBox.value(), \
  1461. self.ui.thresholdSpinBox.value(), \
  1462. str(self.ui.replComboBox.currentText()), \
  1463. self.ui.rollOnSpinBox.value(), \
  1464. self.ui.despikeInterpWinSpinBox.value(),
  1465. self.ui.mplwidget))
  1466. def calcQ(self):
  1467. if "Calc Q" not in self.YamlNode.Stacking.keys():
  1468. #print("In CalcQ", yaml.dump(self.YamlNode.Processing) )
  1469. self.YamlNode.Stacking["Calc Q"] = True
  1470. #print( yaml.dump(self.YamlNode.Processing) )
  1471. self.Log()
  1472. else:
  1473. err_msg = "Q values have already been calculated"
  1474. reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1475. err_msg)
  1476. return
  1477. self.lock("pulse moment calculation")
  1478. thread.start_new_thread(self.RAWDataProc.effectivePulseMoment, \
  1479. (self.ui.CentralVSpinBox.value(), \
  1480. self.ui.mplwidget))
  1481. def harmonicModel(self):
  1482. self.lock("harmonic noise modelling")
  1483. Harm = OrderedDict()
  1484. Harm["STEP " + str(len(self.YamlNode.Processing))] = "Harmonic modelling"
  1485. Harm["NF"] = str( self.ui.NHarmonicsFreqsSpin.value() )
  1486. Harm["Segments"] = str( self.ui.NSegments.value() )
  1487. Harm["Proc. ref."] = self.ui.harmRef.isChecked()
  1488. if self.ui.searchAll.currentText() == "All":
  1489. Harm["search"] = self.ui.searchAll.currentText()
  1490. Search = False
  1491. else:
  1492. #Harm["search"] = self.ui.searchAll.currentText()
  1493. Harm["search"] = str(self.ui.Nsearch.value())
  1494. Search = self.ui.Nsearch.value()
  1495. if self.ui.boundsCheck.isChecked():
  1496. Harm["Bounds"] = str(self.ui.bounds.value())
  1497. Bounds = self.ui.bounds.value()
  1498. else:
  1499. Harm["Bounds"] = self.ui.boundsCheck.isChecked()
  1500. Bounds = 0
  1501. Harm["f0K1"] = str( self.ui.f0K1Spin.value() )
  1502. Harm["f0KN"] = str( self.ui.f0KNSpin.value() )
  1503. Harm["f0Ks"] = str( self.ui.f0KsSpin.value() )
  1504. Harm["f0"] = str( self.ui.f0Spin.value() )
  1505. if self.ui.NHarmonicsFreqsSpin.value() > 1:
  1506. Harm["f1K1"] = str( self.ui.f1K1Spin.value() )
  1507. Harm["f1KN"] = str( self.ui.f1KNSpin.value() )
  1508. Harm["f1Ks"] = str( self.ui.f1KsSpin.value() )
  1509. Harm["f1"] = str( self.ui.f1Spin.value() )
  1510. self.YamlNode.Processing.append(Harm)
  1511. self.Log()
  1512. thread.start_new_thread(self.RAWDataProc.harmonicModel, \
  1513. ( \
  1514. self.ui.NHarmonicsFreqsSpin.value(), \
  1515. self.ui.f0Spin.value(), \
  1516. self.ui.f0K1Spin.value(), \
  1517. self.ui.f0KNSpin.value(), \
  1518. self.ui.f0KsSpin.value(), \
  1519. self.ui.NSegments.value(), \
  1520. self.ui.f1Spin.value(), \
  1521. self.ui.f1K1Spin.value(), \
  1522. self.ui.f1KNSpin.value(), \
  1523. self.ui.f1KsSpin.value(), \
  1524. Search, \
  1525. Bounds, \
  1526. self.ui.harmRef.isChecked(), \
  1527. self.ui.plotHarmonic.isChecked(), \
  1528. self.ui.mplwidget \
  1529. ) \
  1530. )
  1531. def FDSmartStack(self):
  1532. if "TD stack" not in self.YamlNode.Stacking.keys():
  1533. self.YamlNode.Stacking["TD stack"] = {}
  1534. self.YamlNode.Stacking["TD stack"]["outlier"] = str( self.ui.outlierTestCB.currentText() )
  1535. self.YamlNode.Stacking["TD stack"]["cutoff"] = str( self.ui.MADCutoff.value() )
  1536. self.Log()
  1537. else:
  1538. err_msg = "TD noise cancellation has already been applied!"
  1539. reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1540. err_msg)
  1541. return
  1542. self.lock("time-domain smart stack")
  1543. thread.start_new_thread(self.RAWDataProc.TDSmartStack, \
  1544. (str(self.ui.outlierTestCB.currentText()), \
  1545. self.ui.MADCutoff.value(),
  1546. self.ui.mplwidget))
  1547. def adaptFilter(self):
  1548. self.lock("TD noise cancellation filter")
  1549. # Log processing
  1550. Adapt = OrderedDict()
  1551. Adapt["STEP " + str(len(self.YamlNode.Processing)) ] = "TD noise cancellation"
  1552. #print(Adapt) # this locks STEP in as first...
  1553. Adapt["n_Taps"] = self.ui.MTapsSpinBox.value()
  1554. Adapt["lambda"] = self.ui.adaptLambdaSpinBox.value()
  1555. Adapt["truncate"] = self.ui.adaptTruncateSpinBox.value()
  1556. Adapt["mu"] = self.ui.adaptMuSpinBox.value()
  1557. Adapt["PCA"] = self.ui.PCAComboBox.currentText()
  1558. #Adapt # this locsk in the dict ordering...
  1559. #print(Adapt) # this locks in the dict...
  1560. self.YamlNode.Processing.append(Adapt)
  1561. self.Log( )
  1562. thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \
  1563. (self.ui.MTapsSpinBox.value(), \
  1564. self.ui.adaptLambdaSpinBox.value(), \
  1565. self.ui.adaptTruncateSpinBox.value(), \
  1566. self.ui.adaptMuSpinBox.value(), \
  1567. str(self.ui.PCAComboBox.currentText()), \
  1568. self.ui.plotRLS.isChecked(), \
  1569. self.ui.mplwidget))
  1570. def sumDataChans(self):
  1571. self.lock("Summing data channels")
  1572. Sum = OrderedDict()
  1573. Sum["STEP " + str(len(self.YamlNode.Processing))] = "Channel sum"
  1574. self.YamlNode.Processing.append(Sum)
  1575. self.Log( )
  1576. self.dataChan = [self.dataChan[0]]
  1577. self.ui.sumDataBox.setEnabled(False)
  1578. thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, self.ui.sumType.currentText(), self.ui.sumAll.isChecked() ) )
  1579. def adaptFilterFD(self):
  1580. self.lock("FD noise cancellation filter")
  1581. thread.start_new_thread(self.RAWDataProc.adaptiveFilterFD, \
  1582. (str(self.ui.windowTypeComboBox.currentText()), \
  1583. self.ui.windowBandwidthSpinBox.value(), \
  1584. self.ui.CentralVSpinBox.value(), \
  1585. self.ui.mplwidget))
  1586. def logGUI(self):
  1587. # You have a race condiditon where the GUI is modifying the Yaml node while you are updating it
  1588. # hence, we need to cache these. More elegant solutions exist
  1589. if "B_0" in self.YamlNode.META:
  1590. B0 = self.YamlNode.META["B_0"]["intensity"]
  1591. Bdec = self.YamlNode.META["B_0"]["dec"]
  1592. Binc = self.YamlNode.META["B_0"]["inc"]
  1593. if "DateTime" in self.YamlNode.META:
  1594. [Date,Time] = self.YamlNode.META["DateTime"].split("T")
  1595. year,month,day = Date.split("-")
  1596. if "Temp" in self.YamlNode.META:
  1597. temp = float(self.YamlNode.META["Temp"])
  1598. if "Coordinates" in self.YamlNode.META:
  1599. UTM = self.YamlNode.META["Coordinates"]["UTM"]
  1600. LatBand = self.YamlNode.META["Coordinates"]["LatBand"]
  1601. Ellipsoid = self.YamlNode.META["Coordinates"]["ellipsoid"]
  1602. # and set
  1603. if "Location" in self.YamlNode.META:
  1604. self.ui.locEdit.setText( self.YamlNode.META["Location"] )
  1605. if "Field Notes" in self.YamlNode.META:
  1606. self.ui.txtComments.setText( self.YamlNode.META["Field Notes"] )
  1607. if "B_0" in self.YamlNode.META:
  1608. self.ui.incSpinBox.setValue( Binc )
  1609. self.ui.decSpinBox.setValue( Bdec )
  1610. self.ui.intensitySpinBox.setValue( B0 )
  1611. if "DateTime" in self.YamlNode.META:
  1612. self.ui.dateEdit.setDate( datetime.date(int(year), int(month), int(day)) )
  1613. self.ui.timeEdit.setTime( datetime.time.fromisoformat( Time ) )
  1614. if "Temp" in self.YamlNode.META:
  1615. self.ui.tempSpinBox.setValue(temp)
  1616. if "Coordinates" in self.YamlNode.META:
  1617. self.ui.UTMzone.setCurrentText(UTM)
  1618. self.ui.latBand.setCurrentText(LatBand)
  1619. self.ui.ellipsoid.setCurrentText(Ellipsoid)
  1620. def logSite(self):
  1621. self.YamlNode.META["Location"] = self.ui.locEdit.text()
  1622. self.YamlNode.META["Coordinates"] = OrderedDict()
  1623. self.YamlNode.META["Coordinates"]["UTM"] = self.ui.UTMzone.currentText()
  1624. self.YamlNode.META["Coordinates"]["LatBand"] = self.ui.latBand.currentText()
  1625. self.YamlNode.META["Coordinates"]["ellipsoid"] = self.ui.ellipsoid.currentText()
  1626. self.YamlNode.META["DateTime"] = self.ui.dateEdit.date().toString("yyyy-MM-dd") + "T" + str( self.ui.timeEdit.time().toString("hh:mm") )
  1627. self.YamlNode.META["Temp"] = self.ui.tempSpinBox.value()
  1628. self.YamlNode.META["B_0"] = OrderedDict()
  1629. self.YamlNode.META["B_0"]["inc"] = self.ui.incSpinBox.value()
  1630. self.YamlNode.META["B_0"]["dec"] = self.ui.decSpinBox.value()
  1631. self.YamlNode.META["B_0"]["intensity"] = self.ui.intensitySpinBox.value()
  1632. self.YamlNode.META["Field Notes"] = self.ui.txtComments.toPlainText()
  1633. self.YamlNode.META["Loops"] = OrderedDict()
  1634. for loop in self.loops:
  1635. print(self.loops[loop])
  1636. self.YamlNode.META["Loops"][loop] = loop + ".pwa"
  1637. self.Log()
  1638. def bandPassFilter(self):
  1639. self.lock("bandpass filter")
  1640. # Log processing
  1641. Band = OrderedDict()
  1642. Band["STEP " + str(len(self.YamlNode.Processing))] = "Bandpass filter"
  1643. Band["central_nu"] = str(self.ui.CentralVSpinBox.value())
  1644. Band["passband"] = str(self.ui.passBandSpinBox.value())
  1645. Band["stopband"] = str(self.ui.stopBandSpinBox.value())
  1646. Band["gpass"] = str(self.ui.gpassSpinBox.value())
  1647. Band["gstop"] = str(self.ui.gstopSpinBox.value())
  1648. Band["type"] = str(self.ui.fTypeComboBox.currentText())
  1649. self.YamlNode.Processing.append(Band)
  1650. self.Log( )
  1651. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value()
  1652. self.ui.lcdTotalDeadTime.display( nv )
  1653. thread.start_new_thread(self.RAWDataProc.bandpassFilter, \
  1654. (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() ))
  1655. def downsample(self):
  1656. self.lock("resampling")
  1657. # Log processing
  1658. Resample = OrderedDict()
  1659. Resample["STEP "+ str(len(self.YamlNode.Processing))] = "Resample"
  1660. Resample["downsample factor"] = str(self.ui.downSampleSpinBox.value())
  1661. Resample["truncate length"] = str(self.ui.truncateSpinBox.value())
  1662. self.YamlNode.Processing.append(Resample)
  1663. self.Log( )
  1664. thread.start_new_thread(self.RAWDataProc.downsample, \
  1665. (self.ui.truncateSpinBox.value(), \
  1666. self.ui.downSampleSpinBox.value(), \
  1667. self.ui.dsPlot.isChecked(), \
  1668. self.ui.mplwidget))
  1669. def quadDet(self):
  1670. method = ['trf','dogbox','lm'][int(self.ui.QDMethod.currentIndex())]
  1671. loss = ['linear','soft_l1','cauchy','huber'][int(self.ui.QDLoss.currentIndex())]
  1672. # allow overwrite of Quad Det.
  1673. self.YamlNode.Stacking["Quadrature detection"] = {}
  1674. self.YamlNode.Stacking["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1675. self.YamlNode.Stacking["Quadrature detection"]["method"] = method
  1676. self.YamlNode.Stacking["Quadrature detection"]["loss"] = loss
  1677. self.Log()
  1678. #if "Quadrature detection" not in self.YamlNode.Processing.keys():
  1679. # self.YamlNode.Processing["Quadrature detection"] = {}
  1680. # self.YamlNode.Processing["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1681. # self.Log()
  1682. #else:
  1683. # self.YamlNode.Processing["Quadrature detection"] = {}
  1684. # self.YamlNode.Processing["Quadrature detection"]["trim"] = str( self.ui.trimSpin.value() )
  1685. # self.Log()
  1686. #err_msg = "Quadrature detection has already been done!"
  1687. #reply =QtWidgets.QMessageBox.critical(self, 'Error',
  1688. # err_msg)
  1689. #return
  1690. self.lock("quadrature detection")
  1691. thread.start_new_thread(self.RAWDataProc.quadDet, \
  1692. (self.ui.trimSpin.value(), method, loss, self.ui.mplwidget))
  1693. self.ui.plotQD.setEnabled(True)
  1694. def plotQD(self):
  1695. self.lock("plot QD")
  1696. thread.start_new_thread(self.RAWDataProc.plotQuadDet, \
  1697. (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget))
  1698. def gateIntegrate(self):
  1699. if "Gate integrate" not in self.YamlNode.Stacking.keys():
  1700. self.YamlNode.Stacking["Gate integrate"] = {}
  1701. self.YamlNode.Stacking["Gate integrate"]["gpd"] = str(self.ui.GPDspinBox.value( ) )
  1702. self.Log()
  1703. self.lock("gate integration")
  1704. thread.start_new_thread(self.RAWDataProc.gateIntegrate, \
  1705. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), self.ui.mplwidget))
  1706. self.ui.actionExport_Preprocessed_Dataset.setEnabled(True)
  1707. self.ui.plotGI.setEnabled(True)
  1708. def plotGI(self):
  1709. self.lock("plot gate integrate")
  1710. thread.start_new_thread(self.RAWDataProc.plotGateIntegrate, \
  1711. (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), \
  1712. self.ui.QDType_2.currentIndex(), self.ui.mplwidget))
  1713. def designFilter(self):
  1714. [bord, fe] = self.RAWDataProc.designFilter( \
  1715. self.ui.CentralVSpinBox.value(), \
  1716. self.ui.passBandSpinBox.value(), \
  1717. self.ui.stopBandSpinBox.value(), \
  1718. self.ui.gpassSpinBox.value(), \
  1719. self.ui.gstopSpinBox.value(), \
  1720. str(self.ui.fTypeComboBox.currentText()),
  1721. self.ui.mplwidget
  1722. )
  1723. self.ui.lcdNumberFilterOrder.display(bord)
  1724. self.ui.lcdNumberFTauDead.display(1e3*fe)
  1725. self.ui.bandPassGO.setEnabled(1)
  1726. ################################################################
  1727. # Hack for MacOS to force refresh of group box and plot
  1728. # this has an undesirable effect that it causes the groupbox to 'jump' up
  1729. # TODO come up with a better solution
  1730. self.ui.mplwidget.hide()
  1731. self.ui.mplwidget.show()
  1732. self.ui.BandPassBox.hide()
  1733. self.ui.BandPassBox.show()
  1734. def windowFilter(self):
  1735. self.lock("window filter")
  1736. # Log processing
  1737. Window = OrderedDict()
  1738. Window["STEP " + str(len(self.YamlNode.Processing))] = "Window filter"
  1739. Window["type"] = str(self.ui.windowTypeComboBox.currentText())
  1740. Window["width"] = str(self.ui.windowBandwidthSpinBox.value())
  1741. Window["centre"] = str(self.ui.CentralVSpinBox.value() )
  1742. Window["trim"] = str(self.ui.windowTrim.isChecked())
  1743. self.YamlNode.Processing.append(Window)
  1744. self.Log( )
  1745. if self.ui.windowTrim.isChecked():
  1746. nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdWinDead.value()
  1747. self.ui.lcdTotalDeadTime.display( nv )
  1748. thread.start_new_thread(self.RAWDataProc.windowFilter, \
  1749. (str(self.ui.windowTypeComboBox.currentText()), \
  1750. self.ui.windowBandwidthSpinBox.value(), \
  1751. self.ui.CentralVSpinBox.value(), \
  1752. self.ui.windowTrim.isChecked(), \
  1753. self.ui.mplwidget))
  1754. def designFDFilter(self):
  1755. mPulse = "None"
  1756. if u"Pulse 1" in self.RAWDataProc.DATADICT.keys():
  1757. mPulse = u"Pulse 1"
  1758. elif u"Pulse 2" in self.RAWDataProc.DATADICT.keys():
  1759. mPulse = u"Pulse 2"
  1760. a,b,c,d,dead,ndead = self.RAWDataProc.computeWindow( \
  1761. mPulse,
  1762. self.ui.windowBandwidthSpinBox.value(), \
  1763. self.ui.CentralVSpinBox.value(), \
  1764. str(self.ui.windowTypeComboBox.currentText()), \
  1765. self.ui.mplwidget )
  1766. self.ui.lcdWinDead.display(dead)
  1767. ################################################################
  1768. # Hack for MacOS to force refresh of group box and plot
  1769. # this has an undesirable effect that it causes the groupbox to 'jump' up
  1770. # TODO come up with a better solution
  1771. self.ui.mplwidget.hide()
  1772. self.ui.mplwidget.show()
  1773. self.ui.windowFilterGroupBox.hide()
  1774. self.ui.windowFilterGroupBox.show()
  1775. def updateProgressBar(self, percent):
  1776. self.ui.barProgress.setValue(percent)
  1777. def updateProc(self):
  1778. if str(self.ui.FIDProcComboBox.currentText()) == "Pulse 1":
  1779. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  1780. elif str(self.ui.FIDProcComboBox.currentText()) == "Pulse 2":
  1781. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  1782. else:
  1783. self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0])
  1784. self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0])
  1785. self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp )
  1786. def doneStatus(self): # unlocks GUI
  1787. self.ui.statusbar.clearMessage ( )
  1788. self.ui.barProgress.hide()
  1789. self.updateProc()
  1790. self.enableAll()
  1791. def lock(self, string):
  1792. self.ui.statusbar.showMessage ( string )
  1793. self.ui.barProgress.show()
  1794. self.ui.barProgress.setValue(0)
  1795. self.disable()
  1796. def unlock(self):
  1797. self.ui.statusbar.clearMessage ( )
  1798. self.ui.barProgress.hide()
  1799. self.enableAll()
  1800. def done(self):
  1801. self.ui.statusbar.showMessage ( "" )
  1802. ################################################################
  1803. ################################################################
  1804. # Boiler plate main function
  1805. import pkg_resources
  1806. from pkg_resources import resource_string
  1807. import matplotlib.image as mpimg
  1808. import matplotlib.pyplot as plt
  1809. from akvo.gui.logo import plotLogo
  1810. def main():
  1811. # splash screen logo
  1812. logo = pkg_resources.resource_filename(__name__, 'akvo.png')
  1813. logo2 = pkg_resources.resource_filename(__name__, 'akvo2.png')
  1814. qApp = QtWidgets.QApplication(sys.argv)
  1815. ssplash = True
  1816. if ssplash:
  1817. pixmap = QtGui.QPixmap(logo)
  1818. splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  1819. splash.show()
  1820. aw = ApplicationWindow()
  1821. #img=mpimg.imread(logo)
  1822. for ax in [ aw.ui.mplwidget ]:
  1823. ax.fig.clear()
  1824. subplot = ax.fig.add_subplot(211)
  1825. # old logo plot
  1826. ax.fig.patch.set_facecolor( None )
  1827. ax.fig.patch.set_alpha( .0 )
  1828. #subplot.imshow(img)
  1829. #ax.fig.patch.set_visible(False)
  1830. subplot.axis('off')
  1831. plotLogo(subplot)
  1832. subplot.xaxis.set_major_locator(plt.NullLocator())
  1833. subplot.yaxis.set_major_locator(plt.NullLocator())
  1834. subplot2 = ax.fig.add_subplot(212)
  1835. subplot2.text(0.5, 1.,'surface NMR workbench',
  1836. horizontalalignment='center',
  1837. verticalalignment='center',
  1838. size=22,
  1839. transform = subplot2.transAxes)
  1840. subplot2.xaxis.set_major_locator(plt.NullLocator())
  1841. subplot2.yaxis.set_major_locator(plt.NullLocator())
  1842. subplot2.axis('off')
  1843. ax.draw()
  1844. if ssplash:
  1845. splash.showMessage("Loading modules")
  1846. splash.finish(aw)
  1847. #time.sleep(1)
  1848. aw.setWindowTitle("Akvo v"+str(VERSION))
  1849. aw.show()
  1850. qApp.setWindowIcon(QtGui.QIcon(logo2))
  1851. sys.exit(qApp.exec_())
  1852. if __name__ == "__main__":
  1853. main()