Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AtomicContactCountFilter.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 sw=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file protocols/protein_interface_design/filters/AtomicContactCountFilter.cc
11 /// @brief
12 /// @author Alex Ford (fordas@uw.edu)
13 
14 #include <algorithm>
15 #include <iterator>
16 
17 #include <boost/foreach.hpp>
18 #include <boost/algorithm/string/join.hpp>
19 
20 #include <ObjexxFCL/FArray1D.hh>
21 #include <basic/Tracer.hh>
22 
25 #include <core/pose/Pose.hh>
30 #include <core/types.hh>
32 #include <utility/tag/Tag.hh>
36 
41 
45 
46 namespace protocols {
47 namespace protein_interface_design {
48 namespace filters {
49 
50 static basic::Tracer TR("protocols.protein_interface_design.filters.AtomicContactCountFilter");
51 
52 
54  protocols::filters::Filter( "AtomicContactCount" ),
55  distance_cutoff_(4.5)
56 {
58 }
59 
61  Filter( "AtomicContactCount" ),
62  distance_cutoff_(distance_cutoff)
63 {
65 }
66 
68  Filter(src),
69  task_factory_(src.task_factory_),
70  distance_cutoff_(src.distance_cutoff_),
71  filter_mode_(src.filter_mode_),
72  normalize_by_sasa_(src.normalize_by_sasa_),
73  jump_(src.jump_),
74  sym_dof_name_(src.sym_dof_name_)
75 {
76 }
77 
79 
82 
84 {
85  task_factory_ = task_factory;
86  jump_ = 0;
87  sym_dof_name_ = "";
88  normalize_by_sasa_ = false;
89 
90  filter_mode_ = ALL;
91 }
92 
93 void AtomicContactCountFilter::initialize_cross_jump(core::Size jump, std::string sym_dof_name, core::pack::task::TaskFactoryOP task_factory, bool normalize_by_sasa)
94 {
95  task_factory_ = task_factory;
96  jump_ = jump;
97  sym_dof_name_ = sym_dof_name;
98  normalize_by_sasa_ = normalize_by_sasa;
99 
101 }
102 
103 void AtomicContactCountFilter::initialize_cross_chain(core::pack::task::TaskFactoryOP task_factory, bool normalize_by_sasa, bool detect_chains_for_interface)
104 {
105  task_factory_ = task_factory;
106  jump_ = 0;
107  sym_dof_name_ = "";
108  normalize_by_sasa_ = normalize_by_sasa;
109 
110  filter_mode_ = detect_chains_for_interface ? CROSS_CHAIN_DETECTED : CROSS_CHAIN_ALL;
111 }
112 
114  utility::tag::TagPtr const tag,
118  core::pose::Pose const & /*pose*/
119 )
120 {
121  distance_cutoff_ = tag->getOption< core::Real >( "distance", 4.5 );
122 
123  std::string specified_mode = tag->getOption< std::string >( "partition", "none" );
124  std::string specified_normalized_by_sasa = tag->getOption< std::string >( "normalize_by_sasa", "0" );
125 
126  if (specified_mode == "none")
127  {
129  }
130  else if (specified_mode == "jump")
131  {
133  tag->getOption< core::Size >( "jump", 1 ),
134  tag->getOption< std::string >( "sym_dof_name", "" ),
136  specified_normalized_by_sasa != "0");
137  }
138  else if (specified_mode == "chain")
139  {
140 
143  specified_normalized_by_sasa != "0",
144  specified_normalized_by_sasa == "detect_by_task");
145  }
146 
147  if (filter_mode_ == ALL && specified_normalized_by_sasa != "0")
148  {
149  TR.Error << "Must specify jump or chain partition mode in AtomicContactFilter with normalize_by_sasa: " << tag << std::endl;
150  utility_exit_with_message("Must specify jump or chain partition mode in AtomicContactFilter with normalize_by_sasa.");
151  }
152 
153  TR.Debug << "Parsed AtomicContactCount filter: <AtomicContactCount" <<
154  " distance=" << distance_cutoff_ <<
155  " jump=" << jump_ <<
156  " normalize_by_sasa=" << (normalize_by_sasa_ ? (filter_mode_ != CROSS_CHAIN_DETECTED ? "1" : "detect_by_task") : "0") <<
157  " />" << std::endl;
158 }
159 
161 {
162  // Create map of target residues using taskoperation
164 
165  if ( task_factory_ != 0 )
166  {
167  task = task_factory_->create_task_and_apply_taskoperations( pose );
168  TR.Debug << "Initializing from packer task." << std::endl;
169  }
170  else
171  {
172  TR.Debug << "No packer task specified, using default task." << std::endl;
173  }
174 
175  bool symmetric = core::pose::symmetry::is_symmetric( pose );
176 
177  if ( symmetric )
178  {
180  }
181 
182  // Create lookup of target residues
184  for (core::Size resi = 1; resi <= pose.n_residue(); resi++)
185  {
186  if( task->pack_residue(resi) )
187  {
188  target.push_back(resi);
189  }
190  }
191 
192  if (TR.Debug.visible())
193  {
194  TR.Debug << "Targets from task: ";
195  std::copy(target.begin(), target.end(), std::ostream_iterator<core::Size>(TR.Debug, ","));
196  TR.Debug << std::endl;
197  }
198 
199  // Divide residues into partitions based on filter mode
200  utility::vector1<core::Size> residue_partition;
201  utility::vector1<core::Size> target_jumps;
202 
203  if (filter_mode_ == ALL)
204  {
205  TR.Debug << "Partitioning by residue number." << std::endl;
206  // Each residue is a separate partition
207  for (core::Size i = 1; i <= pose.total_residue(); ++i)
208  {
209  residue_partition.push_back(i);
210  }
211  }
213  {
214  TR.Debug << "Partitioning by residue chain." << std::endl;
215 
216  for (core::Size i = 1; i <= pose.total_residue(); ++i)
217  {
218  residue_partition.push_back(pose.chain(i));
219  }
220  }
221  else if (filter_mode_ == CROSS_JUMP)
222  {
223  TR.Debug << "Partitioning by jump." << std::endl;
224 
225  // Lookup symmetry-aware jump identifier
226  if ( sym_dof_name_ != "" ) {
227  target_jumps.push_back( core::pose::symmetry::sym_dof_jump_num( pose, sym_dof_name_ ) );
228  } else if (!symmetric) {
229  target_jumps.push_back( jump_ );
230  } else {
231  // all slidable jumps
232  Size nslidedofs = core::pose::symmetry::symmetry_info(pose)->num_slidablejumps();
233  for (Size j = 1; j <= nslidedofs; j++)
234  target_jumps.push_back( core::pose::symmetry::get_sym_aware_jump_num(pose, j ) );
235  }
236 
237  // Partition pose by jump
238  ObjexxFCL::FArray1D<bool> jump_partition ( pose.total_residue(), false );
239  if (!symmetric) {
240  pose.fold_tree().partition_by_jump( target_jumps[1], jump_partition );
241  } else {
243  core::pose::symmetry::symmetry_info(pose), jump_partition );
244  }
245 
246  for (core::Size i = 1; i <= pose.total_residue(); ++i)
247  {
248  residue_partition.push_back(jump_partition(i));
249  }
250  }
251 
252  if (TR.Trace.visible())
253  {
254  TR.Trace << "Residue partitions from task: ";
255  for (core::Size i = 1; i <= residue_partition.size(); ++i)
256  {
257  TR.Trace << i << ":" << residue_partition[i] << ",";
258  }
259  TR.Trace << std::endl;
260  }
261 
262  // Count all cross-partition contacts
263  core::Size contact_count = 0;
264  utility::vector1<bool> indy_resis;
265  if ( symmetric )
266  {
268  indy_resis = symm_info->independent_residues();
269  }
270 
271  for (core::Size i = 1; i <= target.size(); i++)
272  {
273  if ( symmetric && (filter_mode_ == CROSS_JUMP) )
274  {
275  // TODO: ALEX FORD: Fix so that can take multiple tasks. One that specifies the residues for which counts are analyzed and the other task specifies all of the other residues with which to look for interactions.
276  // The residue_partition logic works in this case, but may not make sense for symmetric assemblies in cross_chain mode.
277  // For multicomponent systems we only want to count contacts from residues in the primary subunit corresponding to the user-specified symdof
278  if (!indy_resis[target[i]] || residue_partition[target[i]]) continue;
279  }
280  for (core::Size j = i+1; j <= target.size(); j++)
281  {
282  if (residue_partition[target[i]] != residue_partition[target[j]])
283  {
284  core::conformation::Residue const & residue_i = pose.residue(target[i]);
285  core::conformation::Residue const & residue_j = pose.residue(target[j]);
286 
287  for (core::Size atom_i = residue_i.first_sidechain_atom(); atom_i <= residue_i.nheavyatoms(); atom_i++)
288  {
289  if (residue_i.atom_type(atom_i).element() != "C")
290  {
291  continue;
292  }
293 
294  for (core::Size atom_j = residue_j.first_sidechain_atom(); atom_j <= residue_j.nheavyatoms(); atom_j++)
295  {
296  if (residue_j.atom_type(atom_j).element() != "C")
297  {
298  continue;
299  }
300 
301  if (residue_i.xyz(atom_i).distance(residue_j.xyz(atom_j)) <= distance_cutoff_)
302  {
303  TR.Debug << "select (resi " << target[i] << " and name " << residue_i.atom_name(atom_i) << ") + (resi " << target[j] << "and name " << residue_j.atom_name(atom_j) << ")" << std::endl;
304  contact_count += 1;
305  }
306  }
307  }
308  }
309  }
310  }
311 
312  TR.Debug << "Found cross partition contacts:" << contact_count << std::endl;
313 
314  if (normalize_by_sasa_)
315  {
316  TR.Debug << "Normalizing cross partition contacts by sasa." << std::endl;
317 
318  core::Real interface_sasa;
319 
320  if (filter_mode_ == ALL)
321  {
322  utility_exit_with_message("AtomicContactCount filter unable to normalize by sasa in all-contact mode.");
323  }
324  else if (filter_mode_ == CROSS_CHAIN_DETECTED ||
326  {
327  std::set<core::Size> interface_chains;
328 
330  {
331  // Detect chains containing target residues.
332  for (core::Size i = 1; i <= target.size(); ++i)
333  {
334  interface_chains.insert(pose.chain(target[i]));
335  }
336  }
337  else if (filter_mode_ == CROSS_CHAIN_ALL)
338  {
339  // Add all pose chains
340  for (core::Size i = 1; i <= pose.conformation().num_chains(); ++i)
341  {
342  interface_chains.insert(i);
343  }
344  }
345 
346  TR.Debug << "Identified interface chains:";
347  std::copy(interface_chains.begin(), interface_chains.end(), std::ostream_iterator<core::Size>(TR.Debug, ","));
348  TR.Debug << std::endl;
349 
350  if (interface_chains.size() != pose.conformation().num_chains())
351  {
352  TR.Debug << "Pruning target pose to interface chains.";
353  core::pose::Pose interface_pose(pose);
354 
355  // Delete chains not in the chain list in reverse order in order to preserve chain number during deletion.
356  for (core::Size i = interface_pose.conformation().num_chains(); i >= 1; --i)
357  {
358  if (interface_chains.count(i) == 0)
359  {
360  TR.Debug << "Pruning target pose chain: " << i <<
361  "[" << interface_pose.conformation().chain_begin( i ) <<
362  "]" << interface_pose.conformation().chain_end( i ) << std::endl;
363 
364  interface_pose.conformation().delete_residue_range_slow(
365  interface_pose.conformation().chain_begin( i ),
366  interface_pose.conformation().chain_end( i ));
367  }
368  }
369 
370  if (TR.Trace.visible())
371  {
372  TR.Trace << "Pruned pose:" << std::endl << interface_pose << std::endl;
373  }
374 
375  // Calculate sasa across all remaining jumps
377  utility::vector1<core::Size> sasa_jumps;
378  for (core::Size i = 1; i <= interface_pose.num_jump(); ++i)
379  {
380  TR.Debug << "Adding jump to sasa filter: " << i << std::endl;
381  sasa_jumps.push_back(i);
382  }
383  sasa_filter.jumps(sasa_jumps);
384 
385  interface_sasa = sasa_filter.compute(interface_pose);
386  }
387  else
388  {
389  TR.Debug << "Using original pose, interface chains include entire pose." << std::endl;
390 
391  // Calculate sasa across all jumps
393  utility::vector1<core::Size> sasa_jumps;
394  for (core::Size i = 1; i <= pose.num_jump(); ++i)
395  {
396  TR.Debug << "Adding jump to sasa filter: " << i << std::endl;
397  sasa_jumps.push_back(i);
398  }
399  sasa_filter.jumps(sasa_jumps);
400  interface_sasa = sasa_filter.compute(pose);
401  }
402  }
403  else if (filter_mode_ == CROSS_JUMP)
404  {
405  TR.Debug << "Normalizing on jump." << std::endl;
406 
407  // Calculate sasa across the specified jump
409 
410  TR.Debug << "Adding jump to sasa filter: " << target_jumps[1] << std::endl;
411  if ( symmetric && (sym_dof_name_ != ""))
412  {
413  sasa_filter.sym_dof_names(sym_dof_name_);
414  }
415  else
416  {
417  sasa_filter.jumps(target_jumps);
418  }
419  interface_sasa = sasa_filter.compute(pose);
420  }
421 
422  TR.Debug << "Calculated interface sasa: " << interface_sasa << std::endl;
423 
424  if (interface_sasa != 0)
425  {
426  return contact_count / interface_sasa;
427  }
428  else
429  {
430  return 0;
431  }
432  }
433  else
434  {
435  return contact_count;
436  }
437 }
438 
441 
443 AtomicContactCountFilterCreator::keyname() const { return "AtomicContactCount"; }
444 
445 }
446 }
447 }