Rust API ======== .. code:: rust use readcon_db::{ConCorpus, Select}; let db = ConCorpus::open("/tmp/corpus")?; db.append_trajectory_path(1, "run.con")?; let keys = db.select( &Select::new() .trajectory(1) .require_symbol("Cu") .natoms_range(1, 10_000) .limit(100), )?; let h = db.frame_hash(keys[0])?; assert_eq!(db.find_by_hash(h)?, Some(keys[0])); let text = db.get_frame_text(keys[0])?; let frame = db.get_frame(keys[0])?; // ConFrame Exact match: .. code:: rust let sel = Select::new().exact_hash(h.to_bytes()); let hits = db.select(&sel)?; See crate docs (``cargo doc --open``) for ``Error`` variants and ``ContentHash::to_hex``. Topology keys ------------- Exact match stays xxHash3 on CON bytes. The coarser identity is the bonded graph up to relabelling from ``seams fingerprint FILE --format json``. .. code:: rust use readcon_db::{AnnotateTopologyOpts, ConCorpus, Select, TrajMeta}; db.annotate_topology(AnnotateTopologyOpts::new(3.0))?; let hits = db.select(&Select::new().topo_key(hex))?; let same = db.find_by_topology_path("perm.con")?; let meta: TrajMeta = db.traj_meta(1)?.unwrap(); // meta.topo_cutoff / topo_graph / topo_hops / topo_method +------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | API | Role | +==================================================================+========================================================================================================================================================================================================================+ | ``ConCorpus::annotate_topology`` | Shells ``seams fingerprint FILE --format json --cutoff C --graph G --hops H``. Resolves the binary from ``--seams`` / ``SEAMS`` / ``PATH``. Default graph ``cutoff``, hops 2. Cutoff required. Refuses a mixed method. | +------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``ConCorpus::find_by_topology_path`` / ``find_by_topology_text`` | Fingerprint a file (or CON text) with the recorded corpus params and look up ``idx_topo``. Errors if nothing is annotated or if seams is missing. | +------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``Select::topo_key`` | Prefix-scan ``idx_topo`` (topology-key utf-8 | +------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``TrajMeta`` | Optional ``topo_cutoff``, ``topo_graph``, ``topo_hops``, ``topo_method`` (serde default; old JSON still loads). Ingest/extend preserve these fields. | +------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ CLI: .. code:: text readcon-db annotate-topology --cutoff A [--graph G] [--hops N] [--seams PATH] readcon-db select --topo-key HEX readcon-db find-by-topology Missing seams: nonzero exit and a stderr message that names ``seams fingerprint``. How-to: :doc:`/howto/topology`. .. code:: rust use readcon_db::{ canonicalize_unit, join_drained_roots, ConCorpus, ShardedConCorpus, }; let blob = db.pack_frames(&keys)?; let a = db.collect_h5md(1)?; db.append_trajectory_path_units(1, "run.con", Some(serde_json::json!({ "length": "A", "energy": "ev", "time": "femtosecond" })))?; db.set_trajectory_units(1, serde_json::json!({"length": "nm", "energy": "eV"}))?; let _ = canonicalize_unit("A")?; ShardedConCorpus::drain_to(src, dest)?; join_drained_roots(&[dest_a, dest_b], joined)?; ``set_trajectory_units`` converts stored numbers. A v3.1 clock or velocities frame with no ``units.time`` is an error, not a silent ``fs``; v1, v2, and v3.0 clocks with no ``units.time`` still convert as ``fs``. ``append_trajectory_path_units`` and ``extend_trajectory_path_units`` stamp incoming frames. H5MD velocities follow D10 and are written as ``Angstrom ps-1``. v1, v2, and v3.0 frames use ``(amu*angstrom^2/eV)^0.5`` whatever the time label says. v3.1 frames use ``units.time`` and ``collect_h5md`` fails when velocities have no ``units.time``. ``H5mdCollectOpts.velocity_time_unit`` overrides that rule for a file that breaks it. The clock (``time``, ``timestep``, H5MD time) uses ``units.time`` when that key is present. A v3.1 frame with ``time`` or ``timestep`` and no ``units.time`` is an error, and the same override supplies that missing clock unit. A present ``units.time`` still scales the clock. v1, v2, and v3.0 clocks with no ``units.time`` are read as ``fs``. Cooked SoA (RCSO) ----------------- See ``docs/orgmode/cooked-soa.org``. Tier is opt-in; CON text remains authority. Bindings expose cook / delete / has-valid / positions / forces / velocities.