def _rebuild_operators(self):
        if self.mesh.x.lbc.type == 'pml' and self.compact:
            # build intermediates for the compact operator
            raise ValidationFunctionError(
                " This solver is in construction and is not yet complete. For variable density and compact PML."
            )
            dof = self.mesh.dof(include_bc=True)

            oc = self.operator_components

            built = oc.get('_numpy_components_built', False)
            oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2)
            # build the static components
            if not built:
                # build Dxx
                oc.Dxx = build_derivative_matrix(
                    self.mesh,
                    2,
                    self.spatial_accuracy_order,
                    dimension='x',
                    use_shifted_differences=self.spatial_shifted_differences)
                # build Dzz
                oc.Dzz = build_derivative_matrix(
                    self.mesh,
                    2,
                    self.spatial_accuracy_order,
                    dimension='z',
                    use_shifted_differences=self.spatial_shifted_differences)
                # build Dx
                oc.Dx = build_derivative_matrix(
                    self.mesh,
                    1,
                    self.spatial_accuracy_order,
                    dimension='x',
                    use_shifted_differences=self.spatial_shifted_differences)

                # build Dz
                oc.Dz = build_derivative_matrix(
                    self.mesh,
                    1,
                    self.spatial_accuracy_order,
                    dimension='z',
                    use_shifted_differences=self.spatial_shifted_differences)

                # build sigma
                oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh)

                oc._numpy_components_built = True
        else:
            # build intermediates for operator with auxiliary fields
            dof = self.mesh.dof(include_bc=True)

            oc = self.operator_components

            built = oc.get('_numpy_components_built', False)

            # build the static components
            if not built:
                # build sigmax
                sx = build_sigma(self.mesh, self.mesh.x)
                oc.sigmax = make_diag_mtx(sx)

                # build sigmaz
                sz = build_sigma(self.mesh, self.mesh.z)
                oc.sigmaz = make_diag_mtx(sz)

                # build Dx
                oc.minus_Dx = build_derivative_matrix(
                    self.mesh,
                    1,
                    self.spatial_accuracy_order,
                    dimension='x',
                    use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dx.data *= -1

                # build Dz
                oc.minus_Dz = build_derivative_matrix(
                    self.mesh,
                    1,
                    self.spatial_accuracy_order,
                    dimension='z',
                    use_shifted_differences=self.spatial_shifted_differences)
                oc.minus_Dz.data *= -1

                # build other useful things
                oc.I = spsp.eye(dof, dof)
                oc.empty = spsp.csr_matrix((dof, dof))

                # useful intermediates
                oc.sigma_xz = make_diag_mtx(sx * sz)
                oc.sigma_xPz = oc.sigmax + oc.sigmaz

                oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx
                oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz

                oc._numpy_components_built = True

        kappa = self.model_parameters.kappa
        rho = self.model_parameters.rho
        oc.m1 = make_diag_mtx((kappa**-1).reshape(-1, ))
        oc.m2 = make_diag_mtx((rho**-1).reshape(-1, ))
        # build heterogenous laplacian
        sh = self.mesh.shape(include_bc=True, as_grid=True)
        deltas = [self.mesh.x.delta, self.mesh.z.delta]
        oc.L = build_derivative_matrix_VDA(self.mesh,
                                           2,
                                           self.spatial_accuracy_order,
                                           alpha=rho**-1)

        # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho.
        # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian.
        # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying
        # a divergence operator by oc.m2 by a gradient operator.

        self.K = spsp.bmat([[
            oc.m1 * oc.sigma_xz - oc.L, oc.minus_Dx * oc.m2,
            oc.minus_Dz * oc.m2
        ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty],
                            [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]])

        self.C = spsp.bmat([[oc.m1 * oc.sigma_xPz, oc.empty, oc.empty],
                            [oc.empty, oc.I, oc.empty],
                            [oc.empty, oc.empty, oc.I]])

        self.M = spsp.bmat([[oc.m1, oc.empty, oc.empty],
                            [oc.empty, oc.empty, oc.empty],
                            [oc.empty, oc.empty, oc.empty]])
    def _rebuild_operators(self):

        VariableDensityAcousticTimeScalar_2D._rebuild_operators(self)

        dof = self.mesh.dof(include_bc=True)

        oc = self.operator_components

        built = oc.get('_numpy_components_built', False)

        # build the static components
        if not built:
            # build sigmax
            sx = build_sigma(self.mesh, self.mesh.x)
            oc.sigmax = make_diag_mtx(sx)

            # build sigmaz
            sz = build_sigma(self.mesh, self.mesh.z)
            oc.sigmaz = make_diag_mtx(sz)

            # build Dx
            oc.Dx = build_derivative_matrix(self.mesh,
                                            1,
                                            self.spatial_accuracy_order,
                                            dimension='x')
            oc.minus_Dx = copy.deepcopy(
                oc.Dx)  #more storage, but less computations
            oc.minus_Dx.data *= -1

            # build Dz
            oc.Dz = build_derivative_matrix(self.mesh,
                                            1,
                                            self.spatial_accuracy_order,
                                            dimension='z')
            oc.minus_Dz = copy.deepcopy(
                oc.Dz)  #more storage, but less computations
            oc.minus_Dz.data *= -1

            # build other useful things
            oc.I = spsp.eye(dof, dof)
            oc.empty = spsp.csr_matrix((dof, dof))

            # useful intermediates
            oc.sigma_xz = make_diag_mtx(sx * sz)
            oc.sigma_xPz = oc.sigmax + oc.sigmaz

            oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx
            oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz

            oc._numpy_components_built = True

        kappa = self.model_parameters.kappa
        rho = self.model_parameters.rho

        oc.m1 = make_diag_mtx((kappa**-1).reshape(-1, ))
        oc.m2 = make_diag_mtx((rho**-1).reshape(-1, ))

        oc.L = build_derivative_matrix_VDA(self.mesh,
                                           2,
                                           self.spatial_accuracy_order,
                                           alpha=rho**-1)

        # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho.
        # Ian's implementation used the regular Dx operators in the PML even though the heterogeneous Laplacian with staggered derivative operators is used in the physical domain.
        # I (Bram) did not change this or investigate if this causes some problems but am noting it here for completeness.

        K = spsp.bmat([[
            oc.m1 * oc.sigma_xz - oc.L, oc.minus_Dx * oc.m2,
            oc.minus_Dz * oc.m2
        ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty],
                       [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]])

        C = spsp.bmat([[oc.m1 * oc.sigma_xPz, oc.empty, oc.empty],
                       [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I]
                       ]) / self.dt

        M = spsp.bmat([[oc.m1, oc.empty, oc.empty],
                       [oc.empty, oc.empty, oc.empty],
                       [oc.empty, oc.empty, oc.empty]]) / self.dt**2

        Stilde_inv = M + C
        Stilde_inv.data = 1. / Stilde_inv.data

        self.A_k = Stilde_inv * (2 * M - K + C)
        self.A_km1 = -1 * Stilde_inv * (M)
        self.A_f = Stilde_inv
    def _rebuild_operators(self):
        if self.mesh.x.lbc.type == 'pml' and self.compact:
          # build intermediates for the compact operator
          raise ValidationFunctionError(" This solver is in construction and is not yet complete. For variable density and compact PML.")
          dof = self.mesh.dof(include_bc=True)

          oc = self.operator_components

          built = oc.get('_numpy_components_built', False)
          oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2)
          # build the static components
          if not built:          
            # build Dxx
            oc.Dxx = build_derivative_matrix(self.mesh,
                                                  2,
                                                  self.spatial_accuracy_order,
                                                  dimension='x',
                                                  use_shifted_differences=self.spatial_shifted_differences)
            # build Dzz
            oc.Dzz = build_derivative_matrix(self.mesh,
                                                  2,
                                                  self.spatial_accuracy_order,
                                                  dimension='z',
                                                  use_shifted_differences=self.spatial_shifted_differences)
            # build Dx
            oc.Dx = build_derivative_matrix(self.mesh,
                                                  1,
                                                  self.spatial_accuracy_order,
                                                  dimension='x',
                                                  use_shifted_differences=self.spatial_shifted_differences)
            
            # build Dz
            oc.Dz = build_derivative_matrix(self.mesh,
                                                  1,
                                                  self.spatial_accuracy_order,
                                                  dimension='z',
                                                  use_shifted_differences=self.spatial_shifted_differences)
                                                  
            # build sigma
            oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh)

            oc._numpy_components_built = True
        else:
          # build intermediates for operator with auxiliary fields
          dof = self.mesh.dof(include_bc=True)

          oc = self.operator_components

          built = oc.get('_numpy_components_built', False)

          # build the static components
          if not built:
            # build sigmax
            sx = build_sigma(self.mesh, self.mesh.x)
            oc.sigmax = make_diag_mtx(sx)

            # build sigmaz
            sz = build_sigma(self.mesh, self.mesh.z)
            oc.sigmaz = make_diag_mtx(sz)

            # build Dx
            oc.minus_Dx = build_derivative_matrix(self.mesh,
                                                  1,
                                                  self.spatial_accuracy_order,
                                                  dimension='x',
                                                  use_shifted_differences=self.spatial_shifted_differences)
            oc.minus_Dx.data *= -1

            # build Dz
            oc.minus_Dz = build_derivative_matrix(self.mesh,
                                                  1,
                                                  self.spatial_accuracy_order,
                                                  dimension='z',
                                                  use_shifted_differences=self.spatial_shifted_differences)
            oc.minus_Dz.data *= -1

            # build other useful things
            oc.I = spsp.eye(dof, dof)
            oc.empty = spsp.csr_matrix((dof, dof))

            # useful intermediates
            oc.sigma_xz  = make_diag_mtx(sx*sz)
            oc.sigma_xPz = oc.sigmax + oc.sigmaz

            oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx
            oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz

            oc._numpy_components_built = True

        kappa = self.model_parameters.kappa
        rho = self.model_parameters.rho
        oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,))
        oc.m2 = make_diag_mtx((rho**-1).reshape(-1,))
        # build heterogenous laplacian
        sh = self.mesh.shape(include_bc=True,as_grid=True)
        deltas = [self.mesh.x.delta,self.mesh.z.delta]
        oc.L = build_derivative_matrix_VDA(self.mesh,
                                           2,
                                           self.spatial_accuracy_order,
                                           alpha = rho**-1
                                           )

        # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. 
        # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian.
        # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying
        # a divergence operator by oc.m2 by a gradient operator.

        self.K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ],
                            [oc.minus_sigma_zMx_Dx, oc.sigmax,   oc.empty    ],
                            [oc.minus_sigma_xMz_Dz, oc.empty,    oc.sigmaz   ]])

        self.C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty],
                            [oc.empty,          oc.I,     oc.empty],
                            [oc.empty,          oc.empty, oc.I    ]])

        self.M = spsp.bmat([[    oc.m1, oc.empty, oc.empty],
                            [oc.empty, oc.empty, oc.empty],
                            [oc.empty, oc.empty, oc.empty]])
    def _rebuild_operators(self):
    
            VariableDensityAcousticTimeScalar_2D._rebuild_operators(self)
    
            dof = self.mesh.dof(include_bc=True)
    
            oc = self.operator_components
    
            built = oc.get('_numpy_components_built', False)
    
            # build the static components
            if not built:
                # build sigmax
                sx = build_sigma(self.mesh, self.mesh.x)
                oc.sigmax = make_diag_mtx(sx)
    
                # build sigmaz
                sz = build_sigma(self.mesh, self.mesh.z)
                oc.sigmaz = make_diag_mtx(sz)
    
                # build Dx
                oc.Dx = build_derivative_matrix(self.mesh,
                                                        1,
                                                        self.spatial_accuracy_order,
                                                        dimension='x')
                oc.minus_Dx = copy.deepcopy(oc.Dx)      #more storage, but less computations
                oc.minus_Dx.data *= -1                  
    
                # build Dz
                oc.Dz = build_derivative_matrix(self.mesh,
                                                        1,
                                                        self.spatial_accuracy_order,
                                                        dimension='z')
                oc.minus_Dz = copy.deepcopy(oc.Dz)      #more storage, but less computations
                oc.minus_Dz.data *= -1                                  

    
                # build other useful things
                oc.I = spsp.eye(dof, dof)
                oc.empty = spsp.csr_matrix((dof, dof))
    
                # useful intermediates
                oc.sigma_xz  = make_diag_mtx(sx*sz)
                oc.sigma_xPz = oc.sigmax + oc.sigmaz
    
                oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx
                oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz
    
                oc._numpy_components_built = True

            kappa = self.model_parameters.kappa
            rho = self.model_parameters.rho
    
            oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,))
            oc.m2 = make_diag_mtx((rho**-1).reshape(-1,))

            oc.L = build_derivative_matrix_VDA(self.mesh,
                                               2,
                                               self.spatial_accuracy_order,
                                               alpha = rho**-1
                                               )
            
    
            # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. 
            # Ian's implementation used the regular Dx operators in the PML even though the heterogeneous Laplacian with staggered derivative operators is used in the physical domain.
            # I (Bram) did not change this or investigate if this causes some problems but am noting it here for completeness. 
            
            K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ],
                           [oc.minus_sigma_zMx_Dx, oc.sigmax,   oc.empty    ],
                           [oc.minus_sigma_xMz_Dz, oc.empty,    oc.sigmaz   ]])
    
            C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty],
                           [oc.empty,          oc.I,     oc.empty],
                           [oc.empty,          oc.empty, oc.I    ]]) / self.dt
    
            M = spsp.bmat([[    oc.m1, oc.empty, oc.empty],
                           [oc.empty, oc.empty, oc.empty],
                           [oc.empty, oc.empty, oc.empty]]) / self.dt**2
    
            Stilde_inv = M+C
            Stilde_inv.data = 1./Stilde_inv.data
    
            self.A_k   = Stilde_inv*(2*M - K + C)
            self.A_km1 = -1*Stilde_inv*(M)
            self.A_f   = Stilde_inv