Here we use SimPEG and simpegEM to forward-model the electromagnetic response of a plate. We use two plate geometries, one a circle, and one a disk with a hole in it. The plates are defined to have equal volumes. For a source, we use a vertical magnetic dipole and for receivers we measure both the in-phase (or real) and quadrature (or imaginary) components. We take advantage of the cylindrical symmetry of this problem and treat it as a 2D cylindrically symmetric one.
The coordinate system is:
This is the iPython Notebook, an interactive coding and computation environment
To use the notebook:
In [1]:
# import the necessary packages
from SimPEG import *
import simpegEM as EM
%pylab inline
Define the size and conductivity of the plate and background. Here, we set up two models, one of a circular fracture and one for a disk that has a hole in it (outer radius Rd1, inner radius Rd2). The thickness of each plate is equal and given by the variable t. The radius of the circular plate is chosen so that the volume of the disk plate and the circular plate are equal.
In [2]:
# Model Parameters
sigback = 1e-2 # 100 Ohm-m background
sigfrac = 2000. # S/m Frac: conductivity
t = 5e-3 # fracture thickness
# for the disk distribution
Rd1 = 20. # inner radius
Rd2 = 40. # outer radius (m)
# for the circle disribution
Rc = np.sqrt(Rd2**2 -Rd1**2) # conserve volume between examples
Here we specify the survey parameters. We are using a single vertical magnetic dipole transmitter positioned at the origin and multipple receivers. The parameters we are setting are:
Here, we also calculate the skin-depth (delta), which is used to estimate how quickly the fields decay. This is important to note this value because we need to make sure that the mesh is large enough that the fields will have decayed by the time they get to the boundary (typically we want the mesh to extend >2 times this value).
In [4]:
# Survey Parameters
freq = np.logspace(1, 5, 20) # frequency
print freq
# z - along the well
# receivers
nrx = 101. # number of receivers
rxx = 100. # x location of receivers
rxz = np.linspace(-150,150,nrx) # z location of receivers along the well
# transmitter
txz = 0. # transmitter z location
# transmitter moment
txmom = 2000 # Am^2
# Noise Floor
flr = 1e-14 # smallest signal we can measure
perc_cutoff = 3 # smallest percent difference we are confident in
# calculate the skin depth
delta = 500./np.sqrt(freq*sigback)
print delta # skin depth
Now to solve the problem, we need to discretize it. To do this we define a mesh on which our model and fields will live and on which we will solve the problem.
In [5]:
# set up a mesh (all units are meters)
csx, ncx, npadx = 5 , 41, 20 # cell size, number of core cells, number of padding cells in the x- direction
csz, ncz, npadz = 5 , 44, 20 # cell size, number of core cells, number of padding cells in the z- direction
hx = Utils.meshTensor([(csx,npadx,-0.7), (csx,ncx), (csx,npadx,1.3)]) # vector of cell widths in the x-direction
hz = Utils.meshTensor([(csz,npadz,-1.3), (csz,ncz), (csz,npadz,1.3)]) # vector of cell widths in the z-direction
mesh = Mesh.CylMesh([hx,1,hz], [0.,0,-hz.sum()/2.]) # define the cylindrical mesh using SimPEG
mesh.plotGrid() # Plot the mesh
print mesh.nC
Now that we have a mesh, we need to define our model on that mesh. Since the fracture is so thin compared to the size of the cells, we upscale the conductivity, that is, make a coarse approximation of the conductivity on the coarse mesh. To do this, we treat the cells with the plate running through them as anisotropic, so the conductivity varies with direction. We treat the vertical component of the conductivity like a series circuit and the component parallel to the plate as a parallel circuit.
In [6]:
# find where in the mesh the circle and disc should be
fracCircle = (mesh.gridCC[:,0]>mesh.hx[0]) & (mesh.gridCC[:,0]<=Rc) & (mesh.gridCC[:,2]<np.max(np.array([csz,t/2.]))) & (mesh.gridCC[:,2]>-np.max(np.array([csz,t/2.])))
fracDisc = (mesh.gridCC[:,0]>Rd1) & (mesh.gridCC[:,0]<=Rd2) & (mesh.gridCC[:,2]<np.max(np.array([csz,t/2.]))) & (mesh.gridCC[:,2]>-np.max(np.array([csz,t/2.])))
# inline functions for series and parallel circuit approximations of the anisotropic conductivity
scaleByCT = lambda sig1,t1,t2: sig1*t1/t2
Hxyz = Utils.ndgrid(mesh.hx,np.r_[0.],mesh.hz)
# Background conductivity
sigBack = sigback*np.ones((mesh.nC))
# conductivity model for the circular frac
sigfracCircle = sigback*np.ones((mesh.nC)) # anisotropic conductivity
sigfracCircle[fracCircle] = scaleByCT(sigfrac,t,Hxyz[fracCircle,2])
# conductivity model for the disc frac
sigfracDisc = sigback*np.ones((mesh.nC)) # anisotropic conductivity
sigfracDisc[fracDisc] = scaleByCT(sigfrac,t,Hxyz[fracDisc,2])
In [66]:
# plot them
fs = 32 # fontsize
xlim = [0.,150.] #xlimits
zlim = [-200., 200.] #ylimits
def plotIt(img,label=None,title=None):
plt.colorbar(img,label=label)
plt.xlim(xlim)
plt.ylim(zlim)
plt.plot(0.,txz,'d',markersize=12,markeredgecolor='white',markerfacecolor='white')
plt.plot(rxx*np.ones(rxz.shape),rxz,'o',markersize=4,markeredgecolor='yellow',markerfacecolor='yellow')
plt.title(title)
plt.fontsize = fs
plt.grid(which='both')
return
# Circle
plotIt(mesh.plotImage(np.log10(sigfracCircle))[0],'$\sigma$','Circle, Parallel Conductivity: $\sigma$')
# Disc
plotIt(mesh.plotImage(np.log10(sigfracDisc))[0],'$\sigma$','Disc, Parallel Conductivity: $\sigma$')
Pair the problem and the survey so that we can create fields and collect data
In [67]:
# receivers
XYZ = Utils.ndgrid(np.r_[rxx],np.r_[0.],np.r_[rxz]) # define receivers on grid
Rx0 = EM.FDEM.RxFDEM(XYZ, 'bzr') # create real / in-phase receivers
Rx1 = EM.FDEM.RxFDEM(XYZ, 'bzi') # create imag / quadrature receivers
# transmitters
txlist = []
for f in freq:
Tx = EM.FDEM.TxFDEM(np.r_[0.,0.,txz], 'VMD',f,[Rx0,Rx1]) # create vertical magnetic dipole transmitter
txlist.append(Tx)
# pair the problem and survey
survey = EM.FDEM.SurveyFDEM(txlist) # set survey
prb = EM.FDEM.ProblemFDEM_e(mesh) # set problem
prb.pair(survey) # pair problem and survey
In [68]:
# background - no fracture
dPrimary = survey.dpred(sigBack)*txmom # in-phase
print 'Done Calculating Primary'
# circle model
dCircle = survey.dpred(sigfracCircle)*txmom
print 'Done Calculating Circle'
# circle model
dDisc = survey.dpred(sigfracDisc)*txmom
print 'Done Calculating Disc'
In [69]:
# Sort Data
dPrim = np.reshape(dPrimary,(freq.size,2*nrx))
dCirc = np.reshape(dCircle,(freq.size,2*nrx))
dDisc = np.reshape(dDisc,(freq.size,2*nrx))
# Sort into In-Phase and Quadrature
dPrimI = dPrim[:,:nrx]
dPrimQ = dPrim[:,nrx:]
dCircI = dCirc[:,:nrx]
dCircQ = dCirc[:,nrx:]
dDiscI = dDisc[:,:nrx]
dDiscQ = dDisc[:,nrx:]
In [70]:
freq_ind = 6
print freq[freq_ind]
In [71]:
plt.figure(figsize=(11,6))
# Plot In-Phase
plt.subplot(121)
plt.plot(rxz,dCircI[freq_ind,:],rxz,dDiscI[freq_ind,:],linewidth=2)
plt.plot(rxz,flr*np.ones(rxz.shape),'--k', rxz,-flr*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('In-Phase')
plt.ylabel('Magnetic Field Response (T)')
plt.xlabel('x (m)')
print 'Max In-Phase Responses: Circle %e T , Disc %e T' %(np.max(dCircI[freq_ind,:]), np.max(dDiscI[freq_ind,:]))
# Plot Quadrature
plt.subplot(122)
plt.plot(rxz,dCircQ[freq_ind,:],rxz,dDiscQ[freq_ind,:],linewidth=2)
plt.plot(rxz,flr*np.ones(rxz.shape),'--k', rxz,-flr*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('Quadrature')
plt.legend(['Circle','Disc'],loc=2, bbox_to_anchor = (1.0, 1.0),title='Model')
plt.ylabel('Magnetic Field Response (T)')
plt.xlabel('x (m)')
print 'Max Quadrature Responses: Circle %e T , Disc %e T' %(np.max(dCircQ[freq_ind,:]), np.max(dDiscQ[freq_ind,:]))
plt.tight_layout()
plt.show()
In [72]:
# Difference between circle and disc signals
Idiff = dCircI[freq_ind,:]-dDiscI[freq_ind,:]
Qdiff = dCircQ[freq_ind,:]-dDiscQ[freq_ind,:]
plt.figure(figsize=(11,6))
# Plot In-phase
plt.subplot(121)
plt.plot(rxz,Idiff,linewidth=2)
plt.plot(rxz,flr*np.ones(rxz.shape),'--k', rxz,-flr*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('In-Phase')
plt.ylabel('Difference Magnetic Field Response (T)')
plt.xlabel('x (m)')
print 'Max In-Phase Difference: %e T' %(np.max(dCircI-dDiscI))
# Plot Quadrature
plt.subplot(122)
plt.plot(rxz,Qdiff,linewidth=2)
plt.plot(rxz,flr*np.ones(rxz.shape),'--k', rxz,-flr*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('Quadrature')
plt.legend(['Circle - Disc'],loc=2, bbox_to_anchor = (1.0, 1.0))
plt.ylabel('Difference Magnetic Field Response (T)')
plt.xlabel('x (m)')
print 'Max Quadrature Difference: %e T' %(np.max(dCircQ[freq_ind,:]-dDiscQ[freq_ind,:]))
plt.tight_layout()
plt.show()
In [73]:
# Percent difference between circle and disc models
IPerc = (dCircI[freq_ind,:]-dDiscI[freq_ind,:])/np.max(np.abs([dCircI[freq_ind,:],dDiscI[freq_ind,:]]))*100
QPerc = (dCircQ[freq_ind,:]-dDiscQ[freq_ind,:])/np.max(np.abs([dCircQ[freq_ind,:],dDiscQ[freq_ind,:]]))*100
plt.figure(figsize=(11,6))
# Plot In-Phase
plt.subplot(121)
plt.plot(rxz,IPerc,linewidth=2)
plt.plot(rxz,perc_cutoff*np.ones(rxz.shape),'--k', rxz,-perc_cutoff*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('In-Phase')
plt.ylabel('Difference Magnetic Field Response (%)')
plt.xlabel('x (m)')
print 'Max In-Phase Difference: %d %s' %(np.max(IPerc), '%')
# Plot Quadrature
plt.subplot(122)
plt.plot(rxz,QPerc ,linewidth=2)
plt.plot(rxz,perc_cutoff*np.ones(rxz.shape),'--k', rxz,-perc_cutoff*np.ones(rxz.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('Quadrature')
plt.legend(['(Circle - Disc)/max(Circle,Disc) *100%'],loc=2, bbox_to_anchor = (1.0, 1.0))
plt.ylabel('Difference Magnetic Field Response (%)')
plt.xlabel('x (m)')
print 'Max Quadrature Difference: %d %s' %(np.max(QPerc), '%')
plt.tight_layout()
plt.show()
In [74]:
# choose receiver position to plot
rxind = np.floor(nrx/2.) # plot the middle receiver
print rxz[rxind]
In [75]:
plt.figure(figsize=(11,6))
# Plot In-Phase
plt.subplot(121)
plt.semilogx(freq,dCircI[:,rxind],'-o',freq,dDiscI[:,rxind],'-o',linewidth=2)
plt.plot(freq,flr*np.ones(freq.shape),'--k', freq,-flr*np.ones(freq.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('In-Phase')
plt.ylabel('Magnetic Field Response (T)')
plt.xlabel('frequency (Hz)')
print 'Max In-Phase Responses: Circle %e T , Disc %e T' %(np.max(dCircI), np.max(dDiscI))
# Plot Quadrature
plt.subplot(122)
plt.semilogx(freq,dCircQ[:,rxind],'-o',freq,dDiscQ[:,rxind],'-o',linewidth=2)
plt.plot(freq,flr*np.ones(freq.shape),'--k', freq,-flr*np.ones(freq.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('Quadrature')
plt.legend(['Circle','Disc'],loc=2, bbox_to_anchor = (1.0, 1.0),title='Model')
plt.ylabel('Magnetic Field Response (T)')
plt.xlabel('fraquency (Hz)')
print 'Max Quadrature Responses: Circle %e T , Disc %e T' %(np.max(dCircQ), np.max(dDiscQ))
plt.tight_layout()
plt.show()
In [65]:
# Difference between circle and disc signals
Idiff = dCircI[:,rxind]-dDiscI[:,rxind]
Qdiff = dCircQ[:,rxind]-dDiscQ[:,rxind]
plt.figure(figsize=(11,6))
# Plot In-phase
plt.subplot(121)
plt.semilogx(freq,Idiff,'-o',linewidth=2)
plt.plot(freq,flr*np.ones(freq.shape),'--k', freq,-flr*np.ones(freq.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('In-Phase')
plt.ylabel('Difference Magnetic Field Response (T)')
plt.xlabel('frequency (Hz)')
print 'Max In-Phase Difference: %e T' %(np.max(dCircI-dDiscI))
# Plot Quadrature
plt.subplot(122)
plt.semilogx(freq,Qdiff,'-o',linewidth=2)
plt.plot(freq,flr*np.ones(freq.shape),'--k', freq,-flr*np.ones(freq.shape),'--k',linewidth=2)
plt.grid(which='both')
plt.title('Quadrature')
plt.legend(['Circle - Disc'],loc=2, bbox_to_anchor = (1.0, 1.0))
plt.ylabel('Difference Magnetic Field Response (T)')
plt.xlabel('x (m)')
print 'Max Quadrature Difference: %e T' %(np.max(dCircQ-dDiscQ))
plt.tight_layout()
plt.show()
In [64]: