ferritin_plms/ligandmpnn/
proteinfeatures.rs1use crate::featurize::utilities::aa1to_int;
12use candle_core::{Device, Result, Tensor};
13use std::collections::{HashMap, HashSet};
14
15#[allow(dead_code)]
16pub struct ProteinFeatures {
17 pub(crate) s: Tensor,
19 pub(crate) x: Tensor,
21 pub(crate) x_mask: Option<Tensor>,
23 pub(crate) y: Tensor,
25 pub(crate) y_t: Tensor,
27 pub(crate) y_m: Option<Tensor>,
29 pub(crate) r_idx: Tensor,
31 pub(crate) chain_labels: Option<Vec<f64>>,
33 pub(crate) chain_letters: Vec<String>,
35 pub(crate) mask_c: Option<Tensor>,
37 pub(crate) chain_list: Vec<String>,
38}
39impl ProteinFeatures {
40 pub fn get_coords(&self) -> &Tensor {
41 &self.x
42 }
43 pub fn get_sequence(&self) -> &Tensor {
44 &self.s
45 }
46 pub fn get_sequence_mask(&self) -> Option<&Tensor> {
47 self.x_mask.as_ref()
48 }
49 pub fn get_residue_index(&self) -> &Tensor {
50 &self.r_idx
51 }
52 #[allow(clippy::type_complexity)] pub fn get_encoded(
54 &self,
55 ) -> Result<(Vec<String>, HashMap<String, usize>, HashMap<usize, String>)> {
56 let r_idx_list = &self.r_idx.flatten_all()?.to_vec1::<u32>()?;
57 let chain_letters_list = &self.chain_letters;
58 let encoded_residues: Vec<String> = r_idx_list
59 .iter()
60 .enumerate()
61 .map(|(i, r_idx)| format!("{}{}", chain_letters_list[i], r_idx))
62 .collect();
63 let encoded_residue_dict: HashMap<String, usize> = encoded_residues
64 .iter()
65 .enumerate()
66 .map(|(i, s)| (s.clone(), i))
67 .collect();
68 let encoded_residue_dict_rev: HashMap<usize, String> = encoded_residues
69 .iter()
70 .enumerate()
71 .map(|(i, s)| (i, s.clone()))
72 .collect();
73 Ok((
74 encoded_residues,
75 encoded_residue_dict,
76 encoded_residue_dict_rev,
77 ))
78 }
79 pub fn get_encoded_tensor(&self, fixed_residues: String, device: &Device) -> Result<Tensor> {
82 let res_set: HashSet<String> = fixed_residues.split(' ').map(String::from).collect();
83 let (encoded_res, _, _) = &self.get_encoded()?;
84 Tensor::from_iter(
85 encoded_res
86 .iter()
87 .map(|item| u32::from(!res_set.contains(item))),
88 device,
89 )
90 }
91 pub fn get_chain_mask_tensor(
92 &self,
93 chains_to_design: Vec<String>,
94 device: &Device,
95 ) -> Result<Tensor> {
96 let mask_values: Vec<u32> = self
97 .chain_letters
98 .iter()
99 .map(|chain| u32::from(chains_to_design.contains(chain)))
100 .collect();
101 Tensor::from_iter(mask_values, device)
102 }
103 pub fn update_mask(&mut self, tensor: Tensor) -> Result<()> {
104 self.x_mask = match self.x_mask.as_ref() {
105 Some(mask) => Some(mask.mul(&tensor)?),
106 None => Some(tensor),
107 };
108 Ok(())
109 }
110 pub fn create_bias_tensor(&self, bias_aa: Option<String>) -> Result<Tensor> {
113 let device = self.s.device();
114 let dtype = self.s.dtype();
115 match bias_aa {
116 None => Tensor::zeros(21, dtype, device),
117 Some(bias_aa) => {
118 let mut bias_values = vec![0.0f32; 21];
119 for pair in bias_aa.split(',') {
120 if let Some((aa, value_str)) = pair.split_once(':')
121 && let Ok(value) = value_str.parse::<f32>()
122 && let Some(aa_char) = aa.chars().next()
123 {
124 let idx = aa1to_int(aa_char) as usize;
125 bias_values[idx] = value;
126 }
127 }
128 Tensor::from_slice(&bias_values, 21, device)
129 }
130 }
131 }
132 pub fn save_to_safetensor(&self, path: &str) -> Result<()> {
133 let mut tensors: HashMap<String, Tensor> = HashMap::new();
134 tensors.insert("protein_atom_sequence".to_string(), self.s.clone());
136 tensors.insert("protein_atom_positions".to_string(), self.x.clone());
137 tensors.insert("ligand_atom_positions".to_string(), self.y.clone());
138 tensors.insert("ligand_atom_name".to_string(), self.y_t.clone());
139 candle_core::safetensors::save(&tensors, path)?;
140 Ok(())
141 }
142}