Surface NMR processing and inversion GUI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

akvoGUI.py 67KB

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