123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- from akvo.tressel.SlidesPlot import *
- import numpy as np
- import sys
- import matplotlib.pyplot as plt
- import cmocean
- from pylab import meshgrid
- from akvo.tressel.logbarrier import *
- import yaml,os
-
- from matplotlib.colors import LogNorm
- from matplotlib.colors import LightSource
- from matplotlib.ticker import ScalarFormatter
- from matplotlib.ticker import MaxNLocator
- from matplotlib.ticker import AutoMinorLocator
- from matplotlib.ticker import LogLocator
- from matplotlib.ticker import FormatStrFormatter
- from matplotlib.colors import Normalize
-
- import cmocean
- from akvo.tressel.lemma_yaml import *
- from akvo.tressel import nonlinearinv as nl
-
- import pandas as pd
-
- def buildKQT(K0,tg,T2Bins):
- """
- Constructs a QT inversion kernel from an initial amplitude one.
- """
- nlay, nq = np.shape(K0)
- nt2 = len(T2Bins)
- nt = len(tg)
- KQT = np.zeros( ( nq*nt,nt2*nlay), dtype=np.complex128 )
- for iq in range(nq):
- for it in range(nt):
- for ilay in range(nlay):
- for it2 in range(nt2):
- #KQT[iq*nt + it,ilay*nt2+it2] = K0[ilay,iq]*np.exp(-((10+tg[it])*1e-3)/(1e-3*T2Bins[it2]))
- KQT[iq*nt + it,ilay*nt2+it2] = K0[ilay,iq]*np.exp(-((10+tg[it])*1e-3)/(1e-3*T2Bins[it2]))
- return KQT
-
- def loadAkvoData(fnamein, chan):
- """ Loads data from an Akvo YAML file. The 0.02 is hard coded as the pulse length. This needs to be
- corrected in future kernel calculations. The current was reported but not the pulse length.
- """
- fname = (os.path.splitext(fnamein)[0])
- with open(fnamein, 'r') as stream:
- try:
- AKVO = (yaml.load(stream, Loader=yaml.Loader))
- except yaml.YAMLError as exc:
- print(exc)
- exit()
-
- Z = np.zeros( (AKVO.nPulseMoments, AKVO.Gated["Pulse 1"]["abscissa"].size ) )
- ZS = np.zeros( (AKVO.nPulseMoments, AKVO.Gated["Pulse 1"]["abscissa"].size ) )
- for q in range(AKVO.nPulseMoments):
- Z[q] = AKVO.Gated["Pulse 1"][chan]["Q-"+str(q) + " CA"].data
- if chan == "Chan. 1":
- ZS[q] = AKVO.Gated["Pulse 1"][chan]["STD"].data
- elif chan == "Chan. 2":
- ZS[q] = AKVO.Gated["Pulse 1"][chan]["STD"].data
- elif chan == "Chan. 3":
- ZS[q] = AKVO.Gated["Pulse 1"][chan]["STD"].data
- elif chan == "Chan. 4":
- ZS[q] = AKVO.Gated["Pulse 1"][chan]["STD"].data
- else:
- print("DOOM!!!")
- exit()
- #Z *= 1e-9
- #ZS *= 1e-9
-
- J = AKVO.Pulses["Pulse 1"]["current"].data
- J = np.append(J,J[-1]+(J[-1]-J[-2]))
- Q = AKVO.pulseLength[0]*J
- return Z, ZS, AKVO.Gated["Pulse 1"]["abscissa"].data #, Q
-
- def catLayers(K0):
- K = np.zeros( (len(K0.keys()), len(K0["layer-0"].data)) , dtype=complex )
- for lay in range(len(K0.keys())):
- #print(K0["layer-"+str(lay)].data) # print (lay)
- K[lay] =K0["layer-"+str(lay)].data # print (lay)
- return 1e9*K # invert in nV
-
- def loadK0(fname):
- """ Loads in initial amplitude kernel
- """
- print("loading K0", fname)
- with open(fname) as f:
- K0 = yaml.load(f, Loader=yaml.Loader)
- K = catLayers(K0.K0)
- ifaces = np.array(K0.Interfaces.data)
- return ifaces, K
- #return ifaces, np.abs(K)
-
-
-
- def main():
-
- if (len (sys.argv) < 2):
- print ("akvoQT invertParameters.yaml")
- exit()
-
- with open(sys.argv[1], 'r') as stream:
- try:
- cont = (yaml.load(stream, Loader=yaml.Loader))
- except yaml.YAMLError as exc:
- print(exc)
-
- ###############################################
- # Load in data
- ###############################################
- V = []
- VS = []
- tg = 0
- for dat in cont['data']:
- for ch in cont['data'][dat]['channels']:
- print("dat", dat, "ch", ch)
- v,vs,tg = loadAkvoData(dat, ch)
- V.append(v)
- VS.append(vs)
- for iv in range(1, len(V)):
- V[0] = np.concatenate( (V[0], V[iv]) )
- VS[0] = np.concatenate( (VS[0], VS[iv]) )
- V = V[0]
- VS = VS[0]
-
- ###############################################
- # Load in kernels
- ###############################################
- K0 = []
- for kern in cont["K0"]:
- ifaces,k0 = loadK0( kern )
- K0.append(k0)
- for ik in range(1, len(K0)):
- K0[0] = np.concatenate( (K0[0].T, K0[ik].T) ).T
- K0 = K0[0]
-
- #plt.matshow(np.real(K0))
- #plt.show()
- #exit()
-
- ###################
- # VERY Simple DOI #
- maxq = np.argmax(np.abs(K0), axis=1)
- maxK = .1 * np.abs(K0)[ np.arange(0,len(ifaces)-1), maxq ] # 10% water is arbitrary
- SNR = maxK / (VS[0][0])
-
- #SNR[SNR>1] = 1
- SNRidx = len(ifaces)-3
- while SNR[SNRidx] > SNR[SNRidx+1] and SNRidx > 2:
- SNRidx -= 1
-
- #print("IDX", SNRidx)
- #plt.plot(ifaces[0:-1], SNR)
- #plt.plot(ifaces[0:-1][SNRidx], SNR[SNRidx], '.',markersize=12)
- #plt.gca().axhline(y=VS[0][0], xmin=0, xmax=ifaces[-1], color='r')
- #plt.gca().axhline(y=1, xmin=0, xmax=ifaces[-1], color='r')
- #K0T = np.dot(K0, K0.T)
- #K0T = np.dot(K0, np.dot( VS[0][0]* np.eye(len(ifaces)-1,1), K0.T) )
- #K0T = np.dot(K0, np.dot( 1/(VS[0][0]**2) * np.eye(np.shape(K0)[1]), K0.T) )
- #plt.matshow(0.05 * np.sqrt(K0T))
- #plt.colorbar()
- #plt.plot(ifaces[0:-1], np.diag( 0.01* np.sqrt(K0T)))
- #print(np.shape(K0T), len(ifaces)-1)
- #plt.show()
- #exit()
-
- ###############################################
- # Build full kernel
- ###############################################
- T2Bins = np.logspace( np.log10(cont["T2Bins"]["low"]), np.log10(cont["T2Bins"]["high"]), cont["T2Bins"]["number"], endpoint=True, base=10)
- KQT = np.real(buildKQT(np.abs(K0),tg,T2Bins))
-
- # model resolution matrix
- np.linalg.svd(KQT)
-
- exit()
-
- ###############################################
- # Linear Inversion
- ###############################################
- print("Calling inversion", flush=True)
- inv, ibreak, errn, phim, phid, mkappa, Wd, Wm, alphastar = logBarrier(KQT, np.ravel(V), T2Bins, "lcurve", MAXITER=150, sigma=np.ravel(VS), alpha=1e6, smooth="Smallest" )
-
- ###############################################
- # Non-linear refinement!
- ###############################################
-
- KQTc = buildKQT(K0, tg, T2Bins)
- prec = np.abs(np.dot(KQTc, inv))
- phidc = np.linalg.norm(np.dot(Wd,prec-np.ravel(V)))**2
- #PREc = np.reshape( prec, np.shape(V) )
- print("PHID linear=", errn, "PHID complex=", phidc/len(np.ravel(V)))
-
- res = nl.nonlinearinversion(inv, Wd, KQTc, np.ravel(V), Wm, alphastar )
- if res.success == True:
- INVc = np.reshape(res.x, (len(ifaces)-1,cont["T2Bins"]["number"]) )
- prec = np.abs(np.dot(KQTc, res.x))
- phidc = np.linalg.norm(np.dot(Wd,prec-np.ravel(V)))**2
- #PREc = np.reshape( prec, np.shape(V) )
- print("PHID linear=", errn, "PHID nonlinear=", phidc/len(np.ravel(V)))
-
- # Perform second fit around results of first
- res = nl.nonlinearinversion(res.x, Wd, KQTc, np.ravel(V), Wm, alphastar )
- if res.success == True:
- INVc = np.reshape(res.x, (len(ifaces)-1,cont["T2Bins"]["number"]) )
- prec = np.abs(np.dot(KQTc, res.x))
- phidc = np.linalg.norm(np.dot(Wd,prec-np.ravel(V)))**2
- #PREc = np.reshape( prec, np.shape(V) )
- print("PHID linear=", errn, "PHID nonlinear=", phidc/len(np.ravel(V)))
-
- #plt.matshow(INVc)
- #KQTc = buildKQT(K0,tg,T2Bins)
-
- #plt.matshow(PREc, cmap='Blues')
- #plt.gca().set_title("complex predicted")
- #plt.colorbar()
-
- ###############################################
- # Appraise
- ###############################################
-
-
-
-
-
- pre = np.dot(KQT,inv)
- PRE = np.reshape( pre, np.shape(V) )
- plt.matshow(PRE, cmap='Blues')
- plt.gca().set_title("predicted")
- plt.colorbar()
-
- DIFF = (PRE-V) / VS
- md = np.max(np.abs(DIFF))
- plt.matshow(DIFF, cmap=cmocean.cm.balance, vmin=-md, vmax=md)
- plt.gca().set_title("misfit / $\widehat{\sigma}$")
- plt.colorbar()
-
- plt.matshow(V, cmap='Blues')
- plt.gca().set_title("observed")
- plt.colorbar()
-
-
- T2Bins = np.append( T2Bins, T2Bins[-1] + (T2Bins[-1]-T2Bins[-2]) )
- INV = np.reshape(inv, (len(ifaces)-1,cont["T2Bins"]["number"]) )
-
- #alphas = np.tile(SNR, (len(T2Bins)-1,1))
- #colors = Normalize(1e-6, np.max(INV.T), clip=True)(INV.T)
- #colors = cmocean.cm.tempo(colors)
- ##colors[..., -1] = alphas
- #print(np.shape(colors))
- #print(np.shape(INV.T))
-
- #greys = np.full((*(INV.T).shape, 3), 70, dtype=np.uint8)
-
- ############## LINEAR RESULT ##########################
-
- Y,X = meshgrid( ifaces, T2Bins )
- fig = plt.figure( figsize=(pc2in(20.0),pc2in(22.)) )
- ax1 = fig.add_axes( [.2,.15,.6,.7] )
- im = ax1.pcolor(X, Y, INV.T, cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolor(X[0:SNRidx,:], Y[0:SNRidx,:], INV.T[0:SNRidx,:], cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolor(X[SNRidx::,:], Y[SNRidx::,:], INV.T[SNRidx::,:], cmap=cmocean.cm.tempo, alpha=.5) #cmap='viridis')
- #im = ax1.pcolormesh(X, Y, INV.T, alpha=alphas) #, cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolormesh(X, Y, INV.T, alpha=alphas) #, cmap=cmocean.cm.tempo) #cmap='viridis')
- #ax1.axhline( y=ifaces[SNRidx], xmin=T2Bins[0], xmax=T2Bins[-1], color='black' )
- im.set_edgecolor('face')
- ax1.set_xlim( T2Bins[0], T2Bins[-1] )
- ax1.set_ylim( ifaces[-1], ifaces[0] )
- cb = plt.colorbar(im, label = u"PWC (m$^3$/m$^3$)") #, format='%1.1f')
- cb.locator = MaxNLocator( nbins = 4)
- cb.ax.yaxis.set_offset_position('left')
- cb.update_ticks()
-
- ax1.set_xlabel(u"$T_2^*$ (ms)")
- ax1.set_ylabel(u"depth (m)")
-
- ax1.get_xaxis().set_major_formatter(FormatStrFormatter('%1.0f'))
- ax1.get_yaxis().set_major_formatter(FormatStrFormatter('%1.0f'))
- ax1.xaxis.set_major_locator( MaxNLocator(nbins = 4) )
-
- #ax1.xaxis.set_label_position('top')
-
- ax2 = ax1.twiny()
- ax2.plot( np.sum(INV, axis=1), (ifaces[1:]+ifaces[0:-1])/2 , color='red' )
- ax2.set_xlabel(u"total water (m$^3$/m$^3$)")
- ax2.set_ylim( ifaces[-1], ifaces[0] )
- ax2.xaxis.set_major_locator( MaxNLocator(nbins = 3) )
- ax2.get_xaxis().set_major_formatter(FormatStrFormatter('%0.2f'))
- ax2.axhline( y=ifaces[SNRidx], xmin=0, xmax=1, color='black', linestyle='dashed' )
- #ax2.xaxis.set_label_position('bottom')
-
- plt.savefig("akvoInversion.pdf")
-
-
- ############## NONLINEAR RESULT ##########################
-
- Y,X = meshgrid( ifaces, T2Bins )
- fig = plt.figure( figsize=(pc2in(20.0),pc2in(22.)) )
- ax1 = fig.add_axes( [.2,.15,.6,.7] )
- im = ax1.pcolor(X, Y, INVc.T, cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolor(X[0:SNRidx,:], Y[0:SNRidx,:], INV.T[0:SNRidx,:], cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolor(X[SNRidx::,:], Y[SNRidx::,:], INV.T[SNRidx::,:], cmap=cmocean.cm.tempo, alpha=.5) #cmap='viridis')
- #im = ax1.pcolormesh(X, Y, INV.T, alpha=alphas) #, cmap=cmocean.cm.tempo) #cmap='viridis')
- #im = ax1.pcolormesh(X, Y, INV.T, alpha=alphas) #, cmap=cmocean.cm.tempo) #cmap='viridis')
- #ax1.axhline( y=ifaces[SNRidx], xmin=T2Bins[0], xmax=T2Bins[-1], color='black' )
- im.set_edgecolor('face')
- ax1.set_xlim( T2Bins[0], T2Bins[-1] )
- ax1.set_ylim( ifaces[-1], ifaces[0] )
- cb = plt.colorbar(im, label = u"PWC (m$^3$/m$^3$)") #, format='%1.1f')
- cb.locator = MaxNLocator( nbins = 4)
- cb.ax.yaxis.set_offset_position('left')
- cb.update_ticks()
-
- ax1.set_xlabel(u"$T_2^*$ (ms)")
- ax1.set_ylabel(u"depth (m)")
-
- ax1.get_xaxis().set_major_formatter(FormatStrFormatter('%1.0f'))
- ax1.get_yaxis().set_major_formatter(FormatStrFormatter('%1.0f'))
- ax1.xaxis.set_major_locator( MaxNLocator(nbins = 4) )
-
- #ax1.xaxis.set_label_position('top')
-
- ax2 = ax1.twiny()
- ax2.plot( np.sum(INVc, axis=1), (ifaces[1:]+ifaces[0:-1])/2 , color='red' )
- ax2.set_xlabel(u"total water (m$^3$/m$^3$)")
- ax2.set_ylim( ifaces[-1], ifaces[0] )
- ax2.xaxis.set_major_locator( MaxNLocator(nbins = 3) )
- ax2.get_xaxis().set_major_formatter(FormatStrFormatter('%0.2f'))
- #ax2.axhline( y=ifaces[SNRidx], xmin=0, xmax=1, color='black', linestyle='dashed' )
- #ax2.xaxis.set_label_position('bottom')
- fig.suptitle("Non linear inversion")
- plt.savefig("akvoInversionNL.pdf")
-
-
-
- #############
- # water plot#
-
- fig2 = plt.figure( figsize=(pc2in(20.0),pc2in(22.)) )
- ax = fig2.add_axes( [.2,.15,.6,.7] )
-
- # Bound water cutoff
- Bidx = T2Bins[0:-1]<33.0
- twater = np.sum(INV, axis=1)
- bwater = np.sum(INV[:,Bidx], axis=1)
-
- ax.plot( twater, (ifaces[0:-1]+ifaces[1::])/2, label="NMR total water", color='blue' )
- ax.plot( bwater, (ifaces[0:-1]+ifaces[1::])/2, label="NMR bound water", color='green' )
-
- ax.fill_betweenx((ifaces[0:-1]+ifaces[1::])/2 , twater, bwater, where=twater >= bwater, facecolor='blue', alpha=.5)
- ax.fill_betweenx((ifaces[0:-1]+ifaces[1::])/2 , bwater, 0, where=bwater >= 0, facecolor='green', alpha=.5)
-
- ax.set_xlabel(r"$\theta_N$ (m$^3$/m$^3$)")
- ax.set_ylabel(r"depth (m)")
-
- ax.set_ylim( ifaces[-1], ifaces[0] )
- ax.set_xlim( 0, ax.get_xlim()[1] )
-
- #ax.axhline( y=ifaces[SNRidx], xmin=0, xmax=1, color='black', linestyle='dashed' )
-
- plt.savefig("akvoInversionWC.pdf")
- plt.legend()
-
-
- # Report results into a text file
- fr = pd.DataFrame( INV, columns=T2Bins[0:-1] )
- fr.insert(0, "layer top", ifaces[0:-1] )
- fr.insert(1, "layer bottom", ifaces[1::] )
- fr.insert(2, "NMR total water", np.sum(INV, axis=1) )
- fr.insert(3, "NMR bound water", bwater )
- fr.insert(4, "Layer SNR", SNR )
-
- fr.to_csv("akvoInversion.csv")
- #fr.to_excel("akvoInversion.xlsx")
-
-
- plt.show()
-
- if __name__ == "__main__":
- main()
|