def setUpClass(self): print('\n------- Testing Primary Secondary Source HJ -> EB --------\n') # receivers self.rxlist = [] for rxtype in ['b', 'e']: rx = getattr(FDEM.Rx, 'Point_{}'.format(rxtype)) for orientation in ['x', 'y', 'z']: for comp in ['real', 'imag']: self.rxlist.append(rx(rx_locs, component=comp, orientation=orientation)) # primary self.primaryProblem = FDEM.Problem3D_j(meshp, sigmaMap=primaryMapping) self.primaryProblem.solver = Solver s_e = np.zeros(meshp.nF) inds = meshp.nFx + Utils.closestPoints(meshp, src_loc, gridLoc='Fz') s_e[inds] = 1./csz primarySrc = FDEM.Src.RawVec_e( self.rxlist, freq=freq, s_e=s_e/meshp.area ) self.primarySurvey = FDEM.Survey([primarySrc]) # Secondary Problem self.secondaryProblem = FDEM.Problem3D_e(meshs, sigmaMap=mapping) self.secondaryProblem.Solver = Solver self.secondarySrc = FDEM.Src.PrimSecMappedSigma( self.rxlist, freq, self.primaryProblem, self.primarySurvey, primaryMap2Meshs ) self.secondarySurvey = FDEM.Survey([self.secondarySrc]) self.secondaryProblem.pair(self.secondarySurvey) # Full 3D problem to compare with self.problem3D = FDEM.Problem3D_e(meshs, sigmaMap=mapping) self.problem3D.Solver = Solver s_e3D = np.zeros(meshs.nE) inds = (meshs.nEx + meshs.nEy + Utils.closestPoints(meshs, src_loc, gridLoc='Ez')) s_e3D[inds] = [1./(len(inds))] * len(inds) self.problem3D.model = model src3D = FDEM.Src.RawVec_e(self.rxlist, freq=freq, s_e=s_e3D) self.survey3D = FDEM.Survey([src3D]) self.problem3D.pair(self.survey3D) # solve and store fields print(' solving primary - secondary') self.fields_primsec = self.secondaryProblem.fields(model) print(' ... done') self.fields_primsec = self.secondaryProblem.fields(model) print(' solving 3D') self.fields_3D = self.problem3D.fields(model) print(' ... done') return None
def setupSecondaryProblem(self, mapping=None): print('Setting up Secondary Problem') if mapping is None: mapping = [('sigma', Maps.IdentityMap(self.meshs))] sec_problem = FDEM.Problem3D_e(self.meshs, sigmaMap=mapping) sec_problem.Solver = Solver print('... done setting up secondary problem') return sec_problem
def setUp(self): cs = 10. ncx, ncy, ncz = 30., 30., 30. npad = 10. hx = [(cs, npad, -1.5), (cs, ncx), (cs, npad, 1.5)] hy = [(cs, npad, -1.5), (cs, ncy), (cs, npad, 1.5)] hz = [(cs, npad, -1.5), (cs, ncz), (cs, npad, 1.5)] self.mesh = Mesh.TensorMesh([hx, hy, hz], 'CCC') mapping = Maps.ExpMap(self.mesh) self.freq = 1. self.prob_e = FDEM.Problem3D_e(self.mesh, mapping=mapping) self.prob_b = FDEM.Problem3D_b(self.mesh, mapping=mapping) self.prob_h = FDEM.Problem3D_h(self.mesh, mapping=mapping) self.prob_j = FDEM.Problem3D_j(self.mesh, mapping=mapping) loc = np.r_[0., 0., 0.] self.loc = Utils.mkvc( self.mesh.gridCC[Utils.closestPoints(self.mesh, loc, 'CC'), :])
def run(plotIt=True): """ Mesh: Plotting with defining range ================================== When using a large Mesh with the cylindrical code, it is advantageous to define a :code:`range_x` and :code:`range_y` when plotting with vectors. In this case, only the region inside of the range is interpolated. In particular, you often want to ignore padding cells. """ # ## Model Parameters # # We define a # - resistive halfspace and # - conductive sphere # - radius of 30m # - center is 50m below the surface # electrical conductivities in S/m sig_halfspace = 1e-6 sig_sphere = 1e0 sig_air = 1e-8 # depth to center, radius in m sphere_z = -50. sphere_radius = 30. # ## Survey Parameters # # - Transmitter and receiver 20m above the surface # - Receiver offset from transmitter by 8m horizontally # - 25 frequencies, logaritmically between $10$ Hz and $10^5$ Hz boom_height = 20. rx_offset = 8. freqs = np.r_[1e1, 1e5] # source and receiver location in 3D space src_loc = np.r_[0., 0., boom_height] rx_loc = np.atleast_2d(np.r_[rx_offset, 0., boom_height]) # print the min and max skin depths to make sure mesh is fine enough and # extends far enough def skin_depth(sigma, f): return 500. / np.sqrt(sigma * f) print('Minimum skin depth (in sphere): {:.2e} m '.format( skin_depth(sig_sphere, freqs.max()))) print('Maximum skin depth (in background): {:.2e} m '.format( skin_depth(sig_halfspace, freqs.min()))) # ## Mesh # # Here, we define a cylindrically symmetric tensor mesh. # # ### Mesh Parameters # # For the mesh, we will use a cylindrically symmetric tensor mesh. To # construct a tensor mesh, all that is needed is a vector of cell widths in # the x and z-directions. We will define a core mesh region of uniform cell # widths and a padding region where the cell widths expand "to infinity". # x-direction csx = 2 # core mesh cell width in the x-direction ncx = np.ceil( 1.2 * sphere_radius / csx ) # number of core x-cells (uniform mesh slightly beyond sphere radius) npadx = 50 # number of x padding cells # z-direction csz = 1 # core mesh cell width in the z-direction ncz = np.ceil( 1.2 * (boom_height - (sphere_z - sphere_radius)) / csz ) # number of core z-cells (uniform cells slightly below bottom of sphere) npadz = 52 # number of z padding cells # padding factor (expand cells to infinity) pf = 1.3 # cell spacings in the x and z directions hx = Utils.meshTensor([(csx, ncx), (csx, npadx, pf)]) hz = Utils.meshTensor([(csz, npadz, -pf), (csz, ncz), (csz, npadz, pf)]) # define a SimPEG mesh mesh = Mesh.CylMesh([hx, 1, hz], x0=np.r_[0., 0., -hz.sum() / 2. - boom_height]) # ### Plot the mesh # # Below, we plot the mesh. The cyl mesh is rotated around x=0. Ensure that # each dimension extends beyond the maximum skin depth. # # Zoom in by changing the xlim and zlim. # X and Z limits we want to plot to. Try xlim = np.r_[0., 2.5e6] zlim = np.r_[-2.5e6, 2.5e6] fig, ax = plt.subplots(1, 1) mesh.plotGrid(ax=ax) ax.set_title('Simulation Mesh') ax.set_xlim(xlim) ax.set_ylim(zlim) print('The maximum skin depth is (in background): {:.2e} m. ' 'Does the mesh go sufficiently past that?'.format( skin_depth(sig_halfspace, freqs.min()))) # ## Put Model on Mesh # # Now that the model parameters and mesh are defined, we can define # electrical conductivity on the mesh. # # The electrical conductivity is defined at cell centers when using the # finite volume method. So here, we define a vector that contains an # electrical conductivity value for every cell center. # create a vector that has one entry for every cell center sigma = sig_air * np.ones( mesh.nC) # start by defining the conductivity of the air everwhere sigma[mesh.gridCC[:, 2] < 0.] = sig_halfspace # assign halfspace cells below the earth # indices of the sphere (where (x-x0)**2 + (z-z0)**2 <= R**2) sphere_ind = ((mesh.gridCC[:, 0]**2 + (mesh.gridCC[:, 2] - sphere_z)**2) <= sphere_radius**2) sigma[sphere_ind] = sig_sphere # assign the conductivity of the sphere # Plot a cross section of the conductivity model fig, ax = plt.subplots(1, 1) cb = plt.colorbar(mesh.plotImage(np.log10(sigma), ax=ax, mirror=True)[0]) # plot formatting and titles cb.set_label('$\log_{10}\sigma$', fontsize=13) ax.axis('equal') ax.set_xlim([-120., 120.]) ax.set_ylim([-100., 30.]) ax.set_title('Conductivity Model') # ## Set up the Survey # # Here, we define sources and receivers. For this example, the receivers # are magnetic flux recievers, and are only looking at the secondary field # (eg. if a bucking coil were used to cancel the primary). The source is a # vertical magnetic dipole with unit moment. # Define the receivers, we will sample the real secondary magnetic flux # density as well as the imaginary magnetic flux density bz_r = FDEM.Rx.Point_bSecondary( locs=rx_loc, orientation='z', component='real') # vertical real b-secondary bz_i = FDEM.Rx.Point_b( locs=rx_loc, orientation='z', component='imag') # vertical imag b (same as b-secondary) rxList = [bz_r, bz_i] # list of receivers # Define the list of sources - one source for each frequency. The source is # a point dipole oriented in the z-direction srcList = [ FDEM.Src.MagDipole(rxList, f, src_loc, orientation='z') for f in freqs ] print( 'There are {nsrc} sources (same as the number of frequencies - {nfreq}). ' 'Each source has {nrx} receivers sampling the resulting b-fields'. format(nsrc=len(srcList), nfreq=len(freqs), nrx=len(rxList))) # ## Set up Forward Simulation # # A forward simulation consists of a paired SimPEG problem and Survey. # For this example, we use the E-formulation of Maxwell's equations, # solving the second-order system for the electric field, which is defined # on the cell edges of the mesh. This is the `prob` variable below. The # `survey` takes the source list which is used to construct the RHS for the # problem. The source list also contains the receiver information, so the # `survey` knows how to sample fields and fluxes that are produced by # solving the `prob`. # define a problem - the statement of which discrete pde system we want to # solve prob = FDEM.Problem3D_e(mesh, sigmaMap=Maps.IdentityMap(mesh)) prob.solver = Solver survey = FDEM.Survey(srcList) # tell the problem and survey about each other - so the RHS can be # constructed for the problem and the # resulting fields and fluxes can be sampled by the receiver. prob.pair(survey) # ### Solve the forward simulation # # Here, we solve the problem for the fields everywhere on the mesh. fields = prob.fields(sigma) # ### Plot the fields # # Lets look at the physics! # log-scale the colorbar from matplotlib.colors import LogNorm fig, ax = plt.subplots(1, 2, figsize=(12, 6)) def plotMe(field, ax): plt.colorbar(mesh.plotImage(field, vType='F', view='vec', range_x=[-100., 100.], range_y=[-180., 60.], pcolorOpts={ 'norm': LogNorm(), 'cmap': plt.get_cmap('viridis') }, streamOpts={'color': 'k'}, ax=ax, mirror=True)[0], ax=ax) plotMe(fields[srcList[0], 'bSecondary'].real, ax[0]) ax[0].set_title('Real B-Secondary, {}Hz'.format(freqs[0])) plotMe(fields[srcList[1], 'bSecondary'].real, ax[1]) ax[1].set_title('Real B-Secondary, {}Hz'.format(freqs[1])) plt.tight_layout() if plotIt: plt.show()