Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rms_util.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 core/scoring/rms_util.cc
11 /// @brief RMS stuff from rosetta++
12 /// @author Christopher Miles (cmiles@uw.edu)
13 /// @author James Thompson
14 /// @author Ian Davis
15 /// @date Wed Aug 22 12:10:37 2007
16 ///
17 
18 // Unit headers
19 #include <core/scoring/rms_util.hh>
21 
22 // C/C++ headers
23 #include <algorithm>
24 #include <iomanip>
25 #include <iostream>
26 #include <map>
27 #include <string>
28 #include <utility>
29 
30 // External headers
31 #include <boost/assign.hpp>
32 #include <boost/assign/std/vector.hpp>
33 #include <boost/unordered/unordered_map.hpp>
34 
35 // Project headers
36 #include <core/types.hh>
37 #include <core/pose/Pose.hh>
38 #include <core/pose/MiniPose.hh>
39 #include <core/pose/util.hh>
40 #include <core/id/types.hh>
46 #include <core/id/AtomID.hh>
47 #include <core/id/AtomID_Map.hh>
50 
51 // Utility headers
52 #include <basic/prof.hh>
53 #include <basic/Tracer.hh>
54 #include <basic/options/option.hh>
55 #include <basic/options/keys/in.OptionKeys.gen.hh>
56 #include <numeric/util.hh>
57 #include <numeric/xyzVector.hh>
58 #include <numeric/model_quality/maxsub.hh>
59 #include <numeric/model_quality/rms.hh>
60 #include <ObjexxFCL/FArray1D.hh>
61 #include <ObjexxFCL/FArray2D.hh>
62 #include <utility/exit.hh>
63 
64 #include <utility/vector1.hh>
65 
66 //Auto Headers
67 #include <core/pose/util.tmpl.hh>
68 
69 using namespace ObjexxFCL;
70 
71 namespace core {
72 namespace scoring {
73 
74 static basic::Tracer tr("core.scoring.rms_util");
75 
77  const core::pose::Pose& mod,
78  const std::map<core::Size, core::Size>& residues) {
79  using core::Real;
80  using core::Size;
82  using numeric::xyzVector;
83  using std::map;
84  using std::string;
85 
86  static map<char, string> gdtsc_atom = boost::assign::map_list_of
87  ('A', "CA")
88  ('C', "SG")
89  ('D', "OD2")
90  ('E', "OE2")
91  ('F', "CZ")
92  ('G', "CA")
93  ('H', "NE2")
94  ('I', "CD1")
95  ('K', "NZ")
96  ('L', "CD1")
97  ('M', "CE")
98  ('N', "OD1")
99  ('P', "CG")
100  ('Q', "OE1")
101  ('R', "NH2")
102  ('S', "OG")
103  ('T', "OG1")
104  ('V', "CG1")
105  ('W', "CH2")
106  ('Y', "OH");
107 
108  if (!ref.is_fullatom() || !mod.is_fullatom()) {
109  tr.Warning << "Reference and model must be fullatom for gdtsc()" << std::endl;
110  return -1;
111  }
112 
113  // Retrieve ref, mod coordinates
114  int expected_num_atoms = residues.size();
115  int actual_num_atoms = 0;
116  FArray2D<Real> coords_ref(3, expected_num_atoms);
117  FArray2D<Real> coords_mod(3, expected_num_atoms);
118 
119  int count = 1;
120  for (map<Size, Size>::const_iterator i = residues.begin(); i != residues.end(); ++i, ++count) {
121  const Size ref_idx = i->first;
122  const Size mod_idx = i->second;
123  const char ref_residue = ref.residue(ref_idx).name1();
124  const char mod_residue = mod.residue(mod_idx).name1();
125 
126  if (ref_residue != mod_residue) {
127  tr.Warning << "Reference and model must have identical sequences for gdtha-- "
128  << ref_residue << " != " << mod_residue << std::endl;
129  continue;
130  }
131 
132  ++actual_num_atoms;
133  const NamedAtomID ref_atom(gdtsc_atom[ref_residue], ref_idx);
134  const xyzVector<Real>& xyz_ref = ref.xyz(ref_atom);
135  coords_ref(1, count) = xyz_ref.x();
136  coords_ref(2, count) = xyz_ref.y();
137  coords_ref(3, count) = xyz_ref.z();
138 
139  const NamedAtomID mod_atom(gdtsc_atom[mod_residue], mod_idx);
140  const xyzVector<Real>& xyz_mod = mod.xyz(mod_atom);
141  coords_mod(1, count) = xyz_mod.x();
142  coords_mod(2, count) = xyz_mod.y();
143  coords_mod(3, count) = xyz_mod.z();
144  }
145 
146  // Calculate maxsub over several distance thresholds
147  Real sum = 0;
148  Size num_dists = 10;
149 
150  for (Size i = 1; i <= num_dists; ++i) {
151  Real dist_threshold = 0.5 * i; // 0.5, 1.0, ...
152 
153  int nali;
154  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
155  numeric::model_quality::maxsub(
156  actual_num_atoms, coords_ref, coords_mod,
157  mxrms, mxpsi, nali, mxzscore, mxeval, mxscore,
158  dist_threshold, dist_threshold);
159 
160  Real pct_residues = static_cast<Real>(nali) / static_cast<Real>(actual_num_atoms);
161  sum += pct_residues;
162  }
163 
164  return sum / num_dists;
165 }
166 
168  const core::pose::Pose& mod,
169  const std::map<core::Size, core::Size>& residues) {
170  using core::Real;
171  using core::Size;
172  using core::id::NamedAtomID;
173  using numeric::xyzVector;
174 
175  // Retrieve ref, mod coordinates
176  int expected_num_atoms = residues.size();
177  int actual_num_atoms = 0;
178  FArray2D<Real> coords_ref(3, expected_num_atoms);
179  FArray2D<Real> coords_mod(3, expected_num_atoms);
180 
181  int count = 1;
182  for (std::map<Size, Size>::const_iterator i = residues.begin(); i != residues.end(); ++i, ++count) {
183  const Size ref_idx = i->first;
184  const Size mod_idx = i->second;
185  const char ref_residue = ref.residue(ref_idx).name1();
186  const char mod_residue = mod.residue(mod_idx).name1();
187 
188  if (ref_residue != mod_residue) {
189  tr.Warning << "Reference and model must have identical sequences for gdtha-- "
190  << ref_residue << " != " << mod_residue << std::endl;
191  continue;
192  }
193 
194  ++actual_num_atoms;
195  const NamedAtomID ref_atom("CA", ref_idx);
196  const xyzVector<Real>& xyz_ref = ref.xyz(ref_atom);
197  coords_ref(1, count) = xyz_ref.x();
198  coords_ref(2, count) = xyz_ref.y();
199  coords_ref(3, count) = xyz_ref.z();
200 
201  const NamedAtomID mod_atom("CA", mod_idx);
202  const xyzVector<Real>& xyz_mod = mod.xyz(mod_atom);
203  coords_mod(1, count) = xyz_mod.x();
204  coords_mod(2, count) = xyz_mod.y();
205  coords_mod(3, count) = xyz_mod.z();
206  }
207 
208  // Calculate maxsub over several distance thresholds
209  Real dists[] = {0.5, 1.0, 2.0, 4.0};
210  Size num_dists = 4;
211  Real sum = 0;
212 
213  for (Size i = 0; i < num_dists; ++i) {
214  Real dist_threshold = dists[i];
215 
216  int nali;
217  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
218  numeric::model_quality::maxsub(
219  actual_num_atoms, coords_ref, coords_mod,
220  mxrms, mxpsi, nali, mxzscore, mxeval, mxscore,
221  dist_threshold, dist_threshold);
222 
223  Real pct_residues = static_cast<Real>(nali) / static_cast<Real>(actual_num_atoms);
224  sum += pct_residues;
225  }
226 
227  return sum / num_dists;
228 }
229 
230 void invert_exclude_residues( Size nres, utility::vector1<int> const& exclude_list, ResidueSelection& residue_selection ) {
231  residue_selection.clear();
232 
233  for( Size ir = 1; ir <= nres; ++ir ) {
234  bool exclude_residue = false;
235  for( Size ex = 1; ex <= exclude_list.size(); ex ++ ){
236  if( int(exclude_list[ex]) == int(ir) ) {
237  exclude_residue = true;
238  break;
239  }
240  }
241 
242  if ( !exclude_residue ) {
243  residue_selection.push_back( ir );
244  }
245  } // for ( Size ir = 1; ir <= native_pose.total_residue(); ++ir )
246 }
247 
249  ResidueSelection tmp;
250  invert_exclude_residues( nres, exclude_list, tmp );
251  return tmp;
252 }
253 
254 Real native_CA_rmsd( const core::pose::Pose & native_pose, const core::pose::Pose & pose ){
255  using namespace basic::options;
256  using namespace basic::options::OptionKeys;
257 
258  if ( option[ in::file::native_exclude_res ].user() ) {
259  ResidueSelection residues;
260  invert_exclude_residues( native_pose.total_residue(), option[ in::file::native_exclude_res ](), residues );
261  return core::scoring::CA_rmsd( native_pose, pose, residues );
262  } else {
263  // no residues excluded from the native.
264  return core::scoring::CA_rmsd( native_pose, pose );
265  }
266 } // native_CA_rmsd
267 
268 Real native_CA_gdtmm( const core::pose::Pose & native_pose, const core::pose::Pose & pose ){
269  using namespace basic::options;
270  using namespace basic::options::OptionKeys;
271 
272  if ( option[ in::file::native_exclude_res ].user() ) {
273  ResidueSelection residues;
274  invert_exclude_residues( native_pose.total_residue(), option[ in::file::native_exclude_res ](), residues );
275  return core::scoring::CA_gdtmm( native_pose, pose, residues );
276  } else {
277  // no residues excluded from the native.
278  return core::scoring::CA_gdtmm( native_pose, pose );
279  }
280 } // native_CA_gdtmm
281 
282 /// @details Just iterates over all automorphisms for this residue type and chooses the minimum RMS.
285  core::conformation::Residue const & rsd1,
286  core::conformation::Residue const & rsd2,
287  bool superimpose
288 )
289 {
290  using namespace core;
291  using namespace core::chemical;
292  using namespace core::conformation;
293  // name() and total number of atoms may actually be different, if we're comparing e.g. tautomers
294  if( rsd1.type().name3() != rsd2.type().name3() ) utility_exit_with_message("Residue type name3 mismatch");
295  if( rsd1.nheavyatoms() != rsd2.nheavyatoms() ) utility_exit_with_message("Residue number-of-heavy-atoms mismatch");
296  core::Real best_rms = 1e99;
297  int counter = 0;
298  // Make atom-number translation table
299  ResidueTypeCOP rsd1_type( &(rsd1.type()) );
300  AutomorphismIterator ai( rsd1_type );
301  AtomIndices old2new( ai.next() );
302  // For each permutation of automorphisms...
303  while( old2new.size() > 0 ) {
304  counter++;
305  if( counter%10000 == 0 ) tr.Info << counter << " so far..." << std::endl;
306 
307  // Print out translation table for debugging
308  //std::cout << "[";
309  //for(Size i = 1; i <= old2new.size(); ++i) std::cout << " " << old2new[i];
310  //std::cout << " ]\n";
311  //for(Size j = 1; j <= old2new.size(); ++j) std::cout << " " << j << " --> " << old2new[j] << " / " << rsd1.type().atom_name(j) << " --> " << rsd1.type().atom_name(old2new[j]) << "\n";
312 
313  // Compute rmsd
314  if( superimpose ) {
317  for ( core::Size j = 1; j <= rsd1.type().natoms(); ++j ) {
318  if ( !rsd1.atom_type(j).is_hydrogen() ) {
319  // This is the step where we effectively re-assign atom names
320  // in hopes of reducing RMS (e.g. by "flipping" a phenyl ring).
321  p1_coords.push_back( rsd1.xyz( j ) );
322  p2_coords.push_back( rsd2.xyz( old2new[j] ) );
323  }
324  }
325  runtime_assert( p1_coords.size() == p2_coords.size() );
326  int const natoms = p1_coords.size();
327  ObjexxFCL::FArray2D< core::Real > p1a( 3, natoms );
328  ObjexxFCL::FArray2D< core::Real > p2a( 3, natoms );
329  for ( int j = 0; j < natoms; ++j ) {
330  for ( int k = 0; k < 3; ++k ) { // k = X, Y and Z
331  p1a(k+1,j+1) = p1_coords[j][k];
332  p2a(k+1,j+1) = p2_coords[j][k];
333  }
334  }
335  core::Real const curr_rms = numeric::model_quality::rms_wrapper( natoms, p1a, p2a );
336  // Check vs. minimum rmsd
337  if( curr_rms < best_rms ) {
338  //tr.Debug << "New rms of " << curr_rms << " beats previous best of " << best_rms << std::endl;
339  best_rms = curr_rms;
340  }
341  } else { // don't superimpose
342  core::Real sum2( 0.0 );
343  core::Size natoms( 0 );
344  for ( core::Size j = 1; j <= rsd1.type().natoms(); ++j ) {
345  if ( !rsd1.atom_type(j).is_hydrogen() ) {
346  // This is the step where we effectively re-assign atom names
347  // in hopes of reducing RMS (e.g. by "flipping" a phenyl ring).
348  core::Vector diff = rsd1.xyz( j ) - rsd2.xyz( old2new[j] );
349  sum2 += diff.length_squared();
350  natoms += 1;
351  }
352  }
353  core::Real const curr_rms = std::sqrt(sum2 / natoms);
354  // Check vs. minimum rmsd
355  if( curr_rms < best_rms ) {
356  //tr.Debug << "New rms of " << curr_rms << " beats previous best of " << best_rms << std::endl;
357  best_rms = curr_rms;
358  }
359  }
360  old2new = ai.next();
361  } // done checking all automorphisms
362  tr.Debug << counter << " automorphisms from iterator; best rms is " << best_rms << std::endl;
363  return best_rms;
364 }
365 
366 
367 //////////////////////////////////////////////////////////////////////////////
368 // Predicate functions to use with rmsd_no_super() and rmsd_with_super()
369 
370 bool
372  core::pose::Pose const & pose1,
373  core::pose::Pose const & ,//pose2,
374  core::Size resno,
375  core::Size atomno
376 )
377 {
378  core::conformation::Residue const & rsd = pose1.residue(resno);
379  return rsd.is_protein() && rsd.has("CA") && rsd.atom_index("CA") == atomno;
380 }
381 
382 bool
384  core::pose::Pose const & pose1,
385  core::pose::Pose const & ,//pose2,
386  core::Size resno,
387  core::Size atomno
388 )
389 {
390  core::conformation::Residue const & rsd = pose1.residue(resno);
391  return rsd.is_protein() && ( ( rsd.has("CA") && rsd.atom_index("CA") == atomno ) || ( rsd.has("CB") && rsd.atom_index("CB") == atomno ) );
392 }
393 
394 bool
396  core::pose::Pose const & pose1,
397  core::pose::Pose const & ,//pose2,
398  core::Size resno,
399  core::Size atomno
400 )
401 {
402  core::conformation::Residue const & rsd = pose1.residue(resno);
403  return (rsd.is_protein() && ( rsd.has("CA") && rsd.atom_index("CA") == atomno )) ||
404  ( rsd.has("N") && rsd.atom_index("N") == atomno ) ||
405  ( rsd.has("C") && rsd.atom_index("C") == atomno );
406 }
407 
408 bool
410  core::pose::Pose const & pose1,
411  core::pose::Pose const & ,//pose2,
412  core::Size resno,
413  core::Size atomno
414 )
415 {
416  core::conformation::Residue const & rsd = pose1.residue(resno);
417  return (rsd.is_protein() && ( rsd.has("CA") && rsd.atom_index("CA") == atomno )) ||
418  ( rsd.has("N") && rsd.atom_index("N") == atomno ) ||
419  ( rsd.has("C") && rsd.atom_index("C") == atomno ) ||
420  ( rsd.has("O") && rsd.atom_index("O") == atomno );
421 }
422 
423 bool
425  core::pose::Pose const & pose1,
426  core::pose::Pose const & ,//pose2,
427  core::Size resno,
428  core::Size atomno
429 )
430 {
431  core::chemical::ResidueType const & rsd = pose1.residue_type(resno);
432  return rsd.is_protein() && (rsd.first_sidechain_atom() <= atomno ) && ( !rsd.atom_is_hydrogen( atomno ) );
433 }
434 
435 bool
437  core::pose::Pose const & pose1,
438  core::pose::Pose const & ,//pose2,
439  core::Size resno,
440  core::Size atomno
441 )
442 {
443  core::conformation::Residue const & rsd = pose1.residue(resno);
444  return !rsd.is_polymer() && !rsd.atom_is_hydrogen(atomno);
445 }
446 
447 bool
449  core::conformation::Residue const & residue1,
450  core::conformation::Residue const &, // residue2
451  core::Size atomno
452 ){
453  return !residue1.is_polymer() && !residue1.atom_is_hydrogen(atomno);
454 }
455 
456 bool
458  core::pose::Pose const & pose1,
459  core::pose::Pose const & ,//pose2,
460  core::Size resno,
461  core::Size atomno
462 )
463 {
464  core::conformation::Residue const & rsd = pose1.residue(resno);
465  return rsd.is_polymer() && !rsd.atom_is_hydrogen(atomno);
466 }
467 
468 bool
470  core::pose::Pose const & pose1,
471  core::pose::Pose const & ,//pose2,
472  core::Size resno,
473  core::Size atomno
474 )
475 {
476  core::conformation::Residue const & rsd = pose1.residue(resno);
477  return !rsd.atom_is_hydrogen(atomno);
478 }
479 
480 bool
482  core::pose::Pose const & pose1,
483  core::pose::Pose const & ,//pose2,
484  core::Size resno,
485  core::Size atomno
486 )
487 {
488  core::conformation::Residue const & rsd = pose1.residue(resno);
489  return rsd.nbr_atom() == atomno;
490 }
491 
492 /////////////////////////////////////////////
493 // Predicate classes for more complex control
494 
495 bool ResRangePredicate::operator()(
496  core::pose::Pose const & pose1,
497  core::pose::Pose const & pose2,
498  core::Size resno,
499  core::Size atomno) const {
500  if ( resno < start_ || resno > end_ ) { return false; }
501  else { return (*pred_)(pose1, pose2, resno, atomno); }
502 }
503 
504 bool SelectedResPredicate::operator()(
505  core::pose::Pose const & pose1,
506  core::pose::Pose const & pose2,
507  core::Size resno,
508  core::Size atomno) const {
509  if ( std::find( selected_.begin(), selected_.end(), resno ) == selected_.end() ) { return false; }
510  else { return (*pred_)(pose1, pose2, resno, atomno); }
511 }
512 
513 bool ExcludedResPredicate::operator()(
514  core::pose::Pose const & pose1,
515  core::pose::Pose const & pose2,
516  core::Size resno,
517  core::Size atomno) const {
518  if ( std::find( excluded_.begin(), excluded_.end(), resno ) != excluded_.end() ) { return false; }
519  else { return (*pred_)(pose1, pose2, resno, atomno); }
520 }
521 
522 
523 /////////////////////////////////////////////////////////////////////////
524 
527  const core::pose::Pose & pose1,
528  const core::pose::Pose & pose2
529 ) {
530  using namespace core;
531  Size start ( 1 );
532  Size end ( std::min( pose1.total_residue(), pose2.total_residue() ) );
533  return CA_rmsd( pose1, pose2, start, end );
534 } // CA_rmsd
535 
538  const core::pose::Pose & pose1,
539  const core::pose::Pose & pose2,
540  Size start,
541  Size end
542 ) {
543  PROF_START( basic::CA_RMSD_EVALUATION );
544  using namespace core;
545  // copy coords into Real arrays
546  int natoms;
547  FArray2D< core::Real > p1a;
548  FArray2D< core::Real > p2a;
549  PredicateOP pred( new ResRangePredicate( start, end, new IsProteinCAPredicate ) );
550  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, pred() );
551 
552  if ( (int) (end - start + 1) > natoms ) { tr.Warning << "WARNING: In CA_rmsd, residue range " << start << " to " << end
553  << " requested but only " << natoms << " protein CA atoms found." << std::endl; }
554 
555  Real rms = numeric::model_quality::rms_wrapper( natoms, p1a, p2a );
556  if(rms < 0.00001) rms = 0.0;
557  PROF_STOP( basic::CA_RMSD_EVALUATION );
558  return rms;
559 } // CA_rmsd
560 
561 /// @detail Populates the output parameter with the xyz coordinates of
562 /// a subset of <pose>'s CA atoms, which are specified in <residues>
564  const utility::vector1<core::Size>& residues,
565  FArray2D<core::Real>* coords) {
566  using core::Real;
567  using core::Size;
568  using core::id::NamedAtomID;
569  using numeric::xyzVector;
570  using utility::vector1;
571 
572  coords->dimension(3, residues.size());
573 
574  for (Size i = 1; i <= residues.size(); ++i) {
575  const NamedAtomID id("CA", residues[i]);
576  const xyzVector<Real>& xyz = pose.xyz(id);
577  (*coords)(1, i) = xyz.x();
578  (*coords)(2, i) = xyz.y();
579  (*coords)(3, i) = xyz.z();
580  }
581 }
582 
584  const core::pose::Pose& pose2,
585  const std::map<core::Size, core::Size>& residues) {
586  using core::Real;
587  using core::Size;
588  using utility::vector1;
589 
590  vector1<Size> residues_1; // residues in pose1
591  vector1<Size> residues_2; // residues in pose2
592  for (std::map<Size, Size>::const_iterator i = residues.begin(); i != residues.end(); ++i) {
593  Size res_1 = i->first;
594  Size res_2 = i->second;
595  residues_1.push_back(res_1);
596  residues_2.push_back(res_2);
597  }
598 
599  FArray2D<Real> p1; // coordinates of CA atoms of selected residues in pose1
600  FArray2D<Real> p2; // coordinates of CA atoms of selected residues in pose2
601  retrieve_coordinates(pose1, residues_1, &p1);
602  retrieve_coordinates(pose2, residues_2, &p2);
603 
604  return numeric::model_quality::rms_wrapper(residues.size(), p1, p2);
605 }
606 
608  const core::pose::Pose& pose2,
609  const std::map<core::Size, core::Size>& residues) {
610  using core::Real;
611  using core::Size;
612  using utility::vector1;
613 
614  vector1<Size> residues_1; // residues in pose1
615  vector1<Size> residues_2; // residues in pose2
616  for (std::map<Size, Size>::const_iterator i = residues.begin(); i != residues.end(); ++i) {
617  Size res_1 = i->first;
618  Size res_2 = i->second;
619  residues_1.push_back(res_1);
620  residues_2.push_back(res_2);
621  }
622 
623  FArray2D<Real> p1; // coordinates of CA atoms of selected residues in pose1
624  FArray2D<Real> p2; // coordinates of CA atoms of selected residues in pose2
625  retrieve_coordinates(pose1, residues_1, &p1);
626  retrieve_coordinates(pose2, residues_2, &p2);
627 
628  Real m_1_1, m_2_2, m_3_3, m_4_3, m_7_4;
629  return xyz_gdtmm(p1, p2, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4);
630 }
631 
634  const core::pose::Pose & pose1,
635  const core::pose::Pose & pose2,
636  Size start,
637  Size end,
638  utility::vector1< Size > const& exclude
639 ) {
640  PROF_START( basic::CA_RMSD_EVALUATION );
641  using namespace core;
642  // copy coords into Real arrays
643  int natoms;
644  FArray2D< core::Real > p1a;//( 3, pose1.total_residue() );
645  FArray2D< core::Real > p2a;//( 3, pose2.total_residue() );
646  PredicateOP pred( new ResRangePredicate( start, end, new ExcludedResPredicate( exclude, new IsProteinCAPredicate )) );
647  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, pred() );
648 
649  // Calc rms
650  Real rms = numeric::model_quality::rms_wrapper( natoms, p1a, p2a );
651  if(rms < 0.00001) rms = 0.0;
652  PROF_STOP( basic::CA_RMSD_EVALUATION );
653  return rms;
654 } // CA_rmsd
655 
658  const core::pose::Pose & pose1,
659  const core::pose::Pose & pose2
660 ) {
661 
662  using namespace core;
663  Size start ( 1 );
664  Size end ( std::min( pose1.total_residue(), pose2.total_residue() ) );
666  return bb_rmsd( pose1, pose2, start, end, blank );
667 } // bb_rmsd
668 
671  const core::pose::Pose & pose1,
672  const core::pose::Pose & pose2,
673  Size,
674  Size,
676 ) {
677  using namespace core;
678  Real rms = rmsd_with_super( pose1, pose2, is_protein_backbone );
679  return rms;
680 } // bb_rmsd
681 
684  const core::pose::Pose & pose1,
685  const core::pose::Pose & pose2
686 ) {
687 
688  using namespace core;
689  Size start ( 1 );
690  Size end ( std::min( pose1.total_residue(), pose2.total_residue() ) );
692  return bb_rmsd_including_O( pose1, pose2, start, end, blank );
693 } // bb_rmsd_including_O
694 
697  const core::pose::Pose & pose1,
698  const core::pose::Pose & pose2,
699  Size,
700  Size,
702 ) {
703  using namespace core;
705  return rms;
706 } // bb_rmsd_including_O
707 
710  const core::pose::Pose & pose1,
711  const core::pose::Pose & pose2,
712  std::list< Size > residue_selection //the std::list can be sorted!
713 ) {
714  PROF_START( basic::CA_RMSD_EVALUATION );
715  using namespace core;
716  // copy coords into Real arrays
717  int natoms;
718  FArray2D< core::Real > p1a;//( 3, pose1.total_residue() );
719  FArray2D< core::Real > p2a;//( 3, pose2.total_residue() );
720  PredicateOP pred( new SelectedResPredicate( residue_selection, new IsProteinCAPredicate ) );
721  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, pred() );
722 
723  if ( (int) residue_selection.size() > natoms ) { tr.Warning << "WARNING: In CA_rmsd " << residue_selection.size()
724  << " residues selected but only " << natoms << " protein CA atoms found." << std::endl; }
725 
726  // Calc rms
727  PROF_STOP( basic::CA_RMSD_EVALUATION );
728  return numeric::model_quality::rms_wrapper( natoms, p1a, p2a );
729 } // CA_rmsd
730 
733  const core::pose::Pose & pose1,
734  const core::pose::Pose & pose2
735 ) {
736 
737  using namespace core;
738  Real rms = rmsd_with_super( pose1, pose2, is_heavyatom );
739  return rms;
740 } // all atom rmsd
741 
744  const core::pose::Pose & pose1,
745  const core::pose::Pose & pose2,
746  std::list< Size > residue_selection //the std::list can be sorted!
747 )
748 {
749  using namespace core;
750  Real rms = rmsd_with_super( pose1, pose2, residue_selection, is_heavyatom );
751  return rms;
752 } // CA_rmsd
753 
756  const core::pose::Pose & pose1,
757  const core::pose::Pose & pose2
758 ) {
759 
760  using namespace core;
761  Real rms = rmsd_with_super( pose1, pose2, is_nbr_atom );
762  return rms;
763 } // nbr_atom_rmsd
764 
765 // fill_rmsd_coordinates() is in rms_util.tmpl.hh
766 
767 int
769  const core::pose::Pose & pose1,
770  const core::pose::Pose & pose2,
771  Real rms
772 )
773 {
774  const int nres1( pose1.total_residue() );
775 
776  static std::string atom_name = "CA";
777  int natoms(0);
778  FArray2D< double > p1a( 3, nres1 );
779  FArray2D< double > p2a( 3, nres1 );
780  // fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, "CA" );
781  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, is_protein_CA );
782 
783  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
784  int nali;
785  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rms );
786  //logeval = std::log(mxeval);
787  return nali;
788 }
789 
790 int
792  const core::pose::Pose & pose1,
793  const core::pose::Pose & pose2,
794  std::list< Size > residue_selection, //the std::list can be sorted!
795  Real rms
796 ) {
797 
798  using namespace core;
799  // copy coords into Real arrays
800  int natoms;
801  FArray2D< core::Real > p1a;//( 3, pose1.total_residue() );
802  FArray2D< core::Real > p2a;//( 3, pose2.total_residue() );
803  PredicateOP pred( new SelectedResPredicate( residue_selection, new IsProteinCAPredicate ) );
804  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, pred() );
805 
806  if ( (int) residue_selection.size() > natoms ) { tr.Warning << "WARNING: In CA_maxsub " << residue_selection.size()
807  << " residues selected but only " << natoms << " protein CA atoms found." << std::endl; }
808 
809  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
810  int nali;
811  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rms );
812  //logeval = std::log(mxeval);
813  return nali;
814 }
815 
817  FArray2D< core::Real > p1a,
818  FArray2D< core::Real > p2a,
819  int natoms
820 ) {
821  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
822  int nali;
823  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore );
824  return nali;
825 }
826 
827 int
829  const core::pose::Pose & pose1,
830  const core::pose::Pose & pose2,
831  utility::vector1< bool > //subset
832 )
833 {
834  const int nres1( pose1.total_residue() );
835 
836  static std::string atom_name = "CA";
837  int natoms(0);
838  FArray2D< double > p1a( 3, nres1 );
839  FArray2D< double > p2a( 3, nres1 );
840  // fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, "CA" );
841  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, is_protein_CA );
842 
843  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
844  int nali;
845  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore );
846  //logeval = std::log(mxeval);
847  return nali;
848 } // CA_maxsub_by_subset
849 
852  core::pose::Pose const& pose1,
853  core::pose::Pose const& pose2,
854  std::list< Size > residue_selection, //the std::list can be sorted! -- note std::sort can be applied to vectors
855  core::Real& m_1_1,
856  core::Real& m_2_2,
857  core::Real& m_3_3,
858  core::Real& m_4_3,
859  core::Real& m_7_4
860 ) {
861  int natoms;
862  FArray2D< core::Real > p1a( 3, pose1.total_residue() );
863  FArray2D< core::Real > p2a( 3, pose2.total_residue() );
864  PredicateOP pred( new SelectedResPredicate( residue_selection, new IsProteinCAPredicate ) );
865  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, pred() );
866 
867  if ( (int) residue_selection.size() > natoms ) { tr.Warning << "WARNING: In CA_gdtmm " << residue_selection.size()
868  << " residues selected but only " << natoms << " protein CA atoms found." << std::endl; }
869 
870  core::Real gdtmm = xyz_gdtmm( p1a, p2a, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4 );
871  return gdtmm;
872 }
873 
876  core::pose::Pose const& pose1,
877  core::pose::Pose const& pose2,
878  core::Real& m_1_1,
879  core::Real& m_2_2,
880  core::Real& m_3_3,
881  core::Real& m_4_3,
882  core::Real& m_7_4
883 ) {
884  int natoms;
885  FArray2D< core::Real > p1a( 3, pose1.total_residue() );
886  FArray2D< core::Real > p2a( 3, pose2.total_residue() );
887  fill_rmsd_coordinates( natoms, p1a, p2a, pose1, pose2, is_protein_CA );
888 
889  core::Real gdtmm = xyz_gdtmm( p1a, p2a, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4 );
890  return gdtmm;
891 }
892 
895  FArray2D< core::Real > p1a,
896  FArray2D< core::Real > p2a
897 ) {
898  core::Real m_1_1, m_2_2, m_3_3, m_4_3, m_7_4;
899  core::Real gdtmm = xyz_gdtmm( p1a, p2a, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4 );
900  return gdtmm;
901 }
902 
905  FArray2D< core::Real > p1a,
906  FArray2D< core::Real > p2a,
907  core::Real& m_1_1,
908  core::Real& m_2_2,
909  core::Real& m_3_3,
910  core::Real& m_4_3,
911  core::Real& m_7_4
912 ) {
913  int natoms = p1a.size2();
914  runtime_assert( (p1a.size() == p2a.size()) && (p1a.size2() == p2a.size2()) );
915  double mxrms, mxpsi, mxzscore, mxscore, mxeval;
916  int nali;
917 
918  core::Real rmstol, disttol;
919  rmstol = 1.0;
920  disttol = 1.0;
921  tr.Trace << "call maxsub with rmstol " << rmstol << " and disttol " << disttol << std::endl;
922  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rmstol, disttol );
923  m_1_1 = core::Real( nali ) / core::Real( natoms );
924 
925  rmstol = 2.0;
926  disttol = 2.0;
927  tr.Trace << "call maxsub with rmstol " << rmstol << " and disttol " << disttol << std::endl;
928  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rmstol, disttol );
929  m_2_2 = core::Real( nali ) / core::Real( natoms );
930 
931  rmstol = 3.0;
932  disttol = 3.0;
933  tr.Trace << "call maxsub with rmstol " << rmstol << " and disttol " << disttol << std::endl;
934  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rmstol, disttol );
935  m_3_3 = core::Real( nali ) / core::Real( natoms );
936 
937  rmstol = 3.0;
938  disttol = 4.0;
939  tr.Trace << "call maxsub with rmstol " << rmstol << " and disttol " << disttol << std::endl;
940  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rmstol, disttol );
941  m_4_3 = core::Real( nali ) / core::Real( natoms );
942 
943  rmstol = 4.0;
944  disttol = 7.0;
945  tr.Trace << "call maxsub with rmstol " << rmstol << " and disttol " << disttol << std::endl;
946  numeric::model_quality::maxsub( natoms, p1a, p2a, mxrms, mxpsi, nali, mxzscore, mxeval, mxscore, rmstol, disttol );
947  m_7_4 = core::Real( nali ) / core::Real( natoms );
948 
949  return (m_1_1 + m_2_2 + m_3_3 + m_4_3 + m_7_4 )/5.0;
950 }
951 
954  core::pose::Pose const& pose1,
955  core::pose::Pose const& pose2
956 ) {
957  core::Real m_1_1, m_2_2, m_3_3, m_4_3, m_7_4;
958  return CA_gdtmm( pose1, pose2, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4 );
959 }
960 
963  core::pose::Pose const& pose1,
964  core::pose::Pose const& pose2,
965  std::list< Size> residue_selection
966 ) {
967  core::Real m_1_1, m_2_2, m_3_3, m_4_3, m_7_4;
968  return CA_gdtmm( pose1, pose2, residue_selection, m_1_1, m_2_2, m_3_3, m_4_3, m_7_4 );
969 }
970 
971 /// @details Superimpose mod_pose onto ref_pose using the AtomID mapping, which maps atoms in mod_pose onto
972 /// atoms in ref_pose. Returns rmsd over alignment.
973 ///
974 /// @note Atoms in mod_pose whose ids map to bogus atom ids will not be used in the fitting
975 ///
976 /// Usage example: superimpose pose1 onto pose2 by mapping C-alphas of residue 10-30 onto residues 20-40
977 ///
978 /// id::AtomID_Map< id::AtomID > atom_map;
979 /// id::initialize( atom_map, pose1, id::BOGUS_ATOM_ID ); // maps every atomid to bogus atom
980 ///
981 /// for ( Size i=10; i<=30; ++i ) {
982 /// id::AtomID const id1( pose1.residue(i).atom_index("CA"), i );
983 /// id::AtomID const id2( pose2.residue(i+10).atom_index("CA"), i+10 );
984 /// atom_map[ id1 ] = id2;
985 /// }
986 /// superimpose_pose( pose1, pose2, atom_map );
987 ///
988 
989 Real
991  pose::Pose & mod_pose,
992  pose::Pose const & ref_pose,
993  id::AtomID_Map< id::AtomID > const & atom_map // from mod_pose to ref_pose
994 )
995 {
996  pose::MiniPose mini_ref_pose( ref_pose ); //minipose is a lightweight pose with just xyz positions (& fold tree)
997  return superimpose_pose(mod_pose, mini_ref_pose, atom_map );
998 }
999 
1000 Real
1002  pose::Pose & mod_pose,
1003  pose::MiniPose const & ref_pose,
1004  id::AtomID_Map< id::AtomID > const & atom_map // from mod_pose to ref_pose
1005 )
1006 {
1007  using namespace numeric::model_quality;
1008  using namespace id;
1009 
1010  /// how many atoms in mod_pose?
1011  Size natoms(0);
1012  for ( Size i=1; i<= mod_pose.total_residue(); ++i ) natoms += mod_pose.residue(i).natoms();
1013 
1014  // pack coords into local arrays for passing into the rms fitting routine
1015  FArray2D_double xx1(3,natoms);
1016  FArray2D_double xx2(3,natoms);
1017  FArray1D_double wt(natoms);
1018 
1019 
1020  Size nsup(0);
1021  { // pack coordinates into the local arrays
1022  Size atomno(0);
1023  Vector const zero_vector(0.0);
1024  for ( Size i=1; i<= mod_pose.total_residue(); ++i ) {
1025  for ( Size j=1; j<= mod_pose.residue(i).natoms(); ++j ) {
1026  ++atomno;
1027  AtomID const & aid( atom_map[ id::AtomID( j,i) ] );
1028  Vector const & x1( aid.valid() ? ref_pose.xyz( aid ) : zero_vector );
1029  Vector const & x2( mod_pose.residue(i).xyz(j) );
1030  wt( atomno ) = ( aid.valid() ? 1.0 : 0.0 );
1031  if ( aid.valid() ) ++nsup;
1032  for ( Size k=1; k<= 3; ++k ) {
1033  xx1(k,atomno) = x1(k);
1034  xx2(k,atomno) = x2(k);
1035  }
1036  }
1037  }
1038  runtime_assert( atomno == natoms );
1039  }
1040 
1041  // calculate starting center of mass (COM):
1042  FArray1D_double COM(3);
1043  COMAS(xx1,wt,natoms,COM(1),COM(2),COM(3));
1044 
1045  // superimpose:: shifts xx1, shifts and transforms xx2;
1046  double rms;
1047  rmsfitca2(natoms,xx1,xx2,wt,nsup,rms);
1048 
1049  if ( true ) { // debug:
1050  double tmp1,tmp2,tmp3;
1051  COMAS(xx1,wt,natoms,tmp1,tmp2,tmp3); // store xcen,ycen,zcen vals for later
1052  //std::cout << "zero??: " << std::abs(tmp1) + std::abs(tmp2) + std::abs(tmp3)
1053  // << std::endl;
1054  runtime_assert( std::abs(tmp1) + std::abs(tmp2) + std::abs(tmp3) < 1e-3 );
1055  }
1056 
1057  { // translate xx2 by COM and fill in the new mod_pose coordinates
1058  Size atomno(0);
1059  Vector x2;
1060  for ( Size i=1; i<= mod_pose.total_residue(); ++i ) {
1061  for ( Size j=1; j<= mod_pose.residue_type(i).natoms(); ++j ) { // use residue_type to prevent internal coord update
1062  ++atomno;
1063  for ( Size k=1; k<= 3; ++k ) x2(k) = xx2(k,atomno) + COM(k);
1064  mod_pose.set_xyz( id::AtomID( j,i), x2 );
1065  }
1066  }
1067  runtime_assert( atomno == natoms );
1068  }
1069 
1070  return ( static_cast < Real > ( rms ) );
1071 }
1072 
1073 /// @details both poses must have the same length.
1074 Real
1076  pose::Pose & mod_pose,
1077  pose::Pose const & ref_pose
1078 )
1079 {
1080  runtime_assert( mod_pose.total_residue() == ref_pose.total_residue() );
1083  for ( Size ii = 1; ii <= mod_pose.total_residue(); ++ii ) {
1084  if ( ii > ref_pose.total_residue() ) break;
1085  if ( ! mod_pose.residue(ii).has("CA") ) continue;
1086  if ( ! ref_pose.residue(ii).has("CA") ) continue;
1087 
1088  id::AtomID const id1( mod_pose.residue(ii).atom_index("CA"), ii );
1089  id::AtomID const id2( ref_pose.residue(ii).atom_index("CA"), ii );
1090  atom_map.set( id1, id2 );
1091 
1092  }
1093  return superimpose_pose( mod_pose, ref_pose, atom_map );
1094 }
1095 
1096 core::Real
1098  const core::pose::Pose & native_pose,
1099  const core::pose::Pose & pose
1100 )
1101 {
1102  using namespace core;
1103  using namespace conformation::symmetry;
1104 
1105  runtime_assert( core::pose::symmetry::is_symmetric( native_pose ) || core::pose::symmetry::is_symmetric( pose ) );
1106 
1107  SymmetricConformation const & symm_conf (
1108  dynamic_cast<SymmetricConformation const & > ( pose.conformation()) );
1109  SymmetryInfoCOP symm_info( symm_conf.Symmetry_Info() );
1110 
1111 
1112  int const nres_monomer ( symm_info->num_independent_residues() );
1113  int const N ( symm_info->subunits() );
1114  int const nres ( symm_info->num_total_residues_without_pseudo() );
1115  FArray2D< core::Real > p1a_shuffle( 3, nres );
1116 
1117  core::Real rms = 1e3; //Since fast_rms has not been evaluated yet
1118 
1119  // copy coords into Real arrays
1120  int natoms;
1121  FArray2D< core::Real > p1a;//( 3, pose1.total_residue() );
1122  FArray2D< core::Real > p2a;//( 3, pose2.total_residue() );
1123  fill_rmsd_coordinates( natoms, p1a, p2a, native_pose, pose, is_protein_CA );
1124  if (natoms%nres_monomer != 0 ) {
1125  tr.Warning << "CA atoms in fill_rmsd " << natoms << "is not a multiple of number of residues per subunit " << nres_monomer << std::endl;
1126  }
1127 
1128  // Calc rms
1129  std::vector< std::vector<int> > shuffle_map;
1130  create_shuffle_map_recursive_rms(std::vector<int>(), N,shuffle_map);
1131  for (int j=1; j < int (shuffle_map.size()); j++ ){
1132  for (int i=0; i < N; ++i ) {
1133  int const begin ( shuffle_map.at(j).at(i)*nres_monomer*3);
1134  for ( int k = 0; k < nres_monomer*3; ++k ) {
1135  int const begin_shuffled (i*nres_monomer*3);
1136  p1a_shuffle[begin_shuffled+k] = p1a[begin+k];
1137  }
1138  }
1139  Real rms_shuffle = numeric::model_quality::rms_wrapper( natoms, p1a_shuffle, p2a );
1140  if ( rms_shuffle < rms ) {
1141  rms = rms_shuffle;
1142  }
1143  }
1144 
1145  if(rms < 0.00001) rms = 0.0;
1146  return rms;
1147 }
1148 
1149 // @details This is a recursive algorithm to generate all combinations of
1150 // n digits where a number can only occur once in the sequence.
1151 // The size scales as N! so don't use this for large values of N!!!
1152 void
1154  std::vector<int> sequence,
1155  int const N,
1156  std::vector< std::vector<int> > & map
1157 )
1158 {
1159  if ( int(sequence.size()) == N ){
1160  map.push_back(sequence);
1161  return;
1162  }
1163  for (int i=0; i< N; i++) {
1164  bool exist (false);
1165  for (int j=0; j < int(sequence.size()); j++) {
1166  if (sequence.at(j) == i )
1167  exist = true;
1168  }
1169  if (!exist) {
1170  std::vector<int> sequence_tmp (sequence);
1171  sequence_tmp.push_back(i);
1172  create_shuffle_map_recursive_rms(sequence_tmp,N,map);
1173  }
1174  }
1175 }
1176 
1177 /////////////////////////////////////////////////////////////
1178 /// @details Should be more robust to crazy variant type mismatches. Both poses must have the same length.
1179 Real
1181  pose::Pose const & mod_pose,
1182  pose::Pose const & ref_pose,
1183  std::map< core::id::AtomID, core::id::AtomID > atom_id_map
1184 )
1185 {
1186  utility::vector1< Size > calc_rms_res;
1187  for ( Size n = 1; n <= mod_pose.total_residue(); n++ ) calc_rms_res.push_back( n );
1188 
1189  return rms_at_corresponding_atoms( mod_pose, ref_pose, atom_id_map, calc_rms_res );
1190 }
1191 
1192 /////////////////////////////////////////////////////////////
1193 /// @details Should be more robust to crazy variant type mismatches. Both poses must have the same length.
1194 Real
1196  pose::Pose const & mod_pose,
1197  pose::Pose const & ref_pose,
1198  std::map< core::id::AtomID, core::id::AtomID > atom_id_map,
1199  utility::vector1< Size > const & calc_rms_res
1200 )
1201 {
1202  utility::vector1< bool > is_calc_rms( mod_pose.total_residue(), false );
1203  for ( Size n = 1; n <= calc_rms_res.size(); n++ ) is_calc_rms[ calc_rms_res[ n ] ] = true;
1204 
1205  utility::vector1< Vector > p1_coords, p2_coords;
1206 
1207  for ( std::map< core::id::AtomID, core::id::AtomID >::const_iterator iter = atom_id_map.begin();
1208  iter != atom_id_map.end(); iter++ ) {
1209 
1210  assert ( mod_pose.residue( (iter->first).rsd() ).atom_name( (iter->first).atomno() ) ==
1211  ref_pose.residue( (iter->second).rsd() ).atom_name( (iter->second).atomno() ) );
1212 
1213  if ( !is_calc_rms[ (iter->first).rsd() ] ) continue;
1214  if ( !is_calc_rms[ (iter->second).rsd() ] ) continue;
1215 
1216  Vector const & p1( mod_pose.xyz( iter->first ));
1217  Vector const & p2( ref_pose.xyz( iter->second ));
1218  p1_coords.push_back( p1 );
1219  p2_coords.push_back( p2 );
1220  }
1221  return numeric::model_quality::calc_rms( p1_coords, p2_coords );
1222 }
1223 
1224 /// @details Calculates RMSD of all atoms in AtomID map, no need for the poses to be the same length.
1225 Real
1227  pose::Pose const & mod_pose,
1228  pose::Pose const & ref_pose,
1229  std::map< core::id::AtomID, core::id::AtomID > atom_id_map
1230 )
1231 {
1232  utility::vector1< Vector > p1_coords, p2_coords;
1233 
1234  for ( std::map< core::id::AtomID, core::id::AtomID >::const_iterator iter = atom_id_map.begin();
1235  iter != atom_id_map.end(); iter++ ) {
1236 
1237  assert ( mod_pose.residue( (iter->first).rsd() ).atom_name( (iter->first).atomno() ) ==
1238  ref_pose.residue( (iter->second).rsd() ).atom_name( (iter->second).atomno() ) );
1239 
1240  Vector const & p1( mod_pose.xyz( iter->first ));
1241  Vector const & p2( ref_pose.xyz( iter->second ));
1242  p1_coords.push_back( p1 );
1243  p2_coords.push_back( p2 );
1244  }
1245  return numeric::model_quality::calc_rms( p1_coords, p2_coords );
1246 }
1247 
1248 Real
1250  pose::Pose const & mod_pose,
1251  pose::Pose const & ref_pose,
1252  std::map< core::id::AtomID, core::id::AtomID > atom_id_map ){
1253 
1254  utility::vector1< Size > calc_rms_res;
1255  for ( Size n = 1; n <= mod_pose.total_residue(); n++ ) calc_rms_res.push_back( n );
1256 
1257  return rms_at_corresponding_atoms_no_super( mod_pose, ref_pose, atom_id_map, calc_rms_res );
1258 }
1259 
1260 Real
1262  pose::Pose const & mod_pose,
1263  pose::Pose const & ref_pose,
1264  std::map< core::id::AtomID, core::id::AtomID > atom_id_map,
1265  utility::vector1< Size > const & calc_rms_res
1266 )
1267 {
1268  utility::vector1< bool > is_calc_rms( mod_pose.total_residue(), false );
1269  for ( Size n = 1; n <= calc_rms_res.size(); n++ ) is_calc_rms[ calc_rms_res[ n ] ] = true;
1270 
1271  Size natoms( 0 );
1272  Real sum( 0.0 );
1273  for ( std::map< core::id::AtomID, core::id::AtomID >::const_iterator iter = atom_id_map.begin();
1274  iter != atom_id_map.end(); iter++ ) {
1275 
1276  assert ( mod_pose.residue( (iter->first).rsd() ).atom_name( (iter->first).atomno() ) ==
1277  ref_pose.residue( (iter->second).rsd() ).atom_name( (iter->second).atomno() ) );
1278 
1279  if ( !is_calc_rms[ (iter->first).rsd() ] ) continue;
1280  if ( !is_calc_rms[ (iter->second).rsd() ] ) continue;
1281 
1282  Vector const & p1( mod_pose.xyz( iter->first ));
1283  Vector const & p2( ref_pose.xyz( iter->second ));
1284 
1285  sum += (p1 - p2).length_squared();
1286  natoms++;
1287  }
1288  return std::sqrt( sum / natoms );
1289 }
1290 
1291 Real
1293  pose::Pose const & mod_pose,
1294  pose::Pose const & ref_pose
1295  )
1296 {
1297  std::map< core::id::AtomID, core::id::AtomID > atom_id_map;
1298  setup_matching_heavy_atoms( mod_pose, ref_pose, atom_id_map );
1299  return rms_at_corresponding_atoms( mod_pose, ref_pose, atom_id_map );
1300 }
1301 
1302 void
1303 setup_matching_heavy_atoms( core::pose::Pose const & pose1, core::pose::Pose const & pose2, std::map< core::id::AtomID, core::id::AtomID > & atom_id_map ){
1304 
1305  using namespace core::id;
1306  using namespace core::conformation;
1307 
1308  atom_id_map.clear();
1309  assert( pose1.sequence() == pose2.sequence() );
1310 
1311  for (Size i = 1; i <= pose1.total_residue(); i++ ) {
1312  Residue const & rsd1 = pose1.residue( i );
1313  Residue const & rsd2 = pose2.residue( i );
1314 
1315  for ( Size j = 1; j <= rsd1.nheavyatoms(); j++ ) {
1316  std::string name( rsd1.atom_name( j ) );
1317  if ( !rsd2.has( name ) ) continue;
1318 
1319  if( rsd1.is_virtual(j)) continue;
1320 
1321  Size const j2( rsd2.atom_index( name ) );
1322  if( rsd2.is_virtual(j2) ) continue;
1323 
1324  atom_id_map[ AtomID( j, i ) ] = AtomID( j2, i ) ;
1325  }
1326  }
1327 }
1328 
1329 /// @details Iterates over all non-hydrogen sidechain atoms of two residues and returns their rmsd without superposition.
1330 core::Real
1332 {
1333  runtime_assert( res1->name3() == res2->name3() );
1334  std::vector< core::Size > compare_atoms;
1335  core::Real sum2( 0.0 );
1336 
1337  if( fxnal_group_only ) {
1338  std::string const name1 = res1->name3();
1339  if( name1 == "GLY" )
1340  compare_atoms.push_back( res1->atom_index("CA"));
1341  if( name1 == "ALA" )
1342  compare_atoms.push_back( res1->atom_index("CB"));
1343  if( name1 == "SER" )
1344  compare_atoms.push_back( res1->atom_index("OG"));
1345  if( name1 == "THR" )
1346  compare_atoms.push_back( res1->atom_index("OG1"));
1347  if( name1 == "CYS" )
1348  compare_atoms.push_back( res1->atom_index("SG"));
1349  if( name1 == "VAL" ) {
1350  compare_atoms.push_back( res1->atom_index("CG1"));
1351  compare_atoms.push_back( res1->atom_index("CG2"));
1352  }
1353  if( name1 == "LEU" ) {
1354  compare_atoms.push_back( res1->atom_index("CD1"));
1355  compare_atoms.push_back( res1->atom_index("CD2"));
1356  }
1357  if( name1 == "ILE" ) {
1358  compare_atoms.push_back( res1->atom_index("CD1"));
1359  compare_atoms.push_back( res1->atom_index("CG2"));
1360  }
1361  if( name1 == "MET" ) {
1362  compare_atoms.push_back( res1->atom_index("CE"));
1363  compare_atoms.push_back( res1->atom_index("SD"));
1364  }
1365  if( name1 == "PRO" )
1366  compare_atoms.push_back( res1->atom_index("CG"));
1367  if( name1 == "PHE" ) {
1368  compare_atoms.push_back( res1->atom_index("CZ"));
1369  compare_atoms.push_back( res1->atom_index("CE1"));
1370  compare_atoms.push_back( res1->atom_index("CE2"));
1371  }
1372  if( name1 == "TYR" )
1373  compare_atoms.push_back( res1->atom_index("OH"));
1374  if( name1 == "TRP" )
1375  compare_atoms.push_back( res1->atom_index("NE1"));
1376  if( name1 == "ASP" ) {
1377  compare_atoms.push_back( res1->atom_index("OD1"));
1378  compare_atoms.push_back( res1->atom_index("OD2"));
1379  }
1380  if( name1 == "GLU" ) {
1381  compare_atoms.push_back( res1->atom_index("OE1"));
1382  compare_atoms.push_back( res1->atom_index("OE2"));
1383  }
1384  if( name1 == "ASN" ) {
1385  compare_atoms.push_back( res1->atom_index("OD1"));
1386  compare_atoms.push_back( res1->atom_index("ND2"));
1387  }
1388  if( name1 == "GLN" ) {
1389  compare_atoms.push_back( res1->atom_index("OE1"));
1390  compare_atoms.push_back( res1->atom_index("NE2"));
1391  }
1392  if( name1 == "HIS" ) {
1393  compare_atoms.push_back( res1->atom_index("ND1"));
1394  compare_atoms.push_back( res1->atom_index("NE2"));
1395  }
1396  if( name1 == "LYS" )
1397  compare_atoms.push_back( res1->atom_index("NZ"));
1398  if( name1 == "ARG" ) {
1399  compare_atoms.push_back( res1->atom_index("NH1"));
1400  compare_atoms.push_back( res1->atom_index("NH2"));
1401  }
1402 
1403  }
1404  else {
1405  core::Size num_atoms ( res1->natoms() );
1406  if ( num_atoms > res2->natoms() ){
1407  num_atoms = res2->natoms();
1408  }
1409  for ( core::Size j = res1->first_sidechain_atom(); j <= num_atoms; ++j ) {
1410  if( !res1->atom_type(j).is_heavyatom() ) continue;
1411  compare_atoms.push_back( j );
1412  }
1413  }
1414 
1415  // compare over sidechain heavy atoms only, ignoring hydrogens
1416  for ( std::vector< core::Size >::const_iterator it = compare_atoms.begin(); it != compare_atoms.end(); ++it ) {
1417  core::Size const atomno = *it;
1418  core::Vector const diff = res1->xyz(atomno) - res2->xyz(atomno);
1419  sum2 += diff.length_squared();
1420  }
1421 
1422  return std::sqrt(sum2 / compare_atoms.size() );
1423 }
1424 
1425 //////////////////////////////////////////////////////////////////////////
1426 void
1427 setup_matching_CA_atoms( core::pose::Pose const & pose1, core::pose::Pose const & pose2, std::map< core::id::AtomID, core::id::AtomID > & atom_id_map ){
1428 
1429  utility::vector1< std::string > protein_backbone_heavy_atoms;
1430  protein_backbone_heavy_atoms.push_back( " CA " );
1431  setup_matching_atoms_with_given_names( pose1, pose2, protein_backbone_heavy_atoms, atom_id_map );
1432 
1433 }
1434 
1435 //////////////////////////////////////////////////////////////////////////
1436 void
1438  std::map< core::id::AtomID, core::id::AtomID > & atom_id_map ){
1439 
1440  utility::vector1< std::string > protein_backbone_heavy_atoms;
1441  protein_backbone_heavy_atoms.push_back( " N ");
1442  protein_backbone_heavy_atoms.push_back( " CA ");
1443  protein_backbone_heavy_atoms.push_back( " C ");
1444  protein_backbone_heavy_atoms.push_back( " O ");
1445  setup_matching_atoms_with_given_names( pose1, pose2, protein_backbone_heavy_atoms, atom_id_map );
1446 }
1447 
1448 //////////////////////////////////////////////////////////////////////////
1449 void
1451  utility::vector1< std::string > const & atom_names_to_find,
1452  std::map< core::id::AtomID, core::id::AtomID > & atom_id_map ){
1453  using namespace core::id;
1454  using namespace core::conformation;
1455  using namespace core::chemical;
1456 
1457  atom_id_map.clear();
1458 
1459  for (Size i = 1; i <= pose1.total_residue(); i++ ) {
1460  Residue const & rsd1 = pose1.residue( i );
1461  Residue const & rsd2 = pose2.residue( i );
1462  ResidueType const & rsd_type1 = pose1.residue_type( i );
1463  ResidueType const & rsd_type2 = pose2.residue_type( i );
1464 
1465  for ( Size n = 1; n <= atom_names_to_find.size(); n++ ) {
1466  std::string const & atom_name = atom_names_to_find[ n ];
1467 
1468  if ( !rsd_type1.has_atom_name( atom_name ) ) continue;
1469  if ( !rsd_type2.has_atom_name( atom_name ) ) continue;
1470 
1471  Size const j1 = rsd1.atom_index( atom_name );
1472  if( rsd1.is_virtual( j1 )) continue;
1473 
1474  Size const j2 = rsd2.atom_index( atom_name );
1475  if( rsd2.is_virtual( j2 )) continue;
1476 
1477  atom_id_map[ AtomID( j1, i ) ] = AtomID( j2, i ) ;
1478  }
1479  }
1480 }
1481 
1482 /// @detail Computes the RMSD of the jump residues (jump point +/- 1 residue) of
1483 /// <model> and <reference>. Jump residues are identified by scanning <reference>'s
1484 /// FoldTree. Results are stored in the output parameter <rmsds>, keyed by the index
1485 /// of the jump point. For example,
1486 ///
1487 /// Jump 100 => 10
1488 /// rmsds[10] = rmsd(residues 9-11 in reference, residues 9-11 in model)
1489 void compute_jump_rmsd(const core::pose::Pose& reference,
1490  const core::pose::Pose& model,
1491  boost::unordered_map<core::Size, core::Real>* rmsds) {
1492  using core::Size;
1494  assert(rmsds);
1495 
1496  // Identify jump residues
1497  const FoldTree& tree = model.fold_tree();
1498  for (Size i = 1; i <= tree.nres(); ++i) {
1499  if (!tree.is_jump_point(i))
1500  continue;
1501 
1502  // Edge cases at pose start/stop
1503  if ((i - 1) < 1 || (i + 1) > model.total_residue())
1504  continue;
1505 
1506  (*rmsds)[i] = CA_rmsd(reference, model, i - 1, i + 1);
1507  }
1508 }
1509 
1510 } // namespace core
1511 } // namespace scoring