Arko006 commited on
Commit
dbbf75a
·
verified ·
1 Parent(s): 1f50fb7

Upload models/molecule_graph.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. models/molecule_graph.py +115 -0
models/molecule_graph.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ from rdkit import Chem
4
+ from rdkit.Chem import AllChem
5
+ from torch_geometric.data import Data
6
+
7
+
8
+ ATOM_ENCODER = {
9
+ 6: [1, 0, 0, 0, 0, 0, 0],
10
+ 7: [0, 1, 0, 0, 0, 0, 0],
11
+ 8: [0, 0, 1, 0, 0, 0, 0],
12
+ 16: [0, 0, 0, 1, 0, 0, 0],
13
+ 15: [0, 0, 0, 0, 1, 0, 0],
14
+ 17: [0, 0, 0, 0, 0, 1, 0],
15
+ 35: [0, 0, 0, 0, 0, 1, 0],
16
+ 9: [0, 0, 0, 0, 0, 1, 0],
17
+ 53: [0, 0, 0, 0, 0, 1, 0],
18
+ }
19
+
20
+ HYBRIDIZATION_MAP = {
21
+ Chem.rdchem.HybridizationType.SP: [1, 0, 0, 0, 0],
22
+ Chem.rdchem.HybridizationType.SP2: [0, 1, 0, 0, 0],
23
+ Chem.rdchem.HybridizationType.SP3: [0, 0, 1, 0, 0],
24
+ Chem.rdchem.HybridizationType.SP3D: [0, 0, 0, 1, 0],
25
+ Chem.rdchem.HybridizationType.SP3D2: [0, 0, 0, 0, 1],
26
+ }
27
+
28
+ BOND_ENCODER = {
29
+ Chem.rdchem.BondType.SINGLE: [1, 0, 0, 0],
30
+ Chem.rdchem.BondType.DOUBLE: [0, 1, 0, 0],
31
+ Chem.rdchem.BondType.TRIPLE: [0, 0, 1, 0],
32
+ Chem.rdchem.BondType.AROMATIC: [0, 0, 0, 1],
33
+ }
34
+
35
+
36
+ def one_hot(val, choices):
37
+ return [1 if val == c else 0 for c in choices]
38
+
39
+
40
+ def get_atom_features(atom):
41
+ atomic_num = atom.GetAtomicNum()
42
+ atomic_type = ATOM_ENCODER.get(atomic_num, [0, 0, 0, 0, 0, 0, 0])
43
+
44
+ hybridization = HYBRIDIZATION_MAP.get(
45
+ atom.GetHybridization(), [0, 0, 0, 0, 0]
46
+ )
47
+
48
+ degree = min(atom.GetDegree(), 6)
49
+ degree_feat = degree / 6.0
50
+
51
+ valence = min(atom.GetTotalValence(), 8)
52
+ valence_feat = valence / 8.0
53
+
54
+ formal_charge = np.clip(atom.GetFormalCharge(), -3, 3)
55
+ charge_feat = (formal_charge + 3) / 6.0
56
+
57
+ aromatic = 1.0 if atom.GetIsAromatic() else 0.0
58
+
59
+ h_count = min(atom.GetTotalNumHs(), 4)
60
+ h_feat = h_count / 4.0
61
+
62
+ return atomic_type + hybridization + [degree_feat, valence_feat, charge_feat, aromatic, h_feat]
63
+
64
+
65
+ def get_bond_features(bond):
66
+ bond_type = BOND_ENCODER.get(bond.GetBondType(), [0, 0, 0, 0])
67
+ conjugated = 1.0 if bond.GetIsConjugated() else 0.0
68
+
69
+ stereo = bond.GetStereo()
70
+ stereo_vec = one_hot(stereo, [
71
+ Chem.rdchem.BondStereo.STEREONONE,
72
+ Chem.rdchem.BondStereo.STEREOANY,
73
+ Chem.rdchem.BondStereo.STEREOZ,
74
+ Chem.rdchem.BondStereo.STEREOE,
75
+ ])
76
+
77
+ return bond_type + [conjugated] + stereo_vec
78
+
79
+
80
+ def smiles_to_graph(smiles: str) -> Data:
81
+ mol = Chem.MolFromSmiles(smiles)
82
+ if mol is None:
83
+ raise ValueError(f"Invalid SMILES: {smiles}")
84
+
85
+ mol = Chem.AddHs(mol)
86
+ AllChem.EmbedMolecule(mol, randomSeed=42)
87
+ AllChem.MMFFOptimizeMolecule(mol)
88
+ mol = Chem.RemoveHs(mol)
89
+
90
+ atom_features = []
91
+ for atom in mol.GetAtoms():
92
+ atom_features.append(get_atom_features(atom))
93
+
94
+ x = torch.tensor(atom_features, dtype=torch.float32)
95
+
96
+ edge_indices = []
97
+ edge_features = []
98
+
99
+ for bond in mol.GetBonds():
100
+ i = bond.GetBeginAtomIdx()
101
+ j = bond.GetEndAtomIdx()
102
+ edge_indices.append([i, j])
103
+ edge_indices.append([j, i])
104
+ bf = get_bond_features(bond)
105
+ edge_features.append(bf)
106
+ edge_features.append(bf)
107
+
108
+ if len(edge_indices) == 0:
109
+ edge_index = torch.zeros((2, 0), dtype=torch.long)
110
+ edge_attr = torch.zeros((0, len(edge_features[0]) if edge_features else 6), dtype=torch.float32)
111
+ else:
112
+ edge_index = torch.tensor(edge_indices, dtype=torch.long).t().contiguous()
113
+ edge_attr = torch.tensor(edge_features, dtype=torch.float32)
114
+
115
+ return Data(x=x, edge_index=edge_index, edge_attr=edge_attr)