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

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