Package mmLib :: Module CIFBuilder
[hide private]
[frames] | no frames]

Source Code for Module mmLib.CIFBuilder

  1  ## Copyright 2002-2010 by PyMMLib Development Group (see AUTHORS file) 
  2  ## This code is part of the PyMMLib distribution and governed by 
  3  ## its license.  Please see the LICENSE file that should have been 
  4  ## included as part of this package. 
  5  import CIF 
  6  import Structure 
  7  import StructureBuilder 
  8  from ConsoleOutput import warning 
  9   
10 -def add_string(m, key, table, column, row):
11 try: 12 v = table.get_value(column, row) 13 if v in ('', '?', '.'): 14 return False 15 m[key] = str(v) 16 return True 17 except (IndexError, KeyError): 18 return False 19 return False
20
21 -def add_number(m, key, table, column, row):
22 try: 23 v = table.get_value(column, row) 24 if v in ('', '?', '.'): 25 return False 26 m[key] = CIF.makeNumber(v) 27 return True 28 except (IndexError, KeyError, ValueError): 29 return False
30
31 -class CIFStructureBuilder(StructureBuilder.StructureBuilder):
32 """Builds a new Structure object by loading a CIF file. 33 """ 34
35 - def read_start(self, filobj):
36 ## parse the CIF file 37 cif_file = CIF.CIFFile() 38 cif_file.load_file(filobj) 39 if len(cif_file.data_blocks) != 1: 40 warning("read_start: only single-structure CIF files supported") 41 self.halt = True 42 return 43 self.cif = cif_file.data_blocks[0] 44 self.get_cell_parameters() 45 self.atom_site_name_map = {}
46
47 - def get_cell_parameters(self):
48 """Read unit information form various tags and compute 49 the fractional-to-Cartesian conversion matrix. 50 """ 51 a = CIF.makeNumber(self.cif.tags["cell_length_a"]) 52 b = CIF.makeNumber(self.cif.tags["cell_length_b"]) 53 c = CIF.makeNumber(self.cif.tags["cell_length_c"]) 54 alpha_degrees = CIF.makeNumber(self.cif.tags["cell_angle_alpha"]) 55 beta_degrees = CIF.makeNumber(self.cif.tags["cell_angle_beta"]) 56 gamma_degrees = CIF.makeNumber(self.cif.tags["cell_angle_gamma"]) 57 z = self.cif.tags["cell_formula_units_z"] 58 space_group = self.cif.tags.get("symmetry_space_group_name_h-m", None) 59 unit_cell = { 60 "length_a": a, 61 "length_b": b, 62 "length_c": c, 63 "angle_alpha": alpha_degrees, 64 "angle_beta": beta_degrees, 65 "angle_gamma": gamma_degrees, 66 "z": z, 67 "space_group": space_group 68 } 69 self.load_unit_cell(unit_cell) 70 71 # 72 # Transformation matrix from 73 # http://www.ccl.net/cca/documents/molecular-modeling/node4.html 74 # 75 import math 76 alpha = math.radians(alpha_degrees) 77 cosa = math.cos(alpha) 78 sina = math.sin(alpha) 79 beta = math.radians(beta_degrees) 80 cosb = math.cos(beta) 81 sinb = math.sin(beta) 82 gamma = math.radians(gamma_degrees) 83 cosg = math.cos(gamma) 84 sing = math.sin(gamma) 85 V = a * b * c * math.sqrt(1 - cosa * cosa - cosb * cosb 86 - cosg * cosg + 2 * cosa * cosb * cosg) 87 self.xform = [ 88 [ a, b * cosg, c * cosb ], 89 [ 0, b * sing, c * (cosa - cosb * cosg) / sing ], 90 [ 0, 0, V / (a * b * sing) ], 91 ]
92
93 - def read_atoms(self):
94 """Read atom information form the atom_site section. 95 """ 96 for t in self.cif.tables: 97 if "atom_site_label" in t.columns: 98 table = t 99 break 100 else: 101 warning("read_atoms: no atom_site section found") 102 self.halt = True 103 return 104 105 for i in range(len(table.rows)): 106 atm_map = { 107 "res_name": self.cif.name, 108 "fragment_id": "1", 109 "chain_id": " ", 110 } 111 add_string(atm_map, "name", table, "atom_site_label", i) 112 add_string(atm_map, "element", table, "atom_site_type_symbol", i) 113 add_number(atm_map, "fractx", table, "atom_site_fract_x", i) 114 add_number(atm_map, "fracty", table, "atom_site_fract_y", i) 115 add_number(atm_map, "fractz", table, "atom_site_fract_z", i) 116 add_number(atm_map, "temp_factor", 117 table, "atom_site_U_iso_or_equiv", i) 118 add_number(atm_map, "occupancy", table, "atom_site_occupancy", i) 119 try: 120 fx = atm_map["fractx"] 121 fy = atm_map["fracty"] 122 fz = atm_map["fractz"] 123 except KeyError: 124 warning("read_atoms: missing coordinates") 125 else: 126 fc = [ fx, fy, fz ] 127 xyz = [ 0.0, 0.0, 0.0 ] 128 for i in range(3): 129 sum = 0.0 130 for j in range(3): 131 sum += self.xform[i][j] * fc[j] 132 xyz[i] = sum 133 atm_map["x"] = xyz[0] 134 atm_map["y"] = xyz[1] 135 atm_map["z"] = xyz[2] 136 atm = self.load_atom(atm_map) 137 self.atom_site_name_map[atm_map["name"]] = atm 138 #print "%d atoms" % len(self.atom_site_name_map) 139 140 ## load the bonds 141 bond_map = {} 142 self.read_geom_bond(bond_map) 143 self.read_geom_angle(bond_map) 144 self.load_bonds(bond_map)
145 #print "%d bonds" % len(bond_map) 146
147 - def read_geom_bond(self, bond_map):
148 """Read bond information form the geom_bond section. 149 """ 150 for t in self.cif.tables: 151 if "geom_bond_atom_site_label_1" in t.columns: 152 table = t 153 break 154 else: 155 warning("read_atoms: no geom_bond section found") 156 return 157 158 for row in range(len(table.rows)): 159 name1 = table.get_value("geom_bond_atom_site_label_1", row) 160 try: 161 atom1 = self.atom_site_name_map[name1] 162 except KeyError: 163 warning("read_atoms: bond references non-existent atom '%s'" 164 % name1) 165 continue 166 name2 = table.get_value("geom_bond_atom_site_label_2", row) 167 try: 168 atom2 = self.atom_site_name_map[name2] 169 except KeyError: 170 warning("read_atoms: bond references non-existent atom '%s'" 171 % name2) 172 continue 173 174 if id(atom1) < id(atom2): 175 bnd = (atom1, atom2) 176 else: 177 bnd = (atom2, atom1) 178 bond_map[bnd] = {}
179
180 - def read_geom_angle(self, bond_map):
181 """Read bond information form the geom_angle section. 182 """ 183 for t in self.cif.tables: 184 if "geom_angle_atom_site_label_1" in t.columns: 185 table = t 186 break 187 else: 188 warning("read_atoms: no geom_angle section found") 189 return 190 191 for row in range(len(table.rows)): 192 name1 = table.get_value("geom_angle_atom_site_label_1", row) 193 atom1 = self.atom_site_name_map[name1] 194 name2 = table.get_value("geom_angle_atom_site_label_2", row) 195 atom2 = self.atom_site_name_map[name2] 196 name3 = table.get_value("geom_angle_atom_site_label_3", row) 197 atom3 = self.atom_site_name_map[name3] 198 199 if id(atom1) < id(atom2): 200 bnd = (atom1, atom2) 201 else: 202 bnd = (atom2, atom1) 203 bond_map[bnd] = {} 204 205 if id(atom2) < id(atom3): 206 bnd = (atom2, atom3) 207 else: 208 bnd = (atom3, atom2) 209 bond_map[bnd] = {}
210
211 - def read_metadata(self):
212 self.read_structure_id() 213 self.struct.cif_data = self.cif
214
215 - def read_structure_id(self):
216 """Read the PDB ID. 217 """ 218 name_tags = [ 219 "chemical_name_common", 220 "database_code_depnum_ccdc_archive", 221 "chemical_name_systematic", 222 ] 223 for tag in name_tags: 224 try: 225 entry_id = self.cif.tags[tag].strip() 226 except KeyError: 227 pass 228 else: 229 if entry_id != '.' and entry_id != '?': 230 self.load_structure_id(entry_id) 231 break
232 233 if __name__ == "__main__":
234 - def builder_test(test_file):
235 csb = CIFStructureBuilder(fil=test_file) 236 s = csb.struct 237 print s
238 builder_test("ccd.cif") 239