def _align(self): pp_a = self._pp(self.protein_A, 'A') # seq_a = pp_a.get_sequence() pp_b = self._pp(self.protein_B, ' ') # seq_b = pp_b.get_sequence() # global_align = pairwise2.align.globalxx(seq_a, seq_b)[0] # msa = MultipleSeqAlignment([SeqRecord(Seq(global_align[0], alphabet=generic_protein), id='A'), # SeqRecord(Seq(global_align[1], alphabet=generic_protein), id='B')]) msa = self.alignment # offset_a = re.search(r'[^-]', str(msa[0].seq)).span()[0] # offset_b = re.search(r'[^-]', str(msa[1].seq)).span()[0] plus = 1000 for i in range(len(pp_a)): pp_a[i].id = (pp_a[i].id[0], plus + i, pp_a[i].id[2]) for i in range(len(pp_b)): pp_b[i].id = (pp_b[i].id[0], plus + i, pp_b[i].id[2]) new_chain_a = Chain(' ') for i in pp_a: # i.id = (i.id[0], i.id[1] - plus, i.id[2]) new_chain_a.add(i) new_chain_b = Chain(' ') for i in pp_b: # i.id = (i.id[0], i.id[1] - plus, i.id[2]) new_chain_b.add(i) io = PDBIO() io.set_structure(new_chain_a) io.save(f'.tmp.protein_a.pdb') io = PDBIO() io.set_structure(new_chain_b) io.save(f'.tmp.protein_b.pdb')
def add(self, residue): """Add PdbResidue object to site (in the residues list and dict)""" residue = residue.copy(include_structure=True) if type(residue) == PdbResidue: self.residues.append(residue) self.residues_dict[residue.full_id] = residue residue.parent_site = self if type(residue) == Het: self.ligands.append(residue) residue.parent_site = self if residue.is_polymer: if residue.chain in self.structure[0]: for r in residue.structure: self.structure[0][residue.chain].add(r) return True self.structure[0].add(residue.structure) return True if residue.structure: # Initialize structure if empty if self.structure is None: self.structure = Structure(self.id) self.structure.add(Model(0)) chain_id = residue.structure.get_parent().get_id() if chain_id not in self.structure[0]: self.structure[0].add(Chain(chain_id)) # Add residue structure to site structure if residue.structure.get_id() not in self.structure[0][chain_id]: self.structure[0][chain_id].add(residue.structure) return True
def retrieve_sphere_model(structure): #, score): """ each chain is here represented by centre of mass only """ sphere_struct = Structure('clustering_model') my_model = Model(0) sphere_struct.add(my_model) #bedzie zmieniona numeracja chain_mass_centres, index = [], 0 for chain in structure.get_chains(): my_chain = Chain(chain.id) sphere_struct[0].add(my_chain) coord = calculate_centre_of_complex(chain) chain_mass_centres.append(coord) my_residue = Residue((' ', index, ' '), chain.id, ' ') coords = array(coord, 'f') atom = Atom('CA', coords, 0, 0, ' ', 'CA', 1) my_chain.add(my_residue) my_residue.add(atom) index += 1 del structure return sphere_struct
def renumber(chain, new_id=" "): """ Renumber a chain from 1, stripping insertion codes. :param `Bio.PDB.Chain` chain: structure to sanitise. :param str new_id: ID of the new chain. :return: A 2-tuple containing the following: 1. The new :py:class:`Bio.PDB.Chain.Chain` object. 2. A list of tuples containing the old residue ID, as returned by :py:meth:`Bio.PDB.Chain.Chain.get_id`. """ mapping = [] sanitised_chain = Chain(new_id) for res_index, res in enumerate(chain): sanitised_res = Residue( (res.get_id()[0], res_index + 1, ' '), res.get_resname(), res.get_segid()) mapping.append(res.get_id()) for atom in res: sanitised_res.add(atom.copy()) sanitised_chain.add(sanitised_res) return mapping, sanitised_chain
def renumber_windowed_model(self, structure: Structure, alphafold_mmCIF_dict: Dict) -> Structure: # Grab the Alphafold dictionary entry that descrives the residue range in the structure seq_db_align_begin = int(alphafold_mmCIF_dict['_ma_target_ref_db_details.seq_db_align_begin'][0]) seq_db_align_end = int(alphafold_mmCIF_dict['_ma_target_ref_db_details.seq_db_align_end'][0]) # start empty renumbered_structure = Structure(structure.id) for model in structure: renumbered_model = Model(model.id) for chain in model: transcript_residue_number = seq_db_align_begin renumbered_chain = Chain(chain.id) for residue in chain: renumbered_residue = residue.copy() renumbered_residue.id = (' ', transcript_residue_number, ' ') # The above copy routines fail to copy disorder properly - so just wipe out all notion of disorder for atom in renumbered_residue: atom.disordered_flag = 0 renumbered_residue.disordered = 0 renumbered_chain.add(renumbered_residue) transcript_residue_number += 1 assert transcript_residue_number == seq_db_align_end + 1 renumbered_model.add(renumbered_chain) renumbered_structure.add(renumbered_model) return renumbered_structure
def getStructFromFasta(self, fname, chainType): ''' Creates a Bio.PDB.Structure object from a fasta file contained in fname. Atoms are not filled and thus no coordiantes availables. Implements from Structure to Residue hierarchy. :param fname: str. path to fasta file @chainType: str. "l" or "r" ''' seq = self.parseFasta( fname, inputNumber="1" if chainType == "l" else "2") #inpuNumber is used to report which partner fails if error prefix = self.splitExtendedPrefix(self.getExtendedPrefix(fname))[0] chainId = chainType.upper() residues = [] struct = Structure(prefix) model = Model(0) struct.add(model) chain = Chain(chainId) model.add(chain) for i, aa in enumerate(seq): try: resname = one_to_three(aa) except KeyError: resname = "UNK" res = Residue((' ', i, ' '), resname, prefix) chain.add(res) return struct
def slice(cls, obj, selection, name='slice'): """Create a new Structure object 'S2' from a slice of the current one, 'S1'. <selection> defines which descendents 'S1' will be stored in 'S2'.""" from Bio.PDB.Structure import Structure from Bio.PDB.Model import Model from Bio.PDB.Chain import Chain ent = Structure(name) # Biopython structure object # Loop over selection and determine what model/chain objects we need to create in order to # store the slice models = {} for item in selection: mid = item[1] cid = item[2] if mid not in models: models[mid] = set() # store chain ids models[mid].add(cid) # Create model/chains to store slice for mid in models: ent.add(Model(mid)) for cid in models[mid]: ent[mid].add(Chain(cid)) # Add residues to slice for item in selection: mid = item[1] cid = item[2] rid = item[3] ent[mid][cid].add(obj[mid][cid][rid].copy()) return cls(ent, name=name)
def create_sphere_representation(self): """ each chain is here represented by centre of mass only """ new_struct = Structure('sphrere') my_model = Model(0) new_struct.add(my_model) chain_mass_centres, index = [], 1 my_chain = Chain(self.fa_struct.chain) new_struct[0].add(my_chain) coord, self.molmass, self.radius = self.calculate_centre_of_complex( self.fa_struct.struct) my_residue = Residue((' ', index, ' '), "ALA", ' ') coords = array(coord, 'f') atom = Atom('CA', coords, 0, 0, ' ', ' CA', 1) my_chain.add(my_residue) my_residue.add(atom) self.cg_struct = new_struct name = "dddd" + self.fa_struct.chain self.save_pdb(new_struct, name)
def create_new_chain(self, old_struct): s = Structure(old_struct.chain) my_model = Model(0) s.add(my_model) my_chain = Chain(old_struct.chain) my_model.add(my_chain) #what if more chains in one component? return s
def retrieve_ca_model(structure): """ chains are represented only by main chain atoms (Calfas or C4') """ reduced_struct = Structure('clustering_model') my_model = Model(0) reduced_struct.add(my_model) main_chain_atoms = [] for ch in structure[0]: my_chain = Chain(ch.id) reduced_struct[0].add(my_chain) for resi in ch: for atom in resi: #print "----", resi.id, resi.get_segid(), ch.id if atom.get_name() == "CA" or atom.get_name( ) == "C4'" or atom.get_name() == "C4*": my_residue = Residue((' ', resi.id[1], ' '), resi.get_resname(), ' ') atom = Atom('CA', atom.coord, 0, ' ', ' ', 'CA', atom.get_serial_number()) my_chain.add(my_residue) my_residue.add(atom) main_chain_atoms.append(atom) return reduced_struct
def normalize_chain(chain: Chain) -> Chain: new_chain = Chain(chain.id) for residue in chain: try: new_chain.add(normalize_residue(residue)) except UnknownResidueError: pass return new_chain
def create_new_chain(self, id): """ """ self.fragment_lattice = Structure(id) my_model = Model(0) self.fragment_lattice.add(my_model) my_chain = Chain(id) my_model.add(my_chain) #what if more chains in one component?
def __create_superimposed_pdb(self): def fill_in_chain(chain, protein_id, rotation_matrix = None): for index,residue in enumerate(self.proteins[protein_id].get_residues()): residue.id = (residue.id[0], index, residue.id[2]) chain.add(residue) merged_model = Model(0) chain_a = Chain('A') chain_b = Chain('B') fill_in_chain(chain_a, 0) fill_in_chain(chain_b, 1) merged_model.add(chain_a) merged_model.add(chain_b) return merged_model
def initialize_res(residue: Union[Geo, str]) -> Structure: """Creates a new structure containing a single amino acid. The type and geometry of the amino acid are determined by the argument, which has to be either a geometry object or a single-letter amino acid code. The amino acid will be placed into chain A of model 0.""" if isinstance(residue, Geo): geo = residue elif isinstance(residue, str): geo = geometry(residue) else: raise ValueError("Invalid residue argument:", residue) segID = 1 AA = geo.residue_name CA_N_length = geo.CA_N_length CA_C_length = geo.CA_C_length N_CA_C_angle = geo.N_CA_C_angle CA_coord = np.array([0.0, 0.0, 0.0]) C_coord = np.array([CA_C_length, 0, 0]) N_coord = np.array([ CA_N_length * math.cos(N_CA_C_angle * (math.pi / 180.0)), CA_N_length * math.sin(N_CA_C_angle * (math.pi / 180.0)), 0, ]) N = Atom("N", N_coord, 0.0, 1.0, " ", " N", 0, "N") # Check if the peptide is capped or not if geo.residue_name == "ACE": CA = Atom("CH3", CA_coord, 0.0, 1.0, " ", " CH3", 0, "C") else: CA = Atom("CA", CA_coord, 0.0, 1.0, " ", " CA", 0, "C") C = Atom("C", C_coord, 0.0, 1.0, " ", " C", 0, "C") ##Create Carbonyl atom (to be moved later) C_O_length = geo.C_O_length CA_C_O_angle = geo.CA_C_O_angle N_CA_C_O_diangle = geo.N_CA_C_O_diangle carbonyl = calculateCoordinates(N, CA, C, C_O_length, CA_C_O_angle, N_CA_C_O_diangle) O = Atom("O", carbonyl, 0.0, 1.0, " ", " O", 0, "O") res = make_res_of_type(segID, N, CA, C, O, geo) cha = Chain("A") cha.add(res) mod = Model(0) mod.add(cha) struc = Structure("X") struc.add(mod) return struc
def add_dummy_structure(self): """Adds a dummy atom of zero coordinates to mark a gap in visualisation software""" dummy_atom = Atom('DUM', np.zeros(3), 0, 1, ' ', 'DUM', -999) dummy_residue = Residue((' ', -1 * self.chiral_id, ' '), 'DUM', '?') dummy_residue.add(dummy_atom) dummy_chain = Chain('?') dummy_chain.add(dummy_residue) self.dummy_structure = dummy_residue return True
def __make_structure_from_residues__(self, residues): """ Makes a Structure object either from a pdbfile or a list of residues """ # KR: this probably can be outsourced to another module. struct = Structure('s') model = Model('m') n_chain = 1 chain = Chain('c%i' % n_chain) for residue in residues: if chain.has_id(residue.id): model.add(chain) n_chain += 1 chain = Chain('c%i' % n_chain) chain.add(residue) model.add(chain) struct.add(model) return struct
def get_structure(self, name='RNA chain'): """Returns chain as a PDB.Structure object.""" struc = Structure(name) model = Model(0) chain = Chain(self.chain_name) struc.add(model) struc[0].add(chain) for resi in self: struc[0][self.chain_name].add(resi) return struc
def add_chain_to_struct(self, chain_id): """ adds another model to BIO.pdb structure object Parameters: ----------- chain_id : chain name Returns: --------- self.struct : Bio.PDB structure with new chain """ chain = Chain(chain_id) self.struct[0].add(chain)
def init_chain(self, chain_id): """Initiate a new Chain object with given id. Arguments: o chain_id - string """ if self.model.has_id(chain_id): self.chain = self.model[chain_id] warnings.warn( "WARNING: Chain %s is discontinuous at line %i." % (chain_id, self.line_counter), PDBConstructionWarning) else: self.chain = Chain(chain_id) self.model.add(self.chain)
def create_new_structure(self, name, chain_id): """ creates new Bio.PDB structure object Parameters: ----------- name : structure name chain_id : chain name (e.g. A, B, C) Returns: --------- self.struct : Bio.PDB object with model and chain inside """ self.struct = Structure(name) my_model = Model(0) my_chain = Chain(chain_id) self.struct.add(my_model) self.struct[0].add(my_chain)
def initialize_res(residue): '''Creates a new structure containing a single amino acid. The type and geometry of the amino acid are determined by the argument, which has to be either a geometry object or a single-letter amino acid code. The amino acid will be placed into chain A of model 0.''' if isinstance( residue, Geo ): geo = residue else: geo= Geo(residue) segID=1 AA= geo.residue_name CA_N_length=geo.CA_N_length CA_C_length=geo.CA_C_length N_CA_C_angle=geo.N_CA_C_angle CA_coord= np.array([0.,0.,0.]) C_coord= np.array([CA_C_length,0,0]) N_coord = np.array([CA_N_length*math.cos(N_CA_C_angle*(math.pi/180.0)),CA_N_length*math.sin(N_CA_C_angle*(math.pi/180.0)),0]) N= Atom("N", N_coord, 0.0 , 1.0, " "," N", 0, "N") CA=Atom("CA", CA_coord, 0.0 , 1.0, " "," CA", 0,"C") C= Atom("C", C_coord, 0.0, 1.0, " ", " C",0,"C") ##Create Carbonyl atom (to be moved later) C_O_length=geo.C_O_length CA_C_O_angle=geo.CA_C_O_angle N_CA_C_O_diangle=geo.N_CA_C_O_diangle carbonyl=calculateCoordinates(N, CA, C, C_O_length, CA_C_O_angle, N_CA_C_O_diangle) O= Atom("O",carbonyl , 0.0 , 1.0, " "," O", 0, "O") res=makeRes(segID, N, CA, C, O, geo) cha= Chain('A') cha.add(res) mod= Model(0) mod.add(cha) struc= Structure('X') struc.add(mod) return struc
def create_structure(coords, pdb_type, remove_masked): """Create the structure. Args: coords: 3D coordinates of structure pdb_type: predict or actual structure remove_masked: whether to include masked atoms. If false, the masked atoms have coordinates of [0,0,0]. Returns: structure """ name = protein.id_ structure = Structure(name) model = Model(0) chain = Chain('A') for i, residue in enumerate(protein.primary): residue = AA_LETTERS[residue] if int(protein.mask[i]) == 1 or remove_masked == False: new_residue = Residue((' ', i + 1, ' '), residue, ' ') j = 3 * i atom_list = ['N', 'CA', 'CB'] for k, atom in enumerate(atom_list): new_atom = Atom(name=atom, coord=coords[j + k, :], bfactor=0, occupancy=1, altloc=' ', fullname=" {} ".format(atom), serial_number=0) new_residue.add(new_atom) chain.add(new_residue) model.add(chain) structure.add(model) io = PDBIO() io.set_structure(structure) io.save(save_dir + name + '_' + pdb_type + '.pdb') return structure
def select_structure(selector, structure): new_structure = Structure(structure.id) for model in structure: if not selector.accept_model(model): continue new_model = Model(model.id, model.serial_num) new_structure.add(new_model) for chain in model: if not selector.accept_chain(chain): continue new_chain = Chain(chain.id) new_model.add(new_chain) for residue in chain: if not selector.accept_residue(residue): continue new_residue = Residue(residue.id, residue.resname, residue.segid) new_chain.add(new_residue) for atom in residue: if selector.accept_atom(atom): new_residue.add(atom) return new_structure
def createPDBFile(self): "Create test CIF file with 12 Atoms in icosahedron vertexes" from Bio.PDB.Structure import Structure from Bio.PDB.Model import Model from Bio.PDB.Chain import Chain from Bio.PDB.Residue import Residue from Bio.PDB.Atom import Atom from Bio.PDB.mmcifio import MMCIFIO import os CIFFILENAME = "/tmp/out.cif" # create atom struct with ico simmety (i222r) icosahedron = Icosahedron(circumscribed_radius=100, orientation='222r') pentomVectorI222r = icosahedron.getVertices() # create biopython object structure = Structure('result') # structure_id model = Model(1, 1) # model_id,serial_num structure.add(model) chain = Chain('A') # chain Id model.add(chain) for i, v in enumerate(pentomVectorI222r, 1): res_id = (' ', i, ' ') # first arg ' ' -> aTOm else heteroatom res_name = "ALA" #+ str(i) # define name of residue res_segid = ' ' residue = Residue(res_id, res_name, res_segid) chain.add(residue) # ATOM name, coord, bfactor, occupancy, altloc, fullname, serial_number, # element=None) atom = Atom('CA', v, 0., 1., " ", " CA ", i, "C") residue.add(atom) io = MMCIFIO() io.set_structure(structure) # delete file if exists if os.path.exists(CIFFILENAME): os.remove(CIFFILENAME) io.save(CIFFILENAME) return CIFFILENAME
def polymer(cls, reslist, mcsa_id=None, pdb_id=None, chain='', parent_site=None): """Alternative constructor for polymers. Takes a residue list and returns a polymer ligand""" poly = cls(mcsa_id, pdb_id, resname='*P*', resid=None, chain=chain, structure=None, parent_site=parent_site, calculate_scores=False) poly.structure = Chain(chain) for res in reslist: if res.get_id() not in poly.structure: poly.structure.add(res.copy()) poly.similarity, poly.best_match = poly.get_similarity() poly.centrality = poly.get_centrality() return poly
def renumberChain(self, chainID, offset=0, modelID='0', filename="output.mmcif"): # get chain object chain = self.structure[modelID][chainID] # remove chain from model self.structure[modelID].detach_child(chainID) from Bio.PDB.Chain import Chain # create new chain newChain = Chain(chainID) for residue in chain: # remove residue, otherwise we cannot renumber it residue.detach_parent() rId = residue.id res_id = list(rId) res_id[1] = res_id[1] + offset if res_id[1] < 0: raise ValueError('Residue number cant be <= 0') residue.id = tuple(res_id) newChain.add(residue) self.structure[modelID].add(newChain) self.write(filename)
def initialize_res(residue): '''Creates a new structure containing a single amino acid. The type and geometry of the amino acid are determined by the argument, which has to be either a geometry object or a single-letter amino acid code. The amino acid will be placed into chain A of model 0.''' if isinstance( residue, Geo ): geo = residue else: geo=geometry(residue) segID=1 AA= geo.residue_name CA_N_length=geo.CA_N_length CA_C_length=geo.CA_C_length N_CA_C_angle=geo.N_CA_C_angle CA_coord= numpy.array([0.,0.,0.]) C_coord= numpy.array([CA_C_length,0,0]) N_coord = numpy.array([CA_N_length*math.cos(N_CA_C_angle*(math.pi/180.0)),CA_N_length*math.sin(N_CA_C_angle*(math.pi/180.0)),0]) N= Atom("N", N_coord, 0.0 , 1.0, " "," N", 0, "N") CA=Atom("CA", CA_coord, 0.0 , 1.0, " "," CA", 0,"C") C= Atom("C", C_coord, 0.0, 1.0, " ", " C",0,"C") ##Create Carbonyl atom (to be moved later) C_O_length=geo.C_O_length CA_C_O_angle=geo.CA_C_O_angle N_CA_C_O_diangle=geo.N_CA_C_O_diangle carbonyl=calculateCoordinates(N, CA, C, C_O_length, CA_C_O_angle, N_CA_C_O_diangle) O= Atom("O",carbonyl , 0.0 , 1.0, " "," O", 0, "O") if(AA=='G'): res=makeGly(segID, N, CA, C, O, geo) elif(AA=='A'): res=makeAla(segID, N, CA, C, O, geo) elif(AA=='S'): res=makeSer(segID, N, CA, C, O, geo) elif(AA=='C'): res=makeCys(segID, N, CA, C, O, geo) elif(AA=='V'): res=makeVal(segID, N, CA, C, O, geo) elif(AA=='I'): res=makeIle(segID, N, CA, C, O, geo) elif(AA=='L'): res=makeLeu(segID, N, CA, C, O, geo) elif(AA=='T'): res=makeThr(segID, N, CA, C, O, geo) elif(AA=='R'): res=makeArg(segID, N, CA, C, O, geo) elif(AA=='K'): res=makeLys(segID, N, CA, C, O, geo) elif(AA=='D'): res=makeAsp(segID, N, CA, C, O, geo) elif(AA=='E'): res=makeGlu(segID, N, CA, C, O, geo) elif(AA=='N'): res=makeAsn(segID, N, CA, C, O, geo) elif(AA=='Q'): res=makeGln(segID, N, CA, C, O, geo) elif(AA=='M'): res=makeMet(segID, N, CA, C, O, geo) elif(AA=='H'): res=makeHis(segID, N, CA, C, O, geo) elif(AA=='P'): res=makePro(segID, N, CA, C, O, geo) elif(AA=='F'): res=makePhe(segID, N, CA, C, O, geo) elif(AA=='Y'): res=makeTyr(segID, N, CA, C, O, geo) elif(AA=='W'): res=makeTrp(segID, N, CA, C, O, geo) else: res=makeGly(segID, N, CA, C, O, geo) cha= Chain('A') cha.add(res) mod= Model(0) mod.add(cha) struc= Structure('X') struc.add(mod) return struc
# nie jestem pewien dlaczego to nie działa. Pojawia się błąd: # AttributeError: 'module' object has no attribute 'array' from Bio import PDB from Bio.PDB import PDBParser, NeighborSearch, Superimposer, PDBIO from Bio.PDB.Atom import Atom from Bio.PDB.Residue import Residue from Bio.PDB.Chain import Chain from Bio.PDB.Model import Model from Bio.PDB.Structure import Structure my_structure = Structure('Cytosine') my_model = Model(0) my_chain = Chain('A') my_residue = Residue((' ', 1, ' '), 'C', ' ') atoms = [{ 'name': 'N1', 'coord': PDB.Atom.array([64.612, 45.818, 10.877], 'f'), 'bfactor': 42.59, 'occupancy': 1.0, 'altloc': ' ', 'fullname': 'N1', 'serial_number': 1 }, { 'name': 'C2', 'coord': PDB.Atom.array([65.472, 46.868, 10.634], 'f'), 'bfactor': 44.48, 'occupancy': 1.0, 'altloc': ' ', 'fullname': 'C2', 'serial_number': 2
def undo(cls, input, outfile=None, ligand_chain=None, residue_dict=None, write=True): if residue_dict is None: residue_dict = cls.extract_residue_dict(input) if not residue_dict: raise CombineChainError("No residue dict") parser = PDB.PDBParser(QUIET=True) structure = parser.get_structure( os.path.splitext(os.path.basename(input))[0], input) if len(structure.child_list) > 1: raise CombineChainError("Input has more than one model: %s" % structure.child_list) model = structure.child_list[0] chain_id_list = [c.id for c in model.child_list] chain_id_set = set(chain_id_list) if len(chain_id_list) != len(chain_id_set): raise CombineChainError("Non-unique chain IDs") if ligand_chain is not None: try: chain_id_set.remove(ligand_chain) except ValueError: raise CombineChainError("Ligand chain %s not found in %s", ligand_chain, input) if len(chain_id_set) > 1: logging.debug(input) raise CombineChainError("Input has more than one chain: %s" % model.child_list) receptor_chain = chain_id_set.pop() chain = model[receptor_chain] residue_list = sorted(residue_dict.keys()) for x, residue in enumerate(residue_list): data = residue_dict[residue] chainid = data['CHAIN'] try: next_change = residue_list[x + 1] except IndexError: next_change = None new_chain = Chain(chainid) model.add(new_chain) for res in chain.get_list(): resseq = res.id[1] if (next_change is None or resseq < next_change) and resseq >= residue: chain.detach_child(res.id) new_chain.add(res) if write: if outfile is None: fileparts = list(os.path.splitext(input)) fileparts.insert(1, "_split") outfile = "".join(fileparts) if not os.path.isabs(outfile): outdir = os.path.dirname(input) outfile = os.path.join(outdir, outfile) io = PDB.PDBIO() io.set_structure(structure) io.save(outfile) return outfile else: return structure assert False