Module bioiain.base.atom
Classes
class BIAtom (data)-
Expand source code
class BIAtom(PseudoAtom): def __init__(self, data): if len(data) == 1: data = data[0] for k, v in data.items(): if v == "." or v == "?" or v=="None": #print(k, "is empty for:", data["id"]) #print(data) data[k] = None essential_labs = [ "group_PDB", "id", "type_symbol", "label_alt_id", "label_atom_id", "label_comp_id", "label_seq_id", "label_asym_id", "label_entity_id", "auth_atom_id", "auth_comp_id", "auth_seq_id", "auth_asym_id", "Cartn_x", "Cartn_y", "Cartn_z", "occupancy", "B_iso_or_equiv", "pdbx_PDB_model_num", "pdbx_PDB_ins_code", ] self.misc = {} for k, v in data.items(): if not (k in essential_labs): self.misc[k] = v #ATOM self.atomnum = int(data["id"]) self.type = data["group_PDB"] # ATOM / HETATM self.element = data["type_symbol"].strip() #C self.name = data["label_atom_id"].strip() # CA (Auto) self.name2 = data["auth_atom_id"].strip() # CA (Given) self.prime = False if "'" in self.name: self.prime = True self.name = self.name.replace("'", "").strip() self.name2 = self.name2.replace("'", "").strip() #RES self.resname = data["label_comp_id"] # Auto self.resname2 = data["auth_comp_id"] # Given self.resseq = data["label_seq_id"] # Auto if self.resseq is not None: self.resseq = int(self.resseq) self.resnum = data["auth_seq_id"] # Given if self.resnum is not None: self.resnum = int(self.resnum) #CHAIN self.chain = data["label_asym_id"] # Auto self.complex = data["auth_asym_id"] # Given self.entity = int(data["label_entity_id"]) self.model = int(data["pdbx_PDB_model_num"]) #PROPERTIES self.id = (self.name, self.resnum, self.complex) # Ambiguous (author) self.id2 = (self.name, self.resseq, self.chain, self.entity) # Not ambiguous (label) self.id3 = (self.atomnum, self.type, self.element, self.name, self.resseq, self.chain, self.model) # Unique x = float(data["Cartn_x"]) y = float(data["Cartn_y"]) z = float(data["Cartn_z"]) coord = (x, y, z) super().__init__(coord) self.occupancy = float(data["occupancy"]) self.b = float(data["B_iso_or_equiv"]) self.ins_code = data.get("pdbx_PDB_ins_code", None) #DISORDER if "label_alt_id" not in data: data["label_alt_id"] = "." self.alt_id = data["label_alt_id"] if self.alt_id is None or self.alt_id == "None": self.alt_id = "." if self.alt_id == ".": self.disordered = False self.doppelgangers = None self.favourite = None else: self.disordered = True self.doppelgangers = [] self.favourite = True def print_full(self): if self.disordered: if self.favourite: r = "\n<bi.{} id={}.{} b={} occupancy={} (disordred)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) for datm in self.doppelgangers: r += "\n - <bi.{} id={}.{} b={} occupancy={} (disordered)>".format(self.__class__.__name__, datm.id, datm.alt_id, datm.b, datm.occupancy) return r else: return "<bi.{} id={}.{} b={} occupancy={} (disordred/not-favourite)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) else: return "<bi.{} id={} b={}>".format(self.__class__.__name__, self.id, self.b) def __repr__(self): if self.disordered: if self.favourite: return "<bi.{} id={}.{} b={} occupancy={} (disordred)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) else: return "<bi.{} id={}.{} b={} occupancy={} (disordred/not-favourite)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) else: return "<bi.{} id={} b={}>".format(self.__class__.__name__, self.id, self.b) def __iter__(self): if not self.disordered or self.doppelgangers is None: self.i = 0 #raise AtomDisorderException("Trying to iterate over a non-disordered atom") return self else: self.i = 0 return self def __next__(self): if not self.disordered or self.doppelgangers is None: if self.i == 0: self.i += 1 return self else: self.i = None raise StopIteration if self.i > len(self.doppelgangers): self.i = None raise StopIteration else: if self.i == 0: self.i += 1 return self else: self.i += 1 #print(len(self.doppelgangers), self.i, self.i-2) return self.doppelgangers[self.i - 2] def set_bfactor(self, bfactor): for t in self: t.b = float(bfactor) return self.b def set_coord(self, coord): for t in self: t.coord = float(coord) return self.b def set_misc(self, label, value): for t in self: t.misc[label] = value return self.misc[label] def get_misc(self, label, keyerror="undefined"): if label in self.misc: return self.misc[label] else: if keyerror == "undefined": raise KeyError else: return keyerror def pdb_string(self, new_id=None): record_name = f"{self.type:<6s}"[-6:] if new_id is None: atom_serial_number = f"{self.atomnum:5d}"[-5:] else: atom_serial_number = f"{new_id:5d}"[-5:] if len(self.element) >= 2 or len(self.name) >= 4: atom_name = f"{self.name:<4s}"[-4:] else: atom_name = f" {self.name:<3s}"[-4:] if self.alt_id is None or self.alt_id==".": alternate_location_indicator = " " else: alternate_location_indicator = f"{self.alt_id:1s}"[0] residue_name = f"{self.resname:>3s}"[:3] chain_identifier = f"{self.chain:1s}"[0] residue_sequence_number = f"{self.resnum:>4d}"[-4:] code_for_insertions_of_residues = " " # ?? xcoord = f"{self.x:>8.3f}"[:8] ycoord = f"{self.y:>8.3f}"[:8] zcoord = f"{self.z:>8.3f}"[:8] occupancy = f"{self.occupancy:>6.2f}"[-6:] temperature_factor = f"{self.b:>6.2f}"[-6:] segment_identifier = f" " # ?? element_symbol = f"{self.element:>2s}"[:2] charge = " " # ?? string = "" string+=record_name # 1-6 string+=atom_serial_number # 7-11 string+=" " # 12 string+=atom_name # 13-16 string+=alternate_location_indicator # 17 string+=residue_name # 18-20 string+=" " # 21 string+=chain_identifier # 22 string+=residue_sequence_number # 23-26 string+=code_for_insertions_of_residues # 26 string+=" " # 28-30 string+=xcoord # 31-38 string+=ycoord # 39-46 string+=zcoord # 47-54 string+=occupancy # 55-60 string+=temperature_factor # 61-66 string+= " " # 67-72 string+=segment_identifier # 73-76 string+=element_symbol # 77-78 string+=charge # 79-80 return string @staticmethod def _none_point(val): if val is None: return "." if type(val) == float: return f"{val:7.3f}" elif type(val) == int: return f"{val:>3d}" elif type(val) in [list, tuple, dict]: log("warning", "Data type not insertable in mmcif:", type(val)) return "." else: return f"{str(val):<3s}" def _mmcif_dict(self, include_misc=True): try: data = {} data["group_PDB"] = f"{self.type:6s}" data["id"] = f"{self.atomnum:4d}" data["label_alt_id"] = f"{self._none_point(self.alt_id):>1s}" data["type_symbol"] = f"{self._none_point(self.element):<2s}" if self.prime and not self.name.endswith("'"): data["label_atom_id"] = f"\"{self.name:>2s}'\"" else: data["label_atom_id"] = f"{self._none_point(self.name):<5s}" data["label_comp_id"] =f"{self._none_point(self.resname):<3s}" data["label_seq_id"] = f"{self._none_point(self.resseq):>3s}" data["label_asym_id"] = f"{self._none_point(self.chain):1s}" data["label_entity_id"] = f"{self._none_point(self.entity):1s}" if self.prime and not self.name2.endswith("'"): data["auth_atom_id"] = f"\"{self._none_point(self.name2):>2s}'\"" else: data["auth_atom_id"] = f"{self._none_point(self.name2):<5s}" data["auth_comp_id"] =f"{self._none_point(self.resname2):<3s}" data["auth_seq_id"] = f"{self._none_point(self.resnum):>3s}" data["auth_asym_id"] = f"{self._none_point(self.complex):1s}" data["pdbx_PDB_model_num"] = f"{self._none_point(self.model):>2s}" data["Cartn_x"] = f"{self.x:7.3f}" data["Cartn_y"] = f"{self.y:7.3f}" data["Cartn_z"] = f"{self.z:7.3f}" data["occupancy"] = f"{self.occupancy:6.3f}" data["B_iso_or_equiv"] = f"{self.b:6.2f}" data["pdbx_PDB_ins_code"] = f"{self._none_point(self.ins_code):>1s}" except Exception as e: log("ERROR", "Generating atom mmcif dict") print(self) print(self.__dict__) raise e if include_misc: for k, v in self.misc.items(): data[k] = self._none_point(v) return dataAncestors
Methods
def get_misc(self, label, keyerror='undefined')-
Expand source code
def get_misc(self, label, keyerror="undefined"): if label in self.misc: return self.misc[label] else: if keyerror == "undefined": raise KeyError else: return keyerror def pdb_string(self, new_id=None)-
Expand source code
def pdb_string(self, new_id=None): record_name = f"{self.type:<6s}"[-6:] if new_id is None: atom_serial_number = f"{self.atomnum:5d}"[-5:] else: atom_serial_number = f"{new_id:5d}"[-5:] if len(self.element) >= 2 or len(self.name) >= 4: atom_name = f"{self.name:<4s}"[-4:] else: atom_name = f" {self.name:<3s}"[-4:] if self.alt_id is None or self.alt_id==".": alternate_location_indicator = " " else: alternate_location_indicator = f"{self.alt_id:1s}"[0] residue_name = f"{self.resname:>3s}"[:3] chain_identifier = f"{self.chain:1s}"[0] residue_sequence_number = f"{self.resnum:>4d}"[-4:] code_for_insertions_of_residues = " " # ?? xcoord = f"{self.x:>8.3f}"[:8] ycoord = f"{self.y:>8.3f}"[:8] zcoord = f"{self.z:>8.3f}"[:8] occupancy = f"{self.occupancy:>6.2f}"[-6:] temperature_factor = f"{self.b:>6.2f}"[-6:] segment_identifier = f" " # ?? element_symbol = f"{self.element:>2s}"[:2] charge = " " # ?? string = "" string+=record_name # 1-6 string+=atom_serial_number # 7-11 string+=" " # 12 string+=atom_name # 13-16 string+=alternate_location_indicator # 17 string+=residue_name # 18-20 string+=" " # 21 string+=chain_identifier # 22 string+=residue_sequence_number # 23-26 string+=code_for_insertions_of_residues # 26 string+=" " # 28-30 string+=xcoord # 31-38 string+=ycoord # 39-46 string+=zcoord # 47-54 string+=occupancy # 55-60 string+=temperature_factor # 61-66 string+= " " # 67-72 string+=segment_identifier # 73-76 string+=element_symbol # 77-78 string+=charge # 79-80 return string def print_full(self)-
Expand source code
def print_full(self): if self.disordered: if self.favourite: r = "\n<bi.{} id={}.{} b={} occupancy={} (disordred)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) for datm in self.doppelgangers: r += "\n - <bi.{} id={}.{} b={} occupancy={} (disordered)>".format(self.__class__.__name__, datm.id, datm.alt_id, datm.b, datm.occupancy) return r else: return "<bi.{} id={}.{} b={} occupancy={} (disordred/not-favourite)>".format(self.__class__.__name__, self.id, self.alt_id, self.b, self.occupancy) else: return "<bi.{} id={} b={}>".format(self.__class__.__name__, self.id, self.b) def set_bfactor(self, bfactor)-
Expand source code
def set_bfactor(self, bfactor): for t in self: t.b = float(bfactor) return self.b def set_coord(self, coord)-
Expand source code
def set_coord(self, coord): for t in self: t.coord = float(coord) return self.b def set_misc(self, label, value)-
Expand source code
def set_misc(self, label, value): for t in self: t.misc[label] = value return self.misc[label]
Inherited members
class PseudoAtom (coords, fractional=False)-
Expand source code
class PseudoAtom(object): child_class = None def __init__(self, coords, fractional=False): self.x, self.y, self.z = coords self.coord = (self.x, self.y, self.z) self.is_fractional = fractional self._all_is_frac = False self._last_centre = None self._sym_coords = {} self.element = getattr(self, "element", None) def __repr__(self): return f"<bi.{self.__class__.__name__} at: {self.coord} (frac:{self.is_fractional})>" def __str__(self): return repr(self) def __add__(self, other): if type(other) in (int, float): if len(other) == 1: a = (other, other, other) elif len(other) == 3: a = other else: raise TypeError self.x += a[0] self.y += a[1] self.z += a[2] self.coord = self.x, self.y, self.z return self else: raise NotImplementedError() def __sub__(self, other): if type(other) in (int, float): if len(other) == 1: a = (other, other, other) elif len(other) == 3: a = other else: raise TypeError self.x -= a[0] self.y -= a[1] self.z -= a[2] self.coord = self.x, self.y, self.z return self else: raise NotImplementedError() def copy(self): from copy import deepcopy new = deepcopy(self) return new @staticmethod def _to_frac(coord, params): x, y, z = coord nx = (x * params["vvy"]) + (y * params["vvz"]) + (z * params["uuz"]) ny = (y * params["uuy"]) + (z * params["vv"]) nz = z * params["uu"] return nx, ny, nz @staticmethod def _to_orth(coord, params): t1, t2, t3 = coord tz = t3 / params["uu"] ty = (t2 - tz * params["vv"]) / params["uuy"] tx = (t1 - ty * params["vvz"] - tz * params["uuz"]) / params["vvy"] return tx, ty, tz def to_frac(self, params): if self.is_fractional: log("Warning", f"Atom: {self} is already fractional") raise AlreadyFractional(self) self._orth_coords = self.coord nx, ny, nz = self._to_frac(self.coord, params) self.x = nx self.y = ny self.z = nz self.coord = (self.x, self.y, self.z) self.is_fractional = True return self def to_orth(self, params): if not self.is_fractional: log("Warning", f"Atom: {self} is already orthogonal") raise AlreadyOrthogonal(self) self._frac_coords = self.coord tx, ty, tz = self._to_orth(self.coord, params) self.x = tx self.y = ty self.z = tz self.coord = (self.x, self.y, self.z) self.is_fractional = False return self def closest(self, target, symops, params, centre=None, first_only=True, force=False): if not self.is_fractional: len_fn = length else: len_fn = flength distances_all = {opn:(v,len_fn(vector(v, target), params=params), pos) for opn, (v, pos) in self.all(symops, params, centre, force=force).items()} sorted_all = {k: v for k, v in sorted(distances_all.items(), key=lambda x: x[1][1])} #print([(k, d, pos ) for k, (v, d, pos) in sorted_all.items()]) if first_only: for opn, (v, d, pos) in sorted_all.items(): return v, d, opn, pos return sorted_all def all(self, symops, params, centre=None, force=False): all_coords = {} if self._last_centre == centre and self._all_is_frac == self.is_fractional and not force: for opn, symop in symops.items(): if opn in self._sym_coords.keys(): all_coords[opn] = self._sym_coords[opn] else: all_coords[opn] = self.at(symop, params, centre=centre) else: for opn, symop in symops.items(): all_coords[opn] = self.at(symop, params, centre=centre) self._all_is_frac = self.is_fractional return all_coords def at(self, symop, params, centre=None, centre_is_frac=False): if not self.is_fractional: p2 = np.array(self._to_frac(self.coord, params)) was_orth = True else: was_orth = False p2 = np.array(self.coord) if centre is None: if self.is_fractional: centre = np.array(self.coord) else: centre = np.array(self._to_frac(self.coord, params)) else: if centre_is_frac: centre = np.array(centre) else: centre = np.array(self._to_frac(centre, params)) p2s = np.array(self._symop(p2, symop)) + 99.5 delta = ( ( p2s - np.array(centre) ) % 1 ) - 0.5 new = np.array(centre) + delta position = (new - p2s + 99.5) for p in position: assert p % 1 == 0 position = tuple([int(p) for p in position]) if position == (0,0,0): position = None if was_orth: new = self._to_orth(new, params) return new, position @staticmethod def _symop(coord, symop, position=None): rot = symop["rot"] tra = symop["tra"] x, y, z = coord nx = (rot[0][0] * x) + (rot[0][1] * y) + (rot[0][2] * z) + tra[0] ny = (rot[1][0] * x) + (rot[1][1] * y) + (rot[1][2] * z) + tra[1] nz = (rot[2][0] * x) + (rot[2][1] * y) + (rot[2][2] * z) + tra[2] if position is not None: nx += position[0] ny += position[1] nz += position[2] return nx, ny, nz def symop(self, symop, params, position=None): if not self.is_fractional: self.to_frac(params) was_orth = True else: was_orth = False nx, ny, nz = self._symop(self.coord, symop, position=position) self.x = nx self.y = ny self.z = nz self.coord = (self.x, self.y, self.z) if was_orth: self.to_orth(params) return selfSubclasses
Class variables
var child_class-
The type of the None singleton.
Methods
def all(self, symops, params, centre=None, force=False)-
Expand source code
def all(self, symops, params, centre=None, force=False): all_coords = {} if self._last_centre == centre and self._all_is_frac == self.is_fractional and not force: for opn, symop in symops.items(): if opn in self._sym_coords.keys(): all_coords[opn] = self._sym_coords[opn] else: all_coords[opn] = self.at(symop, params, centre=centre) else: for opn, symop in symops.items(): all_coords[opn] = self.at(symop, params, centre=centre) self._all_is_frac = self.is_fractional return all_coords def at(self, symop, params, centre=None, centre_is_frac=False)-
Expand source code
def at(self, symop, params, centre=None, centre_is_frac=False): if not self.is_fractional: p2 = np.array(self._to_frac(self.coord, params)) was_orth = True else: was_orth = False p2 = np.array(self.coord) if centre is None: if self.is_fractional: centre = np.array(self.coord) else: centre = np.array(self._to_frac(self.coord, params)) else: if centre_is_frac: centre = np.array(centre) else: centre = np.array(self._to_frac(centre, params)) p2s = np.array(self._symop(p2, symop)) + 99.5 delta = ( ( p2s - np.array(centre) ) % 1 ) - 0.5 new = np.array(centre) + delta position = (new - p2s + 99.5) for p in position: assert p % 1 == 0 position = tuple([int(p) for p in position]) if position == (0,0,0): position = None if was_orth: new = self._to_orth(new, params) return new, position def closest(self, target, symops, params, centre=None, first_only=True, force=False)-
Expand source code
def closest(self, target, symops, params, centre=None, first_only=True, force=False): if not self.is_fractional: len_fn = length else: len_fn = flength distances_all = {opn:(v,len_fn(vector(v, target), params=params), pos) for opn, (v, pos) in self.all(symops, params, centre, force=force).items()} sorted_all = {k: v for k, v in sorted(distances_all.items(), key=lambda x: x[1][1])} #print([(k, d, pos ) for k, (v, d, pos) in sorted_all.items()]) if first_only: for opn, (v, d, pos) in sorted_all.items(): return v, d, opn, pos return sorted_all def copy(self)-
Expand source code
def copy(self): from copy import deepcopy new = deepcopy(self) return new def symop(self, symop, params, position=None)-
Expand source code
def symop(self, symop, params, position=None): if not self.is_fractional: self.to_frac(params) was_orth = True else: was_orth = False nx, ny, nz = self._symop(self.coord, symop, position=position) self.x = nx self.y = ny self.z = nz self.coord = (self.x, self.y, self.z) if was_orth: self.to_orth(params) return self def to_frac(self, params)-
Expand source code
def to_frac(self, params): if self.is_fractional: log("Warning", f"Atom: {self} is already fractional") raise AlreadyFractional(self) self._orth_coords = self.coord nx, ny, nz = self._to_frac(self.coord, params) self.x = nx self.y = ny self.z = nz self.coord = (self.x, self.y, self.z) self.is_fractional = True return self def to_orth(self, params)-
Expand source code
def to_orth(self, params): if not self.is_fractional: log("Warning", f"Atom: {self} is already orthogonal") raise AlreadyOrthogonal(self) self._frac_coords = self.coord tx, ty, tz = self._to_orth(self.coord, params) self.x = tx self.y = ty self.z = tz self.coord = (self.x, self.y, self.z) self.is_fractional = False return self