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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752
  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. Data = np.zeros( (len(self.ORS), len(self.ORS[0].T2T)) )
  341. times = self.ORS[0].T2T
  342. depTol = np.abs(self.ORS[self.headerstr[0]].depth - self.ORS[self.headerstr[-1]].depth)
  343. t2scale = 100*depTol / len(self.ORS) #TODO adjust based on total depth, was 20
  344. for ff in self.headerstr:
  345. nT2 = len(self.ORS[ff].DistRes['Time'].T2Bins)
  346. dp.append( self.ORS[ff].depth )
  347. phi.append( np.sum( self.ORS[ff].DistRes['mod'] ) )
  348. LogMeanT2.append( np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / phi[ii] ) )
  349. FFV.append( np.sum( self.ORS[ff].DistRes['mod'][ self.ORS[ff].DistRes['Time'].T2Bins>=cutoff]) )
  350. 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
  351. CBFV.append( np.sum( self.ORS[ff].DistRes['mod'][ self.ORS[ff].DistRes['Time'].T2Bins<cutoff2]) + 1e-6 ) # epsilon
  352. self.kt.plot( self.ORS[ff].DistRes['Time'].T2Bins, dp[ii] - t2scale*self.ORS[ff].DistRes['mod'] , color='blue' )
  353. 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')
  354. Data[ff,:] = self.ORS[ff].T2D.imag
  355. 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]))
  356. #if np.abs( phi[-1] - (FFV[-1] + BFV[-1] + CBFV[-1]) ) > 1e-6:
  357. # print("mismatch", phi[-1] - (FFV[-1] + BFV[-1] + CBFV[-1]), CBFV[-1] )
  358. #else:
  359. # print("nope", CBFV[-1])
  360. ii += 1
  361. dat.close()
  362. #k = ((c*np.array(phi))**m) * ( (np.array(FFV)/np.array(BFV))**n)
  363. k = c * 1e4 * (np.array(phi)**m) * ((np.array(FFV)/(np.array(BFV)+np.array(CBFV)))**n)
  364. ############################################################
  365. # porosity logs
  366. # TI, TODO these fill_between cause errors with Javelin data? Why?
  367. #self.kp.plot( phi, dp , label = r"$\phi_{NMR}$", color='blue' )
  368. #try:
  369. # self.kp.fill_betweenx(np.array(dp), np.array(phi), alpha=1., color='blue' ) #, label = r"$BFV_{TC}$" )
  370. #except:
  371. # print ("shapes of dp and phi", np.shape(np.array(dp)), np.shape(np.array(phi)))
  372. FFV = np.array(FFV)
  373. BFV = np.array(BFV)
  374. CBFV = np.array(CBFV)
  375. # Plot cumulitive of all pore sizes below, that way the visible portion corresponds with the PWC
  376. self.kp.plot( FFV+BFV+CBFV , dp , label = r"$FFV_{TC}$", color='blue' ) # don't plot implicit
  377. self.kp.fill_betweenx(dp, FFV+BFV+CBFV, alpha=1, color='blue' ) #, label = r"$BFV_{TC}$" )
  378. self.kp.plot( BFV+CBFV, dp , label = r"$BFV_{TC}$" , color='green')
  379. self.kp.fill_betweenx(dp, BFV+CBFV, alpha=1, color='green' ) #, label = r"$BFV_{TC}$" )
  380. self.kp.plot( CBFV, dp , label = r"$CBFV_{TC}$" , color='brown')
  381. self.kp.fill_betweenx(dp, CBFV, alpha=1, color='brown' ) #, label = r"$BFV_{TC}$" )
  382. #ax.fill_between(xs, ys, where=ys>=d, interpolate=True, color='blue')
  383. self.kp.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  384. self.kp.set_xlim( [ 0, self.kp.get_xlim()[1] ] )
  385. ####################################################################################
  386. # Data Plot
  387. #self.dd.matshow()
  388. #X,Y = meshgrid( np.log10(times), dp )
  389. # pcolor cuts one spot, need to extrapolate
  390. ma = self.ui.maskNSpinBox_4.value()
  391. dp2 = np.append( dp, dp[-1]+(dp[-1]-dp[-2]) )
  392. times2 = np.append( times, times[-1]+(times[-1]-times[-2]) )
  393. times2 = times2[ma:]
  394. #times2 = np.append( times[ma:], times[ma:-1]+(times[-1]-times[-2]) )
  395. dp2 = dp2 - (dp[1]-dp[0]) *.5
  396. X,Y = meshgrid( times2, dp2 )
  397. #self.mp.matshow(Data, aspect = 'auto')
  398. #pc = self.dd.pcolor(X,Y, Data, cmap = 'coolwarm', vmin = 0)
  399. pc = self.dd.pcolor(X,Y, Data[:,ma:], cmap = 'viridis') #, vmin = -np.max(Data[:,ma:]))
  400. #pc = self.dd.pcolor(X,Y, Data, cmap = 'seismic_r') #, vmin=-.5, vmax=.5) #, vmin = 0)
  401. #self.dd.set_ylim( self.dd.get_ylim()[::-1] )
  402. self.dd.set_ylim( np.max(dp2), np.min(dp2) )
  403. self.dd.set_xlim( times2[0], times2[-1] )
  404. #self.dd.set_xlim( np.log10(times[0]), np.log10(times[-1]) )
  405. self.dd.set_xscale("log", nonposy='clip')
  406. ############################################################
  407. # decay logs
  408. #self.kt.plot( LogMeanT2, dp , label = r"$T_{2ML}$" )
  409. #self.kt.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ]) # use same range as others
  410. # Don't plot huge K's
  411. self.kk.set_xlim( [ min(self.kk.get_xlim()), 1e6 ]) # use same range as others
  412. # permeability logs
  413. self.kk.plot( k, dp , label = r"$\kappa_{TC}$", color='red' )
  414. #self.kk.set_ylim( [ max(self.kk.get_ylim()), min(self.kk.get_ylim()) ])
  415. self.kk.set_xlim( [ 1e-1, self.kk.get_xlim()[1] ] )
  416. self.kk.grid()
  417. # don't plot y axis labels, except on data plot (far left)
  418. #self.kk.axes.get_yaxis().set_ticks([])
  419. #self.kp.axes.get_yaxis().set_ticks([])
  420. #self.kt.axes.get_yaxis().set_ticks([])
  421. # above kills dd labels too
  422. plt.setp( self.kk.axes.get_yticklabels(), visible=False)
  423. plt.setp( self.kp.axes.get_yticklabels(), visible=False)
  424. plt.setp( self.kt.axes.get_yticklabels(), visible=False)
  425. #h1, l1 = self.kp.get_legend_handles_labels()
  426. #h2, l2 = self.kkp.get_legend_handles_labels()
  427. #self.kp.legend(h1+h2, l1+l2, numpoints=1)
  428. # try to avoid legends, they detract from logs
  429. #self.kp.legend()
  430. #self.kk.legend()
  431. #self.kt.legend()
  432. self.kp.xaxis.set_major_locator(MaxNLocator(3))
  433. #self.dd.xaxis.set_major_locator(MaxNLocator(3))
  434. cb = self.ui.qplot_5.getFigure().colorbar(pc, self.dc, orientation='horizontal')
  435. cb.solids.set_edgecolor("face")
  436. #tick_locator = MaxNLocator(nbins=5)
  437. cb.locator = MaxNLocator(5) #tick_locator
  438. cb.update_ticks()
  439. self.ui.qplot_5.draw()
  440. def sdr(self):
  441. """ Estimates permeability based on Schlumberger-Doll Research (SDR) equation
  442. \kappa = c \phi^m T_{2ML}^n
  443. """
  444. if not self.ui.saveDatBox_3.isChecked():
  445. self.ui.qplot_5.getFigure().clf()
  446. self.kp = self.ui.qplot_5.getFigure().add_subplot(131)
  447. self.kt = self.ui.qplot_5.getFigure().add_subplot(132)
  448. self.kk = self.ui.qplot_5.getFigure().add_subplot(133)
  449. self.kk.set_xlabel(r"$\kappa$ [mD]")
  450. self.kp.set_xlabel(r"$\phi$ [m$^3$ / m$^3$]")
  451. self.kt.set_xlabel(r"$T_2$ [s]")
  452. self.kp.set_ylabel(r"depth [m]")
  453. #self.kt.set_ylabel(r"depth [m]")
  454. #self.kk.set_ylabel(r"depth [m]")
  455. # permeability and decay time in log10
  456. self.kk.set_xscale('log', basex=10)
  457. self.kt.set_xscale('log', basex=10)
  458. self.kp.set_title(r"NMR water (b,t)")
  459. self.kt.set_title(r"NMR $T_2$")
  460. self.kk.set_title(r"$\kappa_{NMR}$")
  461. self.kp.xaxis.set_major_locator(MaxNLocator(4))
  462. #self.dd.xaxis.set_major_locator(MaxNLocator(4))
  463. #self.kt.xaxis.set_major_locator(MaxNLocator(5))
  464. #self.kk.xaxis.set_major_locator(MaxNLocator(5))
  465. #self.kp.set_title("permeability")
  466. c = self.ui.SDR_c.value()
  467. m = self.ui.SDR_m.value()
  468. n = self.ui.SDR_n.value()
  469. dp = []
  470. phi = []
  471. LogMeanT2 = []
  472. ii = 0
  473. for ff in self.headerstr:
  474. dp.append( self.ORS[ff].depth )
  475. phi.append( np.sum( self.ORS[ff].DistRes['mod'] ) )
  476. #theta = np.sum( self.ORS[ff].DistRes['mod'] )
  477. LogMeanT2.append( np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / phi[ii] ) )
  478. ii += 1
  479. #print ("LogMeanT2", LogMeanT2)
  480. # 1e3 converts to ms where c is designed for
  481. k = c*np.array(phi)**m * ((1e3 * np.array(LogMeanT2))**n)
  482. self.kp.plot( phi, dp , label = r"$\phi_{NMR}$" )
  483. self.kt.plot( LogMeanT2, dp , linewidth=2, color='blue', label = r"$T_{2ML}$" )
  484. self.kk.plot( k, dp , label = r"$\kappa_{SDR}$", color='blue' )
  485. self.kp.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  486. self.kk.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  487. self.kt.set_ylim( [ max(self.kp.get_ylim()), min(self.kp.get_ylim()) ])
  488. #h1, l1 = self.kp.get_legend_handles_labels()
  489. #h2, l2 = self.kkp.get_legend_handles_labels()
  490. #self.kp.legend(h1+h2, l1+l2, numpoints=1)
  491. #self.kkp.grid()
  492. self.ui.qplot_5.draw()
  493. def model(self):
  494. from pylab import meshgrid
  495. # TODO add noise std column which will be interesting for resolution analysis
  496. #self.ui.modelTableWidget.setColumnCount(4)
  497. #for ii in range( self.ui.modelTableWidget.rowCount() ):
  498. # for jj in range( self.ui.modelTableWidget.columnCount() ):
  499. # if self.ui.modelTableWidget.item(ii, jj) != None:
  500. # print( str(ii) + "\t" + str(jj) + "\t" + str( self.ui.modelTableWidget.item(ii, jj).text() ) )
  501. self.DepthProfile = True
  502. Bottom = self.ui.doubleSpinBoxBottom.value()
  503. Top = self.ui.doubleSpinBoxTop.value()
  504. Dz = self.ui.doubleSpinBoxDz.value()
  505. T = self.ui.doubleSpinBoxTTrain.value()
  506. TauE = 1e-3 * self.ui.doubleSpinBoxTauE.value()
  507. Mean = self.ui.doubleSpinBoxMean.value()
  508. Std = self.ui.doubleSpinBoxStd.value()
  509. times = np.arange(TauE, T, TauE)
  510. dp = np.arange(Bottom, Top, -Dz)
  511. Data = np.zeros( (len(dp), len(times)) )
  512. Noise = np.zeros( (len(dp), len(times)) )
  513. Mod = np.zeros( (len(dp) )) + 1e-6
  514. Por = np.zeros( (len(dp) ))
  515. Por = np.zeros( (len(dp) ))
  516. for ii in range( self.ui.modelTableWidget.rowCount() ):
  517. a = type(self.ui.modelTableWidget.item(ii, 0))
  518. if str(a) == "<class 'NoneType'>": # ugly hack needed by PySide for some strange reason.
  519. pass #print ("NONE")
  520. else: #if type(self.ui.modelTableWidget.item(ii, 0)) != None:
  521. #print ("type", type(self.ui.modelTableWidget.item(ii, 0)))
  522. for iid in range(len(dp)):
  523. #print self.ui.modelTableWidget.item(ii, 0).text(), dp[iid], self.ui.modelTableWidget.item(ii, 1).text()
  524. try:
  525. if dp[iid] > eval(str(self.ui.modelTableWidget.item(ii, 0).text()) ) and dp[iid] <= eval(str(self.ui.modelTableWidget.item(ii, 1).text()) ):
  526. Mod[iid] = 1e-3 * eval( str(self.ui.modelTableWidget.item(ii, 2).text() ))
  527. Por[iid] = 1e-2 * eval(str(self.ui.modelTableWidget.item(ii, 3).text() ))
  528. # Append the data for multi-exponential
  529. Data[iid, :] += Por[iid] * np.exp( -times/ Mod[iid] ) + np.random.normal( 0, eval(str( self.ui.modelTableWidget.item(ii,4).text())), len(times) )
  530. Noise[iid,:] += np.random.normal( 0, eval(str( self.ui.modelTableWidget.item(ii,4).text())), len(times) )
  531. except:
  532. pass
  533. self.ORS.clear() # = {}
  534. self.headerstr = [] #.clear() # = []
  535. for iid in range(len(dp)):
  536. self.headerstr.append( iid )
  537. self.ORS[iid] = MRProc( ) # Fast
  538. self.ORS[iid].NE = len(times)
  539. self.ORS[iid].TAUE = TauE
  540. self.ORS[iid].NS = 1 # TODO consider what to do here
  541. self.ORS[iid].T2T = times
  542. self.ORS[iid].T2D = Noise[iid,:] + 1j*Data[iid,:]
  543. self.ORS[iid].T2N = Noise[iid,:]
  544. self.ORS[iid].sigma = np.std( Noise[iid,:] )
  545. self.ORS[iid].depth = dp[iid]
  546. # Doom, why
  547. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  548. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("enableINV()"), self.enableINV)
  549. #QtCore.QObject.connect(self.ORS[iid], QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  550. # enable gate integrate
  551. self.enableDSP()
  552. self.ui.bulkProcessGroupBox.setEnabled(True)
  553. self.ui.batchLoadDataPushButton.setEnabled(True)
  554. self.ui.gateGroupBox.setEnabled(True)
  555. # disable buttons, do flow
  556. self.ui.WindowStackBox.setChecked(False)
  557. self.ui.envelopeGroupBox.setChecked(False)
  558. self.ui.phaseGroupBox.setChecked(False)
  559. self.ui.gateGroupBox.setChecked(True)
  560. #self.ui.WindowStackGO.checked(False)
  561. #self.ui.envelopeGO.checked(False)
  562. #self.ui.phaseGO.checked(False)
  563. self.ui.gateGO.setEnabled(False)
  564. # Enable Inversions
  565. self.enableINV()
  566. #for iz in range(len(dp)):
  567. #Data[iz,:] = 1e-2*dp[iz] + np.exp(-times/.324)
  568. # Data[iz,:] = Por[iz] * np.exp( -times/ Mod[iz] )
  569. # OK, so now I need to get these into data container class
  570. # for now just make data and plot it
  571. if not self.ui.saveDatBox_2.isChecked():
  572. self.ui.qplot_4.getFigure().clf()
  573. self.mp = self.ui.qplot_4.getFigure().add_subplot(111)
  574. self.mp.set_title("synthetic data")
  575. X,Y = meshgrid( times, dp )
  576. #self.mp.matshow(Data, aspect = 'auto')
  577. self.mp.pcolor(X,Y, Data, cmap = 'hot_r')
  578. self.mp.set_ylim( self.mp.get_ylim()[::-1] )
  579. self.ui.qplot_4.draw()
  580. def jgFit(self):
  581. T2Bw = 1e-3 * self.ui.T2bwSpinBox.value()
  582. #T2Bw = 2.
  583. Times = {}
  584. Times2 = np.empty(0)
  585. TauE = []
  586. Data = np.empty(0) #{}
  587. Datap = np.empty(0) #{}
  588. Sigma = np.empty(0) #{}
  589. mask = self.ui.maskNSpinBox_5.value()
  590. for ff in self.headerstr:
  591. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  592. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  593. TauE.append(self.ORS[ff].TAUE)
  594. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  595. Datap = np.append( Datap, np.imag(self.ORS[ff].T2D)[mask::] / np.exp(-self.ORS[ff].T2T[mask::]/(self.ui.A0SpinBox.value()*T2Bw) ) )
  596. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  597. # Plot up data, TODO need a separate thread for this, unresponsive GUI
  598. #self.plotDIFF(Times2, Data, Sigma)
  599. #self.plotDIFF2(Times2, Data, Datap, Sigma)
  600. #############################################
  601. # Generate Kernel for inversion to J(G)
  602. Times = {}
  603. Times2 = np.empty(0)
  604. TauE = []
  605. Data = np.empty(0) #{}
  606. Sigma = np.empty(0) #{}
  607. mask = self.ui.maskNSpinBox_5.value()
  608. for ff in self.headerstr:
  609. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  610. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  611. TauE.append(self.ORS[ff].TAUE)
  612. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  613. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  614. self.GBins = np.linspace(self.ui.gminSpinBox.value(), self.ui.gmaxSpinBox.value(), num=self.ui.ngSpinBox.value(), endpoint=True)
  615. #self.GBins = np.logspace(np.log10(self.ui.gminSpinBox.value()), np.log10(self.ui.gmaxSpinBox.value()), num=self.ui.ngSpinBox.value(), endpoint=True)
  616. INV = pwcTime()
  617. INV.generateJGKernel(TauE, Times, 1e-5*self.ui.dwSpinBox.value() , self.GBins, self.ui.DTau.value())
  618. self.jgModel = logBarrier(INV.JG, Datap, MAXITER=500, sigma=Sigma, alpha=1e20) #, smooth=True) #
  619. pre = np.dot(INV.JG, self.jgModel)
  620. #self.plotDIFF(Times2, Data, Sigma, Datap) #pre)
  621. self.plotDIFF2(Times2, Data, Datap, Sigma, pre)
  622. # Plot model
  623. self.ui.qplot_7.getFigure().clf()
  624. self.msp0 = self.ui.qplot_7.getFigure().add_axes([.15,.2,.75,.65])
  625. self.msp0.plot(self.GBins, self.jgModel, color='black', linewidth=3)
  626. self.msp0.grid()
  627. self.msp0.set_xlabel("$J(G)$ [G/cm]")
  628. self.msp0.set_ylabel("intensity")
  629. self.ui.qplot_7.draw()
  630. #plt.show()
  631. def diffusion(self):
  632. from pylab import meshgrid
  633. #print ("Diffusion Inversion")
  634. Times = {}
  635. Times2 = np.empty(0)
  636. TauE = []
  637. Data = np.empty(0) #{}
  638. Sigma = np.empty(0) #{}
  639. mask = self.ui.maskNSpinBox_5.value()
  640. for ff in self.headerstr:
  641. Times[self.ORS[ff].TAUE] = self.ORS[ff].T2T[mask::]
  642. Times2 = np.append( Times2, self.ORS[ff].T2T[mask::] )
  643. TauE.append(self.ORS[ff].TAUE)
  644. Data = np.append( Data, np.imag(self.ORS[ff].T2D)[mask::] )
  645. Sigma = np.append( Sigma, self.ORS[ff].sigma[mask::] )
  646. self.INV = pwcTime()
  647. #self.D = np.linspace(1e-9*self.ui.Dmin.value(), 1e-5*self.ui.Dmax.value(), num=self.ui.nDBins.value(), endpoint=True)
  648. 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)
  649. self.INV.setT2( 1e-3*self.ui.lowT2SpinBox.value(), 1e-3*self.ui.hiT2SpinBox.value(), self.ui.nT2SpinBox.value(), self.ui.distT2Box.currentText() )
  650. if self.ui.jgComboBox.currentText() == "Distribution":
  651. print("Using J(G) Distribution")
  652. self.INV.generateGDenv( TauE, Times, self.D, self.GBins, self.jgModel, self.ui.DTau.value() )
  653. else:
  654. print("Using constant G")
  655. self.INV.generateGDenv( TauE, Times, self.D, np.array([self.ui.jgcSpinBox.value()]), np.array([1.]) )
  656. # Plot up data, TODO need a separate thread for this, unresponsive GUI
  657. self.plotDIFF(Times2, Data, Sigma)
  658. # OK now invert TODO, need to speed this up. Sparse matrices and/or implicit ATWdTWdA?
  659. model = logBarrier(self.INV.GD, Data, MAXITER=500, sigma=Sigma, alpha=1e10, callback=None) #self.plotDmod) #, smooth=True) #
  660. pre = np.dot(self.INV.GD, model)
  661. self.plotDIFF(Times2, Data, Sigma, pre)
  662. self.plotDmod(model)
  663. def plotDmod(self, model):
  664. # plot models and fit
  665. self.DMod = np.reshape(model, (len(self.D), len(self.INV.T2Bins)))
  666. # Save to file for analysis
  667. print("saving D mod to dmod.bin")
  668. res = open('dmod.bin', 'wb')
  669. np.save(res, self.D)
  670. np.save(res, self.INV.T2Bins)
  671. np.save(res, model)
  672. #if not self.ui.saveModBox.isChecked():
  673. self.ui.qplot_7.getFigure().clf()
  674. self.msp0 = self.ui.qplot_7.getFigure().add_axes([.15,.2,.65,.65])
  675. self.csp0 = self.ui.qplot_7.getFigure().add_axes([.85,.2,.025,.65])
  676. #self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  677. #self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  678. #for ff in self.headerstr:
  679. #X,Y = meshgrid( np.concatenate( (np.array([.999*self.INV.T2Bins[0]]), self.INV.T2Bins) ), \
  680. # np.concatenate( (np.array([.999*self.D[0]]), self.D)) ) # pcolor needs an extra bin
  681. X,Y = meshgrid( self.INV.T2Bins, self.D ) # pcolor needs an extra bin
  682. #cmap = plt.get_cmap('hot_r') #'
  683. imsa = self.msp0.pcolor(X, Y, self.DMod, cmap='hot_r', edgecolors='w') #, rasterized=True)
  684. self.msp0.set_xlabel("$T_2$ [s]")
  685. self.msp0.set_ylabel("D [cm$^2$/s]")
  686. self.msp0.set_yscale('log', basey=10)
  687. self.msp0.set_xscale('log', basex=10)
  688. plt.colorbar(imsa, self.csp0) #self.msp0)
  689. #cb1 = mpl.colorbar.ColorbarBase(self.cbax, cmap=wmap,
  690. # norm=nnorm,
  691. # orientation='horizontal',
  692. # extend='both',
  693. # format = r'%i')
  694. #self.msp0.imshow( self.DMod, interpolation='bicubic' ) #self.ORS[ff].MonoRes['rt20'], self.ORS[ff].MonoRes['b0'], 'o', markersize=6, label="mono")
  695. # self.msp0.legend(numpoints=1)
  696. #plt.ylabel("D [cm$^2$/s]")
  697. #plt.xlabel("$T_2$ [s]")
  698. self.ui.qplot_7.draw()
  699. #print ("FINISHED DIFFUSION")
  700. def gate(self, ff=None):
  701. #print ("GATING")
  702. if ff == None:
  703. ff = self.headerstr[0]
  704. self.ui.logTextBrowser.append( "Gate integrate correct" + "GPD")
  705. self.lock("time gating")
  706. rawThread = thread.start_new_thread(self.ORS[ff].gateIntegrate, (self.ui.gpdSpinBox.value(),self.ui.stackEfficiency.value()) )
  707. #rawThread = thread.start_new_thread(self.ORS[ff].CorrectedAmplitude, (0,0) )
  708. #self.ui.logTextBrowser.append( "Envelope Detect: " + str(self.ui.fTypeComboBox.currentText() ))
  709. def openCMRLog(self):
  710. print("CMR log process")
  711. import scipy.io as sio
  712. try:
  713. with open('.akvo.cmr.last.path') as f:
  714. fpath = f.readline()
  715. pass
  716. except IOError as e:
  717. fpath = '.'
  718. self.DepthProfile == True
  719. self.burst = False # True
  720. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open Schlumberger CMR Log Series', fpath, r"CMR MATLAB (*.mat)" )]
  721. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  722. self.ui.headerFileTextBrowser.clear()
  723. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  724. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  725. self.ui.logTextBrowser.clear()
  726. path,filen=os.path.split(str(self.headerstr[0] ))
  727. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  728. f = open('.akvo.cmr.last.path', 'w')
  729. if str(self.headerstr[0]):
  730. f.write( str(self.headerstr[0]) ) # prompt last file
  731. self.ui.headerFileBox.setEnabled(True)
  732. #########################################
  733. # LOAD the data and do some basic work
  734. self.ORSConnect( str(self.headerstr[0]) )
  735. CMR_PHI_CONV = 0.00068 # this is temperature dependent, should be in files, but wasn't!
  736. self.lock("loading RAW record")
  737. matfile = self.headerstr[0]
  738. if fileExtension == ".mat":
  739. Data = sio.loadmat(self.headerstr[0])
  740. # the Schlumberger data has a burst mode at the end of the record which is designed only to capture
  741. # fast decays. I don't see a record of the number in the files, is often 30
  742. ne = np.shape(Data["echo_amp_x"].T[:,0])[0] - 30
  743. nb = 30 # number of burst echoes
  744. T2T = 2e-4 * np.arange(1, ne+1, 1) # .2 ms seems to be CMR standard, not in data files
  745. T2Tb = 2e-4 * np.arange(1, nb+1, 1) # burst times
  746. # T2T = np.concatenate( (T2T,T2Tb) )
  747. TAUE = T2T[3] - T2T[2]
  748. NS = 1
  749. self.ORS.clear() # = {}
  750. self.headerstr = [] #.clear() # = []
  751. # TODO query for depth step and data quality factor
  752. iiid = 0
  753. #################################
  754. dmin = 7672 # Morrow #
  755. dmax = 7707 # Morrow Bottom #
  756. #################################
  757. #dmin = 7672+10.25 # Morrow #
  758. #dmax = 7707-10.25 # Morrow Bottom #
  759. #dmin = 0
  760. #dmax = 7510
  761. #dmax = 10000
  762. for iid in range(len(Data['depth'])):
  763. dep = float(Data['depth'][iid])
  764. #if True:
  765. if dep > dmin and dep <= dmax:
  766. self.headerstr.append( iiid )
  767. self.ORS[iiid] = MRProc( ) # Fast
  768. self.ORS[iiid].NE = ne #len(Data['time'][:,0])
  769. self.ORS[iiid].TAUE = TAUE
  770. self.ORS[iiid].NS = 1 # TODO consider what to do here
  771. self.ORS[iiid].T2T = T2T
  772. self.ORS[iiid].T2Tb = T2Tb
  773. self.ORS[iiid].burst = False #True
  774. # long record
  775. 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]
  776. # burst data
  777. 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]
  778. # both
  779. #self.ORS[iiid].T2D = CMR_PHI_CONV*Data["echo_amp_r"].T[:,iid] - CMR_PHI_CONV*1j*Data["echo_amp_x"].T[:,iid]
  780. self.ORS[iiid].depth = float(Data['depth'][iid]) * 0.3048 # Schlumberger logs in feet
  781. iiid += 1
  782. self.enableDSP()
  783. # disable buttons, do flow
  784. self.ui.WindowStackGO.setEnabled(False)
  785. self.ui.envelopeGO.setEnabled(False)
  786. self.ui.phaseGO.setEnabled(False)
  787. self.ui.WindowStackBox.setChecked(False)
  788. self.ui.envelopeGroupBox.setChecked(False)
  789. self.ui.phaseGroupBox.setChecked(True)
  790. self.ui.gateGroupBox.setChecked(True)
  791. self.ui.gateGroupBox.setEnabled(True)
  792. self.ui.gateGO.setEnabled(False)
  793. self.ui.bulkProcessGroupBox.setEnabled(True)
  794. self.ui.batchLoadDataPushButton.setEnabled(True)
  795. self.ui.logTextBrowser.append( "opened header file " + matfile )
  796. def openVCLogSeries(self):
  797. import scipy.io as sio
  798. try:
  799. with open('.akvo.last.vcl.path') as f:
  800. fpath = f.readline()
  801. pass
  802. except IOError as e:
  803. fpath = '.'
  804. self.DepthProfile == True
  805. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open VistaClara Log Series', fpath, r"CMR (*.mat)" )]
  806. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  807. self.ui.headerFileTextBrowser.clear()
  808. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  809. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  810. self.ui.logTextBrowser.clear()
  811. path,filen=os.path.split(str(self.headerstr[0] ))
  812. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  813. f = open('.akvo.last.vcl.path', 'w')
  814. if str(self.headerstr[0]):
  815. f.write( str(self.headerstr[0]) ) # prompt last file
  816. self.ui.headerFileBox.setEnabled(True)
  817. #########################################
  818. # LOAD the data and do some basic work
  819. self.ORSConnect( str(self.headerstr[0]) )
  820. self.lock("loading RAW record")
  821. matfile = self.headerstr[0] #.clear() # = []
  822. if fileExtension == ".mat":
  823. Data = sio.loadmat(self.headerstr[0])
  824. T2T = Data['time'][:,0]
  825. TAUE = T2T[3] - T2T[2]
  826. NS = 1
  827. self.ORS.clear() # = {}
  828. self.headerstr = [] #.clear() # = []
  829. # TODO query for depth step and data quality factor
  830. for iid in range(len(Data['depth'])):
  831. self.headerstr.append( iid )
  832. self.ORS[iid] = MRProc( ) # Fast
  833. self.ORS[iid].NE = len(Data['time'][:,0])
  834. self.ORS[iid].TAUE = TAUE
  835. self.ORS[iid].NS = 1 # TODO consider what to do here
  836. self.ORS[iid].T2T = T2T
  837. # What about moving window std.dev?
  838. self.ORS[iid].sigma = np.std(1e-2*Data['se_vector_wc'][:,iid][-100::]) # slowly varying at end?
  839. self.ORS[iid].T2N = np.random.normal( 0, self.ORS[iid].sigma, len(T2T) )
  840. self.ORS[iid].T2D = self.ORS[iid].T2N + 1j*1e-2*Data['se_vector_wc'][:,iid]
  841. #self.ORS[iid].depth = Data['depth'][iid][0]
  842. # TODO pass into GUI for weird Javelin data that is not recorded correctly
  843. self.ORS[iid].depth = 2.25- .25 * Data['depth'][iid][0]
  844. self.enableDSP()
  845. # disable buttons, do flow
  846. self.ui.WindowStackGO.setEnabled(False)
  847. self.ui.envelopeGO.setEnabled(False)
  848. self.ui.phaseGO.setEnabled(False)
  849. self.ui.WindowStackBox.setChecked(False)
  850. self.ui.envelopeGroupBox.setChecked(False)
  851. self.ui.phaseGroupBox.setChecked(False)
  852. self.ui.gateGroupBox.setChecked(True)
  853. self.ui.gateGroupBox.setEnabled(True)
  854. self.ui.gateGO.setEnabled(False)
  855. self.ui.bulkProcessGroupBox.setEnabled(True)
  856. self.ui.batchLoadDataPushButton.setEnabled(True)
  857. self.ui.logTextBrowser.append( "opened header file " + matfile )
  858. def openMultipleRecords(self):
  859. try:
  860. with open('.akvo.last.path') as f:
  861. fpath = f.readline()
  862. pass
  863. except IOError as e:
  864. fpath = '.'
  865. self.headerstrRAW = QtGui.QFileDialog.getOpenFileNames(self, 'Open multiple record', fpath, r"ORS RAW files (*.ors *.ors2);;Vista Clara Mid Field (*.vcm)")
  866. # ;;Vista Clara Javelin Processed (*.mat)" )
  867. self.headerstr = [] #[QtGui.QFileDialog.getOpenFileName(self, 'Open single record', fpath, r"ORS RAW files (*.ors *.ors2 *.vcm);;VC Mid field (*.vcm)" )]
  868. # Windoze and \ in paths
  869. #for iff in range(len(self.headerstr)) :
  870. # self.headerstr[iff] = os.path.normpath( str(self.headerstr[iff]) )
  871. # fix Windows stupid conventions
  872. for iff in range(len(self.headerstrRAW[0])) :
  873. #self.headerstr[iff] = os.path.normpath( str(self.headerstr[iff][0]) )
  874. self.headerstr.append( os.path.normpath( str(self.headerstrRAW[0][iff]) ))
  875. f = open('.akvo.last.path', 'w')
  876. if str(self.headerstr[0]):
  877. f.write( str(self.headerstr[0]) ) # prompt last file
  878. # Enable all the DSP stuff, but disable individual GO buttons
  879. self.enableDSP()
  880. self.ui.bulkProcessGroupBox.setEnabled(True)
  881. self.ui.batchLoadDataPushButton.setEnabled(True)
  882. self.ui.gateGroupBox.setEnabled(True)
  883. # disable buttons, do flow
  884. self.ui.WindowStackGO.setEnabled(False)
  885. self.ui.envelopeGO.setEnabled(False)
  886. self.ui.phaseGO.setEnabled(False)
  887. self.ui.gateGO.setEnabled(False)
  888. for ff in self.headerstr:
  889. self.ORS[ff] = MRProc( ) # Fast
  890. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableDSP()"), self.enableDSP)
  891. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("enableINV()"), self.enableINV)
  892. QtCore.QObject.connect(self.ORS[ff], QtCore.SIGNAL("doneStatus()"), self.doneStatus)
  893. #self.ORSConnect( ff )
  894. self.ui.diffusionGroupBox.setEnabled(True)
  895. self.ui.diffusionGroupBox.setChecked(True)
  896. path,filen=os.path.split(str(self.headerstr[0] ))
  897. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  898. if fileExtension == ".vcm":
  899. self.ui.phaseGroupBox.setChecked(False)
  900. self.ui.envelopeGroupBox.setChecked(False)
  901. self.ui.WindowStackBox.setChecked(False)
  902. def hangon(self):
  903. self.plotLOG10ENV()
  904. # reopen processing flow
  905. # Enable all the DSP stuff, but disable individual GO buttons
  906. self.enableDSP()
  907. self.ui.bulkProcessGroupBox.setEnabled(True)
  908. self.ui.batchLoadDataPushButton.setEnabled(True)
  909. self.ui.gateGroupBox.setEnabled(True)
  910. # disable buttons, do flow
  911. self.ui.WindowStackGO.setEnabled(False)
  912. self.ui.envelopeGO.setEnabled(False)
  913. self.ui.phaseGO.setEnabled(False)
  914. self.ui.gateGO.setEnabled(False)
  915. # Enable Inversions
  916. self.enableINV( )
  917. def batch(self):
  918. import threading
  919. # Plot all data
  920. #self.ui.qplot.getFigure().clf()
  921. #sp0 = self.ui.qplot.getFigure().add_subplot(211)
  922. #sp1 = self.ui.qplot.getFigure().add_subplot(212)
  923. #########################################
  924. # LOAD the data and do some basic work
  925. #self.unlock()
  926. self.lock("batch processing records")
  927. pars = { 'ftype' : str(self.ui.fTypeComboBox.currentText()), \
  928. 'winTrimLeft' : self.ui.winTrimLeftSpinBox.value(), \
  929. 'winTrimRight' : self.ui.winTrimRightSpinBox.value(), \
  930. 'offset' : self.ui.offsetSpinBox.value(), \
  931. 'gpd' : self.ui.gpdSpinBox.value(),
  932. 'stackEfficiency' : self.ui.stackEfficiency.value() }
  933. total = len(self.headerstr)
  934. iif = 1
  935. for ff in self.headerstr:
  936. rawThread = threading.Thread( target=self.ORS[ff].batchThread, args=(pars, ff, os.path.isfile(str(ff)), self.ui.WindowStackBox.isChecked(), \
  937. self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked()) )
  938. self.updateProgressBar(1e2*iif/total)
  939. rawThread.start()
  940. rawThread.join()
  941. iif += 1
  942. #rawThread = thread.start_new_thread(self.ORS[ff].batchThread, (pars, ff, os.path.isfile(ff), self.ui.WindowStackBox.isChecked(), \
  943. # self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked()) )
  944. #self.ORS[ff].batchThread(pars, ff, os.path.isfile(ff), self.ui.WindowStackBox.isChecked(), \
  945. # self.ui.envelopeGroupBox.isChecked(), self.ui.phaseGroupBox.isChecked(), self.ui.gateGroupBox.isChecked())
  946. self.unlock()
  947. self.hangon()
  948. #rawThread = thread.start_new_thread(self.ORS.loadORSFile, \
  949. # (str(ff),))
  950. #rawThread = thread.start_new_thread(self.batchThread, (None,))
  951. #self.batchThread(ff)
  952. def openSingleRecord(self):
  953. try:
  954. with open('.akvo.last.path') as f:
  955. fpath = f.readline()
  956. pass
  957. except IOError as e:
  958. fpath = '.'
  959. self.headerstrRAW = [QtGui.QFileDialog.getOpenFileName(self, 'Open single record', fpath, r"ORS RAW files (*.ors *.ors2 *.vcm);;VC Mid field (*.vcm)")]
  960. #;;VC Javelin (*.mat)" )]
  961. self.headerstr = [os.path.normpath( str(self.headerstrRAW[0][0]) )]
  962. #print(self.headerstr)
  963. #exit()
  964. self.ui.headerFileTextBrowser.clear()
  965. self.ui.headerFileTextBrowser.append( self.headerstr[0] )
  966. # clear the processing log? TODO do we want to do this? Not sure what about multiple inputs?
  967. self.ui.logTextBrowser.clear()
  968. path,filen=os.path.split(str(self.headerstr[0] ))
  969. fileName, fileExtension = os.path.splitext( str(self.headerstr[0]) )
  970. f = open('.akvo.last.path', 'w')
  971. if str(self.headerstr[0]):
  972. f.write( str(self.headerstr[0]) ) # prompt last file
  973. self.ui.headerFileBox.setEnabled(True)
  974. #########################################
  975. # LOAD the data and do some basic work
  976. self.ORSConnect( str(self.headerstr[0]) )
  977. self.lock("loading RAW record")
  978. if fileExtension == ".ors":
  979. rawThread = thread.start_new_thread(self.ORS[self.headerstr[0]].loadORSFile, \
  980. (str(self.headerstr[0]),))
  981. elif fileExtension == ".vcm":
  982. rawThread = thread.start_new_thread(self.ORS[self.headerstr[0]].loadVCMFile, \
  983. (str(self.headerstr[0]),))
  984. self.ui.gateGroupBox.setEnabled(True)
  985. self.ui.phaseGroupBox.setChecked(False)
  986. self.ui.envelopeGroupBox.setChecked(False)
  987. self.ui.WindowStackBox.setChecked(False)
  988. # disable buttons, do flow
  989. self.ui.WindowStackGO.setEnabled(False)
  990. self.ui.envelopeGO.setEnabled(False)
  991. self.ui.phaseGO.setEnabled(False)
  992. self.ui.gateGO.setEnabled(True)
  993. self.ui.logTextBrowser.append( "opened header file " + self.headerstr[0] )
  994. self.enableDSP( )
  995. #################################################################################################
  996. ################# PLOTTING ROUTINES ###########################################################
  997. #################################################################################################
  998. def plotRAW(self, ff=None):
  999. if ff == None:
  1000. ff = self.headerstr[0]
  1001. self.ui.statusbar.showMessage ( "plotting RAW" )
  1002. #########################################
  1003. # plot
  1004. self.ui.qplot.getFigure().clf()
  1005. self.ui.qplot.draw()
  1006. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1007. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1008. #DATASTACK = np.average(ORS.DATA, axis=0)
  1009. # Can we instead concatinate some of these in order to only call plot 1 time?
  1010. nt = len(self.ORS[ff].TIMES)
  1011. for iss in range(0, self.ORS[ff].NS):
  1012. times = np.empty(nt*self.ORS[ff].NE)
  1013. dati = np.empty(nt*self.ORS[ff].NE)
  1014. datr = np.empty(nt*self.ORS[ff].NE)
  1015. #COLOUR = np.empty((nt*self.ORS[ff].NE, 3))
  1016. for ie in range(0, self.ORS[ff].NE):
  1017. #COLOUR[nt*ie:nt*(ie+1),:] = np.array([ie/self.ORS[ff].NE, 0., 1.-ie/self.ORS[ff].NE]) # for plots
  1018. times[nt*ie:nt*(ie+1)] = self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES
  1019. dati[nt*ie:nt*(ie+1)] = np.imag(self.ORS[ff].DATA[iss,ie])
  1020. datr[nt*ie:nt*(ie+1)] = np.real(self.ORS[ff].DATA[iss,ie])
  1021. #sp0.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.imag(self.ORS[ff].DATA[iss,ie]), color=COLOUR)
  1022. #sp1.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.real(self.ORS[ff].DATA[iss,ie]), color=COLOUR)
  1023. sp0.plot(times, dati, '.', color='blue', markersize=1) #COLOUR) doesn't work
  1024. sp1.plot(times, datr, '.', color='blue', markersize=1)
  1025. sp0.set_title("imaginary")
  1026. sp1.set_title("real")
  1027. self.ui.qplot.getFigure().suptitle("RAW quadrature data")
  1028. sp1.set_xlabel("time [s]")
  1029. plt.setp(sp0.get_xticklabels(), visible=False)
  1030. self.ui.qplot.draw()
  1031. def plotWIN(self, ff=None):
  1032. if ff == None:
  1033. ff = self.headerstr[0]
  1034. #########################################
  1035. # plot
  1036. self.ui.qplot.getFigure().clf()
  1037. self.ui.qplot.draw()
  1038. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1039. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1040. nt = len(self.ORS[ff].TIMES)
  1041. times = np.empty(nt*self.ORS[ff].NE)
  1042. dati = np.empty(nt*self.ORS[ff].NE)
  1043. datr = np.empty(nt*self.ORS[ff].NE)
  1044. for ie in range(0, self.ORS[ff].NE):
  1045. times[nt*ie:nt*(ie+1)] = self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES
  1046. dati[nt*ie:nt*(ie+1)] = np.imag(self.ORS[ff].DATASTACK[ie])
  1047. datr[nt*ie:nt*(ie+1)] = np.real(self.ORS[ff].DATASTACK[ie])
  1048. #COLOUR = np.array([ie/self.ORS[ff].NE, 0., 1.-ie/self.ORS[ff].NE]) # for plots
  1049. #sp0.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.imag(self.ORS[ff].DATASTACK[ie]), color=COLOUR)
  1050. #sp1.plot( self.ORS[ff].TAUE*(float)(ie) + self.ORS[ff].TIMES, np.real(self.ORS[ff].DATASTACK[ie]), color=COLOUR)
  1051. sp0.plot(times, dati, '.', color='blue', markersize=1) #COLOUR) doesn't work
  1052. sp1.plot(times, datr, '.', color='blue', markersize=1)
  1053. sp0.set_title("imaginary")
  1054. sp1.set_title("real")
  1055. self.ui.qplot.getFigure().suptitle("RAW quadrature data")
  1056. sp1.set_xlabel("time [s]")
  1057. plt.setp(sp0.get_xticklabels(), visible=False)
  1058. self.ui.qplot.draw()
  1059. def plotENV(self, ff=None):
  1060. if ff == None:
  1061. ff = self.headerstr[0]
  1062. #########################################
  1063. # plot
  1064. self.ui.qplot.getFigure().clf()
  1065. self.ui.qplot.draw()
  1066. sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1067. sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1068. sp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='.', yerr=self.ORS[ff].sigma, label="data imag")
  1069. sp1.errorbar(self.ORS[ff].T2T, np.real(self.ORS[ff].T2D), fmt='.', yerr=np.std(self.ORS[ff].T2D.real), label="data real")
  1070. if self.ORS[ff].NS > 2:
  1071. sp1.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2N), fmt='.', yerr=self.ORS[ff].sigma, label="noise imag")
  1072. sp0.axhline(linewidth=1, color='#d62728')
  1073. sp1.axhline(linewidth=1, color='#d62728')
  1074. sp0.set_title("imaginary")
  1075. sp1.set_title("real")
  1076. self.ui.qplot.getFigure().suptitle("$T_2$ envelope dude")
  1077. sp1.set_xlabel("time [s]")
  1078. plt.setp(sp0.get_xticklabels(), visible=False)
  1079. self.ui.qplot.draw()
  1080. def plotLOG10ENV(self):
  1081. #Valid names are: ['Blues', 'BuGn', 'BuPu', 'GnBu', 'Greens', 'Greys', 'OrRd', 'Oranges', 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']
  1082. nc = max(3, len(self.headerstr))
  1083. if len(self.headerstr) > 9:
  1084. nc = 9
  1085. colours = brewer2mpl.get_map("Greens", "Sequential", nc).mpl_colors# [::-1]
  1086. self.ui.qplot.getFigure().clf()
  1087. if self.burst:
  1088. sp0 = self.ui.qplot.getFigure().add_subplot(221, facecolor=[.4,.4,.4])
  1089. sp0b = self.ui.qplot.getFigure().add_subplot(222, facecolor=[.4,.4,.4])
  1090. sp1 = self.ui.qplot.getFigure().add_subplot(223, facecolor=[.4,.4,.4], sharex=sp0, sharey=sp0)
  1091. sp1b = self.ui.qplot.getFigure().add_subplot(224, facecolor=[.4,.4,.4], sharex=sp0b, sharey=sp0b)
  1092. #plt.tight_layout(self.ui.qplot.getFigure())
  1093. else:
  1094. sp0 = self.ui.qplot.getFigure().add_subplot(211, facecolor=[.4,.4,.4])
  1095. sp1 = self.ui.qplot.getFigure().add_subplot(212, facecolor=[.4,.4,.4], sharex=sp0, sharey=sp0)
  1096. if len(self.headerstr) <= 2:
  1097. iif = 1
  1098. else:
  1099. iif = 0
  1100. # why to -1?
  1101. #for ff in self.headerstr[::-1]:
  1102. for ff in self.headerstr:
  1103. self.plotSingleLOG10ENV( self.ORS[ff], sp0, sp1, colours[iif%9], ff )
  1104. if self.burst:
  1105. self.plotSingleLOG10ENVBurst( self.ORS[ff], sp0b, sp1b, colours[iif%9], ff )
  1106. iif += 1
  1107. NLOG = True #True # True
  1108. if NLOG:
  1109. # write out noise log for GJI article
  1110. nlog = open("noise.dat", 'w')
  1111. nlog2 = open("noise2.dat", 'w')
  1112. first = False
  1113. for ff in self.headerstr[::-1]:
  1114. if not first:
  1115. times = self.ORS[ff].T2T
  1116. ifirst = True
  1117. for tt in times:
  1118. if ifirst:
  1119. nlog.write( str(tt) )
  1120. nlog2.write( str(tt) )
  1121. ifirst = False
  1122. else:
  1123. nlog.write( r"," + str(tt) )
  1124. nlog2.write( r"," + str(tt) )
  1125. nlog.write( "\n" )
  1126. nlog2.write( "\n" )
  1127. first = True
  1128. dat = self.ORS[ff].T2D.real
  1129. ifirst = True
  1130. for d in dat:
  1131. if ifirst:
  1132. nlog.write( str(d) )
  1133. ifirst = False
  1134. else:
  1135. nlog.write( r"," + str(d) )
  1136. nlog.write( "\n" )
  1137. dat = self.ORS[ff].T2D.imag
  1138. ifirst = True
  1139. for d in dat:
  1140. if ifirst:
  1141. nlog2.write( str(d) )
  1142. ifirst = False
  1143. else:
  1144. nlog2.write( r"," + str(d) )
  1145. nlog2.write( "\n" )
  1146. nlog.close()
  1147. nlog2.close()
  1148. sp0.set_title("imaginary")
  1149. sp1.set_title("real")
  1150. sp1.set_xlabel("time (s)")
  1151. sp1.set_ylabel("signal (PU)")
  1152. sp0.set_ylabel("signal (PU)")
  1153. plt.setp(sp0.get_xticklabels(), visible=False)
  1154. sp0.set_xscale('log', basex=10)
  1155. sp1.set_xscale('log', basex=10)
  1156. sp0.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1157. sp1.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1158. if self.burst:
  1159. sp0b.set_title("burst im")
  1160. sp1b.set_title("$\Re$burst")
  1161. sp1b.set_xlabel("time [s]")
  1162. plt.setp(sp0b.get_xticklabels(), visible=False)
  1163. sp0b.set_xscale('log', basex=10)
  1164. sp1b.set_xscale('log', basex=10)
  1165. sp0b.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1166. sp1b.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1167. # making the tickmarks white, longer, and wider
  1168. #sp0.tick_params(axis='both', which='both', color='w')#,length=3,width=2)
  1169. #sp1.tick_params(axis='both', which='both', color='w')#,length=3,width=2)
  1170. self.ui.qplot.draw()
  1171. self.doneStatus()
  1172. def plotSingleLOG10ENV(self, ORS, sp0, sp1, colour, ff):
  1173. #########################################
  1174. # plot
  1175. #self.ui.qplot.draw()
  1176. #sp0 = self.ui.qplot.getFigure().add_subplot(211)
  1177. #sp1 = self.ui.qplot.getFigure().add_subplot(212)
  1178. #dataf = open("javelin_" + str(ff) + ".dat", "w")
  1179. #for ii in range(len(ORS.T2D)):
  1180. # dataf.write( "%f\t%f\t%f\n" %(ORS.T2T[ii],np.imag(ORS.T2D[ii]),ORS.sigma[ii]) )
  1181. #print ("sigma", ORS.sigma)
  1182. sp0.errorbar(ORS.T2T, np.imag(ORS.T2D), fmt='.', color=colour, yerr=ORS.sigma, label="data imag")
  1183. sp1.errorbar(ORS.T2T, np.real(ORS.T2D), fmt='.', color=colour, yerr=ORS.sigma, label="data real")
  1184. if ORS.NS > 2:
  1185. sp1.errorbar(ORS.T2T, np.imag(ORS.T2N), fmt='.', yerr=ORS.sigma, label="noise imag")
  1186. def plotSingleLOG10ENVBurst(self, ORS, sp0, sp1, colour, ff):
  1187. sp0.errorbar(ORS.T2Tb, np.imag(ORS.T2Db), fmt='.', color=colour, yerr=ORS.sigmaBurst, label="data imag")
  1188. sp1.errorbar(ORS.T2Tb, np.real(ORS.T2Db), fmt='.', color=colour, yerr=ORS.sigmaBurst, label="data real")
  1189. #if ORS.NS > 2:
  1190. # sp1.errorbar(ORS.T2Tb, np.imag(ORS.T2Nb), fmt='.', yerr=ORS.sigma, label="noise imag")
  1191. def plotMONO(self):
  1192. # TODO for masked data, show differently in fit
  1193. #########################################
  1194. # plot
  1195. if not self.ui.saveDatBox.isChecked():
  1196. self.ui.qplot_2.getFigure().clf()
  1197. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1198. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1199. self.dsp0.set_title("data")
  1200. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1201. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1202. self.dsp1.set_xlabel("time [s]")
  1203. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1204. self.dsp0.set_xscale('log', basex=10)
  1205. self.dsp1.set_xscale('log', basex=10)
  1206. for ff in self.headerstr:
  1207. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', yerr=self.ORS[ff].sigma, label="data imag")
  1208. self.dsp0.plot(self.ORS[ff].MonoRes['t'], self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1209. 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")
  1210. #sp0.legend(numpoints=1)
  1211. #sp1.legend(numpoints=1)
  1212. self.ui.qplot_2.draw()
  1213. #########################################
  1214. # plot model
  1215. if not self.ui.saveModBox.isChecked():
  1216. self.ui.qplot_3.getFigure().clf()
  1217. self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111)
  1218. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1219. self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  1220. for ff in self.headerstr:
  1221. self.msp0.plot( self.ORS[ff].MonoRes['rt20'], self.ORS[ff].MonoRes['b0'], 'o', markersize=6, label="mono")
  1222. self.msp0.legend(numpoints=1)
  1223. self.ui.qplot_3.draw()
  1224. def plotBI(self):
  1225. # TODO for masked data, show differently in fit
  1226. #########################################
  1227. # plot
  1228. if not self.ui.saveDatBox.isChecked():
  1229. self.ui.qplot_2.getFigure().clf()
  1230. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1231. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1232. self.dsp0.set_title("data")
  1233. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1234. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1235. self.dsp1.set_xlabel("time [s]")
  1236. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1237. self.dsp0.set_xscale('log', basex=10)
  1238. self.dsp1.set_xscale('log', basex=10)
  1239. for ff in self.headerstr:
  1240. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', yerr=self.ORS[ff].sigma, label="data imag")
  1241. self.dsp0.plot(self.ORS[ff].BiRes['t'], self.ORS[ff].BiRes['env'], 'o', label=self.ORS[ff].BiRes['rfit'])
  1242. 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")
  1243. #sp0.legend(numpoints=1)
  1244. #sp1.legend(numpoints=1)
  1245. self.ui.qplot_2.draw()
  1246. #########################################
  1247. # plot model
  1248. if not self.ui.saveModBox.isChecked():
  1249. self.ui.qplot_3.getFigure().clf()
  1250. self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111)
  1251. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1252. self.msp0.set_ylabel(r"$A_0$ [rku]", color='black')
  1253. for ff in self.headerstr:
  1254. self.msp0.plot( self.ORS[ff].BiRes['rt20'], self.ORS[ff].BiRes['b0'], 'o', markersize=6, label="bi1")
  1255. self.msp0.plot( self.ORS[ff].BiRes['rrt20'], self.ORS[ff].BiRes['bb0'], 'o', markersize=6, label="bi2")
  1256. self.msp0.legend(numpoints=1)
  1257. self.ui.qplot_3.draw()
  1258. def plotDIFF(self, Times2, Data, Sigma, Fit=None):
  1259. #########################################
  1260. # Plot up Data and Errorbars
  1261. if not self.ui.saveDatBox.isChecked():
  1262. self.ui.qplot_6.getFigure().clf()
  1263. self.dsp0 = self.ui.qplot_6.getFigure().add_subplot(211)
  1264. self.dsp1 = self.ui.qplot_6.getFigure().add_subplot(212)
  1265. self.dsp0.set_title("data")
  1266. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1267. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1268. self.dsp1.set_xlabel("time [s]")
  1269. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1270. self.dsp0.set_xscale('log', basex=10)
  1271. self.dsp1.set_xscale('log', basex=10)
  1272. #for ff in self.headerstr:
  1273. self.dsp0.errorbar(Times2, Data, fmt='o', yerr=Sigma, label="data imag")
  1274. if Fit != None:
  1275. self.dsp0.plot(Times2, Fit, 'o', label="fit")
  1276. #self.dsp0.plot(self.ORS[ff].T2T, self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1277. self.dsp1.errorbar(Times2, Data - Fit , fmt='o', yerr=Sigma, label="mono")
  1278. #sp0.legend(numpoints=1)
  1279. #sp1.legend(numpoints=1)
  1280. self.ui.qplot_6.draw()
  1281. def plotDIFF2(self, Times2, Data, Datap, Sigma, Fit=None):
  1282. #########################################
  1283. # Plot up Data and Errorbars
  1284. if not self.ui.saveDatBox.isChecked():
  1285. self.ui.qplot_6.getFigure().clf()
  1286. self.dsp0 = self.ui.qplot_6.getFigure().add_subplot(211)
  1287. self.dsp1 = self.ui.qplot_6.getFigure().add_subplot(212)
  1288. self.dsp0.set_title("data")
  1289. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1290. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1291. self.dsp1.set_xlabel("time [s]")
  1292. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1293. self.dsp0.set_xscale('log', basex=10)
  1294. self.dsp1.set_xscale('log', basex=10)
  1295. #for ff in self.headerstr:
  1296. self.dsp0.errorbar(Times2, Data, fmt='o', yerr=Sigma, label="data imag")
  1297. self.dsp0.errorbar(Times2, Datap, fmt='o', yerr=Sigma, label="data imag")
  1298. if Fit != None:
  1299. self.dsp0.plot(Times2, Fit, 'o', label="fit")
  1300. #self.dsp0.plot(self.ORS[ff].T2T, self.ORS[ff].MonoRes['env'], 'o', label=self.ORS[ff].MonoRes['rfit'])
  1301. self.dsp1.errorbar(Times2, Datap - Fit , fmt='o', yerr=Sigma, label="mono")
  1302. #sp0.legend(numpoints=1)
  1303. #sp1.legend(numpoints=1)
  1304. self.ui.qplot_6.draw()
  1305. def plotDIST(self, mask):
  1306. #########################################
  1307. # plot data
  1308. if not self.ui.saveDatBox.isChecked():
  1309. self.ui.qplot_2.getFigure().clf()
  1310. self.dsp0 = self.ui.qplot_2.getFigure().add_subplot(211)
  1311. self.dsp1 = self.ui.qplot_2.getFigure().add_subplot(212)
  1312. self.dsp0.set_title("data")
  1313. self.dsp1.set_title("residuals with 1 $\sigma$ errorbars")
  1314. #self.ui.qplot_2.getFigure().suptitle("multi-exponential fit")
  1315. self.dsp1.set_xlabel("time [s]")
  1316. plt.setp(self.dsp0.get_xticklabels(), visible=False)
  1317. self.dsp0.set_xscale('log', basex=10)
  1318. self.dsp1.set_xscale('log', basex=10)
  1319. for ff in self.headerstr:
  1320. self.dsp0.errorbar(self.ORS[ff].T2T, np.imag(self.ORS[ff].T2D), fmt='o', color='blue', yerr=self.ORS[ff].sigma, label="data")
  1321. self.dsp0.plot(self.ORS[ff].T2T[mask:], self.ORS[ff].DistRes['env'], '.', color='red', label='dist')#, label=self.ORS[ff].MonoRes['rfit'])
  1322. 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")
  1323. #self.dsp0.legend(numpoints=1)
  1324. #self.dsp1.legend(numpoints=1)
  1325. #self.ui.qplot_2.draw()
  1326. nc = max(3, len(self.headerstr))
  1327. if len(self.headerstr) > 9:
  1328. nc = 9
  1329. colours = brewer2mpl.get_map("Greens", "Sequential", nc).mpl_colors# [::-1]
  1330. #########################################
  1331. # plot model
  1332. if not self.ui.saveModBox.isChecked():
  1333. self.ui.qplot_3.getFigure().clf()
  1334. #self.msp0 = self.ui.qplot_3.getFigure().add_subplot(111, facecolor=[.4,.4,.4])
  1335. self.msp0 = self.ui.qplot_3.getFigure().add_axes([.155,.2,.7,.65], facecolor=[.4,.4,.4])
  1336. self.msp0.set_xlabel(r"$T_2$ [s]", color='black')
  1337. self.msp0.set_ylabel(r"PWC (m$^3$/m$^3$)", color='black')
  1338. self.msp1 = self.msp0.twinx()
  1339. self.msp1.set_ylabel(r"total water (%)", color='black')
  1340. self.msp0.set_xscale('log', basex=10)
  1341. self.msp0.xaxis.grid(b=True, which='major', color='black', linestyle='-')
  1342. if len(self.headerstr) <= 2:
  1343. iif = 1
  1344. else:
  1345. iif = 0
  1346. print("%s,%s,%s"%("theta","LogMeanT2","filename"))
  1347. for ff in self.headerstr[::-1]:
  1348. #############################
  1349. # Plot dist. model
  1350. # consider normalizing by bin width? If you shift nBins it appears that water content varies
  1351. self.msp0.plot(self.ORS[ff].DistRes['Time'].T2Bins, self.ORS[ff].DistRes['mod'], '-', color=colours[iif%nc], linewidth=2, label="recovered")
  1352. ################################
  1353. # Log mean and total water
  1354. theta = np.sum( self.ORS[ff].DistRes['mod'] )
  1355. LogMeanT2 = np.exp(np.sum( self.ORS[ff].DistRes['mod'] * np.log( self.ORS[ff].DistRes['Time'].T2Bins) ) / theta )
  1356. # print("%1.5e,%1.5e,%s"%(theta,LogMeanT2, os.path.basename(ff)))
  1357. self.msp1.plot(LogMeanT2, 1e2*theta, 'o', markersize=6, color=colours[iif%nc], label="$T_{2ML}$")
  1358. iif += 1
  1359. #self.msp0.xaxis.grid(b=True, which='minor', color=[.2,.2,.2], linestyle='-')
  1360. #self.dsp1.set_xscale('log', basex=10)
  1361. #self.msp0.legend(numpoints=1)
  1362. self.ui.qplot_3.draw()
  1363. if __name__ == "__main__":
  1364. import time
  1365. import matplotlib.image as mpimg
  1366. app = QtGui.QApplication(sys.argv)
  1367. # splash a little advertising
  1368. #pixmap = QtGui.QPixmap("XRI_LOGO2.jpg")
  1369. #splash = QtGui.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
  1370. #splash.show()
  1371. #splash.showMessage("Loaded modules");
  1372. # Build main app
  1373. myapp = MyForm()
  1374. # dummy plot
  1375. img=mpimg.imread('./lemma.png')
  1376. for ax in [ myapp.ui.qplot, myapp.ui.qplot_2, myapp.ui.qplot_3 ]:
  1377. subplot = ax.getFigure().add_subplot(111)
  1378. ax.getFigure().patch.set_facecolor( None )
  1379. ax.getFigure().patch.set_alpha( .0 )
  1380. subplot.imshow(img)
  1381. subplot.xaxis.set_major_locator(plt.NullLocator())
  1382. subplot.yaxis.set_major_locator(plt.NullLocator())
  1383. ax.draw()
  1384. #subplot = myapp.ui.qplot.getFigure().add_subplot(111)
  1385. #myapp.ui.qplot.getFigure().patch.set_facecolor( None )
  1386. #myapp.ui.qplot.getFigure().patch.set_alpha( .0 )
  1387. #subplot.imshow(img)
  1388. #subplot.xaxis.set_major_locator(plt.NullLocator())
  1389. #subplot.yaxis.set_major_locator(plt.NullLocator())
  1390. #myapp.ui.qplot.draw()
  1391. myapp.show()
  1392. #splash.finish(myapp);
  1393. sys.exit(app.exec_())