1use std::collections::HashMap;
10use std::marker::PhantomData;
11
12pub mod invariants;
13pub mod ops;
14pub mod protein;
15pub mod resinfo;
16
17macro_rules! row_id {
22 ($name:ident) => {
23 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24 pub struct $name(u32);
25
26 impl $name {
27 #[must_use]
28 pub const fn new(index: u32) -> Self {
29 Self(index)
30 }
31
32 #[must_use]
33 pub const fn index(self) -> u32 {
34 self.0
35 }
36 }
37 };
38}
39
40row_id!(AtomId);
41row_id!(ResidueId);
42row_id!(ChainId);
43row_id!(EntityId);
44row_id!(ModelId);
45row_id!(BondId);
46row_id!(AssemblyId);
47row_id!(AltLocGroupId);
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct RowSpan<T> {
55 pub start: u32,
56 pub len: u32,
57 _marker: PhantomData<T>,
58}
59
60impl<T> RowSpan<T> {
61 #[must_use]
62 pub const fn new(start: u32, len: u32) -> Self {
63 Self {
64 start,
65 len,
66 _marker: PhantomData,
67 }
68 }
69
70 #[must_use]
71 pub const fn end(self) -> u32 {
72 self.start + self.len
73 }
74
75 #[must_use]
76 pub const fn is_empty(self) -> bool {
77 self.len == 0
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub enum ResidueKind {
87 AminoAcid,
88 DNA,
89 RNA,
90 Saccharide,
91 Water,
92 Ligand,
93 Ion,
94 Cofactor,
95 Unknown,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99pub enum PolymerKind {
100 Peptide,
101 DNA,
102 RNA,
103 PeptideLike,
104 NucleicAcidHybrid,
105 Saccharide,
106 NonPolymer,
107 Water,
108 Unknown,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112pub enum EntityKind {
113 Polymer,
114 NonPolymer,
115 Branched,
116 Water,
117 Unknown,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
121pub enum ChainKind {
122 Protein,
123 DNA,
124 RNA,
125 ProteinDNAComplex,
126 ProteinRNAComplex,
127 LigandOnly,
128 WaterOnly,
129 Mixed,
130 Unknown,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub struct PdbAtomSerial(pub i32);
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
143pub struct PdbChainId(pub [u8; 4], pub u8);
144
145impl PdbChainId {
146 #[must_use]
147 pub fn as_str(&self) -> &str {
148 std::str::from_utf8(&self.0[..self.1 as usize]).unwrap_or("")
149 }
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
154pub struct PdbSeqId {
155 pub seq_num: i32,
156 pub ins_code: Option<u8>,
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub struct AtomName(pub [u8; 4]);
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
169pub struct ResidueName(pub [u8; 4], pub u8);
170
171impl ResidueName {
172 #[must_use]
173 pub fn as_str(&self) -> &str {
174 std::str::from_utf8(&self.0[..self.1 as usize]).unwrap_or("")
175 }
176}
177
178#[must_use]
179pub fn classify_residue_name(name: ResidueName) -> ResidueKind {
180 let info = resinfo::find_tabulated_residue(name.as_str());
181 if info.is_amino_acid() {
182 ResidueKind::AminoAcid
183 } else if info.is_water() {
184 ResidueKind::Water
185 } else {
186 ResidueKind::Unknown
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 fn residue_name(value: &str) -> ResidueName {
195 let mut bytes = [0; 4];
196 bytes[..value.len()].copy_from_slice(value.as_bytes());
197 ResidueName(bytes, value.len() as u8)
198 }
199
200 #[test]
201 fn classifies_complete_gemmi_amino_acid_vocabulary() {
202 let amino_acids = resinfo::RESIDUE_INFO_TABLE
203 .iter()
204 .filter(|info| info.is_amino_acid())
205 .collect::<Vec<_>>();
206 assert_eq!(amino_acids.len(), 128);
207 for info in amino_acids {
208 assert_eq!(
209 classify_residue_name(residue_name(info.name)),
210 ResidueKind::AminoAcid
211 );
212 }
213 }
214
215 #[test]
216 fn classifies_gemmi_water_names_without_guessing_other_residues() {
217 for name in ["HOH", "DOD", "WAT", "H2O"] {
218 assert_eq!(
219 classify_residue_name(residue_name(name)),
220 ResidueKind::Water
221 );
222 }
223 assert_eq!(
224 classify_residue_name(residue_name("XYZ")),
225 ResidueKind::Unknown
226 );
227 }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232pub struct AltLocLabel(pub u8);
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
239pub struct AtomSourceIds {
240 pub serial: Option<PdbAtomSerial>,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
244pub enum BioCalcFlag {
245 #[default]
246 NotSet,
247 NoHydrogen,
248 Determined,
249 Calculated,
250 Dummy,
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
254pub struct ResidueSourceIds {
255 pub seq_id: Option<PdbSeqId>,
256 pub label_seq_id: Option<i32>,
257 pub segment_id: Option<[u8; 4]>,
258 pub subchain_id: Option<PdbChainId>,
259 pub label_entity_id: Option<EntityId>,
260}
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub struct ChainSourceIds {
264 pub auth_chain_id: Option<PdbChainId>,
265 pub label_asym_id: Option<PdbChainId>,
266}
267
268#[derive(Debug, Clone, PartialEq, Eq)]
269pub struct EntitySourceIds {
270 pub source_entity_id: String,
271}
272
273#[derive(Debug, Clone, PartialEq)]
278pub struct AtomRow {
279 pub residue_id: ResidueId,
280 pub name: AtomName,
281 pub element: crate::Element,
282 pub altloc: Option<AltLocLabel>,
283 pub occupancy: Option<f32>,
284 pub b_iso: Option<f32>,
285 pub formal_charge: Option<i8>,
286 pub anisou: Option<[f32; 6]>,
287 pub calc_flag: BioCalcFlag,
288 pub tls_group_id: Option<i16>,
289 pub fraction: Option<f32>,
290 pub source: AtomSourceIds,
291}
292
293#[derive(Debug, Clone, PartialEq)]
294pub struct ResidueRow {
295 pub chain_id: ChainId,
296 pub atom_span: RowSpan<AtomId>,
297 pub name: ResidueName,
298 pub kind: ResidueKind,
299 pub entity_kind: EntityKind,
300 pub het_flag: Option<char>,
301 pub source: ResidueSourceIds,
302 pub sifts_unp: Option<BioSiftsUnpResidue>,
303}
304
305#[derive(Debug, Clone, PartialEq)]
306pub struct ChainRow {
307 pub model_id: ModelId,
308 pub entity_id: Option<EntityId>,
309 pub residue_span: RowSpan<ResidueId>,
310 pub kind: ChainKind,
311 pub source: ChainSourceIds,
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
315pub struct EntityRow {
316 pub kind: EntityKind,
317 pub polymer_kind: PolymerKind,
318 pub reflects_microhetero: bool,
319 pub sequence: Vec<String>,
320 pub dbrefs: Vec<BioEntityDbRef>,
321 pub sifts_unp_acc: Vec<String>,
322 pub subchains: Vec<PdbChainId>,
323 pub source: EntitySourceIds,
324}
325
326#[derive(Debug, Clone, PartialEq, Eq, Default)]
327pub struct BioEntityDbRef {
328 pub db_name: String,
329 pub accession_code: String,
330 pub id_code: String,
331 pub isoform: String,
332 pub seq_begin: Option<PdbSeqId>,
336 pub seq_end: Option<PdbSeqId>,
337 pub db_begin: Option<PdbSeqId>,
338 pub db_end: Option<PdbSeqId>,
339 pub label_seq_begin: Option<i32>,
340 pub label_seq_end: Option<i32>,
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
344pub struct BioSiftsUnpResidue {
345 pub res: Option<char>,
346 pub acc_index: u8,
347 pub num: u16,
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Default)]
351pub struct BioModRes {
352 pub chain_name: String,
353 pub res_id: PdbSeqId,
354 pub residue_name: String,
355 pub parent_comp_id: String,
356 pub mod_id: String,
357 pub details: String,
358}
359
360#[derive(Debug, Clone, PartialEq)]
361pub struct ModelRow {
362 pub chain_span: RowSpan<ChainId>,
363 pub source_model_number: Option<i32>,
364}
365
366#[derive(Debug, Clone, PartialEq, Default)]
367pub struct BioMetadata {
368 pub entry_id: Option<String>,
369 pub title: Option<String>,
370 pub pdbx_keywords: Option<String>,
371 pub keywords: Option<String>,
372 pub experimental_method: Option<String>,
373 pub received_initial_deposition_date: Option<String>,
374 pub authors: Vec<String>,
375 pub software: Vec<BioSoftwareItem>,
376 pub refinement: Vec<BioRefinementInfo>,
377 pub experiments: Vec<BioExperimentInfo>,
378 pub experiment_crystals: Vec<BioExperimentCrystalInfo>,
379 pub solved_by: Option<String>,
380 pub starting_model: Option<String>,
381 pub remark_300_detail: Option<String>,
382}
383
384#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
385pub enum BioSoftwareClassification {
386 DataCollection,
387 DataExtraction,
388 DataProcessing,
389 DataReduction,
390 DataScaling,
391 ModelBuilding,
392 Phasing,
393 Refinement,
394 #[default]
395 Unspecified,
396}
397
398#[derive(Debug, Clone, PartialEq, Default)]
399pub struct BioSoftwareItem {
400 pub name: String,
401 pub version: String,
402 pub date: String,
403 pub description: String,
404 pub contact_author: String,
405 pub contact_author_email: String,
406 pub classification: BioSoftwareClassification,
407}
408
409#[derive(Debug, Clone, PartialEq, Default)]
410pub struct BioRefinementBin {
411 pub resolution_high: Option<f64>,
412 pub resolution_low: Option<f64>,
413 pub completeness: Option<f64>,
414 pub reflection_count: Option<i32>,
415 pub work_set_count: Option<i32>,
416 pub rfree_set_count: Option<i32>,
417 pub r_all: Option<f64>,
418 pub r_work: Option<f64>,
419 pub r_free: Option<f64>,
420 pub cc_fo_fc_work: Option<f64>,
421 pub cc_fo_fc_free: Option<f64>,
422 pub fsc_work: Option<f64>,
423 pub fsc_free: Option<f64>,
424 pub cc_intensity_work: Option<f64>,
425 pub cc_intensity_free: Option<f64>,
426}
427
428#[derive(Debug, Clone, PartialEq, Default)]
429pub struct BioRefinementRestraint {
430 pub name: String,
431 pub count: Option<i32>,
432 pub weight: Option<f64>,
433 pub function: String,
434 pub dev_ideal: Option<f64>,
435}
436
437#[derive(Debug, Clone, PartialEq, Default)]
438pub struct BioTlsSelection {
439 pub chain: String,
440 pub res_begin: Option<PdbSeqId>,
441 pub res_end: Option<PdbSeqId>,
442 pub details: String,
443}
444
445#[derive(Debug, Clone, PartialEq)]
446pub struct BioTlsGroup {
447 pub num_id: Option<i16>,
448 pub id: String,
449 pub selections: Vec<BioTlsSelection>,
450 pub origin: [f64; 3],
451 pub t: [[f64; 3]; 3],
452 pub l: [[f64; 3]; 3],
453 pub s: [[f64; 3]; 3],
454}
455
456impl Default for BioTlsGroup {
457 fn default() -> Self {
458 Self {
459 num_id: None,
460 id: String::new(),
461 selections: Vec::new(),
462 origin: [f64::NAN; 3],
463 t: [[f64::NAN; 3]; 3],
464 l: [[f64::NAN; 3]; 3],
465 s: [[f64::NAN; 3]; 3],
466 }
467 }
468}
469
470#[derive(Debug, Clone, PartialEq)]
471pub struct BioAnisotropicB {
472 pub u11: f64,
473 pub u22: f64,
474 pub u33: f64,
475 pub u12: f64,
476 pub u13: f64,
477 pub u23: f64,
478}
479
480impl Default for BioAnisotropicB {
481 fn default() -> Self {
482 Self {
483 u11: f64::NAN,
484 u22: f64::NAN,
485 u33: f64::NAN,
486 u12: f64::NAN,
487 u13: f64::NAN,
488 u23: f64::NAN,
489 }
490 }
491}
492
493#[derive(Debug, Clone, PartialEq, Default)]
494pub struct BioRefinementInfo {
495 pub id: String,
496 pub resolution_high: Option<f64>,
497 pub resolution_low: Option<f64>,
498 pub completeness: Option<f64>,
499 pub reflection_count: Option<i32>,
500 pub work_set_count: Option<i32>,
501 pub rfree_set_count: Option<i32>,
502 pub r_all: Option<f64>,
503 pub r_work: Option<f64>,
504 pub r_free: Option<f64>,
505 pub cross_validation_method: String,
506 pub rfree_selection_method: String,
507 pub bin_count: Option<i32>,
508 pub bins: Vec<BioRefinementBin>,
509 pub mean_b: Option<f64>,
510 pub aniso_b: BioAnisotropicB,
511 pub luzzati_error: Option<f64>,
512 pub dpi_blow_r: Option<f64>,
513 pub dpi_blow_rfree: Option<f64>,
514 pub dpi_cruickshank_r: Option<f64>,
515 pub dpi_cruickshank_rfree: Option<f64>,
516 pub cc_fo_fc_work: Option<f64>,
517 pub cc_fo_fc_free: Option<f64>,
518 pub fsc_work: Option<f64>,
519 pub fsc_free: Option<f64>,
520 pub cc_intensity_work: Option<f64>,
521 pub cc_intensity_free: Option<f64>,
522 pub restr_stats: Vec<BioRefinementRestraint>,
523 pub tls_groups: Vec<BioTlsGroup>,
524 pub remarks: String,
525}
526
527#[derive(Debug, Clone, PartialEq, Default)]
528pub struct BioReflectionsInfo {
529 pub resolution_high: Option<f64>,
530 pub resolution_low: Option<f64>,
531 pub completeness: Option<f64>,
532 pub redundancy: Option<f64>,
533 pub r_merge: Option<f64>,
534 pub r_sym: Option<f64>,
535 pub mean_i_over_sigma: Option<f64>,
536}
537
538#[derive(Debug, Clone, PartialEq, Default)]
539pub struct BioExperimentInfo {
540 pub method: String,
541 pub number_of_crystals: Option<i32>,
542 pub unique_reflections: Option<i32>,
543 pub diffraction_ids: Vec<String>,
544 pub reflections: BioReflectionsInfo,
545 pub b_wilson: Option<f64>,
546 pub shells: Vec<BioReflectionsInfo>,
547}
548
549#[derive(Debug, Clone, PartialEq, Default)]
550pub struct BioDiffractionInfo {
551 pub id: String,
552 pub collection_date: String,
553 pub temperature: Option<f64>,
554 pub source: String,
555 pub source_type: String,
556 pub synchrotron: String,
557 pub beamline: String,
558 pub wavelengths: String,
559 pub scattering_type: String,
560 pub monochromator: String,
561 pub optics: String,
562 pub detector: String,
563 pub detector_make: String,
564 pub mono_or_laue: Option<char>,
565}
566
567#[derive(Debug, Clone, PartialEq, Default)]
568pub struct BioExperimentCrystalInfo {
569 pub id: String,
570 pub description: String,
571 pub ph: Option<f64>,
572 pub ph_range: String,
573 pub diffractions: Vec<BioDiffractionInfo>,
574}
575
576#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
577pub enum BioAsu {
578 #[default]
579 Any,
580 Same,
581 Different,
582}
583
584#[derive(Debug, Clone, PartialEq, Eq, Default)]
585pub struct BioAtomAddress {
586 pub chain_name: String,
587 pub seq_id: Option<PdbSeqId>,
588 pub residue_name: String,
589 pub atom_name: String,
590 pub altloc: Option<AltLocLabel>,
591}
592
593#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
594pub enum BioConnectionType {
595 Covale,
596 Disulf,
597 Hydrog,
598 MetalC,
599 #[default]
600 Unknown,
601}
602
603#[derive(Debug, Clone, PartialEq, Default)]
604pub struct BioConnection {
605 pub name: String,
606 pub type_: BioConnectionType,
607 pub partner1: BioAtomAddress,
608 pub partner2: BioAtomAddress,
609 pub asu: BioAsu,
610 pub reported_sym: [i16; 4],
611 pub reported_distance: Option<f64>,
612 pub link_id: String,
613}
614
615#[derive(Debug, Clone, PartialEq, Default)]
616pub struct BioCisPep {
617 pub partner_c: BioAtomAddress,
618 pub partner_n: BioAtomAddress,
619 pub model_num: i32,
620 pub only_altloc: Option<AltLocLabel>,
621 pub reported_angle: Option<f64>,
622}
623
624#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
625pub enum BioHelixClass {
626 #[default]
627 UnknownHelix,
628 RAlpha,
629 ROmega,
630 RPi,
631 RGamma,
632 R310,
633 LAlpha,
634 LOmega,
635 LGamma,
636 Helix27,
637 HelixPolyProlineNone,
638}
639
640#[derive(Debug, Clone, PartialEq)]
641pub struct BioHelix {
642 pub start: BioAtomAddress,
643 pub end: BioAtomAddress,
644 pub helix_class: BioHelixClass,
645 pub length: i32,
646}
647
648impl Default for BioHelix {
649 fn default() -> Self {
650 Self {
655 start: BioAtomAddress::default(),
656 end: BioAtomAddress::default(),
657 helix_class: BioHelixClass::UnknownHelix,
658 length: -1,
659 }
660 }
661}
662
663impl BioHelix {
664 pub fn set_helix_class_as_int(&mut self, n: i32) {
665 self.helix_class = match n {
666 1 => BioHelixClass::RAlpha,
667 2 => BioHelixClass::ROmega,
668 3 => BioHelixClass::RPi,
669 4 => BioHelixClass::RGamma,
670 5 => BioHelixClass::R310,
671 6 => BioHelixClass::LAlpha,
672 7 => BioHelixClass::LOmega,
673 8 => BioHelixClass::LGamma,
674 9 => BioHelixClass::Helix27,
675 10 => BioHelixClass::HelixPolyProlineNone,
676 _ => BioHelixClass::UnknownHelix,
677 };
678 }
679}
680
681#[derive(Debug, Clone, PartialEq, Default)]
682pub struct BioSheetStrand {
683 pub start: BioAtomAddress,
684 pub end: BioAtomAddress,
685 pub hbond_atom2: BioAtomAddress,
686 pub hbond_atom1: BioAtomAddress,
687 pub sense: i32,
688 pub name: String,
689}
690
691#[derive(Debug, Clone, PartialEq, Default)]
692pub struct BioSheet {
693 pub name: String,
694 pub strands: Vec<BioSheetStrand>,
695}
696
697#[derive(Debug, Clone, Copy, PartialEq)]
698pub struct BioTransform {
699 pub mat: [[f64; 3]; 3],
700 pub vec: [f64; 3],
701}
702
703impl Default for BioTransform {
704 fn default() -> Self {
705 Self {
713 mat: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
714 vec: [0.0, 0.0, 0.0],
715 }
716 }
717}
718
719#[derive(Debug, Clone, PartialEq, Default)]
720pub struct BioNcsOperator {
721 pub id: String,
722 pub given: bool,
723 pub transform: BioTransform,
724}
725
726#[derive(Debug, Clone, PartialEq, Default)]
727pub struct BioAssemblyOperator {
728 pub name: String,
729 pub type_: String,
730 pub transform: BioTransform,
731}
732
733#[derive(Debug, Clone, PartialEq, Default)]
734pub struct BioAssemblyGenerator {
735 pub chains: Vec<String>,
736 pub subchains: Vec<String>,
737 pub operators: Vec<BioAssemblyOperator>,
738}
739
740#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
741pub enum BioAssemblySpecialKind {
742 #[default]
743 NA,
744 CompleteIcosahedral,
745 RepresentativeHelical,
746 CompletePoint,
747}
748
749#[derive(Debug, Clone, PartialEq, Default)]
750pub struct BioAssembly {
751 pub name: String,
752 pub author_determined: bool,
753 pub software_determined: bool,
754 pub special_kind: BioAssemblySpecialKind,
755 pub oligomeric_count: i32,
756 pub oligomeric_details: String,
757 pub software_name: String,
758 pub absa: Option<f64>,
759 pub ssa: Option<f64>,
760 pub more: Option<f64>,
761 pub generators: Vec<BioAssemblyGenerator>,
762}
763
764#[derive(Debug, Clone, Copy, PartialEq)]
765pub struct CrystalCell {
766 pub a: f64,
767 pub b: f64,
768 pub c: f64,
769 pub alpha: f64,
770 pub beta: f64,
771 pub gamma: f64,
772}
773
774#[derive(Debug, Clone, PartialEq)]
775pub struct CrystalInfo {
776 pub cell: CrystalCell,
777 pub spacegroup_hm: Option<String>,
778 pub z_pdb: Option<String>,
779 pub scale: Option<BioTransform>,
780 pub frac: BioTransform,
781 pub orth: BioTransform,
782 pub explicit_matrices: bool,
783 pub cs_count: i16,
784 pub cell_images: Vec<BioTransform>,
785}
786
787#[derive(Debug, Clone, PartialEq, Default)]
794pub struct CoordinateBlock {
795 pub(crate) positions: Vec<[f64; 3]>,
796}
797
798impl CoordinateBlock {
799 #[must_use]
800 pub fn positions(&self) -> &[[f64; 3]] {
801 &self.positions
802 }
803}
804
805#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
806pub enum BioCoorFormat {
807 Pdb,
808 Mmcif,
809 Mmjson,
810 ChemComp,
811 #[default]
812 Unknown,
813 Detect,
814}
815
816#[derive(Debug, Clone, PartialEq, Default)]
826pub struct BioStructure {
827 pub(crate) name: String,
828 pub(crate) input_format: BioCoorFormat,
829 pub(crate) atoms: Vec<AtomRow>,
830 pub(crate) residues: Vec<ResidueRow>,
831 pub(crate) chains: Vec<ChainRow>,
832 pub(crate) entities: Vec<EntityRow>,
833 pub(crate) models: Vec<ModelRow>,
834 pub(crate) coordinates: CoordinateBlock,
835 pub(crate) metadata: BioMetadata,
836 pub(crate) crystal: Option<CrystalInfo>,
837 pub(crate) resolution: Option<f64>,
838 pub(crate) non_ascii_line: Option<usize>,
839 pub(crate) raw_remarks: Vec<String>,
840 pub(crate) ter_status: char,
841 pub(crate) has_d_fraction: bool,
842 pub(crate) mod_residues: Vec<BioModRes>,
843 pub(crate) shortened_ccd_codes: Vec<(String, String)>,
844 pub(crate) conect_map: HashMap<i32, Vec<i32>>,
845 pub(crate) deferred_conn_records: Vec<String>,
846 pub(crate) connections: Vec<BioConnection>,
847 pub(crate) cispeps: Vec<BioCisPep>,
848 pub(crate) helices: Vec<BioHelix>,
849 pub(crate) sheets: Vec<BioSheet>,
850 pub(crate) remark_290_operators: Vec<String>,
851 pub(crate) assemblies: Vec<BioAssembly>,
852 pub(crate) has_origx: bool,
853 pub(crate) origx: BioTransform,
854 pub(crate) ncs_operators: Vec<BioNcsOperator>,
855 pub(crate) ncs_oper_identity_id: Option<String>,
856}
857
858impl BioStructure {
859 #[must_use]
860 pub fn new() -> Self {
861 Self::default()
862 }
863
864 pub fn from_pdb_str(text: &str) -> Result<Self, crate::io::bio::BioReadError> {
866 Self::from_pdb_str_with_params(text, crate::io::bio::BioPdbReadParams::default())
867 }
868
869 pub fn from_pdb(
871 path: impl AsRef<std::path::Path>,
872 ) -> Result<Self, crate::io::bio::BioReadError> {
873 let path = path.as_ref();
874 let text =
875 std::fs::read_to_string(path).map_err(|error| crate::io::bio::BioReadError::Parse {
876 line_number: 0,
877 message: format!("failed to read PDB file '{}': {error}", path.display()),
878 })?;
879 Self::from_str_with_format(&text, &path.to_string_lossy(), BioCoorFormat::Pdb)
880 }
881
882 pub fn from_pdb_str_with_params(
884 text: &str,
885 params: crate::io::bio::BioPdbReadParams,
886 ) -> Result<Self, crate::io::bio::BioReadError> {
887 crate::io::bio::read_pdb_bio_structure_from_str_with_params(text, params)
888 }
889
890 pub fn from_mmcif_str(text: &str, path: &str) -> Result<Self, crate::io::bio::BioReadError> {
892 Self::from_str_with_format(text, path, BioCoorFormat::Mmcif)
893 }
894
895 pub fn from_mmcif(
897 path: impl AsRef<std::path::Path>,
898 ) -> Result<Self, crate::io::bio::BioReadError> {
899 let path = path.as_ref();
900 let text =
901 std::fs::read_to_string(path).map_err(|error| crate::io::bio::BioReadError::Parse {
902 line_number: 0,
903 message: format!("failed to read mmCIF file '{}': {error}", path.display()),
904 })?;
905 Self::from_mmcif_str(&text, &path.to_string_lossy())
906 }
907
908 pub fn from_structure_str(
910 text: &str,
911 path: &str,
912 ) -> Result<Self, crate::io::bio::BioReadError> {
913 Self::from_str_with_format(text, path, BioCoorFormat::Detect)
914 }
915
916 pub fn from_str_with_format(
918 text: &str,
919 path: &str,
920 format: BioCoorFormat,
921 ) -> Result<Self, crate::io::bio::BioReadError> {
922 crate::io::bio::read_structure_from_memory(text, path, format)
923 }
924
925 pub fn to_mmcif(&self) -> Result<String, crate::io::bio::BioWriteError> {
927 self.to_mmcif_with_options(crate::io::bio::MmcifWriteOptions::default())
928 }
929
930 pub fn to_mmcif_with_options(
932 &self,
933 options: crate::io::bio::MmcifWriteOptions,
934 ) -> Result<String, crate::io::bio::BioWriteError> {
935 crate::io::bio::bio_structure_to_mmcif(self, options)
936 }
937
938 pub fn write_mmcif(
940 &self,
941 path: impl AsRef<std::path::Path>,
942 ) -> Result<(), crate::io::bio::BioWriteError> {
943 self.write_mmcif_with_options(path, crate::io::bio::MmcifWriteOptions::default())
944 }
945
946 pub fn write_mmcif_with_options(
948 &self,
949 path: impl AsRef<std::path::Path>,
950 options: crate::io::bio::MmcifWriteOptions,
951 ) -> Result<(), crate::io::bio::BioWriteError> {
952 crate::io::bio::write_bio_structure_mmcif(self, path.as_ref(), options)
953 }
954
955 #[must_use]
956 pub fn num_atoms(&self) -> usize {
957 self.atoms.len()
958 }
959
960 #[must_use]
961 pub fn num_residues(&self) -> usize {
962 self.residues.len()
963 }
964
965 #[must_use]
966 pub fn num_chains(&self) -> usize {
967 self.chains.len()
968 }
969
970 #[must_use]
971 pub fn num_models(&self) -> usize {
972 self.models.len()
973 }
974
975 #[must_use]
976 pub fn num_entities(&self) -> usize {
977 self.entities.len()
978 }
979
980 #[must_use]
981 pub fn name(&self) -> &str {
982 &self.name
983 }
984
985 #[must_use]
986 pub fn input_format(&self) -> BioCoorFormat {
987 self.input_format
988 }
989
990 #[must_use]
991 pub fn atoms(&self) -> &[AtomRow] {
992 &self.atoms
993 }
994
995 #[must_use]
996 pub fn residues(&self) -> &[ResidueRow] {
997 &self.residues
998 }
999
1000 #[must_use]
1001 pub fn chains(&self) -> &[ChainRow] {
1002 &self.chains
1003 }
1004
1005 #[must_use]
1006 pub fn models(&self) -> &[ModelRow] {
1007 &self.models
1008 }
1009
1010 #[must_use]
1011 pub fn entities(&self) -> &[EntityRow] {
1012 &self.entities
1013 }
1014
1015 #[must_use]
1016 pub fn metadata(&self) -> &BioMetadata {
1017 &self.metadata
1018 }
1019
1020 #[must_use]
1021 pub fn crystal(&self) -> Option<&CrystalInfo> {
1022 self.crystal.as_ref()
1023 }
1024
1025 #[must_use]
1026 pub fn resolution(&self) -> Option<f64> {
1027 self.resolution
1028 }
1029
1030 #[must_use]
1031 pub fn ter_status(&self) -> char {
1032 self.ter_status
1033 }
1034
1035 #[must_use]
1036 pub fn connections(&self) -> &[BioConnection] {
1037 &self.connections
1038 }
1039
1040 #[must_use]
1041 pub fn cispeps(&self) -> &[BioCisPep] {
1042 &self.cispeps
1043 }
1044
1045 #[must_use]
1046 pub fn mod_residues(&self) -> &[BioModRes] {
1047 &self.mod_residues
1048 }
1049
1050 #[must_use]
1051 pub fn assemblies(&self) -> &[BioAssembly] {
1052 &self.assemblies
1053 }
1054
1055 #[must_use]
1056 pub fn has_origx(&self) -> bool {
1057 self.has_origx
1058 }
1059
1060 #[must_use]
1061 pub fn origx(&self) -> &BioTransform {
1062 &self.origx
1063 }
1064
1065 #[must_use]
1066 pub fn ncs_operators(&self) -> &[BioNcsOperator] {
1067 &self.ncs_operators
1068 }
1069
1070 #[must_use]
1071 pub fn ncs_oper_identity_id(&self) -> Option<&str> {
1072 self.ncs_oper_identity_id.as_deref()
1073 }
1074
1075 #[must_use]
1076 pub fn coordinates(&self) -> &CoordinateBlock {
1077 &self.coordinates
1078 }
1079
1080 #[must_use]
1081 pub fn atom_position(&self, atom: AtomId) -> Option<[f64; 3]> {
1082 self.coordinates
1083 .positions
1084 .get(atom.index() as usize)
1085 .copied()
1086 }
1087
1088 #[must_use]
1089 pub fn residue_atoms(&self, residue: ResidueId) -> Option<&[AtomRow]> {
1090 let row = self.residues.get(residue.index() as usize)?;
1091 let start = row.atom_span.start as usize;
1092 let end = row.atom_span.end() as usize;
1093 self.atoms.get(start..end)
1094 }
1095}