def filter_before_build ( pdb_hierarchy, fmodel, geometry_restraints_manager, selection=None, params=None, verbose=True, log=sys.stdout) : """ Pick residues suitable for building alternate conformations - by default, this means no MolProbity/geometry outliers, good fit to map, no missing atoms, and no pre-existing alternates, but with significant difference density nearby. """ from mmtbx.validation import molprobity from mmtbx.rotamer import rotamer_eval import mmtbx.monomer_library.server from mmtbx import building from iotbx.pdb import common_residue_names_get_class from scitbx.array_family import flex if (selection is None) : selection = flex.bool(fmodel.xray_structure.scatterers().size(), True) pdb_atoms = pdb_hierarchy.atoms() assert (pdb_atoms.size() == fmodel.xray_structure.scatterers().size()) pdb_atoms.reset_i_seq() full_validation = molprobity.molprobity( pdb_hierarchy=pdb_hierarchy, fmodel=fmodel, geometry_restraints_manager=geometry_restraints_manager, outliers_only=False, rotamer_library="8000") if (verbose) : full_validation.show(out=log) multi_criterion = full_validation.as_multi_criterion_view() if (params is None) : params = libtbx.phil.parse(filter_params_str).extract() mon_lib_srv = mmtbx.monomer_library.server.server() two_fofc_map, fofc_map = building.get_difference_maps(fmodel=fmodel) residues = [] filters = params.discard_outliers make_sub_header("Identifying candidates for building", out=log) # TODO parallelize for chain in pdb_hierarchy.only_model().chains() : if (not chain.is_protein()) : continue for residue_group in chain.residue_groups() : atom_groups = residue_group.atom_groups() id_str = residue_group.id_str() i_seqs = residue_group.atoms().extract_i_seq() residue_sel = selection.select(i_seqs) if (not residue_sel.all_eq(True)) : continue if (len(atom_groups) > 1) : print >> log, " %s is already multi-conformer" % id_str continue atom_group = atom_groups[0] res_class = common_residue_names_get_class(atom_group.resname) if (res_class != "common_amino_acid") : print >> log, " %s: non-standard residue" % id_str continue missing_atoms = rotamer_eval.eval_residue_completeness( residue=atom_group, mon_lib_srv=mon_lib_srv, ignore_hydrogens=True) if (len(missing_atoms) > 0) : # residues modeled as pseudo-ALA are allowed by default; partially # missing sidechains are more problematic if ((building.is_stub_residue(atom_group)) and (not params.ignore_stub_residues)) : pass else : print >> log, " %s: missing or incomplete sidechain" % \ (id_str, len(missing_atoms)) continue validation = multi_criterion.get_residue_group_data(residue_group) is_outlier = is_validation_outlier(validation, params) if (is_outlier) : print >> log, " %s" % str(validation) continue if (params.use_difference_map) : i_seqs_no_hd = building.get_non_hydrogen_atom_indices(residue_group) map_stats = building.local_density_quality( fofc_map=fofc_map, two_fofc_map=two_fofc_map, atom_selection=i_seqs_no_hd, xray_structure=fmodel.xray_structure, radius=params.sampling_radius) if ((map_stats.number_of_atoms_below_fofc_map_level() == 0) and (map_stats.fraction_of_nearby_grid_points_above_cutoff()==0)) : if (verbose) : print >> log, " no difference density for %s" % id_str continue residues.append(residue_group.only_atom_group()) if (len(residues) == 0) : raise Sorry("No residues passed the filtering criteria.") print >> log, "" print >> log, "Alternate conformations will be tried for %d residue(s):" % \ len(residues) building.show_chain_resseq_ranges(residues, out=log, prefix=" ") print >> log, "" return residues
def __call__(self, atom_group, log, window_size=2, backbone_sample_angle=10, anneal=False, annealing_temperature=1000, use_chi1_sampling=False): import iotbx.pdb.hierarchy from scitbx.array_family import flex assert (atom_group is not None) pdb_hierarchy = self.pdb_hierarchy.deep_copy() xray_structure = self.xray_structure.deep_copy_scatterers() geometry_restraints_manager = self.geometry_restraints_manager # FIXME this doesn't work - can't recover the atom_group afterwards! #hd_sel = xray_structure.hd_selection() #n_hydrogen = hd_sel.count(True) #if (n_hydrogen > 0): # non_hd_sel = ~hd_sel # pdb_hierarchy = pdb_hierarchy.select(non_hd_sel) # xray_structure = xray_structure.select(non_hd_sel) # geometry_restraints_manager = geometry_restraints_manager.select( # non_hd_sel) pdb_atoms = pdb_hierarchy.atoms() pdb_atoms.reset_i_seq() isel = building.extract_iselection([atom_group]) atom_group = pdb_atoms[isel[0]].parent() atom_group_start = atom_group.detached_copy() needs_rebuild = not building.is_stub_residue(atom_group) residue_group = atom_group.parent() assert (len(residue_group.atom_groups()) == 1) sel_residues = building.get_window_around_residue( residue=atom_group, window_size=window_size) # get rid of sidechains for surrounding residues only adjacent_residues = [] for other_rg in sel_residues: if (other_rg != residue_group): adjacent_residues.append(other_rg) building.remove_sidechain_atoms(adjacent_residues) pdb_atoms = pdb_hierarchy.atoms() adjacent_trimmed_atom_names = pdb_atoms.extract_name() adjacent_trimmed_sel = pdb_atoms.extract_i_seq() xrs_adjacent_trimmed = xray_structure.select(adjacent_trimmed_sel) grm_adjacent_trimmed = geometry_restraints_manager.select( adjacent_trimmed_sel) pdb_atoms.reset_i_seq() # get rid of central sidechain and refine mainchain for entire window truncate = (not atom_group.resname in ["GLY", "ALA"]) # XXX PRO? if (truncate): building.remove_sidechain_atoms([atom_group]) pdb_atoms = pdb_hierarchy.atoms() all_mc_sel = pdb_atoms.extract_i_seq() xrs_mc = xrs_adjacent_trimmed.select(all_mc_sel) pdb_atoms.reset_i_seq() window_mc_sel = building.extract_iselection(sel_residues) selection = flex.bool(pdb_atoms.size(), False).set_selected(window_mc_sel, True) restraints_manager = grm_adjacent_trimmed.select(all_mc_sel) box = building.box_build_refine_base( xray_structure=xrs_mc, pdb_hierarchy=pdb_hierarchy, selection=selection, processed_pdb_file=None, target_map=self.target_map, geometry_restraints_manager=restraints_manager.geometry, d_min=self.d_min, out=null_out(), debug=True) box.restrain_atoms(selection=box.others_in_box, reference_sigma=0.1) box.real_space_refine(selection=box.selection_in_box) sites_new = box.update_original_coordinates() pdb_atoms.set_xyz(sites_new) # extend and replace existing residue. this is done in such a way that # the original atom ordering for the central residue is preserved, which # allows us to use the pre-existing geometry restraints instead of # re-calculating them every time this function is called. target_atom_group = self.ideal_dict[atom_group.resname.lower()].\ only_model().only_chain().only_residue_group().only_atom_group() new_atom_group_base = extend_sidechains.extend_residue( residue=atom_group, target_atom_group=target_atom_group, mon_lib_srv=self.mon_lib_srv) new_atom_group = iotbx.pdb.hierarchy.atom_group( resname=atom_group.resname) for atom in atom_group_start.atoms(): for new_atom in new_atom_group_base.atoms(): if (new_atom.name == atom.name): new_atom_group.append_atom(new_atom.detached_copy()) n_atoms_new = len(new_atom_group.atoms()) n_atoms_start = len(atom_group_start.atoms()) if (n_atoms_new != n_atoms_start): raise RuntimeError( ("Inconsistent atom counts for residue %s after " + "building (%d versus %d).") % (atom_group.id_str(), n_atoms_start, n_atoms_new)) rg = atom_group.parent() rg.remove_atom_group(atom_group) rg.append_atom_group(new_atom_group) pdb_atoms = pdb_hierarchy.atoms() pdb_atoms.reset_i_seq() new_names = pdb_atoms.extract_name() assert new_names.all_eq(adjacent_trimmed_atom_names) # get new box around this residue residue_sel = building.extract_iselection([new_atom_group]) selection = flex.bool(pdb_atoms.size(), False).set_selected(residue_sel, True) xrs_adjacent_trimmed.set_sites_cart(pdb_atoms.extract_xyz()) box = building.box_build_refine_base( xray_structure=xrs_adjacent_trimmed, pdb_hierarchy=pdb_hierarchy, selection=selection, processed_pdb_file=None, target_map=self.target_map, geometry_restraints_manager=grm_adjacent_trimmed.geometry, d_min=self.d_min, out=null_out(), debug=True) # place sidechain using mmtbx.refinement.real_space.fit_residue if ((atom_group.resname in rotatable_sidechain_atoms) and (use_chi1_sampling)): fit_chi1_simple(residue=box.only_residue(), unit_cell=box.unit_cell_box, target_map=box.target_map_box, rotamer_eval=self.rotamer_eval) box.update_sites_from_pdb_atoms() else: box.fit_residue_in_box(backbone_sample_angle=backbone_sample_angle) if (anneal): box.anneal(start_temperature=annealing_temperature) #box.real_space_refine() sites_new = box.update_original_coordinates() pdb_hierarchy.atoms().set_xyz(sites_new) return building.atom_group_as_hierarchy(new_atom_group)
def __call__ (self, atom_group, log, window_size=2, backbone_sample_angle=10, anneal=False, annealing_temperature=1000, use_chi1_sampling=False) : import iotbx.pdb.hierarchy from scitbx.array_family import flex assert (atom_group is not None) pdb_hierarchy = self.pdb_hierarchy.deep_copy() xray_structure = self.xray_structure.deep_copy_scatterers() geometry_restraints_manager = self.geometry_restraints_manager # FIXME this doesn't work - can't recover the atom_group afterwards! #hd_sel = xray_structure.hd_selection() #n_hydrogen = hd_sel.count(True) #if (n_hydrogen > 0) : # non_hd_sel = ~hd_sel # pdb_hierarchy = pdb_hierarchy.select(non_hd_sel) # xray_structure = xray_structure.select(non_hd_sel) # geometry_restraints_manager = geometry_restraints_manager.select( # non_hd_sel) pdb_atoms = pdb_hierarchy.atoms() pdb_atoms.reset_i_seq() isel = building.extract_iselection([atom_group]) atom_group = pdb_atoms[isel[0]].parent() atom_group_start = atom_group.detached_copy() needs_rebuild = not building.is_stub_residue(atom_group) residue_group = atom_group.parent() assert (len(residue_group.atom_groups()) == 1) sel_residues = building.get_window_around_residue( residue=atom_group, window_size=window_size) # get rid of sidechains for surrounding residues only adjacent_residues = [] for other_rg in sel_residues : if (other_rg != residue_group) : adjacent_residues.append(other_rg) building.remove_sidechain_atoms(adjacent_residues) pdb_atoms = pdb_hierarchy.atoms() adjacent_trimmed_atom_names = pdb_atoms.extract_name() adjacent_trimmed_sel = pdb_atoms.extract_i_seq() xrs_adjacent_trimmed = xray_structure.select(adjacent_trimmed_sel) grm_adjacent_trimmed = geometry_restraints_manager.select( adjacent_trimmed_sel) pdb_atoms.reset_i_seq() # get rid of central sidechain and refine mainchain for entire window truncate = (not atom_group.resname in ["GLY","ALA"]) # XXX PRO? if (truncate) : building.remove_sidechain_atoms([ atom_group ]) pdb_atoms = pdb_hierarchy.atoms() all_mc_sel = pdb_atoms.extract_i_seq() xrs_mc = xrs_adjacent_trimmed.select(all_mc_sel) pdb_atoms.reset_i_seq() window_mc_sel = building.extract_iselection(sel_residues) selection = flex.bool(pdb_atoms.size(), False).set_selected(window_mc_sel, True) restraints_manager = grm_adjacent_trimmed.select(all_mc_sel) box = building.box_build_refine_base( xray_structure=xrs_mc, pdb_hierarchy=pdb_hierarchy, selection=selection, processed_pdb_file=None, target_map=self.target_map, geometry_restraints_manager=restraints_manager.geometry, d_min=self.d_min, out=null_out(), debug=True) box.restrain_atoms( selection=box.others_in_box, reference_sigma=0.1) box.real_space_refine(selection=box.selection_in_box) sites_new = box.update_original_coordinates() pdb_atoms.set_xyz(sites_new) # extend and replace existing residue. this is done in such a way that # the original atom ordering for the central residue is preserved, which # allows us to use the pre-existing geometry restraints instead of # re-calculating them every time this function is called. new_atom_group_base = extend_sidechains.extend_residue( residue=atom_group, ideal_dict=self.ideal_dict, hydrogens=False, mon_lib_srv=self.mon_lib_srv, match_conformation=True) new_atom_group = iotbx.pdb.hierarchy.atom_group(resname=atom_group.resname) for atom in atom_group_start.atoms() : for new_atom in new_atom_group_base.atoms() : if (new_atom.name == atom.name) : new_atom_group.append_atom(new_atom.detached_copy()) n_atoms_new = len(new_atom_group.atoms()) n_atoms_start = len(atom_group_start.atoms()) if (n_atoms_new != n_atoms_start) : raise RuntimeError(("Inconsistent atom counts for residue %s after "+ "building (%d versus %d).") % (atom_group.id_str(), n_atoms_start, n_atoms_new)) rg = atom_group.parent() rg.remove_atom_group(atom_group) rg.append_atom_group(new_atom_group) pdb_atoms = pdb_hierarchy.atoms() pdb_atoms.reset_i_seq() new_names = pdb_atoms.extract_name() assert new_names.all_eq(adjacent_trimmed_atom_names) # get new box around this residue residue_sel = building.extract_iselection([ new_atom_group ]) selection = flex.bool(pdb_atoms.size(), False).set_selected(residue_sel, True) xrs_adjacent_trimmed.set_sites_cart(pdb_atoms.extract_xyz()) box = building.box_build_refine_base( xray_structure=xrs_adjacent_trimmed, pdb_hierarchy=pdb_hierarchy, selection=selection, processed_pdb_file=None, target_map=self.target_map, geometry_restraints_manager=grm_adjacent_trimmed.geometry, d_min=self.d_min, out=null_out(), debug=True) # place sidechain using mmtbx.refinement.real_space.fit_residue if ((atom_group.resname in rotatable_sidechain_atoms) and (use_chi1_sampling)) : fit_chi1_simple( residue=box.only_residue(), unit_cell=box.unit_cell_box, target_map=box.target_map_box, rotamer_eval=self.rotamer_eval) box.update_sites_from_pdb_atoms() else : box.fit_residue_in_box(backbone_sample_angle=backbone_sample_angle) if (anneal) : box.anneal(start_temperature=annealing_temperature) #box.real_space_refine() sites_new = box.update_original_coordinates() pdb_hierarchy.atoms().set_xyz(sites_new) return building.atom_group_as_hierarchy(new_atom_group)