Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ShapeComplementarityFilter.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 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/filters/ShapeComplementarityFilter.cc
11 /// @brief Filter structures by shape complementarity and/or interface area
12 /// @author Luki Goldschmidt (luki@mbi.ucla.edu)
13 
14 // Unit Headers
17 
18 // Project Headers
19 #include <core/types.hh>
20 #include <core/pose/Pose.hh>
25 
26 // Utility headers
27 #include <utility/vector1.fwd.hh>
28 #include <utility/exit.hh>
29 #include <basic/Tracer.hh>
31 #include <core/pose/selection.hh>
32 #include <basic/options/option.hh>
33 #include <basic/options/keys/matdes.OptionKeys.gen.hh>
35 #include <protocols/jd2/Job.hh>
37 
38 // Parser headers
40 #include <utility/tag/Tag.hh>
41 
42 #include <utility/vector0.hh>
43 #include <utility/vector1.hh>
44 
45 
46 //// C++ headers
47 static basic::Tracer tr("protocols.filters.ShapeComplementarityFilter");
48 
49 namespace protocols {
50 namespace simple_filters {
51 
52 // @brief default constructor
54  Filter( "ShapeComplementarity" ),
55  filtered_sc_( 0.50 ),
56  filtered_area_( 250 ),
57  jump_id_( 1 ),
58  quick_( false ),
59  verbose_( false ),
60  residues1_( ),
61  residues2_( ),
62  sym_dof_name_(""),
63  multicomp_(false)
64 {}
65 
66 
67 // @brief constructor with arguments
68 ShapeComplementarityFilter::ShapeComplementarityFilter( Real const & filtered_sc, Real const & filtered_area,
69  Size const & jump_id, Size const & quick, Size const & verbose):
70  Filter( "ShapeComplementarity" ),
71  filtered_sc_( filtered_sc ),
72  filtered_area_( filtered_area ),
73  jump_id_( jump_id ),
74  quick_( quick ),
75  verbose_( verbose ),
76  residues1_( ),
77  residues2_( ),
78  sym_dof_name_("")
79 {}
80 
81 // @brief copy constructor
83  Super( rval ),
84  filtered_sc_( rval.filtered_sc_ ),
85  filtered_area_( rval.filtered_area_ ),
86  jump_id_( rval.jump_id_ ),
87  quick_( rval.quick_ ),
88  verbose_( rval.verbose_ ),
89  residues1_( rval.residues1_ ),
90  residues2_( rval.residues2_ ),
91  sym_dof_name_( rval.sym_dof_name_ )
92 {}
93 
97 void ShapeComplementarityFilter::quick( Size const & quick ) { quick_ = quick; }
103 
104 /// @brief
106 {
107  if(scc_.GetResults().valid)
108  return 1;
109 
110  if(!scc_.Init())
111  return 0;
112  if(quick_)
113  scc_.settings.density = 5.0;
114  scc_.Reset();
115 
116  bool symm = core::pose::symmetry::is_symmetric( pose );
117  Real nsubs_scalefactor = 1.0;
118 
119  if (!residues1_.empty() && !residues2_.empty()) {
121  r != residues1_.end(); ++r)
122  scc_.AddResidue(0, pose.residue(*r));
123 
125  r != residues2_.end(); ++r)
126  scc_.AddResidue(1, pose.residue(*r));
127 
128  if(!scc_.Calc())
129  return 0;
130 
131  } else if (!symm) {
132 
133  if(!scc_.Calc( pose, jump_id_ ))
134  return 0;
135 
136  } else {
137  if ( multicomp_ ) {
138  // MULTI COMPONENT SYMM
139  int sym_aware_jump_id = 0;
140  runtime_assert( sym_dof_name() != "" );
141  sym_aware_jump_id = core::pose::symmetry::sym_dof_jump_num( pose, sym_dof_name() );
142 
143  tr << "Using jump_id " << sym_aware_jump_id << " to partition pose" << std::endl;
144  if(!scc_.Calc( pose, sym_aware_jump_id ))
145  return 0;
146 
148  nsubs_scalefactor = (Real) subs.size() ;
149  } else {
150  // SINGLE COMPONENT SYMM
151  ObjexxFCL::FArray1D_bool is_upstream ( pose.total_residue(), false );
152  utility::vector1<Size> sym_aware_jump_ids;
153 
154  if ( sym_dof_name() != "" ) {
155  sym_aware_jump_ids.push_back( core::pose::symmetry::sym_dof_jump_num( pose, sym_dof_name() ) );
156  } else {
157  // all slidable jumps
158  Size nslidedofs = core::pose::symmetry::symmetry_info(pose)->num_slidablejumps();
159  for (Size j = 1; j <= nslidedofs; j++)
160  sym_aware_jump_ids.push_back( core::pose::symmetry::get_sym_aware_jump_num(pose, j ) );
161  }
162 
163  // partition & fill residueX_ vectors
164  core::pose::symmetry::partition_by_symm_jumps( sym_aware_jump_ids, pose.fold_tree(), core::pose::symmetry::symmetry_info(pose), is_upstream );
165  Size nupstream=0;
166  for (int i=1; i<=pose.total_residue(); ++i) {
167  if (pose.residue(i).aa() == core::chemical::aa_vrt) continue;
168  scc_.AddResidue(is_upstream(i)?0:1, pose.residue(i));
169  if (is_upstream(i)) nupstream++;
170  }
171  // scalefactor
172  nsubs_scalefactor = (Real)( nupstream / core::pose::symmetry::symmetry_info(pose)->get_nres_subunit() );
173 
174  if(!scc_.Calc())
175  return 0;
176  }
177  }
178 
180  if(verbose_) {
181 
182  // Verbose view
183  tr << "==================================================" << std::endl;
184  tr << std::endl;
185  for(int i = 0; i <= 2; i++) {
186  if(i < 2)
187  tr << "Molecule " << (i+1) << ":" << std::endl;
188  else
189  tr << "Total/Average for both molecules:" << std::endl;
190 
191  tr << " Total Atoms: " << r.surface[i].nAtoms << std::endl;
192  tr << " Buried Atoms: " << r.surface[i].nBuriedAtoms << std::endl;
193  tr << " Blocked Atoms: " << r.surface[i].nBlockedAtoms << std::endl;
194  tr << " Total Dots: " << r.surface[i].nAllDots << std::endl;
195  tr << " Trimmed Surface Dots: " << r.surface[i].nTrimmedDots << std::endl;
196  tr << " Trimmed Area: " << r.surface[i].trimmedArea << " (avg) " << std::endl;
197  tr << std::endl;
198  }
199  tr << std::endl;
200 
201  for(int i = 0; i <= 2; i++) {
202  if(i < 2)
203  tr << "Molecule " << (i+1) << "->" << ((i+1)%2+1) << ": " << std::endl;
204  else
205  tr << "Average for both molecules:" << std::endl;
206  tr << " Mean Separation: " << r.surface[i].d_mean << std::endl;
207  tr << " Median Separation: " << r.surface[i].d_median << std::endl;
208  tr << " Mean Shape Compl.: " << r.surface[i].s_mean << std::endl;
209  tr << " Median Shape Compl.: " << r.surface[i].s_median << std::endl;
210  tr << std::endl;
211  }
212 
213  }
214 
215  tr << "Shape complementarity: " << r.sc << std::endl;
216  tr << "Interface area: " << r.area << std::endl;
217  if ( nsubs_scalefactor != 1) {
218  tr << "Area per monomer: " << ( (core::Real) r.area / nsubs_scalefactor ) << std::endl ;
219  }
220  tr << "Interface seperation: " << r.distance << std::endl;
221 
222  return 1;
223 }
224 
225 /// @brief
227 {
228  scc_.Reset(); // Unfortunately, this line had to be added. While reducing
229  // efficiency in normal use cases by forcing recalculation of
230  // presumably the same value, it is necessary for greedy
231  // optimization using the GreedyOptMutationMover, which calls
232  // the report_sm() function of filters directly. -Neil King
233  if(compute( pose )) {
234  if ( write_int_area_ ) {
236  std::string column_header = this->get_user_defined_name() + "_int_area";
237  core::Real int_area = scc_.GetResults().area ;
238 
239  // symmetric scalefactor
241  if ( multicomp_ ) {
243  int_area /= (Real) subs.size() ;
244  } else {
245  ObjexxFCL::FArray1D_bool is_upstream ( pose.total_residue(), false );
246  utility::vector1<Size> sym_aware_jump_ids;
247  if ( sym_dof_name() != "" ) {
248  sym_aware_jump_ids.push_back( core::pose::symmetry::sym_dof_jump_num( pose, sym_dof_name() ) );
249  } else {
250  Size nslidedofs = core::pose::symmetry::symmetry_info(pose)->num_slidablejumps();
251  for (Size j = 1; j <= nslidedofs; j++) sym_aware_jump_ids.push_back( core::pose::symmetry::get_sym_aware_jump_num(pose, j ) );
252  }
253  core::pose::symmetry::partition_by_symm_jumps( sym_aware_jump_ids, pose.fold_tree(), core::pose::symmetry::symmetry_info(pose), is_upstream );
254  Size nupstream=0;
255  for (int i=1; i<=pose.total_residue(); ++i) {
256  if (pose.residue(i).aa() == core::chemical::aa_vrt) continue;
257  if (is_upstream(i)) nupstream++;
258  }
259  int_area /= (Real)( nupstream / core::pose::symmetry::symmetry_info(pose)->get_nres_subunit() );
260  }
261  }
262  job->add_string_real_pair(column_header, int_area );
263  }
264  return scc_.GetResults().sc;
265  }
266  return -1;
267 }
268 
269 // @brief returns true if the given pose passes the filter, false otherwise.
270 // In this case, the test is whether the give pose has high enough shape
271 // complementarity.
272 bool ShapeComplementarityFilter::apply( Pose const & pose ) const
273 {
274  scc_.Reset();
275 
276  if(!compute( pose ))
277  return false;
278 
279  Real sc = scc_.GetResults().sc;
280  Real area = scc_.GetResults().area;
281 
282  if( sc < filtered_sc_ ) {
283  tr << "Filter failed current < threshold sc: " << sc << " < " << filtered_sc_ << std::endl;
284  return false;
285  }
286 
287  if( area < filtered_area_ ) {
288  tr << "Filter failed current < threshold interface area: " << area << " < " << filtered_area_ << std::endl;
289  return false;
290  }
291 
292  tr << "Successfully filtered: " << sc << std::endl;
293  return true;
294 } // apply_filter
295 
296 /// @brief parse xml
297 void
299  TagPtr const tag,
300  DataMap &,
301  filters::Filters_map const &,
302  Movers_map const &,
303  Pose const & pose )
304 {
305  filtered_sc_ = tag->getOption<Real>( "min_sc", 0.50 );
306  filtered_area_ = tag->getOption<Real>( "min_interface", 0 );
307  verbose_ = tag->getOption<Size>( "verbose", false );
308  quick_ = tag->getOption<Size>( "quick", false );
309  jump_id_ = tag->getOption<Size>( "jump", 1 );
310  write_int_area_ = tag->getOption<bool>( "write_int_area", false );
311  sym_dof_name(tag->getOption<std::string>( "sym_dof_name", "" ));
312  multicomp( tag->getOption< bool >("multicomp", 0) );
313 
314  if(tag->hasOption("residues1")) {
315  residues1_ = core::pose::get_resnum_list(tag, "residues1", pose);
316  if(residues1_.empty())
317  tr.Warning << "Failed to parse residue range: " << tag->getOption<std::string> ("residues1") << ". Using default." << std::endl;
318  }
319  if(tag->hasOption("residues2")) {
320  residues2_ = core::pose::get_resnum_list(tag, "residues2", pose);
321  if(residues2_.empty())
322  tr.Warning << "Failed to parse residue range: " << tag->getOption<std::string> ("residues2") << ". Using default." << std::endl;
323  }
324 
325  tr.Info << "Structures with shape complementarity < " << filtered_sc_ << ", interface area < " <<
326  filtered_area_ << " A^2 will be filtered." << std::endl;
327 
328  if(quick_)
329  tr.Info << "Calculating shape complementarity in quick mode with less accuracy." << std::endl;
330  if(!residues1_.empty() && !residues2_.empty()) {
331  tr.Info << "Using residues for molecule surface (rosetta numbering):" << std::endl;
332  tr.Info << " Surface 1: ";
333  for(utility::vector1<Size>::const_iterator r = residues1_.begin(); r != residues1_.end(); ++r)
334  tr.Info << (r == residues1_.begin() ? "" : ", ") << *r;
335  tr.Info << std::endl;
336  tr.Info << " Surface 2: ";
337  for(utility::vector1<Size>::const_iterator r = residues2_.begin(); r != residues2_.end(); ++r)
338  tr.Info << (r == residues2_.begin() ? "" : ", ") << *r;
339  tr.Info << std::endl;
340  } else {
341  if(!residues1_.empty() || !residues2_.empty())
342  tr.Warning << "Ignoring residue range selection since residues" << (residues1_.empty() ? 1 : 2) << " is empty." << std::endl;
343  if(jump_id_ != 1)
344  tr.Info << "Using Jump ID " << jump_id_ << " to define surfaces." << std::endl;
345  }
346 }
347 
348 void ShapeComplementarityFilter::parse_def( utility::lua::LuaObject const & def,
349  utility::lua::LuaObject const & /*score_fxns*/,
350  utility::lua::LuaObject const & /*tasks*/ ) {
351  filtered_sc_ = def["min_sc"] ? def["min_sc"].to<Real>() : 0.50;
352  filtered_area_ = def["min_interface"] ? def["min_interface"].to<Real>() : 0;
353  verbose_ = def["verbose"] ? def["verbose"].to<Size>() : 0;
354  quick_ = def["quick"] ? def["quick"].to<Size>() : 0;
355  jump_id_ = def["jump"] ? def["jump"].to<Size>() : 1;
356  write_int_area_ = def["write_int_area"] ? def["write_int_area"].to<bool>() : false;
357 
358  if(def["residues1"] ) {
359  for (utility::lua::LuaIterator i=def["residues1"].begin(), end; i != end; ++i) {
360  residues1_.push_back( (*i).to<core::Size>() );
361  }
362  if(residues1_.empty())
363  tr.Warning << "Failed to parse residue1 range, using default." << std::endl;
364  }
365  if(def["residues2"] ) {
366  for (utility::lua::LuaIterator i=def["residues2"].begin(), end; i != end; ++i) {
367  residues2_.push_back( (*i).to<core::Size>() );
368  }
369  if(residues2_.empty())
370  tr.Warning << "Failed to parse residue2 range, using default." << std::endl;
371  }
372 
373  tr.Info << "Structures with shape complementarity < " << filtered_sc_ << ", interface area < " <<
374  filtered_area_ << " A^2 will be filtered." << std::endl;
375 
376  if(quick_)
377  tr.Info << "Calculating shape complementarity in quick mode with less accuracy." << std::endl;
378  if(!residues1_.empty() && !residues2_.empty()) {
379  tr.Info << "Using residues for molecule surface (rosetta numbering):" << std::endl;
380  tr.Info << " Surface 1: ";
381  for(utility::vector1<Size>::const_iterator r = residues1_.begin(); r != residues1_.end(); ++r)
382  tr.Info << (r == residues1_.begin() ? "" : ", ") << *r;
383  tr.Info << std::endl;
384  tr.Info << " Surface 2: ";
385  for(utility::vector1<Size>::const_iterator r = residues2_.begin(); r != residues2_.end(); ++r)
386  tr.Info << (r == residues2_.begin() ? "" : ", ") << *r;
387  tr.Info << std::endl;
388  } else {
389  if(!residues1_.empty() || !residues2_.empty())
390  tr.Warning << "Ignoring residue range selection since residues" << (residues1_.empty() ? 1 : 2) << " is empty." << std::endl;
391  if(jump_id_ != 1)
392  tr.Info << "Using Jump ID " << jump_id_ << " to define surfaces." << std::endl;
393  }
394 }
395 
398 
400 ShapeComplementarityFilterCreator::keyname() const { return "ShapeComplementarity"; }
401 
402 
403 } // filters
404 } // protocols