Skip to content

Reading POD5 Files

The Reader struct provides efficient access to POD5 file contents.

Opening a File

1
2
3
use escapepod_signal::Reader;

let reader = Reader::open("experiment.pod5")?;

The file is memory-mapped for efficient access. The reader validates the file signature and parses the footer on open.

File Information

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Number of reads in the file
let count = reader.read_count()?;

// Number of batches (internal structure)
let batches = reader.read_batch_count()?;

// Access run info
for (i, run_info) in reader.run_infos().iter().enumerate() {
    println!("Run {}: {}", i, run_info.acquisition_id);
}

Iterating Over Reads

1
2
3
4
5
6
7
// Iterate over all reads
for read in reader.reads()? {
    println!("Read: {}", read.read_id);
    println!("  Channel: {}", read.channel);
    println!("  Samples: {}", read.num_samples);
    println!("  End reason: {:?}", read.end_reason);
}

Accessing Signal Data

Signal data is stored separately and must be explicitly requested:

1
2
3
4
5
6
// Get signal for a specific read
let signal: Vec<i16> = reader.get_signal(&read)?;

// Signal is raw ADC values
println!("Signal length: {}", signal.len());
println!("First 10 samples: {:?}", &signal[..10.min(signal.len())]);

Converting to Physical Units

The signal is stored as raw ADC values. Convert to picoamps (pA) using calibration:

1
2
3
4
5
6
7
fn to_picoamps(signal: &[i16], offset: f32, scale: f32) -> Vec<f32> {
    signal.iter()
        .map(|&s| (s as f32 + offset) * scale)
        .collect()
}

let pa_signal = to_picoamps(&signal, read.calibration_offset, read.calibration_scale);

Finding Specific Reads

Filter reads by their UUIDs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use uuid::Uuid;
use std::collections::HashSet;

let target_ids: HashSet<Uuid> = [
    Uuid::parse_str("a1b2c3d4-e5f6-7890-abcd-ef1234567890")?,
].into_iter().collect();

// Filter reads while iterating
for read in reader.reads()? {
    if target_ids.contains(&read.read_id) {
        println!("Found: {}", read.read_id);
    }
}

Get all read IDs in the file:

1
2
let all_ids = reader.read_ids()?;
println!("File contains {} reads", all_ids.len());

Batch Access

For advanced use cases, access raw Arrow batches:

1
2
3
4
for batch_idx in 0..reader.read_batch_count()? {
    let batch = reader.read_batch(batch_idx)?;
    println!("Batch {} has {} rows", batch_idx, batch.num_rows());
}

Run Info Access

Access run information by index:

1
2
3
4
5
6
// Get run info for a read
let run_info = reader.get_run_info(read.run_info_index)?;

println!("Acquisition ID: {}", run_info.acquisition_id);
println!("Sample rate: {} Hz", run_info.sample_rate);
println!("Flow cell: {:?}", run_info.tracking_id.get("flow_cell_id"));

Memory Efficiency

The reader uses memory-mapping, so:

  • Only accessed data is loaded into memory
  • Large files don't consume proportional RAM
  • Multiple readers can share the same memory-mapped data
1
2
// Safe to open very large files
let reader = Reader::open("large_file.pod5")?;  // Doesn't load entire file