use pdbrust::parse_pdb_file;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
println!("=== PDBRust Filtering Demo ===\n");
let structure = parse_pdb_file("examples/pdb_files/1UBQ.pdb")?;
println!("Original structure: {} atoms", structure.atoms.len());
println!("Chains: {:?}", structure.get_chain_ids());
println!("\n--- Chain Extraction ---");
let chain_a = structure.keep_only_chain("A");
println!("Chain A only: {} atoms", chain_a.atoms.len());
println!("\n--- Atom Type Filtering ---");
let ca_only = structure.keep_only_ca();
println!("CA atoms only: {} atoms", ca_only.atoms.len());
let backbone = structure.keep_only_backbone();
println!(
"Backbone only (N, CA, C, O): {} atoms",
backbone.atoms.len()
);
let ca_coords = structure.get_ca_coords(None);
println!("CA coordinates extracted: {} points", ca_coords.len());
let chain_a_ca_coords = structure.get_ca_coords(Some("A"));
println!("Chain A CA coordinates: {} points", chain_a_ca_coords.len());
println!("\n--- Removing Unwanted Atoms ---");
let no_ligands = structure.remove_ligands();
println!(
"After remove_ligands(): {} atoms (removed {})",
no_ligands.atoms.len(),
structure.atoms.len() - no_ligands.atoms.len()
);
let no_hydrogens = structure.remove_hydrogens();
println!(
"After remove_hydrogens(): {} atoms (removed {})",
no_hydrogens.atoms.len(),
structure.atoms.len() - no_hydrogens.atoms.len()
);
println!("\n--- Fluent API (Method Chaining) ---");
let cleaned = structure
.remove_ligands()
.remove_hydrogens()
.keep_only_chain("A")
.keep_only_backbone();
println!("Chained: remove_ligands -> remove_hydrogens -> chain A -> backbone");
println!("Result: {} atoms", cleaned.atoms.len());
let ca_repr = structure.remove_ligands().keep_only_ca();
println!(
"\nCA representation (no ligands): {} atoms",
ca_repr.atoms.len()
);
println!("\n--- In-Place Modifications ---");
let mut mutable = structure.clone();
let (cx, cy, cz) = mutable.get_centroid();
println!("Original centroid: ({:.2}, {:.2}, {:.2})", cx, cy, cz);
mutable.center_structure();
let (cx, cy, cz) = mutable.get_centroid();
println!("After centering: ({:.2}, {:.2}, {:.2})", cx, cy, cz);
mutable.renumber_atoms();
println!(
"Atoms renumbered: first={}, last={}",
mutable.atoms.first().map(|a| a.serial).unwrap_or(0),
mutable.atoms.last().map(|a| a.serial).unwrap_or(0)
);
let mut multi_chain = structure.clone();
multi_chain.normalize_chain_ids();
println!("Chains normalized: {:?}", multi_chain.get_chain_ids());
let mut reindexed = structure.clone();
reindexed.reindex_residues();
if let Some(first_atom) = reindexed.atoms.first() {
println!("First residue after reindex: {}", first_atom.residue_seq);
}
println!("\n--- Working with Residues ---");
let residues = structure.get_residues();
println!("Total residues: {}", residues.len());
let chain_a_residues = structure.get_residues_for_chain("A");
println!("Chain A residues: {}", chain_a_residues.len());
let sequence = structure.get_sequence("A");
if !sequence.is_empty() {
let seq_preview: Vec<_> = sequence.iter().take(10).collect();
println!(
"Chain A sequence (first 10 residues): {:?}{}",
seq_preview,
if sequence.len() > 10 { "..." } else { "" }
);
}
println!("\n=== Summary ===");
println!("Filtering operations are non-destructive (return new structures)");
println!("Use method chaining for clean, readable pipelines");
println!("In-place modifications require &mut and modify the structure");
Ok(())
}