def DerivProjfieldsTest(inputSetup, comp="All", freq=False): survey, simulation = nsem.utils.test_utils.setupSimpegNSEM_ePrimSec( inputSetup, comp, freq) print( "Derivative test of data projection for eFormulation primary/secondary\n" ) # simulation.mapping = maps.ExpMap(simulation.mesh) # Initate things for the derivs Test src = survey.source_list[0] np.random.seed(1983) u0x = np.random.randn( survey.mesh.nE) + np.random.randn(survey.mesh.nE) * 1j u0y = np.random.randn( survey.mesh.nE) + np.random.randn(survey.mesh.nE) * 1j u0 = np.vstack((mkvc(u0x, 2), mkvc(u0y, 2))) f0 = simulation.fieldsPair(survey.mesh, survey) # u0 = np.hstack((mkvc(u0_px,2),mkvc(u0_py,2))) f0[src, "e_pxSolution"] = u0[:len(u0) / 2] # u0x f0[src, "e_pySolution"] = u0[len(u0) / 2::] # u0y def fun(u): f = simulation.fieldsPair(survey.mesh, survey) f[src, "e_pxSolution"] = u[:len(u) / 2] f[src, "e_pySolution"] = u[len(u) / 2::] return ( rx.eval(src, survey.mesh, f), lambda t: rx.evalDeriv(src, survey.mesh, f0, mkvc(t, 2)), ) return tests.checkDerivative(fun, u0, num=4, plotIt=False, eps=FLR)
def test_ana_forward(self): # Compute 3-component mag data self.survey.pair(self.prob_xyz) d = self.prob_xyz.fields(self.model) ndata = self.locXyz.shape[0] dbx = d[0:ndata] dby = d[ndata:2 * ndata] dbz = d[2 * ndata:] # Compute tmi mag data self.survey.pair(self.prob_tmi) dtmi = self.prob_tmi.fields(self.model) # Compute analytical response from a magnetized sphere bxa, bya, bza = PF.MagAnalytics.MagSphereFreeSpace( self.locXyz[:, 0], self.locXyz[:, 1], self.locXyz[:, 2], self.rad, 0, 0, 0, self.chi, self.b0) # Projection matrix Ptmi = mkvc(self.b0) / np.sqrt(np.sum(self.b0**2.)) btmi = mkvc(Ptmi.dot(np.vstack((bxa, bya, bza)))) err_xyz = (np.linalg.norm(d - np.r_[bxa, bya, bza]) / np.linalg.norm(np.r_[bxa, bya, bza])) err_tmi = np.linalg.norm(dtmi - btmi) / np.linalg.norm(btmi) self.assertTrue(err_xyz < 0.005 and err_tmi < 0.005)
def S_eDeriv_m(self, problem, v, adjoint=False): ''' Get the derivative of S_e wrt to sigma (m) ''' # Need to deal with if problem.mesh.dim == 1: # Need to use the faceInnerProduct ePri = self.ePrimary(problem)[:, 1] MsigmaDeriv = ( problem.mesh.getFaceInnerProductDeriv(problem.sigma)(ePri) * problem.sigmaDeriv) # MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2 if adjoint: # return MsigmaDeriv.T * v else: # v should be nC size return MsigmaDeriv * v if problem.mesh.dim == 2: raise NotImplementedError('The NSEM 2D problem is not implemented') if problem.mesh.dim == 3: # Need to take the derivative of both u_px and u_py # And stack them to be of the correct size e_p = self.ePrimary(problem) if adjoint: return sp.hstack(( problem.MeSigmaDeriv(e_p[:, 0]).T, problem.MeSigmaDeriv(e_p[:, 1]).T)) * v else: return np.hstack(( mkvc(problem.MeSigmaDeriv(e_p[:, 0]) * v, 2), mkvc(problem.MeSigmaDeriv(e_p[:, 1]) * v, 2)))
def S_eDeriv_m(self, problem, v, adjoint=False): """ Get the derivative of S_e wrt to sigma (m) """ # Need to deal with if problem.mesh.dim == 1: # Need to use the faceInnerProduct MsigmaDeriv = ( problem.mesh.getFaceInnerProductDeriv(problem.curModel.sigma)(self.ePrimary(problem)[:, 1]) * problem.curModel.sigmaDeriv ) # MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2 if problem.mesh.dim == 2: pass if problem.mesh.dim == 3: # Need to take the derivative of both u_px and u_py ePri = self.ePrimary(problem) # MsigmaDeriv = problem.MeSigmaDeriv(ePri[:,0]) + problem.MeSigmaDeriv(ePri[:,1]) # MsigmaDeriv = problem.MeSigmaDeriv(np.sum(ePri,axis=1)) if adjoint: return sp.hstack((problem.MeSigmaDeriv(ePri[:, 0]).T, problem.MeSigmaDeriv(ePri[:, 1]).T)) * v else: return np.hstack( (mkvc(problem.MeSigmaDeriv(ePri[:, 0]) * v, 2), mkvc(problem.MeSigmaDeriv(ePri[:, 1]) * v, 2)) ) if adjoint: # return MsigmaDeriv.T * v else: # v should be nC size return MsigmaDeriv * v
def getADeriv(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. :param float freq: Frequency :param SimPEG.EM.NSEM.FieldsNSEM u: NSEM Fields object :param numpy.ndarray v: vector of size (nU,) (adjoint=False) and size (nP,) (adjoint=True) :rtype: numpy.ndarray :return: Calculated derivative (nP,) (adjoint=False) and (nU,)[NOTE return as a (nU/2,2) columnwise polarizations] (adjoint=True) for both polarizations """ # Fix u to be a matrix nE,2 # This considers both polarizations and returns a nE,2 matrix for each polarization # The solution types sol0, sol1 = self._solutionType if adjoint: dMe_dsigV = ( self.MeSigmaDeriv(u[sol0], v[:self.mesh.nE], adjoint) + self.MeSigmaDeriv(u[sol1], v[self.mesh.nE:], adjoint) ) else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( ( mkvc(self.MeSigmaDeriv(u[sol0], v, adjoint), 2), mkvc(self.MeSigmaDeriv(u[sol1], v, adjoint), 2) ) ) return 1j * omega(freq) * dMe_dsigV
def test_ana_forward(self): # Compute 3-component mag data self.survey.pair(self.prob_xyz) d = self.prob_xyz.fields(self.model) ndata = self.locXyz.shape[0] dbx = d[0:ndata] dby = d[ndata:2*ndata] dbz = d[2*ndata:] # Compute tmi mag data self.survey.pair(self.prob_tmi) dtmi = self.prob_tmi.fields(self.model) # Compute analytical response from a magnetized sphere bxa, bya, bza = PF.MagAnalytics.MagSphereFreeSpace(self.locXyz[:, 0], self.locXyz[:, 1], self.locXyz[:, 2], self.rad, 0, 0, 0, self.chi, self.b0) # Projection matrix Ptmi = mkvc(self.b0)/np.sqrt(np.sum(self.b0**2.)) btmi = mkvc(Ptmi.dot(np.vstack((bxa, bya, bza)))) err_xyz = (np.linalg.norm(d-np.r_[bxa, bya, bza]) / np.linalg.norm(np.r_[bxa, bya, bza])) err_tmi = np.linalg.norm(dtmi-btmi)/np.linalg.norm(btmi) self.assertTrue(err_xyz < 0.005 and err_tmi < 0.005)
def test_basic_inversion(self): """ Test to see if inversion recovers model """ h = [(2, 30)] meshObj = Mesh.TensorMesh((h, h, [(2, 10)]), x0='CCN') mod = 0.00025 * np.ones(meshObj.nC) mod[(meshObj.gridCC[:, 0] > -4.) & (meshObj.gridCC[:, 1] > -4.) & (meshObj.gridCC[:, 0] < 4.) & (meshObj.gridCC[:, 1] < 4.)] = 0.001 times = np.logspace(-4, -2, 5) waveObj = VRM.WaveformVRM.SquarePulse(0.02) x, y = np.meshgrid(np.linspace(-17, 17, 16), np.linspace(-17, 17, 16)) x, y, z = mkvc(x), mkvc(y), 0.5 * np.ones(np.size(x)) rxList = [VRM.Rx.Point(np.c_[x, y, z], times, 'dbdt', 'z')] txNodes = np.array([[-20, -20, 0.001], [20, -20, 0.001], [20, 20, 0.001], [-20, 20, 0.01], [-20, -20, 0.001]]) txList = [VRM.Src.LineCurrent(rxList, txNodes, 1., waveObj)] Survey = VRM.Survey(txList) Problem = VRM.Problem_Linear(meshObj, refFact=2) Problem.pair(Survey) Survey.makeSyntheticData(mod) Survey.eps = 1e-11 dmis = DataMisfit.l2_DataMisfit(Survey) W = mkvc((np.sum(np.array(Problem.A)**2, axis=0)))**0.25 reg = Regularization.Simple(meshObj, alpha_s=0.01, alpha_x=1., alpha_y=1., alpha_z=1., cell_weights=W) opt = Optimization.ProjectedGNCG(maxIter=20, lower=0., upper=1e-2, maxIterLS=20, tolCG=1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) directives = [ Directives.BetaSchedule(coolingFactor=2, coolingRate=1), Directives.TargetMisfit() ] inv = Inversion.BaseInversion(invProb, directiveList=directives) m0 = 1e-6 * np.ones(len(mod)) mrec = inv.run(m0) dmis_final = np.sum( (dmis.W.diagonal() * (Survey.dobs - Problem.fields(mrec)))**2) mod_err_2 = np.sqrt(np.sum((mrec - mod)**2)) / np.size(mod) mod_err_inf = np.max(np.abs(mrec - mod)) self.assertTrue(dmis_final < Survey.nD and mod_err_2 < 5e-6 and mod_err_inf < np.max(mod))
def test_basic_inversion(self): """ Test to see if inversion recovers model """ h = [(2, 30)] meshObj = Mesh.TensorMesh((h, h, [(2, 10)]), x0='CCN') mod = 0.00025*np.ones(meshObj.nC) mod[(meshObj.gridCC[:, 0] > -4.) & (meshObj.gridCC[:, 1] > -4.) & (meshObj.gridCC[:, 0] < 4.) & (meshObj.gridCC[:, 1] < 4.)] = 0.001 times = np.logspace(-4, -2, 5) waveObj = VRM.WaveformVRM.SquarePulse(delt=0.02) x, y = np.meshgrid(np.linspace(-17, 17, 16), np.linspace(-17, 17, 16)) x, y, z = mkvc(x), mkvc(y), 0.5*np.ones(np.size(x)) rxList = [VRM.Rx.Point(np.c_[x, y, z], times=times, fieldType='dbdt', fieldComp='z')] txNodes = np.array([[-20, -20, 0.001], [20, -20, 0.001], [20, 20, 0.001], [-20, 20, 0.01], [-20, -20, 0.001]]) txList = [VRM.Src.LineCurrent(rxList, txNodes, 1., waveObj)] Survey = VRM.Survey(txList) Survey.t_active = np.zeros(Survey.nD, dtype=bool) Survey.set_active_interval(-1e6, 1e6) Problem = VRM.Problem_Linear(meshObj, ref_factor=2) Problem.pair(Survey) Survey.makeSyntheticData(mod) Survey.eps = 1e-11 dmis = DataMisfit.l2_DataMisfit(Survey) W = mkvc((np.sum(np.array(Problem.A)**2, axis=0)))**0.25 reg = Regularization.Simple( meshObj, alpha_s=0.01, alpha_x=1., alpha_y=1., alpha_z=1., cell_weights=W ) opt = Optimization.ProjectedGNCG( maxIter=20, lower=0., upper=1e-2, maxIterLS=20, tolCG=1e-4 ) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) directives = [ Directives.BetaSchedule(coolingFactor=2, coolingRate=1), Directives.TargetMisfit() ] inv = Inversion.BaseInversion(invProb, directiveList=directives) m0 = 1e-6*np.ones(len(mod)) mrec = inv.run(m0) dmis_final = np.sum((dmis.W.diagonal()*(Survey.dobs - Problem.fields(mrec)))**2) mod_err_2 = np.sqrt(np.sum((mrec-mod)**2))/np.size(mod) mod_err_inf = np.max(np.abs(mrec-mod)) self.assertTrue(dmis_final < Survey.nD and mod_err_2 < 5e-6 and mod_err_inf < np.max(mod))
def getADeriv(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. :param float freq: Frequency :param SimPEG.EM.NSEM.FieldsNSEM u: NSEM Fields object :param numpy.ndarray v: vector of size (nU,) (adjoint=False) and size (nP,) (adjoint=True) :rtype: numpy.ndarray :return: Calculated derivative (nP,) (adjoint=False) and (nU,)[NOTE return as a (nU/2,2) columnwise polarizations] (adjoint=True) for both polarizations """ # Fix u to be a matrix nE,2 # This considers both polarizations and returns a nE,2 matrix for each polarization # The solution types sol0, sol1 = self._solutionType if adjoint: dMe_dsigV = sp.hstack((self.MeSigmaDeriv( u[sol0]).T, self.MeSigmaDeriv(u[sol1]).T)) * v else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( (mkvc(self.MeSigmaDeriv(u[sol0]) * v, 2), mkvc(self.MeSigmaDeriv(u[sol1]) * v, 2))) return 1j * omega(freq) * dMe_dsigV
def getInputs(): """ Function that returns Mesh, freqs, rx_loc, elev. """ # Make a mesh M = discretize.TensorMesh( [ [(200, 6, -1.5), (200.0, 4), (200, 6, 1.5)], [(200, 6, -1.5), (200.0, 4), (200, 6, 1.5)], [(200, 8, -1.5), (200.0, 8), (200, 8, 1.5)], ], x0=["C", "C", "C"], ) # Setup the model # Set the frequencies freqs = np.logspace(1, -3, 5) elev = 0 # Setup the the survey object # Receiver locations rx_x, rx_y = np.meshgrid(np.arange(-350, 350, 200), np.arange(-350, 350, 200)) rx_loc = np.hstack((mkvc(rx_x, 2), mkvc(rx_y, 2), elev + np.zeros( (np.prod(rx_x.shape), 1)))) return M, freqs, rx_loc, elev
def S_eDeriv_m(self, problem, v, adjoint=False): ''' Get the derivative of S_e wrt to sigma (m) ''' # Need to deal with if problem.mesh.dim == 1: # Need to use the faceInnerProduct MsigmaDeriv = ( problem.mesh.getFaceInnerProductDeriv( problem.sigma)(self.ePrimary(problem)[:, 1]) * problem.sigmaDeriv) # MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2 if problem.mesh.dim == 2: pass if problem.mesh.dim == 3: # Need to take the derivative of both u_px and u_py ePri = self.ePrimary(problem) if adjoint: return sp.hstack(( problem.MeSigmaDeriv(ePri[:, 0]).T, problem.MeSigmaDeriv(ePri[:, 1]).T)) * v else: return np.hstack(( mkvc(problem.MeSigmaDeriv(ePri[:, 0]) * v, 2), mkvc(problem.MeSigmaDeriv(ePri[:, 1]) * v, 2) )) if adjoint: # return MsigmaDeriv.T * v else: # v should be nC size return MsigmaDeriv * v
def S_eDeriv_m(self, problem, v, adjoint = False): ''' Get the derivative of S_e wrt to sigma (m) ''' # Need to deal with if problem.mesh.dim == 1: # Need to use the faceInnerProduct ePri = self.ePrimary(problem)[:,1] MsigmaDeriv = problem.mesh.getFaceInnerProductDeriv(problem.sigma)(ePri) * problem.sigmaDeriv # MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2 if adjoint: # return MsigmaDeriv.T * v else: # v should be nC size return MsigmaDeriv * v if problem.mesh.dim == 2: raise NotImplementedError('The NSEM 2D problem is not implemented') if problem.mesh.dim == 3: # Need to take the derivative of both u_px and u_py # And stack them to be of the correct size e_p = self.ePrimary(problem) if adjoint: return sp.hstack(( problem.MeSigmaDeriv(e_p[:,0]).T, problem.MeSigmaDeriv(e_p[:,1]).T ))*v else: return np.hstack(( mkvc(problem.MeSigmaDeriv(e_p[:,0]) * v,2), mkvc(problem.MeSigmaDeriv(e_p[:,1])*v,2) ))
def importFiles(self): """ Function to import EDI files into a object. """ # Constants that are needed for convertion of units # Temp lists tmpStaList = [] tmpCompList = ['freq','x','y','z'] tmpCompList.extend(self.comps) # Make the outarray dtRI = [(compS.lower().replace('.',''),float) for compS in tmpCompList] # Loop through all the files for nrEDI, EDIfile in enumerate(self.filesList): # Read the file into a list of the lines with open(EDIfile,'r') as fid: EDIlines = fid.readlines() # Find the location latD, longD, elevM = _findLatLong(EDIlines) # Transfrom coordinates transCoord = self._transfromPoints(longD,latD) # Extract the name of the file (station) EDIname = EDIfile.split(os.sep)[-1].split('.')[0] # Arrange the data staList = [EDIname, EDIfile, transCoord[0], transCoord[1], elevM[0]] # Add to the station list tmpStaList.extend(staList) # Read the frequency data freq = _findEDIcomp('>FREQ',EDIlines) # Make the temporary rec array. tArrRec = ( np.nan*np.ones( (len(freq),len(dtRI)) ) ).view(dtRI) #np.concatenate((freq*np.ones((locs.shape[0],1)),locs,np.nan*np.ones((locs.shape[0],8))),axis=1).view(dtRI) # Add data to the array tArrRec['freq'] = mkvc(freq,2) tArrRec['x'] = mkvc(np.ones((len(freq),1))*transCoord[0],2) tArrRec['y'] = mkvc(np.ones((len(freq),1))*transCoord[1],2) tArrRec['z'] = mkvc(np.ones((len(freq),1))*elevM[0],2) for comp in self.comps: # Deal with converting units of the impedance tensor if 'Z' in comp: unitConvert = self._impUnitEDI2SI else: unitConvert = 1 # Rotate the data since EDI x is *north, y *east but Simpeg uses x *east, y *north (* means internal reference frame) key = [comp.lower().replace('.','').replace(s,t) for s,t in [['xx','yy'],['xy','yx'],['yx','xy'],['yy','xx']] if s in comp.lower()][0] tArrRec[key] = mkvc(unitConvert*_findEDIcomp('>'+comp,EDIlines),2) # Make a masked array mArrRec = np.ma.MaskedArray(rec2ndarr(tArrRec),mask=np.isnan(rec2ndarr(tArrRec))).view(dtype=tArrRec.dtype) try: outTemp = recFunc.stack_arrays((outTemp,mArrRec)) except NameError as e: outTemp = mArrRec # Assign the data self._data = outTemp
def Jtvec(self, m, v, u=None): """ Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector. :param numpy.ndarray m (nC, 1) - conductive model :param numpy.ndarray v (nD, 1) - vector :param MTfields object u (optional) - MT fields object, if not given it is calculated :rtype: MTdata object :return: Data sensitivities wrt m """ if u is None: u = 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) for freq in self.survey.freqs: AT = self.getA(freq).T ATinv = self.Solver(AT, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): ftype = self._fieldType + 'Solution' u_src = u[src, :] for rx in src.rxList: # Get the adjoint evalDeriv # PTv needs to be nE, PTv = rx.evalDeriv(src, self.mesh, u, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m # Get the dA_duIT = ATinv * PTv dA_dmT = self.getADeriv_m(freq, u_src, mkvc(dA_duIT), adjoint=True) dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True) # Make du_dmT if dRHS_dmT is None: du_dmT = -dA_dmT else: du_dmT = -dA_dmT + dRHS_dmT # Select the correct component # du_dmT needs to be of size nC, real_or_imag = rx.projComp if real_or_imag == 'real': Jtv += du_dmT.real elif real_or_imag == 'imag': Jtv += -du_dmT.real else: raise Exception('Must be real or imag') # Clean the factorization, clear memory. ATinv.clean() return Jtv
def Jtvec(self, m, v, f=None): """ Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector. :param numpy.ndarray m: inversion model (nP,) :param numpy.ndarray v: vector which we take adjoint product with (nP,) :param SimPEG.EM.NSEM.FieldsNSEM f (optional): NSEM fields object, if not given it is calculated :rtype: numpy.ndarray :return: Jtv (nP,) Data sensitivities wrt m """ if f is None: f = self.fields(m) self.model = m # Ensure v is a data object. if not isinstance(v, self.dataPair): v = self.dataPair(self.survey, v) Jtv = np.zeros(m.size) for freq in self.survey.freqs: AT = self.getA(freq).T ATinv = self.Solver(AT, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # u_src needs to have both polarizations u_src = f[src, :] for rx in src.rxList: # Get the adjoint evalDeriv # PTv needs to be nE,2 PTv = rx.evalDeriv( src, self.mesh, f, mkvc(v[src, rx]), adjoint=True) # wrt f, need possibility wrt m # Get the dA_duIT = mkvc(ATinv * PTv) # Force (nU,) shape dA_dmT = self.getADeriv(freq, u_src, dA_duIT, adjoint=True) dRHS_dmT = self.getRHSDeriv(freq, dA_duIT, adjoint=True) # Make du_dmT du_dmT = -dA_dmT + dRHS_dmT # Select the correct component # du_dmT needs to be of size (nP,) number of model parameters real_or_imag = rx.component if real_or_imag == 'real': Jtv += np.array(du_dmT, dtype=complex).real elif real_or_imag == 'imag': Jtv += -np.array(du_dmT, dtype=complex).real else: raise Exception('Must be real or imag') # Clean the factorization, clear memory. ATinv.clean() return Jtv
def getADeriv(self, freq, u, v, adjoint=False): """ The derivative of A wrt sigma """ u_src = u['e_1dSolution'] dMfSigma_dm = self.MfSigmaDeriv(u_src) if adjoint: return 1j * omega(freq) * mkvc(dMfSigma_dm.T * v, ) # Note: output has to be nN/nF, not nC/nE. # v should be nC return 1j * omega(freq) * mkvc(dMfSigma_dm * v, )
def getADeriv(self, freq, u, v, adjoint=False): """ The derivative of A wrt sigma """ u_src = u['e_1dSolution'] dMfSigma_dm = self.MfSigmaDeriv(u_src) if adjoint: return 1j * omega(freq) * mkvc(dMfSigma_dm.T * v,) # Note: output has to be nN/nF, not nC/nE. # v should be nC return 1j * omega(freq) * mkvc(dMfSigma_dm * v,)
def Jtvec(self, m, v, f=None): """ Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector. :param numpy.ndarray m: inversion model (nP,) :param numpy.ndarray v: vector which we take adjoint product with (nP,) :param SimPEG.EM.NSEM.FieldsNSEM f (optional): NSEM fields object, if not given it is calculated :rtype: numpy.ndarray :return: Jtv (nP,) Data sensitivities wrt m """ if f is None: f = self.fields(m) self.model = m # Ensure v is a data object. if not isinstance(v, self.dataPair): v = self.dataPair(self.survey, v) Jtv = np.zeros(m.size) for freq in self.survey.freqs: AT = self.getA(freq).T ATinv = self.Solver(AT, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # u_src needs to have both polarizations u_src = f[src, :] for rx in src.rxList: # Get the adjoint evalDeriv # PTv needs to be nE,2 PTv = rx.evalDeriv(src, self.mesh, f, mkvc(v[src, rx]), adjoint=True) # wrt f, need possibility wrt m # Get the dA_duIT = mkvc(ATinv * PTv) # Force (nU,) shape dA_dmT = self.getADeriv(freq, u_src, dA_duIT, adjoint=True) dRHS_dmT = self.getRHSDeriv(freq, dA_duIT, adjoint=True) # Make du_dmT du_dmT = -dA_dmT + dRHS_dmT # Select the correct component # du_dmT needs to be of size (nP,) number of model parameters real_or_imag = rx.component if real_or_imag == 'real': Jtv += np.array(du_dmT, dtype=complex).real elif real_or_imag == 'imag': Jtv += -np.array(du_dmT, dtype=complex).real else: raise Exception('Must be real or imag') # Clean the factorization, clear memory. ATinv.clean() return Jtv
def Jtvec(self, m, v, u=None): if u is None: u = 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) for freq in self.survey.freqs: AT = self.getA(freq).T ATinv = self.Solver(AT, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): ftype = self._fieldType + 'Solution' u_src = u[src, :] for rx in src.rxList: # Get the adjoint projectFieldsDeriv # PTv needs to be nE, PTv = rx.projectFieldsDeriv( src, self.mesh, u, mkvc(v[src, rx], 2), adjoint=True) # wrt u, need possibility wrt m # Get the dA_duIT = ATinv * PTv dA_dmT = self.getADeriv_m(freq, u_src, mkvc(dA_duIT), adjoint=True) dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True) # Make du_dmT if dRHS_dmT is None: du_dmT = -dA_dmT else: du_dmT = -dA_dmT + dRHS_dmT # Select the correct component # du_dmT needs to be of size nC, real_or_imag = rx.projComp if real_or_imag == 'real': Jtv += du_dmT.real elif real_or_imag == 'imag': Jtv += -du_dmT.real else: raise Exception('Must be real or imag') return Jtv
def _getSubsetAcolumns(self, xyzc, xyzh, pp, qq, refFlag): """ This method returns the refined sensitivities for columns that will be replaced in the A matrix for source pp and refinement factor qq. .. .. INPUTS: .. .. xyzc -- Cell centers of topo mesh cells N X 3 array .. .. xyzh -- Cell widths of topo mesh cells N X 3 array .. .. pp -- Source ID .. .. qq -- Mesh refinement factor .. .. refFlag -- refinement factors for all topo mesh cells .. .. OUTPUTS: .. .. Acols -- Columns containing replacement sensitivities """ # GET SUBMESH GRID n = 2**qq [nx, ny, nz] = np.meshgrid( np.linspace(1, n, n) - 0.5, np.linspace(1, n, n) - 0.5, np.linspace(1, n, n) - 0.5) nxyz_sub = np.c_[mkvc(nx), mkvc(ny), mkvc(nz)] xyzh_sub = xyzh[refFlag == qq, :] # Get widths of cells to be refined xyzc_sub = xyzc[refFlag == qq, :] - xyzh[ refFlag == qq, :] / 2 # Get bottom southwest corners of cells to be refined m = np.shape(xyzc_sub)[0] xyzc_sub = np.kron(xyzc_sub, np.ones( (n**3, 1))) # Kron for n**3 refined cells xyzh_sub = np.kron(xyzh_sub / n, np.ones( (n**3, 1))) # Kron for n**3 refined cells with widths h/n nxyz_sub = np.kron(np.ones((m, 1)), nxyz_sub) # Kron for n**3 refined cells xyzc_sub = xyzc_sub + xyzh_sub * nxyz_sub # GET SUBMESH A MATRIX AND COLLAPSE TO COLUMNS G = self._getGeometryMatrix(xyzc_sub, xyzh_sub, pp) H0 = self._getH0matrix(xyzc_sub, pp) Acols = (G * H0) * sp.kron(sp.diags(np.ones(m)), np.ones((n**3, 1))) return Acols
def Jvec(self, m, v, f=None): """ Function to calculate the data sensitivities dD/dm times a vector. :param numpy.ndarray m: conductivity model (nP,) :param numpy.ndarray v: vector which we take sensitivity product with (nP,) :param SimPEG.EM.NSEM.FieldsNSEM (optional) u: NSEM fields object, if not given it is calculated :rtype: numpy.ndarray :return: Jv (nData,) Data sensitivities wrt m """ # Calculate the fields if not given as input if f is None: f = self.fields(m) # Set current model self.curModel = m # Initiate the Jv object Jv = self.dataPair(self.survey) # Loop all the frequenies for freq in self.survey.freqs: # Get the system A = self.getA(freq) # Factor Ainv = self.Solver(A, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # We need fDeriv_m = df/du*du/dm + df/dm # Construct du/dm, it requires a solve # NOTE: need to account for the 2 polarizations in the derivatives. u_src = f[ src, :] # u should be a vector by definition. Need to fix this... # dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by Ainv. # The 2 columns are each of the polarizations. dA_dm_v = self.getADeriv( freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns. dRHS_dm_v = self.getRHSDeriv( freq, v) # Size: nE,2 (u_px,u_py) in the columns. # Calculate du/dm*v du_dm_v = Ainv * (-dA_dm_v + dRHS_dm_v) # Calculate the projection derivatives for rx in src.rxList: # Calculate dP/du*du/dm*v Jv[src, rx] = rx.evalDeriv( src, self.mesh, f, mkvc(du_dm_v)) # wrt uPDeriv_u(mkvc(du_dm)) Ainv.clean() # Return the vectorized sensitivities return mkvc(Jv)
def Jvec(self, m, v, u=None): """ Function to calculate the data sensitivities dD/dm times a vector. :param numpy.ndarray (nC, 1) - conductive model :param numpy.ndarray (nC, 1) - random vector :param MTfields object (optional) - MT fields object, if not given it is calculated :rtype: MTdata object :return: Data sensitivities wrt m """ # Calculate the fields if u is None: u = self.fields(m) # Set current model self.curModel = m # Initiate the Jv object Jv = self.dataPair(self.survey) # Loop all the frequenies for freq in self.survey.freqs: dA_du = self.getA(freq) # dA_duI = self.Solver(dA_du, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # We need fDeriv_m = df/du*du/dm + df/dm # Construct du/dm, it requires a solve # NOTE: need to account for the 2 polarizations in the derivatives. u_src = u[src, :] # dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations. dA_dm = self.getADeriv_m( freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns. dRHS_dm = self.getRHSDeriv_m( freq, v) # Size: nE,2 (u_px,u_py) in the columns. if dRHS_dm is None: du_dm = dA_duI * (-dA_dm) else: du_dm = dA_duI * (-dA_dm + dRHS_dm) # Calculate the projection derivatives for rx in src.rxList: # Get the projection derivative # v should be of size 2*nE (for 2 polarizations) PDeriv_u = lambda t: rx.projectFieldsDeriv( src, self.mesh, u, t ) # wrt u, we don't have have PDeriv wrt m Jv[src, rx] = PDeriv_u(mkvc(du_dm)) # Return the vectorized sensitivities return mkvc(Jv)
def writeUBC_DCobs(fileName,Tx,Rx,d,wd, dtype): from SimPEG import np, mkvc import re """ 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: :param rx, tx, d, wd :return Created on Mon December 7th, 2015 @author: dominiquef """ fid = open(fileName,'w') fid.write('! GENERAL FORMAT\n') for ii in range(len(Tx)): tx = np.asarray(Tx[ii]) rx = np.asarray(Rx[ii]) nrx = rx.shape[0] fid.write('\n') if re.match(dtype,'2D'): for jj in range(nrx): fid.writelines("%e " % ii for ii in mkvc(tx)) fid.writelines("%e " % ii for ii in mkvc(rx[jj])) fid.write('%e %e\n'% (d[ii][jj],wd[ii][jj])) #np.savetxt(fid, np.c_[ rx ,np.asarray(d[ii]), np.asarray(wd[ii]) ], fmt='%e',delimiter=' ',newline='\n') elif re.match(dtype,'3D'): fid.write('\n') fid.writelines("%e " % ii for ii in mkvc(tx)) fid.write('%i\n'% nrx) np.savetxt(fid, np.c_[ rx ,np.asarray(d[ii]), np.asarray(wd[ii]) ], fmt='%e',delimiter=' ',newline='\n') fid.close()
def fields(self, m=None): """Computes the fields at every time d(t) = G*M(t)""" if self.ispaired is False: AssertionError("Problem must be paired with survey to generate A matrix") # Fields from each source srcList = self.survey.srcList nSrc = len(srcList) f = [] for pp in range(0, nSrc): rxList = srcList[pp].rxList nRx = len(rxList) waveObj = srcList[pp].waveform for qq in range(0, nRx): times = rxList[qq].times eta = waveObj.getLogUniformDecay( rxList[qq].fieldType, times, self.chi0, self.dchi, self.tau1, self.tau2 ) f.append(mkvc((self.A[qq] * np.matrix(eta)).T)) return np.array(np.hstack(f))
def getADeriv_m(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. """ # This considers both polarizations and returns a nE,2 matrix for each polarization if adjoint: dMe_dsigV = sp.hstack((self.MeSigmaDeriv(u['e_pxSolution']).T, self.MeSigmaDeriv(u['e_pySolution']).T)) * v else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( (mkvc(self.MeSigmaDeriv(u['e_pxSolution']) * v, 2), mkvc(self.MeSigmaDeriv(u['e_pySolution']) * v, 2))) return 1j * omega(freq) * dMe_dsigV
def fields(self, m=None): """Computes the fields at every time d(t) = G*M(t)""" if self.ispaired is False: AssertionError( "Problem must be paired with survey to generate A matrix") # Fields from each source srcList = self.survey.srcList nSrc = len(srcList) f = [] for pp in range(0, nSrc): rxList = srcList[pp].rxList nRx = len(rxList) waveObj = srcList[pp].waveform for qq in range(0, nRx): times = rxList[qq].times eta = waveObj.getLogUniformDecay(rxList[qq].fieldType, times, self.chi0, self.dchi, self.tau1, self.tau2) f.append(mkvc((self.A[qq] * np.matrix(eta)).T)) return np.array(np.hstack(f))
def _aey_py_u(self, vec): """ """ # vec is (nD,) and returns a (nU,) return self.f._e_pyDeriv_u(self.src, self.Pey.T * mkvc(vec, ), adjoint=True)
def fields(self, m): ''' Function to calculate all the fields for the model m. :param np.ndarray (nC,) m: Conductivity model :param np.ndarray (nC,) m_back: Background conductivity model ''' self.curModel = m # RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields F = Fields1D_e(self.mesh, self.survey) for freq in self.survey.freqs: if self.verbose: startTime = time.time() print 'Starting work for {:.3e}'.format(freq) sys.stdout.flush() A = self.getA(freq) rhs, e_o = self.getRHS(freq) Ainv = self.Solver(A, **self.solverOpts) e_i = Ainv * rhs e = mkvc(np.r_[e_o[0], e_i, e_o[1]], 2) # Store the fields Src = self.survey.getSrcByFreq(freq) # NOTE: only store e fields F[Src, 'e_1dSolution'] = e[:, 0] if self.verbose: print 'Ran for {:f} seconds'.format(time.time() - startTime) sys.stdout.flush() return F
def fields(self, m): ''' Function to calculate all the fields for the model m. :param np.ndarray (nC,) m: Conductivity model :param np.ndarray (nC,) m_back: Background conductivity model ''' self.curModel = m # RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields F = FieldsMT_1D(self.mesh, self.survey) for freq in self.survey.freqs: if self.verbose: startTime = time.time() print 'Starting work for {:.3e}'.format(freq) sys.stdout.flush() A = self.getA(freq) rhs, e_o = self.getRHS(freq) Ainv = self.Solver(A, **self.solverOpts) e_i = Ainv * rhs e = mkvc(np.r_[e_o[0], e_i, e_o[1]],2) # Store the fields Src = self.survey.getSrcByFreq(freq) # NOTE: only store e fields F[Src, 'e_1dSolution'] = e[:,0] if self.verbose: print 'Ran for {:f} seconds'.format(time.time()-startTime) sys.stdout.flush() return F
def Jvec(self, m, v, u=None): """ Function to calculate the data sensitivities dD/dm times a vector. :param numpy.ndarray m (nC, 1) - conductive model :param numpy.ndarray v (nC, 1) - random vector :param MTfields object (optional) - MT fields object, if not given it is calculated :rtype: MTdata object :return: Data sensitivities wrt m """ # Calculate the fields if u is None: u = self.fields(m) # Set current model self.curModel = m # Initiate the Jv object Jv = self.dataPair(self.survey) # Loop all the frequenies for freq in self.survey.freqs: dA_du = self.getA(freq) # dA_duI = self.Solver(dA_du, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # We need fDeriv_m = df/du*du/dm + df/dm # Construct du/dm, it requires a solve # NOTE: need to account for the 2 polarizations in the derivatives. u_src = u[src,:] # dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations. dA_dm = self.getADeriv_m(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns. dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns. if dRHS_dm is None: du_dm = dA_duI * ( -dA_dm ) else: du_dm = dA_duI * ( -dA_dm + dRHS_dm ) # Calculate the projection derivatives for rx in src.rxList: # Get the projection derivative # v should be of size 2*nE (for 2 polarizations) PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, u, t) # wrt u, we don't have have PDeriv wrt m Jv[src, rx] = PDeriv_u(mkvc(du_dm)) dA_duI.clean() # Return the vectorized sensitivities return mkvc(Jv)
def fun(u): f = simulation.fieldsPair(survey.mesh, survey) f[src, "e_pxSolution"] = u[:len(u) / 2] f[src, "e_pySolution"] = u[len(u) / 2::] return ( rx.eval(src, survey.mesh, f), lambda t: rx.evalDeriv(src, survey.mesh, f0, mkvc(t, 2)), )
def Jtvec(self, m, v, u=None): if u is None: u = 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) for freq in self.survey.freqs: AT = self.getA(freq).T ATinv = self.Solver(AT, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): ftype = self._fieldType + 'Solution' u_src = u[src, :] for rx in src.rxList: # Get the adjoint projectFieldsDeriv # PTv needs to be nE, PTv = rx.projectFieldsDeriv(src, self.mesh, u, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m # Get the dA_duIT = ATinv * PTv dA_dmT = self.getADeriv_m(freq, u_src, mkvc(dA_duIT), adjoint=True) dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True) # Make du_dmT if dRHS_dmT is None: du_dmT = -dA_dmT else: du_dmT = -dA_dmT + dRHS_dmT # Select the correct component # du_dmT needs to be of size nC, real_or_imag = rx.projComp if real_or_imag == 'real': Jtv += du_dmT.real elif real_or_imag == 'imag': Jtv += -du_dmT.real else: raise Exception('Must be real or imag') return Jtv
def Jvec(self, m, v, f=None): """ Function to calculate the data sensitivities dD/dm times a vector. :param numpy.ndarray m: conductivity model (nP,) :param numpy.ndarray v: vector which we take sensitivity product with (nP,) :param SimPEG.EM.NSEM.FieldsNSEM (optional) u: NSEM fields object, if not given it is calculated :rtype: numpy.ndarray :return: Jv (nData,) Data sensitivities wrt m """ # Calculate the fields if not given as input if f is None: f = self.fields(m) # Set current model self.model = m # Initiate the Jv object Jv = self.dataPair(self.survey) # Loop all the frequenies for freq in self.survey.freqs: # Get the system A = self.getA(freq) # Factor Ainv = self.Solver(A, **self.solverOpts) for src in self.survey.getSrcByFreq(freq): # We need fDeriv_m = df/du*du/dm + df/dm # Construct du/dm, it requires a solve # NOTE: need to account for the 2 polarizations in the derivatives. u_src = f[src,:] # u should be a vector by definition. Need to fix this... # dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by Ainv. # The 2 columns are each of the polarizations. dA_dm_v = self.getADeriv(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns. dRHS_dm_v = self.getRHSDeriv(freq, v) # Size: nE,2 (u_px,u_py) in the columns. # Calculate du/dm*v du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v) # Calculate the projection derivatives for rx in src.rxList: # Calculate dP/du*du/dm*v Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, mkvc(du_dm_v)) # wrt uPDeriv_u(mkvc(du_dm)) Ainv.clean() # Return the vectorized sensitivities return mkvc(Jv)
def getRHSDeriv(self, freq, v, adjoint=False): """ The derivative of the RHS wrt sigma """ Src = self.survey.getSrcByFreq(freq)[0] S_eDeriv = mkvc(Src.S_eDeriv_m(self, v, adjoint), ) return -1j * omega(freq) * S_eDeriv
def getRHSDeriv(self, freq, v, adjoint=False): """ The derivative of the RHS wrt sigma """ Src = self.survey.getSrcByFreq(freq)[0] S_eDeriv = mkvc(Src.S_eDeriv_m(self, v, adjoint),) return -1j * omega(freq) * S_eDeriv
def projectFields(self, u): """ Predicted data. .. math:: d_\\text{pred} = Pu(m) """ P = self.getP(self.prob.mesh) return P*mkvc(u[self.srcList, 'phi_sol'])
def _getSubsetAcolumns(self, xyzc, xyzh, pp, qq, refFlag): """ This method returns the refined sensitivities for columns that will be replaced in the A matrix for source pp and refinement factor qq. .. .. INPUTS: .. .. xyzc -- Cell centers of topo mesh cells N X 3 array .. .. xyzh -- Cell widths of topo mesh cells N X 3 array .. .. pp -- Source ID .. .. qq -- Mesh refinement factor .. .. refFlag -- refinement factors for all topo mesh cells .. .. OUTPUTS: .. .. Acols -- Columns containing replacement sensitivities """ # GET SUBMESH GRID n = 2**qq [nx, ny, nz] = np.meshgrid( np.linspace(1, n, n)-0.5, np.linspace(1, n, n)-0.5, np.linspace(1, n, n)-0.5) nxyz_sub = np.c_[mkvc(nx), mkvc(ny), mkvc(nz)] xyzh_sub = xyzh[refFlag == qq, :] # Get widths of cells to be refined xyzc_sub = xyzc[refFlag == qq, :] - xyzh[refFlag == qq, :]/2 # Get bottom southwest corners of cells to be refined m = np.shape(xyzc_sub)[0] xyzc_sub = np.kron(xyzc_sub, np.ones((n**3, 1))) # Kron for n**3 refined cells xyzh_sub = np.kron(xyzh_sub/n, np.ones((n**3, 1))) # Kron for n**3 refined cells with widths h/n nxyz_sub = np.kron(np.ones((m, 1)), nxyz_sub) # Kron for n**3 refined cells xyzc_sub = xyzc_sub + xyzh_sub*nxyz_sub # GET SUBMESH A MATRIX AND COLLAPSE TO COLUMNS G = self._getGeometryMatrix(xyzc_sub, xyzh_sub, pp) H0 = self._getH0matrix(xyzc_sub, pp) Acols = (G*H0)*sp.kron(sp.diags(np.ones(m)), np.ones((n**3, 1))) return Acols
def setup1DSurvey(sigmaHalf, tD=False, structure=False): # Frequency num_frequencies = 33 freqs = np.logspace(3, -3, num_frequencies) # Make the mesh ct = 5 air = meshTensor([(ct, 25, 1.3)]) # coreT0 = meshTensor([(ct,15,1.2)]) # coreT1 = np.kron(meshTensor([(coreT0[-1],15,1.3)]),np.ones((7,))) core = np.concatenate((np.kron(meshTensor([(ct, 15, -1.2)]), np.ones( (10, ))), meshTensor([(ct, 20)]))) bot = meshTensor([(core[0], 20, -1.3)]) x0 = -np.array([np.sum(np.concatenate((core, bot)))]) m1d = discretize.TensorMesh([np.concatenate((bot, core, air))], x0=x0) # Make the model sigma = np.zeros(m1d.nC) + sigmaHalf sigma[m1d.gridCC > 0] = 1e-8 sigmaBack = sigma.copy() # Add structure if structure: shallow = (m1d.gridCC < -200) * (m1d.gridCC > -600) deep = (m1d.gridCC < -3000) * (m1d.gridCC > -5000) sigma[shallow] = 1 sigma[deep] = 0.1 receiver_list = [] for rxType in ["z1d", "z1d"]: receiver_list.append( Point1DImpedance(mkvc(np.array([0.0]), 2).T, "real")) receiver_list.append( Point1DImpedance(mkvc(np.array([0.0]), 2).T, "imag")) # Source list source_list = [] if tD: for freq in freqs: source_list.append(Planewave_xy_1DhomotD(receiver_list, freq)) else: for freq in freqs: source_list.append(Planewave_xy_1Dprimary(receiver_list, freq)) survey = Survey(source_list) return (survey, sigma, sigmaBack, m1d)
def toRecArray(self,returnType='RealImag'): ''' Function that returns a numpy.recarray for a SimpegMT impedance data object. :param str returnType: Switches between returning a rec array where the impedance is split to real and imaginary ('RealImag') or is a complex ('Complex') ''' # Define the record fields dtRI = [('freq',float),('x',float),('y',float),('z',float),('zxxr',float),('zxxi',float),('zxyr',float),('zxyi',float), ('zyxr',float),('zyxi',float),('zyyr',float),('zyyi',float),('tzxr',float),('tzxi',float),('tzyr',float),('tzyi',float)] dtCP = [('freq',float),('x',float),('y',float),('z',float),('zxx',complex),('zxy',complex),('zyx',complex),('zyy',complex),('tzx',complex),('tzy',complex)] impList = ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi'] for src in self.survey.srcList: # Temp array for all the receivers of the source. # Note: needs to be written more generally, using diffterent rxTypes and not all the data at the locaitons # Assume the same locs for all RX locs = src.rxList[0].locs if locs.shape[1] == 1: locs = np.hstack((np.array([[0.0,0.0]]),locs)) elif locs.shape[1] == 2: locs = np.hstack((np.array([[0.0]]),locs)) tArrRec = np.concatenate((src.freq*np.ones((locs.shape[0],1)),locs,np.nan*np.ones((locs.shape[0],12))),axis=1).view(dtRI) # np.array([(src.freq,rx.locs[0,0],rx.locs[0,1],rx.locs[0,2],np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ) for rx in src.rxList],dtype=dtRI) # Get the type and the value for the DataMT object as a list typeList = [[rx.rxType.replace('z1d','zyx'),self[src,rx]] for rx in src.rxList] # Insert the values to the temp array for nr,(key,val) in enumerate(typeList): tArrRec[key] = mkvc(val,2) # Masked array mArrRec = np.ma.MaskedArray(rec2ndarr(tArrRec),mask=np.isnan(rec2ndarr(tArrRec))).view(dtype=tArrRec.dtype) # Unique freq and loc of the masked array uniFLmarr = np.unique(mArrRec[['freq','x','y','z']]).copy() try: outTemp = recFunc.stack_arrays((outTemp,mArrRec)) #outTemp = np.concatenate((outTemp,dataBlock),axis=0) except NameError as e: outTemp = mArrRec if 'RealImag' in returnType: outArr = outTemp elif 'Complex' in returnType: # Add the real and imaginary to a complex number outArr = np.empty(outTemp.shape,dtype=dtCP) for comp in ['freq','x','y','z']: outArr[comp] = outTemp[comp].copy() for comp in ['zxx','zxy','zyx','zyy','tzx','tzy']: outArr[comp] = outTemp[comp+'r'].copy() + 1j*outTemp[comp+'i'].copy() else: raise NotImplementedError('{:s} is not implemented, as to be RealImag or Complex.') # Return return outArr
def Jvec(self, m, v, u=None): """ :param numpy.array m: model :param numpy.array v: vector to multiply :param numpy.array u: fields :rtype: numpy.array :return: Jv .. math:: c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0 \\nabla_u (A(m)u - q) = A(m) \\nabla_m (A(m)u - q) = G\\text{sdiag}(Du)\\nabla_m(M(mT(m))) Where M() is the mass matrix and mT is the model transform. .. math:: J = - P \left( \\nabla_u c(m, u) \\right)^{-1} \\nabla_m c(m, u) J(v) = - P ( A(m)^{-1} ( G\\text{sdiag}(Du)\\nabla_m(M(mT(m))) v ) ) """ # Set current model; clear dependent property $\mathbf{A(m)}$ self.curModel = m sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ if u is None: # Run forward simulation if $u$ not provided u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol'] else: u = u[self.survey.srcList, 'phi_sol'] D = self.mesh.faceDiv G = self.mesh.cellGrad # Derivative of model transform, $\deriv{\sigma}{\m}$ dsigdm_x_v = self.curModel.transformDeriv * v # 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$ dA_du = self.A # Solve for $\deriv{u}{m}$ # dCdu_inv = self.Solver(dCdu, **self.solverOpts) if self.Ainv is None: self.Ainv = self.Solver(dA_du, **self.solverOpts) P = self.survey.getP(self.mesh) Jv = - P * mkvc( self.Ainv * dCdm_x_v ) return Jv
def readUBC_DC2DModel(fileName): from SimPEG import np, mkvc """ 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 """ # Open fileand skip header... assume that we know the mesh already obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') dim = np.array(obsfile[0].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) model[:,ii] = mm model = model[:,::-1] else: if len(obsfile[1:])==1: mm = np.array(obsfile[1:].split(),dtype=float) else: mm = np.array(obsfile[1:],dtype=float) # Permute the second dimension to flip the order model = mm.reshape(dim[1],dim[0]) model = model[::-1,:] model = np.transpose(model, (1, 0)) model = mkvc(model) return model
def S_eDeriv_m(self, problem, v, adjoint=False): ''' Get the derivative of S_e wrt to sigma (m) ''' # Need to deal with if problem.mesh.dim == 1: # Need to use the faceInnerProduct MsigmaDeriv = ( problem.mesh.getFaceInnerProductDeriv( problem.sigma)(self.ePrimary(problem)[:, 1]) * problem.sigmaDeriv) # MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2 if problem.mesh.dim == 2: pass if problem.mesh.dim == 3: # Need to take the derivative of both u_px and u_py ePri = self.ePrimary(problem) if adjoint: return ( problem.MeSigmaDeriv( ePri[:, 0], v[:int(v.shape[0]/2)], adjoint ) + problem.MeSigmaDeriv( ePri[:, 1], v[int(v.shape[0]/2):], adjoint ) ) # return sp.hstack(( # problem.MeSigmaDeriv(ePri[:, 0]).T, # problem.MeSigmaDeriv(ePri[:, 1]).T)) * v else: return np.hstack(( mkvc(problem.MeSigmaDeriv(ePri[:, 0], v, adjoint), 2), mkvc(problem.MeSigmaDeriv(ePri[:, 1], v, adjoint), 2) )) if adjoint: # return MsigmaDeriv.T * v else: # v should be nC size return MsigmaDeriv * v
def readUBC_DC2DModel(fileName): """ 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 """ 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='!') dim = np.array(obsfile[0].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) model[:,ii] = mm model = model[:,::-1] else: if len(obsfile[1:])==1: mm = np.array(obsfile[1:].split(),dtype=float) else: mm = np.array(obsfile[1:],dtype=float) # Permute the second dimension to flip the order model = mm.reshape(dim[1],dim[0]) model = model[::-1,:] model = np.transpose(model, (1, 0)) model = mkvc(model) return model
def getRHS(self, freq): """ Function to return the right hand side for the system. :param float freq: Frequency :rtype: numpy.ndarray :return: RHS for 1 polarizations, primary fields (nF, 1) """ # Get sources for the frequncy(polarizations) Src = self.survey.getSrcByFreq(freq)[0] # Only select the yx polarization S_e = mkvc(Src.S_e(self)[:, 1], 2) return -1j * omega(freq) * S_e
def getADeriv_m(self, freq, u, v, adjoint=False): # Nee to account for both the polarizations # dMe_dsig = (self.MeSigmaDeriv( u['e_pxSolution'] ) + self.MeSigmaDeriv( u['e_pySolution'] )) # dMe_dsig = (self.MeSigmaDeriv( u['e_pxSolution'] + u['e_pySolution'] )) # # dMe_dsig = self.MeSigmaDeriv( u ) # if adjoint: # return 1j * omega(freq) * ( dMe_dsig.T * v ) # As in simpegEM # return 1j * omega(freq) * ( dMe_dsig * v ) # As in simpegEM # This considers both polarizations and returns a nE,2 matrix for each polarization if adjoint: dMe_dsigV = sp.hstack((self.MeSigmaDeriv(u['e_pxSolution']).T, self.MeSigmaDeriv(u['e_pySolution']).T)) * v else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( (mkvc(self.MeSigmaDeriv(u['e_pxSolution']) * v, 2), mkvc(self.MeSigmaDeriv(u['e_pySolution']) * v, 2))) return 1j * omega(freq) * dMe_dsigV
def getADeriv_m(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. """ # This considers both polarizations and returns a nE,2 matrix for each polarization if adjoint: dMe_dsigV = sp.hstack(( self.MeSigmaDeriv( u['e_pxSolution'] ).T, self.MeSigmaDeriv(u['e_pySolution'] ).T ))*v else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack(( mkvc(self.MeSigmaDeriv( u['e_pxSolution'] )*v,2), mkvc( self.MeSigmaDeriv(u['e_pySolution'] )*v,2) )) return 1j * omega(freq) * dMe_dsigV
def fields(self, m): """Computes the fields d = T*A*m""" assert self.ispaired, "Problem must be paired with survey to predict data" self.model = m # Initiates/updates model and initiates mapping # Project to active mesh cells # m = np.matrix(self.xiMap * m).T m = np.matrix(self.xiMap * m).T # Must return as a numpy array return mkvc(sp.coo_matrix.dot(self.T, np.dot(self.A, m)))
def grid_survey(spacing,width, x0 = (0,0,0), topo=None): """ grid_survey(spacing,width) Generate concentric grid surveys centered at the origin :grid: List of grid spacing :width: Grid width return: rxLoc an n-by-3 receiver locations """ rxLoc = [] if len(spacing)!=len(width): raise 'Number of elements in spacing different than grid width' ii = -1 for dx in spacing: ii += 1 # Define survey grids centered at [0,0] # Number of grid points that fits in the width nC = int(width[ii]/dx) rxVec = -width[ii]/2. + dx/2. + np.asarray(range(nC))*dx rxGridx, rxGridy = np.meshgrid(rxVec,rxVec) rxGridx += x0[0] rxGridy += x0[1] if topo is not None: rxGridz = scipy.interpolate.griddata(topo[:,:2], topo[:,2], (rxGridx, rxGridy), method='linear') + x0[2] else: rxGridz = np.zeros_like(rxGridx) + x0[2] # Remove points if already inside inner grid if ii > 0: indx = np.logical_and(np.logical_and(rxGridy<rxLoc[:,1].max(), rxGridy>rxLoc[:,1].min()),np.logical_and(rxGridx>rxLoc[:,0].min(), rxGridx<rxLoc[:,0].max())) indx = indx.reshape(rxGridx.shape) rxGridx = rxGridx[indx==0] rxGridy = rxGridy[indx==0] rxGridz = rxGridz[indx==0] rxLoc = np.vstack([rxLoc, np.c_[mkvc(rxGridx),mkvc(rxGridy),mkvc(rxGridz)]]) else: rxLoc = np.c_[mkvc(rxGridx),mkvc(rxGridy),mkvc(rxGridz)] return rxGridx, rxGridy, rxGridz
def fields(self, m): """Computes the fields d = T*A*m""" if self.ispaired is False: AssertionError( "Problem must be paired with survey to generate A matrix") self.model = m # Initiates/updates model and initiates mapping # Project to active mesh cells # m = np.matrix(self.xiMap * m).T m = np.matrix(self.xiMap * m).T # Must return as a numpy array return mkvc(sp.coo_matrix.dot(self.T, np.dot(self.A, m)))
def fields(self, m): """Computes the fields d = T*A*m""" if self.ispaired is False: AssertionError("Problem must be paired with survey to generate A matrix") self.model = m # Initiates/updates model and initiates mapping # Project to active mesh cells # m = np.matrix(self.xiMap * m).T m = np.matrix(self.xiMap * m).T # Must return as a numpy array return mkvc(sp.coo_matrix.dot(self.T, np.dot(self.A, m)))
def dataMis_AnalyticPrimarySecondary(sigmaHalf): # Make the survey # Primary secondary survey, sig, sigBG, mesh = nsem.utils.test_utils.setup1DSurvey( sigmaHalf, False, structure=True) # Analytic data simulation = nsem.Simulation1DPrimarySecondary(mesh, sigmaPrimary=sig, sigma=sig, survey=survey) dataAnaObj = calculateAnalyticSolution(survey.source_list, mesh, sig) data = simulation.dpred() dataAna = mkvc(dataAnaObj) return np.all((data - dataAna) / dataAna < 2.0)
def Jvec(self, m, v, f=None): """Compute Pd*T*A*dxidm*v""" if self.ispaired is False: AssertionError("Problem must be paired with survey to generate A matrix") # Jacobian of xi wrt model dxidm = self.xiMap.deriv(m) # dxidm*v v = np.matrix(dxidm*v).T # Dot product with A v = self.A*v # Get active time rows of T T = self.T.tocsr()[self.survey.t_active, :] # Must return an array return mkvc(sp.csr_matrix.dot(T, v))
def Jtvec(self, m, v, f=None): """Compute (Pd*T*A*dxidm)^T * v""" if self.ispaired is False: AssertionError("Problem must be paired with survey to generate A matrix") # Define v as a column vector v = np.matrix(v).T # Get T'*Pd'*v T = self.T.tocsr()[self.survey.t_active, :] v = sp.csc_matrix.dot(T.transpose(), v) # Multiply by A' v = (np.dot(v.T, self.A)).T # Jacobian of xi wrt model dxidm = self.xiMap.deriv(m) # Must return an array return mkvc(dxidm.T*v)
def _hx(self): return self.Pbx * mkvc(self.f[self.src, 'b_1d'], 2) / mu_0
def eval(self, src, mesh, f): ''' Project the fields to natural source data. :param SrcMT src: The source of the fields to project :param SimPEG.Mesh mesh: :param FieldsMT f: Natural source fields object to project ''' ## NOTE: Assumes that e is on t if self.projType is 'Z1D': Pex = mesh.getInterpolationMat(self.locs[:,-1],'Fx') Pbx = mesh.getInterpolationMat(self.locs[:,-1],'Ex') ex = Pex*mkvc(f[src,'e_1d'],2) bx = Pbx*mkvc(f[src,'b_1d'],2)/mu_0 # Note: Has a minus sign in front, to comply with quadrant calculations. # Can be derived from zyx case for the 3D case. f_part_complex = -ex/bx # elif self.projType is 'Z2D': elif self.projType is 'Z3D': ## NOTE: Assumes that e is on edges and b on the faces. Need to generalize that or use a prop of fields to determine that. if self.locs.ndim == 3: eFLocs = self.locs[:,:,0] bFLocs = self.locs[:,:,1] else: eFLocs = self.locs bFLocs = self.locs # Get the projection Pex = mesh.getInterpolationMat(eFLocs,'Ex') Pey = mesh.getInterpolationMat(eFLocs,'Ey') Pbx = mesh.getInterpolationMat(bFLocs,'Fx') Pby = mesh.getInterpolationMat(bFLocs,'Fy') # Get the fields at location # px: x-polaration and py: y-polaration. ex_px = Pex*f[src,'e_px'] ey_px = Pey*f[src,'e_px'] ex_py = Pex*f[src,'e_py'] ey_py = Pey*f[src,'e_py'] hx_px = Pbx*f[src,'b_px']/mu_0 hy_px = Pby*f[src,'b_px']/mu_0 hx_py = Pbx*f[src,'b_py']/mu_0 hy_py = Pby*f[src,'b_py']/mu_0 # Make the complex data if 'zxx' in self.rxType: f_part_complex = ( ex_px*hy_py - ex_py*hy_px)/(hx_px*hy_py - hx_py*hy_px) elif 'zxy' in self.rxType: f_part_complex = (-ex_px*hx_py + ex_py*hx_px)/(hx_px*hy_py - hx_py*hy_px) elif 'zyx' in self.rxType: f_part_complex = ( ey_px*hy_py - ey_py*hy_px)/(hx_px*hy_py - hx_py*hy_px) elif 'zyy' in self.rxType: f_part_complex = (-ey_px*hx_py + ey_py*hx_px)/(hx_px*hy_py - hx_py*hy_px) elif self.projType is 'T3D': if self.locs.ndim == 3: horLoc = self.locs[:,:,0] vertLoc = self.locs[:,:,1] else: horLoc = self.locs vertLoc = self.locs Pbx = mesh.getInterpolationMat(horLoc,'Fx') Pby = mesh.getInterpolationMat(horLoc,'Fy') Pbz = mesh.getInterpolationMat(vertLoc,'Fz') bx_px = Pbx*f[src,'b_px'] by_px = Pby*f[src,'b_px'] bz_px = Pbz*f[src,'b_px'] bx_py = Pbx*f[src,'b_py'] by_py = Pby*f[src,'b_py'] bz_py = Pbz*f[src,'b_py'] if 'tzx' in self.rxType: f_part_complex = (- by_px*bz_py + by_py*bz_px)/(bx_px*by_py - bx_py*by_px) if 'tzy' in self.rxType: f_part_complex = ( bx_px*bz_py - bx_py*bz_px)/(bx_px*by_py - bx_py*by_px) else: NotImplementedError('Projection of {:s} receiver type is not implemented.'.format(self.rxType)) # Get the real or imag component real_or_imag = self.projComp f_part = getattr(f_part_complex, real_or_imag) # print f_part return f_part
def evalDeriv(self, src, mesh, f, v, adjoint=False): """ The derivative of the projection wrt u :param MTsrc src: MT source :param TensorMesh mesh: Mesh defining the topology of the problem :param MTfields f: MT fields object of the source :param numpy.ndarray v: Random vector of size """ real_or_imag = self.projComp if not adjoint: if self.projType is 'Z1D': Pex = mesh.getInterpolationMat(self.locs[:,-1],'Fx') Pbx = mesh.getInterpolationMat(self.locs[:,-1],'Ex') # ex = Pex*mkvc(f[src,'e_1d'],2) # bx = Pbx*mkvc(f[src,'b_1d'],2)/mu_0 dP_de = -mkvc(Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0))*(Pex*v),2) dP_db = mkvc( Utils.sdiag(Pex*mkvc(f[src,'e_1d'],2))*(Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)).T*Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)))*(Pbx*f._bDeriv_u(src,v)/mu_0),2) PDeriv_complex = np.sum(np.hstack((dP_de,dP_db)),1) elif self.projType is 'Z2D': raise NotImplementedError('Has not been implement for 2D impedance tensor') elif self.projType is 'Z3D': if self.locs.ndim == 3: eFLocs = self.locs[:,:,0] bFLocs = self.locs[:,:,1] else: eFLocs = self.locs bFLocs = self.locs # Get the projection Pex = mesh.getInterpolationMat(eFLocs,'Ex') Pey = mesh.getInterpolationMat(eFLocs,'Ey') Pbx = mesh.getInterpolationMat(bFLocs,'Fx') Pby = mesh.getInterpolationMat(bFLocs,'Fy') # Get the fields at location # px: x-polaration and py: y-polaration. ex_px = Pex*f[src,'e_px'] ey_px = Pey*f[src,'e_px'] ex_py = Pex*f[src,'e_py'] ey_py = Pey*f[src,'e_py'] hx_px = Pbx*f[src,'b_px']/mu_0 hy_px = Pby*f[src,'b_px']/mu_0 hx_py = Pbx*f[src,'b_py']/mu_0 hy_py = Pby*f[src,'b_py']/mu_0 # Derivatives as lambda functions # The size of the diratives should be nD,nU ex_px_u = lambda vec: Pex*f._e_pxDeriv_u(src,vec) ey_px_u = lambda vec: Pey*f._e_pxDeriv_u(src,vec) ex_py_u = lambda vec: Pex*f._e_pyDeriv_u(src,vec) ey_py_u = lambda vec: Pey*f._e_pyDeriv_u(src,vec) # NOTE: Think b_p?Deriv_u should return a 2*nF size matrix hx_px_u = lambda vec: Pbx*f._b_pxDeriv_u(src,vec)/mu_0 hy_px_u = lambda vec: Pby*f._b_pxDeriv_u(src,vec)/mu_0 hx_py_u = lambda vec: Pbx*f._b_pyDeriv_u(src,vec)/mu_0 hy_py_u = lambda vec: Pby*f._b_pyDeriv_u(src,vec)/mu_0 # Update the input vector sDiag = lambda t: Utils.sdiag(mkvc(t,2)) # Define the components of the derivative Hd = sDiag(1./(sDiag(hx_px)*hy_py - sDiag(hx_py)*hy_px)) Hd_uV = sDiag(hy_py)*hx_px_u(v) + sDiag(hx_px)*hy_py_u(v) - sDiag(hx_py)*hy_px_u(v) - sDiag(hy_px)*hx_py_u(v) # Calculate components if 'zxx' in self.rxType: Zij = sDiag(Hd*( sDiag(ex_px)*hy_py - sDiag(ex_py)*hy_px )) ZijN_uV = sDiag(hy_py)*ex_px_u(v) + sDiag(ex_px)*hy_py_u(v) - sDiag(ex_py)*hy_px_u(v) - sDiag(hy_px)*ex_py_u(v) elif 'zxy' in self.rxType: Zij = sDiag(Hd*(-sDiag(ex_px)*hx_py + sDiag(ex_py)*hx_px )) ZijN_uV = -sDiag(hx_py)*ex_px_u(v) - sDiag(ex_px)*hx_py_u(v) + sDiag(ex_py)*hx_px_u(v) + sDiag(hx_px)*ex_py_u(v) elif 'zyx' in self.rxType: Zij = sDiag(Hd*( sDiag(ey_px)*hy_py - sDiag(ey_py)*hy_px )) ZijN_uV = sDiag(hy_py)*ey_px_u(v) + sDiag(ey_px)*hy_py_u(v) - sDiag(ey_py)*hy_px_u(v) - sDiag(hy_px)*ey_py_u(v) elif 'zyy' in self.rxType: Zij = sDiag(Hd*(-sDiag(ey_px)*hx_py + sDiag(ey_py)*hx_px )) ZijN_uV = -sDiag(hx_py)*ey_px_u(v) - sDiag(ey_px)*hx_py_u(v) + sDiag(ey_py)*hx_px_u(v) + sDiag(hx_px)*ey_py_u(v) # Calculate the complex derivative PDeriv_complex = Hd * (ZijN_uV - Zij * Hd_uV ) elif self.projType is 'T3D': if self.locs.ndim == 3: eFLocs = self.locs[:,:,0] bFLocs = self.locs[:,:,1] else: eFLocs = self.locs bFLocs = self.locs # Get the projection Pbx = mesh.getInterpolationMat(bFLocs,'Fx') Pby = mesh.getInterpolationMat(bFLocs,'Fy') Pbz = mesh.getInterpolationMat(bFLocs,'Fz') # Get the fields at location # px: x-polaration and py: y-polaration. bx_px = Pbx*f[src,'b_px'] by_px = Pby*f[src,'b_px'] bz_px = Pbz*f[src,'b_px'] bx_py = Pbx*f[src,'b_py'] by_py = Pby*f[src,'b_py'] bz_py = Pbz*f[src,'b_py'] # Derivatives as lambda functions # NOTE: Think b_p?Deriv_u should return a 2*nF size matrix bx_px_u = lambda vec: Pbx*f._b_pxDeriv_u(src,vec) by_px_u = lambda vec: Pby*f._b_pxDeriv_u(src,vec) bz_px_u = lambda vec: Pbz*f._b_pxDeriv_u(src,vec) bx_py_u = lambda vec: Pbx*f._b_pyDeriv_u(src,vec) by_py_u = lambda vec: Pby*f._b_pyDeriv_u(src,vec) bz_py_u = lambda vec: Pbz*f._b_pyDeriv_u(src,vec) # Update the input vector sDiag = lambda t: Utils.sdiag(mkvc(t,2)) # Define the components of the derivative Hd = sDiag(1./(sDiag(bx_px)*by_py - sDiag(bx_py)*by_px)) Hd_uV = sDiag(by_py)*bx_px_u(v) + sDiag(bx_px)*by_py_u(v) - sDiag(bx_py)*by_px_u(v) - sDiag(by_px)*bx_py_u(v) if 'tzx' in self.rxType: Tij = sDiag(Hd*( - sDiag(by_px)*bz_py + sDiag(by_py)*bz_px )) TijN_uV = -sDiag(by_px)*bz_py_u(v) - sDiag(bz_py)*by_px_u(v) + sDiag(by_py)*bz_px_u(v) + sDiag(bz_px)*by_py_u(v) elif 'tzy' in self.rxType: Tij = sDiag(Hd*( sDiag(bx_px)*bz_py - sDiag(bx_py)*bz_px )) TijN_uV = sDiag(bz_py)*bx_px_u(v) + sDiag(bx_px)*bz_py_u(v) - sDiag(bx_py)*bz_px_u(v) - sDiag(bz_px)*bx_py_u(v) # Calculate the complex derivative PDeriv_complex = Hd * (TijN_uV - Tij * Hd_uV ) # Extract the real number for the real/imag components. Pv = np.array(getattr(PDeriv_complex, real_or_imag)) elif adjoint: # Note: The v vector is real and the return should be complex if self.projType is 'Z1D': Pex = mesh.getInterpolationMat(self.locs[:,-1],'Fx') Pbx = mesh.getInterpolationMat(self.locs[:,-1],'Ex') # ex = Pex*mkvc(f[src,'e_1d'],2) # bx = Pbx*mkvc(f[src,'b_1d'],2)/mu_0 dP_deTv = -mkvc(Pex.T*Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)).T*v,2) db_duv = Pbx.T/mu_0*Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0))*(Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0))).T*Utils.sdiag(Pex*mkvc(f[src,'e_1d'],2)).T*v dP_dbTv = mkvc(f._bDeriv_u(src,db_duv,adjoint=True),2) PDeriv_real = np.sum(np.hstack((dP_deTv,dP_dbTv)),1) elif self.projType is 'Z2D': raise NotImplementedError('Has not be implement for 2D impedance tensor') elif self.projType is 'Z3D': if self.locs.ndim == 3: eFLocs = self.locs[:,:,0] bFLocs = self.locs[:,:,1] else: eFLocs = self.locs bFLocs = self.locs # Get the projection Pex = mesh.getInterpolationMat(eFLocs,'Ex') Pey = mesh.getInterpolationMat(eFLocs,'Ey') Pbx = mesh.getInterpolationMat(bFLocs,'Fx') Pby = mesh.getInterpolationMat(bFLocs,'Fy') # Get the fields at location # px: x-polaration and py: y-polaration. aex_px = mkvc(mkvc(f[src,'e_px'],2).T*Pex.T) aey_px = mkvc(mkvc(f[src,'e_px'],2).T*Pey.T) aex_py = mkvc(mkvc(f[src,'e_py'],2).T*Pex.T) aey_py = mkvc(mkvc(f[src,'e_py'],2).T*Pey.T) ahx_px = mkvc(mkvc(f[src,'b_px'],2).T/mu_0*Pbx.T) ahy_px = mkvc(mkvc(f[src,'b_px'],2).T/mu_0*Pby.T) ahx_py = mkvc(mkvc(f[src,'b_py'],2).T/mu_0*Pbx.T) ahy_py = mkvc(mkvc(f[src,'b_py'],2).T/mu_0*Pby.T) # Derivatives as lambda functions aex_px_u = lambda vec: f._e_pxDeriv_u(src,Pex.T*vec,adjoint=True) aey_px_u = lambda vec: f._e_pxDeriv_u(src,Pey.T*vec,adjoint=True) aex_py_u = lambda vec: f._e_pyDeriv_u(src,Pex.T*vec,adjoint=True) aey_py_u = lambda vec: f._e_pyDeriv_u(src,Pey.T*vec,adjoint=True) ahx_px_u = lambda vec: f._b_pxDeriv_u(src,Pbx.T*vec,adjoint=True)/mu_0 ahy_px_u = lambda vec: f._b_pxDeriv_u(src,Pby.T*vec,adjoint=True)/mu_0 ahx_py_u = lambda vec: f._b_pyDeriv_u(src,Pbx.T*vec,adjoint=True)/mu_0 ahy_py_u = lambda vec: f._b_pyDeriv_u(src,Pby.T*vec,adjoint=True)/mu_0 # Update the input vector # Define shortcuts sDiag = lambda t: Utils.sdiag(mkvc(t,2)) sVec = lambda t: Utils.sp.csr_matrix(mkvc(t,2)) # Define the components of the derivative aHd = sDiag(1./(sDiag(ahx_px)*ahy_py - sDiag(ahx_py)*ahy_px)) aHd_uV = lambda x: ahx_px_u(sDiag(ahy_py)*x) + ahx_px_u(sDiag(ahy_py)*x) - ahy_px_u(sDiag(ahx_py)*x) - ahx_py_u(sDiag(ahy_px)*x) # Need to fix this to reflect the adjoint if 'zxx' in self.rxType: Zij = sDiag(aHd*( sDiag(ahy_py)*aex_px - sDiag(ahy_px)*aex_py)) ZijN_uV = lambda x: aex_px_u(sDiag(ahy_py)*x) + ahy_py_u(sDiag(aex_px)*x) - ahy_px_u(sDiag(aex_py)*x) - aex_py_u(sDiag(ahy_px)*x) elif 'zxy' in self.rxType: Zij = sDiag(aHd*(-sDiag(ahx_py)*aex_px + sDiag(ahx_px)*aex_py)) ZijN_uV = lambda x:-aex_px_u(sDiag(ahx_py)*x) - ahx_py_u(sDiag(aex_px)*x) + ahx_px_u(sDiag(aex_py)*x) + aex_py_u(sDiag(ahx_px)*x) elif 'zyx' in self.rxType: Zij = sDiag(aHd*( sDiag(ahy_py)*aey_px - sDiag(ahy_px)*aey_py)) ZijN_uV = lambda x: aey_px_u(sDiag(ahy_py)*x) + ahy_py_u(sDiag(aey_px)*x) - ahy_px_u(sDiag(aey_py)*x) - aey_py_u(sDiag(ahy_px)*x) elif 'zyy' in self.rxType: Zij = sDiag(aHd*(-sDiag(ahx_py)*aey_px + sDiag(ahx_px)*aey_py)) ZijN_uV = lambda x:-aey_px_u(sDiag(ahx_py)*x) - ahx_py_u(sDiag(aey_px)*x) + ahx_px_u(sDiag(aey_py)*x) + aey_py_u(sDiag(ahx_px)*x) # Calculate the complex derivative PDeriv_real = ZijN_uV(aHd*v) - aHd_uV(Zij.T*aHd*v)# # NOTE: Need to reshape the output to go from 2*nU array to a (nU,2) matrix for each polarization # PDeriv_real = np.hstack((mkvc(PDeriv_real[:len(PDeriv_real)/2],2),mkvc(PDeriv_real[len(PDeriv_real)/2::],2))) PDeriv_real = PDeriv_real.reshape((2,mesh.nE)).T elif self.projType is 'T3D': if self.locs.ndim == 3: bFLocs = self.locs[:,:,1] else: bFLocs = self.locs # Get the projection Pbx = mesh.getInterpolationMat(bFLocs,'Fx') Pby = mesh.getInterpolationMat(bFLocs,'Fy') Pbz = mesh.getInterpolationMat(bFLocs,'Fz') # Get the fields at location # px: x-polaration and py: y-polaration. abx_px = mkvc(mkvc(f[src,'b_px'],2).T*Pbx.T) aby_px = mkvc(mkvc(f[src,'b_px'],2).T*Pby.T) abz_px = mkvc(mkvc(f[src,'b_px'],2).T*Pbz.T) abx_py = mkvc(mkvc(f[src,'b_py'],2).T*Pbx.T) aby_py = mkvc(mkvc(f[src,'b_py'],2).T*Pby.T) abz_py = mkvc(mkvc(f[src,'b_py'],2).T*Pbz.T) # Derivatives as lambda functions abx_px_u = lambda vec: f._b_pxDeriv_u(src,Pbx.T*vec,adjoint=True) aby_px_u = lambda vec: f._b_pxDeriv_u(src,Pby.T*vec,adjoint=True) abz_px_u = lambda vec: f._b_pxDeriv_u(src,Pbz.T*vec,adjoint=True) abx_py_u = lambda vec: f._b_pyDeriv_u(src,Pbx.T*vec,adjoint=True) aby_py_u = lambda vec: f._b_pyDeriv_u(src,Pby.T*vec,adjoint=True) abz_py_u = lambda vec: f._b_pyDeriv_u(src,Pbz.T*vec,adjoint=True) # Update the input vector # Define shortcuts sDiag = lambda t: Utils.sdiag(mkvc(t,2)) sVec = lambda t: Utils.sp.csr_matrix(mkvc(t,2)) # Define the components of the derivative aHd = sDiag(1./(sDiag(abx_px)*aby_py - sDiag(abx_py)*aby_px)) aHd_uV = lambda x: abx_px_u(sDiag(aby_py)*x) + abx_px_u(sDiag(aby_py)*x) - aby_px_u(sDiag(abx_py)*x) - abx_py_u(sDiag(aby_px)*x) # Need to fix this to reflect the adjoint if 'tzx' in self.rxType: Tij = sDiag(aHd*( -sDiag(abz_py)*aby_px + sDiag(abz_px)*aby_py)) TijN_uV = lambda x: -abz_py_u(sDiag(aby_px)*x) - aby_px_u(sDiag(abz_py)*x) + aby_py_u(sDiag(abz_px)*x) + abz_px_u(sDiag(aby_py)*x) elif 'tzy' in self.rxType: Tij = sDiag(aHd*( sDiag(abz_py)*abx_px - sDiag(abz_px)*abx_py)) TijN_uV = lambda x: abx_px_u(sDiag(abz_py)*x) + abz_py_u(sDiag(abx_px)*x) - abx_py_u(sDiag(abz_px)*x) - abz_px_u(sDiag(abx_py)*x) # Calculate the complex derivative PDeriv_real = TijN_uV(aHd*v) - aHd_uV(Tij.T*aHd*v)# # NOTE: Need to reshape the output to go from 2*nU array to a (nU,2) matrix for each polarization # PDeriv_real = np.hstack((mkvc(PDeriv_real[:len(PDeriv_real)/2],2),mkvc(PDeriv_real[len(PDeriv_real)/2::],2))) PDeriv_real = PDeriv_real.reshape((2,mesh.nE)).T # Extract the data if real_or_imag == 'imag': Pv = 1j*PDeriv_real elif real_or_imag == 'real': Pv = PDeriv_real.astype(complex) return Pv