Borehole NMR processing
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.

main.py 76KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774
  1. #!/usr/bin/env python
  2. from __future__ import division
  3. import sys, os
  4. sys.path.append( '../.' )
  5. import matplotlib
  6. matplotlib.use('Qt4Agg')
  7. matplotlib.rcParams['backend.qt4']='PySide'
  8. #matplotlib.rcParams['mathtext.fontset']='stixsans' # sans-serif in plots
  9. from MRProc import MRProc
  10. from pwctimeWhite import pwcTime
  11. from logbarrier import *
  12. from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
  13. from pylab import meshgrid
  14. from matplotlib.ticker import MaxNLocator
  15. #from pyqtgraph.widgets.MatplotlibWidget import MatplotlibWidget
  16. from MatplotlibWidget import MatplotlibWidget
  17. #from PyQt5 import QtCore, QtGui
  18. from PySide import QtCore, QtGui
  19. from borehole2 import Ui_MainWindow
  20. import brewer2mpl
  21. import numpy as np
  22. from matplotlib.figure import Figure
  23. import matplotlib.pyplot as plt
  24. from multiprocessing import Lock, Process, Queue, Pool, current_process
  25. #from pylasdev import *
  26. # thread is good for GUI/process control, but use multiprocess if you want to exploit many cores
  27. # in traditional HPC type application
  28. try:
  29. import thread
  30. except ImportError:
  31. import _thread as thread #Py3K changed it.
  32. class MyForm(QtGui.QMainWindow): #, threading.Thread):
  33. def __init__(self, parent=None):
  34. #QtGui.QWidget.__init__(self, parent)
  35. super(MyForm, self).__init__(parent)
  36. self.ui = Ui_MainWindow()
  37. self.ui.setupUi(self)
  38. # Add progressbar to statusbar
  39. self.ui.barProgress = QtGui.QProgressBar()
  40. self.ui.statusbar.addPermanentWidget(self.ui.barProgress, 0);
  41. self.ui.barProgress.setMaximumSize(100, 16777215);
  42. self.ui.barProgress.hide();
  43. # signals and slots
  44. QtCore.QObject.connect(self.ui.actionLoadRecord, QtCore.SIGNAL("triggered()"), self.openSingleRecord )
  45. QtCore.QObject.connect(self.ui.actionLoadRecords, QtCore.SIGNAL("triggered()"), self.openMultipleRecords )
  46. QtCore.QObject.connect(self.ui.actionLoadLogSeries, QtCore.SIGNAL("triggered()"), self.openVCLogSeries )
  47. QtCore.QObject.connect(self.ui.actionOpen_CMR_Log, QtCore.SIGNAL("triggered()"), self.openCMRLog )
  48. # preprocess
  49. QtCore.QObject.connect(self.ui.WindowStackGO, QtCore.SIGNAL("clicked()"), self.windowAndStack )
  50. QtCore.QObject.connect(self.ui.envelopeGO, QtCore.SIGNAL("clicked()"), self.envelope )
  51. QtCore.QObject.connect(self.ui.phaseGO, QtCore.SIGNAL("clicked()"), self.phase )
  52. QtCore.QObject.connect(self.ui.gateGO, QtCore.SIGNAL("clicked()"), self.gate )
  53. QtCore.QObject.connect(self.ui.batchLoadDataPushButton, QtCore.SIGNAL("clicked()"), self.batch )
  54. # inversion
  55. QtCore.QObject.connect(self.ui.monoGO, QtCore.SIGNAL("clicked()"), self.mono )
  56. QtCore.QObject.connect(self.ui.multiGO, QtCore.SIGNAL("clicked()"), self.multi )
  57. # Diffusion
  58. QtCore.QObject.connect(self.ui.JgGO, QtCore.SIGNAL("clicked()"), self.jgFit )
  59. QtCore.QObject.connect(self.ui.diffusionGO, QtCore.SIGNAL("clicked()"), self.diffusion )
  60. QtCore.QObject.connect( self.ui.jgComboBox, QtCore.SIGNAL("currentIndexChanged(int)"), self.jgc ) #this, SLOT(comboBoxIndexChanged()) )
  61. # forward modelling
  62. QtCore.QObject.connect(self.ui.modelGO, QtCore.SIGNAL("clicked()"), self.model )
  63. # \kappa estimates
  64. QtCore.QObject.connect(self.ui.sdrGO, QtCore.SIGNAL("clicked()"), self.sdr )
  65. QtCore.QObject.connect(self.ui.tcGO, QtCore.SIGNAL("clicked()"), self.tc )
  66. #QtCore.QObject.connect(self.ui.windowFilterGO, QtCore.SIGNAL("clicked()"), self.windowFilter )
  67. #QtCore.QObject.connect(self.ui.despikeGO, QtCore.SIGNAL("clicked()"), self.despikeFilter )
  68. #QtCore.QObject.connect(self.ui.adaptGO, QtCore.SIGNAL("clicked()"), self.adaptFilter )
  69. #QtCore.QObject.connect(self.ui.adaptFDGO, QtCore.SIGNAL("clicked()"), self.adaptFilterFD )
  70. ##########################################################################
  71. # modelling Table
  72. self.ui.modelTableWidget.setRowCount(10)
  73. self.ui.modelTableWidget.setColumnCount(5)
  74. #Labels = QtCore.QStringList( ) # ["A", "B", "C"] )
  75. self.ui.modelTableWidget.setHorizontalHeaderLabels( ["Top [m]","Bottom [m]","T_2 [ms]","Porosity [%]", "noise std"] )
  76. self.ui.modelTableWidget.cellChanged.connect(self.cellChanged)
  77. self.ui.modelTableWidget.setDragDropOverwriteMode(False)
  78. self.ui.modelTableWidget.setDragEnabled(True)
  79. self.ui.modelTableWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
  80. #item->setFlags(item->flags() & ~(Qt::ItemIsDropEnabled))
  81. # Only for CMR data
  82. self.burst = False
  83. # Dictionary of procesors
  84. self.ORS = {}
  85. # Do we have a whole hole dataset?
  86. self.DepthProfile = False
  87. def jgc(self):
  88. print("JCD Docc")
  89. if ( self.ui.jgComboBox.currentText() == "Constant" ):
  90. self.ui.jgcSpinBox.setEnabled(True)
  91. else:
  92. self.ui.jgcSpinBox.setEnabled(False)
  93. def ORSConnect(self, ff):
  94. self.ORS[ff] = MRProc( ) # Fast
  95. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar)
  96. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  97. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableINV()"), self.enableINV)
  98. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotRAW()"), self.plotRAW)
  99. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotWIN()"), self.plotWIN)
  100. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotENV()"), self.plotENV)
  101. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotLOG10ENV()"), self.plotLOG10ENV)
  102. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotMONO()"), self.plotMONO)
  103. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotBI()"), self.plotBI)
  104. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("plotDIST(int)"), self.plotDIST)
  105. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  106. QtCore.QObject.connect(self, QtCore.SIGNAL("doneStatus2()"), self.doneStatus)
  107. def doneStatus(self): #, enable): # unlocks GUI
  108. self.ui.statusbar.clearMessage ( )
  109. self.ui.barProgress.hide()
  110. #self.updateProc()
  111. #self.enableAll()
  112. def lock(self, string):
  113. self.ui.statusbar.showMessage ( string )
  114. self.ui.barProgress.show()
  115. self.ui.barProgress.setValue(0)
  116. self.disable()
  117. def unlock(self):
  118. self.ui.statusbar.clearMessage ( )
  119. self.ui.barProgress.hide()
  120. self.enableAll()
  121. def done(self):
  122. self.ui.statusbar.showMessage ( "" )
  123. def updateProgressBar(self, percent):
  124. self.ui.barProgress.setValue(percent)
  125. def disable(self):
  126. self.ui.WindowStackBox.setEnabled(False)
  127. self.ui.envelopeGroupBox.setEnabled(False)
  128. self.ui.phaseGroupBox.setEnabled(False)
  129. self.ui.gateGroupBox.setEnabled(False)
  130. #self.ui.adaptFDBox.setEnabled(False)
  131. #self.ui.qCalcGroupBox.setEnabled(False)
  132. #self.ui.FDSmartStackGroupBox.setEnabled(False)
  133. def enableAll(self):
  134. self.enableDSP()
  135. #self.enableQC()
  136. def enableDSP(self):
  137. # Bandpass filter
  138. self.ui.WindowStackBox.setEnabled(True)
  139. self.ui.WindowStackBox.setChecked(True)
  140. #self.ui.WindowStackGO.setEnabled(False) # default on need to design first
  141. # downsample
  142. self.ui.envelopeGroupBox.setEnabled(True)
  143. self.ui.envelopeGroupBox.setChecked(True)
  144. # Phase
  145. self.ui.phaseGroupBox.setEnabled(True)
  146. self.ui.phaseGroupBox.setChecked(True)
  147. # FD Adaptive filtering
  148. #self.ui.adaptFDBox.setEnabled(True)
  149. #self.ui.adaptFDBox.setChecked(True)
  150. #self.enableQC()
  151. #QtCore.QObject.connect(self.ORS, QtCore.SIGNAL("updateProc()"), self.updateProc)
  152. def enableINV(self):
  153. # time gating
  154. self.ui.gateGroupBox.setEnabled(True)
  155. self.ui.gateGroupBox.setChecked(True)
  156. # mono
  157. self.ui.monoGroupBox.setEnabled(True)
  158. self.ui.monoGroupBox.setChecked(True)
  159. # bi
  160. #self.ui.biGroupBox.setEnabled(True)
  161. #self.ui.biGroupBox.setChecked(True)
  162. # dist
  163. self.ui.multiGroupBox.setEnabled(True)
  164. self.ui.multiGroupBox.setChecked(True)
  165. def windowAndStack(self, ff=None):
  166. if ff == None:
  167. ff = self.headerstr[0]
  168. #self.ORS.WindowAndStack() # Fast
  169. self.lock("window and stack records")
  170. #self.ORS = MRProc( ) # Fast
  171. #self.ORS.loadORSFile( self.headerstr )
  172. rawThread = thread.start_new_thread(self.ORS[ff].WindowAndStack, \
  173. (str(self.ui.fTypeComboBox.currentText()), self.ui.winTrimLeftSpinBox.value(), self.ui.winTrimRightSpinBox.value() ))
  174. self.ui.logTextBrowser.append( "Windowed and stack: " + str(self.ui.fTypeComboBox.currentText() ))
  175. def envelope(self, ff=None):
  176. if ff == None:
  177. ff = self.headerstr[0]
  178. self.lock("window and stack records")
  179. rawThread = thread.start_new_thread(self.ORS[ff].T2EnvelopeDetect, (self.ui.offsetSpinBox.value(),) )
  180. self.ui.logTextBrowser.append( "Envelope Detect: " + str(self.ui.fTypeComboBox.currentText() ))
  181. # Now we can do inversions or gate integraion
  182. #self.enableINV( )
  183. def phase(self, ff=None):
  184. if ff == None:
  185. ff = self.headerstr[0]
  186. self.lock("window and stack records")
  187. rawThread = thread.start_new_thread(self.ORS[ff].CorrectedAmplitude, (0,0) )
  188. self.ui.logTextBrowser.append( "Phase correct")
  189. def mono(self):
  190. self.lock("mono-exponential fit")
  191. # TODO thread this
  192. if self.ui.expComboBox.currentText() == "mono":
  193. for ff in self.headerstr:
  194. #rawThread = thread.start_new_thread(self.ORS[ str(ff) ].MonoFit, (self.ui.maskNSpinBox_2.value(), str(self.ui.interceptComboBox.currentText())) )
  195. self.ORS[ff].MonoFit(self.ui.maskNSpinBox_2.value(), str(self.ui.interceptComboBox.currentText()))
  196. self.ui.logTextBrowser.append( "mono-exponential fit")
  197. self.plotMONO()
  198. elif self.ui.expComboBox.currentText() == "bi":
  199. for ff in self.headerstr:
  200. #rawThread = thread.start_new_thread(self.ORS[ str(ff) ].MonoFit, (self.ui.maskNSpinBox_2.value(), str(self.ui.interceptComboBox.currentText())) )
  201. self.ORS[ff].BiFit(self.ui.maskNSpinBox_2.value(), str(self.ui.interceptComboBox.currentText()))
  202. self.ui.logTextBrowser.append( "bi-exponential fit")
  203. self.plotBI()
  204. def multiMP(self, q):
  205. # TODO consider use of pool here instead! Easiest way to limit number of processes
  206. # Pool does not like to use class member functions. There are workarounds but I can't be bothered.
  207. processes = []
  208. # Smooth = False
  209. # if str(self.ui.DistConstraint.currentText()) == "Smooth":
  210. # Smooth = True
  211. # elif str(self.ui.DistConstraint.currentText()) == "Smallest":
  212. # Smooth = False
  213. # else:
  214. # print ("Smooth operator my ass")
  215. # exit(3)
  216. for ff in self.headerstr:
  217. p = Process( target=self.ORS[ff].DistFitMP, args= (q, ff, 0, self.ui.maskNSpinBox_4.value(), self.ui.nT2SpinBox.value(), \
  218. 1e-3*self.ui.lowT2SpinBox.value(), 1e-3*self.ui.hiT2SpinBox.value(), self.ui.distT2Box.currentText(), \
  219. self.ui.DistConstraint.currentText(), self.ui.betaScale.value()
  220. ) )
  221. processes.append(p)
  222. return processes
  223. def multi(self):
  224. import pickle
  225. import multiprocessing
  226. self.lock("multi-exponential fit")
  227. q = Queue()
  228. procs = self.multiMP(q)
  229. zombies = []
  230. while len(procs) > 0:
  231. if len(multiprocessing.active_children()) < multiprocessing.cpu_count():
  232. p = procs.pop()
  233. p.start()
  234. zombies.append(p)
  235. # kill the zombies...well manage them again
  236. # joining like this is sort of problematic as it locks main thread
  237. # better to use some kind of signal.
  238. for p in zombies:
  239. p.join()
  240. # We are finished
  241. self.doneStatus()
  242. self.lock("parsing results")
  243. for ff in self.headerstr:
  244. tag = q.get() #['tag']) #q.get()
  245. Dict = pickle.load( open( str(tag)+".p", "rb" ) )
  246. #print (Dict)
  247. self.ORS[Dict['tag']].DistRes = Dict
  248. self.plotDISTPar()
  249. def plotDISTPar(self):
  250. self.plotDIST( self.ui.maskNSpinBox_4.value() )
  251. self.ui.qplot_2.draw()
  252. self.ui.qplot_3.draw()
  253. if (self.DepthProfile == True):
  254. dp = []
  255. mod = []
  256. for ff in self.headerstr:
  257. dp.append( self.ORS[ff].depth )
  258. mod.append( self.ORS[ff].DistRes['mod'] )
  259. #self.msp0.plot(self.ORS[ff].DistRes['Time'].T2Bins, self.ORS[ff].DistRes['mod'], linewidth=2, label="recovered")
  260. X,Y = meshgrid( self.ORS[ff].DistRes['Time'].T2Bins, dp )
  261. #self.mp.matshow(Data, aspect = 'auto')
  262. self.mp.pcolor(X,Y, np.array(mod), cmap = 'hot_r')
  263. #self.mp.set_ylim( self.mp.get_ylim()[::-1] )
  264. self.ui.qplot_4.draw()
  265. def cellChanged(self):
  266. # TODO consider building the model whenever this is called. Would be nice to be able to
  267. # do that. Would require instead dist of T2 I guess.
  268. jj = self.ui.modelTableWidget.currentColumn()
  269. ii = self.ui.modelTableWidget.currentRow()
  270. #if self.ui.modelTableWidget.item(ii, jj) == None:
  271. # return
  272. try:
  273. eval (str( self.ui.modelTableWidget.item(ii, jj).text() ))
  274. except:
  275. #print ("cell changed ERROR", str( self.ui.modelTableWidget.item(ii, jj).text() ) )
  276. #Error = QtGui.QErrorMessage()
  277. Error = QtGui.QMessageBox()
  278. #Error.showMessage("NOT A NUMERIC VALUE")
  279. Error.setWindowTitle("Error!")
  280. Error.setText("Non-numeric value encountered")
  281. Error.setDetailedText("Modelling parameters must be able to be cast into numeric values.")
  282. Error.exec_()
  283. def tc(self):
  284. """ Computes the permeabiliy based on Timur-Coates equation
  285. k = c phi^m (ffv/bfv)^n
  286. k = permeability
  287. phi = nmr porosity
  288. m = porosity exponent, 2-4 is standard.
  289. ffv = free fluid volume (T2 above cutoff)
  290. bfv = bound fluid volume (T2 below cutoff)
  291. n = fluid exponent 2 is standard
  292. c = prefactor
  293. cutoff = bfv : ffv cutoff, 33 ms is standard
  294. """
  295. if not self.ui.saveDatBox_3.isChecked():
  296. self.ui.qplot_5.getFigure().clf()
  297. #self.dd = self.ui.qplot_5.getFigure().add_subplot(141)
  298. #self.kp = self.ui.qplot_5.getFigure().add_subplot(142, sharey = self.dd)
  299. #self.kt = self.ui.qplot_5.getFigure().add_subplot(143, sharey = self.dd)
  300. #self.kk = self.ui.qplot_5.getFigure().add_subplot(144, sharey = self.dd)
  301. #self.ui.qplot_5.getFigure().tight_layout() # TODO tweak spacing tight is almost good.
  302. #plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
  303. # add_axes()
  304. self.dd = self.ui.qplot_5.getFigure().add_axes( [ .075, .15, .2, .8] , facecolor='black' )
  305. self.kp = self.ui.qplot_5.getFigure().add_axes( [ .300, .15, .2, .8] , sharey=self.dd )
  306. self.kt = self.ui.qplot_5.getFigure().add_axes( [ .525, .15, .2, .8] , sharey=self.dd )
  307. self.kk = self.ui.qplot_5.getFigure().add_axes( [ .750, .15, .2, .8] , sharey=self.dd )
  308. self.dc = self.ui.qplot_5.getFigure().add_axes( [ .075, .05, .2, .02] )
  309. #self.kkp = self.kp.twiny()
  310. self.kk.set_xlabel(r"$\kappa$ [mD]")
  311. self.kp.set_xlabel(r"$\phi$ [m$^3$ / m$^3$]")
  312. self.kt.set_xlabel(r"$T_2$ [s]")
  313. self.dd.set_xlabel(r"time [s]")
  314. self.dd.set_ylabel(r"depth [m]")
  315. #self.kt.set_ylabel(r"depth [m]")
  316. #self.kk.set_ylabel(r"depth [m]")
  317. # permeability and decay time in log10
  318. self.kk.set_xscale('log', basex=10)
  319. self.kt.set_xscale('log', basex=10)
  320. self.dd.set_title(r"CPMG time series")
  321. self.kp.set_title(r"NMR water (c,b,f)")
  322. self.kt.set_title(r"NMR $T_2$")
  323. self.kk.set_title(r"$\kappa_{NMR}$")
  324. #self.kt.xaxis.set_major_locator(MaxNLocator(5))
  325. #self.kk.xaxis.set_major_locator(MaxNLocator(5))
  326. c = self.ui.TC_c.value()
  327. m = self.ui.TC_m.value()
  328. n = self.ui.TC_n.value()
  329. cutoff = self.ui.TC_cutoff.value() * 1e-3
  330. cutoff2 = .003
  331. dp = []
  332. phi = []
  333. FFV = []
  334. BFV = []
  335. CBFV = []
  336. LogMeanT2 = []
  337. ii = 0
  338. dat = open("NMR-log.dat","w")
  339. dat.write( "#depth,phi,T_2ML,FFV,BFV,CBFV\n" )
  340. results = file("inversion.csv",'w')
  341. Data = np.zeros( (len(self.ORS), len(self.ORS[0].T2T)) )
  342. times = self.ORS[0].T2T
  343. depTol = np.abs(self.ORS[self.headerstr[0]].depth - self.ORS[self.headerstr[-1]].depth)
  344. t2scale = 100*depTol / len(self.ORS) #TODO adjust based on total depth, was 20
  345. for ff in self.headerstr:
  346. nT2 = len(self.ORS[ff].DistRes['Time'].T2Bins)
  347. dp.append( self.ORS[ff].depth )
  348. phi.append( np.sum( self.ORS[ff].DistRes['mod'] ) )
  349. LogMeanT2.append( np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / phi[ii] ) )
  350. FFV.append( np.sum( self.ORS[ff].DistRes['mod'][ self.ORS[ff].DistRes['Time'].T2Bins>=cutoff]) )
  351. BFV.append( np.sum( self.ORS[ff].DistRes['mod'][ np.logical_and( self.ORS[ff].DistRes['Time'].T2Bins<cutoff, self.ORS[ff].DistRes['Time'].T2Bins>=cutoff2) ] + 1e-6 ) ) # add small epsilon value
  352. CBFV.append( np.sum( self.ORS[ff].DistRes['mod'][ self.ORS[ff].DistRes['Time'].T2Bins<cutoff2]) + 1e-6 ) # epsilon
  353. self.kt.plot( self.ORS[ff].DistRes['Time'].T2Bins, dp[ii] - t2scale*self.ORS[ff].DistRes['mod'] , color='blue' )
  354. self.kt.fill_between( self.ORS[ff].DistRes['Time'].T2Bins, dp[ii] - t2scale*self.ORS[ff].DistRes['mod'], dp[ii]*np.ones( nT2 ), alpha=1, color='LimeGreen')
  355. Data[ff,:] = self.ORS[ff].T2D.imag
  356. for iid, val in enumerate(self.ORS[ff].DistRes['mod']):
  357. if iid == 0:
  358. for it2, t2b in enumerate( self.ORS[ff].DistRes['Time'].T2Bins ):
  359. if it2 == 0:
  360. results.write( "%1.4f" %(t2b) )
  361. else:
  362. results.write( ",%1.4f" %(t2b) )
  363. results.write("\n")
  364. results.write( "%1.4f" %(val) )
  365. else:
  366. results.write( ",%1.4f" %(val) )
  367. results.write("\n")
  368. dat.write( "%1.4f,%1.4f,%1.4f,%1.4f,%1.4f,%1.4f\n" %(dp[-1],phi[-1],LogMeanT2[-1],FFV[-1],BFV[-1],CBFV[-1]))
  369. #if np.abs( phi[-1] - (FFV[-1] + BFV[-1] + CBFV[-1]) ) > 1e-6:
  370. # print("mismatch", phi[-1] - (FFV[-1] + BFV[-1] + CBFV[-1]), CBFV[-1] )
  371. #else:
  372. # print("nope", CBFV[-1])
  373. ii += 1
  374. results.close()
  375. dat.close()
  376. #k = ((c*np.array(phi))**m) * ( (np.array(FFV)/np.array(BFV))**n)
  377. k = c * 1e4 * (np.array(phi)**m) * ((np.array(FFV)/(np.array(BFV)+np.array(CBFV)))**n)
  378. ############################################################
  379. # porosity logs
  380. # TI, TODO these fill_between cause errors with Javelin data? Why?
  381. #self.kp.plot( phi, dp , label = r"$\phi_{NMR}$", color='blue' )
  382. #try:
  383. # self.kp.fill_betweenx(np.array(dp), np.array(phi), alpha=1., color='blue' ) #, label = r"$BFV_{TC}$" )
  384. #except:
  385. # print ("shapes of dp and phi", np.shape(np.array(dp)), np.shape(np.array(phi)))
  386. FFV = np.array(FFV)
  387. BFV = np.array(BFV)
  388. CBFV = np.array(CBFV)
  389. # Plot cumulitive of all pore sizes below, that way the visible portion corresponds with the PWC
  390. self.kp.plot( FFV+BFV+CBFV , dp , label = r"$FFV_{TC}$", color='blue' ) # don't plot implicit
  391. self.kp.fill_betweenx(dp, FFV+BFV+CBFV, alpha=1, color='blue' ) #, label = r"$BFV_{TC}$" )
  392. self.kp.plot( BFV+CBFV, dp , label = r"$BFV_{TC}$" , color='green')
  393. self.kp.fill_betweenx(dp, BFV+CBFV, alpha=1, color='green' ) #, label = r"$BFV_{TC}$" )
  394. self.kp.plot( CBFV, dp , label = r"$CBFV_{TC}$" , color='brown')
  395. self.kp.fill_betweenx(dp, CBFV, alpha=1, color='brown' ) #, label = r"$BFV_{TC}$" )
  396. #ax.fill_between(xs, ys, where=ys>=d, interpolate=True, color='blue')
  397. self.kp.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  398. self.kp.set_xlim( [ 0, self.kp.get_xlim()[1] ] )
  399. ####################################################################################
  400. # Data Plot
  401. #self.dd.matshow()
  402. #X,Y = meshgrid( np.log10(times), dp )
  403. # pcolor cuts one spot, need to extrapolate
  404. ma = self.ui.maskNSpinBox_4.value()
  405. dp2 = np.append( dp, dp[-1]+(dp[-1]-dp[-2]) )
  406. times2 = np.append( times, times[-1]+(times[-1]-times[-2]) )
  407. times2 = times2[ma:]
  408. #times2 = np.append( times[ma:], times[ma:-1]+(times[-1]-times[-2]) )
  409. dp2 = dp2 - (dp[1]-dp[0]) *.5
  410. X,Y = meshgrid( times2, dp2 )
  411. #self.mp.matshow(Data, aspect = 'auto')
  412. #pc = self.dd.pcolor(X,Y, Data, cmap = 'coolwarm', vmin = 0)
  413. pc = self.dd.pcolor(X,Y, Data[:,ma:], cmap = 'viridis') #, vmin = -np.max(Data[:,ma:]))
  414. #pc = self.dd.pcolor(X,Y, Data, cmap = 'seismic_r') #, vmin=-.5, vmax=.5) #, vmin = 0)
  415. #self.dd.set_ylim( self.dd.get_ylim()[::-1] )
  416. np.savez("cmrdata",times2=times2,dp2=dp2,X=X, Y=Y, data=Data[:,ma:])
  417. self.dd.set_ylim( np.max(dp2), np.min(dp2) )
  418. self.dd.set_xlim( times2[0], times2[-1] )
  419. #self.dd.set_xlim( np.log10(times[0]), np.log10(times[-1]) )
  420. self.dd.set_xscale("log", nonposx='clip')
  421. ############################################################
  422. # decay logs
  423. #self.kt.plot( LogMeanT2, dp , label = r"$T_{2ML}$" )
  424. #self.kt.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ]) # use same range as others
  425. # Don't plot huge K's
  426. self.kk.set_xlim( [ min(self.kk.get_xlim()), 1e6 ]) # use same range as others
  427. # permeability logs
  428. self.kk.plot( k, dp , label = r"$\kappa_{TC}$", color='red' )
  429. #self.kk.set_ylim( [ max(self.kk.get_ylim()), min(self.kk.get_ylim()) ])
  430. self.kk.set_xlim( [ 1e-1, self.kk.get_xlim()[1] ] )
  431. self.kk.grid()
  432. # don't plot y axis labels, except on data plot (far left)
  433. #self.kk.axes.get_yaxis().set_ticks([])
  434. #self.kp.axes.get_yaxis().set_ticks([])
  435. #self.kt.axes.get_yaxis().set_ticks([])
  436. # above kills dd labels too
  437. plt.setp( self.kk.axes.get_yticklabels(), visible=False)
  438. plt.setp( self.kp.axes.get_yticklabels(), visible=False)
  439. plt.setp( self.kt.axes.get_yticklabels(), visible=False)
  440. #h1, l1 = self.kp.get_legend_handles_labels()
  441. #h2, l2 = self.kkp.get_legend_handles_labels()
  442. #self.kp.legend(h1+h2, l1+l2, numpoints=1)
  443. # try to avoid legends, they detract from logs
  444. #self.kp.legend()
  445. #self.kk.legend()
  446. #self.kt.legend()
  447. self.kp.xaxis.set_major_locator(MaxNLocator(3))
  448. #self.dd.xaxis.set_major_locator(MaxNLocator(3))
  449. cb = self.ui.qplot_5.getFigure().colorbar(pc, self.dc, orientation='horizontal')
  450. cb.solids.set_edgecolor("face")
  451. #tick_locator = MaxNLocator(nbins=5)
  452. cb.locator = MaxNLocator(5) #tick_locator
  453. cb.update_ticks()
  454. self.ui.qplot_5.draw()
  455. def sdr(self):
  456. """ Estimates permeability based on Schlumberger-Doll Research (SDR) equation
  457. \kappa = c \phi^m T_{2ML}^n
  458. """
  459. if not self.ui.saveDatBox_3.isChecked():
  460. self.ui.qplot_5.getFigure().clf()
  461. self.kp = self.ui.qplot_5.getFigure().add_subplot(131)
  462. self.kt = self.ui.qplot_5.getFigure().add_subplot(132)
  463. self.kk = self.ui.qplot_5.getFigure().add_subplot(133)
  464. self.kk.set_xlabel(r"$\kappa$ [mD]")
  465. self.kp.set_xlabel(r"$\phi$ [m$^3$ / m$^3$]")
  466. self.kt.set_xlabel(r"$T_2$ [s]")
  467. self.kp.set_ylabel(r"depth [m]")
  468. #self.kt.set_ylabel(r"depth [m]")
  469. #self.kk.set_ylabel(r"depth [m]")
  470. # permeability and decay time in log10
  471. self.kk.set_xscale('log', basex=10)
  472. self.kt.set_xscale('log', basex=10)
  473. self.kp.set_title(r"NMR water (b,t)")
  474. self.kt.set_title(r"NMR $T_2$")
  475. self.kk.set_title(r"$\kappa_{NMR}$")
  476. self.kp.xaxis.set_major_locator(MaxNLocator(4))
  477. #self.dd.xaxis.set_major_locator(MaxNLocator(4))
  478. #self.kt.xaxis.set_major_locator(MaxNLocator(5))
  479. #self.kk.xaxis.set_major_locator(MaxNLocator(5))
  480. #self.kp.set_title("permeability")
  481. c = self.ui.SDR_c.value()
  482. m = self.ui.SDR_m.value()
  483. n = self.ui.SDR_n.value()
  484. dp = []
  485. phi = []
  486. LogMeanT2 = []
  487. ii = 0
  488. for ff in self.headerstr:
  489. dp.append( self.ORS[ff].depth )
  490. phi.append( np.sum( self.ORS[ff].DistRes['mod'] ) )
  491. #theta = np.sum( self.ORS[ff].DistRes['mod'] )
  492. LogMeanT2.append( np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / phi[ii] ) )
  493. ii += 1
  494. #print ("LogMeanT2", LogMeanT2)
  495. # 1e3 converts to ms where c is designed for
  496. k = c*np.array(phi)**m * ((1e3 * np.array(LogMeanT2))**n)
  497. self.kp.plot( phi, dp , label = r"$\phi_{NMR}$" )
  498. self.kt.plot( LogMeanT2, dp , linewidth=2, color='blue', label = r"$T_{2ML}$" )
  499. self.kk.plot( k, dp , label = r"$\kappa_{SDR}$", color='blue' )
  500. self.kp.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  501. self.kk.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  502. self.kt.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  503. #h1, l1 = self.kp.get_legend_handles_labels()
  504. #h2, l2 = self.kkp.get_legend_handles_labels()
  505. #self.kp.legend(h1+h2, l1+l2, numpoints=1)
  506. #self.kkp.grid()
  507. self.ui.qplot_5.draw()
  508. def model(self):
  509. from pylab import meshgrid
  510. # TODO add noise std column which will be interesting for resolution analysis
  511. #self.ui.modelTableWidget.setColumnCount(4)
  512. #for ii in range( self.ui.modelTableWidget.rowCount() ):
  513. # for jj in range( self.ui.modelTableWidget.columnCount() ):
  514. # if self.ui.modelTableWidget.item(ii, jj) != None:
  515. # print( str(ii) + "\t" + str(jj) + "\t" + str( self.ui.modelTableWidget.item(ii, jj).text() ) )
  516. self.DepthProfile = True
  517. Bottom = self.ui.doubleSpinBoxBottom.value()
  518. Top = self.ui.doubleSpinBoxTop.value()
  519. Dz = self.ui.doubleSpinBoxDz.value()
  520. T = self.ui.doubleSpinBoxTTrain.value()
  521. TauE = 1e-3 * self.ui.doubleSpinBoxTauE.value()
  522. Mean = self.ui.doubleSpinBoxMean.value()
  523. Std = self.ui.doubleSpinBoxStd.value()
  524. times = np.arange(TauE, T, TauE)
  525. dp = np.arange(Bottom, Top, -Dz)
  526. Data = np.zeros( (len(dp), len(times)) )
  527. Noise = np.zeros( (len(dp), len(times)) )
  528. Mod = np.zeros( (len(dp) )) + 1e-6
  529. Por = np.zeros( (len(dp) ))
  530. Por = np.zeros( (len(dp) ))
  531. for ii in range( self.ui.modelTableWidget.rowCount() ):
  532. a = type(self.ui.modelTableWidget.item(ii, 0))
  533. if str(a) == "<class 'NoneType'>": # ugly hack needed by PySide for some strange reason.
  534. pass #print ("NONE")
  535. else: #if type(self.ui.modelTableWidget.item(ii, 0)) != None:
  536. #print ("type", type(self.ui.modelTableWidget.item(ii, 0)))
  537. for iid in range(len(dp)):
  538. #print self.ui.modelTableWidget.item(ii, 0).text(), dp[iid], self.ui.modelTableWidget.item(ii, 1).text()
  539. try:
  540. if dp[iid] > eval(str(self.ui.modelTableWidget.item(ii, 0).text()) ) and dp[iid] <= eval(str(self.ui.modelTableWidget.item(ii, 1).text()) ):
  541. Mod[iid] = 1e-3 * eval( str(self.ui.modelTableWidget.item(ii, 2).text() ))
  542. Por[iid] = 1e-2 * eval(str(self.ui.modelTableWidget.item(ii, 3).text() ))
  543. # Append the data for multi-exponential
  544. Data[iid, :] += Por[iid] * np.exp( -times/ Mod[iid] ) + np.random.normal( 0, eval(str( self.ui.modelTableWidget.item(ii,4).text())), len(times) )
  545. Noise[iid,:] += np.random.normal( 0, eval(str( self.ui.modelTableWidget.item(ii,4).text())), len(times) )
  546. except:
  547. pass
  548. self.ORS.clear() # = {}
  549. self.headerstr = [] #.clear() # = []
  550. for iid in range(len(dp)):
  551. self.headerstr.append( iid )
  552. self.ORS[iid] = MRProc( ) # Fast
  553. self.ORS[iid].NE = len(times)
  554. self.ORS[iid].TAUE = TauE
  555. self.ORS[iid].NS = 1 # TODO consider what to do here
  556. self.ORS[iid].T2T = times
  557. self.ORS[iid].T2D = Noise[iid,:] + 1j*Data[iid,:]
  558. self.ORS[iid].T2N = Noise[iid,:]
  559. self.ORS[iid].sigma = np.std( Noise[iid,:] )
  560. self.ORS[iid].depth = dp[iid]
  561. # Doom, why
  562. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  563. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("enableINV()"), self.enableINV)
  564. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  565. # enable gate integrate
  566. self.enableDSP()
  567. self.ui.bulkProcessGroupBox.setEnabled(True)
  568. self.ui.batchLoadDataPushButton.setEnabled(True)
  569. self.ui.gateGroupBox.setEnabled(True)
  570. # disable buttons, do flow
  571. self.ui.WindowStackBox.setChecked(False)
  572. self.ui.envelopeGroupBox.setChecked(False)
  573. self.ui.phaseGroupBox.setChecked(False)
  574. self.ui.gateGroupBox.setChecked(True)
  575. #self.ui.WindowStackGO.checked(False)
  576. #self.ui.envelopeGO.checked(False)
  577. #self.ui.phaseGO.checked(False)
  578. self.ui.gateGO.setEnabled(False)
  579. # Enable Inversions
  580. self.enableINV()
  581. #for iz in range(len(dp)):
  582. #Data[iz,:] = 1e-2*dp[iz] + np.exp(-times/.324)
  583. # Data[iz,:] = Por[iz] * np.exp( -times/ Mod[iz] )
  584. # OK, so now I need to get these into data container class
  585. # for now just make data and plot it
  586. if not self.ui.saveDatBox_2.isChecked():
  587. self.ui.qplot_4.getFigure().clf()
  588. self.mp = self.ui.qplot_4.getFigure().add_subplot(111)
  589. self.mp.set_title("synthetic data")
  590. X,Y = meshgrid( times, dp )
  591. #self.mp.matshow(Data, aspect = 'auto')
  592. self.mp.pcolor(X,Y, Data, cmap = 'hot_r')
  593. self.mp.set_ylim( self.mp.get_ylim()[::-1] )
  594. self.ui.qplot_4.draw()
  595. def jgFit(self):
  596. T2Bw = 1e-3 * self.ui.T2bwSpinBox.value()
  597. #T2Bw = 2.
  598. Times = {}
  599. Times2 = np.empty(0)
  600. TauE = []
  601. Data = np.empty(0) #{}
  602. Datap = np.empty(0) #{}
  603. Sigma = np.empty(0) #{}
  604. mask = self.ui.maskNSpinBox_5.value()
  605. for ff in self.headerstr:
  606. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  607. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  608. TauE.append(self.ORS[ff].TAUE)
  609. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  610. Datap = np.append( Datap, np.imag(self.ORS[ff].T2D)[mask::] / np.exp(-self.ORS[ff].T2T[mask::]/(self.ui.A0SpinBox.value()*T2Bw) ) )
  611. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  612. # Plot up data, TODO need a separate thread for this, unresponsive GUI
  613. #self.plotDIFF(Times2, Data, Sigma)
  614. #self.plotDIFF2(Times2, Data, Datap, Sigma)
  615. #############################################
  616. # Generate Kernel for inversion to J(G)
  617. Times = {}
  618. Times2 = np.empty(0)
  619. TauE = []
  620. Data = np.empty(0) #{}
  621. Sigma = np.empty(0) #{}
  622. mask = self.ui.maskNSpinBox_5.value()
  623. for ff in self.headerstr:
  624. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  625. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  626. TauE.append(self.ORS[ff].TAUE)
  627. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  628. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  629. self.GBins = np.linspace(self.ui.gminSpinBox.value(), self.ui.gmaxSpinBox.value(), num=self.ui.ngSpinBox.value(), endpoint=True)
  630. #self.GBins = np.logspace(np.log10(self.ui.gminSpinBox.value()), np.log10(self.ui.gmaxSpinBox.value()), num=self.ui.ngSpinBox.value(), endpoint=True)
  631. INV = pwcTime()
  632. INV.generateJGKernel(TauE, Times, 1e-5*self.ui.dwSpinBox.value() , self.GBins, self.ui.DTau.value())
  633. self.jgModel = logBarrier(INV.JG, Datap, MAXITER=500, sigma=Sigma, alpha=1e20) #, smooth=True) #
  634. pre = np.dot(INV.JG, self.jgModel)
  635. #self.plotDIFF(Times2, Data, Sigma, Datap) #pre)
  636. self.plotDIFF2(Times2, Data, Datap, Sigma, pre)
  637. # Plot model
  638. self.ui.qplot_7.getFigure().clf()
  639. self.msp0 = self.ui.qplot_7.getFigure().add_axes([.15,.2,.75,.65])
  640. self.msp0.plot(self.GBins, self.jgModel, color='black', linewidth=3)
  641. self.msp0.grid()
  642. self.msp0.set_xlabel("$J(G)$ [G/cm]")
  643. self.msp0.set_ylabel("intensity")
  644. self.ui.qplot_7.draw()
  645. #plt.show()
  646. def diffusion(self):
  647. from pylab import meshgrid
  648. #print ("Diffusion Inversion")
  649. Times = {}
  650. Times2 = np.empty(0)
  651. TauE = []
  652. Data = np.empty(0) #{}
  653. Sigma = np.empty(0) #{}
  654. mask = self.ui.maskNSpinBox_5.value()
  655. for ff in self.headerstr:
  656. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  657. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  658. TauE.append(self.ORS[ff].TAUE)
  659. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  660. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  661. self.INV = pwcTime()
  662. #self.D = np.linspace(1e-9*self.ui.Dmin.value(), 1e-5*self.ui.Dmax.value(), num=self.ui.nDBins.value(), endpoint=True)
  663. self.D = np.logspace(np.log10(1e-9*self.ui.Dmin.value()), np.log10(1e-5*self.ui.Dmax.value()), num=self.ui.nDBins.value(), endpoint=True)
  664. self.INV.setT2( 1e-3*self.ui.lowT2SpinBox.value(), 1e-3*self.ui.hiT2SpinBox.value(), self.ui.nT2SpinBox.value(), self.ui.distT2Box.currentText() )
  665. if self.ui.jgComboBox.currentText() == "Distribution":
  666. print("Using J(G) Distribution")
  667. self.INV.generateGDenv( TauE, Times, self.D, self.GBins, self.jgModel, self.ui.DTau.value() )
  668. else:
  669. print("Using constant G")
  670. self.INV.generateGDenv( TauE, Times, self.D, np.array([self.ui.jgcSpinBox.value()]), np.array([1.]) )
  671. # Plot up data, TODO need a separate thread for this, unresponsive GUI
  672. self.plotDIFF(Times2, Data, Sigma)
  673. # OK now invert TODO, need to speed this up. Sparse matrices and/or implicit ATWdTWdA?
  674. model = logBarrier(self.INV.GD, Data, MAXITER=500, sigma=Sigma, alpha=1e10, callback=None) #self.plotDmod) #, smooth=True) #
  675. pre = np.dot(self.INV.GD, model)
  676. self.plotDIFF(Times2, Data, Sigma, pre)
  677. self.plotDmod(model)
  678. def plotDmod(self, model):
  679. # plot models and fit
  680. self.DMod = np.reshape(model, (len(self.D), len(self.INV.T2Bins)))
  681. # Save to file for analysis
  682. print("saving D mod to dmod.bin")
  683. res = open('dmod.bin', 'wb')
  684. np.save(res, self.D)
  685. np.save(res, self.INV.T2Bins)
  686. np.save(res, model)
  687. #if not self.ui.saveModBox.isChecked():
  688. self.ui.qplot_7.getFigure().clf()
  689. self.msp0 = self.ui.qplot_7.getFigure().add_axes([.15,.2,.65,.65])
  690. self.csp0 = self.ui.qplot_7.getFigure().add_axes([.85,.2,.025,.65])
  691. #self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  692. #self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  693. #for ff in self.headerstr:
  694. #X,Y = meshgrid( np.concatenate( (np.array([.999*self.INV.T2Bins[0]]), self.INV.T2Bins) ), \
  695. # np.concatenate( (np.array([.999*self.D[0]]), self.D)) ) # pcolor needs an extra bin
  696. X,Y = meshgrid( self.INV.T2Bins, self.D ) # pcolor needs an extra bin
  697. #cmap = plt.get_cmap('hot_r') #'
  698. imsa = self.msp0.pcolor(X, Y, self.DMod, cmap='hot_r', edgecolors='w') #, rasterized=True)
  699. self.msp0.set_xlabel("$T_2$ [s]")
  700. self.msp0.set_ylabel("D [cm$^2$/s]")
  701. self.msp0.set_yscale('log', basey=10)
  702. self.msp0.set_xscale('log', basex=10)
  703. plt.colorbar(imsa, self.csp0) #self.msp0)
  704. #cb1 = mpl.colorbar.ColorbarBase(self.cbax, cmap=wmap,
  705. # norm=nnorm,
  706. # orientation='horizontal',
  707. # extend='both',
  708. # format = r'%i')
  709. #self.msp0.imshow( self.DMod, interpolation='bicubic' ) #self.ORS[ff].MonoRes['rt20'], self.ORS[ff].MonoRes['b0'], 'o', markersize=6, label="mono")
  710. # self.msp0.legend(numpoints=1)
  711. #plt.ylabel("D [cm$^2$/s]")
  712. #plt.xlabel("$T_2$ [s]")
  713. self.ui.qplot_7.draw()
  714. #print ("FINISHED DIFFUSION")
  715. def gate(self, ff=None):
  716. #print ("GATING")
  717. if ff == None:
  718. ff = self.headerstr[0]
  719. self.ui.logTextBrowser.append( "Gate integrate correct" + "GPD")
  720. self.lock("time gating")
  721. rawThread = thread.start_new_thread(self.ORS[ff].gateIntegrate, (self.ui.gpdSpinBox.value(),self.ui.stackEfficiency.value()) )
  722. #rawThread = thread.start_new_thread(self.ORS[ff].CorrectedAmplitude, (0,0) )
  723. #self.ui.logTextBrowser.append( "Envelope Detect: " + str(self.ui.fTypeComboBox.currentText() ))
  724. def openCMRLog(self):
  725. print("CMR log process")
  726. import scipy.io as sio
  727. try:
  728. with open('.akvo.cmr.last.path') as f:
  729. fpath = f.readline()
  730. pass
  731. except IOError as e:
  732. fpath = '.'
  733. self.DepthProfile == True
  734. self.burst = False # True
  735. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open Schlumberger CMR Log Series', fpath, r"CMR MATLAB (*.mat)" )]
  736. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  737. self.ui.headerFileTextBrowser.clear()
  738. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  739. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  740. self.ui.logTextBrowser.clear()
  741. path,filen=os.path.split(str(self.headerstr[0] ))
  742. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  743. f = open('.akvo.cmr.last.path', 'w')
  744. if str(self.headerstr[0]):
  745. f.write( str(self.headerstr[0]) ) # prompt last file
  746. self.ui.headerFileBox.setEnabled(True)
  747. #########################################
  748. # LOAD the data and do some basic work
  749. self.ORSConnect( str(self.headerstr[0]) )
  750. CMR_PHI_CONV = 0.00068 # this is temperature dependent, should be in files, but wasn't!
  751. self.lock("loading RAW record")
  752. matfile = self.headerstr[0]
  753. if fileExtension == ".mat":
  754. Data = sio.loadmat(self.headerstr[0])
  755. # the Schlumberger data has a burst mode at the end of the record which is designed only to capture
  756. # fast decays. I don't see a record of the number in the files, is often 30
  757. ne = np.shape(Data["echo_amp_x"].T[:,0])[0] - 30
  758. nb = 30 # number of burst echoes
  759. T2T = 2e-4 * np.arange(1, ne+1, 1) # .2 ms seems to be CMR standard, not in data files
  760. T2Tb = 2e-4 * np.arange(1, nb+1, 1) # burst times
  761. # T2T = np.concatenate( (T2T,T2Tb) )
  762. TAUE = T2T[3] - T2T[2]
  763. NS = 1
  764. self.ORS.clear() # = {}
  765. self.headerstr = [] #.clear() # = []
  766. # TODO query for depth step and data quality factor
  767. iiid = 0
  768. #################################
  769. dmin = 7672 # Morrow #
  770. dmax = 7707 # Morrow Bottom #
  771. #################################
  772. #dmin = 7672 - 150 # Morrow #
  773. #dmax = 7707 - 120 # Morrow Bottom #
  774. #dmin = 7672+10.25 # Morrow #
  775. #dmax = 7707-10.25 # Morrow Bottom #
  776. #dmin = 0
  777. #dmax = 7510
  778. #dmax = 10000
  779. for iid in range(len(Data['depth'])):
  780. dep = float(Data['depth'][iid])
  781. #if True:
  782. if dep > dmin and dep <= dmax:
  783. self.headerstr.append( iiid )
  784. self.ORS[iiid] = MRProc( ) # Fast
  785. self.ORS[iiid].NE = ne #len(Data['time'][:,0])
  786. self.ORS[iiid].TAUE = TAUE
  787. self.ORS[iiid].NS = 1 # TODO consider what to do here
  788. self.ORS[iiid].T2T = T2T
  789. self.ORS[iiid].T2Tb = T2Tb
  790. self.ORS[iiid].burst = False #True
  791. # long record
  792. self.ORS[iiid].T2D = CMR_PHI_CONV*Data["echo_amp_r"].T[0:ne,iid] - CMR_PHI_CONV*1j*Data["echo_amp_x"].T[0:ne,iid]
  793. # burst data
  794. self.ORS[iiid].T2Db = CMR_PHI_CONV*Data["echo_amp_r"].T[ne:,iid] - CMR_PHI_CONV*1j*Data["echo_amp_x"].T[ne:,iid]
  795. # both
  796. #self.ORS[iiid].T2D = CMR_PHI_CONV*Data["echo_amp_r"].T[:,iid] - CMR_PHI_CONV*1j*Data["echo_amp_x"].T[:,iid]
  797. self.ORS[iiid].depth = float(Data['depth'][iid]) * 0.3048 # Schlumberger logs in feet
  798. iiid += 1
  799. self.enableDSP()
  800. # disable buttons, do flow
  801. self.ui.WindowStackGO.setEnabled(False)
  802. self.ui.envelopeGO.setEnabled(False)
  803. self.ui.phaseGO.setEnabled(False)
  804. self.ui.WindowStackBox.setChecked(False)
  805. self.ui.envelopeGroupBox.setChecked(False)
  806. self.ui.phaseGroupBox.setChecked(True)
  807. self.ui.gateGroupBox.setChecked(True)
  808. self.ui.gateGroupBox.setEnabled(True)
  809. self.ui.gateGO.setEnabled(False)
  810. self.ui.bulkProcessGroupBox.setEnabled(True)
  811. self.ui.batchLoadDataPushButton.setEnabled(True)
  812. self.ui.logTextBrowser.append( "opened header file " + matfile )
  813. def openVCLogSeries(self):
  814. import scipy.io as sio
  815. try:
  816. with open('.akvo.last.vcl.path') as f:
  817. fpath = f.readline()
  818. pass
  819. except IOError as e:
  820. fpath = '.'
  821. self.DepthProfile == True
  822. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open VistaClara Log Series', fpath, r"CMR (*.mat)" )]
  823. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  824. self.ui.headerFileTextBrowser.clear()
  825. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  826. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  827. self.ui.logTextBrowser.clear()
  828. path,filen=os.path.split(str(self.headerstr[0] ))
  829. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  830. f = open('.akvo.last.vcl.path', 'w')
  831. if str(self.headerstr[0]):
  832. f.write( str(self.headerstr[0]) ) # prompt last file
  833. self.ui.headerFileBox.setEnabled(True)
  834. #########################################
  835. # LOAD the data and do some basic work
  836. self.ORSConnect( str(self.headerstr[0]) )
  837. self.lock("loading RAW record")
  838. matfile = self.headerstr[0] #.clear() # = []
  839. if fileExtension == ".mat":
  840. Data = sio.loadmat(self.headerstr[0])
  841. T2T = Data['time'][:,0]
  842. TAUE = T2T[3] - T2T[2]
  843. NS = 1
  844. self.ORS.clear() # = {}
  845. self.headerstr = [] #.clear() # = []
  846. # TODO query for depth step and data quality factor
  847. for iid in range(len(Data['depth'])):
  848. self.headerstr.append( iid )
  849. self.ORS[iid] = MRProc( ) # Fast
  850. self.ORS[iid].NE = len(Data['time'][:,0])
  851. self.ORS[iid].TAUE = TAUE
  852. self.ORS[iid].NS = 1 # TODO consider what to do here
  853. self.ORS[iid].T2T = T2T
  854. # What about moving window std.dev?
  855. self.ORS[iid].sigma = np.std(1e-2*Data['se_vector_wc'][:,iid][-100::]) # slowly varying at end?
  856. self.ORS[iid].T2N = np.random.normal( 0, self.ORS[iid].sigma, len(T2T) )
  857. self.ORS[iid].T2D = self.ORS[iid].T2N + 1j*1e-2*Data['se_vector_wc'][:,iid]
  858. #self.ORS[iid].depth = Data['depth'][iid][0]
  859. # TODO pass into GUI for weird Javelin data that is not recorded correctly
  860. self.ORS[iid].depth = 2.25- .25 * Data['depth'][iid][0]
  861. self.enableDSP()
  862. # disable buttons, do flow
  863. self.ui.WindowStackGO.setEnabled(False)
  864. self.ui.envelopeGO.setEnabled(False)
  865. self.ui.phaseGO.setEnabled(False)
  866. self.ui.WindowStackBox.setChecked(False)
  867. self.ui.envelopeGroupBox.setChecked(False)
  868. self.ui.phaseGroupBox.setChecked(False)
  869. self.ui.gateGroupBox.setChecked(True)
  870. self.ui.gateGroupBox.setEnabled(True)
  871. self.ui.gateGO.setEnabled(False)
  872. self.ui.bulkProcessGroupBox.setEnabled(True)
  873. self.ui.batchLoadDataPushButton.setEnabled(True)
  874. self.ui.logTextBrowser.append( "opened header file " + matfile )
  875. def openMultipleRecords(self):
  876. try:
  877. with open('.akvo.last.path') as f:
  878. fpath = f.readline()
  879. pass
  880. except IOError as e:
  881. fpath = '.'
  882. self.headerstrRAW = QtGui.QFileDialog.getOpenFileNames(self, 'Open multiple record', fpath, r"ORS RAW files (*.ors *.ors2);;Vista Clara Mid Field (*.vcm)")
  883. # ;;Vista Clara Javelin Processed (*.mat)" )
  884. self.headerstr = [] #[QtGui.QFileDialog.getOpenFileName(self, 'Open single record', fpath, r"ORS RAW files (*.ors *.ors2 *.vcm);;VC Mid field (*.vcm)" )]
  885. # Windoze and \ in paths
  886. #for iff in range(len(self.headerstr)) :
  887. # self.headerstr[iff] = os.path.normpath( str(self.headerstr[iff]) )
  888. # fix Windows stupid conventions
  889. for iff in range(len(self.headerstrRAW[0])) :
  890. #self.headerstr[iff] = os.path.normpath( str(self.headerstr[iff][0]) )
  891. self.headerstr.append( os.path.normpath( str(self.headerstrRAW[0][iff]) ))
  892. f = open('.akvo.last.path', 'w')
  893. if str(self.headerstr[0]):
  894. f.write( str(self.headerstr[0]) ) # prompt last file
  895. # Enable all the DSP stuff, but disable individual GO buttons
  896. self.enableDSP()
  897. self.ui.bulkProcessGroupBox.setEnabled(True)
  898. self.ui.batchLoadDataPushButton.setEnabled(True)
  899. self.ui.gateGroupBox.setEnabled(True)
  900. # disable buttons, do flow
  901. self.ui.WindowStackGO.setEnabled(False)
  902. self.ui.envelopeGO.setEnabled(False)
  903. self.ui.phaseGO.setEnabled(False)
  904. self.ui.gateGO.setEnabled(False)
  905. for ff in self.headerstr:
  906. self.ORS[ff] = MRProc( ) # Fast
  907. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  908. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableINV()"), self.enableINV)
  909. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  910. #self.ORSConnect( ff )
  911. self.ui.diffusionGroupBox.setEnabled(True)
  912. self.ui.diffusionGroupBox.setChecked(True)
  913. path,filen=os.path.split(str(self.headerstr[0] ))
  914. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  915. if fileExtension == ".vcm":
  916. self.ui.phaseGroupBox.setChecked(False)
  917. self.ui.envelopeGroupBox.setChecked(False)
  918. self.ui.WindowStackBox.setChecked(False)
  919. def hangon(self):
  920. self.plotLOG10ENV()
  921. # reopen processing flow
  922. # Enable all the DSP stuff, but disable individual GO buttons
  923. self.enableDSP()
  924. self.ui.bulkProcessGroupBox.setEnabled(True)
  925. self.ui.batchLoadDataPushButton.setEnabled(True)
  926. self.ui.gateGroupBox.setEnabled(True)
  927. # disable buttons, do flow
  928. self.ui.WindowStackGO.setEnabled(False)
  929. self.ui.envelopeGO.setEnabled(False)
  930. self.ui.phaseGO.setEnabled(False)
  931. self.ui.gateGO.setEnabled(False)
  932. # Enable Inversions
  933. self.enableINV( )
  934. def batch(self):
  935. import threading
  936. # Plot all data
  937. #self.ui.qplot.getFigure().clf()
  938. #sp0 = self.ui.qplot.getFigure().add_subplot(211)
  939. #sp1 = self.ui.qplot.getFigure().add_subplot(212)
  940. #########################################
  941. # LOAD the data and do some basic work
  942. #self.unlock()
  943. self.lock("batch processing records")
  944. pars = { 'ftype' : str(self.ui.fTypeComboBox.currentText()), \
  945. 'winTrimLeft' : self.ui.winTrimLeftSpinBox.value(), \
  946. 'winTrimRight' : self.ui.winTrimRightSpinBox.value(), \
  947. 'offset' : self.ui.offsetSpinBox.value(), \
  948. 'gpd' : self.ui.gpdSpinBox.value(),
  949. 'stackEfficiency' : self.ui.stackEfficiency.value() }
  950. total = len(self.headerstr)
  951. iif = 1
  952. for ff in self.headerstr:
  953. rawThread = threading.Thread( target=self.ORS[ff].batchThread, args=(pars, ff, os.path.isfile(str(ff)), self.ui.WindowStackBox.isChecked(), \
  954. self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked()) )
  955. self.updateProgressBar(1e2*iif/total)
  956. rawThread.start()
  957. rawThread.join()
  958. iif += 1
  959. #rawThread = thread.start_new_thread(self.ORS[ff].batchThread, (pars, ff, os.path.isfile(ff), self.ui.WindowStackBox.isChecked(), \
  960. # self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked()) )
  961. #self.ORS[ff].batchThread(pars, ff, os.path.isfile(ff), self.ui.WindowStackBox.isChecked(), \
  962. # self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked())
  963. self.unlock()
  964. self.hangon()
  965. #rawThread = thread.start_new_thread(self.ORS.loadORSFile, \
  966. # (str(ff),))
  967. #rawThread = thread.start_new_thread(self.batchThread, (None,))
  968. #self.batchThread(ff)
  969. def openSingleRecord(self):
  970. try:
  971. with open('.akvo.last.path') as f:
  972. fpath = f.readline()
  973. pass
  974. except IOError as e:
  975. fpath = '.'
  976. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open single record', fpath, r"ORS RAW files (*.ors *.ors2 *.vcm);;VC Mid field (*.vcm)")]
  977. #;;VC Javelin (*.mat)" )]
  978. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  979. #print(self.headerstr)
  980. #exit()
  981. self.ui.headerFileTextBrowser.clear()
  982. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  983. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  984. self.ui.logTextBrowser.clear()
  985. path,filen=os.path.split(str(self.headerstr[0] ))
  986. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  987. f = open('.akvo.last.path', 'w')
  988. if str(self.headerstr[0]):
  989. f.write( str(self.headerstr[0]) ) # prompt last file
  990. self.ui.headerFileBox.setEnabled(True)
  991. #########################################
  992. # LOAD the data and do some basic work
  993. self.ORSConnect( str(self.headerstr[0]) )
  994. self.lock("loading RAW record")
  995. if fileExtension == ".ors":
  996. rawThread = thread.start_new_thread(self.ORS[self.headerstr[0]].loadORSFile, \
  997. (str(self.headerstr[0]),))
  998. elif fileExtension == ".vcm":
  999. rawThread = thread.start_new_thread(self.ORS[self.headerstr[0]].loadVCMFile, \
  1000. (str(self.headerstr[0]),))
  1001. self.ui.gateGroupBox.setEnabled(True)
  1002. self.ui.phaseGroupBox.setChecked(False)
  1003. self.ui.envelopeGroupBox.setChecked(False)
  1004. self.ui.WindowStackBox.setChecked(False)
  1005. # disable buttons, do flow
  1006. self.ui.WindowStackGO.setEnabled(False)
  1007. self.ui.envelopeGO.setEnabled(False)
  1008. self.ui.phaseGO.setEnabled(False)
  1009. self.ui.gateGO.setEnabled(True)
  1010. self.ui.logTextBrowser.append( "opened header file " + self.headerstr[0] )
  1011. self.enableDSP( )
  1012. #################################################################################################
  1013. ################# PLOTTING ROUTINES ###########################################################
  1014. #################################################################################################
  1015. def plotRAW(self, ff=None):
  1016. if ff == None:
  1017. ff = self.headerstr[0]
  1018. self.ui.statusbar.showMessage ( "plotting RAW" )
  1019. #########################################
  1020. # plot
  1021. self.ui.qplot.getFigure().clf()
  1022. self.ui.qplot.draw()
  1023. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1024. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1025. #DATASTACK = np.average(ORS.DATA, axis=0)
  1026. # Can we instead concatinate some of these in order to only call plot 1 time?
  1027. nt = len(self.ORS[ff].TIMES)
  1028. for iss in range(0, self.ORS[ff].NS):
  1029. times = np.empty(nt*self.ORS[ff].NE)
  1030. dati = np.empty(nt*self.ORS[ff].NE)
  1031. datr = np.empty(nt*self.ORS[ff].NE)
  1032. #COLOUR = np.empty((nt*self.ORS[ff].NE, 3))
  1033. for ie in range(0, self.ORS[ff].NE):
  1034. #COLOUR[nt*ie:nt*(ie+1),:] = np.array([ie/self.ORS[ff].NE, 0., 1.-ie/self.ORS[ff].NE]) # for plots
  1035. times[nt*ie:nt*(ie+1)] = self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES
  1036. dati[nt*ie:nt*(ie+1)] = np.imag(self.ORS[ff].DATA[iss,ie])
  1037. datr[nt*ie:nt*(ie+1)] = np.real(self.ORS[ff].DATA[iss,ie])
  1038. #sp0.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.imag(self.ORS[ff].DATA[iss,ie]), color=COLOUR)
  1039. #sp1.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.real(self.ORS[ff].DATA[iss,ie]), color=COLOUR)
  1040. sp0.plot(times, dati, '.', color='blue', markersize=1) #COLOUR) doesn't work
  1041. sp1.plot(times, datr, '.', color='blue', markersize=1)
  1042. sp0.set_title("imaginary")
  1043. sp1.set_title("real")
  1044. self.ui.qplot.getFigure().suptitle("RAW quadrature data")
  1045. sp1.set_xlabel("time [s]")
  1046. plt.setp(sp0.get_xticklabels(), visible=False)
  1047. self.ui.qplot.draw()
  1048. def plotWIN(self, ff=None):
  1049. if ff == None:
  1050. ff = self.headerstr[0]
  1051. #########################################
  1052. # plot
  1053. self.ui.qplot.getFigure().clf()
  1054. self.ui.qplot.draw()
  1055. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1056. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1057. nt = len(self.ORS[ff].TIMES)
  1058. times = np.empty(nt*self.ORS[ff].NE)
  1059. dati = np.empty(nt*self.ORS[ff].NE)
  1060. datr = np.empty(nt*self.ORS[ff].NE)
  1061. for ie in range(0, self.ORS[ff].NE):
  1062. times[nt*ie:nt*(ie+1)] = self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES
  1063. dati[nt*ie:nt*(ie+1)] = np.imag(self.ORS[ff].DATASTACK[ie])
  1064. datr[nt*ie:nt*(ie+1)] = np.real(self.ORS[ff].DATASTACK[ie])
  1065. #COLOUR = np.array([ie/self.ORS[ff].NE, 0., 1.-ie/self.ORS[ff].NE]) # for plots
  1066. #sp0.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.imag(self.ORS[ff].DATASTACK[ie]), color=COLOUR)
  1067. #sp1.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.real(self.ORS[ff].DATASTACK[ie]), color=COLOUR)
  1068. sp0.plot(times, dati, '.', color='blue', markersize=1) #COLOUR) doesn't work
  1069. sp1.plot(times, datr, '.', color='blue', markersize=1)
  1070. sp0.set_title("imaginary")
  1071. sp1.set_title("real")
  1072. self.ui.qplot.getFigure().suptitle("RAW quadrature data")
  1073. sp1.set_xlabel("time [s]")
  1074. plt.setp(sp0.get_xticklabels(), visible=False)
  1075. self.ui.qplot.draw()
  1076. def plotENV(self, ff=None):
  1077. if ff == None:
  1078. ff = self.headerstr[0]
  1079. #########################################
  1080. # plot
  1081. self.ui.qplot.getFigure().clf()
  1082. self.ui.qplot.draw()
  1083. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1084. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1085. sp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='.', yerr=self.ORS[ff].sigma, label="data imag")
  1086. sp1.errorbar(self.ORS[ff].T2T, np.real(self.ORS[ff].T2D), fmt='.', yerr=np.std(self.ORS[ff].T2D.real), label="data real")
  1087. if self.ORS[ff].NS > 2:
  1088. sp1.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2N), fmt='.', yerr=self.ORS[ff].sigma, label="noise imag")
  1089. sp0.axhline(linewidth=1, color='#d62728')
  1090. sp1.axhline(linewidth=1, color='#d62728')
  1091. sp0.set_title("imaginary")
  1092. sp1.set_title("real")
  1093. self.ui.qplot.getFigure().suptitle("$T_2$ envelope dude")
  1094. sp1.set_xlabel("time [s]")
  1095. plt.setp(sp0.get_xticklabels(), visible=False)
  1096. self.ui.qplot.draw()
  1097. def plotLOG10ENV(self):
  1098. #Valid names are: ['Blues', 'BuGn', 'BuPu', 'GnBu', 'Greens', 'Greys', 'OrRd', 'Oranges', 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']
  1099. nc = max(3, len(self.headerstr))
  1100. if len(self.headerstr) > 9:
  1101. nc = 9
  1102. colours = brewer2mpl.get_map("Greens", "Sequential", nc).mpl_colors# [::-1]
  1103. self.ui.qplot.getFigure().clf()
  1104. if self.burst:
  1105. sp0 = self.ui.qplot.getFigure().add_subplot(221, facecolor=[.4,.4,.4])
  1106. sp0b = self.ui.qplot.getFigure().add_subplot(222, facecolor=[.4,.4,.4])
  1107. sp1 = self.ui.qplot.getFigure().add_subplot(223, facecolor=[.4,.4,.4], sharex=sp0, sharey=sp0)
  1108. sp1b = self.ui.qplot.getFigure().add_subplot(224, facecolor=[.4,.4,.4], sharex=sp0b, sharey=sp0b)
  1109. #plt.tight_layout(self.ui.qplot.getFigure())
  1110. else:
  1111. sp0 = self.ui.qplot.getFigure().add_subplot(211, facecolor=[.4,.4,.4])
  1112. sp1 = self.ui.qplot.getFigure().add_subplot(212, facecolor=[.4,.4,.4], sharex=sp0, sharey=sp0)
  1113. if len(self.headerstr) <= 2:
  1114. iif = 1
  1115. else:
  1116. iif = 0
  1117. # why to -1?
  1118. #for ff in self.headerstr[::-1]:
  1119. for ff in self.headerstr:
  1120. self.plotSingleLOG10ENV( self.ORS[ff], sp0, sp1, colours[iif%9], ff )
  1121. if self.burst:
  1122. self.plotSingleLOG10ENVBurst( self.ORS[ff], sp0b, sp1b, colours[iif%9], ff )
  1123. iif += 1
  1124. NLOG = True #True # True
  1125. if NLOG:
  1126. # write out noise log for GJI article
  1127. nlog = open("noise.dat", 'w')
  1128. nlog2 = open("noise2.dat", 'w')
  1129. first = False
  1130. for ff in self.headerstr[::-1]:
  1131. if not first:
  1132. times = self.ORS[ff].T2T
  1133. ifirst = True
  1134. for tt in times:
  1135. if ifirst:
  1136. nlog.write( str(tt) )
  1137. nlog2.write( str(tt) )
  1138. ifirst = False
  1139. else:
  1140. nlog.write( r"," + str(tt) )
  1141. nlog2.write( r"," + str(tt) )
  1142. nlog.write( "\n" )
  1143. nlog2.write( "\n" )
  1144. first = True
  1145. dat = self.ORS[ff].T2D.real
  1146. ifirst = True
  1147. for d in dat:
  1148. if ifirst:
  1149. nlog.write( str(d) )
  1150. ifirst = False
  1151. else:
  1152. nlog.write( r"," + str(d) )
  1153. nlog.write( "\n" )
  1154. dat = self.ORS[ff].T2D.imag
  1155. ifirst = True
  1156. for d in dat:
  1157. if ifirst:
  1158. nlog2.write( str(d) )
  1159. ifirst = False
  1160. else:
  1161. nlog2.write( r"," + str(d) )
  1162. nlog2.write( "\n" )
  1163. nlog.close()
  1164. nlog2.close()
  1165. sp0.set_title("imaginary")
  1166. sp1.set_title("real")
  1167. sp1.set_xlabel("time (s)")
  1168. sp1.set_ylabel("signal (PU)")
  1169. sp0.set_ylabel("signal (PU)")
  1170. plt.setp(sp0.get_xticklabels(), visible=False)
  1171. sp0.set_xscale('log', basex=10)
  1172. sp1.set_xscale('log', basex=10)
  1173. sp0.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1174. sp1.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1175. if self.burst:
  1176. sp0b.set_title("burst im")
  1177. sp1b.set_title("$\Re$burst")
  1178. sp1b.set_xlabel("time [s]")
  1179. plt.setp(sp0b.get_xticklabels(), visible=False)
  1180. sp0b.set_xscale('log', basex=10)
  1181. sp1b.set_xscale('log', basex=10)
  1182. sp0b.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1183. sp1b.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1184. # making the tickmarks white, longer, and wider
  1185. #sp0.tick_params(axis='both', which='both', color='w')#,length=3,width=2)
  1186. #sp1.tick_params(axis='both', which='both', color='w')#,length=3,width=2)
  1187. self.ui.qplot.draw()
  1188. self.doneStatus()
  1189. def plotSingleLOG10ENV(self, ORS, sp0, sp1, colour, ff):
  1190. #########################################
  1191. # plot
  1192. #self.ui.qplot.draw()
  1193. #sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1194. #sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1195. #dataf = open("javelin_" + str(ff) + ".dat", "w")
  1196. #for ii in range(len(ORS.T2D)):
  1197. # dataf.write( "%f\t%f\t%f\n" %(ORS.T2T[ii],np.imag(ORS.T2D[ii]),ORS.sigma[ii]) )
  1198. #print ("sigma", ORS.sigma)
  1199. sp0.errorbar(ORS.T2T, np.imag(ORS.T2D), fmt='.', color=colour, yerr=ORS.sigma, label="data imag")
  1200. sp1.errorbar(ORS.T2T, np.real(ORS.T2D), fmt='.', color=colour, yerr=ORS.sigma, label="data real")
  1201. if ORS.NS > 2:
  1202. sp1.errorbar(ORS.T2T, np.imag(ORS.T2N), fmt='.', yerr=ORS.sigma, label="noise imag")
  1203. def plotSingleLOG10ENVBurst(self, ORS, sp0, sp1, colour, ff):
  1204. sp0.errorbar(ORS.T2Tb, np.imag(ORS.T2Db), fmt='.', color=colour, yerr=ORS.sigmaBurst, label="data imag")
  1205. sp1.errorbar(ORS.T2Tb, np.real(ORS.T2Db), fmt='.', color=colour, yerr=ORS.sigmaBurst, label="data real")
  1206. #if ORS.NS > 2:
  1207. # sp1.errorbar(ORS.T2Tb, np.imag(ORS.T2Nb), fmt='.', yerr=ORS.sigma, label="noise imag")
  1208. def plotMONO(self):
  1209. # TODO for masked data, show differently in fit
  1210. #########################################
  1211. # plot
  1212. if not self.ui.saveDatBox.isChecked():
  1213. self.ui.qplot_2.getFigure().clf()
  1214. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1215. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1216. self.dsp0.set_title("data")
  1217. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1218. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1219. self.dsp1.set_xlabel("time [s]")
  1220. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1221. self.dsp0.set_xscale('log', basex=10)
  1222. self.dsp1.set_xscale('log', basex=10)
  1223. for ff in self.headerstr:
  1224. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', yerr=self.ORS[ff].sigma, label="data imag")
  1225. self.dsp0.plot(self.ORS[ff].MonoRes['t'], self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1226. self.dsp1.errorbar(self.ORS[ff].MonoRes['t'], self.ORS[ff].MonoRes['env'] - self.ORS[ff].T2D.imag , fmt='o', yerr=self.ORS[ff].sigma, label="mono")
  1227. #sp0.legend(numpoints=1)
  1228. #sp1.legend(numpoints=1)
  1229. self.ui.qplot_2.draw()
  1230. #########################################
  1231. # plot model
  1232. if not self.ui.saveModBox.isChecked():
  1233. self.ui.qplot_3.getFigure().clf()
  1234. self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111)
  1235. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1236. self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  1237. for ff in self.headerstr:
  1238. self.msp0.plot( self.ORS[ff].MonoRes['rt20'], self.ORS[ff].MonoRes['b0'], 'o', markersize=6, label="mono")
  1239. self.msp0.legend(numpoints=1)
  1240. self.ui.qplot_3.draw()
  1241. def plotBI(self):
  1242. # TODO for masked data, show differently in fit
  1243. #########################################
  1244. # plot
  1245. if not self.ui.saveDatBox.isChecked():
  1246. self.ui.qplot_2.getFigure().clf()
  1247. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1248. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1249. self.dsp0.set_title("data")
  1250. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1251. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1252. self.dsp1.set_xlabel("time [s]")
  1253. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1254. self.dsp0.set_xscale('log', basex=10)
  1255. self.dsp1.set_xscale('log', basex=10)
  1256. for ff in self.headerstr:
  1257. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', yerr=self.ORS[ff].sigma, label="data imag")
  1258. self.dsp0.plot(self.ORS[ff].BiRes['t'], self.ORS[ff].BiRes['env'], 'o', label=self.ORS[ff].BiRes['rfit'])
  1259. self.dsp1.errorbar(self.ORS[ff].BiRes['t'], self.ORS[ff].BiRes['env'] - self.ORS[ff].T2D.imag , fmt='o', yerr=self.ORS[ff].sigma, label="mono")
  1260. #sp0.legend(numpoints=1)
  1261. #sp1.legend(numpoints=1)
  1262. self.ui.qplot_2.draw()
  1263. #########################################
  1264. # plot model
  1265. if not self.ui.saveModBox.isChecked():
  1266. self.ui.qplot_3.getFigure().clf()
  1267. self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111)
  1268. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1269. self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  1270. for ff in self.headerstr:
  1271. self.msp0.plot( self.ORS[ff].BiRes['rt20'], self.ORS[ff].BiRes['b0'], 'o', markersize=6, label="bi1")
  1272. self.msp0.plot( self.ORS[ff].BiRes['rrt20'], self.ORS[ff].BiRes['bb0'], 'o', markersize=6, label="bi2")
  1273. self.msp0.legend(numpoints=1)
  1274. self.ui.qplot_3.draw()
  1275. def plotDIFF(self, Times2, Data, Sigma, Fit=None):
  1276. #########################################
  1277. # Plot up Data and Errorbars
  1278. if not self.ui.saveDatBox.isChecked():
  1279. self.ui.qplot_6.getFigure().clf()
  1280. self.dsp0 = self.ui.qplot_6.getFigure().add_subplot(211)
  1281. self.dsp1 = self.ui.qplot_6.getFigure().add_subplot(212)
  1282. self.dsp0.set_title("data")
  1283. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1284. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1285. self.dsp1.set_xlabel("time [s]")
  1286. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1287. self.dsp0.set_xscale('log', basex=10)
  1288. self.dsp1.set_xscale('log', basex=10)
  1289. #for ff in self.headerstr:
  1290. self.dsp0.errorbar(Times2, Data, fmt='o', yerr=Sigma, label="data imag")
  1291. if Fit != None:
  1292. self.dsp0.plot(Times2, Fit, 'o', label="fit")
  1293. #self.dsp0.plot(self.ORS[ff].T2T, self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1294. self.dsp1.errorbar(Times2, Data - Fit , fmt='o', yerr=Sigma, label="mono")
  1295. #sp0.legend(numpoints=1)
  1296. #sp1.legend(numpoints=1)
  1297. self.ui.qplot_6.draw()
  1298. def plotDIFF2(self, Times2, Data, Datap, Sigma, Fit=None):
  1299. #########################################
  1300. # Plot up Data and Errorbars
  1301. if not self.ui.saveDatBox.isChecked():
  1302. self.ui.qplot_6.getFigure().clf()
  1303. self.dsp0 = self.ui.qplot_6.getFigure().add_subplot(211)
  1304. self.dsp1 = self.ui.qplot_6.getFigure().add_subplot(212)
  1305. self.dsp0.set_title("data")
  1306. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1307. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1308. self.dsp1.set_xlabel("time [s]")
  1309. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1310. self.dsp0.set_xscale('log', basex=10)
  1311. self.dsp1.set_xscale('log', basex=10)
  1312. #for ff in self.headerstr:
  1313. self.dsp0.errorbar(Times2, Data, fmt='o', yerr=Sigma, label="data imag")
  1314. self.dsp0.errorbar(Times2, Datap, fmt='o', yerr=Sigma, label="data imag")
  1315. if Fit != None:
  1316. self.dsp0.plot(Times2, Fit, 'o', label="fit")
  1317. #self.dsp0.plot(self.ORS[ff].T2T, self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1318. self.dsp1.errorbar(Times2, Datap - Fit , fmt='o', yerr=Sigma, label="mono")
  1319. #sp0.legend(numpoints=1)
  1320. #sp1.legend(numpoints=1)
  1321. self.ui.qplot_6.draw()
  1322. def plotDIST(self, mask):
  1323. #########################################
  1324. # plot data
  1325. if not self.ui.saveDatBox.isChecked():
  1326. self.ui.qplot_2.getFigure().clf()
  1327. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1328. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1329. self.dsp0.set_title("data")
  1330. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1331. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1332. self.dsp1.set_xlabel("time [s]")
  1333. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1334. self.dsp0.set_xscale('log', basex=10)
  1335. self.dsp1.set_xscale('log', basex=10)
  1336. for ff in self.headerstr:
  1337. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', color='blue', yerr=self.ORS[ff].sigma, label="data")
  1338. self.dsp0.plot(self.ORS[ff].T2T[mask:], self.ORS[ff].DistRes['env'], '.', color='red', label='dist')#, label=self.ORS[ff].MonoRes['rfit'])
  1339. self.dsp1.errorbar(self.ORS[ff].T2T[mask:], self.ORS[ff].DistRes['env'] - self.ORS[ff].T2D.imag[mask:] , fmt='o', yerr=self.ORS[ff].sigma[mask:], label="dist")
  1340. #self.dsp0.legend(numpoints=1)
  1341. #self.dsp1.legend(numpoints=1)
  1342. #self.ui.qplot_2.draw()
  1343. nc = max(3, len(self.headerstr))
  1344. if len(self.headerstr) > 9:
  1345. nc = 9
  1346. colours = brewer2mpl.get_map("Greens", "Sequential", nc).mpl_colors# [::-1]
  1347. #########################################
  1348. # plot model
  1349. if not self.ui.saveModBox.isChecked():
  1350. self.ui.qplot_3.getFigure().clf()
  1351. #self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111, facecolor=[.4,.4,.4])
  1352. self.msp0 = self.ui.qplot_3.getFigure().add_axes([.155,.2,.7,.65], facecolor=[.4,.4,.4])
  1353. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1354. self.msp0.set_ylabel(r"PWC (m$^3$/m$^3$)", color='black')
  1355. self.msp1 = self.msp0.twinx()
  1356. self.msp1.set_ylabel(r"total water (%)", color='black')
  1357. self.msp0.set_xscale('log', basex=10)
  1358. self.msp0.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1359. if len(self.headerstr) <= 2:
  1360. iif = 1
  1361. else:
  1362. iif = 0
  1363. print("%s,%s,%s"%("theta","LogMeanT2","filename"))
  1364. for ff in self.headerstr[::-1]:
  1365. #############################
  1366. # Plot dist. model
  1367. # consider normalizing by bin width? If you shift nBins it appears that water content varies
  1368. self.msp0.plot(self.ORS[ff].DistRes['Time'].T2Bins, self.ORS[ff].DistRes['mod'], '-', color=colours[iif%nc], linewidth=2, label="recovered")
  1369. ################################
  1370. # Log mean and total water
  1371. theta = np.sum( self.ORS[ff].DistRes['mod'] )
  1372. LogMeanT2 = np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / theta )
  1373. # print("%1.5e,%1.5e,%s"%(theta,LogMeanT2, os.path.basename(ff)))
  1374. self.msp1.plot(LogMeanT2, 1e2*theta, 'o', markersize=6, color=colours[iif%nc], label="$T_{2ML}$")
  1375. iif += 1
  1376. #self.msp0.xaxis.grid(b=True, which='minor', color=[.2,.2,.2], linestyle='-')
  1377. #self.dsp1.set_xscale('log', basex=10)
  1378. #self.msp0.legend(numpoints=1)
  1379. self.ui.qplot_3.draw()
  1380. if __name__ == "__main__":
  1381. import time
  1382. import matplotlib.image as mpimg
  1383. app = QtGui.QApplication(sys.argv)
  1384. # splash a little advertising
  1385. #pixmap = QtGui.QPixmap("XRI_LOGO2.jpg")
  1386. #splash = QtGui.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  1387. #splash.show()
  1388. #splash.showMessage("Loaded modules");
  1389. # Build main app
  1390. myapp = MyForm()
  1391. # dummy plot
  1392. img=mpimg.imread('./lemma.png')
  1393. for ax in [ myapp.ui.qplot, myapp.ui.qplot_2, myapp.ui.qplot_3 ]:
  1394. subplot = ax.getFigure().add_subplot(111)
  1395. ax.getFigure().patch.set_facecolor( None )
  1396. ax.getFigure().patch.set_alpha( .0 )
  1397. subplot.imshow(img)
  1398. subplot.xaxis.set_major_locator(plt.NullLocator())
  1399. subplot.yaxis.set_major_locator(plt.NullLocator())
  1400. ax.draw()
  1401. #subplot = myapp.ui.qplot.getFigure().add_subplot(111)
  1402. #myapp.ui.qplot.getFigure().patch.set_facecolor( None )
  1403. #myapp.ui.qplot.getFigure().patch.set_alpha( .0 )
  1404. #subplot.imshow(img)
  1405. #subplot.xaxis.set_major_locator(plt.NullLocator())
  1406. #subplot.yaxis.set_major_locator(plt.NullLocator())
  1407. #myapp.ui.qplot.draw()
  1408. myapp.show()
  1409. #splash.finish(myapp);
  1410. sys.exit(app.exec_())