In [27]:
from SimPEG import * 
%matplotlib inline
import matplotlib.pyplot as plt

DC Resistivity Simulations

DC resistivity is a zero-frequency electromagnetic problem. A DC resistivity geophysical survey is sensitive to variations in electrical conductivity. To conduct a DC resistivity survey, we use a source source electrode to inject a current into the subsurface and sink to pick up that current.

The governing equation is:

$$ \nabla \cdot \sigma \nabla \phi = -s $$

where $\sigma$ is the electrical conductivity (S/m) which varies depending on the subsurface materials, $\phi$ is the electric potential (V), and $s$ is the source term, which captures the impact of both the source and sink.

Set up a Mesh

We will solve the DC problem using a finite volume simulation, which requires that we set up a mesh on which to compute. For this example, we use a 2D mesh, but this can be expanded to 3D using mesh = Mesh.TensorMesh([nx,ny,nz]).

We use the SimPEG package (http://simpeg.xyz/) to perform the simulation.


In [28]:
# Define a unit square domain 
# This can be hidden and imported depending on how much you want to show

nx,ny = 60,60 # number of cells in x,y
mesh = Mesh.TensorMesh([nx,ny]) # build a tensor mesh
sigma = np.ones(mesh.nC) # assign a conductivity model

# create source
xp, yp = 0.25, 0.5
xn, yn = 0.75, 0.5
sigmaback = 1.
s = sigmaback*np.zeros(mesh.nC)
indp = Utils.closestPoints(mesh,np.r_[xp,yp],'CC')
indn = Utils.closestPoints(mesh,np.r_[xn,yn],'CC')
s[indp] = 1.
s[indn] = -1

# conductive block
sigmabl = 100.
p0 = np.r_[0.4,0.4]
p1 = np.r_[0.6,0.6]

In [29]:
# Build differential operators using the SimPEG mesh class
# This can be hidden and imported depending on how much you want to expose

def getOperators(mesh,sigma):
    Div = mesh.faceDiv
    Sigma = Utils.sdiag(1/(mesh.aveF2CC.T * (1/sigma)))
    Grad = mesh.cellGrad
    return Div, Sigma, Grad

def getA(mesh,sigma): 
    Div, Sigma, Grad = getOperators(mesh,sigma)
    return Div * Sigma * Grad

DC Resistivity

$ \nabla \cdot \sigma \nabla \phi = -s $

Here we set up and solve the DC resistivity problem


In [30]:
# Construct A Matrix
Div, Sigma, Grad = getOperators(mesh,sigma)
A = Div * Sigma * Grad # looks like the equation!
Ainv = Solver(A)

In [31]:
phi = Ainv * -s # solve

In [32]:
mesh.plotImage(phi)
plt.title('Electric Potential, $\phi$')


Out[32]:
<matplotlib.text.Text at 0x1072cded0>

Wrap this up


In [33]:
# this can be hidden and imported 
def SolveDC(xp,yp,xn,yn,mesh,sigma):
    
    # set up the source
    s = np.zeros(mesh.nC)
    indp = Utils.closestPoints(mesh,np.r_[xp,yp],'CC')
    indn = Utils.closestPoints(mesh,np.r_[xn,yn],'CC')
    s[indp] = 1.
    s[indn] = -1.
    
    # get A
    A = getA(mesh,sigma)
    A[0,0] *= 1/mesh.vol[0] # correct for the null space
    Ainv = Solver(A)
    
    # solve
    phi = Ainv * -s
    phi -= phi[-1]

    return phi 

def plotPhi(phi):
    mesh.plotImage(phi)
    plt.title('Electric Potential, $\phi$')
    plt.show()

Lets Explore using Interact

Move the source

The model has a uniform background conductivity:

  • sigma = 1 S/m

We excite the system using a source which has positive and negative electrodes (ie. a current source and a current). We will plot the electric potential; when a DC resistivity survey is conducted, the data are potential differences, measured in units of volts.

The parameters you can explore here are:

  • xp: x-position of the positive electrode
  • yp: y-position of the positive electrode
  • xn: x-position of the negative electrode
  • yn: y-position of the negative electrode

In [34]:
from IPython.html.widgets import interact

interact(lambda xp,yp,xn,yn: plotPhi(SolveDC(xp,yp,xn,yn,mesh,sigma)), xp=[0.1,0.8,0.05],yp=[0.1,0.9,0.05],xn=[0.2,0.9,0.05],yn=[0.1,0.9,0.05])


Add a Conductive Block


In [35]:
def CondBlock(xp,yp,xn,yn,mesh,sigma,sigmabl,p0,p1):  
    sigmaBl = Utils.ModelBuilder.defineBlock(mesh.gridCC, p0, p1, np.r_[sigmabl,sigmaback])
    return SolveDC(xp,yp,xn,yn,mesh,sigmaBl)

What happens if we add a conductive block?

A conductive block with a conductivity of 100 S/m in the 1 S/m background. If you move the positive and negative electrodes around, can you find it? How big is it?


In [36]:
interact(lambda xp,yp,xn,yn: plotPhi(CondBlock(xp,yp,xn,yn,mesh,sigma,sigmabl,p0,p1)), xp=[0.1,0.8,0.05],yp=[0.1,0.9,0.05],xn=[0.2,0.9,0.05],yn=[0.1,0.9,0.05])


Out[36]:
<function __main__.<lambda>>

Plot the secondary potential

Write a function to compute the secondary field


In [37]:
def CondBlockSecondary(xp,yp,xn,yn,mesh,sigma,sigmabl,p0,p1):
    sigmaBl = Utils.ModelBuilder.defineBlock(mesh.gridCC, p0, p1, np.r_[sigmabl,sigmaback])
    sec = SolveDC(xp,yp,xn,yn,mesh,sigmaBl) - SolveDC(xp,yp,xn,yn,mesh,sigma)
    return sec

Here, we plot the difference in potentials computed with and without the block, ie. the signal due to the presence of the block


In [38]:
interact(lambda xp,yp,xn,yn: plotPhi(CondBlockSecondary(xp,yp,xn,yn,mesh,sigma,sigmabl,p0,p1)), xp=[0.1,0.8,0.05],yp=[0.1,0.9,0.05],xn=[0.2,0.9,0.05],yn=[0.1,0.9,0.05])


All parameters active

Here, you can play with all of the parameters in this model:

  • xp: x-position of the positive electrode
  • yp: y-position of the positive electrode
  • xn: x-position of the negative electrode
  • yn: y-position of the negative electrode
  • log10_sigmabl: $log_{10}(\sigma_{\text{block}})$
  • blcx : x-center of the block
  • blcy : y-center of the block
  • bldx : x-width of the block
  • bldy : y-width of the block

The first widget shows the measured potential and the second shows the secondary potential


In [39]:
# total potential
interact(lambda xp,yp,xn,yn,log10_sigmabl,blcx,blcy,bldx,bldy: plotPhi(CondBlock(xp,yp,xn,yn,mesh,sigma,10.**(log10_sigmabl),np.r_[blcx-bldx/2.,blcy-bldy/2.],np.r_[blcx+bldx/2.,blcy+bldy/2.])), xp=[0.1,0.8,0.05],yp=[0.1,0.9,0.05],xn=[0.2,0.9,0.05],yn=[0.1,0.9,0.05],log10_sigmabl=[-5,5,0.5],blcx=[0.,1.,0.05],blcy=[0.,1.,0.05],bldx=[0.,1.,0.05],bldy=[0.,1.,0.05])


Out[39]:
<function __main__.<lambda>>

In [40]:
# secondary potential
interact(lambda xp,yp,xn,yn,log10_sigmabl,blcx,blcy,bldx,bldy: plotPhi(CondBlockSecondary(xp,yp,xn,yn,mesh,sigma,10.**(log10_sigmabl),np.r_[blcx-bldx/2.,blcy-bldy/2.],np.r_[blcx+bldx/2.,blcy+bldy/2.])), xp=[0.1,0.8,0.05],yp=[0.1,0.9,0.05],xn=[0.2,0.9,0.05],yn=[0.1,0.9,0.05],log10_sigmabl=[-5,5,0.5],blcx=[0.,1.,0.05],blcy=[0.,1.,0.05],bldx=[0.,1.,0.05],bldy=[0.,1.,0.05])


Out[40]:
<function __main__.<lambda>>

In [ ]:


In [ ]: