Ejemplo n.º 1
0
    def test_convergence_vertical(self):
        """
        Test the convergence of the solution to analytic results from
        Cowan (2016) and test accuracy
        """

        h = [(2, 20)]
        meshObj = discretize.TensorMesh((h, h, h), x0="CCN")

        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0
        mod = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj.nC)

        times = np.array([1e-3])
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        z = 0.5
        a = 0.1
        loc_rx = np.c_[0.0, 0.0, z]
        rxList = [
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="z")
        ]
        txList = [
            vrm.sources.CircLoop(rxList, np.r_[0.0, 0.0, z], a,
                                 np.r_[0.0, 0.0], 1.0, waveObj)
        ]

        Survey2 = vrm.Survey(txList)
        Survey3 = vrm.Survey(txList)
        Survey4 = vrm.Survey(txList)
        Survey5 = vrm.Survey(txList)
        Problem2 = vrm.Simulation3DLinear(meshObj, refinement_factor=2)
        Problem3 = vrm.Simulation3DLinear(meshObj, refinement_factor=3)
        Problem4 = vrm.Simulation3DLinear(meshObj, refinement_factor=4)
        Problem5 = vrm.Simulation3DLinear(meshObj, refinement_factor=5)
        Problem2.pair(Survey2)
        Problem3.pair(Survey3)
        Problem4.pair(Survey4)
        Problem5.pair(Survey5)
        Fields2 = Problem2.fields(mod)
        Fields3 = Problem3.fields(mod)
        Fields4 = Problem4.fields(mod)
        Fields5 = Problem5.fields(mod)

        F = -(1 / np.log(tau2 / tau1)) * (1 / times - 1 / (times + 0.02))
        Fields_true = ((0.5 * np.pi * a**2 / np.pi) * (dchi / (2 + dchi)) *
                       ((2 * z)**2 + a**2)**-1.5 * F)

        Errs = np.abs(
            (np.r_[Fields2, Fields3, Fields4, Fields5] - Fields_true) /
            Fields_true)

        Test1 = Errs[-1] < 0.005
        Test2 = np.all(Errs[1:] - Errs[0:-1] < 0.0)

        self.assertTrue(Test1 and Test2)
Ejemplo n.º 2
0
    def test_basic_inversion(self):
        """
        Test to see if inversion recovers model
        """

        h = [(2, 30)]
        meshObj = discretize.TensorMesh((h, h, [(2, 10)]), x0="CCN")

        mod = 0.00025 * np.ones(meshObj.nC)
        mod[(meshObj.gridCC[:, 0] > -4.0)
            & (meshObj.gridCC[:, 1] > -4.0)
            & (meshObj.gridCC[:, 0] < 4.0)
            & (meshObj.gridCC[:, 1] < 4.0)] = 0.001

        times = np.logspace(-4, -2, 5)
        waveObj = vrm.waveforms.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))
        receiver_list = [
            vrm.Rx.Point(np.c_[x, y, z],
                         times=times,
                         fieldType="dbdt",
                         orientation="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(receiver_list, txNodes, 1.0, waveObj)]

        Survey = vrm.Survey(txList)
        Survey.t_active = np.zeros(Survey.nD, dtype=bool)
        Survey.set_active_interval(-1e6, 1e6)
        Problem = vrm.Simulation3DLinear(meshObj,
                                         survey=Survey,
                                         refinement_factor=2)
        dobs = Problem.make_synthetic_data(mod)
        Survey.noise_floor = 1e-11

        dmis = data_misfit.L2DataMisfit(data=dobs, simulation=Problem)
        W = mkvc((np.sum(np.array(Problem.A)**2, axis=0)))**0.25
        reg = regularization.Simple(meshObj,
                                    alpha_s=0.01,
                                    alpha_x=1.0,
                                    alpha_y=1.0,
                                    alpha_z=1.0,
                                    cell_weights=W)
        opt = optimization.ProjectedGNCG(maxIter=20,
                                         lower=0.0,
                                         upper=1e-2,
                                         maxIterLS=20,
                                         tolCG=1e-4)
        invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
        directives = [
            BetaSchedule(coolingFactor=2, coolingRate=1),
            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() * (mkvc(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))
Ejemplo n.º 3
0
##########################################################################
# Forward Simulation
# ------------------
#
# Here we predict data by solving the forward problem. For the VRM problem,
# we use a sensitivity refinement strategy for cells # that are proximal to
# transmitters. This is controlled through the *refinement_factor* and *refinement_distance*
# properties.
#

# Defining the problem
problem_vrm = VRM.Simulation3DLinear(
    mesh,
    survey=survey_vrm,
    indActive=topoCells,
    refinement_factor=3,
    refinement_distance=[1.25, 2.5, 3.75],
)

# Predict VRM response
fields_vrm = problem_vrm.dpred(xi_true)

# Add an artificial TEM response. An analytic solution for the response near
# the surface of a conductive half-space (Nabighian, 1979) is scaled at each
# location to provide lateral variability in the TEM response.
n_times = len(times)
n_loc = loc.shape[0]

sig = 1e-1
mu0 = 4 * np.pi * 1e-7
Ejemplo n.º 4
0
    def test_sources(self):
        """
        Multiple source classes are used to make a small dipole source with the
        same orientation and dipole moment. Test ensures the same fields are
        computed.
        """

        np.random.seed(self.seed)

        h = [0.5, 0.5]
        meshObj = discretize.TensorMesh((h, h, h), x0="CCC")

        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0
        mod = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj.nC)

        times = np.logspace(-4, -2, 3)
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        phi = np.random.uniform(-np.pi, np.pi)
        psi = np.random.uniform(-np.pi, np.pi)
        Rrx = 3.0
        loc_rx = (Rrx * np.c_[np.sin(phi) * np.cos(psi),
                              np.sin(phi) * np.sin(psi),
                              np.cos(phi)])

        receiver_list = [
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="x")
        ]
        receiver_list.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="y"))
        receiver_list.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="z"))

        alpha = np.random.uniform(0, np.pi)
        beta = np.random.uniform(-np.pi, np.pi)
        Rtx = 4.0
        loc_tx = (Rtx * np.r_[np.sin(alpha) * np.cos(beta),
                              np.sin(alpha) * np.sin(beta),
                              np.cos(alpha), ])

        txList = [
            vrm.sources.MagDipole(receiver_list, loc_tx, [0.0, 0.0, 0.01],
                                  waveObj)
        ]
        txList.append(
            vrm.sources.CircLoop(
                receiver_list,
                loc_tx,
                np.sqrt(0.01 / np.pi),
                np.r_[0.0, 0.0],
                1.0,
                waveObj,
            ))
        px = loc_tx[0] + np.r_[-0.05, 0.05, 0.05, -0.05, -0.05]
        py = loc_tx[1] + np.r_[-0.05, -0.05, 0.05, 0.05, -0.05]
        pz = loc_tx[2] * np.ones(5)
        txList.append(
            vrm.sources.LineCurrent(receiver_list, np.c_[px, py, pz], 1.0,
                                    waveObj))

        Survey = vrm.Survey(txList)
        Problem = vrm.Simulation3DLinear(meshObj,
                                         survey=Survey,
                                         refinement_factor=1)
        Fields = Problem.fields(mod)

        err1 = np.all(
            np.abs(Fields[9:18] - Fields[0:9]) /
            (np.abs(Fields[0:9]) + 1e-14) < 0.005)
        err2 = np.all(
            np.abs(Fields[18:] - Fields[0:9]) /
            (np.abs(Fields[0:9]) + 1e-14) < 0.005)
        err3 = np.all(
            np.abs(Fields[9:18] - Fields[18:]) /
            (np.abs(Fields[18:]) + 1e-14) < 0.005)

        self.assertTrue(err1 and err2 and err3)
Ejemplo n.º 5
0
    def test_receiver_types(self):
        """
        Test ensures the fields predicted for each receiver type
        are correct.
        """

        np.random.seed(self.seed)

        h1 = [0.25, 0.25]
        meshObj_Tensor = discretize.TensorMesh((h1, h1, h1), x0="CCN")

        chi0 = 0.0
        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0

        # Tensor Model
        mod = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj_Tensor.nC)

        times = np.array([1e-3])
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        phi = np.random.uniform(-np.pi, np.pi)
        psi = np.random.uniform(-np.pi, np.pi)
        R = 5.0
        loc_rx = (R * np.c_[np.sin(phi) * np.cos(psi),
                            np.sin(phi) * np.sin(psi),
                            np.cos(phi)])
        loc_tx = (0.5 * np.r_[np.sin(phi) * np.cos(psi),
                              np.sin(phi) * np.sin(psi),
                              np.cos(phi)])

        receiver_list1 = [
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="x")
        ]
        receiver_list1.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="y"))
        receiver_list1.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="z"))

        w = 0.1
        N = 100
        receiver_list2 = [
            vrm.receivers.SquareLoop(
                loc_rx,
                times=times,
                width=w,
                nTurns=N,
                fieldType="dhdt",
                orientation="x",
            )
        ]
        receiver_list2.append(
            vrm.receivers.SquareLoop(
                loc_rx,
                times=times,
                width=w,
                nTurns=N,
                fieldType="dhdt",
                orientation="y",
            ))
        receiver_list2.append(
            vrm.receivers.SquareLoop(
                loc_rx,
                times=times,
                width=w,
                nTurns=N,
                fieldType="dhdt",
                orientation="z",
            ))

        txList1 = [
            vrm.sources.MagDipole(receiver_list1, loc_tx, [1.0, 1.0, 1.0],
                                  waveObj)
        ]
        txList2 = [
            vrm.sources.MagDipole(receiver_list2, loc_tx, [1.0, 1.0, 1.0],
                                  waveObj)
        ]

        Survey1 = vrm.Survey(txList1)
        Survey2 = vrm.Survey(txList2)
        Problem1 = vrm.Simulation3DLinear(
            meshObj_Tensor,
            survey=Survey1,
            refinement_factor=2,
            refinement_distance=[1.9, 3.6],
        )
        Problem2 = vrm.Simulation3DLinear(
            meshObj_Tensor,
            survey=Survey2,
            refinement_factor=2,
            refinement_distance=[1.9, 3.6],
        )
        Fields1 = Problem1.fields(mod)
        Fields2 = Problem2.fields(mod)

        Err = np.abs(Fields1 - Fields2)

        Test = np.all(Err < 1e-6)

        self.assertTrue(Test)
Ejemplo n.º 6
0
    def test_vs_mesh_vs_loguniform(self):
        """
        Test to make sure OcTree matches Tensor results and linear vs
        loguniform match
        """

        h1 = [(2, 4)]
        h2 = 0.5 * np.ones(16)
        meshObj_Tensor = discretize.TensorMesh((h1, h1, h1), x0="000")
        meshObj_OcTree = discretize.TreeMesh([h2, h2, h2], x0="000")

        x, y, z = np.meshgrid(
            np.c_[1.0, 3.0, 5.0, 7.0],
            np.c_[1.0, 3.0, 5.0, 7.0],
            np.c_[1.0, 3.0, 5.0, 7.0],
        )
        x = x.reshape((4**3, 1))
        y = y.reshape((4**3, 1))
        z = z.reshape((4**3, 1))
        loc_rx = np.c_[x, y, z]
        meshObj_OcTree.insert_cells(loc_rx,
                                    2 * np.ones((4**3)),
                                    finalize=False)

        x, y, z = np.meshgrid(np.c_[1.0, 3.0, 5.0, 7.0],
                              np.c_[1.0, 3.0, 5.0, 7.0], np.c_[5.0, 7.0])
        x = x.reshape((32, 1))
        y = y.reshape((32, 1))
        z = z.reshape((32, 1))
        loc_rx = np.c_[x, y, z]
        meshObj_OcTree.insert_cells(loc_rx, 3 * np.ones((32)), finalize=False)

        x, y, z = np.meshgrid(
            np.c_[3.5, 4.0, 4.5, 5.0, 5.5],
            np.c_[3.5, 4.0, 4.5, 5.0, 5.5],
            np.c_[6.0, 6.5, 7.0, 7.5],
        )
        x = x.reshape((100, 1))
        y = y.reshape((100, 1))
        z = z.reshape((100, 1))
        loc_rx = np.c_[x, y, z]
        meshObj_OcTree.insert_cells(loc_rx, 4 * np.ones((100)), finalize=True)

        chi0 = 0.0
        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0

        # Tensor Models
        mod_a = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj_Tensor.nC)
        mod_chi0_a = chi0 * np.ones(meshObj_Tensor.nC)
        mod_dchi_a = dchi * np.ones(meshObj_Tensor.nC)
        mod_tau1_a = tau1 * np.ones(meshObj_Tensor.nC)
        mod_tau2_a = tau2 * np.ones(meshObj_Tensor.nC)

        # OcTree Models
        mod_b = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj_OcTree.nC)
        mod_chi0_b = chi0 * np.ones(meshObj_OcTree.nC)
        mod_dchi_b = dchi * np.ones(meshObj_OcTree.nC)
        mod_tau1_b = tau1 * np.ones(meshObj_OcTree.nC)
        mod_tau2_b = tau2 * np.ones(meshObj_OcTree.nC)

        times = np.array([1e-3])
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        loc_rx = np.c_[4.0, 4.0, 8.25]
        receiver_list = [
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="z")
        ]
        txList = [
            vrm.sources.MagDipole(receiver_list, np.r_[4.0, 4.0, 8.25],
                                  [0.0, 0.0, 1.0], waveObj)
        ]

        survey = vrm.Survey(txList)
        Problem1 = vrm.Simulation3DLinear(
            meshObj_Tensor,
            survey=survey,
            refinement_factor=2,
            refinement_distance=[1.9, 3.6],
        )
        Problem2 = vrm.Simulation3DLogUniform(
            meshObj_Tensor,
            survey=survey,
            refinement_factor=2,
            refinement_distance=[1.9, 3.6],
            chi0=mod_chi0_a,
            dchi=mod_dchi_a,
            tau1=mod_tau1_a,
            tau2=mod_tau2_a,
        )
        Problem3 = vrm.Simulation3DLinear(meshObj_OcTree,
                                          survey=survey,
                                          refinement_factor=0)
        Problem4 = vrm.Simulation3DLogUniform(
            meshObj_OcTree,
            survey=survey,
            refinement_factor=0,
            chi0=mod_chi0_b,
            dchi=mod_dchi_b,
            tau1=mod_tau1_b,
            tau2=mod_tau2_b,
        )
        Fields1 = Problem1.fields(mod_a)
        Fields2 = Problem2.fields()
        Fields3 = Problem3.fields(mod_b)
        Fields4 = Problem4.fields()
        dpred1 = Problem1.dpred(mod_a)
        dpred2 = Problem2.dpred(mod_a)

        Err1 = np.abs((Fields1 - Fields2) / Fields1)
        Err2 = np.abs((Fields2 - Fields3) / Fields2)
        Err3 = np.abs((Fields3 - Fields4) / Fields3)
        Err4 = np.abs((Fields4 - Fields1) / Fields4)
        Err5 = np.abs((dpred1 - dpred2) / dpred1)

        Test1 = Err1 < 0.01
        Test2 = Err2 < 0.01
        Test3 = Err3 < 0.01
        Test4 = Err4 < 0.01
        Test5 = Err5 < 0.01

        self.assertTrue(Test1 and Test2 and Test3 and Test4 and Test5)
Ejemplo n.º 7
0
    def test_convergence_radial(self):
        """
        Test the convergence of the solution to analytic results from
        Cowan (2016) and test accuracy
        """

        h = [(2, 30)]
        meshObj = discretize.TensorMesh((h, h, [(2, 20)]), x0="CCN")

        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0
        mod = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj.nC)

        times = np.array([1e-3])
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        z = 0.25
        a = 5
        receiver_list = [
            vrm.receivers.Point(np.c_[a, 0.0, z],
                                times=times,
                                fieldType="dhdt",
                                orientation="x")
        ]
        receiver_list.append(
            vrm.receivers.Point(np.c_[0.0, a, z],
                                times=times,
                                fieldType="dhdt",
                                orientation="y"))
        txList = [
            vrm.sources.CircLoop(receiver_list, np.r_[0.0, 0.0, z], a,
                                 np.r_[0.0, 0.0], 1.0, waveObj)
        ]

        survey = vrm.Survey(txList)
        Problem2 = vrm.Simulation3DLinear(meshObj,
                                          survey=survey,
                                          refinement_factor=2)
        Problem3 = vrm.Simulation3DLinear(meshObj,
                                          survey=survey,
                                          refinement_factor=3)
        Problem4 = vrm.Simulation3DLinear(meshObj,
                                          survey=survey,
                                          refinement_factor=4)
        Problem5 = vrm.Simulation3DLinear(meshObj,
                                          survey=survey,
                                          refinement_factor=5)
        Fields2 = Problem2.fields(mod)
        Fields3 = Problem3.fields(mod)
        Fields4 = Problem4.fields(mod)
        Fields5 = Problem5.fields(mod)

        gamma = 4 * z * (2 / np.pi)**1.5
        F = -(1 / np.log(tau2 / tau1)) * (1 / times - 1 / (times + 0.02))
        Fields_true = 0.5 * (dchi / (2 + dchi)) * (np.pi * gamma)**-1 * F

        ErrsX = np.abs((np.r_[Fields2[0], Fields3[0], Fields4[0], Fields5[0]] -
                        Fields_true) / Fields_true)
        ErrsY = np.abs((np.r_[Fields2[1], Fields3[1], Fields4[1], Fields5[1]] -
                        Fields_true) / Fields_true)

        Testx1 = ErrsX[-1] < 0.01
        Testy1 = ErrsY[-1] < 0.01
        Testx2 = np.all(ErrsX[1:] - ErrsX[0:-1] < 0.0)
        Testy2 = np.all(ErrsY[1:] - ErrsY[0:-1] < 0.0)

        self.assertTrue(Testx1 and Testx2 and Testy1 and Testy2)
Ejemplo n.º 8
0
    def test_predict_dipolar(self):

        np.random.seed(self.seed)

        h = [0.05, 0.05]
        meshObj = discretize.TensorMesh((h, h, h), x0="CCC")

        dchi = 0.01
        tau1 = 1e-8
        tau2 = 1e0
        mod = (dchi / np.log(tau2 / tau1)) * np.ones(meshObj.nC)

        times = np.logspace(-4, -2, 3)
        waveObj = vrm.waveforms.SquarePulse(delt=0.02)

        phi = np.random.uniform(-np.pi, np.pi)
        psi = np.random.uniform(-np.pi, np.pi)
        R = 2.0
        loc_rx = (R * np.c_[np.sin(phi) * np.cos(psi),
                            np.sin(phi) * np.sin(psi),
                            np.cos(phi)])

        receiver_list = [
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="x")
        ]
        receiver_list.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="y"))
        receiver_list.append(
            vrm.receivers.Point(loc_rx,
                                times=times,
                                fieldType="dhdt",
                                orientation="z"))

        alpha = np.random.uniform(0, np.pi)
        beta = np.random.uniform(-np.pi, np.pi)
        loc_tx = [0.0, 0.0, 0.0]
        Src = vrm.sources.CircLoop(receiver_list, loc_tx, 25.0,
                                   np.r_[alpha, beta], 1.0, waveObj)
        txList = [Src]

        Survey = vrm.Survey(txList)
        Problem = vrm.Simulation3DLinear(meshObj,
                                         survey=Survey,
                                         refinement_factor=0)
        Fields = Problem.fields(mod)

        H0 = Src.getH0(np.c_[0.0, 0.0, 0.0])
        dmdtx = (-H0[0, 0] * 0.1**3 * (dchi / np.log(tau2 / tau1)) *
                 (1 / times[1] - 1 / (times[1] + 0.02)))
        dmdty = (-H0[0, 1] * 0.1**3 * (dchi / np.log(tau2 / tau1)) *
                 (1 / times[1] - 1 / (times[1] + 0.02)))
        dmdtz = (-H0[0, 2] * 0.1**3 * (dchi / np.log(tau2 / tau1)) *
                 (1 / times[1] - 1 / (times[1] + 0.02)))
        dmdot = np.dot(np.r_[dmdtx, dmdty, dmdtz], loc_rx.T)

        fx = (1 /
              (4 * np.pi)) * (3 * loc_rx[0, 0] * dmdot / R**5 - dmdtx / R**3)
        fy = (1 /
              (4 * np.pi)) * (3 * loc_rx[0, 1] * dmdot / R**5 - dmdty / R**3)
        fz = (1 /
              (4 * np.pi)) * (3 * loc_rx[0, 2] * dmdot / R**5 - dmdtz / R**3)

        self.assertTrue(
            np.all(
                np.abs(Fields[1:-1:3] - np.r_[fx, fy, fz]) < 1e-5 *
                np.sqrt((Fields[1:-1:3]**2).sum())))
Ejemplo n.º 9
0
#
# Here we define the formulation for solving Maxwell's equations. We have chosen
# to model the off-time VRM response. There are two important keyword arguments,
# *refinement_factor* and *refinement_distance*. These are used to refine the
# sensitivities of the cells near the transmitters. This improves the accuracy
# of the forward simulation without having to refine the mesh near transmitters.
#

# For this example, cells lying within 2 m of a transmitter will be modeled
# as if they are comprised of 4^3 equal smaller cells. Cells within 4 m of a
# transmitter will be modeled as if they are comprised of 2^3 equal smaller
# cells.
simulation = vrm.Simulation3DLinear(
    mesh,
    survey=survey,
    indActive=ind_active,
    refinement_factor=2,
    refinement_distance=[2.0, 4.0],
)

#######################################
# Predict Data and Plot
# ---------------------
#

# Predict VRM response
dpred = simulation.dpred(model)

# Reshape for plotting
n_times = len(time_channels)
n_waveforms = len(waveform_list)