コード例 #1
0
ファイル: FieldsFDEM.py プロジェクト: lheagy/simpegem
 def _hPrimary(self, hSolution, srcList):
     hPrimary = np.zeros_like(hSolution,dtype = complex)
     for i, src in enumerate(srcList):
         hp = src.hPrimary(self.prob)
         if hp is not None:
             hPrimary[:,i] += hp
         return hPrimary
コード例 #2
0
ファイル: FieldsFDEM.py プロジェクト: lheagy/simpegem
 def _jPrimary(self, jSolution, srcList):
     jPrimary = np.zeros_like(jSolution,dtype = complex)
     for i, src in enumerate(srcList):
         jp = src.jPrimary(self.prob) 
         if jp is not None:
             jPrimary[:,i] += jp
     return jPrimary
コード例 #3
0
ファイル: FieldsFDEM.py プロジェクト: lheagy/simpegem
 def _ePrimary(self, eSolution, srcList):
     ePrimary = np.zeros_like(eSolution)
     for i, src in enumerate(srcList):
         ep = src.ePrimary(self.prob)
         if ep is not None:
             ePrimary[:,i] = ep     
     return ePrimary
コード例 #4
0
ファイル: FieldsMT.py プロジェクト: simpeg/simpegmt
 def _e_pyPrimary(self, e_pySolution, srcList):
     e_pyPrimary = np.zeros_like(e_pySolution)
     for i, src in enumerate(srcList):
         ep = src.ePrimary(self.survey.prob)
         if ep is not None:
             e_pyPrimary[:, i] = ep[:, 1]
     return e_pyPrimary
コード例 #5
0
ファイル: FieldsFDEM.py プロジェクト: lheagy/simpegem
 def _bPrimary(self, bSolution, srcList):
     bPrimary = np.zeros_like(bSolution)
     for i, src in enumerate(srcList):
         bp = src.bPrimary(self.prob)
         if bp is not None:
             bPrimary[:,i] = bp
     return bPrimary
コード例 #6
0
 def _ePrimary(self, eSolution, srcList):
     ePrimary = np.zeros_like(eSolution)
     for i, src in enumerate(srcList):
         ep = src.ePrimary(self.survey.prob)
         if ep is not None:
             ePrimary[:,i] = ep[:,-1]
     return ePrimary
コード例 #7
0
ファイル: FieldsMT.py プロジェクト: simpeg/simpegmt
 def _e_pyDeriv_u(self, src, v, adjoint=False):
     """
     Takes the derivative of e_py wrt u
     """
     if adjoint:
         # adjoint: returns a 2*nE long vector with zero's for px
         return np.vstack((np.zeros_like(v), v))
     # Not adjoint: return only the px part of the vector
     return v[len(v) / 2 : :]
コード例 #8
0
 def _e_pyDeriv_u(self, src, v, adjoint = False):
     '''
     Takes the derivative of e_py wrt u
     '''
     if adjoint:
         # adjoint: returns a 2*nE long vector with zero's for px
         return np.vstack((np.zeros_like(v),v))
     # Not adjoint: return only the px part of the vector
     return v[len(v)/2::]
コード例 #9
0
ファイル: FieldsMT.py プロジェクト: dakentod/simpeg
 def _e_pxDeriv_u(self, src, v, adjoint = False):
     '''
     Takes the derivative of e_px wrt u
     '''
     if adjoint:
         # adjoint: returns a 2*nE long vector with zero's for py
         return np.vstack((v,np.zeros_like(v)))
     # Not adjoint: return only the px part of the vector
     return v[:len(v)/2]
コード例 #10
0
def halfSpaceProblemAnaVMDDiff(showIt=False, waveformType="STEPOFF"):
    cs, ncx, ncz, npad = 20., 25, 25, 15
    hx = [(cs, ncx), (cs, npad, 1.3)]
    hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)]
    mesh = Mesh.CylMesh([hx, 1, hz], '00C')
    sighalf = 1e-2
    siginf = np.ones(mesh.nC) * 1e-8
    siginf[mesh.gridCC[:, -1] < 0.] = sighalf
    eta = np.ones(mesh.nC) * 0.2
    tau = np.ones(mesh.nC) * 0.005
    c = np.ones(mesh.nC) * 0.7
    m = np.r_[siginf, eta, tau, c]
    iMap = Maps.IdentityMap(nP=int(mesh.nC))
    maps = [('sigmaInf', iMap), ('eta', iMap), ('tau', iMap), ('c', iMap)]
    prb = ProblemATEMIP_b(mesh, mapping=maps)

    if waveformType == "GENERAL":
        # timeon = np.cumsum(np.r_[np.ones(10)*1e-3, np.ones(10)*5e-4, np.ones(10)*1e-4])
        timeon = np.cumsum(np.r_[np.ones(10) * 1e-3,
                                 np.ones(10) * 5e-4,
                                 np.ones(10) * 1e-4])
        timeon -= timeon.max()
        timeoff = np.cumsum(np.r_[np.ones(20) * 1e-5,
                                  np.ones(20) * 1e-4,
                                  np.ones(20) * 1e-3])
        time = np.r_[timeon, timeoff]
        current_on = np.ones_like(timeon)
        current_on[[0, -1]] = 0.
        current = np.r_[current_on, np.zeros_like(timeoff)]
        wave = np.c_[time, current]
        prb.waveformType = "GENERAL"
        prb.currentwaveform(wave)
        prb.t0 = time.min()
    elif waveformType == "STEPOFF":
        prb.timeSteps = [(1e-5, 20), (1e-4, 20), (1e-3, 10)]
    offset = 20.
    tobs = np.logspace(-4, -2, 21)
    rx = EM.TDEM.RxTDEM(np.array([[offset, 0., 0.]]), tobs, "bz")
    src = EM.TDEM.SrcTDEM_VMD_MVP([rx],
                                  np.array([[0., 0., 0.]]),
                                  waveformType=waveformType)
    survey = EM.TDEM.SurveyTDEM([src])
    prb.Solver = MumpsSolver
    prb.pair(survey)
    out = survey.dpred(m)
    bz_ana = mu_0 * hzAnalyticDipoleT_CC(
        offset, rx.times, sigmaInf=sighalf, eta=eta[0], tau=tau[0], c=c[0])
    err = np.linalg.norm(bz_ana - out) / np.linalg.norm(bz_ana)
    print '>> Relative error = ', err

    if showIt:
        plt.loglog(rx.times, abs(bz_ana), 'k')
        plt.loglog(rx.times, abs(out), 'b.')
        plt.show()
    return err
コード例 #11
0
ファイル: analytictest_vmd.py プロジェクト: sgkang/simpegAIP
def halfSpaceProblemAnaVMDDiff(showIt=False, waveformType="STEPOFF"):
    cs, ncx, ncz, npad = 20., 25, 25, 15
    hx = [(cs, ncx), (cs, npad, 1.3)]
    hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)]
    mesh = Mesh.CylMesh([hx, 1, hz], '00C')
    prb = ProblemATEM_b(mesh)
    if waveformType == "GENERAL":
        timeon = np.cumsum(np.r_[np.ones(10) * 1e-3,
                                 np.ones(10) * 5e-4,
                                 np.ones(10) * 1e-4])
        timeon -= timeon.max()
        timeoff = np.cumsum(np.r_[np.ones(10) * 5e-5,
                                  np.ones(10) * 1e-4,
                                  np.ones(10) * 5e-4,
                                  np.ones(10) * 1e-3,
                                  np.ones(10) * 5e-3])
        time = np.r_[timeon, timeoff]
        current_on = np.ones_like(timeon)
        current_on[[0, -1]] = 0.
        current = np.r_[current_on, np.zeros_like(timeoff)]
        wave = np.c_[time, current]
        prb.waveformType = "GENERAL"
        prb.currentwaveform(wave)
        prb.t0 = time.min()
    elif waveformType == "STEPOFF":
        prb.timeSteps = [(1e-5, 10), (5e-5, 10), (1e-4, 10), (5e-4, 10),
                         (1e-3, 10), (5e-3, 10)]
    offset = 20.
    tobs = np.logspace(-4, -2, 21)
    rx = EM.TDEM.RxTDEM(np.array([[offset, 0., 0.]]), tobs, "bz")
    src = EM.TDEM.SrcTDEM_VMD_MVP([rx],
                                  np.array([[0., 0., 0.]]),
                                  waveformType=waveformType)
    survey = EM.TDEM.SurveyTDEM([src])
    prb.Solver = MumpsSolver
    sigma = np.ones(mesh.nC) * 1e-8
    active = mesh.gridCC[:, 2] < 0.
    sig_half = 1e-2
    sigma[active] = sig_half
    prb.pair(survey)

    out = survey.dpred(sigma)
    bz_ana = mu_0 * hzAnalyticDipoleT(offset, rx.times, sig_half)
    err = np.linalg.norm(bz_ana - out) / np.linalg.norm(bz_ana)
    print '>> Relative error = ', err

    if showIt:
        plt.loglog(rx.times, bz_ana, 'k')
        plt.loglog(rx.times, out, 'b.')
        plt.show()
    return err
コード例 #12
0
def halfSpaceProblemAnaVMDDiff(showIt=False, waveformType="STEPOFF"):
	cs, ncx, ncz, npad = 20., 25, 25, 15
	hx = [(cs,ncx), (cs,npad,1.3)]
	hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)]
	mesh = Mesh.CylMesh([hx,1,hz], '00C')   
	sighalf = 1e-2
	siginf = np.ones(mesh.nC)*1e-8
	siginf[mesh.gridCC[:,-1]<0.] = sighalf
	eta = np.ones(mesh.nC)*0.2
	tau = np.ones(mesh.nC)*0.005
	c = np.ones(mesh.nC)*0.7
	m = np.r_[siginf, eta, tau, c]
	iMap = Maps.IdentityMap(nP=int(mesh.nC))
	maps = [('sigmaInf', iMap), ('eta', iMap), ('tau', iMap), ('c', iMap)]
	prb = ProblemATEMIP_b(mesh, mapping = maps)	

	if waveformType =="GENERAL":
		# timeon = np.cumsum(np.r_[np.ones(10)*1e-3, np.ones(10)*5e-4, np.ones(10)*1e-4])
		timeon = np.cumsum(np.r_[np.ones(10)*1e-3, np.ones(10)*5e-4, np.ones(10)*1e-4])
		timeon -= timeon.max()
		timeoff = np.cumsum(np.r_[np.ones(20)*1e-5, np.ones(20)*1e-4, np.ones(20)*1e-3])
		time = np.r_[timeon, timeoff]
		current_on = np.ones_like(timeon)
		current_on[[0,-1]] = 0.
		current = np.r_[current_on, np.zeros_like(timeoff)]
		wave = np.c_[time, current]		
		prb.waveformType = "GENERAL"
		prb.currentwaveform(wave)
		prb.t0 = time.min()
	elif waveformType =="STEPOFF":
		prb.timeSteps = [(1e-5, 20), (1e-4, 20), (1e-3, 10)]
	offset = 20.
	tobs = np.logspace(-4, -2, 21)
	rx = EM.TDEM.RxTDEM(np.array([[offset, 0., 0.]]), tobs, "bz")
	src = EM.TDEM.SrcTDEM_VMD_MVP([rx], np.array([[0., 0., 0.]]), waveformType=waveformType)
	survey = EM.TDEM.SurveyTDEM([src])
	prb.Solver = MumpsSolver
	prb.pair(survey)
	out = survey.dpred(m)
	bz_ana = mu_0*hzAnalyticDipoleT_CC(offset, rx.times, sigmaInf=sighalf, eta=eta[0], tau=tau[0], c=c[0])
	err = np.linalg.norm(bz_ana-out)/np.linalg.norm(bz_ana)
	print '>> Relative error = ', err

	if showIt:
		plt.loglog(rx.times, abs(bz_ana), 'k')
		plt.loglog(rx.times, abs(out), 'b.')
		plt.show()	
	return err
コード例 #13
0
ファイル: analytictest_vmd.py プロジェクト: sgkang/simpegAIP
def halfSpaceProblemAnaVMDDiff(showIt=False, waveformType="STEPOFF"):
	cs, ncx, ncz, npad = 20., 25, 25, 15
	hx = [(cs,ncx), (cs,npad,1.3)]
	hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)]
	mesh = Mesh.CylMesh([hx,1,hz], '00C')    
	prb = ProblemATEM_b(mesh)
	if waveformType =="GENERAL":
		timeon = np.cumsum(np.r_[np.ones(10)*1e-3, np.ones(10)*5e-4, np.ones(10)*1e-4])
		timeon -= timeon.max()
		timeoff = np.cumsum(np.r_[np.ones(10)*5e-5, np.ones(10)*1e-4, np.ones(10)*5e-4, np.ones(10)*1e-3, np.ones(10)*5e-3])
		time = np.r_[timeon, timeoff]
		current_on = np.ones_like(timeon)
		current_on[[0,-1]] = 0.
		current = np.r_[current_on, np.zeros_like(timeoff)]
		wave = np.c_[time, current]		
		prb.waveformType = "GENERAL"
		prb.currentwaveform(wave)
		prb.t0 = time.min()
	elif waveformType =="STEPOFF":
		prb.timeSteps = [(1e-5, 10), (5e-5, 10), (1e-4, 10), (5e-4, 10), (1e-3, 10),(5e-3, 10)]
	offset = 20.
	tobs = np.logspace(-4, -2, 21)
	rx = EM.TDEM.RxTDEM(np.array([[offset, 0., 0.]]), tobs, "bz")
	src = EM.TDEM.SrcTDEM_VMD_MVP([rx], np.array([[0., 0., 0.]]), waveformType=waveformType)
	survey = EM.TDEM.SurveyTDEM([src])
	prb.Solver = MumpsSolver
	sigma = np.ones(mesh.nC)*1e-8
	active = mesh.gridCC[:,2]<0.
	sig_half = 1e-2
	sigma[active] = sig_half
	prb.pair(survey)

	out = survey.dpred(sigma)
	bz_ana = mu_0*hzAnalyticDipoleT(offset, rx.times, sig_half)
	err = np.linalg.norm(bz_ana-out)/np.linalg.norm(bz_ana)
	print '>> Relative error = ', err

	if showIt:
		plt.loglog(rx.times, bz_ana, 'k')
		plt.loglog(rx.times, out, 'b.')
		plt.show()	
	return err
コード例 #14
0
ファイル: ProblemTDEM.py プロジェクト: westamine/simpeg
    def Jtvec(self, m, v, f=None):

        """
        Jvec computes the adjoint of the sensitivity times a vector

        .. math::
            \mathbf{J}^\\top \mathbf{v} =  \left(
            \\frac{d\mathbf{u}}{d\mathbf{m}} ^ \\top
            \\frac{d\mathbf{F}}{d\mathbf{u}} ^ \\top  +
            \\frac{\partial\mathbf{F}}{\partial\mathbf{m}} ^ \\top \\right)
            \\frac{d\mathbf{P}}{d\mathbf{F}} ^ \\top \mathbf{v}

        where

        .. math::
            \\frac{d\mathbf{u}}{d\mathbf{m}} ^\\top \mathbf{A}^\\top  +
            \\frac{d\mathbf{A}(\mathbf{u})}{d\mathbf{m}} ^ \\top =
            \\frac{d \mathbf{RHS}}{d \mathbf{m}} ^ \\top
        """

        if f is None:
            f = self.fields(m)

        self.model = m
        ftype = self._fieldType + 'Solution'  # the thing we solved for

        # Ensure v is a data object.
        if not isinstance(v, self.dataPair):
            v = self.dataPair(self.survey, v)

        df_duT_v = Fields_Derivs(self.mesh, self.survey)

        # same size as fields at a single timestep
        ATinv_df_duT_v = np.zeros(
            (
                len(self.survey.srcList),
                len(f[self.survey.srcList[0], ftype, 0])
            ),
            dtype=float
        )
        JTv = np.zeros(m.shape, dtype=float)

        # Loop over sources and receivers to create a fields object:
        # PT_v, df_duT_v, df_dmT_v
        # initialize storage for PT_v (don't need to preserve over sources)
        PT_v = Fields_Derivs(self.mesh, self.survey)
        for src in self.survey.srcList:
            # Looping over initializing field class is appending memory!
            # PT_v = Fields_Derivs(self.mesh, self.survey) # initialize storage
            # #for PT_v (don't need to preserve over sources)
            # initialize size
            df_duT_v[src, '{}Deriv'.format(self._fieldType), :] = (
                np.zeros_like(f[src, self._fieldType, :])
            )

            for rx in src.rxList:
                PT_v[src, '{}Deriv'.format(rx.projField), :] = rx.evalDeriv(
                    src, self.mesh, self.timeMesh, f, Utils.mkvc(v[src, rx]),
                    adjoint=True
                ) # this is +=

                # PT_v = np.reshape(curPT_v,(len(curPT_v)/self.timeMesh.nN,
                # self.timeMesh.nN), order='F')
                df_duTFun = getattr(f, '_{}Deriv'.format(rx.projField), None)

                for tInd in range(self.nT+1):
                    cur = df_duTFun(
                        tInd, src, None, Utils.mkvc(
                            PT_v[src, '{}Deriv'.format(rx.projField), tInd]
                        ),
                        adjoint=True
                    )

                    df_duT_v[src, '{}Deriv'.format(self._fieldType), tInd] = (
                        df_duT_v[src, '{}Deriv'.format(self._fieldType), tInd] +
                        Utils.mkvc(cur[0], 2))
                    JTv = cur[1] + JTv

        del PT_v # no longer need this

        AdiagTinv = None

        # Do the back-solve through time
        # if the previous timestep is the same: no need to refactor the matrix
        # for tInd, dt in zip(range(self.nT), self.timeSteps):

        for tInd in reversed(range(self.nT)):
            # tInd = tIndP - 1
            if AdiagTinv is not None and (
                tInd <= self.nT and
                self.timeSteps[tInd] != self.timeSteps[tInd+1]
            ):
                AdiagTinv.clean()
                AdiagTinv = None

            # refactor if we need to
            if AdiagTinv is None:  # and tInd > -1:
                Adiag = self.getAdiag(tInd)
                AdiagTinv = self.Solver(Adiag.T, **self.solverOpts)

            if tInd < self.nT - 1:
                Asubdiag = self.getAsubdiag(tInd+1)

            for isrc, src in enumerate(self.survey.srcList):

                # solve against df_duT_v
                if tInd >= self.nT-1:
                    # last timestep (first to be solved)
                    ATinv_df_duT_v[isrc, :] = AdiagTinv * df_duT_v[
                        src, '{}Deriv'.format(self._fieldType), tInd+1]
                elif tInd > -1:
                    ATinv_df_duT_v[isrc, :] = AdiagTinv * (
                        Utils.mkvc(df_duT_v[
                            src, '{}Deriv'.format(self._fieldType), tInd+1
                        ]
                    ) - Asubdiag.T * Utils.mkvc(ATinv_df_duT_v[isrc, :]))

                if tInd < self.nT:
                    dAsubdiagT_dm_v = self.getAsubdiagDeriv(
                        tInd, f[src, ftype, tInd], ATinv_df_duT_v[isrc, :],
                        adjoint=True)
                else:
                    dAsubdiagT_dm_v = Utils.Zero()

                dRHST_dm_v = self.getRHSDeriv(
                        tInd+1, src, ATinv_df_duT_v[isrc, :], adjoint=True
                        )  # on nodes of time mesh

                un_src = f[src, ftype, tInd+1]
                # cell centered on time mesh
                dAT_dm_v = self.getAdiagDeriv(
                    tInd, un_src, ATinv_df_duT_v[isrc, :], adjoint=True
                )

                JTv = JTv + Utils.mkvc(
                    -dAT_dm_v - dAsubdiagT_dm_v + dRHST_dm_v
                )

        # del df_duT_v, ATinv_df_duT_v, A, Asubdiag
        if AdiagTinv is not None:
            AdiagTinv.clean()

        return Utils.mkvc(JTv).astype(float)
コード例 #15
0
    def Jtvec(self, m, v, f=None):

        """
        Jvec computes the adjoint of the sensitivity times a vector

        .. math::
            \mathbf{J}^\\top \mathbf{v} =  \left(
            \\frac{d\mathbf{u}}{d\mathbf{m}} ^ \\top
            \\frac{d\mathbf{F}}{d\mathbf{u}} ^ \\top  +
            \\frac{\partial\mathbf{F}}{\partial\mathbf{m}} ^ \\top \\right)
            \\frac{d\mathbf{P}}{d\mathbf{F}} ^ \\top \mathbf{v}

        where

        .. math::
            \\frac{d\mathbf{u}}{d\mathbf{m}} ^\\top \mathbf{A}^\\top  +
            \\frac{d\mathbf{A}(\mathbf{u})}{d\mathbf{m}} ^ \\top =
            \\frac{d \mathbf{RHS}}{d \mathbf{m}} ^ \\top
        """

        if f is None:
            f = self.fields(m)

        self.curModel = m
        ftype = self._fieldType + 'Solution'  # the thing we solved for

        # Ensure v is a data object.
        if not isinstance(v, self.dataPair):
            v = self.dataPair(self.survey, v)

        df_duT_v = Fields_Derivs(self.mesh, self.survey)

        # same size as fields at a single timestep
        ATinv_df_duT_v = np.zeros((len(self.survey.srcList),
                                   len(f[self.survey.srcList[0], ftype, 0])),
                                  dtype=float)
        JTv = np.zeros(m.shape, dtype=float)

        # Loop over sources and receivers to create a fields object:
        # PT_v, df_duT_v, df_dmT_v
        # initialize storage for PT_v (don't need to preserve over sources)
        PT_v = Fields_Derivs(self.mesh, self.survey)
        for src in self.survey.srcList:
            # Looping over initializing field class is appending memory!
            # PT_v = Fields_Derivs(self.mesh, self.survey) # initialize storage
            # #for PT_v (don't need to preserve over sources)
            # initialize size
            df_duT_v[src, '{}Deriv'.format(self._fieldType), :] = np.zeros_like(
                f[src, self._fieldType, :])

            for rx in src.rxList:
                PT_v[src, '{}Deriv'.format(rx.projField), :] = rx.evalDeriv(
                    src, self.mesh, self.timeMesh, Utils.mkvc(v[src, rx]),
                    adjoint=True) # this is +=

                # PT_v = np.reshape(curPT_v,(len(curPT_v)/self.timeMesh.nN,
                # self.timeMesh.nN), order='F')
                df_duTFun = getattr(f, '_{}Deriv'.format(rx.projField), None)

                for tInd in range(self.nT+1):
                    cur = df_duTFun(
                        tInd, src, None, Utils.mkvc(PT_v[
                            src, '{}Deriv'.format(rx.projField), tInd]),
                        adjoint=True)
                    df_duT_v[src, '{}Deriv'.format(self._fieldType), tInd] = (
                        df_duT_v[src, '{}Deriv'.format(self._fieldType), tInd] +
                        Utils.mkvc(cur[0], 2))
                    JTv = cur[1] + JTv

        del PT_v # no longer need this

        AdiagTinv = None

        # Do the back-solve through time
        # if the previous timestep is the same: no need to refactor the matrix
        # for tInd, dt in zip(range(self.nT), self.timeSteps):

        for tInd in reversed(range(self.nT)):
            # tInd = tIndP - 1
            if AdiagTinv is not None and (
                tInd <= self.nT and
                self.timeSteps[tInd] != self.timeSteps[tInd+1]
            ):
                AdiagTinv.clean()
                AdiagTinv = None

            # refactor if we need to
            if AdiagTinv is None:  # and tInd > -1:
                Adiag = self.getAdiag(tInd)
                AdiagTinv = self.Solver(Adiag.T, **self.solverOpts)

            if tInd < self.nT - 1:
                Asubdiag = self.getAsubdiag(tInd+1)

            for isrc, src in enumerate(self.survey.srcList):

                # solve against df_duT_v
                if tInd >= self.nT-1:
                    # last timestep (first to be solved)
                    ATinv_df_duT_v[isrc, :] = AdiagTinv * df_duT_v[
                        src, '{}Deriv'.format(self._fieldType), tInd+1]
                elif tInd > -1:
                    ATinv_df_duT_v[isrc, :] = AdiagTinv * (Utils.mkvc(df_duT_v[
                        src, '{}Deriv'.format(self._fieldType), tInd+1]) -
                        Asubdiag.T * Utils.mkvc(ATinv_df_duT_v[isrc, :]))

                if tInd < self.nT:
                    dAsubdiagT_dm_v = self.getAsubdiagDeriv(
                        tInd, f[src, ftype, tInd], ATinv_df_duT_v[isrc, :],
                        adjoint=True)
                else:
                    dAsubdiagT_dm_v = Utils.Zero()

                dRHST_dm_v = self.getRHSDeriv(
                        tInd+1, src, ATinv_df_duT_v[isrc, :], adjoint=True
                        )  # on nodes of time mesh

                un_src = f[src, ftype, tInd+1]
                # cell centered on time mesh
                dAT_dm_v = self.getAdiagDeriv(tInd, un_src,
                                              ATinv_df_duT_v[isrc, :],
                                              adjoint=True)

                JTv = JTv + Utils.mkvc(-dAT_dm_v - dAsubdiagT_dm_v +
                                       dRHST_dm_v)

        # del df_duT_v, ATinv_df_duT_v, A, Asubdiag
        if AdiagTinv is not None:
            AdiagTinv.clean()

        return Utils.mkvc(JTv).astype(float)