Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
atom_tree_diff.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/import_pose/silent/atom_tree_diff.cc
11 ///
12 /// @brief Silent-file format based on "diffs" of AtomTree DOFs
13 /// @author Ian W. Davis
14 
15 
17 
18 #include <core/types.hh>
23 #include <core/id/AtomID.hh>
24 #include <core/id/DOF_ID.hh>
25 #include <core/io/pdb/file_data.hh>
30 #include <core/kinematics/Jump.hh>
31 #include <core/pose/Pose.hh>
32 #include <core/scoring/Energies.hh>
33 #include <core/scoring/rms_util.hh>
36 #include <basic/Tracer.hh>
37 #include <numeric/angle.functions.hh>
38 #include <numeric/random/random.hh>
39 #include <utility/vector1.hh>
40 #include <utility/io/izstream.hh>
41 
42 #include <algorithm>
43 #include <set>
44 #include <sstream>
45 
46 #define foreach BOOST_FOREACH
47 
48 namespace core {
49 namespace import_pose {
50 namespace atom_tree_diffs {
51 
52 
53 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54 /// @brief Provides a StrictWeakOrdering comparator for sorting elements of a ScoresMap by one particular score type.
55 /// @details Obviously, all entries in the map must have that score type present, or this dies a horrible death.
57 public:
58  typedef ScoresPairList::value_type value_type;
59  ScoreLessThanComparator(std::string const & score_name, bool reverse=false): score_name_(score_name), reverse_(reverse) {}
62  { return reverse_ ^ (a.second[score_name_] < b.second[score_name_]); }
63 private:
65  bool reverse_;
66 };
67 
68 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70  scores_(),
71  tag_idx_(),
72  offsets_(),
73  ref_poses_(),
74  in_(),
75  file_read_(false)
76 {}
77 
78 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80  scores_(),
81  tag_idx_(),
82  offsets_(),
83  ref_poses_(),
84  in_(),
85  file_read_(false)
86 {
87  read_file(filename);
88 }
89 
91  assert( ! file_read_ ); // only read file once, by constructor or elsewhere. can't read multiple files yet
92  in_.open(filename.c_str());
93  core::pose::PoseOP ref_pose;
94  std::set<std::string> used_tags;
95  while(true) {
96  std::string tag;
97  std::map< std::string, core::Real > scores;
98  // in_ is now positioned just after the SCORES line of the *previous* structure
99  // If we use this position, we must call header_from_atom_tree_diff() when re-reading.
100  long curr_pos = in_.tellg();
101  if( ! header_from_atom_tree_diff(in_, tag, scores) ) break;
102  // in_ is now positioned just after the SCORES line of *this* structure
103  // If we use this position, we must NOT call header_from_atom_tree_diff() when re-reading.
104  //long curr_pos = in_.tellg();
105 
106  if( used_tags.count(tag) > 0 ) {
107  basic::Error() << "Tag " << tag << " appears at least twice in the atom_tree_diff file! Discarding structure..." << std::endl;
108  continue;
109  }
110  core::Size const end= tag.find_last_of('_');
111  if( end == std::string::npos){
112  utility_exit_with_message(tag+" doesn't end with a 4-digit code");
113  }
114  std::string ref_tag= tag.substr(0, end);
115  if( scores.find("is_reference_pose") != scores.end() ) {
116  core::pose::Pose empty_pose;
117  ref_pose = new core::pose::Pose();
119  unique_ref_poses_.push_back(ref_pose);
120  core::Size const start= ref_tag.find_first_of('_');
121  ref_tag= ref_tag.substr(start+1);
122  if( ref_tags_.find(ref_tag) != ref_tags_.end() ){
123  basic::Error() << "Tag " << ref_tag << " appears at least twice in the atom_tree_diff file! Discarding reference structure..." << std::endl;
124  continue;
125  }
126  ref_tags_[ref_tag]= 0;
127  ref_poses_[ref_tag] = ref_pose;
128  } else { // not a reference pose, actual data
129  scores_.push_back( std::make_pair(tag, scores) );
130  tag_idx_[tag] = scores_.size();
131  offsets_[tag] = curr_pos;
132  ++ref_tags_[ref_tag];
133  ref_poses_[tag] = ref_pose;
134  // Missing ref_pose will fail hard when trying to read_pose(), so no worries.
135  // Some silent files will deliberately omit a reference pose to reduce size.
136  //if( ref_pose() == NULL ) basic::Error() << "Tag " << tag << " has no reference pose!" << std::endl;
137  }
138  }
139  // Once we've hit EOF, we need to reopen the file before we can successfully seek again.
140  in_.close();
141  in_.clear(); // this is required for Linux, though not OS X
142  in_.open(filename.c_str());
143  file_read_= true;
144 }
145 
147 {
148  in_.close();
149 }
150 
151 bool AtomTreeDiff::has_ref_pose(std::string const & tag) const{
152  return ref_poses_.find(tag) != ref_poses_.end() ;
153 }
154 
155 bool AtomTreeDiff::has_tag(std::string const & tag) const{
156  return tag_idx_.find(tag) != tag_idx_.end();
157 }
158 
159 bool AtomTreeDiff::has_ref_tag(std::string const & tag) const{
160  return ref_poses_.find(tag) != ref_poses_.end();
161 }
162 
163 //static
165  std::string const & score_name,
166  ScoresPairList & scores,
167  bool descending /*=false*/
168 )
169 {
170  std::stable_sort(scores.begin(), scores.end(), ScoreLessThanComparator(score_name, descending));
171 }
172 
173 
175 {
176  if( ref_poses_.find(tag) == ref_poses_.end() || ref_poses_[tag]() == NULL ) {
177  utility_exit_with_message("No reference pose available for "+tag);
178  }
179  read_pose( tag, pose_out, *(ref_poses_[tag]) );
180 }
181 
182 void AtomTreeDiff::read_pose(std::string const & tag, core::pose::Pose & pose_out, core::pose::Pose const & ref_pose)
183 {
184  //std::cout << "Seeking to " << offsets_[tag] << std::endl;
185  in_.seekg( offsets_[tag] );
186  //std::cout << "Now at " << in_.tellg() << std::endl;
187  if( offsets_[tag] != (long)in_.tellg() ) {
188  utility_exit_with_message("Unable to seek in input file!");
189  }
190 
191  std::string tag_reread;
192  Scores scores_reread;
193  if( !core::import_pose::atom_tree_diffs::header_from_atom_tree_diff(in_, tag_reread, scores_reread) || tag != tag_reread ) {
194  utility_exit_with_message("Seek took us to the wrong entry!");
195  }
196  pose_from_atom_tree_diff( in_, ref_pose, pose_out );
197 }
198 
199 
200 // For reasons I don't understand, GCC will not compile this if I mark this "const":
202 {
203  if( ref_poses_.find(tag) == ref_poses_.end() || ref_poses_[tag]() == NULL ) {
204  utility_exit_with_message("No reference pose available for "+tag);
205  }
206  return ref_poses_[tag];
207 }
208 
209 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
211  std::ostream & out,
212  std::string const & pose_tag,
213  std::map< std::string, core::Real > const & scores
214 )
215 {
216  // Repeating the pose tag in the score line is a great convenience
217  // for grepping out score data and later correlating it with a model.
218  out << "SCORES " << pose_tag;
219  foreach(ScorePair pair, scores){
220  // Scores that are very near zero have artificially high precision
221  // when rendered in scientific notation, leading to numerical instability in benchmarks.
222  // Stupid C++ doesn't seem to have a fixed-point output mode
223  // that doesn't also append extra (unneeded) zeros to the end of every float.
224  core::Real val = pair.second;
225  if( std::abs(val) < 1e-8 ) val = 0.0;
226  out << ' ' << pair.first << ' ' << val;
227  }
228  out << '\n';
229 }
230 
231 
232 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
233 ///@details Writes out the given pose in PDB format (plus fold tree).
234 /// When reading back in, this pose will be used as the reference point for all
235 /// subsequent poses, until another reference pose is reached.
237  std::ostream & out,
238  std::string const & pose_tag,
239  Scores const & scores,
240  core::pose::Pose const & pose
241 )
242 {
243  out << "POSE_TAG " << pose_tag << '\n';
244 
245  Scores mod_scores = scores; // a mutable copy
246  mod_scores["is_reference_pose"] = 1;
247  dump_score_line(out, pose_tag, mod_scores);
248 
249  out << "BEGIN_PDB_FORMAT " << pose_tag << '\n';
251  out << "END_PDB_FORMAT " << pose_tag << '\n';
252 
253  // Some variants introduce extra DOFs but do not change the three-letter name.
254  // Useless MUTATE entries will be ignored when reading in.
255  for(Size rsd = 1, rsd_end = pose.total_residue(); rsd <= rsd_end; ++rsd) {
256  out << "MUTATE " << rsd << " " << pose.residue_type(rsd).name() << "\n";
257  }
258 
259  core::kinematics::FoldTree const & foldtree = pose.fold_tree();
260 
261  //basic::OWrapperStream ws(out);
262  out << foldtree; // writes FOLD_TREE ... and its own newline.
263 
264  out << "END_POSE_TAG " << pose_tag << '\n';
265 }
266 
267 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
268 ///@details Writes out the given pose in a atom_tree_diff-type format by only
269 /// recording AtomTree DOFs that differ from ref_pose.
270 /// Thus pose and ref_pose should have the same sequence and AtomTree topology.
271 /// The entry is labeled with the given textual tag and 0+ named numeric scores.
272 /// The number of digits of precision after the decimal point can be specified
273 /// independently for backbone and sidechain.
274 /// More precision reduces propagated coordinate error but increases both the
275 /// number of characters used per value and the total number of values written.
276 /// The default values should be very good for most applications.
278  std::ostream & out,
279  std::string const & pose_tag,
280  std::map< std::string, core::Real > const & scores,
281  core::pose::Pose const & ref_pose_in,
282  core::pose::Pose const & pose,
283  int bb_precision /*= 6*/,
284  int sc_precision /*= 4*/,
285  int bondlen_precision /*= 2*/
286 )
287 {
288  using core::Size;
289  using core::Real;
290  using basic::Warning;
291  using namespace core::id;
292  using namespace core::scoring;
293 
294  if(bb_precision < sc_precision) Warning() << "Crazy fool, bb_precision should be >= sc_precision!" << std::endl;
295  Real bb_tol = 1.0, sc_tol = 1.0, bondlen_tol = 1.0;
296  for(int i = 0; i < bb_precision; ++i) bb_tol /= 10.0;
297  for(int i = 0; i < sc_precision; ++i) sc_tol /= 10.0;
298  for(int i = 0; i < bondlen_precision; ++i) bondlen_tol /= 10.0;
299 
300  core::kinematics::AtomTree const & atom_tree = pose.atom_tree();
301  core::kinematics::FoldTree const & foldtree = pose.fold_tree();
302 
303  out << "POSE_TAG " << pose_tag << '\n';
304  dump_score_line(out, pose_tag, scores);
305 
306  // Also diff sequence, by transforming copy of ref_pose
307  // to match seq. of pose, then computing atom_tree diffs.
308  core::pose::Pose ref_pose(ref_pose_in);
309  for(Size rsd = 1, rsd_end = pose.total_residue(); rsd <= rsd_end; ++rsd) {
310  if( pose.residue_type(rsd).name() == ref_pose.residue_type(rsd).name() ) continue;
311  using namespace core::conformation;
312  ResidueOP newres = ResidueFactory::create_residue(pose.residue_type(rsd), ref_pose.residue(rsd), ref_pose.conformation());
313  ref_pose.replace_residue(rsd, *newres, true /*orient backbone*/);
314  out << "MUTATE " << rsd << " " << pose.residue_type(rsd).name() << "\n";
315  }
316 
317  // Needed for custom foldtrees in docking. Hasn't been tested yet...
318  // Probably want to set the fold tree before setting any DOFs, so we put it near the top.
319  out << foldtree; // writes FOLD_TREE ... and its own newline.
320 
321  // Save stream state
322  // We use fixed # of digits after the decimal because phi and theta
323  // are in radians, so all DOF values fall within the range [-4,4].
324  std::ios_base::fmtflags orig_flags = out.flags();
325  std::streamsize orig_precision = out.precision();
326  out.setf( std::ios_base::fixed );
327 
328  // DOFs for bonded atoms
329  for(Size rsd = 1, rsd_end = pose.total_residue(); rsd <= rsd_end; ++rsd) {
330  bool const is_jump_residue = foldtree.is_jump_point(rsd);
331  for(Size atom = 1, atom_end = pose.residue(rsd).natoms(); atom <= atom_end; ++atom) {
332  AtomID aid(atom, rsd);
333  DOF_ID dof_phi(aid, PHI), dof_theta(aid, THETA), dof_d(aid, D);
334  if( atom_tree.atom(aid).is_jump() ) {
335  // Jump atoms have the rbN values all set to zero -- maybe vestigal part of atom tree?
336  } else {
337  // Backbone heavyatoms have to be very precise, or else a lot of error
338  // can propagate to the end of the chain.
339  // Sidechain atoms and hydrogens don't have to worry nearly so much.
340  // (Except for jump residues, where the stubs on either end must be very precise!)
341  bool is_backbone = is_jump_residue // i.e. things should be "backbone" if they're anchors for a jump!
342  || (pose.residue(rsd).atom_type(atom).is_heavyatom() && atom <= pose.residue(rsd).last_backbone_atom());
343  int precision = (is_backbone ? bb_precision : sc_precision);
344  Real tol = (is_backbone ? bb_tol : sc_tol);
345 
346  Real before_phi = ref_pose.dof(dof_phi), before_theta = ref_pose.dof(dof_theta), before_d = ref_pose.dof(dof_d);
347  Real after_phi = pose.dof(dof_phi), after_theta = pose.dof(dof_theta), after_d = pose.dof(dof_d);
348  // Format: resno atomno phi [theta [d]], only for atoms with changed DOFs
349  // Phi comes first because dihedrals change most often.
350  // Theta comes next because in most cases bond angles don't change, so we can omit it!
351  // D comes last and requires least precision, because it doesn't control a lever-arm effect.
352  bool const changed_phi = (std::abs(numeric::nearest_angle_radians(after_phi, before_phi) - before_phi) > tol); // otherwise get bogus diffs near pi
353  bool const changed_theta = (std::abs(after_theta - before_theta) > tol); // rarely near pi, so I haven't put in the check
354  bool const changed_d = (std::abs(after_d - before_d) > bondlen_tol);
355  if( changed_phi || changed_theta || changed_d ) {
356  out.precision( precision );
357  out << rsd << ' ' << atom;
358  //out << ' ' << pose.residue(rsd).name() << ' ' << pose.residue(rsd).atom_name(atom); // debugging
359  out << ' ' << after_phi;
360  if( changed_theta || changed_d ) {
361  out << ' ' << after_theta;
362  if( changed_d ) {
363  out.precision( bondlen_precision );
364  out << ' ' << after_d;
365  }
366  }
367  out << '\n';
368  }
369  }// end non-jump atom
370  }// end loop over atoms
371  }// end loop over residues
372 
373  // DOFs for jumps
374  for(int jump = 1, jump_end = pose.num_jump(); jump <= jump_end; ++jump) {
375  out << "JUMP " << jump;
376  out.precision( 12 ); // matrix needs to be very exact
377  for ( int i = 1; i <= 3; ++i ) {
378  for ( int j = 1; j <= 3; ++j ) {
379  out << ' ' << pose.jump(jump).get_rotation()(i,j);
380  }
381  }
382  out.precision( 4 ); // distance needs one more decimal than PDB coords, max
383  for ( int i = 1; i <= 3; ++i ) {
384  out << ' ' << pose.jump(jump).get_translation()(i);
385  }
386  out << '\n';
387  }
388 
389  // Explicit END_POSE_TAG is a good safeguard against file corruption, where
390  // a process gets killed halfway through outputting a pose.
391  // The missing END_POSE_TAG line(s) and/or POSE_TAG occuring in the middle of a line
392  // are signs of this kind of file corruption (should be repairable by hand).
393  out << "END_POSE_TAG " << pose_tag << '\n';
394 
395  // Restore stream state
396  out.flags( orig_flags );
397  out.precision( orig_precision );
398 }
399 
400 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
401 ///@details Reads from the current stream position until it finds both a
402 /// pose_tag line and a scores line, then extracts the data and returns it.
403 /// Returns true on success and false on failure.
405  std::istream & in,
406  std::string & pose_tag_out,
407  Scores & scores_out
408 )
409 {
410  scores_out.clear();
411  bool found_tag = false, found_scores = false;
412  while( in.good() && !( found_tag && found_scores ) ) {
413  std::string line, key;
414  core::Real value;
415  getline(in, line);
416  if( in.fail() ) return false;
417  std::istringstream is(line);
418  is >> key;
419  if( key == "POSE_TAG" ) {
420  found_tag = true;
421  is >> pose_tag_out;
422  } else if ( key == "SCORES" ) {
423  is >> key; // discard redundant pose_tag field
424  found_scores = true;
425  while( is.good() ) {
426  is >> key >> value;
427  if( is.fail() ) break;
428  scores_out[ key ] = value;
429  }
430  }
431  // else just ignore and discard this line
432  }
433  return ( found_tag && found_scores );
434 }
435 
436 
437 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
438 ///@details Extracts a pose-diff and sets the DOFs of "pose" accordingly,
439 /// working from the current stream position. Use header_from_atom_tree_diff()
440 /// to locate the pose you wish to extract prior to calling this function.
441 /// Returns false if there is some sort of IO or format error.
443  std::istream & in,
444  core::pose::Pose const & ref_pose,
445  core::pose::Pose & pose
446 )
447 {
449  using namespace core::id;
450  using namespace core::scoring;
451 
452  // start with pose as a copy of ref_pose:
453  pose = ref_pose; // deep copy
454 
455  static basic::Tracer TR("core.import_pose.atom_tree_diffs.atom_tree_diff.pose_from_atom_tree_diff");
456  while( in.good() ) {
457  std::string line, key;
458  getline(in, line);
459  if( in.fail() ) {
460  TR << "getline() failed" << std::endl;
461  return false;
462  }
463  //std::cout << " " << line << std::endl; // for debugging
464  std::istringstream is(line);
465  // Start by assuming it will be an atom line, then backtrack if not
466  core::Size rsd_no, atom_no;
467  is >> rsd_no >> atom_no;
468  if( is.fail() ) {
469  //TR << "oops, not an atom line!" << std::endl;
470  //TR << ">> " << line << std::endl;
471  is.clear();
472  is.seekg(0, std::ios::beg);
473  is >> key;
474  if( key == "END_POSE_TAG" ) return true;
475  // I changed to uppercase for format consistency on 6 Dec 2007.
476  // Check for the deprecated lowercase version could eventually be removed.
477  else if( key == "JUMP" || key == "jump" ) {
478  core::Size jump_no;
479  is >> jump_no;
480  if( is.fail() || jump_no < 1 || jump_no > pose.num_jump() ) {
481  TR << "uh-oh, pose doesn't have a jump " << jump_no << std::endl;
482  } else {
483  Jump::Matrix mat;
484  Jump::Vector vec;
485  Jump jump;
486  for ( int i = 1; i <= 3; ++i ) {
487  for ( int j = 1; j <= 3; ++j ) {
488  is >> mat(i,j);
489  }
490  }
491  for ( int i = 1; i <= 3; ++i ) {
492  is >> vec(i);
493  }
494  if( is.fail() ) {
495  TR << "error reading in jump data for jump " << jump_no << std::endl;
496  } else {
497  jump.set_rotation(mat);
498  jump.set_translation(vec);
499  pose.set_jump(jump_no, jump);
500  }
501  }
502  } else if( key == "MUTATE" ) {
503  core::Size resnum;
504  std::string resname;
505  is >> resnum >> resname;
506  if( is.fail() ) {
507  TR << "error reading sequence mutation data" << std::endl;
508  } else if( resnum < 1 || resnum > pose.total_residue() ) {
509  TR << "d'oh, pose doesn't have a residue " << resnum << std::endl;
510  } else if( !pose.residue(resnum).residue_type_set().has_name(resname) ) {
511  TR << "unrecognized residue type name '" << resname << "'" << std::endl;
512  } else if( pose.residue_type(resnum).name() == resname ) {
513  // These will happen routinely when reading a reference pose,
514  // where the entire sequence is specified explicitly.
515  TR.Debug << "ignoring no-op mutation: MUTATE " << resnum << " " << resname << std::endl;
516  } else {
517  using namespace core::conformation;
519  // if can't find residue name, name_map() calls exit()
520  pose.residue(resnum).residue_type_set().name_map(resname),
521  pose.residue(resnum), pose.conformation());
522  pose.replace_residue(resnum, *newres, true /*orient backbone*/);
523  }
524  } else if( key == "FOLD_TREE" ) {
525  // This is typically present only when using embedded PDB format (see below).
527  is.clear();
528  is.seekg(0, std::ios::beg);
529  is >> foldtree;
530  if( !is.fail() && Size(foldtree.nres()) == pose.total_residue() ) {
531  pose.fold_tree(foldtree);
532  } else {
533  TR << "danger danger, error reading fold tree" << std::endl;
534  }
535  } else if( key == "BEGIN_PDB_FORMAT" ) {
536  // Just an embedded PDB-format file, separated by delimiters.
537  // This is currently used for writing reference structures for the diffs,
538  // but could also be used in cases where a diff just isn't efficient.
539  using namespace core::chemical;
540  using namespace core::import_pose;
541  std::string const end_pdb_key = "END_PDB_FORMAT";
542  std::vector< io::pdb::Record > pdb_data;
543  while( in.good() ) {
544  getline(in, line);
545  if( in.fail() ) {
546  TR << "getline() failed while reading embedded PDB" << std::endl;
547  return false;
548  }
549  if( line.size() >= end_pdb_key.size() && line.compare(0, end_pdb_key.size(), end_pdb_key) == 0 ) break; // my kingdom for startswith()!
550  // I can't figure out if getline() might leave behind a \n or \r\n,
551  // but all real PDB records are longer than 2 characters anyway.
552  else if( line.size() > 2 ) pdb_data.push_back( io::pdb::PDB_DReader::mapStringToRecord(line) );
553  }
555  fd.filename = "atom_tree_diff.pdb"; // I'm afraid to leave this empty...
556  pose.clear();
557  core::import_pose::build_pose(fd, pose, *(ChemicalManager::get_instance()->residue_type_set( FA_STANDARD )));
558  }
559  } else { // it's an atom line...
560  if( rsd_no < 1 || rsd_no > pose.total_residue() ) {
561  TR << "uh-oh, pose doesn't have a residue " << rsd_no << std::endl;
562  } else if( atom_no < 1 || atom_no > pose.residue_type(rsd_no).natoms() ) {
563  TR << "uh-oh, residue " << rsd_no << " doesn't have an atom " << atom_no << std::endl;
564  } else {
565  core::Real phi_value, theta_value, d_value;
566  //TR << "setting dofs for " << rsd_no << " " << atom_no << " ...";
567  AtomID aid(atom_no, rsd_no);
568  DOF_ID dof_phi(aid, PHI), dof_theta(aid, THETA), dof_d(aid, D);
569  is >> phi_value;
570  if( !is.fail() ) {
571  //TR << " phi";
572  pose.set_dof( dof_phi, phi_value );
573  is >> theta_value;
574  if( !is.fail() ) {
575  //TR << " theta";
576  pose.set_dof( dof_theta, theta_value );
577  is >> d_value;
578  if( !is.fail() ) {
579  //TR << " d (!)";
580  pose.set_dof( dof_d, d_value );
581  }
582  }
583  }
584  else TR << "somebody screwed up ... no phi to set for " << rsd_no << " " << atom_no << " !" << std::endl;
585  //TR << std::endl;
586  }
587  }
588  }
589  TR << "beeg trouble for moose and squirrel -- reached EOF" << std::endl;
590  return false;
591 }
592 
593 
594 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
595 ///@brief Helper for dump_atom_tree_diff(), fills map with weighted score terms.
597  core::pose::Pose & pose,
598  core::scoring::ScoreFunction const & sfxn,
599  Scores & scores_out
600 )
601 {
602  using namespace core::scoring;
603 
604  core::Real const tot_score = sfxn( pose );
605  /// Now handled automatically. sfxn.accumulate_residue_total_energies( pose );
606 
607  // Which score terms to use
608  typedef utility::vector1<ScoreType> ScoreTypeVec;
609  ScoreTypeVec score_types;
610  for(int i = 1; i <= n_score_types; ++i) {
611  ScoreType ii = ScoreType(i);
612  if ( sfxn.has_nonzero_weight(ii) ) score_types.push_back(ii);
613  }
614 
615  scores_out.clear();
616  foreach(ScoreType score_type, score_types){
617  scores_out[ name_from_score_type(score_type) ] = ( sfxn.get_weight(score_type) * pose.energies().total_energies()[ score_type ] );
618  }
619  scores_out[ name_from_score_type(core::scoring::total_score) ] = tot_score;
620 }
621 
622 
623 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
624 ///@details Copies the pose and adds random noise to the AtomTree DOFs
625 /// in the Nth digit (specified by bb_precision and sc_precision).
626 /// This simulates the roundoff error introduced by writing an atom_tree diff
627 /// to file and then reconstructing a pose from it.
628 /// Backbone needs to be more precise than sidechains because in typical foldtrees
629 /// it propagates errors over a much longer distance (i.e. the whole protein chain
630 /// rather than just to the end of the sidechain).
631 /// Using 200-500 residue single-chain globular proteins with one ligand each,
632 /// 6 digits of backbone precision and 4 digits of sidechain precision give
633 /// RMS coordinate errors of 0.0001 to 0.0003. Since this is smaller than
634 /// the least significant digit in a PDB file, it should have an imperceptible
635 /// effect on the final structure.
636 /// Even in release mode, this function takes a long time: 30 sec to 1 minute.
638  core::pose::Pose const & ref_pose,
639  int bb_precision /*= 6*/,
640  int sc_precision /*= 4*/
641 )
642 {
643  using core::Size;
644  using core::Real;
645  using basic::T;
646  using basic::Warning;
647  using numeric::random::RG;
648  using namespace core::id;
649  using namespace core::scoring;
650 
651  if(bb_precision < sc_precision) Warning() << "Crazy fool, bb_precision should be >= sc_precision!" << std::endl;
652  Real bb_tol = 1.0, sc_tol = 1.0;
653  for(int i = 0; i < bb_precision; ++i) bb_tol /= 10.0;
654  for(int i = 0; i < sc_precision; ++i) sc_tol /= 10.0;
655 
656  core::pose::Pose pose(ref_pose);
657  core::kinematics::AtomTree const & atom_tree = pose.atom_tree();
658  core::kinematics::FoldTree const & foldtree = pose.fold_tree();
659 
660  for(Size rsd = 1, rsd_end = pose.total_residue(); rsd <= rsd_end; ++rsd) {
661  bool const is_jump_residue = foldtree.is_jump_point(rsd);
662  for(Size atom = 1, atom_end = pose.residue(rsd).natoms(); atom <= atom_end; ++atom) {
663  AtomID aid(atom, rsd);
664  DOF_ID dof_phi(aid, PHI), dof_theta(aid, THETA), dof_d(aid, D);
665  if( atom_tree.atom(aid).is_jump() ) {
666  // Jump atoms have the rbN values all set to zero -- maybe vestigal part of atom tree?
667  } else {
668  // Backbone heavyatoms have to be very precise, or else a lot of error
669  // can propagate to the end of the chain.
670  // Sidechain atoms and hydrogens don't have to worry nearly so much.
671  //bool is_backbone = pose.residue(rsd).atom_type(atom).is_heavyatom() && atom <= pose.residue(rsd).last_backbone_atom();
672  bool is_backbone = is_jump_residue // i.e. things should be "backbone" if they're anchors for a jump!
673  || (pose.residue(rsd).atom_type(atom).is_heavyatom() && atom <= pose.residue(rsd).last_backbone_atom());
674  //Real precision = (is_backbone ? bb_precision : sc_precision);
675  Real tol = (is_backbone ? bb_tol : sc_tol);
676 
677  // Introduce random error into our copy pose, +/- tol/2
678  pose.set_dof(dof_phi, pose.dof(dof_phi) + tol * (RG.uniform() - 0.5));
679  pose.set_dof(dof_theta, pose.dof(dof_theta) + tol * (RG.uniform() - 0.5));
680  pose.set_dof(dof_d, pose.dof(dof_d) + tol * (RG.uniform() - 0.5));
681  }// end non-jump atom
682  }// end loop over atoms
683  }// end loop over residues
684 
685  T("rms_error_with_noise") << "bb=" << bb_precision << "," << bb_tol << " sc=" << sc_precision << "," << sc_tol
686  << " rms_no_super=" << rmsd_no_super(ref_pose, pose, is_heavyatom) << " rms_with_super=" << rmsd_with_super(ref_pose, pose, is_heavyatom)
687  << " polymer_rms_no_super=" << rmsd_no_super(ref_pose, pose, is_polymer_heavyatom) << " polymer_rms_with_super=" << rmsd_with_super(ref_pose, pose, is_polymer_heavyatom)
688  << std::endl;
689 }
690 
691 ///@brief Test if given file is an atom_tree_diff
693  utility::io::izstream infile( filename );
694  return file_is_atom_tree_diff( infile );
695 }
696 
697 ///@brief Test if given stream is an atom_tree_diff
698 ///@details If everything goes right, after the call, the read position should be at the same place it was to start with
699 bool file_is_atom_tree_diff( std::istream & in ) {
700  bool retval = false;
701  std::streampos startpos(in.tellg());
702  std::string ignored_pose_tag;
703  Scores ignored_scores;
704  // There's probably a better heuristic
705  retval = header_from_atom_tree_diff(in, ignored_pose_tag, ignored_scores);
706  in.seekg(startpos);
707  return retval;
708 }
709 
710 } // atom_tree_diffs
711 } // import_pose
712 } // core