From df78f7b33aca3a0c77d202d1bd9c11b99f9aa64b Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 3 Feb 2016 14:35:03 -0800 Subject: [PATCH 001/168] 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 002/168] 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 003/168] 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 004/168] 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 005/168] 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 006/168] 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 007/168] 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 008/168] 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 009/168] 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 010/168] 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 011/168] 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 012/168] 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 013/168] 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 014/168] 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 015/168] 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 016/168] 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 017/168] 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 018/168] 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 019/168] 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 020/168] 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 021/168] 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 022/168] 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 023/168] 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 024/168] 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 025/168] 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 026/168] 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 027/168] 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 028/168] 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 029/168] 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 030/168] 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 031/168] 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 032/168] 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 033/168] 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 034/168] 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 5fb8cdb88c8608daf198ad8e9b351153119c7fbd Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 13:00:37 -0700 Subject: [PATCH 035/168] example casing forward simulation to calculate vertical current --- .../Examples/EM_Schenkel_Morrison_Casing.py | 269 ++++++++++++++++++ SimPEG/Examples/__init__.py | 3 +- docs/examples/EM_Schenkel_Morrison_Casing.rst | 52 ++++ 3 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 SimPEG/Examples/EM_Schenkel_Morrison_Casing.py create mode 100644 docs/examples/EM_Schenkel_Morrison_Casing.rst diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py new file mode 100644 index 00000000..ef51b25c --- /dev/null +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -0,0 +1,269 @@ +from SimPEG import * +from SimPEG.EM import FDEM, Analytics, mu_0 +import time + +try: + from pymatsolver import MumpsSolver + solver = MumpsSolver +except Exception: + solver = SolverLU + pass + +def run(plotIt=True): + """ + EM: Schenkel and Morrison Casing Model + ====================================== + + Here we will create and run a FDEM forward simulation based on the + Schenkel and Morrison Casing Model + + - `Schenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. + + .. _Schenkel, C. J., and H. F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 + + The model consists of: + - Air: Conductivity 1e-8 S/m, above z = 0 + - Background: conductivity 1e-2 S/m, below z = 0 + - Casing: conductivity 1e6 S/m + - 300m long + - radius of 0.1m + - thickness of 6e-3m + + Inside the casing, we take the same conductivity as the background. + + We are using an EM code to simulate DC, so we use frequency low enough + that the skin depth inside the casing is longer than the casing length (f + = 1e-6 Hz). The plot produced is of the current inside the casing. + + These results are shown in the SEG abstract by Yang et al., 2016: 3D DC + resistivity modeling of steel casing for reservoir monitoring using + equivalent resistor network. The solver used to produce these results and + achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ + + .. _pymatsolver: https://github.com/rowanc1/pymatsolver + + """ + + if plotIt: + import matplotlib.pylab as plt + + # ------------------ MODEL ------------------ + sigmaair = 1e-8 # air + sigmaback = 1e-2 # background + sigmacasing = 1e6 # casing + sigmainside = sigmaback # inside the casing + + + casing_t = 0.006 # 1cm thickness + casing_l = 300 # length of the casing + + casing_r = 0.1 + casing_a = casing_r - casing_t/2. # inner radius + casing_b = casing_r + casing_t/2. # outer radius + casing_z = np.r_[-casing_l,0.] + + + # ------------------ SURVEY PARAMETERS ------------------ + freqs = np.r_[1e-6] #[1e-1, 1, 5] # frequencies + dsz = -300 # down-hole z source location + src_loc = np.r_[0.,0.,dsz] + inf_loc = np.r_[0.,0.,1e4] + + print 'Skin Depth: ', [(500./np.sqrt(sigmaback*_)) for _ in freqs] + + + # ------------------ MESH ------------------ + # fine cells near well bore + csx1, csx2 = 2e-3, 60. + pfx1, pfx2 = 1.3, 1.3 + ncx1 = np.ceil(casing_b/csx1+2) + + # pad nicely to second cell size + npadx1 = np.floor(np.log(csx2/csx1) / np.log(pfx1)) + hx1a,hx1b = Utils.meshTensor([(csx1,ncx1)]),Utils.meshTensor([(csx1,npadx1,pfx1)]) + dx1 = sum(hx1a)+sum(hx1b) + dx1 = np.floor(dx1/csx2) + hx1b *= (dx1*csx2 - sum(hx1a))/sum(hx1b) + + # second chunk of mesh + dx2 = 300. # uniform mesh out to here + ncx2 = np.ceil((dx2 - dx1)/csx2) + npadx2 = 45 + hx2a, hx2b = Utils.meshTensor([(csx2,ncx2)]), Utils.meshTensor([(csx2,npadx2,pfx2)]) + hx = np.hstack([hx1a,hx1b,hx2a,hx2b]) + + # z-direction + csz = 0.05 + nza = 10 + ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0]/csz))+10, 68, 68 # cell size, number of core cells, number of padding cells in the x- direction + hz = Utils.meshTensor([(csz,npadzd,-1.3), (csz,ncz), (csz,npadzu,1.3)]) # vector of cell widths in the z-direction + + # Mesh + mesh = Mesh.CylMesh([hx,1.,hz], [0.,0.,-np.sum(hz[:npadzu+ncz-nza])]) + + print 'Mesh Extent xmax: %f,: zmin: %f, zmax: %f'%(mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max()) + print 'Number of cells', mesh.nC + + if plotIt is True: + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + ax.set_title('Simulation Mesh') + mesh.plotGrid(ax=ax) + plt.show() + + # Put the model on the mesh + sigWholespace = sigmaback*np.ones((mesh.nC)) + + sigBack = sigWholespace.copy() + sigBack[mesh.gridCC[:,2] > 0.] = sigmaair + + sigCasing = sigBack.copy() + iCasingZ = (mesh.gridCC[:,2] <= casing_z[1]) & (mesh.gridCC[:,2] >= casing_z[0]) + iCasingX = (mesh.gridCC[:,0] >= casing_a) & (mesh.gridCC[:,0] <= casing_b) + iCasing = iCasingX & iCasingZ + sigCasing[iCasing] = sigmacasing + + + if plotIt is True: + + # plotting parameters + xlim = np.r_[0., 0.2] + zlim = np.r_[-350., 10.] + clim_sig = np.r_[-8,6] + + # plot models + fig, ax = plt.subplots(1,1,figsize=(4,4)) + + f = plt.colorbar(mesh.plotImage(np.log10(sigCasing),ax=ax)[0], ax=ax) + ax.grid(which='both') + ax.set_title('Log_10 (Sigma)') + ax.set_xlim(xlim) + ax.set_ylim(zlim) + f.set_clim(clim_sig) + + plt.show() + + + # -------------- Sources -------------------- + # Define Custom Current Sources + + # surface source + sg_x = np.zeros(mesh.vnF[0],dtype=complex) + sg_y = np.zeros(mesh.vnF[1],dtype=complex) + sg_z = np.zeros(mesh.vnF[2],dtype=complex) + + nza = 2 # put the wire two cells above the surface + ncin = 2 + + # vertically directed wire + sgv_indx = (mesh.gridFz[:,0] > casing_a) & (mesh.gridFz[:,0] < casing_a + csx1) # hook it up to casing at the surface + sgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2) + sgv_ind = sgv_indx & sgv_indz + sg_z[sgv_ind] = -1. + + # horizontally directed wire + sgh_indx = (mesh.gridFx[:,0] > casing_a) & (mesh.gridFx[:,0] <= inf_loc[2]) + sgh_indz = (mesh.gridFx[:,2] > csz*(nza-0.5)) & (mesh.gridFx[:,2] < csz*(nza+0.5)) + sgh_ind = sgh_indx & sgh_indz + sg_x[sgh_ind] = -1. + + sgv2_indx = (mesh.gridFz[:,0] >= mesh.gridFx[sgh_ind,0].max()) & (mesh.gridFz[:,0] <= inf_loc[2]*1.2) # hook it up to casing at the surface + sgv2_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2) + sgv2_ind = sgv2_indx & sgv2_indz + sg_z[sgv2_ind] = 1. + + # assemble the source + sg = np.hstack([sg_x,sg_y,sg_z]) + sg_p = [FDEM.Src.RawVec_e([],_,sg/mesh.area) for _ in freqs] + + # downhole source + dg_x = np.zeros(mesh.vnF[0],dtype=complex) + dg_y = np.zeros(mesh.vnF[1],dtype=complex) + dg_z = np.zeros(mesh.vnF[2],dtype=complex) + + # vertically directed wire + dgv_indx = (mesh.gridFz[:,0] < csx1) # go through the center of the well + dgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] > dsz + csz/2.) + dgv_ind = dgv_indx & dgv_indz + dg_z[dgv_ind] = -1. + + # couple to the casing downhole + dgh_indx = mesh.gridFx[:,0] < casing_a + csx1 + dgh_indz = (mesh.gridFx[:,2] < dsz + csz) & (mesh.gridFx[:,2] >= dsz) + dgh_ind = dgh_indx & dgh_indz + dg_x[dgh_ind] = 1. + + # horizontal part at surface + dgh2_indx = mesh.gridFx[:,0] <= inf_loc[2]*1.2 + dgh2_indz = sgh_indz.copy() + dgh2_ind = dgh2_indx & dgh2_indz + dg_x[dgh2_ind] = -1. + + # vertical part at surface + dgv2_ind = sgv2_ind.copy() + dg_z[dgv2_ind] = 1. + + # assemble the source + dg = np.hstack([dg_x,dg_y,dg_z]) + dg_p = [FDEM.Src.RawVec_e([],_,dg/mesh.area) for _ in freqs] + + # ------------ Problem and Survey --------------- + survey = FDEM.Survey(sg_p + dg_p) + mapping = [('sigma', Maps.IdentityMap(mesh))] + problem = FDEM.Problem_h(mesh, mapping=mapping) + problem.pair(survey) + + # ------------- Solve --------------------------- + t0 = time.time() + fieldsCasing = problem.fields(sigCasing) + print 'Time to solve 2 sources', time.time() - t0 + + # Plot current + + # current density + jn0 = fieldsCasing[dg_p,'j'] + jn1 = fieldsCasing[sg_p,'j'] + + # current + in0 = [mesh.area*fieldsCasing[dg_p,'j'][:,i] for i in range(len(freqs))] + in1 = [mesh.area*fieldsCasing[sg_p,'j'][:,i] for i in range(len(freqs))] + + in0 = np.vstack(in0).T + in1 = np.vstack(in1).T + + # integrate to get z-current inside casing + inds_inx = (mesh.gridFz[:,0] >= casing_a) & (mesh.gridFz[:,0] <= casing_b) + inds_inz = (mesh.gridFz[:,2] >= dsz ) & (mesh.gridFz[:,2] <= 0) + inds_fz = inds_inx & inds_inz + + indsx = [False]*mesh.nFx + inds = list(indsx) + list(inds_fz) + + in0_in = in0[np.r_[inds]] + in1_in = in1[np.r_[inds]] + z_in = mesh.gridFz[inds_fz,2] + + in0_in = in0_in.reshape([in0_in.shape[0]/3,3]) + in1_in = in1_in.reshape([in1_in.shape[0]/3,3]) + z_in = z_in.reshape([z_in.shape[0]/3,3]) + + I0 = in0_in.sum(1).real + I1 = in1_in.sum(1).real + z_in = z_in[:,0] + + if plotIt is True: + fig, ax = plt.subplots(1,2,figsize=(12,4)) + + ax[0].plot(z_in,np.absolute(I0), z_in,np.absolute(I1)) + ax[0].legend(['top casing', 'bottom casing'],loc='best') + ax[0].set_title('Magnitude of Current') + + ax[1].semilogy(z_in,np.absolute(I0), z_in,np.absolute(I1)) + ax[1].legend(['top casing', 'bottom casing'],loc='best') + ax[1].set_title('Magnitude of Current') + ax[1].set_ylim([1e-2, 1.]) + + plt.show() + +if __name__ == '__main__': + run() + diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index cce22296..4647ad90 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -5,6 +5,7 @@ import DC_Analytic_Dipole import DC_Forward_PseudoSection import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace +import EM_Schenkel_Morrison_Casing import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 import Forward_BasicDirectCurrent @@ -19,7 +20,7 @@ import Mesh_Tensor_Creation import MT_1D_ForwardAndInversion import MT_3D_Foward -__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "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", "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_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/EM_Schenkel_Morrison_Casing.rst b/docs/examples/EM_Schenkel_Morrison_Casing.rst new file mode 100644 index 00000000..54e74dba --- /dev/null +++ b/docs/examples/EM_Schenkel_Morrison_Casing.rst @@ -0,0 +1,52 @@ +.. _examples_EM_Schenkel_Morrison_Casing: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Schenkel and Morrison Casing Model +================================== + + we will create and run a FDEM forward simulation based on the +nkel and Morrison Casing Model + +chenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. + +Schenkel, C. J., and H. F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 + +model consists of: +r: Conductivity 1e-8 S/m, above z = 0 +ckground: conductivity 1e-2 S/m, below z = 0 +sing: conductivity 1e6 S/m +- 300m long +- radius of 0.1m +- thickness of 6e-3m + +de the casing, we take the same conductivity as the background. + +re using an EM code to simulate DC, so we use frequency low enough + the skin depth inside the casing is longer than the casing length (f +-6 Hz). The plot produced is of the current inside the casing. + +e results are shown in the SEG abstract by Yang et al., 2016: 3D DC +stivity modeling of steel casing for reservoir monitoring using +valent resistor network. The solver used to produce these results and +eve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ + +pymatsolver: https://github.com/rowanc1/pymatsolver + + + +.. plot:: + + from SimPEG import Examples + Examples.EM_Schenkel_Morrison_Casing.run() + +.. literalinclude:: ../../SimPEG/Examples/EM_Schenkel_Morrison_Casing.py + :language: python + :linenos: From fbec011983e6939e8e8435a6cc827ed856135216 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 14:29:39 -0700 Subject: [PATCH 036/168] typo fix --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 2 +- docs/examples/EM_Schenkel_Morrison_Casing.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index ef51b25c..bcf277e1 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -19,7 +19,7 @@ def run(plotIt=True): - `Schenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. - .. _Schenkel, C. J., and H. F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 + .. _Schenkel, C.J., and H.F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 The model consists of: - Air: Conductivity 1e-8 S/m, above z = 0 diff --git a/docs/examples/EM_Schenkel_Morrison_Casing.rst b/docs/examples/EM_Schenkel_Morrison_Casing.rst index 54e74dba..6f356277 100644 --- a/docs/examples/EM_Schenkel_Morrison_Casing.rst +++ b/docs/examples/EM_Schenkel_Morrison_Casing.rst @@ -17,7 +17,7 @@ nkel and Morrison Casing Model chenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. -Schenkel, C. J., and H. F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 +Schenkel, C.J., and H.F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 model consists of: r: Conductivity 1e-8 S/m, above z = 0 From 7aa559921145503a5b42dd317cbdda0f47ca5bd1 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 14:41:45 -0700 Subject: [PATCH 037/168] improve the description --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 6 ++++-- docs/examples/EM_Schenkel_Morrison_Casing.rst | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index bcf277e1..7cfd4c9c 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -14,8 +14,10 @@ def run(plotIt=True): EM: Schenkel and Morrison Casing Model ====================================== - Here we will create and run a FDEM forward simulation based on the - Schenkel and Morrison Casing Model + Here we create and run a FDEM forward simulation to calculate the vertical + current inside a steel-cased. The model is based on the Schenkel and + Morrison Casing Model, and the results are used in a 2016 SEG abstract by + Yang et al. - `Schenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. diff --git a/docs/examples/EM_Schenkel_Morrison_Casing.rst b/docs/examples/EM_Schenkel_Morrison_Casing.rst index 6f356277..730b8507 100644 --- a/docs/examples/EM_Schenkel_Morrison_Casing.rst +++ b/docs/examples/EM_Schenkel_Morrison_Casing.rst @@ -12,8 +12,10 @@ Schenkel and Morrison Casing Model ================================== - we will create and run a FDEM forward simulation based on the -nkel and Morrison Casing Model + we create and run a FDEM forward simulation to calculate the vertical +ent inside a steel-cased. The model is based on the Schenkel and +ison Casing Model, and the results are used in a 2016 SEG abstract by + et al. chenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. From 824ce64c7e7e00f25fa1dd76bfcb88488f1de785 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 14:56:56 -0700 Subject: [PATCH 038/168] more descriptive titles --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index 7cfd4c9c..701c67d4 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -257,11 +257,11 @@ def run(plotIt=True): ax[0].plot(z_in,np.absolute(I0), z_in,np.absolute(I1)) ax[0].legend(['top casing', 'bottom casing'],loc='best') - ax[0].set_title('Magnitude of Current') + ax[0].set_title('Magnitude of Vertical Current in Casing') ax[1].semilogy(z_in,np.absolute(I0), z_in,np.absolute(I1)) ax[1].legend(['top casing', 'bottom casing'],loc='best') - ax[1].set_title('Magnitude of Current') + ax[1].set_title('Magnitude of Vertical Current in Casing') ax[1].set_ylim([1e-2, 1.]) plt.show() From b6438688d8224d136eaf993932a29d6b09ab4192 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 15:40:06 -0700 Subject: [PATCH 039/168] removed link for Schenkel paper (it seems to time-out) --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index 701c67d4..e9d37cfe 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -19,9 +19,8 @@ def run(plotIt=True): Morrison Casing Model, and the results are used in a 2016 SEG abstract by Yang et al. - - `Schenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. + - Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. - .. _Schenkel, C.J., and H.F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 The model consists of: - Air: Conductivity 1e-8 S/m, above z = 0 From 9c220ef37cde8c7faf1f67dfff622687c22e98dd Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 23:05:04 -0700 Subject: [PATCH 040/168] 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 c7883673bfc37323e04edfde71c7a731de34fc0a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 31 Mar 2016 09:36:55 -0700 Subject: [PATCH 041/168] added the figshare doi link for the example --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 5 +++++ docs/examples/EM_Schenkel_Morrison_Casing.rst | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index e9d37cfe..0a719ea7 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -43,6 +43,11 @@ def run(plotIt=True): .. _pymatsolver: https://github.com/rowanc1/pymatsolver + This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 + + If you would use this example for a code comparison, or build upon it, a + citation would be much appreciated! + """ if plotIt: diff --git a/docs/examples/EM_Schenkel_Morrison_Casing.rst b/docs/examples/EM_Schenkel_Morrison_Casing.rst index 730b8507..77bf1fa2 100644 --- a/docs/examples/EM_Schenkel_Morrison_Casing.rst +++ b/docs/examples/EM_Schenkel_Morrison_Casing.rst @@ -17,9 +17,8 @@ ent inside a steel-cased. The model is based on the Schenkel and ison Casing Model, and the results are used in a 2016 SEG abstract by et al. -chenkel, C.J., and H.F. Morrison, 1990`_, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. +henkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. -Schenkel, C.J., and H.F. Morrison, 1990: http://onlinelibrary.wiley.com/store/10.1111/j.1365-2478.1990.tb01868.x/asset/j.1365-2478.1990.tb01868.x.pdf?v=1&t=imdt3o85&s=38248af166c2887ed587d94c8ccafad30b480529 model consists of: r: Conductivity 1e-8 S/m, above z = 0 @@ -42,6 +41,11 @@ eve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ pymatsolver: https://github.com/rowanc1/pymatsolver + example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 + +ou would use this example for a code comparison, or build upon it, a +tion would be much appreciated! + .. plot:: From b531c162a229644f6daaa673ab69cd1e74df0da0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 31 Mar 2016 23:50:35 -0700 Subject: [PATCH 042/168] tab so we don't cut off the first characters in the docstring --- .../Examples/EM_Schenkel_Morrison_Casing.py | 52 +++++++++---------- docs/examples/EM_Schenkel_Morrison_Casing.rst | 52 +++++++++---------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index 0a719ea7..76af4a3d 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -11,42 +11,42 @@ except Exception: def run(plotIt=True): """ - EM: Schenkel and Morrison Casing Model - ====================================== + EM: Schenkel and Morrison Casing Model + ====================================== - Here we create and run a FDEM forward simulation to calculate the vertical - current inside a steel-cased. The model is based on the Schenkel and - Morrison Casing Model, and the results are used in a 2016 SEG abstract by - Yang et al. + Here we create and run a FDEM forward simulation to calculate the vertical + current inside a steel-cased. The model is based on the Schenkel and + Morrison Casing Model, and the results are used in a 2016 SEG abstract by + Yang et al. - - Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. + - Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. - The model consists of: - - Air: Conductivity 1e-8 S/m, above z = 0 - - Background: conductivity 1e-2 S/m, below z = 0 - - Casing: conductivity 1e6 S/m - - 300m long - - radius of 0.1m - - thickness of 6e-3m + The model consists of: + - Air: Conductivity 1e-8 S/m, above z = 0 + - Background: conductivity 1e-2 S/m, below z = 0 + - Casing: conductivity 1e6 S/m + - 300m long + - radius of 0.1m + - thickness of 6e-3m - Inside the casing, we take the same conductivity as the background. + Inside the casing, we take the same conductivity as the background. - We are using an EM code to simulate DC, so we use frequency low enough - that the skin depth inside the casing is longer than the casing length (f - = 1e-6 Hz). The plot produced is of the current inside the casing. + We are using an EM code to simulate DC, so we use frequency low enough + that the skin depth inside the casing is longer than the casing length (f + = 1e-6 Hz). The plot produced is of the current inside the casing. - These results are shown in the SEG abstract by Yang et al., 2016: 3D DC - resistivity modeling of steel casing for reservoir monitoring using - equivalent resistor network. The solver used to produce these results and - achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ + These results are shown in the SEG abstract by Yang et al., 2016: 3D DC + resistivity modeling of steel casing for reservoir monitoring using + equivalent resistor network. The solver used to produce these results and + achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ - .. _pymatsolver: https://github.com/rowanc1/pymatsolver + .. _pymatsolver: https://github.com/rowanc1/pymatsolver - This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 + This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 - If you would use this example for a code comparison, or build upon it, a - citation would be much appreciated! + If you would use this example for a code comparison, or build upon it, a + citation would be much appreciated! """ diff --git a/docs/examples/EM_Schenkel_Morrison_Casing.rst b/docs/examples/EM_Schenkel_Morrison_Casing.rst index 77bf1fa2..55f00168 100644 --- a/docs/examples/EM_Schenkel_Morrison_Casing.rst +++ b/docs/examples/EM_Schenkel_Morrison_Casing.rst @@ -9,42 +9,42 @@ .. --------------------------------- .. -Schenkel and Morrison Casing Model -================================== +EM: Schenkel and Morrison Casing Model +====================================== - we create and run a FDEM forward simulation to calculate the vertical -ent inside a steel-cased. The model is based on the Schenkel and -ison Casing Model, and the results are used in a 2016 SEG abstract by - et al. +Here we create and run a FDEM forward simulation to calculate the vertical +current inside a steel-cased. The model is based on the Schenkel and +Morrison Casing Model, and the results are used in a 2016 SEG abstract by +Yang et al. -henkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. +- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686. -model consists of: -r: Conductivity 1e-8 S/m, above z = 0 -ckground: conductivity 1e-2 S/m, below z = 0 -sing: conductivity 1e6 S/m -- 300m long -- radius of 0.1m -- thickness of 6e-3m +The model consists of: +- Air: Conductivity 1e-8 S/m, above z = 0 +- Background: conductivity 1e-2 S/m, below z = 0 +- Casing: conductivity 1e6 S/m + - 300m long + - radius of 0.1m + - thickness of 6e-3m -de the casing, we take the same conductivity as the background. +Inside the casing, we take the same conductivity as the background. -re using an EM code to simulate DC, so we use frequency low enough - the skin depth inside the casing is longer than the casing length (f --6 Hz). The plot produced is of the current inside the casing. +We are using an EM code to simulate DC, so we use frequency low enough +that the skin depth inside the casing is longer than the casing length (f += 1e-6 Hz). The plot produced is of the current inside the casing. -e results are shown in the SEG abstract by Yang et al., 2016: 3D DC -stivity modeling of steel casing for reservoir monitoring using -valent resistor network. The solver used to produce these results and -eve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ +These results are shown in the SEG abstract by Yang et al., 2016: 3D DC +resistivity modeling of steel casing for reservoir monitoring using +equivalent resistor network. The solver used to produce these results and +achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_ -pymatsolver: https://github.com/rowanc1/pymatsolver +.. _pymatsolver: https://github.com/rowanc1/pymatsolver - example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 +This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1 -ou would use this example for a code comparison, or build upon it, a -tion would be much appreciated! +If you would use this example for a code comparison, or build upon it, a +citation would be much appreciated! From 5d9d74693234102d6ce593577a2e2532ddea1c16 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 3 Apr 2016 10:42:28 -0700 Subject: [PATCH 043/168] 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 044/168] 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 045/168] 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 046/168] 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 047/168] 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 048/168] 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 049/168] 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 050/168] 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 051/168] 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 052/168] 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 053/168] 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 054/168] 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 055/168] 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 056/168] 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 fb60f45a3c5201992969a518ade32c64dd7ccee8 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 08:46:51 -0700 Subject: [PATCH 057/168] Fixed osr import in ediFilesUtils, moved into class which imports only on build up. Fixed the boolean error in Directives. --- SimPEG/Directives.py | 2 +- SimPEG/MT/Utils/ediFilesUtils.py | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 2ed27c20..7e412781 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -255,7 +255,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): 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: + 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: diff --git a/SimPEG/MT/Utils/ediFilesUtils.py b/SimPEG/MT/Utils/ediFilesUtils.py index 55818a87..cc8aef8a 100644 --- a/SimPEG/MT/Utils/ediFilesUtils.py +++ b/SimPEG/MT/Utils/ediFilesUtils.py @@ -7,17 +7,21 @@ from SimPEG.MT.Utils.dataUtils import rec2ndarr # Import modules import numpy as np import os, sys, re -try: - import osr -except ImportError as e: - print 'Could not import osr, missing the gdal package' - pass + class EDIimporter: """ A class to import EDIfiles. """ + # Import the coordinate projections + try: + import osr + except ImportError as e: + print 'Could not import osr, missing the gdal package' + raise e + + # Define data converters _impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit _impUnitSI2EDI = 1./_impUnitEDI2SI # ConvertZ[V/A] SI unit to Z[mV/km/nT] (as in EDI) @@ -26,8 +30,8 @@ class EDIimporter: comps = None # Hidden properties - _outEPSG = None - _2out = None + _outEPSG = None # Project info + _2out = None # The projection operator def __init__(self, EDIfilesList, compList=None, outEPSG=None): From f15a628136264bdcf49b86009204be7c81866450 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 09:01:30 -0700 Subject: [PATCH 058/168] Moved the osr import into the projection function. --- SimPEG/MT/Utils/ediFilesUtils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SimPEG/MT/Utils/ediFilesUtils.py b/SimPEG/MT/Utils/ediFilesUtils.py index cc8aef8a..d8f5e0ad 100644 --- a/SimPEG/MT/Utils/ediFilesUtils.py +++ b/SimPEG/MT/Utils/ediFilesUtils.py @@ -14,12 +14,7 @@ class EDIimporter: A class to import EDIfiles. """ - # Import the coordinate projections - try: - import osr - except ImportError as e: - print 'Could not import osr, missing the gdal package' - raise e + # Define data converters _impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit @@ -117,6 +112,12 @@ class EDIimporter: # nOutData=length(obj.data); # obj.data(nOutData+1:nOutData+length(TEMP.data),:) = TEMP.data; def _transfromPoints(self,longD,latD): + # Import the coordinate projections + try: + import osr + except ImportError as e: + print 'Could not import osr, missing the gdal package\nCan not project coordinates' + raise e # Coordinates convertor if self._2out is None: src = osr.SpatialReference() From d13c540be0e2cfa49fe137eaaba77270c7dd4219 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 09:25:20 -0700 Subject: [PATCH 059/168] 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 8a18e479ab5f31994c0e3641954b0dcdb94729ff Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 11:48:17 -0700 Subject: [PATCH 060/168] Removed the testProjDeriv (not needed, included in Jvec). --- tests/mt/test_Problem3D_againstAnalytic.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/mt/test_Problem3D_againstAnalytic.py b/tests/mt/test_Problem3D_againstAnalytic.py index f68e515f..602dbaeb 100644 --- a/tests/mt/test_Problem3D_againstAnalytic.py +++ b/tests/mt/test_Problem3D_againstAnalytic.py @@ -242,9 +242,6 @@ class TestAnalytics(unittest.TestCase): def test_appRes1en3(self):self.assertTrue(appResPhsHalfspace_eFrom_ps_Norm(1e-3)) def test_appPhs1en3(self):self.assertTrue(appResPhsHalfspace_eFrom_ps_Norm(1e-3,False)) - # Do a derivative test - def test_derivProj1(self):self.assertTrue(DerivProjfieldsTest(halfSpace(1e-2))) - # Do a derivative test of Jvec # def test_derivJvec_zxxr(self):self.assertTrue(DerivJvecTest(random(1e-2),'zxxr',.1)) # def test_derivJvec_zxxi(self):self.assertTrue(DerivJvecTest(random(1e-2),'zxxi',.1)) From e305600de516a8f8afa83f3a2b388e9be17111ee Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 13:09:28 -0700 Subject: [PATCH 061/168] 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 062/168] 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)] From 083742cb40923ebfd488f037b4730b4786c57df0 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Fri, 8 Apr 2016 09:34:30 -0700 Subject: [PATCH 063/168] Removing repeated directives --- SimPEG/Directives.py | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 7e412781..5e83dc82 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -222,7 +222,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): 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: + 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: @@ -237,40 +237,6 @@ 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.smoothModel == 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): From 90b030140899a84296dee5373b0e291d05bcd067 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Fri, 8 Apr 2016 09:40:26 -0700 Subject: [PATCH 064/168] Fixing bug in write out. --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 5e83dc82..d6cab804 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -222,7 +222,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): 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: + 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: From 35bac38c8bdaf49235d79adffef23b95d3d0485f Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 14 Apr 2016 22:41:47 -0700 Subject: [PATCH 065/168] working on mixed BC --- SimPEG/Mesh/DiffOperators.py | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index d0363001..b4a4b1ba 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -584,7 +584,67 @@ class DiffOperators(object): return Pbc, Pin, Pout + def getBCProjWF_simple(self, discretization='CC'): + """ + The weak form boundary condition projection matrices + when mixed boundary condition is used + + + """ + + if discretization is not 'CC': + raise NotImplementedError('Boundary conditions only implemented for CC discretization.') + + def projBC(n): + ij = ([0,n], [0,1]) + vals = [0,0] + vals[0] = 1 + vals[1] = 1 + return sp.csr_matrix((vals, ij), shape=(n+1,2)) + + def projDirichlet(n, bc): + bc = checkBC(bc) + ij = ([0,n], [0,1]) + vals = [0,0] + if(bc[0] == 'dirichlet'): + vals[0] = -1 + if(bc[1] == 'dirichlet'): + vals[1] = 1 + return sp.csr_matrix((vals, ij), shape=(n+1,2)) + + BC = [['dirichlet','dirichlet'],['dirichlet','dirichlet'],['dirichlet','dirichlet']] + n = self.vnC + indF = self.faceBoundaryInd + if(self.dim == 1): + Pbc = projDirichlet(n[0], BC[0]) + B = projBC(n[0]) + indF = indF[0] | indF[1] + Pbc = Pbc*sdiag(self.area[indF]) + + elif(self.dim == 2): + Pbc1 = sp.kron(speye(n[1]), projDirichlet(n[0], BC[0])) + Pbc2 = sp.kron(projDirichlet(n[1], BC[1]), speye(n[0])) + Pbc = sp.block_diag((Pbc1, Pbc2), format="csr") + B1 = sp.kron(speye(n[1]), projBC(n[0])) + B2 = sp.kron(projBC(n[1]), speye(n[0])) + B = sp.block_diag((B1, B2), format="csr") + indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3])] + Pbc = Pbc*sdiag(self.area[indF]) + + elif(self.dim == 3): + Pbc1 = kron3(speye(n[2]), speye(n[1]), projDirichlet(n[0], BC[0])) + Pbc2 = kron3(speye(n[2]), projDirichlet(n[1], BC[1]), speye(n[0])) + Pbc3 = kron3(projDirichlet(n[2], BC[2]), speye(n[1]), speye(n[0])) + Pbc = sp.block_diag((Pbc1, Pbc2, Pbc3), format="csr") + B1 = kron3(speye(n[2]), speye(n[1]), projBC(n[0])) + B2 = kron3(speye(n[2]), projBC(n[1]), speye(n[0])) + B3 = kron3(projBC(n[2]), speye(n[1]), speye(n[0])) + B = sp.block_diag((B1, B2, B3), format="csr") + indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3]), (indF[4] | indF[5])] + Pbc = Pbc*sdiag(self.area[indF]) + + return Pbc, B.T # --------------- Averaging --------------------- @property From 119bc801c7d880e1bd5223e6b31a3801cf866478 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 15 Apr 2016 14:51:19 -0700 Subject: [PATCH 066/168] start of DC refactor in EM/Static --- SimPEG/EM/Base.py | 13 ++++-- SimPEG/EM/FDEM/FieldsFDEM.py | 2 +- SimPEG/EM/FDEM/SrcFDEM.py | 1 - SimPEG/EM/FDEM/SurveyFDEM.py | 4 +- SimPEG/EM/Static/DC/FieldsDC.py | 72 +++++++++++++++++++++++++++++ SimPEG/EM/Static/DC/ProblemDC.py | 79 ++++++++++++++++++++++++++++++++ SimPEG/EM/Static/DC/RxDC.py | 66 ++++++++++++++++++++++++++ SimPEG/EM/Static/DC/SrcDC.py | 60 ++++++++++++++++++++++++ SimPEG/EM/Static/DC/SurveyDC.py | 18 ++++++++ SimPEG/EM/Static/DC/__init__.py | 5 ++ 10 files changed, 313 insertions(+), 7 deletions(-) create mode 100644 SimPEG/EM/Static/DC/FieldsDC.py create mode 100644 SimPEG/EM/Static/DC/ProblemDC.py create mode 100644 SimPEG/EM/Static/DC/RxDC.py create mode 100644 SimPEG/EM/Static/DC/SrcDC.py create mode 100644 SimPEG/EM/Static/DC/SurveyDC.py create mode 100644 SimPEG/EM/Static/DC/__init__.py diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index a16cdb91..dd349b43 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -1,6 +1,7 @@ from SimPEG import Survey, Problem, Utils, Models, Maps, PropMaps, np, sp, Solver as SimpegSolver from scipy.constants import mu_0 + class EMPropMap(Maps.PropMap): """ Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m) @@ -70,6 +71,12 @@ class BaseEMProblem(Problem.BaseProblem): self._Mf = self.mesh.getFaceInnerProduct() return self._Mf + @property + def Vol(self): + if getattr(self, '_Vol', None) is None: + self._Vol = Utils.sdiag(self.mesh.vol) + return self._Vol + # ----- Magnetic Permeability ----- # @property @@ -192,7 +199,7 @@ class BaseEMSurvey(Survey.BaseSurvey): self.srcList = srcList Survey.BaseSurvey.__init__(self, **kwargs) - def eval(self, u): + def eval(self, f): """ Project fields to receiver locations :param Fields u: fields object @@ -202,8 +209,8 @@ class BaseEMSurvey(Survey.BaseSurvey): data = Survey.Data(self) for src in self.srcList: for rx in src.rxList: - data[src, rx] = rx.eval(src, self.mesh, u) + data[src, rx] = rx.eval(src, self.mesh, f) return data - def evalDeriv(self, u): + def evalDeriv(self, f): raise Exception('Use Receivers to project fields deriv.') diff --git a/SimPEG/EM/FDEM/FieldsFDEM.py b/SimPEG/EM/FDEM/FieldsFDEM.py index e2193973..add2dbc9 100644 --- a/SimPEG/EM/FDEM/FieldsFDEM.py +++ b/SimPEG/EM/FDEM/FieldsFDEM.py @@ -181,7 +181,7 @@ class Fields_e(Fields): } def __init__(self, mesh, survey, **kwargs): - Fields.__init__(self,mesh,survey,**kwargs) + Fields.__init__(self, mesh, survey, **kwargs) def startup(self): self.prob = self.survey.prob diff --git a/SimPEG/EM/FDEM/SrcFDEM.py b/SimPEG/EM/FDEM/SrcFDEM.py index 87967dd5..f1dfef44 100644 --- a/SimPEG/EM/FDEM/SrcFDEM.py +++ b/SimPEG/EM/FDEM/SrcFDEM.py @@ -14,7 +14,6 @@ class BaseSrc(Survey.BaseSrc): def eval(self, prob): """ - Evaluate the source terms. - :math:`s_m` : magnetic source term - :math:`s_e` : electric source term diff --git a/SimPEG/EM/FDEM/SurveyFDEM.py b/SimPEG/EM/FDEM/SurveyFDEM.py index 1552a12c..9659ded6 100644 --- a/SimPEG/EM/FDEM/SurveyFDEM.py +++ b/SimPEG/EM/FDEM/SurveyFDEM.py @@ -63,9 +63,9 @@ class Rx(SimPEG.Survey.BaseRx): """Component projection (real/imag)""" return self.knownRxTypes[self.rxType][2] - def projGLoc(self, u): + def projGLoc(self, f): """Grid Location projection (e.g. Ex Fy ...)""" - return u._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1] + return f._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1] def eval(self, src, mesh, f): """ diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py new file mode 100644 index 00000000..9ca221a0 --- /dev/null +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -0,0 +1,72 @@ +import SimPEG +from SimPEG.Utils import Identity, Zero + +class Fields(SimPEG.Problem.Fields): + knownFields = {} + dtype = float + + def _phiDeriv(self, src, du_dm_v, v, adjoint=False): + if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None: + raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._phiDeriv_u(src, v, adjoint), self._phiDeriv_m(src, v, adjoint) + return np.array(self._phiDeriv_u(src, du_dm_v, adjoint) + self._phiDeriv_m(src, v, adjoint), dtype = complex) + + def _eDeriv(self, src, du_dm_v, v, adjoint=False): + if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None: + raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._eDeriv_u(src, v, adjoint), self._eDeriv_m(src, v, adjoint) + return np.array(self._eDeriv_u(src, du_dm_v, adjoint) + self._eDeriv_m(src, v, adjoint), dtype = complex) + + def _jDeriv(self, src, du_dm_v, v, adjoint=False): + if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None: + raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint) + return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex) + + +class Fields_CC(Fields): + knownFields = {'phiSolution':'CC'} + aliasFields = { + 'phi': ['phiSolution','CC','_phi'], + 'j' : ['phiSolution','F','_j'], + 'e' : ['phiSolution','F','_e'], + } + # primary - secondary + # CC variables + + def __init__(self, mesh, survey, **kwargs): + Fields.__init__(self, mesh, survey, **kwargs) + + def startup(self): + self.prob = self.survey.prob + + def _GLoc(self, fieldType): + if fieldType == 'phi': + return 'CC' + elif fieldType == 'e' or fieldType == 'j': + return 'F' + else: + raise Exception('Field type must be phi, e, j') + + def _phi(self, phiSolution, srcList): + return phiSolution + + def _phiDeriv_u(): + return Identity() + + def _phiDeriv_m(): + return Zero() + + def _j(self, phiSolution, srcList): + raise NotImplementedError + + def _e(self, phiSolution, srcList): + raise NotImplementedError + + diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py new file mode 100644 index 00000000..f8f80234 --- /dev/null +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -0,0 +1,79 @@ +from SimPEG import Problem +from SimPEG.EM.Base import BaseEMProblem +from SurveyDC import Survey +from FieldsDC import Fields, Fields_CC + +class BaseDCProblem(BaseEMProblem): + + surveyPair = Survey + fieldsPair = Fields + + def fields(self, m): + self.curModel = m + f = self.fieldsPair(self.mesh, self.survey) + A = self.getA() + self.Ainv = self.Solver(A, **self.solverOpts) + RHS = self.getRHS() + u = self.Ainv * RHS + Srcs = self.survey.srcList + f[Srcs, self._solutionType] = u + return f + + def Jvec(self, m, v, f=None): + raise NotImplementedError + + def Jtvec(self, m, v, f=None): + raise NotImplementedError + + def getSourceTerm(self): + """ + takes concept of source and turns it into a matrix + """ + raise NotImplementedError + + + +class Problem3D_CC(BaseDCProblem): + + _solutionType = 'phiSolution' + _formulation = 'HJ' # CC potentials means J is on faces + fieldsPair = Fields_CC + + def __init__(self, mesh, **kwargs): + BaseDCProblem.__init__(self, mesh, **kwargs) + + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + + D = self.mesh.faceDiv + MfRhoI = self.MfRhoI + V = self.Vol + A = D * ( MfRhoI * ( D.T * V ) ) + + if self._makeASymmetric is True: + return V.T * A + return A + + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + if self._makeASymmetric is True: + return self.Vol.T * RHS + return RHS + + diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py new file mode 100644 index 00000000..f9a2546d --- /dev/null +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -0,0 +1,66 @@ +import SimPEG +# from SimPEG.EM.Base import BaseEMSurvey +from SimPEG.Utils import Zero, closestPoints + +class BaseRx(SimPEG.Survey.BaseRx): + loc = None + rxType = None + + knownRxTypes = { + 'phi':['phi',None], + 'ex':['e','x'], + 'ey':['e','y'], + 'ez':['e','z'], + 'jx':['j','x'], + 'jy':['j','y'], + 'jz':['j','z'], + } + + def __init__(self, **kwargs): + SimPEG.Survey.BaseRx.__init__(locs, rxType, **kwargs) + + @property + def projField(self): + """Field Type projection (e.g. e b ...)""" + return self.knownRxTypes[self.rxType][0] + + def projGLoc(self, f): + """Grid Location projection (e.g. Ex Fy ...)""" + comp = self.knownRxTypes[self.rxType][1] + if comp is not None: + return f._GLoc(self.rxType[0]) + comp + return f._GLoc(self.rxType[0]) + + def eval(self, src, mesh, f): + P = self.getP(self.prob.mesh) + return P*f[src, self.projField] + +# DC.Rx.Dipole(locs) +class Dipole(BaseRx): + + def __init__(self, locsM, locsN, rxType = 'phi', **kwargs): + assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size' + self.locs = [locsM, locsN] + BaseRx.__init__(self) + + @property + def nD(self): + """Number of data in the receiver.""" + return self.locs[0].shape[0] + + def getP(self,mesh): + if mesh in self._Ps: + return self._Ps[mesh] + + P0 = mesh.getInterpolationMat(self.locs[0], self.projGLoc) + P1 = mesh.getInterpolationMat(self.locs[1], self.projGLoc) + P = P0 - P1 + + if self.storeProjections: + self._Ps[mesh] = P + return P + + +# class Pole(BaseRx): + + diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py new file mode 100644 index 00000000..61f490fa --- /dev/null +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -0,0 +1,60 @@ +import SimPEG +# from SimPEG.EM.Base import BaseEMSurvey +from SimPEG.Utils import Zero, closestPoints + +class BaseSrc(SimPEG.Survey.BaseSrc): + + current = 1 + loc = None + + def __init__(self, rxList, **kwargs): + SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs) + + def eval(self, prob): + raise NotImplementedError + + def evalDeriv(self, prob): + Zero() + + +class Dipole(BaseSrc): + + def __init__(self, rxList, locA, locB, **kwargs): + assert locA.shape == locB.shape, 'Shape of locA and locB should be the same' + self.loc = [locA, locB] + BaseSrc.__init__(self, rxList, **kwargs) + + def eval(self, prob): + if prob._formulation == 'HJ': + inds = closestPoints(prob.mesh, self.loc) + q = np.zeros(prob.mesh.nC) + q[inds] = self.current * np.r_[1., -1.] + elif prob._formulation == 'EB': + # TODO: there is probably a faster way to do this + # Utils.cellNodes , Utils.cellFaces, Utils.cellEdges + raise NotImplementedError + return q + + # def bc_contribution + + +# How to treat boundary conditions here + +class Pole(BaseSrc): + + def __init__(self, rxList, loc, **kwargs): + BaseSrc.__init__(self, rxList, loc=loc, **kwargs) + + def eval(self, prob): + if prob._formulation == 'HJ': + inds = closestPoints(prob.mesh, self.loc) + q = np.zeros(prob.mesh.nC) + q[inds] = self.current * np.r_[1.] + elif prob._formulation == 'EB': + # TODO: there is probably a faster way to do this + # Utils.cellNodes , Utils.cellFaces, Utils.cellEdges + raise NotImplementedError + return q + + # def bc_contribution + diff --git a/SimPEG/EM/Static/DC/SurveyDC.py b/SimPEG/EM/Static/DC/SurveyDC.py new file mode 100644 index 00000000..3b631bef --- /dev/null +++ b/SimPEG/EM/Static/DC/SurveyDC.py @@ -0,0 +1,18 @@ +import SimPEG +from SimPEG.EM.Base import BaseEMSurvey +from SimPEG import sp +from SimPEG.Utils import Zero, Identity +from RxDC import BaseRx +from SrcDC import BaseSrc + +class Survey(BaseEMSurvey): + rxPair = BaseRx + srcPair = BaseSrc + + def __init__(self, srcList, **kwargs): + self.srcList = srcList + BaseEMSurvey.__init__(self, srcList, **kwargs) + + + + diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py new file mode 100644 index 00000000..a3e1eba5 --- /dev/null +++ b/SimPEG/EM/Static/DC/__init__.py @@ -0,0 +1,5 @@ +from ProblemDC import Problem3D_CC +from SurveyDC import Survey +import SrcDC as Src #Pole +import RxDC as Rx +from FieldsDC import Fields_CC From 8739ba0f2072daabfe7e1a820beffa64ef00cb62 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 15 Apr 2016 16:53:43 -0700 Subject: [PATCH 067/168] working dc fwd --- SimPEG/EM/FDEM/FDEM.py | 1 + SimPEG/EM/Static/DC/ProblemDC.py | 28 +++++++++++++++++++++++++++- SimPEG/EM/Static/DC/RxDC.py | 25 ++++++++++++++----------- SimPEG/EM/Static/DC/SrcDC.py | 1 + SimPEG/EM/Static/__init__.py | 1 + SimPEG/EM/TDEM/SurveyTDEM.py | 12 ++++++------ SimPEG/EM/__init__.py | 1 + 7 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 SimPEG/EM/Static/__init__.py diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/FDEM.py index caca7602..1ac494b9 100644 --- a/SimPEG/EM/FDEM/FDEM.py +++ b/SimPEG/EM/FDEM/FDEM.py @@ -167,6 +167,7 @@ class BaseFDEMProblem(BaseEMProblem): for i, src in enumerate(Srcs): smi, sei = src.eval(self) + #Why are you adding? s_m[:,i] = s_m[:,i] + smi s_e[:,i] = s_e[:,i] + sei diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index f8f80234..f712e036 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -2,6 +2,7 @@ from SimPEG import Problem from SimPEG.EM.Base import BaseEMProblem from SurveyDC import Survey from FieldsDC import Fields, Fields_CC +import numpy as np class BaseDCProblem(BaseEMProblem): @@ -29,9 +30,28 @@ class BaseDCProblem(BaseEMProblem): """ takes concept of source and turns it into a matrix """ - raise NotImplementedError + """ + Evaluates the sources for a given frequency and puts them in matrix form + :param float freq: Frequency + :rtype: (numpy.ndarray, numpy.ndarray) + :return: s_m, s_e (nE or nF, nSrc) + """ + Srcs = self.survey.srcList + + if self._formulation is 'EB': + n = self.mesh.nN + # return NotImplementedError + + elif self._formulation is 'HJ': + n = self.mesh.nC + + q = np.zeros((n, len(Srcs))) + + for i, src in enumerate(Srcs): + q[:,i] = src.eval(self) + return q class Problem3D_CC(BaseDCProblem): @@ -63,6 +83,8 @@ class Problem3D_CC(BaseDCProblem): return V.T * A return A + def getADeriv(): + raise NotImplementedError def getRHS(self): """ @@ -76,4 +98,8 @@ class Problem3D_CC(BaseDCProblem): return self.Vol.T * RHS return RHS + def getRHSDeriv(): + raise NotImplementedError + + diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py index f9a2546d..9fbd05cb 100644 --- a/SimPEG/EM/Static/DC/RxDC.py +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -3,7 +3,7 @@ import SimPEG from SimPEG.Utils import Zero, closestPoints class BaseRx(SimPEG.Survey.BaseRx): - loc = None + locs = None rxType = None knownRxTypes = { @@ -16,8 +16,9 @@ class BaseRx(SimPEG.Survey.BaseRx): 'jz':['j','z'], } - def __init__(self, **kwargs): - SimPEG.Survey.BaseRx.__init__(locs, rxType, **kwargs) + def __init__(self, locs, rxType, **kwargs): + SimPEG.Survey.BaseRx.__init__(self, locs, rxType, **kwargs) + @property def projField(self): @@ -28,11 +29,11 @@ class BaseRx(SimPEG.Survey.BaseRx): """Grid Location projection (e.g. Ex Fy ...)""" comp = self.knownRxTypes[self.rxType][1] if comp is not None: - return f._GLoc(self.rxType[0]) + comp - return f._GLoc(self.rxType[0]) + return f._GLoc(self.rxType) + comp + return f._GLoc(self.rxType) def eval(self, src, mesh, f): - P = self.getP(self.prob.mesh) + P = self.getP(mesh, self.projGLoc(f)) return P*f[src, self.projField] # DC.Rx.Dipole(locs) @@ -40,24 +41,26 @@ class Dipole(BaseRx): def __init__(self, locsM, locsN, rxType = 'phi', **kwargs): assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size' - self.locs = [locsM, locsN] - BaseRx.__init__(self) + locs = [locsM, locsN] + # We may not need this ... + BaseRx.__init__(self, locs, rxType) @property def nD(self): """Number of data in the receiver.""" return self.locs[0].shape[0] - def getP(self,mesh): + def getP(self, mesh, Gloc): if mesh in self._Ps: return self._Ps[mesh] - P0 = mesh.getInterpolationMat(self.locs[0], self.projGLoc) - P1 = mesh.getInterpolationMat(self.locs[1], self.projGLoc) + P0 = mesh.getInterpolationMat(self.locs[0], Gloc) + P1 = mesh.getInterpolationMat(self.locs[1], Gloc) P = P0 - P1 if self.storeProjections: self._Ps[mesh] = P + return P diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 61f490fa..cc855118 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -1,6 +1,7 @@ import SimPEG # from SimPEG.EM.Base import BaseEMSurvey from SimPEG.Utils import Zero, closestPoints +import numpy as np class BaseSrc(SimPEG.Survey.BaseSrc): diff --git a/SimPEG/EM/Static/__init__.py b/SimPEG/EM/Static/__init__.py new file mode 100644 index 00000000..6ebc9df2 --- /dev/null +++ b/SimPEG/EM/Static/__init__.py @@ -0,0 +1 @@ +import DC diff --git a/SimPEG/EM/TDEM/SurveyTDEM.py b/SimPEG/EM/TDEM/SurveyTDEM.py index 4d04f0ae..9c9ed4b9 100644 --- a/SimPEG/EM/TDEM/SurveyTDEM.py +++ b/SimPEG/EM/TDEM/SurveyTDEM.py @@ -87,7 +87,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM): def getInitialFields(self, mesh): """Vertical magnetic dipole, magnetic vector potential""" if self.waveformType == "STEPOFF": - print ">> Step waveform: Non-zero initial condition" + print ">> Step waveform: Non-zero initial condition" if mesh._meshType is 'CYL': if mesh.isSymmetric: MVP = MagneticDipoleVectorPotential(self.loc, mesh, 'Ey') @@ -96,8 +96,8 @@ class SrcTDEM_VMD_MVP(SrcTDEM): elif mesh._meshType is 'TENSOR': MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez']) else: - raise Exception('Unknown mesh for VMD') - return {"b": mesh.edgeCurl*MVP} + raise Exception('Unknown mesh for VMD') + return {"b": mesh.edgeCurl*MVP} elif self.waveformType == "GENERAL": print ">> General waveform: Zero initial condition" return {"b": np.zeros(mesh.nF)} @@ -113,7 +113,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM): elif mesh._meshType is 'TENSOR': MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez']) else: - raise Exception('Unknown mesh for VMD') + raise Exception('Unknown mesh for VMD') return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP @@ -122,7 +122,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM): self.loc = loc self.radius = radius self.waveformType = waveformType - SrcTDEM.__init__(self,rxList) + SrcTDEM.__init__(self,rxList) def getInitialFields(self, mesh): """Circular Loop, magnetic vector potential""" @@ -153,7 +153,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM): elif mesh._meshType is 'TENSOR': MVP = MagneticLoopVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'], self.radius) else: - raise Exception('Unknown mesh for CircularLoop') + raise Exception('Unknown mesh for CircularLoop') return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP diff --git a/SimPEG/EM/__init__.py b/SimPEG/EM/__init__.py index 565f63a8..e42afbc5 100644 --- a/SimPEG/EM/__init__.py +++ b/SimPEG/EM/__init__.py @@ -1,5 +1,6 @@ import TDEM import FDEM +import Static import Base import Analytics import Utils From 28005dde45b4469fb6c9202c22b3b7b85dba37d6 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 15 Apr 2016 17:17:18 -0700 Subject: [PATCH 068/168] change minor bug for meshIO --- SimPEG/Mesh/MeshIO.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Mesh/MeshIO.py b/SimPEG/Mesh/MeshIO.py index 7501a66f..16d1b457 100644 --- a/SimPEG/Mesh/MeshIO.py +++ b/SimPEG/Mesh/MeshIO.py @@ -21,7 +21,7 @@ class TensorMeshIO(object): if '*' in seg: st = seg sp = seg.split('*') - re = np.array(sp[0],dtype=int)*(' ' + sp[1]) + re = int(sp[0])*(' ' + sp[1]) line = line.replace(st,re.strip()) return np.array(line.split(),dtype=float) From cd5339322eb545c0ef0759e56e3de756a86506ea Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 21 Apr 2016 11:00:20 -0700 Subject: [PATCH 069/168] sketch of DC --- SimPEG/EM/Static/DC/ProblemDC.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index f712e036..cc9c1ebb 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -83,8 +83,8 @@ class Problem3D_CC(BaseDCProblem): return V.T * A return A - def getADeriv(): - raise NotImplementedError + def getADeriv(self, u, v, adjoint= False): + def getRHS(self): """ From 2c09be9fc12a8046feadcc240f25b74dd2d439ae Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 21 Apr 2016 14:44:37 -0700 Subject: [PATCH 070/168] Working Mixed boundary conditions and testing ... --- tests/mesh/test_Mixed_boundaryPoisson.py | 395 +++++++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 tests/mesh/test_Mixed_boundaryPoisson.py diff --git a/tests/mesh/test_Mixed_boundaryPoisson.py b/tests/mesh/test_Mixed_boundaryPoisson.py new file mode 100644 index 00000000..7a15f36d --- /dev/null +++ b/tests/mesh/test_Mixed_boundaryPoisson.py @@ -0,0 +1,395 @@ +import numpy as np +import scipy.sparse as sp +import unittest +import matplotlib.pyplot as plt +from SimPEG import * + +MESHTYPES = ['uniformTensorMesh'] + +def getxBCyBC(mesh, alpha, beta, gamma): +# def getxBCyBC(mesh, alpha, beta, gamma): + """ + + """ + if mesh.dim == 1: #1D + if (len(alpha) != 2 or len(beta) != 2 or len(gamma) != 2): + raise Exception("Lenght of list, alpha should be 2") + fCCxm,fCCxp = mesh.cellBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + + xBC = np.r_[xBC_xm, xBC_xp] + yBC = np.r_[yBC_xm, yBC_xp] + + elif mesh.dim == 2: #2D + if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4): + raise Exception("Lenght of list, alpha should be 4") + + fCCxm,fCCxp,fCCym,fCCyp = mesh.cellBoundaryInd + fxm,fxp,fym,fyp = mesh.faceBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] + alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] + + h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym) + b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym) + a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp) + b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + xBC_ym = 0.5*a_ym + xBC_yp = 0.5*a_yp/b_yp + yBC_ym = 0.5*(1.-b_ym) + yBC_yp = 0.5*(1.-1./b_yp) + + sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]]) + sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]]) + + xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx] + xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy] + yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx] + yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy] + + xBC = np.r_[xBC_x, xBC_y] + yBC = np.r_[yBC_x, yBC_y] + + elif mesh.dim == 3: #3D + if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6): + raise Exception("Lenght of list, alpha should be 6") + fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd + fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + h_zm, h_zp = mesh.gridCC[fCCzm], mesh.gridCC[fCCzp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] + alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] + alpha_zm, beta_zm, gamma_zm = alpha[2], beta[2], gamma[2] + alpha_zp, beta_zp, gamma_zp = alpha[3], beta[3], gamma[3] + + h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym) + b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym) + a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp) + b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp) + + a_zm = gamma_zm/(0.5*alpha_zm-beta_zm/h_zm) + b_zm = (0.5*alpha_zm+beta_zm/h_zm)/(0.5*alpha_zm-beta_zm/h_zm) + a_zp = gamma_zp/(0.5*alpha_zp-beta_zp/h_zp) + b_zp = (0.5*alpha_zp+beta_zp/h_zp)/(0.5*alpha_zp-beta_zp/h_zp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + xBC_ym = 0.5*a_ym + xBC_yp = 0.5*a_yp/b_yp + yBC_ym = 0.5*(1.-b_ym) + yBC_yp = 0.5*(1.-1./b_yp) + xBC_zm = 0.5*a_zm + xBC_zp = 0.5*a_zp/b_zp + yBC_zm = 0.5*(1.-b_zm) + yBC_zp = 0.5*(1.-1./b_zp) + + sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]]) + sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]]) + sortindsfz = np.argsort(np.r_[np.arange(mesh.nFz)[fzm], np.arange(mesh.nFz)[fzp]]) + + xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx] + xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy] + xBC_z = np.r_[xBC_zm, xBC_zp][sortindsfz] + + yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx] + yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy] + yBC_z = np.r_[yBC_zm, yBC_zp][sortindsfz] + + xBC = np.r_[xBC_x, xBC_y, xBC_z] + yBC = np.r_[yBC_x, yBC_y, yBC_z] + + return xBC, yBC + +class Test1D_InhomogeneousMixed(Tests.OrderTest): + name = "1D - Mixed" + meshTypes = MESHTYPES + meshDimension = 1 + expectedOrders = 2 + meshSizes = [4, 8, 16, 32] + + def getError(self): + #Test function + phi_fun = lambda x: np.cos(np.pi*x) + j_fun = lambda x: np.pi*np.sin(np.pi*x) + phi_deriv = lambda x: -j_fun(x) + q_fun = lambda x: (np.pi**2)*np.cos(np.pi*x) + + xc_ana = phi_fun(self.M.gridCC) + q_ana = q_fun(self.M.gridCC) + j_ana = j_fun(self.M.gridFx) + + # Get boundary locations + vecN = self.M.vectorNx + vecC = self.M.vectorCCx + + # Setup Mixed B.C (alpha, beta, gamma) + alpha_xm, alpha_xp = 1., 1. + beta_xm, beta_xp = 1., 1. + alpha = np.r_[alpha_xm, alpha_xp] + beta = np.r_[beta_xm, beta_xp] + vecN = self.M.vectorNx + vecC = self.M.vectorCCx + phi_bc = phi_fun(vecN[[0,-1]]) + phi_deriv_bc = phi_deriv(vecN[[0,-1]]) + gamma = alpha*phi_bc + beta*phi_deriv_bc + x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + + + sigma = np.ones(self.M.nC) + Mfrho = self.M.getFaceInnerProduct(1./sigma) + MfrhoI = self.M.getFaceInnerProduct(1./sigma, invMat=True) + V = Utils.sdiag(self.M.vol) + Div = V*self.M.faceDiv + P_BC, B = self.M.getBCProjWF_simple() + q = q_fun(self.M.gridCC) + M = B*self.M.aveCC2F + G = Div.T - P_BC*Utils.sdiag(y_BC)*M + rhs = V*q + Div*MfrhoI*P_BC*x_BC + A = Div*MfrhoI*G + + if self.myTest == 'xc': + #TODO: fix the null space + Ainv = Solver(A) + xc = Ainv*rhs + err = np.linalg.norm((xc-xc_ana), np.inf) + else: + NotImplementedError + return err + + + def test_order(self): + print "==== Testing Mixed boudary conduction for CC-problem ====" + self.name = "1D" + self.myTest = 'xc' + self.orderTest() + +class Test2D_InhomogeneousMixed(Tests.OrderTest): + name = "2D - Mixed" + meshTypes = MESHTYPES + meshDimension = 2 + expectedOrders = 2 + meshSizes = [4, 8, 16, 32] + + def getError(self): + #Test function + phi_fun = lambda x: np.cos(np.pi*x[:,0])*np.cos(np.pi*x[:,1]) + j_funX = lambda x: +np.pi*np.sin(np.pi*x[:,0])*np.cos(np.pi*x[:,1]) + j_funY = lambda x: +np.pi*np.cos(np.pi*x[:,0])*np.sin(np.pi*x[:,1]) + phideriv_funX = lambda x: -j_funX(x) + phideriv_funY = lambda x: -j_funY(x) + q_fun = lambda x: +2*(np.pi**2)*phi_fun(x) + + xc_ana = phi_fun(self.M.gridCC) + q_ana = q_fun(self.M.gridCC) + jX_ana = j_funX(self.M.gridFx) + jY_ana = j_funY(self.M.gridFy) + j_ana = np.r_[jX_ana,jY_ana] + + # Get boundary locations + fxm,fxp,fym,fyp = self.M.faceBoundaryInd + gBFxm = self.M.gridFx[fxm,:] + gBFxp = self.M.gridFx[fxp,:] + gBFym = self.M.gridFy[fym,:] + gBFyp = self.M.gridFy[fyp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + alpha_xm, alpha_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + beta_xm, beta_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + alpha_ym, alpha_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + beta_ym, beta_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + + phi_bc_xm, phi_bc_xp = phi_fun(gBFxm), phi_fun(gBFxp) + phi_bc_ym, phi_bc_yp = phi_fun(gBFym), phi_fun(gBFyp) + + phiderivX_bc_xm, phiderivX_bc_xp = phideriv_funX(gBFxm), phideriv_funX(gBFxp) + phiderivY_bc_ym, phiderivY_bc_yp = phideriv_funY(gBFym), phideriv_funY(gBFyp) + + gamma_fun = lambda alpha, beta, phi, phi_deriv: alpha*phi + beta*phi_deriv + gamma_xm = gamma_fun(alpha_xm, beta_xm, phi_bc_xm, phiderivX_bc_xm) + gamma_xp = gamma_fun(alpha_xp, beta_xp, phi_bc_xp, phiderivX_bc_xp) + gamma_ym = gamma_fun(alpha_ym, beta_ym, phi_bc_ym, phiderivY_bc_ym) + gamma_yp = gamma_fun(alpha_yp, beta_yp, phi_bc_yp, phiderivY_bc_yp) + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] + + x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + + + sigma = np.ones(self.M.nC) + Mfrho = self.M.getFaceInnerProduct(1./sigma) + MfrhoI = self.M.getFaceInnerProduct(1./sigma, invMat=True) + V = Utils.sdiag(self.M.vol) + Div = V*self.M.faceDiv + P_BC, B = self.M.getBCProjWF_simple() + q = q_fun(self.M.gridCC) + M = B*self.M.aveCC2F + G = Div.T - P_BC*Utils.sdiag(y_BC)*M + rhs = V*q + Div*MfrhoI*P_BC*x_BC + A = Div*MfrhoI*G + + if self.myTest == 'xc': + Ainv = Solver(A) + xc = Ainv*rhs + err = np.linalg.norm((xc-xc_ana), np.inf) + else: + NotImplementedError + return err + + + def test_order(self): + print "==== Testing Mixed boudary conduction for CC-problem ====" + self.name = "2D" + self.myTest = 'xc' + self.orderTest() + +class Test3D_InhomogeneousMixed(Tests.OrderTest): + name = "3D - Mixed" + meshTypes = MESHTYPES + meshDimension = 3 + expectedOrders = 2 + meshSizes = [4, 8, 16] + + def getError(self): + #Test function + phi_fun = lambda x: np.cos(np.pi*x[:,0])*np.cos(np.pi*x[:,1])*np.cos(np.pi*x[:,2]) + j_funX = lambda x: +np.pi*np.sin(np.pi*x[:,0])*np.cos(np.pi*x[:,1])*np.cos(np.pi*x[:,2]) + j_funY = lambda x: +np.pi*np.cos(np.pi*x[:,0])*np.sin(np.pi*x[:,1])*np.cos(np.pi*x[:,2]) + j_funZ = lambda x: +np.pi*np.cos(np.pi*x[:,0])*np.cos(np.pi*x[:,1])*np.sin(np.pi*x[:,2]) + + phideriv_funX = lambda x: -j_funX(x) + phideriv_funY = lambda x: -j_funY(x) + phideriv_funZ = lambda x: -j_funZ(x) + + q_fun = lambda x: 3*(np.pi**2)*phi_fun(x) + + xc_ana = phi_fun(self.M.gridCC) + q_ana = q_fun(self.M.gridCC) + jX_ana = j_funX(self.M.gridFx) + jY_ana = j_funY(self.M.gridFy) + j_ana = np.r_[jX_ana,jY_ana,jY_ana] + + # Get boundary locations + fxm,fxp,fym,fyp,fzm,fzp = self.M.faceBoundaryInd + gBFxm = self.M.gridFx[fxm,:] + gBFxp = self.M.gridFx[fxp,:] + gBFym = self.M.gridFy[fym,:] + gBFyp = self.M.gridFy[fyp,:] + gBFzm = self.M.gridFz[fzm,:] + gBFzp = self.M.gridFz[fzp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + alpha_xm, alpha_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + beta_xm, beta_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + alpha_ym, alpha_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + beta_ym, beta_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + alpha_zm, alpha_zp = np.ones_like(gBFzm[:,1]), np.ones_like(gBFzp[:,1]) + beta_zm, beta_zp = np.ones_like(gBFzm[:,1]), np.ones_like(gBFzp[:,1]) + + + phi_bc_xm, phi_bc_xp = phi_fun(gBFxm), phi_fun(gBFxp) + phi_bc_ym, phi_bc_yp = phi_fun(gBFym), phi_fun(gBFyp) + phi_bc_zm, phi_bc_zp = phi_fun(gBFzm), phi_fun(gBFzp) + + phiderivX_bc_xm, phiderivX_bc_xp = phideriv_funX(gBFxm), phideriv_funX(gBFxp) + phiderivY_bc_ym, phiderivY_bc_yp = phideriv_funY(gBFym), phideriv_funY(gBFyp) + phiderivY_bc_zm, phiderivY_bc_zp = phideriv_funY(gBFzm), phideriv_funY(gBFzp) + + gamma_fun = lambda alpha, beta, phi, phi_deriv: alpha*phi + beta*phi_deriv + gamma_xm = gamma_fun(alpha_xm, beta_xm, phi_bc_xm, phiderivX_bc_xm) + gamma_xp = gamma_fun(alpha_xp, beta_xp, phi_bc_xp, phiderivX_bc_xp) + gamma_ym = gamma_fun(alpha_ym, beta_ym, phi_bc_ym, phiderivY_bc_ym) + gamma_yp = gamma_fun(alpha_yp, beta_yp, phi_bc_yp, phiderivY_bc_yp) + gamma_zm = gamma_fun(alpha_zm, beta_zm, phi_bc_zm, phiderivY_bc_zm) + gamma_zp = gamma_fun(alpha_zp, beta_zp, phi_bc_zp, phiderivY_bc_zp) + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] + + x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + + + sigma = np.ones(self.M.nC) + Mfrho = self.M.getFaceInnerProduct(1./sigma) + MfrhoI = self.M.getFaceInnerProduct(1./sigma, invMat=True) + V = Utils.sdiag(self.M.vol) + Div = V*self.M.faceDiv + P_BC, B = self.M.getBCProjWF_simple() + q = q_fun(self.M.gridCC) + M = B*self.M.aveCC2F + G = Div.T - P_BC*Utils.sdiag(y_BC)*M + rhs = V*q + Div*MfrhoI*P_BC*x_BC + A = Div*MfrhoI*G + + if self.myTest == 'xc': + #TODO: fix the null space + Ainv = Solver(A) + xc = Ainv*rhs + err = np.linalg.norm((xc-xc_ana), np.inf) + else: + NotImplementedError + return err + + + def test_order(self): + print "==== Testing Mixed boudary conduction for CC-problem ====" + self.name = "3D" + self.myTest = 'xc' + self.orderTest() + + + +if __name__ == '__main__': + unittest.main() From 606488d152591605876c1f767b0c0afcac355034 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 21 Apr 2016 21:58:40 -0700 Subject: [PATCH 071/168] Major fix to IRLS. --- SimPEG/DCIP/DCIPUtils.py | 152 +++++++++++++++++++----------- SimPEG/Directives.py | 4 +- SimPEG/Examples/Inversion_IRLS.py | 6 +- SimPEG/Regularization.py | 12 +-- 4 files changed, 109 insertions(+), 65 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index e94b930f..97c30e89 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='dpdp', dtype="appc", clim=None): +def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -192,9 +192,6 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): from scipy.interpolate import griddata import pylab as plt - # Set depth to 0 for now - z0 = 0. - # Pre-allocate midx = [] midz = [] @@ -259,38 +256,53 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ]) - ax = axs - # Grid points 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') - + + # Scale the color scheme if clim == None: vmin, vmax = rho.min(), rho.max() else: vmin, vmax = clim[0], clim[1] + # Plot data 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) + ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, vmin = vmin, vmax = vmax) + plt.gca().tick_params(axis='both', which='major', labelsize=8) - 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) + if contour is not None: + plt.contour(grid_x,grid_z,grid_rho,levels = contour,colors = 'r', vmin = vmin, vmax = vmax) + + # Add scatter points + axs.scatter(midx,midz,s=10,c=rho.T, vmin = vmin, vmax = vmax) + + if colorbar: + + if dtype == 'volt': + cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal") - # Plot apparent resistivity - ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + else: + cbar = plt.colorbar(ph, ax = axs, 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) + + if cblabel: + 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) - #ax.set_xticklabels([]) - #ax.set_yticklabels([]) + + + if not axlabel: + axs.set_xticklabels([]) + axs.set_yticklabels([]) plt.gca().set_aspect('equal', adjustable='box') @@ -448,15 +460,15 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): survey = DC.SurveyDC(SrcList) return survey, Tx, Rx -def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): +def writeUBC_DCobs(fileName, DCsurvey, dtype='3D', stype='SURFACE', iptype = 0): """ Write UBC GIF DCIP 2D or 3D observation file Input: - :string fileName -> including path where the file is written out - :DCsurvey -> DC survey class object - :string dtype -> either '2D' | '3D' - :string stype -> either 'SURFACE' | 'GENERAL' + :string fileName -> including path where the file is written out + :DCsurvey DC survey class object + :string dtype -> either '2D' | '3D' + :string stype -> either 'SURFACE' | 'GENERAL' Output: :param UBC2D-Data file @@ -471,10 +483,16 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'" assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'" - + fid = open(fileName,'w') - fid.write('! ' + stype + ' FORMAT\n') - + + + if iptype!=0: + fid.write('IPTYPE=%i\n'%iptype) + + else: + fid.write('! ' + stype + ' FORMAT\n') + count = 0 for ii in range(DCsurvey.nSrc): @@ -498,7 +516,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): B = np.repeat(tx[0,1],M.shape[0],axis=0) M = M[:,0] N = N[:,0] - + np.savetxt(fid, np.c_[A, B, M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') @@ -506,18 +524,25 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): if stype == 'SURFACE': - fid.writelines("%e " % ii for ii in mkvc(tx[0,:])) + fid.writelines("%f " % ii for ii in mkvc(tx[0,:])) M = M[:,0] N = N[:,0] if stype == 'GENERAL': + # Flip sign for z-elevation to depth + tx[2::2,:] = -tx[2::2,:] + fid.writelines("%e " % ii for ii in mkvc(tx[::2,:])) M = M[:,0::2] N = N[:,0::2] + # Flip sign for z-elevation to depth + M[:,1::2] = -M[:,1::2] + N[:,1::2] = -N[:,1::2] + fid.write('%i\n'% nD) - np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') + np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%f',delimiter=' ',newline='\n') if dtype=='3D': @@ -529,11 +554,12 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): if stype == 'GENERAL': - fid.writelines("%e " % ii for ii in mkvc(tx)) + fid.writelines("%e " % ii for ii in mkvc(tx[0:3,:])) fid.write('%i\n'% nD) np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') - + fid.write('\n') + count += nD fid.close() @@ -640,51 +666,59 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): DCsurvey2D.std = np.asarray(DCsurvey.std) return DCsurvey2D - -def readUBC_DC3Dobs(fileName): + +def readUBC_DC3Dobs(fileName, dtype = 'DC'): """ - Read UBC GIF DCIP 3D observation file and generate survey + Read UBC GIF IP 3D observation file and generate survey Input: :param fileName, path to the UBC GIF 3D obs file Output: - :param DCIPsurvey + :param IPsurvey :return - Created on Mon April 6th, 2015 - @author: dominiquef """ - + zflag = True # Flag for z value provided + # Load file - obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') - + if dtype == 'IP': + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE') + + elif dtype == 'DC': + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') + + else: + print "dtype must be 'DC'(default) | 'IP'" + # Pre-allocate srcLists = [] Rx = [] d = [] wd = [] - zflag = True # Flag for z value provided + # Countdown for number of obs/tx count = 0 for ii in range(obsfile.shape[0]): + # Skip if blank line if not obsfile[ii]: continue - # First line is transmitter with number of receivers + # First line or end of a transmitter block, read transmitter info if count==0: - - temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T) + # Read the line + temp = (np.fromstring(obsfile[ii], dtype=float, sep=' ').T) count = int(temp[-1]) # Check if z value is provided, if False -> nan if len(temp)==5: - tx = np.r_[temp[0:2],np.nan,temp[0:2],np.nan] - zflag = False + tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan] + + zflag = False # Pass on the flag to the receiver loc else: tx = temp[:-1] @@ -692,8 +726,16 @@ def readUBC_DC3Dobs(fileName): rx = [] continue - temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') + temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string + # Filter out negative IP +# if temp[-2] < 0: +# count = count -1 +# print "Negative!" +# +# else: + + # If the Z-location is provided, otherwise put nan if zflag: rx.append(temp[:-2]) @@ -703,7 +745,7 @@ def readUBC_DC3Dobs(fileName): wd.append(temp[-1]) else: - rx.append(np.r_[temp[0:2],np.nan,temp[0:2],np.nan] ) + rx.append(np.r_[temp[0:2],np.nan,temp[2:4],np.nan] ) # Check if there is data with the location if len(temp)==6: d.append(temp[-2]) @@ -711,7 +753,7 @@ def readUBC_DC3Dobs(fileName): count = count -1 - # Reach the end of transmitter block + # Reach the end of transmitter block, append the src, rx and continue if count == 0: rx = np.asarray(rx) Rx = DC.RxDipole(rx[:,:3],rx[:,3:]) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index b694a2f1..193911fe 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -300,6 +300,8 @@ class Update_IRLS(InversionDirective): self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + self.reg._W = None + class Update_lin_PreCond(InversionDirective): @@ -308,7 +310,7 @@ class Update_lin_PreCond(InversionDirective): 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. + 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' diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index c236860d..06ef4be4 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -86,12 +86,12 @@ def run(N=200, plotIt=True): #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.eps_p = 5e-2 + reg.eps_q = 1e-2 reg.norms = [0., 0., 2., 2.] reg.wght = wr - opt = Optimization.ProjectedGNCG(maxIter=5 ,lower=-2.,upper=2., maxIterCG= 100, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 195e6203..ed1039ec 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -728,14 +728,14 @@ class Sparse(Simple): @property def W(self): """Full regularization matrix W""" - #if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - #self._W = sp.vstack(wlist) - return sp.vstack(wlist) + if getattr(self, '_W', None) is None: + wlist = (self.Wsmall, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W def R(self, f_m , eps, exponent): - eta = (eps**(1-exponent/2.))**0.5 - r = eta / (f_m**2.+ 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 From 79183ae9fbfc06d0e0575d1b90a12f35dfc5b91c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 22 Apr 2016 16:05:43 -0700 Subject: [PATCH 072/168] fIX MESH io --- SimPEG/Mesh/MeshIO.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimPEG/Mesh/MeshIO.py b/SimPEG/Mesh/MeshIO.py index 7501a66f..1c042237 100644 --- a/SimPEG/Mesh/MeshIO.py +++ b/SimPEG/Mesh/MeshIO.py @@ -21,10 +21,9 @@ class TensorMeshIO(object): if '*' in seg: st = seg sp = seg.split('*') - re = np.array(sp[0],dtype=int)*(' ' + sp[1]) + re = int(sp[0])*(' ' + sp[1]) line = line.replace(st,re.strip()) return np.array(line.split(),dtype=float) - # Read the file as line strings, remove lines with comment = ! msh = np.genfromtxt(fileName,delimiter='\n',dtype=np.str,comments='!') From 5ec6e79a39ab85549f71f03394411953e41df8a4 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 22 Apr 2016 17:47:36 -0700 Subject: [PATCH 073/168] MfRhoIDeriv --- SimPEG/EM/Base.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index dd349b43..0df18cdb 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -190,7 +190,13 @@ class BaseEMProblem(Problem.BaseProblem): """ Derivative of :code:`MfRhoI` with respect to the model. """ - return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv + + dMfRhoI_dI = -self.MfRhoI**2 + dMf_drho = self.mesh.getEdgeInnerProductDeriv(self.curModel.rho)(u) + drho_dm = self.curModel.rhoDeriv + return dMfRhoI_dI * ( dMf_drho * ( drho_dm)) + + # return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv class BaseEMSurvey(Survey.BaseSurvey): From 8775364d8f4b56d92e801c2df99cca4614a3a74a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 22 Apr 2016 17:48:26 -0700 Subject: [PATCH 074/168] start of the sketch of Jvec (not to be trusted yet!) --- SimPEG/EM/Static/DC/ProblemDC.py | 42 +++++++++++++++-- SimPEG/EM/Static/DC/RxDC.py | 2 +- SimPEG/EM/Static/DC/Utils.py | 38 ++++++++++++++++ SimPEG/EM/Static/DC/__init__.py | 1 + tests/em/static/__init__.py | 12 +++++ tests/em/static/test_DC.py | 77 ++++++++++++++++++++++++++++++++ tests/em/static/test_DC_deriv.py | 0 7 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 SimPEG/EM/Static/DC/Utils.py create mode 100644 tests/em/static/__init__.py create mode 100644 tests/em/static/test_DC.py create mode 100644 tests/em/static/test_DC_deriv.py diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index cc9c1ebb..602ce3d8 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -3,6 +3,7 @@ from SimPEG.EM.Base import BaseEMProblem from SurveyDC import Survey from FieldsDC import Fields, Fields_CC import numpy as np +from SimPEG.Utils import Zero class BaseDCProblem(BaseEMProblem): @@ -21,7 +22,30 @@ class BaseDCProblem(BaseEMProblem): return f def Jvec(self, m, v, f=None): - raise NotImplementedError + + if f is None: + f = self.fields(m) + + self.curModel = m + + Jv = self.dataPair(self.survey) #same size as the data + + A = self.getA() + Ainv = self.Solver(A, **self.solverOpts) + + for src in self.survey.srcList: + u_src = f[src, self._solutionType] # solution vector + dA_dm_v = self.getADeriv(u_src, v) + dRHS_dm_v = self.getRHSDeriv(src, v) + print type(dA_dm_v + dRHS_dm_v), (dA_dm_v + dRHS_dm_v).shape + du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v ) + + for rx in src.rxList: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + Ainv.clean() + return Utils.mkvc(Jv) def Jtvec(self, m, v, f=None): raise NotImplementedError @@ -85,6 +109,18 @@ class Problem3D_CC(BaseDCProblem): def getADeriv(self, u, v, adjoint= False): + D = self.mesh.faceDiv + MfRhoIDeriv = self.MfRhoIDeriv + V = self.Vol + + if adjoint: + if self._makeASymmetric is True: + v = V * v + return V.T * ( D * ( MfRhoIDeriv(D * v) ) ) + + if self._makeASymmetric is True: + return V.T * ( D * ( MfRhoIDeriv( * D.T * ( V * u ) ) * v ) ) + return D * ( MfRhoIDeriv( D.T * ( V * v ) ) ) def getRHS(self): """ @@ -98,8 +134,8 @@ class Problem3D_CC(BaseDCProblem): return self.Vol.T * RHS return RHS - def getRHSDeriv(): - raise NotImplementedError + def getRHSDeriv(self, src, v, adjoint=False): + return Zero() diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py index 9fbd05cb..779ffde0 100644 --- a/SimPEG/EM/Static/DC/RxDC.py +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -48,7 +48,7 @@ class Dipole(BaseRx): @property def nD(self): """Number of data in the receiver.""" - return self.locs[0].shape[0] + return int(self.locs[0].size / 2) def getP(self, mesh, Gloc): if mesh in self._Ps: diff --git a/SimPEG/EM/Static/DC/Utils.py b/SimPEG/EM/Static/DC/Utils.py new file mode 100644 index 00000000..647590cc --- /dev/null +++ b/SimPEG/EM/Static/DC/Utils.py @@ -0,0 +1,38 @@ +import numpy as np + +def WennerSrcList(nElecs, aSpacing, in2D=False, plotIt=False): + + import SimPEG.EM.Static.DC as DC + + elocs = np.arange(0,aSpacing*nElecs,aSpacing) + elocs -= (nElecs*aSpacing - aSpacing)/2 + space = 1 + WENNER = np.zeros((0,),dtype=int) + for ii in range(nElecs): + for jj in range(nElecs): + test = np.r_[jj,jj+space,jj+space*2,jj+space*3] + if np.any(test >= nElecs): + break + WENNER = np.r_[WENNER, test] + space += 1 + WENNER = WENNER.reshape((-1,4)) + + + if plotIt: + for i, s in enumerate('rbkg'): + plt.plot(elocs[WENNER[:,i]],s+'.') + plt.show() + + # Create sources and receivers + i = 0 + if in2D: + getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0] + else: + getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0, 0] + srcList = [] + for i in range(WENNER.shape[0]): + rx = DC.Rx.Dipole(getLoc(i,1),getLoc(i,2)) + src = DC.Src.Dipole([rx], getLoc(i,0),getLoc(i,3)) + srcList += [src] + + return srcList diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py index a3e1eba5..dcc40764 100644 --- a/SimPEG/EM/Static/DC/__init__.py +++ b/SimPEG/EM/Static/DC/__init__.py @@ -3,3 +3,4 @@ from SurveyDC import Survey import SrcDC as Src #Pole import RxDC as Rx from FieldsDC import Fields_CC +import Utils diff --git a/tests/em/static/__init__.py b/tests/em/static/__init__.py new file mode 100644 index 00000000..420388ef --- /dev/null +++ b/tests/em/static/__init__.py @@ -0,0 +1,12 @@ +import os +import glob +import unittest + +if __name__ == '__main__': + test_file_strings = glob.glob('test_*.py') + module_strings = [str[0:len(str)-3] for str in test_file_strings] + suites = [unittest.defaultTestLoader.loadTestsFromName(str) for str + in module_strings] + testSuite = unittest.TestSuite(suites) + + unittest.TextTestRunner(verbosity=2).run(testSuite) diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py new file mode 100644 index 00000000..a25dcf67 --- /dev/null +++ b/tests/em/static/test_DC.py @@ -0,0 +1,77 @@ +import unittest +from SimPEG import * +import SimPEG.EM.Static.DC as DC + + +class DCProblemTests(unittest.TestCase): + + def setUp(self): + + aSpacing=2.5 + nElecs=10 + + surveySize = nElecs*aSpacing - aSpacing + cs = surveySize/nElecs/4 + + mesh = Mesh.TensorMesh([ + [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], + [(cs,3, -1.3),(cs,3,1.3)], + # [(cs,5, -1.3),(cs,10)] + ],'CN') + + srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) + survey = DC.Survey(srcList) + problem = DC.Problem3D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) + problem.pair(survey) + + mSynth = np.ones(mesh.nC) + survey.makeSyntheticData(mSynth) + + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) + + + def test_massMatrices(self): + Gu = np.random.rand(self.mesh.nF) + def derChk(m): + self.p.curModel = m + return [self.p.Msig * Gu, self.p.dMdsig(Gu)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/em/static/test_DC_deriv.py b/tests/em/static/test_DC_deriv.py new file mode 100644 index 00000000..e69de29b From 64b94861a01b2fcfe3da7a2c76df6ac97ff0b41c Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 22 Apr 2016 23:09:31 -0700 Subject: [PATCH 075/168] working on DC problem CC and N --- SimPEG/EM/Analytics/DC.py | 34 +++++++++++ SimPEG/EM/Analytics/__init__.py | 1 + SimPEG/EM/Static/DC/FieldsDC.py | 37 ++++++++++++ SimPEG/EM/Static/DC/ProblemDC.py | 100 +++++++++++++++++++++++++------ SimPEG/Mesh/MeshIO.py | 2 +- 5 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 SimPEG/EM/Analytics/DC.py diff --git a/SimPEG/EM/Analytics/DC.py b/SimPEG/EM/Analytics/DC.py new file mode 100644 index 00000000..69d17090 --- /dev/null +++ b/SimPEG/EM/Analytics/DC.py @@ -0,0 +1,34 @@ +import numpy as np +from scipy.constants import mu_0, pi + +def DCAnalytic(txloc, rxlocs, sigma, flag="wholespace"): + """ + Analytic solution for electric potential from a postive pole + + Input variables: + + txloc = a xyz location of A (+) electrode (np.r_[xa, ya, za]) + + rxlocs = [M, N] + M: xyz locations of M (+) electrode (np.c_[xmlocs, ymlocs, zmlocs]) + N: xyz locations of N (-) electrode (np.c_[xnlocs, ynlocs, znlocs]) + + sigma = conductivity (either float or complex) + flag = "wholsespace" or "halfspace" + + """ + M = rxlocs[0] + N = rxlocs[1] + + rM = np.sqrt( (M[:,0]-txloc[0])**2 + (M[:,1]-txloc[1])**2 + (M[:,2]-txloc[1])**2 ) + rN = np.sqrt( (N[:,0]-txloc[0])**2 + (N[:,1]-txloc[1])**2 + (N[:,2]-txloc[1])**2 ) + + phiM = 1./(4*np.pi*rM*sigma) + phiN = 1./(4*np.pi*rN*sigma) + phi = phiM - phiN + + if flag == "halfspace": + phi *= 2 + + return phi + diff --git a/SimPEG/EM/Analytics/__init__.py b/SimPEG/EM/Analytics/__init__.py index 5b7a8851..d251f205 100644 --- a/SimPEG/EM/Analytics/__init__.py +++ b/SimPEG/EM/Analytics/__init__.py @@ -1,3 +1,4 @@ from TDEM import hzAnalyticDipoleT from FDEM import hzAnalyticDipoleF from FDEMcasing import * +from DC import DCAnalytic diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py index 9ca221a0..91b243c1 100644 --- a/SimPEG/EM/Static/DC/FieldsDC.py +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -69,4 +69,41 @@ class Fields_CC(Fields): def _e(self, phiSolution, srcList): raise NotImplementedError +class Fields_N(Fields): + knownFields = {'phiSolution':'N'} + aliasFields = { + 'phi': ['phiSolution','N','_phi'], + 'j' : ['phiSolution','E','_j'], + 'e' : ['phiSolution','E','_e'], + } + # primary - secondary + # N variables + def __init__(self, mesh, survey, **kwargs): + Fields.__init__(self, mesh, survey, **kwargs) + + def startup(self): + self.prob = self.survey.prob + + def _GLoc(self, fieldType): + if fieldType == 'phi': + return 'N' + elif fieldType == 'e' or fieldType == 'j': + return 'E' + else: + raise Exception('Field type must be phi, e, j') + + def _phi(self, phiSolution, srcList): + return phiSolution + + def _phiDeriv_u(): + return Identity() + + def _phiDeriv_m(): + return Zero() + + def _j(self, phiSolution, srcList): + raise NotImplementedError + + def _e(self, phiSolution, srcList): + raise NotImplementedError diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index f712e036..c41c8f62 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -1,7 +1,8 @@ from SimPEG import Problem from SimPEG.EM.Base import BaseEMProblem from SurveyDC import Survey -from FieldsDC import Fields, Fields_CC +from FieldsDC import Fields, Fields_CC, Fields_N +from SimPEG.Utils import sdiag import numpy as np class BaseDCProblem(BaseEMProblem): @@ -53,16 +54,15 @@ class BaseDCProblem(BaseEMProblem): q[:,i] = src.eval(self) return q -class Problem3D_CC(BaseDCProblem): +class Problem3D_N(BaseDCProblem): _solutionType = 'phiSolution' - _formulation = 'HJ' # CC potentials means J is on faces - fieldsPair = Fields_CC + _formulation = 'EB' # N potentials means B is on faces + fieldsPair = Fields_N def __init__(self, mesh, **kwargs): BaseDCProblem.__init__(self, mesh, **kwargs) - def getA(self): """ @@ -73,18 +73,21 @@ class Problem3D_CC(BaseDCProblem): """ # TODO: this won't work for full anisotropy - - D = self.mesh.faceDiv - MfRhoI = self.MfRhoI - V = self.Vol - A = D * ( MfRhoI * ( D.T * V ) ) - - if self._makeASymmetric is True: - return V.T * A + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + A = Grad.T * MeSigma * Grad + # if self._makeASymmetric is True: + # return V.T * A return A - def getADeriv(): - raise NotImplementedError + def getADeriv(self, u, v, adoint=False): + """ + + Product of the derivative of our system matrix with respect to the model and a vector + + """ + return Div*self.MfRhoIDeriv(Div.T*u) + def getRHS(self): """ @@ -94,12 +97,71 @@ class Problem3D_CC(BaseDCProblem): """ RHS = self.getSourceTerm() - if self._makeASymmetric is True: - return self.Vol.T * RHS + # if self._makeASymmetric is True: + # return self.Vol.T * RHS return RHS - def getRHSDeriv(): - raise NotImplementedError + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + qDeriv = src.evalDeriv(self, adjoint=adjoint) + return qDeriv + +class Problem3D_CC(BaseDCProblem): + + _solutionType = 'phiSolution' + _formulation = 'HJ' # CC potentials means J is on faces + fieldsPair = Fields_CC + + def __init__(self, mesh, **kwargs): + BaseDCProblem.__init__(self, mesh, **kwargs) + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + # V = self.Vol + # Div = V*self.mesh.faceDiv + MfRhoI = self.MfRhoI + A = self.Div * MfRhoI * self.Div.T + # if self._makeASymmetric is True: + # return V.T * A + return A + + def getADeriv(self, u, v, adoint=False): + """ + + Product of the derivative of our system matrix with respect to the model and a vector + + """ + return Div*self.MfRhoIDeriv(Div.T*u) + + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + # if self._makeASymmetric is True: + # return self.Vol.T * RHS + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + qDeriv = src.evalDeriv(self, adjoint=adjoint) + return qDeriv diff --git a/SimPEG/Mesh/MeshIO.py b/SimPEG/Mesh/MeshIO.py index 7501a66f..16d1b457 100644 --- a/SimPEG/Mesh/MeshIO.py +++ b/SimPEG/Mesh/MeshIO.py @@ -21,7 +21,7 @@ class TensorMeshIO(object): if '*' in seg: st = seg sp = seg.split('*') - re = np.array(sp[0],dtype=int)*(' ' + sp[1]) + re = int(sp[0])*(' ' + sp[1]) line = line.replace(st,re.strip()) return np.array(line.split(),dtype=float) From 73001abfc584edb1526ca1fbcee985a434cd528a Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sat, 23 Apr 2016 01:24:31 -0700 Subject: [PATCH 076/168] fix bug --- SimPEG/EM/Base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index ac28b3a1..491dcf71 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -192,7 +192,7 @@ class BaseEMProblem(Problem.BaseProblem): """ dMfRhoI_dI = -self.MfRhoI**2 - dMf_drho = self.mesh.getFaceInnerProduct(self.curModel.rho)(u) + dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) drho_dm = self.curModel.rhoDeriv return dMfRhoI_dI * ( dMf_drho * ( drho_dm)) From 8cac166fba57d361887f85fdc566cb557468f634 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sat, 23 Apr 2016 10:40:47 -0700 Subject: [PATCH 077/168] Working Jvec: Getting closer to understand how modular EM code is working ... --- SimPEG/EM/Static/DC/FieldsDC.py | 3 ++- SimPEG/EM/Static/DC/ProblemDC.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py index 46a779f5..07b81806 100644 --- a/SimPEG/EM/Static/DC/FieldsDC.py +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -12,6 +12,7 @@ class Fields(SimPEG.Problem.Fields): if adjoint: return self._phiDeriv_u(src, v, adjoint=adjoint), self._phiDeriv_m(src, v, adjoint=adjoint) + return np.array(self._phiDeriv_u(src, du_dm_v, adjoint) + self._phiDeriv_m(src, v, adjoint), dtype = float) def _eDeriv(self, src, du_dm_v, v, adjoint=False): @@ -59,7 +60,7 @@ class Fields_CC(Fields): return phiSolution def _phiDeriv_u(self, src, v, adjoint = False): - return Identity() + return Identity()*v def _phiDeriv_m(self, src, v, adjoint = False): return Zero() diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 25ac7fcf..ff3fff0f 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -1,4 +1,4 @@ -from SimPEG import Problem +from SimPEG import Problem, Utils from SimPEG.EM.Base import BaseEMProblem from SurveyDC import Survey from FieldsDC import Fields, Fields_CC, Fields_N @@ -38,7 +38,6 @@ class BaseDCProblem(BaseEMProblem): u_src = f[src, self._solutionType] # solution vector dA_dm_v = self.getADeriv(u_src, v) dRHS_dm_v = self.getRHSDeriv(src, v) - print type(dA_dm_v + dRHS_dm_v), (dA_dm_v + dRHS_dm_v).shape du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v ) for rx in src.rxList: From 0e16645b67d85ac2f0a9c5e653a07898a8dd3ac6 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sat, 23 Apr 2016 11:06:24 -0700 Subject: [PATCH 078/168] working Jtvec --- SimPEG/EM/Static/DC/ProblemDC.py | 43 ++++++++++++++++++++++++++------ SimPEG/EM/Static/DC/RxDC.py | 8 +++++- tests/em/static/test_DC.py | 38 +++++++++++----------------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index ff3fff0f..a31731a1 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -44,22 +44,47 @@ class BaseDCProblem(BaseEMProblem): df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) - Ainv.clean() return Utils.mkvc(Jv) def Jtvec(self, m, v, f=None): - raise NotImplementedError + if f is None: + f = self.fields(m) + + self.curModel = m + + # Ensure v is a data object. + if not isinstance(v, self.dataPair): + v = self.dataPair(self.survey, v) + + Jtv = np.zeros(m.size) + AT = self.getA().T + ATinv = self.Solver(AT, **self.solverOpts) + + for src in self.survey.srcList: + u_src = f[src, self._solutionType] + for rx in src.rxList: + PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + + ATinvdf_duT = ATinv * df_duT + + dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + du_dmT = -dA_dmT + dRHS_dmT + Jtv += df_dmT + du_dmT + + return Utils.mkvc(Jtv) def getSourceTerm(self): """ takes concept of source and turns it into a matrix """ """ - Evaluates the sources for a given frequency and puts them in matrix form + Evaluates the sources, and puts them in matrix form - :param float freq: Frequency :rtype: (numpy.ndarray, numpy.ndarray) - :return: s_m, s_e (nE or nF, nSrc) + :return: q (nC or nN, nSrc) """ Srcs = self.survey.srcList @@ -128,8 +153,10 @@ class Problem3D_N(BaseDCProblem): """ Derivative of the right hand side with respect to the model """ - qDeriv = src.evalDeriv(self, adjoint=adjoint) - return qDeriv + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() class Problem3D_CC(BaseDCProblem): @@ -169,7 +196,7 @@ class Problem3D_CC(BaseDCProblem): if adjoint: # if self._makeASymmetric is True: # v = V * v - return D * MfRhoIDeriv(D * v) + return( MfRhoIDeriv( D.T * u ).T) * ( D.T * v) # I think we should deprecate this for DC problem. # if self._makeASymmetric is True: diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py index 7692c880..7d50392e 100644 --- a/SimPEG/EM/Static/DC/RxDC.py +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -38,7 +38,13 @@ class BaseRx(SimPEG.Survey.BaseRx): def evalDeriv(self, src, mesh, f, v, adjoint=False): P = self.getP(mesh, self.projGLoc(f)) - return P*v + if not adjoint: + return P*v + elif adjoint: + return P.T*v + + + # DC.Rx.Dipole(locs) class Dipole(BaseRx): diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py index 7de2ea45..6c777acf 100644 --- a/tests/em/static/test_DC.py +++ b/tests/em/static/test_DC.py @@ -47,31 +47,21 @@ class DCProblemTests(unittest.TestCase): passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) - # def test_adjoint(self): - # # Adjoint Test - # u = np.random.rand(self.mesh.nC*self.survey.nSrc) - # v = np.random.rand(self.mesh.nC) - # w = np.random.rand(self.survey.dobs.shape[0]) - # wtJv = w.dot(self.p.Jvec(self.m0, v)) - # vtJtw = v.dot(self.p.Jtvec(self.m0, w)) - # passed = np.abs(wtJv - vtJtw) < 1e-10 - # print 'Adjoint Test', np.abs(wtJv - vtJtw), passed - # self.assertTrue(passed) - - # def test_dataObj(self): - # derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) - # self.assertTrue(passed) - - - # def test_massMatrices(self): - # Gu = np.random.rand(self.mesh.nF) - # def derChk(m): - # self.p.curModel = m - # return [self.p.Msig * Gu, self.p.dMdsig(Gu)] - # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) - # self.assertTrue(passed) + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) if __name__ == '__main__': unittest.main() From d8bfb27415ad6f34a38e8097f32dae8c473caddf Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sat, 23 Apr 2016 15:25:44 -0700 Subject: [PATCH 079/168] Quick fix to MeshIO --- SimPEG/Directives.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 193911fe..3cdb5000 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -301,7 +301,7 @@ class Update_IRLS(InversionDirective): self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d self.reg._W = None - + class Update_lin_PreCond(InversionDirective): @@ -313,7 +313,7 @@ class Update_lin_PreCond(InversionDirective): 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' + class Update_Wj(InversionDirective): """ From f55d9573a602b7e91b37623fbe14e05455328f5d Mon Sep 17 00:00:00 2001 From: Brendan Smithyman Date: Sun, 24 Apr 2016 13:21:49 -0400 Subject: [PATCH 080/168] Installation (i.e., setup.py) is no longer dependent on Numpy already being present. --- setup.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 3383c7f7..5308db47 100644 --- a/setup.py +++ b/setup.py @@ -5,16 +5,17 @@ SimPEG is a python package for simulation and gradient based parameter estimation in the context of geophysical applications. """ -import numpy as np - import os import sys import subprocess from distutils.core import setup +from distutils.command.build_ext import build_ext from setuptools import find_packages from distutils.extension import Extension + + CLASSIFIERS = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', @@ -51,11 +52,16 @@ if args.count("build_ext") > 0 and args.count("--inplace") == 0: try: from Cython.Build import cythonize from Cython.Distutils import build_ext - cythonKwargs = dict(cmdclass={'build_ext': build_ext}) USE_CYTHON = True except Exception, e: USE_CYTHON = False - cythonKwargs = dict() + +class NumpyBuild(build_ext): + def finalize_options(self): + build_ext.finalize_options(self) + __builtins__.__NUMPY_SETUP__ = False + import numpy + self.include_dirs.append(numpy.get_include()) ext = '.pyx' if USE_CYTHON else '.c' @@ -94,8 +100,8 @@ setup( classifiers=CLASSIFIERS, platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"], use_2to3 = False, - include_dirs=[np.get_include()], + cmdclass={'build_ext':NumpyBuild}, + setup_requires=['numpy'], ext_modules = extensions, scripts=scripts, - **cythonKwargs ) From 0bb001973cfd77d869f38c72e04902e8f97f693a Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 13:01:03 -0700 Subject: [PATCH 081/168] workking nodal discretizations --- SimPEG/EM/Static/DC/BoundaryUtils.py | 158 +++++++++++++++++++++++++++ SimPEG/EM/Static/DC/ProblemDC.py | 25 +++-- SimPEG/EM/Static/DC/SrcDC.py | 12 +- SimPEG/EM/Static/DC/__init__.py | 2 +- tests/em/static/test_DC.py | 61 ++++++++++- 5 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 SimPEG/EM/Static/DC/BoundaryUtils.py diff --git a/SimPEG/EM/Static/DC/BoundaryUtils.py b/SimPEG/EM/Static/DC/BoundaryUtils.py new file mode 100644 index 00000000..5ec3282c --- /dev/null +++ b/SimPEG/EM/Static/DC/BoundaryUtils.py @@ -0,0 +1,158 @@ +import numpy as np + +def getxBCyBC_CC(mesh, alpha, beta, gamma): +# def getxBCyBC(mesh, alpha, beta, gamma): + """ + This is a subfunction generating mixed-boundary condition: + + .. math:: + + \nabla \cdot \vec{j} = -\nabla \cdot \vec{j}_s = q + + \rho \vec{j} = -\nabla \phi \phi + + \alpha \phi + \beta \frac{\partial \phi}{\partial r} = \gamma \ at \ r = \partial \Omega + + xBC = f_1(\alpha, \beta, \gamma) + yBC = f(\alpha, \beta, \gamma) + + Computes xBC and yBC for cell-centered discretizations + """ + if mesh.dim == 1: #1D + if (len(alpha) != 2 or len(beta) != 2 or len(gamma) != 2): + raise Exception("Lenght of list, alpha should be 2") + fCCxm,fCCxp = mesh.cellBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + + xBC = np.r_[xBC_xm, xBC_xp] + yBC = np.r_[yBC_xm, yBC_xp] + + elif mesh.dim == 2: #2D + if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4): + raise Exception("Lenght of list, alpha should be 4") + + fCCxm,fCCxp,fCCym,fCCyp = mesh.cellBoundaryInd + fxm,fxp,fym,fyp = mesh.faceBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] + alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] + + h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym) + b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym) + a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp) + b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + xBC_ym = 0.5*a_ym + xBC_yp = 0.5*a_yp/b_yp + yBC_ym = 0.5*(1.-b_ym) + yBC_yp = 0.5*(1.-1./b_yp) + + sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]]) + sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]]) + + xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx] + xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy] + yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx] + yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy] + + xBC = np.r_[xBC_x, xBC_y] + yBC = np.r_[yBC_x, yBC_y] + + elif mesh.dim == 3: #3D + if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6): + raise Exception("Lenght of list, alpha should be 6") + fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd + fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd + nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() + h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + h_zm, h_zp = mesh.gridCC[fCCzm], mesh.gridCC[fCCzp] + + alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] + alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] + alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] + alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] + alpha_zm, beta_zm, gamma_zm = alpha[2], beta[2], gamma[2] + alpha_zp, beta_zp, gamma_zp = alpha[3], beta[3], gamma[3] + + h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + + a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) + b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) + a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp) + b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp) + + a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym) + b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym) + a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp) + b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp) + + a_zm = gamma_zm/(0.5*alpha_zm-beta_zm/h_zm) + b_zm = (0.5*alpha_zm+beta_zm/h_zm)/(0.5*alpha_zm-beta_zm/h_zm) + a_zp = gamma_zp/(0.5*alpha_zp-beta_zp/h_zp) + b_zp = (0.5*alpha_zp+beta_zp/h_zp)/(0.5*alpha_zp-beta_zp/h_zp) + + xBC_xm = 0.5*a_xm + xBC_xp = 0.5*a_xp/b_xp + yBC_xm = 0.5*(1.-b_xm) + yBC_xp = 0.5*(1.-1./b_xp) + xBC_ym = 0.5*a_ym + xBC_yp = 0.5*a_yp/b_yp + yBC_ym = 0.5*(1.-b_ym) + yBC_yp = 0.5*(1.-1./b_yp) + xBC_zm = 0.5*a_zm + xBC_zp = 0.5*a_zp/b_zp + yBC_zm = 0.5*(1.-b_zm) + yBC_zp = 0.5*(1.-1./b_zp) + + sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]]) + sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]]) + sortindsfz = np.argsort(np.r_[np.arange(mesh.nFz)[fzm], np.arange(mesh.nFz)[fzp]]) + + xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx] + xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy] + xBC_z = np.r_[xBC_zm, xBC_zp][sortindsfz] + + yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx] + yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy] + yBC_z = np.r_[yBC_zm, yBC_zp][sortindsfz] + + xBC = np.r_[xBC_x, xBC_y, xBC_z] + yBC = np.r_[yBC_x, yBC_y, yBC_z] + + return xBC, yBC diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index a31731a1..40d4183f 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -10,9 +10,14 @@ class BaseDCProblem(BaseEMProblem): surveyPair = Survey fieldsPair = Fields + Ainv = None def fields(self, m): self.curModel = m + + if not self.Ainv == None: + self.Ainv.clean() + f = self.fieldsPair(self.mesh, self.survey) A = self.getA() self.Ainv = self.Solver(A, **self.solverOpts) @@ -32,13 +37,12 @@ class BaseDCProblem(BaseEMProblem): Jv = self.dataPair(self.survey) #same size as the data A = self.getA() - Ainv = self.Solver(A, **self.solverOpts) for src in self.survey.srcList: u_src = f[src, self._solutionType] # solution vector dA_dm_v = self.getADeriv(u_src, v) dRHS_dm_v = self.getRHSDeriv(src, v) - du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v ) + du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) for rx in src.rxList: df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) @@ -57,8 +61,8 @@ class BaseDCProblem(BaseEMProblem): v = self.dataPair(self.survey, v) Jtv = np.zeros(m.size) - AT = self.getA().T - ATinv = self.Solver(AT, **self.solverOpts) + AT = self.getA() + for src in self.survey.srcList: u_src = f[src, self._solutionType] @@ -67,7 +71,7 @@ class BaseDCProblem(BaseEMProblem): df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) - ATinvdf_duT = ATinv * df_duT + ATinvdf_duT = self.Ainv * df_duT dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) @@ -128,13 +132,18 @@ class Problem3D_N(BaseDCProblem): # return V.T * A return A - def getADeriv(self, u, v, adoint=False): + def getADeriv(self, u, v, adjoint=False): """ Product of the derivative of our system matrix with respect to the model and a vector """ - return Div*self.MfRhoIDeriv(Div.T*u) + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + if not adjoint: + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + elif adjoint: + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) def getRHS(self): @@ -196,7 +205,7 @@ class Problem3D_CC(BaseDCProblem): if adjoint: # if self._makeASymmetric is True: # v = V * v - return( MfRhoIDeriv( D.T * u ).T) * ( D.T * v) + return(MfRhoIDeriv( D.T * u ).T) * ( D.T * v) # I think we should deprecate this for DC problem. # if self._makeASymmetric is True: diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index cc855118..3ed6067d 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -31,9 +31,9 @@ class Dipole(BaseSrc): q = np.zeros(prob.mesh.nC) q[inds] = self.current * np.r_[1., -1.] elif prob._formulation == 'EB': - # TODO: there is probably a faster way to do this - # Utils.cellNodes , Utils.cellFaces, Utils.cellEdges - raise NotImplementedError + inds = closestPoints(prob.mesh, self.loc) + q = np.zeros(prob.mesh.nN) + q[inds] = self.current * np.r_[1., -1.] return q # def bc_contribution @@ -52,9 +52,9 @@ class Pole(BaseSrc): q = np.zeros(prob.mesh.nC) q[inds] = self.current * np.r_[1.] elif prob._formulation == 'EB': - # TODO: there is probably a faster way to do this - # Utils.cellNodes , Utils.cellFaces, Utils.cellEdges - raise NotImplementedError + inds = closestPoints(prob.mesh, self.loc) + q = np.zeros(prob.mesh.nN) + q[inds] = self.current * np.r_[1.] return q # def bc_contribution diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py index dcc40764..57da57e8 100644 --- a/SimPEG/EM/Static/DC/__init__.py +++ b/SimPEG/EM/Static/DC/__init__.py @@ -1,4 +1,4 @@ -from ProblemDC import Problem3D_CC +from ProblemDC import Problem3D_CC, Problem3D_N from SurveyDC import Survey import SrcDC as Src #Pole import RxDC as Rx diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py index 6c777acf..3472a27e 100644 --- a/tests/em/static/test_DC.py +++ b/tests/em/static/test_DC.py @@ -3,7 +3,7 @@ from SimPEG import * import SimPEG.EM.Static.DC as DC -class DCProblemTests(unittest.TestCase): +class DCProblemTestsCC(unittest.TestCase): def setUp(self): @@ -63,5 +63,64 @@ class DCProblemTests(unittest.TestCase): passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) +class DCProblemTestsN(unittest.TestCase): + + def setUp(self): + + aSpacing=2.5 + nElecs=10 + + surveySize = nElecs*aSpacing - aSpacing + cs = surveySize/nElecs/4 + + mesh = Mesh.TensorMesh([ + [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], + [(cs,3, -1.3),(cs,3,1.3)], + # [(cs,5, -1.3),(cs,10)] + ],'CN') + + srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) + survey = DC.Survey(srcList) + problem = DC.Problem3D_N(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) + problem.pair(survey) + + mSynth = np.ones(mesh.nC) + survey.makeSyntheticData(mSynth) + + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + self.assertTrue(passed) if __name__ == '__main__': unittest.main() From a48224ed8b6eca2233f2501d55c9ff08b29e5059 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 13:18:36 -0700 Subject: [PATCH 082/168] no message --- tests/mesh/test_Mixed_boundaryPoisson.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mesh/test_Mixed_boundaryPoisson.py b/tests/mesh/test_Mixed_boundaryPoisson.py index 7a15f36d..d5dcb6fa 100644 --- a/tests/mesh/test_Mixed_boundaryPoisson.py +++ b/tests/mesh/test_Mixed_boundaryPoisson.py @@ -194,6 +194,7 @@ class Test1D_InhomogeneousMixed(Tests.OrderTest): q = q_fun(self.M.gridCC) M = B*self.M.aveCC2F G = Div.T - P_BC*Utils.sdiag(y_BC)*M + # Mrhoj = D.T V phi + P_BC*Utils.sdiag(y_BC)*M phi - P_BC*x_BC rhs = V*q + Div*MfrhoI*P_BC*x_BC A = Div*MfrhoI*G From eeee594f09a8f13d592848f5d9d8dec712c523ef Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 13:29:38 -0700 Subject: [PATCH 083/168] Problem3D_N is tested! --- SimPEG/EM/Static/DC/FieldsDC.py | 2 +- tests/em/static/test_DC.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py index 07b81806..9999c56a 100644 --- a/SimPEG/EM/Static/DC/FieldsDC.py +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -99,7 +99,7 @@ class Fields_N(Fields): return phiSolution def _phiDeriv_u(self, src, v, adjoint = False): - return Identity() + return Identity()*v def _phiDeriv_m(self, src, v, adjoint = False): return Zero() diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py index 3472a27e..1d83d32c 100644 --- a/tests/em/static/test_DC.py +++ b/tests/em/static/test_DC.py @@ -104,7 +104,7 @@ class DCProblemTestsN(unittest.TestCase): def test_misfit(self): derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) def test_adjoint(self): @@ -114,13 +114,13 @@ class DCProblemTestsN(unittest.TestCase): w = np.random.rand(self.survey.dobs.shape[0]) wtJv = w.dot(self.p.Jvec(self.m0, v)) vtJtw = v.dot(self.p.Jtvec(self.m0, w)) - passed = np.abs(wtJv - vtJtw) < 1e-10 + passed = np.abs(wtJv - vtJtw) < 1e-8 print 'Adjoint Test', np.abs(wtJv - vtJtw), passed self.assertTrue(passed) def test_dataObj(self): derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) if __name__ == '__main__': unittest.main() From fcc2b8b22a9d09a837c91536f5f51bf1ecfcf603 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 13:32:44 -0700 Subject: [PATCH 084/168] Handling null space of A --- SimPEG/EM/Static/DC/ProblemDC.py | 4 ++++ tests/em/static/test_DC.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 40d4183f..04a07c57 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -128,6 +128,10 @@ class Problem3D_N(BaseDCProblem): MeSigma = self.MeSigma Grad = self.mesh.nodalGrad A = Grad.T * MeSigma * Grad + + # Handling ... singularity + A[0,0] = A[0,0] + 1. + # if self._makeASymmetric is True: # return V.T * A return A diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py index 1d83d32c..99b384aa 100644 --- a/tests/em/static/test_DC.py +++ b/tests/em/static/test_DC.py @@ -104,7 +104,7 @@ class DCProblemTestsN(unittest.TestCase): def test_misfit(self): derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) def test_adjoint(self): @@ -120,7 +120,7 @@ class DCProblemTestsN(unittest.TestCase): def test_dataObj(self): derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) if __name__ == '__main__': unittest.main() From 1936a046833d3d5b8a073d2e6a87c2206a1c9c97 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 13:56:37 -0700 Subject: [PATCH 085/168] Working on implementing mixed BC to DC problem --- SimPEG/EM/Static/DC/ProblemDC.py | 139 ++++++++++++++++--------------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 04a07c57..7ec32919 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -5,6 +5,7 @@ from FieldsDC import Fields, Fields_CC, Fields_N from SimPEG.Utils import sdiag import numpy as np from SimPEG.Utils import Zero +from BoundaryUtils import getxBCyBC_CC class BaseDCProblem(BaseEMProblem): @@ -106,71 +107,6 @@ class BaseDCProblem(BaseEMProblem): q[:,i] = src.eval(self) return q -class Problem3D_N(BaseDCProblem): - - _solutionType = 'phiSolution' - _formulation = 'EB' # N potentials means B is on faces - fieldsPair = Fields_N - - def __init__(self, mesh, **kwargs): - BaseDCProblem.__init__(self, mesh, **kwargs) - - def getA(self): - """ - - Make the A matrix for the cell centered DC resistivity problem - - A = D MfRhoI D^\\top V - - """ - - # TODO: this won't work for full anisotropy - MeSigma = self.MeSigma - Grad = self.mesh.nodalGrad - A = Grad.T * MeSigma * Grad - - # Handling ... singularity - A[0,0] = A[0,0] + 1. - - # if self._makeASymmetric is True: - # return V.T * A - return A - - def getADeriv(self, u, v, adjoint=False): - """ - - Product of the derivative of our system matrix with respect to the model and a vector - - """ - MeSigma = self.MeSigma - Grad = self.mesh.nodalGrad - if not adjoint: - return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) - elif adjoint: - return self.MeSigmaDeriv(Grad*u).T * (Grad*v) - - - def getRHS(self): - """ - RHS for the DC problem - - q - """ - - RHS = self.getSourceTerm() - # if self._makeASymmetric is True: - # return self.Vol.T * RHS - return RHS - - def getRHSDeriv(self, src, v, adjoint=False): - """ - Derivative of the right hand side with respect to the model - """ - # TODO: add qDeriv for RHS depending on m - # qDeriv = src.evalDeriv(self, adjoint=adjoint) - # return qDeriv - return Zero() - class Problem3D_CC(BaseDCProblem): _solutionType = 'phiSolution' @@ -180,6 +116,12 @@ class Problem3D_CC(BaseDCProblem): def __init__(self, mesh, **kwargs): BaseDCProblem.__init__(self, mesh, **kwargs) + def setBC(self): + self.Div = V * self.mesh.faceDiv + P_BC, B = self.mesh.getBCProjWF_simple() + M = B*self.mesh.aveCC2F + Grad = Div.T - P_BC*Utils.sdiag(y_BC)*M + def getA(self): """ @@ -241,4 +183,71 @@ class Problem3D_CC(BaseDCProblem): return Zero() +class Problem3D_N(BaseDCProblem): + + _solutionType = 'phiSolution' + _formulation = 'EB' # N potentials means B is on faces + fieldsPair = Fields_N + + def __init__(self, mesh, **kwargs): + BaseDCProblem.__init__(self, mesh, **kwargs) + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + A = Grad.T * MeSigma * Grad + + # Handling Null space of A + A[0,0] = A[0,0] + 1. + + # if self._makeASymmetric is True: + # return V.T * A + return A + + def getADeriv(self, u, v, adjoint=False): + """ + + Product of the derivative of our system matrix with respect to the model and a vector + + """ + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + if not adjoint: + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + elif adjoint: + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + # if self._makeASymmetric is True: + # return self.Vol.T * RHS + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() + + + From dcd4fbf97311762376c3fe2698cb980580d0f086 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 24 Apr 2016 15:23:14 -0700 Subject: [PATCH 086/168] Implemented mixed B.C. to CC problem. Fix bugs in get fuction getxBCyBC_CC --- SimPEG/EM/Static/DC/BoundaryUtils.py | 36 +++++----- SimPEG/EM/Static/DC/ProblemDC.py | 84 ++++++++++++++++++++---- SimPEG/EM/Static/DC/SrcDC.py | 2 +- tests/em/static/test_DC.py | 9 +-- tests/mesh/test_Mixed_boundaryPoisson.py | 63 +++++++++++------- 5 files changed, 135 insertions(+), 59 deletions(-) diff --git a/SimPEG/EM/Static/DC/BoundaryUtils.py b/SimPEG/EM/Static/DC/BoundaryUtils.py index 5ec3282c..3967eb46 100644 --- a/SimPEG/EM/Static/DC/BoundaryUtils.py +++ b/SimPEG/EM/Static/DC/BoundaryUtils.py @@ -28,7 +28,8 @@ def getxBCyBC_CC(mesh, alpha, beta, gamma): alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + # h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_xm, h_xp = mesh.hx[0], mesh.hx[-1] a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) @@ -47,19 +48,19 @@ def getxBCyBC_CC(mesh, alpha, beta, gamma): if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4): raise Exception("Lenght of list, alpha should be 4") - fCCxm,fCCxp,fCCym,fCCyp = mesh.cellBoundaryInd fxm,fxp,fym,fyp = mesh.faceBoundaryInd - nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] - h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum() alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] - h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] - h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + # h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + # h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + + h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp) + h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp) a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) @@ -94,23 +95,24 @@ def getxBCyBC_CC(mesh, alpha, beta, gamma): elif mesh.dim == 3: #3D if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6): raise Exception("Lenght of list, alpha should be 6") - fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd + # fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd - nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] - h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] - h_zm, h_zp = mesh.gridCC[fCCzm], mesh.gridCC[fCCzp] + nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum() alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] - alpha_zm, beta_zm, gamma_zm = alpha[2], beta[2], gamma[2] - alpha_zp, beta_zp, gamma_zp = alpha[3], beta[3], gamma[3] + alpha_zm, beta_zm, gamma_zm = alpha[4], beta[4], gamma[4] + alpha_zp, beta_zp, gamma_zp = alpha[5], beta[5], gamma[5] - h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] - h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] - h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + # h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + # h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + # h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + + h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp) + h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp) + h_zm, h_zp = mesh.hz[0]*np.ones_like(alpha_zm), mesh.hz[-1]*np.ones_like(alpha_zp) a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 7ec32919..9f05d876 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -115,12 +115,7 @@ class Problem3D_CC(BaseDCProblem): def __init__(self, mesh, **kwargs): BaseDCProblem.__init__(self, mesh, **kwargs) - - def setBC(self): - self.Div = V * self.mesh.faceDiv - P_BC, B = self.mesh.getBCProjWF_simple() - M = B*self.mesh.aveCC2F - Grad = Div.T - P_BC*Utils.sdiag(y_BC)*M + self.setBC() def getA(self): """ @@ -131,11 +126,11 @@ class Problem3D_CC(BaseDCProblem): """ - V = self.Vol - D = V * self.mesh.faceDiv + D = self.Div + G = self.Grad # TODO: this won't work for full anisotropy MfRhoI = self.MfRhoI - A = D * MfRhoI * D.T + A = D * MfRhoI * G # I think we should deprecate this for DC problem. # if self._makeASymmetric is True: @@ -144,19 +139,19 @@ class Problem3D_CC(BaseDCProblem): def getADeriv(self, u, v, adjoint= False): - V = self.Vol - D = V * self.mesh.faceDiv + D = self.Div + G = self.Grad MfRhoIDeriv = self.MfRhoIDeriv if adjoint: # if self._makeASymmetric is True: # v = V * v - return(MfRhoIDeriv( D.T * u ).T) * ( D.T * v) + return(MfRhoIDeriv( G * u ).T) * ( D.T * v) # I think we should deprecate this for DC problem. # if self._makeASymmetric is True: # return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) ) - return D * (MfRhoIDeriv( D.T * u ) * v) + return D * (MfRhoIDeriv( G * u ) * v) def getRHS(self): """ @@ -182,6 +177,69 @@ class Problem3D_CC(BaseDCProblem): # return qDeriv return Zero() + def setBC(self): + if self.mesh.dim==3: + fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + gBFzm = self.mesh.gridFz[fzm,:] + gBFzp = self.mesh.gridFz[fzp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + alpha_zm, alpha_zp = temp_zm*0., temp_zp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + beta_zm, beta_zp = temp_zm, temp_zp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + gamma_zm, gamma_zp = temp_zm*0., temp_zp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] + + elif self.mesh.dim==2: + + fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] + + x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma) + V = self.Vol + self.Div = V * self.mesh.faceDiv + P_BC, B = self.mesh.getBCProjWF_simple() + M = B*self.mesh.aveCC2F + self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M + class Problem3D_N(BaseDCProblem): diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 3ed6067d..1e64835e 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -15,7 +15,7 @@ class BaseSrc(SimPEG.Survey.BaseSrc): raise NotImplementedError def evalDeriv(self, prob): - Zero() + return Zero() class Dipole(BaseSrc): diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC.py index 99b384aa..227d4614 100644 --- a/tests/em/static/test_DC.py +++ b/tests/em/static/test_DC.py @@ -8,7 +8,7 @@ class DCProblemTestsCC(unittest.TestCase): def setUp(self): aSpacing=2.5 - nElecs=10 + nElecs=5 surveySize = nElecs*aSpacing - aSpacing cs = surveySize/nElecs/4 @@ -16,7 +16,7 @@ class DCProblemTestsCC(unittest.TestCase): mesh = Mesh.TensorMesh([ [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], [(cs,3, -1.3),(cs,3,1.3)], - # [(cs,5, -1.3),(cs,10)] + # [(cs,5, -1.3),(cs,10)] ],'CN') srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) @@ -44,7 +44,7 @@ class DCProblemTestsCC(unittest.TestCase): def test_misfit(self): derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) def test_adjoint(self): @@ -60,7 +60,7 @@ class DCProblemTestsCC(unittest.TestCase): def test_dataObj(self): derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) class DCProblemTestsN(unittest.TestCase): @@ -122,5 +122,6 @@ class DCProblemTestsN(unittest.TestCase): derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) + if __name__ == '__main__': unittest.main() diff --git a/tests/mesh/test_Mixed_boundaryPoisson.py b/tests/mesh/test_Mixed_boundaryPoisson.py index d5dcb6fa..3aa1dbcd 100644 --- a/tests/mesh/test_Mixed_boundaryPoisson.py +++ b/tests/mesh/test_Mixed_boundaryPoisson.py @@ -6,10 +6,23 @@ from SimPEG import * MESHTYPES = ['uniformTensorMesh'] -def getxBCyBC(mesh, alpha, beta, gamma): +def getxBCyBC_CC(mesh, alpha, beta, gamma): # def getxBCyBC(mesh, alpha, beta, gamma): """ + This is a subfunction generating mixed-boundary condition: + .. math:: + + \nabla \cdot \vec{j} = -\nabla \cdot \vec{j}_s = q + + \rho \vec{j} = -\nabla \phi \phi + + \alpha \phi + \beta \frac{\partial \phi}{\partial r} = \gamma \ at \ r = \partial \Omega + + xBC = f_1(\alpha, \beta, \gamma) + yBC = f(\alpha, \beta, \gamma) + + Computes xBC and yBC for cell-centered discretizations """ if mesh.dim == 1: #1D if (len(alpha) != 2 or len(beta) != 2 or len(gamma) != 2): @@ -21,7 +34,8 @@ def getxBCyBC(mesh, alpha, beta, gamma): alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + # h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] + h_xm, h_xp = mesh.hx[0], mesh.hx[-1] a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) @@ -40,19 +54,19 @@ def getxBCyBC(mesh, alpha, beta, gamma): if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4): raise Exception("Lenght of list, alpha should be 4") - fCCxm,fCCxp,fCCym,fCCyp = mesh.cellBoundaryInd fxm,fxp,fym,fyp = mesh.faceBoundaryInd - nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] - h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] + nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum() alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] - h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] - h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + # h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + # h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + + h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp) + h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp) a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) @@ -87,23 +101,24 @@ def getxBCyBC(mesh, alpha, beta, gamma): elif mesh.dim == 3: #3D if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6): raise Exception("Lenght of list, alpha should be 6") - fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd + # fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd - nBC = fCCxm.sum()+fCCxp.sum()+fCCxm.sum()+fCCxp.sum() - h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp] - h_ym, h_yp = mesh.gridCC[fCCym], mesh.gridCC[fCCyp] - h_zm, h_zp = mesh.gridCC[fCCzm], mesh.gridCC[fCCzp] + nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum() alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0] alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1] alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2] alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3] - alpha_zm, beta_zm, gamma_zm = alpha[2], beta[2], gamma[2] - alpha_zp, beta_zp, gamma_zp = alpha[3], beta[3], gamma[3] + alpha_zm, beta_zm, gamma_zm = alpha[4], beta[4], gamma[4] + alpha_zp, beta_zp, gamma_zp = alpha[5], beta[5], gamma[5] - h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] - h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] - h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + # h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0] + # h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1] + # h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2] + + h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp) + h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp) + h_zm, h_zp = mesh.hz[0]*np.ones_like(alpha_zm), mesh.hz[-1]*np.ones_like(alpha_zp) a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm) b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm) @@ -182,7 +197,7 @@ class Test1D_InhomogeneousMixed(Tests.OrderTest): phi_bc = phi_fun(vecN[[0,-1]]) phi_deriv_bc = phi_deriv(vecN[[0,-1]]) gamma = alpha*phi_bc + beta*phi_deriv_bc - x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma) sigma = np.ones(self.M.nC) @@ -265,7 +280,7 @@ class Test2D_InhomogeneousMixed(Tests.OrderTest): beta = [beta_xm, beta_xp, beta_ym, beta_yp] gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] - x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma) sigma = np.ones(self.M.nC) @@ -335,8 +350,8 @@ class Test3D_InhomogeneousMixed(Tests.OrderTest): beta_xm, beta_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) alpha_ym, alpha_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) beta_ym, beta_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) - alpha_zm, alpha_zp = np.ones_like(gBFzm[:,1]), np.ones_like(gBFzp[:,1]) - beta_zm, beta_zp = np.ones_like(gBFzm[:,1]), np.ones_like(gBFzp[:,1]) + alpha_zm, alpha_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) + beta_zm, beta_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) phi_bc_xm, phi_bc_xp = phi_fun(gBFxm), phi_fun(gBFxp) @@ -345,7 +360,7 @@ class Test3D_InhomogeneousMixed(Tests.OrderTest): phiderivX_bc_xm, phiderivX_bc_xp = phideriv_funX(gBFxm), phideriv_funX(gBFxp) phiderivY_bc_ym, phiderivY_bc_yp = phideriv_funY(gBFym), phideriv_funY(gBFyp) - phiderivY_bc_zm, phiderivY_bc_zp = phideriv_funY(gBFzm), phideriv_funY(gBFzp) + phiderivY_bc_zm, phiderivY_bc_zp = phideriv_funZ(gBFzm), phideriv_funZ(gBFzp) gamma_fun = lambda alpha, beta, phi, phi_deriv: alpha*phi + beta*phi_deriv gamma_xm = gamma_fun(alpha_xm, beta_xm, phi_bc_xm, phiderivX_bc_xm) @@ -359,7 +374,7 @@ class Test3D_InhomogeneousMixed(Tests.OrderTest): beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] - x_BC, y_BC = getxBCyBC(self.M, alpha, beta, gamma) + x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma) sigma = np.ones(self.M.nC) From f944f9b76b81ad85ab7477f18184cf6f0c6d60b6 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 25 Apr 2016 10:58:54 -0700 Subject: [PATCH 087/168] 1. Add distributed source for nodal discretization 2. Add Analytic tests 3. Fix simple bug in PlotSlice for nodal variable 4. Add more analytic function (sphere) --- SimPEG/EM/Analytics/DC.py | 81 ++++++++++++++++++- SimPEG/EM/Analytics/__init__.py | 2 +- SimPEG/EM/Static/DC/SrcDC.py | 10 +-- SimPEG/Mesh/View.py | 2 +- tests/em/static/test_DC_analytic.py | 68 ++++++++++++++++ tests/em/static/test_DC_deriv.py | 0 .../{test_DC.py => test_DC_jvecjtvecadj.py} | 0 7 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 tests/em/static/test_DC_analytic.py delete mode 100644 tests/em/static/test_DC_deriv.py rename tests/em/static/{test_DC.py => test_DC_jvecjtvecadj.py} (100%) diff --git a/SimPEG/EM/Analytics/DC.py b/SimPEG/EM/Analytics/DC.py index 69d17090..4fb03fd3 100644 --- a/SimPEG/EM/Analytics/DC.py +++ b/SimPEG/EM/Analytics/DC.py @@ -1,7 +1,7 @@ import numpy as np from scipy.constants import mu_0, pi -def DCAnalytic(txloc, rxlocs, sigma, flag="wholespace"): +def DCAnalyticHalf(txloc, rxlocs, sigma, flag="wholespace"): """ Analytic solution for electric potential from a postive pole @@ -32,3 +32,82 @@ def DCAnalytic(txloc, rxlocs, sigma, flag="wholespace"): return phi +deg2rad = lambda deg: deg/180.*np.pi +rad2deg = lambda rad: rad*180./np.pi + +def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \ + flag = "sec", order=12): +# def DCSpherePointCurrent(txloc, rxloc, xc, radius, rho, rho1, \ +# flag = "sec", order=12): + """ + + Parameters: + + txloc (array) : current electrode location (x,y,z) + xc (float) : x center of depressed sphere + rxloc (array) : electrode locations + (Nx3 array, # of electrodes) + radius (float): radius of the sphere (m) + rho (float) : resistivity of the background (ohm-m) + rho1 (float) : resistivity of the sphere + flag (string) : "sec", "total", "prim" + (default="sec") + "sec": secondary potential only due to sphere + "prim": primary potential from the point source + "total": "sec"+"prim" + order (float) : maximum order of Legendre polynomial + (default=12) + + Written by Seogi Kang (skang@eos.ubc.ca) + Ph.D. Candidate of University of British Columbia, Canada + + """ + + Pleg = [] + # Compute Legendre Polynomial + for i in range(order): + Pleg.append(special.legendre(i, monic=0)) + + + rho = 1./sigma + rho1 = 1./sigma1 + + # Center of the sphere should be aligned in txloc in y-direction + yc = txloc[1] + xyz = np.c_[rxloc[:,0]-xc, rxloc[:,1]-yc, rxloc[:,2]] + r = np.sqrt( (xyz**2).sum(axis=1) ) + + x0 = abs(txloc[0]-xc) + + costheta = xyz[:,0]/r * (txloc[0]-xc)/x0 + phi = np.zeros_like(r) + R = (r**2+x0**2.-2.*r*x0*costheta)**0.5 + # primary potential in a whole space + prim = rho*1./(4*np.pi*R) + + if flag =="prim": + return prim + + sphind = r < radius + out = np.zeros_like(r) + for n in range(order): + An, Bn = AnBnfun(n, radius, x0, rho, rho1) + dumout = An*r[~sphind]**(-n-1.)*Pleg[n](costheta[~sphind]) + out[~sphind] += dumout + dumin = Bn*r[sphind]**(n)*Pleg[n](costheta[sphind]) + out[sphind] += dumin + + out[~sphind] += prim[~sphind] + + if flag == "sec": + return out-prim + elif flag == "total": + return out + +def AnBnfun(n, radius, x0, rho, rho1, I=1.): + const = I*rho/(4*np.pi) + bunmo = n*rho + (n+1)*rho1 + An = const * radius**(2*n+1) / x0 ** (n+1.) * n * \ + (rho1-rho) / bunmo + Bn = const * 1. / x0 ** (n+1.) * (2*n+1) * (rho1) / bunmo + return An, Bn diff --git a/SimPEG/EM/Analytics/__init__.py b/SimPEG/EM/Analytics/__init__.py index d251f205..9df2aef7 100644 --- a/SimPEG/EM/Analytics/__init__.py +++ b/SimPEG/EM/Analytics/__init__.py @@ -1,4 +1,4 @@ from TDEM import hzAnalyticDipoleT from FDEM import hzAnalyticDipoleF from FDEMcasing import * -from DC import DCAnalytic +from DC import DCAnalyticHalf, DCAnalyticSphere diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 1e64835e..4eda7fe2 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -1,6 +1,6 @@ import SimPEG # from SimPEG.EM.Base import BaseEMSurvey -from SimPEG.Utils import Zero, closestPoints +from SimPEG.Utils import Zero, closestPoints, mkvc import numpy as np class BaseSrc(SimPEG.Survey.BaseSrc): @@ -27,13 +27,13 @@ class Dipole(BaseSrc): def eval(self, prob): if prob._formulation == 'HJ': - inds = closestPoints(prob.mesh, self.loc) + inds = closestPoints(prob.mesh, self.loc, gridLoc='CC') q = np.zeros(prob.mesh.nC) q[inds] = self.current * np.r_[1., -1.] elif prob._formulation == 'EB': - inds = closestPoints(prob.mesh, self.loc) - q = np.zeros(prob.mesh.nN) - q[inds] = self.current * np.r_[1., -1.] + qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense() + qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense() + q = mkvc(qa+qb) return q # def bc_contribution diff --git a/SimPEG/Mesh/View.py b/SimPEG/Mesh/View.py index 089d7d9a..6f009dc9 100644 --- a/SimPEG/Mesh/View.py +++ b/SimPEG/Mesh/View.py @@ -206,7 +206,7 @@ class TensorView(object): return out viewOpts = ['real','imag','abs','vec'] normalOpts = ['X', 'Y', 'Z'] - vTypeOpts = ['CC', 'CCv','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez'] + vTypeOpts = ['CC', 'CCv','N','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez'] # Some user error checking assert vType in vTypeOpts, "vType must be in ['%s']" % "','".join(vTypeOpts) diff --git a/tests/em/static/test_DC_analytic.py b/tests/em/static/test_DC_analytic.py new file mode 100644 index 00000000..3755c6ba --- /dev/null +++ b/tests/em/static/test_DC_analytic.py @@ -0,0 +1,68 @@ +import unittest +from SimPEG import Mesh, Utils, EM, Maps, np +import SimPEG.EM.Static.DC as DC + +class DCProblemAnalyticTests(unittest.TestCase): + + def setUp(self): + + cs = 25. + hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hz = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + sigma = np.ones(mesh.nC)*1e-2 + + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") + phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") + data_anal = phiA-phiB + + rx = DC.Rx.Dipole(M, N) + src = DC.Src.Dipole([rx], Aloc, Bloc) + survey = DC.Survey([src]) + + self.survey = survey + self.mesh = mesh + self.sigma = sigma + self.data_anal = data_anal + + try: + from pymatsolver import MumpsSolver + self.Solver = MumpsSolver + except ImportError, e: + self.Solver = SolverLU + + def test_N(self): + problem = DC.Problem3D_N(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: + passed = True + else: + passed = False + self.assertTrue(passed) + + def test_CC(self): + problem = DC.Problem3D_N(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: + passed = True + print ">> DC analytic test for Problem3D_CC is pased" + else: + passed = False + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/em/static/test_DC_deriv.py b/tests/em/static/test_DC_deriv.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/em/static/test_DC.py b/tests/em/static/test_DC_jvecjtvecadj.py similarity index 100% rename from tests/em/static/test_DC.py rename to tests/em/static/test_DC_jvecjtvecadj.py From 6a064c5f96c106e54dc80412039f22ebf5b6d5d7 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 25 Apr 2016 11:00:32 -0700 Subject: [PATCH 088/168] Minor changes --- tests/em/static/test_DC_analytic.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/em/static/test_DC_analytic.py b/tests/em/static/test_DC_analytic.py index 3755c6ba..53d494e2 100644 --- a/tests/em/static/test_DC_analytic.py +++ b/tests/em/static/test_DC_analytic.py @@ -38,7 +38,7 @@ class DCProblemAnalyticTests(unittest.TestCase): except ImportError, e: self.Solver = SolverLU - def test_N(self): + def test_Problem3D_N(self): problem = DC.Problem3D_N(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) @@ -46,21 +46,24 @@ class DCProblemAnalyticTests(unittest.TestCase): err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) if err < 0.2: passed = True + print ">> DC analytic test for Problem3D_N is passed" else: passed = False + print ">> DC analytic test for Problem3D_N is failed" self.assertTrue(passed) - def test_CC(self): - problem = DC.Problem3D_N(self.mesh) + def test_Problem3D_CC(self): + problem = DC.Problem3D_CC(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) if err < 0.2: passed = True - print ">> DC analytic test for Problem3D_CC is pased" + print ">> DC analytic test for Problem3D_CC is passed" else: passed = False + print ">> DC analytic test for Problem3D_CC is failed" self.assertTrue(passed) if __name__ == '__main__': From 92e2fd67de0752a97806139c21c0cfc3e346644d Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 27 Apr 2016 15:25:40 -0700 Subject: [PATCH 089/168] minor fixes. --- SimPEG/EM/Analytics/DC.py | 12 +++++++++--- SimPEG/EM/Static/DC/SrcDC.py | 4 ++-- SimPEG/EM/Static/DC/__init__.py | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/SimPEG/EM/Analytics/DC.py b/SimPEG/EM/Analytics/DC.py index 4fb03fd3..3949b2e5 100644 --- a/SimPEG/EM/Analytics/DC.py +++ b/SimPEG/EM/Analytics/DC.py @@ -1,5 +1,6 @@ import numpy as np from scipy.constants import mu_0, pi +from scipy import special def DCAnalyticHalf(txloc, rxlocs, sigma, flag="wholespace"): """ @@ -36,7 +37,7 @@ deg2rad = lambda deg: deg/180.*np.pi rad2deg = lambda rad: rad*180./np.pi def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \ - flag = "sec", order=12): + flag = "sec", order=12, halfspace=False): # def DCSpherePointCurrent(txloc, rxloc, xc, radius, rho, rho1, \ # flag = "sec", order=12): """ @@ -99,10 +100,15 @@ def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \ out[~sphind] += prim[~sphind] + if halfspace: + scale = 2 + else: + scale = 1 + if flag == "sec": - return out-prim + return scale*(out-prim) elif flag == "total": - return out + return scale*out def AnBnfun(n, radius, x0, rho, rho1, I=1.): const = I*rho/(4*np.pi) diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 4eda7fe2..7879ba0c 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -5,7 +5,7 @@ import numpy as np class BaseSrc(SimPEG.Survey.BaseSrc): - current = 1 + current = 1.0 loc = None def __init__(self, rxList, **kwargs): @@ -33,7 +33,7 @@ class Dipole(BaseSrc): elif prob._formulation == 'EB': qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense() qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense() - q = mkvc(qa+qb) + q = self.current * mkvc(qa+qb) return q # def bc_contribution diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py index 57da57e8..82cf76d5 100644 --- a/SimPEG/EM/Static/DC/__init__.py +++ b/SimPEG/EM/Static/DC/__init__.py @@ -3,4 +3,5 @@ from SurveyDC import Survey import SrcDC as Src #Pole import RxDC as Rx from FieldsDC import Fields_CC +from BoundaryUtils import getxBCyBC_CC import Utils From d14cd444ac59b7594ded7b3635fc5f114f1d7bb4 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 27 Apr 2016 23:04:28 -0700 Subject: [PATCH 090/168] working 2.5D fwd problem. --- SimPEG/EM/Static/DC/FieldsDC_2D.py | 106 +++++++++++++ SimPEG/EM/Static/DC/ProblemDC_2D.py | 235 ++++++++++++++++++++++++++++ SimPEG/EM/Static/DC/RxDC.py | 57 ++++++- SimPEG/EM/Static/DC/SrcDC.py | 2 - SimPEG/EM/Static/DC/SurveyDC.py | 22 ++- SimPEG/EM/Static/DC/__init__.py | 3 +- 6 files changed, 415 insertions(+), 10 deletions(-) create mode 100644 SimPEG/EM/Static/DC/FieldsDC_2D.py create mode 100644 SimPEG/EM/Static/DC/ProblemDC_2D.py diff --git a/SimPEG/EM/Static/DC/FieldsDC_2D.py b/SimPEG/EM/Static/DC/FieldsDC_2D.py new file mode 100644 index 00000000..77e3199e --- /dev/null +++ b/SimPEG/EM/Static/DC/FieldsDC_2D.py @@ -0,0 +1,106 @@ +import SimPEG +import Utils, numpy as np, scipy.sparse as sp + +class Fields_ky(SimPEG.Problem.TimeFields): + + """ + + Fancy Field Storage for a 2.5D code. + + u[:,'phi', kyInd] = phi + print u[src0,'phi'] + + Only one field type is stored for + each problem, the rest are computed. The fields obejct acts like an array and is indexed by + .. code-block:: python + f = problem.fields(m) + e = f[srcList,'e'] + j = f[srcList,'j'] + + If accessing all sources for a given field, use the :code:`:` + .. code-block:: python + f = problem.fields(m) + phi = f[:,'phi'] + e = f[:,'e'] + b = f[:,'b'] + The array returned will be size (nE or nF, nSrcs :math:`\\times` nFrequencies) + """ + + knownFields = {} + dtype = float + + def _phiDeriv(self,kyInd, src, du_dm_v, v, adjoint=False): + if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None: + raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._phiDeriv_u(kyInd, src, v, adjoint=adjoint), self._phiDeriv_m(kyInd, src, v, adjoint=adjoint) + + return np.array(self._phiDeriv_u(kyInd, src, du_dm_v, adjoint) + self._phiDeriv_m(kyInd, src, v, adjoint), dtype = float) + + def _eDeriv(self,kyInd, src, du_dm_v, v, adjoint=False): + if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None: + raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._eDeriv_u(kyInd, src, v, adjoint), self._eDeriv_m(kyInd, src, v, adjoint) + return np.array(self._eDeriv_u(kyInd, src, du_dm_v, adjoint) + self._eDeriv_m(kyInd, src, v, adjoint), dtype = float) + + def _jDeriv(self,kyInd, src, du_dm_v, v, adjoint=False): + if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None: + raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0]) + + if adjoint: + return self._jDeriv_u(kyInd, src, v, adjoint), self._jDeriv_m(kyInd, src, v, adjoint) + return np.array(self._jDeriv_u(kyInd, src, du_dm_v, adjoint) + self._jDeriv_m(kyInd, src, v, adjoint), dtype = float) + + + # def _eDeriv(self, tInd, src, dun_dm_v, v, adjoint=False): + # if adjoint is True: + # return self._eDeriv_u(tInd, src, v, adjoint), self._eDeriv_m(tInd, src, v, adjoint) + # return self._eDeriv_u(tInd, src, dun_dm_v) + self._eDeriv_m(tInd, src, v) + + # def _bDeriv(self, tInd, src, dun_dm_v, v, adjoint=False): + # if adjoint is True: + # return self._bDeriv_u(tInd, src, v, adjoint), self._bDeriv_m(tInd, src, v, adjoint) + # return self._bDeriv_u(tInd, src, dun_dm_v) + self._bDeriv_m(tInd, src, v) + + +class Fields_ky_CC(Fields_ky): + knownFields = {'phiSolution':'CC'} + aliasFields = { + 'phi': ['phiSolution','CC','_phi'], + 'j' : ['phiSolution','F','_j'], + 'e' : ['phiSolution','F','_e'], + } + # primary - secondary + # CC variables + + def __init__(self, mesh, survey, **kwargs): + Fields_ky.__init__(self, mesh, survey, **kwargs) + + def startup(self): + self.prob = self.survey.prob + + def _GLoc(self, fieldType): + if fieldType == 'phi': + return 'CC' + elif fieldType == 'e' or fieldType == 'j': + return 'F' + else: + raise Exception('Field type must be phi, e, j') + + def _phi(self, phiSolution, src, kyInd): + return phiSolution + + def _phiDeriv_u(self, kyInd, src, v, adjoint = False): + return Identity()*v + + def _phiDeriv_m(self, kyInd, src, v, adjoint = False): + return Zero() + + def _j(self, phiSolution, srcList): + raise NotImplementedError + + def _e(self, phiSolution, srcList): + raise NotImplementedError diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py new file mode 100644 index 00000000..ee04a560 --- /dev/null +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -0,0 +1,235 @@ +from SimPEG import Problem, Utils +from SimPEG.EM.Base import BaseEMProblem +from SurveyDC import Survey, Survey_ky +from FieldsDC_2D import Fields_ky, Fields_ky_CC +from SimPEG.Utils import sdiag +import numpy as np +from SimPEG.Utils import Zero +from BoundaryUtils import getxBCyBC_CC + +class BaseDCProblem_2D(BaseEMProblem): + + surveyPair = Survey_ky + fieldsPair = Fields_ky + nky = 15 + ky = np.logspace(-4, 1, nky) + Ainv = [None for i in range(nky)] + nT = nky # Only for using TimeFields + + def fields(self, m): + self.curModel = m + + if not self.Ainv[0] == None: + for i in range(self.nky): + self.Ainv[i].clean() + + f = self.fieldsPair(self.mesh, self.survey) + Srcs = self.survey.srcList + for iky in range(self.nky): + ky = self.ky[iky] + A = self.getA(ky) + self.Ainv[iky] = self.Solver(A, **self.solverOpts) + RHS = self.getRHS(ky) + u = self.Ainv[iky] * RHS + f[Srcs, self._solutionType, iky] = u + return f + + # def Jvec(self, m, v, f=None): + + # if f is None: + # f = self.fields(m) + + # self.curModel = m + + # Jv = self.dataPair(self.survey) #same size as the data + + # A = self.getA() + + # for src in self.survey.srcList: + # u_src = f[src, self._solutionType] # solution vector + # dA_dm_v = self.getADeriv(u_src, v) + # dRHS_dm_v = self.getRHSDeriv(src, v) + # du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) + + # for rx in src.rxList: + # df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + # df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + # Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + # return Utils.mkvc(Jv) + + # def Jtvec(self, m, v, f=None): + # if f is None: + # f = self.fields(m) + + # self.curModel = m + + # # Ensure v is a data object. + # if not isinstance(v, self.dataPair): + # v = self.dataPair(self.survey, v) + + # Jtv = np.zeros(m.size) + # AT = self.getA() + + + # for src in self.survey.srcList: + # u_src = f[src, self._solutionType] + # for rx in src.rxList: + # PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + # df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + # df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + + # ATinvdf_duT = self.Ainv * df_duT + + # dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + # dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + # du_dmT = -dA_dmT + dRHS_dmT + # Jtv += df_dmT + du_dmT + + # return Utils.mkvc(Jtv) + + def getSourceTerm(self, ky): + """ + takes concept of source and turns it into a matrix + """ + """ + Evaluates the sources, and puts them in matrix form + + :rtype: (numpy.ndarray, numpy.ndarray) + :return: q (nC or nN, nSrc) + """ + + Srcs = self.survey.srcList + + if self._formulation is 'EB': + n = self.mesh.nN + # return NotImplementedError + + elif self._formulation is 'HJ': + n = self.mesh.nC + + q = np.zeros((n, len(Srcs))) + + for i, src in enumerate(Srcs): + q[:,i] = src.eval(self) + return q + +class Problem2D_CC(BaseDCProblem_2D): + + _solutionType = 'phiSolution' + _formulation = 'HJ' # CC potentials means J is on faces + fieldsPair = Fields_ky_CC + + def __init__(self, mesh, **kwargs): + BaseDCProblem_2D.__init__(self, mesh, **kwargs) + self.setBC() + + def getA(self, ky): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + D = self.Div + G = self.Grad + vol = self.mesh.vol + # TODO: this won't work for full anisotropy + MfRhoI = self.MfRhoI + # Get resistivity rho + rho = self.curModel.rho + A = D * MfRhoI * G + Utils.sdiag(ky**2*vol/rho) + return A + + def getADeriv(self, ky, u, v, adjoint= False): + + D = self.Div + G = self.Grad + MfRhoIDeriv = self.MfRhoIDeriv + + if adjoint: + return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + Utils.sdiag(ky**2*mesh.vol)*v + return D * ((MfRhoIDeriv( G * u )) * v) + Utils.sdiag(ky**2*mesh.vol)*v + + def getRHS(self, ky): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm(ky) + return RHS + + def getRHSDeriv(self, ky, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, ky, adjoint=adjoint) + # return qDeriv + return Zero() + + def setBC(self): + if self.mesh.dim==3: + fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + gBFzm = self.mesh.gridFz[fzm,:] + gBFzp = self.mesh.gridFz[fzp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + alpha_zm, alpha_zp = temp_zm*0., temp_zp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + beta_zm, beta_zp = temp_zm, temp_zp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + gamma_zm, gamma_zp = temp_zm*0., temp_zp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] + + elif self.mesh.dim==2: + + fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] + + x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma) + V = self.Vol + self.Div = V * self.mesh.faceDiv + P_BC, B = self.mesh.getBCProjWF_simple() + M = B*self.mesh.aveCC2F + self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py index 7d50392e..f7c7d352 100644 --- a/SimPEG/EM/Static/DC/RxDC.py +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -1,5 +1,5 @@ import SimPEG -# from SimPEG.EM.Base import BaseEMSurvey +import numpy as np from SimPEG.Utils import Zero, closestPoints class BaseRx(SimPEG.Survey.BaseRx): @@ -43,9 +43,6 @@ class BaseRx(SimPEG.Survey.BaseRx): elif adjoint: return P.T*v - - - # DC.Rx.Dipole(locs) class Dipole(BaseRx): @@ -77,6 +74,56 @@ class Dipole(BaseRx): return P -# class Pole(BaseRx): +class Dipole_ky(BaseRx): + + def __init__(self, locsM, locsN, rxType = 'phi', **kwargs): + assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size' + locs = [locsM, locsN] + # We may not need this ... + BaseRx.__init__(self, locs, rxType) + + @property + def nD(self): + """Number of data in the receiver.""" + return self.locs[0].shape[0] + + # Not sure why ... + # return int(self.locs[0].size / 2) + + def getP(self, mesh, Gloc): + if mesh in self._Ps: + return self._Ps[mesh] + + P0 = mesh.getInterpolationMat(self.locs[0], Gloc) + P1 = mesh.getInterpolationMat(self.locs[1], Gloc) + P = P0 - P1 + if self.storeProjections: + self._Ps[mesh] = P + return P + + def eval(self, ky, src, mesh, f): + P = self.getP(mesh, self.projGLoc(f)) + Pf = P*f[src, self.projField,:] + return self.IntTrapezoidal(ky, Pf, y=0.) + + def evalDeriv(self, ky, src, mesh, f, v, adjoint=False): + P = self.getP(mesh, self.projGLoc(f)) + if not adjoint: + return P*v + elif adjoint: + return P.T*v + + def IntTrapezoidal(self, ky, Pf, y=0.): + phi = np.zeros(Pf.shape[0]) + nky = ky.size + dky = np.diff(ky) + dky = np.r_[dky[0], dky] + phi0 = Pf[:,0] + for iky in range(nky): + phi1 = 2./np.pi*Pf[:,iky]/2. + phi += phi1*dky[iky]/2.*np.cos(ky[iky]*y) + phi += phi0*dky[iky]/2.*np.cos(ky[iky]*y) + phi0 = phi1.copy() + return phi diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 7879ba0c..60a53dff 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -57,5 +57,3 @@ class Pole(BaseSrc): q[inds] = self.current * np.r_[1.] return q - # def bc_contribution - diff --git a/SimPEG/EM/Static/DC/SurveyDC.py b/SimPEG/EM/Static/DC/SurveyDC.py index 3b631bef..62e2922a 100644 --- a/SimPEG/EM/Static/DC/SurveyDC.py +++ b/SimPEG/EM/Static/DC/SurveyDC.py @@ -1,6 +1,6 @@ import SimPEG from SimPEG.EM.Base import BaseEMSurvey -from SimPEG import sp +from SimPEG import sp, Survey from SimPEG.Utils import Zero, Identity from RxDC import BaseRx from SrcDC import BaseSrc @@ -13,6 +13,24 @@ class Survey(BaseEMSurvey): self.srcList = srcList BaseEMSurvey.__init__(self, srcList, **kwargs) +class Survey_ky(BaseEMSurvey): + rxPair = BaseRx + srcPair = BaseSrc + def __init__(self, srcList, **kwargs): + self.srcList = srcList + BaseEMSurvey.__init__(self, srcList, **kwargs) - + def eval(self, f): + """ + Project fields to receiver locations + :param Fields u: fields object + :rtype: numpy.ndarray + :return: data + """ + data = SimPEG.Survey.Data(self) + ky = self.prob.ky + for src in self.srcList: + for rx in src.rxList: + data[src, rx] = rx.eval(ky, src, self.mesh, f) + return data diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py index 82cf76d5..8c790084 100644 --- a/SimPEG/EM/Static/DC/__init__.py +++ b/SimPEG/EM/Static/DC/__init__.py @@ -1,5 +1,6 @@ from ProblemDC import Problem3D_CC, Problem3D_N -from SurveyDC import Survey +from ProblemDC_2D import Problem2D_CC +from SurveyDC import Survey, Survey_ky import SrcDC as Src #Pole import RxDC as Rx from FieldsDC import Fields_CC From 0610289fdf049196b0a539593727920bd8b13060 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 28 Apr 2016 11:18:37 -0700 Subject: [PATCH 091/168] Working Jvec for 2.5D DC code --- SimPEG/EM/Static/DC/FieldsDC_2D.py | 3 +- SimPEG/EM/Static/DC/ProblemDC_2D.py | 62 ++++++---- SimPEG/EM/Static/DC/RxDC.py | 18 +-- SimPEG/EM/Static/DC/SrcDC.py | 5 - SimPEG/EM/Static/DC/SurveyDC.py | 4 +- tests/em/static/test_DC_2D_jvecjtvecadj.py | 127 +++++++++++++++++++++ 6 files changed, 180 insertions(+), 39 deletions(-) create mode 100644 tests/em/static/test_DC_2D_jvecjtvecadj.py diff --git a/SimPEG/EM/Static/DC/FieldsDC_2D.py b/SimPEG/EM/Static/DC/FieldsDC_2D.py index 77e3199e..5b75031d 100644 --- a/SimPEG/EM/Static/DC/FieldsDC_2D.py +++ b/SimPEG/EM/Static/DC/FieldsDC_2D.py @@ -1,5 +1,6 @@ import SimPEG -import Utils, numpy as np, scipy.sparse as sp +from SimPEG.Utils import Identity, Zero +import numpy as np class Fields_ky(SimPEG.Problem.TimeFields): diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index ee04a560..8ebb9c67 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -12,7 +12,7 @@ class BaseDCProblem_2D(BaseEMProblem): surveyPair = Survey_ky fieldsPair = Fields_ky nky = 15 - ky = np.logspace(-4, 1, nky) + kys = np.logspace(-4, 1, nky) Ainv = [None for i in range(nky)] nT = nky # Only for using TimeFields @@ -26,7 +26,7 @@ class BaseDCProblem_2D(BaseEMProblem): f = self.fieldsPair(self.mesh, self.survey) Srcs = self.survey.srcList for iky in range(self.nky): - ky = self.ky[iky] + ky = self.kys[iky] A = self.getA(ky) self.Ainv[iky] = self.Solver(A, **self.solverOpts) RHS = self.getRHS(ky) @@ -34,28 +34,44 @@ class BaseDCProblem_2D(BaseEMProblem): f[Srcs, self._solutionType, iky] = u return f - # def Jvec(self, m, v, f=None): + def Jvec(self, m, v, f=None): - # if f is None: - # f = self.fields(m) + if f is None: + f = self.fields(m) - # self.curModel = m + self.curModel = m - # Jv = self.dataPair(self.survey) #same size as the data + Jv = self.dataPair(self.survey) #same size as the data + Jv0 = self.dataPair(self.survey) - # A = self.getA() + # Assume y=0. + # This needs some thoughts to implement in general when src is dipole + dky = np.diff(self.kys) + dky = np.r_[dky[0], dky] + y = 0. - # for src in self.survey.srcList: - # u_src = f[src, self._solutionType] # solution vector - # dA_dm_v = self.getADeriv(u_src, v) - # dRHS_dm_v = self.getRHSDeriv(src, v) - # du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) - - # for rx in src.rxList: - # df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) - # df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) - # Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) - # return Utils.mkvc(Jv) + for iky in range(self.nky): + ky = self.kys[iky] + A = self.getA(ky) + for src in self.survey.srcList: + u_src = f[src, self._solutionType, iky] # solution vector + dA_dm_v = self.getADeriv(ky, u_src, v) + dRHS_dm_v = self.getRHSDeriv(ky, src, v) + du_dm_v = self.Ainv[iky] * ( - dA_dm_v + dRHS_dm_v ) + for rx in src.rxList: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False) + # Trapezoidal intergration + Jv1_temp = 1./np.pi*rx.evalDeriv(ky, src, self.mesh, f, df_dm_v) + if iky==0: + #First assigment + Jv[src, rx] = Jv1_temp*dky[iky]*np.cos(ky*y) + else: + Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y) + Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y) + Jv0[src, rx] = Jv1_temp.copy() + JV[iky,isrc,:] = Jv1_temp.copy() + return Utils.mkvc(Jv) # def Jtvec(self, m, v, f=None): # if f is None: @@ -146,11 +162,13 @@ class Problem2D_CC(BaseDCProblem_2D): D = self.Div G = self.Grad + vol = self.mesh.vol MfRhoIDeriv = self.MfRhoIDeriv - + rho = self.curModel.rho if adjoint: - return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + Utils.sdiag(ky**2*mesh.vol)*v - return D * ((MfRhoIDeriv( G * u )) * v) + Utils.sdiag(ky**2*mesh.vol)*v + return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v + + return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v def getRHS(self, ky): """ diff --git a/SimPEG/EM/Static/DC/RxDC.py b/SimPEG/EM/Static/DC/RxDC.py index f7c7d352..d2ec6098 100644 --- a/SimPEG/EM/Static/DC/RxDC.py +++ b/SimPEG/EM/Static/DC/RxDC.py @@ -102,10 +102,10 @@ class Dipole_ky(BaseRx): self._Ps[mesh] = P return P - def eval(self, ky, src, mesh, f): + def eval(self, kys, src, mesh, f): P = self.getP(mesh, self.projGLoc(f)) Pf = P*f[src, self.projField,:] - return self.IntTrapezoidal(ky, Pf, y=0.) + return self.IntTrapezoidal(kys, Pf, y=0.) def evalDeriv(self, ky, src, mesh, f, v, adjoint=False): P = self.getP(mesh, self.projGLoc(f)) @@ -114,16 +114,16 @@ class Dipole_ky(BaseRx): elif adjoint: return P.T*v - def IntTrapezoidal(self, ky, Pf, y=0.): + def IntTrapezoidal(self, kys, Pf, y=0.): phi = np.zeros(Pf.shape[0]) - nky = ky.size - dky = np.diff(ky) + nky = kys.size + dky = np.diff(kys) dky = np.r_[dky[0], dky] - phi0 = Pf[:,0] + phi0 = 1./np.pi*Pf[:,0] for iky in range(nky): - phi1 = 2./np.pi*Pf[:,iky]/2. - phi += phi1*dky[iky]/2.*np.cos(ky[iky]*y) - phi += phi0*dky[iky]/2.*np.cos(ky[iky]*y) + phi1 = 1./np.pi*Pf[:,iky] + phi += phi1*dky[iky]/2.*np.cos(kys[iky]*y) + phi += phi0*dky[iky]/2.*np.cos(kys[iky]*y) phi0 = phi1.copy() return phi diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 60a53dff..5f4ac0e2 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -36,11 +36,6 @@ class Dipole(BaseSrc): q = self.current * mkvc(qa+qb) return q - # def bc_contribution - - -# How to treat boundary conditions here - class Pole(BaseSrc): def __init__(self, rxList, loc, **kwargs): diff --git a/SimPEG/EM/Static/DC/SurveyDC.py b/SimPEG/EM/Static/DC/SurveyDC.py index 62e2922a..fb3d49a7 100644 --- a/SimPEG/EM/Static/DC/SurveyDC.py +++ b/SimPEG/EM/Static/DC/SurveyDC.py @@ -29,8 +29,8 @@ class Survey_ky(BaseEMSurvey): :return: data """ data = SimPEG.Survey.Data(self) - ky = self.prob.ky + kys = self.prob.kys for src in self.srcList: for rx in src.rxList: - data[src, rx] = rx.eval(ky, src, self.mesh, f) + data[src, rx] = rx.eval(kys, src, self.mesh, f) return data diff --git a/tests/em/static/test_DC_2D_jvecjtvecadj.py b/tests/em/static/test_DC_2D_jvecjtvecadj.py new file mode 100644 index 00000000..ad7198e9 --- /dev/null +++ b/tests/em/static/test_DC_2D_jvecjtvecadj.py @@ -0,0 +1,127 @@ +import unittest +from SimPEG import * +import SimPEG.EM.Static.DC as DC + + +class DCProblem_2DTestsCC(unittest.TestCase): + + def setUp(self): + + cs = 12.5 + hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy],x0="CN") + x = np.linspace(-135, 250., 20) + M = Utils.ndgrid(x-12.5, np.r_[0.]) + N = Utils.ndgrid(x+12.5, np.r_[0.]) + A0loc = np.r_[-150, 0.] + A1loc = np.r_[-130, 0.] + rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + rx = DC.Rx.Dipole_ky(M, N) + src0 = DC.Src.Pole([rx], A0loc) + src1 = DC.Src.Pole([rx], A1loc) + survey = DC.Survey_ky([src0, src1]) + problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) + problem.pair(survey) + + mSynth = np.ones(mesh.nC) + survey.makeSyntheticData(mSynth) + + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + # def test_adjoint(self): + # # Adjoint Test + # u = np.random.rand(self.mesh.nC*self.survey.nSrc) + # v = np.random.rand(self.mesh.nC) + # w = np.random.rand(self.survey.dobs.shape[0]) + # wtJv = w.dot(self.p.Jvec(self.m0, v)) + # vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + # passed = np.abs(wtJv - vtJtw) < 1e-10 + # print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + # self.assertTrue(passed) + + # def test_dataObj(self): + # derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + # self.assertTrue(passed) + +# class DCProblemTestsN(unittest.TestCase): + +# def setUp(self): + +# aSpacing=2.5 +# nElecs=10 + +# surveySize = nElecs*aSpacing - aSpacing +# cs = surveySize/nElecs/4 + +# mesh = Mesh.TensorMesh([ +# [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], +# [(cs,3, -1.3),(cs,3,1.3)], +# # [(cs,5, -1.3),(cs,10)] +# ],'CN') + +# srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) +# survey = DC.Survey(srcList) +# problem = DC.Problem3D_N(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) +# problem.pair(survey) + +# mSynth = np.ones(mesh.nC) +# survey.makeSyntheticData(mSynth) + +# # Now set up the problem to do some minimization +# dmis = DataMisfit.l2_DataMisfit(survey) +# reg = Regularization.Tikhonov(mesh) +# opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) +# invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) +# inv = Inversion.BaseInversion(invProb) + +# self.inv = inv +# self.reg = reg +# self.p = problem +# self.mesh = mesh +# self.m0 = mSynth +# self.survey = survey +# self.dmis = dmis + +# def test_misfit(self): +# derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] +# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) +# self.assertTrue(passed) + +# def test_adjoint(self): +# # Adjoint Test +# u = np.random.rand(self.mesh.nC*self.survey.nSrc) +# v = np.random.rand(self.mesh.nC) +# w = np.random.rand(self.survey.dobs.shape[0]) +# wtJv = w.dot(self.p.Jvec(self.m0, v)) +# vtJtw = v.dot(self.p.Jtvec(self.m0, w)) +# passed = np.abs(wtJv - vtJtw) < 1e-8 +# print 'Adjoint Test', np.abs(wtJv - vtJtw), passed +# self.assertTrue(passed) + +# def test_dataObj(self): +# derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] +# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) +# self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() From ef602eaab1f03dfbfb5bba8b55170f4968f4dca4 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 28 Apr 2016 18:13:18 -0700 Subject: [PATCH 092/168] working Jtvec --- SimPEG/EM/Static/DC/ProblemDC_2D.py | 64 ++++++++++++++-------- tests/em/static/test_DC_2D_jvecjtvecadj.py | 32 +++++------ 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index 8ebb9c67..30c10d97 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -70,38 +70,57 @@ class BaseDCProblem_2D(BaseEMProblem): Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y) Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y) Jv0[src, rx] = Jv1_temp.copy() - JV[iky,isrc,:] = Jv1_temp.copy() return Utils.mkvc(Jv) - # def Jtvec(self, m, v, f=None): - # if f is None: - # f = self.fields(m) + def Jtvec(self, m, v, f=None): + if f is None: + f = self.fields(m) - # self.curModel = m + self.curModel = m - # # Ensure v is a data object. - # if not isinstance(v, self.dataPair): - # v = self.dataPair(self.survey, v) + # Ensure v is a data object. + if not isinstance(v, self.dataPair): + v = self.dataPair(self.survey, v) - # Jtv = np.zeros(m.size) - # AT = self.getA() + Jtv = np.zeros(m.size) + + # Assume y=0. + # This needs some thoughts to implement in general when src is dipole + dky = np.diff(self.kys) + dky = np.r_[dky[0], dky] + y = 0. - # for src in self.survey.srcList: - # u_src = f[src, self._solutionType] - # for rx in src.rxList: - # PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m - # df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) - # df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + for src in self.survey.srcList: - # ATinvdf_duT = self.Ainv * df_duT + for rx in src.rxList: - # dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) - # dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) - # du_dmT = -dA_dmT + dRHS_dmT - # Jtv += df_dmT + du_dmT + Jtv_temp1 = np.zeros(m.size) + Jtv_temp0 = np.zeros(m.size) - # return Utils.mkvc(Jtv) + for iky in range(self.nky): + u_src = f[src, self._solutionType, iky] + ky = self.kys[iky] + AT = self.getA(ky) + PTv = rx.evalDeriv(ky, src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duT, df_dmT = df_duTFun(iky, src, None, PTv, adjoint=True) + + ATinvdf_duT = self.Ainv[iky] * df_duT + + dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True) + dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True) + du_dmT = -dA_dmT + dRHS_dmT + Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT) + # Trapezoidal intergration + if iky==0: + #First assigment + Jtv += Jtv_temp1*dky[iky]*np.cos(ky*y) + else: + Jtv += Jtv_temp1*dky[iky]/2.*np.cos(ky*y) + Jtv += Jtv_temp0*dky[iky]/2.*np.cos(ky*y) + Jtv_temp0 = Jtv_temp1.copy() + return Utils.mkvc(Jtv) def getSourceTerm(self, ky): """ @@ -167,7 +186,6 @@ class Problem2D_CC(BaseDCProblem_2D): rho = self.curModel.rho if adjoint: return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v - return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v def getRHS(self, ky): diff --git a/tests/em/static/test_DC_2D_jvecjtvecadj.py b/tests/em/static/test_DC_2D_jvecjtvecadj.py index ad7198e9..6beee640 100644 --- a/tests/em/static/test_DC_2D_jvecjtvecadj.py +++ b/tests/em/static/test_DC_2D_jvecjtvecadj.py @@ -24,14 +24,14 @@ class DCProblem_2DTestsCC(unittest.TestCase): problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) problem.pair(survey) - mSynth = np.ones(mesh.nC) + mSynth = np.ones(mesh.nC)*1. survey.makeSyntheticData(mSynth) # Now set up the problem to do some minimization dmis = DataMisfit.l2_DataMisfit(survey) reg = Regularization.Tikhonov(mesh) opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e0) inv = Inversion.BaseInversion(invProb) self.inv = inv @@ -47,21 +47,21 @@ class DCProblem_2DTestsCC(unittest.TestCase): passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) - # def test_adjoint(self): - # # Adjoint Test - # u = np.random.rand(self.mesh.nC*self.survey.nSrc) - # v = np.random.rand(self.mesh.nC) - # w = np.random.rand(self.survey.dobs.shape[0]) - # wtJv = w.dot(self.p.Jvec(self.m0, v)) - # vtJtw = v.dot(self.p.Jtvec(self.m0, w)) - # passed = np.abs(wtJv - vtJtw) < 1e-10 - # print 'Adjoint Test', np.abs(wtJv - vtJtw), passed - # self.assertTrue(passed) + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) - # def test_dataObj(self): - # derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) - # self.assertTrue(passed) + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) # class DCProblemTestsN(unittest.TestCase): From 38aef03f9df81a8660f08873eaf4f0269475a21a Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 29 Apr 2016 09:35:03 -0700 Subject: [PATCH 093/168] Working 2.5D fwd (nodal discretization) On going Jvec and Jtvec --- SimPEG/EM/Base.py | 2 - SimPEG/EM/Static/DC/FieldsDC_2D.py | 39 +++++ SimPEG/EM/Static/DC/ProblemDC.py | 4 - SimPEG/EM/Static/DC/ProblemDC_2D.py | 90 ++++++++++- SimPEG/EM/Static/DC/SrcDC.py | 5 +- SimPEG/EM/Static/DC/__init__.py | 2 +- tests/em/static/test_DC_2D_jvecjtvecadj.py | 166 ++++++++++----------- 7 files changed, 209 insertions(+), 99 deletions(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index 491dcf71..496f5227 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -134,7 +134,6 @@ class BaseEMProblem(Problem.BaseProblem): """ return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * self.curModel.sigmaDeriv - @property def MeSigmaI(self): """ @@ -157,7 +156,6 @@ class BaseEMProblem(Problem.BaseProblem): return dMeSigmaI_dI * ( dMe_dsig * ( dsig_dm)) # return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma, invMat=True)(u) - @property def MfRho(self): """ diff --git a/SimPEG/EM/Static/DC/FieldsDC_2D.py b/SimPEG/EM/Static/DC/FieldsDC_2D.py index 5b75031d..da1fbf97 100644 --- a/SimPEG/EM/Static/DC/FieldsDC_2D.py +++ b/SimPEG/EM/Static/DC/FieldsDC_2D.py @@ -105,3 +105,42 @@ class Fields_ky_CC(Fields_ky): def _e(self, phiSolution, srcList): raise NotImplementedError + +class Fields_ky_N(Fields_ky): + knownFields = {'phiSolution':'N'} + aliasFields = { + 'phi': ['phiSolution','N','_phi'], + 'j' : ['phiSolution','E','_j'], + 'e' : ['phiSolution','E','_e'], + } + # primary - secondary + # CC variables + + def __init__(self, mesh, survey, **kwargs): + Fields_ky.__init__(self, mesh, survey, **kwargs) + + def startup(self): + self.prob = self.survey.prob + + def _GLoc(self, fieldType): + if fieldType == 'phi': + return 'N' + elif fieldType == 'e' or fieldType == 'j': + return 'E' + else: + raise Exception('Field type must be phi, e, j') + + def _phi(self, phiSolution, src, kyInd): + return phiSolution + + def _phiDeriv_u(self, kyInd, src, v, adjoint = False): + return Identity()*v + + def _phiDeriv_m(self, kyInd, src, v, adjoint = False): + return Zero() + + def _j(self, phiSolution, srcList): + raise NotImplementedError + + def _e(self, phiSolution, srcList): + raise NotImplementedError diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 9f05d876..0dd4f259 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -267,8 +267,6 @@ class Problem3D_N(BaseDCProblem): # Handling Null space of A A[0,0] = A[0,0] + 1. - # if self._makeASymmetric is True: - # return V.T * A return A def getADeriv(self, u, v, adjoint=False): @@ -293,8 +291,6 @@ class Problem3D_N(BaseDCProblem): """ RHS = self.getSourceTerm() - # if self._makeASymmetric is True: - # return self.Vol.T * RHS return RHS def getRHSDeriv(self, src, v, adjoint=False): diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index 30c10d97..2b5ed305 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -1,7 +1,7 @@ from SimPEG import Problem, Utils from SimPEG.EM.Base import BaseEMProblem from SurveyDC import Survey, Survey_ky -from FieldsDC_2D import Fields_ky, Fields_ky_CC +from FieldsDC_2D import Fields_ky, Fields_ky_CC, Fields_ky_N from SimPEG.Utils import sdiag import numpy as np from SimPEG.Utils import Zero @@ -90,14 +90,10 @@ class BaseDCProblem_2D(BaseEMProblem): dky = np.r_[dky[0], dky] y = 0. - for src in self.survey.srcList: - for rx in src.rxList: - Jtv_temp1 = np.zeros(m.size) Jtv_temp0 = np.zeros(m.size) - for iky in range(self.nky): u_src = f[src, self._solutionType, iky] ky = self.kys[iky] @@ -152,7 +148,7 @@ class Problem2D_CC(BaseDCProblem_2D): _solutionType = 'phiSolution' _formulation = 'HJ' # CC potentials means J is on faces - fieldsPair = Fields_ky_CC + fieldsPair = Fields_ky_N def __init__(self, mesh, **kwargs): BaseDCProblem_2D.__init__(self, mesh, **kwargs) @@ -269,3 +265,85 @@ class Problem2D_CC(BaseDCProblem_2D): P_BC, B = self.mesh.getBCProjWF_simple() M = B*self.mesh.aveCC2F self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M + +class Problem2D_N(BaseDCProblem_2D): + + _solutionType = 'phiSolution' + _formulation = 'EB' # CC potentials means J is on faces + fieldsPair = Fields_ky_N + + def __init__(self, mesh, **kwargs): + BaseDCProblem_2D.__init__(self, mesh, **kwargs) + # self.setBC() + + @property + def MnSigma(self): + """ + Node inner product matrix for \\(\\sigma\\). Used in the E-B formulation + """ + # TODO: only works isotropic sigma + sigma = self.curModel.sigma + vol = self.mesh.vol + MnSigma = Utils.sdiag(self.mesh.aveN2CC.T*(Utils.sdiag(vol)*sigma)) + + return MnSigma + + def MnSigmaDeriv(self, u): + """ + Derivative of MnSigma with respect to the model + """ + sigma = self.curModel.sigma + sigmaderiv = self.curModel.sigmaDeriv + vol = self.mesh.vol + return Utils.sdiag(u)*self.mesh.aveN2CC.T*Utils.sdiag(vol) * self.curModel.sigmaDeriv + + def getA(self, ky): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + MeSigma = self.MeSigma + MnSigma = self.MnSigma + Grad = self.mesh.nodalGrad + # Get conductivity sigma + sigma = self.curModel.sigma + A = Grad.T * MeSigma * Grad + ky**2*MnSigma + + # Handling Null space of A + A[0,0] = A[0,0] + 1. + return A + + def getADeriv(self, ky, u, v, adjoint= False): + + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + sigma = self.curModel.sigma + vol = self.mesh.vol + + if adjoint: + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u)*v + + def getRHS(self, ky): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm(ky) + return RHS + + def getRHSDeriv(self, ky, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, ky, adjoint=adjoint) + # return qDeriv + return Zero() diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 5f4ac0e2..02dae23e 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -47,8 +47,7 @@ class Pole(BaseSrc): q = np.zeros(prob.mesh.nC) q[inds] = self.current * np.r_[1.] elif prob._formulation == 'EB': - inds = closestPoints(prob.mesh, self.loc) - q = np.zeros(prob.mesh.nN) - q[inds] = self.current * np.r_[1.] + q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense() + q = self.current * mkvc(q) return q diff --git a/SimPEG/EM/Static/DC/__init__.py b/SimPEG/EM/Static/DC/__init__.py index 8c790084..1080e391 100644 --- a/SimPEG/EM/Static/DC/__init__.py +++ b/SimPEG/EM/Static/DC/__init__.py @@ -1,5 +1,5 @@ from ProblemDC import Problem3D_CC, Problem3D_N -from ProblemDC_2D import Problem2D_CC +from ProblemDC_2D import Problem2D_CC, Problem2D_N from SurveyDC import Survey, Survey_ky import SrcDC as Src #Pole import RxDC as Rx diff --git a/tests/em/static/test_DC_2D_jvecjtvecadj.py b/tests/em/static/test_DC_2D_jvecjtvecadj.py index 6beee640..0740adc7 100644 --- a/tests/em/static/test_DC_2D_jvecjtvecadj.py +++ b/tests/em/static/test_DC_2D_jvecjtvecadj.py @@ -3,7 +3,67 @@ from SimPEG import * import SimPEG.EM.Static.DC as DC -class DCProblem_2DTestsCC(unittest.TestCase): +# class DCProblem_2DTestsCC(unittest.TestCase): + +# def setUp(self): + +# cs = 12.5 +# hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] +# hy = [(cs,7, -1.3),(cs,20)] +# mesh = Mesh.TensorMesh([hx, hy],x0="CN") +# x = np.linspace(-135, 250., 20) +# M = Utils.ndgrid(x-12.5, np.r_[0.]) +# N = Utils.ndgrid(x+12.5, np.r_[0.]) +# A0loc = np.r_[-150, 0.] +# A1loc = np.r_[-130, 0.] +# rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] +# rx = DC.Rx.Dipole_ky(M, N) +# src0 = DC.Src.Pole([rx], A0loc) +# src1 = DC.Src.Pole([rx], A1loc) +# survey = DC.Survey_ky([src0, src1]) +# problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) +# problem.pair(survey) + +# mSynth = np.ones(mesh.nC)*1. +# survey.makeSyntheticData(mSynth) + +# # Now set up the problem to do some minimization +# dmis = DataMisfit.l2_DataMisfit(survey) +# reg = Regularization.Tikhonov(mesh) +# opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) +# invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e0) +# inv = Inversion.BaseInversion(invProb) + +# self.inv = inv +# self.reg = reg +# self.p = problem +# self.mesh = mesh +# self.m0 = mSynth +# self.survey = survey +# self.dmis = dmis + +# def test_misfit(self): +# derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] +# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) +# self.assertTrue(passed) + +# def test_adjoint(self): +# # Adjoint Test +# u = np.random.rand(self.mesh.nC*self.survey.nSrc) +# v = np.random.rand(self.mesh.nC) +# w = np.random.rand(self.survey.dobs.shape[0]) +# wtJv = w.dot(self.p.Jvec(self.m0, v)) +# vtJtw = v.dot(self.p.Jtvec(self.m0, w)) +# passed = np.abs(wtJv - vtJtw) < 1e-10 +# print 'Adjoint Test', np.abs(wtJv - vtJtw), passed +# self.assertTrue(passed) + +# def test_dataObj(self): +# derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] +# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) +# self.assertTrue(passed) + +class DCProblemTestsN(unittest.TestCase): def setUp(self): @@ -21,7 +81,7 @@ class DCProblem_2DTestsCC(unittest.TestCase): src0 = DC.Src.Pole([rx], A0loc) src1 = DC.Src.Pole([rx], A1loc) survey = DC.Survey_ky([src0, src1]) - problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) + problem = DC.Problem2D_N(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) problem.pair(survey) mSynth = np.ones(mesh.nC)*1. @@ -34,94 +94,34 @@ class DCProblem_2DTestsCC(unittest.TestCase): invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e0) inv = Inversion.BaseInversion(invProb) - self.inv = inv - self.reg = reg - self.p = problem - self.mesh = mesh - self.m0 = mSynth + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth self.survey = survey - self.dmis = dmis + self.dmis = dmis def test_misfit(self): derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) self.assertTrue(passed) - def test_adjoint(self): - # Adjoint Test - u = np.random.rand(self.mesh.nC*self.survey.nSrc) - v = np.random.rand(self.mesh.nC) - w = np.random.rand(self.survey.dobs.shape[0]) - wtJv = w.dot(self.p.Jvec(self.m0, v)) - vtJtw = v.dot(self.p.Jtvec(self.m0, w)) - passed = np.abs(wtJv - vtJtw) < 1e-10 - print 'Adjoint Test', np.abs(wtJv - vtJtw), passed - self.assertTrue(passed) + # def test_adjoint(self): + # # Adjoint Test + # u = np.random.rand(self.mesh.nC*self.survey.nSrc) + # v = np.random.rand(self.mesh.nC) + # w = np.random.rand(self.survey.dobs.shape[0]) + # wtJv = w.dot(self.p.Jvec(self.m0, v)) + # vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + # passed = np.abs(wtJv - vtJtw) < 1e-8 + # print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + # self.assertTrue(passed) - def test_dataObj(self): - derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) - self.assertTrue(passed) - -# class DCProblemTestsN(unittest.TestCase): - -# def setUp(self): - -# aSpacing=2.5 -# nElecs=10 - -# surveySize = nElecs*aSpacing - aSpacing -# cs = surveySize/nElecs/4 - -# mesh = Mesh.TensorMesh([ -# [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], -# [(cs,3, -1.3),(cs,3,1.3)], -# # [(cs,5, -1.3),(cs,10)] -# ],'CN') - -# srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) -# survey = DC.Survey(srcList) -# problem = DC.Problem3D_N(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) -# problem.pair(survey) - -# mSynth = np.ones(mesh.nC) -# survey.makeSyntheticData(mSynth) - -# # Now set up the problem to do some minimization -# dmis = DataMisfit.l2_DataMisfit(survey) -# reg = Regularization.Tikhonov(mesh) -# opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) -# invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) -# inv = Inversion.BaseInversion(invProb) - -# self.inv = inv -# self.reg = reg -# self.p = problem -# self.mesh = mesh -# self.m0 = mSynth -# self.survey = survey -# self.dmis = dmis - -# def test_misfit(self): -# derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] -# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) -# self.assertTrue(passed) - -# def test_adjoint(self): -# # Adjoint Test -# u = np.random.rand(self.mesh.nC*self.survey.nSrc) -# v = np.random.rand(self.mesh.nC) -# w = np.random.rand(self.survey.dobs.shape[0]) -# wtJv = w.dot(self.p.Jvec(self.m0, v)) -# vtJtw = v.dot(self.p.Jtvec(self.m0, w)) -# passed = np.abs(wtJv - vtJtw) < 1e-8 -# print 'Adjoint Test', np.abs(wtJv - vtJtw), passed -# self.assertTrue(passed) - -# def test_dataObj(self): -# derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] -# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) -# self.assertTrue(passed) + # def test_dataObj(self): + # derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + # self.assertTrue(passed) if __name__ == '__main__': unittest.main() From 225394f74e8c03ba5d938cd9eed70f726d4f27b7 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 11:10:04 -0700 Subject: [PATCH 094/168] Latest commit --- SimPEG/Directives.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 3cdb5000..ee29e770 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -258,6 +258,7 @@ class Update_IRLS(InversionDirective): phi_m_last = None phi_d_last = None + def initialize(self): # Scale the regularization for changes in norm @@ -275,7 +276,7 @@ class Update_IRLS(InversionDirective): self.phi_d_last = self.invProb.phi_d def endIter(self): - # Cool the threshold parameter + # Cool the threshold parameter if required if getattr(self, 'factor', None) is not None: eps = self.reg.eps / self.factor @@ -290,16 +291,17 @@ class Update_IRLS(InversionDirective): # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - # Temporarely set gamma to 1. + # Temporarely set gamma to 1. to get raw phi_m self.reg.gamma = 1. - # Compute change in model objective function and update scaling + # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) + # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d - + # Set the weighting matrix to None so that it is recomputed next time + # it is called in the inversion self.reg._W = None class Update_lin_PreCond(InversionDirective): @@ -340,3 +342,19 @@ class Update_Wj(InversionDirective): JtJdiag = JtJdiag / max(JtJdiag) self.reg.wght = JtJdiag + +class Scale_Beta(InversionDirective): + """ + Instead of a linear cooling schedule, beta is allowed to change based + on the ratio between the target misfit and the current data misfit. The + update is done only if the misfit is outside some threshold bounds. + """ + tol = 0.05 + + def endIter(self): + + # Check if misfit is within the tolerance, otherwise adjust beta + val = self.invProb.phi_d / (self.survey.nD*0.5) + + if np.abs(1.-val) > self.tol: + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d From c83b460672df464598600f7b793927d26e4a4605 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:43:31 -0700 Subject: [PATCH 095/168] Surface to Indices (GoCAD and VTK) --- SimPEG/Utils/io_utils.py | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 SimPEG/Utils/io_utils.py diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py new file mode 100644 index 00000000..f68ee68c --- /dev/null +++ b/SimPEG/Utils/io_utils.py @@ -0,0 +1,132 @@ +from SimPEG import np, Mesh +import time as tm +import vtk, vtk.util.numpy_support as npsup +import re + +def read_GOCAD_ts(tsfile): + """ + + Read GOCAD triangulated surface (*.ts) file + INPUT: + tsfile: Triangulated surface + + OUTPUT: + vrts : Array of vertices in XYZ coordinates [n x 3] + trgl : Array of index for triangles [m x 3]. The order of the vertices + is important and describes the normal + n = cross( (P2 - P1 ) , (P3 - P1) ) + + Author: @fourndo + + """ + + + fid = open(tsfile,'r') + line = fid.readline() + + # Skip all the lines until the vertices + while re.match('TFACE',line)==None: + line = fid.readline() + + line = fid.readline() + vrtx = [] + + # Run down all the vertices and save in array + while re.match('VRTX',line): + l_input = re.split('[\s*]',line) + temp = np.array(l_input[2:5]) + vrtx.append(temp.astype(np.float)) + + # Read next line + line = fid.readline() + + vrtx = np.asarray(vrtx) + + # Skip lines to the triangles + while re.match('TRGL',line)==None: + line = fid.readline() + + # Run down the list of triangles + trgl = [] + + # Run down all the vertices and save in array + while re.match('TRGL',line): + l_input = re.split('[\s*]',line) + temp = np.array(l_input[1:4]) + trgl.append(temp.astype(np.int)) + + # Read next line + line = fid.readline() + + trgl = np.asarray(trgl) + + return vrtx, trgl + +def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True): + """" + Function to read gocad polystructure file and output indexes of mesh with in the structure. + + """ + # Adjust the index + trgl = trgl - 1 + + # Make vtk pts + ptsvtk = vtk.vtkPoints() + ptsvtk.SetData(npsup.numpy_to_vtk(vrtx,deep=1)) + + # Make the polygon connection + polys = vtk.vtkCellArray() + for face in trgl: + poly = vtk.vtkPolygon() + poly.GetPointIds().SetNumberOfIds(len(face)) + for nrv, vert in enumerate(face): + poly.GetPointIds().SetId(nrv,vert) + polys.InsertNextCell(poly) + + # Make the polydata, structure of connections and vrtx + polyData = vtk.vtkPolyData() + polyData.SetPoints(ptsvtk) + polyData.SetPolys(polys) + + # Make implicit func + ImpDistFunc = vtk.vtkImplicitPolyDataDistance() + ImpDistFunc.SetInput(polyData) + + # Convert the mesh + vtkMesh = vtk.vtkRectilinearGrid() + vtkMesh.SetDimensions(mesh.nNx,mesh.nNy,mesh.nNz) + vtkMesh.SetXCoordinates(npsup.numpy_to_vtk(mesh.vectorNx, deep=1)) + vtkMesh.SetYCoordinates(npsup.numpy_to_vtk(mesh.vectorNy, deep=1)) + vtkMesh.SetZCoordinates(npsup.numpy_to_vtk(mesh.vectorNz, deep=1)) + # Add indexes + vtkInd = npsup.numpy_to_vtk(np.arange(mesh.nC), deep=1) + vtkInd.SetName('Index') + vtkMesh.GetCellData().AddArray(vtkInd) + + extractImpDistRectGridFilt = vtk.vtkExtractGeometry() # Object constructor + extractImpDistRectGridFilt.SetImplicitFunction(ImpDistFunc) # + extractImpDistRectGridFilt.SetInputData(vtkMesh) + + if boundaries is True: + extractImpDistRectGridFilt.ExtractBoundaryCellsOn() + + else: + extractImpDistRectGridFilt.ExtractBoundaryCellsOff() + + if internal=True is True: + extractImpDistRectGridFilt.ExtractInsideOn() + + else: + extractImpDistRectGridFilt.ExtractInsideOff() + + print "Extracting indices from grid..." + # Executing the pipe + extractImpDistRectGridFilt.Update() + + # Get index inside + insideGrid = extractImpDistRectGridFilt.GetOutput() + insideGrid = npsup.vtk_to_numpy(insideGrid.GetCellData().GetArray('Index')) + + + # Return the indexes inside + return insideGrid From 028a16a45a3f0306e4911f675e29f5acee120de1 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:44:42 -0700 Subject: [PATCH 096/168] Syntax bug. --- SimPEG/Utils/io_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py index f68ee68c..e46c13db 100644 --- a/SimPEG/Utils/io_utils.py +++ b/SimPEG/Utils/io_utils.py @@ -113,7 +113,7 @@ def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True): else: extractImpDistRectGridFilt.ExtractBoundaryCellsOff() - if internal=True is True: + if internal is True: extractImpDistRectGridFilt.ExtractInsideOn() else: From 00db6746d4272dd953773300dc815c0a0ee0008e Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:50:56 -0700 Subject: [PATCH 097/168] Add a warnign about mesh attributes --- SimPEG/Utils/io_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py index e46c13db..323feb0c 100644 --- a/SimPEG/Utils/io_utils.py +++ b/SimPEG/Utils/io_utils.py @@ -18,6 +18,11 @@ def read_GOCAD_ts(tsfile): Author: @fourndo + + .. note:: + + Remove all attributes from the GoCAD surface before exporting it! + """ From a0174e4f3043216cbc302be4fd775cda2674cf95 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 29 Apr 2016 12:52:45 -0700 Subject: [PATCH 098/168] kwarg name updates --- SimPEG/DCIP/DCIPUtils.py | 84 ++++++++++----------- SimPEG/Examples/DC_Forward_PseudoSection.py | 32 ++++---- 2 files changed, 55 insertions(+), 61 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index e94b930f..91eab0b3 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='dpdp', dtype="appc", clim=None): +def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt', clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -177,16 +177,12 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): Assumes flat topo for now... Input: - :param d2D, z0 - :switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole) - :switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential) + :param DCsurvey, z0 + :switch surveyType -> Either 'pole-dipole' | 'dipole-dipole' + :switch unitType=-> Either 'appResistivity' | 'appConductivity' | 'volt' Output: :figure scatter plot overlayed on image - Edited Feb 17th, 2016 - - @author: dominiquef - """ from SimPEG import np from scipy.interpolate import griddata @@ -221,39 +217,39 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): Cmid = (Tx[0][0] + Tx[1][0])/2 Pmid = (Rx[0][:,0] + Rx[1][:,0])/2 - # Change output for dtype - if dtype == 'volt': + # Change output for unitType + if unitType == 'volt': rho = np.hstack([rho,data]) else: # Compute pant leg of apparent rho - if stype == 'pdp': + if surveyType == 'pole-dipole': leg = data * 2*np.pi * MA * ( MA + MN ) / MN - elif stype == 'dpdp': + elif surveyType == 'dipole-dipole': leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) else: - print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """ + print """unitType must be 'pole-dipole' | 'dipole-dipole' """ break - if dtype == 'appc': + if unitType == 'appConductivity': leg = np.log10(abs(1./leg)) rho = np.hstack([rho,leg]) - elif dtype == 'appr': + elif unitType == 'appResistivity': leg = np.log10(abs(leg)) rho = np.hstack([rho,leg]) else: - print """dtype must be 'appr' | 'appc' | 'volt' """ + print """unitType must be 'appResistivity' | 'appConductivity' | 'volt' """ break midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) @@ -278,12 +274,12 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - - if dtype == 'appc': + + if unitType == 'appConductivity': cbar.set_label("App.Cond",size=12) - elif dtype == 'appr': + elif unitType == 'appResistivity': cbar.set_label("App.Res.",size=12) - elif dtype == 'volt': + elif unitType == 'volt': cbar.set_label("Potential (V)",size=12) # Plot apparent resistivity @@ -298,7 +294,7 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): return ph -def gen_DCIPsurvey(endl, mesh, stype, a, b, n): +def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): """ Load in endpoints and survey specifications to generate Tx, Rx location stations. @@ -308,7 +304,7 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): Input: :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] :object mesh -> SimPEG mesh object - :switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient' + :switch surveyType -> 'dipole-dipole' | 'pole-dipole' | 'gradient' : param a, n -> pole seperation, number of rx dipoles per tx Output: @@ -354,14 +350,14 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): SrcList = [] - if stype != 'gradient': + if surveyType != 'gradient': for ii in range(0, int(nstn)-1): - if stype == 'dpdp': + if surveyType == 'dipole-dipole': tx = np.c_[M[ii,:],N[ii,:]] - elif stype == 'pdp': + elif surveyType == 'pole-dipole': tx = np.c_[M[ii,:],M[ii,:]] # Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]]) @@ -390,13 +386,13 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): Rx.append(np.c_[P1,P2]) rxClass = DC.RxDipole(P1, P2) Tx.append(tx) - if stype == 'dpdp': + if surveyType == 'dipole-dipole': srcClass = DC.SrcDipole([rxClass], M[ii,:],N[ii,:]) - elif stype == 'pdp': + elif surveyType == 'pole-dipole': srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:]) SrcList.append(srcClass) - elif stype == 'gradient': + elif surveyType == 'gradient': # Gradient survey only requires Tx at end of line and creates a square # grid of receivers at in the middle at a pre-set minimum distance @@ -443,20 +439,20 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): srcClass = DC.SrcDipole([rxClass], M[0,:], N[-1,:]) SrcList.append(srcClass) else: - print """stype must be either 'pdp', 'dpdp' or 'gradient'. """ + print """surveyType must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """ survey = DC.SurveyDC(SrcList) return survey, Tx, Rx -def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): +def writeUBC_DCobs(fileName, DCsurvey, dim, surveyType): """ Write UBC GIF DCIP 2D or 3D observation file Input: :string fileName -> including path where the file is written out :DCsurvey -> DC survey class object - :string dtype -> either '2D' | '3D' - :string stype -> either 'SURFACE' | 'GENERAL' + :string dim -> either '2D' | '3D' + :string surveyType -> either 'SURFACE' | 'GENERAL' Output: :param UBC2D-Data file @@ -469,11 +465,11 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): """ from SimPEG import mkvc - assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'" - assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'" + assert (dim=='2D') | (dim=='3D'), "Data must be either '2D' | '3D'" + assert (surveyType=='SURFACE') | (surveyType=='GENERAL') | (surveyType=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'" fid = open(fileName,'w') - fid.write('! ' + stype + ' FORMAT\n') + fid.write('! ' + surveyType + ' FORMAT\n') count = 0 @@ -488,10 +484,10 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): M = rx[0] N = rx[1] - # Adapt source-receiver location for dtype and stype - if dtype=='2D': + # Adapt source-receiver location for dim and surveyType + if dim=='2D': - if stype == 'SIMPLE': + if surveyType == 'SIMPLE': #fid.writelines("%e " % ii for ii in mkvc(tx[0,:])) A = np.repeat(tx[0,0],M.shape[0],axis=0) @@ -504,13 +500,13 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): else: - if stype == 'SURFACE': + if surveyType == 'SURFACE': fid.writelines("%e " % ii for ii in mkvc(tx[0,:])) M = M[:,0] N = N[:,0] - if stype == 'GENERAL': + if surveyType == 'GENERAL': fid.writelines("%e " % ii for ii in mkvc(tx[::2,:])) M = M[:,0::2] @@ -519,15 +515,15 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.write('%i\n'% nD) np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') - if dtype=='3D': + if dim=='3D': - if stype == 'SURFACE': + if surveyType == 'SURFACE': fid.writelines("%e " % ii for ii in mkvc(tx[0:2,:])) M = M[:,0:2] N = N[:,0:2] - if stype == 'GENERAL': + if surveyType == 'GENERAL': fid.writelines("%e " % ii for ii in mkvc(tx)) @@ -538,7 +534,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.close() -def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): +def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'): """ Read DC survey and projects the coordinate system according to the flag = 'Xloc' | 'Yloc' | 'local' (default) diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 53467826..240cbb33 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -2,7 +2,7 @@ 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', dtype='appc', plotIt=True): +def run(loc=None, sig=None, radi=None, param=None, surveyType='dipole-dipole', unitType='appConductivity', plotIt=True): """ DC Forward Simulation ===================== @@ -15,14 +15,14 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p 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) + surveyType = survey type 'pole-dipole' or 'dipole-dipole' + unitType = Data type "appResistivity" | "appConductivity" | "volt" Created by @fourndo """ - 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)" + assert surveyType in ['pole-dipole', 'dipole-dipole'], "Source type (surveyType) must be pdp or dpdp (pole dipole or dipole dipole)" + assert unitType in ['appResistivity', 'appConductivity', 'volt'], "Unit type (unitType) must be appResistivity or appConductivity or volt (potential)" if loc is None: loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]] @@ -73,8 +73,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p 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]) - survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2]) + # [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2]) + survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2]) # Define some global geometry dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) @@ -118,8 +118,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p rxloc_N = np.asarray(Rx[ii][:,3:]) - # For usual cases "dpdp" or "gradient" - if stype == 'pdp': + # For usual cases 'dipole-dipole' or "gradient" + if surveyType == 'pole-dipole': # Create an "inifinity" pole tx = np.squeeze(Tx[ii][:,0:1]) tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2 @@ -157,12 +157,12 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p fig = plt.figure(figsize=(7,7)) ax = plt.subplot(2,1,1, aspect='equal') # 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) + 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', + 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') @@ -188,15 +188,13 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p ax2 = plt.subplot(2,1,2, aspect='equal') # 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) + 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 - dat = DC.plot_pseudoSection(survey2D,ax2,stype=stype, dtype = dtype) - - # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') + dat = DC.plot_pseudoSection(survey2D, ax2, surveyType=surveyType, unitType=unitType) # 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') From 4257ea77b357bdab1811ac8f9adfb82845a6cf55 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 29 Apr 2016 15:09:04 -0700 Subject: [PATCH 099/168] remove InjectActiveCellsTopo. you should use InjectActiveCells --- SimPEG/Maps.py | 77 -------------------------------------------------- 1 file changed, 77 deletions(-) diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index f17d2314..3e97499f 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -533,83 +533,6 @@ class ActiveCells(InjectActiveCells): FutureWarning) InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC) -class InjectActiveCellsTopo(IdentityMap): - """ - Active model parameters. Extend for cells on topography to air cell (only works for tensor mesh) - - """ - - indActive = None #: Active Cells - valInactive = None #: Values of inactive Cells - nC = None #: Number of cells in the full model - - def __init__(self, mesh, indActive, nC=None): - self.mesh = mesh - - self.nC = nC or mesh.nC - - if indActive.dtype is not bool: - z = np.zeros(self.nC,dtype=bool) - z[indActive] = True - indActive = z - self.indActive = indActive - - self.indInactive = np.logical_not(indActive) - inds = np.nonzero(self.indActive)[0] - self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP)) - - @property - def shape(self): - return (self.nC, self.nP) - - @property - def nP(self): - """Number of parameters in the model.""" - return self.indActive.sum() - - def _transform(self, m): - val_temp = np.zeros(self.mesh.nC) - val_temp[self.indActive] = m - valInactive = np.zeros(self.mesh.nC) - #1D - if self.mesh.dim == 1: - z_temp = self.mesh.gridCC - val_temp[~self.indActive] = val_temp[np.argmax(z_temp[self.indActive])] - #2D - elif self.mesh.dim == 2: - act_temp = self.indActive.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F') - val_temp = val_temp.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F') - y_temp = self.mesh.gridCC[:,1].reshape((self.mesh.nCx, self.mesh.nCy), order = 'F') - for i in range(self.mesh.nCx): - act_tempx = act_temp[i,:] == 1 - val_temp[i,~act_tempx] = val_temp[i,np.argmax(y_temp[i,act_tempx])] - valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive] - #3D - elif self.mesh.dim == 3: - act_temp = self.indActive.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F') - val_temp = val_temp.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F') - z_temp = self.mesh.gridCC[:,2].reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F') - for i in range(self.mesh.nCx*self.mesh.nCy): - act_tempxy = act_temp[i,:] == 1 - val_temp[i,~act_tempxy] = val_temp[i,np.argmax(z_temp[i,act_tempxy])] - valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive] - - self.valInactive = valInactive - - return self.P*m + self.valInactive - - def inverse(self, D): - return self.P.T*D - - def deriv(self, m): - return self.P - -class ActiveCellsTopo(InjectActiveCellsTopo): - def __init__(self, mesh, indActive, valInactive, nC=None): - warnings.warn( - "`ActiveCellsTopo` is deprecated and will be removed in future versions. Use `InjectActiveCellsTopo` instead", - FutureWarning) - InjectActiveCellsTopo.__init__(self, mesh, indActive, valInactive, nC) class Weighting(IdentityMap): """ From 056dc09fa63a3cc0e6582a915b5605f1f4206338 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 15:10:30 -0700 Subject: [PATCH 100/168] Fix Update_Precondition directive --- SimPEG/Directives.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index ee29e770..b32cd798 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -305,11 +305,24 @@ class Update_IRLS(InversionDirective): self.reg._W = None class Update_lin_PreCond(InversionDirective): - - + """ + Create a Jacobi preconditioner for the linear problem + """ + onlyOnStart=True + + def initialize(self): + + if getattr(self.opt, 'approxHinv', None) is 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 + def endIter(self): # Cool the threshold parameter - + if self.onlyOnStart==True: + return + 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. From 3d1dfc13d7a2d5aee0f0859c1df28fb3be617fcd Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 15:49:44 -0700 Subject: [PATCH 101/168] Change Update_PreConditioner to default False --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index b32cd798..e51c904e 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -308,7 +308,7 @@ class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem """ - onlyOnStart=True + onlyOnStart=False def initialize(self): From 9b2eec0ea34c87ef533bc8c33f06c25382f110ff Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 1 May 2016 12:33:39 -0700 Subject: [PATCH 102/168] Working 2.5D nodal discretization (Jvec and Jtvec) --- SimPEG/EM/Static/DC/ProblemDC_2D.py | 6 ++--- tests/em/static/test_DC_2D_jvecjtvecadj.py | 30 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index 2b5ed305..86f9dc72 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -148,7 +148,7 @@ class Problem2D_CC(BaseDCProblem_2D): _solutionType = 'phiSolution' _formulation = 'HJ' # CC potentials means J is on faces - fieldsPair = Fields_ky_N + fieldsPair = Fields_ky_CC def __init__(self, mesh, **kwargs): BaseDCProblem_2D.__init__(self, mesh, **kwargs) @@ -326,8 +326,8 @@ class Problem2D_N(BaseDCProblem_2D): vol = self.mesh.vol if adjoint: - return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v - return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u)*v + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u).T*v + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v def getRHS(self, ky): """ diff --git a/tests/em/static/test_DC_2D_jvecjtvecadj.py b/tests/em/static/test_DC_2D_jvecjtvecadj.py index 0740adc7..9412614e 100644 --- a/tests/em/static/test_DC_2D_jvecjtvecadj.py +++ b/tests/em/static/test_DC_2D_jvecjtvecadj.py @@ -104,24 +104,24 @@ class DCProblemTestsN(unittest.TestCase): def test_misfit(self): derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] - passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) - # def test_adjoint(self): - # # Adjoint Test - # u = np.random.rand(self.mesh.nC*self.survey.nSrc) - # v = np.random.rand(self.mesh.nC) - # w = np.random.rand(self.survey.dobs.shape[0]) - # wtJv = w.dot(self.p.Jvec(self.m0, v)) - # vtJtw = v.dot(self.p.Jtvec(self.m0, w)) - # passed = np.abs(wtJv - vtJtw) < 1e-8 - # print 'Adjoint Test', np.abs(wtJv - vtJtw), passed - # self.assertTrue(passed) + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-8 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) - # def test_dataObj(self): - # derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] - # passed = Tests.checkDerivative(derChk, self.m0, plotIt=False) - # self.assertTrue(passed) + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) if __name__ == '__main__': unittest.main() From 4df6f340d3f8bfd45695b21650b6ef214da738ac Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 1 May 2016 13:13:20 -0700 Subject: [PATCH 103/168] Add _e, _j, _charge for field objects Now it is possible to gram three of them from phiSolution --- SimPEG/EM/Static/DC/FieldsDC.py | 47 +++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py index 9999c56a..1e5b3744 100644 --- a/SimPEG/EM/Static/DC/FieldsDC.py +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -1,6 +1,7 @@ import SimPEG from SimPEG.Utils import Identity, Zero import numpy as np +from scipy.constants import epsilon_0 class Fields(SimPEG.Problem.Fields): knownFields = {} @@ -38,13 +39,15 @@ class Fields_CC(Fields): 'phi': ['phiSolution','CC','_phi'], 'j' : ['phiSolution','F','_j'], 'e' : ['phiSolution','F','_e'], + 'charge' : ['phiSolution','CC','_charge'], } # primary - secondary # CC variables def __init__(self, mesh, survey, **kwargs): Fields.__init__(self, mesh, survey, **kwargs) - + mesh.setCellGradBC("neumann") + cellGrad = mesh.cellGrad def startup(self): self.prob = self.survey.prob @@ -66,10 +69,26 @@ class Fields_CC(Fields): return Zero() def _j(self, phiSolution, srcList): - raise NotImplementedError + """ + .. math:: + \mathbf{j} = \mathbf{M}^{f \ -1}_{\rho} \mathbf{G} \phi + """ + return self.prob.MfRhoI*self.prob.Grad*phiSolution def _e(self, phiSolution, srcList): - raise NotImplementedError + """ + In HJ formulation e is not well-defined!! + .. math:: + \vec{e} = -\nabla \phi + """ + return -self.mesh.cellGrad*phiSolution + + def _charge(self, phiSolution, srcList): + """ + .. math:: + \int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0} + """ + return epsilon_0*self.prob.Vol*(self.mesh.faceDiv*self._e(phiSolution, srcList)) class Fields_N(Fields): knownFields = {'phiSolution':'N'} @@ -77,6 +96,7 @@ class Fields_N(Fields): 'phi': ['phiSolution','N','_phi'], 'j' : ['phiSolution','E','_j'], 'e' : ['phiSolution','E','_e'], + 'charge' : ['phiSolution','N','_charge'], } # primary - secondary # N variables @@ -105,7 +125,24 @@ class Fields_N(Fields): return Zero() def _j(self, phiSolution, srcList): - raise NotImplementedError + """ + In EB formulation j is not well-defined!! + .. math:: + \mathbf{j} = - \mathbf{M}^{e}_{\sigma} \mathbf{G} \phi + """ + return self.prob.MeSigma * self._e(phiSolution, srcList) def _e(self, phiSolution, srcList): - raise NotImplementedError + """ + In HJ formulation e is not well-defined!! + .. math:: + \vec{e} = -\nabla \phi + """ + return -self.mesh.nodalGrad * phiSolution + + def _charge(self, phiSolution, srcList): + """ + .. math:: + \int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0} + """ + return - epsilon_0*(mesh.nodalGrad.T*self._e(phiSolution, srcList)) From ba8f270b3adb7d9aa6553b3ffac739ed7fef0cba Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 1 May 2016 13:17:16 -0700 Subject: [PATCH 104/168] start of surface2ind_topo --- SimPEG/Examples/Utils_surface2ind_topo.py | 42 +++++++++++++++ SimPEG/Utils/__init__.py | 1 + SimPEG/Utils/modelutils.py | 63 +++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 SimPEG/Examples/Utils_surface2ind_topo.py create mode 100644 SimPEG/Utils/modelutils.py diff --git a/SimPEG/Examples/Utils_surface2ind_topo.py b/SimPEG/Examples/Utils_surface2ind_topo.py new file mode 100644 index 00000000..61a0f937 --- /dev/null +++ b/SimPEG/Examples/Utils_surface2ind_topo.py @@ -0,0 +1,42 @@ +from SimPEG import * +from SimPEG.Utils import surface2ind_topo + + +def run(plotIt=False, nx = 5, ny = 5): + """ + Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below + a topographic surface. + + """ + + mesh = Mesh.TensorMesh([nx,ny], x0='CC') # 2D mesh + xtopo = np.linspace(mesh.gridN[:,0].min(), mesh.gridN[:,0].max()) + topo = 0.4*np.sin(xtopo*5) # define a topographic surface + + Topo = np.hstack([Utils.mkvc(xtopo,2),Utils.mkvc(topo,2)]) #make it an array + + indcc = surface2ind_topo(mesh, Topo,'CC') + + if plotIt: + from matplotlib.pylab import plt + from scipy.interpolate import interp1d + fig, ax = plt.subplots(1,1,figsize=(6,6)) + mesh.plotGrid(ax=ax, nodes=True, centers=True) + ax.plot(xtopo,topo,'k',linewidth=1) + # ax.plot(mesh.vectorNx, interp1d(xtopo,topo)(mesh.vectorNx),'--k',linewidth=3) + ax.plot(mesh.vectorCCx, interp1d(xtopo,topo)(mesh.vectorCCx),'--k',linewidth=3) + + + aveN2CC = Utils.sdiag(mesh.aveN2CC.T.sum(1))*mesh.aveN2CC.T + a = aveN2CC * indcc + a[a > 0] = 1. + a[a < 0.25] = np.nan + a = a.reshape(mesh.vnN, order='F') + masked_array = np.ma.array(a, mask=np.isnan(a)) + ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap = plt.cm.gray,alpha=0.2) + plt.show() + + + +if __name__ == '__main__': + run(plotIt=True) diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 18c1994f..c7597fee 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -7,3 +7,4 @@ from CounterUtils import * import ModelBuilder import SolverUtils from coordutils import * +from modelutils import * diff --git a/SimPEG/Utils/modelutils.py b/SimPEG/Utils/modelutils.py new file mode 100644 index 00000000..dad92fae --- /dev/null +++ b/SimPEG/Utils/modelutils.py @@ -0,0 +1,63 @@ +from matutils import mkvc, ndgrid +import numpy as np + +def surface2ind_topo(mesh, topo, gridLoc='CC'): +# def genActiveindfromTopo(mesh, topo): + """ + Get active indices from topography + """ + + + if mesh.dim == 3: + from scipy.interpolate import NearestNDInterpolator + Ftopo = NearestNDInterpolator(topo[:,:2], topo[:,2]) + + if gridLoc == 'CC': + XY = ndgrid(mesh.vectorCCx, mesh.vectorCCy) + Zcc = mesh.gridCC[:,2].reshape((np.prod(mesh.vnC[:2]), mesh.nCz), order='F') + + gridTopo = Ftopo(XY) + actind = [gridTopo[ixy] <= Zcc[ixy,:] for ixy in range(np.prod(mesh.vnC[0]))] + actind = np.hstack(actind) + + elif gridLoc == 'N': + + XY = ndgrid(mesh.vectorNx, mesh.vectorNy) + gridTopo = Ftopo(XY).reshape(mesh.vnN[:2], order='F') + + if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']: + raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType) + + Nz = mesh.vectorNz[1:] # TODO: this will only work for tensor meshes + actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F') + + for ii in range(mesh.nCx): + for jj in range(mesh.nCy): + actind[ii,jj,:] = [np.all(gridTopo[ii:ii+2, jj:jj+2] >= Nz[kk]) for kk in range(len(Nz)) ] + + elif mesh.dim == 2: + from scipy.interpolate import interp1d + Ftopo = interp1d(topo[:,0], topo[:,1]) + + if gridLoc == 'CC': + gridTopo = Ftopo(mesh.gridCC[:,0]) + actind = mesh.gridCC[:,1] <= gridTopo + + elif gridLoc == 'N': + + gridTopo = Ftopo(mesh.vectorNx) + if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']: + raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType) + + Ny = mesh.vectorNy[1:] # TODO: this will only work for tensor meshes + actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F') + + for ii in range(mesh.nCx): + actind[ii,:] = [np.all(gridTopo[ii:ii+2] > Ny[kk]) for kk in range(len(Ny)) ] + + else: + raise NotImplementedError('surface2ind_topo not implemented for 1D mesh') + + return mkvc(actind) + + From 350818d80256c4dfc6a363ae6645288a2e7819b7 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Sun, 1 May 2016 13:21:48 -0700 Subject: [PATCH 105/168] add analytic test for 2D dc problems. --- tests/em/static/test_DC_2D_analytic.py | 71 ++++++++++++++ tests/em/static/test_DC_2D_jvecjtvecadj.py | 102 ++++++++++----------- tests/em/static/test_DC_analytic.py | 48 +++++----- 3 files changed, 145 insertions(+), 76 deletions(-) create mode 100644 tests/em/static/test_DC_2D_analytic.py diff --git a/tests/em/static/test_DC_2D_analytic.py b/tests/em/static/test_DC_2D_analytic.py new file mode 100644 index 00000000..53d494e2 --- /dev/null +++ b/tests/em/static/test_DC_2D_analytic.py @@ -0,0 +1,71 @@ +import unittest +from SimPEG import Mesh, Utils, EM, Maps, np +import SimPEG.EM.Static.DC as DC + +class DCProblemAnalyticTests(unittest.TestCase): + + def setUp(self): + + cs = 25. + hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hz = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + sigma = np.ones(mesh.nC)*1e-2 + + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") + phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") + data_anal = phiA-phiB + + rx = DC.Rx.Dipole(M, N) + src = DC.Src.Dipole([rx], Aloc, Bloc) + survey = DC.Survey([src]) + + self.survey = survey + self.mesh = mesh + self.sigma = sigma + self.data_anal = data_anal + + try: + from pymatsolver import MumpsSolver + self.Solver = MumpsSolver + except ImportError, e: + self.Solver = SolverLU + + def test_Problem3D_N(self): + problem = DC.Problem3D_N(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: + passed = True + print ">> DC analytic test for Problem3D_N is passed" + else: + passed = False + print ">> DC analytic test for Problem3D_N is failed" + self.assertTrue(passed) + + def test_Problem3D_CC(self): + problem = DC.Problem3D_CC(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: + passed = True + print ">> DC analytic test for Problem3D_CC is passed" + else: + passed = False + print ">> DC analytic test for Problem3D_CC is failed" + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/em/static/test_DC_2D_jvecjtvecadj.py b/tests/em/static/test_DC_2D_jvecjtvecadj.py index 9412614e..b96529cf 100644 --- a/tests/em/static/test_DC_2D_jvecjtvecadj.py +++ b/tests/em/static/test_DC_2D_jvecjtvecadj.py @@ -3,65 +3,65 @@ from SimPEG import * import SimPEG.EM.Static.DC as DC -# class DCProblem_2DTestsCC(unittest.TestCase): +class DCProblem_2DTestsCC(unittest.TestCase): -# def setUp(self): + def setUp(self): -# cs = 12.5 -# hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] -# hy = [(cs,7, -1.3),(cs,20)] -# mesh = Mesh.TensorMesh([hx, hy],x0="CN") -# x = np.linspace(-135, 250., 20) -# M = Utils.ndgrid(x-12.5, np.r_[0.]) -# N = Utils.ndgrid(x+12.5, np.r_[0.]) -# A0loc = np.r_[-150, 0.] -# A1loc = np.r_[-130, 0.] -# rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] -# rx = DC.Rx.Dipole_ky(M, N) -# src0 = DC.Src.Pole([rx], A0loc) -# src1 = DC.Src.Pole([rx], A1loc) -# survey = DC.Survey_ky([src0, src1]) -# problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) -# problem.pair(survey) + cs = 12.5 + hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy],x0="CN") + x = np.linspace(-135, 250., 20) + M = Utils.ndgrid(x-12.5, np.r_[0.]) + N = Utils.ndgrid(x+12.5, np.r_[0.]) + A0loc = np.r_[-150, 0.] + A1loc = np.r_[-130, 0.] + rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + rx = DC.Rx.Dipole_ky(M, N) + src0 = DC.Src.Pole([rx], A0loc) + src1 = DC.Src.Pole([rx], A1loc) + survey = DC.Survey_ky([src0, src1]) + problem = DC.Problem2D_CC(mesh, mapping=[('rho', Maps.IdentityMap(mesh))]) + problem.pair(survey) -# mSynth = np.ones(mesh.nC)*1. -# survey.makeSyntheticData(mSynth) + mSynth = np.ones(mesh.nC)*1. + survey.makeSyntheticData(mSynth) -# # Now set up the problem to do some minimization -# dmis = DataMisfit.l2_DataMisfit(survey) -# reg = Regularization.Tikhonov(mesh) -# opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) -# invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e0) -# inv = Inversion.BaseInversion(invProb) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e0) + inv = Inversion.BaseInversion(invProb) -# self.inv = inv -# self.reg = reg -# self.p = problem -# self.mesh = mesh -# self.m0 = mSynth -# self.survey = survey -# self.dmis = dmis + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis -# def test_misfit(self): -# derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] -# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) -# self.assertTrue(passed) + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) -# def test_adjoint(self): -# # Adjoint Test -# u = np.random.rand(self.mesh.nC*self.survey.nSrc) -# v = np.random.rand(self.mesh.nC) -# w = np.random.rand(self.survey.dobs.shape[0]) -# wtJv = w.dot(self.p.Jvec(self.m0, v)) -# vtJtw = v.dot(self.p.Jtvec(self.m0, w)) -# passed = np.abs(wtJv - vtJtw) < 1e-10 -# print 'Adjoint Test', np.abs(wtJv - vtJtw), passed -# self.assertTrue(passed) + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) -# def test_dataObj(self): -# derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] -# passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) -# self.assertTrue(passed) + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) class DCProblemTestsN(unittest.TestCase): diff --git a/tests/em/static/test_DC_analytic.py b/tests/em/static/test_DC_analytic.py index 53d494e2..e0b8b611 100644 --- a/tests/em/static/test_DC_analytic.py +++ b/tests/em/static/test_DC_analytic.py @@ -6,26 +6,23 @@ class DCProblemAnalyticTests(unittest.TestCase): def setUp(self): - cs = 25. - hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] - hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] - hz = [(cs,7, -1.3),(cs,20)] - mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") - sigma = np.ones(mesh.nC)*1e-2 + cs = 12.5 + hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy],x0="CN") + sighalf = 1e-2 + sigma = np.ones(mesh.nC)*sighalf + x = np.linspace(-135, 250., 20) + M = Utils.ndgrid(x-12.5, np.r_[0.]) + N = Utils.ndgrid(x+12.5, np.r_[0.]) + A0loc = np.r_[-150, 0.] + A1loc = np.r_[-130, 0.] + rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + data_anal = EM.Analytics.DCAnalyticHalf(np.r_[A0loc, 0.], rxloc, sighalf, flag="halfspace") - x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] - y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] - Aloc = np.r_[-200., 0., 0.] - Bloc = np.r_[200., 0., 0.] - M = Utils.ndgrid(x-25.,y, np.r_[0.]) - N = Utils.ndgrid(x+25.,y, np.r_[0.]) - phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") - phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") - data_anal = phiA-phiB - - rx = DC.Rx.Dipole(M, N) - src = DC.Src.Dipole([rx], Aloc, Bloc) - survey = DC.Survey([src]) + rx = DC.Rx.Dipole_ky(M, N) + src0 = DC.Src.Pole([rx], A0loc) + survey = DC.Survey_ky([src0]) self.survey = survey self.mesh = mesh @@ -39,12 +36,13 @@ class DCProblemAnalyticTests(unittest.TestCase): self.Solver = SolverLU def test_Problem3D_N(self): - problem = DC.Problem3D_N(self.mesh) + + problem = DC.Problem2D_N(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) - if err < 0.2: + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: passed = True print ">> DC analytic test for Problem3D_N is passed" else: @@ -53,12 +51,12 @@ class DCProblemAnalyticTests(unittest.TestCase): self.assertTrue(passed) def test_Problem3D_CC(self): - problem = DC.Problem3D_CC(self.mesh) + problem = DC.Problem2D_CC(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) - if err < 0.2: + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: passed = True print ">> DC analytic test for Problem3D_CC is passed" else: From d350dc258d3054f62a492102bcb32b3c5fa5382c Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 2 May 2016 08:55:29 -0700 Subject: [PATCH 106/168] minor fix for Fields_N and started IP problem. --- SimPEG/EM/Static/DC/FieldsDC.py | 2 +- SimPEG/EM/Static/DC/ProblemIP.py | 182 +++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 SimPEG/EM/Static/DC/ProblemIP.py diff --git a/SimPEG/EM/Static/DC/FieldsDC.py b/SimPEG/EM/Static/DC/FieldsDC.py index 1e5b3744..6fcea083 100644 --- a/SimPEG/EM/Static/DC/FieldsDC.py +++ b/SimPEG/EM/Static/DC/FieldsDC.py @@ -145,4 +145,4 @@ class Fields_N(Fields): .. math:: \int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0} """ - return - epsilon_0*(mesh.nodalGrad.T*self._e(phiSolution, srcList)) + return - epsilon_0*(self.mesh.nodalGrad.T*self.mesh.getEdgeInnerProduct()*self._e(phiSolution, srcList)) diff --git a/SimPEG/EM/Static/DC/ProblemIP.py b/SimPEG/EM/Static/DC/ProblemIP.py new file mode 100644 index 00000000..f48bb77d --- /dev/null +++ b/SimPEG/EM/Static/DC/ProblemIP.py @@ -0,0 +1,182 @@ +from SimPEG import * +from BaseDC import SurveyDC, FieldsDC_CC + +class SurveyIP(SurveyDC): + """ + **SurveyDC** + + Geophysical DC resistivity data. + + """ + + def __init__(self, srcList, **kwargs): + self.srcList = srcList + Survey.BaseSurvey.__init__(self, **kwargs) + self._Ps = {} + + def dpred(self, m, f=None): + """ + Predicted data. + + .. math:: + d_\\text{pred} = Pf(m) + """ + + return self.prob.forward(m) + + +class ProblemIP(BaseDCProblem): + """ + **ProblemIP** + + Geophysical IP resistivity problem. + + """ + + surveyPair = SurveyDC + Solver = Solver + sigma = None + Ainv = None + u = None + + def __init__(self, mesh, **kwargs): + Problem.BaseProblem.__init__(self, mesh) + self.mesh.setCellGradBC('neumann') + Utils.setKwargs(self, **kwargs) + + # deleteTheseOnModelUpdate = ['_A', '_Msig', '_dMdsig'] + + @property + def Msig(self): + if getattr(self, '_Msig', None) is None: + # sigma = self.curModel.transform + sigma = self.sigma + Av = self.mesh.aveF2CC + self._Msig = Utils.sdiag(1/(self.mesh.dim * Av.T * (1/sigma))) + return self._Msig + + @property + def dMdsig(self): + if getattr(self, '_dMdsig', None) is None: + # sigma = self.curModel.transform + sigma = self.sigma + Av = self.mesh.aveF2CC + dMdprop = self.mesh.dim * Utils.sdiag(self.Msig.diagonal()**2) * Av.T * Utils.sdiag(1./sigma**2) + self._dMdsig = lambda Gu: Utils.sdiag(Gu) * dMdprop + return self._dMdsig + + @property + def A(self): + """ + Makes the matrix A(m) for the DC resistivity problem. + + :param numpy.array m: model + :rtype: scipy.csc_matrix + :return: A(m) + + .. math:: + c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0 + + Where M() is the mass matrix and mT is the model transform. + """ + if getattr(self, '_A', None) is None: + D = self.mesh.faceDiv + G = self.mesh.cellGrad + self._A = D*self.Msig*G + # Remove the null space from the matrix. + self._A[-1,-1] /= self.mesh.vol[-1] + self._A = self._A.tocsc() + return self._A + + def getRHS(self): + # if self.mesh not in self._rhsDict: + RHS = np.array([src.eval(self) for src in self.survey.srcList]).T + # self._rhsDict[mesh] = RHS + # return self._rhsDict[mesh] + return RHS + + def fields(self, m): + if self.u is None: + A = self.A + if self.Ainv == None: + self.Ainv = self.Solver(A, **self.solverOpts) + Q = self.getRHS() + self.u = self.Ainv * Q + return self.u + + def forward(self, m, u=None): + # Set current model; clear dependent property $\mathbf{A(m)}$ + self.curModel = m + # sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ + sigma = self.sigma + if self.u is None: + # Run forward simulation if $u$ not provided + u = self.fields(sigma) + + shp = (self.mesh.nC, self.survey.nSrc) + u = self.u.reshape(shp, order='F') + + D = self.mesh.faceDiv + G = self.mesh.cellGrad + # Derivative of model transform, $\deriv{\sigma}{\m}$ + # dsigdm_x_v = self.curModel.transformDeriv * v + + dsigdm_x_v = Utils.sdiag(sigma) * self.curModel.transformDeriv * m + + # Take derivative of $C(m,u)$ w.r.t. $m$ + dCdm_x_v = np.empty_like(u) + # loop over fields for each source + for i in range(self.survey.nSrc): + # Derivative of inner product, $\left(\mathbf{M}_{1/\sigma}^f\right)^{-1}$ + dAdsig = D * self.dMdsig( G * u[:,i] ) + dCdm_x_v[:, i] = dAdsig * dsigdm_x_v + + # Take derivative of $C(m,u)$ w.r.t. $u$ + + if self.Ainv == None: + self.Ainv = self.Solver(A, **self.solverOpts) + + # dCdu = self.A + # Solve for $\deriv{u}{m}$ + # dCdu_inv = self.Solver(dCdu, **self.solverOpts) + P = self.survey.getP(self.mesh) + J_x_v = - P * mkvc( self.Ainv * dCdm_x_v ) + return -J_x_v + + def Jvec(self, m, v, f=None): + return self.forward(v) + + def Jtvec(self, m, v, f=None): + + self.curModel = m + # sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ + sigma = self.sigma + if self.u is None: + u = self.fields(sigma) + else: + u = self.u + shp = (self.mesh.nC, self.survey.nSrc) + u = u.reshape(shp, order='F') + P = self.survey.getP(self.mesh) + PT_x_v = (P.T*v).reshape(shp, order='F') + + D = self.mesh.faceDiv + G = self.mesh.cellGrad + A = self.A + mT_dm = Utils.sdiag(sigma)*self.mapping.deriv(m) + # mT_dm = self.mapping.deriv(m) + + # dCdu = A.T + # Ainv = self.Solver(dCdu, **self.solverOpts) + # if self.Ainv == None: + self.Ainv = self.Solver(A.T, **self.solverOpts) + + w = self.Ainv * PT_x_v + + Jtv = 0 + for i, ui in enumerate(u.T): # loop over each column + Jtv += self.dMdsig( G * ui ).T * ( D.T * w[:,i] ) + + Jtv = - mT_dm.T * ( Jtv ) + return -Jtv + From bd63e6716166b2bf39c7bf6669b2eb96b7a4bd9c Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 2 May 2016 10:03:01 -0700 Subject: [PATCH 107/168] working on IP fix bug in RhoDeriv!! --- SimPEG/EM/Base.py | 3 +- SimPEG/EM/Static/DC/ProblemIP.py | 280 +++++++++++++------------------ 2 files changed, 122 insertions(+), 161 deletions(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index 496f5227..f4da700c 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -191,8 +191,7 @@ class BaseEMProblem(Problem.BaseProblem): dMfRhoI_dI = -self.MfRhoI**2 dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) - drho_dm = self.curModel.rhoDeriv - return dMfRhoI_dI * ( dMf_drho * ( drho_dm)) + return dMfRhoI_dI * ( dMf_drho * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) ) # return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv diff --git a/SimPEG/EM/Static/DC/ProblemIP.py b/SimPEG/EM/Static/DC/ProblemIP.py index f48bb77d..86015ab8 100644 --- a/SimPEG/EM/Static/DC/ProblemIP.py +++ b/SimPEG/EM/Static/DC/ProblemIP.py @@ -1,182 +1,144 @@ -from SimPEG import * -from BaseDC import SurveyDC, FieldsDC_CC +from SimPEG import Problem, Utils +from SimPEG.EM.Base import BaseEMProblem +from SurveyDC import Survey +from FieldsDC import Fields, Fields_CC, Fields_N +from SimPEG.Utils import sdiag +import numpy as np +from SimPEG.Utils import Zero +from BoundaryUtils import getxBCyBC_CC -class SurveyIP(SurveyDC): +class IPPropMap(Maps.PropMap): """ - **SurveyDC** - - Geophysical DC resistivity data. - + Property Map for IP Problems. The electrical chargeability, + (\\(\\eta\\)) is the default inversion property """ - def __init__(self, srcList, **kwargs): - self.srcList = srcList - Survey.BaseSurvey.__init__(self, **kwargs) - self._Ps = {} - - def dpred(self, m, f=None): - """ - Predicted data. - - .. math:: - d_\\text{pred} = Pf(m) - """ - - return self.prob.forward(m) + eta = Maps.Property("Electrical Chargeability", defaultInvProp = True) + sigma = Maps.Property("Electrical Conductivity", defaultInvProp = False, propertyLink=('rho',Maps.ReciprocalMap)) + rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap)) -class ProblemIP(BaseDCProblem): - """ - **ProblemIP** +class BaseIPProblem(BaseEMProblem): - Geophysical IP resistivity problem. - - """ - - surveyPair = SurveyDC - Solver = Solver - sigma = None + surveyPair = Survey + fieldsPair = Fields + PropMap = IPPropMap Ainv = None - u = None - - def __init__(self, mesh, **kwargs): - Problem.BaseProblem.__init__(self, mesh) - self.mesh.setCellGradBC('neumann') - Utils.setKwargs(self, **kwargs) - - # deleteTheseOnModelUpdate = ['_A', '_Msig', '_dMdsig'] - - @property - def Msig(self): - if getattr(self, '_Msig', None) is None: - # sigma = self.curModel.transform - sigma = self.sigma - Av = self.mesh.aveF2CC - self._Msig = Utils.sdiag(1/(self.mesh.dim * Av.T * (1/sigma))) - return self._Msig - - @property - def dMdsig(self): - if getattr(self, '_dMdsig', None) is None: - # sigma = self.curModel.transform - sigma = self.sigma - Av = self.mesh.aveF2CC - dMdprop = self.mesh.dim * Utils.sdiag(self.Msig.diagonal()**2) * Av.T * Utils.sdiag(1./sigma**2) - self._dMdsig = lambda Gu: Utils.sdiag(Gu) * dMdprop - return self._dMdsig - - @property - def A(self): - """ - Makes the matrix A(m) for the DC resistivity problem. - - :param numpy.array m: model - :rtype: scipy.csc_matrix - :return: A(m) - - .. math:: - c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0 - - Where M() is the mass matrix and mT is the model transform. - """ - if getattr(self, '_A', None) is None: - D = self.mesh.faceDiv - G = self.mesh.cellGrad - self._A = D*self.Msig*G - # Remove the null space from the matrix. - self._A[-1,-1] /= self.mesh.vol[-1] - self._A = self._A.tocsc() - return self._A - - def getRHS(self): - # if self.mesh not in self._rhsDict: - RHS = np.array([src.eval(self) for src in self.survey.srcList]).T - # self._rhsDict[mesh] = RHS - # return self._rhsDict[mesh] - return RHS + f = None def fields(self, m): - if self.u is None: - A = self.A - if self.Ainv == None: - self.Ainv = self.Solver(A, **self.solverOpts) - Q = self.getRHS() - self.u = self.Ainv * Q - return self.u - - def forward(self, m, u=None): - # Set current model; clear dependent property $\mathbf{A(m)}$ self.curModel = m - # sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ - sigma = self.sigma - if self.u is None: - # Run forward simulation if $u$ not provided - u = self.fields(sigma) - shp = (self.mesh.nC, self.survey.nSrc) - u = self.u.reshape(shp, order='F') - - D = self.mesh.faceDiv - G = self.mesh.cellGrad - # Derivative of model transform, $\deriv{\sigma}{\m}$ - # dsigdm_x_v = self.curModel.transformDeriv * v - - dsigdm_x_v = Utils.sdiag(sigma) * self.curModel.transformDeriv * m - - # Take derivative of $C(m,u)$ w.r.t. $m$ - dCdm_x_v = np.empty_like(u) - # loop over fields for each source - for i in range(self.survey.nSrc): - # Derivative of inner product, $\left(\mathbf{M}_{1/\sigma}^f\right)^{-1}$ - dAdsig = D * self.dMdsig( G * u[:,i] ) - dCdm_x_v[:, i] = dAdsig * dsigdm_x_v - - # Take derivative of $C(m,u)$ w.r.t. $u$ - - if self.Ainv == None: - self.Ainv = self.Solver(A, **self.solverOpts) - - # dCdu = self.A - # Solve for $\deriv{u}{m}$ - # dCdu_inv = self.Solver(dCdu, **self.solverOpts) - P = self.survey.getP(self.mesh) - J_x_v = - P * mkvc( self.Ainv * dCdm_x_v ) - return -J_x_v + if self.f is None: + f = self.fieldsPair(self.mesh, self.survey) + if self.Ainv == None: + A = self.getA() + self.Ainv = self.Solver(A, **self.solverOpts) + RHS = self.getRHS() + u = self.Ainv * RHS + Srcs = self.survey.srcList + f[Srcs, self._solutionType] = u + return f def Jvec(self, m, v, f=None): - return self.forward(v) - def Jtvec(self, m, v, f=None): + if f is None: + f = self.fields(m) self.curModel = m - # sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ - sigma = self.sigma - if self.u is None: - u = self.fields(sigma) - else: - u = self.u - shp = (self.mesh.nC, self.survey.nSrc) - u = u.reshape(shp, order='F') - P = self.survey.getP(self.mesh) - PT_x_v = (P.T*v).reshape(shp, order='F') - D = self.mesh.faceDiv - G = self.mesh.cellGrad - A = self.A - mT_dm = Utils.sdiag(sigma)*self.mapping.deriv(m) - # mT_dm = self.mapping.deriv(m) + Jv = self.dataPair(self.survey) #same size as the data - # dCdu = A.T - # Ainv = self.Solver(dCdu, **self.solverOpts) - # if self.Ainv == None: - self.Ainv = self.Solver(A.T, **self.solverOpts) + A = self.getA() - w = self.Ainv * PT_x_v + for src in self.survey.srcList: + u_src = f[src, self._solutionType] # solution vector + dA_dm_v = self.getADeriv(u_src, v) + dRHS_dm_v = self.getRHSDeriv(src, v) + du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) - Jtv = 0 - for i, ui in enumerate(u.T): # loop over each column - Jtv += self.dMdsig( G * ui ).T * ( D.T * w[:,i] ) + for rx in src.rxList: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + return Utils.mkvc(Jv) - Jtv = - mT_dm.T * ( Jtv ) - return -Jtv + def Jtvec(self, m, v, f=None): + if f is None: + f = self.fields(m) + + self.curModel = m + + # Ensure v is a data object. + if not isinstance(v, self.dataPair): + v = self.dataPair(self.survey, v) + + Jtv = np.zeros(m.size) + AT = self.getA() + + + for src in self.survey.srcList: + u_src = f[src, self._solutionType] + for rx in src.rxList: + PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + ATinvdf_duT = self.Ainv * df_duT + dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + du_dmT = -dA_dmT + dRHS_dmT + Jtv += df_dmT + du_dmT + + return Utils.mkvc(Jtv) + + def getSourceTerm(self): + """ + takes concept of source and turns it into a matrix + """ + """ + Evaluates the sources, and puts them in matrix form + + :rtype: (numpy.ndarray, numpy.ndarray) + :return: q (nC or nN, nSrc) + """ + + Srcs = self.survey.srcList + + if self._formulation is 'EB': + n = self.mesh.nN + # return NotImplementedError + + elif self._formulation is 'HJ': + n = self.mesh.nC + + q = np.zeros((n, len(Srcs))) + + for i, src in enumerate(Srcs): + q[:,i] = src.eval(self) + return q + + @property + def deleteTheseOnModelUpdate(self): + toDelete = [] + return toDelete + + # assume log rho or log cond + + def MfRhoIDeriv(self,u): + """ + Derivative of :code:`MfRhoI` with respect to the model. + """ + + dMfRhoI_dI = -self.MfRhoI**2 + dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) + drho_dlogrho = Utils.sdiag(self.curModel.rho) + return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho)) + + # TODO: This should take a vector + def MeSigmaDeriv(self, u): + """ + Derivative of MeSigma with respect to the model + """ + dsigma_dlogsigma = Utils.sdiag(self.curModel.sigma) + return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * dsigma_dlogsigma From dd45a6a0855a90bc1ef382293661a5240f700463 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Mon, 2 May 2016 11:40:02 -0700 Subject: [PATCH 108/168] name updates in DC_Forward_PseudoSection, DC_Utils, example for Utils_surface2ind_topo --- SimPEG/DCIP/DCIPUtils.py | 113 ++++++++++----------- SimPEG/EM/Base.py | 3 +- SimPEG/Examples/Utils_surface2ind_topo.py | 1 - SimPEG/Examples/__init__.py | 3 +- docs/examples/DC_Forward_PseudoSection.rst | 6 +- docs/examples/Utils_surface2ind_topo.rst | 24 +++++ 6 files changed, 82 insertions(+), 68 deletions(-) create mode 100644 docs/examples/Utils_surface2ind_topo.rst diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 91eab0b3..800b478c 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -1,4 +1,4 @@ -from SimPEG import np +from SimPEG import np, Utils import BaseDC as DC import BaseDC as IP @@ -118,34 +118,27 @@ def readUBC_DC3Dobstopo(filename,mesh,topo,probType="CC"): def readUBC_DC2DModel(fileName): """ - Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg + Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg - Input: - :param fileName, path to the UBC GIF 2D model file - - Output: - :param SimPEG TensorMesh 2D object - :return - - Created on Thu Nov 12 13:14:10 2015 - - @author: dominiquef + :param string fileName: path to the UBC GIF 2D model file + :rtype: TensorMesh + :return: SimPEG TensorMesh 2D object """ from SimPEG import np, mkvc # Open fileand skip header... assume that we know the mesh already - obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') + obsfile = np.genfromtxt(fileName, delimiter=' \n', dtype=np.str, comments='!') - dim = np.array(obsfile[0].split(),dtype=float) + dim = np.array(obsfile[0].split(), dtype=float) - temp = np.array(obsfile[1].split(),dtype=float) + temp = np.array(obsfile[1].split(), dtype=float) if len(temp) > 1: model = np.zeros(dim) for ii in range(len(obsfile)-1): - mm = np.array(obsfile[ii+1].split(),dtype=float) + mm = np.array(obsfile[ii+1].split(), dtype=float) model[:,ii] = mm model = model[:,::-1] @@ -153,10 +146,10 @@ def readUBC_DC2DModel(fileName): else: if len(obsfile[1:])==1: - mm = np.array(obsfile[1:].split(),dtype=float) + mm = np.array(obsfile[1:].split(), dtype=float) else: - mm = np.array(obsfile[1:],dtype=float) + mm = np.array(obsfile[1:], dtype=float) # Permute the second dimension to flip the order model = mm.reshape(dim[1],dim[0]) @@ -171,17 +164,16 @@ def readUBC_DC2DModel(fileName): def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt', clim=None): """ - Read list of 2D tx-rx location and plot a speudo-section of apparent - resistivity. + Read list of 2D tx-rx location and plot a speudo-section of apparent + resistivity. - Assumes flat topo for now... + Assumes flat topo for now... - Input: - :param DCsurvey, z0 - :switch surveyType -> Either 'pole-dipole' | 'dipole-dipole' - :switch unitType=-> Either 'appResistivity' | 'appConductivity' | 'volt' - Output: - :figure scatter plot overlayed on image + :param SurveyDC DCsurvey: + :param string surveyType: Either 'pole-dipole' | 'dipole-dipole' + :param string unitType: Either 'appResistivity' | 'appConductivity' | 'volt' + :rtype: matplotlib.plt + :return: figure scatter plot overlayed on image """ from SimPEG import np @@ -294,27 +286,24 @@ def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt return ph -def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): +def gen_DCIPsurvey(endl, mesh, surveyType, AM_sep, MN_sep, nrx): """ - Load in endpoints and survey specifications to generate Tx, Rx location - stations. + Load in endpoints and survey specifications to generate Tx, Rx location + stations. - Assumes flat topo for now... + Assumes flat topo for now... - Input: - :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] - :object mesh -> SimPEG mesh object - :switch surveyType -> 'dipole-dipole' | 'pole-dipole' | 'gradient' - : param a, n -> pole seperation, number of rx dipoles per tx + :param numpy.array endl: input endpoints [[x1, y1] , [x2, y2]] + :param Mesh mesh: SimPEG mesh object + :param string surveyType: 'dipole-dipole' | 'pole-dipole' | 'gradient' + :param float AM_sep: transmitter (A) - receiver (M) seperation + :param float b: receiver dipole seperation + :param float nrx: pole seperation, number of rx dipoles per tx - Output: - :param Tx, Rx -> List objects for each tx location - Lines: P1x, P1y, P1z, P2x, P2y, P2z + :rtype: DC.Survey, Src, Rx + :returns: DC survey, Source - Created on Wed December 9th, 2015 - - @author: dominiquef - !! Require clean up to deal with DCsurvey + !! Require clean up to deal with DCsurvey """ from SimPEG import np @@ -330,17 +319,17 @@ def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): dl_x = ( endl[1,0] - endl[0,0] ) / dl_len dl_y = ( endl[1,1] - endl[0,1] ) / dl_len - nstn = np.floor( dl_len / a ) + nstn = np.floor( dl_len / AM_sep ) # Compute discrete pole location along line - stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a - stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a + stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*AM_sep + stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*AM_sep # Create line of P1 locations M = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]] # Create line of P2 locations - N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] + N = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] ## Build list of Tx-Rx locations depending on survey type # Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn] @@ -366,22 +355,22 @@ def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1]) # Number of receivers to fit - nstn = np.min([np.floor( (AB - b) / a ) , n]) + nstn = np.min([np.floor( (AB - MN_sep) / AM_sep ) , nrx]) # Check if there is enough space, else break the loop if nstn <= 0: continue # Compute discrete pole location along line - stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a - stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a + stn_x = N[ii,0] + dl_x*MN_sep + np.array(range(int(nstn)))*dl_x*AM_sep + stn_y = N[ii,1] + dl_y*MN_sep + np.array(range(int(nstn)))*dl_y*AM_sep # Create receiver poles # Create line of P1 locations P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]] # Create line of P2 locations - P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] + P2 = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] Rx.append(np.c_[P1,P2]) rxClass = DC.RxDipole(P1, P2) @@ -400,23 +389,23 @@ def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): Tx.append(np.c_[M[0,:],N[-1,:]]) # Get the edge limit of survey area - min_x = endl[0,0] + dl_x * b - min_y = endl[0,1] + dl_y * b + min_x = endl[0,0] + dl_x * MN_sep + min_y = endl[0,1] + dl_y * MN_sep - max_x = endl[1,0] - dl_x * b - max_y = endl[1,1] - dl_y * b + max_x = endl[1,0] - dl_x * MN_sep + max_y = endl[1,1] - dl_y * MN_sep box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 ) box_w = box_l/2. - nstn = np.floor( box_l / a ) + nstn = np.floor( box_l / AM_sep ) # Compute discrete pole location along line - stn_x = min_x + np.array(range(int(nstn)))*dl_x*a - stn_y = min_y + np.array(range(int(nstn)))*dl_y*a + stn_x = min_x + np.array(range(int(nstn)))*dl_x*AM_sep + stn_y = min_y + np.array(range(int(nstn)))*dl_y*AM_sep # Define number of cross lines - nlin = int(np.floor( box_w / a )) + nlin = int(np.floor( box_w / AM_sep )) lind = range(-nlin,nlin+1) ngrad = nstn * len(lind) @@ -425,12 +414,12 @@ def gen_DCIPsurvey(endl, mesh, surveyType, a, b, n): for ii in range( len(lind) ): # Move line in perpendicular direction by dipole spacing - lxx = stn_x - lind[ii]*a*dl_y - lyy = stn_y + lind[ii]*a*dl_x + lxx = stn_x - lind[ii]*AM_sep*dl_y + lyy = stn_y + lind[ii]*AM_sep*dl_x M = np.c_[ lxx, lyy , np.ones(nstn).T*mesh.vectorNz[-1]] - N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] + N = np.c_[ lxx+AM_sep*dl_x, lyy+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N] diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index a16cdb91..032b4429 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -165,7 +165,8 @@ class BaseEMProblem(Problem.BaseProblem): """ Derivative of :code:`MfRho` with respect to the model. """ - return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) + return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * self.curModel.rhoDeriv + # (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) # self.curModel.rhoDeriv @property diff --git a/SimPEG/Examples/Utils_surface2ind_topo.py b/SimPEG/Examples/Utils_surface2ind_topo.py index 61a0f937..4ed1cdaf 100644 --- a/SimPEG/Examples/Utils_surface2ind_topo.py +++ b/SimPEG/Examples/Utils_surface2ind_topo.py @@ -37,6 +37,5 @@ def run(plotIt=False, nx = 5, ny = 5): plt.show() - if __name__ == '__main__': run(plotIt=True) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index c67652a2..24828466 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -20,8 +20,9 @@ import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation import MT_1D_ForwardAndInversion import MT_3D_Foward +import Utils_surface2ind_topo -__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"] +__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", "Utils_surface2ind_topo"] ##### AUTOIMPORTS ##### diff --git a/docs/examples/DC_Forward_PseudoSection.rst b/docs/examples/DC_Forward_PseudoSection.rst index 80cf0307..4231e944 100644 --- a/docs/examples/DC_Forward_PseudoSection.rst +++ b/docs/examples/DC_Forward_PseudoSection.rst @@ -20,9 +20,9 @@ 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 +surveyType = survey type 'pole-dipole' or 'dipole-dipole' +unitType = Data type "appResistivity" | "appConductivity" | "volt" +Created by @fourndo diff --git a/docs/examples/Utils_surface2ind_topo.rst b/docs/examples/Utils_surface2ind_topo.rst new file mode 100644 index 00000000..04b27d5d --- /dev/null +++ b/docs/examples/Utils_surface2ind_topo.rst @@ -0,0 +1,24 @@ +.. _examples_Utils_surface2ind_topo: + +.. --------------------------------- .. +.. .. +.. THIS FILE IS AUTO GENEREATED .. +.. .. +.. SimPEG/Examples/__init__.py .. +.. .. +.. --------------------------------- .. + + +Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below +a topographic surface. + + + +.. plot:: + + from SimPEG import Examples + Examples.Utils_surface2ind_topo.run() + +.. literalinclude:: ../../SimPEG/Examples/Utils_surface2ind_topo.py + :language: python + :linenos: From fa6033c4384112a252ab10bbd7ce6c14f1b350e8 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 2 May 2016 12:00:39 -0700 Subject: [PATCH 109/168] Working 3D IP problem (CC and N). --- SimPEG/EM/Static/DC/ProblemIP.py | 144 ------------ SimPEG/EM/Static/DC/SurveyDC.py | 2 + SimPEG/EM/Static/IP/ProblemIP.py | 375 +++++++++++++++++++++++++++++++ SimPEG/EM/Static/IP/SurveyIP.py | 23 ++ SimPEG/EM/Static/IP/__init__.py | 2 + SimPEG/EM/Static/__init__.py | 1 + 6 files changed, 403 insertions(+), 144 deletions(-) delete mode 100644 SimPEG/EM/Static/DC/ProblemIP.py create mode 100644 SimPEG/EM/Static/IP/ProblemIP.py create mode 100644 SimPEG/EM/Static/IP/SurveyIP.py create mode 100644 SimPEG/EM/Static/IP/__init__.py diff --git a/SimPEG/EM/Static/DC/ProblemIP.py b/SimPEG/EM/Static/DC/ProblemIP.py deleted file mode 100644 index 86015ab8..00000000 --- a/SimPEG/EM/Static/DC/ProblemIP.py +++ /dev/null @@ -1,144 +0,0 @@ -from SimPEG import Problem, Utils -from SimPEG.EM.Base import BaseEMProblem -from SurveyDC import Survey -from FieldsDC import Fields, Fields_CC, Fields_N -from SimPEG.Utils import sdiag -import numpy as np -from SimPEG.Utils import Zero -from BoundaryUtils import getxBCyBC_CC - -class IPPropMap(Maps.PropMap): - """ - Property Map for IP Problems. The electrical chargeability, - (\\(\\eta\\)) is the default inversion property - """ - - eta = Maps.Property("Electrical Chargeability", defaultInvProp = True) - sigma = Maps.Property("Electrical Conductivity", defaultInvProp = False, propertyLink=('rho',Maps.ReciprocalMap)) - rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap)) - - -class BaseIPProblem(BaseEMProblem): - - surveyPair = Survey - fieldsPair = Fields - PropMap = IPPropMap - Ainv = None - f = None - - def fields(self, m): - self.curModel = m - - if self.f is None: - f = self.fieldsPair(self.mesh, self.survey) - if self.Ainv == None: - A = self.getA() - self.Ainv = self.Solver(A, **self.solverOpts) - RHS = self.getRHS() - u = self.Ainv * RHS - Srcs = self.survey.srcList - f[Srcs, self._solutionType] = u - return f - - def Jvec(self, m, v, f=None): - - if f is None: - f = self.fields(m) - - self.curModel = m - - Jv = self.dataPair(self.survey) #same size as the data - - A = self.getA() - - for src in self.survey.srcList: - u_src = f[src, self._solutionType] # solution vector - dA_dm_v = self.getADeriv(u_src, v) - dRHS_dm_v = self.getRHSDeriv(src, v) - du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) - - for rx in src.rxList: - df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) - df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) - Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) - return Utils.mkvc(Jv) - - def Jtvec(self, m, v, f=None): - if f is None: - f = self.fields(m) - - self.curModel = m - - # Ensure v is a data object. - if not isinstance(v, self.dataPair): - v = self.dataPair(self.survey, v) - - Jtv = np.zeros(m.size) - AT = self.getA() - - - for src in self.survey.srcList: - u_src = f[src, self._solutionType] - for rx in src.rxList: - PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m - df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) - df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) - ATinvdf_duT = self.Ainv * df_duT - dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) - dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) - du_dmT = -dA_dmT + dRHS_dmT - Jtv += df_dmT + du_dmT - - return Utils.mkvc(Jtv) - - def getSourceTerm(self): - """ - takes concept of source and turns it into a matrix - """ - """ - Evaluates the sources, and puts them in matrix form - - :rtype: (numpy.ndarray, numpy.ndarray) - :return: q (nC or nN, nSrc) - """ - - Srcs = self.survey.srcList - - if self._formulation is 'EB': - n = self.mesh.nN - # return NotImplementedError - - elif self._formulation is 'HJ': - n = self.mesh.nC - - q = np.zeros((n, len(Srcs))) - - for i, src in enumerate(Srcs): - q[:,i] = src.eval(self) - return q - - @property - def deleteTheseOnModelUpdate(self): - toDelete = [] - return toDelete - - # assume log rho or log cond - - def MfRhoIDeriv(self,u): - """ - Derivative of :code:`MfRhoI` with respect to the model. - """ - - dMfRhoI_dI = -self.MfRhoI**2 - dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) - drho_dlogrho = Utils.sdiag(self.curModel.rho) - return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho)) - - # TODO: This should take a vector - def MeSigmaDeriv(self, u): - """ - Derivative of MeSigma with respect to the model - """ - dsigma_dlogsigma = Utils.sdiag(self.curModel.sigma) - return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * dsigma_dlogsigma - diff --git a/SimPEG/EM/Static/DC/SurveyDC.py b/SimPEG/EM/Static/DC/SurveyDC.py index fb3d49a7..d9c493a2 100644 --- a/SimPEG/EM/Static/DC/SurveyDC.py +++ b/SimPEG/EM/Static/DC/SurveyDC.py @@ -34,3 +34,5 @@ class Survey_ky(BaseEMSurvey): for rx in src.rxList: data[src, rx] = rx.eval(kys, src, self.mesh, f) return data + + diff --git a/SimPEG/EM/Static/IP/ProblemIP.py b/SimPEG/EM/Static/IP/ProblemIP.py new file mode 100644 index 00000000..d35bf09e --- /dev/null +++ b/SimPEG/EM/Static/IP/ProblemIP.py @@ -0,0 +1,375 @@ +from SimPEG import Problem, Utils, Maps, Mesh +from SimPEG.EM.Base import BaseEMProblem +from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N +from SimPEG.Utils import sdiag +import numpy as np +from SimPEG.Utils import Zero +from SimPEG.EM.Static.DC import getxBCyBC_CC +from SurveyIP import Survey + +class IPPropMap(Maps.PropMap): + """ + Property Map for IP Problems. The electrical chargeability, + (\\(\\eta\\)) is the default inversion property + """ + eta = Maps.Property("Electrical Chargeability", defaultInvProp = True) + # sigma = Maps.Property("Electrical Conductivity", defaultVal=mu_0, propertyLink=('rho',Maps.ReciprocalMap)) + # rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap)) + +class BaseIPProblem(BaseEMProblem): + + surveyPair = Survey + fieldsPair = Fields + PropMap = IPPropMap + Ainv = None + sigma = None + rho = None + f = None + Ainv = None + + def fields(self, m): + self.curModel = m + if self.f is None: + self.f = self.fieldsPair(self.mesh, self.survey) + if self.Ainv == None: + A = self.getA() + self.Ainv = self.Solver(A, **self.solverOpts) + RHS = self.getRHS() + u = self.Ainv * RHS + Srcs = self.survey.srcList + self.f[Srcs, self._solutionType] = u + return self.f + + def Jvec(self, m, v, f=None): + + if f is None: + f = self.fields(m) + + self.curModel = m + + Jv = self.dataPair(self.survey) #same size as the data + + A = self.getA() + + for src in self.survey.srcList: + u_src = f[src, self._solutionType] # solution vector + dA_dm_v = self.getADeriv(u_src, v) + dRHS_dm_v = self.getRHSDeriv(src, v) + du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) + + for rx in src.rxList: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + # Conductivity (d u / d log sigma) + if self._formulation is 'EB': + return -Utils.mkvc(Jv) + # Conductivity (d u / d log rho) + if self._formulation is 'HJ': + return Utils.mkvc(Jv) + + def Jtvec(self, m, v, f=None): + if f is None: + f = self.fields(m) + + self.curModel = m + + # Ensure v is a data object. + if not isinstance(v, self.dataPair): + v = self.dataPair(self.survey, v) + + Jtv = np.zeros(m.size) + AT = self.getA() + + for src in self.survey.srcList: + u_src = f[src, self._solutionType] + for rx in src.rxList: + PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + ATinvdf_duT = self.Ainv * df_duT + dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + du_dmT = -dA_dmT + dRHS_dmT + Jtv += df_dmT + du_dmT + + if self._formulation is 'EB': + return -Utils.mkvc(Jtv) + if self._formulation is 'HJ': + return Utils.mkvc(Jtv) + + def getSourceTerm(self): + """ + takes concept of source and turns it into a matrix + """ + """ + Evaluates the sources, and puts them in matrix form + + :rtype: (numpy.ndarray, numpy.ndarray) + :return: q (nC or nN, nSrc) + """ + + Srcs = self.survey.srcList + + if self._formulation is 'EB': + n = self.mesh.nN + # return NotImplementedError + + elif self._formulation is 'HJ': + n = self.mesh.nC + + q = np.zeros((n, len(Srcs))) + + for i, src in enumerate(Srcs): + q[:,i] = src.eval(self) + return q + + @property + def deleteTheseOnModelUpdate(self): + toDelete = [] + return toDelete + + # assume log rho or log cond + @property + def MeSigma(self): + """ + Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation + """ + if getattr(self, '_MeSigma', None) is None: + self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma) + return self._MeSigma + + @property + def MfRhoI(self): + """ + Inverse of :code:`MfRho` + """ + if getattr(self, '_MfRhoI', None) is None: + self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True) + return self._MfRhoI + + def MfRhoIDeriv(self,u): + """ + Derivative of :code:`MfRhoI` with respect to the model. + """ + + dMfRhoI_dI = -self.MfRhoI**2 + dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u) + drho_dlogrho = Utils.sdiag(self.rho) + return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho)) + + # TODO: This should take a vector + def MeSigmaDeriv(self, u): + """ + Derivative of MeSigma with respect to the model + """ + dsigma_dlogsigma = Utils.sdiag(self.sigma) + return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma + +class Problem3D_CC(BaseIPProblem): + + _solutionType = 'phiSolution' + _formulation = 'HJ' # CC potentials means J is on faces + fieldsPair = Fields_CC + + def __init__(self, mesh, **kwargs): + BaseIPProblem.__init__(self, mesh, **kwargs) + self.setBC() + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + D = self.Div + G = self.Grad + # TODO: this won't work for full anisotropy + MfRhoI = self.MfRhoI + A = D * MfRhoI * G + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return V.T * A + return A + + def getADeriv(self, u, v, adjoint= False): + + D = self.Div + G = self.Grad + MfRhoIDeriv = self.MfRhoIDeriv + + if adjoint: + # if self._makeASymmetric is True: + # v = V * v + return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) ) + return D * (MfRhoIDeriv( G * u ) * v) + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return self.Vol.T * RHS + + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() + + def setBC(self): + if self.mesh.dim==3: + fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + gBFzm = self.mesh.gridFz[fzm,:] + gBFzp = self.mesh.gridFz[fzp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + alpha_zm, alpha_zp = temp_zm*0., temp_zp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + beta_zm, beta_zp = temp_zm, temp_zp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + gamma_zm, gamma_zp = temp_zm*0., temp_zp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] + + elif self.mesh.dim==2: + + fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] + + x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma) + V = self.Vol + self.Div = V * self.mesh.faceDiv + P_BC, B = self.mesh.getBCProjWF_simple() + M = B*self.mesh.aveCC2F + self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M + + +class Problem3D_N(BaseIPProblem): + + _solutionType = 'phiSolution' + _formulation = 'EB' # N potentials means B is on faces + fieldsPair = Fields_N + + def __init__(self, mesh, **kwargs): + BaseIPProblem.__init__(self, mesh, **kwargs) + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + A = Grad.T * MeSigma * Grad + + # Handling Null space of A + A[0,0] = A[0,0] + 1. + + return A + + def getADeriv(self, u, v, adjoint=False): + """ + + Product of the derivative of our system matrix with respect to the model and a vector + + """ + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + if not adjoint: + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + elif adjoint: + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() + +if __name__ == '__main__': + + + cs = 12.5 + hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hz = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + sigma = np.ones(mesh.nC) + prob = BaseIPProblem(mesh, sigma=sigma) + + diff --git a/SimPEG/EM/Static/IP/SurveyIP.py b/SimPEG/EM/Static/IP/SurveyIP.py new file mode 100644 index 00000000..c980d927 --- /dev/null +++ b/SimPEG/EM/Static/IP/SurveyIP.py @@ -0,0 +1,23 @@ +import SimPEG +from SimPEG.EM.Base import BaseEMSurvey +from SimPEG import sp, Survey +from SimPEG.Utils import Zero, Identity +from SimPEG.EM.Static.DC.SrcDC import BaseSrc +from SimPEG.EM.Static.DC.RxDC import BaseRx + +class Survey(BaseEMSurvey): + rxPair = BaseRx + srcPair = BaseSrc + + def __init__(self, srcList, **kwargs): + self.srcList = srcList + BaseEMSurvey.__init__(self, srcList, **kwargs) + + def dpred(self, m, f=None): + """ + Predicted data. + + .. math:: + d_\\text{pred} = Pf(m) + """ + return self.prob.Jvec(m, m, f=f) diff --git a/SimPEG/EM/Static/IP/__init__.py b/SimPEG/EM/Static/IP/__init__.py new file mode 100644 index 00000000..663117d3 --- /dev/null +++ b/SimPEG/EM/Static/IP/__init__.py @@ -0,0 +1,2 @@ +from ProblemIP import Problem3D_CC, Problem3D_N +from SurveyIP import Survey diff --git a/SimPEG/EM/Static/__init__.py b/SimPEG/EM/Static/__init__.py index 6ebc9df2..c9b4dc0d 100644 --- a/SimPEG/EM/Static/__init__.py +++ b/SimPEG/EM/Static/__init__.py @@ -1 +1,2 @@ import DC +import IP From ddb11096c8e92f69bade78a1f80dfbc1fa0b4d03 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 2 May 2016 15:05:31 -0700 Subject: [PATCH 110/168] Working on IP --- SimPEG/EM/Static/IP/ProblemIP.py | 5 +- tests/em/static/test_DC_2D_analytic.py | 46 ++++++++------- tests/em/static/test_DC_analytic.py | 48 ++++++++-------- tests/em/static/test_IP_fwd.py | 77 ++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 50 deletions(-) create mode 100644 tests/em/static/test_IP_fwd.py diff --git a/SimPEG/EM/Static/IP/ProblemIP.py b/SimPEG/EM/Static/IP/ProblemIP.py index d35bf09e..dcf12d6b 100644 --- a/SimPEG/EM/Static/IP/ProblemIP.py +++ b/SimPEG/EM/Static/IP/ProblemIP.py @@ -13,8 +13,6 @@ class IPPropMap(Maps.PropMap): (\\(\\eta\\)) is the default inversion property """ eta = Maps.Property("Electrical Chargeability", defaultInvProp = True) - # sigma = Maps.Property("Electrical Conductivity", defaultVal=mu_0, propertyLink=('rho',Maps.ReciprocalMap)) - # rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap)) class BaseIPProblem(BaseEMProblem): @@ -92,9 +90,10 @@ class BaseIPProblem(BaseEMProblem): dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) du_dmT = -dA_dmT + dRHS_dmT Jtv += df_dmT + du_dmT - + # Conductivity ((d u / d log sigma).T) if self._formulation is 'EB': return -Utils.mkvc(Jtv) + # Conductivity ((d u / d log rho).T) if self._formulation is 'HJ': return Utils.mkvc(Jtv) diff --git a/tests/em/static/test_DC_2D_analytic.py b/tests/em/static/test_DC_2D_analytic.py index 53d494e2..a6e3e6ab 100644 --- a/tests/em/static/test_DC_2D_analytic.py +++ b/tests/em/static/test_DC_2D_analytic.py @@ -6,26 +6,23 @@ class DCProblemAnalyticTests(unittest.TestCase): def setUp(self): - cs = 25. - hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] - hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] - hz = [(cs,7, -1.3),(cs,20)] - mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") - sigma = np.ones(mesh.nC)*1e-2 - - x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] - y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] - Aloc = np.r_[-200., 0., 0.] - Bloc = np.r_[200., 0., 0.] - M = Utils.ndgrid(x-25.,y, np.r_[0.]) - N = Utils.ndgrid(x+25.,y, np.r_[0.]) - phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") - phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") - data_anal = phiA-phiB + cs = 12.5 + hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy],x0="CN") + sighalf = 1e-2 + sigma = np.ones(mesh.nC)*sighalf + x = np.linspace(-135, 250., 20) + M = Utils.ndgrid(x-12.5, np.r_[0.]) + N = Utils.ndgrid(x+12.5, np.r_[0.]) + A0loc = np.r_[-150, 0.] + A1loc = np.r_[-130, 0.] + rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + data_anal = EM.Analytics.DCAnalyticHalf(np.r_[A0loc, 0.], rxloc, sighalf, flag="halfspace") rx = DC.Rx.Dipole(M, N) - src = DC.Src.Dipole([rx], Aloc, Bloc) - survey = DC.Survey([src]) + src0 = DC.Src.Pole([rx], A0loc) + survey = DC.Survey([src0]) self.survey = survey self.mesh = mesh @@ -39,12 +36,13 @@ class DCProblemAnalyticTests(unittest.TestCase): self.Solver = SolverLU def test_Problem3D_N(self): - problem = DC.Problem3D_N(self.mesh) + + problem = DC.Problem2D_N(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) - if err < 0.2: + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: passed = True print ">> DC analytic test for Problem3D_N is passed" else: @@ -53,12 +51,12 @@ class DCProblemAnalyticTests(unittest.TestCase): self.assertTrue(passed) def test_Problem3D_CC(self): - problem = DC.Problem3D_CC(self.mesh) + problem = DC.Problem2D_CC(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) - if err < 0.2: + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: passed = True print ">> DC analytic test for Problem3D_CC is passed" else: diff --git a/tests/em/static/test_DC_analytic.py b/tests/em/static/test_DC_analytic.py index e0b8b611..53d494e2 100644 --- a/tests/em/static/test_DC_analytic.py +++ b/tests/em/static/test_DC_analytic.py @@ -6,23 +6,26 @@ class DCProblemAnalyticTests(unittest.TestCase): def setUp(self): - cs = 12.5 - hx = [(cs,7, -1.3),(cs,61),(cs,7, 1.3)] - hy = [(cs,7, -1.3),(cs,20)] - mesh = Mesh.TensorMesh([hx, hy],x0="CN") - sighalf = 1e-2 - sigma = np.ones(mesh.nC)*sighalf - x = np.linspace(-135, 250., 20) - M = Utils.ndgrid(x-12.5, np.r_[0.]) - N = Utils.ndgrid(x+12.5, np.r_[0.]) - A0loc = np.r_[-150, 0.] - A1loc = np.r_[-130, 0.] - rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] - data_anal = EM.Analytics.DCAnalyticHalf(np.r_[A0loc, 0.], rxloc, sighalf, flag="halfspace") + cs = 25. + hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hz = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + sigma = np.ones(mesh.nC)*1e-2 - rx = DC.Rx.Dipole_ky(M, N) - src0 = DC.Src.Pole([rx], A0loc) - survey = DC.Survey_ky([src0]) + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") + phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") + data_anal = phiA-phiB + + rx = DC.Rx.Dipole(M, N) + src = DC.Src.Dipole([rx], Aloc, Bloc) + survey = DC.Survey([src]) self.survey = survey self.mesh = mesh @@ -36,13 +39,12 @@ class DCProblemAnalyticTests(unittest.TestCase): self.Solver = SolverLU def test_Problem3D_N(self): - - problem = DC.Problem2D_N(self.mesh) + problem = DC.Problem3D_N(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size - if err < 0.05: + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: passed = True print ">> DC analytic test for Problem3D_N is passed" else: @@ -51,12 +53,12 @@ class DCProblemAnalyticTests(unittest.TestCase): self.assertTrue(passed) def test_Problem3D_CC(self): - problem = DC.Problem2D_CC(self.mesh) + problem = DC.Problem3D_CC(self.mesh) problem.Solver = self.Solver problem.pair(self.survey) data = self.survey.dpred(self.sigma) - err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size - if err < 0.05: + err= np.linalg.norm(data-self.data_anal)/np.linalg.norm(self.data_anal) + if err < 0.2: passed = True print ">> DC analytic test for Problem3D_CC is passed" else: diff --git a/tests/em/static/test_IP_fwd.py b/tests/em/static/test_IP_fwd.py new file mode 100644 index 00000000..9643a0bb --- /dev/null +++ b/tests/em/static/test_IP_fwd.py @@ -0,0 +1,77 @@ +import unittest +from SimPEG import Mesh, Utils, EM, Maps, np +import SimPEG.EM.Static.DC as DC + +class IPProblemAnalyticTests(unittest.TestCase): + + def setUp(self): + + cs = 12.5 + hx = [(cs,2, -1.3),(cs,61),(cs,2, 1.3)] + hy = [(cs,2, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy],x0="CN") + sighalf = 1e-2 + sigma = np.ones(mesh.nC)*sighalf + x = np.linspace(-135, 250., 20) + M = Utils.ndgrid(x-12.5, np.r_[0.]) + N = Utils.ndgrid(x+12.5, np.r_[0.]) + A0loc = np.r_[-150, 0.] + A1loc = np.r_[-130, 0.] + rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + + blkind = Utils.ModelBuilder.getIndicesSphere(xc, radius, mesh.gridCC) + sigmaInf = np.ones(mesh.nC)*1e-2 + eta = np.zeros(mesh.nC) + eta[blkind] = 0.1 + sigma0 = sigmaInf*(1.-eta) + + rx = DC.Rx.Dipole_ky(M, N) + src0 = DC.Src.Pole([rx], A0loc) + surveyDC = DC.Survey([src0]) + surveyIP = DC.Survey_ky([src0]) + + self.surveyDC = surveyDC + self.surveyIP = surveyIP + + self.mesh = mesh + self.sigma = sigma + self.data_anal = data_anal + + try: + from pymatsolver import MumpsSolver + self.Solver = MumpsSolver + except ImportError, e: + self.Solver = SolverLU + + def test_Problem3D_N(self): + + problem = DC.Problem2D_N(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: + passed = True + print ">> DC analytic test for Problem3D_N is passed" + else: + passed = False + print ">> DC analytic test for Problem3D_N is failed" + self.assertTrue(passed) + + def test_Problem3D_CC(self): + problem = DC.Problem2D_CC(self.mesh) + problem.Solver = self.Solver + problem.pair(self.survey) + data = self.survey.dpred(self.sigma) + err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + if err < 0.05: + passed = True + print ">> DC analytic test for Problem3D_CC is passed" + else: + passed = False + print ">> DC analytic test for Problem3D_CC is failed" + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() + From 354e57f24ed9ef4e571b2522f50deba60503d238 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 2 May 2016 16:47:16 -0700 Subject: [PATCH 111/168] Problem3D_CC and _N for IP are all tested a) fwd b) jvec, jtvec c) adjoint --- tests/em/static/test_DC_2D_analytic.py | 2 +- tests/em/static/test_IP_fwd.py | 85 +++++++++------- tests/em/static/test_IP_jvecjtvecadj.py | 126 ++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 tests/em/static/test_IP_jvecjtvecadj.py diff --git a/tests/em/static/test_DC_2D_analytic.py b/tests/em/static/test_DC_2D_analytic.py index a6e3e6ab..7a8fe1b6 100644 --- a/tests/em/static/test_DC_2D_analytic.py +++ b/tests/em/static/test_DC_2D_analytic.py @@ -22,7 +22,7 @@ class DCProblemAnalyticTests(unittest.TestCase): rx = DC.Rx.Dipole(M, N) src0 = DC.Src.Pole([rx], A0loc) - survey = DC.Survey([src0]) + survey = DC.Survey_ky([src0]) self.survey = survey self.mesh = mesh diff --git a/tests/em/static/test_IP_fwd.py b/tests/em/static/test_IP_fwd.py index 9643a0bb..98bb7e90 100644 --- a/tests/em/static/test_IP_fwd.py +++ b/tests/em/static/test_IP_fwd.py @@ -1,41 +1,43 @@ import unittest from SimPEG import Mesh, Utils, EM, Maps, np import SimPEG.EM.Static.DC as DC +import SimPEG.EM.Static.IP as IP class IPProblemAnalyticTests(unittest.TestCase): def setUp(self): cs = 12.5 - hx = [(cs,2, -1.3),(cs,61),(cs,2, 1.3)] - hy = [(cs,2, -1.3),(cs,20)] - mesh = Mesh.TensorMesh([hx, hy],x0="CN") - sighalf = 1e-2 - sigma = np.ones(mesh.nC)*sighalf - x = np.linspace(-135, 250., 20) - M = Utils.ndgrid(x-12.5, np.r_[0.]) - N = Utils.ndgrid(x+12.5, np.r_[0.]) - A0loc = np.r_[-150, 0.] - A1loc = np.r_[-130, 0.] - rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] + npad=2 + hx = [(cs,npad, -1.3),(cs,21),(cs,npad, 1.3)] + hy = [(cs,npad, -1.3),(cs,21),(cs,npad, 1.3)] + hz = [(cs,npad, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + x = mesh.vectorCCx[(mesh.vectorCCx>-80.)&(mesh.vectorCCx<80.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-80.)&(mesh.vectorCCy<80.)] + Aloc = np.r_[-100., 0., 0.] + Bloc = np.r_[100., 0., 0.] + M = Utils.ndgrid(x-12.5,y, np.r_[0.]) + N = Utils.ndgrid(x+12.5,y, np.r_[0.]) + radius = 50. + xc = np.r_[0., 0., -100] blkind = Utils.ModelBuilder.getIndicesSphere(xc, radius, mesh.gridCC) sigmaInf = np.ones(mesh.nC)*1e-2 eta = np.zeros(mesh.nC) eta[blkind] = 0.1 sigma0 = sigmaInf*(1.-eta) - rx = DC.Rx.Dipole_ky(M, N) - src0 = DC.Src.Pole([rx], A0loc) - surveyDC = DC.Survey([src0]) - surveyIP = DC.Survey_ky([src0]) + rx = DC.Rx.Dipole(M, N) + src = DC.Src.Dipole([rx], Aloc, Bloc) + surveyDC = DC.Survey([src]) self.surveyDC = surveyDC - self.surveyIP = surveyIP - self.mesh = mesh - self.sigma = sigma - self.data_anal = data_anal + self.sigmaInf = sigmaInf + self.sigma0 = sigma0 + self.src = src + self.eta = eta try: from pymatsolver import MumpsSolver @@ -45,31 +47,48 @@ class IPProblemAnalyticTests(unittest.TestCase): def test_Problem3D_N(self): - problem = DC.Problem2D_N(self.mesh) - problem.Solver = self.Solver - problem.pair(self.survey) - data = self.survey.dpred(self.sigma) - err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + problemDC = DC.Problem3D_N(self.mesh) + problemDC.Solver = self.Solver + problemDC.pair(self.surveyDC) + data0 = self.surveyDC.dpred(self.sigma0) + finf = problemDC.fields(self.sigmaInf) + datainf = self.surveyDC.dpred(self.sigmaInf, f=finf) + problemIP = IP.Problem3D_N(self.mesh, sigma=self.sigmaInf, Ainv=problemDC.Ainv, f=finf) + problemIP.Solver = self.Solver + surveyIP = IP.Survey([self.src]) + problemIP.pair(surveyIP) + data_full = data0 - datainf + data = surveyIP.dpred(self.eta) + err= np.linalg.norm((data-data_full)/data_full)**2 / data_full.size if err < 0.05: passed = True - print ">> DC analytic test for Problem3D_N is passed" + print ">> IP forward test for Problem3D_N is passed" else: passed = False - print ">> DC analytic test for Problem3D_N is failed" + print ">> IP forward test for Problem3D_N is failed" self.assertTrue(passed) def test_Problem3D_CC(self): - problem = DC.Problem2D_CC(self.mesh) - problem.Solver = self.Solver - problem.pair(self.survey) - data = self.survey.dpred(self.sigma) - err= np.linalg.norm((data-self.data_anal)/self.data_anal)**2 / self.data_anal.size + + problemDC = DC.Problem3D_CC(self.mesh) + problemDC.Solver = self.Solver + problemDC.pair(self.surveyDC) + data0 = self.surveyDC.dpred(self.sigma0) + finf = problemDC.fields(self.sigmaInf) + datainf = self.surveyDC.dpred(self.sigmaInf, f=finf) + problemIP = IP.Problem3D_CC(self.mesh, rho=1./self.sigmaInf, Ainv=problemDC.Ainv, f=finf) + problemIP.Solver = self.Solver + surveyIP = IP.Survey([self.src]) + problemIP.pair(surveyIP) + data_full = data0 - datainf + data = surveyIP.dpred(self.eta) + err= np.linalg.norm((data-data_full)/data_full)**2 / data_full.size if err < 0.05: passed = True - print ">> DC analytic test for Problem3D_CC is passed" + print ">> IP forward test for Problem3D_CC is passed" else: passed = False - print ">> DC analytic test for Problem3D_CC is failed" + print ">> IP forward test for Problem3D_CC is failed" self.assertTrue(passed) if __name__ == '__main__': diff --git a/tests/em/static/test_IP_jvecjtvecadj.py b/tests/em/static/test_IP_jvecjtvecadj.py new file mode 100644 index 00000000..7a455784 --- /dev/null +++ b/tests/em/static/test_IP_jvecjtvecadj.py @@ -0,0 +1,126 @@ +import unittest +from SimPEG import * +import SimPEG.EM.Static.DC as DC +import SimPEG.EM.Static.IP as IP + + +class IPProblemTestsCC(unittest.TestCase): + + def setUp(self): + + aSpacing=2.5 + nElecs=5 + + surveySize = nElecs*aSpacing - aSpacing + cs = surveySize/nElecs/4 + + mesh = Mesh.TensorMesh([ + [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], + [(cs,3, -1.3),(cs,3,1.3)], + # [(cs,5, -1.3),(cs,10)] + ],'CN') + + srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) + survey = IP.Survey(srcList) + sigma = np.ones(mesh.nC) + problem = IP.Problem3D_CC(mesh, rho=1./sigma) + problem.pair(survey) + mSynth = np.ones(mesh.nC)*0.1 + survey.makeSyntheticData(mSynth) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + +class IPProblemTestsN(unittest.TestCase): + + def setUp(self): + + aSpacing=2.5 + nElecs=5 + + surveySize = nElecs*aSpacing - aSpacing + cs = surveySize/nElecs/4 + + mesh = Mesh.TensorMesh([ + [(cs,10, -1.3),(cs,surveySize/cs),(cs,10, 1.3)], + [(cs,3, -1.3),(cs,3,1.3)], + # [(cs,5, -1.3),(cs,10)] + ],'CN') + + srcList = DC.Utils.WennerSrcList(nElecs, aSpacing, in2D=True) + survey = IP.Survey(srcList) + sigma = np.ones(mesh.nC) + problem = IP.Problem3D_N(mesh, sigma=sigma) + problem.pair(survey) + mSynth = np.ones(mesh.nC)*0.1 + survey.makeSyntheticData(mSynth) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-8 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() From 6e12bdc57ae8dfafcfb83854ecba1dedf05aa415 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Tue, 3 May 2016 09:20:58 -0700 Subject: [PATCH 112/168] Moving Dom's DCutils ... --- SimPEG/DCIP/DCIPUtils.py | 2 +- SimPEG/EM/Static/Utils/StaticUtils.py | 317 ++++++++++++++++++++++++++ SimPEG/EM/Static/Utils/__init__.py | 1 + 3 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 SimPEG/EM/Static/Utils/StaticUtils.py create mode 100644 SimPEG/EM/Static/Utils/__init__.py diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index e94b930f..e598b60b 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -278,7 +278,7 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - + if dtype == 'appc': cbar.set_label("App.Cond",size=12) elif dtype == 'appr': diff --git a/SimPEG/EM/Static/Utils/StaticUtils.py b/SimPEG/EM/Static/Utils/StaticUtils.py new file mode 100644 index 00000000..43181c8a --- /dev/null +++ b/SimPEG/EM/Static/Utils/StaticUtils.py @@ -0,0 +1,317 @@ +from SimPEG import np +from SimPEG.EM.Static import DC, IP + +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. + + Assumes flat topo for now... + + 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 + + Edited Feb 17th, 2016 + + @author: dominiquef + + """ + from SimPEG import np + from scipy.interpolate import griddata + import pylab as plt + + # Set depth to 0 for now + z0 = 0. + + # Pre-allocate + midx = [] + midz = [] + rho = [] + LEG = [] + count = 0 # Counter for data + for ii in range(DCsurvey.nSrc): + + Tx = DCsurvey.srcList[ii].loc + Rx = DCsurvey.srcList[ii].rxList[0].locs + + nD = DCsurvey.srcList[ii].rxList[0].nD + + data = DCsurvey.dobs[count:count+nD] + count += nD + + # Get distances between each poles A-B-M-N + if stype == 'pdp': + MA = np.abs(Tx[0] - Rx[0][:,0]) + NA = np.abs(Tx[0] - Rx[1][:,0]) + MN = np.abs(Rx[1][:,0] - Rx[0][:,0]) + + # Create mid-point location + Cmid = Tx[0] + Pmid = (Rx[0][:,0] + Rx[1][:,0])/2 + if DCsurvey.mesh.dim == 2: + zsrc = Tx[1] + elif DCsurvey.mesh.dim ==3: + zsrc = Tx[2] + + elif stype == 'dpdp': + MA = np.abs(Tx[0][0] - Rx[0][:,0]) + MB = np.abs(Tx[1][0] - Rx[0][:,0]) + NA = np.abs(Tx[0][0] - Rx[1][:,0]) + NB = np.abs(Tx[1][0] - Rx[1][:,0]) + + # Create mid-point location + Cmid = (Tx[0][0] + Tx[1][0])/2 + Pmid = (Rx[0][:,0] + Rx[1][:,0])/2 + if DCsurvey.mesh.dim == 2: + zsrc = (Tx[0][1] + Tx[1][1])/2 + elif DCsurvey.mesh.dim ==3: + zsrc = (Tx[0][2] + Tx[1][2])/2 + + # Change output for dtype + if dtype == 'volt': + + rho = np.hstack([rho,data]) + + else: + + # 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 ) + LEG.append(1./(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 ]) + if DCsurvey.mesh.dim==3: + midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ]) + elif DCsurvey.mesh.dim==2: + midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ]) + ax = axs + + # Grid points + 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] + + 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), vmin=vmin, vmax=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) + + 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') + + + + return ph, LEG + +def gen_DCIPsurvey(endl, mesh, stype, a, b, n): + """ + Load in endpoints and survey specifications to generate Tx, Rx location + stations. + + Assumes flat topo for now... + + Input: + :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] + :object mesh -> SimPEG mesh object + :switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient' + : param a, n -> pole seperation, number of rx dipoles per tx + + Output: + :param Tx, Rx -> List objects for each tx location + Lines: P1x, P1y, P1z, P2x, P2y, P2z + + Created on Wed December 9th, 2015 + + @author: dominiquef + !! Require clean up to deal with DCsurvey + """ + + from SimPEG import np + + def xy_2_r(x1,x2,y1,y2): + r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) ) + return r + + ## Evenly distribute electrodes and put on surface + # Mesure survey length and direction + dl_len = xy_2_r(endl[0,0],endl[1,0],endl[0,1],endl[1,1]) + + dl_x = ( endl[1,0] - endl[0,0] ) / dl_len + dl_y = ( endl[1,1] - endl[0,1] ) / dl_len + + nstn = np.floor( dl_len / a ) + + # Compute discrete pole location along line + stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a + stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a + + if mesh.dim==2: + ztop = mesh.vectorNy[-1] + # Create line of P1 locations + M = np.c_[stn_x, np.ones(nstn).T*ztop] + # Create line of P2 locations + N = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop] + + elif mesh.dim==3: + ztop = mesh.vectorNz[-1] + # Create line of P1 locations + M = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop] + # Create line of P2 locations + N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop] + + + ## Build list of Tx-Rx locations depending on survey type + # Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn] + # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] + SrcList = [] + + + if stype != 'gradient': + + for ii in range(0, int(nstn)-1): + + + if stype == 'dpdp': + tx = np.c_[M[ii,:],N[ii,:]] + elif stype == 'pdp': + tx = np.c_[M[ii,:],M[ii,:]] + + # Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]]) + + # Current elctrode seperation + AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1]) + + # Number of receivers to fit + nstn = np.min([np.floor( (AB - b) / a ) , n]) + + # Check if there is enough space, else break the loop + if nstn <= 0: + continue + + # Compute discrete pole location along line + stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a + stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a + + # Create receiver poles + + if mesh.dim==3: + # Create line of P1 locations + P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop] + # Create line of P2 locations + P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop] + rxClass = DC.Rx.Dipole(P1, P2) + + elif mesh.dim==2: + # Create line of P1 locations + P1 = np.c_[stn_x, np.ones(nstn).T*ztop] + # Create line of P2 locations + P2 = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop] + rxClass = DC.Rx.Dipole_ky(P1, P2) + + if stype == 'dpdp': + srcClass = DC.Src.Dipole([rxClass], M[ii,:],N[ii,:]) + elif stype == 'pdp': + srcClass = DC.Src.Pole([rxClass], M[ii,:]) + SrcList.append(srcClass) + + elif stype == 'gradient': + + # Gradient survey only requires Tx at end of line and creates a square + # grid of receivers at in the middle at a pre-set minimum distance + + # Get the edge limit of survey area + min_x = endl[0,0] + dl_x * b + min_y = endl[0,1] + dl_y * b + + max_x = endl[1,0] - dl_x * b + max_y = endl[1,1] - dl_y * b + + box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 ) + box_w = box_l/2. + + nstn = np.floor( box_l / a ) + + # Compute discrete pole location along line + stn_x = min_x + np.array(range(int(nstn)))*dl_x*a + stn_y = min_y + np.array(range(int(nstn)))*dl_y*a + + # Define number of cross lines + nlin = int(np.floor( box_w / a )) + lind = range(-nlin,nlin+1) + + ngrad = nstn * len(lind) + + rx = np.zeros([ngrad,6]) + for ii in range( len(lind) ): + + # Move line in perpendicular direction by dipole spacing + lxx = stn_x - lind[ii]*a*dl_y + lyy = stn_y + lind[ii]*a*dl_x + + + M = np.c_[ lxx, lyy , np.ones(nstn).T*ztop] + N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*ztop] + rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N] + + if mesh.dim==3: + rxClass = DC.Rx.Dipole(rx[:,:3], rx[:,3:]) + elif mesh.dim==2: + M = M[:,[0,2]] + N = N[:,[0,2]] + rxClass = DC.Rx.Dipole_ky(rx[:,[0,2]], rx[:,[3,5]]) + srcClass = DC.Src.Dipole([rxClass], M[0,:], N[-1,:]) + SrcList.append(srcClass) + else: + print """stype must be either 'pdp', 'dpdp' or 'gradient'. """ + + + return SrcList + diff --git a/SimPEG/EM/Static/Utils/__init__.py b/SimPEG/EM/Static/Utils/__init__.py new file mode 100644 index 00000000..adc317ae --- /dev/null +++ b/SimPEG/EM/Static/Utils/__init__.py @@ -0,0 +1 @@ +from StaticUtils import * From a7f89131b461160b175f53471ea8807aa55131b5 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Tue, 3 May 2016 11:26:28 -0700 Subject: [PATCH 113/168] Playing with 2.5D DC inversion TODOs: Parallelize ky ... (currently pretty slow) --- SimPEG/EM/Static/DC/ProblemDC_2D.py | 2 ++ SimPEG/EM/Static/Utils/StaticUtils.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index 86f9dc72..2e40fde9 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -50,6 +50,7 @@ class BaseDCProblem_2D(BaseEMProblem): dky = np.r_[dky[0], dky] y = 0. + #TODO: this loop is pretty slow .. (Parellize) for iky in range(self.nky): ky = self.kys[iky] A = self.getA(ky) @@ -94,6 +95,7 @@ class BaseDCProblem_2D(BaseEMProblem): for rx in src.rxList: Jtv_temp1 = np.zeros(m.size) Jtv_temp0 = np.zeros(m.size) + #TODO: this loop is pretty slow .. (Parellize) for iky in range(self.nky): u_src = f[src, self._solutionType, iky] ky = self.kys[iky] diff --git a/SimPEG/EM/Static/Utils/StaticUtils.py b/SimPEG/EM/Static/Utils/StaticUtils.py index 43181c8a..d8e0d0c8 100644 --- a/SimPEG/EM/Static/Utils/StaticUtils.py +++ b/SimPEG/EM/Static/Utils/StaticUtils.py @@ -213,7 +213,6 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] SrcList = [] - if stype != 'gradient': for ii in range(0, int(nstn)-1): @@ -262,6 +261,7 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): srcClass = DC.Src.Pole([rxClass], M[ii,:]) SrcList.append(srcClass) + # TODO: test gradient array! elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square From 00bbe0f35ee9318b3f1c370322aa3f01e54aa9ce Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 3 May 2016 15:04:36 -0700 Subject: [PATCH 114/168] if mapping is none, create an identity map that is size indactive.nonzero for regularization --- SimPEG/Regularization.py | 3 +++ tests/base/test_regularization.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 195e6203..7fe976fc 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -311,6 +311,9 @@ class BaseRegularization(object): tmp = indActive indActive = np.zeros(mesh.nC, dtype=bool) indActive[tmp] = True + if indActive is not None and mapping is None: + mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size) + 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 5aa21ad5..6dddfb74 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -65,10 +65,8 @@ class RegularizationTests(unittest.TestCase): elif mesh.dim == 3: 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=indActive.nonzero()[0].size) - for indAct in [indActive, indActive.nonzero()[0]]: # test both bool and integers - reg = r(mesh, mapping=mapping, indActive=indAct) + reg = r(mesh, indActive=indAct) m = np.random.rand(mesh.nC)[indAct] reg.mref = np.ones_like(m)*np.mean(m) From 224105364d65a55db12ab4e190deea6d476ddef6 Mon Sep 17 00:00:00 2001 From: sgkang Date: Tue, 3 May 2016 17:39:07 -0700 Subject: [PATCH 115/168] df_dmT + du_dmT has dtype('o') This seems making problem depending on which machine you are using .... or numpy version. We may need to clarify what is sparse and dense for arrays!! --- SimPEG/EM/Static/DC/ProblemDC_2D.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC_2D.py b/SimPEG/EM/Static/DC/ProblemDC_2D.py index 2e40fde9..52b14ce5 100644 --- a/SimPEG/EM/Static/DC/ProblemDC_2D.py +++ b/SimPEG/EM/Static/DC/ProblemDC_2D.py @@ -83,7 +83,7 @@ class BaseDCProblem_2D(BaseEMProblem): if not isinstance(v, self.dataPair): v = self.dataPair(self.survey, v) - Jtv = np.zeros(m.size) + Jtv = np.zeros(m.size, dtype=float) # Assume y=0. # This needs some thoughts to implement in general when src is dipole @@ -93,8 +93,8 @@ class BaseDCProblem_2D(BaseEMProblem): for src in self.survey.srcList: for rx in src.rxList: - Jtv_temp1 = np.zeros(m.size) - Jtv_temp0 = np.zeros(m.size) + Jtv_temp1 = np.zeros(m.size, dtype=float) + Jtv_temp0 = np.zeros(m.size, dtype=float) #TODO: this loop is pretty slow .. (Parellize) for iky in range(self.nky): u_src = f[src, self._solutionType, iky] @@ -109,7 +109,7 @@ class BaseDCProblem_2D(BaseEMProblem): dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True) dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True) du_dmT = -dA_dmT + dRHS_dmT - Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT) + Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT).astype(float) # Trapezoidal intergration if iky==0: #First assigment From 69ec3744150a2451b7932c6f2cd16ef115bb89d0 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Tue, 3 May 2016 19:03:41 -0700 Subject: [PATCH 116/168] minor changes --- SimPEG/EM/Static/DC/SrcDC.py | 33 +++++++++++++++++++++++++++ SimPEG/EM/Static/Utils/StaticUtils.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/SimPEG/EM/Static/DC/SrcDC.py b/SimPEG/EM/Static/DC/SrcDC.py index 02dae23e..ae52f376 100644 --- a/SimPEG/EM/Static/DC/SrcDC.py +++ b/SimPEG/EM/Static/DC/SrcDC.py @@ -51,3 +51,36 @@ class Pole(BaseSrc): q = self.current * mkvc(q) return q + +# class Dipole_ky(BaseSrc): + +# def __init__(self, rxList, locA, locB, **kwargs): +# assert locA.shape == locB.shape, 'Shape of locA and locB should be the same' +# self.loc = [locA[[0,2]], locB[[0,2]]] +# BaseSrc.__init__(self, rxList, **kwargs) + +# def eval(self, prob): +# if prob._formulation == 'HJ': +# inds = closestPoints(prob.mesh, self.loc, gridLoc='CC') +# q = np.zeros(prob.mesh.nC) +# q[inds] = self.current * np.r_[1., -1.] +# elif prob._formulation == 'EB': +# qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense() +# qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense() +# q = self.current * mkvc(qa+qb) +# return q + +# class Pole_ky(BaseSrc): + +# def __init__(self, rxList, loc, **kwargs): +# BaseSrc.__init__(self, rxList, loc=loc, **kwargs) + +# def eval(self, prob): +# if prob._formulation == 'HJ': +# inds = closestPoints(prob.mesh, self.loc[[0,2]]) +# q = np.zeros(prob.mesh.nC) +# q[inds] = self.current * np.r_[1.] +# elif prob._formulation == 'EB': +# q = prob.mesh.getInterpolationMat(self.loc[[0,2]], locType='N').todense() +# q = self.current * mkvc(q) +# return q diff --git a/SimPEG/EM/Static/Utils/StaticUtils.py b/SimPEG/EM/Static/Utils/StaticUtils.py index d8e0d0c8..43181c8a 100644 --- a/SimPEG/EM/Static/Utils/StaticUtils.py +++ b/SimPEG/EM/Static/Utils/StaticUtils.py @@ -213,6 +213,7 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] SrcList = [] + if stype != 'gradient': for ii in range(0, int(nstn)-1): @@ -261,7 +262,6 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): srcClass = DC.Src.Pole([rxClass], M[ii,:]) SrcList.append(srcClass) - # TODO: test gradient array! elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square From c488dabf9a113be5d277fa258c6e1a9a9d8e050e Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 4 May 2016 12:48:29 -0700 Subject: [PATCH 117/168] working on IP --- SimPEG/EM/Static/IP/ProblemIP.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/EM/Static/IP/ProblemIP.py b/SimPEG/EM/Static/IP/ProblemIP.py index dcf12d6b..4ff81990 100644 --- a/SimPEG/EM/Static/IP/ProblemIP.py +++ b/SimPEG/EM/Static/IP/ProblemIP.py @@ -154,7 +154,7 @@ class BaseIPProblem(BaseEMProblem): dMfRhoI_dI = -self.MfRhoI**2 dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u) - drho_dlogrho = Utils.sdiag(self.rho) + drho_dlogrho = Utils.sdiag(self.rho)*self.curModel.etaDeriv return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho)) # TODO: This should take a vector @@ -162,7 +162,7 @@ class BaseIPProblem(BaseEMProblem): """ Derivative of MeSigma with respect to the model """ - dsigma_dlogsigma = Utils.sdiag(self.sigma) + dsigma_dlogsigma = Utils.sdiag(self.sigma)*self.curModel.etaDeriv return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma class Problem3D_CC(BaseIPProblem): From 4e296c4cd5194495b9b397fc87a724925ca608a6 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 4 May 2016 16:01:29 -0700 Subject: [PATCH 118/168] Update PreCond Directive to allow inactive cells mapping --- SimPEG/Directives.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index e51c904e..4fc1ffc5 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -315,7 +315,7 @@ class Update_lin_PreCond(InversionDirective): if getattr(self.opt, 'approxHinv', None) is 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.) + PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC def endIter(self): @@ -326,7 +326,7 @@ class Update_lin_PreCond(InversionDirective): 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.) + PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC From dbdcc3cefb28cfaa7802b28468d5f0cc60f70e9f Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 4 May 2016 22:06:32 -0700 Subject: [PATCH 119/168] use sigma in MfRhoDeriv - due to propmap bug --- SimPEG/EM/Base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index 032b4429..a16cdb91 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -165,8 +165,7 @@ class BaseEMProblem(Problem.BaseProblem): """ Derivative of :code:`MfRho` with respect to the model. """ - return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * self.curModel.rhoDeriv - # (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) + return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) # self.curModel.rhoDeriv @property From 66440b0478b434adaa9bbb07c13ce056fd3f45f3 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 4 May 2016 22:14:41 -0700 Subject: [PATCH 120/168] add depreciation warnings to DCIP utils for activeind from topo --- SimPEG/DCIP/DCIPUtils.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 800b478c..f4e643eb 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -1,12 +1,16 @@ from SimPEG import np, Utils import BaseDC as DC import BaseDC as IP +import warnings def getActiveindfromTopo(mesh, topo): # def genActiveindfromTopo(mesh, topo): """ Get active indices from topography """ + warnings.warn( + "`getActiveindfromTopo` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead", + FutureWarning) from scipy.interpolate import NearestNDInterpolator if mesh.dim==3: nCxy = mesh.nCx*mesh.nCy @@ -28,6 +32,9 @@ def gettopoCC(mesh, airind): """ Get topography from active indices of mesh. """ + warnings.warn( + "`gettopoCC` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead", + FutureWarning) mesh2D = Mesh.TensorMesh([mesh.hx, mesh.hy], mesh.x0[:2]) zc = mesh.gridCC[:,2] AIRIND = airind.reshape((mesh.vnC[0]*mesh.vnC[1],mesh.vnC[2]), order='F') @@ -630,16 +637,9 @@ def readUBC_DC3Dobs(fileName): """ Read UBC GIF DCIP 3D observation file and generate survey - Input: - :param fileName, path to the UBC GIF 3D obs file - - Output: - :param DCIPsurvey - :return - - Created on Mon April 6th, 2015 - - @author: dominiquef + :param string fileName:, path to the UBC GIF 3D obs file + :rtype: Survey + :return: DCIPsurvey """ From 0379df2bf22bed20151ed29ece5e41e95e6e98cf Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 4 May 2016 22:27:02 -0700 Subject: [PATCH 121/168] attempt to clean up docs in DCIP utils --- SimPEG/DCIP/DCIPUtils.py | 73 ++++++++++++---------------------------- 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index f4e643eb..49f9ba2b 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -444,21 +444,14 @@ def writeUBC_DCobs(fileName, DCsurvey, dim, surveyType): """ Write UBC GIF DCIP 2D or 3D observation file - Input: - :string fileName -> including path where the file is written out - :DCsurvey -> DC survey class object - :string dim -> either '2D' | '3D' - :string surveyType -> either 'SURFACE' | 'GENERAL' - - Output: - :param UBC2D-Data file - :return - - Last edit: February 16th, 2016 - - @author: dominiquef - + :param string fileName: including path where the file is written out + :param Survey DCsurvey: DC survey class object + :param string dim: either '2D' | '3D' + :param string surveyType: either 'SURFACE' | 'GENERAL' + :rtype: file + :return: UBC2D-Data file """ + from SimPEG import mkvc assert (dim=='2D') | (dim=='3D'), "Data must be either '2D' | '3D'" @@ -539,15 +532,9 @@ def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'): The Z value is preserved, but Y coordinates zeroed. - Input: - :param survey3D - - Output: - :figure survey2D - - Edited April 6th, 2016 - - @author: dominiquef + :param DC.Survey survey3D: 3D simpeg DC survey + :rtype: DC.Survey + :return: survey2D """ from SimPEG import np @@ -715,17 +702,9 @@ def readUBC_DC2Dobs(fileName): ------- NEEDS TO BE UPDATED ------ Read UBC GIF 2D observation file and generate arrays for tx-rx location - Input: - :param fileName, path to the UBC GIF 2D model file - - Output: - :param rx, tx - :return - - Created on Thu Nov 12 13:14:10 2015 - - @author: dominiquef - + :param string fileName: path to the UBC GIF 2D model file + :rtype: (DC.Src, DC.Rx, ??, ??) + :return: source_locs, rx_locs, ??, ?? """ from SimPEG import np @@ -765,11 +744,9 @@ def readUBC_DC2Dpre(fileName): 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 - - Output: - DCsurvey - :return + :param string fileName: path to the UBC GIF 3D obs file + :rtype: DC.Survey + :return: DCsurvey Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >> @@ -831,12 +808,9 @@ def readUBC_DC2DMesh(fileName): """ Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg - Input: - :param fileName, path to the UBC GIF mesh file - - Output: - :param SimPEG TensorMesh 2D object - :return + :param string fileName: path to the UBC GIF mesh file + :rtype: Mesh.TensorMesh + :return: SimPEG TensorMesh 2D object Created on Thu Nov 12 13:14:10 2015 @@ -902,12 +876,9 @@ def xy_2_lineID(DCsurvey): they were collected. May need to generalize for random point locations, but will be more expensive - Input: - :param DCdict Vectors of station location - - Output: - :param LineID Vector of integers - :return + :param numpy.array DCdict: Vectors of station location + :rtype: numpy.array + :return: LineID Vector of integers Created on Thu Feb 11, 2015 From fbb8cf2731e10000f71e2056215a363ffc0d4023 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 4 May 2016 23:17:01 -0700 Subject: [PATCH 122/168] modularizing regularization --- SimPEG/Regularization.py | 404 ++++++++++++++++++++++++++------------- 1 file changed, 269 insertions(+), 135 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index fc101a61..fd974130 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -403,7 +403,203 @@ class BaseRegularization(object): return mD.T * ( self.W.T * ( self.W * ( mD * v) ) ) -class Tikhonov(BaseRegularization): +class Simple(BaseRegularization): + """ + Simple regularization that does not include length scales in the derivatives. + """ + + mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options + 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") + 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 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): + """Regularization matrix Wx""" + if getattr(self, '_Wx', None) is None: + 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*(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*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil + return self._Wz + + @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 self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + 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) + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + wlist = (self.Wsmall, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W + + @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 self._Wsmooth + + + @Utils.timeIt + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) + + @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 _evalSmoothx(self, m): + if self.mrefInSmooth == True: + r = self.Wx * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wx * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothy(self, m): + if self.mrefInSmooth == True: + r = self.Wy * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wy * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothz(self, m): + if self.mrefInSmooth == True: + r = self.Wz * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wz * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmooth(self, m): + phiSmooth = self._evalSmoothx(m) + if self.regmesh.dim > 1: + phiSmooth += self._evalSmoothy(m) + if self.regmesh.dim > 2: + phiSmooth += self._evalSmoothz(m) + return phiSmooth + + @Utils.timeIt + def _evalSmoothxDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wx * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wx * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wx * ( self.mapping * m ) + return r.T * ( self.Wx * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothyDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wy * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wy * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wy * ( self.mapping * m ) + return r.T * ( self.Wy * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothzDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wz * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wz * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wz * ( self.mapping * m ) + return r.T * ( self.Wz * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothDeriv(self,m): + deriv = self._evalSmoothxDeriv(m) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyDeriv(m) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzDeriv(m) + return deriv + + + @Utils.timeIt + def eval(self, m): + return self._evalSmall(m) + self._evalSmooth(m) + + @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})} + + """ + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + + + +class Tikhonov(Simple): """ L2 Tikhonov regularization with both smallness and smoothness (first order derivative) contributions. @@ -493,56 +689,92 @@ class Tikhonov(BaseRegularization): self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz return self._Wzz + @property - def Wsmooth(self): + def Wsmooth2(self): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx, self.Wxx) + wlist = (self.Wxx) if self.regmesh.dim > 1: - wlist += (self.Wy, self.Wyy) + wlist += (self.Wyy) if self.regmesh.dim > 2: - wlist += (self.Wz, self.Wzz) + wlist += (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.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 _evalSmooth(self, m): + def _evalSmoothxx(self, m): if self.mrefInSmooth == True: - r = self.Wsmooth * ( self.mapping * (m - self.mref) ) + r = self.Wxx * ( self.mapping * (m - self.mref) ) elif self.mrefInSmooth == False: - r = self.Wsmooth * ( self.mapping * (m) ) + r = self.Wxx * ( self.mapping * (m) ) return 0.5 * r.dot(r) + @Utils.timeIt + def _evalSmoothyy(self, m): + if self.mrefInSmooth == True: + r = self.Wyy * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wyy * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmoothzz(self, m): + if self.mrefInSmooth == True: + r = self.Wzz * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wzz * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def _evalSmooth2(self, m): + phiSmooth2 = self._evalSmoothxx(m) + if self.regmesh.dim > 1: + phiSmooth2 += self._evalSmoothyy(m) + if self.regmesh.dim > 2: + phiSmooth2 += self._evalSmoothzz(m) + return phiSmooth2 + + @Utils.timeIt + def _evalSmoothxxDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wxx * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wxx * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wxx * ( self.mapping * m ) + return r.T * ( self.Wxx * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothyyDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wyy * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wyy * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wyy * ( self.mapping * m ) + return r.T * ( self.Wyy * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmoothzzDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wzz * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wzz * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wzz * ( self.mapping * m ) + return r.T * ( self.Wzz * self.mapping.deriv(m) ) + + @Utils.timeIt + def _evalSmooth2Deriv(self,m): + deriv = self._evalSmoothxxDeriv(m) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyyDeriv(m) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzzDeriv(m) + return deriv + + @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) ) + return self._evalSmall(m) + self._evalSmooth(m) + self._evalSmooth2(m) @Utils.timeIt def evalDeriv(self, m): @@ -560,88 +792,9 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmooth2Deriv(m) -class Simple(Tikhonov): - """ - Simple regularization that does not include length scales in the derivatives. - """ - - 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") - 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 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): - """Regularization matrix Wx""" - if getattr(self, '_Wx', None) is None: - 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*(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*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil - return self._Wz - - @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 self._Wsmooth - - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - 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 _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) - class Sparse(Simple): @@ -716,25 +869,6 @@ class Sparse(Simple): 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.Wsmall, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W def R(self, f_m , eps, exponent): From b4ab60c2601b6cb2dd64a65d58863f66f265f458 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 5 May 2016 11:55:56 -0700 Subject: [PATCH 123/168] Add model mapping to sparse regularization --- SimPEG/Regularization.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index ed1039ec..1b0d180f 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -663,7 +663,7 @@ class Sparse(Simple): self.Rs = Utils.speye(self.regmesh.nC) else: - f_m = self.curModel - self.reg.mref + f_m = self.mapping * (self.curModel - self.reg.mref) 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 ) @@ -679,7 +679,7 @@ class Sparse(Simple): self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: - f_m = self.regmesh.cellDiffxStencil * self.curModel + f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel) self.rx = self.R( f_m , self.eps_q, self.norms[1]) self.Rx = Utils.sdiag( self.rx ) @@ -693,7 +693,7 @@ class Sparse(Simple): self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) else: - f_m = self.regmesh.cellDiffyStencil * self.curModel + f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel) self.ry = self.R( f_m , self.eps_q, self.norms[2]) self.Ry = Utils.sdiag( self.ry ) @@ -707,7 +707,7 @@ class Sparse(Simple): self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) else: - f_m = self.regmesh.cellDiffzStencil * self.curModel + f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel) self.rz = self.R( f_m , self.eps_q, self.norms[3]) self.Rz = Utils.sdiag( self.rz ) From 069127333d641fa2e4173825a59a1508f5299665 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 5 May 2016 16:41:21 -0700 Subject: [PATCH 124/168] allow interpolation to different cartsian grid locations --- SimPEG/Mesh/CylMesh.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/SimPEG/Mesh/CylMesh.py b/SimPEG/Mesh/CylMesh.py index ecdf36ac..802b13a3 100644 --- a/SimPEG/Mesh/CylMesh.py +++ b/SimPEG/Mesh/CylMesh.py @@ -330,7 +330,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): raise NotImplementedError('wrapping in the averaging is not yet implemented') return self._aveF2CCV - def getInterpolationMatCartMesh(self, Mrect, locType='CC'): + def getInterpolationMatCartMesh(self, Mrect, locType='CC', locTypeTo=None): """ Takes a cartesian mesh and returns a projection to translate onto the cartesian grid. """ @@ -338,19 +338,22 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): assert self.isSymmetric, "Currently we have not taken into account other projections for more complicated CylMeshes" + if locTypeTo is None: + locTypeTo = locType + if locType == 'F': # do this three times for each component - X = self.getInterpolationMatCartMesh(Mrect, locType='Fx') - Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy') - Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz') + X = self.getInterpolationMatCartMesh(Mrect, locType='Fx', locTypeTo=locTypeTo+'x') + Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy', locTypeTo=locTypeTo+'y') + Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz', locTypeTo=locTypeTo+'z') return sp.vstack((X,Y,Z)) if locType == 'E': - X = self.getInterpolationMatCartMesh(Mrect, locType='Ex') - Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey') + X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x') + Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y') Z = spzeros(Mrect.nEz, self.nE) return sp.vstack((X,Y,Z)) - grid = getattr(Mrect, 'grid' + locType) + grid = getattr(Mrect, 'grid' + locTypeTo) # This is unit circle stuff, 0 to 2*pi, starting at x-axis, rotating counter clockwise in an x-y slice theta = - np.arctan2(grid[:,0] - self.cartesianOrigin[0], grid[:,1] - self.cartesianOrigin[1]) + np.pi/2 theta[theta < 0] += np.pi*2.0 @@ -366,7 +369,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): 'Ex': Mrect.tangents[:Mrect.nEx,:], 'Ey': Mrect.tangents[Mrect.nEx:(Mrect.nEx+Mrect.nEy),:], 'Ez': Mrect.tangents[-Mrect.nEz:,:], - }[locType] + }[locTypeTo] if 'F' in locType: normals = np.c_[np.cos(theta), np.sin(theta), np.zeros(theta.size)] proj = ( normals * dotMe ).sum(axis=1) From 82782304767f423cd24545d8a151b6a5715d763d Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 10:35:27 -0700 Subject: [PATCH 125/168] Use LocTypeTo to allow interpolation to different grid locations --- SimPEG/Mesh/CylMesh.py | 2 +- tests/mesh/test_cylMesh.py | 84 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/SimPEG/Mesh/CylMesh.py b/SimPEG/Mesh/CylMesh.py index 802b13a3..f0b6751e 100644 --- a/SimPEG/Mesh/CylMesh.py +++ b/SimPEG/Mesh/CylMesh.py @@ -350,7 +350,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): if locType == 'E': X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x') Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y') - Z = spzeros(Mrect.nEz, self.nE) + Z = spzeros(getattr(Mrect, 'n' + locTypeTo + 'z'), self.nE) return sp.vstack((X,Y,Z)) grid = getattr(Mrect, 'grid' + locTypeTo) diff --git a/tests/mesh/test_cylMesh.py b/tests/mesh/test_cylMesh.py index 5a963398..c7cd44ae 100644 --- a/tests/mesh/test_cylMesh.py +++ b/tests/mesh/test_cylMesh.py @@ -146,6 +146,20 @@ class TestCyl2DMesh(unittest.TestCase): assert np.abs(Pr*(Pc2r*mc) - Pc*mc).max() < 1e-3 + def test_getInterpMatCartMesh_Cells2Nodes(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + mc = np.arange(Mc.nC) + xr = np.linspace(0,0.4,50) + xc = np.linspace(0,0.4,50) + 0.2 + Pr = Mr.getInterpolationMat(np.c_[xr,np.ones(50)*-0.2,np.ones(50)*0.5],'N') + Pc = Mc.getInterpolationMat(np.c_[xc,np.zeros(50),np.ones(50)*0.5],'CC') + Pc2r = Mc.getInterpolationMatCartMesh(Mr, 'CC', locTypeTo='N') + + assert np.abs(Pr*(Pc2r*mc) - Pc*mc).max() < 1e-3 + def test_getInterpMatCartMesh_Faces(self): Mr = Mesh.TensorMesh([100,100,2], x0='CC0') @@ -177,6 +191,37 @@ class TestCyl2DMesh(unittest.TestCase): assert np.abs(mag[dist > 0.1].min() - 1) < TOL + def test_getInterpMatCartMesh_Faces2Edges(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + Pf2e = Mc.getInterpolationMatCartMesh(Mr, 'F', locTypeTo='E') + mf = np.ones(Mc.nF) + + ecart = Pf2e * mf + + excc = Mr.aveEx2CC*Mr.r(ecart, 'E', 'Ex') + eycc = Mr.aveEy2CC*Mr.r(ecart, 'E', 'Ey') + ezcc = Mr.r(ecart, 'E', 'Ez') + + indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) + indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5]) + + TOL = 1e-2 + assert np.abs(float(excc[indX]) - 1) < TOL + assert np.abs(float(excc[indY]) - 0) < TOL + assert np.abs(float(eycc[indX]) - 0) < TOL + assert np.abs(float(eycc[indY]) - 1) < TOL + assert np.abs((ezcc - 1).sum()) < TOL + + mag = (excc**2 + eycc**2)**0.5 + dist = ((Mr.gridCC[:,0] + 0.2)**2 + (Mr.gridCC[:,1] + 0.2)**2)**0.5 + + assert np.abs(mag[dist > 0.1].max() - 1) < TOL + assert np.abs(mag[dist > 0.1].min() - 1) < TOL + + def test_getInterpMatCartMesh_Edges(self): Mr = Mesh.TensorMesh([100,100,2], x0='CC0') @@ -185,11 +230,42 @@ class TestCyl2DMesh(unittest.TestCase): Pe = Mc.getInterpolationMatCartMesh(Mr, 'E') me = np.ones(Mc.nE) - erect = Pe * me + ecart = Pe * me - excc = Mr.aveEx2CC*Mr.r(erect, 'E', 'Ex') - eycc = Mr.aveEy2CC*Mr.r(erect, 'E', 'Ey') - ezcc = Mr.r(erect, 'E', 'Ez') + excc = Mr.aveEx2CC*Mr.r(ecart, 'E', 'Ex') + eycc = Mr.aveEy2CC*Mr.r(ecart, 'E', 'Ey') + ezcc = Mr.aveEz2CC*Mr.r(ecart, 'E', 'Ez') + + indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) + indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5]) + + TOL = 1e-2 + assert np.abs(float(excc[indX]) - 0) < TOL + assert np.abs(float(excc[indY]) + 1) < TOL + assert np.abs(float(eycc[indX]) - 1) < TOL + assert np.abs(float(eycc[indY]) - 0) < TOL + assert np.abs(ezcc.sum()) < TOL + + mag = (excc**2 + eycc**2)**0.5 + dist = ((Mr.gridCC[:,0] + 0.2)**2 + (Mr.gridCC[:,1] + 0.2)**2)**0.5 + + assert np.abs(mag[dist > 0.1].max() - 1) < TOL + assert np.abs(mag[dist > 0.1].min() - 1) < TOL + + + def test_getInterpMatCartMesh_Edges2Faces(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + Pe2f = Mc.getInterpolationMatCartMesh(Mr, 'E', locTypeTo='F') + me = np.ones(Mc.nE) + + frect = Pe2f * me + + excc = Mr.aveFx2CC*Mr.r(frect, 'F', 'Fx') + eycc = Mr.aveFy2CC*Mr.r(frect, 'F', 'Fy') + ezcc = Mr.r(frect, 'F', 'Fz') indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5]) From d8eeb7cd0511d9a30341b6f58d40da6905d42750 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 11:18:36 -0700 Subject: [PATCH 126/168] use Problem3D_assumption, Fields3D_assumption --- SimPEG/EM/Base.py | 18 +++++++++++++++ SimPEG/EM/FDEM/FDEM.py | 24 ++++++++++---------- SimPEG/EM/FDEM/FieldsFDEM.py | 16 ++++++------- SimPEG/EM/FDEM/__init__.py | 4 ++-- SimPEG/EM/Utils/testingUtils.py | 8 +++---- tests/em/fdem/forward/test_FDEM_analytics.py | 6 ++--- tests/em/fdem/forward/test_FDEM_forwardHB.py | 4 ++-- 7 files changed, 49 insertions(+), 31 deletions(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index a16cdb91..431086a4 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -61,6 +61,15 @@ class BaseEMProblem(Problem.BaseProblem): self._Me = self.mesh.getEdgeInnerProduct() return self._Me + @property + def MeI(self): + """ + Edge inner product matrix + """ + if getattr(self, '_MeI', None) is None: + self._MeI = self.mesh.getEdgeInnerProduct(invMat=True) + return self._MeI + @property def Mf(self): """ @@ -70,6 +79,15 @@ class BaseEMProblem(Problem.BaseProblem): self._Mf = self.mesh.getFaceInnerProduct() return self._Mf + @property + def MfI(self): + """ + Face inner product matrix + """ + if getattr(self, '_MfI', None) is None: + self._MfI = self.mesh.getFaceInnerProduct(invMat=True) + return self._MfI + # ----- Magnetic Permeability ----- # @property diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/FDEM.py index caca7602..78e7fa61 100644 --- a/SimPEG/EM/FDEM/FDEM.py +++ b/SimPEG/EM/FDEM/FDEM.py @@ -1,7 +1,7 @@ from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver from scipy.constants import mu_0 from SurveyFDEM import Survey as SurveyFDEM -from FieldsFDEM import Fields, Fields_e, Fields_b, Fields_h, Fields_j +from FieldsFDEM import Fields, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j from SimPEG.EM.Base import BaseEMProblem from SimPEG.EM.Utils import omega @@ -17,8 +17,8 @@ class BaseFDEMProblem(BaseEMProblem): \mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\ {\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}} - if using the E-B formulation (:code:`Problem_e` - or :code:`Problem_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity. + if using the E-B formulation (:code:`Problem3D_e` + or :code:`Problem3D_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity. If we write Maxwell's equations in terms of \\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\) @@ -28,7 +28,7 @@ class BaseFDEMProblem(BaseEMProblem): \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + i \omega \mathbf{M_{\mu}^e} \mathbf{h} = \mathbf{s_m} \\\\ \mathbf{C} \mathbf{h} - \mathbf{j} = \mathbf{s_e} - if using the H-J formulation (:code:`Problem_j` or :code:`Problem_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity. + if using the H-J formulation (:code:`Problem3D_j` or :code:`Problem3D_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity. The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\) """ @@ -177,7 +177,7 @@ class BaseFDEMProblem(BaseEMProblem): ################################ E-B Formulation ######################################### ########################################################################################## -class Problem_e(BaseFDEMProblem): +class Problem3D_e(BaseFDEMProblem): """ By eliminating the magnetic flux density using @@ -199,7 +199,7 @@ class Problem_e(BaseFDEMProblem): _solutionType = 'eSolution' _formulation = 'EB' - fieldsPair = Fields_e + fieldsPair = Fields3D_e def __init__(self, mesh, **kwargs): BaseFDEMProblem.__init__(self, mesh, **kwargs) @@ -288,7 +288,7 @@ class Problem_e(BaseFDEMProblem): return C.T * (MfMui * s_mDeriv(v)) -1j * omega(freq) * s_eDeriv(v) -class Problem_b(BaseFDEMProblem): +class Problem3D_b(BaseFDEMProblem): """ We eliminate :math:`\mathbf{e}` using @@ -310,7 +310,7 @@ class Problem_b(BaseFDEMProblem): _solutionType = 'bSolution' _formulation = 'EB' - fieldsPair = Fields_b + fieldsPair = Fields3D_b def __init__(self, mesh, **kwargs): BaseFDEMProblem.__init__(self, mesh, **kwargs) @@ -436,7 +436,7 @@ class Problem_b(BaseFDEMProblem): ########################################################################################## -class Problem_j(BaseFDEMProblem): +class Problem3D_j(BaseFDEMProblem): """ We eliminate \\\(\\\mathbf{h}\\\) using @@ -458,7 +458,7 @@ class Problem_j(BaseFDEMProblem): _solutionType = 'jSolution' _formulation = 'HJ' - fieldsPair = Fields_j + fieldsPair = Fields3D_j def __init__(self, mesh, **kwargs): BaseFDEMProblem.__init__(self, mesh, **kwargs) @@ -577,7 +577,7 @@ class Problem_j(BaseFDEMProblem): -class Problem_h(BaseFDEMProblem): +class Problem3D_h(BaseFDEMProblem): """ We eliminate \\\(\\\mathbf{j}\\\) using @@ -596,7 +596,7 @@ class Problem_h(BaseFDEMProblem): _solutionType = 'hSolution' _formulation = 'HJ' - fieldsPair = Fields_h + fieldsPair = Fields3D_h def __init__(self, mesh, **kwargs): BaseFDEMProblem.__init__(self, mesh, **kwargs) diff --git a/SimPEG/EM/FDEM/FieldsFDEM.py b/SimPEG/EM/FDEM/FieldsFDEM.py index e2193973..47f37616 100644 --- a/SimPEG/EM/FDEM/FieldsFDEM.py +++ b/SimPEG/EM/FDEM/FieldsFDEM.py @@ -160,9 +160,9 @@ class Fields(SimPEG.Problem.Fields): return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint) return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex) -class Fields_e(Fields): +class Fields3D_e(Fields): """ - Fields object for Problem_e. + Fields object for Problem3D_e. :param Mesh mesh: mesh :param Survey survey: survey @@ -426,9 +426,9 @@ class Fields_e(Fields): -class Fields_b(Fields): +class Fields3D_b(Fields): """ - Fields object for Problem_b. + Fields object for Problem3D_b. :param Mesh mesh: mesh :param Survey survey: survey @@ -693,9 +693,9 @@ class Fields_b(Fields): return Zero() -class Fields_j(Fields): +class Fields3D_j(Fields): """ - Fields object for Problem_j. + Fields object for Problem3D_j. :param Mesh mesh: mesh :param Survey survey: survey @@ -988,9 +988,9 @@ class Fields_j(Fields): return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( s_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) ) -class Fields_h(Fields): +class Fields3D_h(Fields): """ - Fields object for Problem_h. + Fields object for Problem3D_h. :param Mesh mesh: mesh :param Survey survey: survey diff --git a/SimPEG/EM/FDEM/__init__.py b/SimPEG/EM/FDEM/__init__.py index 978972f5..1565d062 100644 --- a/SimPEG/EM/FDEM/__init__.py +++ b/SimPEG/EM/FDEM/__init__.py @@ -1,3 +1,3 @@ from SurveyFDEM import Rx, Src, Survey -from FDEM import BaseFDEMProblem, Problem_e, Problem_b, Problem_j, Problem_h -from FieldsFDEM import * \ No newline at end of file +from FDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h +from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h diff --git a/SimPEG/EM/Utils/testingUtils.py b/SimPEG/EM/Utils/testingUtils.py index e5e75c06..00461e2d 100644 --- a/SimPEG/EM/Utils/testingUtils.py +++ b/SimPEG/EM/Utils/testingUtils.py @@ -57,19 +57,19 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False): if fdemType == 'e': survey = EM.FDEM.Survey(Src) - prb = EM.FDEM.Problem_e(mesh, mapping=mapping) + prb = EM.FDEM.Problem3D_e(mesh, mapping=mapping) elif fdemType == 'b': survey = EM.FDEM.Survey(Src) - prb = EM.FDEM.Problem_b(mesh, mapping=mapping) + prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping) elif fdemType == 'j': survey = EM.FDEM.Survey(Src) - prb = EM.FDEM.Problem_j(mesh, mapping=mapping) + prb = EM.FDEM.Problem3D_j(mesh, mapping=mapping) elif fdemType == 'h': survey = EM.FDEM.Survey(Src) - prb = EM.FDEM.Problem_h(mesh, mapping=mapping) + prb = EM.FDEM.Problem3D_h(mesh, mapping=mapping) else: raise NotImplementedError() diff --git a/tests/em/fdem/forward/test_FDEM_analytics.py b/tests/em/fdem/forward/test_FDEM_analytics.py index 9786e7c8..f596d638 100644 --- a/tests/em/fdem/forward/test_FDEM_analytics.py +++ b/tests/em/fdem/forward/test_FDEM_analytics.py @@ -33,7 +33,7 @@ class FDEM_analyticTests(unittest.TestCase): survey = EM.FDEM.Survey([Src0]) - prb = EM.FDEM.Problem_b(mesh, mapping=mapping) + prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping) prb.pair(survey) try: @@ -125,8 +125,8 @@ class FDEM_analyticTests(unittest.TestCase): mapping = [('sigma', Maps.IdentityMap(mesh)),('mu', Maps.IdentityMap(mesh))] - prbe = EM.FDEM.Problem_h(mesh, mapping=mapping) - prbm = EM.FDEM.Problem_e(mesh, mapping=mapping) + prbe = EM.FDEM.Problem3D_h(mesh, mapping=mapping) + prbm = EM.FDEM.Problem3D_e(mesh, mapping=mapping) prbe.pair(surveye) # pair problem and survey prbm.pair(surveym) diff --git a/tests/em/fdem/forward/test_FDEM_forwardHB.py b/tests/em/fdem/forward/test_FDEM_forwardHB.py index 545a5014..8fce615b 100644 --- a/tests/em/fdem/forward/test_FDEM_forwardHB.py +++ b/tests/em/fdem/forward/test_FDEM_forwardHB.py @@ -12,7 +12,7 @@ testBH = True verbose = False TOLEJHB = 1 # averaging and more sensitive to boundary condition violations (ie. the impact of violating the boundary conditions in each case is different.) -#TODO: choose better testing parameters to lower this +#TODO: choose better testing parameters to lower this SrcList = ['RawVec', 'MagDipole_Bfield', 'MagDipole', 'CircularLoop'] @@ -125,4 +125,4 @@ class FDEM_CrossCheck(unittest.TestCase): self.assertTrue(crossCheckTest(SrcList, 'b', 'h', 'hzi', verbose=verbose, TOL=TOLEJHB)) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() From 52747c09262d5fa835d15f445ef9a3fccd4dba4d Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 11:35:28 -0700 Subject: [PATCH 127/168] update example --- SimPEG/Examples/EM_FDEM_1D_Inversion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index e76b2439..824c4f95 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -42,7 +42,7 @@ def run(plotIt=True): ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5) - rxOffset=10. + rxOffset=10. bzi = EM.FDEM.Rx(np.array([[rxOffset, 0., 1e-3]]), 'bzi') freqs = np.logspace(1,3,10) @@ -52,7 +52,7 @@ def run(plotIt=True): [srcList.append(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) + prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping) try: from pymatsolver import MumpsSolver From f7c46ed83be33915ca91ad64265a90758941f151 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 12:41:06 -0700 Subject: [PATCH 128/168] Rx classes for FDEM --- SimPEG/EM/FDEM/RxFDEM.py | 105 ++++++++++++++++ SimPEG/EM/FDEM/SurveyFDEM.py | 121 +------------------ SimPEG/EM/FDEM/__init__.py | 4 +- SimPEG/EM/Utils/testingUtils.py | 17 ++- SimPEG/Examples/EM_FDEM_1D_Inversion.py | 2 +- tests/em/fdem/forward/test_FDEM_analytics.py | 2 +- 6 files changed, 123 insertions(+), 128 deletions(-) create mode 100644 SimPEG/EM/FDEM/RxFDEM.py diff --git a/SimPEG/EM/FDEM/RxFDEM.py b/SimPEG/EM/FDEM/RxFDEM.py new file mode 100644 index 00000000..d0445ff8 --- /dev/null +++ b/SimPEG/EM/FDEM/RxFDEM.py @@ -0,0 +1,105 @@ +import SimPEG +from SimPEG.EM.Utils import * +from SimPEG.EM.Base import BaseEMSurvey +from scipy.constants import mu_0 +from SimPEG.Utils import Zero, Identity +import SrcFDEM as Src +import RxFDEM as Rx +from SimPEG import sp + +class BaseRx(SimPEG.Survey.BaseRx): + """ + Frequency domain receivers + + :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + """ + + def __init__(self, locs, orientation=None, real_or_imag=None): + assert(orientation in ['x','y','z']), "Orientation %s not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented."%orientation + assert(real_or_imag in ['real', 'imag']), "'real_or_imag' must be 'real' or 'imag', not %s"%real_or_imag + + self.projComp = orientation + self.real_or_imag = real_or_imag + + SimPEG.Survey.BaseRx.__init__(self, locs, rxType=None) #TODO: remove rxType from baseRx + + def projGLoc(self, u): + """Grid Location projection (e.g. Ex Fy ...)""" + return u._GLoc(self.projField) + self.projComp + + def eval(self, src, mesh, f): + """ + Project fields to recievers to get data. + + :param Source src: FDEM source + :param Mesh mesh: mesh used + :param Fields f: fields object + :rtype: numpy.ndarray + :return: fields projected to recievers + """ + + P = self.getP(mesh, self.projGLoc(f)) + f_part_complex = f[src, self.projField] + # get the real or imag component + f_part = getattr(f_part_complex, self.real_or_imag) + + return P*f_part + + def evalDeriv(self, src, mesh, f, v, adjoint=False): + """ + Derivative of projected fields with respect to the inversion model times a vector. + + :param Source src: FDEM source + :param Mesh mesh: mesh used + :param Fields f: fields object + :param numpy.ndarray v: vector to multiply + :rtype: numpy.ndarray + :return: fields projected to recievers + """ + + P = self.getP(mesh, self.projGLoc(f)) + + if not adjoint: + Pv_complex = P * v + # real_or_imag = self.projComp + Pv = getattr(Pv_complex, self.real_or_imag) + elif adjoint: + Pv_real = P.T * v + + # real_or_imag = self.projComp + if self.real_or_imag == 'imag': + Pv = 1j*Pv_real + elif self.real_or_imag == 'real': + Pv = Pv_real.astype(complex) + else: + raise NotImplementedError('must be real or imag') + + return Pv + + +class eField(BaseRx): + + def __init__(self, locs, orientation=None, real_or_imag=None): + self.projField = 'e' + BaseRx.__init__(self, locs, orientation, real_or_imag) + + +class bField(BaseRx): + + def __init__(self, locs, orientation=None, real_or_imag=None): + self.projField = 'b' + BaseRx.__init__(self, locs, orientation, real_or_imag) + + +class hField(BaseRx): + + def __init__(self, locs, orientation=None, real_or_imag=None): + self.projField = 'h' + BaseRx.__init__(self, locs, orientation, real_or_imag) + + +class jField(BaseRx): + + def __init__(self, locs, orientation=None, real_or_imag=None): + self.projField = 'j' + BaseRx.__init__(self, locs, orientation, real_or_imag) diff --git a/SimPEG/EM/FDEM/SurveyFDEM.py b/SimPEG/EM/FDEM/SurveyFDEM.py index 1552a12c..46ae2523 100644 --- a/SimPEG/EM/FDEM/SurveyFDEM.py +++ b/SimPEG/EM/FDEM/SurveyFDEM.py @@ -4,126 +4,9 @@ from SimPEG.EM.Base import BaseEMSurvey from scipy.constants import mu_0 from SimPEG.Utils import Zero, Identity import SrcFDEM as Src +import RxFDEM as Rx from SimPEG import sp - -#################################################### -# Receivers -#################################################### - -class Rx(SimPEG.Survey.BaseRx): - """ - Frequency domain receivers - - :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) - :param string rxType: reciever type from knownRxTypes - """ - - knownRxTypes = { - 'exr':['e', 'x', 'real'], - 'eyr':['e', 'y', 'real'], - 'ezr':['e', 'z', 'real'], - 'exi':['e', 'x', 'imag'], - 'eyi':['e', 'y', 'imag'], - 'ezi':['e', 'z', 'imag'], - - 'bxr':['b', 'x', 'real'], - 'byr':['b', 'y', 'real'], - 'bzr':['b', 'z', 'real'], - 'bxi':['b', 'x', 'imag'], - 'byi':['b', 'y', 'imag'], - 'bzi':['b', 'z', 'imag'], - - 'jxr':['j', 'x', 'real'], - 'jyr':['j', 'y', 'real'], - 'jzr':['j', 'z', 'real'], - 'jxi':['j', 'x', 'imag'], - 'jyi':['j', 'y', 'imag'], - 'jzi':['j', 'z', 'imag'], - - 'hxr':['h', 'x', 'real'], - 'hyr':['h', 'y', 'real'], - 'hzr':['h', 'z', 'real'], - 'hxi':['h', 'x', 'imag'], - 'hyi':['h', 'y', 'imag'], - 'hzi':['h', 'z', 'imag'], - } - radius = None - - def __init__(self, locs, rxType): - SimPEG.Survey.BaseRx.__init__(self, locs, rxType) - - @property - def projField(self): - """Field Type projection (e.g. e b ...)""" - return self.knownRxTypes[self.rxType][0] - - @property - def projComp(self): - """Component projection (real/imag)""" - return self.knownRxTypes[self.rxType][2] - - def projGLoc(self, u): - """Grid Location projection (e.g. Ex Fy ...)""" - return u._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1] - - def eval(self, src, mesh, f): - """ - Project fields to recievers to get data. - - :param Source src: FDEM source - :param Mesh mesh: mesh used - :param Fields f: fields object - :rtype: numpy.ndarray - :return: fields projected to recievers - """ - # projGLoc = u._GLoc(self.knownRxTypes[self.rxType][0]) - # projGLoc += self.knownRxTypes[self.rxType][1] - - P = self.getP(mesh, self.projGLoc(f)) - f_part_complex = f[src, self.projField] - # get the real or imag component - real_or_imag = self.projComp - f_part = getattr(f_part_complex, real_or_imag) - - return P*f_part - - def evalDeriv(self, src, mesh, f, v, adjoint=False): - """ - Derivative of projected fields with respect to the inversion model times a vector. - - :param Source src: FDEM source - :param Mesh mesh: mesh used - :param Fields f: fields object - :param numpy.ndarray v: vector to multiply - :rtype: numpy.ndarray - :return: fields projected to recievers - """ - - P = self.getP(mesh, self.projGLoc(f)) - - if not adjoint: - Pv_complex = P * v - real_or_imag = self.projComp - Pv = getattr(Pv_complex, real_or_imag) - elif adjoint: - Pv_real = P.T * v - - real_or_imag = self.projComp - if real_or_imag == 'imag': - Pv = 1j*Pv_real - elif real_or_imag == 'real': - Pv = Pv_real.astype(complex) - else: - raise NotImplementedError('must be real or imag') - - return Pv - - -#################################################### -# Survey -#################################################### - class Survey(BaseEMSurvey): """ Frequency domain electromagnetic survey @@ -132,7 +15,7 @@ class Survey(BaseEMSurvey): """ srcPair = Src.BaseSrc - rxPair = Rx + rxPair = Rx.BaseRx def __init__(self, srcList, **kwargs): # Sort these by frequency diff --git a/SimPEG/EM/FDEM/__init__.py b/SimPEG/EM/FDEM/__init__.py index 1565d062..1701fe3e 100644 --- a/SimPEG/EM/FDEM/__init__.py +++ b/SimPEG/EM/FDEM/__init__.py @@ -1,3 +1,5 @@ -from SurveyFDEM import Rx, Src, Survey +from SurveyFDEM import Survey +import SrcFDEM as Src +import RxFDEM as Rx from FDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h diff --git a/SimPEG/EM/Utils/testingUtils.py b/SimPEG/EM/Utils/testingUtils.py index 00461e2d..c3fc50d2 100644 --- a/SimPEG/EM/Utils/testingUtils.py +++ b/SimPEG/EM/Utils/testingUtils.py @@ -26,31 +26,36 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False): x = np.array([np.linspace(-5.*cs,-2.*cs,3),np.linspace(5.*cs,2.*cs,3)]) + cs/4. #don't sample right by the source, slightly off alignment from either staggered grid XYZ = Utils.ndgrid(x,x,np.linspace(-2.*cs,2.*cs,5)) - Rx0 = EM.FDEM.Rx(XYZ, comp) + Rx0 = getattr(EM.FDEM.Rx, comp[0] + 'Field') + if comp[2] == 'r': + real_or_imag = 'real' + elif comp[2] == 'i': + real_or_imag = 'imag' + rx0 = Rx0(XYZ, comp[1], 'imag') Src = [] for SrcType in SrcList: if SrcType is 'MagDipole': - Src.append(EM.FDEM.Src.MagDipole([Rx0], freq=freq, loc=np.r_[0.,0.,0.])) + Src.append(EM.FDEM.Src.MagDipole([rx0], freq=freq, loc=np.r_[0.,0.,0.])) elif SrcType is 'MagDipole_Bfield': - Src.append(EM.FDEM.Src.MagDipole_Bfield([Rx0], freq=freq, loc=np.r_[0.,0.,0.])) + Src.append(EM.FDEM.Src.MagDipole_Bfield([rx0], freq=freq, loc=np.r_[0.,0.,0.])) elif SrcType is 'CircularLoop': - Src.append(EM.FDEM.Src.CircularLoop([Rx0], freq=freq, loc=np.r_[0.,0.,0.])) + Src.append(EM.FDEM.Src.CircularLoop([rx0], freq=freq, loc=np.r_[0.,0.,0.])) elif SrcType is 'RawVec': if fdemType is 'e' or fdemType is 'b': S_m = np.zeros(mesh.nF) S_e = np.zeros(mesh.nE) S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3 S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3 - Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, mesh.getEdgeInnerProduct()*S_e)) + Src.append(EM.FDEM.Src.RawVec([rx0], freq, S_m, mesh.getEdgeInnerProduct()*S_e)) elif fdemType is 'h' or fdemType is 'j': S_m = np.zeros(mesh.nE) S_e = np.zeros(mesh.nF) S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3 S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3 - Src.append(EM.FDEM.Src.RawVec([Rx0], freq, mesh.getEdgeInnerProduct()*S_m, S_e)) + Src.append(EM.FDEM.Src.RawVec([rx0], freq, mesh.getEdgeInnerProduct()*S_m, S_e)) if verbose: print ' Fetching %s problem' % (fdemType) diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index 824c4f95..1764f28c 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -43,7 +43,7 @@ def run(plotIt=True): rxOffset=10. - bzi = EM.FDEM.Rx(np.array([[rxOffset, 0., 1e-3]]), 'bzi') + bzi = EM.FDEM.Rx.bField(np.array([[rxOffset, 0., 1e-3]]), orientation='z', real_or_imag='imag') freqs = np.logspace(1,3,10) srcLoc = np.array([0., 0., 10.]) diff --git a/tests/em/fdem/forward/test_FDEM_analytics.py b/tests/em/fdem/forward/test_FDEM_analytics.py index f596d638..0ea43ca7 100644 --- a/tests/em/fdem/forward/test_FDEM_analytics.py +++ b/tests/em/fdem/forward/test_FDEM_analytics.py @@ -28,7 +28,7 @@ class FDEM_analyticTests(unittest.TestCase): x = np.linspace(-10,10,5) XYZ = Utils.ndgrid(x,np.r_[0],np.r_[0]) - rxList = EM.FDEM.Rx(XYZ, 'exi') + rxList = EM.FDEM.Rx.eField(XYZ, orientation='x', real_or_imag='imag') Src0 = EM.FDEM.Src.MagDipole([rxList],loc=np.r_[0.,0.,0.], freq=freq) survey = EM.FDEM.Survey([Src0]) From cb042ac9380a20eb431d6b39ef6c8eff554ac94c Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 13:00:29 -0700 Subject: [PATCH 129/168] cleanup imports, docstrings --- SimPEG/EM/FDEM/RxFDEM.py | 43 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/SimPEG/EM/FDEM/RxFDEM.py b/SimPEG/EM/FDEM/RxFDEM.py index d0445ff8..ef58d807 100644 --- a/SimPEG/EM/FDEM/RxFDEM.py +++ b/SimPEG/EM/FDEM/RxFDEM.py @@ -1,17 +1,13 @@ import SimPEG -from SimPEG.EM.Utils import * -from SimPEG.EM.Base import BaseEMSurvey -from scipy.constants import mu_0 -from SimPEG.Utils import Zero, Identity -import SrcFDEM as Src -import RxFDEM as Rx from SimPEG import sp class BaseRx(SimPEG.Survey.BaseRx): """ - Frequency domain receivers + Frequency domain receiver base class :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + :param string orientation: receiver orientation 'x', 'y' or 'z' + :param string real_or_imag: real or imaginary component 'real' or 'imag' """ def __init__(self, locs, orientation=None, real_or_imag=None): @@ -40,8 +36,7 @@ class BaseRx(SimPEG.Survey.BaseRx): P = self.getP(mesh, self.projGLoc(f)) f_part_complex = f[src, self.projField] - # get the real or imag component - f_part = getattr(f_part_complex, self.real_or_imag) + f_part = getattr(f_part_complex, self.real_or_imag) # get the real or imag component return P*f_part @@ -61,12 +56,10 @@ class BaseRx(SimPEG.Survey.BaseRx): if not adjoint: Pv_complex = P * v - # real_or_imag = self.projComp Pv = getattr(Pv_complex, self.real_or_imag) elif adjoint: Pv_real = P.T * v - # real_or_imag = self.projComp if self.real_or_imag == 'imag': Pv = 1j*Pv_real elif self.real_or_imag == 'real': @@ -78,6 +71,13 @@ class BaseRx(SimPEG.Survey.BaseRx): class eField(BaseRx): + """ + Electric field FDEM receiver + + :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + :param string orientation: receiver orientation 'x', 'y' or 'z' + :param string real_or_imag: real or imaginary component 'real' or 'imag' + """ def __init__(self, locs, orientation=None, real_or_imag=None): self.projField = 'e' @@ -85,6 +85,13 @@ class eField(BaseRx): class bField(BaseRx): + """ + Magnetic flux FDEM receiver + + :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + :param string orientation: receiver orientation 'x', 'y' or 'z' + :param string real_or_imag: real or imaginary component 'real' or 'imag' + """ def __init__(self, locs, orientation=None, real_or_imag=None): self.projField = 'b' @@ -92,6 +99,13 @@ class bField(BaseRx): class hField(BaseRx): + """ + Magnetic field FDEM receiver + + :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + :param string orientation: receiver orientation 'x', 'y' or 'z' + :param string real_or_imag: real or imaginary component 'real' or 'imag' + """ def __init__(self, locs, orientation=None, real_or_imag=None): self.projField = 'h' @@ -99,6 +113,13 @@ class hField(BaseRx): class jField(BaseRx): + """ + Current density FDEM receiver + + :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) + :param string orientation: receiver orientation 'x', 'y' or 'z' + :param string real_or_imag: real or imaginary component 'real' or 'imag' + """ def __init__(self, locs, orientation=None, real_or_imag=None): self.projField = 'j' From 0a714663d38d255595346dd656a2bdf36cf81c3a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 13:12:37 -0700 Subject: [PATCH 130/168] update Jtvec to work with Rx classes --- SimPEG/EM/FDEM/FDEM.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/FDEM.py index 78e7fa61..026230c6 100644 --- a/SimPEG/EM/FDEM/FDEM.py +++ b/SimPEG/EM/FDEM/FDEM.py @@ -137,10 +137,9 @@ class BaseFDEMProblem(BaseEMProblem): df_dmT = df_dmT + du_dmT # TODO: this should be taken care of by the reciever? - real_or_imag = rx.projComp - if real_or_imag is 'real': + if rx.real_or_imag is 'real': Jtv += np.array(df_dmT, dtype=complex).real - elif real_or_imag is 'imag': + elif rx.real_or_imag is 'imag': Jtv += - np.array(df_dmT, dtype=complex).real else: raise Exception('Must be real or imag') From 8803956d8301747f182fb2f23c70b8c324fc76c6 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Mon, 9 May 2016 19:58:56 +0900 Subject: [PATCH 131/168] Working on SIP --- SimPEG/EM/Static/SIP/ProblemSIP.py | 422 +++++++++++++++++++++++++++++ SimPEG/EM/Static/SIP/RxSIP.py | 82 ++++++ SimPEG/EM/Static/SIP/SurveySIP.py | 32 +++ SimPEG/EM/Static/SIP/__init__.py | 2 + SimPEG/EM/Static/__init__.py | 1 + 5 files changed, 539 insertions(+) create mode 100644 SimPEG/EM/Static/SIP/ProblemSIP.py create mode 100644 SimPEG/EM/Static/SIP/RxSIP.py create mode 100644 SimPEG/EM/Static/SIP/SurveySIP.py create mode 100644 SimPEG/EM/Static/SIP/__init__.py diff --git a/SimPEG/EM/Static/SIP/ProblemSIP.py b/SimPEG/EM/Static/SIP/ProblemSIP.py new file mode 100644 index 00000000..d01ae706 --- /dev/null +++ b/SimPEG/EM/Static/SIP/ProblemSIP.py @@ -0,0 +1,422 @@ +from SimPEG import Problem, Utils, Maps, Mesh +from SimPEG.EM.Base import BaseEMProblem +from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N +from SimPEG.Utils import sdiag +import numpy as np +from SimPEG.Utils import Zero +from SimPEG.EM.Static.DC import getxBCyBC_CC +from SurveySIP import Survey + +class ColeColePropMap(Maps.PropMap): + """ + Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m) + """ + + eta = Maps.Property("Electrical Conductivity", defaultInvProp=True) + tau = Maps.Property("Electrical Conductivity", defaultVal=0.1, propertyLink=('taui', Maps.ReciprocalMap)) + taui = Maps.Property("Electrical Conductivity", defaultVal=1., propertyLink=('tau', Maps.ReciprocalMap)) + c = Maps.Property("Electrical Conductivity", defaultVal=1.) + + +class BaseSIPProblem(BaseEMProblem): + + surveyPair = Survey + fieldsPair = Fields + PropMap = ColeColePropMap + Ainv = None + sigma = None + rho = None + f = None + Ainv = None + + def DebyeTime(t): + peta = self.curModel.eta*np.exp(-self.curModel.taui*t) + return peta + + def EtaDeriv(t): + return np.exp(-self.curModel.taui*t) + + def TauiDeriv(t): + return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) + + def fields(self, m): + self.curModel = m + if self.f is None: + self.f = self.fieldsPair(self.mesh, self.survey) + if self.Ainv == None: + A = self.getA() + self.Ainv = self.Solver(A, **self.solverOpts) + RHS = self.getRHS() + u = self.Ainv * RHS + Srcs = self.survey.srcList + self.f[Srcs, self._solutionType] = u + return self.f + + def forward(self, m, f=None): + + if f is None: + f = self.fields(m) + + self.curModel = m + Jv = self.dataPair(self.survey) #same size as the data + # A = self.getA() + JvAll = [] + for tind in range(len(self.survey.times)): + #Pseudo-chareability + v = DebyeTime(self.survey.times[tind]) + for src in self.survey.srcList: + u_src = f[src, self._solutionType] # solution vector + dA_dm_v = self.getADeriv(u_src, v) + dRHS_dm_v = self.getRHSDeriv(src, v) + du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) + for rx in src.rxList: + timeindex = rx.getTimeP(self.survey.times) + if timeindex[tind]: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + JvAll.append(Utils.mkvc(Jv)) + # Conductivity (d u / d log sigma) + if self._formulation is 'EB': + return -np.hstack(JvAll) + # Conductivity (d u / d log rho) + if self._formulation is 'HJ': + return np.hstack(JvAll) + + # def Jvec(self, m, v, f=None): + + # if f is None: + # f = self.fields(m) + + # self.curModel = m + + # Jv = self.dataPair(self.survey) #same size as the data + # x1 = + # x2 = + # # A = self.getA() + # for src in self.survey.srcList: + # u_src = f[src, self._solutionType] # solution vector + + # dA_dm_v = self.getADeriv(u_src, v) + # dRHS_dm_v = self.getRHSDeriv(src, v) + # du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) + + # for rx in src.rxList: + + # for tind in range(len(self.survey.times)): + # df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + # df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) + # Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + # # Conductivity (d u / d log sigma) + # if self._formulation is 'EB': + # return -Utils.mkvc(Jv) + # # Conductivity (d u / d log rho) + # if self._formulation is 'HJ': + # return Utils.mkvc(Jv) + + # def Jtvec(self, m, v, f=None): + # if f is None: + # f = self.fields(m) + + # self.curModel = m + + # # Ensure v is a data object. + # if not isinstance(v, self.dataPair): + # v = self.dataPair(self.survey, v) + + # Jtv = np.zeros(m.size) + # # AT = self.getA() + + # for src in self.survey.srcList: + # u_src = f[src, self._solutionType] + # for rx in src.rxList: + # PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m + # df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + # df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + # ATinvdf_duT = self.Ainv * df_duT + # dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + # dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + # du_dmT = -dA_dmT + dRHS_dmT + # Jtv += df_dmT + du_dmT + # # Conductivity ((d u / d log sigma).T) + # if self._formulation is 'EB': + # return -Utils.mkvc(Jtv) + # # Conductivity ((d u / d log rho).T) + # if self._formulation is 'HJ': + # return Utils.mkvc(Jtv) + + def getSourceTerm(self): + """ + takes concept of source and turns it into a matrix + """ + """ + Evaluates the sources, and puts them in matrix form + + :rtype: (numpy.ndarray, numpy.ndarray) + :return: q (nC or nN, nSrc) + """ + + Srcs = self.survey.srcList + + if self._formulation is 'EB': + n = self.mesh.nN + # return NotImplementedError + + elif self._formulation is 'HJ': + n = self.mesh.nC + + q = np.zeros((n, len(Srcs))) + + for i, src in enumerate(Srcs): + q[:,i] = src.eval(self) + return q + + @property + def deleteTheseOnModelUpdate(self): + toDelete = [] + return toDelete + + # assume log rho or log cond + @property + def MeSigma(self): + """ + Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation + """ + if getattr(self, '_MeSigma', None) is None: + self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma) + return self._MeSigma + + @property + def MfRhoI(self): + """ + Inverse of :code:`MfRho` + """ + if getattr(self, '_MfRhoI', None) is None: + self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True) + return self._MfRhoI + + def MfRhoIDeriv(self,u): + """ + Derivative of :code:`MfRhoI` with respect to the model. + """ + + dMfRhoI_dI = -self.MfRhoI**2 + dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u) + drho_dlogrho = Utils.sdiag(self.rho) + return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho)) + + # TODO: This should take a vector + def MeSigmaDeriv(self, u): + """ + Derivative of MeSigma with respect to the model + """ + dsigma_dlogsigma = Utils.sdiag(self.sigma) + return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma + +class Problem3D_CC(BaseSIPProblem): + + _solutionType = 'phiSolution' + _formulation = 'HJ' # CC potentials means J is on faces + fieldsPair = Fields_CC + + def __init__(self, mesh, **kwargs): + BaseSIPProblem.__init__(self, mesh, **kwargs) + self.setBC() + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + D = self.Div + G = self.Grad + # TODO: this won't work for full anisotropy + MfRhoI = self.MfRhoI + A = D * MfRhoI * G + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return V.T * A + return A + + def getADeriv(self, u, v, adjoint= False): + + D = self.Div + G = self.Grad + MfRhoIDeriv = self.MfRhoIDeriv + + if adjoint: + # if self._makeASymmetric is True: + # v = V * v + return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) ) + return D * (MfRhoIDeriv( G * u ) * v) + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + + # I think we should deprecate this for DC problem. + # if self._makeASymmetric is True: + # return self.Vol.T * RHS + + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() + + def setBC(self): + if self.mesh.dim==3: + fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + gBFzm = self.mesh.gridFz[fzm,:] + gBFzp = self.mesh.gridFz[fzp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + alpha_zm, alpha_zp = temp_zm*0., temp_zp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + beta_zm, beta_zp = temp_zm, temp_zp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + gamma_zm, gamma_zp = temp_zm*0., temp_zp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] + + elif self.mesh.dim==2: + + fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd + gBFxm = self.mesh.gridFx[fxm,:] + gBFxp = self.mesh.gridFx[fxp,:] + gBFym = self.mesh.gridFy[fym,:] + gBFyp = self.mesh.gridFy[fyp,:] + + # Setup Mixed B.C (alpha, beta, gamma) + temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0]) + temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1]) + + alpha_xm, alpha_xp = temp_xm*0., temp_xp*0. + alpha_ym, alpha_yp = temp_ym*0., temp_yp*0. + + beta_xm, beta_xp = temp_xm, temp_xp + beta_ym, beta_yp = temp_ym, temp_yp + + gamma_xm, gamma_xp = temp_xm*0., temp_xp*0. + gamma_ym, gamma_yp = temp_ym*0., temp_yp*0. + + alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp] + beta = [beta_xm, beta_xp, beta_ym, beta_yp] + gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp] + + x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma) + V = self.Vol + self.Div = V * self.mesh.faceDiv + P_BC, B = self.mesh.getBCProjWF_simple() + M = B*self.mesh.aveCC2F + self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M + + +class Problem3D_N(BaseSIPProblem): + + _solutionType = 'phiSolution' + _formulation = 'EB' # N potentials means B is on faces + fieldsPair = Fields_N + + def __init__(self, mesh, **kwargs): + BaseSIPProblem.__init__(self, mesh, **kwargs) + + def getA(self): + """ + + Make the A matrix for the cell centered DC resistivity problem + + A = D MfRhoI D^\\top V + + """ + + # TODO: this won't work for full anisotropy + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + A = Grad.T * MeSigma * Grad + + # Handling Null space of A + A[0,0] = A[0,0] + 1. + + return A + + def getADeriv(self, u, v, adjoint=False): + """ + + Product of the derivative of our system matrix with respect to the model and a vector + + """ + MeSigma = self.MeSigma + Grad = self.mesh.nodalGrad + if not adjoint: + return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + elif adjoint: + return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + + + def getRHS(self): + """ + RHS for the DC problem + + q + """ + + RHS = self.getSourceTerm() + return RHS + + def getRHSDeriv(self, src, v, adjoint=False): + """ + Derivative of the right hand side with respect to the model + """ + # TODO: add qDeriv for RHS depending on m + # qDeriv = src.evalDeriv(self, adjoint=adjoint) + # return qDeriv + return Zero() + +if __name__ == '__main__': + + + cs = 12.5 + hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)] + hz = [(cs,7, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + sigma = np.ones(mesh.nC) + prob = BaseSIPProblem(mesh, sigma=sigma) + + diff --git a/SimPEG/EM/Static/SIP/RxSIP.py b/SimPEG/EM/Static/SIP/RxSIP.py new file mode 100644 index 00000000..f4ff1a2f --- /dev/null +++ b/SimPEG/EM/Static/SIP/RxSIP.py @@ -0,0 +1,82 @@ +import SimPEG +import numpy as np +from SimPEG.Utils import Zero, closestPoints + +class BaseRx(SimPEG.Survey.BaseTimeRx): + locs = None + rxType = None + + knownRxTypes = { + 'phi':['phi',None], + 'ex':['e','x'], + 'ey':['e','y'], + 'ez':['e','z'], + 'jx':['j','x'], + 'jy':['j','y'], + 'jz':['j','z'], + } + + def __init__(self, locs, times, rxType, **kwargs): + SimPEG.Survey.BaseTimeRx.__init__(self, locs, times, rxType, **kwargs) + + @property + def projField(self): + """Field Type projection (e.g. e b ...)""" + return self.knownRxTypes[self.rxType][0] + + def projGLoc(self, f): + """Grid Location projection (e.g. Ex Fy ...)""" + comp = self.knownRxTypes[self.rxType][1] + if comp is not None: + return f._GLoc(self.rxType) + comp + return f._GLoc(self.rxType) + + def getTimeP(self, timesall): + """ + Returns the time projection matrix. + + .. note:: + + This is not stored in memory, but is created on demand. + """ + time_inds = np.in1d(timesall, self.times) + return time_inds + + def evalDeriv(self, src, mesh, f, v, adjoint=False): + P = self.getP(mesh, self.projGLoc(f)) + if not adjoint: + return P*v + elif adjoint: + return P.T*v + + +# DC.Rx.Dipole(locs) +class Dipole(BaseRx): + + def __init__(self, locsM, locsN, times, rxType = 'phi', **kwargs): + assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size' + locs = [locsM, locsN] + # We may not need this ... + BaseRx.__init__(self, locs, times, rxType) + + @property + def nD(self): + """Number of data in the receiver.""" + return self.locs[0].shape[0] * len(self.times) + + # Not sure why ... + # return int(self.locs[0].size / 2) + + + def getP(self, mesh, Gloc): + if mesh in self._Ps: + return self._Ps[mesh] + + P0 = mesh.getInterpolationMat(self.locs[0], Gloc) + P1 = mesh.getInterpolationMat(self.locs[1], Gloc) + P = P0 - P1 + + if self.storeProjections: + self._Ps[mesh] = P + + return P diff --git a/SimPEG/EM/Static/SIP/SurveySIP.py b/SimPEG/EM/Static/SIP/SurveySIP.py new file mode 100644 index 00000000..de375794 --- /dev/null +++ b/SimPEG/EM/Static/SIP/SurveySIP.py @@ -0,0 +1,32 @@ +import SimPEG +from SimPEG.EM.Base import BaseEMSurvey +from SimPEG import np, sp, Survey +from SimPEG.Utils import Zero, Identity +from SimPEG.EM.Static.DC.SrcDC import BaseSrc +from SimPEG.EM.Static.SIP.RxSIP import BaseRx + +class Survey(BaseEMSurvey): + rxPair = BaseRx + srcPair = BaseSrc + times = None + + def __init__(self, srcList, **kwargs): + self.srcList = srcList + BaseEMSurvey.__init__(self, srcList, **kwargs) + self.getUniqueTimes() + + def getUniqueTimes(self): + time_rx = [] + for src in self.srcList: + for rx in src.rxList: + time_rx.append(rx.times) + self.times = np.unique(np.hstack(time_rx)) + + def dpred(self, m, f=None): + """ + Predicted data. + + .. math:: + d_\\text{pred} = Pf(m) + """ + return self.prob.Jvec(m, m, f=f) diff --git a/SimPEG/EM/Static/SIP/__init__.py b/SimPEG/EM/Static/SIP/__init__.py new file mode 100644 index 00000000..f81ceb3c --- /dev/null +++ b/SimPEG/EM/Static/SIP/__init__.py @@ -0,0 +1,2 @@ +from ProblemSIP import Problem3D_CC, Problem3D_N +from SurveySIP import Survey diff --git a/SimPEG/EM/Static/__init__.py b/SimPEG/EM/Static/__init__.py index c9b4dc0d..f6e0e757 100644 --- a/SimPEG/EM/Static/__init__.py +++ b/SimPEG/EM/Static/__init__.py @@ -1,2 +1,3 @@ import DC import IP +import SIP From 73c219ff5c3ce9af371a479a050783223cfbe89a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Mon, 9 May 2016 12:29:52 -0700 Subject: [PATCH 132/168] updated Problem naming in casing example --- SimPEG/Examples/EM_Schenkel_Morrison_Casing.py | 2 +- docs/examples/DC_Forward_PseudoSection.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py index 76af4a3d..930b452a 100644 --- a/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py +++ b/SimPEG/Examples/EM_Schenkel_Morrison_Casing.py @@ -215,7 +215,7 @@ def run(plotIt=True): # ------------ Problem and Survey --------------- survey = FDEM.Survey(sg_p + dg_p) mapping = [('sigma', Maps.IdentityMap(mesh))] - problem = FDEM.Problem_h(mesh, mapping=mapping) + problem = FDEM.Problem3D_h(mesh, mapping=mapping) problem.pair(survey) # ------------- Solve --------------------------- diff --git a/docs/examples/DC_Forward_PseudoSection.rst b/docs/examples/DC_Forward_PseudoSection.rst index 80cf0307..29855d4a 100644 --- a/docs/examples/DC_Forward_PseudoSection.rst +++ b/docs/examples/DC_Forward_PseudoSection.rst @@ -22,7 +22,7 @@ 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 +Created by @fourndo From fb5434695f13388790df41b6f4b293a5425d053d Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 10 May 2016 14:31:45 -0700 Subject: [PATCH 133/168] Alpha_s default to 1.0 --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 7f50ea59..8fdb9fd5 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -409,7 +409,7 @@ class Simple(BaseRegularization): """ mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Wsmall'], "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") From eaa37f42e47b3e1d01ed10fd50d9b7cd8d29796f Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 14:51:56 -0700 Subject: [PATCH 134/168] remove duplicate evalSmall --- SimPEG/Regularization.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 8fdb9fd5..1276cbb6 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -469,10 +469,6 @@ class Simple(BaseRegularization): 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) @property def W(self): From 3f0c89f10b3783e63b14ccb530b565613d0cbff0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 14:53:43 -0700 Subject: [PATCH 135/168] remove extra Ws --- SimPEG/Regularization.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 1276cbb6..361a3206 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -470,27 +470,6 @@ class Simple(BaseRegularization): return self._W - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W - - @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 self._Wsmooth - - @Utils.timeIt def _evalSmall(self, m): r = self.Wsmall * ( self.mapping * (m - self.mref) ) From 2a802c1aa3ae90b120cb828194c36dfd2d57ccbf Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 16:39:47 -0700 Subject: [PATCH 136/168] weights --> cell_weights, removed vol term from simple regularization --- SimPEG/Regularization.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 361a3206..5d40adf8 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -413,40 +413,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. + cell_weights = 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 + if isinstance(self.cell_weights,float): + self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights @property 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) + self._Wsmall = Utils.sdiag((self.alpha_s*self.cell_weights)**0.5) return self._Wsmall @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*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil + self._Wx = Utils.sdiag((self.alpha_x * (self.regmesh.aveCC2Fx*self.cell_weights))**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*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil + self._Wy = Utils.sdiag((self.alpha_y * (self.regmesh.aveCC2Fy*self.cell_weights))**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*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil + self._Wz = Utils.sdiag((self.alpha_z * (self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.regmesh.cellDiffzStencil return self._Wz @property @@ -779,13 +779,13 @@ class Sparse(Simple): curModel = None # use a model to compute the weights gamma = 1. norms = [0., 2., 2., 2.] - wght = 1. + cell_weights = 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 + if isinstance(self.cell_weights,float): + self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights @property def Wsmall(self): @@ -799,7 +799,7 @@ class Sparse(Simple): #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 + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs @property @@ -814,7 +814,7 @@ class Sparse(Simple): 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 + return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.Rx*self.regmesh.cellDiffxStencil @property def Wy(self): @@ -828,7 +828,7 @@ class Sparse(Simple): 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 + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property def Wz(self): @@ -842,7 +842,7 @@ class Sparse(Simple): 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 + return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil def R(self, f_m , eps, exponent): From 955bd54019b9e6fccf8f766ce83d4fdde9ac61f0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 16:46:11 -0700 Subject: [PATCH 137/168] notation cleanup in Regularization --- SimPEG/Regularization.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 5d40adf8..16bb4b9f 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,4 +1,6 @@ -import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp +import Utils, Maps, Mesh +import numpy as np +import scipy.sparse as sp class RegularizationMesh(object): """ @@ -476,7 +478,7 @@ class Simple(BaseRegularization): return 0.5 * r.dot(r) @Utils.timeIt - def _evalSmallDeriv(self,m): + def _evalSmallDeriv(self, m): r = self.Wsmall * ( self.mapping * (m - self.mref) ) return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) @@ -514,7 +516,7 @@ class Simple(BaseRegularization): return phiSmooth @Utils.timeIt - def _evalSmoothxDeriv(self,m): + def _evalSmoothxDeriv(self, m): if self.mrefInSmooth == True: r = self.Wx * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wx * self.mapping.deriv(m - self.mref) ) @@ -523,7 +525,7 @@ class Simple(BaseRegularization): return r.T * ( self.Wx * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmoothyDeriv(self,m): + def _evalSmoothyDeriv(self, m): if self.mrefInSmooth == True: r = self.Wy * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wy * self.mapping.deriv(m - self.mref) ) @@ -532,7 +534,7 @@ class Simple(BaseRegularization): return r.T * ( self.Wy * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmoothzDeriv(self,m): + def _evalSmoothzDeriv(self, m): if self.mrefInSmooth == True: r = self.Wz * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wz * self.mapping.deriv(m - self.mref) ) @@ -541,7 +543,7 @@ class Simple(BaseRegularization): return r.T * ( self.Wz * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmoothDeriv(self,m): + def _evalSmoothDeriv(self, m): deriv = self._evalSmoothxDeriv(m) if self.regmesh.dim > 1: deriv += self._evalSmoothyDeriv(m) @@ -711,7 +713,7 @@ class Tikhonov(Simple): return phiSmooth2 @Utils.timeIt - def _evalSmoothxxDeriv(self,m): + def _evalSmoothxxDeriv(self, m): if self.mrefInSmooth == True: r = self.Wxx * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wxx * self.mapping.deriv(m - self.mref) ) @@ -720,7 +722,7 @@ class Tikhonov(Simple): return r.T * ( self.Wxx * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmoothyyDeriv(self,m): + def _evalSmoothyyDeriv(self, m): if self.mrefInSmooth == True: r = self.Wyy * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wyy * self.mapping.deriv(m - self.mref) ) @@ -729,7 +731,7 @@ class Tikhonov(Simple): return r.T * ( self.Wyy * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmoothzzDeriv(self,m): + def _evalSmoothzzDeriv(self, m): if self.mrefInSmooth == True: r = self.Wzz * ( self.mapping * ( m - self.mref ) ) return r.T * ( self.Wzz * self.mapping.deriv(m - self.mref) ) @@ -738,7 +740,7 @@ class Tikhonov(Simple): return r.T * ( self.Wzz * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmooth2Deriv(self,m): + def _evalSmooth2Deriv(self, m): deriv = self._evalSmoothxxDeriv(m) if self.regmesh.dim > 1: deriv += self._evalSmoothyyDeriv(m) @@ -774,12 +776,12 @@ class Tikhonov(Simple): class Sparse(Simple): # set default values - eps_p = 1e-1 - eps_q = 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.] - cell_weights = 1. + gamma = 1. + norms = [0., 2., 2., 2.] + cell_weights = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) From 7964ebce50f86b87f11873cfb0e40632f4eb930f Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 10 May 2016 17:20:46 -0700 Subject: [PATCH 138/168] Update directive to None the Wsmooth after iteration. --- SimPEG/Directives.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 4fc1ffc5..008cc57b 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -303,26 +303,27 @@ class Update_IRLS(InversionDirective): # Set the weighting matrix to None so that it is recomputed next time # it is called in the inversion self.reg._W = None + self.reg._Wsmooth = None class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem """ onlyOnStart=False - + def initialize(self): - + if getattr(self.opt, 'approxHinv', None) is 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((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC - + def endIter(self): # Cool the threshold parameter if self.onlyOnStart==True: return - + 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. From 11e6b452c96cf419e0f36224975c7c8fdbba8a8b Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 17:26:16 -0700 Subject: [PATCH 139/168] renamed FDEM.py to ProblemFDEM.py, changed real_or_imag to component --- SimPEG/EM/FDEM/{FDEM.py => ProblemFDEM.py} | 4 +-- SimPEG/EM/FDEM/RxFDEM.py | 40 +++++++++++----------- SimPEG/EM/FDEM/__init__.py | 2 +- SimPEG/Examples/EM_FDEM_1D_Inversion.py | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) rename SimPEG/EM/FDEM/{FDEM.py => ProblemFDEM.py} (99%) diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/ProblemFDEM.py similarity index 99% rename from SimPEG/EM/FDEM/FDEM.py rename to SimPEG/EM/FDEM/ProblemFDEM.py index 026230c6..75b05bf9 100644 --- a/SimPEG/EM/FDEM/FDEM.py +++ b/SimPEG/EM/FDEM/ProblemFDEM.py @@ -137,9 +137,9 @@ class BaseFDEMProblem(BaseEMProblem): df_dmT = df_dmT + du_dmT # TODO: this should be taken care of by the reciever? - if rx.real_or_imag is 'real': + if rx.component is 'real': Jtv += np.array(df_dmT, dtype=complex).real - elif rx.real_or_imag is 'imag': + elif rx.component is 'imag': Jtv += - np.array(df_dmT, dtype=complex).real else: raise Exception('Must be real or imag') diff --git a/SimPEG/EM/FDEM/RxFDEM.py b/SimPEG/EM/FDEM/RxFDEM.py index ef58d807..f15040fb 100644 --- a/SimPEG/EM/FDEM/RxFDEM.py +++ b/SimPEG/EM/FDEM/RxFDEM.py @@ -7,15 +7,15 @@ class BaseRx(SimPEG.Survey.BaseRx): :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) :param string orientation: receiver orientation 'x', 'y' or 'z' - :param string real_or_imag: real or imaginary component 'real' or 'imag' + :param string component: real or imaginary component 'real' or 'imag' """ - def __init__(self, locs, orientation=None, real_or_imag=None): + def __init__(self, locs, orientation=None, component=None): assert(orientation in ['x','y','z']), "Orientation %s not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented."%orientation - assert(real_or_imag in ['real', 'imag']), "'real_or_imag' must be 'real' or 'imag', not %s"%real_or_imag + assert(component in ['real', 'imag']), "'component' must be 'real' or 'imag', not %s"%component self.projComp = orientation - self.real_or_imag = real_or_imag + self.component = component SimPEG.Survey.BaseRx.__init__(self, locs, rxType=None) #TODO: remove rxType from baseRx @@ -36,7 +36,7 @@ class BaseRx(SimPEG.Survey.BaseRx): P = self.getP(mesh, self.projGLoc(f)) f_part_complex = f[src, self.projField] - f_part = getattr(f_part_complex, self.real_or_imag) # get the real or imag component + f_part = getattr(f_part_complex, self.component) # get the real or imag component return P*f_part @@ -56,13 +56,13 @@ class BaseRx(SimPEG.Survey.BaseRx): if not adjoint: Pv_complex = P * v - Pv = getattr(Pv_complex, self.real_or_imag) + Pv = getattr(Pv_complex, self.component) elif adjoint: Pv_real = P.T * v - if self.real_or_imag == 'imag': + if self.component == 'imag': Pv = 1j*Pv_real - elif self.real_or_imag == 'real': + elif self.component == 'real': Pv = Pv_real.astype(complex) else: raise NotImplementedError('must be real or imag') @@ -76,12 +76,12 @@ class eField(BaseRx): :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) :param string orientation: receiver orientation 'x', 'y' or 'z' - :param string real_or_imag: real or imaginary component 'real' or 'imag' + :param string component: real or imaginary component 'real' or 'imag' """ - def __init__(self, locs, orientation=None, real_or_imag=None): + def __init__(self, locs, orientation=None, component=None): self.projField = 'e' - BaseRx.__init__(self, locs, orientation, real_or_imag) + BaseRx.__init__(self, locs, orientation, component) class bField(BaseRx): @@ -90,12 +90,12 @@ class bField(BaseRx): :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) :param string orientation: receiver orientation 'x', 'y' or 'z' - :param string real_or_imag: real or imaginary component 'real' or 'imag' + :param string component: real or imaginary component 'real' or 'imag' """ - def __init__(self, locs, orientation=None, real_or_imag=None): + def __init__(self, locs, orientation=None, component=None): self.projField = 'b' - BaseRx.__init__(self, locs, orientation, real_or_imag) + BaseRx.__init__(self, locs, orientation, component) class hField(BaseRx): @@ -104,12 +104,12 @@ class hField(BaseRx): :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) :param string orientation: receiver orientation 'x', 'y' or 'z' - :param string real_or_imag: real or imaginary component 'real' or 'imag' + :param string component: real or imaginary component 'real' or 'imag' """ - def __init__(self, locs, orientation=None, real_or_imag=None): + def __init__(self, locs, orientation=None, component=None): self.projField = 'h' - BaseRx.__init__(self, locs, orientation, real_or_imag) + BaseRx.__init__(self, locs, orientation, component) class jField(BaseRx): @@ -118,9 +118,9 @@ class jField(BaseRx): :param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`) :param string orientation: receiver orientation 'x', 'y' or 'z' - :param string real_or_imag: real or imaginary component 'real' or 'imag' + :param string component: real or imaginary component 'real' or 'imag' """ - def __init__(self, locs, orientation=None, real_or_imag=None): + def __init__(self, locs, orientation=None, component=None): self.projField = 'j' - BaseRx.__init__(self, locs, orientation, real_or_imag) + BaseRx.__init__(self, locs, orientation, component) diff --git a/SimPEG/EM/FDEM/__init__.py b/SimPEG/EM/FDEM/__init__.py index 1701fe3e..c4ff6451 100644 --- a/SimPEG/EM/FDEM/__init__.py +++ b/SimPEG/EM/FDEM/__init__.py @@ -1,5 +1,5 @@ from SurveyFDEM import Survey import SrcFDEM as Src import RxFDEM as Rx -from FDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h +from ProblemFDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index 0a5c59a0..95e3f09f 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -43,7 +43,7 @@ def run(plotIt=True): rxOffset=10. - bzi = EM.FDEM.Rx.bField(np.array([[rxOffset, 0., 1e-3]]), orientation='z', real_or_imag='imag') + bzi = EM.FDEM.Rx.bField(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag') freqs = np.logspace(1,3,10) srcLoc = np.array([0., 0., 10.]) From c1b1c2467f737aa6462070826b4ee5277f343dc4 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 19:57:16 -0700 Subject: [PATCH 140/168] import from ProblemFDEM in baseMT, fixed a missed real_or_imag --> component --- SimPEG/MT/BaseMT.py | 2 +- tests/em/fdem/forward/test_FDEM_analytics.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/MT/BaseMT.py b/SimPEG/MT/BaseMT.py index c201dfb0..579f590f 100644 --- a/SimPEG/MT/BaseMT.py +++ b/SimPEG/MT/BaseMT.py @@ -1,5 +1,5 @@ from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np -from SimPEG.EM.FDEM.FDEM import BaseFDEMProblem +from SimPEG.EM.FDEM.ProblemFDEM import BaseFDEMProblem from SurveyMT import Survey, Data from FieldsMT import BaseMTFields diff --git a/tests/em/fdem/forward/test_FDEM_analytics.py b/tests/em/fdem/forward/test_FDEM_analytics.py index 0ea43ca7..b9de4a26 100644 --- a/tests/em/fdem/forward/test_FDEM_analytics.py +++ b/tests/em/fdem/forward/test_FDEM_analytics.py @@ -28,7 +28,7 @@ class FDEM_analyticTests(unittest.TestCase): x = np.linspace(-10,10,5) XYZ = Utils.ndgrid(x,np.r_[0],np.r_[0]) - rxList = EM.FDEM.Rx.eField(XYZ, orientation='x', real_or_imag='imag') + rxList = EM.FDEM.Rx.eField(XYZ, orientation='x', component='imag') Src0 = EM.FDEM.Src.MagDipole([rxList],loc=np.r_[0.,0.,0.], freq=freq) survey = EM.FDEM.Survey([Src0]) From 90a3030796234798c3755745810415f52ef5a77e Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 21:39:15 -0700 Subject: [PATCH 141/168] fixed 2 deriv --- SimPEG/Examples/Inversion_IRLS.py | 4 +- SimPEG/Regularization.py | 123 ++++++++++++++++++++++++++++-- 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 06ef4be4..c925cce2 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -84,12 +84,12 @@ def run(N=200, plotIt=True): #============================================================================== #reg.recModel = mrec - reg.wght = np.ones(mesh.nC) + # reg.cell_weight = np.ones(mesh.nC) reg.mref = np.zeros(mesh.nC) reg.eps_p = 5e-2 reg.eps_q = 1e-2 reg.norms = [0., 0., 2., 2.] - reg.wght = wr + reg.cell_weight = wr opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 16bb4b9f..5947ed03 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -410,11 +410,11 @@ class Simple(BaseRegularization): Simple regularization that does not include length scales in the derivatives. """ - mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = False #: include mref in the smoothness? 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") + 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") cell_weights = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): @@ -454,6 +454,8 @@ class Simple(BaseRegularization): @property def Wsmooth(self): """Full smoothness regularization matrix W""" + print 'wtf why are we using Wsmooth' + raise NotImplementedError if getattr(self, '_Wsmooth', None) is None: wlist = (self.Wx,) if self.regmesh.dim > 1: @@ -482,6 +484,13 @@ class Simple(BaseRegularization): r = self.Wsmall * ( self.mapping * (m - self.mref) ) return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) + @Utils.timeIt + def _evalSmall2Deriv(self, m, v = None): + rDeriv = self.Wsmall * ( self.mapping.deriv(m - self.mref) ) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + @Utils.timeIt def _evalSmoothx(self, m): if self.mrefInSmooth == True: @@ -524,6 +533,17 @@ class Simple(BaseRegularization): r = self.Wx * ( self.mapping * m ) return r.T * ( self.Wx * self.mapping.deriv(m) ) + @Utils.timeIt + def _evalSmoothx2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wx * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wx * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + @Utils.timeIt def _evalSmoothyDeriv(self, m): if self.mrefInSmooth == True: @@ -533,6 +553,17 @@ class Simple(BaseRegularization): r = self.Wy * ( self.mapping * m ) return r.T * ( self.Wy * self.mapping.deriv(m) ) + @Utils.timeIt + def _evalSmoothy2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wy * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wy * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + @Utils.timeIt def _evalSmoothzDeriv(self, m): if self.mrefInSmooth == True: @@ -542,6 +573,17 @@ class Simple(BaseRegularization): r = self.Wz * ( self.mapping * m ) return r.T * ( self.Wz * self.mapping.deriv(m) ) + @Utils.timeIt + def _evalSmoothz2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wz * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wz * ( self.mapping.deriv(m) ) + + if v is not None: + return rDeriv.T * ( rDeriv * v ) + return rDeriv.T * rDeriv + @Utils.timeIt def _evalSmoothDeriv(self, m): deriv = self._evalSmoothxDeriv(m) @@ -551,6 +593,15 @@ class Simple(BaseRegularization): deriv += self._evalSmoothzDeriv(m) return deriv + @Utils.timeIt + def _evalSmooth2Deriv(self, m, v=None): + deriv = self._evalSmoothx2Deriv(m, v) + if self.regmesh.dim > 1: + deriv += self._evalSmoothy2Deriv(m, v) + if self.regmesh.dim > 2: + deriv += self._evalSmoothz2Deriv(m, v) + return deriv + @Utils.timeIt def eval(self, m): @@ -574,6 +625,10 @@ class Simple(BaseRegularization): """ return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + @Utils.timeIt + def eval2Deriv(self, m, v=None): + return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + class Tikhonov(Simple): @@ -740,7 +795,37 @@ class Tikhonov(Simple): return r.T * ( self.Wzz * self.mapping.deriv(m) ) @Utils.timeIt - def _evalSmooth2Deriv(self, m): + def _evalSmoothxx2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wxx * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wxx * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothyy2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wyy * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wyy * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothzz2Deriv(self, m, v=None): + if self.mrefInSmooth == True: + rDeriv = self.Wzz * ( self.mapping.deriv( m - self.mref ) ) + elif self.mrefInSmooth == False: + rDeriv = self.Wzz * self.mapping.deriv(m) + if v is not None: + return rDeriv.T * (rDeriv * v) + return rDeriv.T * rDeriv + + @Utils.timeIt + def _evalSmoothDeriv2(self, m): deriv = self._evalSmoothxxDeriv(m) if self.regmesh.dim > 1: deriv += self._evalSmoothyyDeriv(m) @@ -748,6 +833,15 @@ class Tikhonov(Simple): deriv += self._evalSmoothzzDeriv(m) return deriv + @Utils.timeIt + def _evalSmooth2Deriv2(self, m, v=None): + deriv = self._evalSmoothxx2Deriv(m, v) + if self.regmesh.dim > 1: + deriv += self._evalSmoothyy2Deriv(m, v) + if self.regmesh.dim > 2: + deriv += self._evalSmoothzz2Deriv(m, v) + return deriv + @Utils.timeIt def eval(self, m): @@ -769,7 +863,24 @@ class Tikhonov(Simple): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmooth2Deriv(m) + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmoothDeriv2(m) + + def eval2Deriv(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})} + + """ + return self._evalSmall2Deriv(m) + self._evalSmooth2Deriv(m) + self._evalSmooth2Deriv2(m) From 3dd9ecc9cd7f95b596d9027595013f9ca4647035 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 10 May 2016 22:10:19 -0700 Subject: [PATCH 142/168] fix tikhonov 2Deriv --- SimPEG/Regularization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 5947ed03..8f1b2d2c 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -865,7 +865,7 @@ class Tikhonov(Simple): """ return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmoothDeriv2(m) - def eval2Deriv(self, m): + def eval2Deriv(self, m, v=None): """ The regularization is: @@ -880,7 +880,7 @@ class Tikhonov(Simple): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - return self._evalSmall2Deriv(m) + self._evalSmooth2Deriv(m) + self._evalSmooth2Deriv2(m) + return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + self._evalSmooth2Deriv2(m, v) From e10d6878fb86b129953e68c3749307321a7d8eea Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 11 May 2016 07:58:06 -0700 Subject: [PATCH 143/168] Remove Wsmooth from def W and replace by parts --- SimPEG/Regularization.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 8f1b2d2c..3263ba9a 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -469,7 +469,11 @@ class Simple(BaseRegularization): def W(self): """Full regularization matrix W""" if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) + wlist = (self.Wsmall, self.Wx) + if self.regmesh.dim > 1: + wlist += (self.Wy,) + if self.regmesh.dim > 2: + wlist += (self.Wz,) self._W = sp.vstack(wlist) return self._W From a690cab13132681f7b9972f3c72547883af5c422 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 11 May 2016 09:05:13 -0700 Subject: [PATCH 144/168] simple field receivers are `Point` receivers --- SimPEG/EM/FDEM/RxFDEM.py | 16 ++++++++-------- SimPEG/EM/Utils/testingUtils.py | 2 +- SimPEG/Examples/EM_FDEM_1D_Inversion.py | 2 +- tests/em/fdem/forward/test_FDEM_analytics.py | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/SimPEG/EM/FDEM/RxFDEM.py b/SimPEG/EM/FDEM/RxFDEM.py index f15040fb..53d6c722 100644 --- a/SimPEG/EM/FDEM/RxFDEM.py +++ b/SimPEG/EM/FDEM/RxFDEM.py @@ -70,7 +70,7 @@ class BaseRx(SimPEG.Survey.BaseRx): return Pv -class eField(BaseRx): +class Point_e(BaseRx): """ Electric field FDEM receiver @@ -81,10 +81,10 @@ class eField(BaseRx): def __init__(self, locs, orientation=None, component=None): self.projField = 'e' - BaseRx.__init__(self, locs, orientation, component) + super(Point_e, self).__init__(locs, orientation, component) -class bField(BaseRx): +class Point_b(BaseRx): """ Magnetic flux FDEM receiver @@ -95,10 +95,10 @@ class bField(BaseRx): def __init__(self, locs, orientation=None, component=None): self.projField = 'b' - BaseRx.__init__(self, locs, orientation, component) + super(Point_b, self).__init__(locs, orientation, component) -class hField(BaseRx): +class Point_h(BaseRx): """ Magnetic field FDEM receiver @@ -109,10 +109,10 @@ class hField(BaseRx): def __init__(self, locs, orientation=None, component=None): self.projField = 'h' - BaseRx.__init__(self, locs, orientation, component) + super(Point_h, self).__init__(locs, orientation, component) -class jField(BaseRx): +class Point_j(BaseRx): """ Current density FDEM receiver @@ -123,4 +123,4 @@ class jField(BaseRx): def __init__(self, locs, orientation=None, component=None): self.projField = 'j' - BaseRx.__init__(self, locs, orientation, component) + super(Point_j, self).__init__(locs, orientation, component) diff --git a/SimPEG/EM/Utils/testingUtils.py b/SimPEG/EM/Utils/testingUtils.py index c3fc50d2..22c925b6 100644 --- a/SimPEG/EM/Utils/testingUtils.py +++ b/SimPEG/EM/Utils/testingUtils.py @@ -26,7 +26,7 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False): x = np.array([np.linspace(-5.*cs,-2.*cs,3),np.linspace(5.*cs,2.*cs,3)]) + cs/4. #don't sample right by the source, slightly off alignment from either staggered grid XYZ = Utils.ndgrid(x,x,np.linspace(-2.*cs,2.*cs,5)) - Rx0 = getattr(EM.FDEM.Rx, comp[0] + 'Field') + Rx0 = getattr(EM.FDEM.Rx, 'Point_' + comp[0]) if comp[2] == 'r': real_or_imag = 'real' elif comp[2] == 'i': diff --git a/SimPEG/Examples/EM_FDEM_1D_Inversion.py b/SimPEG/Examples/EM_FDEM_1D_Inversion.py index 95e3f09f..4275903d 100644 --- a/SimPEG/Examples/EM_FDEM_1D_Inversion.py +++ b/SimPEG/Examples/EM_FDEM_1D_Inversion.py @@ -43,7 +43,7 @@ def run(plotIt=True): rxOffset=10. - bzi = EM.FDEM.Rx.bField(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag') + bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag') freqs = np.logspace(1,3,10) srcLoc = np.array([0., 0., 10.]) diff --git a/tests/em/fdem/forward/test_FDEM_analytics.py b/tests/em/fdem/forward/test_FDEM_analytics.py index b9de4a26..6f283666 100644 --- a/tests/em/fdem/forward/test_FDEM_analytics.py +++ b/tests/em/fdem/forward/test_FDEM_analytics.py @@ -28,7 +28,7 @@ class FDEM_analyticTests(unittest.TestCase): x = np.linspace(-10,10,5) XYZ = Utils.ndgrid(x,np.r_[0],np.r_[0]) - rxList = EM.FDEM.Rx.eField(XYZ, orientation='x', component='imag') + rxList = EM.FDEM.Rx.Point_e(XYZ, orientation='x', component='imag') Src0 = EM.FDEM.Src.MagDipole([rxList],loc=np.r_[0.,0.,0.], freq=freq) survey = EM.FDEM.Survey([Src0]) From 029171fb1d7652207f7ba10423d0f3a8ceef89d1 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 11 May 2016 09:09:26 -0700 Subject: [PATCH 145/168] use .format for strings --- SimPEG/EM/FDEM/ProblemFDEM.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/EM/FDEM/ProblemFDEM.py b/SimPEG/EM/FDEM/ProblemFDEM.py index 75b05bf9..2aed1d91 100644 --- a/SimPEG/EM/FDEM/ProblemFDEM.py +++ b/SimPEG/EM/FDEM/ProblemFDEM.py @@ -87,7 +87,7 @@ class BaseFDEMProblem(BaseEMProblem): du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v ) for rx in src.rxList: - df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dmFun = getattr(f, '_{0}Deriv'.format(rx.projField), None) df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) Ainv.clean() @@ -125,7 +125,7 @@ class BaseFDEMProblem(BaseEMProblem): for rx in src.rxList: PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m - df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duTFun = getattr(f, '_{0}Deriv'.format(rx.projField), None) df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) ATinvdf_duT = ATinv * df_duT From cd2360b8153a9b4f343cfdb81d084e5f36c49132 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 11 May 2016 23:04:14 -0700 Subject: [PATCH 146/168] Stash the regularization between each beta --- SimPEG/Directives.py | 24 ++++++++++++-- SimPEG/Regularization.py | 67 ++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 008cc57b..a9b74276 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -271,6 +271,14 @@ class Update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma + print "Initial gamma ", np.linalg.norm(self.reg.gamma) + # Reset the regularization matrices so that it is + # recalculated with new gamma + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None + self.reg._W = None if getattr(self, 'phi_d_last', None) is None: self.phi_d_last = self.invProb.phi_d @@ -294,16 +302,26 @@ class Update_IRLS(InversionDirective): # Temporarely set gamma to 1. to get raw phi_m self.reg.gamma = 1. + # Reset the regularization matrices so that it is + # recalculated for current model + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None + self.reg._W = None + # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - # Set the weighting matrix to None so that it is recomputed next time - # it is called in the inversion + # Reset the regularization matrices again for new gamma + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None self.reg._W = None - self.reg._Wsmooth = None class Update_lin_PreCond(InversionDirective): """ diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 3263ba9a..5dc5aba0 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -468,6 +468,7 @@ class Simple(BaseRegularization): @property def W(self): """Full regularization matrix W""" + print 'wtf why are we using W' if getattr(self, '_W', None) is None: wlist = (self.Wsmall, self.Wx) if self.regmesh.dim > 1: @@ -907,60 +908,66 @@ class Sparse(Simple): @property def Wsmall(self): """Regularization matrix Wsmall""" - if getattr(self, 'curModel', None) is None: - self.Rs = Utils.speye(self.regmesh.nC) + if getattr(self,'_Wsmall', None) is None: + if getattr(self, 'curModel', None) is None: + self.Rs = Utils.speye(self.regmesh.nC) - else: - f_m = self.mapping * (self.curModel - self.reg.mref) - 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 ) + else: + f_m = self.mapping * (self.curModel - self.reg.mref) + self.rs = self.R(f_m , self.eps_p, self.norms[0]) + self.Rs = Utils.sdiag( self.rs ) - return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs + self._Wsmall = Utils.sdiag((self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs + return self._Wsmall @property def Wx(self): """Regularization matrix Wx""" + if getattr(self,'_Wx', None) is None: + if getattr(self, 'curModel', None) is None: + self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) - if getattr(self, 'curModel', None) is None: - self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) + else: + f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel) + self.rx = self.R( f_m , self.eps_q, self.norms[1]) + self.Rx = Utils.sdiag( self.rx ) - else: - f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel) - self.rx = self.R( f_m , self.eps_q, self.norms[1]) - self.Rx = Utils.sdiag( self.rx ) + self._Wx = Utils.sdiag(( self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.cell_weights))**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.cell_weights))**0.5)*self.Rx*self.regmesh.cellDiffxStencil + return self._Wx @property def Wy(self): """Regularization matrix Wy""" + if getattr(self,'_Wy', None) is None: + if getattr(self, 'curModel', None) is None: + self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) - if getattr(self, 'curModel', None) is None: - self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) + else: + f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel) + self.ry = self.R( f_m , self.eps_q, self.norms[2]) + self.Ry = Utils.sdiag( self.ry ) - else: - f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel) - self.ry = self.R( f_m , self.eps_q, self.norms[2]) - self.Ry = Utils.sdiag( self.ry ) + self._Wy = Utils.sdiag((self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.cell_weights))**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.cell_weights))**0.5)*self.Ry*self.regmesh.cellDiffyStencil + return self._Wy @property def Wz(self): """Regularization matrix Wz""" + if getattr(self,'_Wz', None) is None: + if getattr(self, 'curModel', None) is None: + self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) - if getattr(self, 'curModel', None) is None: - self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) + else: + f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel) + self.rz = self.R( f_m , self.eps_q, self.norms[3]) + self.Rz = Utils.sdiag( self.rz ) - else: - f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel) - 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.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil + self._Wz = Utils.sdiag((self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil + return self._Wz def R(self, f_m , eps, exponent): From 3cc46131a3138096441fb4c423c5f4f21543d2b4 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 12 May 2016 08:31:01 -0700 Subject: [PATCH 147/168] Temporary change ... comment out W and Wsmooth --- SimPEG/Directives.py | 6 ++--- SimPEG/Regularization.py | 52 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index a9b74276..6b15be9f 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -278,7 +278,6 @@ class Update_IRLS(InversionDirective): self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - self.reg._W = None if getattr(self, 'phi_d_last', None) is None: self.phi_d_last = self.invProb.phi_d @@ -308,20 +307,19 @@ class Update_IRLS(InversionDirective): self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - self.reg._W = None # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - + print "New gamma ", np.linalg.norm(self.reg.gamma) + # Reset the regularization matrices again for new gamma self.reg._Wsmall = None self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - self.reg._W = None class Update_lin_PreCond(InversionDirective): """ diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 5dc5aba0..422c8f9c 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -451,32 +451,32 @@ class Simple(BaseRegularization): self._Wz = Utils.sdiag((self.alpha_z * (self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.regmesh.cellDiffzStencil return self._Wz - @property - def Wsmooth(self): - """Full smoothness regularization matrix W""" - print 'wtf why are we using Wsmooth' - raise NotImplementedError - 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 self._Wsmooth - - @property - def W(self): - """Full regularization matrix W""" - print 'wtf why are we using W' - if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wx) - if self.regmesh.dim > 1: - wlist += (self.Wy,) - if self.regmesh.dim > 2: - wlist += (self.Wz,) - self._W = sp.vstack(wlist) - return self._W +# @property +# def Wsmooth(self): +# """Full smoothness regularization matrix W""" +# print 'wtf why are we using Wsmooth' +# raise NotImplementedError +# 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 self._Wsmooth +# +# @property +# def W(self): +# """Full regularization matrix W""" +# print 'wtf why are we using W' +# if getattr(self, '_W', None) is None: +# wlist = (self.Wsmall, self.Wx) +# if self.regmesh.dim > 1: +# wlist += (self.Wy,) +# if self.regmesh.dim > 2: +# wlist += (self.Wz,) +# self._W = sp.vstack(wlist) +# return self._W @Utils.timeIt From fd3bde787f3a9bc570ad8386e36eb16a7d3da1d3 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 12 May 2016 14:58:16 -0700 Subject: [PATCH 148/168] Propose change to the Projected_GNCG solver. Add inner GN iterations. Nice improvement to the convergence of IRLS --- SimPEG/Directives.py | 49 ++++++++++++++++++---- SimPEG/Examples/Inversion_IRLS.py | 20 ++++----- SimPEG/Optimization.py | 70 +++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 21 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 6b15be9f..f5c25249 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -144,6 +144,35 @@ class BetaSchedule(InversionDirective): if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter self.invProb.beta /= self.coolingFactor +#class BetaSchedule_PGN_CG(InversionDirective): +# """BetaSchedule""" +# +# coolingFactor = 5. +# coolingRate = 1 +# GN_step_last = None +# GN_step_c = None +# +# def endIter(self): +# +# """ Compute the change in GN step, and proceed with cooling if below tol""" +# if self.opt.iter == 1: +# self.GN_step_last = np.linalg.norm(self.opt.xc - self.opt.x_last) +# d_GN_step = 1. +# +# else: +# self.GN_step_c = np.linalg.norm(self.opt.xc - self.opt.x_last) +# d_GN_step = self.GN_step_c / self.GN_step_last +# +# # Re-initiate last GN step +# self.GN_step_last = self.GN_step_c +# +# print "GN_step_last: ", self.GN_step_last +# print "d_GN_step: ", d_GN_step +# +# if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: +# if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter +# self.invProb.beta /= self.coolingFactor + class TargetMisfit(InversionDirective): @property @@ -265,13 +294,16 @@ class Update_IRLS(InversionDirective): if getattr(self, 'phi_m_last', None) is not None: self.reg.curModel = self.invProb.curModel + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None self.reg.gamma = 1. 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 - print "Initial gamma ", np.linalg.norm(self.reg.gamma) # Reset the regularization matrices so that it is # recalculated with new gamma self.reg._Wsmall = None @@ -295,12 +327,6 @@ 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. to get raw phi_m - self.reg.gamma = 1. - # Reset the regularization matrices so that it is # recalculated for current model self.reg._Wsmall = None @@ -308,13 +334,18 @@ class Update_IRLS(InversionDirective): self.reg._Wy = None self.reg._Wz = None + # Update the model used for the IRLS weights + self.reg.curModel = self.invProb.curModel + + # Temporarely set gamma to 1. to get raw phi_m + self.reg.gamma = 1. + # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - print "New gamma ", np.linalg.norm(self.reg.gamma) - + # Reset the regularization matrices again for new gamma self.reg._Wsmall = None self.reg._Wx = None diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index c925cce2..6551bf21 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -18,6 +18,8 @@ def run(N=200, plotIt=True): mesh = Mesh.TensorMesh([N]) m0 = np.ones(mesh.nC) * 1e-4 + mref = np.zeros(mesh.nC) + nk = 10 jk = np.linspace(1.,nk,nk) p = -2. @@ -51,12 +53,13 @@ def run(N=200, plotIt=True): wr = ( wr/np.max(wr) ) reg = Regularization.Simple(mesh) - reg.wght = wr + reg.mref = mref + reg.cell_weights = wr dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1./wd - opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, tolCG = 1e-4) + opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, maxIterGN=1, tolCG = 1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) invProb.curModel = m0 @@ -76,22 +79,15 @@ def run(N=200, plotIt=True): phid = invProb.phi_d reg = Regularization.Sparse(mesh) + reg.mref = mref + reg.cell_weights = wr -#============================================================================== -# 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.cell_weight = np.ones(mesh.nC) reg.mref = np.zeros(mesh.nC) reg.eps_p = 5e-2 reg.eps_q = 1e-2 reg.norms = [0., 0., 2., 2.] - reg.cell_weight = wr - opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 77704733..95f53320 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -893,6 +893,10 @@ class ProjectedGNCG(BFGS, Minimize, Remember): lower = -np.inf upper = np.inf + # Variables to control inner GN iterations + rdm_tol = 1e-2 # Tolerance for largest change in step (Default 1%) + maxIterGN = 3 # Maximum number of GN inner iterations + def _startup(self, x0): # ensure bound vectors are the same size as the model if type(self.lower) is not np.ndarray: @@ -938,6 +942,72 @@ class ProjectedGNCG(BFGS, Minimize, Remember): def approxHinv(self, value): self._approxHinv = value + @Utils.timeIt + def minimize(self, evalFunction, x0): + """minimize(evalFunction, x0) + + Minimizes the function (evalFunction) starting at the location x0. + + :param def evalFunction: function handle that evaluates: f, g, H = F(x) + :param numpy.ndarray x0: starting location + :rtype: numpy.ndarray + :return: x, the last iterate of the optimization algorithm + + The GN newton steps are repeated until it the maxIterGN is reached or the + relative step change falls below some tolrerance. + + """ + self.evalFunction = evalFunction + self.startup(x0) + self.printInit() + + + while True: + self.doStartIteration() + self.f, self.g, self.H = evalFunction(self.xc, return_g=True, return_H=True) + self.printIter() + if self.stoppingCriteria(): break + + # Inner GN iterations, stop on maximum number of iterations + # or on tolerance for step length change + GN_count = 0 + dm0 = None # Initial GN step length + dmc = None # Current GN step length + rdm = 1. # Relative change in step length + + while rdm > self.rdm_tol and GN_count < self.maxIterGN: + + GN_count += 1 + self.searchDirection = self.findSearchDirection() + p = self.scaleSearchDirection(self.searchDirection) + xt, passLS = self.modifySearchDirection(p) + if not passLS: + xt, caught = self.modifySearchDirectionBreak(p) + if not caught: return self.xc + + if GN_count == 1: + dm0 = np.linalg.norm(self.xc - xt) + dmc = dm0 + + else: + dmc = np.linalg.norm(self.xc - xt) + + rdm = dmc / dm0 + self.xc = xt # Update current model + + # Form system for next iteration + self.f, self.g, self.H = evalFunction(self.xc, return_g=True, return_H=True) + + print "GN iter: %i,\t dm: %8.5e,\t rdm: %8.5e"% (GN_count, dmc, rdm) + + self.doEndIteration(xt) + if self.stopNextIteration: break + + self.printDone() + self.finish() + + return self.xc + @Utils.timeIt def findSearchDirection(self): From c88263234bd0d5cac71d6ddb4bf9a8d50dbcbd45 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 17 May 2016 23:56:06 -0700 Subject: [PATCH 149/168] rename FDEM --> ProblemFDEM --- SimPEG/EM/FDEM/{FDEM.py => ProblemFDEM.py} | 0 SimPEG/EM/FDEM/__init__.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename SimPEG/EM/FDEM/{FDEM.py => ProblemFDEM.py} (100%) diff --git a/SimPEG/EM/FDEM/FDEM.py b/SimPEG/EM/FDEM/ProblemFDEM.py similarity index 100% rename from SimPEG/EM/FDEM/FDEM.py rename to SimPEG/EM/FDEM/ProblemFDEM.py diff --git a/SimPEG/EM/FDEM/__init__.py b/SimPEG/EM/FDEM/__init__.py index 1701fe3e..c4ff6451 100644 --- a/SimPEG/EM/FDEM/__init__.py +++ b/SimPEG/EM/FDEM/__init__.py @@ -1,5 +1,5 @@ from SurveyFDEM import Survey import SrcFDEM as Src import RxFDEM as Rx -from FDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h +from ProblemFDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h From 10c8791514e9bf636d71331adbda2f63327fa8a5 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 18 May 2016 00:33:30 -0700 Subject: [PATCH 150/168] update base MT to import ProblemFDEM --- SimPEG/MT/BaseMT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/MT/BaseMT.py b/SimPEG/MT/BaseMT.py index c201dfb0..579f590f 100644 --- a/SimPEG/MT/BaseMT.py +++ b/SimPEG/MT/BaseMT.py @@ -1,5 +1,5 @@ from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np -from SimPEG.EM.FDEM.FDEM import BaseFDEMProblem +from SimPEG.EM.FDEM.ProblemFDEM import BaseFDEMProblem from SurveyMT import Survey, Data from FieldsMT import BaseMTFields From e8bd78f63d8ac84e749e15471e69e40a8174ccd8 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 19 May 2016 02:09:48 +0900 Subject: [PATCH 151/168] Working Spectral IP: - Fwd - Jvec - Jtvec --- SimPEG/EM/Static/SIP/ProblemSIP.py | 146 +++++++++++---------- SimPEG/EM/Static/SIP/RxSIP.py | 8 +- SimPEG/EM/Static/SIP/SrcSIP.py | 64 ++++++++++ SimPEG/EM/Static/SIP/SurveySIP.py | 76 ++++++++++- SimPEG/EM/Static/SIP/__init__.py | 4 +- tests/em/static/test_SIP_jvecjtvecadj.py | 154 +++++++++++++++++++++++ 6 files changed, 382 insertions(+), 70 deletions(-) create mode 100644 SimPEG/EM/Static/SIP/SrcSIP.py create mode 100644 tests/em/static/test_SIP_jvecjtvecadj.py diff --git a/SimPEG/EM/Static/SIP/ProblemSIP.py b/SimPEG/EM/Static/SIP/ProblemSIP.py index d01ae706..e4ab33d8 100644 --- a/SimPEG/EM/Static/SIP/ProblemSIP.py +++ b/SimPEG/EM/Static/SIP/ProblemSIP.py @@ -5,7 +5,7 @@ from SimPEG.Utils import sdiag import numpy as np from SimPEG.Utils import Zero from SimPEG.EM.Static.DC import getxBCyBC_CC -from SurveySIP import Survey +from SurveySIP import Survey, Data class ColeColePropMap(Maps.PropMap): """ @@ -22,6 +22,7 @@ class BaseSIPProblem(BaseEMProblem): surveyPair = Survey fieldsPair = Fields + dataPair = Data PropMap = ColeColePropMap Ainv = None sigma = None @@ -29,15 +30,17 @@ class BaseSIPProblem(BaseEMProblem): f = None Ainv = None - def DebyeTime(t): + def DebyeTime(self, t): peta = self.curModel.eta*np.exp(-self.curModel.taui*t) return peta - def EtaDeriv(t): - return np.exp(-self.curModel.taui*t) + def EtaDeriv(self, t, v): + v = np.array(v, dtype=float) + return np.exp(-self.curModel.taui*t) * (self.curModel.etaDeriv*v) - def TauiDeriv(t): - return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) + def TauiDeriv(self, t, v): + v = np.array(v, dtype=float) + return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) * (self.curModel.tauiDeriv*v) def fields(self, m): self.curModel = m @@ -63,7 +66,8 @@ class BaseSIPProblem(BaseEMProblem): JvAll = [] for tind in range(len(self.survey.times)): #Pseudo-chareability - v = DebyeTime(self.survey.times[tind]) + t = self.survey.times[tind] + v = self.DebyeTime(t) for src in self.survey.srcList: u_src = f[src, self._solutionType] # solution vector dA_dm_v = self.getADeriv(u_src, v) @@ -74,76 +78,88 @@ class BaseSIPProblem(BaseEMProblem): if timeindex[tind]: df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) - Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) - JvAll.append(Utils.mkvc(Jv)) + Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v) + # Conductivity (d u / d log sigma) if self._formulation is 'EB': - return -np.hstack(JvAll) - # Conductivity (d u / d log rho) + return -Utils.mkvc(Jv) + # Resistivity (d u / d log rho) if self._formulation is 'HJ': - return np.hstack(JvAll) + return Utils.mkvc(Jv) - # def Jvec(self, m, v, f=None): + def Jvec(self, m, v, f=None): - # if f is None: - # f = self.fields(m) + if f is None: + f = self.fields(m) - # self.curModel = m + self.curModel = m + Jv = self.dataPair(self.survey) #same size as the data + # A = self.getA() + JvAll = [] + #Assume only eta and tau (eta first then tau) + # v = [2*Mx1] + v = v.reshape((int(v.size/2), 2), order='F') - # Jv = self.dataPair(self.survey) #same size as the data - # x1 = - # x2 = - # # A = self.getA() - # for src in self.survey.srcList: - # u_src = f[src, self._solutionType] # solution vector + for tind in range(len(self.survey.times)): + t = self.survey.times[tind] + v0 = self.EtaDeriv(t, v[:,0]) + v1 = self.TauiDeriv(t, v[:,1]) + for src in self.survey.srcList: + u_src = f[src, self._solutionType] # solution vector + dA_dm_v0 = self.getADeriv(u_src, v0) + dRHS_dm_v0 = self.getRHSDeriv(src, v0) + du_dm_v0 = self.Ainv * ( - dA_dm_v0 + dRHS_dm_v0 ) + dA_dm_v1 = self.getADeriv(u_src, v1) + dRHS_dm_v1 = self.getRHSDeriv(src, v1) + du_dm_v1 = self.Ainv * ( - dA_dm_v1 + dRHS_dm_v1 ) + for rx in src.rxList: + timeindex = rx.getTimeP(self.survey.times) + if timeindex[tind]: + df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_dm_v0 = df_dmFun(src, du_dm_v0, v0, adjoint=False) + df_dm_v1 = df_dmFun(src, du_dm_v1, v1, adjoint=False) + Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v0) + Jv[src, rx, t] += rx.evalDeriv(src, self.mesh, f, df_dm_v1) + # Conductivity (d u / d log sigma) + if self._formulation is 'EB': + return -Jv.tovec() + # Resistivity (d u / d log rho) + if self._formulation is 'HJ': + return Jv.tovec() - # dA_dm_v = self.getADeriv(u_src, v) - # dRHS_dm_v = self.getRHSDeriv(src, v) - # du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v ) + def Jtvec(self, m, v, f=None): + if f is None: + f = self.fields(m) - # for rx in src.rxList: + self.curModel = m - # for tind in range(len(self.survey.times)): - # df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None) - # df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False) - # Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v) - # # Conductivity (d u / d log sigma) - # if self._formulation is 'EB': - # return -Utils.mkvc(Jv) - # # Conductivity (d u / d log rho) - # if self._formulation is 'HJ': - # return Utils.mkvc(Jv) + # Ensure v is a data object. + if not isinstance(v, self.dataPair): + v = self.dataPair(self.survey, v) - # def Jtvec(self, m, v, f=None): - # if f is None: - # f = self.fields(m) + Jtv= np.zeros(m.size) + for tind in range(len(self.survey.times)): + t = self.survey.times[tind] + for src in self.survey.srcList: + u_src = f[src, self._solutionType] + for rx in src.rxList: + timeindex = rx.getTimeP(self.survey.times) + if timeindex[tind]: + PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx, t], adjoint=True) # wrt f, need possibility wrt m + df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) + df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) + ATinvdf_duT = self.Ainv * df_duT + dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) + dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) + du_dmT = -dA_dmT + dRHS_dmT + Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT), self.TauiDeriv(self.survey.times[tind], du_dmT)] - # self.curModel = m - - # # Ensure v is a data object. - # if not isinstance(v, self.dataPair): - # v = self.dataPair(self.survey, v) - - # Jtv = np.zeros(m.size) - # # AT = self.getA() - - # for src in self.survey.srcList: - # u_src = f[src, self._solutionType] - # for rx in src.rxList: - # PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m - # df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None) - # df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True) - # ATinvdf_duT = self.Ainv * df_duT - # dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) - # dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) - # du_dmT = -dA_dmT + dRHS_dmT - # Jtv += df_dmT + du_dmT - # # Conductivity ((d u / d log sigma).T) - # if self._formulation is 'EB': - # return -Utils.mkvc(Jtv) - # # Conductivity ((d u / d log rho).T) - # if self._formulation is 'HJ': - # return Utils.mkvc(Jtv) + # Conductivity ((d u / d log sigma).T) + if self._formulation is 'EB': + return -Jtv + # Conductivity ((d u / d log rho).T) + if self._formulation is 'HJ': + return Jtv def getSourceTerm(self): """ diff --git a/SimPEG/EM/Static/SIP/RxSIP.py b/SimPEG/EM/Static/SIP/RxSIP.py index f4ff1a2f..b8144d0f 100644 --- a/SimPEG/EM/Static/SIP/RxSIP.py +++ b/SimPEG/EM/Static/SIP/RxSIP.py @@ -62,7 +62,13 @@ class Dipole(BaseRx): @property def nD(self): """Number of data in the receiver.""" - return self.locs[0].shape[0] * len(self.times) + # return self.locs[0].shape[0] * len(self.times) + return self.locs[0].shape[0] + + @property + def nRx(self): + """Number of data in the receiver.""" + return self.locs[0].shape[0] # Not sure why ... # return int(self.locs[0].size / 2) diff --git a/SimPEG/EM/Static/SIP/SrcSIP.py b/SimPEG/EM/Static/SIP/SrcSIP.py new file mode 100644 index 00000000..b1f0a452 --- /dev/null +++ b/SimPEG/EM/Static/SIP/SrcSIP.py @@ -0,0 +1,64 @@ +import SimPEG +# from SimPEG.EM.Base import BaseEMSurvey +from SimPEG.Utils import Zero, closestPoints, mkvc +import numpy as np + +class BaseSrc(SimPEG.Survey.BaseSrc): + + current = 1.0 + loc = None + + def __init__(self, rxList, **kwargs): + SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs) + + def eval(self, prob): + raise NotImplementedError + + def evalDeriv(self, prob): + return Zero() + + @property + def nD(self): + """Number of data""" + return self.vnD.sum() + + @property + def vnD(self): + """Vector number of data""" + return np.array([rx.nD*len(rx.times) for rx in self.rxList]) + + + +class Dipole(BaseSrc): + + def __init__(self, rxList, locA, locB, **kwargs): + assert locA.shape == locB.shape, 'Shape of locA and locB should be the same' + self.loc = [locA, locB] + BaseSrc.__init__(self, rxList, **kwargs) + + def eval(self, prob): + if prob._formulation == 'HJ': + inds = closestPoints(prob.mesh, self.loc, gridLoc='CC') + q = np.zeros(prob.mesh.nC) + q[inds] = self.current * np.r_[1., -1.] + elif prob._formulation == 'EB': + qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense() + qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense() + q = self.current * mkvc(qa+qb) + return q + +class Pole(BaseSrc): + + def __init__(self, rxList, loc, **kwargs): + BaseSrc.__init__(self, rxList, loc=loc, **kwargs) + + def eval(self, prob): + if prob._formulation == 'HJ': + inds = closestPoints(prob.mesh, self.loc) + q = np.zeros(prob.mesh.nC) + q[inds] = self.current * np.r_[1.] + elif prob._formulation == 'EB': + q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense() + q = self.current * mkvc(q) + return q + diff --git a/SimPEG/EM/Static/SIP/SurveySIP.py b/SimPEG/EM/Static/SIP/SurveySIP.py index de375794..9362a35c 100644 --- a/SimPEG/EM/Static/SIP/SurveySIP.py +++ b/SimPEG/EM/Static/SIP/SurveySIP.py @@ -1,9 +1,11 @@ import SimPEG from SimPEG.EM.Base import BaseEMSurvey -from SimPEG import np, sp, Survey +from SimPEG import np, sp, Survey, Utils from SimPEG.Utils import Zero, Identity -from SimPEG.EM.Static.DC.SrcDC import BaseSrc +from SimPEG.EM.Static.SIP.SrcSIP import BaseSrc from SimPEG.EM.Static.SIP.RxSIP import BaseRx +import uuid + class Survey(BaseEMSurvey): rxPair = BaseRx @@ -29,4 +31,72 @@ class Survey(BaseEMSurvey): .. math:: d_\\text{pred} = Pf(m) """ - return self.prob.Jvec(m, m, f=f) + return self.prob.forward(m, f=f) + + +class Data(SimPEG.Survey.Data): + """Fancy data storage by Src and Rx""" + + def __init__(self, survey, v=None): + self.uid = str(uuid.uuid4()) + self.survey = survey + self._dataDict = {} + for src in self.survey.srcList: + self._dataDict[src] = {} + for rx in src.rxList: + self._dataDict[src][rx] = {} + + if v is not None: + self.fromvec(v) + + def _ensureCorrectKey(self, key): + if type(key) is tuple: + if len(key) is not 3: + raise KeyError('Key must be [Src, Rx, tInd]') + if key[0] not in self.survey.srcList: + raise KeyError('Src Key must be a source in the survey.') + if key[1] not in key[0].rxList: + raise KeyError('Rx Key must be a receiver for the source.') + return key + elif isinstance(key, self.survey.srcPair): + if key not in self.survey.srcList: + raise KeyError('Key must be a source in the survey.') + return key, None, None + else: + raise KeyError('Key must be [Src] or [Src,Rx] or [Src, Rx, tInd]') + + def __setitem__(self, key, value): + src, rx, t = self._ensureCorrectKey(key) + assert rx is not None, 'set data using [Src, Rx]' + assert isinstance(value, np.ndarray), 'value must by ndarray' + assert value.size == rx.nD, "value must have the same number of data as the source." + self._dataDict[src][rx][t] = Utils.mkvc(value) + + def __getitem__(self, key): + src, rx, t = self._ensureCorrectKey(key) + if rx is not None: + if rx not in self._dataDict[src]: + raise Exception('Data for receiver has not yet been set.') + return self._dataDict[src][rx][t] + + return np.concatenate([self[src,rx, t] for rx in src.rxList]) + + def tovec(self): + val = [] + for src in self.survey.srcList: + for rx in src.rxList: + for t in rx.times: + val.append(self[src, rx, t]) + return np.concatenate(val) + + + def fromvec(self, v): + v = Utils.mkvc(v) + assert v.size == self.survey.nD, 'v must have the correct number of data.' + indBot, indTop = 0, 0 + for src in self.survey.srcList: + for rx in src.rxList: + for t in rx.times: + indTop += rx.nRx + self[src, rx, t] = v[indBot:indTop] + indBot += rx.nRx diff --git a/SimPEG/EM/Static/SIP/__init__.py b/SimPEG/EM/Static/SIP/__init__.py index f81ceb3c..94fdb591 100644 --- a/SimPEG/EM/Static/SIP/__init__.py +++ b/SimPEG/EM/Static/SIP/__init__.py @@ -1,2 +1,4 @@ from ProblemSIP import Problem3D_CC, Problem3D_N -from SurveySIP import Survey +from SurveySIP import Survey, Data +import SrcSIP as Src #Pole +import RxSIP as Rx diff --git a/tests/em/static/test_SIP_jvecjtvecadj.py b/tests/em/static/test_SIP_jvecjtvecadj.py new file mode 100644 index 00000000..6e6f071d --- /dev/null +++ b/tests/em/static/test_SIP_jvecjtvecadj.py @@ -0,0 +1,154 @@ +import unittest +from SimPEG import * +import SimPEG +from SimPEG import Mesh, Utils, EM, Maps, np, Survey +from SimPEG.EM.Static import SIP, DC, IP +from pymatsolver import MumpsSolver + + +class IPProblemTestsCC(unittest.TestCase): + + def setUp(self): + + cs = 25. + hx = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hy = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hz = [(cs,0, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + blkind0 = Utils.ModelBuilder.getIndicesSphere(np.r_[-100., -100., -200.], 75., mesh.gridCC) + blkind1 = Utils.ModelBuilder.getIndicesSphere(np.r_[100., 100., -200.], 75., mesh.gridCC) + sigma = np.ones(mesh.nC)*1e-2 + eta = np.zeros(mesh.nC) + tau = np.ones_like(sigma)*1. + eta[blkind0] = 0.1 + eta[blkind1] = 0.1 + tau[blkind0] = 0.1 + tau[blkind1] = 0.01 + + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + + times = np.arange(10)*1e-3 + 1e-3 + rx = SIP.Rx.Dipole(M, N, times) + src = SIP.Src.Dipole([rx], Aloc, Bloc) + survey = SIP.Survey([src]) + colemap = [("eta", Maps.IdentityMap(mesh)), ("taui", Maps.IdentityMap(mesh))] + problem = SIP.Problem3D_CC(mesh, rho=1./sigma, mapping=colemap) + problem.Solver = MumpsSolver + problem.pair(survey) + mSynth = np.r_[eta, 1./tau] + survey.makeSyntheticData(mSynth) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC*2) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-10 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + +class IPProblemTestsN(unittest.TestCase): + + def setUp(self): + + cs = 25. + hx = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hy = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hz = [(cs,0, -1.3),(cs,20)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN") + blkind0 = Utils.ModelBuilder.getIndicesSphere(np.r_[-100., -100., -200.], 75., mesh.gridCC) + blkind1 = Utils.ModelBuilder.getIndicesSphere(np.r_[100., 100., -200.], 75., mesh.gridCC) + sigma = np.ones(mesh.nC)*1e-2 + eta = np.zeros(mesh.nC) + tau = np.ones_like(sigma)*1. + eta[blkind0] = 0.1 + eta[blkind1] = 0.1 + tau[blkind0] = 0.1 + tau[blkind1] = 0.01 + + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + + times = np.arange(10)*1e-3 + 1e-3 + rx = SIP.Rx.Dipole(M, N, times) + src = SIP.Src.Dipole([rx], Aloc, Bloc) + survey = SIP.Survey([src]) + colemap = [("eta", Maps.IdentityMap(mesh)), ("taui", Maps.IdentityMap(mesh))] + problem = SIP.Problem3D_N(mesh, sigma=sigma, mapping=colemap) + problem.Solver = MumpsSolver + problem.pair(survey) + mSynth = np.r_[eta, 1./tau] + survey.makeSyntheticData(mSynth) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + reg = Regularization.Tikhonov(mesh) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC*2) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-8 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() From c4c97ae054602376cf2d5df596b3d5729a723709 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 20 May 2016 00:04:20 -0700 Subject: [PATCH 152/168] Ad MultiRegularization for inverting multiple parameters --- SimPEG/EM/Static/SIP/Regularization.py | 105 +++++++++++++++++++++++++ SimPEG/EM/Static/SIP/__init__.py | 1 + 2 files changed, 106 insertions(+) create mode 100644 SimPEG/EM/Static/SIP/Regularization.py diff --git a/SimPEG/EM/Static/SIP/Regularization.py b/SimPEG/EM/Static/SIP/Regularization.py new file mode 100644 index 00000000..4a067929 --- /dev/null +++ b/SimPEG/EM/Static/SIP/Regularization.py @@ -0,0 +1,105 @@ +from SimPEG import Utils, Maps, Mesh, sp, np +from SimPEG.Regularization import BaseRegularization, Simple + +class MultiRegularization(Simple): + """ + **MultiRegularization Class** + + This is used to regularize the model space + having multiple models [m1, m2, m3, ...] :: + + reg = Regularization(mesh) + + """ + nModels = None # Number of models + ratios = None + crossgrad = False + + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) + if self.nModels == None: + raise Exception("Put nModels as a initial input!") + if self.ratios == None: + self.ratios = [1. for imodel in range(self.nModels)] + + @property + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + vecs = [] + for imodel in range(self.nModels): + vecs.append((self.regmesh.vol*self.alpha_s*self.wght*self.ratios[imodel])**0.5) + self._Wsmall = Utils.sdiag(np.hstack(vecs)) + return self._Wsmall + + @property + def Wx(self): + """Regularization matrix Wx""" + if getattr(self, '_Wx', None) is None: + mats = [] + for imodel in range(self.nModels): + mats.append(Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*self.ratios[imodel]*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil) + self._Wx = sp.block_diag(mats) + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + if getattr(self, '_Wy', None) is None: + mats = [] + for imodel in range(self.nModels): + mats.append(Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol*self.alpha_y*self.ratios[imodel]*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil) + self._Wy = sp.block_diag(mats) + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + if getattr(self, '_Wz', None) is None: + mats = [] + for imodel in range(self.nModels): + mats.append(Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*self.ratios[imodel]*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil) + self._Wz = sp.block_diag(mats) + return self._Wz + + @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 self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + 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 _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 _evalCross(self, m): + if self.crossgrad == False: + return 0. + elif self.crossgrad == True: + r = self.Wcross * ( self.mapping * m) + return 0.5 * r.dot(r) + diff --git a/SimPEG/EM/Static/SIP/__init__.py b/SimPEG/EM/Static/SIP/__init__.py index 94fdb591..1de46fcf 100644 --- a/SimPEG/EM/Static/SIP/__init__.py +++ b/SimPEG/EM/Static/SIP/__init__.py @@ -2,3 +2,4 @@ from ProblemSIP import Problem3D_CC, Problem3D_N from SurveySIP import Survey, Data import SrcSIP as Src #Pole import RxSIP as Rx +from Regularization import MultiRegularization From 0179631fe31db5bfa2b6800210cdc973f8bcb683 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Fri, 20 May 2016 01:57:40 -0700 Subject: [PATCH 153/168] Starting Cross gradient ... --- SimPEG/EM/Static/SIP/Regularization.py | 47 +++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/SimPEG/EM/Static/SIP/Regularization.py b/SimPEG/EM/Static/SIP/Regularization.py index 4a067929..a327ce4d 100644 --- a/SimPEG/EM/Static/SIP/Regularization.py +++ b/SimPEG/EM/Static/SIP/Regularization.py @@ -12,8 +12,12 @@ class MultiRegularization(Simple): """ nModels = None # Number of models - ratios = None - crossgrad = False + ratios = None # Ratio for different models + crossgrad = False # Use cross gradient or not + betacross = 1. + wx = [] + wy = [] + wz = [] def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @@ -38,7 +42,8 @@ class MultiRegularization(Simple): if getattr(self, '_Wx', None) is None: mats = [] for imodel in range(self.nModels): - mats.append(Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*self.ratios[imodel]*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil) + self.wx.append(Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*self.ratios[imodel]*(self.regmesh.aveCC2Fx*self.wght))**0.5)) + mats.append(self.wx[imodel]*self.regmesh.cellDiffxStencil) self._Wx = sp.block_diag(mats) return self._Wx @@ -48,7 +53,8 @@ class MultiRegularization(Simple): if getattr(self, '_Wy', None) is None: mats = [] for imodel in range(self.nModels): - mats.append(Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol*self.alpha_y*self.ratios[imodel]*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil) + self.wy.append(Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol*self.alpha_y*self.ratios[imodel]*(self.regmesh.aveCC2Fy*self.wght))**0.5)) + mats.append(self.wy[imodel]*self.regmesh.cellDiffyStencil) self._Wy = sp.block_diag(mats) return self._Wy @@ -58,7 +64,8 @@ class MultiRegularization(Simple): if getattr(self, '_Wz', None) is None: mats = [] for imodel in range(self.nModels): - mats.append(Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*self.ratios[imodel]*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil) + self.wz.append(Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*self.ratios[imodel]*(self.regmesh.aveCC2Fz*self.wght))**0.5)) + mats.append(self.wz[imodel]*self.regmesh.cellDiffzStencil) self._Wz = sp.block_diag(mats) return self._Wz @@ -95,11 +102,27 @@ class MultiRegularization(Simple): r = self.Wsmooth * ( self.mapping * m) return 0.5 * r.dot(r) - @Utils.timeIt - def _evalCross(self, m): - if self.crossgrad == False: - return 0. - elif self.crossgrad == True: - r = self.Wcross * ( self.mapping * m) - return 0.5 * r.dot(r) + # TODO: Implement Cross Gradients.. + # @Utils.timeIt + # def _evalCross(self, m): + # if self.crossgrad == False: + # return 0. + # elif self.crossgrad == True: + # M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F") + + # for imodel in range(self.nModels): + # ux.append(self.regmesh.aveFx2CC*self.regmesh.wx[imodel]*M[:,imodel]) + # uy.append(self.regmesh.aveFy2CC*self.regmesh.wy[imodel]*M[:,imodel]) + # uz.append(self.regmesh.aveFz2CC*self.regmesh.wz[imodel]*M[:,imodel]) + + # ax, ay, az = ux[0], uy[0], uz[0] + # for imodel in range(1,self.nModels): + # bx, by, bz = ux[imodel], uy[imodel], uz[imodel] + # cx = ay*bz - az*by + # cy = az*bx - ax*bz + # cz = ax*by - ay*bx + # ax, ay, az = cx.copy(), cy.copy(), cz.copy() + # r = np.r_[ax, ay, az]*np.sqrt(self.betacross) + + # return 0.5 * r.dot(r) From 8936fa40215bbe19b37838402cdf992da314114b Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 22 May 2016 11:42:23 -0700 Subject: [PATCH 154/168] use phi_d_star, chifact in defining target misfit --- SimPEG/Directives.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 4fc1ffc5..93e51f62 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -146,10 +146,15 @@ class BetaSchedule(InversionDirective): class TargetMisfit(InversionDirective): + chifact = 1. + phi_d_star = None + @property def target(self): if getattr(self, '_target', None) is None: - self._target = self.survey.nD*0.5 + if self.phi_d_star is None: + self.phi_d_star = 0.5 * self.survey.nD + self._target = self.chifact * self.phi_d_star # the factor of 0.5 is because we do phid = 0.5*|| dpred - dobs||^2 return self._target @target.setter def target(self, val): @@ -309,20 +314,20 @@ class Update_lin_PreCond(InversionDirective): Create a Jacobi preconditioner for the linear problem """ onlyOnStart=False - + def initialize(self): - + if getattr(self.opt, 'approxHinv', None) is 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((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC - + def endIter(self): # Cool the threshold parameter if self.onlyOnStart==True: return - + 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. From e25b496ab0117d2a6b4f8e73ba3f6ca96a09c7c0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Mon, 23 May 2016 12:07:14 -0700 Subject: [PATCH 155/168] allow kwarg input of primary fields --- SimPEG/EM/FDEM/SrcFDEM.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/SimPEG/EM/FDEM/SrcFDEM.py b/SimPEG/EM/FDEM/SrcFDEM.py index 6da924be..2c97adf1 100644 --- a/SimPEG/EM/FDEM/SrcFDEM.py +++ b/SimPEG/EM/FDEM/SrcFDEM.py @@ -10,6 +10,10 @@ class BaseSrc(Survey.BaseSrc): freq = None integrate = False + _ePrimary = None + _bPrimary = None + _hPrimary = None + _jPrimary = None def __init__(self, rxList, **kwargs): Survey.BaseSrc.__init__(self, rxList, **kwargs) @@ -53,7 +57,9 @@ class BaseSrc(Survey.BaseSrc): :rtype: numpy.ndarray :return: primary magnetic flux density """ - return Zero() + if self._bPrimary is None: + return Zero() + return self._bPrimary def hPrimary(self, prob): """ @@ -63,7 +69,9 @@ class BaseSrc(Survey.BaseSrc): :rtype: numpy.ndarray :return: primary magnetic field """ - return Zero() + if self._hPrimary is None: + return Zero() + return self._hPrimary def ePrimary(self, prob): """ @@ -73,7 +81,9 @@ class BaseSrc(Survey.BaseSrc): :rtype: numpy.ndarray :return: primary electric field """ - return Zero() + if self._ePrimary is None: + return Zero() + return self._ePrimary def jPrimary(self, prob): """ @@ -83,7 +93,9 @@ class BaseSrc(Survey.BaseSrc): :rtype: numpy.ndarray :return: primary current density """ - return Zero() + if self._jPrimary is None: + return Zero() + return self._jPrimary def s_m(self, prob): """ @@ -144,6 +156,7 @@ class RawVec_e(BaseSrc): def __init__(self, rxList, freq, s_e): self._s_e = np.array(s_e, dtype=complex) self.freq = float(freq) + self._ePrimary = ePrimary BaseSrc.__init__(self, rxList) From beca0203dfcd0cfc7197512a90004f4cab2a5491 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Mon, 23 May 2016 12:11:03 -0700 Subject: [PATCH 156/168] typo fix --- SimPEG/EM/FDEM/SrcFDEM.py | 1 - 1 file changed, 1 deletion(-) diff --git a/SimPEG/EM/FDEM/SrcFDEM.py b/SimPEG/EM/FDEM/SrcFDEM.py index 2c97adf1..e7650164 100644 --- a/SimPEG/EM/FDEM/SrcFDEM.py +++ b/SimPEG/EM/FDEM/SrcFDEM.py @@ -156,7 +156,6 @@ class RawVec_e(BaseSrc): def __init__(self, rxList, freq, s_e): self._s_e = np.array(s_e, dtype=complex) self.freq = float(freq) - self._ePrimary = ePrimary BaseSrc.__init__(self, rxList) From 2c87a50d29b9888cba3f2701d19c9a44924432dd Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Mon, 23 May 2016 12:21:29 -0700 Subject: [PATCH 157/168] add kwargs to raw vec e,m --- SimPEG/EM/FDEM/SrcFDEM.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/EM/FDEM/SrcFDEM.py b/SimPEG/EM/FDEM/SrcFDEM.py index e7650164..9bb6ffce 100644 --- a/SimPEG/EM/FDEM/SrcFDEM.py +++ b/SimPEG/EM/FDEM/SrcFDEM.py @@ -153,11 +153,11 @@ class RawVec_e(BaseSrc): :param bool integrate: Integrate the source term (multiply by Me) [False] """ - def __init__(self, rxList, freq, s_e): + def __init__(self, rxList, freq, s_e, **kwargs): self._s_e = np.array(s_e, dtype=complex) self.freq = float(freq) - BaseSrc.__init__(self, rxList) + BaseSrc.__init__(self, rxList, **kwargs) def s_e(self, prob): """ @@ -182,11 +182,11 @@ class RawVec_m(BaseSrc): :param bool integrate: Integrate the source term (multiply by Me) [False] """ - def __init__(self, rxList, freq, s_m, integrate=True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()): + def __init__(self, rxList, freq, s_m, **kwargs): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()): self._s_m = np.array(s_m, dtype=complex) self.freq = float(freq) - BaseSrc.__init__(self, rxList) + BaseSrc.__init__(self, rxList, **kwargs) def s_m(self, prob): """ From f20fcb4504ef3f229d951982d6bc39a09c58da6a Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Tue, 24 May 2016 08:45:12 -0700 Subject: [PATCH 158/168] Minor type error based upon numpy version Cross gradient? --- SimPEG/EM/Static/DC/ProblemDC.py | 2 +- SimPEG/EM/Static/IP/ProblemIP.py | 2 +- SimPEG/EM/Static/SIP/Regularization.py | 116 ++++++++++++++++++++----- 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/SimPEG/EM/Static/DC/ProblemDC.py b/SimPEG/EM/Static/DC/ProblemDC.py index 0dd4f259..51b528a5 100644 --- a/SimPEG/EM/Static/DC/ProblemDC.py +++ b/SimPEG/EM/Static/DC/ProblemDC.py @@ -77,7 +77,7 @@ class BaseDCProblem(BaseEMProblem): dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) du_dmT = -dA_dmT + dRHS_dmT - Jtv += df_dmT + du_dmT + Jtv += (df_dmT + du_dmT).astype(float) return Utils.mkvc(Jtv) diff --git a/SimPEG/EM/Static/IP/ProblemIP.py b/SimPEG/EM/Static/IP/ProblemIP.py index 4ff81990..a637516a 100644 --- a/SimPEG/EM/Static/IP/ProblemIP.py +++ b/SimPEG/EM/Static/IP/ProblemIP.py @@ -89,7 +89,7 @@ class BaseIPProblem(BaseEMProblem): dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) du_dmT = -dA_dmT + dRHS_dmT - Jtv += df_dmT + du_dmT + Jtv += (df_dmT + du_dmT).astype(float) # Conductivity ((d u / d log sigma).T) if self._formulation is 'EB': return -Utils.mkvc(Jtv) diff --git a/SimPEG/EM/Static/SIP/Regularization.py b/SimPEG/EM/Static/SIP/Regularization.py index a327ce4d..3c20e6fe 100644 --- a/SimPEG/EM/Static/SIP/Regularization.py +++ b/SimPEG/EM/Static/SIP/Regularization.py @@ -89,6 +89,11 @@ class MultiRegularization(Simple): self._W = sp.vstack(wlist) return self._W + + @Utils.timeIt + def eval(self, m): + return self._evalSmall(m) + self._evalSmooth(m) + @Utils.timeIt def _evalSmall(self, m): r = self.Wsmall * ( self.mapping * (m - self.mref) ) @@ -102,27 +107,98 @@ class MultiRegularization(Simple): r = self.Wsmooth * ( self.mapping * m) return 0.5 * r.dot(r) - # TODO: Implement Cross Gradients.. - # @Utils.timeIt - # def _evalCross(self, m): - # if self.crossgrad == False: - # return 0. - # elif self.crossgrad == True: - # M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F") + def cross(a,b): + ax, ay, az = a[0], a[1], a[2] + bx, by, bz = b[0], b[1], b[2] + cx = ay*bz - az*by + cy = az*bx - ax*bz + cz = ax*by - ay*bx + return [cx, cy, cz] - # for imodel in range(self.nModels): - # ux.append(self.regmesh.aveFx2CC*self.regmesh.wx[imodel]*M[:,imodel]) - # uy.append(self.regmesh.aveFy2CC*self.regmesh.wy[imodel]*M[:,imodel]) - # uz.append(self.regmesh.aveFz2CC*self.regmesh.wz[imodel]*M[:,imodel]) + # TODO: Implement Cross Gradients.. + @Utils.timeIt + def _evalCross(self, m): + if self.crossgrad == False: + return 0. + elif self.crossgrad == True: + M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F") + + ax = self.regmesh.aveFx2CC*self.regmesh.wx[0]*M[:,0] + ay = self.regmesh.aveFy2CC*self.regmesh.wy[0]*M[:,0] + az = self.regmesh.aveFz2CC*self.regmesh.wz[0]*M[:,0] + bx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1] + by = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1] + bz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1] + #ab + out_ab = cross([ax, ay, az], [bx, by, bz]) + r = np.r_[out_ab[0], out_ab[1], out_ab[2]]*np.sqrt(self.betacross) + + if self.nModels == 3: + cx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1] + cy = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1] + cz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1] + #ac + out_ac = cross([ax, ay, az], [cx, cy, cz]) + #bc + out_bc = cross([bx, by, bz], [cx, cy, cz]) + r = np.r_[r, np.hstack(out_ac)*np.sqrt(self.betacross), np.hstack(out_bc)*np.sqrt(self.betacross)] + + 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})} + + """ + deriv = self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + if self.crossgrad==True: + deriv += self._evalCrossDeriv(m) + return deriv + + @Utils.timeIt + def _evalCrossDeriv(self,m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) + + @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 + + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the second derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W} + + """ + mD = self.mapping.deriv(m - self.mref) + if v is None: + return mD.T * self.W.T * self.W * mD + + return mD.T * ( self.W.T * ( self.W * ( mD * v) ) ) - # ax, ay, az = ux[0], uy[0], uz[0] - # for imodel in range(1,self.nModels): - # bx, by, bz = ux[imodel], uy[imodel], uz[imodel] - # cx = ay*bz - az*by - # cy = az*bx - ax*bz - # cz = ax*by - ay*bx - # ax, ay, az = cx.copy(), cy.copy(), cz.copy() - # r = np.r_[ax, ay, az]*np.sqrt(self.betacross) - # return 0.5 * r.dot(r) From 21d817d9a257138d90daa647bc67d9ec0ebbc58e Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Tue, 24 May 2016 21:53:18 -0700 Subject: [PATCH 159/168] fix bug for adjoint problem --- SimPEG/EM/Static/SIP/ProblemSIP.py | 17 ++++-- tests/em/static/test_SIP_jvecjtvecadj.py | 78 ++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/SimPEG/EM/Static/SIP/ProblemSIP.py b/SimPEG/EM/Static/SIP/ProblemSIP.py index e4ab33d8..88b85a7b 100644 --- a/SimPEG/EM/Static/SIP/ProblemSIP.py +++ b/SimPEG/EM/Static/SIP/ProblemSIP.py @@ -34,13 +34,20 @@ class BaseSIPProblem(BaseEMProblem): peta = self.curModel.eta*np.exp(-self.curModel.taui*t) return peta - def EtaDeriv(self, t, v): + def EtaDeriv(self, t, v, adjoint=False): v = np.array(v, dtype=float) - return np.exp(-self.curModel.taui*t) * (self.curModel.etaDeriv*v) + if adjoint: + return self.curModel.etaDeriv.T * (np.exp(-self.curModel.taui*t)*v) + else: + return np.exp(-self.curModel.taui*t) * (self.curModel.etaDeriv*v) - def TauiDeriv(self, t, v): + + def TauiDeriv(self, t, v, adjoint=False): v = np.array(v, dtype=float) - return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) * (self.curModel.tauiDeriv*v) + if adjoint: + return -self.curModel.tauiDeriv.T * (self.curModel.eta*t*np.exp(-self.curModel.taui*t)*v) + else: + return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) * (self.curModel.tauiDeriv*v) def fields(self, m): self.curModel = m @@ -152,7 +159,7 @@ class BaseSIPProblem(BaseEMProblem): dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True) dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True) du_dmT = -dA_dmT + dRHS_dmT - Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT), self.TauiDeriv(self.survey.times[tind], du_dmT)] + Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT, adjoint=True), self.TauiDeriv(self.survey.times[tind], du_dmT, adjoint=True)] # Conductivity ((d u / d log sigma).T) if self._formulation is 'EB': diff --git a/tests/em/static/test_SIP_jvecjtvecadj.py b/tests/em/static/test_SIP_jvecjtvecadj.py index 6e6f071d..7cdb6def 100644 --- a/tests/em/static/test_SIP_jvecjtvecadj.py +++ b/tests/em/static/test_SIP_jvecjtvecadj.py @@ -150,5 +150,83 @@ class IPProblemTestsN(unittest.TestCase): passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) self.assertTrue(passed) +class IPProblemTestsN_air(unittest.TestCase): + + def setUp(self): + + cs = 25. + hx = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hy = [(cs,0, -1.3),(cs,21),(cs,0, 1.3)] + hz = [(cs,0, -1.3),(cs,20),(cs,0, 1.3)] + mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCC") + blkind0 = Utils.ModelBuilder.getIndicesSphere(np.r_[-100., -100., -200.], 75., mesh.gridCC) + blkind1 = Utils.ModelBuilder.getIndicesSphere(np.r_[100., 100., -200.], 75., mesh.gridCC) + sigma = np.ones(mesh.nC)*1e-2 + airind = mesh.gridCC[:,2]>0. + sigma[airind] = 1e-8 + eta = np.zeros(mesh.nC) + tau = np.ones_like(sigma)*1. + eta[blkind0] = 0.1 + eta[blkind1] = 0.1 + tau[blkind0] = 0.1 + tau[blkind1] = 0.01 + + actmapeta = Maps.InjectActiveCells(mesh, ~airind, 0.) + actmaptau = Maps.InjectActiveCells(mesh, ~airind, 1.) + + x = mesh.vectorCCx[(mesh.vectorCCx>-155.)&(mesh.vectorCCx<155.)] + y = mesh.vectorCCx[(mesh.vectorCCy>-155.)&(mesh.vectorCCy<155.)] + Aloc = np.r_[-200., 0., 0.] + Bloc = np.r_[200., 0., 0.] + M = Utils.ndgrid(x-25.,y, np.r_[0.]) + N = Utils.ndgrid(x+25.,y, np.r_[0.]) + + times = np.arange(10)*1e-3 + 1e-3 + rx = SIP.Rx.Dipole(M, N, times) + src = SIP.Src.Dipole([rx], Aloc, Bloc) + survey = SIP.Survey([src]) + colemap = [("eta", Maps.IdentityMap(mesh)*actmapeta), ("taui", Maps.IdentityMap(mesh)*actmaptau)] + problem = SIP.Problem3D_N(mesh, sigma=sigma, mapping=colemap) + problem.Solver = MumpsSolver + problem.pair(survey) + mSynth = np.r_[eta[~airind], 1./tau[~airind]] + survey.makeSyntheticData(mSynth) + # Now set up the problem to do some minimization + dmis = DataMisfit.l2_DataMisfit(survey) + regmap = Maps.IdentityMap(nP=int(mSynth[~airind].size*2)) + reg = SIP.MultiRegularization(mesh, mapping=regmap, nModels=2, indActive=~airind) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4) + inv = Inversion.BaseInversion(invProb) + + self.inv = inv + self.reg = reg + self.p = problem + self.mesh = mesh + self.m0 = mSynth + self.survey = survey + self.dmis = dmis + + def test_misfit(self): + derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + + def test_adjoint(self): + # Adjoint Test + u = np.random.rand(self.mesh.nC*self.survey.nSrc) + v = np.random.rand(self.mesh.nC) + w = np.random.rand(self.survey.dobs.shape[0]) + wtJv = w.dot(self.p.Jvec(self.m0, v)) + vtJtw = v.dot(self.p.Jtvec(self.m0, w)) + passed = np.abs(wtJv - vtJtw) < 1e-8 + print 'Adjoint Test', np.abs(wtJv - vtJtw), passed + self.assertTrue(passed) + + def test_dataObj(self): + derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)] + passed = Tests.checkDerivative(derChk, self.m0, plotIt=False, num=3) + self.assertTrue(passed) + if __name__ == '__main__': unittest.main() From 339543b89342e06acabf46f1f20ea0e701a0023a Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 25 May 2016 23:28:58 -0700 Subject: [PATCH 160/168] Incorporate Lindsey's comments on documenting codes --- SimPEG/EM/Analytics/DC.py | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/SimPEG/EM/Analytics/DC.py b/SimPEG/EM/Analytics/DC.py index 121bb14b..f67843d6 100644 --- a/SimPEG/EM/Analytics/DC.py +++ b/SimPEG/EM/Analytics/DC.py @@ -6,16 +6,16 @@ def DCAnalyticHalf(txloc, rxlocs, sigma, earth_type="wholespace"): """ Analytic solution for electric potential from a postive pole - Input variables: - - txloc = a xyz location of A (+) electrode (np.r_[xa, ya, za]) + :param array txloc: a xyz location of A (+) electrode (np.r_[xa, ya, za]) + :param list rxlocs: xyz locations of M (+) and N (-) electrodes [M, N] + e.g. rxlocs = [M, N] - M: xyz locations of M (+) electrode (np.c_[xmlocs, ymlocs, zmlocs]) - N: xyz locations of N (-) electrode (np.c_[xnlocs, ynlocs, znlocs]) + M: xyz locations of M (+) electrode (np.c_[xmlocs, ymlocs, zmlocs]) + N: xyz locations of N (-) electrode (np.c_[xnlocs, ynlocs, znlocs]) - sigma = conductivity (either float or complex) - earth_type = "wholsespace" or "halfspace" + :param float or complex sigma: values of conductivity + :param string earth_type: values of conductivity ("wholsespace" or "halfspace") """ M = rxlocs[0] @@ -44,20 +44,19 @@ def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \ Parameters: - txloc (array) : current electrode location (x,y,z) - xc (float) : x center of depressed sphere - rxloc (array) : electrode locations - (Nx3 array, # of electrodes) - radius (float): radius of the sphere (m) - rho (float) : resistivity of the background (ohm-m) - rho1 (float) : resistivity of the sphere - field_type (string) : "secondary", "total", "primary" - (default="secondary") - "secondary": secondary potential only due to sphere - "primary": primary potential from the point source - "total": "secondary"+"primary" - order (float) : maximum order of Legendre polynomial - (default=12) + :param array txloc: A (+) current electrode location (x,y,z) + :param array xc: x center of depressed sphere + :param array rxloc: M(+) electrode locations / (Nx3 array, # of electrodes) + + :param float radius: radius (float): radius of the sphere (m) + :param float rho: resistivity of the background (ohm-m) + :param float rho1: resistivity of the sphere + :param string field_type: : "secondary", "total", "primary" + (default="secondary") + "secondary": secondary potential only due to sphere + "primary": primary potential from the point source + "total": "secondary"+"primary" + :param float order: maximum order of Legendre polynomial (default=12) Written by Seogi Kang (skang@eos.ubc.ca) Ph.D. Candidate of University of British Columbia, Canada From 51d82eee26eaeeea0dc3335bf88255ab20e2db22 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Thu, 26 May 2016 09:32:19 -0700 Subject: [PATCH 161/168] Minor fixes to be merged to dev --- tests/em/static/test_DC_2D_analytic.py | 4 ++-- tests/em/static/test_DC_analytic.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/em/static/test_DC_2D_analytic.py b/tests/em/static/test_DC_2D_analytic.py index 7a8fe1b6..699bcbce 100644 --- a/tests/em/static/test_DC_2D_analytic.py +++ b/tests/em/static/test_DC_2D_analytic.py @@ -18,9 +18,9 @@ class DCProblemAnalyticTests(unittest.TestCase): A0loc = np.r_[-150, 0.] A1loc = np.r_[-130, 0.] rxloc = [np.c_[M, np.zeros(20)], np.c_[N, np.zeros(20)]] - data_anal = EM.Analytics.DCAnalyticHalf(np.r_[A0loc, 0.], rxloc, sighalf, flag="halfspace") + data_anal = EM.Analytics.DCAnalyticHalf(np.r_[A0loc, 0.], rxloc, sighalf, earth_type="halfspace") - rx = DC.Rx.Dipole(M, N) + rx = DC.Rx.Dipole_ky(M, N) src0 = DC.Src.Pole([rx], A0loc) survey = DC.Survey_ky([src0]) diff --git a/tests/em/static/test_DC_analytic.py b/tests/em/static/test_DC_analytic.py index 53d494e2..b8ebfc81 100644 --- a/tests/em/static/test_DC_analytic.py +++ b/tests/em/static/test_DC_analytic.py @@ -19,8 +19,8 @@ class DCProblemAnalyticTests(unittest.TestCase): Bloc = np.r_[200., 0., 0.] M = Utils.ndgrid(x-25.,y, np.r_[0.]) N = Utils.ndgrid(x+25.,y, np.r_[0.]) - phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, flag="halfspace") - phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, flag="halfspace") + phiA = EM.Analytics.DCAnalyticHalf(Aloc, [M,N], 1e-2, earth_type="halfspace") + phiB = EM.Analytics.DCAnalyticHalf(Bloc, [M,N], 1e-2, earth_type="halfspace") data_anal = phiA-phiB rx = DC.Rx.Dipole(M, N) From 1c53129da6b8e34dbe7ec972f28f5bbe74c9f980 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 26 May 2016 17:58:30 -0700 Subject: [PATCH 162/168] fix bug in prop map linked derivs --- SimPEG/PropMaps.py | 4 ++-- tests/base/test_PropMaps.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/SimPEG/PropMaps.py b/SimPEG/PropMaps.py index 527a6f7e..e4f65973 100644 --- a/SimPEG/PropMaps.py +++ b/SimPEG/PropMaps.py @@ -74,7 +74,7 @@ class Property(object): if linkedMap is None: return None linkMap = linkMapClass(None) * linkedMap - m = getattr(self, '%s'%linkName) + m = getattr(self, '%sModel'%linkName) return linkMap.deriv( m ) m = getattr(self, '%sModel'%prop.name) @@ -239,7 +239,7 @@ class PropMap(object): setattr(self, '%sMap'%name, mapping) setattr(self, '%sIndex'%name, slices.get(name, slice(nP, nP + mapping.nP))) nP += mapping.nP - self.nP = nP + self.nP = nP @property def defaultInvProp(self): diff --git a/tests/base/test_PropMaps.py b/tests/base/test_PropMaps.py index ef22aaad..e012949f 100644 --- a/tests/base/test_PropMaps.py +++ b/tests/base/test_PropMaps.py @@ -1,6 +1,7 @@ import unittest from SimPEG import * from scipy.constants import mu_0 +from SimPEG import Tests class MyPropMap(Maps.PropMap): @@ -187,6 +188,34 @@ class TestPropMaps(unittest.TestCase): MyReciprocalPropMap([('sigma', iMap), ('mu', iMap)]) # This should be fine + def test_linked_derivs_sigma(self): + mesh = Mesh.TensorMesh([4,5], x0='CC') + + mapping = Maps.ExpMap(mesh) + propmap = MyReciprocalPropMap([('rho', mapping)]) + + x0 = np.random.rand(mesh.nC) + m = propmap(x0) + + # test Sigma + testme = lambda v: [1./(m.rhoMap*v), m.sigmaDeriv] + print 'Testing Rho from Sigma' + Tests.checkDerivative(testme, x0, dx=0.01*x0, num=5, plotIt=False) + + def test_linked_derivs_rho(self): + mesh = Mesh.TensorMesh([4,5], x0='CC') + + mapping = Maps.ExpMap(mesh) + propmap = MyReciprocalPropMap([('sigma', mapping)]) + + x0 = np.random.rand(mesh.nC) + m = propmap(x0) + + # test Sigma + testme = lambda v: [1./(m.sigmaMap*v), m.rhoDeriv] + print 'Testing Rho from Sigma' + Tests.checkDerivative(testme, x0, dx=0.01*x0, num=5, plotIt=False) + if __name__ == '__main__': unittest.main() From aa1086eba348840f64057f46dba0163baeb0c74c Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 26 May 2016 18:03:09 -0700 Subject: [PATCH 163/168] use fixed prop map in EM --- SimPEG/EM/Base.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/SimPEG/EM/Base.py b/SimPEG/EM/Base.py index e45cb33d..2a2ce363 100644 --- a/SimPEG/EM/Base.py +++ b/SimPEG/EM/Base.py @@ -169,9 +169,7 @@ class BaseEMProblem(Problem.BaseProblem): dMeSigmaI_dI = -self.MeSigmaI**2 dMe_dsig = self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) - dsig_dm = self.curModel.sigmaDeriv - return dMeSigmaI_dI * ( dMe_dsig * ( dsig_dm)) - # return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma, invMat=True)(u) + return dMeSigmaI_dI * ( dMe_dsig * self.curModel.sigmaDeriv ) @property def MfRho(self): @@ -187,8 +185,7 @@ class BaseEMProblem(Problem.BaseProblem): """ Derivative of :code:`MfRho` with respect to the model. """ - return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) - # self.curModel.rhoDeriv + return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * self.curModel.rhoDeriv @property def MfRhoI(self): @@ -208,9 +205,7 @@ class BaseEMProblem(Problem.BaseProblem): dMfRhoI_dI = -self.MfRhoI**2 dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) - return dMfRhoI_dI * ( dMf_drho * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv) ) - - # return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv + return dMfRhoI_dI * ( dMf_drho * self.curModel.rhoDeriv ) class BaseEMSurvey(Survey.BaseSurvey): From 022e1f7660dd0b20e44b00ebb919a0a2cf77b036 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 27 May 2016 13:11:31 -0700 Subject: [PATCH 164/168] Update IRLS directive to allow multiple GN iterations. Remove modifications to the ProjGN solver. Update IRLS example. --- SimPEG/Directives.py | 156 ++++++++++++++++-------------- SimPEG/Examples/Inversion_IRLS.py | 14 +-- SimPEG/Optimization.py | 72 +------------- SimPEG/Regularization.py | 38 ++++++-- 4 files changed, 121 insertions(+), 159 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index f5c25249..b84d78d1 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -144,34 +144,6 @@ class BetaSchedule(InversionDirective): if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter self.invProb.beta /= self.coolingFactor -#class BetaSchedule_PGN_CG(InversionDirective): -# """BetaSchedule""" -# -# coolingFactor = 5. -# coolingRate = 1 -# GN_step_last = None -# GN_step_c = None -# -# def endIter(self): -# -# """ Compute the change in GN step, and proceed with cooling if below tol""" -# if self.opt.iter == 1: -# self.GN_step_last = np.linalg.norm(self.opt.xc - self.opt.x_last) -# d_GN_step = 1. -# -# else: -# self.GN_step_c = np.linalg.norm(self.opt.xc - self.opt.x_last) -# d_GN_step = self.GN_step_c / self.GN_step_last -# -# # Re-initiate last GN step -# self.GN_step_last = self.GN_step_c -# -# print "GN_step_last: ", self.GN_step_last -# print "d_GN_step: ", d_GN_step -# -# if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: -# if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter -# self.invProb.beta /= self.coolingFactor class TargetMisfit(InversionDirective): @@ -286,10 +258,16 @@ class Update_IRLS(InversionDirective): gamma = None phi_m_last = None phi_d_last = None - - + f_old = None + f_min_change = 1e-1 + coolingRate = 3 + maxIRLSiter = 10 + + def initialize(self): - + + self.IRLSiter = 0 + # Scale the regularization for changes in norm if getattr(self, 'phi_m_last', None) is not None: @@ -310,48 +288,75 @@ class Update_IRLS(InversionDirective): self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - + if getattr(self, 'phi_d_last', None) is None: self.phi_d_last = self.invProb.phi_d + if getattr(self, 'f_last', None) is None: + self.f_old = self.invProb.evalFunction(self.reg.curModel, return_g=False, return_H=False) + print self.f_old def endIter(self): - # Cool the threshold parameter if required - if getattr(self, 'factor', None) is not None: - eps = self.reg.eps / self.factor + + + # Only update after GN iterations + if self.opt.iter % self.coolingRate == 0: + + self.IRLSiter += 1 - if getattr(self, 'eps_min', None) is not None: - self.reg.eps = np.max([self.eps_min,eps]) - else: - self.reg.eps = eps - - # Get phi_m at the end of current iteration - self.phi_m_last = self.invProb.phi_m_last - - # Reset the regularization matrices so that it is - # recalculated for current model - self.reg._Wsmall = None - self.reg._Wx = None - self.reg._Wy = None - self.reg._Wz = None - - # Update the model used for the IRLS weights - self.reg.curModel = self.invProb.curModel - - # Temporarely set gamma to 1. to get raw phi_m - self.reg.gamma = 1. - - # Compute new model objective function value - phim_new = self.reg.eval(self.invProb.curModel) - - # Update gamma to scale the regularization between IRLS iterations - self.reg.gamma = self.phi_m_last / phim_new - - # Reset the regularization matrices again for new gamma - self.reg._Wsmall = None - self.reg._Wx = None - self.reg._Wy = None - self.reg._Wz = None + self.f_change = np.abs(self.f_old - self.opt.f_last) / self.f_old + + print "Function decrease" + str(self.f_change) + + # Check for maximum number of IRLS cycles + if self.IRLSiter == self.maxIRLSiter: + self.opt.stopNextIteration = True + return + + # Check if the function has changed enough + if self.f_change < self.f_min_change: + self.opt.stopNextIteration = True + return + else: + self.f_old = self.opt.f_last + + # Cool the threshold parameter if required + 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 + + # Get phi_m at the end of current iteration + self.phi_m_last = self.invProb.phi_m_last + + # Reset the regularization matrices so that it is + # recalculated for current model + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None + + # Update the model used for the IRLS weights + self.reg.curModel = self.invProb.curModel + + # Temporarely set gamma to 1. to get raw phi_m + self.reg.gamma = 1. + + # Compute new model objective function value + phim_new = self.reg.eval(self.invProb.curModel) + + # Update gamma to scale the regularization between IRLS iterations + self.reg.gamma = self.phi_m_last / phim_new + + # Reset the regularization matrices again for new gamma + self.reg._Wsmall = None + self.reg._Wx = None + self.reg._Wy = None + self.reg._Wz = None + # Compute the change in class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem @@ -411,11 +416,14 @@ class Scale_Beta(InversionDirective): update is done only if the misfit is outside some threshold bounds. """ tol = 0.05 - + coolingRate=5 + def endIter(self): - - # Check if misfit is within the tolerance, otherwise adjust beta - val = self.invProb.phi_d / (self.survey.nD*0.5) - - if np.abs(1.-val) > self.tol: - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + + # Only update after GN iterations + if self.opt.iter % self.coolingRate == 0: + # Check if misfit is within the tolerance, otherwise adjust beta + val = self.invProb.phi_d / (self.survey.nD*0.5) + + if np.abs(1.-val) > self.tol: + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 6551bf21..d1da048f 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -20,7 +20,7 @@ def run(N=200, plotIt=True): m0 = np.ones(mesh.nC) * 1e-4 mref = np.zeros(mesh.nC) - nk = 10 + nk = 15 jk = np.linspace(1.,nk,nk) p = -2. q = 1. @@ -59,7 +59,7 @@ def run(N=200, plotIt=True): dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1./wd - opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, maxIterGN=1, tolCG = 1e-4) + opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) invProb.curModel = m0 @@ -83,18 +83,18 @@ def run(N=200, plotIt=True): reg.cell_weights = wr reg.mref = np.zeros(mesh.nC) - reg.eps_p = 5e-2 + reg.eps_p = 1e-3 reg.eps_q = 1e-2 reg.norms = [0., 0., 2., 2.] - opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) - #betaest = Directives.BetaEstimate_ByEig() + update_beta = Directives.Scale_Beta(tol = 0.05, coolingRate=5) 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, coolingRate=5 ) - inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) + inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS,update_beta]) m0 = mrec diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 95f53320..05214dd5 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -893,10 +893,6 @@ class ProjectedGNCG(BFGS, Minimize, Remember): lower = -np.inf upper = np.inf - # Variables to control inner GN iterations - rdm_tol = 1e-2 # Tolerance for largest change in step (Default 1%) - maxIterGN = 3 # Maximum number of GN inner iterations - def _startup(self, x0): # ensure bound vectors are the same size as the model if type(self.lower) is not np.ndarray: @@ -942,72 +938,6 @@ class ProjectedGNCG(BFGS, Minimize, Remember): def approxHinv(self, value): self._approxHinv = value - @Utils.timeIt - def minimize(self, evalFunction, x0): - """minimize(evalFunction, x0) - - Minimizes the function (evalFunction) starting at the location x0. - - :param def evalFunction: function handle that evaluates: f, g, H = F(x) - :param numpy.ndarray x0: starting location - :rtype: numpy.ndarray - :return: x, the last iterate of the optimization algorithm - - The GN newton steps are repeated until it the maxIterGN is reached or the - relative step change falls below some tolrerance. - - """ - self.evalFunction = evalFunction - self.startup(x0) - self.printInit() - - - while True: - self.doStartIteration() - self.f, self.g, self.H = evalFunction(self.xc, return_g=True, return_H=True) - self.printIter() - if self.stoppingCriteria(): break - - # Inner GN iterations, stop on maximum number of iterations - # or on tolerance for step length change - GN_count = 0 - dm0 = None # Initial GN step length - dmc = None # Current GN step length - rdm = 1. # Relative change in step length - - while rdm > self.rdm_tol and GN_count < self.maxIterGN: - - GN_count += 1 - self.searchDirection = self.findSearchDirection() - p = self.scaleSearchDirection(self.searchDirection) - xt, passLS = self.modifySearchDirection(p) - if not passLS: - xt, caught = self.modifySearchDirectionBreak(p) - if not caught: return self.xc - - if GN_count == 1: - dm0 = np.linalg.norm(self.xc - xt) - dmc = dm0 - - else: - dmc = np.linalg.norm(self.xc - xt) - - rdm = dmc / dm0 - self.xc = xt # Update current model - - # Form system for next iteration - self.f, self.g, self.H = evalFunction(self.xc, return_g=True, return_H=True) - - print "GN iter: %i,\t dm: %8.5e,\t rdm: %8.5e"% (GN_count, dmc, rdm) - - self.doEndIteration(xt) - if self.stopNextIteration: break - - self.printDone() - self.finish() - - return self.xc - @Utils.timeIt def findSearchDirection(self): @@ -1078,4 +1008,4 @@ class ProjectedGNCG(BFGS, Minimize, Remember): indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0)) delx[indx] = 0. - return delx + return delx \ No newline at end of file diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 422c8f9c..c3b1c9e5 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -890,14 +890,37 @@ class Tikhonov(Simple): class Sparse(Simple): - + """ + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top R^\\top R W(m-m_\\text{ref})} + + where the IRLS weight + + .. math:: + + R = \eta TO FINISH LATER!!! + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top R^\\top R W (m-m_\\text{ref})} + + The IRLS weights are recomputed after each beta solves. + It is strongly recommended to do a few Gauss-Newton iterations + before updating. + """ + # set default values - eps_p = 1e-1 - eps_q = 1e-1 - curModel = None # use a model to compute the weights - gamma = 1. - norms = [0., 2., 2., 2.] - cell_weights = 1. + eps_p = 1e-1 # Threshold value for the model norm + eps_q = 1e-1 # Threshold value for the model gradient norm + curModel = None # Requires model to compute the weights + gamma = 1. # Model norm scaling to smooth out convergence + norms = [0., 2., 2., 2.] # Values for norm on (m, dmdx, dmdy, dmdz) + cell_weights = 1. # Consider overwriting with sensitivity weights def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @@ -971,6 +994,7 @@ class Sparse(Simple): def R(self, f_m , eps, exponent): + # Eta scaling is important for mix-norms...do not mess with it eta = (eps**(1.-exponent/2.))**0.5 r = eta / (f_m**2.+ eps**2.)**((1.-exponent/2.)/2.) From 3b4bec9c0b40b0ce949cea8422adef1f29b81bb7 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sat, 28 May 2016 11:27:09 -0700 Subject: [PATCH 165/168] Refactor IRLS iterations, full solves from l2->lp Adapt Example --- SimPEG/Directives.py | 206 ++++++++++++++++++------------ SimPEG/Examples/Inversion_IRLS.py | 66 +++++----- SimPEG/Regularization.py | 1 + 3 files changed, 158 insertions(+), 115 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index b84d78d1..8727d925 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -144,7 +144,7 @@ class BetaSchedule(InversionDirective): if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter self.invProb.beta /= self.coolingFactor - + class TargetMisfit(InversionDirective): @property @@ -238,12 +238,6 @@ 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 UpdateReferenceModel(Parameter): - -# mref0 = None - -# def nextIter(self): # mref = getattr(self, 'm_prev', None) # if mref is None: # if self.debug: print 'UpdateReferenceModel is using mref0' @@ -254,109 +248,165 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): class Update_IRLS(InversionDirective): eps_min = None + eps_p = None + eps_q = None + norms = [2.,2.,2.,2.] factor = None gamma = None phi_m_last = None phi_d_last = None f_old = None - f_min_change = 1e-1 - coolingRate = 3 - maxIRLSiter = 10 - + f_min_change = 1e-2 + beta_tol = 5e-2 + # Solving parameter for IRLS (mode:2) + IRLSiter = 0 + minGNiter = 6 + maxIRLSiter = 10 + iterStart = 0 + + # Beta schedule + coolingFactor = 2. + coolingRate = 1 + + mode = 1 + + @property + def target(self): + if getattr(self, '_target', None) is None: + self._target = self.survey.nD + return self._target + @target.setter + def target(self, val): + self._target = val + def initialize(self): - - self.IRLSiter = 0 - - # 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._Wsmall = None - self.reg._Wx = None - self.reg._Wy = None - self.reg._Wz = None - self.reg.gamma = 1. - phim_new = self.reg.eval(self.invProb.curModel) - self.gamma = self.phi_m_last / phim_new + if self.mode == 1: + self.reg.norms = [2., 2., 2., 2.] +# # 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._Wsmall = None +# self.reg._Wx = None +# self.reg._Wy = None +# self.reg._Wz = None +# self.reg.gamma = 1. +# 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 +# # Reset the regularization matrices so that it is +# # recalculated with new gamma +# self.reg._Wsmall = None +# self.reg._Wx = None +# self.reg._Wy = None +# self.reg._Wz = None - self.reg.curModel = self.invProb.curModel - self.reg.gamma = self.gamma - # Reset the regularization matrices so that it is - # recalculated with new gamma - self.reg._Wsmall = None - self.reg._Wx = None - self.reg._Wy = None - self.reg._Wz = None - - if getattr(self, 'phi_d_last', None) is None: - self.phi_d_last = self.invProb.phi_d - - if getattr(self, 'f_last', None) is None: - self.f_old = self.invProb.evalFunction(self.reg.curModel, return_g=False, return_H=False) - print self.f_old - def endIter(self): - - - # Only update after GN iterations - if self.opt.iter % self.coolingRate == 0: +# if getattr(self, 'phi_d_last', None) is None: +# self.phi_d_last = self.invProb.phi_d +# +# if getattr(self, 'f_last', None) is None: +# self.f_old = self.invProb.evalFunction(self.reg.curModel, return_g=False, return_H=False) +# print self.f_old + def endIter(self): + + # After reaching target misfit with l2-norm, switch to IRLS (mode:2) + if self.invProb.phi_d < self.target and self.mode == 1: + print "Convergence with smooth l2-norm regularization: Start IRLS steps..." + + self.mode = 2 + print self.eps_p, self.eps_q, self.norms + self.reg.eps_p = self.eps_p + self.reg.eps_q = self.eps_q + self.reg.norms = self.norms + self.coolingFactor = 1. + self.coolingRate = 1 + self.iterStart = self.opt.iter + self.phi_d_last = self.invProb.phi_d + self.phi_m_last = self.invProb.phi_m_last + + self.reg.l2model = self.invProb.curModel + self.reg.curModel = self.invProb.curModel + + if getattr(self, 'f_old', None) is None: + self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False) + + if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: + if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter + self.invProb.beta /= self.coolingFactor + + + # Only update after GN iterations + if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2: + self.IRLSiter += 1 - self.f_change = np.abs(self.f_old - self.opt.f_last) / self.f_old - - print "Function decrease" + str(self.f_change) - + phim_new = self.reg.eval(self.invProb.curModel) + self.f_change = np.abs(self.f_old - phim_new) / self.f_old + + print "Regularization decrease: %6.3e" % (self.f_change) + # Check for maximum number of IRLS cycles if self.IRLSiter == self.maxIRLSiter: + print "Reach maximum number of IRLS cycles: %i" % self.maxIRLSiter self.opt.stopNextIteration = True return - + # Check if the function has changed enough - if self.f_change < self.f_min_change: + if self.f_change < self.f_min_change and self.IRLSiter > 1: + print "Minimum decrease in regularization. End of IRLS" self.opt.stopNextIteration = True - return - else: - self.f_old = self.opt.f_last - + return + else: + self.f_old = phim_new + # Cool the threshold parameter if required 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 - + # Get phi_m at the end of current iteration self.phi_m_last = self.invProb.phi_m_last - + # Reset the regularization matrices so that it is # recalculated for current model self.reg._Wsmall = None self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - + # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - + # Temporarely set gamma to 1. to get raw phi_m self.reg.gamma = 1. - + # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) - + # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - + # Reset the regularization matrices again for new gamma self.reg._Wsmall = None self.reg._Wx = None self.reg._Wy = None self.reg._Wz = None - # Compute the change in + # Check if misfit is within the tolerance, otherwise adjust beta + val = self.invProb.phi_d / (self.survey.nD*0.5) + + if np.abs(1.-val) > self.beta_tol: + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem @@ -409,21 +459,15 @@ class Update_Wj(InversionDirective): self.reg.wght = JtJdiag -class Scale_Beta(InversionDirective): - """ - Instead of a linear cooling schedule, beta is allowed to change based - on the ratio between the target misfit and the current data misfit. The - update is done only if the misfit is outside some threshold bounds. - """ - tol = 0.05 - coolingRate=5 - - def endIter(self): - - # Only update after GN iterations - if self.opt.iter % self.coolingRate == 0: - # Check if misfit is within the tolerance, otherwise adjust beta - val = self.invProb.phi_d / (self.survey.nD*0.5) - - if np.abs(1.-val) > self.tol: - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d +#class Scale_Beta(InversionDirective): +# """ +# Instead of a linear cooling schedule, beta is allowed to change based +# on the ratio between the target misfit and the current data misfit. The +# update is done only if the misfit is outside some threshold bounds. +# """ +# tol = 0.05 +# coolingRate=5 +# +# def endIter(self): +# +# diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index d1da048f..5c1a8770 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -52,51 +52,49 @@ def run(N=200, plotIt=True): wr = np.sum(prob.G**2.,axis=0)**0.5 wr = ( wr/np.max(wr) ) - reg = Regularization.Simple(mesh) - reg.mref = mref - reg.cell_weights = wr - +# reg = Regularization.Simple(mesh) +# reg.mref = mref +# reg.cell_weights = wr +# dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1./wd - - opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4) - invProb = InvProblem.BaseInvProblem(dmis, reg, opt) - invProb.curModel = m0 - - beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) - target = Directives.TargetMisfit() - +# +# opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4) +# invProb = InvProblem.BaseInvProblem(dmis, reg, opt) +# invProb.curModel = m0 +# +# beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) +# target = Directives.TargetMisfit() +# betaest = Directives.BetaEstimate_ByEig() - inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) - - - mrec = inv.run(m0) - ml2 = mrec - print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) - - # Switch regularization to sparse - phim = invProb.phi_m_last - phid = invProb.phi_d +# inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) +# +# +# mrec = inv.run(m0) +# ml2 = mrec +# print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) +# +# # Switch regularization to sparse +# phim = invProb.phi_m_last +# phid = invProb.phi_d reg = Regularization.Sparse(mesh) reg.mref = mref reg.cell_weights = wr reg.mref = np.zeros(mesh.nC) - reg.eps_p = 1e-3 - reg.eps_q = 1e-2 - reg.norms = [0., 0., 2., 2.] + eps_p = 1e-3 + eps_q = 1e-2 + norms = [0., 0., 2., 2.] opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) - invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) - beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) - update_beta = Directives.Scale_Beta(tol = 0.05, coolingRate=5) - target = Directives.TargetMisfit() - IRLS = Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid, coolingRate=5 ) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt) + #beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) + #update_beta = Directives.Scale_Beta(tol = 0.05, coolingRate=5) +# target = Directives.TargetMisfit() + IRLS = Directives.Update_IRLS( norms=norms, eps_p=eps_p, eps_q=eps_q) - inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS,update_beta]) - - m0 = mrec + inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest]) # Run inversion mrec = inv.run(m0) @@ -113,7 +111,7 @@ def run(N=200, plotIt=True): axes[0].set_title('Columns of matrix G') axes[1].plot(mesh.vectorCCx, mtrue, 'b-') - axes[1].plot(mesh.vectorCCx, ml2, 'r-') + axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-') #axes[1].legend(('True Model', 'Recovered Model')) axes[1].set_ylim(-1.0,1.25) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index c3b1c9e5..3304022a 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -918,6 +918,7 @@ class Sparse(Simple): eps_p = 1e-1 # Threshold value for the model norm eps_q = 1e-1 # Threshold value for the model gradient norm curModel = None # Requires model to compute the weights + l2model = None gamma = 1. # Model norm scaling to smooth out convergence norms = [0., 2., 2., 2.] # Values for norm on (m, dmdx, dmdy, dmdz) cell_weights = 1. # Consider overwriting with sensitivity weights From 825511e9d3756db1cd92985b31a43f1d18c681b1 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Sun, 29 May 2016 13:17:22 -0700 Subject: [PATCH 166/168] Add a curvilinear plotImage function, update example. --- SimPEG/Examples/Forward_BasicDirectCurrent.py | 33 +---- SimPEG/Mesh/CurvilinearMesh.py | 99 +-------------- SimPEG/Mesh/View.py | 118 ++++++++++++------ 3 files changed, 84 insertions(+), 166 deletions(-) diff --git a/SimPEG/Examples/Forward_BasicDirectCurrent.py b/SimPEG/Examples/Forward_BasicDirectCurrent.py index efbb287c..30cf0ed1 100644 --- a/SimPEG/Examples/Forward_BasicDirectCurrent.py +++ b/SimPEG/Examples/Forward_BasicDirectCurrent.py @@ -5,18 +5,15 @@ from SimPEG import Mesh, Utils, np, SolverLU def run(plotIt=True): # Step1: Generate Tensor and Curvilinear Mesh sz = [40,40] - # Tensor Mesh tM = Mesh.TensorMesh(sz) - # Curvilinear Mesh rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate')) + # Step2: Direct Current (DC) operator def DCfun(mesh, pts): D = mesh.faceDiv - G = D.T sigma = 1e-2*np.ones(mesh.nC) - Msigi = mesh.getFaceInnerProduct(1./sigma) - MsigI = Utils.sdInv(Msigi) - A = D*MsigI*G + MsigI = mesh.getFaceInnerProduct(sigma, invProp=True, invMat=True) + A = -D*MsigI*D.T A[-1,-1] /= mesh.vol[-1] # Remove null space rhs = np.zeros(mesh.nC) txind = Utils.meshutils.closestPoints(mesh, pts) @@ -37,39 +34,17 @@ def run(plotIt=True): if not plotIt: return import matplotlib.pyplot as plt - import matplotlib - from matplotlib.mlab import griddata #Step4: Making Figure fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) - label = ["(a)", "(b)"] - opts = {} vmin, vmax = phitM.min(), phitM.max() dat = tM.plotImage(phitM, ax=axes[0], clim=(vmin, vmax), grid=True) - - #TODO: At the moment Curvilinear Mesh do not have plotimage - - Xi = tM.gridCC[:,0].reshape(sz[0], sz[1], order='F') - Yi = tM.gridCC[:,1].reshape(sz[0], sz[1], order='F') - PHIrM = griddata(rM.gridCC[:,0], rM.gridCC[:,1], phirM, Xi, Yi, interp='linear') - axes[1].contourf(Xi, Yi, PHIrM, 100, vmin=vmin, vmax=vmax) - + dat = rM.plotImage(phirM, ax=axes[1], clim=(vmin, vmax), grid=True) cb = plt.colorbar(dat[0], ax=axes[0]); cb.set_label("Voltage (V)") cb = plt.colorbar(dat[0], ax=axes[1]); cb.set_label("Voltage (V)") - tM.plotGrid(ax=axes[0], **opts) axes[0].set_title('TensorMesh') - rM.plotGrid(ax=axes[1], **opts) axes[1].set_title('CurvilinearMesh') - for i in range(2): - axes[i].set_xlim(0.025, 0.975) - axes[i].set_ylim(0.025, 0.975) - axes[i].text(0., 1.0, label[i], fontsize=20) - if i==0: - axes[i].set_ylabel("y") - else: - axes[i].set_ylabel(" ") - axes[i].set_xlabel("x") plt.show() diff --git a/SimPEG/Mesh/CurvilinearMesh.py b/SimPEG/Mesh/CurvilinearMesh.py index f8b0bcd2..abc9ff3a 100644 --- a/SimPEG/Mesh/CurvilinearMesh.py +++ b/SimPEG/Mesh/CurvilinearMesh.py @@ -2,6 +2,7 @@ from SimPEG import Utils, np from BaseMesh import BaseRectangularMesh from DiffOperators import DiffOperators from InnerProducts import InnerProducts +from View import CurvView # Some helper functions. length2D = lambda x: (x[:, 0]**2 + x[:, 1]**2)**0.5 @@ -10,7 +11,7 @@ normalize2D = lambda x: x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2)) normalize3D = lambda x: x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2)) -class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts): +class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts, CurvView): """ CurvilinearMesh is a mesh class that deals with curvilinear meshes. @@ -330,102 +331,6 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts): - ############################################# - # Plotting Functions # - ############################################# - - def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False): - """Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions. - - - .. plot:: - :include-source: - - from SimPEG import Mesh, Utils - X, Y = Utils.exampleLrmGrid([3,3],'rotate') - M = Mesh.CurvilinearMesh([X, Y]) - M.plotGrid(showIt=True) - - """ - import matplotlib.pyplot as plt - import matplotlib - from mpl_toolkits.mplot3d import Axes3D - mkvc = Utils.mkvc - - axOpts = {'projection':'3d'} if self.dim == 3 else {} - if ax is None: ax = plt.subplot(111, **axOpts) - - NN = self.r(self.gridN, 'N', 'N', 'M') - if self.dim == 2: - - if lines: - X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten() - Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten() - - X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten() - Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten() - - X = np.r_[X1, X2] - Y = np.r_[Y1, Y2] - - ax.plot(X, Y, 'b-') - if centers: - ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro') - - # Nx = self.r(self.normals, 'F', 'Fx', 'V') - # Ny = self.r(self.normals, 'F', 'Fy', 'V') - # Tx = self.r(self.tangents, 'E', 'Ex', 'V') - # Ty = self.r(self.tangents, 'E', 'Ey', 'V') - - # ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo') - - # nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten() - # nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten() - # ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs') - # ax.plot(nX, nY, 'r-') - - # nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten() - # nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten() - # #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs') - # ax.plot(nX, nY, 'g-') - - # tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten() - # tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten() - # ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^') - # ax.plot(tX, tY, 'r-') - - # nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten() - # nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten() - # #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^') - # ax.plot(nX, nY, 'g-') - - elif self.dim == 3: - X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten() - Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten() - Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten() - - X2 = np.c_[mkvc(NN[0][:, :-1, :]), mkvc(NN[0][:, 1:, :]), mkvc(NN[0][:, :-1, :])*np.nan].flatten() - Y2 = np.c_[mkvc(NN[1][:, :-1, :]), mkvc(NN[1][:, 1:, :]), mkvc(NN[1][:, :-1, :])*np.nan].flatten() - Z2 = np.c_[mkvc(NN[2][:, :-1, :]), mkvc(NN[2][:, 1:, :]), mkvc(NN[2][:, :-1, :])*np.nan].flatten() - - X3 = np.c_[mkvc(NN[0][:, :, :-1]), mkvc(NN[0][:, :, 1:]), mkvc(NN[0][:, :, :-1])*np.nan].flatten() - Y3 = np.c_[mkvc(NN[1][:, :, :-1]), mkvc(NN[1][:, :, 1:]), mkvc(NN[1][:, :, :-1])*np.nan].flatten() - Z3 = np.c_[mkvc(NN[2][:, :, :-1]), mkvc(NN[2][:, :, 1:]), mkvc(NN[2][:, :, :-1])*np.nan].flatten() - - X = np.r_[X1, X2, X3] - Y = np.r_[Y1, Y2, Y3] - Z = np.r_[Z1, Z2, Z3] - - ax.plot(X, Y, 'b', zs=Z) - ax.set_zlabel('x3') - - ax.grid(True) - ax.set_xlabel('x1') - ax.set_ylabel('x2') - - if showIt: plt.show() - - if __name__ == '__main__': nc = 5 h1 = np.cumsum(np.r_[0, np.ones(nc)/(nc)]) diff --git a/SimPEG/Mesh/View.py b/SimPEG/Mesh/View.py index 8eb22098..72225040 100644 --- a/SimPEG/Mesh/View.py +++ b/SimPEG/Mesh/View.py @@ -552,7 +552,8 @@ class CurvView(object): def __init__(self): pass - def plotGrid(self, length=0.05, showIt=False): + + def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False): """Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions. @@ -560,60 +561,63 @@ class CurvView(object): :include-source: from SimPEG import Mesh, Utils - X, Y = Utils.exampleCurvGird([3,3],'rotate') + X, Y = Utils.exampleLrmGrid([3,3],'rotate') M = Mesh.CurvilinearMesh([X, Y]) M.plotGrid(showIt=True) """ + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + + axOpts = {'projection':'3d'} if self.dim == 3 else {} + if ax is None: ax = plt.subplot(111, **axOpts) + NN = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: - fig = plt.figure(2) - fig.clf() - ax = plt.subplot(111) - X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten() - Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten() - X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten() - Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten() + if lines: + X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten() + Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten() - X = np.r_[X1, X2] - Y = np.r_[Y1, Y2] + X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten() + Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten() - plt.plot(X, Y) + X = np.r_[X1, X2] + Y = np.r_[Y1, Y2] - plt.hold(True) - Nx = self.r(self.normals, 'F', 'Fx', 'V') - Ny = self.r(self.normals, 'F', 'Fy', 'V') - Tx = self.r(self.tangents, 'E', 'Ex', 'V') - Ty = self.r(self.tangents, 'E', 'Ey', 'V') + ax.plot(X, Y, 'b-') + if centers: + ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro') - plt.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo') + # Nx = self.r(self.normals, 'F', 'Fx', 'V') + # Ny = self.r(self.normals, 'F', 'Fy', 'V') + # Tx = self.r(self.tangents, 'E', 'Ex', 'V') + # Ty = self.r(self.tangents, 'E', 'Ey', 'V') - nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten() - nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten() - plt.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs') - plt.plot(nX, nY, 'r-') + # ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo') - nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten() - nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten() - #plt.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs') - plt.plot(nX, nY, 'g-') + # nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten() + # nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten() + # ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs') + # ax.plot(nX, nY, 'r-') - tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten() - tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten() - plt.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^') - plt.plot(tX, tY, 'r-') + # nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten() + # nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten() + # #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs') + # ax.plot(nX, nY, 'g-') - nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten() - nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten() - #plt.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^') - plt.plot(nX, nY, 'g-') - plt.axis('equal') + # tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten() + # tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten() + # ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^') + # ax.plot(tX, tY, 'r-') + + # nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten() + # nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten() + # #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^') + # ax.plot(nX, nY, 'g-') elif self.dim == 3: - fig = plt.figure(3) - fig.clf() - ax = fig.add_subplot(111, projection='3d') X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten() Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten() Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten() @@ -630,16 +634,50 @@ class CurvView(object): Y = np.r_[Y1, Y2, Y3] Z = np.r_[Z1, Z2, Z3] - plt.plot(X, Y, 'b', zs=Z) + ax.plot(X, Y, 'b', zs=Z) ax.set_zlabel('x3') ax.grid(True) - ax.hold(False) ax.set_xlabel('x1') ax.set_ylabel('x2') if showIt: plt.show() + def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None): + if self.dim == 3: raise NotImplementedError('This is not yet done!') + + import matplotlib.pyplot as plt + import matplotlib + from mpl_toolkits.mplot3d import Axes3D + import matplotlib.colors as colors + import matplotlib.cm as cmx + + if ax is None: ax = plt.subplot(111) + jet = cm = plt.get_cmap('jet') + cNorm = colors.Normalize( + vmin=I.min() if clim is None else clim[0], + vmax=I.max() if clim is None else clim[1]) + + scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet) + # ax.set_xlim((self.x0[0], self.h[0].sum())) + # ax.set_ylim((self.x0[1], self.h[1].sum())) + + Nx = self.r(self.gridN[:,0],'N','N','M') + Ny = self.r(self.gridN[:,1],'N','N','M') + cell = self.r(I,'CC','CC','M') + + for ii in range(self.nCx): + for jj in range(self.nCy): + I = [ii,ii+1,ii+1,ii] + J = [jj,jj,jj+1,jj+1] + ax.add_patch(plt.Polygon(np.c_[Nx[I,J],Ny[I,J]], facecolor=scalarMap.to_rgba(cell[ii,jj]), edgecolor='k' if grid else 'none')) + + scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots + ax.set_xlabel('x') + ax.set_ylabel('y') + if showIt: plt.show() + return [scalarMap] + if __name__ == '__main__': from SimPEG import * From e476bf0059b3c6f8e75665bffa1e699b586919a1 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sun, 29 May 2016 14:09:29 -0700 Subject: [PATCH 167/168] Cleanup Sparse Reg and Directives --- SimPEG/Directives.py | 71 +++++++------------------------ SimPEG/Examples/Inversion_IRLS.py | 16 +++---- 2 files changed, 23 insertions(+), 64 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 8727d925..98770666 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -258,66 +258,39 @@ class Update_IRLS(InversionDirective): f_old = None f_min_change = 1e-2 beta_tol = 5e-2 - + # Solving parameter for IRLS (mode:2) IRLSiter = 0 - minGNiter = 6 + minGNiter = 5 maxIRLSiter = 10 iterStart = 0 - + # Beta schedule coolingFactor = 2. coolingRate = 1 - + mode = 1 - + @property def target(self): if getattr(self, '_target', None) is None: - self._target = self.survey.nD + self._target = self.survey.nD*0.5 return self._target @target.setter def target(self, val): self._target = val - + def initialize(self): if self.mode == 1: self.reg.norms = [2., 2., 2., 2.] -# # 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._Wsmall = None -# self.reg._Wx = None -# self.reg._Wy = None -# self.reg._Wz = None -# self.reg.gamma = 1. -# 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 -# # Reset the regularization matrices so that it is -# # recalculated with new gamma -# self.reg._Wsmall = None -# self.reg._Wx = None -# self.reg._Wy = None -# self.reg._Wz = None -# if getattr(self, 'phi_d_last', None) is None: -# self.phi_d_last = self.invProb.phi_d -# -# if getattr(self, 'f_last', None) is None: -# self.f_old = self.invProb.evalFunction(self.reg.curModel, return_g=False, return_H=False) -# print self.f_old - def endIter(self): # After reaching target misfit with l2-norm, switch to IRLS (mode:2) if self.invProb.phi_d < self.target and self.mode == 1: print "Convergence with smooth l2-norm regularization: Start IRLS steps..." - + self.mode = 2 print self.eps_p, self.eps_q, self.norms self.reg.eps_p = self.eps_p @@ -328,17 +301,18 @@ class Update_IRLS(InversionDirective): self.iterStart = self.opt.iter self.phi_d_last = self.invProb.phi_d self.phi_m_last = self.invProb.phi_m_last - + self.reg.l2model = self.invProb.curModel self.reg.curModel = self.invProb.curModel - + if getattr(self, 'f_old', None) is None: self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False) - + + # Beta Schedule if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter self.invProb.beta /= self.coolingFactor - + # Only update after GN iterations if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2: @@ -401,12 +375,12 @@ class Update_IRLS(InversionDirective): self.reg._Wy = None self.reg._Wz = None - # Check if misfit is within the tolerance, otherwise adjust beta + # Check if misfit is within the tolerance, otherwise scale beta val = self.invProb.phi_d / (self.survey.nD*0.5) - + if np.abs(1.-val) > self.beta_tol: self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d - + class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem @@ -458,16 +432,3 @@ class Update_Wj(InversionDirective): JtJdiag = JtJdiag / max(JtJdiag) self.reg.wght = JtJdiag - -#class Scale_Beta(InversionDirective): -# """ -# Instead of a linear cooling schedule, beta is allowed to change based -# on the ratio between the target misfit and the current data misfit. The -# update is done only if the misfit is outside some threshold bounds. -# """ -# tol = 0.05 -# coolingRate=5 -# -# def endIter(self): -# -# diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 5c1a8770..afd90525 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -1,7 +1,7 @@ from SimPEG import * -def run(N=200, plotIt=True): +def run(N=100, plotIt=True): """ Inversion: Linear Problem ========================= @@ -19,8 +19,8 @@ def run(N=200, plotIt=True): m0 = np.ones(mesh.nC) * 1e-4 mref = np.zeros(mesh.nC) - - nk = 15 + + nk = 10 jk = np.linspace(1.,nk,nk) p = -2. q = 1. @@ -83,18 +83,16 @@ def run(N=200, plotIt=True): reg.cell_weights = wr reg.mref = np.zeros(mesh.nC) - eps_p = 1e-3 - eps_q = 1e-2 + eps_p = 5e-2 + eps_q = 5e-2 norms = [0., 0., 2., 2.] opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) - #beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) - #update_beta = Directives.Scale_Beta(tol = 0.05, coolingRate=5) -# target = Directives.TargetMisfit() + update_Jacobi = Directives.Update_lin_PreCond() IRLS = Directives.Update_IRLS( norms=norms, eps_p=eps_p, eps_q=eps_q) - inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest]) + inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi]) # Run inversion mrec = inv.run(m0) From 62eb4541cbdb086023870a1df0564a74498dafe2 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 29 May 2016 15:48:15 -0700 Subject: [PATCH 168/168] update example name --> based on mesh --- ...sicDirectCurrent.py => Mesh_Basic_ForwardDC.py} | 10 ++++++++-- SimPEG/Examples/__init__.py | 4 ++-- ...cDirectCurrent.rst => Mesh_Basic_ForwardDC.rst} | 14 +++++++++----- 3 files changed, 19 insertions(+), 9 deletions(-) rename SimPEG/Examples/{Forward_BasicDirectCurrent.py => Mesh_Basic_ForwardDC.py} (89%) rename docs/examples/{Forward_BasicDirectCurrent.rst => Mesh_Basic_ForwardDC.rst} (55%) diff --git a/SimPEG/Examples/Forward_BasicDirectCurrent.py b/SimPEG/Examples/Mesh_Basic_ForwardDC.py similarity index 89% rename from SimPEG/Examples/Forward_BasicDirectCurrent.py rename to SimPEG/Examples/Mesh_Basic_ForwardDC.py index 30cf0ed1..bd4ea18a 100644 --- a/SimPEG/Examples/Forward_BasicDirectCurrent.py +++ b/SimPEG/Examples/Mesh_Basic_ForwardDC.py @@ -1,8 +1,14 @@ from SimPEG import Mesh, Utils, np, SolverLU -## 2D DC forward modeling example with Tensor and Curvilinear Meshes - def run(plotIt=True): + + """ + Mesh: Basic Forward 2D DC Resistivity + ===================================== + + 2D DC forward modeling example with Tensor and Curvilinear Meshes + """ + # Step1: Generate Tensor and Curvilinear Mesh sz = [40,40] tM = Mesh.TensorMesh(sz) diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index c67652a2..c592e454 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -8,9 +8,9 @@ import EM_FDEM_Analytic_MagDipoleWholespace import EM_Schenkel_Morrison_Casing import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 -import Forward_BasicDirectCurrent import Inversion_IRLS import Inversion_Linear +import Mesh_Basic_ForwardDC import Mesh_Basic_PlotImage import Mesh_Basic_Types import Mesh_Operators_CahnHilliard @@ -21,7 +21,7 @@ import Mesh_Tensor_Creation import MT_1D_ForwardAndInversion import 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"] +__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", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_ForwardDC", "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/Forward_BasicDirectCurrent.rst b/docs/examples/Mesh_Basic_ForwardDC.rst similarity index 55% rename from docs/examples/Forward_BasicDirectCurrent.rst rename to docs/examples/Mesh_Basic_ForwardDC.rst index 20b39eb8..df18050e 100644 --- a/docs/examples/Forward_BasicDirectCurrent.rst +++ b/docs/examples/Mesh_Basic_ForwardDC.rst @@ -1,4 +1,4 @@ -.. _examples_Forward_BasicDirectCurrent: +.. _examples_Mesh_Basic_ForwardDC: .. --------------------------------- .. .. .. @@ -8,14 +8,18 @@ .. .. .. --------------------------------- .. -Forward BasicDirectCurrent -========================== + +Mesh: Basic Forward 2D DC Resistivity +===================================== + +2D DC forward modeling example with Tensor and Curvilinear Meshes + .. plot:: from SimPEG import Examples - Examples.Forward_BasicDirectCurrent.run() + Examples.Mesh_Basic_ForwardDC.run() -.. literalinclude:: ../../SimPEG/Examples/Forward_BasicDirectCurrent.py +.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_ForwardDC.py :language: python :linenos: