Header declarations¶
FiberHMM records what it did, and what a BAM contains, in @PG and @CO
header lines. @CO lines are written as @CO<TAB><text>; pysam's
header.to_dict()["CO"] returns the text.
| Line | Written by | Purpose |
|---|---|---|
@PG |
every producer (call, apply, recall-tfs/-nucs, dedup, pair, merge, tag-m5c, consensus, tag-consensus, …) |
provenance: command line, version, resolved settings |
@CO FIBERHMM-CHEMISTRY:v1: |
call, apply, recall-tfs/-nucs, pair/merge (joint recall) |
authoritative chemistry of the calls, and the code and tables that made them |
@CO MA-TYPES:v1: |
every command that writes MA |
advisory list of MA group names |
@CO fiberhmm:coord=molecular |
call, apply, recall-tfs/-nucs |
coordinate-frame marker; the same runs also put coord=molecular in their @PG DS. dedup, pair, merge, tag-m5c, call-m5c, tag-consensus and strand-rescue-annotate put coord=molecular in their own @PG DS when the tags they carried over are molecular. See Footprint-tag coordinate frame |
@CO FIBERHMM-CONSENSUS-MA:v1: |
consensus, transfer |
meaning of the consensus layers' bytes |
@CO FIBERHMM-CONSENSUS-FAMILY:v1: |
consensus, transfer |
one entry per class and layer |
@CO FIBERHMM-STRAND-RESCUE:v6: |
strand-rescue-annotate |
shadow-layer contract |
@CO FIBERHMM-TF-FAMILY:v1: |
tag-consensus |
family-slot contract |
@SQ M5, @SQ TP:circular, @CO FIBERHMM-REFERENCE:v1: |
pipeline |
identity and topology of the reference (plasmid maps) |
input @RG/@PG/@CO; basecaller=... tokens in @PG DS |
pipeline, call |
basecaller provenance |
Header lines are copied by samtools and most other tools, so they survive
downstream processing unless a tool rewrites the header.
A fiberhmm-call output adds its three @CO lines in this order:
@CO fiberhmm:coord=molecular
@CO FIBERHMM-CHEMISTRY:v1:assay=daf;enzyme=ddda;platform=pacbio;mode=daf;apply_sha256=…;pg=fiberhmm-call;…
@CO MA-TYPES:v1:nuc,msp,tf
@PG¶
fiberhmm-call's DS field states the frame and every resolved setting:
FiberHMM fused apply+recall; coord=molecular (ns/nl/as/al/MA in molecular original-fiber coordinates); mode=daf enzyme=ddda prob_threshold=128 primary_only=off alignments=primary-supplementary tf_decoder=multi_interval_v1 tf_interval_penalty=5.0 recall_nucs=True nuc_recall_policy=conservative nuc_profile=ddda_phase_posterior_v1 nuc_sha256=c86b05dc... phase_nrl=0 ddda_derived_tf_edge_gap=12 chimera_filter=on dedup=j0.95/mark/ends50 daf_snp_mask=on/3sites daf_unaligned_mask=on daf_insert_consensus=on/0of0/min20 daf_run_mask=>=2/keep-one cpg_mask=unmethylated-only hmm_cpg_mask=on
primary_only=on only with --alignments primary. DAF runs record
daf_unaligned_mask=on|off and
daf_insert_consensus=off|on/<used>of<clusters>/min<N> (n/a outside DAF).
The recallers record the recall subset. Recall reads the input's @PG to
warn when a SNP mask or reference used at calling time cannot be re-applied.
FIBERHMM-CHEMISTRY¶
@CO FIBERHMM-CHEMISTRY:v1:assay=daf;enzyme=ddda;platform=pacbio;mode=daf;model=ddda_TF;nuc_model=ddda_phase_posterior_v1;nuc_sha256=c86b05dc07e45392880e3460cf7f8880593ecad174e0a338d36ac53b7d0172d6
@CO FIBERHMM-CHEMISTRY:v1:assay=fiber-seq;enzyme=hia5;platform=nanopore;mode=nanopore-fiber;model=hia5_nanopore
;-separated key=value fields. Required: assay, enzyme, platform,
mode. Producers may add fields such as model, and nuc_model /
nuc_sha256 (the nucleosome profile and its file digest) when a distinct
nucleosome profile is active. Keys match [a-z][a-z0-9_]*; values match
[A-Za-z0-9_.+-]+.
Since 3.0 each run also records what made its calls, after the required fields (keys sorted):
| Field | Value |
|---|---|
apply_sha256 |
sha256 of the emission table of the footprint (apply) pass |
recall_sha256 |
sha256 of the table of the recall pass (the apply table when it is reused) |
nuc_model_sha256 |
sha256 of a separate nucleosome-likelihood table (DddA), when used |
fiberhmm_version |
FiberHMM version |
fiberhmm_commit |
git commit of the code (<sha>+dirty with local changes under fiberhmm/), when known: running from a git checkout, or a wheel built from one; omitted otherwise |
pg |
the @PG ID of the run the declaration belongs to |
@CO FIBERHMM-CHEMISTRY:v1:assay=fiber-seq;enzyme=hia5;platform=nanopore;mode=nanopore-fiber;apply_sha256=ff7c7790…;fiberhmm_commit=…;fiberhmm_version=3.0.0;model=hia5_nanopore;pg=fiberhmm-call;recall_sha256=ff7c7790…
A BAM processed several times holds one declaration per run.
fiberhmm-check compares these fields with the known
fixes to tell whether the BAM needs re-running.
Vocabulary:
assay=daf;enzyme=ddda|dddb;mode=daf, with the sequencingplatform=pacbio|nanopore(unknownonly when unavailable);assay=fiber-seq;enzyme=hia5withplatform=pacbio;mode=pacbio-fiberorplatform=nanopore;mode=nanopore-fiber;customfor a custom assay, enzyme or mode (for example a run with-mand no--enzyme:enzyme=custom).
A valid declaration is authoritative for the chemistry. It never decides the
coordinate frame of the footprint tags: pass-through producers add it while
carrying older reads unchanged (see
Footprint-tag coordinate frame).
Several lines with the same four
required fields are allowed (for example after successive models add
different model values); incompatible required fields are a conflict, and
FiberHMM producers refuse to relabel silently. Readers ignore malformed lines
and unknown versions. For BAMs made before the declaration existed, tools
infer the chemistry, with lower confidence, from a fiberhmm-call @PG
record; filenames are never used.
Reconciliation. fiberhmm-call and fiberhmm-recall-tfs/-recall-nucs
reconcile their declaration with the input's: a custom model without
--enzyme inherits the input's assay, enzyme and platform when the mode
matches; any other disagreement stops the run unless --replace-chemistry
is given, which drops the input's declaration and writes this run's (see
Choosing the chemistry).
Readers. Recall (missing --seq), fiberhmm-extract and fiberhmm-qc
(ML threshold, QC profile), and fiberhmm-consensus/fiberhmm-transfer
(emission model) take the chemistry from this line.
Python: fiberhmm.io.bam_header.declared_chemistries(header) returns the
valid declarations as dictionaries.
MA-TYPES¶
MA group names are extensible and otherwise appear only inside per-read
MA:Z values, so a viewer would have to scan reads to discover rare layers.
This line advertises the names a BAM may contain. It lists names only (no
strand or quality suffix); names are case-sensitive and match [A-Za-z0-9_]+.
Several lines are allowed; readers take the ordered union. Producers keep
existing lines and append one line with the names not yet declared.
It is a discovery hint, not part of MA correctness:
- records remain authoritative; a reader accepts names that were not declared;
- a missing name does not mean biological absence, and declarations never
determine
AQarity; - missing, stale or malformed declarations are ignored;
- declaring a name never creates an empty per-read group.
Repair an older BAM in place, from known names or by scanning every alignment:
fiberhmm-utils ma-types out/matypes.bam --types nuc,msp,tf,ddda_mcg
fiberhmm-utils ma-types out/matypes.bam --scan
Updated out/matypes.bam in place (300 alignments); added: ddda_mcg; declared union: nuc,msp,tf,ddda_mcg
Scanned all 300 alignments (300 with MA); observed: nuc,msp,tf
All requested MA types were already declared; BAM left unchanged.
The utility writes and validates a temporary BAM next to the original,
rebuilds an existing BAI/CSI index and then replaces both; per-read tags are
copied unchanged. Python: declared_ma_types(header) and
append_ma_types(header, names) in fiberhmm.io.bam_header.
Consensus headers¶
fiberhmm-consensus and fiberhmm-transfer BAM exports carry:
- one
FIBERHMM-CONSENSUS-MA:v1:line, a JSON object recording the engine, export scope and windows, the layers, the meaning of every byte (quality_names,layer_quality_names,q0,fi,fq,op, …), and the run's parameters and input digest; - one
FIBERHMM-CONSENSUS-FAMILY:v1:line per class and layer, a JSON object:
@CO FIBERHMM-CONSENSUS-FAMILY:v1:{"annotation_name": "fhcr_9ca5cf4d4ac4fc4ffb286f0b", "chrom": "chrDemo", "end": 10065, "extent": "class_consensus_span", "family_key": "class_001", "fi": 1, "input_digest": "...", "layer": "tf_consensus", "stage": "resolved", "start": 10041}
annotation_name is the AN token of the class's annotations; fi its
slot; start/end the class consensus span (lattice recaller) or the union
of the labelled calls (staged engine). DAF classes add a per-dataset
strand_resolution with trusted_strand (CT, GA, both, none),
trusted_strands, supported_strands, per-strand resolution_nats and the
threshold. fiberhmm.inference.consensus.bam_export.read_family_catalog(header)
returns {"contracts": [...], "families": [...]}.
Strand rescue and family slots¶
FIBERHMM-STRAND-RESCUE:v6: (from fiberhmm-strand-rescue-annotate) is a
;-separated contract: the groups (nuc_sr,tf_sr), quality spec and scale,
the meaning of q0/q1/q2 for each role, the display rule
(display_sr_if=q0>=T;threshold_named_only=true), the roles (Rn, H), the
baseline sentinel row (255,0,0) and the nucleosome invariants. v2–v5 BAMs
are still validated by fiberhmm-strand-rescue-audit.
FIBERHMM-TF-FAMILY:v1: (from fiberhmm-tag-consensus) declares
layer=tf_sr;quality_spec=QQQQQ, the five byte meanings, the slot reuse
distance (fi_reuse_separation_bp=24) and the SHA-256 of the assignment
table.
Basecaller provenance¶
fiberhmm-pipeline carries every unaligned input BAM's @RG lines, @PG
chain and @CO lines into its aligned BAM (dorado's
@PG ID:basecaller PN:dorado and @RG ... DS:runid=... basecall_model=...
modbase_models=...; PacBio ccs, jasmine, fibertools), chains minimap2
and fiberhmm-pipeline after them (PP), and keeps every read's RG tag
pointing at a declared group: an ID two inputs use for different lines gets
-2, -3... (identical lines are merged); reads from FASTQ get the
pipeline's own group (the sample name). FiberHMM @PG records and
FIBERHMM-*/MA-TYPES @CO lines of a BAM that is realigned are dropped
(the calls are not carried).
The fiberhmm-pipeline and fiberhmm-call @PG DS end with what is known
about the basecaller:
basecaller=dorado basecaller_version=2.0.1 basecall_model=dna_r10.4.1_e8.2_400bps_sup@v5.2.0 modbase_models=dna_r10.4.1_e8.2_400bps_sup@v5.2.0_6mA@v1 basecaller_sources=program:pg,version:pg,basecall_model:rg_ds,modbase_models:rg_ds
| Token | Value |
|---|---|
basecaller |
program (dorado, guppy, ccs...), or unknown |
basecaller_version |
its version, or unknown |
basecall_model |
basecalling model, or unknown |
modbase_models |
comma-separated modification models; none = basecalled without one; unknown = not recorded |
basecaller_sources |
field:source for each known field |
Sources, highest precedence first: override (--basecaller-info /
--modbase-model), recorded-override (an override recorded by an earlier
FiberHMM run), rg_ds (@RG DS), pg / pg_cl (the basecaller's @PG
and its command line), read_rg (dorado's per-read read group,
<runid>_<model>), recorded (other values an earlier FiberHMM run
recorded). Several values in one source (inputs basecalled differently) are
joined with commas. Python:
fiberhmm.io.provenance.basecaller_provenance(header, reads=...) returns
them as a dict; parse_ds_tokens(ds) reads the tokens back.
FIBERHMM-REFERENCE¶
fiberhmm-pipeline records which reference a BAM was aligned to, so a viewer
can pair it with the right FASTA or plasmid map even after files are renamed
(see Plasmids):
- every
@SQline getsM5, the MD5 of the contig sequence (upper case, no whitespace; the SAM standard); - a circular contig gets
TP:circular(SAM standard). Its alignments may run pastLN, the SAM-preferred form for reads through the origin of a circular reference: a positionp > LNmeansp - LN; - for a reference made from a plasmid map, and for every circular contig,
one
@COline per contig:
@CO FIBERHMM-REFERENCE:v1:contig=N1;length=12179;md5=1276ace935ddb3051497a9b2b956a0c2;topology=circular;source=N1.dna;source_format=snapgene;source_sha256=02bb9705b987b8df586ff0723c7d24de49f5683a85654c669a5bfc8e80243d88
;-separated key=value fields; values are percent-encoded (RFC 3986:
A–Z a–z 0–9 . _ - + stay literal, so a file name with spaces or ; is
safe). Fields:
| Key | Value |
|---|---|
contig |
the contig name (the @SQ SN) |
length |
contig length (the @SQ LN) |
md5 |
as @SQ M5 |
topology |
circular or linear |
source |
file name of the map or FASTA, without its directory |
source_format |
snapgene, genbank, embl or fasta |
source_sha256 |
SHA-256 of that file as given |
Readers ignore unknown keys and unknown versions. fiberhmm-call and the other
FiberHMM producers copy the input header, so the lines survive calling.
Python: fiberhmm.pipeline.reference.declared_references(header) returns the
parsed lines; parse_reference_comment(text) parses one.