///|
fn parse_sam(text : String) -> @src.AlignSamDocument {
@src.align_sam_parse(text) catch {
AlignSamError(message) => abort("SAM parsing failed: " + message)
}
}
///|
fn demo_reference() -> String {
"N".repeat(4) + "ACGTTCGGAA" + "N".repeat(26)
}
///|
fn optional_int(value : Int32?) -> String {
match value {
Some(item) => item.to_string()
None => "unknown"
}
}
///|
fn coordinate_text(values : Array[Int32]) -> String {
let output = StringBuilder()
output.write_char('[')
for index in 0.. 0 {
output.write_string(", ")
}
output.write_string(values[index].to_string())
}
output.write_char(']')
output.to_string()
}
///|
fn main {
println("=== Biopython Bio.Align.sam Demo ===")
println("\n1. Parse headers, references, and records")
let document = parse_sam(@src.align_sam_example_data())
println(
" headers=" +
document.headers.length().to_string() +
", references=" +
document.references.length().to_string() +
", alignments=" +
document.alignments.length().to_string(),
)
match document.reference("chr1") {
Some(reference) =>
println(
" reference " +
reference.name +
", length=" +
reference.length.to_string(),
)
None => abort("chr1 was not indexed")
}
println("\n2. Inspect a clipped and gapped forward alignment")
let forward = document.alignments[0]
let stats = forward.stats()
println(" " + forward.summary())
println(
" CIGAR=" +
@src.align_sam_cigar_string(forward.cigar) +
", query bases=" +
stats.query_consumed.to_string() +
", reference bases=" +
stats.reference_consumed.to_string(),
)
match forward.target_to_query(8) {
Some(position) =>
println(" target base 8 maps to query base " + position.to_string())
None => println(" target base 8 lies in a gap")
}
let md = match forward.string_tag("MD") {
Some(value) => value
None => "unknown"
}
println(" NM=" + optional_int(forward.computed_nm()) + ", MD=" + md)
println("\n3. Reconstruct aligned rows and calculate MD")
let rows = forward.aligned_rows(reference_sequence=demo_reference()) catch {
AlignSamError(message) => abort("row reconstruction failed: " + message)
}
let calculated_md = @src.align_sam_calculate_md(forward, demo_reference()) catch {
AlignSamError(message) => abort("MD calculation failed: " + message)
}
println(" target " + rows.0)
println(" query " + rows.1)
println(" calculated MD=" + calculated_md)
println("\n4. Inspect reverse-strand and spliced coordinates")
let reverse = document.alignments[1]
println(
" reverse=" +
reverse.is_reverse().to_string() +
", biological query=" +
reverse.query_sequence,
)
println(
" query path " +
coordinate_text(reverse.query_coordinates) +
", skipped reference bases=" +
reverse.stats().skipped.to_string(),
)
match reverse.target_to_query(27) {
Some(position) =>
println(
" target base 27 maps to reverse query base " + position.to_string(),
)
None => println(" target base 27 lies in the skipped interval")
}
println("\n5. Construct and round-trip a typed SAM record")
let tags = [
@src.align_sam_integer_tag("NM", 0),
@src.align_sam_string_tag("RG", "demo"),
@src.align_sam_float_array_tag("BF", [0.25, 0.75]),
] catch {
AlignSamError(message) => abort("tag construction failed: " + message)
}
let created = @src.align_sam_create(
"created_read",
"chr1",
40,
15,
"AACGTT",
"1S4M1S",
reverse=true,
mapq=50,
qualities=[30, 31, 32, 33, 34, 35],
tags~,
) catch {
AlignSamError(message) => abort("alignment construction failed: " + message)
}
let record = @src.align_sam_format(created) catch {
AlignSamError(message) => abort("SAM formatting failed: " + message)
}
let reparsed = parse_sam("@SQ\tSN:chr1\tLN:40\n" + record).alignments[0]
println(" " + record)
println(
" round-trip query=" +
reparsed.query_sequence +
", mapq=" +
optional_int(reparsed.mapq) +
", tags=" +
reparsed.tags.length().to_string(),
)
println("=== Demo Complete ===")
}