Line Bundles
On a 2-manifold, each tangent space is isomorphic to . A k-atic director (a headless director with k-fold rotational symmetry) lives in the complex line bundle with connection , where is the Levi-Civita connection 1-form.
The line_bundle module provides discrete sections of these bundles, the
associated Bochner Laplacian, and exact topological defect detection.
Section<K>
Section<K> stores one Complex<f64> per vertex. The const generic K
determines the k-atic order:
| K | Field type | Defect charges |
|---|---|---|
| 1 | Tangent vector (spin-1) | |
| 2 | Nematic (spin-2) | |
| 4 | Tetratic (spin-4) | |
| 6 | Hexatic (spin-6) |
use cartan_dec::line_bundle::Section;
use num_complex::Complex;
// Nematic section (K=2): one complex number per vertex.
let z = Section::<2>::uniform(nv, Complex::new(0.3, 0.4));
// Scalar order parameter S = 2|z|.
let s = z.scalar_order();
// Normalise to unit order (|z| = 1 at each vertex).
z.normalise(1e-15);Compile-time K gives type safety: you cannot accidentally add a
Section<2> to a Section<4>.
Connection Angles
The discrete Levi-Civita connection is stored as angle-valued 1-forms on
edges. ConnectionAngles precomputes two sets:
- Primal (): vertex-to-vertex transport along primal edges. Used for the nematic Bochner Laplacian and defect charges.
- Dual (): face-to-face transport along dual edges. Used for face-based vector Laplacians in Stokes solvers.
Transport of a k-atic section along primal edge multiplies by .
use cartan_dec::line_bundle::ConnectionAngles;
let conn = ConnectionAngles::from_mesh(&mesh, &manifold);
// conn.primal[e]: vertex-vertex connection angle for edge e
// conn.dual[e]: face-face connection angle for edge eBochner Laplacian
BochnerLaplacian<K> is a sparse Hermitian complex matrix assembled from
cotangent weights and connection transport phases:
Off-diagonal entry for edge : . Diagonal: sum of incident cotangent weights. Negative semi-definite by construction.
use cartan_dec::line_bundle::BochnerLaplacian;
let lap = BochnerLaplacian::<2>::from_mesh_data(&mesh, &hodge, &conn);
let delta_z = lap.apply(&z); // Delta^L zDefect Charges
Topological charges are computed per face using the discrete winding number plus the Gaussian curvature correction:
The discrete Poincare-Hopf theorem holds exactly: .
use cartan_dec::line_bundle::defect_charges;
let charges = defect_charges(§ion, &conn, &mesh, &gauss_curvature_per_face);
let total: f64 = charges.iter().sum();
// total == chi(M) to machine precisionVeronese Map
For interop between the complex line bundle representation and the standard Q-tensor, the Veronese map sends :
use cartan_dec::line_bundle::{section_to_q_components, q_components_to_section};
let (q1, q2) = section_to_q_components(§ion);
let recovered = q_components_to_section(&q1, &q2);References
- Zhu, Saintillan, Chern. "Active nematic fluids on Riemannian 2-manifolds." arXiv:2405.06044, 2024. Sections 2.1 and 3.