Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RotamerDots.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/pack/interaction_graph/RotamerDots.cc
11 /// @brief RotamerDots classes files - ported from rosetta++
12 /// @author Andrew Leaver-Fay
13 /// @author Ron Jacak
14 
15 // Unit Headers
20 #include <core/scoring/sasa.hh>
21 #include <basic/Tracer.hh>
22 #include <core/types.hh>
23 
24 
26 
27 // ObjexxFCL Headers
28 #include <ObjexxFCL/ubyte.hh>
29 #include <ObjexxFCL/format.hh>
30 #include <ObjexxFCL/FArray1.hh>
31 
32 // Numeric Headers
33 #include <numeric/constants.hh> // pi
34 #include <numeric/xyzVector.hh> // to get distance
35 // AUTO-REMOVED #include <numeric/xyzVector.io.hh>
36 
37 // Utility Headers
38 #include <utility/vector1.hh>
39 #include <utility/vector1.functions.hh>
40 // AUTO-REMOVED #include <utility/string_util.hh>
41 
42 // C++ Headers
43 // AUTO-REMOVED #include <cstring>
44 #include <vector>
45 // AUTO-REMOVED #include <fstream>
46 #include <iostream>
47 
49 #include <utility/options/BooleanVectorOption.hh>
50 #include <ObjexxFCL/FArray2D.hh>
51 #include <boost/algorithm/string/erase.hpp>
52 
53 
54 static basic::Tracer TR_DS("core.pack.interaction_graph.RotamerDots.DotSphere");
55 static basic::Tracer TR_RD("core.pack.interaction_graph.RotamerDots.RotamerDots");
56 static basic::Tracer TR_RDC("core.pack.interaction_graph.RotamerDots.RotamerDotsCache");
57 static basic::Tracer TR_RDRD("core.pack.interaction_graph.RotamerDots.RotamerDotsRadiusData");
58 
59 
60 using namespace ObjexxFCL::fmt;
61 
62 namespace core {
63 namespace pack {
64 namespace interaction_graph {
65 
66 
67 bool unpack_ubyte( ObjexxFCL::ubyte const & value, core::Size which_bit ) {
68 
69  switch ( which_bit ) {
70  case 0 :
71  return value & static_cast< ObjexxFCL::ubyte >(0x01);
72  case 1 :
73  return value & static_cast< ObjexxFCL::ubyte >(0x02);
74  case 2 :
75  return value & static_cast< ObjexxFCL::ubyte >(0x04);
76  case 3 :
77  return value & static_cast< ObjexxFCL::ubyte >(0x08);
78  case 4 :
79  return value & static_cast< ObjexxFCL::ubyte >(0x10);
80  case 5 :
81  return value & static_cast< ObjexxFCL::ubyte >(0x20);
82  case 6 :
83  return value & static_cast< ObjexxFCL::ubyte >(0x40);
84  case 7 :
85  return value & static_cast< ObjexxFCL::ubyte >(0x80);
86  default :
87  utility_exit(); // this should never happen
88  }
89 
90  return false;
91 }
92 
93 void write_sphere_list_header( std::ostream & ostr, std::string const & color, bool off = false ) {
94 
95  ostr << "@spherelist color= " << color << " radius= 0.1";
96  if ( off ) {
97  ostr << " off";
98  }
99  ostr << "\n";
100 }
101 
102 void write_dot( std::ostream & ostr, core::Vector const & center, core::Real radius, Size const dot_index, std::string const & dot_name ) {
103  Vector coord = center + radius * RotamerDots::dot_coord( dot_index );
104  ostr << "{" << dot_name << "} P " << coord.x() << " " << coord.y() << " " << coord.z() << "\n";
105 }
106 
107 
108 void
110  std::ostream & ostr,
111  std::string const & label,
112  std::string const & color,
113  core::Vector const & center,
114  core::Real radius,
115  utility::vector1< ObjexxFCL::ubyte > const & dot_masks
116 )
117 {
118  bool first = true;
119  Size count = 1;
120  std::string name = label;
121  for ( Size ii = 1; ii <= 21; ++ii ) {
122  for ( Size jj = 0; jj < 8; ++jj ) {
123  if ( unpack_ubyte( dot_masks[ ii ], jj ) ) {
124  if ( first ) {
125  first = false;
126  write_sphere_list_header( ostr, color );
127  write_dot( ostr, center, radius, count, name );
128  name = "\"";
129  } else {
130  write_dot( ostr, center, radius, count, name );
131  }
132  }
133  ++count;
134  if ( count == 163 ) break;
135  }
136  if ( count == 163 ) break;
137  }
138 }
139 
140 void write_sphere_list_farray( std::ostream & ostr, std::string const & label, std::string const & color,
141  core::Vector const & center, core::Real radius, ObjexxFCL::FArray1< ObjexxFCL::ubyte > const & dot_masks ) {
142 
143  bool first = true;
144  Size count = 1;
145  std::string name = label;
146  for ( Size ii = 1; ii <= 21; ++ii ) {
147  for ( Size jj = 0; jj < 8; ++jj ) {
148  if ( unpack_ubyte( dot_masks( ii ), jj ) ) {
149  if ( first ) {
150  first = false;
151  write_sphere_list_header( ostr, color );
152  write_dot( ostr, center, radius, count, name );
153  name = "\"";
154  } else {
155  write_dot( ostr, center, radius, count, name );
156  }
157  }
158  ++count;
159  if ( count == 163 ) break;
160  }
161  if ( count == 163 ) break;
162  }
163 }
164 
165 
166 
167 //----------------------------------------------------------------------------//
168 //----------------------------- Dot Sphere Class -----------------------------//
169 //----------------------------------------------------------------------------//
170 
171 ///
172 /// @begin DotSphere::DotSphere
173 ///
174 /// @brief
175 /// default constructor, initializes all dot counts to zero
176 ///
177 DotSphere::DotSphere() :
178  dots_coverage_count_(),
179  num_covered_(0),
180  num_covered_current_( false )
181 {
182  zero();
183 }
184 
185 
186 ///
187 /// @begin DotSphere::~DotSphere
188 ///
190 
191 
192 ///
193 /// @begin DotSphere::DotSphere
194 ///
195 /// @brief
196 /// copy constructor
197 ///
198 /// @detailed
199 /// memcpy is much faster than the FArray operator =
200 ///
205 }
206 
207 
208 ///
209 /// @begin DotSphere::operator=
210 ///
211 /// @brie=
212 /// assignment operator
213 ///
214 DotSphere const & DotSphere::operator= ( DotSphere const & rhs ) {
218  return *this;
219 }
220 
221 
222 ///
223 /// @begin DotSphere::operator!=
224 ///
225 /// @brief
226 /// Comparison operator. Using this in debugging. When alternate state rotamer dots is not equal to current state
227 /// rotamer dots, then I print some extra debugging information. But this could be useful for other purposes, too.
228 /// Since RotamerDots objects contain DotSphere objects, to compare RD objects, this class needs its own comparison
229 /// operator, too.
230 ///
231 bool DotSphere::operator!= ( DotSphere const & rhs ) {
232 
234  return true;
235  for ( Size ii=0; ii < NUM_BYTES_IN_DOT_SPHERE_OVERLAP_ARRAYS; ++ii ) {
236  for ( Size jj=0; jj < 8; ++jj ) {
237  Size ii8_jj = ii*8 + jj;
238  if ( dots_coverage_count_[ ii8_jj ] != rhs.dots_coverage_count_[ ii8_jj ] ) {
239  return true;
240  }
241  }
242  }
243 
244  return false;
245 }
246 
247 ///
248 /// @begin DotSphere::zero
249 ///
250 /// @detailed
251 /// sets the dot coverage counts to zero for all dots
252 /// memset is fast -- a lot of time is spent in this function so I'm using c-style arrays instead of the FArrays
253 ///
255  if ( num_covered_current_ && num_covered_ == 0 )
256  return;
258  num_covered_ = 0;
259  num_covered_current_ = true;
260 }
261 
262 
263 ///
264 /// @begin DotSphere::increment_count
265 ///
266 /// @brief
267 /// increment the count for the dots using an input ubyte array.
268 ///
269 /// @detailed
270 /// Each bit in this ubyte array corresponds to a single dot on the surface of this sphere. Dot coverage counts are
271 /// incremented for dots whose corresponding bits in the ubyte array are '1'. dots_coverage_count_ is C-style array
272 /// of unsigned chars. So, index 0 returns the first char (or one byte), index 20*8+7, or 167, is the last char/byte.
273 ///
274 /// @param
275 /// overlap_mask - a utility::vector1 of size 21 that holds ObjexxFCL ubytes. overlap_mask[ bb ] will return a single ubyte
276 /// which will determine whether the dots for that region of the vector should be incremented. Because it's a vector1
277 /// and this method uses a 0-based array, we have to remember to convert the array index to 1-based before looking at
278 /// what's in overlap_mask.
279 ///
281 
282  // for ( j = 1; val && j <= 0x80; j <<= 1 )
283  // In this example, j is going to be 1, then 2, 4, 8, 16, 32, 64 and finally 128 as the loop progresses.
284  // In binary, that's 0000:0001, 0000:0010, 0000:0100, 0000:1000, 0001:0000, 0010:0000, 0100:0000 and 1000:0000.
285  // Since there's no way to specify binary constants in C++, it's clearer to use Hex: 0x01, 0x02, 0x04, 0x08, 0x10,
286  // 0x20, 0x40, and 0x80.
287  // So bitwise AND with 0x04, is bitwise AND with 0000:0100 which returns either 0000:0100 or 0000:0000. We case that
288  // to a bool (which is a byte), which gives 0000:0001 or 0000:0000, which we then cast back to an unsigned char
289  // because that's what the type is in dots_coverage_count_. The reason we do this is because we want to increment
290  // the count at the bit location of dots_coverage_count regardless if the value is 0010:0000 or 0000:0001. If we tried
291  // to add 0000:1000 to the dots_coverage_count bit location, we'd be adding '8' and not '1' to that location.
292  // This is just one way to do this; there are definitely other ways.
293 
294  for ( Size bb = 0; bb < NUM_BYTES_IN_DOT_SPHERE_OVERLAP_ARRAYS; ++bb ) {
295  const Size bb8 = bb*8;
296  dots_coverage_count_[ bb8 + 0 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x01));
297  dots_coverage_count_[ bb8 + 1 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x02));
298  dots_coverage_count_[ bb8 + 2 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x04));
299  dots_coverage_count_[ bb8 + 3 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x08));
300  dots_coverage_count_[ bb8 + 4 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x10));
301  dots_coverage_count_[ bb8 + 5 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x20));
302  dots_coverage_count_[ bb8 + 6 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x40));
303  dots_coverage_count_[ bb8 + 7 ] += static_cast <unsigned char> ( static_cast<bool> (overlap_mask[ bb+1 ] & 0x80));
304  }
305 
306  //std::cout << "dots_coverage_count_: ";
307  //print( std::cout );
308 
309  num_covered_current_ = false;
310 }
311 
312 
313 ///
314 /// @begin DotSphere::get_num_uncovered
315 ///
316 /// @brief
317 /// returns the total number of dots on this atom whose coverage count is 0
318 ///
319 /// @detailed
320 /// if the coverage count has not been modified since the last time the number of covered dots was counted, then the
321 /// method uses the cached result.
322 ///
324  if ( ! num_covered_current_ ) {
326  }
327  return NUM_DOTS_TOTAL - num_covered_;
328 }
329 
330 
331 ///
332 /// @begin DotSphere::get_num_covered
333 ///
334 /// @brief
335 /// returns the total number of dots on this atom with a non-zero coverage count
336 ///
337 /// @detailed
338 /// if the coverage count has not been modified since the last time the number of covered dots was counted, then the
339 /// method uses the cached result
340 ///
342  if ( ! num_covered_current_ )
344  return num_covered_;
345 }
346 
347 
348 ///
349 /// @begin DotSphere::count_num_covered
350 ///
351 /// @brief
352 /// iterates across all dots and stores the number with a non-zero coverage count for later use
353 ///
354 /// @detailed
355 /// both num_covered_ and num_covered_current_ are declared mutable so that they may be modified in this const method
356 ///
358 
359  num_covered_ = 0;
360  //TR_DS << "count_num_covered(): counts not current. coverage_counts_: " << std::endl;
361  for ( Size ii=0; ii < NUM_DOTS_TOTAL; ++ii ) {
362  //if ( ii % 8 == 0 ) TR_DS << " ";
363  if ( dots_coverage_count_[ ii ] != 0 ) {
364  num_covered_++;
365  //TR_DS << "1";
366  }
367  }
368  //TR_DS << std::endl;
369  num_covered_current_ = true;
370 }
371 
372 
373 ///
374 /// @begin DotSphere::operator -=
375 ///
376 /// @brief
377 /// decrements the coverage count for this sphere by the coverage count of the rhs sphere
378 ///
380  num_covered_current_ = false;
381  for ( Size ii = 0; ii < NUM_COUNTS_TO_ALLOCATE; ++ii ) {
382  dots_coverage_count_[ ii ] -= rhs.dots_coverage_count_[ ii ];
383  }
384  return *this;
385 }
386 
387 
388 ///
389 /// @begin DotSphere::operator +=
390 ///
391 /// @brief
392 /// increments the coverage count for this sphere by the coverage count of the rhs sphere
393 ///
395  num_covered_current_ = false;
396  for (Size ii = 0; ii < NUM_COUNTS_TO_ALLOCATE; ++ii) {
397  dots_coverage_count_[ ii ] += rhs.dots_coverage_count_[ ii ];
398  }
399  return *this;
400 }
401 
402 
403 ///
404 /// @begin DotSphere::get_dot_covered
405 ///
406 /// @brief
407 /// Returns a boolean indicating whether the given dot is covered. Note, this function takes in a 1-based dot-index
408 /// and converts that to 0-based for the C-style array used by this class.
409 ///
410 bool DotSphere::get_dot_covered( Size dot_index ) const {
411  assert( dot_index > 0 && dot_index <= NUM_DOTS_TOTAL );
412  return ( dots_coverage_count_[ dot_index - 1 ] != 0 );
413 }
414 
415 
416 ///
417 /// @begin DotSphere::write_to_compact_array
418 ///
419 /// @brief
420 /// note, this method results in loss of information; counts > 1 are truncated to 1.
421 /// bitwise OR with 0000:0001 results in 0000:0001.
422 ///
424 
425  for ( Size ii=0; ii < NUM_BYTES_IN_DOT_SPHERE_OVERLAP_ARRAYS; ++ii ) {
426  Size bb8 = ii*8;
427  if ( dots_coverage_count_[ bb8 + 0 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x01);
428  if ( dots_coverage_count_[ bb8 + 1 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x02);
429  if ( dots_coverage_count_[ bb8 + 2 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x04);
430  if ( dots_coverage_count_[ bb8 + 3 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x08);
431  if ( dots_coverage_count_[ bb8 + 4 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x10);
432  if ( dots_coverage_count_[ bb8 + 5 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x20);
433  if ( dots_coverage_count_[ bb8 + 6 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x40);
434  if ( dots_coverage_count_[ bb8 + 7 ] > 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x80);
435  }
436 }
437 
439 {
440  /// convention; the dots that do not exist are not to be considered exposed.
441  /// the first two bytes in the 21st position describe dots 161 and 162; the remaining
442  /// dots describe 6 dots that do not exist... even if their coverage counts are 0, do not
443  /// report that they are exposed!
444  std::fill( compact.begin(), compact.end(), static_cast< ObjexxFCL::ubyte > (0) );
445  for ( Size ii=0; ii < NUM_BYTES_IN_DOT_SPHERE_OVERLAP_ARRAYS - 1; ++ii ) {
446  Size bb8 = ii*8;
447  if ( dots_coverage_count_[ bb8 + 0 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x01);
448  if ( dots_coverage_count_[ bb8 + 1 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x02);
449  if ( dots_coverage_count_[ bb8 + 2 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x04);
450  if ( dots_coverage_count_[ bb8 + 3 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x08);
451  if ( dots_coverage_count_[ bb8 + 4 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x10);
452  if ( dots_coverage_count_[ bb8 + 5 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x20);
453  if ( dots_coverage_count_[ bb8 + 6 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x40);
454  if ( dots_coverage_count_[ bb8 + 7 ] == 0 ) compact[ ii+1 ] |= static_cast< ObjexxFCL::ubyte > (0x80);
455  }
456  Size const last = NUM_BYTES_IN_DOT_SPHERE_OVERLAP_ARRAYS - 1;
457  Size const lastx8 = 8 * last;
458  if ( dots_coverage_count_[ lastx8 + 0 ] == 0 ) compact[ last+1 ] |= static_cast< ObjexxFCL::ubyte > (0x01);
459  if ( dots_coverage_count_[ lastx8 + 1 ] == 0 ) compact[ last+1 ] |= static_cast< ObjexxFCL::ubyte > (0x02);
460 
461 }
462 
463 ///
464 /// @begin DotSphere::print
465 ///
466 /// @brief
467 /// Writes coverage counts to the output stream. if a dot is covered by 10 or more residues, prints 9 to the output stream instead.
468 /// Useful for debugging.
469 ///
470 void DotSphere::print( std::ostream & os ) const {
471 
472  for ( Size ii=0; ii < NUM_COUNTS_TO_ALLOCATE; ++ii ) {
473  if ( ii % 16 == 0 )
474  os << ii+1 << ":";
475  if ( dots_coverage_count_[ii] < 10 ) {
476  os << (Size)dots_coverage_count_[ii];
477  } else os << "9";
478 
479  if (ii % 8 == 7)
480  os << " ";
481  }
482  os << std::endl;
483  return;
484 }
485 
486 ///
487 /// @begin operator<< ( ostream, DotSphere)
488 ///
489 /// @brief
490 /// invokes print on the input DotSphere object
491 ///
492 std::ostream & operator<< ( std::ostream & os, DotSphere const & ds ) {
493  ds.print(os);
494  return os;
495 }
496 
497 
498 //----------------------------------------------------------------------------//
499 //---------------------------- Rotamer Dots Class ----------------------------//
500 //----------------------------------------------------------------------------//
501 
502 Size const RotamerDots::num_bytes_ = 21;
505 
508 
509 ObjexxFCL::FArray2D_int const * RotamerDots::lg_angles_( 0 );
510 ObjexxFCL::FArray2D_ubyte const * RotamerDots::lg_masks_( 0 );
511 
512 
513 ///
514 /// @begin RotamerDots::RotamerDots
515 ///
517  rotamer_(0),
518  num_atoms_(0),
519  sasa_(0),
520  sasa_is_current_(false)
521 {}
522 
523 ///
524 /// @begin RotamerDots::RotamerDots
525 ///
526 /// @brief
527 /// Custom constructor for a RotamerDots object
528 ///
529 /// @detailed
530 /// One RotamerDots object get allocated for every state of a first class IG Node, for all first class IG Nodes of a
531 /// protein being designed. That's potentially a very large number of states. This class should only hold the information
532 /// it needs to hold to do its job.
533 ///
535  conformation::ResidueCOP rotamer,
536  bool exclude_hydrogen_atoms /*=false*/,
537  bool use_expanded_polar_atom_radii /*=false*/
538 ) :
539  rotamer_(rotamer),
540  sasa_(0),
541  sasa_is_current_(false)
542 {
543  if ( exclude_hydrogen_atoms ) {
544  num_atoms_ = rotamer->nheavyatoms();
545  } else {
546  num_atoms_ = rotamer->natoms();
547  }
548 
549  atom_counts_.resize( num_atoms_ );
550  atom_sasa_.resize( num_atoms_ );
551 
552  if ( ! sasa_arrays_initialized_ ) {
554  //that function will set sasa_arrays_initialized_ to true;
555  }
556 
557  // every instance needs to have the radii_ pointer set. radii_ can't be static because two RotamerDots objects may
558  // want to use different atom radii for calculating SASA.
559  if ( use_expanded_polar_atom_radii ) {
561  } else {
563  }
564 
565 }
566 
567 ///
568 /// @begin RotamerDots::~RotamerDots
569 ///
571  //TR_RD << "called destructor" << std::endl;
572 }
573 
574 
575 ///
576 /// @begin RotamerDots::RotamerDots
577 ///
578 /// @brief
579 /// copy constructor
580 ///
582  utility::pointer::ReferenceCount(),
583  rotamer_( rhs.rotamer_ ),
584  num_atoms_( rhs.num_atoms_ ),
585  atom_counts_( rhs.atom_counts_ ),
586 
587  sasa_( rhs.sasa_ ),
588  sasa_is_current_( rhs.sasa_is_current_ ),
589  atom_sasa_( rhs.atom_sasa_ ),
590  radii_( rhs.radii_ )
591 {}
592 
593 
594 ///
595 /// @begin RotamerDots::copy
596 ///
597 /// @brief
598 /// Copy method for the RotamerDots class. Also used by the assignment operator.
599 ///
600 void RotamerDots::copy( RotamerDots const & rhs ) {
601  rotamer_ = rhs.rotamer_;
602  num_atoms_ = rhs.num_atoms_;
604 
605  sasa_ = rhs.sasa_;
606  atom_sasa_ = rhs.atom_sasa_;
608  radii_ = rhs.radii_;
609 }
610 
611 ///
612 /// @begin RotamerDots::operator=
613 ///
615  copy( rhs );
616  return *this;
617 }
618 
619 ///
620 /// @begin RotamerDots::operator!=
621 ///
622 /// @brief
623 /// Used during debugging of the HPatchIG. Some extra information is printed if current state dots is NOT EQUAL to
624 /// alternate state dots at a Node/BGNode.
625 ///
627 
628  if ( state_unassigned() || rhs.state_unassigned() ) {
629  return true; // I guess they could both be unassigned, but better to return not equal than equal
630  }
631 
632  if ( rotamer_ != rhs.rotamer_ || num_atoms_ != rhs.num_atoms_ ) return true;
633  if ( sasa_ != rhs.sasa_ || sasa_is_current_ != rhs.sasa_is_current_ ) return true;
634  if ( atom_counts_.size() != rhs.atom_counts_.size() ) return true;
635  if ( atom_sasa_.size() != rhs.atom_sasa_.size() ) return true;
636  if ( radii_ != rhs.radii_ ) return true;
637 
638  //TR_RD << "operator!=() score info same. checking if dot sphere objects match." << std::endl;
639  for ( Size ii=1; ii <= atom_counts_.size(); ++ii ) {
640  if ( atom_counts_[ ii ] != rhs.atom_counts_[ ii ] )
641  return true;
642  }
643 
644  return false;
645 }
646 
647 
648 ///
649 /// @begin RotamerDots::zero
650 ///
651 /// @brief
652 /// Zeros out all of the contained data except the rotamer pointer and the radii array.
653 ///
654 /// @detailed
655 /// So far, this function only gets called by the BGNode::prep_for_simA() call so that multiple runs through an
656 /// interaction graph can be done. If the rotamer dots object on the BGNodes isn't "cleared" after a run, then the run
657 /// immediately following will have the incorrect counts.
658 ///
660 
661  // leave the rotamer and num_atoms_ variables untouched
662  //rotamer_ = 0;
663  //num_atoms_ = 0;
664 
665  sasa_ = 0.0;
666  sasa_is_current_ = false;
667 
668  for ( Size ii = 1; ii <= atom_counts_.size(); ++ii ) {
669  atom_sasa_[ ii ] = 0.0;
670  atom_counts_[ ii ].zero(); // calls zero() on each DotSphere instance
671  }
672 
673 }
674 
675 
676 ///
677 /// @begin RotamerDots::overlaps
678 ///
679 /// @brief
680 /// Returns true if this RotamerDots object has any sphere overlap with the passed in RotamerDots object.
681 ///
682 /// @detailed
683 /// This method only checks to see if two RotamerDots objects are within touching distance of each other. It is used
684 /// to determine whether Edges or BGEdges should be created in the IG. Calculate this using the expanded polar atom
685 /// radii. If we don't, there's a chance that a state substitution on a Node may cause SASA changes (when expanded polars
686 /// are used) on a BGNode, but if we didn't assume expanded radii in this method, there would be no edge between the two
687 /// nodes.
688 ///
689 bool RotamerDots::overlaps( RotamerDots const & other ) const {
690 
691  Real distance_squared, atom1_radius, atom2_radius;
692 
693  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
694  for ( Size jj = 1; jj <= other.get_num_atoms(); ++jj ) {
695 
696  distance_squared = get_atom_coords_xyz( ii ).distance_squared( other.get_atom_coords_xyz( jj ) );
697 
698  atom1_radius = get_atom_radius( ii ) + probe_radius_;
699  atom2_radius = other.get_atom_radius( jj ) + probe_radius_;
700 
701  // exit if large probe radii touch
702  if ( distance_squared <= (atom1_radius + atom2_radius) * (atom1_radius + atom2_radius) )
703  return true;
704  }
705  }
706  return false;
707 }
708 
709 
710 ///
711 /// @begin RotamerDots::rotamer
712 ///
715  return rotamer_;
716 }
717 
718 ///
719 /// @begin RotamerDots::state_unassigned
720 ///
721 /// @brief
722 /// Is the state of this RotamerDots object unassigned?
723 ///
725  if ( rotamer_ == 0 )
726  return true;
727  return false;
728 }
729 
730 ///
731 /// @begin RotamerDots::get_num_atoms
732 ///
733 /// @brief
734 /// Returns the number of atoms this RotamerDots object is keeping SASA for.
735 ///
737  return num_atoms_;
738 }
739 
740 ///
741 /// @begin RotamerDots::get_atom_coords_xyz
742 ///
743 /// @brief
744 /// Return the xyz coordinates of an atom in this RotamerDots instance.
745 ///
747  if ( rotamer_ == 0 )
748  return numeric::xyzVector< Real >(0,0,0);
749 
750  return rotamer_->xyz( atom_index );
751 }
752 
753 
754 ///
755 /// @begin RotamerDots::get_atom_radius
756 ///
757 /// @brief
758 /// Returns the SASA radius for the passed in atom type. The DB file should have been read in at construct time.
759 ///
760 /// @detailed
761 /// Many of the functions in this class iterate over 1 .. num_atoms_.
762 /// That's not the same thing as an atom type index which is what the radii vector is indexed with. So before we can return
763 /// the radius, we have to convert the passed in atom_index into the right atom in the residue and then use that to get the
764 /// right type.
765 ///
767  if ( rotamer_ == 0 )
768  return 0.0;
769 
770  conformation::Atom const & atom( rotamer_->atom( atom_index ) );
771  return (*radii_)[ atom.type() ];
772 
773 }
774 
775 ///
776 /// @begin RotamerDots::radius_for_attype
777 ///
778 /// @brief
779 /// Same as the above, but skips the conversion from atom index to atom type index.
780 ///
782 RotamerDots::radius_for_attype( Size const attype_index ) {
783  return (*radii_)[ attype_index ];
784 }
785 
786 
787 ///
788 /// @begin RotamerDots::max_atom_radius
789 ///
790 /// @brief
791 /// Returns the maximum atom radius. Used only by the SurfacePotential class.
792 ///
795  return utility::max( *radii_ );
796 }
797 
798 
799 ///
800 /// @begin RotamerDots::get_radii
801 ///
802 /// @brief
803 /// Returns a pointer to the radii vector. Used only by the InvRotamerDots class.
804 ///
807  return radii_;
808 }
809 
810 ///
811 /// @begin RotamerDots::invert_to_boolmasks
812 ///
813 /// @brief
814 /// Inverts the current dot counts and saves them to the passed in vector.
815 ///
817 
818  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
819  atom_counts_[ ii ].invert_to_compact_array( inv_dots[ ii ] );
820  }
821 }
822 
823 /// @brief invert the current dot counts for a subset of the atoms in this rotamer.
824 void
827  utility::vector1< Size > const & ats_to_update
828 ) const
829 {
830  for ( Size ii = 1, iiend = ats_to_update.size(); ii <= iiend; ++ii ) {
831  atom_counts_[ ats_to_update[ ii ] ].invert_to_compact_array( inv_dots[ ats_to_update[ ii ] ] );
832  }
833 }
834 
835 
840  return dot_coords_[ index ];
841 }
842 
843 
844 ///
845 /// @begin RotamerDots::initialize_sasa_arrays
846 ///
847 /// @brief
848 /// Initializes the pointers to the angles and masks FArrays used by sasa.cc and inits the dot sphere coordinates.
849 ///
850 /// @detailed
851 /// This call should only occur once (when the first RotamerDots object get constructed) and never again.
852 ///
854 
855  if ( sasa_arrays_initialized_ ) return;
857 
860 
862 
863  return;
864 }
865 
866 
867 ///
868 /// @begin RotamerDots::increment_self_overlap
869 ///
870 /// @brief
871 /// computes and stores self-induced dot coverage. uses a vector1 of vector1 of ubytes to store the calculated overlap information.
872 ///
873 /// @detailed
874 /// uses get_atom_atom_coverage() which in turn uses get_overlap() and get_orientation() method calls in sasa.cc to get
875 /// the right overlap "masks". when all atom pairs are complete, converts the masks into coverage "counts" which are stored
876 /// in the DotSphere class (member variable atom_counts_).
877 ///
878 /// to handle the possibility of keeping expanded_polar SASA, we have to run the nested loop over atoms a second time through
879 /// using the expanded_polar version of get_atom_radius().
880 ///
882 
883  using namespace utility; // for utility::vector1
884 
885  vector1< vector1< ObjexxFCL::ubyte > > self_overlap( num_atoms_, vector1< ObjexxFCL::ubyte >( num_bytes_, ObjexxFCL::ubyte( 0 ) ) );
886 
887  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
888  Vector atom1_xyz = get_atom_coords_xyz( ii );
889  Real atom1_radius = get_atom_radius( ii );
890 
891  // only have to iterate over the higher indexed atoms for INTRA res overlaps
892  for ( Size jj = ii+1; jj <= num_atoms_; ++jj ) {
893  Vector atom2_xyz = get_atom_coords_xyz( jj );
894  Real atom2_radius = get_atom_radius( jj );
895 
896  Real dist = 0.0f;
897  get_atom_atom_coverage( atom1_xyz, atom1_radius, atom2_xyz, atom2_radius, self_overlap[ii], self_overlap[jj], dist );
898  }
899  }
900 
901  //TR_RD << "increment_self_overlap(): incrementing with counts: " << std::endl;
902  //for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
903  // RotamerDotsCache rdc;
904  // rdc.print_bit_string( self_overlap[ ii ] );
905  //}
906 
907  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
908  //TR_RD << "increment_self_overlap(): calling increment_count() on atom dotsphere " << ii << std::endl;
909  atom_counts_[ii].increment_count( self_overlap[ ii ] );
910  }
911 
912  sasa_is_current_ = false;
913 }
914 
915 
916 ///
917 /// @begin RotamerDots::increment_this_and_cache
918 ///
919 /// @brief
920 /// Add rotamer coverage counts for dots on this object only, leaving rhs unaltered.
921 ///
922 /// @detailed
923 /// In the context of the HPatchIG, this method is called by all FCNodes to increment the overlap a BG residue has on
924 /// the FCNode. It is called by all BG Edges, to make sure that all FCNodes that are connected to a BG residue get this
925 /// method called by them. 'other' in this case is a BG residue, and 'this_overlap_on_other' is the overlap that is
926 /// caused by all-states-possible-at-this-node on the BG node. Yes, that's keeping the same information in two places,
927 /// but it makes updating hpatch score calculations later faster. (ronj)
928 ///
930  RotamerDots const & other,
931  RotamerDotsCache & this_overlap_on_other,
932  utility::vector1< utility::vector1< bool > > & atom_atom_overlaps_cache
933 ) {
934 
935  RotamerDotsCache this_dots_covered_by_other( num_atoms_ );
936  // can't make the variable above be static because this function gets called by all kinds of FC nodes, which will
937  // have varying numbers of atoms. Then the member vector inside RDC would not be sized correctly and errors would
938  // occur.
939 
940  /*TR_RD << "atom_atom_overlaps_cache.size(): " << atom_atom_overlaps_cache.size() << std::endl;
941  for ( Size ii=1; ii <= atom_atom_overlaps_cache.size(); ++ii ) {
942  TR_RD << "atom_atom_overlaps_cache[ " << ii << " ].size(): " << atom_atom_overlaps_cache[ ii ].size() << std::endl;
943  }
944  TR_RD << std::endl;*/
945 
946  get_overlap_cache( other, this_overlap_on_other, this_dots_covered_by_other, atom_atom_overlaps_cache );
947 
948  // 'increment_count_for_some' is a class method in RotamerDotsCache objects
949  //TR_RD << "increment_this_and_cache(): this_dots_covered_by_other: " << std::endl;
950  //this_dots_covered_by_other.print( std::cout );
951 
952  //TR_RD << "increment_this_and_cache(): others_dots_covered_by_this: " << std::endl;
953  //this_overlap_on_other.print( std::cout );
954 
955  // increment_from_cached will update both regular and expanded polar SASA. the hard part is getting get_overlap_cache()
956  // to do it right.
957  increment_from_cached( this_dots_covered_by_other );
958 
959 }
960 
961 
962 ///
963 /// @begin RotamerDots::get_overlap_cache
964 ///
965 /// @brief
966 /// computes the overlap each rotamer (this & other) induce on each other and stores that information in the RotamerDotsCache objects
967 ///
968 /// @param
969 /// other - [in] - the other RotamerDots object
970 /// other_dots_covered_by_this - [out] - the Cache for the dots on the surface of other that are covered by the atoms on this rotamer
971 /// this_dots_covered_by_other - [out] - the Cache for the dots on the surface of this that are covered by the atoms on the other rotamer
972 /// atom_atom_overlaps_cache - [out] - holds a boolean indicating whether two atoms have overlapping, solvent-exposed surface area
973 ///
975  RotamerDots const & other,
976  RotamerDotsCache & others_dots_covered_by_this,
977  RotamerDotsCache & this_dots_covered_by_other,
978  utility::vector1< utility::vector1< bool > > & atom_atom_overlaps_cache
979 ) const {
980 
981  using namespace utility;
982 
983  //apl static so that they will be allocated exactly once - we don't want to use new and delete in the inner most loop.
984  static vector1< vector1< ObjexxFCL::ubyte > > vv_this_covered_by_other;
985  static vector1< vector1< ObjexxFCL::ubyte > > vv_other_covered_by_this;
986 
987  // clear and resize takes alot of time; just make resize calls instead and zero out indices as necessary
988  //vv_this_covered_by_other.clear();
989  //vv_this_covered_by_other.resize( num_atoms_, vector1< ObjexxFCL::ubyte >( num_bytes_, ObjexxFCL::ubyte( 0 ) ) );
990  //vv_other_covered_by_this.clear();
991  //vv_other_covered_by_this.resize( other.get_num_atoms(), vector1< ObjexxFCL::ubyte >( num_bytes_, ObjexxFCL::ubyte( 0 ) ) );
992 
993  if ( vv_this_covered_by_other.size() < num_atoms_ ) {
994  vv_this_covered_by_other.resize( num_atoms_, vector1< ObjexxFCL::ubyte >( num_bytes_, ObjexxFCL::ubyte( 0 ) ) );
995  }
996  if ( vv_other_covered_by_this.size() < other.get_num_atoms() ) {
997  vv_other_covered_by_this.resize( other.get_num_atoms(), vector1< ObjexxFCL::ubyte >( num_bytes_, ObjexxFCL::ubyte( 0 ) ) );
998  }
999 
1000  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
1001  for ( Size jj = 1; jj <= num_bytes_; ++jj ) {
1002  vv_this_covered_by_other[ ii ][ jj ] = 0;
1003  }
1004  }
1005  for ( Size ii = 1; ii <= other.num_atoms_; ++ii ) {
1006  for ( Size jj = 1; jj <= num_bytes_; ++jj ) {
1007  vv_other_covered_by_this[ ii ][ jj ] = 0;
1008  }
1009  }
1010 
1011  // calls the zero() class method on both of the RotamerDotsCache references passed in. I guess we do that to invalidate the cache
1012  // before storing the new cache values.
1013  others_dots_covered_by_this.zero();
1014  this_dots_covered_by_other.zero();
1015 
1016  get_res_res_overlap( other, vv_this_covered_by_other, vv_other_covered_by_this, atom_atom_overlaps_cache );
1017 
1018  this_dots_covered_by_other.increment_count( vv_this_covered_by_other );
1019  others_dots_covered_by_this.increment_count( vv_other_covered_by_this );
1020 
1021 }
1022 
1023 
1024 ///
1025 /// @begin RotamerDots::get_res_res_overlap()
1026 ///
1027 /// @brief
1028 /// Calls get_atom_atom_coverage for all atom pairs between res1 and res2. This method gets called by RotamerDots::get_overlap_cache().
1029 ///
1031  RotamerDots const & other_res,
1032  utility::vector1< utility::vector1< ObjexxFCL::ubyte > > & res1_covered_by_res2, // may include more entries than atoms
1033  utility::vector1< utility::vector1< ObjexxFCL::ubyte > > & res2_covered_by_res1, // may include more entries than atoms
1034  utility::vector1< utility::vector1< bool > > & atom_atom_overlaps_cache
1035 ) const {
1036 
1037  Real square_distance = 0.0f;
1038  bool overlap;
1039  for ( Size ii = 1; ii <= num_atoms_; ++ii ) { // 'this'/self residues atoms
1040 
1041  Vector ii_atom_xyz = get_atom_coords_xyz( ii );
1042  Real ii_atom_radius;
1043  ii_atom_radius = get_atom_radius( ii );
1044 
1045  for ( Size jj = 1; jj <= other_res.get_num_atoms(); ++jj ) {
1046 
1047  Vector jj_atom_xyz = other_res.get_atom_coords_xyz( jj );
1048  Real jj_atom_radius;
1049  jj_atom_radius = other_res.get_atom_radius( jj );
1050 
1051  overlap = get_atom_atom_coverage( ii_atom_xyz, ii_atom_radius, jj_atom_xyz, jj_atom_radius, res1_covered_by_res2[ ii ], res2_covered_by_res1[ jj ], square_distance );
1052 
1053  // set the overlaps bool if overlap was found. the outer vector holds the changing node's atoms (or other_res, as it
1054  // is referred to in this function) and the inner vector is for this RD object's atoms.
1055  if ( overlap )
1056  atom_atom_overlaps_cache[ jj ][ ii ] = true;
1057 
1058  if ( square_distance > (ii_atom_radius + jj_atom_radius) * (ii_atom_radius + jj_atom_radius) ) {
1059  break;
1060  }
1061  }
1062  }
1063 }
1064 
1065 
1066 ///
1067 /// @begin RotamerDots::get_atom_atom_coverage()
1068 ///
1069 /// @brief
1070 /// returns false if the two spheres do not overlap at all. otherwise, saves the overlap masks to the input vectors.
1071 ///
1072 bool RotamerDots::get_atom_atom_coverage( Vector const & at1_xyz, Real at1_base_radius,
1073  Vector const & at2_xyz, Real at2_base_radius,
1074  utility::vector1< ObjexxFCL::ubyte > & at1_sphere_covered,
1075  utility::vector1< ObjexxFCL::ubyte > & at2_sphere_covered, Real dist_sq ) const {
1076 
1077  int degree_of_overlap;
1078  int aphi_1_2, aphi_2_1;
1079  int theta_1_2, theta_2_1;
1080  int masknum;
1081 
1082  Real at1_radius = at1_base_radius + probe_radius_;
1083  Real at2_radius = at2_base_radius + probe_radius_;
1084 
1085  // exit if large probe radii do not touch
1086  dist_sq = at1_xyz.distance_squared( at2_xyz );
1087  if ( dist_sq > (at1_radius + at2_radius) * (at1_radius + at2_radius) ) {
1088  return false;
1089  }
1090  Real const distance = std::sqrt( dist_sq );
1091 
1092  //ronj this block represents the amount of surface area covered up on atom1 by atom2
1093  core::scoring::get_overlap( at1_radius, at2_radius, distance, degree_of_overlap );
1094  core::scoring::get_2way_orientation( at1_xyz, at2_xyz, aphi_1_2, theta_1_2, aphi_2_1, theta_2_1, distance );
1095 
1096  Size closest_dot1 = (*lg_angles_)( aphi_1_2, theta_1_2 );
1097  masknum = ( closest_dot1 * 100 ) + degree_of_overlap;
1098  for ( Size bb = 1, bbli = (*lg_masks_).index( bb, masknum ); bb <= num_bytes_; ++bb, ++bbli ) {
1099  at1_sphere_covered[ bb ] |= (*lg_masks_)[ bbli ];
1100  }
1101 
1102  //ronj the amount of surface area covered up on atom2 by atom1
1103  core::scoring::get_overlap( at2_radius, at1_radius, distance, degree_of_overlap );
1104 
1105  Size closest_dot2 = (*lg_angles_)( aphi_2_1, theta_2_1 );
1106  masknum = ( closest_dot2 * 100 ) + degree_of_overlap;
1107  for ( Size bb = 1, bbli = (*lg_masks_).index( bb, masknum ); bb <= num_bytes_; ++bb, ++bbli ) {
1108  at2_sphere_covered[ bb ] |= (*lg_masks_)[ bbli ];
1109  }
1110 
1111  return true;
1112 }
1113 
1114 
1115 ///
1116 /// @begin RotamerDots::increment_from_cached
1117 ///
1118 /// @brief
1119 /// Increments the dot coverage count for this rotamer from a coverage cache
1120 ///
1122 
1123  if ( cache.atom_counts_.size() != atom_counts_.size() )
1124  TR_RD << "increment_from_cached(): cache.size(): " << cache.atom_counts_.size() << ", atom_counts_.size(): " << atom_counts_.size() << std::endl;
1125  assert( cache.atom_counts_.size() == atom_counts_.size() );
1126  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
1127  atom_counts_[ ii ] += cache.atom_counts_[ ii ];
1128  }
1129 
1130  sasa_is_current_ = false;
1131 }
1132 
1133 
1134 ///
1135 /// @begin RotamerDots::decrement_from_cached
1136 ///
1137 /// @brief
1138 /// decrements the dot coverage count for this by the coverage stored in the input RotamerDotsCache object
1139 ///
1141 
1142  assert( cache.atom_counts_.size() == atom_counts_.size() );
1143  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
1144  atom_counts_[ ii ] -= cache.atom_counts_[ ii ];
1145  }
1146 
1147  sasa_is_current_ = false;
1148 }
1149 
1150 
1151 ///
1152 /// @begin RotamerDots::increment_both
1153 ///
1154 /// @brief
1155 /// Add rotamer coverage counts for dots on both this and other. sets sasa_is_current_ to false on both this and rhs
1156 ///
1157 /// @detailed
1158 /// One use case involves BGNodes initializing overlap with other BGNodes. This is a brute force all BGNode v all BGNode
1159 /// pairwise increment on the RotamerDots objects each Node holds. That's why we call increment *both*.
1160 /// We don't care about the cache values in this case, but to use increment_both_and_cache, we have to create Cache variables
1161 /// to use as references.
1162 ///
1164 
1165  RotamerDotsCache others_dots_covered_by_this( other.get_num_atoms() );
1166  others_dots_covered_by_this.zero();
1167 
1168  RotamerDotsCache this_dots_covered_by_other( num_atoms_ );
1169  this_dots_covered_by_other.zero();
1170 
1171  // can't make the variables above be static because this function gets called by all kinds of FC nodes, which will
1172  // have varying numbers of atoms. Then the member vector inside RDC would not be sized correctly and errors would
1173  // occur. But RDC object are pretty lightweight, so it shouldn't result in a big performance hit.
1175  increment_both_and_cache( other, others_dots_covered_by_this, this_dots_covered_by_other, dummy );
1176 }
1177 
1178 ///
1179 /// @begin RotamerDots::increment_both_and_cache
1180 ///
1181 /// @detailed
1182 /// Add rotamer coverage counts for dots on both this and other. Cache's the overlap this and other have with each other for greater efficiency.
1183 /// The second parameter are the dots on the surface of other_rotamer that this overlaps. The third parameter are the dots on the surface of this
1184 /// that other_rotamer overlaps. The fourth parameter lives on the Edges of the IG and stores a boolean indicating whether two atoms have
1185 /// overlapping, solvent-exposed surface area. Instead of recalculating this for all residue pairs every substitution, keep it in this cache.
1186 /// The vectors are already sized. The outer vector has the "other_rotamer"'s atoms and the inner vector is for the atoms in this class's residue.
1187 /// The structure just gets passed down to get_overlap_cache() and it eventually gets filled in get_atom_atom_coverage().
1188 ///
1189 /// If the class is keeping the expanded polar atom SASA also, then this function makes an extra call to get_overlap_cache()
1190 /// to get the extra overlap that happens when polar atom radii are expanded.
1191 ///
1192 void RotamerDots::increment_both_and_cache( RotamerDots & other_rotamer, RotamerDotsCache & others_dots_covered_by_this,
1193  RotamerDotsCache & this_dots_covered_by_other, utility::vector1< utility::vector1< bool > > & atom_atom_overlaps_cache ) {
1194 
1195  get_overlap_cache( other_rotamer, others_dots_covered_by_this, this_dots_covered_by_other, atom_atom_overlaps_cache );
1196 
1197  //TR_RD << "increment_both_and_cache(): overlap found:" << std::endl;
1198  //this_dots_covered_by_other.print( std::cout );
1199  //others_dots_covered_by_this.print( std::cout );
1200 
1201  increment_from_cached( this_dots_covered_by_other );
1202  other_rotamer.increment_from_cached( others_dots_covered_by_this );
1203 
1204 }
1205 
1206 
1207 ///
1208 /// @begin RotamerDots::get_sasa
1209 ///
1210 /// @brief
1211 /// Given the current dot coverage counts, returns the total SASA of this residue.
1212 ///
1213 /// @detailed
1214 /// This method does not do any work figuring out who is overlapping with this rotamer. It assumes that work has been
1215 /// done. Instead, it returns the SASA of the dot counts currently held. If the dot counts have not changed since the
1216 /// last time get_sasa() got called then sasa_is_current_ will be true. In that case, the method will just return the
1217 /// the variable sasa_. If the counts have changed, it iterates over all the atoms and recalculates the total SASA.
1218 /// That value is stored in sasa_ and sasa_is_current_ is set to true.
1219 ///
1220 /// The reason both sasa_ and sasa_is_current_ are "mutable" is so that they can be modified inside this const function.
1221 ///
1223 
1224  if ( state_unassigned() )
1225  return 0.0f;
1226 
1227  if ( sasa_is_current_ )
1228  return sasa_;
1229 
1230  Real fraction_uncovered = 0.0;
1231  Real atom_radius = 0.0;
1232  Real const four_pi = 4.0 * Real( numeric::constants::d::pi );
1233  Real atom_area_exposed = 0.0;
1234 
1235  sasa_ = 0.0;
1236  for ( Size ii = 1; ii <= atom_counts_.size(); ++ii ) {
1237  fraction_uncovered = static_cast< Real >( get_num_uncovered( ii ) ) / atom_counts_[ii].get_total_dots();
1238  atom_radius = get_atom_radius( ii ) + probe_radius_;
1239  atom_area_exposed = four_pi * ( atom_radius * atom_radius ) * fraction_uncovered;
1240  //std::cout << "get_sasa(): atom: " << ii << ", rad: " << atom_radius << ", %-uncovered: " << fraction_uncovered << ", exposed: " << atom_area_exposed << std::endl;
1241 
1242  atom_sasa_[ ii ] = atom_area_exposed;
1243  sasa_ += atom_area_exposed;
1244  }
1245 
1246  sasa_is_current_ = true;
1247 
1248  return sasa_;
1249 }
1250 
1251 
1252 ///
1253 /// @begin RotamerDots::get_atom_sasa
1254 ///
1255 /// @brief
1256 /// Given the current dot coverage counts, returns the total SASA for a particular atom index.
1257 /// Assumes that get_atom_sasa() will never be called when the object is in the unassigned state.
1258 ///
1259 Real RotamerDots::get_atom_sasa( Size atom_index ) const {
1260  if ( ! sasa_is_current_ )
1261  get_sasa();
1262 
1263  return atom_sasa_[ atom_index ];
1264 }
1265 
1266 
1267 ///
1268 /// @begin RotamerDots::get_num_uncovered
1269 ///
1270 /// @brief
1271 /// Returns the number of uncovered dots on the given atom, when using standard SASA radii.
1272 /// Note: no expanded polars version of this method.
1273 ///
1275  return atom_counts_[ atom ].get_num_uncovered();
1276 }
1277 
1278 
1279 ///
1280 /// @begin RotamerDots::get_num_covered
1281 ///
1282 /// @brief
1283 /// Note: no expanded polars version of this method.
1284 ///
1286 
1287  Size total_num_covered = 0;
1288  for ( Size ii=1; ii <= atom_counts_.size(); ++ii ) {
1289  total_num_covered += atom_counts_[ ii ].get_num_covered();
1290  }
1291 
1292  return total_num_covered;
1293 }
1294 
1295 
1296 ///
1297 /// @begin RotamerDots::write_dot_kinemage
1298 ///
1299 /*void RotamerDots::write_dot_kinemage( std::ofstream & kinfile ) {
1300 
1301  for ( Size ii = 1; ii <= num_atoms_; ++ii ) {
1302  write_dotlist_header( kinfile, "1.4 exposed dots", "red");
1303  for ( Size jj = 1; jj <= DotSphere::NUM_DOTS_TOTAL; ++jj ) {
1304  if ( ! atom_counts_[ii].get_dot_covered( jj ) ) {
1305  write_dot( kinfile, ii, jj, probe_radius_ );
1306  }
1307  }
1308  write_dotlist_header( kinfile, "SA", "red");
1309  for ( Size jj = 1; jj <= DotSphere::NUM_DOTS_TOTAL; ++jj ) {
1310  if ( ! atom_counts_[ii].get_dot_covered( jj ) ) {
1311  write_dot( kinfile, ii, jj, 0 );
1312  }
1313  }
1314  write_dotlist_header( kinfile, "1.0 A probe Accessible", "green");
1315  for ( Size jj = 1; jj <= DotSphere::NUM_DOTS_TOTAL; ++jj ) {
1316  if ( ! atom_counts_[ii].get_dot_covered( jj ) ) {
1317  write_dot( kinfile, ii, jj, 0 );
1318  }
1319  }
1320  //write_dotlist_header( kinfile, "void surface", "blue");
1321  //for (int jj = 1; jj <= DotSphere::NUM_DOTS_TOTAL; ++jj) {
1322  // if ( atom_counts_[ii].get_dot_covered( jj ) && ! atom_counts_small_probe_[ii].get_dot_covered( jj ) ) {
1323  // write_dot( kinfile, ii, jj, 0 );
1324  // }
1325  //}
1326  //write_dotlist_header( kinfile, "all dots", "white");
1327  //for (int jj = 1; jj <= DotSphere::NUM_DOTS_TOTAL; ++jj)
1328  //{
1329  // write_dot( kinfile, ii, jj, 0 );
1330  //}
1331  }
1332 }
1333 
1334 
1335 ///
1336 /// @begin RotamerDots::write_dotlist_header
1337 ///
1338 void RotamerDots::write_dotlist_header( std::ofstream & kinfile, std::string master_name, std::string color ) {
1339  kinfile << "@dotlist master= {" << master_name << "} color= " << color << "\n";
1340 }
1341 
1342 ///
1343 /// @begin RotamerDots::write_dot
1344 ///
1345 void RotamerDots::write_dot( std::ofstream & kinfile, Size atom, Size dot, Real radius ) {
1346  static numeric::xyzVector< Real > coord;
1347  coord = get_atom_coords_xyz( atom );
1348  coord += (radius + get_atom_radius( atom )) * get_dot_coord( dot );
1349 
1350  write_dot( kinfile, coord, "dot" );
1351 }
1352 
1353 ///
1354 /// @begin RotamerDots::write_dot
1355 ///
1356 void RotamerDots::write_dot( std::ofstream & kinfile, numeric::xyzVector< Real > const & coord, std::string atname ) {
1357  static std::string last_atname = "";
1358  if ( last_atname == atname ) {
1359  kinfile << "{\"} P " << coord.x() << " " << coord.y() << " " << coord.z() << "\n";
1360  } else {
1361  kinfile << "{" << atname << "} P " << coord.x() << " " << coord.y() << " " << coord.z() << "\n";
1362  last_atname = atname;
1363  }
1364 }
1365 
1366 
1367 ///
1368 /// @begin RotamerDots::get_dot_coord
1369 ///
1370 numeric::xyzVector<Real> const & RotamerDots::get_dot_coord( Size dot_id ) {
1371  if ( ! dot_sphere_coordinates_initialized_ ) {
1372  initialize_dot_sphere_coordinates_from_file();
1373  }
1374  return dot_sphere_coordinates_[ dot_id ];
1375 }
1376 
1377 
1378 ///
1379 /// @begin RotamerDots::initialize_dot_sphere_coordinates_from_file
1380 ///
1381 void RotamerDots::initialize_dot_sphere_coordinates_from_file() {
1382 
1383  dot_sphere_coordinates_.resize( DotSphere::NUM_DOTS_TOTAL );
1384 
1385  std::ifstream dotfile("sphere.txt");
1386  for ( Size ii = 1; ii <= DotSphere::NUM_DOTS_TOTAL; ++ii ) {
1387  Real x, y, z;
1388  dotfile >> x >> y >> z;
1389  dot_sphere_coordinates_[ ii ] = -1 * numeric::xyzVector< Real >( x,y,z );
1390  }
1391  dotfile.close();
1392 
1393  dot_sphere_coordinates_initialized_ = true;
1394 }
1395 */
1396 
1397 ///
1398 /// @begin RotamerDots::print
1399 ///
1400 void RotamerDots::print( std::ostream & os ) const {
1401 
1402  if ( state_unassigned() ) {
1403  os << "dots: unassigned" << std::endl;
1404  return;
1405  }
1406 
1407  os << "dots: " << rotamer_->name3() << rotamer_->seqpos() << std::endl;
1408  for ( Size ii=1; ii <= num_atoms_; ++ii ) {
1409  os << "atom " << rotamer_->atom_name( ii ) << ", rad: " << get_atom_radius( ii )
1410  << ", covered: " << ObjexxFCL::fmt::I(3,atom_counts_[ii].get_num_covered()) << ", counts: ";
1411  atom_counts_[ ii ].print( os );
1412  }
1413  os << "num_covered: " << get_num_covered_total() << ", sasa_is_current_: " << sasa_is_current_ << ", sasa: " << get_sasa() << std::endl;
1414 
1415 }
1416 
1417 
1418 std::string RotamerDots::name3() const { return rotamer_->name3(); } // for operator<<
1419 core::Size RotamerDots::seqpos() const { return rotamer_->seqpos(); } // for operator<<
1420 
1421 ///
1422 /// @begin operator<< ( ostream, RotamerDots )
1423 ///
1424 /// @brief
1425 /// invokes print on the input RotamerDots object
1426 ///
1427 std::ostream & operator<< ( std::ostream & os, RotamerDots const & rd ) {
1428  if ( rd.state_unassigned() ) {
1429  os << "unassigned";
1430  return os;
1431  }
1432  os << "rotamer: " << rd.name3() << rd.seqpos() << ", sasa: " << rd.get_sasa();
1433  return os;
1434 }
1435 
1436 /// @details The contents of "sphere.txt", now hard coded.
1437 /// The coordinates in the original file are all on the opposite size of the
1438 /// unit sphere from where they genuinely appear to be.
1439 void
1441 {
1442  dot_coords.resize( 162 );
1443  dot_coords[1] = -1* Vector(0,0,1);
1444  dot_coords[2] = -1* Vector(0.276393,0.850651,0.447214);
1445  dot_coords[3] = -1* Vector(0.894427,0,0.447214);
1446  dot_coords[4] = -1* Vector(0.16246,0.5,0.850651);
1447  dot_coords[5] = -1* Vector(0.525731,0,0.850651);
1448  dot_coords[6] = -1* Vector(0.0776089,0.238856,0.967949);
1449  dot_coords[7] = -1* Vector(0.251148,0,0.967949);
1450  dot_coords[8] = -1* Vector(0.361803,0.262866,0.894427);
1451  dot_coords[9] = -1* Vector(0.688191,0.5,0.525731);
1452  dot_coords[10] = -1* Vector(0.232827,0.716567,0.657513);
1453  dot_coords[11] = -1* Vector(0.447214,0.525731,0.723607);
1454  dot_coords[12] = -1* Vector(0.483974,0.716567,0.502295);
1455  dot_coords[13] = -1* Vector(0.638197,0.262866,0.723607);
1456  dot_coords[14] = -1* Vector(0.753443,0,0.657513);
1457  dot_coords[15] = -1* Vector(0.831052,0.238856,0.502295);
1458  dot_coords[16] = -1* Vector(-0.723607,0.525731,0.447214);
1459  dot_coords[17] = -1* Vector(-0.425325,0.309017,0.850651);
1460  dot_coords[18] = -1* Vector(-0.203183,0.147621,0.967949);
1461  dot_coords[19] = -1* Vector(-0.138197,0.425325,0.894427);
1462  dot_coords[20] = -1* Vector(-0.262866,0.809017,0.525731);
1463  dot_coords[21] = -1* Vector(-0.609548,0.442863,0.657513);
1464  dot_coords[22] = -1* Vector(-0.361803,0.587785,0.723607);
1465  dot_coords[23] = -1* Vector(-0.531939,0.681718,0.502295);
1466  dot_coords[24] = -1* Vector(-0.0527864,0.688191,0.723607);
1467  dot_coords[25] = -1* Vector(0.029644,0.864188,0.502295);
1468  dot_coords[26] = -1* Vector(-0.723607,-0.525731,0.447214);
1469  dot_coords[27] = -1* Vector(-0.425325,-0.309017,0.850651);
1470  dot_coords[28] = -1* Vector(-0.203183,-0.147621,0.967949);
1471  dot_coords[29] = -1* Vector(-0.447214,0,0.894427);
1472  dot_coords[30] = -1* Vector(-0.850651,0,0.525731);
1473  dot_coords[31] = -1* Vector(-0.609548,-0.442863,0.657513);
1474  dot_coords[32] = -1* Vector(-0.67082,-0.16246,0.723607);
1475  dot_coords[33] = -1* Vector(-0.812731,-0.295242,0.502295);
1476  dot_coords[34] = -1* Vector(-0.67082,0.16246,0.723607);
1477  dot_coords[35] = -1* Vector(-0.812731,0.295242,0.502295);
1478  dot_coords[36] = -1* Vector(0.276393,-0.850651,0.447214);
1479  dot_coords[37] = -1* Vector(0.16246,-0.5,0.850651);
1480  dot_coords[38] = -1* Vector(0.0776089,-0.238856,0.967949);
1481  dot_coords[39] = -1* Vector(-0.138197,-0.425325,0.894427);
1482  dot_coords[40] = -1* Vector(-0.262866,-0.809017,0.525731);
1483  dot_coords[41] = -1* Vector(0.232827,-0.716567,0.657513);
1484  dot_coords[42] = -1* Vector(-0.0527864,-0.688191,0.723607);
1485  dot_coords[43] = -1* Vector(0.029644,-0.864188,0.502295);
1486  dot_coords[44] = -1* Vector(-0.361803,-0.587785,0.723607);
1487  dot_coords[45] = -1* Vector(-0.531939,-0.681718,0.502295);
1488  dot_coords[46] = -1* Vector(0.361803,-0.262866,0.894427);
1489  dot_coords[47] = -1* Vector(0.688191,-0.5,0.525731);
1490  dot_coords[48] = -1* Vector(0.638197,-0.262866,0.723607);
1491  dot_coords[49] = -1* Vector(0.831052,-0.238856,0.502295);
1492  dot_coords[50] = -1* Vector(0.447214,-0.525731,0.723607);
1493  dot_coords[51] = -1* Vector(0.483974,-0.716567,0.502295);
1494  dot_coords[52] = -1* Vector(0.723607,0.525731,-0.447214);
1495  dot_coords[53] = -1* Vector(0.951057,0.309017,0);
1496  dot_coords[54] = -1* Vector(0.956626,0.147621,0.251148);
1497  dot_coords[55] = -1* Vector(0.861803,0.425325,0.276393);
1498  dot_coords[56] = -1* Vector(0.587785,0.809017,0);
1499  dot_coords[57] = -1* Vector(0.67082,0.688191,0.276393);
1500  dot_coords[58] = -1* Vector(0.436009,0.864188,0.251148);
1501  dot_coords[59] = -1* Vector(0.809017,0.587785,0);
1502  dot_coords[60] = -1* Vector(0.860696,0.442863,-0.251148);
1503  dot_coords[61] = -1* Vector(0.687157,0.681718,-0.251148);
1504  dot_coords[62] = -1* Vector(-0.276393,0.850651,-0.447214);
1505  dot_coords[63] = -1* Vector(0,1,0);
1506  dot_coords[64] = -1* Vector(0.155218,0.955423,0.251148);
1507  dot_coords[65] = -1* Vector(-0.138197,0.951057,0.276393);
1508  dot_coords[66] = -1* Vector(-0.587785,0.809017,0);
1509  dot_coords[67] = -1* Vector(-0.447214,0.850651,0.276393);
1510  dot_coords[68] = -1* Vector(-0.687157,0.681718,0.251148);
1511  dot_coords[69] = -1* Vector(-0.309017,0.951057,0);
1512  dot_coords[70] = -1* Vector(-0.155218,0.955423,-0.251148);
1513  dot_coords[71] = -1* Vector(-0.436009,0.864188,-0.251148);
1514  dot_coords[72] = -1* Vector(-0.894427,0,-0.447214);
1515  dot_coords[73] = -1* Vector(-0.951057,0.309017,0);
1516  dot_coords[74] = -1* Vector(-0.860696,0.442863,0.251148);
1517  dot_coords[75] = -1* Vector(-0.947214,0.16246,0.276393);
1518  dot_coords[76] = -1* Vector(-0.951057,-0.309017,0);
1519  dot_coords[77] = -1* Vector(-0.947214,-0.16246,0.276393);
1520  dot_coords[78] = -1* Vector(-0.860696,-0.442863,0.251148);
1521  dot_coords[79] = -1* Vector(-1,0,0);
1522  dot_coords[80] = -1* Vector(-0.956626,0.147621,-0.251148);
1523  dot_coords[81] = -1* Vector(-0.956626,-0.147621,-0.251148);
1524  dot_coords[82] = -1* Vector(-0.276393,-0.850651,-0.447214);
1525  dot_coords[83] = -1* Vector(-0.587785,-0.809017,0);
1526  dot_coords[84] = -1* Vector(-0.687157,-0.681718,0.251148);
1527  dot_coords[85] = -1* Vector(-0.447214,-0.850651,0.276393);
1528  dot_coords[86] = -1* Vector(0,-1,0);
1529  dot_coords[87] = -1* Vector(-0.138197,-0.951057,0.276393);
1530  dot_coords[88] = -1* Vector(0.155218,-0.955423,0.251148);
1531  dot_coords[89] = -1* Vector(-0.309017,-0.951057,0);
1532  dot_coords[90] = -1* Vector(-0.436009,-0.864188,-0.251148);
1533  dot_coords[91] = -1* Vector(-0.155218,-0.955423,-0.251148);
1534  dot_coords[92] = -1* Vector(0.723607,-0.525731,-0.447214);
1535  dot_coords[93] = -1* Vector(0.587785,-0.809017,0);
1536  dot_coords[94] = -1* Vector(0.436009,-0.864188,0.251148);
1537  dot_coords[95] = -1* Vector(0.67082,-0.688191,0.276393);
1538  dot_coords[96] = -1* Vector(0.951057,-0.309017,0);
1539  dot_coords[97] = -1* Vector(0.861803,-0.425325,0.276393);
1540  dot_coords[98] = -1* Vector(0.956626,-0.147621,0.251148);
1541  dot_coords[99] = -1* Vector(0.809017,-0.587785,0);
1542  dot_coords[100] = -1* Vector(0.687157,-0.681718,-0.251148);
1543  dot_coords[101] = -1* Vector(0.860696,-0.442863,-0.251148);
1544  dot_coords[102] = -1* Vector(0.262866,0.809017,-0.525731);
1545  dot_coords[103] = -1* Vector(0.531939,0.681718,-0.502295);
1546  dot_coords[104] = -1* Vector(0.447214,0.850651,-0.276393);
1547  dot_coords[105] = -1* Vector(0.309017,0.951057,0);
1548  dot_coords[106] = -1* Vector(0.138197,0.951057,-0.276393);
1549  dot_coords[107] = -1* Vector(-0.029644,0.864188,-0.502295);
1550  dot_coords[108] = -1* Vector(-0.688191,0.5,-0.525731);
1551  dot_coords[109] = -1* Vector(-0.483974,0.716567,-0.502295);
1552  dot_coords[110] = -1* Vector(-0.67082,0.688191,-0.276393);
1553  dot_coords[111] = -1* Vector(-0.809017,0.587785,0);
1554  dot_coords[112] = -1* Vector(-0.861803,0.425325,-0.276393);
1555  dot_coords[113] = -1* Vector(-0.831052,0.238856,-0.502295);
1556  dot_coords[114] = -1* Vector(-0.688191,-0.5,-0.525731);
1557  dot_coords[115] = -1* Vector(-0.831052,-0.238856,-0.502295);
1558  dot_coords[116] = -1* Vector(-0.861803,-0.425325,-0.276393);
1559  dot_coords[117] = -1* Vector(-0.809017,-0.587785,0);
1560  dot_coords[118] = -1* Vector(-0.67082,-0.688191,-0.276393);
1561  dot_coords[119] = -1* Vector(-0.483974,-0.716567,-0.502295);
1562  dot_coords[120] = -1* Vector(0.262866,-0.809017,-0.525731);
1563  dot_coords[121] = -1* Vector(-0.029644,-0.864188,-0.502295);
1564  dot_coords[122] = -1* Vector(0.138197,-0.951057,-0.276393);
1565  dot_coords[123] = -1* Vector(0.309017,-0.951057,0);
1566  dot_coords[124] = -1* Vector(0.447214,-0.850651,-0.276393);
1567  dot_coords[125] = -1* Vector(0.531939,-0.681718,-0.502295);
1568  dot_coords[126] = -1* Vector(0.850651,0,-0.525731);
1569  dot_coords[127] = -1* Vector(0.812731,-0.295242,-0.502295);
1570  dot_coords[128] = -1* Vector(0.947214,-0.16246,-0.276393);
1571  dot_coords[129] = -1* Vector(1,0,0);
1572  dot_coords[130] = -1* Vector(0.947214,0.16246,-0.276393);
1573  dot_coords[131] = -1* Vector(0.812731,0.295242,-0.502295);
1574  dot_coords[132] = -1* Vector(0,0,-1);
1575  dot_coords[133] = -1* Vector(0.425325,0.309017,-0.850651);
1576  dot_coords[134] = -1* Vector(0.609548,0.442863,-0.657513);
1577  dot_coords[135] = -1* Vector(0.361803,0.587785,-0.723607);
1578  dot_coords[136] = -1* Vector(-0.16246,0.5,-0.850651);
1579  dot_coords[137] = -1* Vector(0.0527864,0.688191,-0.723607);
1580  dot_coords[138] = -1* Vector(-0.232827,0.716567,-0.657513);
1581  dot_coords[139] = -1* Vector(0.138197,0.425325,-0.894427);
1582  dot_coords[140] = -1* Vector(0.203183,0.147621,-0.967949);
1583  dot_coords[141] = -1* Vector(-0.0776089,0.238856,-0.967949);
1584  dot_coords[142] = -1* Vector(-0.447214,0.525731,-0.723607);
1585  dot_coords[143] = -1* Vector(-0.525731,0,-0.850651);
1586  dot_coords[144] = -1* Vector(-0.638197,0.262866,-0.723607);
1587  dot_coords[145] = -1* Vector(-0.753443,0,-0.657513);
1588  dot_coords[146] = -1* Vector(-0.361803,0.262866,-0.894427);
1589  dot_coords[147] = -1* Vector(-0.251148,0,-0.967949);
1590  dot_coords[148] = -1* Vector(-0.638197,-0.262866,-0.723607);
1591  dot_coords[149] = -1* Vector(-0.16246,-0.5,-0.850651);
1592  dot_coords[150] = -1* Vector(-0.447214,-0.525731,-0.723607);
1593  dot_coords[151] = -1* Vector(-0.232827,-0.716567,-0.657513);
1594  dot_coords[152] = -1* Vector(-0.361803,-0.262866,-0.894427);
1595  dot_coords[153] = -1* Vector(-0.0776089,-0.238856,-0.967949);
1596  dot_coords[154] = -1* Vector(0.0527864,-0.688191,-0.723607);
1597  dot_coords[155] = -1* Vector(0.425325,-0.309017,-0.850651);
1598  dot_coords[156] = -1* Vector(0.361803,-0.587785,-0.723607);
1599  dot_coords[157] = -1* Vector(0.609548,-0.442863,-0.657513);
1600  dot_coords[158] = -1* Vector(0.138197,-0.425325,-0.894427);
1601  dot_coords[159] = -1* Vector(0.203183,-0.147621,-0.967949);
1602  dot_coords[160] = -1* Vector(0.67082,-0.16246,-0.723607);
1603  dot_coords[161] = -1* Vector(0.67082,0.16246,-0.723607);
1604  dot_coords[162] = -1* Vector(0.447214,0,-0.894427);
1605 }
1606 
1607 
1608 //----------------------------------------------------------------------------//
1609 //------------------------- RotamerDotsRadiusData ---------------------------//
1610 //----------------------------------------------------------------------------//
1611 
1612 /// @brief set initial value as no instance
1614 
1615 /// @brief static function to get the instance of (pointer to) this singleton class
1617  if ( instance_ == 0 ) {
1618  instance_ = new RotamerDotsRadiusData();
1619  }
1620  return instance_;
1621 }
1622 
1623 /// @brief private constructor to guarantee the singleton
1625 
1628 
1629  using namespace core::chemical;
1630 
1631  if ( ROSETTA_SASA_radii_.size() == 0 ) {
1632  // need to size and set the values in the vector
1633 
1634  TR_RDRD << "get_ROSETTA_SASA_radii(): reading in sasa radii database file" << std::endl;
1635 
1636  //j setup the radii array, indexed by the atom type int. atom index for looking up an extra data type stored in the AtomTypes
1637  //ronj reads the values out of the database file sasa_radii.txt in the extras folder of atom_type_sets and stores the values
1638  //ronj for each atom type into the radii array. each index of the radii array corresponds to some atom type.
1639  AtomTypeSet const & atom_type_set = * ChemicalManager::get_instance()->atom_type_set( FA_STANDARD );
1640  ROSETTA_SASA_radii_.resize( atom_type_set.n_atomtypes(), 0.0 );
1641 
1642  core::Size SASA_RADIUS_INDEX = atom_type_set.extra_parameter_index( "SASA_RADIUS" );
1643 
1644  TR_RDRD << "ROSETTA_SASA_radii_: [ ";
1645  for ( core::Size ii=1; ii <= atom_type_set.n_atomtypes(); ++ii ) {
1646  ROSETTA_SASA_radii_[ ii ] = atom_type_set[ ii ].extra_parameter( SASA_RADIUS_INDEX );
1647  TR_RDRD << ROSETTA_SASA_radii_[ ii ] << ", ";
1648  }
1649  TR_RDRD << "]" << std::endl;
1650  }
1651 
1652  return &ROSETTA_SASA_radii_;
1653 
1654 }
1655 
1658 
1659  using namespace core::chemical;
1660 
1661  if ( NACCESS_SASA_radii_.size() == 0 ) {
1662  // need to size and set the values in the vector
1663 
1664  TR_RDRD << "get_NACCESS_SASA_radii(): reading in sasa radii database file" << std::endl;
1665 
1666  AtomTypeSet const & atom_type_set = * ChemicalManager::get_instance()->atom_type_set( FA_STANDARD );
1667  NACCESS_SASA_radii_.resize( atom_type_set.n_atomtypes(), 0.0 );
1668 
1669  core::Size NACCESS_SASA_RADIUS_INDEX = atom_type_set.extra_parameter_index( "NACCESS_SASA_RADIUS" );
1670 
1671  TR_RDRD << "NACCESS_SASA_radii_: [ ";
1672  for ( core::Size ii=1; ii <= atom_type_set.n_atomtypes(); ++ii ) {
1673  NACCESS_SASA_radii_[ ii ] = atom_type_set[ ii ].extra_parameter( NACCESS_SASA_RADIUS_INDEX );
1674  TR_RDRD << NACCESS_SASA_radii_[ ii ] << ", ";
1675  }
1676  TR_RDRD << "]" << std::endl;
1677  }
1678 
1679  return &NACCESS_SASA_radii_;
1680 
1681 }
1682 
1685 
1686  using namespace core::chemical;
1687 
1688  if ( NACCESS_SASA_radii_with_expanded_polars.size() == 0 ) {
1689 
1690  TR_RDRD << "get_NACCESS_SASA_radii_with_expanded_polars(): reading in sasa radii database file" << std::endl;
1691 
1692  utility::vector1< Real >* radii = get_NACCESS_SASA_radii();
1693  NACCESS_SASA_radii_with_expanded_polars.resize( (*radii).size() );
1694 
1695  // used to figure out what atom_type a given index is
1696  AtomTypeSet const & atom_type_set = * ChemicalManager::get_instance()->atom_type_set( FA_STANDARD );
1697 
1698  TR_RDRD << "NACCESS_SASA_radii_with_expanded_polars_: [ ";
1699  for ( Size ii=1; ii <= radii->size(); ++ii ) {
1700  NACCESS_SASA_radii_with_expanded_polars[ ii ] = (*radii)[ ii ];
1701 
1702  core::chemical::AtomType const & at( atom_type_set[ ii ] );
1703  if ( at.element() == "N" || at.element() == "O" ) {
1704  NACCESS_SASA_radii_with_expanded_polars[ ii ] += polar_expansion_radius;
1705  }
1706  TR_RDRD << NACCESS_SASA_radii_with_expanded_polars[ ii ] << ", ";
1707  }
1708  TR_RDRD << "]" << std::endl;
1709 
1710  }
1711 
1712  return &NACCESS_SASA_radii_with_expanded_polars;
1713 
1714 }
1715 
1716 
1717 //----------------------------------------------------------------------------//
1718 //------------------------- Rotamer Dots Cache Class -------------------------//
1719 //----------------------------------------------------------------------------//
1720 
1721 
1722 ///
1723 /// @begin RotamerDotsCache::RotamerDotsCache
1724 ///
1726 
1727 ///
1728 /// @begin RotamerDotsCache::RotamerDotsCache
1729 ///
1731  atom_counts_.resize( num_atoms );
1732 }
1733 
1734 
1735 ///
1736 /// @begin RotamerDotsCache::RotamerDotsCache
1737 ///
1738 /// @brief
1739 /// copy constructor
1740 ///
1742  atom_counts_( rhs.atom_counts_ )
1743 {}
1744 
1745 
1746 ///
1747 /// @begin RotamerDotsCache::~RotamerDotsCache
1748 ///
1750 
1751 
1752 ///
1753 /// @begin RotamerDotsCache::operator=
1754 ///
1755 /// @brief
1756 /// assignment operator
1757 ///
1759  atom_counts_ = rhs.atom_counts_;
1760  return *this;
1761 }
1762 
1763 
1764 ///
1765 /// @begin RotamerDotsCache::resize
1766 ///
1768  //TR_RDC << "resize() called with num_atoms: " << num_atoms << std::endl;
1769  atom_counts_.clear();
1770  atom_counts_.resize( num_atoms );
1771 }
1772 
1773 
1774 ///
1775 /// @begin RotamerDotsCache::zero
1776 ///
1777 /// @brief
1778 /// sets the dot counts to zero for all atoms
1779 ///
1780 /// @detailed
1781 /// if the cache already knows the atom's counts are uniformly 0, it skips it
1782 ///
1783 void
1785  for ( Size ii = 1; ii <= atom_counts_.size(); ++ii ) {
1786  //if ( non_zero_overlap_[ ii ] ) {
1787  atom_counts_[ ii ].zero(); // calls zero() on each DotSphere instance
1788  //}
1789  }
1790  //atom_counts_.clear(); // leaving this in causes the vector to be sized down to 0, causing problems
1791 }
1792 
1793 
1794 ///
1795 /// @begin RotamerDotsCache::increment_count
1796 ///
1797 /// @brief
1798 /// increments the dot coverage counts for all atoms in the cache
1799 ///
1800 /// @param
1801 /// covered - [in] - compact ubyte array of dots; '1' for any covered dot for the vdw + 1.4 A sphere
1802 ///
1804 
1805  //TR_RDC << "increment_count(): atom_counts_.size(): " << atom_counts_.size() << ", covered.size(): " << covered.size() << std::endl;
1806  // do not assert this -- let there be more entries, possibly, in covered array;
1807  // assert( atom_counts_.size() == covered.size() );
1808  assert( atom_counts_.size() <= covered.size() );
1809  for ( Size ii = 1, ii_end = atom_counts_.size(); ii <= ii_end; ++ii ) {
1810  //utility::vector1< ObjexxFCL::ubyte > const & atom_mask = covered[ ii ];
1811  atom_counts_[ ii ].increment_count( covered[ ii ] );
1812  }
1813 
1814 }
1815 
1816 
1817 ///
1818 /// @begin RotamerDotsCache::write_to_compact_array
1819 ///
1820 /// @detailed
1821 /// Called by BGEdges with a reference to a vector1 of vector1 of ubytes representing where to put the compact (count)
1822 /// based representation of all the atom overlap masks.
1823 ///
1824 /// Note: This method only writes the standard SASA dot counts to the passed in array. No version of this function
1825 /// exists for expanded polar atom SASA dot counts.
1826 ///
1828  assert( compact.size() != 0 );
1829  for ( Size ii = 1; ii <= atom_counts_.size(); ++ii ) {
1830  atom_counts_[ ii ].write_to_compact_array( compact[ ii ] );
1831  }
1832 }
1833 
1834 
1835 ///
1836 /// @begin RotamerDotsCache::print()
1837 ///
1839  for ( Size bb = 1; bb <= values.size(); ++bb ) {
1840  if ( (bb-1)*8 % 16 == 0 ) std::cout << (bb-1) * 8 << ":";
1841  for ( int index=7; index >= 0; index-- ) {
1842  std::cout << ( ( (int)values[ bb ] >> index ) & 1 );
1843  }
1844  std::cout << " ";
1845  }
1846  std::cout << std::endl;
1847 }
1848 
1849 
1850 ///
1851 /// @begin RotamerDotsCache::print()
1852 ///
1853 void RotamerDotsCache::print( std::ostream & os ) const {
1854  for ( Size ii = 1; ii <= atom_counts_.size(); ++ii ) {
1855  os << "atom " << I(2,ii) << ": ";
1856  atom_counts_[ ii ].print( os );
1857  }
1858 }
1859 
1860 //----------------------------------------------------------------------------//
1861 //------------------------------ Inverted Dots Class -------------------------//
1862 //----------------------------------------------------------------------------//
1863 
1865 
1867  rotamer_( 0 )
1868 {}
1869 
1870 
1872  utility::pointer::ReferenceCount(),
1873  rotamer_( src.rotamer_ ),
1874  inv_dots_( src.inv_dots_ ),
1875  radii_( src.radii_ )
1876 {}
1877 
1879 
1880 InvRotamerDots const &
1882  if ( this != & rhs ) {
1883  rotamer_ = rhs.rotamer_;
1884  inv_dots_ = rhs.inv_dots_;
1885  radii_ = rhs.radii_;
1886  }
1887  return *this;
1888 }
1889 
1890 void
1892  rotamer_ = rdots.rotamer();
1893  if ( ! rotamer_ ) return;
1894  if ( inv_dots_.size() < rdots.get_num_atoms() ) {
1895  inv_dots_.resize( rdots.get_num_atoms(), utility::vector1< ObjexxFCL::ubyte >( RotamerDots::num_bytes_, ObjexxFCL::ubyte(0) ) );
1896  }
1897  rdots.invert_to_boolmasks( inv_dots_ );
1898  radii_ = rdots.get_radii();
1899 }
1900 
1901 void
1903  RotamerDots const & rdots,
1904  utility::vector1< Size > const & ats_to_update
1905 )
1906 {
1907  rotamer_ = rdots.rotamer();
1908  if ( ! rotamer_ ) return;
1909  if ( inv_dots_.size() < rdots.get_num_atoms() ) {
1910  inv_dots_.resize( rdots.get_num_atoms(), utility::vector1< ObjexxFCL::ubyte >( RotamerDots::num_bytes_, ObjexxFCL::ubyte(0) ) );
1911  }
1912  rdots.invert_to_boolmasks( inv_dots_, ats_to_update );
1913  radii_ = rdots.get_radii();
1914 }
1915 
1916 
1919 {
1920  return rotamer_;
1921 }
1922 
1923 /// @brief Is the intersection between two atoms on this inv-rotamer-dots object exposed?
1924 bool
1926  assert( rotamer_ );
1927  return overlap_exposed( rotamer_->atom( at1 ), inv_dots_[ at1 ], rotamer_->atom( at2 ), inv_dots_[ at2 ] );
1928 }
1929 
1930 /// @brief Is the intersection between one atom on this inv-rotamer-dots object,
1931 /// and one atom on another inv-rotamer-dots object exposed?
1932 bool
1934  Size at_this,
1935  InvRotamerDots const & other,
1936  Size at_other
1937 ) const
1938 {
1939  return overlap_exposed( rotamer_->atom( at_this ), inv_dots_[ at_this ], other.rotamer_->atom( at_other ), other.inv_dots_[ at_other ] );
1940 }
1941 
1942 
1943 bool InvRotamerDots::dot_exposed( Size atomid, Size dot_index ) const {
1944  assert( dot_index > 0 && dot_index <= 162 );
1945  dot_index -= 1;
1946  Size const which_byte = dot_index / 8;
1947  Size const which_bit = dot_index - which_byte * 8 ;
1948  return unpack_ubyte( inv_dots_[ atomid ][ which_byte + 1 ], which_bit );
1949 }
1950 
1952  std::ostream & ostr,
1953  bool group
1954 ) const
1955 {
1956  if ( ! rotamer_ ) return;
1957 
1958  if ( group ) {
1959  ostr << "@group { invdots " << rotamer_->seqpos() << "} dominant\n";
1960  }
1961 
1962  for ( Size ii = 1; ii <= rotamer_->nheavyatoms(); ++ii ) {
1963  Real const ii_rad = (*radii_)[ rotamer_->atom(ii).type() ] + RotamerDots::probe_radius_;
1964  write_sphere_list_uv1( ostr, rotamer_->atom_name( ii ), "gray", rotamer_->xyz( ii ), ii_rad, inv_dots_[ ii ] );
1965  }
1966 }
1967 
1968 void
1970  std::ostream & ostr,
1971  Size const atom_this,
1972  InvRotamerDots const & invdots_other,
1973  Size const atom_other,
1974  bool group
1975 ) const
1976 {
1977  core::conformation::Atom const & at1( rotamer_->atom( atom_this ) );
1978  core::conformation::Atom const & at2( invdots_other.rotamer_->atom( atom_other ) );
1979 
1980  Real const rad1 = (*radii_)[ at1.type() ] + RotamerDots::probe_radius_;
1981  Real const rad2 = (*radii_)[ at2.type() ] + RotamerDots::probe_radius_;
1982 
1983  Real const dist_sq = at1.xyz().distance_squared( at2.xyz() );
1984  assert( dist_sq < (rad1 + rad2) * (rad1 + rad2) );
1985  Real const distance = std::sqrt( dist_sq );
1986 
1987  Real const step_size1 = rad1 * 0.02;
1988  Real const step_size2 = rad2 * 0.02;
1989 
1990  Size const nsteps1 = (Size)(ceil( max_dist_from_dot_to_intersection / step_size1 ));
1991  Size const nsteps2 = (Size)(ceil( max_dist_from_dot_to_intersection / step_size2 ));
1992 
1993  int degree_of_overlap1, degree_of_overlap1_stepped, degree_of_overlap2, degree_of_overlap2_stepped;
1994  int aphi_1_2, aphi_2_1;
1995  int theta_1_2, theta_2_1;
1996 
1997  //ronj this block represents the amount of surface area covered up on atom1 by atom2
1998  core::scoring::get_overlap( rad1, rad2, distance, degree_of_overlap1 );
1999  core::scoring::get_2way_orientation( at1.xyz(), at2.xyz(), aphi_1_2, theta_1_2, aphi_2_1, theta_2_1, distance );
2000 
2001  utility::vector1< ObjexxFCL::ubyte > ring1( 21, ObjexxFCL::ubyte(0) );
2002  utility::vector1< ObjexxFCL::ubyte > ring2( 21, ObjexxFCL::ubyte(0) );
2003 
2004  utility::vector1< ObjexxFCL::ubyte > hit_ring1( 21, ObjexxFCL::ubyte(0) );
2005  utility::vector1< ObjexxFCL::ubyte > hit_ring2( 21, ObjexxFCL::ubyte(0) );
2006 
2007  Size closest_dot1 = (*RotamerDots::lg_angles_)( aphi_1_2, theta_1_2 );
2008  if ( degree_of_overlap1 + nsteps1 > 100 ) {
2009  degree_of_overlap1_stepped = 100;
2010  } else {
2011  degree_of_overlap1_stepped = degree_of_overlap1 + nsteps1;
2012  }
2013 
2014  int const masknum1a = ( closest_dot1 * 100 ) + degree_of_overlap1;
2015  int const masknum1b = ( closest_dot1 * 100 ) + degree_of_overlap1_stepped;
2016 
2017  // so we take two "offsets" into the "masks" table: 1) the one that normally gets used to figure out which dots are covered
2018  // by the neighboring atom, and 2) one that's one "step" in, which represents the "ring" of dots that's just past the ones
2019  // that are covered by the neighboring atom. if we then take the inverse (negate) the normally used mask, we'll get 0's
2020  // whereever there are dots covered by the other atom (instead of 1's) and 1's everywhere else. if we logical AND that
2021  // result with the dots that one "step" in, we'll get 1's at just the ring of dots that's next to the ones that are covered.
2022 
2023  // if we then logical AND the ring of dots with all of the exposed dots on this atom, we can determine if there are any
2024  // exposed dots adjacent to the intersection circle.
2025 
2026  for ( Size bb = 1, bblia = (*RotamerDots::lg_masks_).index( bb, masknum1a ), bblib = (*RotamerDots::lg_masks_).index( bb, masknum1b );
2027  bb <= RotamerDots::num_bytes_; ++bb, ++bblia, ++bblib ) {
2028  ring1[ bb ] = (*RotamerDots::lg_masks_)[ bblib ] & ~ (*RotamerDots::lg_masks_)[ bblia ];
2029  hit_ring1[ bb ] = inv_dots_[ atom_this ][ bb ] & ( (*RotamerDots::lg_masks_)[ bblib ] & ~ (*RotamerDots::lg_masks_)[ bblia ] );
2030  }
2031  std::cout << "exposed dots: ";
2032  utility::vector1< ObjexxFCL::ubyte > exposed_copy1 = inv_dots_[ atom_this ];
2033  print_dot_bit_string( exposed_copy1 );
2034  std::cout << "ring1: ";
2035  print_dot_bit_string( ring1 );
2036  std::cout << "hit_ring1: ";
2037  print_dot_bit_string( hit_ring1 );
2038 
2039  //ronj the amount of surface area covered up on atom2 by atom1
2040  core::scoring::get_overlap( rad2, rad1, distance, degree_of_overlap2 );
2041 
2042  Size closest_dot2 = (*RotamerDots::lg_angles_)( aphi_2_1, theta_2_1 );
2043  if ( degree_of_overlap2 + nsteps2 > 100 ) {
2044  degree_of_overlap2_stepped = 100;
2045  } else {
2046  degree_of_overlap2_stepped = degree_of_overlap2 + nsteps2;
2047  }
2048 
2049  int const masknum2a = ( closest_dot2 * 100 ) + degree_of_overlap2;
2050  int const masknum2b = ( closest_dot2 * 100 ) + degree_of_overlap2_stepped;
2051 
2052  for ( Size bb = 1, bblia = (*RotamerDots::lg_masks_).index( bb, masknum2a ), bblib = (*RotamerDots::lg_masks_).index( bb, masknum2b );
2053  bb <= RotamerDots::num_bytes_; ++bb, ++bblia, ++bblib ) {
2054  ring2[ bb ] = (*RotamerDots::lg_masks_)[ bblib ] & ~ (*RotamerDots::lg_masks_)[ bblia ];
2055  hit_ring2[ bb ] = invdots_other.inv_dots_[ atom_other ][ bb ] & ( (*RotamerDots::lg_masks_)[ bblib ] & ~ (*RotamerDots::lg_masks_)[ bblia ] );
2056  }
2057  std::cout << "exposed dots: ";
2058  utility::vector1< ObjexxFCL::ubyte > exposed_copy2 = invdots_other.inv_dots_[ atom_other ];
2059  print_dot_bit_string( exposed_copy2 );
2060  std::cout << "ring2: ";
2061  print_dot_bit_string( ring2 );
2062  std::cout << "hit_ring2: ";
2063  print_dot_bit_string( hit_ring2 );
2064 
2065  if ( group ) {
2066  ostr << "@group { invdots " << rotamer_->seqpos() << " " << rotamer_->atom_name( atom_this ) << "} dominant\n";
2067  }
2068  write_sphere_list_uv1( ostr, rotamer_->atom_name( atom_this ), "gray", at1.xyz(), rad1, ring1 );
2069 
2070  if ( group ) {
2071  ostr << "@group { invdots " << invdots_other.rotamer_->seqpos() << " " << invdots_other.rotamer_->atom_name( atom_other ) << "} dominant\n";
2072  }
2073  write_sphere_list_uv1( ostr, invdots_other.rotamer_->atom_name( atom_other ), "gray", at2.xyz(), rad2, ring2 );
2074 
2075  if ( group ) {
2076  ostr << "@group { olap " << rotamer_->seqpos() << " " << rotamer_->atom_name( atom_this ) << "} dominant\n";
2077  }
2078  write_sphere_list_uv1( ostr, rotamer_->atom_name( atom_this ), "blue", at1.xyz(), rad1, hit_ring1 );
2079 
2080  if ( group ) {
2081  ostr << "@group { olap " << invdots_other.rotamer_->seqpos() << " " << invdots_other.rotamer_->atom_name( atom_other ) << "} dominant\n";
2082  }
2083  write_sphere_list_uv1( ostr, invdots_other.rotamer_->atom_name( atom_other ), "blue", at2.xyz(), rad2, hit_ring2 );
2084 
2085 }
2086 
2087 
2088 bool
2090  core::conformation::Atom const & at1,
2091  utility::vector1< ObjexxFCL::ubyte > const & at1exposed_dots,
2092  core::conformation::Atom const & at2,
2093  utility::vector1< ObjexxFCL::ubyte > const & at2exposed_dots
2094 ) const
2095 {
2096 
2097  Real const rad1 = (*radii_)[ at1.type() ] + RotamerDots::probe_radius_;
2098  Real const rad2 = (*radii_)[ at2.type() ] + RotamerDots::probe_radius_;
2099 
2100  Real const dist_sq = at1.xyz().distance_squared( at2.xyz() );
2101  assert( dist_sq <= (rad1 + rad2) * (rad1 + rad2) );
2102  Real const distance = std::sqrt( dist_sq );
2103 
2104  Real const step_size1 = rad1 * 0.02;
2105  Real const step_size2 = rad2 * 0.02;
2106 
2107  Size const nsteps1 = (Size)(ceil( max_dist_from_dot_to_intersection / step_size1 ));
2108  Size const nsteps2 = (Size)(ceil( max_dist_from_dot_to_intersection / step_size2 ));
2109 
2110  int degree_of_overlap1, degree_of_overlap2;
2111  int aphi_1_2, aphi_2_1;
2112  int theta_1_2, theta_2_1;
2113 
2114  //ronj this block represents the amount of surface area covered up on atom1 by atom2
2115  core::scoring::get_overlap( rad1, rad2, distance, degree_of_overlap1 );
2116  core::scoring::get_2way_orientation( at1.xyz(), at2.xyz(), aphi_1_2, theta_1_2, aphi_2_1, theta_2_1, distance );
2117 
2118  bool at1_intersection_exposed = false;
2119  Size closest_dot1 = (*RotamerDots::lg_angles_)( aphi_1_2, theta_1_2 );
2120  if ( degree_of_overlap1 + nsteps1 > 100 ) {
2121  for ( Size bb = 1; bb <= RotamerDots::num_bytes_; ++bb ){
2122  if ( at1exposed_dots[ bb ] ) {
2123  at1_intersection_exposed = true;
2124  break;
2125  }
2126  }
2127  } else {
2128  int masknum = ( closest_dot1 * 100 ) + degree_of_overlap1 + nsteps1;
2129  for ( Size bb = 1, bbli = (*RotamerDots::lg_masks_).index( bb, masknum ); bb <= RotamerDots::num_bytes_; ++bb, ++bbli ){
2130  if ( at1exposed_dots[ bb ] & (*RotamerDots::lg_masks_)[ bbli ] ) {
2131  at1_intersection_exposed = true;
2132  break;
2133  }
2134  }
2135  }
2136 
2137  if ( ! at1_intersection_exposed ) return false;
2138 
2139  //ronj the amount of surface area covered up on atom2 by atom1
2140  core::scoring::get_overlap( rad2, rad1, distance, degree_of_overlap2 );
2141 
2142  bool at2_intersection_exposed = false;
2143 
2144  Size closest_dot2 = (*RotamerDots::lg_angles_)( aphi_2_1, theta_2_1 );
2145  if ( degree_of_overlap2 + nsteps2 > 100 ) {
2146  for ( Size bb = 1; bb <= RotamerDots::num_bytes_; ++bb ){
2147  if ( at2exposed_dots[ bb ] ) {
2148  at2_intersection_exposed = true;
2149  break;
2150  }
2151  }
2152  } else {
2153  int masknum = ( closest_dot2 * 100 ) + degree_of_overlap2 + nsteps2;
2154  for ( Size bb = 1, bbli = (*RotamerDots::lg_masks_).index( bb, masknum ); bb <= RotamerDots::num_bytes_; ++bb, ++bbli ){
2155  if ( at2exposed_dots[ bb ] & (*RotamerDots::lg_masks_)[ bbli ] ) {
2156  at2_intersection_exposed = true;
2157  break;
2158  }
2159  }
2160  }
2161 
2162  return at2_intersection_exposed;
2163 }
2164 
2165 ///
2166 /// @begin InvRotamerDots::print_dot_bit_string
2167 ///
2168 /// @brief
2169 /// Helper method I am using to confirm that the dots are being overlapped and bits are being set correctly.
2170 ///
2172  for ( Size bb = 1; bb <= RotamerDots::num_bytes_; ++bb ) {
2173  int bit;
2174  if ( (bb-1)*8 % 16 == 0 ) std::cout << (bb-1) * 8 << ":";
2175  for ( int index=7; index >= 0; index-- ) {
2176  bit = ( ( (int)values[ bb ] >> index ) & 1 );
2177  std::cout << bit;
2178  }
2179  std::cout << " ";
2180  }
2181  std::cout << std::endl;
2182 }
2183 
2184 
2185 } // interaction_graph
2186 } // pack
2187 } // core
2188