From df78f7b33aca3a0c77d202d1bd9c11b99f9aa64b Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 3 Feb 2016 14:35:03 -0800 Subject: [PATCH 01/52] Branch off master Add DC_Pseudo_Section example. --- .../Examples/DC_PseudoSection_Simulation.py | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 SimPEG/Examples/DC_PseudoSection_Simulation.py diff --git a/SimPEG/Examples/DC_PseudoSection_Simulation.py b/SimPEG/Examples/DC_PseudoSection_Simulation.py new file mode 100644 index 00000000..c3517360 --- /dev/null +++ b/SimPEG/Examples/DC_PseudoSection_Simulation.py @@ -0,0 +1,179 @@ +from SimPEG import * +import simpegDCIP as DC +import scipy.interpolate as interpolation +import matplotlib.pyplot as plt +import time +import re + +def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi=np.r_[25.,25.], param = np.r_[30.,30.,5], stype = 'dpdp', plotIt=True): + """ + DC Forward Simulation + + Forward model conductive spheres in a half-space and plot a pseudo-section + + Created on Mon Feb 01 19:28:06 2016 + + @fourndo + """ + + # First we need to create a mesh and a model. + + # This is our mesh + dx = 5. + + hxind = [(dx,15,-1.3), (dx, 75), (dx,15,1.3)] + hyind = [(dx,15,-1.3), (dx, 10), (dx,15,1.3)] + hzind = [(dx,15,-1.3),(dx, 15)] + + mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCN') + + + # Set background conductivity + model = np.ones(mesh.nC) * sig[0] + + # First anomaly + ind = Utils.ModelBuilder.getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) + model[ind] = sig[1] + + # Second anomaly + ind = Utils.ModelBuilder.getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) + model[ind] = sig[2] + + # Get index of the center + indy = int(mesh.nCy/2) + + + # Plot the model for reference + # Define core mesh extent + xlim = 200 + zlim = 125 + + # Specify the survey type: "pdp" | "dpdp" + + + # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh + ends = [(-175,0),(175,0)] + ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] + + # Snap the endpoints to the grid. Easier to create 2D section. + indx = Utils.closestPoints(mesh, ends ) + locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]] + + # We will handle the geometry of the survey for you and create all the combination of tx-rx along line + [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2]) + + # Define some global geometry + dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) + dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len + dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len + azm = np.arctan(dl_y/dl_x) + + #Set boundary conditions + mesh.setCellGradBC('neumann') + + # Define the differential operators needed for the DC problem + Div = mesh.faceDiv + Grad = mesh.cellGrad + Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) + + A = Div*Msig*Grad + + # Change one corner to deal with nullspace + A[0,0] = 1 + A = sp.csc_matrix(A) + + # We will solve the system iteratively, so a pre-conditioner is helpful + # This is simply a Jacobi preconditioner (inverse of the main diagonal) + dA = A.diagonal() + P = sp.spdiags(1/dA,0,A.shape[0],A.shape[0]) + + # Now we can solve the system for all the transmitters + # We want to store the data + data = [] + + # There is probably a more elegant way to do this, but we can just for-loop through the transmitters + for ii in range(len(Tx)): + + start_time = time.time() # Let's time the calculations + + #print("Transmitter %i / %i\r" % (ii+1,len(Tx))) + + # Select dipole locations for receiver + rxloc_M = np.asarray(Rx[ii][:,0:3]) + rxloc_N = np.asarray(Rx[ii][:,3:]) + + + # For usual cases "dpdp" or "gradient" + if not re.match(stype,'pdp'): + inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T ) + RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) + + else: + + # Create an "inifinity" pole + tx = np.squeeze(Tx[ii][:,0:1]) + tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2 + inds = Utils.closestPoints(mesh, np.c_[tx,tinf].T) + RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1] / mesh.vol[inds] ) + + + # Iterative Solve + Ainvb = sp.linalg.bicgstab(P*A,P*RHS, tol=1e-5) + + # We now have the potential everywhere + phi = mkvc(Ainvb[0]) + + # Solve for phi on pole locations + P1 = mesh.getInterpolationMat(rxloc_M, 'CC') + P2 = mesh.getInterpolationMat(rxloc_N, 'CC') + + # Compute the potential difference + dtemp = (P1*phi - P2*phi)*np.pi + + data.append( dtemp ) + print '\rTransmitter {0} of {1} -> Time:{2} sec'.format(ii,len(Tx),time.time()- start_time), + + print 'Transmitter {0} of {1}'.format(ii,len(Tx)) + print 'Forward completed' + + + # Let's just convert the 3D format into 2D (distance along line) and plot + [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(Tx,Rx) + + + # Here is an example for the first tx-rx array + if plotIt: + fig = plt.figure() + ax = plt.subplot(2,1,1, aspect='equal') + mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True) + ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m') + plt.gca().set_aspect('equal', adjustable='box') + + plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') + plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') + plt.xlim([-xlim,xlim]) + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) + + + ax = plt.subplot(2,1,2, aspect='equal') + + # Plot the location of the spheres for reference + circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) + circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) + ax.add_artist(circle1) + ax.add_artist(circle2) + + # Add the speudo section + DC.plot_pseudoSection(Tx2d,Rx2d,data,mesh.vectorNz[-1],stype) + + plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') + plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') + plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) + + plt.show() + + return fig, ax + +if __name__ == '__main__': + run() \ No newline at end of file From 3eeb5dbd3cbd33c941b8821e814e3f7f78f7af67 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 3 Feb 2016 20:03:05 -0800 Subject: [PATCH 02/52] Remove dependency from Utils. Replace by internal function. --- .../Examples/DC_PseudoSection_Simulation.py | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/DC_PseudoSection_Simulation.py b/SimPEG/Examples/DC_PseudoSection_Simulation.py index c3517360..e7c73474 100644 --- a/SimPEG/Examples/DC_PseudoSection_Simulation.py +++ b/SimPEG/Examples/DC_PseudoSection_Simulation.py @@ -16,6 +16,43 @@ def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi @fourndo """ + def getIndicesSphere(center,radius,ccMesh): + """ + Creates a vector containing the sphere indices in the cell centers mesh. + Returns a tuple + + The sphere is defined by the points + + p0, describe the position of the center of the cell + + r, describe the radius of the sphere. + + ccMesh represents the cell-centered mesh + + The points p0 must live in the the same dimensional space as the mesh. + + """ + + # Validation: mesh and point (p0) live in the same dimensional space + dimMesh = np.size(ccMesh[0,:]) + assert len(center) == dimMesh, "Dimension mismatch. len(p0) != dimMesh" + + if dimMesh == 1: + # Define the reference points + + ind = np.abs(center[0] - ccMesh[:,0]) < radius + + elif dimMesh == 2: + # Define the reference points + + ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 ) < radius + + elif dimMesh == 3: + # Define the points + ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 + ( center[2] - ccMesh[:,2] )**2 ) < radius + + # Return a tuple + return ind # First we need to create a mesh and a model. # This is our mesh @@ -32,11 +69,11 @@ def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi model = np.ones(mesh.nC) * sig[0] # First anomaly - ind = Utils.ModelBuilder.getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) + ind = getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) model[ind] = sig[1] # Second anomaly - ind = Utils.ModelBuilder.getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) + ind = getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) model[ind] = sig[2] # Get index of the center From 433457f6497cbf926828d5afd80609ed3793bd9e Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 3 Feb 2016 20:12:55 -0800 Subject: [PATCH 03/52] docs and import for DC_PseudoSection_Simulation.rst --- SimPEG/Examples/__init__.py | 3 +- docs/examples/DC_PseudoSection_Simulation.rst | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 docs/examples/DC_PseudoSection_Simulation.rst diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 7ef15451..4fe604ab 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1,6 +1,7 @@ # Run this file to add imports. ##### AUTOIMPORTS ##### +import DC_PseudoSection_Simulation import EM_FDEM_Analytic_MagDipoleWholespace import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 @@ -14,7 +15,7 @@ import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation -__examples__ = ["EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] +__examples__ = ["DC_PseudoSection_Simulation", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] ##### AUTOIMPORTS ##### diff --git a/docs/examples/DC_PseudoSection_Simulation.rst b/docs/examples/DC_PseudoSection_Simulation.rst new file mode 100644 index 00000000..8f1c3ce1 --- /dev/null +++ b/docs/examples/DC_PseudoSection_Simulation.rst @@ -0,0 +1,28 @@ +.. _examples_DC_PseudoSection_Simulation: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +orward Simulation + +ard model conductive spheres in a half-space and plot a pseudo-section + +ted on Mon Feb 01 19:28:06 2016 + +rndo + + +.. plot:: + + from SimPEG import Examples + Examples.DC_PseudoSection_Simulation.run() + +.. literalinclude:: ../../SimPEG/Examples/DC_PseudoSection_Simulation.py + :language: python + :linenos: From 429d8b119117e17daa6c63592c87ea7ec26ccba3 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 10 Feb 2016 23:45:19 -0800 Subject: [PATCH 04/52] Add EM_FDEM_SusEffects example --- SimPEG/Examples/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index 4fe604ab..b821e10b 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1,6 +1,7 @@ # Run this file to add imports. ##### AUTOIMPORTS ##### +import EM_FDEM_SusEffects import DC_PseudoSection_Simulation import EM_FDEM_Analytic_MagDipoleWholespace import EM_TDEM_1D_Inversion @@ -15,7 +16,8 @@ import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation -__examples__ = ["DC_PseudoSection_Simulation", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] + +__examples__ = ["EM_FDEM_SusEffects","DC_PseudoSection_Simulation", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] ##### AUTOIMPORTS ##### From 47895ef2701ebfbae59c344b2addcaa846c2ea97 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 10 Feb 2016 23:58:48 -0800 Subject: [PATCH 05/52] consistent file name --- SimPEG/Examples/EM_FDEM_SusEffects.py | 7 +++-- SimPEG/Examples/__init__.py | 6 ++-- docs/examples/EM_FDEM_1D_Inversion.rst | 26 ---------------- docs/examples/EM_FDEM_SusEffects.rst | 41 ++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 32 deletions(-) delete mode 100644 docs/examples/EM_FDEM_1D_Inversion.rst create mode 100644 docs/examples/EM_FDEM_SusEffects.rst diff --git a/SimPEG/Examples/EM_FDEM_SusEffects.py b/SimPEG/Examples/EM_FDEM_SusEffects.py index 5021e87f..b7de07bc 100644 --- a/SimPEG/Examples/EM_FDEM_SusEffects.py +++ b/SimPEG/Examples/EM_FDEM_SusEffects.py @@ -5,7 +5,7 @@ from scipy.constants import mu_0 def run(plotIt=True): """ - FDEM: Effects of susceptibility + EM: FDEM: Effects of susceptibility =============================== When airborne freqeuncy domain EM (AFEM) survey is flown over @@ -138,8 +138,9 @@ def run(plotIt=True): axtemp.set_xlim(10, 100.) axtemp.set_title(titles[i]) plt.show() - vizfields(1, primsec="primary", realimag="real") - vizfields(1, primsec="secondary", realimag="real") + return fig, ax + fig1, ax1 = vizfields(1, primsec="primary", realimag="real") + fig2, ax2 = vizfields(1, primsec="secondary", realimag="real") if __name__ == '__main__': run() diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index b821e10b..df65e16b 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1,9 +1,10 @@ # Run this file to add imports. ##### AUTOIMPORTS ##### -import EM_FDEM_SusEffects import DC_PseudoSection_Simulation +import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace +import EM_FDEM_SusEffects import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 import Forward_BasicDirectCurrent @@ -16,8 +17,7 @@ import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation - -__examples__ = ["EM_FDEM_SusEffects","DC_PseudoSection_Simulation", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] +__examples__ = ["DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_FDEM_SusEffects", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation"] ##### AUTOIMPORTS ##### diff --git a/docs/examples/EM_FDEM_1D_Inversion.rst b/docs/examples/EM_FDEM_1D_Inversion.rst deleted file mode 100644 index acbc8cdc..00000000 --- a/docs/examples/EM_FDEM_1D_Inversion.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _examples_EM_FDEM_1D_Inversion: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - - -EM: FDEM: 1D: Inversion -======================= - -Here we will create and run a FDEM 1D inversion. - - - -.. plot:: - - from SimPEG import Examples - Examples.EM_FDEM_1D_Inversion.run() - -.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_1D_Inversion.py - :language: python - :linenos: diff --git a/docs/examples/EM_FDEM_SusEffects.rst b/docs/examples/EM_FDEM_SusEffects.rst new file mode 100644 index 00000000..47cd3644 --- /dev/null +++ b/docs/examples/EM_FDEM_SusEffects.rst @@ -0,0 +1,41 @@ +.. _examples_EM_FDEM_SusEffects: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +FDEM: Effects of susceptibility +=============================== + +When airborne freqeuncy domain EM (AFEM) survey is flown over +the earth including significantly susceptible bodies (magnetite-rich rocks), +negative data is often observed in the real part of the lowest frequency +(e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization +occurs due to a susceptible body when the magnetic field applied. + +To clarify what is happening in the earth when we are exciting the earth with +a loop source in the frequency domain we run three forward modelling: + + - F[:math:`\sigma`, :math:`\mu`]: Anomalous conductivity and susceptibility + - F[:math:`\sigma`, :math:`\mu_0`]: Anomalous conductivity + - F[:math:`\sigma_{air}`, :math:`\mu_0`]: primary field + +We plot vector magnetic fields in the earth. For secondary fields we provide +F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following +figure show only real part, since that is our interest. + + + +.. plot:: + + from SimPEG import Examples + Examples.EM_FDEM_SusEffects.run() + +.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_SusEffects.py + :language: python + :linenos: From fa6bcd3ffa263f62c9e7eebd2f00afba0c041bbd Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 11 Feb 2016 00:10:25 -0800 Subject: [PATCH 06/52] Minor changes --- SimPEG/Examples/EM_FDEM_SusEffects.py | 6 ++++-- docs/examples/EM_FDEM_1D_Inversion.rst | 26 ++++++++++++++++++++++++++ docs/examples/EM_FDEM_SusEffects.rst | 6 +++--- 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 docs/examples/EM_FDEM_1D_Inversion.rst diff --git a/SimPEG/Examples/EM_FDEM_SusEffects.py b/SimPEG/Examples/EM_FDEM_SusEffects.py index b7de07bc..3e50bf91 100644 --- a/SimPEG/Examples/EM_FDEM_SusEffects.py +++ b/SimPEG/Examples/EM_FDEM_SusEffects.py @@ -12,7 +12,7 @@ def run(plotIt=True): the earth including significantly susceptible bodies (magnetite-rich rocks), negative data is often observed in the real part of the lowest frequency (e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization - occurs due to a susceptible body when the magnetic field applied. + occurs due to a susceptible body when the magnetic field is applied. To clarify what is happening in the earth when we are exciting the earth with a loop source in the frequency domain we run three forward modelling: @@ -23,7 +23,7 @@ def run(plotIt=True): We plot vector magnetic fields in the earth. For secondary fields we provide F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following - figure show only real part, since that is our interest. + figure show both real and parts. """ # Generate Cylindrical mesh @@ -128,6 +128,7 @@ def run(plotIt=True): ax = [ax1, ax2, ax3] ax3.text(30, 50, ("Frequency=%5.2f Hz")%(frequency[ifreq]), color="k", fontsize=18) ax2.text(30, 50, primsec, color="k", fontsize=18) + ax1.text(30, 50, realimag, color="k", fontsize=18) for i, axtemp in enumerate(ax): axtemp.plot(np.r_[0, 29.75], np.r_[-50, -50], 'w', lw=3) @@ -141,6 +142,7 @@ def run(plotIt=True): return fig, ax fig1, ax1 = vizfields(1, primsec="primary", realimag="real") fig2, ax2 = vizfields(1, primsec="secondary", realimag="real") + fig4, ax4 = vizfields(1, primsec="secondary", realimag="imag") if __name__ == '__main__': run() diff --git a/docs/examples/EM_FDEM_1D_Inversion.rst b/docs/examples/EM_FDEM_1D_Inversion.rst new file mode 100644 index 00000000..acbc8cdc --- /dev/null +++ b/docs/examples/EM_FDEM_1D_Inversion.rst @@ -0,0 +1,26 @@ +.. _examples_EM_FDEM_1D_Inversion: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +EM: FDEM: 1D: Inversion +======================= + +Here we will create and run a FDEM 1D inversion. + + + +.. plot:: + + from SimPEG import Examples + Examples.EM_FDEM_1D_Inversion.run() + +.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_1D_Inversion.py + :language: python + :linenos: diff --git a/docs/examples/EM_FDEM_SusEffects.rst b/docs/examples/EM_FDEM_SusEffects.rst index 47cd3644..da4b00a0 100644 --- a/docs/examples/EM_FDEM_SusEffects.rst +++ b/docs/examples/EM_FDEM_SusEffects.rst @@ -9,14 +9,14 @@ .. --------------------------------- .. -FDEM: Effects of susceptibility +EM: FDEM: Effects of susceptibility =============================== When airborne freqeuncy domain EM (AFEM) survey is flown over the earth including significantly susceptible bodies (magnetite-rich rocks), negative data is often observed in the real part of the lowest frequency (e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization -occurs due to a susceptible body when the magnetic field applied. +occurs due to a susceptible body when the magnetic field is applied. To clarify what is happening in the earth when we are exciting the earth with a loop source in the frequency domain we run three forward modelling: @@ -27,7 +27,7 @@ a loop source in the frequency domain we run three forward modelling: We plot vector magnetic fields in the earth. For secondary fields we provide F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following -figure show only real part, since that is our interest. +figure show both real and parts. From 3a506b9051cdfcb449f05a725a3c1505568e6059 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 11 Feb 2016 08:54:44 -0800 Subject: [PATCH 07/52] Fix DC examples ... --- .../Examples/DC_PseudoSection_Simulation.py | 154 +++++++++--------- SimPEG/Examples/EM_FDEM_SusEffects.py | 2 +- docs/examples/DC_PseudoSection_Simulation.rst | 11 +- docs/examples/EM_FDEM_SusEffects.rst | 2 +- 4 files changed, 88 insertions(+), 81 deletions(-) diff --git a/SimPEG/Examples/DC_PseudoSection_Simulation.py b/SimPEG/Examples/DC_PseudoSection_Simulation.py index e7c73474..3b9c4c05 100644 --- a/SimPEG/Examples/DC_PseudoSection_Simulation.py +++ b/SimPEG/Examples/DC_PseudoSection_Simulation.py @@ -1,5 +1,6 @@ from SimPEG import * -import simpegDCIP as DC +# import simpegDCIP as DC +from SimPEG import DCIP as DC import scipy.interpolate as interpolation import matplotlib.pyplot as plt import time @@ -7,118 +8,121 @@ import re def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi=np.r_[25.,25.], param = np.r_[30.,30.,5], stype = 'dpdp', plotIt=True): """ - DC Forward Simulation - - Forward model conductive spheres in a half-space and plot a pseudo-section - - Created on Mon Feb 01 19:28:06 2016 - - @fourndo + + DC Forward Simulation + ===================== + + Forward model conductive spheres in a half-space and plot a pseudo-section + + Created on Mon Feb 01 19:28:06 2016 + + @fourndo + """ - + def getIndicesSphere(center,radius,ccMesh): """ Creates a vector containing the sphere indices in the cell centers mesh. Returns a tuple - + The sphere is defined by the points - + p0, describe the position of the center of the cell - + r, describe the radius of the sphere. - + ccMesh represents the cell-centered mesh - + The points p0 must live in the the same dimensional space as the mesh. - + """ - + # Validation: mesh and point (p0) live in the same dimensional space dimMesh = np.size(ccMesh[0,:]) assert len(center) == dimMesh, "Dimension mismatch. len(p0) != dimMesh" - + if dimMesh == 1: # Define the reference points - + ind = np.abs(center[0] - ccMesh[:,0]) < radius - + elif dimMesh == 2: # Define the reference points - + ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 ) < radius - + elif dimMesh == 3: # Define the points ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 + ( center[2] - ccMesh[:,2] )**2 ) < radius - + # Return a tuple return ind # First we need to create a mesh and a model. - + # This is our mesh dx = 5. - + hxind = [(dx,15,-1.3), (dx, 75), (dx,15,1.3)] hyind = [(dx,15,-1.3), (dx, 10), (dx,15,1.3)] hzind = [(dx,15,-1.3),(dx, 15)] - + mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCN') - - + + # Set background conductivity model = np.ones(mesh.nC) * sig[0] - + # First anomaly ind = getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) model[ind] = sig[1] - + # Second anomaly ind = getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) model[ind] = sig[2] - + # Get index of the center indy = int(mesh.nCy/2) - + # Plot the model for reference # Define core mesh extent xlim = 200 zlim = 125 - + # Specify the survey type: "pdp" | "dpdp" - - + + # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh ends = [(-175,0),(175,0)] ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] - + # Snap the endpoints to the grid. Easier to create 2D section. indx = Utils.closestPoints(mesh, ends ) locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]] - + # We will handle the geometry of the survey for you and create all the combination of tx-rx along line [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2]) - + # Define some global geometry - dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) + dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len azm = np.arctan(dl_y/dl_x) #Set boundary conditions mesh.setCellGradBC('neumann') - + # Define the differential operators needed for the DC problem Div = mesh.faceDiv Grad = mesh.cellGrad Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) - + A = Div*Msig*Grad - + # Change one corner to deal with nullspace A[0,0] = 1 A = sp.csc_matrix(A) - + # We will solve the system iteratively, so a pre-conditioner is helpful # This is simply a Jacobi preconditioner (inverse of the main diagonal) dA = A.diagonal() @@ -127,56 +131,56 @@ def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi # Now we can solve the system for all the transmitters # We want to store the data data = [] - + # There is probably a more elegant way to do this, but we can just for-loop through the transmitters for ii in range(len(Tx)): - + start_time = time.time() # Let's time the calculations - + #print("Transmitter %i / %i\r" % (ii+1,len(Tx))) - + # Select dipole locations for receiver rxloc_M = np.asarray(Rx[ii][:,0:3]) rxloc_N = np.asarray(Rx[ii][:,3:]) - + # For usual cases "dpdp" or "gradient" - if not re.match(stype,'pdp'): + if not re.match(stype,'pdp'): inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T ) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) - - else: - + RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) + + else: + # Create an "inifinity" pole tx = np.squeeze(Tx[ii][:,0:1]) tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2 inds = Utils.closestPoints(mesh, np.c_[tx,tinf].T) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1] / mesh.vol[inds] ) - - + RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1] / mesh.vol[inds] ) + + # Iterative Solve Ainvb = sp.linalg.bicgstab(P*A,P*RHS, tol=1e-5) - + # We now have the potential everywhere phi = mkvc(Ainvb[0]) - + # Solve for phi on pole locations P1 = mesh.getInterpolationMat(rxloc_M, 'CC') P2 = mesh.getInterpolationMat(rxloc_N, 'CC') - + # Compute the potential difference dtemp = (P1*phi - P2*phi)*np.pi - - data.append( dtemp ) + + data.append( dtemp ) print '\rTransmitter {0} of {1} -> Time:{2} sec'.format(ii,len(Tx),time.time()- start_time), - + print 'Transmitter {0} of {1}'.format(ii,len(Tx)) print 'Forward completed' - - + + # Let's just convert the 3D format into 2D (distance along line) and plot [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(Tx,Rx) - + # Here is an example for the first tx-rx array if plotIt: @@ -190,27 +194,27 @@ def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') plt.xlim([-xlim,xlim]) plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - ax = plt.subplot(2,1,2, aspect='equal') - + + + ax = plt.subplot(2,1,2, aspect='equal') + # Plot the location of the spheres for reference circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) ax.add_artist(circle1) - ax.add_artist(circle2) - + ax.add_artist(circle2) + # Add the speudo section DC.plot_pseudoSection(Tx2d,Rx2d,data,mesh.vectorNz[-1],stype) - + plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - + plt.show() - + return fig, ax - + if __name__ == '__main__': - run() \ No newline at end of file + run() diff --git a/SimPEG/Examples/EM_FDEM_SusEffects.py b/SimPEG/Examples/EM_FDEM_SusEffects.py index 3e50bf91..1abbb16f 100644 --- a/SimPEG/Examples/EM_FDEM_SusEffects.py +++ b/SimPEG/Examples/EM_FDEM_SusEffects.py @@ -6,7 +6,7 @@ from scipy.constants import mu_0 def run(plotIt=True): """ EM: FDEM: Effects of susceptibility - =============================== + =================================== When airborne freqeuncy domain EM (AFEM) survey is flown over the earth including significantly susceptible bodies (magnetite-rich rocks), diff --git a/docs/examples/DC_PseudoSection_Simulation.rst b/docs/examples/DC_PseudoSection_Simulation.rst index 8f1c3ce1..1d4330a1 100644 --- a/docs/examples/DC_PseudoSection_Simulation.rst +++ b/docs/examples/DC_PseudoSection_Simulation.rst @@ -9,13 +9,16 @@ .. --------------------------------- .. -orward Simulation -ard model conductive spheres in a half-space and plot a pseudo-section +DC Forward Simulation +===================== -ted on Mon Feb 01 19:28:06 2016 +Forward model conductive spheres in a half-space and plot a pseudo-section + +Created on Mon Feb 01 19:28:06 2016 + +@fourndo -rndo .. plot:: diff --git a/docs/examples/EM_FDEM_SusEffects.rst b/docs/examples/EM_FDEM_SusEffects.rst index da4b00a0..3e7dea80 100644 --- a/docs/examples/EM_FDEM_SusEffects.rst +++ b/docs/examples/EM_FDEM_SusEffects.rst @@ -10,7 +10,7 @@ EM: FDEM: Effects of susceptibility -=============================== +=================================== When airborne freqeuncy domain EM (AFEM) survey is flown over the earth including significantly susceptible bodies (magnetite-rich rocks), From 88ef74ac38ed0e29bf95f907912a201c212467b7 Mon Sep 17 00:00:00 2001 From: Thibaut Astic Date: Fri, 12 Feb 2016 15:40:48 -0800 Subject: [PATCH 08/52] MT_1D_analytic example --- .../Examples/MT_1D_analytic_nlayer_Earth.py | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py diff --git a/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py b/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py new file mode 100644 index 00000000..0cccc5f1 --- /dev/null +++ b/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py @@ -0,0 +1,443 @@ +from scipy.constants import epsilon_0, mu_0 +import matplotlib.pyplot as plt +import numpy as np +from ipywidgets import * +#from SimPEG.EM.Utils import k, omega + +""" +MT1D: n layered earth problem +***************************** + +Author: Thibaut Astic +Contact: thast@eos.ubc.ca +Date: January 2016 + +This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics). + +We start by looking at Maxwell's equations in the electric +field \\\(\\\mathbf{E}\\) and the magnetic flux +\\\(\\\mathbf{H}\\) to write the wave equations +\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) & +\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\) + +Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of +\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\) +\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\) + +With U and D the Up and Down components of the E-field. + +The iteration from one layer to another is ensure by: + +\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) = + P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\) + +And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0) +and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability) + +The layer 0 is assumed to be the air layer. + +""" + +#Frequency conversion +omega = lambda f: 2.*np.pi*f + +#Evaluate k wavenumber +k = lambda mu,sig,eps,f: np.sqrt(mu*mu_0*eps*epsilon_0*(2.*np.pi*f)**2.-1.j*mu*mu_0*sig*omega(f)) + +#Define a frquency range for a survey +frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.) + +#Functions to create random physical Perties for a n-layered earth +thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]), + np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1) + ,decimals =1)) + +sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]), + np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1) + ,decimals=3)) + +mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]), + np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1) + ,decimals=1)) + +eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]), + np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1) + ,decimals=1)) + +#Evaluate Impedance Z of a layer +ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k + +#Complex Cole-Cole Conductivity - EM utils +PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c))) + + +#Converted thickness array into top of layer array +def top(thick): + topv= np.zeros(len(thick)+1) + + topv[0]=-thick[0] + + for i in range(1,len(topv),1): + topv[i] = topv[i-1] + thick[i-1] + + return topv + +#Propagation Matrix and theirs inverses + +#matrix T for transition of Up and Down components accross a layer +T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_') + +Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_') + +#transition of Up and Down components accross a layer +UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD + + +#matrix P relating Up and Down components with E and H fields +P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_') + +Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2. + + +#Time Variation of E and H +E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D) +H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U) + +#Plot the configuration of the problem +def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z): + + topn = top(thick) + widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.) + + ax.set_ylim([z.min(),z.max()]) + ax.set_xlim([-widthg,widthg]) + + ax.set_ylabel("Depth (m)", fontsize=16.) + ax.yaxis.tick_right() + ax.yaxis.set_label_position("right") + + #define filling for the different layers + hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ] + + #Write the physical properties of air + ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)), + xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data', + xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data', + fontsize=14.) + + ax.annotate(("$\epsilon_r$= %1i")%(eps[0]), + xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', + xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data', + fontsize=14.) + + ax.annotate(("$\mu_r$= %1i")%(mu[0]), + xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', + xytext=(0, -np.abs(z.max())/3.), textcoords='data', + fontsize=14.) + + #Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern + for i in range(1,len(topn)-1,1): + if topn[i] == topn[i+1]: + pass + else: + ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)), + xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data', + xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data', + fontsize=14.) + + ax.annotate(("$\epsilon_r$= %1i")%(eps[i]), + xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data', + xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data', + fontsize=14.) + + ax.annotate(("$\mu_r$= %1.2f")%(mu[i]), + xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data', + xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data', + fontsize=14.) + + ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black') + ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10]) + + #Write the physical properties of the n-th layer and fill it with pattern + ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black') + ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10]) + + ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)), + xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data', + xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data', + fontsize=14.) + + ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]), + xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data', + xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data', + fontsize=14.) + + ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]), + xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data', + xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data', + fontsize=14.) + + #plot Trees! + ax.annotate("", + xy=(widthg/2., -1.*z.max()/5.), xycoords='data', + xytext=(widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data', + xytext=(widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data', + xytext=(widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data', + xytext=(1.2*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data', + xytext=(1.2*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data', + xytext=(1.2*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data', + xytext=(1.5*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data', + xytext=(1.5*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) + ) + + ax.annotate("", + xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data', + xytext=(1.5*widthg/2., 0.), textcoords='data', + arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) + ) + + + ax.invert_yaxis() + + return ax + +#Propagate Up and Down component for a certain frequency & evaluate E and H field + +def Propagate(f,H,sig,chg,taux,c,mu,eps,n): + + sigcm = np.zeros_like(sig,dtype='complex_') + + for j in range(1,len(sig)): + sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f) + + K = k(mu,sigcm,eps,f) + Z = ImpZ(f,mu,K) + + EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') + UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') + + UD[1,-1] = 1. + + for i in range(-2,-(n+2),-1): + + UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1] + UD = UD/((np.abs(UD[0,:]+UD[1,:])).max()) + + for j in range(0,n+1): + EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j] + + return UD, EH, Z ,K + + +#Evaluate the apparent resistivity and phase for a frequency range +def appres(F,H,sig,chg,taux,c,mu,eps,n): + + Res = np.zeros_like(F) + Phase = np.zeros_like(F) + App_ImpZ= np.zeros_like(F,dtype='complex_') + + for i in range(0,len(F)): + + UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n) + + App_ImpZ[i] = EH[0,1]/EH[1,1] + + Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i])) + Phase[i] = np.angle(App_ImpZ[i], deg = True) + + return Res,Phase + +#Evaluate Up, Down components, E and H field, for a frequency range, +#a discretized depth range and a time range (use to calculate envelope) +def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample): + + topc = top(H) + + layer = np.zeros(len(zsample),dtype=np.int)-1 + + Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') + Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') + Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') + Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') + UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_') + + for i in range(0,n+1,1): + layer = layer+(zsample>=topc[i])*1 + + for j in range(0,len(F)): + + UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n) + + for p in range(0,len(zsample)): + + UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]]) + + for q in range(0,len(tsample)): + + Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F) + Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F) + Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) + Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) + + return Exzt,Hyzt,Uz,Dz,UDaux,layer + + +#Function to Plot Apparent Resistivity and Phase +def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope): + + Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n) + + fig,ax = plt.subplots(1,2,figsize=(16,10)) + + ax[0].scatter(Res,F,color='black') + ax[0].set_xscale('Log') + ax[0].set_yscale('Log') + ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)]) + ax[0].set_ylim([F.min(),F.max()]) + ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black") + ax[0].set_ylabel('Frequency (Hz)',fontsize=16.) + ax[0].grid(which='major') + + ax0 = ax[0].twiny() + + ax0.set_xlim([0.,90.]) + ax0.set_ylim([F.min(),F.max()]) + ax0.scatter(Phase,F,color='purple') + ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple") + + zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.) + + ax[0].tick_params(labelsize=16) + ax[1].tick_params(labelsize=16) + ax0.tick_params(labelsize=16) + + if PlotEnvelope: + + widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0) + fenvelope1n=np.ones(100)*fenvelope + ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black') + + tc=np.arange(0.,1./fenvelope,0.01/(fenvelope)) + Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc) + + ax1=ax[1].twiny() + + ax[1].tick_params(labelsize=16) + ax1.tick_params(labelsize=16) + + ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16) + + ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16) + + ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))), + np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))), + color='blue', alpha=0.1) + + ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))), + np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))), + color='red', alpha=0.1) + + ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc) + ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) + ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) + else: + print 'No envelop (if True, might be slow)' + ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc) + ax[1].get_xaxis().set_ticks([]) + + plt.show() + +#Interactive MT for Notebook +def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope): + + frangn=frange(-5,5,100.) + sig3= np.array([0.,0.001,0.1, 0.001]) + thick3 = np.array([120000.,50.,50.]) + eps3=np.array([1.,1.,1.,1]) + mu3=np.array([1.,1.,1.,1]) + chg3=np.array([0.,0.1,0.,0.2]) + chg3_0=np.array([0.,0.1,0.,0.]) + taux3=np.array([0.,0.1,0.,0.1]) + c3=np.array([1.,1.,1.,1.]) + + sig3[1]=sigl1 + sig3[1]=10.**sig3[1] + sig3[2]=sigl2 + sig3[2]=10.**sig3[2] + sig3[3]=sigl3 + sig3[3]=10.**sig3[3] + mu3[1]=mul1 + mu3[2]=mul2 + mu3[3]=mul3 + eps3[1]=epsl1 + eps3[2]=epsl2 + eps3[3]=epsl3 + thick3[1]=h1 + thick3[2]=h2 + + PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope) + + +def run(n,plotIt=True): + # something to make a plot + + F = frange(-5.,5.,20) + H = thick(50.,100.,n) + sign = sig(-5.,0.,n) + mun = mu(1.,2.,n) + epsn = eps(1.,9.,n) + chg = np.zeros_like(sign) + taux = np.zeros_like(sign) + c = np.zeros_like(sign) + + Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n) + + if plotIt: + + PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True) + + return Res, Phase + +if __name__ == '__main__': + run(3) + + + + + From 4cf5d49524d7d44e390ddd2dc8a12113dcc0b002 Mon Sep 17 00:00:00 2001 From: Thibaut Astic Date: Fri, 12 Feb 2016 15:48:48 -0800 Subject: [PATCH 09/52] Ignoring non functioning examples --- SimPEG/Examples/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index df65e16b..73665644 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -1,10 +1,10 @@ # Run this file to add imports. ##### AUTOIMPORTS ##### -import DC_PseudoSection_Simulation +#import DC_PseudoSection_Simulation import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace -import EM_FDEM_SusEffects +#import EM_FDEM_SusEffects import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 import Forward_BasicDirectCurrent From 6286e48830ff06a82153f973a39faae59f1457e8 Mon Sep 17 00:00:00 2001 From: Thibaut Astic Date: Mon, 15 Feb 2016 13:13:44 -0800 Subject: [PATCH 10/52] Sphere Electrostatic example. code cleaned, commented and updated. --- .../Examples/sphereElectrostatic_example.py | 776 ++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 SimPEG/Examples/sphereElectrostatic_example.py diff --git a/SimPEG/Examples/sphereElectrostatic_example.py b/SimPEG/Examples/sphereElectrostatic_example.py new file mode 100644 index 00000000..4b96f740 --- /dev/null +++ b/SimPEG/Examples/sphereElectrostatic_example.py @@ -0,0 +1,776 @@ +from scipy.constants import epsilon_0 +import matplotlib.pyplot as plt +import matplotlib.colors as colors +import numpy as np +from ipywidgets import * +from SimPEG.Utils import ndgrid, mkvc + +''' +Authors: Thibaut Astic, Lindsey Heagy, Sanna Tyrvainen, Ronghua Peng +Date: December 2015 + +This code defines function to resolve analytically the electrostatic sphere problem. +We first define a problem configuration, with a conductive or resistive sphere in a +wholespace background. +We then calculate the potential, then the electric field, then the current density and +finally the charges accumulation. + +Several plotting functions are defined for data visualisation. + + +''' + +# Plot options +ftsize_title = 18 #font size for titles +ftsize_axis = 14 #font size for axis ticks +ftsize_label = 14 #font size for axis labels + +# Radius function, useful sigma ratio, and log scale converter +r = lambda x,y,z: np.sqrt(x**2.+y**2.+z**2.) +sigf = lambda sig0,sig1: (sig1-sig0)/(sig1+2.*sig0) + +#tools to convert log conductivity in conductivity +def conductivity_log_wrapper(log_sig0,log_sig1): + sig0 = 10.**log_sig0 + sig1 = 10.**log_sig1 + + return sig0,sig1 + +# Examples +#Plot the configuration. Label=False is used to generate a general case figure +def get_Setup(XYZ,sig0,sig1,R,E0,ax,label,colorsphere): + ''' + XYZ: ndgrid + sig0: conductivity of the background + sig1: conductivity of the sphere + R: radius of the sphere + E0: Amplitude of the uniform electrostatic field + ax: ax where to plot the configuration + label: True: plot real values, False: plot general case + colorsphere: color of the sphere, format [x,x,x] + ''' + + xplt = np.linspace(-R, R, num=100) + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + dx = xr[1]-xr[0] + top = np.sqrt(R**2-xplt**2) + bot = -np.sqrt(R**2-xplt**2) + + if R != 0: + ax.plot(xplt, top, xplt, bot, color=colorsphere,linewidth=1.5) + ax.fill_between(xplt,bot,top,color=colorsphere,alpha=0.5 ) + ax.arrow(0.,0.,np.sqrt(2.)*R/2.,np.sqrt(2.)*R/2.,head_width=0.,head_length=0.) + + if label: + ax.annotate(("$\sigma_1$=%3.3f mS/m")%(sig1*10.**(3.)), + xy=(0.,-R/2.), xycoords='data', + xytext=(0.,-R/2.), textcoords='data', + fontsize=14.) + ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), + xy=(0.,-1.5*R), xycoords='data', + xytext=(0.,-1.5*R), textcoords='data', + fontsize=14.) + ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), + xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', + xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', + fontsize=14.) + ax.annotate(('$R$ = %1i m')%(R), + xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', + xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', + fontsize=14.) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.tick_params(labelsize=ftsize_axis) + + else: + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.text(-1.,-np.sqrt(R)/2.-10.,'$\sigma_1$',fontsize=14) + ax.text(-0.05,-R-10,'$\sigma_0$',fontsize=14) + ax.annotate(('$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m'), + xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', + xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', + fontsize=14.) + ax.annotate(('$R$'), + xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', + xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', + fontsize=14.) + ax.set_xlabel('x',fontsize=12) + ax.set_ylabel('y',fontsize=12) + + else: + if label: + ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), + xy=(0.,-1.5*R), xycoords='data', + xytext=(0.,-1.5*R), textcoords='data', + fontsize=14.) + ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), + xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', + xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', + fontsize=14.) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.tick_params(labelsize=ftsize_axis) + + else: + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.text(-0.05,-10,'$\sigma_0$',fontsize=14) + ax.text(xr.min()+np.abs(xr.max()-xr.min())/20., 0, '$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m', fontsize=14) + ax.set_xlabel('x',fontsize=12) + ax.set_ylabel('y',fontsize=12) + + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + [ax.arrow(xr.min(),_,np.abs(xr.max()-xr.min())/20.,0.,head_width=5.,head_length=2.,color='k') for _ in np.linspace(yr.min(),yr.max(),num=10)] + ax.patch.set_facecolor([0.4,0.7,0.4]) + ax.patch.set_alpha(0.2) + + ax.set_aspect('equal') + + + + return ax + +def get_Conductivity(XYZ,sig0,sig1,R): + ''' + Define the conductivity for each point of the space + ''' + x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] + r_view=r(x,y,z) + + ind0= (r_view>R) + ind1= (r_view<=R) + + assert (ind0 + ind1).all(), 'Some indicies not included' + + Sigma = np.zeros_like(x) + + Sigma[ind0] = sig0 + Sigma[ind1] = sig1 + + return Sigma + + +def get_Potential(XYZ,sig0,sig1,R,E0): + + ''' + Function that returns the total, the primary and the secondary potentials, assumes an x-oriented inducing field and that the sphere is at the origin + :input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field + ''' + + x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] + + sig_cur = sigf(sig0,sig1) + + r_cur = r(x,y,z) # current radius + + ind0 = (r_cur > R) + ind1 = (r_cur <= R) + + assert (ind0 + ind1).all(), 'Some indicies not included' + + Vt = np.zeros_like(x) + Vp = np.zeros_like(x) + Vs = np.zeros_like(x) + + Vt[ind0] = -E0*x[ind0]*(1.-sig_cur*R**3./r_cur[ind0]**3.) # total potential outside the sphere + Vt[ind1] = -E0*x[ind1]*3.*sig0/(sig1+2.*sig0) # inside the sphere + + + Vp = - E0*x # primary potential + + Vs = Vt - Vp # secondary potential + + return Vt,Vp,Vs + +#plot the primary potential on ax +def Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax): + + Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + xcirc = xr[np.abs(xr) <= R] + + Pplot = ax.pcolor(xr,yr,Vp.reshape(xr.size,yr.size)) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_title('Primary Potential',fontsize=ftsize_title) + cb = plt.colorbar(Pplot,ax=ax) + cb.set_label(label= 'Potential ($V$)',size=ftsize_label) + cb.ax.tick_params(labelsize=ftsize_axis) + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.set_aspect('equal') + ax.tick_params(labelsize=ftsize_axis) + + return ax + +#plot the total potential on ax +def Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax): + + Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + xcirc = xr[np.abs(xr) <= R] + + + Pplot = ax.pcolor(xr,yr,Vt.reshape(xr.size,yr.size)) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_title('Total Potential',fontsize=ftsize_title) + cb = plt.colorbar(Pplot,ax=ax) + cb.set_label(label= 'Potential ($V$)',size=ftsize_label) + cb.ax.tick_params(labelsize=ftsize_axis) + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.set_aspect('equal') + ax.tick_params(labelsize=ftsize_axis) + + return ax + +#plot the secondary potential on ax +def Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax): + + Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + xcirc = xr[np.abs(xr) <= R] + + Pplot = ax.pcolor(xr,yr,Vs.reshape(xr.size,yr.size)) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_title('Secondary Potential',fontsize=ftsize_title) + cb = plt.colorbar(Pplot,ax=ax) + cb.set_label(label= 'Potential ($V$)',size=ftsize_label) + cb.ax.tick_params(labelsize=ftsize_axis) + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.set_aspect('equal') + ax.tick_params(labelsize=ftsize_axis) + + return ax + + +def get_ElectricField(XYZ,sig0,sig1,R,E0): + ''' + Function that returns the total, the primary and the secondary electric fields, + input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field + ''' + + x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] + + r_cur=r(x,y,z) # current radius + + ind0= (r_cur>R) + ind1= (r_cur<=R) + + assert (ind0 + ind1).all(), 'Some indicies not included' + + Ep = np.zeros(shape=(len(x),3)) + Ep[:,0] = E0 + + Et = np.zeros(shape=(len(x),3)) + + Et[ind0,0] = E0 + E0*R**3./(r_cur[ind0]**5.)*sigf(sig0,sig1)*(2.*x[ind0]**2.-y[ind0]**2.-z[ind0]**2.); + Et[ind0,1] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*y[ind0]*sigf(sig0,sig1); + Et[ind0,2] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*z[ind0]*sigf(sig0,sig1); + + Et[ind1,0] = 3.*sig0/(sig1+2.*sig0)*E0; + Et[ind1,1] = 0.; + Et[ind1,2] = 0.; + + Es = Et - Ep + + return Et, Ep, Es + +#plot the total electric field on ax +def Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax): + + Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + xcirc = xr[np.abs(xr) <= R] + + EtXr = Et[:,0].reshape(xr.size, yr.size) + EtYr = Et[:,1].reshape(xr.size, yr.size) + EtAmp = np.sqrt(Et[:,0]**2+Et[:,1]**2 + Et[:,2]**2).reshape(xr.size, yr.size) + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.tick_params(labelsize=ftsize_axis) + ax.set_aspect('equal') + + Eplot = ax.pcolor(xr,yr,EtAmp) + cb = plt.colorbar(Eplot,ax=ax) + cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') + cb.ax.tick_params(labelsize=ftsize_axis) + ax.streamplot(xr,yr,EtXr,EtYr,color='gray',linewidth=2.,density=0.75)#angles='xy',scale_units='xy',scale=0.05) + ax.set_title('Total Field',fontsize=ftsize_title) + + + return ax + +#plot the secondary electric field on ax +def Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax): + + Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + xcirc = xr[np.abs(xr) <= R] + + EsXr = Es[:,0].reshape(xr.size, yr.size) + EsYr = Es[:,1].reshape(xr.size, yr.size) + EsAmp = np.sqrt(Es[:,0]**2+Es[:,1]**2+Es[:,2]**2).reshape(xr.size, yr.size) + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.tick_params(labelsize=ftsize_axis) + ax.set_aspect('equal') + + Eplot = ax.pcolor(xr,yr,EsAmp) + cb = plt.colorbar(Eplot,ax=ax) + cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') + cb.ax.tick_params(labelsize=ftsize_axis) + ax.streamplot(xr,yr,EsXr,EsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=0.05) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_title('Secondary Field',fontsize=ftsize_title) + + return ax + + +def get_Current(XYZ,sig0,sig1,R,Et,Ep,Es): + ''' + Function that returns the total, the primary and the secondary current densities, + :input: grid, outer sigma, inner sigma, radius of the sphere, total, the primary and the seconadry electric fields, + ''' + + x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] + + r_cur=r(x,y,z) + + ind0= (r_cur>R) + ind1= (r_cur<=R) + + assert (ind0 + ind1).all(), 'Some indicies not included' + + Jt = np.zeros(shape=(len(x),3)) + J0 = np.zeros(shape=(len(x),3)) + Js = np.zeros(shape=(len(x),3)) + + + Jp = sig0*Ep + + Jt[ind0,:] = sig0*Et[ind0,:] + Jt[ind1,:] = sig1*Et[ind1,:] + + Js[ind0,:] = sig0*(Et[ind0,:]-Ep[ind0,:]) + Js[ind1,:] = sig1*Et[ind1,:]-sig0*Ep[ind1,:] + + return Jt,Jp,Js + +#plot the total currents density on ax +def Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax): + + Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) + Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + xcirc = xr[np.abs(xr) <= R] + + JtXr = Jt[:,0].reshape(xr.size, yr.size) + JtYr = Jt[:,1].reshape(xr.size, yr.size) + JtAmp = np.sqrt(Jt[:,0]**2+Jt[:,1]**2+Jt[:,2]**2).reshape(xr.size, yr.size) + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) + ax.tick_params(labelsize=ftsize_axis) + ax.set_aspect('equal') + + Jplot = ax.pcolor(xr,yr,JtAmp.reshape(xr.size,yr.size)) + cb = plt.colorbar(Jplot,ax=ax) + cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') + cb.ax.tick_params(labelsize=ftsize_axis) + ax.streamplot(xr,yr,JtXr,JtYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) + ax.set_title('Total Current Density',fontsize=ftsize_title) + + return ax + + +#plot the secondary currents density on ax +def Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax): + + Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) + Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + xcirc = xr[np.abs(xr) <= R] + + JsXr = Js[:,0].reshape(xr.size, yr.size) + JsYr = Js[:,1].reshape(xr.size, yr.size) + JsAmp = np.sqrt(Js[:,1]**2+Js[:,0]**2+Jt[:,2]**2).reshape(xr.size,yr.size) + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) + ax.tick_params(labelsize=ftsize_axis) + ax.set_aspect('equal') + + Jplot = ax.pcolor(xr,yr,JsAmp.reshape(xr.size,yr.size)) + cb = plt.colorbar(Jplot,ax=ax) + cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') + cb.ax.tick_params(labelsize=ftsize_axis) + ax.streamplot(xr,yr,JsXr,JsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) + ax.set_title('Secondary Current Density',fontsize=ftsize_title) + + return ax + + +def get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep): + ''' + Function that returns the charges accumulation at the background/sphere interface, + :input: grid, outer sigma, inner sigma, radius of the sphere, total and the primary electric fields, + ''' + + x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] + + dx = x[1]-x[0] + + r_cur=r(x,y,z) + + ind0 = (r_cur > R) + ind1 = (r_cur < R) + ind2 = ((r_cur < (R+dx/2)) & (r_cur > (R-dx/2)) ) + + assert (ind0 + ind1 + ind2).all(), 'Some indicies not included' + + rho = np.zeros_like(x) + + rho[ind0] = 0 + rho[ind1] = 0 + rho[ind2] = epsilon_0*3.*Ep[ind2,0]*sigf(sig0,sig1)*x[ind2]/(np.sqrt(x[ind2]**2.+y[ind2]**2.)) + + return rho + +#Plot charges density on ax +def Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax): + + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + xcirc = xr[np.abs(xr) <= R] + + Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) + rho = get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep) + + ax.set_xlim([xr.min(),xr.max()]) + ax.set_ylim([yr.min(),yr.max()]) + ax.set_aspect('equal') + Cplot = ax.pcolor(xr,yr,rho.reshape(xr.size, yr.size)) + cb1 = plt.colorbar(Cplot,ax=ax) + cb1.set_label(label= 'Charge Density ($C/m^2$)',size=ftsize_label) #weight='bold') + cb1.ax.tick_params(labelsize=ftsize_axis) + ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') + ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) + ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) + ax.tick_params(labelsize=ftsize_axis) + ax.set_title('Charges Density', fontsize=ftsize_title) + + return ax + +def MN_Potential_total(sig0,sig1,R,E0,start,end,nbmp,mn): + + ''' + Function that return array of midpoints electrodes, electrodes positions, + potentials differences for total and secondary potentials fields, unormalized and + normalized to electrodes distances. + sig0: background conductivity + sig1: sphere conductivity + R: Sphere's radius + E0: uniform E field value + start: start point for the profile start.shape = (2,) + end: end point for the profile end.shape = (2,) + nbmp: number of dipoles + mn: Space between the M and N electrodes + ''' + + #D: total distance from start to end + D = np.sqrt((start[0]-end[0])**2.+(start[1]-end[1])**2.) + + #MP: dipoles'midpoint positions (x,y) + MP = np.zeros(shape=(nbmp,2)) + MP[:,0] = np.linspace(start[0],end[0],nbmp) + MP[:,1] = np.linspace(start[1],end[1],nbmp) + + #Dipoles'Electrodes positions around each midpoints + EL = np.zeros(shape=(2*nbmp,2)) + for n in range(0,len(EL),2): + EL[n,0] = MP[n/2,0] - ((end[0]-start[0])/D)*mn/2. + EL[n+1,0] = MP[n/2,0] + ((end[0]-start[0])/D)*mn/2. + EL[n,1] = MP[n/2,1] - ((end[1]-start[1])/D)*mn/2. + EL[n+1,1] = MP[n/2,1] + ((end[1]-start[1])/D)*mn/2. + + VtEL = np.zeros(2*nbmp) #Total Potential (Vt-) at each electrode (-EL) + VsEL = np.zeros(2*nbmp) #Secondary Potential (Vt-) at each electrode (-EL) + dVtMP = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) + dVtMPn = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) + dVsMP = np.zeros(nbmp) #Diffence (d-) of Secondaty Potential (Vt-) at each dipole (-MP) + dVsMPn = np.zeros(nbmp) #Diffence (d-) of Secondary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) + dVpMP = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) + dVpMPn = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) + + #Computing VtEL + for m in range(0,2*nbmp): + if (r(EL[m,0],EL[m,1],0) > R): + VtEL[m] = -E0*EL[m,0]*(1.-sigf(sig0,sig1)*R**3./r(EL[m,0],EL[m,1],0)**3.) + else: + VtEL[m] = -E0*EL[m,0]*3.*sig0/(sig1+2.*sig0) + + #Computing VsEL + VsEL = VtEL + E0*EL[:,0] + + #Computing dVtMP, dVsMP + for p in range(0,nbmp): + dVtMP[p] = VtEL[2*p]-VtEL[2*p+1] + dVtMPn[p] = dVtMP[p]/mn + dVsMP[p] = VsEL[2*p]-VsEL[2*p+1] + dVsMPn[p] = dVsMP[p]/mn + + return MP,EL,dVtMP,dVtMPn,dVsMP,dVsMPn + +#Compare the DC response of two configurations +def two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,nb_dipole,electrode_spacing,PlotOpt):#,linearcolor): + + #Define the mesh + xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) + + #Defining the Profile + start = np.array([xstart,ystart]) + end = np.array([xend,yend]) + + #Calculating the data from the defined survey line for Configuration 0 and 1 + MP0,EL0,VtdMP0,VtdMPn0,VsdMP0,VsdMPn0 = MN_Potential_total(sig0,sig1,R0,E0,start,end,nb_dipole,electrode_spacing) + MP1,EL1,VtdMP1,VtdMPn1,VsdMP1,VsdMPn1 = MN_Potential_total(sig0,sig2,R1,E0,start,end,nb_dipole,electrode_spacing) + + + # Initializing the figure + fig = plt.figure(figsize=(20,20)) + ax0 = plt.subplot2grid((20,12), (0, 0),colspan=6,rowspan=6) + ax1 = plt.subplot2grid((20,12), (0, 6),colspan=6,rowspan=6) + ax2 = plt.subplot2grid((20,12), (16, 2), colspan=9,rowspan=4) + ax3 = plt.subplot2grid((20,12), (8, 0),colspan=6,rowspan=6) + ax4 = plt.subplot2grid((20,12), (8, 6),colspan=6,rowspan=6) + + #Plotting the Configuration 0 + ax0 = get_Setup(XYZ,sig0,sig1,R0,E0,ax0,True,[0.6,0.1,0.1]) + + #Plotting the Configuration 1 + ax1 = get_Setup(XYZ,sig0,sig2,R1,E0,ax1,True,[0.1,0.1,0.6]) + + #Plotting the Data (Legends) + ax2.set_title('Potential Differences',fontsize=ftsize_title) + ax2.set_ylabel('Potential difference ($V$)',fontsize=ftsize_label) + ax2.set_xlabel('Distance from start point ($m$)',fontsize=ftsize_label) + ax2.tick_params(labelsize=ftsize_axis) + ax2.grid() + + if PlotOpt == 'Total': + ax3= Plot_Total_Potential(XYZ,sig0,sig1,R0,E0,ax3) + ax4= Plot_Total_Potential(XYZ,sig0,sig2,R1,E0,ax4) + + #Plot the Data (from Configuration 0) + gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VtdMP0 + ,marker='o',color='blue',linewidth=3.,label ='Left Model Response' ) + + #Plot the Data (from Configuration 1) + gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VtdMP1 + ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) + ax2.legend(('Left Model Response','Right Model Response'),loc=4) + + elif PlotOpt == 'Secondary': + #plot the secondary potentials + ax3= Plot_Secondary_Potential(XYZ,sig0,sig1,R0,E0,ax3) + ax4= Plot_Secondary_Potential(XYZ,sig0,sig2,R1,E0,ax4) + + #Plot the data(from configuration 0) + gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VsdMP0,color='blue' + ,marker='o',linewidth=3.,label ='Left Model Response' ) + + + #Plot the Data (from Configuration 1) + gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VsdMP1 + ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) + ax2.legend(('Left Model Response','Right Model Response'),loc=4 ) + + else: + print('What dont you get? Total or Secondary?') + + #Legends + ax3.plot(MP0[:,0],MP0[:,1],color='gray') + Dip_Midpoint0 = ax3.scatter(MP0[:,0],MP0[:,1],color='black') + Electrodes0 = ax3.scatter(EL0[:,0],EL0[:,1],color='red') + ax3.legend([Dip_Midpoint0,Electrodes0], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) + + ax4.plot(MP1[:,0],MP1[:,1],color='gray') + Dip_Midpoint1 = ax4.scatter(MP1[:,0],MP1[:,1],color='black') + Electrodes1 = ax4.scatter(EL1[:,0],EL1[:,1],color='red') + ax4.legend([Dip_Midpoint1,Electrodes1], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) + + return fig + +#Function to visualise and compare any two meaningful plots for the sphere in a uniform backgound with an unifom Electric Field +def interact_conductiveSphere(R,log_sig0,log_sig1,Figure1a,Figure1b,Figure2a,Figure2b): + + sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) + E0 = 1. # inducing field strength in V/m + n = 100 #level of discretisation + xr = np.linspace(-200., 200., n) # X-axis discretization + yr = xr.copy() # Y-axis discretization + zr = np.r_[0] # identical to saying `zr = np.array([0])` + XYZ = ndgrid(xr,yr,zr) # Space Definition + + fig, ax = plt.subplots(1,2,figsize=(18,6)) + + #Setup figure 1 with options Configuration, Total or Secondary, + #then Potential, ElectricField, Current Density or Charges Density + if Figure1a == 'Configuration': + ax[0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0],True,[0.1,0.1,0.6]) + + elif Figure1a == 'Total': + + if Figure1b == 'Potential': + ax[0] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'ElectricField': + ax[0] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'CurrentDensity': + ax[0] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'ChargesDensity': + ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1a == 'Secondary': + + if Figure1b == 'Potential': + ax[0] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'ElectricField': + ax[0] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'CurrentDensity': + ax[0] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[0]) + + elif Figure1b == 'ChargesDensity': + ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) + + + if Figure1a== 'Configuration': + ax[1] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) + print 'While figure1 is plotting Configuration, figure2 plots the primary field' + + elif Figure2a == 'Total': + if Figure2b == 'Potential': + ax[1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'ElectricField': + ax[1] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'CurrentDensity': + ax[1]=Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'ChargesDensity': + ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) + + + elif Figure2a == 'Secondary': + if Figure2b == 'Potential': + ax[1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'ElectricField': + ax[1] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'CurrentDensity': + ax[1] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1]) + + elif Figure2b == 'ChargesDensity': + ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) + + plt.tight_layout(True) + plt.show() + +#Interactive Visualisation of the responses of two configurations to a (pseudo) DC resistivity survey +def interactive_two_configurations_comparison(log_sig0,log_sig1,log_sig2,R0,R1,xstart,ystart,xend,yend,dipole_number,electrode_spacing,matching_spheres_example): + + sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) + sig2 = 10.**log_sig2 + E0 = 1. # inducing field strength in V/m + n = 100 #level of discretisation + xr = np.linspace(-200., 200., n) # X-axis discretization + yr = xr.copy() # Y-axis discretization + zr = np.r_[0] # identical to saying `zr = np.array([0])` + XYZ = ndgrid(xr,yr,zr) # Space Definition + PlotOpt = 'Total' + + if matching_spheres_example: + sig0 = 10.**(-3) + sig1 = 10.**(-2) + sig2 = 1.310344828 * 10**(-3) + R0 = 20. + R1 = 40. + + two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) + + else: + two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) + + plt.tight_layout(True) + plt.show() + + + +if __name__ == '__main__': + sig0 = -3. # conductivity of the wholespace + sig1 = -1. # conductivity of the sphere + sig0, sig1 = conductivity_log_wrapper(sig0,sig1) + R = 50. # radius of the sphere + E0 = 1. # inducing field strength + n = 100 #level of discretisation + xr = np.linspace(-2.*R, 2.*R, n) # X-axis discretization + yr = xr.copy() # Y-axis discretization + zr = np.r_[0] # identical to saying `zr = np.array([0])` + XYZ = ndgrid(xr,yr,zr) # Space Definition + + fig, ax = plt.subplots(2,5,figsize=(50,10)) + ax[0,0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0,0],True,[0.6,0.1,0.1]) + ax[1,0] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1,0]) + ax[0,1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0,1]) + ax[1,1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1,1]) + ax[0,2] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0,2]) + ax[1,2] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1,2]) + ax[0,3] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0,3]) + ax[1,3] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1,3]) + ax[0,4] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[0,4]) + ax[1,4] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1,4]) + + + plt.show() + From a9c9ce6bc8658317f3ad3e763b44cdc9db884f29 Mon Sep 17 00:00:00 2001 From: Thibaut Astic Date: Mon, 15 Feb 2016 19:50:04 -0800 Subject: [PATCH 11/52] remove ipywidget --- SimPEG/Examples/sphereElectrostatic_example.py | 1 - 1 file changed, 1 deletion(-) diff --git a/SimPEG/Examples/sphereElectrostatic_example.py b/SimPEG/Examples/sphereElectrostatic_example.py index 4b96f740..7ff1ead1 100644 --- a/SimPEG/Examples/sphereElectrostatic_example.py +++ b/SimPEG/Examples/sphereElectrostatic_example.py @@ -2,7 +2,6 @@ from scipy.constants import epsilon_0 import matplotlib.pyplot as plt import matplotlib.colors as colors import numpy as np -from ipywidgets import * from SimPEG.Utils import ndgrid, mkvc ''' From 8aa23c31de6fdadde3b3f3059d411251851ebcd4 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 21:53:31 -0800 Subject: [PATCH 12/52] Allow moving off bounds in projected gradient. The current implementation does not allow you to move off the bounds (lower/upper) once you have gotten on them, this allows you to move off of the bound. Please note that more testing should be done to ensure that this does not introduce oscillations into the optimization routine. --- SimPEG/Optimization.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 4f2cb062..54f6c4ff 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -990,4 +990,18 @@ class ProjectedGNCG(BFGS, Minimize, Remember): cgFlag = 1 # End CG Iterations + # Take a gradient step on the active cells if exist + if temp != self.xc.size: + + rhs_a = (Active) * -self.g + + dm_i = max( abs( delx ) ) + dm_a = max( abs(rhs_a) ) + + delx = delx + rhs_a * dm_i / dm_a /10. + + # Only keep gradients going in the right direction on the active set + indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0)) + delx[indx] = 0. + return delx From 05a85018de792c16c8e728f4ab893c715bcd52de Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 21:59:08 -0800 Subject: [PATCH 13/52] Create a Simple and a SparseRegularization class. The SparseRegularization class allows implementation of p-q norms. --- SimPEG/Regularization.py | 210 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 677fba5c..6a65860d 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -282,3 +282,213 @@ class Tikhonov(BaseRegularization): out = mD.T * ( self.W.T * r ) return out + +class Simple(BaseRegularization): + """ + Only for tensor mesh + """ + + smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + + def __init__(self, mesh, mapping=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) + + @property + def Ws(self): + """Regularization matrix Ws""" + if getattr(self,'_Ws', None) is None: + self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + return self._Ws + + @property + def Wx(self): + """Regularization matrix Wx""" + if getattr(self, '_Wx', None) is None: + self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x)**0.5)*self.mesh.unitCellGradx + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + if getattr(self, '_Wy', None) is None: + self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y)**0.5)*self.mesh.unitCellGrady + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + if getattr(self, '_Wz', None) is None: + self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z)**0.5)*self.mesh.unitCellGradz + return self._Wz + + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx,) + if self.mesh.dim > 1: + wlist += (self.Wy,) + if self.mesh.dim > 2: + wlist += (self.Wz,) + self._Wsmooth = sp.vstack(wlist) + return self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W + + @Utils.timeIt + def eval(self, m): + if self.smoothModel == True: + r1 = self.Wsmooth * ( self.mapping * (m) ) + r2 = self.Ws * ( self.mapping * (m - self.mref) ) + return 0.5*(r1.dot(r1)+r2.dot(r2)) + elif self.smoothModel == False: + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) + + + @Utils.timeIt + def evalDeriv(self, m): + """ + + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} + + """ + if self.smoothModel == True: + mD1 = self.mapping.deriv(m) + mD2 = self.mapping.deriv(m - self.mref) + r1 = self.Wsmooth * ( self.mapping * (m)) + r2 = self.Ws * ( self.mapping * (m - self.mref) ) + out1 = mD1.T * ( self.Wsmooth.T * r1 ) + out2 = mD2.T * ( self.Ws.T * r2 ) + out = out1+out2 + elif self.smoothModel == False: + mD = self.mapping.deriv(m - self.mref) + r = self.W * ( self.mapping * (m - self.mref) ) + out = mD.T * ( self.W.T * r ) + return out + + +class SparseRegularization(Simple): + + eps = 1e-1 + m = None + gamma = 1. + p = 0. + qx = 2. + qy = 2. + qz = 2. + + def __init__(self, mesh, mapping=None, **kwargs): + Simple.__init__(self, mesh, mapping=mapping, **kwargs) + + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx, self.Wxx) + if self.mesh.dim > 1: + wlist += (self.Wy, self.Wyy) + if self.mesh.dim > 2: + wlist += (self.Wz, self.Wzz) + self._Wsmooth = sp.vstack(wlist) + return self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W + + @property + def Ws(self): + """Regularization matrix Ws""" + if getattr(self, 'm', None) is None: + self.Rs = Utils.speye(self.mesh.nC) + + else: + f_m = self.m + self.rs = self.R(f_m , self.p, self.eps) + #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) + self.Rs = Utils.sdiag( self.rs ) + + self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + + return self._Ws + + @property + def Wx(self): + """Regularization matrix Wx""" + + if getattr(self, 'm', None) is None: + self.Rx = Utils.speye(self.mesh.unitCellGradx.shape[0]) + + else: + f_m = self.mesh.unitCellGradx * self.m + self.rx = self.R( f_m , self.qx, self.eps) + self.Rx = Utils.sdiag( self.rx ) + + if getattr(self, '_Wx', None) is None: + self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x*self.gamma)**0.5)*self.Rx*self.mesh.unitCellGradx + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + + if getattr(self, 'm', None) is None: + self.Ry = Utils.speye(self.mesh.unitCellGrady.shape[0]) + + else: + f_m = self.mesh.unitCellGrady * self.m + self.ry = self.R( f_m , self.qy, self.eps) + self.Ry = Utils.sdiag( self.ry ) + + if getattr(self, '_Wy', None) is None: + self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y*self.gamma)**0.5)*self.Ry*self.mesh.unitCellGrady + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + + if getattr(self, 'm', None) is None: + self.Rz = Utils.speye(self.mesh.unitCellGradz.shape[0]) + + else: + f_m = self.mesh.unitCellGradz * self.m + self.rz = self.R( f_m , self.qz, self.eps) + self.Rz = Utils.sdiag( self.rz ) + + if getattr(self, '_Wz', None) is None: + self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z*self.gamma)**0.5)*self.Rz*self.mesh.unitCellGradz + return self._Wz + + + def R(self, f_m , p, dec): + + eta = (self.eps**(1-p/2.))**0.5 + r = eta / (f_m**2.+self.eps**2.)**((1-p/2.)/2.) + + return r From c10777a245510e95329dd020f6567ce26aa60f41 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 22:00:12 -0800 Subject: [PATCH 14/52] Addition of unitCellGrad. Possibly rename to cellGradStencil? --- SimPEG/Mesh/DiffOperators.py | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 00bf0259..22b87edd 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -565,6 +565,56 @@ class DiffOperators(object): return Pbc, Pin, Pout + def unitCellGradx(): + doc = """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGradx', None) is None: + + n = self.vnC + gx = ddx(n[0]-1) + gx_square = sp.vstack((gx,gx[-1,:]*-1), format="csr") + + self._unitCellGradx = kron3(speye(n[2]), speye(n[1]), gx_square) + + return self._unitCellGradx + return locals() + unitCellGradx = property(**unitCellGradx()) + + def unitCellGrady(): + doc = """Cell centered Gradient in they dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGrady', None) is None: + + n = self.vnC + gy = ddx(n[1]-1) + gy_square = sp.vstack((gy,gy[-1,:]*-1), format="csr") + + self._unitCellGrady = kron3(speye(n[2]), gy_square, speye(n[0])) + + return self._unitCellGrady + return locals() + unitCellGrady = property(**unitCellGrady()) + + def unitCellGradz(): + doc = """Cell centered Gradient in they dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGradz', None) is None: + + n = self.vnC + gz = ddx(n[2]-1) + gz_square = sp.vstack((gz,gz[-1,:]*-1), format="csr") + + self._unitCellGradz = kron3( gz_square , speye(n[1]), speye(n[0])) + + return self._unitCellGradz + return locals() + unitCellGradz = property(**unitCellGradz()) # --------------- Averaging --------------------- From 1c2fecf3a24e5a90918451fdd5a0ec3f013bff62 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 22:07:33 -0800 Subject: [PATCH 15/52] Add the IRLS Directive. --- SimPEG/Directives.py | 50 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 2ed27c20..476c5916 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -271,7 +271,6 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - # class UpdateReferenceModel(Parameter): # mref0 = None @@ -283,3 +282,52 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # mref = self.mref0 # self.m_prev = self.invProb.m_current # return mref + +class update_IRLS(InversionDirective): + + m = None + eps_min = None + factor = None + gamma = None + phi_m_last = None + + def initialize(self): + + # Scale the regularization for changes in norm + if getattr(self, 'phi_m_last', None) is not None: + self.reg.gamma = 1. + phim_new = self.reg.eval(self.invProb.curModel) + self.gamma = self.phi_m_last / phim_new + + self.reg.gamma = self.gamma + + def endIter(self): + # Cool the threshold parameter + if getattr(self, 'factor', None) is not None: + eps = self.reg.eps / self.factor + + if getattr(self, 'eps_min', None) is not None: + self.reg.eps = np.max([self.eps_min,eps]) + else: + self.reg.eps = eps + + + # Update the model used for the IRLS weights + if getattr(self, 'm', None) is None: + self.reg.m = self.invProb.curModel + + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.prob.mesh.nC))**2. + PC = Utils.sdiag(diagA**-1.) + + self.opt.approxHinv = PC + + phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + +#============================================================================== +# import pylab as plt +# plt.figure() +# ax = plt.subplot(221) +# self.prob.mesh.plotSlice(self.invProb.curModel, ax = ax, normal = 'Z', ind=-5, clim = (0, 0.005)) +#============================================================================== From e4a3e0a16d3e07b9a2217fd30f0fc5274a8d9d8a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 19 Feb 2016 16:23:26 -0800 Subject: [PATCH 16/52] break out the Pac, Pafx, ... and make part of base regularization --- SimPEG/Regularization.py | 121 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6a65860d..0a6f2622 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -55,8 +55,47 @@ class BaseRegularization(object): @property def W(self): """Full regularization weighting matrix W.""" - return sp.identity(self.mapping.nP) + return self._Pac.T * sp.identity(self.mesh.nC) * self. # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + @property + def _Pac(self): + if getattr(self, '__Pac', None) is None: + if self.indActive is None: + self.__Pac = Utils.speye(self.mesh.nC) + else: + self.__Pac = Utils.speye(self.mesh.nC)[:,self.indActive] + return self.__Pac + + @property + def _Pafx(self): + if getattr(self, '__Pafx', None) is None: + if self.indActive is None: + self.__Pafx = Utils.speye(self.mesh.nFx) + else: + indActive_Fx = (self.mesh.aveFx2CC.T * self.indActive) == 1 + self.__Pafx = Utils.speye(self.mesh.nFx)[:,indActive_Fx] + return self.__Pafx + + @property + def _Pafy(self): + if getattr(self, '__Pafy', None) is None: + if self.indActive is None: + self.__Pafy = Utils.speye(self.mesh.nFy) + else: + indActive_Fy = (self.mesh.aveFy2CC.T * self.indActive) == 1 + self.__Pafy = Utils.speye(self.mesh.nFy)[:,indActive_Fy] + return self.__Pafy + + @property + def _Pafz(self): + if getattr(self, '__Pafz', None) is None: + if self.indActive is None: + self.__Pafz = Utils.speye(self.mesh.nFz) + else: + indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 + self.__Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] + return self.__Pafz + @Utils.timeIt def eval(self, m): @@ -133,10 +172,8 @@ class Tikhonov(BaseRegularization): def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Ws = Pac.T * self._Ws * Pac + Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + self._Ws = self._Pac.T * Ws * self._Pac return self._Ws @property @@ -144,14 +181,8 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.mesh.aveF2CC[:,:self.mesh.nFx].T*self.mesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx - - if self.indActive is not None: - indActive_Fx = (self.mesh.aveFx2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafx = Utils.speye(self.mesh.nFx)[:,indActive_Fx] - self._Wx = Pafx.T*self._Wx*Pac - + Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx + self._Wx = self._Pafx.T*Wx*self.self._Pac return self._Wx @property @@ -159,14 +190,8 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: Ave_y_vol = self.mesh.aveF2CC[:,self.mesh.nFx:np.sum(self.mesh.vnF[:2])].T*self.mesh.vol - self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady - - if self.indActive is not None: - indActive_Fy = (self.mesh.aveFy2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafy = Utils.speye(self.mesh.nFy)[:,indActive_Fy] - self._Wy = Pafy.T*self._Wy*Pac - + Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady + self._Wy = self._Pafy.T*Wy*self._Pac return self._Wy @property @@ -174,50 +199,32 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: Ave_z_vol = self.mesh.aveF2CC[:,np.sum(self.mesh.vnF[:2]):].T*self.mesh.vol - self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz - - if self.indActive is not None: - indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] - self._Wz = Pafz.T*self._Wz*Pac - + Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz + self._Wz = self._Pafz.T*Wz*self._Pac return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - self._Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wxx = Pac.T*self._Wxx*Pac - + Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx + self._Wxx = self._Pac.T*Wxx*self._Pac return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - self._Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wyy = Pac.T*self._Wyy*Pac - + Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady + self._Wyy = self._Pac.T*self._Wyy*self._Pac return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - self._Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wzz = Pac.T*self._Wzz*Pac - + Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz + self._Wzz = self._Pac.T*Wzz*self._Pac return self._Wzz @property @@ -346,14 +353,26 @@ class Simple(BaseRegularization): return self._W @Utils.timeIt - def eval(self, m): + def _evalSmall(self, m): + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) + + @Utils.timeIt + def _evalSmooth(self, m): if self.smoothModel == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) + else: + return None + + @Utils.timeIt + def eval(self, m): + phim = self._evalSmall(m) + if self.smoothModel is True: + phim += self._evalSmooth(m) + return phim + @Utils.timeIt From b5f4d8e9997456b4bb6ef2ce84274d59bb8f49a6 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 19 Feb 2016 17:43:50 -0800 Subject: [PATCH 17/52] typo in Regularization.py --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 0a6f2622..d6780c45 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -55,7 +55,7 @@ class BaseRegularization(object): @property def W(self): """Full regularization weighting matrix W.""" - return self._Pac.T * sp.identity(self.mesh.nC) * self. # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + return self._Pac.T * sp.identity(self.mesh.nC) * self._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @property def _Pac(self): From 4e871a43a9f7e756e47ca4e7ba5e6d9b558aea01 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 24 Feb 2016 18:03:42 -0800 Subject: [PATCH 18/52] prototype of defining regularization mesh within Regularization.py for constructing operators for regularization that are not true differential operators --- SimPEG/Mesh/DiffOperators.py | 129 +++++------ SimPEG/Regularization.py | 344 +++++++++++++++++++----------- tests/base/test_regularization.py | 121 ++++++----- 3 files changed, 344 insertions(+), 250 deletions(-) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 22b87edd..10ed2268 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -307,24 +307,28 @@ class DiffOperators(object): return BC _cellGradBC_list = 'neumann' + def _cellGradStencil(self): + BC = self.setCellGradBC(self._cellGradBC_list) + n = self.vnC + if(self.dim == 1): + G = ddxCellGrad(n[0], BC[0]) + elif(self.dim == 2): + G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0])) + G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0])) + G = sp.vstack((G1, G2), format="csr") + elif(self.dim == 3): + G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0])) + G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0])) + G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0])) + G = sp.vstack((G1, G2, G3), format="csr") + return G + def cellGrad(): doc = "The cell centered Gradient, takes you to cell faces." def fget(self): if(self._cellGrad is None): - BC = self.setCellGradBC(self._cellGradBC_list) - n = self.vnC - if(self.dim == 1): - G = ddxCellGrad(n[0], BC[0]) - elif(self.dim == 2): - G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0])) - G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0])) - G = sp.vstack((G1, G2), format="csr") - elif(self.dim == 3): - G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0])) - G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0])) - G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0])) - G = sp.vstack((G1, G2, G3), format="csr") + G = self._cellGradStencil() # Compute areas of cell faces & volumes S = self.area V = self.aveCC2F*self.vol # Average volume between adjacent cells @@ -361,19 +365,24 @@ class DiffOperators(object): _cellGradBC = None cellGradBC = property(**cellGradBC()) + def _cellGradxStencil(self): + BC = ['neumann', 'neumann'] + n = self.vnC + if(self.dim == 1): + G1 = ddxCellGrad(n[0], BC) + elif(self.dim == 2): + G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC)) + elif(self.dim == 3): + G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC)) + return G1 + + def cellGradx(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if getattr(self, '_cellGradx', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - if(self.dim == 1): - G1 = ddxCellGrad(n[0], BC) - elif(self.dim == 2): - G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC)) - elif(self.dim == 3): - G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC)) + G1 = self._cellGradxStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fx', 'V') @@ -382,17 +391,22 @@ class DiffOperators(object): return locals() cellGradx = property(**cellGradx()) + def _cellGradyStencil(self): + if self.dim < 2: return None + BC = ['neumann', 'neumann'] + n = self.vnC + if(self.dim == 2): + G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0])) + elif(self.dim == 3): + G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0])) + return G2 + def cellGrady(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if self.dim < 2: return None if getattr(self, '_cellGrady', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - if(self.dim == 2): - G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0])) - elif(self.dim == 3): - G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0])) + G2 = self._cellGradyStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fy', 'V') @@ -401,14 +415,19 @@ class DiffOperators(object): return locals() cellGrady = property(**cellGrady()) + def _cellGradzStencil(self): + if self.dim < 3: return None + BC = ['neumann', 'neumann'] + n = self.vnC + G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0])) + return G3 + def cellGradz(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if self.dim < 3: return None if getattr(self, '_cellGradz', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0])) + G3 = self._cellGradzStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fz', 'V') @@ -565,56 +584,6 @@ class DiffOperators(object): return Pbc, Pin, Pout - def unitCellGradx(): - doc = """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGradx', None) is None: - - n = self.vnC - gx = ddx(n[0]-1) - gx_square = sp.vstack((gx,gx[-1,:]*-1), format="csr") - - self._unitCellGradx = kron3(speye(n[2]), speye(n[1]), gx_square) - - return self._unitCellGradx - return locals() - unitCellGradx = property(**unitCellGradx()) - - def unitCellGrady(): - doc = """Cell centered Gradient in they dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGrady', None) is None: - - n = self.vnC - gy = ddx(n[1]-1) - gy_square = sp.vstack((gy,gy[-1,:]*-1), format="csr") - - self._unitCellGrady = kron3(speye(n[2]), gy_square, speye(n[0])) - - return self._unitCellGrady - return locals() - unitCellGrady = property(**unitCellGrady()) - - def unitCellGradz(): - doc = """Cell centered Gradient in they dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGradz', None) is None: - - n = self.vnC - gz = ddx(n[2]-1) - gz_square = sp.vstack((gz,gz[-1,:]*-1), format="csr") - - self._unitCellGradz = kron3( gz_square , speye(n[1]), speye(n[0])) - - return self._unitCellGradz - return locals() - unitCellGradz = property(**unitCellGradz()) # --------------- Averaging --------------------- diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index d6780c45..31013dc5 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,61 +1,35 @@ import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp -class BaseRegularization(object): - """ - **Base Regularization Class** +class RegularizationMesh(object): - This is used to regularize the model space:: - - reg = Regularization(mesh) - - """ - - __metaclass__ = Utils.SimPEGMetaClass - - counter = None - - mapPair = Maps.IdentityMap #: A SimPEG.Map Class - - mapping = None #: A SimPEG.Map instance. - mesh = None #: A SimPEG.Mesh instance. - mref = None #: Reference model. - - def __init__(self, mesh, mapping=None, indActive=None, **kwargs): - Utils.setKwargs(self, **kwargs) + def __init__(self, mesh, indActive=None): self.mesh = mesh - assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." - self.mapping = mapping or self.mapPair(mesh) - self.mapping._assertMatchesPair(self.mapPair) self.indActive = indActive @property - def parent(self): - """This is the parent of the regularization.""" - return getattr(self,'_parent',None) - @parent.setter - def parent(self, p): - if getattr(self,'_parent',None) is not None: - print 'Regularization has switched to a new parent!' - self._parent = p + def vol(self): + if getattr(self, '_vol', None) is None: + self._vol = self._Pac.T * self.mesh.vol + return self._vol @property - def inv(self): return self.parent.inv - @property - def invProb(self): return self.parent - @property - def reg(self): return self - @property - def opt(self): return self.parent.opt - @property - def prob(self): return self.parent.prob - @property - def survey(self): return self.parent.survey - + def nC(self): + if getattr(self, '_nC', None) is None: + if self.indActive is None: + self._nC = self.mesh.nC + else: + if self.indActive.dtype == 'bool': + self._nC = sum(self.indActive) + else: + self._nC = len(self.indActive) # you shouldn't pass a vector of int 0, 1 's + return self._nC @property - def W(self): - """Full regularization weighting matrix W.""" - return self._Pac.T * sp.identity(self.mesh.nC) * self._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + def dim(self): + if getattr(self, '_dim', None) is None: + self._dim = self.mesh.dim + return self._dim + @property def _Pac(self): @@ -95,7 +69,170 @@ class BaseRegularization(object): indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 self.__Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] return self.__Pafz + + @property + def aveFx2CC(self): + if getattr(self, '_aveFx2CC', None) is None: + self._aveFx2CC = self._Pac.T * self.mesh.aveFx2CC * self._Pafx + return self._aveFx2CC + + @property + def aveCC2Fx(self): + if getattr(self, '_aveCC2Fx', None) is None: + self._aveCC2Fx = Utils.sdiag(1./(self.aveFx2CC.T).sum(1)) * self.aveFx2CC.T + return self._aveCC2Fx + + @property + def aveFy2CC(self): + if getattr(self, '_aveFy2CC', None) is None: + self._aveFy2CC = self._Pac.T * self.mesh.aveFy2CC * self._Pafy + return self._aveFy2CC + + @property + def aveCC2Fy(self): + if getattr(self, '_aveCC2Fy', None) is None: + self._aveCC2Fy = Utils.sdiag(1./(self.aveFy2CC.T).sum(1)) * self.aveFy2CC.T + return self._aveCC2Fy + + @property + def aveFz2CC(self): + if getattr(self, '_aveFz2CC', None) is None: + self._aveFz2CC = self._Pac.T * self.mesh.aveFz2CC * self._Pafz + return self._aveFz2CC + + @property + def aveCC2Fz(self): + if getattr(self, '_aveCC2Fz', None) is None: + self._aveCC2Fz = Utils.sdiag(1./(self.aveFz2CC.T).sum(1)) * self.aveFz2CC.T + return self._aveCC2Fz + + @property + def cellGradx(self): + if getattr(self, '_cellGradx', None) is None: + self._cellGradx = self._Pafx.T * self.mesh.cellGradx * self._Pac + return self._cellGradx + + @property + def cellGrady(self): + if getattr(self, '_cellGrady', None) is None: + self._cellGrady = self._Pafy.T * self.mesh.cellGrady * self._Pac + return self._cellGrady + + @property + def cellGradz(self): + if getattr(self, '_cellGradz', None) is None: + self._cellGradz = self._Pafz.T * self.mesh.cellGradz * self._Pac + return self._cellGradz + @property + def faceDivx(self): + if getattr(self, '_faceDivx', None) is None: + self._faceDivx = self._Pac.T * self.mesh.faceDivx * self._Pafx + return self._faceDivx + + @property + def faceDivy(self): + if getattr(self, '_faceDivy', None) is None: + self._faceDivy = self._Pac.T * self.mesh.faceDivy * self._Pafy + return self._faceDivy + + @property + def faceDivz(self): + if getattr(self, '_faceDivz', None) is None: + self._faceDivz = self._Pac.T * self.mesh.faceDivz * self._Pafz + return self._faceDivz + + @property + def cellGradxStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + # if self.dim < 3: return None + if getattr(self, '_cellGradxStencil', None) is None: + + self._cellGradxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac + return self._cellGradxStencil + + @property + def cellGradyStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + if self.dim < 2: return None + if getattr(self, '_cellGradyStencil', None) is None: + + self._cellGradyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac + return self._cellGradyStencil + + @property + def cellGradzStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + if self.dim < 3: return None + if getattr(self, '_cellGradzStencil', None) is None: + + self._cellGradzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac + return self._cellGradzStencil + + +class BaseRegularization(object): + """ + **Base Regularization Class** + + This is used to regularize the model space:: + + reg = Regularization(mesh) + + """ + + __metaclass__ = Utils.SimPEGMetaClass + + counter = None + + mapPair = Maps.IdentityMap #: A SimPEG.Map Class + + mapping = None #: A SimPEG.Map instance. + mesh = None #: A SimPEG.Mesh instance. + mref = None #: Reference model. + + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + Utils.setKwargs(self, **kwargs) + assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." + self.regmesh = RegularizationMesh(mesh,indActive) + self.mapping = mapping or self.mapPair(mesh) + self.mapping._assertMatchesPair(self.mapPair) + self.indActive = indActive + + @property + def parent(self): + """This is the parent of the regularization.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + if getattr(self,'_parent',None) is not None: + print 'Regularization has switched to a new parent!' + self._parent = p + + @property + def inv(self): return self.parent.inv + @property + def invProb(self): return self.parent + @property + def reg(self): return self + @property + def opt(self): return self.parent.opt + @property + def prob(self): return self.parent.prob + @property + def survey(self): return self.parent.survey + + + @property + def W(self): + """Full regularization weighting matrix W.""" + return sp.identity(self.regmesh.nC) + # self.regmesh._Pac.T * sp.identity(self.regmesh.nC) * self.regmesh._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @Utils.timeIt def eval(self, m): @@ -151,7 +288,6 @@ class BaseRegularization(object): return mD.T * ( self.W.T * ( self.W * ( mD * v) ) ) - class Tikhonov(BaseRegularization): """ """ @@ -165,66 +301,58 @@ class Tikhonov(BaseRegularization): alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") def __init__(self, mesh, mapping=None, indActive = None, **kwargs): - BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) - self.indActive = indActive + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) - self._Ws = self._Pac.T * Ws * self._Pac + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - Ave_x_vol = self.mesh.aveF2CC[:,:self.mesh.nFx].T*self.mesh.vol - Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx - self._Wx = self._Pafx.T*Wx*self.self._Pac + Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellGradx return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - Ave_y_vol = self.mesh.aveF2CC[:,self.mesh.nFx:np.sum(self.mesh.vnF[:2])].T*self.mesh.vol - Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady - self._Wy = self._Pafy.T*Wy*self._Pac + Ave_y_vol = self.regmesh.aveCC2Fy * self.regmesh.vol + self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellGrady return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - Ave_z_vol = self.mesh.aveF2CC[:,np.sum(self.mesh.vnF[:2]):].T*self.mesh.vol - Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz - self._Wz = self._Pafz.T*Wz*self._Pac + Ave_z_vol = self.regmesh.aveCC2Fz * self.regmesh.vol + self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellGradz return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx - self._Wxx = self._Pac.T*Wxx*self._Pac + self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDivx*self.regmesh.cellGradx return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady - self._Wyy = self._Pac.T*self._Wyy*self._Pac + self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDivy*self.regmesh.cellGrady return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz - self._Wzz = self._Pac.T*Wzz*self._Pac + self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDivz*self.regmesh.cellGradz return self._Wzz @property @@ -232,9 +360,9 @@ class Tikhonov(BaseRegularization): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: wlist = (self.Wx, self.Wxx) - if self.mesh.dim > 1: + if self.regmesh.dim > 1: wlist += (self.Wy, self.Wyy) - if self.mesh.dim > 2: + if self.regmesh.dim > 2: wlist += (self.Wz, self.Wzz) self._Wsmooth = sp.vstack(wlist) return self._Wsmooth @@ -301,35 +429,35 @@ class Simple(BaseRegularization): alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - def __init__(self, mesh, mapping=None, **kwargs): - BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x)**0.5)*self.mesh.unitCellGradx + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellGradxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y)**0.5)*self.mesh.unitCellGrady + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellGradyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z)**0.5)*self.mesh.unitCellGradz + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellGradzStencil return self._Wz @property @@ -337,9 +465,9 @@ class Simple(BaseRegularization): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: wlist = (self.Wx,) - if self.mesh.dim > 1: + if self.regmesh.dim > 1: wlist += (self.Wy,) - if self.mesh.dim > 2: + if self.regmesh.dim > 2: wlist += (self.Wz,) self._Wsmooth = sp.vstack(wlist) return self._Wsmooth @@ -352,25 +480,16 @@ class Simple(BaseRegularization): self._W = sp.vstack(wlist) return self._W - @Utils.timeIt - def _evalSmall(self, m): - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) @Utils.timeIt - def _evalSmooth(self, m): + def eval(self, m): if self.smoothModel == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - else: - return None - - @Utils.timeIt - def eval(self, m): - phim = self._evalSmall(m) - if self.smoothModel is True: - phim += self._evalSmooth(m) + elif self.smoothModel == False: + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) return phim @@ -417,34 +536,15 @@ class SparseRegularization(Simple): qy = 2. qz = 2. - def __init__(self, mesh, mapping=None, **kwargs): - Simple.__init__(self, mesh, mapping=mapping, **kwargs) + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - @property - def Wsmooth(self): - """Full smoothness regularization matrix W""" - if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx, self.Wxx) - if self.mesh.dim > 1: - wlist += (self.Wy, self.Wyy) - if self.mesh.dim > 2: - wlist += (self.Wz, self.Wzz) - self._Wsmooth = sp.vstack(wlist) - return self._Wsmooth - - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W @property def Ws(self): """Regularization matrix Ws""" if getattr(self, 'm', None) is None: - self.Rs = Utils.speye(self.mesh.nC) + self.Rs = Utils.speye(self.regmesh.nC) else: f_m = self.m @@ -452,7 +552,7 @@ class SparseRegularization(Simple): #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs return self._Ws @@ -461,15 +561,15 @@ class SparseRegularization(Simple): """Regularization matrix Wx""" if getattr(self, 'm', None) is None: - self.Rx = Utils.speye(self.mesh.unitCellGradx.shape[0]) + self.Rx = Utils.speye(self.regmesh.cellGradxStencil.shape[0]) else: - f_m = self.mesh.unitCellGradx * self.m + f_m = self.regmesh.cellGradxStencil * self.m self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x*self.gamma)**0.5)*self.Rx*self.mesh.unitCellGradx + self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellGradxStencil return self._Wx @property @@ -477,15 +577,15 @@ class SparseRegularization(Simple): """Regularization matrix Wy""" if getattr(self, 'm', None) is None: - self.Ry = Utils.speye(self.mesh.unitCellGrady.shape[0]) + self.Ry = Utils.speye(self.regmesh.cellGradyStencil.shape[0]) else: - f_m = self.mesh.unitCellGrady * self.m + f_m = self.regmesh.cellGradyStencil * self.m self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y*self.gamma)**0.5)*self.Ry*self.mesh.unitCellGrady + self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellGradyStencil return self._Wy @property @@ -493,15 +593,15 @@ class SparseRegularization(Simple): """Regularization matrix Wz""" if getattr(self, 'm', None) is None: - self.Rz = Utils.speye(self.mesh.unitCellGradz.shape[0]) + self.Rz = Utils.speye(self.regmesh.cellGradzStencil.shape[0]) else: - f_m = self.mesh.unitCellGradz * self.m + f_m = self.regmesh.cellGradzStencil * self.m self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z*self.gamma)**0.5)*self.Rz*self.mesh.unitCellGradz + self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellGradzStencil return self._Wz diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 050c46ac..614d3158 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -5,6 +5,8 @@ from scipy.sparse.linalg import dsolve import inspect TOL = 1e-20 +testReg = True +testRegMesh = True class RegularizationTests(unittest.TestCase): @@ -16,69 +18,92 @@ class RegularizationTests(unittest.TestCase): mesh3 = Mesh.TensorMesh([hx, hy, hz]) self.meshlist = [mesh1,mesh2, mesh3] - def test_regularization(self): - for R in dir(Regularization): - r = getattr(Regularization, R) - if not inspect.isclass(r): continue - if not issubclass(r, Regularization.BaseRegularization): - continue + if testReg: + def test_regularization(self): + for R in dir(Regularization): + r = getattr(Regularization, R) + if not inspect.isclass(r): continue + if not issubclass(r, Regularization.BaseRegularization): + continue - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing %iD'%mesh.dim + print 'Testing %iD'%mesh.dim - mapping = r.mapPair(mesh) - reg = r(mesh, mapping=mapping) - m = np.random.rand(mapping.nP) - reg.mref = np.ones_like(m)*np.mean(m) + mapping = r.mapPair(mesh) + reg = r(mesh, mapping=mapping) + m = np.random.rand(mapping.nP) + reg.mref = np.ones_like(m)*np.mean(m) - print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) - passed = reg.eval(reg.mref) < TOL - self.assertTrue(passed) + print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) + passed = reg.eval(reg.mref) < TOL + self.assertTrue(passed) - print 'Check:', R - passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check:', R + passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) + self.assertTrue(passed) - print 'Check 2 Deriv:', R - passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check 2 Deriv:', R + passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) + self.assertTrue(passed) - def test_regularization_ActiveCells(self): - for R in dir(Regularization): - r = getattr(Regularization, R) - if not inspect.isclass(r): continue - if not issubclass(r, Regularization.BaseRegularization): - continue + def test_regularization_ActiveCells(self): + for R in dir(Regularization): + r = getattr(Regularization, R) + if not inspect.isclass(r): continue + if not issubclass(r, Regularization.BaseRegularization): + continue - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing Active Cells %iD'%(mesh.dim) + print 'Testing Active Cells %iD'%(mesh.dim) - if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) - elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) - elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) + mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) - reg = r(mesh, mapping=mapping, indActive=indAct) - m = np.random.rand(mesh.nC)[indAct] - reg.mref = np.ones_like(m)*np.mean(m) + reg = r(mesh, mapping=mapping, indActive=indAct) + m = np.random.rand(mesh.nC)[indAct] + reg.mref = np.ones_like(m)*np.mean(m) - print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) - passed = reg.eval(reg.mref) < TOL - self.assertTrue(passed) + print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) + passed = reg.eval(reg.mref) < TOL + self.assertTrue(passed) - print 'Check:', R - passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check:', R + passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) + self.assertTrue(passed) - print 'Check 2 Deriv:', R - passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check 2 Deriv:', R + passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) + self.assertTrue(passed) + + if testRegMesh: + def test_regularizationMesh(self): + + for i, mesh in enumerate(self.meshlist): + + print 'Testing %iD'%mesh.dim + + # mapping = r.mapPair(mesh) + # reg = r(mesh, mapping=mapping) + # m = np.random.rand(mapping.nP) + + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + + regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) + + assert (regmesh.vol == mesh.vol[indAct]).all() if __name__ == '__main__': From e3af1fd94e9828caa57a931074fa01a91a3ebf1b Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 24 Feb 2016 20:28:09 -0800 Subject: [PATCH 19/52] convert indActive to a bool if an integer list is provided --- SimPEG/Regularization.py | 10 ++++++---- tests/base/test_regularization.py | 15 ++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 31013dc5..d0fc21b1 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -4,6 +4,7 @@ class RegularizationMesh(object): def __init__(self, mesh, indActive=None): self.mesh = mesh + assert indActive is None or indActive.dtype == 'bool', 'indActive needs to be None or a bool' self.indActive = indActive @property @@ -18,10 +19,7 @@ class RegularizationMesh(object): if self.indActive is None: self._nC = self.mesh.nC else: - if self.indActive.dtype == 'bool': - self._nC = sum(self.indActive) - else: - self._nC = len(self.indActive) # you shouldn't pass a vector of int 0, 1 's + self._nC = sum(self.indActive) return self._nC @property @@ -199,6 +197,10 @@ class BaseRegularization(object): def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Utils.setKwargs(self, **kwargs) assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." + if indActive is not None and indActive.dtype != 'bool': + tmp = indActive + indActive = np.zeros(mesh.nC, dtype=bool) + indActive[tmp] = True self.regmesh = RegularizationMesh(mesh,indActive) self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 614d3158..52cef349 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -59,17 +59,18 @@ class RegularizationTests(unittest.TestCase): print 'Testing Active Cells %iD'%(mesh.dim) if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) + indActive = Utils.mkvc(mesh.gridCC <= 0.8) elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) + mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size) - reg = r(mesh, mapping=mapping, indActive=indAct) - m = np.random.rand(mesh.nC)[indAct] - reg.mref = np.ones_like(m)*np.mean(m) + for indAct in [indActive, indActive.nonzero()[0]]: # test both bool and integers + reg = r(mesh, mapping=mapping, indActive=indAct) + m = np.random.rand(mesh.nC)[indAct] + reg.mref = np.ones_like(m)*np.mean(m) print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) passed = reg.eval(reg.mref) < TOL From 63bf8b9e4d6d16b7d3f3d9271246f86b337df626 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 24 Feb 2016 20:59:51 -0800 Subject: [PATCH 20/52] Add linear survey --- SimPEG/Survey.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index 47a88ae2..cc877c69 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -375,3 +375,11 @@ class BaseSurvey(object): self.dobs = self.dtrue+noise self.std = self.dobs*0 + std return self.dobs + +class LinearSurvey(BaseSurvey): + def projectFields(self, u): + return u + + @property + def nD(self): + return self.prob.G.shape[0] \ No newline at end of file From 6c33455d15ee6d937029ecb7b7ccc3306f09b0c4 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 25 Feb 2016 08:56:18 -0800 Subject: [PATCH 21/52] update Directive for sparse norm --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 476c5916..9ba38e4e 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -317,7 +317,7 @@ class update_IRLS(InversionDirective): self.reg.m = self.invProb.curModel # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.prob.mesh.nC))**2. + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC From 5e5c7ba0fb408645eb5c2fa85340b3af75f01098 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 1 Mar 2016 17:31:37 -0800 Subject: [PATCH 22/52] docs for regmesh, cellGrad--> cellDiff, faceDiv--> faceDiff for regmesh --- SimPEG/Regularization.py | 238 ++++++++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 64 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index d0fc21b1..acd6c68d 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,6 +1,16 @@ import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp class RegularizationMesh(object): + """ + **Regularization Mesh** + + This contains the operators used in the regularization. Note that these + are not necessarily true differential operators, but are constructed from + a SimPEG Mesh. + + :param Mesh mesh: problem mesh + :param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells + """ def __init__(self, mesh, indActive=None): self.mesh = mesh @@ -9,12 +19,22 @@ class RegularizationMesh(object): @property def vol(self): + """ + reduced volume vector + :rtype: numpy.array + :return: reduced cell volume + """ if getattr(self, '_vol', None) is None: self._vol = self._Pac.T * self.mesh.vol return self._vol @property def nC(self): + """ + reduced number of cells + :rtype: int + :return: number of cells being regularized + """ if getattr(self, '_nC', None) is None: if self.indActive is None: self._nC = self.mesh.nC @@ -24,6 +44,11 @@ class RegularizationMesh(object): @property def dim(self): + """ + dimension of regularization mesh (1D, 2D, 3D) + :rtype: int + :return: dimension + """ if getattr(self, '_dim', None) is None: self._dim = self.mesh.dim return self._dim @@ -31,6 +56,11 @@ class RegularizationMesh(object): @property def _Pac(self): + """ + projection matrix that takes from the reduced space of active cells to full modelling space (ie. nC x nindActive) + :rtype: scipy.sparse.csr_matrix + :return: active cell projection matrix + """ if getattr(self, '__Pac', None) is None: if self.indActive is None: self.__Pac = Utils.speye(self.mesh.nC) @@ -40,6 +70,11 @@ class RegularizationMesh(object): @property def _Pafx(self): + """ + projection matrix that takes from the reduced space of active x-faces to full modelling space (ie. nFx x nindActive_Fx ) + :rtype: scipy.sparse.csr_matrix + :return: active face-x projection matrix + """ if getattr(self, '__Pafx', None) is None: if self.indActive is None: self.__Pafx = Utils.speye(self.mesh.nFx) @@ -50,6 +85,11 @@ class RegularizationMesh(object): @property def _Pafy(self): + """ + projection matrix that takes from the reduced space of active y-faces to full modelling space (ie. nFy x nindActive_Fy ) + :rtype: scipy.sparse.csr_matrix + :return: active face-y projection matrix + """ if getattr(self, '__Pafy', None) is None: if self.indActive is None: self.__Pafy = Utils.speye(self.mesh.nFy) @@ -60,6 +100,11 @@ class RegularizationMesh(object): @property def _Pafz(self): + """ + projection matrix that takes from the reduced space of active z-faces to full modelling space (ie. nFz x nindActive_Fz ) + :rtype: scipy.sparse.csr_matrix + :return: active face-z projection matrix + """ if getattr(self, '__Pafz', None) is None: if self.indActive is None: self.__Pafz = Utils.speye(self.mesh.nFz) @@ -70,108 +115,173 @@ class RegularizationMesh(object): @property def aveFx2CC(self): + """ + averaging from active cell centers to active x-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active x-faces + """ if getattr(self, '_aveFx2CC', None) is None: self._aveFx2CC = self._Pac.T * self.mesh.aveFx2CC * self._Pafx return self._aveFx2CC @property def aveCC2Fx(self): + """ + averaging from active x-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active x-faces to active cell centers + """ if getattr(self, '_aveCC2Fx', None) is None: self._aveCC2Fx = Utils.sdiag(1./(self.aveFx2CC.T).sum(1)) * self.aveFx2CC.T return self._aveCC2Fx @property def aveFy2CC(self): + """ + averaging from active cell centers to active y-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active y-faces + """ if getattr(self, '_aveFy2CC', None) is None: self._aveFy2CC = self._Pac.T * self.mesh.aveFy2CC * self._Pafy return self._aveFy2CC @property def aveCC2Fy(self): + """ + averaging from active y-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active y-faces to active cell centers + """ if getattr(self, '_aveCC2Fy', None) is None: self._aveCC2Fy = Utils.sdiag(1./(self.aveFy2CC.T).sum(1)) * self.aveFy2CC.T return self._aveCC2Fy @property def aveFz2CC(self): + """ + averaging from active cell centers to active z-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active z-faces + """ if getattr(self, '_aveFz2CC', None) is None: self._aveFz2CC = self._Pac.T * self.mesh.aveFz2CC * self._Pafz return self._aveFz2CC @property def aveCC2Fz(self): + """ + averaging from active z-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active z-faces to active cell centers + """ if getattr(self, '_aveCC2Fz', None) is None: self._aveCC2Fz = Utils.sdiag(1./(self.aveFz2CC.T).sum(1)) * self.aveFz2CC.T return self._aveCC2Fz @property - def cellGradx(self): - if getattr(self, '_cellGradx', None) is None: - self._cellGradx = self._Pafx.T * self.mesh.cellGradx * self._Pac - return self._cellGradx + def cellDiffx(self): + """ + cell centered difference in the x-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the x-direction + """ + if getattr(self, '_cellDiffx', None) is None: + self._cellDiffx = self._Pafx.T * self.mesh.cellGradx * self._Pac + return self._cellDiffx @property - def cellGrady(self): - if getattr(self, '_cellGrady', None) is None: - self._cellGrady = self._Pafy.T * self.mesh.cellGrady * self._Pac - return self._cellGrady + def cellDiffy(self): + """ + cell centered difference in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ + if getattr(self, '_cellDiffy', None) is None: + self._cellDiffy = self._Pafy.T * self.mesh.cellGrady * self._Pac + return self._cellDiffy @property - def cellGradz(self): - if getattr(self, '_cellGradz', None) is None: - self._cellGradz = self._Pafz.T * self.mesh.cellGradz * self._Pac - return self._cellGradz + def cellDiffz(self): + """ + cell centered difference in the z-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the z-direction + """ + if getattr(self, '_cellDiffz', None) is None: + self._cellDiffz = self._Pafz.T * self.mesh.cellGradz * self._Pac + return self._cellDiffz @property - def faceDivx(self): - if getattr(self, '_faceDivx', None) is None: - self._faceDivx = self._Pac.T * self.mesh.faceDivx * self._Pafx - return self._faceDivx + def faceDiffx(self): + """ + x-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the x-direction + """ + if getattr(self, '_faceDiffx', None) is None: + self._faceDiffx = self._Pac.T * self.mesh.faceDivx * self._Pafx + return self._faceDiffx @property - def faceDivy(self): - if getattr(self, '_faceDivy', None) is None: - self._faceDivy = self._Pac.T * self.mesh.faceDivy * self._Pafy - return self._faceDivy + def faceDiffy(self): + """ + y-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the y-direction + """ + if getattr(self, '_faceDiffy', None) is None: + self._faceDiffy = self._Pac.T * self.mesh.faceDivy * self._Pafy + return self._faceDiffy @property - def faceDivz(self): - if getattr(self, '_faceDivz', None) is None: - self._faceDivz = self._Pac.T * self.mesh.faceDivz * self._Pafz - return self._faceDivz + def faceDiffz(self): + """ + z-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the z-direction + """ + if getattr(self, '_faceDiffz', None) is None: + self._faceDiffz = self._Pac.T * self.mesh.faceDivz * self._Pafz + return self._faceDiffz @property - def cellGradxStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" + def cellDiffxStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the x-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the x-direction + """ + if getattr(self, '_cellDiffxStencil', None) is None: - # if self.dim < 3: return None - if getattr(self, '_cellGradxStencil', None) is None: - - self._cellGradxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac - return self._cellGradxStencil + self._cellDiffxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac + return self._cellDiffxStencil @property - def cellGradyStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - + def cellDiffyStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ if self.dim < 2: return None - if getattr(self, '_cellGradyStencil', None) is None: + if getattr(self, '_cellDiffyStencil', None) is None: - self._cellGradyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac - return self._cellGradyStencil + self._cellDiffyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac + return self._cellDiffyStencil @property - def cellGradzStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - + def cellDiffzStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ if self.dim < 3: return None - if getattr(self, '_cellGradzStencil', None) is None: + if getattr(self, '_cellDiffzStencil', None) is None: - self._cellGradzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac - return self._cellGradzStencil + self._cellDiffzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac + return self._cellDiffzStencil class BaseRegularization(object): @@ -317,7 +427,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellGradx + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx return self._Wx @property @@ -325,7 +435,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: Ave_y_vol = self.regmesh.aveCC2Fy * self.regmesh.vol - self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellGrady + self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellDiffy return self._Wy @property @@ -333,28 +443,28 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: Ave_z_vol = self.regmesh.aveCC2Fz * self.regmesh.vol - self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellGradz + self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellDiffz return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDivx*self.regmesh.cellGradx + self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDiffx*self.regmesh.cellDiffx return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDivy*self.regmesh.cellGrady + self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDiffy*self.regmesh.cellDiffy return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDivz*self.regmesh.cellGradz + self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz return self._Wzz @property @@ -445,21 +555,21 @@ class Simple(BaseRegularization): def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellGradxStencil + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellDiffxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellGradyStencil + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellDiffyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellGradzStencil + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellDiffzStencil return self._Wz @property @@ -563,15 +673,15 @@ class SparseRegularization(Simple): """Regularization matrix Wx""" if getattr(self, 'm', None) is None: - self.Rx = Utils.speye(self.regmesh.cellGradxStencil.shape[0]) + self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: - f_m = self.regmesh.cellGradxStencil * self.m + f_m = self.regmesh.cellDiffxStencil * self.m self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellGradxStencil + self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil return self._Wx @property @@ -579,15 +689,15 @@ class SparseRegularization(Simple): """Regularization matrix Wy""" if getattr(self, 'm', None) is None: - self.Ry = Utils.speye(self.regmesh.cellGradyStencil.shape[0]) + self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) else: - f_m = self.regmesh.cellGradyStencil * self.m + f_m = self.regmesh.cellDiffyStencil * self.m self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellGradyStencil + self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil return self._Wy @property @@ -595,15 +705,15 @@ class SparseRegularization(Simple): """Regularization matrix Wz""" if getattr(self, 'm', None) is None: - self.Rz = Utils.speye(self.regmesh.cellGradzStencil.shape[0]) + self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) else: - f_m = self.regmesh.cellGradzStencil * self.m + f_m = self.regmesh.cellDiffzStencil * self.m self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellGradzStencil + self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil return self._Wz From 2f8b8a36bf71e1ca2e501540b09ee539c4502e01 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 2 Mar 2016 09:46:50 -0800 Subject: [PATCH 23/52] smoothModel --> mrefInSmooth --- SimPEG/Directives.py | 4 ++-- SimPEG/Examples/MT_1D_ForwardAndInversion.py | 2 +- SimPEG/Regularization.py | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 9ba38e4e..0a98bc09 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -216,7 +216,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the data. ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) phi_ms = 0.5*ms.dot(ms) - if self.reg.smoothModel == True: + if self.reg.mrefInSmooth == True: mref = self.reg.mref else: mref = 0 @@ -249,7 +249,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the data. ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) phi_ms = 0.5*ms.dot(ms) - if self.reg.smoothModel == True: + if self.reg.mrefInSmooth == True: mref = self.reg.mref else: mref = 0 diff --git a/SimPEG/Examples/MT_1D_ForwardAndInversion.py b/SimPEG/Examples/MT_1D_ForwardAndInversion.py index cf17e77b..69cedd98 100644 --- a/SimPEG/Examples/MT_1D_ForwardAndInversion.py +++ b/SimPEG/Examples/MT_1D_ForwardAndInversion.py @@ -100,7 +100,7 @@ def run(plotIt=True): # Regularization - with a regularization mesh regMesh = simpeg.Mesh.TensorMesh([m1d.hx[problem.mapping.sigmaMap.maps[-1].indActive]],m1d.x0) reg = simpeg.Regularization.Tikhonov(regMesh) - reg.smoothModel = True + reg.mrefInSmooth = True reg.alpha_s = 1e-7 reg.alpha_x = 1. # Inversion problem diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index acd6c68d..990b79c3 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -403,7 +403,7 @@ class BaseRegularization(object): class Tikhonov(BaseRegularization): """ """ - smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") @@ -489,11 +489,11 @@ class Tikhonov(BaseRegularization): @Utils.timeIt def eval(self, m): - if self.smoothModel == True: + if self.mrefInSmooth == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: + elif self.mrefInSmooth == False: r = self.W * ( self.mapping * (m - self.mref) ) return 0.5*r.dot(r) @@ -515,7 +515,7 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.smoothModel == True: + if self.mrefInSmooth == True: mD1 = self.mapping.deriv(m) mD2 = self.mapping.deriv(m - self.mref) r1 = self.Wsmooth * ( self.mapping * (m)) @@ -523,7 +523,7 @@ class Tikhonov(BaseRegularization): out1 = mD1.T * ( self.Wsmooth.T * r1 ) out2 = mD2.T * ( self.Ws.T * r2 ) out = out1+out2 - elif self.smoothModel == False: + elif self.mrefInSmooth == False: mD = self.mapping.deriv(m - self.mref) r = self.W * ( self.mapping * (m - self.mref) ) out = mD.T * ( self.W.T * r ) @@ -535,7 +535,7 @@ class Simple(BaseRegularization): Only for tensor mesh """ - smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") @@ -595,11 +595,11 @@ class Simple(BaseRegularization): @Utils.timeIt def eval(self, m): - if self.smoothModel == True: + if self.mrefInSmooth == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: + elif self.mrefInSmooth == False: r = self.W * ( self.mapping * (m - self.mref) ) return 0.5*r.dot(r) return phim @@ -623,7 +623,7 @@ class Simple(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.smoothModel == True: + if self.mrefInSmooth == True: mD1 = self.mapping.deriv(m) mD2 = self.mapping.deriv(m - self.mref) r1 = self.Wsmooth * ( self.mapping * (m)) @@ -631,7 +631,7 @@ class Simple(BaseRegularization): out1 = mD1.T * ( self.Wsmooth.T * r1 ) out2 = mD2.T * ( self.Ws.T * r2 ) out = out1+out2 - elif self.smoothModel == False: + elif self.mrefInSmooth == False: mD = self.mapping.deriv(m - self.mref) r = self.W * ( self.mapping * (m - self.mref) ) out = mD.T * ( self.W.T * r ) From 33c9059e4e2b9fae8375923197d23d2dafaa62a7 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 8 Mar 2016 16:40:02 -0800 Subject: [PATCH 24/52] SparseRegularization --> Sparse --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 990b79c3..db1bc39b 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -638,7 +638,7 @@ class Simple(BaseRegularization): return out -class SparseRegularization(Simple): +class Sparse(Simple): eps = 1e-1 m = None From 1946e1f69e7ec756ab64c5bc75d2f43cc0c361d9 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 9 Mar 2016 15:49:08 -0800 Subject: [PATCH 25/52] minor change for plotting --- SimPEG/DCIP/DCIPUtils.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 90bbbca0..eb9d1c44 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype): +def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -230,10 +230,13 @@ def plot_pseudoSection(DCsurvey, axs, stype): elif stype == 'dpdp': leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) - midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) - rho = np.hstack([rho,leg]) + #TODO ... let stick to list then finally convert to array. + if dtype =="voltage": + rho = np.hstack([rho,leg]) + elif dtype =="appr": + rho = np.hstack([rho,data]) ax = axs @@ -242,8 +245,12 @@ def plot_pseudoSection(DCsurvey, axs, stype): grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)] grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear') + if clim == None: + vmin, vmax = rho.min(), rho.max() + else: + vmin, vmax = clim[0], clim[1] - plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin = np.min(rho), vmax = np.max(rho)) + plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal") cmin,cmax = cbar.get_clim() @@ -251,14 +258,14 @@ def plot_pseudoSection(DCsurvey, axs, stype): cbar.set_ticks(ticks) # Plot apparent resistivity - plt.scatter(midx,midz,s=50,c=rho.T) + plt.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) ax.set_xticklabels([]) ax.set_ylabel('Z') ax.yaxis.tick_right() ax.yaxis.set_label_position('right') - plt.gca().set_aspect('equal', adjustable='box') + # plt.gca().set_aspect('equal', adjustable='box') return ax From 4fefccc97dbd5249d68b7b490fb227d423d6c0ee Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 10 Mar 2016 14:25:27 -0800 Subject: [PATCH 26/52] Add readPUBC_DC2Dpre --- SimPEG/DCIP/DCIPUtils.py | 80 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 90bbbca0..996cf8ec 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -249,15 +249,17 @@ def plot_pseudoSection(DCsurvey, axs, stype): cmin,cmax = cbar.get_clim() ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) - + cbar.ax.tick_params(labelsize=10) + # Plot apparent resistivity plt.scatter(midx,midz,s=50,c=rho.T) ax.set_xticklabels([]) - - ax.set_ylabel('Z') - ax.yaxis.tick_right() - ax.yaxis.set_label_position('right') + ax.set_yticklabels([]) + + #ax.set_ylabel('Z') + #ax.yaxis.tick_right() + #ax.yaxis.set_label_position('right') plt.gca().set_aspect('equal', adjustable='box') @@ -735,6 +737,73 @@ def readUBC_DC2Dobs(fileName): return tx, rx, d, wd +def readUBC_DC2Dpre(fileName): + """ + Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + + Input: + :param fileName, path to the UBC GIF 3D obs file + + Output: + DCsurvey + :return + + Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >> + + @author: dominiquef + + """ + + # Load file + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') + + # Pre-allocate + srcLists = [] + Rx = [] + d = [] + zflag = True # Flag for z value provided + + for ii in range(obsfile.shape[0]): + + if not obsfile[ii]: + continue + + # First line is transmitter with number of receivers + + + temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T) + + + # Check if z value is provided, if False -> nan + if len(temp)==5: + tx = np.r_[temp[0],np.nan,np.nan,temp[1],np.nan,np.nan] + zflag = False + + else: + tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]] + + + if zflag: + rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]] + + + else: + rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan] + # Check if there is data with the location + + d.append(temp[-1]) + + + Rx = DC.RxDipole(rx[:,:3],rx[:,3:]) + srcLists.append( DC.SrcDipole( [Rx], tx[:3],tx[3:]) ) + + # Create survey class + survey = DC.SurveyDC(srcLists) + + survey.dobs = np.asarray(d) + + return {'DCsurvey':survey} + def readUBC_DC2DMesh(fileName): """ Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg @@ -928,7 +997,6 @@ def getSrc_locs(DCsurvey): srcMat = np.zeros((DCsurvey.nSrc,2,3)) for ii in range(DCsurvey.nSrc): - print np.asarray(DCsurvey.srcList[ii].loc).shape srcMat[ii,:,:] = np.asarray(DCsurvey.srcList[ii].loc) return srcMat From ef4513bcd42a0ddaba6b52f6c2fba6af4e70c6a0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 10 Mar 2016 14:25:53 -0800 Subject: [PATCH 27/52] some cleanup inside of sparse regularization --- SimPEG/Directives.py | 54 ++++++++++++------------- SimPEG/Regularization.py | 66 ++++++++++++++----------------- tests/base/test_regularization.py | 2 +- 3 files changed, 57 insertions(+), 65 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 0a98bc09..46b0b087 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -285,45 +285,43 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): class update_IRLS(InversionDirective): - m = None - eps_min = None - factor = None - gamma = None - phi_m_last = None + eps_min = None + factor = None + gamma = None + phi_m_last = None - def initialize(self): + def initialize(self): - # Scale the regularization for changes in norm - if getattr(self, 'phi_m_last', None) is not None: - self.reg.gamma = 1. - phim_new = self.reg.eval(self.invProb.curModel) - self.gamma = self.phi_m_last / phim_new + # Scale the regularization for changes in norm + if getattr(self, 'phi_m_last', None) is not None: + self.reg.gamma = 1. + phim_new = self.reg.eval(self.invProb.curModel) + self.gamma = self.phi_m_last / phim_new - self.reg.gamma = self.gamma + self.reg.gamma = self.gamma - def endIter(self): - # Cool the threshold parameter - if getattr(self, 'factor', None) is not None: - eps = self.reg.eps / self.factor + def endIter(self): + # Cool the threshold parameter + if getattr(self, 'factor', None) is not None: + eps = self.reg.eps / self.factor - if getattr(self, 'eps_min', None) is not None: - self.reg.eps = np.max([self.eps_min,eps]) - else: - self.reg.eps = eps + if getattr(self, 'eps_min', None) is not None: + self.reg.eps = np.max([self.eps_min,eps]) + else: + self.reg.eps = eps # Update the model used for the IRLS weights - if getattr(self, 'm', None) is None: - self.reg.m = self.invProb.curModel + self.reg.curModel = self.invProb.curModel - # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. - PC = Utils.sdiag(diagA**-1.) + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. + PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC + self.opt.approxHinv = PC - phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new #============================================================================== # import pylab as plt diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index db1bc39b..6ad94caf 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -6,7 +6,7 @@ class RegularizationMesh(object): This contains the operators used in the regularization. Note that these are not necessarily true differential operators, but are constructed from - a SimPEG Mesh. + a SimPEG Mesh. :param Mesh mesh: problem mesh :param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells @@ -52,7 +52,7 @@ class RegularizationMesh(object): if getattr(self, '_dim', None) is None: self._dim = self.mesh.dim return self._dim - + @property def _Pac(self): @@ -64,7 +64,7 @@ class RegularizationMesh(object): if getattr(self, '__Pac', None) is None: if self.indActive is None: self.__Pac = Utils.speye(self.mesh.nC) - else: + else: self.__Pac = Utils.speye(self.mesh.nC)[:,self.indActive] return self.__Pac @@ -211,7 +211,7 @@ class RegularizationMesh(object): if getattr(self, '_cellDiffz', None) is None: self._cellDiffz = self._Pafz.T * self.mesh.cellGradz * self._Pac return self._cellDiffz - + @property def faceDiffx(self): """ @@ -233,7 +233,7 @@ class RegularizationMesh(object): if getattr(self, '_faceDiffy', None) is None: self._faceDiffy = self._Pac.T * self.mesh.faceDivy * self._Pafy return self._faceDiffy - + @property def faceDiffz(self): """ @@ -310,7 +310,7 @@ class BaseRegularization(object): if indActive is not None and indActive.dtype != 'bool': tmp = indActive indActive = np.zeros(mesh.nC, dtype=bool) - indActive[tmp] = True + indActive[tmp] = True self.regmesh = RegularizationMesh(mesh,indActive) self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) @@ -427,7 +427,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx return self._Wx @property @@ -640,13 +640,14 @@ class Simple(BaseRegularization): class Sparse(Simple): - eps = 1e-1 - m = None - gamma = 1. - p = 0. - qx = 2. - qy = 2. - qz = 2. + # set default values + eps = 1e-1 + curModel = None # use a model to compute the weights + gamma = 1. + p = 0. + qx = 2. + qy = 2. + qz = 2. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @@ -655,71 +656,64 @@ class Sparse(Simple): @property def Ws(self): """Regularization matrix Ws""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rs = Utils.speye(self.regmesh.nC) else: - f_m = self.m + f_m = self.curModel self.rs = self.R(f_m , self.p, self.eps) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs - return self._Ws @property def Wx(self): """Regularization matrix Wx""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: - f_m = self.regmesh.cellDiffxStencil * self.m + f_m = self.regmesh.cellDiffxStencil * self.curModel self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) - if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil - return self._Wx + return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil @property def Wy(self): """Regularization matrix Wy""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) else: - f_m = self.regmesh.cellDiffyStencil * self.m + f_m = self.regmesh.cellDiffyStencil * self.curModel self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) - if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil - return self._Wy + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property def Wz(self): """Regularization matrix Wz""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) else: - f_m = self.regmesh.cellDiffzStencil * self.m + f_m = self.regmesh.cellDiffzStencil * self.curModel self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) - if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil - return self._Wz + return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil - def R(self, f_m , p, dec): + def R(self, f_m , exponent): - eta = (self.eps**(1-p/2.))**0.5 - r = eta / (f_m**2.+self.eps**2.)**((1-p/2.)/2.) + eta = (self.eps**(1-exponent/2.))**0.5 + r = eta / (f_m**2.+self.eps**2.)**((1-exponent/2.)/2.) return r diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 52cef349..97223015 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -18,7 +18,7 @@ class RegularizationTests(unittest.TestCase): mesh3 = Mesh.TensorMesh([hx, hy, hz]) self.meshlist = [mesh1,mesh2, mesh3] - if testReg: + if testReg: def test_regularization(self): for R in dir(Regularization): r = getattr(Regularization, R) From 838035adaef7991dd48f8c6984b32951b032eea7 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 10 Mar 2016 14:30:43 -0800 Subject: [PATCH 28/52] fixed indentation level on test_regularization --- tests/base/test_regularization.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 97223015..5aa21ad5 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -87,24 +87,24 @@ class RegularizationTests(unittest.TestCase): if testRegMesh: def test_regularizationMesh(self): - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing %iD'%mesh.dim + print 'Testing %iD'%mesh.dim - # mapping = r.mapPair(mesh) - # reg = r(mesh, mapping=mapping) - # m = np.random.rand(mapping.nP) + # mapping = r.mapPair(mesh) + # reg = r(mesh, mapping=mapping) + # m = np.random.rand(mapping.nP) - if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) - elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) - elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) + regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) - assert (regmesh.vol == mesh.vol[indAct]).all() + assert (regmesh.vol == mesh.vol[indAct]).all() if __name__ == '__main__': From 38b4079f0bdb23eaa7b5810ed925e2a4f32102ce Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 11 Mar 2016 11:40:47 -0800 Subject: [PATCH 29/52] Move cell-based weights (i.e. distance weighting) inside regularization. Fix gamma parameter update TO DO: Check inversion print screen -> values don't match reality. --- SimPEG/Directives.py | 8 ++++-- SimPEG/Regularization.py | 60 ++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 46b0b087..dbb525f7 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -298,6 +298,7 @@ class update_IRLS(InversionDirective): phim_new = self.reg.eval(self.invProb.curModel) self.gamma = self.phi_m_last / phim_new + self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma def endIter(self): @@ -315,13 +316,14 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC - + + self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + self.reg.gamma = self.invProb.phi_m_last / phim_new #============================================================================== # import pylab as plt diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6ad94caf..6c6b4b4b 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -540,36 +540,40 @@ class Simple(BaseRegularization): alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - + wght = 1. + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) + + if isinstance(self.wght,float): + self.wght = np.ones(self.regmesh.nC) * self.wght @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellDiffxStencil + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellDiffyStencil + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellDiffzStencil + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil return self._Wz @property @@ -648,10 +652,13 @@ class Sparse(Simple): qx = 2. qy = 2. qz = 2. + wght = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + + if isinstance(self.wght,float): + self.wght = np.ones(self.regmesh.nC) * self.wght @property def Ws(self): @@ -661,26 +668,26 @@ class Sparse(Simple): else: f_m = self.curModel - self.rs = self.R(f_m , self.p, self.eps) + self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - - return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs @property def Wx(self): """Regularization matrix Wx""" - + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: f_m = self.regmesh.cellDiffxStencil * self.curModel - self.rx = self.R( f_m , self.qx, self.eps) + self.rx = self.R( f_m , self.qx) self.Rx = Utils.sdiag( self.rx ) - return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil + return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil @property def Wy(self): @@ -691,10 +698,10 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffyStencil * self.curModel - self.ry = self.R( f_m , self.qy, self.eps) + self.ry = self.R( f_m , self.qy) self.Ry = Utils.sdiag( self.ry ) - - return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil + + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property def Wz(self): @@ -705,12 +712,31 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffzStencil * self.curModel - self.rz = self.R( f_m , self.qz, self.eps) + self.rz = self.R( f_m , self.qz) self.Rz = Utils.sdiag( self.rz ) - return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil + return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + #if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx,) + if self.regmesh.dim > 1: + wlist += (self.Wy,) + if self.regmesh.dim > 2: + wlist += (self.Wz,) + #self._Wsmooth = sp.vstack(wlist) + return sp.vstack(wlist) + @property + def W(self): + """Full regularization matrix W""" + #if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + #self._W = sp.vstack(wlist) + return sp.vstack(wlist) + def R(self, f_m , exponent): eta = (self.eps**(1-exponent/2.))**0.5 From d226186c8e68c33657a318db0de41ec2f9a0a16e Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 11 Mar 2016 15:09:31 -0800 Subject: [PATCH 30/52] Add auto-beta adjustment. --- SimPEG/Directives.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index dbb525f7..de1c60c1 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -289,7 +289,8 @@ class update_IRLS(InversionDirective): factor = None gamma = None phi_m_last = None - + phi_d_last = None + def initialize(self): # Scale the regularization for changes in norm @@ -300,7 +301,10 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma - + + if getattr(self, 'phi_d_last', None) is None: + self.phi_d_last = self.invProb.phi_d + def endIter(self): # Cool the threshold parameter if getattr(self, 'factor', None) is not None: @@ -311,20 +315,28 @@ class update_IRLS(InversionDirective): else: self.reg.eps = eps - + # Get phi_m at the end of current iteration + self.phi_m_last = self.invProb.phi_m_last + # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC - + + # Temporarely set gamma to 1. self.reg.gamma = 1. + + # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.invProb.phi_m_last / phim_new - + self.reg.gamma = self.phi_m_last / phim_new + print self.reg.gamma + + # TO DO: Re-scale beta if too much change in misfit + self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d + #============================================================================== # import pylab as plt # plt.figure() From ef467efce03fb02025bc81712c689f3b3f2c8f11 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 15 Mar 2016 20:56:38 -0700 Subject: [PATCH 31/52] Small change to directive --- SimPEG/Directives.py | 1 - 1 file changed, 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index de1c60c1..e5a63547 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -332,7 +332,6 @@ class update_IRLS(InversionDirective): # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) self.reg.gamma = self.phi_m_last / phim_new - print self.reg.gamma # TO DO: Re-scale beta if too much change in misfit self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d From d302a59b2c7b977be1e2264c9f7e66c09e1805d2 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 16 Mar 2016 11:43:25 -0700 Subject: [PATCH 32/52] Change the projection from 3D to 2D --- SimPEG/DCIP/DCIPUtils.py | 56 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 12e13169..3cbf558c 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -523,7 +523,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.close() -def convertObs_DC3D_to_2D(DCsurvey,lineID): +def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): """ Read DC survey and data and change coordinate system to distance along line assuming @@ -580,26 +580,40 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID): Rx = DCsurvey.srcList[indx[ii]].rxList[0].locs nrx = Rx[0].shape[0] - # Find A electrode along line - vec, r = r_unit(x0,Tx[ii][0,0:2]) - A = stn_id(vecTx,vec,r) - - # Find B electrode along line - vec, r = r_unit(x0,Tx[ii][1,0:2]) - B = stn_id(vecTx,vec,r) - - M = np.zeros(nrx) - N = np.zeros(nrx) - for kk in range(nrx): - - # Find all M electrodes along line - vec, r = r_unit(x0,Rx[0][kk,0:2]) - M[kk] = stn_id(vecTx,vec,r) - - # Find all N electrodes along line - vec, r = r_unit(x0,Rx[1][kk,0:2]) - N[kk] = stn_id(vecTx,vec,r) - + if flag == 'local': + # Find A electrode along line + vec, r = r_unit(x0,Tx[ii][0,0:2]) + A = stn_id(vecTx,vec,r) + + # Find B electrode along line + vec, r = r_unit(x0,Tx[ii][1,0:2]) + B = stn_id(vecTx,vec,r) + + M = np.zeros(nrx) + N = np.zeros(nrx) + for kk in range(nrx): + + # Find all M electrodes along line + vec, r = r_unit(x0,Rx[0][kk,0:2]) + M[kk] = stn_id(vecTx,vec,r) + + # Find all N electrodes along line + vec, r = r_unit(x0,Rx[1][kk,0:2]) + N[kk] = stn_id(vecTx,vec,r) + elif flag == 'Yloc': + """ Flip the XY axis locs""" + A = Tx[ii][0,1] + B = Tx[ii][1,1] + M = Rx[0][:,1] + N = Rx[1][:,1] + + elif flag == 'Xloc': + """ Copy the rx-tx locs""" + A = Tx[ii][0,0] + B = Tx[ii][1,0] + M = Rx[0][:,0] + N = Rx[1][:,0] + Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]]) srcLists.append( DC.SrcDipole( [Rx], np.asarray([A,0,Tx[ii][0,2]]),np.asarray([B,0,Tx[ii][1,2]]) ) ) From f92ff1301db92f5dda32125177281064ec59c17f Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 17 Mar 2016 18:45:09 -0700 Subject: [PATCH 33/52] Add reference model in compact term. --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6c6b4b4b..c20ed973 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -667,7 +667,7 @@ class Sparse(Simple): self.Rs = Utils.speye(self.regmesh.nC) else: - f_m = self.curModel + f_m = self.curModel - self.reg.mref self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) From b765699d2fb4cc40bf26ba909f0bc093eb8307fc Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 25 Mar 2016 23:26:52 -0700 Subject: [PATCH 34/52] seperated out smallness and smoothness contributions --- SimPEG/Regularization.py | 198 +++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 100 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index c20ed973..a91da269 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -344,7 +344,6 @@ class BaseRegularization(object): def W(self): """Full regularization weighting matrix W.""" return sp.identity(self.regmesh.nC) - # self.regmesh._Pac.T * sp.identity(self.regmesh.nC) * self.regmesh._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @Utils.timeIt def eval(self, m): @@ -375,11 +374,12 @@ class BaseRegularization(object): @Utils.timeIt def eval2Deriv(self, m, v=None): """ + Second derivative - :param numpy.array m: geophysical model - :param numpy.array v: vector to multiply - :rtype: scipy.sparse.csr_matrix or numpy.ndarray - :return: WtW or WtW*v + :param numpy.array m: geophysical model + :param numpy.array v: vector to multiply + :rtype: scipy.sparse.csr_matrix or numpy.ndarray + :return: WtW or WtW*v The regularization is: @@ -402,25 +402,48 @@ class BaseRegularization(object): class Tikhonov(BaseRegularization): """ + L2 Tikhonov regularization with both smallness and smoothness (first order + derivative) contributions. + + .. math:: + \phi_m(\mathbf{m}) = \\alpha_s \| W_s (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_x \| W_x \\frac{\partial}{\partial x} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_y \| W_y \\frac{\partial}{\partial y} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_z \| W_z \\frac{\partial}{\partial z} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + Note if the key word argument `mrefInSmooth` is False, then mref is not + included in the smoothness contribution. + + :param Mesh mesh: SimPEG mesh + :param Maps mapping: regularization mapping, takes the model from model space to the thing you want to regularize + :param numpy.ndarray indActive: active cell indices for reducing the size of differential operators in the definition of a regularization mesh + :param bool mrefInSmooth: (default = False) put mref in the smoothness component? + :param float alpha_s: (default 1e-6) smallness weight + :param float alpha_x: (default 1) smoothness weight for first derivative in the x-direction + :param float alpha_y: (default 1) smoothness weight for first derivative in the y-direction + :param float alpha_z: (default 1) smoothness weight for first derivative in the z-direction + :param float alpha_xx: (default 1) smoothness weight for second derivative in the x-direction + :param float alpha_yy: (default 1) smoothness weight for second derivative in the y-direction + :param float alpha_zz: (default 1) smoothness weight for second derivative in the z-direction """ - mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") - alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") - alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") - alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - alpha_xx = Utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") - alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") - alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") + mrefInSmooth = False # put mref in the smoothness contribution + alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Wsmall'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + alpha_xx = Utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") + alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") + alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") def __init__(self, mesh, mapping=None, indActive = None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property - def Ws(self): - """Regularization matrix Ws""" - if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) - return self._Ws + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) + return self._Wsmall @property def Wx(self): @@ -483,25 +506,44 @@ class Tikhonov(BaseRegularization): def W(self): """Full regularization matrix W""" if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) self._W = sp.vstack(wlist) return self._W @Utils.timeIt - def eval(self, m): - if self.mrefInSmooth == True: - r1 = self.Wsmooth * ( self.mapping * (m) ) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.mrefInSmooth == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) + @Utils.timeIt + def _evalSmooth(self, m): + if self.mrefInSmooth == True: + r = self.Wsmooth * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wsmooth * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def eval(self, m): + return self._evalSmall(m) + self._evalSmooth(m) + + @Utils.timeIt + def _evalSmallDeriv(self,m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) + + @Utils.timeIt + def _evalSmoothDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wsmooth * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wsmooth * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wsmooth * ( self.mapping * m ) + return r.T * ( self.Wsmooth * self.mapping.deriv(m) ) @Utils.timeIt def evalDeriv(self, m): """ - The regularization is: .. math:: @@ -515,45 +557,33 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.mrefInSmooth == True: - mD1 = self.mapping.deriv(m) - mD2 = self.mapping.deriv(m - self.mref) - r1 = self.Wsmooth * ( self.mapping * (m)) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - out1 = mD1.T * ( self.Wsmooth.T * r1 ) - out2 = mD2.T * ( self.Ws.T * r2 ) - out = out1+out2 - elif self.mrefInSmooth == False: - mD = self.mapping.deriv(m - self.mref) - r = self.W * ( self.mapping * (m - self.mref) ) - out = mD.T * ( self.W.T * r ) - return out + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) -class Simple(BaseRegularization): +class Simple(Tikhonov): """ - Only for tensor mesh + Simple regularization that does not include length scales in the derivatives. """ mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") + alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") wght = 1. - + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + if isinstance(self.wght,float): self.wght = np.ones(self.regmesh.nC) * self.wght @property - def Ws(self): - """Regularization matrix Ws""" - if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) - return self._Ws + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) + return self._Wsmall @property def Wx(self): @@ -592,54 +622,22 @@ class Simple(BaseRegularization): def W(self): """Full regularization matrix W""" if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) self._W = sp.vstack(wlist) return self._W + @Utils.timeIt + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) @Utils.timeIt - def eval(self, m): + def _evalSmooth(self, m): if self.mrefInSmooth == True: - r1 = self.Wsmooth * ( self.mapping * (m) ) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - return 0.5*(r1.dot(r1)+r2.dot(r2)) + r = self.Wsmooth * ( self.mapping * (m - self.mref) ) elif self.mrefInSmooth == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) - return phim - - - - @Utils.timeIt - def evalDeriv(self, m): - """ - - The regularization is: - - .. math:: - - R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} - - So the derivative is straight forward: - - .. math:: - - R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} - - """ - if self.mrefInSmooth == True: - mD1 = self.mapping.deriv(m) - mD2 = self.mapping.deriv(m - self.mref) - r1 = self.Wsmooth * ( self.mapping * (m)) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - out1 = mD1.T * ( self.Wsmooth.T * r1 ) - out2 = mD2.T * ( self.Ws.T * r2 ) - out = out1+out2 - elif self.mrefInSmooth == False: - mD = self.mapping.deriv(m - self.mref) - r = self.W * ( self.mapping * (m - self.mref) ) - out = mD.T * ( self.W.T * r ) - return out + r = self.Wsmooth * ( self.mapping * m) + return 0.5 * r.dot(r) class Sparse(Simple): @@ -656,13 +654,13 @@ class Sparse(Simple): def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + if isinstance(self.wght,float): self.wght = np.ones(self.regmesh.nC) * self.wght @property - def Ws(self): - """Regularization matrix Ws""" + def Wsmall(self): + """Regularization matrix Wsmall""" if getattr(self, 'curModel', None) is None: self.Rs = Utils.speye(self.regmesh.nC) @@ -671,14 +669,14 @@ class Sparse(Simple): self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs @property def Wx(self): """Regularization matrix Wx""" - + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) @@ -700,7 +698,7 @@ class Sparse(Simple): f_m = self.regmesh.cellDiffyStencil * self.curModel self.ry = self.R( f_m , self.qy) self.Ry = Utils.sdiag( self.ry ) - + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property @@ -733,10 +731,10 @@ class Sparse(Simple): def W(self): """Full regularization matrix W""" #if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) #self._W = sp.vstack(wlist) return sp.vstack(wlist) - + def R(self, f_m , exponent): eta = (self.eps**(1-exponent/2.))**0.5 From 9c220ef37cde8c7faf1f67dfff622687c22e98dd Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 23:05:04 -0700 Subject: [PATCH 35/52] default is mrefInSmooth = False --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index a91da269..e43670d2 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -565,7 +565,7 @@ class Simple(Tikhonov): Simple regularization that does not include length scales in the derivatives. """ - mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") From 5d9d74693234102d6ce593577a2e2532ddea1c16 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 3 Apr 2016 10:42:28 -0700 Subject: [PATCH 36/52] kwarg for stepping off bounds in projected gradient --- SimPEG/Optimization.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 54f6c4ff..0a241710 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -888,6 +888,8 @@ class ProjectedGNCG(BFGS, Minimize, Remember): maxIterCG = 5 tolCG = 1e-1 + stepOffBoundsFact = 0.1 # perturbation of the inactive set off the bounds + lower = -np.inf upper = np.inf @@ -998,7 +1000,8 @@ class ProjectedGNCG(BFGS, Minimize, Remember): dm_i = max( abs( delx ) ) dm_a = max( abs(rhs_a) ) - delx = delx + rhs_a * dm_i / dm_a /10. + # perturb inactive set off of bounds so that they are included in the step + delx = delx + self.stepOffBoundsFact * (rhs_a * dm_i / dm_a) # Only keep gradients going in the right direction on the active set indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0)) From 8f73b2e7be524a15411b4ab6765fae8b9fc5b81d Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sun, 3 Apr 2016 17:18:39 -0700 Subject: [PATCH 37/52] Update directives Add IRLS example --- SimPEG/Directives.py | 101 +++++++++++++--------- SimPEG/Examples/Inversion_IRLS.py | 134 ++++++++++++++++++++---------- SimPEG/Regularization.py | 22 +++-- SimPEG/Survey.py | 2 +- 4 files changed, 160 insertions(+), 99 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index e5a63547..de7e0b6b 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -237,39 +237,41 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the file as a npz np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) -class SaveOutputDictEveryIteration(_SaveEveryIteration): - """SaveOutputDictEveryIteration - A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). - """ - - def initialize(self): - print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName - - def endIter(self): - # Save the data. - ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) - phi_ms = 0.5*ms.dot(ms) - if self.reg.mrefInSmooth == True: - mref = self.reg.mref - else: - mref = 0 - mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim==2: - my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_my = 0.5 * my.dot(my) - else: - phi_my = 'NaN' - if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType: - mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mz = 0.5 * mz.dot(mz) - else: - phi_mz = 'NaN' - - - # Save the file as a npz - np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - +#============================================================================== +# class SaveOutputDictEveryIteration(_SaveEveryIteration): +# """SaveOutputDictEveryIteration +# A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). +# """ +# +# def initialize(self): +# print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName +# +# def endIter(self): +# # Save the data. +# ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) +# phi_ms = 0.5*ms.dot(ms) +# if self.reg.mrefInSmooth == True: +# mref = self.reg.mref +# else: +# mref = 0 +# mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_mx = 0.5 * mx.dot(mx) +# if self.prob.mesh.dim==2: +# my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_my = 0.5 * my.dot(my) +# else: +# phi_my = 'NaN' +# if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType: +# mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_mz = 0.5 * mz.dot(mz) +# else: +# phi_mz = 'NaN' +# +# +# # Save the file as a npz +# np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) +# +#============================================================================== # class UpdateReferenceModel(Parameter): @@ -295,6 +297,8 @@ class update_IRLS(InversionDirective): # Scale the regularization for changes in norm if getattr(self, 'phi_m_last', None) is not None: + + self.reg.curModel = self.invProb.curModel self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) self.gamma = self.phi_m_last / phim_new @@ -320,22 +324,39 @@ class update_IRLS(InversionDirective): # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - - # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. - PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC # Temporarely set gamma to 1. self.reg.gamma = 1. # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.phi_m_last / phim_new - # TO DO: Re-scale beta if too much change in misfit - self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d + # TO DO: Check optimization class, data misfit not matching reality + #dpred = self.prob.fields(self.invProb.curModel) + #phid = self.invProb.dmisfit.eval(self.invProb.curModel) + #print self.survey.std[0] + #print phid + #print self.invProb.phi_d + #print self.invProb.phi_d_last + + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + +class update_lin_PreCond(InversionDirective): + + + def endIter(self): + # Cool the threshold parameter + + if getattr(self.opt, 'approxHinv', None) is not None: + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. + PC = Utils.sdiag(diagA**-1.) + self.opt.approxHinv = PC + print 'Updated pre-cond' + #============================================================================== # import pylab as plt # plt.figure() diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index a7f5bd54..53240139 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -1,7 +1,7 @@ from SimPEG import * -def run(N=100, plotIt=True): +def run(N=200, plotIt=True): """ Inversion: Linear Problem ========================= @@ -9,39 +9,21 @@ def run(N=100, plotIt=True): Here we go over the basics of creating a linear problem and inversion. """ - - class LinearSurvey(Survey.BaseSurvey): - def projectFields(self, u): - return u - - class LinearProblem(Problem.BaseProblem): - - surveyPair = LinearSurvey - - def __init__(self, mesh, G, **kwargs): - Problem.BaseProblem.__init__(self, mesh, **kwargs) - self.G = G - - def fields(self, m, u=None): - return self.G.dot(m) - - def Jvec(self, m, v, u=None): - return self.G.dot(v) - - def Jtvec(self, m, v, u=None): - return self.G.T.dot(v) - - + + np.random.seed(1) + std_noise = 1e-2 + mesh = Mesh.TensorMesh([N]) + + m0 = np.ones(mesh.nC) * 1e-4 + nk = 10 + jk = np.linspace(1.,nk,nk) + p = -2. + q = 1. - nk = 20 - jk = np.linspace(1.,20.,nk) - p = -0.25 - q = 0.25 - - g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(2*np.pi*q*jk[k]*mesh.vectorCCx) + g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(np.pi*q*jk[k]*mesh.vectorCCx) G = np.empty((nk, mesh.nC)) @@ -52,25 +34,43 @@ def run(N=100, plotIt=True): mtrue[mesh.vectorCCx > 0.3] = 1. mtrue[mesh.vectorCCx > 0.45] = -0.5 mtrue[mesh.vectorCCx > 0.6] = 0 + - prob = LinearProblem(mesh, G) - survey = LinearSurvey() + prob = Problem.LinearProblem(mesh, G) + survey = Survey.LinearSurvey() survey.pair(prob) - survey.makeSyntheticData(mtrue, std=0.01) - - M = prob.mesh - - reg = Regularization.Tikhonov(mesh) + survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk) + #survey.makeSyntheticData(mtrue, std=std_noise) + + wd = np.ones(nk) * std_noise + + #print survey.std[0] + #M = prob.mesh + # Distance weighting + wr = np.sum(prob.G**2.,axis=0)**0.5 + wr = ( wr/np.max(wr) )**0 + + reg = Regularization.Simple(mesh) + reg.wght = wr + dmis = DataMisfit.l2_DataMisfit(survey) - opt = Optimization.ProjectedGNCG(maxIter=20,lower=-1.,upper=1., maxIterCG= 20, tolCG = 1e-3) + dmis.Wd = 1./wd + + opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, tolCG = 1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) - beta = Directives.BetaSchedule() + invProb.curModel = m0 + + beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) + target = Directives.TargetMisfit() + betaest = Directives.BetaEstimate_ByEig() - inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest]) - m0 = np.zeros_like(survey.mtrue) + inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) + mrec = inv.run(m0) - + + print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + if plotIt: import matplotlib.pyplot as plt @@ -78,12 +78,54 @@ def run(N=100, plotIt=True): for i in range(prob.G.shape[0]): axes[0].plot(prob.G[i,:]) axes[0].set_title('Columns of matrix G') - - axes[1].plot(M.vectorCCx, survey.mtrue, 'b-') - axes[1].plot(M.vectorCCx, mrec, 'r-') - axes[1].legend(('True Model', 'Recovered Model')) + + axes[1].plot(mesh.vectorCCx, mtrue, 'b-') + axes[1].plot(mesh.vectorCCx, mrec, 'r-') + #axes[1].legend(('True Model', 'Recovered Model')) + axes[1].set_ylim(-1.0,1.25) plt.show() + + # Switch regularization to sparse + phim = invProb.phi_m_last + phid = invProb.phi_d + + reg = Regularization.Sparse(mesh) + +#============================================================================== +# fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) +# dmdx = reg.mesh.cellDiffxStencil * mrec +# plt.plot(np.sort(dmdx)) +#============================================================================== + + #reg.recModel = mrec + reg.wght = np.ones(mesh.nC) + reg.mref = np.zeros(mesh.nC) + reg.eps_p = 2e-3 + reg.eps_q = 2e-3 + reg.norms = [0., 0., 2., 2.] + reg.wght = wr + + opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterCG= 200, tolCG = 1e-3) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) + beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) + #betaest = Directives.BetaEstimate_ByEig() + target = Directives.TargetMisfit() + IRLS =Directives.update_IRLS( phi_m_last = phim, phi_d_last = phid ) + + inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) + m0 = mrec + + # Run inversion + mrec = inv.run(m0) + + print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + + if plotIt: + axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2) + axes[1].legend(('True Model', 'Smooth l2-l2', + 'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12) + return prob, survey, mesh, mrec if __name__ == '__main__': diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index ed75ada6..195e6203 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -643,13 +643,11 @@ class Simple(Tikhonov): class Sparse(Simple): # set default values - eps = 1e-1 + eps_p = 1e-1 + eps_q = 1e-1 curModel = None # use a model to compute the weights gamma = 1. - norms = [0., .2, 2., 2., 1.] - qx = 2. - qy = 2. - qz = 2. + norms = [0., 2., 2., 2.] wght = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): @@ -666,7 +664,7 @@ class Sparse(Simple): else: f_m = self.curModel - self.reg.mref - self.rs = self.R(f_m , self.norms[0]) + self.rs = self.R(f_m , self.eps_p, self.norms[0]) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) @@ -682,7 +680,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffxStencil * self.curModel - self.rx = self.R( f_m , self.qx) + self.rx = self.R( f_m , self.eps_q, self.norms[1]) self.Rx = Utils.sdiag( self.rx ) return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil @@ -696,7 +694,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffyStencil * self.curModel - self.ry = self.R( f_m , self.qy) + self.ry = self.R( f_m , self.eps_q, self.norms[2]) self.Ry = Utils.sdiag( self.ry ) return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @@ -710,7 +708,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffzStencil * self.curModel - self.rz = self.R( f_m , self.qz) + self.rz = self.R( f_m , self.eps_q, self.norms[3]) self.Rz = Utils.sdiag( self.rz ) return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil @@ -735,9 +733,9 @@ class Sparse(Simple): #self._W = sp.vstack(wlist) return sp.vstack(wlist) - def R(self, f_m , exponent): + def R(self, f_m , eps, exponent): - eta = (self.eps**(1-exponent/2.))**0.5 - r = eta / (f_m**2.+self.eps**2.)**((1-exponent/2.)/2.) + eta = (eps**(1-exponent/2.))**0.5 + r = eta / (f_m**2.+ eps**2.)**((1-exponent/2.)/2.) return r diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index 9f307c3f..eee2d538 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -372,7 +372,7 @@ class BaseSurvey(object): self.dtrue = self.dpred(m, u=u) noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape) self.dobs = self.dtrue+noise - self.std = self.dobs*0 + std + self.std = self.dobs*0. + std return self.dobs class LinearSurvey(BaseSurvey): From 2ee158e5d77f74603f58b98e054fdb4f343fa685 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sun, 3 Apr 2016 17:26:04 -0700 Subject: [PATCH 38/52] Add distance weighting to example TO DO: Create example with and without distance weights --- SimPEG/Examples/Inversion_IRLS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 53240139..2cb75f31 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -48,7 +48,7 @@ def run(N=200, plotIt=True): #M = prob.mesh # Distance weighting wr = np.sum(prob.G**2.,axis=0)**0.5 - wr = ( wr/np.max(wr) )**0 + wr = ( wr/np.max(wr) ) reg = Regularization.Simple(mesh) reg.wght = wr From df620b42bd97fc8398806050b05881fbc995bbaa Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 5 Apr 2016 13:23:08 -0700 Subject: [PATCH 39/52] Fix plotting for Linear_IRLS example --- SimPEG/Examples/Inversion_IRLS.py | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 2cb75f31..f5475680 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -68,23 +68,9 @@ def run(N=200, plotIt=True): mrec = inv.run(m0) - + ml2 = mrec print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) - - if plotIt: - import matplotlib.pyplot as plt - - fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) - for i in range(prob.G.shape[0]): - axes[0].plot(prob.G[i,:]) - axes[0].set_title('Columns of matrix G') - - axes[1].plot(mesh.vectorCCx, mtrue, 'b-') - axes[1].plot(mesh.vectorCCx, mrec, 'r-') - #axes[1].legend(('True Model', 'Recovered Model')) - axes[1].set_ylim(-1.0,1.25) - plt.show() - + # Switch regularization to sparse phim = invProb.phi_m_last phid = invProb.phi_d @@ -105,7 +91,7 @@ def run(N=200, plotIt=True): reg.norms = [0., 0., 2., 2.] reg.wght = wr - opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterCG= 200, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=5 ,lower=-2.,upper=2., maxIterCG= 100, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() @@ -121,10 +107,24 @@ def run(N=200, plotIt=True): print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + if plotIt: + import matplotlib.pyplot as plt + + fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) + for i in range(prob.G.shape[0]): + axes[0].plot(prob.G[i,:]) + axes[0].set_title('Columns of matrix G') + + axes[1].plot(mesh.vectorCCx, mtrue, 'b-') + axes[1].plot(mesh.vectorCCx, ml2, 'r-') + #axes[1].legend(('True Model', 'Recovered Model')) + axes[1].set_ylim(-1.0,1.25) + axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2) axes[1].legend(('True Model', 'Smooth l2-l2', 'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12) + plt.show() return prob, survey, mesh, mrec From 8d6bd6592371d51ff1b14e5978fb3cc2a0b4c51c Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 5 Apr 2016 14:26:45 -0700 Subject: [PATCH 40/52] Better list comprehension. --- SimPEG/Examples/EM_FDEM_1D_Inversion.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index e76b2439..29f51ed4 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -48,8 +48,7 @@ def run(plotIt=True): freqs = np.logspace(1,3,10) srcLoc = np.array([0., 0., 10.]) - srcList = [] - [srcList.append(EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z')) for freq in freqs] + srcList = [EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z') for freq in freqs] survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem_b(mesh, mapping=mapping) From ba977206eaa43d10b5df49c99631b4c78db9948c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 07:22:18 -0700 Subject: [PATCH 41/52] Create sensitivity re-weighting directive Adapt Map/polymap for actInd (topography) --- SimPEG/Directives.py | 31 ++++++++++++++++++++++++------ SimPEG/Maps.py | 45 ++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index de7e0b6b..ec77b7a1 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -356,10 +356,29 @@ class update_lin_PreCond(InversionDirective): PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC print 'Updated pre-cond' + +class update_Wj(InversionDirective): + """ + Create approx-sensitivity base weighting + """ + k = None -#============================================================================== -# import pylab as plt -# plt.figure() -# ax = plt.subplot(221) -# self.prob.mesh.plotSlice(self.invProb.curModel, ax = ax, normal = 'Z', ind=-5, clim = (0, 0.005)) -#============================================================================== + def endIter(self): + + if self.opt.iter == 2: + m = self.invProb.curModel + if self.k is None: + self.k = int(self.survey.nD/10) + + def JtJv(v): + + Jv = self.prob.Jvec(m, v) + + return self.prob.Jtvec(m,Jv) + + JtJdiag = Utils.diagEst(JtJv,6,k=100) + JtJdiag = JtJdiag + JtJdiag = JtJdiag / max(JtJdiag) + + + self.reg.wght = JtJdiag diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index 5f71d87c..f6b24f10 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -759,15 +759,27 @@ class PolyMap(IdentityMap): m = [\sigma_1, \sigma_2, c] - """ - def __init__(self, mesh, order, logSigma=True, normal='X'): + """ + def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None): IdentityMap.__init__(self, mesh) self.logSigma = logSigma self.order = order - self.normal = normal - - slope = 1e4 - + self.normal = normal + self.actInd = actInd + + if getattr(self, 'actInd', None) is None: + self.actInd = range(self.mesh.nC) + self.nC = self.mesh.nC + + else: + self.nC = len(self.actInd) + + slope = 1e4 + + @property + def shape(self): + return (self.nC, self.nP) + @property def nP(self): if np.isscalar(self.order): @@ -785,8 +797,8 @@ class PolyMap(IdentityMap): sig1, sig2 = np.exp(sig1), np.exp(sig2) #2D if self.mesh.dim == 2: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] if self.normal =='X': f = polynomial.polyval(Y, c) - X elif self.normal =='Y': @@ -795,9 +807,9 @@ class PolyMap(IdentityMap): raise(Exception("Input for normal = X or Y or Z")) #3D elif self.mesh.dim == 3: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] - Z = self.mesh.gridCC[:,2] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] + Z = self.mesh.gridCC[self.actInd,2] if self.normal =='X': f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X elif self.normal =='Y': @@ -806,6 +818,7 @@ class PolyMap(IdentityMap): f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z else: raise(Exception("Input for normal = X or Y or Z")) + else: raise(Exception("Only supports 2D")) @@ -819,8 +832,8 @@ class PolyMap(IdentityMap): sig1, sig2 = np.exp(sig1), np.exp(sig2) #2D if self.mesh.dim == 2: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] if self.normal =='X': f = polynomial.polyval(Y, c) - X @@ -832,9 +845,9 @@ class PolyMap(IdentityMap): raise(Exception("Input for normal = X or Y or Z")) #3D elif self.mesh.dim == 3: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] - Z = self.mesh.gridCC[:,2] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] + Z = self.mesh.gridCC[self.actInd,2] if self.normal =='X': f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X From e646211e7d4e300e0bde758505179da45912be4c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 08:55:52 -0700 Subject: [PATCH 42/52] Review Utils.gen_DCIPsurvey ... lets keep it. --- SimPEG/DCIP/DCIPUtils.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 3cbf558c..1c109559 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -371,16 +371,6 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:]) SrcList.append(srcClass) -#============================================================================== -# elif re.match(stype,'dpdp'): -# -# for ii in range(0, int(nstn)-2): -# -# indx = np.min([ii+n+1,nstn]) -# Tx.append(np.c_[M[ii,:],N[ii,:]]) -# Rx.append(np.c_[M[ii+2:indx,:],N[ii+2:indx,:]]) -#============================================================================== - elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square @@ -533,10 +523,10 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): Assumes flat topo for now... Input: - :param Tx, Rx + :param survey3D Output: - :figure Tx2d, Rx2d + :figure survey2D Edited Feb 17th, 2016 From 15d59a5b50511ae6396d7b74c455e68c1da44878 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 09:00:13 -0700 Subject: [PATCH 43/52] Fix typos in Directives.update_Wj. overseer @lheagy --- SimPEG/Directives.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index ec77b7a1..9926055a 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -376,9 +376,7 @@ class update_Wj(InversionDirective): return self.prob.Jtvec(m,Jv) - JtJdiag = Utils.diagEst(JtJv,6,k=100) - JtJdiag = JtJdiag + JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k) JtJdiag = JtJdiag / max(JtJdiag) - self.reg.wght = JtJdiag From 8b94cd4dfe239318acb4469d6e0958c7dbd3bd76 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 09:14:14 -0700 Subject: [PATCH 44/52] Change flag for convertObs_DC3D_to_2D, which broke the example --- SimPEG/DCIP/DCIPUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 1c109559..d8cf04bf 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -513,7 +513,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.close() -def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): +def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ Read DC survey and data and change coordinate system to distance along line assuming From 2bd5829b42b48108c205d07dc3bec20a416a21ad Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 6 Apr 2016 13:15:03 -0700 Subject: [PATCH 45/52] Add gitter chat --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1c645334..c9b30a78 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,10 @@ SimPEG :target: https://coveralls.io/r/simpeg/simpeg?branch=master :alt: Coverage status +.. image:: http://img.shields.io/badge/GITTER-JOIN_CHAT-brightgreen.svg?style=flat-square + :alt: gitter chat room at https://gitter.im/simpeg/simpeg + :target: https://gitter.im/simpeg/simpeg + Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications. The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features: From f799733a9d9c59961b34e5d6dfcb558daed3bc60 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 14:43:33 -0700 Subject: [PATCH 46/52] Fix TwoSphere example and Utils.pseudoPlot --- SimPEG/DCIP/DCIPUtils.py | 50 ++++++++++--------- SimPEG/Examples/DC_Forward_PseudoSection.py | 55 ++++++++++++++------- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index d8cf04bf..af94ad4e 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): +def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -230,12 +230,14 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): elif stype == 'dpdp': leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + leg = np.log10(abs(1/leg)) + midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) #TODO ... let stick to list then finally convert to array. - if dtype =="voltage": + if dtype =="appr": rho = np.hstack([rho,leg]) - elif dtype =="appr": + elif dtype =="voltage": rho = np.hstack([rho,data]) @@ -250,28 +252,27 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): else: vmin, vmax = clim[0], clim[1] - plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) - cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal") + grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho) + ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, clim=(vmin, vmax)) + cbar = plt.colorbar(format="$10^{%.1f}$",fraction=0.04,orientation="horizontal") cmin,cmax = cbar.get_clim() ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - - # Plot apparent resistivity - plt.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + cbar.set_label("App. Conductivity",size=12) - ax.set_xticklabels([]) - ax.set_yticklabels([]) + # Plot apparent resistivity + ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + + #ax.set_xticklabels([]) + #ax.set_yticklabels([]) - #ax.set_ylabel('Z') - #ax.yaxis.tick_right() - #ax.yaxis.set_label_position('right') plt.gca().set_aspect('equal', adjustable='box') - return ax + return ph def gen_DCIPsurvey(endl, mesh, stype, a, b, n): """ @@ -515,12 +516,12 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ - Read DC survey and data and change - coordinate system to distance along line assuming - all data is acquired along line. - First transmitter pole is assumed to be at the origin + Read DC survey and projects the coordinate system + according to the flag = 'Xloc' | 'Yloc' | 'local' (default) + In the 'local' system, station coordinates are referenced + to distance from the first srcLoc[0].loc[0] - Assumes flat topo for now... + The Z value is preserved, but Y coordinates zeroed. Input: :param survey3D @@ -528,7 +529,7 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): Output: :figure survey2D - Edited Feb 17th, 2016 + Edited April 6th, 2016 @author: dominiquef @@ -618,16 +619,16 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): def readUBC_DC3Dobs(fileName): """ - Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + Read UBC GIF DCIP 3D observation file and generate survey Input: :param fileName, path to the UBC GIF 3D obs file Output: - :param rx, tx, d, wd + :param DCIPsurvey :return - Created on Mon December 7th, 2015 + Created on Mon April 6th, 2015 @author: dominiquef @@ -702,6 +703,7 @@ def readUBC_DC3Dobs(fileName): def readUBC_DC2Dobs(fileName): """ + ------- NEEDS TO BE UPDATED ------ Read UBC GIF 2D observation file and generate arrays for tx-rx location Input: @@ -751,7 +753,7 @@ def readUBC_DC2Dobs(fileName): def readUBC_DC2Dpre(fileName): """ - Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location Input: :param fileName, path to the UBC GIF 3D obs file diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 2f198238..904dcbd3 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -56,7 +56,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Plot the model for reference # Define core mesh extent xlim = 200 - zlim = 125 + zlim = 100 # Specify the survey type: "pdp" | "dpdp" @@ -77,7 +77,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len - azm = np.arctan(dl_y/dl_x) + #azm = np.arctan(dl_y/dl_x) #Set boundary conditions mesh.setCellGradBC('neumann') @@ -146,39 +146,60 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Let's just convert the 3D format into 2D (distance along line) and plot # [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) - survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) + survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc') survey2D.dobs =np.hstack(data) # Here is an example for the first tx-rx array if plotIt: import matplotlib.pyplot as plt - fig = plt.figure() + fig = plt.figure(figsize=(7,7)) ax = plt.subplot(2,1,1, aspect='equal') - mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True) - ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m') + # Plot the location of the spheres for reference + circle1=plt.Circle((loc[0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) + circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) + ax.add_artist(circle1) + ax.add_artist(circle2) + + dat = mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', + ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()])) + + ax.set_title('3-D model') plt.gca().set_aspect('equal', adjustable='box') - + plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') plt.xlim([-xlim,xlim]) plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - ax = plt.subplot(2,1,2, aspect='equal') + + + pos = ax.get_position() + ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height]) + pos = ax.get_position() + cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set + cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal", + ax = ax, ticks=np.linspace(np.log10(sig.min()), + np.log10(sig.max()), 3), format="$10^{%.1f}$") + cb.set_label("Conductivity (S/m)",size=12) + cb.ax.tick_params(labelsize=12) + + # Second plot for the predicted apparent resistivity data + ax2 = plt.subplot(2,1,2, aspect='equal') # Plot the location of the spheres for reference - circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) - circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) - ax.add_artist(circle1) - ax.add_artist(circle2) - + circle1=plt.Circle((loc[0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) + circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) + ax2.add_artist(circle1) + ax2.add_artist(circle2) + + # Add the speudo section - DC.plot_pseudoSection(survey2D,ax,stype) + dat = DC.plot_pseudoSection(survey2D,ax2,stype) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') # plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') # plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') + ax2.set_title('Apparent Conductivity data') + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - plt.show() return fig, ax From 636d178fbf06ccdc30cd4bb8833bbce0e5d3a204 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 6 Apr 2016 16:19:39 -0700 Subject: [PATCH 47/52] removed examples that are in Examples PR --- SimPEG/Directives.py | 48 +- SimPEG/Examples/EM_FDEM_SusEffects.py | 148 ---- .../Examples/MT_1D_analytic_nlayer_Earth.py | 443 ---------- SimPEG/Examples/__init__.py | 5 +- .../Examples/sphereElectrostatic_example.py | 775 ------------------ docs/examples/EM_FDEM_SusEffects.rst | 41 - docs/examples/MT_1D_analytic_nlayer_Earth.rst | 21 - 7 files changed, 25 insertions(+), 1456 deletions(-) delete mode 100644 SimPEG/Examples/EM_FDEM_SusEffects.py delete mode 100644 SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py delete mode 100644 SimPEG/Examples/sphereElectrostatic_example.py delete mode 100644 docs/examples/EM_FDEM_SusEffects.rst delete mode 100644 docs/examples/MT_1D_analytic_nlayer_Earth.rst diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index acccb224..8f93c70a 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -242,10 +242,10 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # """SaveOutputDictEveryIteration # A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). # """ -# +# # def initialize(self): # print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName -# +# # def endIter(self): # # Save the data. # ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) @@ -266,11 +266,11 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # phi_mz = 0.5 * mz.dot(mz) # else: # phi_mz = 'NaN' -# -# +# +# # # Save the file as a npz # np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) -# +# #============================================================================== # class UpdateReferenceModel(Parameter): @@ -292,12 +292,12 @@ class update_IRLS(InversionDirective): gamma = None phi_m_last = None phi_d_last = None - + def initialize(self): # Scale the regularization for changes in norm if getattr(self, 'phi_m_last', None) is not None: - + self.reg.curModel = self.invProb.curModel self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) @@ -305,10 +305,10 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma - + if getattr(self, 'phi_d_last', None) is None: self.phi_d_last = self.invProb.phi_d - + def endIter(self): # Cool the threshold parameter if getattr(self, 'factor', None) is not None: @@ -321,35 +321,35 @@ class update_IRLS(InversionDirective): # Get phi_m at the end of current iteration self.phi_m_last = self.invProb.phi_m_last - + # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - + # Temporarely set gamma to 1. self.reg.gamma = 1. - + # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) self.reg.gamma = self.phi_m_last / phim_new - - - # TO DO: Check optimization class, data misfit not matching reality + + + # TO DO: Check optimization class, data misfit not matching reality #dpred = self.prob.fields(self.invProb.curModel) #phid = self.invProb.dmisfit.eval(self.invProb.curModel) #print self.survey.std[0] #print phid #print self.invProb.phi_d #print self.invProb.phi_d_last - + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d class update_lin_PreCond(InversionDirective): - - + + def endIter(self): # Cool the threshold parameter - + if getattr(self.opt, 'approxHinv', None) is not None: # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. @@ -362,20 +362,20 @@ class update_Wj(InversionDirective): Create approx-sensitivity base weighting """ k = None - + def endIter(self): - + if self.opt.iter == 2: m = self.invProb.curModel if self.k is None: self.k = int(self.survey.nD/10) - + def JtJv(v): Jv = self.prob.Jvec(m, v) - + return self.prob.Jtvec(m,Jv) - + JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k) JtJdiag = JtJdiag / max(JtJdiag) diff --git a/SimPEG/Examples/EM_FDEM_SusEffects.py b/SimPEG/Examples/EM_FDEM_SusEffects.py deleted file mode 100644 index 1abbb16f..00000000 --- a/SimPEG/Examples/EM_FDEM_SusEffects.py +++ /dev/null @@ -1,148 +0,0 @@ -from SimPEG import * -from SimPEG import EM -from pymatsolver import MumpsSolver -from scipy.constants import mu_0 - -def run(plotIt=True): - """ - EM: FDEM: Effects of susceptibility - =================================== - - When airborne freqeuncy domain EM (AFEM) survey is flown over - the earth including significantly susceptible bodies (magnetite-rich rocks), - negative data is often observed in the real part of the lowest frequency - (e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization - occurs due to a susceptible body when the magnetic field is applied. - - To clarify what is happening in the earth when we are exciting the earth with - a loop source in the frequency domain we run three forward modelling: - - - F[:math:`\sigma`, :math:`\mu`]: Anomalous conductivity and susceptibility - - F[:math:`\sigma`, :math:`\mu_0`]: Anomalous conductivity - - F[:math:`\sigma_{air}`, :math:`\mu_0`]: primary field - - We plot vector magnetic fields in the earth. For secondary fields we provide - F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following - figure show both real and parts. - - """ - # Generate Cylindrical mesh - cs, ncx, ncz, npad = 5, 25, 24, 20. - hx = [(cs,ncx), (cs,npad,1.3)] - hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)] - mesh = Mesh.CylMesh([hx,1,hz], '00C') - sighalf = 1e-3 - sigma = np.ones(mesh.nC)*1e-8 - sigmahomo = sigma.copy() - mu = np.ones(mesh.nC)*mu_0 - sigma[mesh.gridCC[:,-1]<0.] = sighalf - blkind = np.logical_and(mesh.gridCC[:,0]<30., (mesh.gridCC[:,2]<0)&(mesh.gridCC[:,2]>-150)&(mesh.gridCC[:,2]<-50)) - sigma[blkind] = 1e-1 - mu[blkind] = mu_0*1.1 - offset = 0. - frequency = np.r_[10., 100., 1000.] - rx0 = EM.FDEM.Rx(np.array([[8., 0., 30.]]), 'bzr') - rx1 = EM.FDEM.Rx(np.array([[8., 0., 30.]]), 'bzi') - srcLists = [] - nfreq = frequency.size - for ifreq in range(nfreq): - src = EM.FDEM.Src.CircularLoop([rx0, rx1], frequency[ifreq], np.array([[0., 0., 30.]]), radius=5.) - srcLists.append(src) - survey = EM.FDEM.Survey(srcLists) - iMap = Maps.IdentityMap(nP=int(mesh.nC)) - # Use PhysPropMap - maps = [('sigma', iMap), ('mu', iMap)] - prob = EM.FDEM.Problem_b(mesh, mapping=maps) - prob.Solver = MumpsSolver - survey.pair(prob) - m = np.r_[sigma, mu] - survey0 = EM.FDEM.Survey(srcLists) - prob0 = EM.FDEM.Problem_b(mesh, mapping=maps) - prob0.Solver = MumpsSolver - survey0.pair(prob0) - m = np.r_[sigma, mu] - m0 = np.r_[sigma, np.ones(mesh.nC)*mu_0] - m00 = np.r_[np.ones(mesh.nC)*1e-8, np.ones(mesh.nC)*mu_0] - # Anomalous conductivity and susceptibility - F = prob.fields(m) - # Only anomalous conductivity - F0 = prob.fields(m0) - # Primary field - F00 = prob.fields(m00) - - if plotIt: - import matplotlib.pyplot as plt - def vizfields(ifreq=0, primsec="secondary",realimag="real"): - - titles = ["F[$\sigma$, $\mu$]", "F[$\sigma$, $\mu_0$]", "F[$\sigma$, $\mu$]-F[$\sigma$, $\mu_0$]"] - actind = np.logical_and(mesh.gridCC[:,0]<200., (mesh.gridCC[:,2]>-400)&(mesh.gridCC[:,2]<200)) - - if primsec=="secondary": - bCCprim = (mesh.aveF2CCV*F00[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - bCC = (mesh.aveF2CCV*F[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F')-bCCprim - bCC0 = (mesh.aveF2CCV*F0[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F')-bCCprim - elif primsec=="primary": - bCC = (mesh.aveF2CCV*F[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - bCC0 = (mesh.aveF2CCV*F0[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - - XYZ = mesh.gridCC[actind,:] - X = XYZ[:,0].reshape((31,43), order='F') - Z = XYZ[:,2].reshape((31,43), order='F') - bx = bCC[actind,0].reshape((31,43), order='F') - bz = bCC[actind,1].reshape((31,43), order='F') - bx0 = bCC0[actind,0].reshape((31,43), order='F') - bz0 = bCC0[actind,1].reshape((31,43), order='F') - - bxsec = (bCC[actind,0]-bCC0[actind,0]).reshape((31,43), order='F') - bzsec = (bCC[actind,1]-bCC0[actind,1]).reshape((31,43), order='F') - - absbreal = np.sqrt(bx.real**2+bz.real**2) - absbimag = np.sqrt(bx.imag**2+bz.imag**2) - absb0real = np.sqrt(bx0.real**2+bz0.real**2) - absb0imag = np.sqrt(bx0.imag**2+bz0.imag**2) - - absbrealsec = np.sqrt(bxsec.real**2+bzsec.real**2) - absbimagsec = np.sqrt(bxsec.imag**2+bzsec.imag**2) - - fig = plt.figure(figsize=(15,5)) - ax1 = plt.subplot(131) - ax2 = plt.subplot(132) - ax3 = plt.subplot(133) - typefield="real" - scale=20 - if realimag=="real": - ax1.contourf(X, Z,np.log10(absbreal), 100) - ax1.quiver(X, Z,bx.real/absbreal,bz.real/absbreal,scale=scale,width=0.005, alpha = 0.5) - ax2.contourf(X, Z,np.log10(absb0real), 100) - ax2.quiver(X, Z,bx0.real/absb0real,bz0.real/absb0real,scale=scale,width=0.005, alpha = 0.5) - ax3.contourf(X, Z,np.log10(absbrealsec), 100) - ax3.quiver(X, Z,bxsec.real/absbrealsec,bzsec.real/absbrealsec,scale=scale,width=0.005, alpha = 0.5) - elif realimag=="imag": - ax1.contourf(X, Z,np.log10(absbimag), 100) - ax1.quiver(X, Z,bx.imag/absbimag,bz.imag/absbimag,scale=scale,width=0.005, alpha = 0.5) - ax2.contourf(X, Z,np.log10(absb0imag), 100) - ax2.quiver(X, Z,bx0.imag/absb0imag,bz0.imag/absb0imag,scale=scale,width=0.005, alpha = 0.5) - ax3.contourf(X, Z,np.log10(absbimagsec), 100) - ax3.quiver(X, Z,bxsec.imag/absbimagsec,bzsec.imag/absbimagsec,scale=scale,width=0.005, alpha = 0.5) - - ax = [ax1, ax2, ax3] - ax3.text(30, 50, ("Frequency=%5.2f Hz")%(frequency[ifreq]), color="k", fontsize=18) - ax2.text(30, 50, primsec, color="k", fontsize=18) - ax1.text(30, 50, realimag, color="k", fontsize=18) - for i, axtemp in enumerate(ax): - axtemp.plot(np.r_[0, 29.75], np.r_[-50, -50], 'w', lw=3) - - axtemp.plot(np.r_[29.5, 29.5], np.r_[-50, -142.5], 'w', lw=3) - axtemp.plot(np.r_[0, 29.5], np.r_[-142.5, -142.5], 'w', lw=3) - axtemp.plot(np.r_[0, 100.], np.r_[0, 0], 'w', lw=3) - axtemp.set_ylim(-200, 100.) - axtemp.set_xlim(10, 100.) - axtemp.set_title(titles[i]) - plt.show() - return fig, ax - fig1, ax1 = vizfields(1, primsec="primary", realimag="real") - fig2, ax2 = vizfields(1, primsec="secondary", realimag="real") - fig4, ax4 = vizfields(1, primsec="secondary", realimag="imag") - -if __name__ == '__main__': - run() diff --git a/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py b/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py deleted file mode 100644 index 0cccc5f1..00000000 --- a/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py +++ /dev/null @@ -1,443 +0,0 @@ -from scipy.constants import epsilon_0, mu_0 -import matplotlib.pyplot as plt -import numpy as np -from ipywidgets import * -#from SimPEG.EM.Utils import k, omega - -""" -MT1D: n layered earth problem -***************************** - -Author: Thibaut Astic -Contact: thast@eos.ubc.ca -Date: January 2016 - -This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics). - -We start by looking at Maxwell's equations in the electric -field \\\(\\\mathbf{E}\\) and the magnetic flux -\\\(\\\mathbf{H}\\) to write the wave equations -\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) & -\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\) - -Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of -\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\) -\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\) - -With U and D the Up and Down components of the E-field. - -The iteration from one layer to another is ensure by: - -\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) = - P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\) - -And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0) -and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability) - -The layer 0 is assumed to be the air layer. - -""" - -#Frequency conversion -omega = lambda f: 2.*np.pi*f - -#Evaluate k wavenumber -k = lambda mu,sig,eps,f: np.sqrt(mu*mu_0*eps*epsilon_0*(2.*np.pi*f)**2.-1.j*mu*mu_0*sig*omega(f)) - -#Define a frquency range for a survey -frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.) - -#Functions to create random physical Perties for a n-layered earth -thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]), - np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1) - ,decimals =1)) - -sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]), - np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1) - ,decimals=3)) - -mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]), - np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1) - ,decimals=1)) - -eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]), - np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1) - ,decimals=1)) - -#Evaluate Impedance Z of a layer -ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k - -#Complex Cole-Cole Conductivity - EM utils -PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c))) - - -#Converted thickness array into top of layer array -def top(thick): - topv= np.zeros(len(thick)+1) - - topv[0]=-thick[0] - - for i in range(1,len(topv),1): - topv[i] = topv[i-1] + thick[i-1] - - return topv - -#Propagation Matrix and theirs inverses - -#matrix T for transition of Up and Down components accross a layer -T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_') - -Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_') - -#transition of Up and Down components accross a layer -UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD - - -#matrix P relating Up and Down components with E and H fields -P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_') - -Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2. - - -#Time Variation of E and H -E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D) -H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U) - -#Plot the configuration of the problem -def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z): - - topn = top(thick) - widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.) - - ax.set_ylim([z.min(),z.max()]) - ax.set_xlim([-widthg,widthg]) - - ax.set_ylabel("Depth (m)", fontsize=16.) - ax.yaxis.tick_right() - ax.yaxis.set_label_position("right") - - #define filling for the different layers - hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ] - - #Write the physical properties of air - ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)), - xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data', - xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[0]), - xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', - xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1i")%(mu[0]), - xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', - xytext=(0, -np.abs(z.max())/3.), textcoords='data', - fontsize=14.) - - #Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern - for i in range(1,len(topn)-1,1): - if topn[i] == topn[i+1]: - pass - else: - ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)), - xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[i]), - xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1.2f")%(mu[i]), - xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black') - ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10]) - - #Write the physical properties of the n-th layer and fill it with pattern - ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black') - ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10]) - - ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)), - xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]), - xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]), - xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - #plot Trees! - ax.annotate("", - xy=(widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - - ax.invert_yaxis() - - return ax - -#Propagate Up and Down component for a certain frequency & evaluate E and H field - -def Propagate(f,H,sig,chg,taux,c,mu,eps,n): - - sigcm = np.zeros_like(sig,dtype='complex_') - - for j in range(1,len(sig)): - sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f) - - K = k(mu,sigcm,eps,f) - Z = ImpZ(f,mu,K) - - EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') - UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') - - UD[1,-1] = 1. - - for i in range(-2,-(n+2),-1): - - UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1] - UD = UD/((np.abs(UD[0,:]+UD[1,:])).max()) - - for j in range(0,n+1): - EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j] - - return UD, EH, Z ,K - - -#Evaluate the apparent resistivity and phase for a frequency range -def appres(F,H,sig,chg,taux,c,mu,eps,n): - - Res = np.zeros_like(F) - Phase = np.zeros_like(F) - App_ImpZ= np.zeros_like(F,dtype='complex_') - - for i in range(0,len(F)): - - UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n) - - App_ImpZ[i] = EH[0,1]/EH[1,1] - - Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i])) - Phase[i] = np.angle(App_ImpZ[i], deg = True) - - return Res,Phase - -#Evaluate Up, Down components, E and H field, for a frequency range, -#a discretized depth range and a time range (use to calculate envelope) -def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample): - - topc = top(H) - - layer = np.zeros(len(zsample),dtype=np.int)-1 - - Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_') - - for i in range(0,n+1,1): - layer = layer+(zsample>=topc[i])*1 - - for j in range(0,len(F)): - - UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n) - - for p in range(0,len(zsample)): - - UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]]) - - for q in range(0,len(tsample)): - - Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F) - Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F) - Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) - Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) - - return Exzt,Hyzt,Uz,Dz,UDaux,layer - - -#Function to Plot Apparent Resistivity and Phase -def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope): - - Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n) - - fig,ax = plt.subplots(1,2,figsize=(16,10)) - - ax[0].scatter(Res,F,color='black') - ax[0].set_xscale('Log') - ax[0].set_yscale('Log') - ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)]) - ax[0].set_ylim([F.min(),F.max()]) - ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black") - ax[0].set_ylabel('Frequency (Hz)',fontsize=16.) - ax[0].grid(which='major') - - ax0 = ax[0].twiny() - - ax0.set_xlim([0.,90.]) - ax0.set_ylim([F.min(),F.max()]) - ax0.scatter(Phase,F,color='purple') - ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple") - - zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.) - - ax[0].tick_params(labelsize=16) - ax[1].tick_params(labelsize=16) - ax0.tick_params(labelsize=16) - - if PlotEnvelope: - - widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0) - fenvelope1n=np.ones(100)*fenvelope - ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black') - - tc=np.arange(0.,1./fenvelope,0.01/(fenvelope)) - Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc) - - ax1=ax[1].twiny() - - ax[1].tick_params(labelsize=16) - ax1.tick_params(labelsize=16) - - ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16) - - ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16) - - ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))), - np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))), - color='blue', alpha=0.1) - - ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))), - np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))), - color='red', alpha=0.1) - - ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc) - ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) - ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) - else: - print 'No envelop (if True, might be slow)' - ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc) - ax[1].get_xaxis().set_ticks([]) - - plt.show() - -#Interactive MT for Notebook -def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope): - - frangn=frange(-5,5,100.) - sig3= np.array([0.,0.001,0.1, 0.001]) - thick3 = np.array([120000.,50.,50.]) - eps3=np.array([1.,1.,1.,1]) - mu3=np.array([1.,1.,1.,1]) - chg3=np.array([0.,0.1,0.,0.2]) - chg3_0=np.array([0.,0.1,0.,0.]) - taux3=np.array([0.,0.1,0.,0.1]) - c3=np.array([1.,1.,1.,1.]) - - sig3[1]=sigl1 - sig3[1]=10.**sig3[1] - sig3[2]=sigl2 - sig3[2]=10.**sig3[2] - sig3[3]=sigl3 - sig3[3]=10.**sig3[3] - mu3[1]=mul1 - mu3[2]=mul2 - mu3[3]=mul3 - eps3[1]=epsl1 - eps3[2]=epsl2 - eps3[3]=epsl3 - thick3[1]=h1 - thick3[2]=h2 - - PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope) - - -def run(n,plotIt=True): - # something to make a plot - - F = frange(-5.,5.,20) - H = thick(50.,100.,n) - sign = sig(-5.,0.,n) - mun = mu(1.,2.,n) - epsn = eps(1.,9.,n) - chg = np.zeros_like(sign) - taux = np.zeros_like(sign) - c = np.zeros_like(sign) - - Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n) - - if plotIt: - - PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True) - - return Res, Phase - -if __name__ == '__main__': - run(3) - - - - - diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index a95bc194..b06bb3a7 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -6,7 +6,6 @@ import DC_Forward_PseudoSection import DC_PseudoSection_Simulation import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace -import EM_FDEM_SusEffects import EM_Schenkel_Morrison_Casing import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 @@ -20,12 +19,10 @@ import Mesh_QuadTree_Creation import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation -import MT_1D_analytic_nlayer_Earth import MT_1D_ForwardAndInversion import MT_3D_Foward -import sphereElectrostatic_example -__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_FDEM_SusEffects", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_analytic_nlayer_Earth", "MT_1D_ForwardAndInversion", "MT_3D_Foward", "sphereElectrostatic_example"] +__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] ##### AUTOIMPORTS ##### diff --git a/SimPEG/Examples/sphereElectrostatic_example.py b/SimPEG/Examples/sphereElectrostatic_example.py deleted file mode 100644 index 7ff1ead1..00000000 --- a/SimPEG/Examples/sphereElectrostatic_example.py +++ /dev/null @@ -1,775 +0,0 @@ -from scipy.constants import epsilon_0 -import matplotlib.pyplot as plt -import matplotlib.colors as colors -import numpy as np -from SimPEG.Utils import ndgrid, mkvc - -''' -Authors: Thibaut Astic, Lindsey Heagy, Sanna Tyrvainen, Ronghua Peng -Date: December 2015 - -This code defines function to resolve analytically the electrostatic sphere problem. -We first define a problem configuration, with a conductive or resistive sphere in a -wholespace background. -We then calculate the potential, then the electric field, then the current density and -finally the charges accumulation. - -Several plotting functions are defined for data visualisation. - - -''' - -# Plot options -ftsize_title = 18 #font size for titles -ftsize_axis = 14 #font size for axis ticks -ftsize_label = 14 #font size for axis labels - -# Radius function, useful sigma ratio, and log scale converter -r = lambda x,y,z: np.sqrt(x**2.+y**2.+z**2.) -sigf = lambda sig0,sig1: (sig1-sig0)/(sig1+2.*sig0) - -#tools to convert log conductivity in conductivity -def conductivity_log_wrapper(log_sig0,log_sig1): - sig0 = 10.**log_sig0 - sig1 = 10.**log_sig1 - - return sig0,sig1 - -# Examples -#Plot the configuration. Label=False is used to generate a general case figure -def get_Setup(XYZ,sig0,sig1,R,E0,ax,label,colorsphere): - ''' - XYZ: ndgrid - sig0: conductivity of the background - sig1: conductivity of the sphere - R: radius of the sphere - E0: Amplitude of the uniform electrostatic field - ax: ax where to plot the configuration - label: True: plot real values, False: plot general case - colorsphere: color of the sphere, format [x,x,x] - ''' - - xplt = np.linspace(-R, R, num=100) - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - dx = xr[1]-xr[0] - top = np.sqrt(R**2-xplt**2) - bot = -np.sqrt(R**2-xplt**2) - - if R != 0: - ax.plot(xplt, top, xplt, bot, color=colorsphere,linewidth=1.5) - ax.fill_between(xplt,bot,top,color=colorsphere,alpha=0.5 ) - ax.arrow(0.,0.,np.sqrt(2.)*R/2.,np.sqrt(2.)*R/2.,head_width=0.,head_length=0.) - - if label: - ax.annotate(("$\sigma_1$=%3.3f mS/m")%(sig1*10.**(3.)), - xy=(0.,-R/2.), xycoords='data', - xytext=(0.,-R/2.), textcoords='data', - fontsize=14.) - ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), - xy=(0.,-1.5*R), xycoords='data', - xytext=(0.,-1.5*R), textcoords='data', - fontsize=14.) - ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.annotate(('$R$ = %1i m')%(R), - xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', - xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', - fontsize=14.) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - - else: - ax.set_xticklabels([]) - ax.set_yticklabels([]) - ax.text(-1.,-np.sqrt(R)/2.-10.,'$\sigma_1$',fontsize=14) - ax.text(-0.05,-R-10,'$\sigma_0$',fontsize=14) - ax.annotate(('$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m'), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.annotate(('$R$'), - xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', - xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', - fontsize=14.) - ax.set_xlabel('x',fontsize=12) - ax.set_ylabel('y',fontsize=12) - - else: - if label: - ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), - xy=(0.,-1.5*R), xycoords='data', - xytext=(0.,-1.5*R), textcoords='data', - fontsize=14.) - ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - - else: - ax.set_xticklabels([]) - ax.set_yticklabels([]) - ax.text(-0.05,-10,'$\sigma_0$',fontsize=14) - ax.text(xr.min()+np.abs(xr.max()-xr.min())/20., 0, '$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m', fontsize=14) - ax.set_xlabel('x',fontsize=12) - ax.set_ylabel('y',fontsize=12) - - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - [ax.arrow(xr.min(),_,np.abs(xr.max()-xr.min())/20.,0.,head_width=5.,head_length=2.,color='k') for _ in np.linspace(yr.min(),yr.max(),num=10)] - ax.patch.set_facecolor([0.4,0.7,0.4]) - ax.patch.set_alpha(0.2) - - ax.set_aspect('equal') - - - - return ax - -def get_Conductivity(XYZ,sig0,sig1,R): - ''' - Define the conductivity for each point of the space - ''' - x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] - r_view=r(x,y,z) - - ind0= (r_view>R) - ind1= (r_view<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Sigma = np.zeros_like(x) - - Sigma[ind0] = sig0 - Sigma[ind1] = sig1 - - return Sigma - - -def get_Potential(XYZ,sig0,sig1,R,E0): - - ''' - Function that returns the total, the primary and the secondary potentials, assumes an x-oriented inducing field and that the sphere is at the origin - :input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field - ''' - - x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] - - sig_cur = sigf(sig0,sig1) - - r_cur = r(x,y,z) # current radius - - ind0 = (r_cur > R) - ind1 = (r_cur <= R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Vt = np.zeros_like(x) - Vp = np.zeros_like(x) - Vs = np.zeros_like(x) - - Vt[ind0] = -E0*x[ind0]*(1.-sig_cur*R**3./r_cur[ind0]**3.) # total potential outside the sphere - Vt[ind1] = -E0*x[ind1]*3.*sig0/(sig1+2.*sig0) # inside the sphere - - - Vp = - E0*x # primary potential - - Vs = Vt - Vp # secondary potential - - return Vt,Vp,Vs - -#plot the primary potential on ax -def Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - Pplot = ax.pcolor(xr,yr,Vp.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Primary Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - -#plot the total potential on ax -def Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - - Pplot = ax.pcolor(xr,yr,Vt.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Total Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - -#plot the secondary potential on ax -def Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - Pplot = ax.pcolor(xr,yr,Vs.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Secondary Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - - -def get_ElectricField(XYZ,sig0,sig1,R,E0): - ''' - Function that returns the total, the primary and the secondary electric fields, - input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - r_cur=r(x,y,z) # current radius - - ind0= (r_cur>R) - ind1= (r_cur<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Ep = np.zeros(shape=(len(x),3)) - Ep[:,0] = E0 - - Et = np.zeros(shape=(len(x),3)) - - Et[ind0,0] = E0 + E0*R**3./(r_cur[ind0]**5.)*sigf(sig0,sig1)*(2.*x[ind0]**2.-y[ind0]**2.-z[ind0]**2.); - Et[ind0,1] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*y[ind0]*sigf(sig0,sig1); - Et[ind0,2] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*z[ind0]*sigf(sig0,sig1); - - Et[ind1,0] = 3.*sig0/(sig1+2.*sig0)*E0; - Et[ind1,1] = 0.; - Et[ind1,2] = 0.; - - Es = Et - Ep - - return Et, Ep, Es - -#plot the total electric field on ax -def Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax): - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - EtXr = Et[:,0].reshape(xr.size, yr.size) - EtYr = Et[:,1].reshape(xr.size, yr.size) - EtAmp = np.sqrt(Et[:,0]**2+Et[:,1]**2 + Et[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Eplot = ax.pcolor(xr,yr,EtAmp) - cb = plt.colorbar(Eplot,ax=ax) - cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,EtXr,EtYr,color='gray',linewidth=2.,density=0.75)#angles='xy',scale_units='xy',scale=0.05) - ax.set_title('Total Field',fontsize=ftsize_title) - - - return ax - -#plot the secondary electric field on ax -def Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax): - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - EsXr = Es[:,0].reshape(xr.size, yr.size) - EsYr = Es[:,1].reshape(xr.size, yr.size) - EsAmp = np.sqrt(Es[:,0]**2+Es[:,1]**2+Es[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Eplot = ax.pcolor(xr,yr,EsAmp) - cb = plt.colorbar(Eplot,ax=ax) - cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,EsXr,EsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=0.05) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Secondary Field',fontsize=ftsize_title) - - return ax - - -def get_Current(XYZ,sig0,sig1,R,Et,Ep,Es): - ''' - Function that returns the total, the primary and the secondary current densities, - :input: grid, outer sigma, inner sigma, radius of the sphere, total, the primary and the seconadry electric fields, - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - r_cur=r(x,y,z) - - ind0= (r_cur>R) - ind1= (r_cur<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Jt = np.zeros(shape=(len(x),3)) - J0 = np.zeros(shape=(len(x),3)) - Js = np.zeros(shape=(len(x),3)) - - - Jp = sig0*Ep - - Jt[ind0,:] = sig0*Et[ind0,:] - Jt[ind1,:] = sig1*Et[ind1,:] - - Js[ind0,:] = sig0*(Et[ind0,:]-Ep[ind0,:]) - Js[ind1,:] = sig1*Et[ind1,:]-sig0*Ep[ind1,:] - - return Jt,Jp,Js - -#plot the total currents density on ax -def Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax): - - Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - JtXr = Jt[:,0].reshape(xr.size, yr.size) - JtYr = Jt[:,1].reshape(xr.size, yr.size) - JtAmp = np.sqrt(Jt[:,0]**2+Jt[:,1]**2+Jt[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Jplot = ax.pcolor(xr,yr,JtAmp.reshape(xr.size,yr.size)) - cb = plt.colorbar(Jplot,ax=ax) - cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,JtXr,JtYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) - ax.set_title('Total Current Density',fontsize=ftsize_title) - - return ax - - -#plot the secondary currents density on ax -def Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax): - - Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - JsXr = Js[:,0].reshape(xr.size, yr.size) - JsYr = Js[:,1].reshape(xr.size, yr.size) - JsAmp = np.sqrt(Js[:,1]**2+Js[:,0]**2+Jt[:,2]**2).reshape(xr.size,yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Jplot = ax.pcolor(xr,yr,JsAmp.reshape(xr.size,yr.size)) - cb = plt.colorbar(Jplot,ax=ax) - cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,JsXr,JsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) - ax.set_title('Secondary Current Density',fontsize=ftsize_title) - - return ax - - -def get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep): - ''' - Function that returns the charges accumulation at the background/sphere interface, - :input: grid, outer sigma, inner sigma, radius of the sphere, total and the primary electric fields, - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - dx = x[1]-x[0] - - r_cur=r(x,y,z) - - ind0 = (r_cur > R) - ind1 = (r_cur < R) - ind2 = ((r_cur < (R+dx/2)) & (r_cur > (R-dx/2)) ) - - assert (ind0 + ind1 + ind2).all(), 'Some indicies not included' - - rho = np.zeros_like(x) - - rho[ind0] = 0 - rho[ind1] = 0 - rho[ind2] = epsilon_0*3.*Ep[ind2,0]*sigf(sig0,sig1)*x[ind2]/(np.sqrt(x[ind2]**2.+y[ind2]**2.)) - - return rho - -#Plot charges density on ax -def Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax): - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - rho = get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_aspect('equal') - Cplot = ax.pcolor(xr,yr,rho.reshape(xr.size, yr.size)) - cb1 = plt.colorbar(Cplot,ax=ax) - cb1.set_label(label= 'Charge Density ($C/m^2$)',size=ftsize_label) #weight='bold') - cb1.ax.tick_params(labelsize=ftsize_axis) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_title('Charges Density', fontsize=ftsize_title) - - return ax - -def MN_Potential_total(sig0,sig1,R,E0,start,end,nbmp,mn): - - ''' - Function that return array of midpoints electrodes, electrodes positions, - potentials differences for total and secondary potentials fields, unormalized and - normalized to electrodes distances. - sig0: background conductivity - sig1: sphere conductivity - R: Sphere's radius - E0: uniform E field value - start: start point for the profile start.shape = (2,) - end: end point for the profile end.shape = (2,) - nbmp: number of dipoles - mn: Space between the M and N electrodes - ''' - - #D: total distance from start to end - D = np.sqrt((start[0]-end[0])**2.+(start[1]-end[1])**2.) - - #MP: dipoles'midpoint positions (x,y) - MP = np.zeros(shape=(nbmp,2)) - MP[:,0] = np.linspace(start[0],end[0],nbmp) - MP[:,1] = np.linspace(start[1],end[1],nbmp) - - #Dipoles'Electrodes positions around each midpoints - EL = np.zeros(shape=(2*nbmp,2)) - for n in range(0,len(EL),2): - EL[n,0] = MP[n/2,0] - ((end[0]-start[0])/D)*mn/2. - EL[n+1,0] = MP[n/2,0] + ((end[0]-start[0])/D)*mn/2. - EL[n,1] = MP[n/2,1] - ((end[1]-start[1])/D)*mn/2. - EL[n+1,1] = MP[n/2,1] + ((end[1]-start[1])/D)*mn/2. - - VtEL = np.zeros(2*nbmp) #Total Potential (Vt-) at each electrode (-EL) - VsEL = np.zeros(2*nbmp) #Secondary Potential (Vt-) at each electrode (-EL) - dVtMP = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) - dVtMPn = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - dVsMP = np.zeros(nbmp) #Diffence (d-) of Secondaty Potential (Vt-) at each dipole (-MP) - dVsMPn = np.zeros(nbmp) #Diffence (d-) of Secondary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - dVpMP = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) - dVpMPn = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - - #Computing VtEL - for m in range(0,2*nbmp): - if (r(EL[m,0],EL[m,1],0) > R): - VtEL[m] = -E0*EL[m,0]*(1.-sigf(sig0,sig1)*R**3./r(EL[m,0],EL[m,1],0)**3.) - else: - VtEL[m] = -E0*EL[m,0]*3.*sig0/(sig1+2.*sig0) - - #Computing VsEL - VsEL = VtEL + E0*EL[:,0] - - #Computing dVtMP, dVsMP - for p in range(0,nbmp): - dVtMP[p] = VtEL[2*p]-VtEL[2*p+1] - dVtMPn[p] = dVtMP[p]/mn - dVsMP[p] = VsEL[2*p]-VsEL[2*p+1] - dVsMPn[p] = dVsMP[p]/mn - - return MP,EL,dVtMP,dVtMPn,dVsMP,dVsMPn - -#Compare the DC response of two configurations -def two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,nb_dipole,electrode_spacing,PlotOpt):#,linearcolor): - - #Define the mesh - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - #Defining the Profile - start = np.array([xstart,ystart]) - end = np.array([xend,yend]) - - #Calculating the data from the defined survey line for Configuration 0 and 1 - MP0,EL0,VtdMP0,VtdMPn0,VsdMP0,VsdMPn0 = MN_Potential_total(sig0,sig1,R0,E0,start,end,nb_dipole,electrode_spacing) - MP1,EL1,VtdMP1,VtdMPn1,VsdMP1,VsdMPn1 = MN_Potential_total(sig0,sig2,R1,E0,start,end,nb_dipole,electrode_spacing) - - - # Initializing the figure - fig = plt.figure(figsize=(20,20)) - ax0 = plt.subplot2grid((20,12), (0, 0),colspan=6,rowspan=6) - ax1 = plt.subplot2grid((20,12), (0, 6),colspan=6,rowspan=6) - ax2 = plt.subplot2grid((20,12), (16, 2), colspan=9,rowspan=4) - ax3 = plt.subplot2grid((20,12), (8, 0),colspan=6,rowspan=6) - ax4 = plt.subplot2grid((20,12), (8, 6),colspan=6,rowspan=6) - - #Plotting the Configuration 0 - ax0 = get_Setup(XYZ,sig0,sig1,R0,E0,ax0,True,[0.6,0.1,0.1]) - - #Plotting the Configuration 1 - ax1 = get_Setup(XYZ,sig0,sig2,R1,E0,ax1,True,[0.1,0.1,0.6]) - - #Plotting the Data (Legends) - ax2.set_title('Potential Differences',fontsize=ftsize_title) - ax2.set_ylabel('Potential difference ($V$)',fontsize=ftsize_label) - ax2.set_xlabel('Distance from start point ($m$)',fontsize=ftsize_label) - ax2.tick_params(labelsize=ftsize_axis) - ax2.grid() - - if PlotOpt == 'Total': - ax3= Plot_Total_Potential(XYZ,sig0,sig1,R0,E0,ax3) - ax4= Plot_Total_Potential(XYZ,sig0,sig2,R1,E0,ax4) - - #Plot the Data (from Configuration 0) - gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VtdMP0 - ,marker='o',color='blue',linewidth=3.,label ='Left Model Response' ) - - #Plot the Data (from Configuration 1) - gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VtdMP1 - ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) - ax2.legend(('Left Model Response','Right Model Response'),loc=4) - - elif PlotOpt == 'Secondary': - #plot the secondary potentials - ax3= Plot_Secondary_Potential(XYZ,sig0,sig1,R0,E0,ax3) - ax4= Plot_Secondary_Potential(XYZ,sig0,sig2,R1,E0,ax4) - - #Plot the data(from configuration 0) - gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VsdMP0,color='blue' - ,marker='o',linewidth=3.,label ='Left Model Response' ) - - - #Plot the Data (from Configuration 1) - gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VsdMP1 - ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) - ax2.legend(('Left Model Response','Right Model Response'),loc=4 ) - - else: - print('What dont you get? Total or Secondary?') - - #Legends - ax3.plot(MP0[:,0],MP0[:,1],color='gray') - Dip_Midpoint0 = ax3.scatter(MP0[:,0],MP0[:,1],color='black') - Electrodes0 = ax3.scatter(EL0[:,0],EL0[:,1],color='red') - ax3.legend([Dip_Midpoint0,Electrodes0], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) - - ax4.plot(MP1[:,0],MP1[:,1],color='gray') - Dip_Midpoint1 = ax4.scatter(MP1[:,0],MP1[:,1],color='black') - Electrodes1 = ax4.scatter(EL1[:,0],EL1[:,1],color='red') - ax4.legend([Dip_Midpoint1,Electrodes1], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) - - return fig - -#Function to visualise and compare any two meaningful plots for the sphere in a uniform backgound with an unifom Electric Field -def interact_conductiveSphere(R,log_sig0,log_sig1,Figure1a,Figure1b,Figure2a,Figure2b): - - sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) - E0 = 1. # inducing field strength in V/m - n = 100 #level of discretisation - xr = np.linspace(-200., 200., n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - - fig, ax = plt.subplots(1,2,figsize=(18,6)) - - #Setup figure 1 with options Configuration, Total or Secondary, - #then Potential, ElectricField, Current Density or Charges Density - if Figure1a == 'Configuration': - ax[0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0],True,[0.1,0.1,0.6]) - - elif Figure1a == 'Total': - - if Figure1b == 'Potential': - ax[0] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ElectricField': - ax[0] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'CurrentDensity': - ax[0] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ChargesDensity': - ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1a == 'Secondary': - - if Figure1b == 'Potential': - ax[0] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ElectricField': - ax[0] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'CurrentDensity': - ax[0] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ChargesDensity': - ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) - - - if Figure1a== 'Configuration': - ax[1] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - print 'While figure1 is plotting Configuration, figure2 plots the primary field' - - elif Figure2a == 'Total': - if Figure2b == 'Potential': - ax[1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ElectricField': - ax[1] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'CurrentDensity': - ax[1]=Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ChargesDensity': - ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) - - - elif Figure2a == 'Secondary': - if Figure2b == 'Potential': - ax[1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ElectricField': - ax[1] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'CurrentDensity': - ax[1] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ChargesDensity': - ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) - - plt.tight_layout(True) - plt.show() - -#Interactive Visualisation of the responses of two configurations to a (pseudo) DC resistivity survey -def interactive_two_configurations_comparison(log_sig0,log_sig1,log_sig2,R0,R1,xstart,ystart,xend,yend,dipole_number,electrode_spacing,matching_spheres_example): - - sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) - sig2 = 10.**log_sig2 - E0 = 1. # inducing field strength in V/m - n = 100 #level of discretisation - xr = np.linspace(-200., 200., n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - PlotOpt = 'Total' - - if matching_spheres_example: - sig0 = 10.**(-3) - sig1 = 10.**(-2) - sig2 = 1.310344828 * 10**(-3) - R0 = 20. - R1 = 40. - - two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) - - else: - two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) - - plt.tight_layout(True) - plt.show() - - - -if __name__ == '__main__': - sig0 = -3. # conductivity of the wholespace - sig1 = -1. # conductivity of the sphere - sig0, sig1 = conductivity_log_wrapper(sig0,sig1) - R = 50. # radius of the sphere - E0 = 1. # inducing field strength - n = 100 #level of discretisation - xr = np.linspace(-2.*R, 2.*R, n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - - fig, ax = plt.subplots(2,5,figsize=(50,10)) - ax[0,0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0,0],True,[0.6,0.1,0.1]) - ax[1,0] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1,0]) - ax[0,1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0,1]) - ax[1,1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1,1]) - ax[0,2] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0,2]) - ax[1,2] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1,2]) - ax[0,3] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0,3]) - ax[1,3] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1,3]) - ax[0,4] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[0,4]) - ax[1,4] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1,4]) - - - plt.show() - diff --git a/docs/examples/EM_FDEM_SusEffects.rst b/docs/examples/EM_FDEM_SusEffects.rst deleted file mode 100644 index 3e7dea80..00000000 --- a/docs/examples/EM_FDEM_SusEffects.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _examples_EM_FDEM_SusEffects: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - - -EM: FDEM: Effects of susceptibility -=================================== - -When airborne freqeuncy domain EM (AFEM) survey is flown over -the earth including significantly susceptible bodies (magnetite-rich rocks), -negative data is often observed in the real part of the lowest frequency -(e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization -occurs due to a susceptible body when the magnetic field is applied. - -To clarify what is happening in the earth when we are exciting the earth with -a loop source in the frequency domain we run three forward modelling: - - - F[:math:`\sigma`, :math:`\mu`]: Anomalous conductivity and susceptibility - - F[:math:`\sigma`, :math:`\mu_0`]: Anomalous conductivity - - F[:math:`\sigma_{air}`, :math:`\mu_0`]: primary field - -We plot vector magnetic fields in the earth. For secondary fields we provide -F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following -figure show both real and parts. - - - -.. plot:: - - from SimPEG import Examples - Examples.EM_FDEM_SusEffects.run() - -.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_SusEffects.py - :language: python - :linenos: diff --git a/docs/examples/MT_1D_analytic_nlayer_Earth.rst b/docs/examples/MT_1D_analytic_nlayer_Earth.rst deleted file mode 100644 index 834121a9..00000000 --- a/docs/examples/MT_1D_analytic_nlayer_Earth.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _examples_MT_1D_analytic_nlayer_Earth: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - -MT 1D analytic nlayer Earth -=========================== - -.. plot:: - - from SimPEG import Examples - Examples.MT_1D_analytic_nlayer_Earth.run() - -.. literalinclude:: ../../SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py - :language: python - :linenos: From 16c6cc8d74ab7ce4e61980cfd009cfedab44dc8f Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 22:17:34 -0700 Subject: [PATCH 48/52] Update speudo plot and allow app_res, app_con, volt --- SimPEG/DCIP/DCIPUtils.py | 80 +++++++++++++-------- SimPEG/Examples/DC_Forward_PseudoSection.py | 54 +++++++------- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index af94ad4e..9b637d82 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): +def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -179,7 +179,7 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): Input: :param d2D, z0 :switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole) - + :switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential) Output: :figure scatter plot overlayed on image @@ -221,25 +221,43 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): Cmid = (Tx[0][0] + Tx[1][0])/2 Pmid = (Rx[0][:,0] + Rx[1][:,0])/2 - # Compute pant leg of apparent rho - if stype == 'pdp': - leg = data * 2*np.pi * MA * ( MA + MN ) / MN + # Change output for dtype + if dtype == 'volt': - leg = np.log10(abs(1/leg)) + rho = np.hstack([rho,data]) - elif stype == 'dpdp': - leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + else: - leg = np.log10(abs(1/leg)) + # Compute pant leg of apparent rho + if stype == 'pdp': + + leg = data * 2*np.pi * MA * ( MA + MN ) / MN + + elif stype == 'dpdp': + + leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + + else: + print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """ + break + + + if dtype == 'appc': + + leg = np.log10(abs(1./leg)) + rho = np.hstack([rho,leg]) + + elif dtype == 'appr': + + leg = np.log10(abs(leg)) + rho = np.hstack([rho,leg]) + + else: + print """dtype must be 'appr' | 'appc' | 'volt' """ + break midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) - #TODO ... let stick to list then finally convert to array. - if dtype =="appr": - rho = np.hstack([rho,leg]) - elif dtype =="voltage": - rho = np.hstack([rho,data]) - ax = axs @@ -260,14 +278,20 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - cbar.set_label("App. Conductivity",size=12) + + if dtype == 'appc': + cbar.set_label("App.Cond",size=12) + elif dtype == 'appr': + cbar.set_label("App.Res.",size=12) + elif dtype == 'volt': + cbar.set_label("Potential (V)",size=12) # Plot apparent resistivity ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) #ax.set_xticklabels([]) #ax.set_yticklabels([]) - + plt.gca().set_aspect('equal', adjustable='box') @@ -516,7 +540,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ - Read DC survey and projects the coordinate system + Read DC survey and projects the coordinate system according to the flag = 'Xloc' | 'Yloc' | 'local' (default) In the 'local' system, station coordinates are referenced to distance from the first srcLoc[0].loc[0] @@ -575,19 +599,19 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): # Find A electrode along line vec, r = r_unit(x0,Tx[ii][0,0:2]) A = stn_id(vecTx,vec,r) - + # Find B electrode along line vec, r = r_unit(x0,Tx[ii][1,0:2]) B = stn_id(vecTx,vec,r) - + M = np.zeros(nrx) N = np.zeros(nrx) for kk in range(nrx): - + # Find all M electrodes along line vec, r = r_unit(x0,Rx[0][kk,0:2]) M[kk] = stn_id(vecTx,vec,r) - + # Find all N electrodes along line vec, r = r_unit(x0,Rx[1][kk,0:2]) N[kk] = stn_id(vecTx,vec,r) @@ -597,14 +621,14 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): B = Tx[ii][1,1] M = Rx[0][:,1] N = Rx[1][:,1] - + elif flag == 'Xloc': """ Copy the rx-tx locs""" A = Tx[ii][0,0] B = Tx[ii][1,0] M = Rx[0][:,0] N = Rx[1][:,0] - + Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]]) srcLists.append( DC.SrcDipole( [Rx], np.asarray([A,0,Tx[ii][0,2]]),np.asarray([B,0,Tx[ii][1,2]]) ) ) @@ -796,15 +820,15 @@ def readUBC_DC2Dpre(fileName): else: tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]] - + if zflag: rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]] - + else: rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan] # Check if there is data with the location - + d.append(temp[-1]) @@ -817,7 +841,7 @@ def readUBC_DC2Dpre(fileName): survey.dobs = np.asarray(d) return {'DCsurvey':survey} - + def readUBC_DC2DMesh(fileName): """ Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 904dcbd3..e1763da6 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -2,19 +2,27 @@ from SimPEG import Mesh, Utils, np, sp import SimPEG.DCIP as DC import time -def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): +def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', plotIt=True): """ DC Forward Simulation ===================== - Forward model conductive spheres in a half-space and plot a pseudo-section - + Forward model two conductive spheres in a half-space and plot a + pseudo-section. Assumes an infinite line source and measures along the + center of the spheres. + + INPUT: + loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] + radi = Radius of spheres [r1,r2] + param = Conductivity of background and two spheres [m0,m1,m2] + stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) + dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) Created by @fourndo on Mon Feb 01 19:28:06 2016 """ assert stype in ['pdp', 'dpdp'], "Source type (stype) must be pdp or dpdp (pole dipole or dipole dipole)" - + assert dtype in ['appr', 'appc', 'volt'], "Data type (dtype) must be appr (app res) or appc (app cond) or volt (potential)" if loc is None: loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]] @@ -27,7 +35,6 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # First we need to create a mesh and a model. - # This is our mesh dx = 5. @@ -52,15 +59,11 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Get index of the center indy = int(mesh.nCy/2) - # Plot the model for reference # Define core mesh extent xlim = 200 zlim = 100 - # Specify the survey type: "pdp" | "dpdp" - - # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh ends = [(-175,0),(175,0)] ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] @@ -82,7 +85,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): #Set boundary conditions mesh.setCellGradBC('neumann') - # Define the differential operators needed for the DC problem + # Define the linear system needed for the DC problem. We assume an infitite + # line source for simplicity. Div = mesh.faceDiv Grad = mesh.cellGrad Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) @@ -145,10 +149,9 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): print 'Forward completed' # Let's just convert the 3D format into 2D (distance along line) and plot - # [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc') survey2D.dobs =np.hstack(data) - # Here is an example for the first tx-rx array + if plotIt: import matplotlib.pyplot as plt fig = plt.figure(figsize=(7,7)) @@ -158,29 +161,29 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) ax.add_artist(circle1) ax.add_artist(circle2) - + dat = mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()])) - + ax.set_title('3-D model') plt.gca().set_aspect('equal', adjustable='box') - + plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') plt.xlim([-xlim,xlim]) plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - pos = ax.get_position() + + + pos = ax.get_position() ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height]) pos = ax.get_position() - cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set + cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal", ax = ax, ticks=np.linspace(np.log10(sig.min()), np.log10(sig.max()), 3), format="$10^{%.1f}$") cb.set_label("Conductivity (S/m)",size=12) - cb.ax.tick_params(labelsize=12) - + cb.ax.tick_params(labelsize=12) + # Second plot for the predicted apparent resistivity data ax2 = plt.subplot(2,1,2, aspect='equal') @@ -189,16 +192,15 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) ax2.add_artist(circle1) ax2.add_artist(circle2) - - + # Add the speudo section - dat = DC.plot_pseudoSection(survey2D,ax2,stype) + dat = DC.plot_pseudoSection(survey2D,ax2,stype=stype, dtype = dtype) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') # plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') # plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') - ax2.set_title('Apparent Conductivity data') - + ax2.set_title('Apparent Conductivity data') + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) plt.show() From 822f6d333d56499398942dcb9be3ab7eda2fe9ef Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 22:29:57 -0700 Subject: [PATCH 49/52] Minor revisions + remove trailing white spaces --- SimPEG/Maps.py | 22 ++++++++++++---------- SimPEG/Survey.py | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index f6b24f10..f17d2314 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -759,27 +759,29 @@ class PolyMap(IdentityMap): m = [\sigma_1, \sigma_2, c] - """ + Can take in an actInd vector to account for topography. + + """ def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None): IdentityMap.__init__(self, mesh) self.logSigma = logSigma self.order = order - self.normal = normal + self.normal = normal self.actInd = actInd - + if getattr(self, 'actInd', None) is None: self.actInd = range(self.mesh.nC) self.nC = self.mesh.nC - + else: - self.nC = len(self.actInd) - - slope = 1e4 - + self.nC = len(self.actInd) + + slope = 1e4 + @property def shape(self): return (self.nC, self.nP) - + @property def nP(self): if np.isscalar(self.order): @@ -818,7 +820,7 @@ class PolyMap(IdentityMap): f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z else: raise(Exception("Input for normal = X or Y or Z")) - + else: raise(Exception("Only supports 2D")) diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index f1ec8225..fbc88276 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -375,7 +375,7 @@ class BaseSurvey(object): self.dtrue = self.dpred(m, f=f) noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape) self.dobs = self.dtrue+noise - self.std = self.dobs*0. + std + self.std = self.dobs*0 + std return self.dobs class LinearSurvey(BaseSurvey): From d13c540be0e2cfa49fe137eaaba77270c7dd4219 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 09:25:20 -0700 Subject: [PATCH 50/52] Uppercase on class names. Add flag for Directive.Update_Wj. Remove trailing spaces. Remove old DC example. --- SimPEG/Directives.py | 23 +- SimPEG/Examples/DC_Forward_PseudoSection.py | 4 +- .../Examples/DC_PseudoSection_Simulation.py | 220 ------------------ SimPEG/Examples/Inversion_IRLS.py | 2 +- 4 files changed, 11 insertions(+), 238 deletions(-) delete mode 100644 SimPEG/Examples/DC_PseudoSection_Simulation.py diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 8f93c70a..98357492 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -285,7 +285,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # self.m_prev = self.invProb.m_current # return mref -class update_IRLS(InversionDirective): +class Update_IRLS(InversionDirective): eps_min = None factor = None @@ -333,18 +333,9 @@ class update_IRLS(InversionDirective): self.reg.gamma = self.phi_m_last / phim_new - - # TO DO: Check optimization class, data misfit not matching reality - #dpred = self.prob.fields(self.invProb.curModel) - #phid = self.invProb.dmisfit.eval(self.invProb.curModel) - #print self.survey.std[0] - #print phid - #print self.invProb.phi_d - #print self.invProb.phi_d_last - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d -class update_lin_PreCond(InversionDirective): +class Update_lin_PreCond(InversionDirective): def endIter(self): @@ -357,15 +348,17 @@ class update_lin_PreCond(InversionDirective): self.opt.approxHinv = PC print 'Updated pre-cond' -class update_Wj(InversionDirective): +class Update_Wj(InversionDirective): """ - Create approx-sensitivity base weighting + Create approx-sensitivity base weighting using the probing method """ - k = None + k = None # Number of probing cycles + itr = None # Iteration number to update Wj, or always update if None def endIter(self): - if self.opt.iter == 2: + if self.itr is None or self.itr == self.opt.iter: + m = self.invProb.curModel if self.k is None: self.k = int(self.survey.nD/10) diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index e1763da6..06858e38 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -7,10 +7,10 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p DC Forward Simulation ===================== - Forward model two conductive spheres in a half-space and plot a + Forward model two conductive spheres in a half-space and plot a pseudo-section. Assumes an infinite line source and measures along the center of the spheres. - + INPUT: loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] radi = Radius of spheres [r1,r2] diff --git a/SimPEG/Examples/DC_PseudoSection_Simulation.py b/SimPEG/Examples/DC_PseudoSection_Simulation.py deleted file mode 100644 index 3b9c4c05..00000000 --- a/SimPEG/Examples/DC_PseudoSection_Simulation.py +++ /dev/null @@ -1,220 +0,0 @@ -from SimPEG import * -# import simpegDCIP as DC -from SimPEG import DCIP as DC -import scipy.interpolate as interpolation -import matplotlib.pyplot as plt -import time -import re - -def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi=np.r_[25.,25.], param = np.r_[30.,30.,5], stype = 'dpdp', plotIt=True): - """ - - DC Forward Simulation - ===================== - - Forward model conductive spheres in a half-space and plot a pseudo-section - - Created on Mon Feb 01 19:28:06 2016 - - @fourndo - - """ - - def getIndicesSphere(center,radius,ccMesh): - """ - Creates a vector containing the sphere indices in the cell centers mesh. - Returns a tuple - - The sphere is defined by the points - - p0, describe the position of the center of the cell - - r, describe the radius of the sphere. - - ccMesh represents the cell-centered mesh - - The points p0 must live in the the same dimensional space as the mesh. - - """ - - # Validation: mesh and point (p0) live in the same dimensional space - dimMesh = np.size(ccMesh[0,:]) - assert len(center) == dimMesh, "Dimension mismatch. len(p0) != dimMesh" - - if dimMesh == 1: - # Define the reference points - - ind = np.abs(center[0] - ccMesh[:,0]) < radius - - elif dimMesh == 2: - # Define the reference points - - ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 ) < radius - - elif dimMesh == 3: - # Define the points - ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 + ( center[2] - ccMesh[:,2] )**2 ) < radius - - # Return a tuple - return ind - # First we need to create a mesh and a model. - - # This is our mesh - dx = 5. - - hxind = [(dx,15,-1.3), (dx, 75), (dx,15,1.3)] - hyind = [(dx,15,-1.3), (dx, 10), (dx,15,1.3)] - hzind = [(dx,15,-1.3),(dx, 15)] - - mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCN') - - - # Set background conductivity - model = np.ones(mesh.nC) * sig[0] - - # First anomaly - ind = getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) - model[ind] = sig[1] - - # Second anomaly - ind = getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) - model[ind] = sig[2] - - # Get index of the center - indy = int(mesh.nCy/2) - - - # Plot the model for reference - # Define core mesh extent - xlim = 200 - zlim = 125 - - # Specify the survey type: "pdp" | "dpdp" - - - # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh - ends = [(-175,0),(175,0)] - ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] - - # Snap the endpoints to the grid. Easier to create 2D section. - indx = Utils.closestPoints(mesh, ends ) - locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]] - - # We will handle the geometry of the survey for you and create all the combination of tx-rx along line - [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2]) - - # Define some global geometry - dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) - dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len - dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len - azm = np.arctan(dl_y/dl_x) - - #Set boundary conditions - mesh.setCellGradBC('neumann') - - # Define the differential operators needed for the DC problem - Div = mesh.faceDiv - Grad = mesh.cellGrad - Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) - - A = Div*Msig*Grad - - # Change one corner to deal with nullspace - A[0,0] = 1 - A = sp.csc_matrix(A) - - # We will solve the system iteratively, so a pre-conditioner is helpful - # This is simply a Jacobi preconditioner (inverse of the main diagonal) - dA = A.diagonal() - P = sp.spdiags(1/dA,0,A.shape[0],A.shape[0]) - - # Now we can solve the system for all the transmitters - # We want to store the data - data = [] - - # There is probably a more elegant way to do this, but we can just for-loop through the transmitters - for ii in range(len(Tx)): - - start_time = time.time() # Let's time the calculations - - #print("Transmitter %i / %i\r" % (ii+1,len(Tx))) - - # Select dipole locations for receiver - rxloc_M = np.asarray(Rx[ii][:,0:3]) - rxloc_N = np.asarray(Rx[ii][:,3:]) - - - # For usual cases "dpdp" or "gradient" - if not re.match(stype,'pdp'): - inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T ) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) - - else: - - # Create an "inifinity" pole - tx = np.squeeze(Tx[ii][:,0:1]) - tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2 - inds = Utils.closestPoints(mesh, np.c_[tx,tinf].T) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1] / mesh.vol[inds] ) - - - # Iterative Solve - Ainvb = sp.linalg.bicgstab(P*A,P*RHS, tol=1e-5) - - # We now have the potential everywhere - phi = mkvc(Ainvb[0]) - - # Solve for phi on pole locations - P1 = mesh.getInterpolationMat(rxloc_M, 'CC') - P2 = mesh.getInterpolationMat(rxloc_N, 'CC') - - # Compute the potential difference - dtemp = (P1*phi - P2*phi)*np.pi - - data.append( dtemp ) - print '\rTransmitter {0} of {1} -> Time:{2} sec'.format(ii,len(Tx),time.time()- start_time), - - print 'Transmitter {0} of {1}'.format(ii,len(Tx)) - print 'Forward completed' - - - # Let's just convert the 3D format into 2D (distance along line) and plot - [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(Tx,Rx) - - - # Here is an example for the first tx-rx array - if plotIt: - fig = plt.figure() - ax = plt.subplot(2,1,1, aspect='equal') - mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True) - ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m') - plt.gca().set_aspect('equal', adjustable='box') - - plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') - plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') - plt.xlim([-xlim,xlim]) - plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - ax = plt.subplot(2,1,2, aspect='equal') - - # Plot the location of the spheres for reference - circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) - circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) - ax.add_artist(circle1) - ax.add_artist(circle2) - - # Add the speudo section - DC.plot_pseudoSection(Tx2d,Rx2d,data,mesh.vectorNz[-1],stype) - - plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') - plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') - plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') - plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - plt.show() - - return fig, ax - -if __name__ == '__main__': - run() diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index a4d9204a..c236860d 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -96,7 +96,7 @@ def run(N=200, plotIt=True): beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() target = Directives.TargetMisfit() - IRLS =Directives.update_IRLS( phi_m_last = phim, phi_d_last = phid ) + IRLS =Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid ) inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) From e305600de516a8f8afa83f3a2b388e9be17111ee Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 13:09:28 -0700 Subject: [PATCH 51/52] Update example list. Add comments for the DC_Forward_PseudoSection example. Fix Z of pseudo section plot. --- SimPEG/DCIP/DCIPUtils.py | 2 +- SimPEG/Examples/DC_Forward_PseudoSection.py | 2 +- SimPEG/Examples/__init__.py | 3 +- docs/examples/DC_Forward_PseudoSection.rst | 10 +++++- docs/examples/DC_PseudoSection_Simulation.rst | 31 ------------------- 5 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 docs/examples/DC_PseudoSection_Simulation.rst diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 9b637d82..e94b930f 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -257,7 +257,7 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): break midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) - midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) + midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ]) ax = axs diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 06858e38..53467826 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -17,7 +17,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p param = Conductivity of background and two spheres [m0,m1,m2] stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) - Created by @fourndo on Mon Feb 01 19:28:06 2016 + Created by @fourndo """ diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index b06bb3a7..c67652a2 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -3,7 +3,6 @@ ##### AUTOIMPORTS ##### import DC_Analytic_Dipole import DC_Forward_PseudoSection -import DC_PseudoSection_Simulation import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace import EM_Schenkel_Morrison_Casing @@ -22,7 +21,7 @@ import Mesh_Tensor_Creation import MT_1D_ForwardAndInversion import MT_3D_Foward -__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] +__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] ##### AUTOIMPORTS ##### diff --git a/docs/examples/DC_Forward_PseudoSection.rst b/docs/examples/DC_Forward_PseudoSection.rst index 1a500cae..80cf0307 100644 --- a/docs/examples/DC_Forward_PseudoSection.rst +++ b/docs/examples/DC_Forward_PseudoSection.rst @@ -12,8 +12,16 @@ DC Forward Simulation ===================== -Forward model conductive spheres in a half-space and plot a pseudo-section +Forward model two conductive spheres in a half-space and plot a +pseudo-section. Assumes an infinite line source and measures along the +center of the spheres. +INPUT: +loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] +radi = Radius of spheres [r1,r2] +param = Conductivity of background and two spheres [m0,m1,m2] +stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) +dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) Created by @fourndo on Mon Feb 01 19:28:06 2016 diff --git a/docs/examples/DC_PseudoSection_Simulation.rst b/docs/examples/DC_PseudoSection_Simulation.rst deleted file mode 100644 index 1d4330a1..00000000 --- a/docs/examples/DC_PseudoSection_Simulation.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _examples_DC_PseudoSection_Simulation: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - - - -DC Forward Simulation -===================== - -Forward model conductive spheres in a half-space and plot a pseudo-section - -Created on Mon Feb 01 19:28:06 2016 - -@fourndo - - - -.. plot:: - - from SimPEG import Examples - Examples.DC_PseudoSection_Simulation.run() - -.. literalinclude:: ../../SimPEG/Examples/DC_PseudoSection_Simulation.py - :language: python - :linenos: From 3e4f47711c57b99f1164d7eab94920a079e7f576 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Thu, 7 Apr 2016 16:35:47 -0700 Subject: [PATCH 52/52] remove mutable arguments. --- SimPEG/Inversion.py | 4 ++- SimPEG/Mesh/TreeMesh.py | 12 +++++-- SimPEG/Mesh/View.py | 36 +++++++++++++++------ SimPEG/Utils/ModelBuilder.py | 18 ++++++++--- SimPEG/Utils/codeutils.py | 4 ++- tests/em/tdem/test_TDEM_forward_Analytic.py | 4 ++- 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 3fe9cfd0..3e92374f 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -33,7 +33,9 @@ class BaseInversion(object): self._directiveList = value self._directiveList.inversion = self - def __init__(self, invProb, directiveList=[], **kwargs): + def __init__(self, invProb, directiveList=None, **kwargs): + if directiveList is None: + directiveList = [] self.directiveList = directiveList Utils.setKwargs(self, **kwargs) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 02c23dee..2c75fda1 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -2131,10 +2131,16 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO): def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=True, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k', 'alpha':0.5}): + pcolorOpts=None, + streamOpts=None, + gridOpts=None): + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k', 'alpha':0.5} assert vType in ['CC','F','E'] assert self.dim == 3 diff --git a/SimPEG/Mesh/View.py b/SimPEG/Mesh/View.py index 089d7d9a..8eb22098 100644 --- a/SimPEG/Mesh/View.py +++ b/SimPEG/Mesh/View.py @@ -42,9 +42,9 @@ class TensorView(object): def plotImage(self, v, vType='CC', grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k'}, + pcolorOpts=None, + streamOpts=None, + gridOpts=None, numbering=True, annotationColor='w' ): """ @@ -84,6 +84,12 @@ class TensorView(object): M.plotImage(v, annotationColor='k', showIt=True) """ + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k'} if ax is None: fig = plt.figure() @@ -174,9 +180,9 @@ class TensorView(object): def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k', 'alpha':0.5} + pcolorOpts=None, + streamOpts=None, + gridOpts=None ): """ @@ -197,6 +203,12 @@ class TensorView(object): M.plotSlice(M.cellGrad*b, 'F', view='vec', grid=True, showIt=True, pcolorOpts={'alpha':0.8}) """ + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k', 'alpha':0.5} if type(vType) in [list, tuple]: assert ax is None, "cannot specify an axis to plot on with this function." fig, axs = plt.subplots(1,len(vType)) @@ -289,11 +301,17 @@ class TensorView(object): def _plotImage2D(self, v, vType='CC', grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k'} + pcolorOpts=None, + streamOpts=None, + gridOpts=None ): + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k'} vTypeOptsCC = ['N','CC','Fx','Fy','Ex','Ey'] vTypeOptsV = ['CCv','F','E'] vTypeOpts = vTypeOptsCC + vTypeOptsV diff --git a/SimPEG/Utils/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py index 435856f7..1b868fe5 100644 --- a/SimPEG/Utils/ModelBuilder.py +++ b/SimPEG/Utils/ModelBuilder.py @@ -88,12 +88,14 @@ def getIndicesBlock(p0,p1,ccMesh): # Return a tuple return ind -def defineBlock(ccMesh,p0,p1,vals=[0,1]): +def defineBlock(ccMesh,p0,p1,vals=None): """ Build a block with the conductivity specified by condVal. Returns an array. vals[0] conductivity of the block vals[1] conductivity of the ground """ + if vals is None: + vals = [0,1] sigma = np.zeros(ccMesh.shape[0]) + vals[1] ind = getIndicesBlock(p0,p1,ccMesh) @@ -101,7 +103,11 @@ def defineBlock(ccMesh,p0,p1,vals=[0,1]): return mkvc(sigma) -def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.): +def defineElipse(ccMesh, center=None, anisotropy=None, slope=10., theta=0.): + if center is None: + center = [0,0,0] + if anisotropy is None: + anisotropy = [1,1,1] G = ccMesh.copy() dim = ccMesh.shape[1] for i in range(dim): @@ -156,7 +162,7 @@ def getIndicesSphere(center,radius,ccMesh): # Return a tuple return ind -def defineTwoLayers(ccMesh,depth,vals=[0,1]): +def defineTwoLayers(ccMesh,depth,vals=None): """ Define a two layered model. Depth of the first layer must be specified. CondVals vector with the conductivity values of the layers. Eg: @@ -167,6 +173,8 @@ def defineTwoLayers(ccMesh,depth,vals=[0,1]): 0 depth zf 1st layer 2nd layer """ + if vals is None: + vals = [0,1] sigma = np.zeros(ccMesh.shape[0]) + vals[1] dim = np.size(ccMesh[0,:]) @@ -252,7 +260,7 @@ def layeredModel(ccMesh, layerTops, layerValues): -def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): +def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None): """ Create a random model by convolving a kernel with a uniformly distributed model. @@ -276,6 +284,8 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): """ + if bounds is None: + bounds = [0,1] if seed is None: seed = np.random.randint(1e3) diff --git a/SimPEG/Utils/codeutils.py b/SimPEG/Utils/codeutils.py index bfd00889..6151c540 100644 --- a/SimPEG/Utils/codeutils.py +++ b/SimPEG/Utils/codeutils.py @@ -55,8 +55,10 @@ def hook(obj, method, name=None, overwrite=False, silent=False): print 'Method '+name+' was not overwritten.' -def setKwargs(obj, ignore=[], **kwargs): +def setKwargs(obj, ignore=None, **kwargs): """Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist.""" + if ignore is None: + ignore = [] for attr in kwargs: if attr in ignore: continue diff --git a/tests/em/tdem/test_TDEM_forward_Analytic.py b/tests/em/tdem/test_TDEM_forward_Analytic.py index dc3696ef..7748b5fc 100644 --- a/tests/em/tdem/test_TDEM_forward_Analytic.py +++ b/tests/em/tdem/test_TDEM_forward_Analytic.py @@ -10,7 +10,9 @@ except ImportError, e: MumpsSolver = SolverLU -def halfSpaceProblemAnaDiff(meshType, sig_half=1e-2, rxOffset=50., bounds=[1e-5,1e-3], showIt=False): +def halfSpaceProblemAnaDiff(meshType, sig_half=1e-2, rxOffset=50., bounds=None, showIt=False): + if bounds is None: + bounds = [1e-5,1e-3] if meshType == 'CYL': cs, ncx, ncz, npad = 5., 30, 10, 15 hx = [(cs,ncx), (cs,npad,1.3)]