def do_q_jacobian_eigenvectors(self, q):
        g = self.gravity_constant
        p = get_primitive_variables(q)
        h = p[0]
        u = p[1]
        if self.num_moments == 0:
            eigenvectors = np.array([[1, u - np.sqrt(g * h)],
                                     [1, u + np.sqrt(g * h)]])
        elif self.num_moments == 1:
            s = p[2]
            eigenvectors = np.array([
                [1, u - np.sqrt(g * h + s * s), 2 * s],
                [1, u, -1 / 2 * (3 * g * h - s * s) / s],
                [1, u + np.sqrt(g * h + s * s), 2 * s],
            ])
        elif self.num_moments == 2:
            raise errors.NotImplementedParameter(
                "FluxFunction.do_q_jacobian_eigenvectors",
                "num_moments",
                self.num_moments,
            )
        elif self.num_moments == 3:
            raise errors.NotImplementedParameter(
                "FluxFunction.do_q_jacobian_eigenvectors",
                "num_moments",
                self.num_moments,
            )

        return eigenvectors
    def quasilinear_eigenvectors_left(self, q, x, t):
        # TODO: needs to be implemented
        errors.MissingImplementation(self.class_str, "quasilinear_eigenvectors_left")
        g = self.gravity_constant
        p = swme.get_primitive_variables(q)
        h = p[0]
        u = p[1]
        eigenvectors = np.zeros((self.num_moments + 2, self.num_moments + 2))
        if self.num_moments == 0:
            sqrt_gh = np.sqrt(g * h)
            eigenvectors[0, 0] = 0.5 * (u + sqrt_gh) / sqrt_gh
            eigenvectors[0, 1] = -0.5 / sqrt_gh

            eigenvectors[1, 0] = -0.5 * (u - sqrt_gh) / sqrt_gh
            eigenvectors[1, 1] = 0.5 / sqrt_gh
        elif self.num_moments == 1:
            s = p[2]
            ghs2 = g * h + s * s
            sqrt_gh_s2 = np.sqrt(ghs2)
            eigenvectors[0, 0] = (
                1.0 / 6.0 * (3.0 * g * h - s * s + 3.0 * sqrt_gh_s2 * u) / ghs2
            )
            eigenvectors[0, 1] = -0.5 / sqrt_gh_s2
            eigenvectors[0, 2] = 1.0 / 3.0 * s / ghs2

            eigenvectors[1, 0] = 4.0 / 3.0 * s * s / ghs2
            eigenvectors[1, 1] = 0.0
            eigenvectors[1, 2] = -2.0 / 3.0 * s / ghs2

            eigenvectors[2, 0] = (
                -1.0
                / 6.0
                * (3.0 * ghs2 * u - (3.0 * g * h - s * s) * sqrt_gh_s2)
                / np.power(ghs2, 1.5)
            )
            eigenvectors[2, 1] = 0.5 / sqrt_gh_s2
            eigenvectors[2, 2] = 1.0 / 3.0 * s / ghs2

        elif self.num_moments == 2:
            raise errors.NotImplementedParameter(
                "ShallowWaterLinearizedMomentEquations.quasilinear_eigenvectors_left",
                "num_moments",
                2,
            )
        elif self.num_moments == 3:
            raise errors.NotImplementedParameter(
                "ShallowWaterLinearizedMomentEquations.quasilinear_eigenvectors_left",
                "num_moments",
                3,
            )

        return eigenvectors
    def quasilinear_eigenvectors_right(self, q, x, t):
        # TODO: needs to be implemented
        errors.MissingImplementation(self.class_str, "quasilinear_eigenvectors_right")
        g = self.gravity_constant
        p = swme.get_primitive_variables(q)
        h = p[0]
        u = p[1]
        eigenvectors = np.zeros((self.num_moments + 2, self.num_moments + 2))
        if self.num_moments == 0:
            sqrt_gh = np.sqrt(g * h)
            eigenvectors[0, 0] = 1.0
            eigenvectors[1, 0] = u - sqrt_gh

            eigenvectors[0, 1] = 1.0
            eigenvectors[1, 1] = u + sqrt_gh
        elif self.num_moments == 1:
            s = p[2]
            sqrt_gh_s2 = np.sqrt(g * h + s * s)
            eigenvectors[0, 0] = 1.0
            eigenvectors[1, 0] = u - sqrt_gh_s2
            eigenvectors[2, 0] = 2.0 * s

            eigenvectors[0, 1] = 1.0
            eigenvectors[1, 1] = u
            eigenvectors[2, 1] = -0.5 * (3.0 * g * h - s * s) / s

            eigenvectors[0, 2] = 1.0
            eigenvectors[1, 2] = u + sqrt_gh_s2
            eigenvectors[2, 2] = 2.0 * s
        elif self.num_moments == 2:
            raise errors.NotImplementedParameter(
                "ShallowWaterLinearizedMomentEquations.quasilinear_eigenvalues_right",
                "num_moments",
                2,
            )
        elif self.num_moments == 3:
            raise errors.NotImplementedParameter(
                "ShallowWaterLinearizedMomentEquations.quasilinear_eigenvectors_right",
                "num_moments",
                3,
            )

        return eigenvectors
    def quasilinear_eigenvectors_right(self, q, x, t, n):
        g = self.gravity_constant
        p = get_primitive_variables(q)
        h = p[0]
        u = p[1]
        eigenvectors = np.zeros((self.num_moments + 2, self.num_moments + 2))
        if self.num_moments == 0:
            sqrtgh = np.sqrt(g * h)
            eigenvectors[0, 0] = 1.0
            eigenvectors[1, 0] = u - sqrtgh

            eigenvectors[0, 1] = 1.0
            eigenvectors[1, 1] = u + sqrtgh
        elif self.num_moments == 1:
            s = p[2]
            sqrtghs2 = np.sqrt(g * h + s * s)
            eigenvectors[0, 0] = 1.0
            eigenvectors[1, 0] = u - sqrtghs2
            eigenvectors[2, 0] = 2.0 * s

            eigenvectors[0, 1] = 1.0
            eigenvectors[1, 1] = u
            eigenvectors[2, 1] = -0.5 * (3.0 * g * h - s * s) / s

            eigenvectors[0, 2] = 1.0
            eigenvectors[1, 2] = u + sqrtghs2
            eigenvectors[2, 2] = 2.0 * s
        elif self.num_moments == 2:
            raise errors.NotImplementedParameter(
                "ShallowWaterMomentEquations.quasilinear_eigenvalues_right",
                "num_moments",
                2,
            )
        elif self.num_moments == 3:
            raise errors.NotImplementedParameter(
                "ShallowWaterMomentEquations.quasilinear_eigenvectors_right",
                "num_moments",
                3,
            )

        return eigenvectors
def gauss_pts_and_wgts_2d_triangle_canonical(quad_order=5):
    # quadrature on canonical triangle
    canonical_volume = canonical_element.Triangle.volume
    if quad_order == 1:
        degree_of_exactness = 1
    elif quad_order == 2:
        degree_of_exactness = 2
    elif quad_order == 3:
        degree_of_exactness = 4
    elif quad_order == 4:
        degree_of_exactness = 6
    elif quad_order == 5:
        degree_of_exactness = 8
    else:
        raise errors.NotImplementedParameter(
            "gauss_pts_and_wgts_2d_triangle_canonical", "quad_order", quad_order
        )

    if degree_of_exactness == 1:
        quad_wgts = canonical_volume * np.array([1.0])
        quad_pts_barycentric = np.array([[1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0]])
    elif degree_of_exactness == 2:
        w0 = 1.0 / 3.0
        quad_wgts = canonical_volume * np.array([w0, w0, w0])
        p0 = np.array([2.0 / 3.0, 1.0 / 6.0, 1.0 / 6.0])
        quad_pts_barycentric = np.array([p0, np.roll(p0, 1), np.roll(p0, 2)])
    elif degree_of_exactness == 3:
        w0 = -0.5625
        w1 = 25.0 / 48.0
        quad_wgts = canonical_volume * np.array([w0, w1, w1, w1])
        p0 = np.array([1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0])
        p1 = np.array([0.6, 0.2, 0.2])
        quad_pts_barycentric = np.array([p0, p1, np.roll(p1, 1), np.roll(p1, 2)])
    elif degree_of_exactness == 4:
        w0 = 0.223381589678011
        w1 = 0.109951743655322
        quad_wgts = canonical_volume * np.array([w0, w0, w0, w1, w1, w1])
        p0 = np.array([0.108103018168070, 0.445948490915965, 0.445948490915965])
        p1 = np.array([0.816847572980459, 0.091576213509771, 0.091576213509771])
        quad_pts_barycentric = np.array(
            [p0, np.roll(p0, 1), np.roll(p0, 2), p1, np.roll(p1, 1), np.roll(p1, 2)]
        )
    elif degree_of_exactness == 5:
        w0 = 0.225
        w1 = 0.132394152788506
        w2 = 0.125939180544827
        quad_wgts = canonical_volume * np.array([w0, w1, w1, w1, w2, w2, w2])
        p0 = np.array([1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0])
        p1 = np.array([0.059715871789770, 0.470142064105115, 0.470142064105115])
        p2 = np.array([0.797426985353087, 0.101286507323456, 0.101286507323456])
        quad_pts_barycentric = np.array(
            [p0, p1, np.roll(p1, 1), np.roll(p1, 2), p2, np.roll(p2, 1), np.roll(p2, 2)]
        )
    elif degree_of_exactness == 6:
        w0 = 0.116786275726379
        w1 = 0.050844906370207
        w2 = 0.082851075618374
        quad_wgts = canonical_volume * np.array(
            [w0, w0, w0, w1, w1, w1, w2, w2, w2, w2, w2, w2]
        )
        p0 = np.array([0.501426509658179, 0.249286745170910, 0.249286745170910])
        p1 = np.array([0.873821971016996, 0.063089014491502, 0.063089014491502])
        p2 = np.array([0.053145049844817, 0.310352451033784, 0.636502499121399])
        p3 = np.flip(p2)
        quad_pts_barycentric = np.array(
            [
                p0,
                np.roll(p0, 1),
                np.roll(p0, 2),
                p1,
                np.roll(p1, 1),
                np.roll(p1, 2),
                p2,
                np.roll(p2, 1),
                np.roll(p2, 2),
                p3,
                np.roll(p3, 1),
                np.roll(p3, 2),
            ]
        )
    elif degree_of_exactness == 8:
        w0 = 0.144315607677787
        w1 = 0.095091634267285
        w2 = 0.103217370534718
        w3 = 0.032458497623198
        w4 = 0.027230314174435
        quad_wgts = canonical_volume * np.array(
            [w0, w1, w1, w1, w2, w2, w2, w3, w3, w3, w4, w4, w4, w4, w4, w4]
        )
        p0 = np.array([1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0])
        p1 = np.array([0.081414823414554, 0.459292588292723, 0.459292588292723])
        p2 = np.array([0.658861384496480, 0.170569307751760, 0.170569307751760])
        p3 = np.array([0.898905543365938, 0.050547228317031, 0.050547228317031])
        p4 = np.array([0.008394777409958, 0.263112829634638, 0.728492392955404])
        p5 = np.flip(p4)
        quad_pts_barycentric = np.array(
            [
                p0,
                p1,
                np.roll(p1, 1),
                np.roll(p1, 2),
                p2,
                np.roll(p2, 1),
                np.roll(p2, 2),
                p3,
                np.roll(p3, 1),
                np.roll(p3, 2),
                p4,
                np.roll(p4, 1),
                np.roll(p4, 2),
                p5,
                np.roll(p5, 1),
                np.roll(p5, 2),
            ]
        )
    else:
        raise errors.NotImplementedParameter(
            "gauss_pts_and_wgts_2d_triangle_canonical",
            "degree_of_exactness",
            degree_of_exactness,
        )

    vertices = canonical_element.Triangle.vertices
    quad_pts = (quad_pts_barycentric @ vertices).T
    return (quad_pts, quad_wgts)