Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ProteinUpstreamBuilder.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 // :noTabs=false:tabSize=4:indentSize=4:
4 //
5 // (c) Copyright Rosetta Commons Member Institutions.
6 // (c) This file is part of the Rosetta software suite and is made available under license.
7 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
8 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
9 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
10 
11 /// @file protocols/match/upstream/ProteinUpstreamBuilder.cc
12 /// @brief
13 /// @author Alex Zanghellini (zanghell@u.washington.edu)
14 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com), porting to mini
15 
16 // Unit headers
18 
19 // Package headers
22 // AUTO-REMOVED #include <protocols/match/downstream/DownstreamBuilder.hh>
26 
27 // Project headers
30 // AUTO-REMOVED #include <core/pose/Pose.hh>
31 #include <basic/options/option.hh>
32 #include <basic/options/keys/packing.OptionKeys.gen.hh>
36 #include <basic/Tracer.hh>
37 
38 // Utility headers
39 #include <utility/exit.hh>
40 #include <utility/string_util.hh>
41 #include <utility/LexicographicalIterator.hh>
42 
43 #include <protocols/match/Hit.hh>
44 #include <utility/vector1.hh>
45 
46 
47 namespace protocols {
48 namespace match {
49 namespace upstream {
50 
51 /// @details Auto-generated virtual destructor
53 
54 static basic::Tracer TR( "protocols.match.upstream.ProteinUpstreamBuilder" );
55 
56 /// dummy return value
58 
59 
60 /*enum ChiStrategy {
61  rotameric_chi_follow_EX_flags,
62  rotameric_chi_mimic_EX_flags,
63  rotameric_chi_step_by_value,
64  rotameric_chi_step_wi_sd_range,
65  rotameric_chi_partition_sd_range,
66  nonrotameric_chi_sample_wi_nrchi_bin,
67  nonrotameric_chi_sample_wi_nrchi_bin_to_lower_boundary
68 };*/
69 
71  strategy_( follow_EX_flags ),
72  sample_level_( core::pack::task::NO_EXTRA_CHI_SAMPLES ),
73  step_size_( 0.0 ),
74  sd_range_( 0.0 ),
75  n_samples_wi_sd_range_( 0 ),
76  nrchi_prob_minimum_for_extra_samples_( 0.2 ),
77  n_samples_per_side_of_nrchi_bin_( 0 )
78 {}
79 
80 
82 
83 void
85 {
86  strategy_ = setting;
87 }
88 
89 void
91 {
93  sample_level_ = setting;
94 }
95 
96 void
98 {
99  assert(
102 
103  step_size_ = setting;
104 }
105 
106 void
108  assert(
111  sd_range_ = setting;
112 }
113 
114 void
116 {
118  n_samples_wi_sd_range_ = setting;
119 }
120 
121 void
123 {
124  assert(
129 }
130 
131 void
133  assert(
137 }
138 
141 
144 {
146  return sample_level_;
147 }
148 
149 
152 {
153  assert(
156  return step_size_;
157 }
158 
161 {
162  assert(
165  return sd_range_;
166 }
167 
170 {
172  return n_samples_wi_sd_range_;
173 }
174 
177 {
178  assert(
183 }
184 
187 {
188  assert(
192 }
193 
194 /*UpstreamResTypeGeometry::UpstreamResTypeGeometry() :
195  restype_name_( "UNINITIALIZED" )
196 {}
197 
198 UpstreamResTypeGeometry::UpstreamResTypeGeometry( core::chemical::ResidueType const & res ) :
199  restype_name_( res.name() )
200 {
201  initialize_from_residue_type( res );
202 }
203 
204 void
205 UpstreamResTypeGeometry::initialize_from_residue_type(
206  core::chemical::ResidueType const & res
207 )
208 {
209  if ( restype_name_ != res.name() ) {
210  restype_name_ = res.name();
211  }
212 
213  /// 1. Resize arrays that depend on the number of atoms
214  Size const n_atoms = res.natoms();
215 
216  controlling_chi_for_atom_ = res.last_controlling_chi();
217  which_point_for_atom_.resize( n_atoms );
218  std::fill( which_point_for_atom_.begin(), which_point_for_atom_.end(), 0 );
219 
220  /// 2. Resize arrays that depend on the number of chi
221  Size const n_chi = res.nchi();
222 
223  chitip_atoms_.resize( n_chi );
224  std::fill( chitip_atoms_.begin(), chitip_atoms_.end(), 0 );
225 
226  ht_for_chitip_atoms_.resize( n_chi );
227  for ( Size ii = 1; ii <= n_chi; ++ii ) ht_for_chitip_atoms_[ ii ].set_identity();
228 
229  nonchitip_atoms_.resize( res.nchi() );
230  for ( Size ii = 1; ii <= n_chi; ++ii ) nonchitip_atoms_[ ii ].clear();
231 
232  points_for_nonchitip_atoms_.resize( res.nchi() );
233  for ( Size ii = 1; ii <= n_chi; ++ii ) points_for_nonchitip_atoms_[ ii ].clear();
234 
235  if ( nchi() == 0 ) return; // match from gly? can't see why you'd want to!
236 
237 
238  for ( Size ii = 1; ii <= n_chi; ++ii ) {
239  assert( res.chi_atoms( ii ).size() == 4 );
240 
241  Size const
242  chiat2( res.chi_atoms( ii )[ 2 ] ),
243  chiat3( res.chi_atoms( ii )[ 3 ] ),
244  chiat4( res.chi_atoms( ii )[ 4 ] );
245 
246  chitip_atoms_[ ii ] = chiat4;
247 
248 
249  ht_for_chitip_atoms_[ ii ].set_xaxis_rotation_rad( -1 * res.icoor( chiat4 ).theta() );
250  ht_for_chitip_atoms_[ ii ].walk_along_z( res.icoor( chiat4 ).d() );
251 
252  HTReal chi_tip_frame(
253  res.xyz( chiat2 ),
254  res.xyz( chiat3 ),
255  res.xyz( chiat4 ) );
256 
257  Size const n_nontip_ats_for_chi = res.atoms_last_controlled_by_chi( ii ).size() - 1;
258 
259  nonchitip_atoms_[ ii ].reserve( n_nontip_ats_for_chi );
260  points_for_nonchitip_atoms_[ ii ].reserve( n_nontip_ats_for_chi );
261 
262  for ( Size jj = 1; jj <= res.atoms_last_controlled_by_chi( ii ).size(); ++jj ) {
263  Size const jjatom = res.atoms_last_controlled_by_chi( ii )[ jj ];
264  if ( jjatom == chiat4 ) continue;
265 
266  Vector jjloc_in_chitip_frame = chi_tip_frame.to_local_coordinate( res.xyz( jjatom ) );
267  nonchitip_atoms_[ ii ].push_back( jjatom );
268  points_for_nonchitip_atoms_[ ii ].push_back( jjloc_in_chitip_frame );
269  which_point_for_atom_[ jjatom ] = points_for_nonchitip_atoms_[ ii ].size();
270  }
271  }
272 }*/
273 
274 
276  backbone_only_( false ),
277  rot_prob_accumulation_limit_( 0.98 ),
278  check_fa_dun_(false),
279  fa_dun_cutoff_(0.0)
280 {}
281 
283 
284 BuildSet::BuildSet( BuildSet const & other ) : parent() {
285  (*this) = other;
286 }
287 
288 
289 BuildSet const &
291 {
292  if ( this != &rhs ) {
293 
294  restype_ = rhs.restype_;
296 
300  algorithm_ = rhs.algorithm_; // SHALLOW COPY
301 
303  atom_radii_ = rhs.atom_radii_;
304 
307  }
308  return *this;
309 }
310 
311 
314  bool backbone_only
315 )
316 {
317  restype_ = restype;
319 
321 
322  sample_strategy_for_chi_.clear();
323  sample_strategy_for_chi_.resize( restype->nchi() );
324 
325  nbonds_from_bb_atom_.resize( restype_->natoms() );
326  atom_radii_.resize( restype_->natoms() );
327 
328  for ( Size ii = 1; ii <= nbonds_from_bb_atom_.size(); ++ii ) {
329  if ( restype_->atom_is_backbone( ii )) {
330  nbonds_from_bb_atom_[ ii ] = 0;
331  } else {
332  Size min_path_dist = 6; /// assume that we only care about bond distances less than 6; anything greater than 5 is "infinite"
333  for ( Size jj = 1; jj <= nbonds_from_bb_atom_.size(); ++jj ) {
334  if ( restype_->atom_is_backbone( jj ) && (Size) restype_->path_distance( ii, jj ) < min_path_dist ) {
335  min_path_dist = restype_->path_distance( ii, jj );
336  }
337  }
338  nbonds_from_bb_atom_[ ii ] = min_path_dist;
339  }
340  }
341 
342  for ( Size ii = 1; ii <= atom_radii_.size(); ++ii ) {
343  atom_radii_[ ii ] = probe_radius_for_atom_type( restype_->atom( ii ).atom_type_index() );
344  }
345 }
346 
348  Size chi,
349  SampleStrategyData const & data
350 )
351 {
352  sample_strategy_for_chi_[ chi ] = data;
353 }
354 
355 
358 )
359 {
361 }
362 
363 void
365  core::Real cutoff )
366 {
367  fa_dun_cutoff_ = cutoff;
368  if( cutoff == 0.0 ) check_fa_dun_ = false;
369  else check_fa_dun_ = true;
370 }
371 
372 
374  BuildSet const & build_set,
376  bool dry_run
377 ) :
378  dry_run_( dry_run ),
379  num_chi_samples_total_( 1 )
380 {
381  Size nchi = build_set.restype().nchi();
382  if ( ! dry_run ) {
383  if ( nchi == 0 ) {
384  n_samples_per_chi_.resize( 1, 1 ); /// pretend we have one sample and one chi
385  } else {
386  n_samples_per_chi_.resize( nchi );
387  std::fill( n_samples_per_chi_.begin(), n_samples_per_chi_.end(), 0 );
388  chi_samples_.resize( nchi );
389  frames_.resize( nchi );
390  }
391  }
392 
393  for ( Size ii = 1; ii <= nchi; ++ii ) {
394 
395  if ( ii > sample.nchi() ) {
396  expand_non_dunbrack_chi( ii, build_set );
397  } else {
398  switch ( build_set.sample_strategy_for_chi( ii ).strategy() ) {
399  case no_samples:
400  if ( !dry_run ) {
401  n_samples_per_chi_[ ii ] = 1;
402  chi_samples_[ ii ].resize( 1 );
403  frames_[ ii ].resize( 1 );
404  chi_samples_[ ii ][ 1 ] = numeric::dihedral_degrees(
405  build_set.restype().atom( build_set.restype().chi_atoms( ii )[ 1 ] ).ideal_xyz(),
406  build_set.restype().atom( build_set.restype().chi_atoms( ii )[ 2 ] ).ideal_xyz(),
407  build_set.restype().atom( build_set.restype().chi_atoms( ii )[ 3 ] ).ideal_xyz(),
408  build_set.restype().atom( build_set.restype().chi_atoms( ii )[ 4 ] ).ideal_xyz() );
409  }
410  break;
411  case follow_EX_flags :
413  break;
414 
416  expand_samples_by_ex_behavior( ii, build_set.sample_strategy_for_chi( ii ).sample_level(), sample );
417  break;
418 
420  expand_samples_by_steps_wi_sdrange( ii, build_set.sample_strategy_for_chi( ii ), sample );
421  break;
422 
423  /// distinction without a difference; when would you ever want to sample the boundary point twice!?
426  expand_samples_for_nrchi_wi_nrchi_bin( ii, build_set.sample_strategy_for_chi( ii ), sample );
427  break;
428 
429  /// UNIMPLEMENTED BELOW:
431  //break;
433  //break;
434  //break;
435  utility_exit_with_message( "unimplemented rotamer building strategy" );
436  break;
437  }
438  }
439  if ( ! dry_run_ ) {
440  create_hts_for_chi( ii );
441  }
442  }
443 
444 }
445 
446 void
448 {
449  using namespace core::pack::task;
450 
451  if ( build_set.restype().is_proton_chi( chi ) ) {
452  Size const proton_chi = build_set.restype().chi_2_proton_chi( chi );
453  bool extra_proton_chi( ex_level_from_flags( chi ) > NO_EXTRA_CHI_SAMPLES );
454 
455  Size nsamples( 1 );
456 
457  if ( build_set.sample_strategy_for_chi( chi ).strategy() == no_samples ) {
458  /// noop
459  nsamples = 1;
460  } else if ( extra_proton_chi ) {
461  nsamples = build_set.restype().proton_chi_samples( proton_chi ).size() *
462  ( 1 + 2*build_set.restype().proton_chi_extra_samples( proton_chi ).size() );
463  } else {
464  nsamples = build_set.restype().proton_chi_samples( proton_chi ).size();
465  }
466 
467  if ( ! dry_run_ ) {
468  chi_samples_[ chi ].reserve( nsamples );
469  if ( build_set.sample_strategy_for_chi( chi ).strategy() == no_samples ) {
470  chi_samples_[ chi ].push_back( build_set.restype().proton_chi_samples( proton_chi )[ 1 ] );
471  } else {
472  for ( Size ii = 1; ii <= build_set.restype().proton_chi_samples( proton_chi ).size(); ++ii ) {
473  if ( extra_proton_chi ) {
474  for ( Size jj = 1; jj <= build_set.restype().proton_chi_extra_samples( proton_chi ).size(); ++jj ) {
475  chi_samples_[ chi ].push_back( build_set.restype().proton_chi_samples( proton_chi )[ ii ] -
476  build_set.restype().proton_chi_extra_samples( proton_chi )[ jj ] );
477  }
478  }
479  chi_samples_[ chi ].push_back( build_set.restype().proton_chi_samples( proton_chi )[ ii ] );
480  if ( extra_proton_chi ) {
481  for ( Size jj = 1; jj <= build_set.restype().proton_chi_extra_samples( proton_chi ).size(); ++jj ) {
482  chi_samples_[ chi ].push_back( build_set.restype().proton_chi_samples( proton_chi )[ ii ] +
483  build_set.restype().proton_chi_extra_samples( proton_chi )[ jj ] );
484  }
485  }
486  }
487  }
488  n_samples_per_chi_[ chi ] = nsamples;
489  }
490  num_chi_samples_total_ *= nsamples;
491  } else {
492  utility_exit_with_message( "Unrecognized chi type in ProteinUpstreamBuilder for " +
493  build_set.restype().name() + " chi# " + utility::to_string( chi ) );
494  }
495 }
496 
497 void
499  Size chi,
500  ExtraRotSample behavior,
502 )
503 {
504  using namespace core::pack::task;
505 
506  Size nsamps( 1 );
507 
508  if ( sample.chi_is_nonrotameric( chi ) ) {
509  if ( behavior != NO_EXTRA_CHI_SAMPLES ) {
510  nsamps = 3;
511  if ( ! dry_run_ ) {
512  n_samples_per_chi_[ chi ] = nsamps;
513  chi_samples_[ chi ].reserve( nsamps );
514  chi_samples_[ chi ].push_back( sample.nrchi_lower_boundary() + 0.5 * ( sample.chi_mean()[ chi ] - sample.nrchi_lower_boundary() ));
515  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
516  chi_samples_[ chi ].push_back( sample.nrchi_upper_boundary() + 0.5 * ( sample.nrchi_upper_boundary() - sample.chi_mean()[ chi ] ));
517  }
518  } else {
519  nsamps = 1;
520  if ( ! dry_run_ ) {
521  n_samples_per_chi_[ chi ] = nsamps;
522  chi_samples_[ chi ].reserve( nsamps );
523  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
524  }
525  }
526  } else { /// rotameric chi
527 
528  switch ( behavior ) {
529  case NO_EXTRA_CHI_SAMPLES :
530  if ( ! dry_run_ ) {
531  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
532  n_samples_per_chi_[ chi ] = 1;
533  }
534  break;
535  case EX_ONE_STDDEV :
536  nsamps = 3;
537  if ( ! dry_run_ ) {
538  chi_samples_[ chi ].reserve( nsamps );
539  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - sample.chi_sd()[ chi ] );
540  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
541  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + sample.chi_sd()[ chi ] );
542  n_samples_per_chi_[ chi ] = nsamps;
543  }
544  break;
546  nsamps = 3;
547  if ( ! dry_run_ ) {
548  chi_samples_[ chi ].reserve( nsamps );
549  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.5 * sample.chi_sd()[ chi ] );
550  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
551  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.5 * sample.chi_sd()[ chi ] );
552  n_samples_per_chi_[ chi ] = nsamps;
553  }
554  break;
556  nsamps = 5;
557  if ( ! dry_run_ ) {
558  chi_samples_[ chi ].reserve( nsamps );
559  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 2 * sample.chi_sd()[ chi ] );
560  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1 * sample.chi_sd()[ chi ] );
561  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
562  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1 * sample.chi_sd()[ chi ] );
563  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 2 * sample.chi_sd()[ chi ] );
564  n_samples_per_chi_[ chi ] = nsamps;
565  }
566  break;
568  nsamps = 5;
569  if ( ! dry_run_ ) {
570  chi_samples_[ chi ].reserve( nsamps );
571  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.0 * sample.chi_sd()[ chi ] );
572  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.5 * sample.chi_sd()[ chi ] );
573  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
574  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.5 * sample.chi_sd()[ chi ] );
575  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.0 * sample.chi_sd()[ chi ] );
576  n_samples_per_chi_[ chi ] = nsamps;
577  }
578  break;
580  nsamps = 9;
581  if ( ! dry_run_ ) {
582  chi_samples_[ chi ].reserve( nsamps );
583  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 2.0 * sample.chi_sd()[ chi ] );
584  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.5 * sample.chi_sd()[ chi ] );
585  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.0 * sample.chi_sd()[ chi ] );
586  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.5 * sample.chi_sd()[ chi ] );
587  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
588  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.5 * sample.chi_sd()[ chi ] );
589  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.0 * sample.chi_sd()[ chi ] );
590  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.5 * sample.chi_sd()[ chi ] );
591  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 2.0 * sample.chi_sd()[ chi ] );
592  n_samples_per_chi_[ chi ] = nsamps;
593  }
594  break;
596  nsamps = 7;
597  if ( ! dry_run_ ) {
598  chi_samples_[ chi ].reserve( nsamps );
599  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.0 * sample.chi_sd()[ chi ] );
600  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.67 * sample.chi_sd()[ chi ] );
601  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.33 * sample.chi_sd()[ chi ] );
602  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
603  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.33 * sample.chi_sd()[ chi ] );
604  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.67 * sample.chi_sd()[ chi ] );
605  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.0 * sample.chi_sd()[ chi ] );
606  n_samples_per_chi_[ chi ] = nsamps;
607  }
608  break;
610  nsamps = 13;
611  if ( ! dry_run_ ) {
612  chi_samples_[ chi ].reserve( nsamps );
613  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.50 * sample.chi_sd()[ chi ] );
614  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.25 * sample.chi_sd()[ chi ] );
615  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 1.00 * sample.chi_sd()[ chi ] );
616  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.75 * sample.chi_sd()[ chi ] );
617  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.50 * sample.chi_sd()[ chi ] );
618  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - 0.25 * sample.chi_sd()[ chi ] );
619  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
620  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.25 * sample.chi_sd()[ chi ] );
621  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.50 * sample.chi_sd()[ chi ] );
622  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 0.75 * sample.chi_sd()[ chi ] );
623  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.00 * sample.chi_sd()[ chi ] );
624  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.25 * sample.chi_sd()[ chi ] );
625  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + 1.50 * sample.chi_sd()[ chi ] );
626  n_samples_per_chi_[ chi ] = nsamps;
627  }
628  break;
629  default :
630  utility_exit_with_message( "Requested ex sample level not yet supported" );
631  break;
632  }
633  }
634  num_chi_samples_total_ *= nsamps;
635 }
636 
637 void
639  Size chi,
640  SampleStrategyData const & stratdat,
642 )
643 {
644  Size nsamps( 1 );
645 
646  runtime_assert( stratdat.strategy() == rotameric_chi_step_wi_sd_range );
647  runtime_assert( stratdat.sd_range() > 0 );
648  runtime_assert( stratdat.step_size() > 0 );
649  Size nsteps = static_cast< int > ( (sample.chi_sd()[ chi ] * stratdat.sd_range()) / stratdat.step_size() );
650  nsamps = 1 + 2 * nsteps;
651 
652  if ( ! dry_run_ ) {
653  n_samples_per_chi_[ chi ] = nsamps;
654  chi_samples_[ chi ].reserve( nsamps );
655  for ( Size ii = nsteps; ii >= 1; --ii ) {
656  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] - ii * stratdat.step_size() );
657  }
658  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
659  for ( Size ii = 1; ii <= nsteps; ++ii ) {
660  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + ii * stratdat.step_size() );
661  }
662  }
663 
664  num_chi_samples_total_ *= nsamps;
665 }
666 
667 void
669  Size chi,
670  SampleStrategyData const & stratdat,
672 )
673 {
674  Size nsamps( 1 );
675  if ( sample.chi_is_nonrotameric( chi ) ) {
676  if ( sample.probability() > stratdat.nrchi_prob_minimum_for_extra_samples() ) {
677  /// expand!
678  nsamps = 1 + ( stratdat.n_samples_per_side_of_nrchi_bin() == 0 ?
679  0 : 2 * stratdat.n_samples_per_side_of_nrchi_bin() - 1 );
680  if ( ! dry_run_ ) {
681  n_samples_per_chi_[ chi ] = nsamps;
682  chi_samples_[ chi ].reserve( nsamps );
683  {// lower
684  Real lower_edge = sample.nrchi_lower_boundary();
685  Real step = ( sample.chi_mean()[ chi ] - lower_edge ) / stratdat.n_samples_per_side_of_nrchi_bin();
686  for ( Size ii = 0; ii < stratdat.n_samples_per_side_of_nrchi_bin(); ++ii ) {
687  chi_samples_[ chi ].push_back( lower_edge + ii * step );
688  }
689  }
690  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
691  {// upper
692  Real upper_edge = sample.nrchi_upper_boundary();
693  Real step = ( upper_edge - sample.chi_mean()[ chi ] ) / stratdat.n_samples_per_side_of_nrchi_bin();
694  for ( Size ii = 1; ii < stratdat.n_samples_per_side_of_nrchi_bin(); ++ii ) {
695  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] + ii * step );
696  }
697  }
698  }
699 
700  } else {
701  nsamps = 1;
702  if ( ! dry_run_ ) {
703  n_samples_per_chi_[ chi ] = nsamps;
704  chi_samples_[ chi ].reserve( nsamps );
705  chi_samples_[ chi ].push_back( sample.chi_mean()[ chi ] );
706  }
707  }
708  } else {
709  utility_exit_with_message( "Cannot treat chi " + utility::to_string( chi ) + " as non-rotameric; did you forget the -dun10 flag?" );
710  }
711  num_chi_samples_total_ *= nsamps;
712 }
713 
714 
715 void
717 {
718  assert( ! dry_run_ );
719  Size const nsamples = chi_samples_[ chi ].size();
720  runtime_assert( nsamples == n_samples_per_chi_[ chi ] );
721  frames_[ chi ].resize( nsamples );
722  for ( Size ii = 1; ii <= nsamples; ++ii ) {
723  frames_[ chi ][ ii ].set_zaxis_rotation_deg( chi_samples_[ chi ][ ii ] );
724  }
725 }
726 
727 
730 {
731  using namespace basic::options;
732  using namespace basic::options::OptionKeys::packing;
733  using namespace core::pack::task;
734 
735  ExtraRotSample sample_level( NO_EXTRA_CHI_SAMPLES );
736 
737  switch ( chi ) {
738  case 1:
739  if ( option[ ex1::ex1 ] ) sample_level = EX_ONE_STDDEV;
740  if ( option[ ex1::level ].user() && option[ ex1::level ] > sample_level ) sample_level = ExtraRotSample( option[ ex1::level ]() );
741  break;
742  case 2 :
743  if ( option[ ex2::ex2 ] ) sample_level = EX_ONE_STDDEV;
744  if ( option[ ex2::level ].user() && option[ ex2::level ] > sample_level ) sample_level = ExtraRotSample( option[ ex2::level ]() );
745  break;
746  case 3 :
747  if ( option[ ex3::ex3 ] ) sample_level = EX_ONE_STDDEV;
748  if ( option[ ex3::level ].user() && option[ ex3::level ] > sample_level ) sample_level = ExtraRotSample( option[ ex3::level ]() );
749  break;
750  case 4 :
751  if ( option[ ex4::ex4 ] ) sample_level = EX_ONE_STDDEV;
752  if ( option[ ex4::level ].user() && option[ ex4::level ] > sample_level ) sample_level = ExtraRotSample( option[ ex4::level ]() );
753  break;
754  }
755  return sample_level;
756 }
757 
758 //Kui 112509 Native. Initial avoid_building_any_rotamers_dueto_native_ to false
759 ProteinUpstreamBuilder::ProteinUpstreamBuilder() : use_input_sc_( false ), avoid_building_any_rotamers_dueto_native_( false )
760 {}
761 
763 
766  return new ProteinUpstreamBuilder( *this );
767 }
768 
769 //Kui 110609 Native
772 }
773 
774 
775 /// @details
776 /// This is the main workhorse function for the upstream builder. There are lots of ways
777 /// to customize the way the loops in this function work, but custom code should be written
778 /// in subroutines called by this function and should not change the function itself.
779 /// It is crucial here that the rotamers are created in the same way they were
780 /// counted in insert(). Make sure that if you change build()'s behavior, that insert()'s
781 /// behavior changes, too!
782 ///
783 /// DO NOT LET THIS FUNCTION EXCEED 150 LINES. CLEAR CODE IS SHORT.
784 std::list< Hit >
786  ScaffoldBuildPoint const & build_point
787 ) const
788 {
789  // std::cout << "APL DEBUG ProteinUpstreamBuilder::build begin" << std::endl;
790  /// Algorithm in brief:
791  /// declare a local hit list; this list will be returned at the end of this method.
792  /// Iterate across residue types to build
793  /// Get the list of base chi samples.
794  /// Build CB coordinate frame. If CB is outside the found-hits accessibility volume, continue.
795  /// for each base chi sample (that's sufficiently probable), enumerate the expanded chi samples,
796  /// and precompute the HT's for each chi sample
797  /// Enumerate the expanded chi combinations (with a LexicographicalIterator )
798  /// If, when building atoms for chi i, an atom collides with the background, continue.
799  /// If the chitip atom for chi i is outside of the found-hits accessibility volume, continue.
800  /// Fill the ResidueCoordinates object with the coordinates for this chi
801  /// Iterate across the ExternalGeomSamplers, calling parent::build_from_three_coords() method
802  /// splice the returned hit list of returned hits into the local hit list.
803  /// return the local list of hits
804 
805  using namespace utility;
806 
807  std::list< Hit > local_hit_list;
808 
809  Size upstream_state = 1;
810  Size n_possible_hits = 0;
811  for ( Size ii = 1; ii <= build_sets_.size(); ++ii ) {
812  core::conformation::Residue rescoords( build_sets_[ ii ].restype(), false );
813  //TR << "Building residue type: " << rescoords.type().name() << std::endl;
814 
815  core::pack::dunbrack::RotamerLibraryScratchSpace dunscratch; //in case we're checking fa_dun for rotamer
817  bool check_fa_dun( build_sets_[ii].check_fa_dun() );
818  core::Real fa_dun_cutoff( build_sets_[ii].fa_dun_cutoff() );
819  if( check_fa_dun ){
820  ProteinBackboneBuildPoint const & bb(
821  static_cast< ProteinBackboneBuildPoint const & >
822  ( build_point ));
823  rescoords.mainchain_torsions()[1] = bb.phi();
824  rescoords.mainchain_torsions()[2] = bb.psi();
825  }
826 
827  Size const ii_nchi = build_sets_[ ii ].restype().nchi(); // may be different from the number of chi that the Dunbrack library defines
828  UpstreamResTypeGeometry const & geom( build_sets_[ ii ].restype_geometry() );
829 
830  vector0< HTReal > chitip_frames( ii_nchi + 1 );
831  Real accumulated_probability( 0.0 );
832 
833  /// Query the rotamer sampler for the list of samples to take
834  DunbrackRotamerSampleDataVector rotamer_samples = sampler_->samples( build_point, build_sets_[ ii ].restype() );
835 
836  /// Load the Residue with the build point coordinates, and compute the CBeta frame.
837  /// Frame 0 defines the frame at CBeta -- to build the chi-tip atom for chi i,
838  /// build from the frame for i-1. For chi 1, start with the frame for "chi 0"
839  chitip_frames[ 0 ] = initialize_rescoords( ii, rescoords, build_point );
840  bool const avoid_building_any_rotamers = atom_coordinate_unacceptable(
841  ii, rescoords, build_sets_[ ii ].restype_geometry().CB_atom_id() );
842 
843 
844  Size ii_nrotamers( 0 );
845 
846  for ( Size jj = 1; jj <= rotamer_samples.size(); ++jj ) {
847 
848  /// Compute the set of extra samples to take for this rotamer.
849  /// The rules for building extra samples are not known to the upstream builder,
850  /// so if the upstream builder is to maintain an accurate "state" id for
851  /// later reconstructing the rotamer described by a hit, the upstream builder
852  /// cannot skip the logic for counting how many extra rotamers there are, and how
853  /// many extra states are being skipped.
854  FullChiSampleSet additional_chi_samples(
855  build_sets_[ ii ], rotamer_samples[ jj ], avoid_building_any_rotamers );
856 
857  //Kui 110509 Native codes
858  // avoid_building_any_rotamers_dueto_native_ is a native residue flag.
859  // If user specific this option, he/she want to use native residue only.
860  if ( avoid_building_any_rotamers || avoid_building_any_rotamers_dueto_native_ ) {
861  /// With a count of how many extra states there are for this rotamer, the upstream
862  /// state may safely advance to the next rotamer.
863  upstream_state += additional_chi_samples.num_chi_samples_total();
864  } else {
865  utility::LexicographicalIterator lex( additional_chi_samples.n_samples_per_chi() );
866 
867  /// Iterate across all combinations of chi dihedrals for this rotamer.
868 
869  Size n_chi_needing_update = ii_nchi;
870  while ( ! lex.at_end() ) {
871  assert( ( n_chi_needing_update >= 1 || ii_nchi == 0 ) && n_chi_needing_update <= ii_nchi );
872  /// Some rotamer placements may be skipped because they either collide with the
873  /// background, or they would produce downstream geometries that are too distant
874  /// from any of the hits generated in previous stages (and therefore would be
875  /// unable to produce a hit that matched the other hits).
876  bool rotamer_acceptable( true );
877 
878  /// Iterate outwards from the closest chi to the most distal chi, starting
879  /// from the chi which last changed: all coordinate frames before that last chi
880  /// are still valid since (by construction) the chi upstream has not changed from the
881  /// previous iteration.
882  for ( Size kk = ii_nchi - n_chi_needing_update + 1; kk <= ii_nchi; ++kk ) {
883  chitip_frames[ kk ] = chitip_frames[ kk - 1 ] *
884  additional_chi_samples.frame( kk, lex[ kk ] ) *
885  geom.ht_for_chitip_atom( kk ); // matrix * matrix * matrix
886  rescoords.set_xyz( geom.chitip_atom( kk ), chitip_frames[ kk ].point());
887  rescoords.chi()[ kk ] = additional_chi_samples.chi_sample( kk, lex[ kk ] );
888  if ( atom_coordinate_unacceptable( ii, rescoords, geom.chitip_atom( kk ) ) ) {
889  rotamer_acceptable = false;
890  }
891  if ( rotamer_acceptable ) {
892  // if the chitip atom is unacceptible, then don't bother computing the coordinates
893  // for the other atoms controlled by this chi.
894  for ( Size ll = 1; ll <= geom.n_nonchitip_atoms_for_chi( kk ); ++ll ) {
895  Size const ll_atno = geom.nonchitip_atom( kk, ll );
896  // matrix * vector
897  rescoords.set_xyz( ll_atno, chitip_frames[ kk ] * geom.points_for_nonchitip_atoms( kk )[ ll ]);
898  if ( atom_coordinate_unacceptable( ii, rescoords, ll_atno )) {
899  rotamer_acceptable = false;
900  break;
901  }
902  }
903  }
904 
905  //dunbrack energy check
906  //apparently we have to specifically
907  //set each chi in the residue object
908  //this check can only be performed after we have specified all the chi angles, so it should only
909  //be performed in the very last iteration through this loop.
910  if ( kk == ii_nchi && rotamer_acceptable && check_fa_dun ) {
911  for ( core::Size res_chi(1); res_chi<= ii_nchi; ++res_chi) {
912  rescoords.chi()[res_chi] = additional_chi_samples.chi_sample( res_chi, lex[ res_chi ] );
913  }
914  if( rotlib->rotamer_energy( rescoords, dunscratch ) >= fa_dun_cutoff ){
915  rotamer_acceptable = false;
916  }
917  }
918 
919  if ( ! rotamer_acceptable ) {
920  /// Bail out. We have a collision for an atom whose coordinates depend on chi kk.
921  /// or we've determined that chi kk cannot place the downstream partner sufficiently close
922  /// to any of the hits generated in previous rounds.
923  /// Advance the lexicographical iterator for dimension kk. If this is the last chi sample
924  /// for chi kk, then chi kk - 1 will be advanced (or kk - 2 if kk - 1 is at it's last
925  /// chi sample, etc.). The coordinates for everything downstream of
926  /// ii_nchi - n_chi_needing_update + 1 will need updating in the next round (if there is one).
927  Size n_skipped = 1;
928  for ( Size ll = kk+1; ll <= ii_nchi; ++ll ) {
929  n_skipped *= lex.dimsize( ll );
930  }
931  upstream_state += n_skipped;
932  ii_nrotamers += n_skipped;
933  n_chi_needing_update = lex.continue_at_dimension( kk );
934  break;
935  }
936  } // end update coordinates for residue
937  if ( ! rotamer_acceptable ) continue; // lex iter has already been updated, and upstream_state already advanced.
938 
939  //std::cout << "ScaffID: " << build_point.index() << " built rotamer # " << upstream_state << " " << rescoords.name();
940  //for ( Size chi = 1; chi <= ii_nchi; ++chi ) std::cout << " " << additional_chi_samples.chi_sample( chi, lex[ chi ] ); std::cout << std::endl;
941 
942  /// Excellent! We've arrived at a conformation for this rotamer that's acceptible (collision free).
943  /// Hand off work to the downstream hit construction algorithm.
944  std::list< Hit > hits = build_sets_[ ii ].algorithm().build(
945  build_point.index(),
946  upstream_state,
947  rescoords );
948  local_hit_list.splice( local_hit_list.end(), hits );
949 
950  /// proceed to the next chi sample -- track how many chi changed and build
951  /// from the first chi that did not change -- that chi's coordinate frame is still
952  /// up to date.
953  n_chi_needing_update = ++lex;
954  ++upstream_state;
955  ++ii_nrotamers;
956  }
957 
958  }
959 
960  /// build rotamers that are sufficiently probable and bail out once we reach
961  /// the dregs. The user controls the dreg limit. Note, however, that matching
962  /// does nothing to point out that low probability rotamers are poor! Include
963  /// low probability rotamers at your own risk.
964  accumulated_probability += rotamer_samples[ jj ].probability();
965  if ( accumulated_probability > build_sets_[ ii ].probability_limit() ) break;
966  } //jj loop over rotamer_samples.size()
967 
968  /// Finally, build rotamers for the input side chain, if the original scaffold build point
969  /// is of the appropriate type
970  /// Kui 110609 Native
971  /// avoid_building_any_rotamers_dueto_native_ specific usage of native residue only.
973 
975  dynamic_cast< OriginalBackboneBuildPoint const * > ( & build_point );
976  if ( orig && & (orig->input_conformation().type()) == & (build_sets_[ ii ].restype()) ) {
977  /// restype match
978  std::list< Hit > hits = build_sets_[ ii ].algorithm().build(
979  build_point.index(),
980  upstream_state,
981  orig->input_conformation() );
982  local_hit_list.splice( local_hit_list.end(), hits );
983  ++upstream_state;
984  n_possible_hits += build_sets_[ ii ].algorithm().n_possible_hits_per_upstream_conformation();
985  //Kui 110609 Native debug
986  //TR << "use_input_sc_:" << use_input_sc_ << " avoid_building_any_rotamers_dueto_native_:"
987  // << avoid_building_any_rotamers_dueto_native_ << std::endl;
988  }
989  }
990 
991  n_possible_hits += ii_nrotamers * build_sets_[ ii ].algorithm().n_possible_hits_per_upstream_conformation();
992  //TR << "Finished building residue type: " << rescoords.type().name() << std::endl;
993  } //ii loop over build sets
994 
995  assert( dynamic_cast< ProteinBackboneBuildPoint const * > ( & build_point ) );
996  ProteinBackboneBuildPoint const & bb( static_cast< ProteinBackboneBuildPoint const & >
997  ( build_point ) );
998 
999  TR << "Considered " << n_possible_hits << " downstream conformations at residue " << bb.original_insertion_point() << " and found " << local_hit_list.size() << " hits." << std::endl;
1000  //std::cout << "APL DEBUG ProteinUpstreamBuilder::build end" << std::endl;
1001  return local_hit_list;
1002 }
1003 
1004 
1005 
1006 /// @brief Replace residue for the amino acid corresponding to the rotamer indicated in the
1007 /// hit at the Pose position seqpos_to_insert_at.
1008 /// @details It is crucial here that the rotamers are counted in the same way they were
1009 /// iterated across in build. Make sure that if build() changes its behavior, that this
1010 /// function also changes its behavior!
1011 void
1013  Hit const & hit,
1014  ScaffoldBuildPoint const & build_point,
1015  UpstreamResidueProcessor & processor
1016 ) const
1017 {
1018  std::list< Hit > hitlist;
1019  hitlist.push_back( hit );
1020  recover_hits( hitlist.begin(), hitlist.end(), build_point, processor );
1021 }
1022 
1023 void
1025  std::list< Hit >::const_iterator hit_iter,
1026  std::list< Hit >::const_iterator hits_end,
1027  ScaffoldBuildPoint const & build_point,
1028  UpstreamResidueProcessor & processor
1029 ) const
1030 {
1031 // assert( hit_iter == hits_end || hit_iter->scaffold_build_id() == build_point.id() );
1032  assert( hit_iter == hits_end || hit_iter->scaffold_build_id() == build_point.index() );
1033  //Hit hit = *hit_iter;
1034  //std::cout << "ProteinUpstreamBuilder::recover hit " << hit.first()[ 1 ] << " " << hit.first()[ 2 ] << std::endl;
1035  /// 1. Figure out which amino acid it is that we're inserting.
1036  Size upstream_state = 1;
1037  for ( Size ii = 1; ii <= build_sets_.size(); ++ii ) {
1038  Size const ii_nchi = build_sets_[ ii ].restype().nchi(); // may be different from the number of chi that the Dunbrack library defines
1039  Real accumulated_probability( 0.0 );
1040 
1041  /// Query the rotamer sampler for the list of samples to take
1042  DunbrackRotamerSampleDataVector rotamer_samples = sampler_->samples( build_point, build_sets_[ ii ].restype() );
1043 
1044  for ( Size jj = 1; jj <= rotamer_samples.size(); ++jj ) {
1045 
1046  /// Determine how many extra samples to take for this rotamer using the "dry_run" flag of the FullChiSampleSet
1047  FullChiSampleSet dry_samples(
1048  build_sets_[ ii ], rotamer_samples[ jj ], /*dry_run*/ true );
1049 
1050  //std::cout << " jj " << jj << " us_state: " << upstream_state << " nsamps: " << dry_samples.num_chi_samples_total() << std::endl;
1051  //Kui Native 110809 - need more testing for native 2nd matching
1052  if ( upstream_state + dry_samples.num_chi_samples_total() <= hit_iter->first()[ 2 ]
1054  /// With a count of how many extra states there are for this rotamer, the upstream
1055  /// state may safely advance to the next rotamer.
1056  upstream_state += dry_samples.num_chi_samples_total();
1057  } else {
1058  UpstreamResTypeGeometry const & geom( build_sets_[ ii ].restype_geometry() );
1059 
1060  /// Determine the actual chi to be used.
1061  FullChiSampleSet additional_chi_samples(
1062  build_sets_[ ii ], rotamer_samples[ jj ], /*dry_run*/ false );
1063 
1064  runtime_assert( dry_samples.num_chi_samples_total() == additional_chi_samples.num_chi_samples_total() );
1065 
1066  utility::LexicographicalIterator lex( additional_chi_samples.n_samples_per_chi() );
1067 
1068  /// Reuse the additional_chi_samples and lex if we have multiple hits that come from
1069  /// the same base-rotamer. The exit conditions for this loop are:
1070  /// the hit list is exhausted, or, the next hit isn't within the set of subrotamers
1071  /// for this base rotamer.
1072  while ( true ) {
1073  lex.set_position_from_index( hit_iter->first()[ 2 ] - upstream_state + 1 );
1074 
1075  utility::vector0< HTReal > chitip_frames( ii_nchi + 1 );
1076  core::conformation::Residue rescoords( build_sets_[ ii ].restype(), false );
1077  chitip_frames[ 0 ] = initialize_rescoords( ii, rescoords, build_point );
1078 
1079  for ( Size kk = 1; kk <= ii_nchi; ++kk ) {
1080  chitip_frames[ kk ] = chitip_frames[ kk - 1 ] *
1081  additional_chi_samples.frame( kk, lex[ kk ] ) *
1082  geom.ht_for_chitip_atom( kk ); // matrix * matrix * matrix
1083  rescoords.set_xyz( geom.chitip_atom( kk ), chitip_frames[ kk ].point());
1084  rescoords.chi()[ kk ] = additional_chi_samples.chi_sample( kk, lex[ kk ] );
1085  for ( Size ll = 1; ll <= geom.n_nonchitip_atoms_for_chi( kk ); ++ll ) {
1086  Size const ll_atno = geom.nonchitip_atom( kk, ll );
1087  // matrix * vector
1088  rescoords.set_xyz( ll_atno, chitip_frames[ kk ] * geom.points_for_nonchitip_atoms( kk )[ ll ]);
1089  }
1090  }
1091 
1092  //std::cout << "ScaffID: " << build_point.index() << " recover rotamer # " << hit_iter->first()[ 2 ] << " " << rescoords.name();
1093  //for ( Size chi = 1; chi <= ii_nchi; ++chi ) std::cout << " " << additional_chi_samples.chi_sample( chi, lex[ chi ] ); std::cout << std::endl;
1094 
1095  /// Hand off the coordinates of the Residue to the UpstreamResidueProcessor
1096  /// Maybe this writes a kinemage file, or inserts the residue into a Pose.
1097  processor.process_hit( *hit_iter, rescoords );
1098 
1099  std::list< Hit >::const_iterator last_hit = hit_iter;
1100  ++hit_iter;
1101  if ( hit_iter == hits_end ) return;
1102  runtime_assert( hit_iter->scaffold_build_id() == last_hit->scaffold_build_id() );
1103  runtime_assert( hit_iter->upstream_conf_id() >= last_hit->upstream_conf_id() ); // sorted order!
1104  if ( upstream_state + dry_samples.num_chi_samples_total() <= hit_iter->first()[ 2 ] ) {
1105  upstream_state += dry_samples.num_chi_samples_total();
1106  break;
1107  }
1108  }
1109  }
1110 
1111  /// build rotamers that are sufficiently probable and bail out once we reach
1112  /// the dregs. The user controls the dreg limit. Note, however, that matching
1113  /// does nothing to point out that low probability rotamers are poor! Include
1114  /// low probability rotamers at your own risk.
1115  accumulated_probability += rotamer_samples[ jj ].probability();
1116  if ( accumulated_probability > build_sets_[ ii ].probability_limit() ) break;
1117  }
1118 
1119  /// Is the hit from the input side chain?
1120  //Kui Native 110809 - need more testing for native 2nd matching
1123  dynamic_cast< OriginalBackboneBuildPoint const * > ( & build_point );
1124  if ( orig && & (orig->input_conformation().type()) == & (build_sets_[ ii ].restype()) ) {
1125  /// restype match
1126  if ( hit_iter->first()[ 2 ] == upstream_state ) {
1127  processor.process_hit( *hit_iter, orig->input_conformation() );
1128  ++hit_iter;
1129  }
1130  if ( hit_iter == hits_end ) return;
1131  ++upstream_state;
1132  }
1133  }
1134  }
1135 
1136  // All rotamers should have been found by now; something is wrong if we reach the end
1137  // of this function instead of leaving trough one of the exit opportunities above.
1138  utility_exit_with_message("ProteinUpstreamBuilder was unable to recover rotamer " +
1139  utility::to_string( hit_iter->first()[ 2 ] ) + " from scaffold build position " +
1140  utility::to_string( hit_iter->first()[ 1 ] ) );
1141 }
1142 
1145 {
1146  return build_sets_.size();
1147 }
1148 
1151 {
1152  return & ( build_sets_[ which_restype ].restype() );
1153 }
1154 
1155 
1156 /// @brief The side chain for two
1157 bool
1159  Hit const & my_hit,
1160  ScaffoldBuildPoint const & build_point_mine,
1161  UpstreamBuilder const & other,
1162  Hit const & other_hit,
1163  ScaffoldBuildPoint const & build_point_other,
1164  bool
1165 ) const
1166 {
1167  return other.compatible( other_hit, build_point_other, *this, my_hit, build_point_mine, false );
1168 
1169 }
1170 
1172  Hit const & my_hit,
1173  ScaffoldBuildPoint const & build_point_mine,
1174  ProteinUpstreamBuilder const & other_builder,
1175  Hit const & other_hit,
1176  ScaffoldBuildPoint const & build_point_other,
1177  bool
1178 ) const
1179 {
1180  /// This sidechain can only be in one position per residue. Declare these
1181  /// SC builders incompatible if they're building from the same build point.
1182  if ( build_point_mine.index() != build_point_other.index() ) {
1183  return true;
1184  } else {
1185  if ( my_hit.first()[ 2 ] == 1 && build_sets_[ 1 ].backbone_only() ) {
1186  return true;
1187  } else if ( other_hit.first()[ 2 ] == 1 && other_builder.build_sets_[ 1 ].backbone_only() ) {
1188  return true;
1189  } else {
1190  return false;
1191  }
1192  }
1193 }
1194 
1195 void
1197  BuildSet const & build_set
1198 )
1199 {
1200  if ( build_set.backbone_only() ) {
1201  //build_sets_.push_front( build_set );
1202  runtime_assert( build_sets_.size() == 0 || ! build_sets_[ 1 ].backbone_only() ); /// only one backbone-only build set allowed
1203  build_sets_.resize( build_sets_.size() + 1 );
1204  for ( Size ii = build_sets_.size(); ii > 1; --ii ) {
1205  build_sets_[ ii ] = build_sets_[ ii - 1 ];
1206  }
1207  build_sets_[ 1 ] = build_set;
1208  } else {
1209  build_sets_.push_back( build_set );
1210  }
1211 }
1212 
1213 BuildSet const &
1215 {
1216  return const_cast< ProteinUpstreamBuilder * > (this)->build_set( restype );
1217 }
1218 
1219 BuildSet &
1221 {
1222  for ( Size ii = 1; ii <= build_sets_.size(); ++ii ) {
1223  if ( & (build_sets_[ ii ].restype()) == restype() ) {
1224  return build_sets_[ ii ];
1225  }
1226  }
1227  utility_exit_with_message( "Could not retrieve a build set for residue type " + restype->name() );
1228 
1229  // appease the compiler
1230  return b;
1231 }
1232 
1233 
1234 void
1236  ProteinSCSamplerCOP sampler
1237 )
1238 {
1239  sampler_ = sampler;
1240 }
1241 
1243 {
1244  //std::cout << "Setting use_input_sidechain" << setting << std::endl;
1245  use_input_sc_ = setting;
1246 }
1247 
1248 
1249 
1250 /// @brief Copy the coordinates from the build_point object into the the rescoords
1251 /// object, compute the coordinate frame at CBeta, copy the CB coordinate into the
1252 /// rescoords object, and return the CBeta frame.
1255  Size build_set_id,
1256  core::conformation::Residue & rescoords,
1257  ScaffoldBuildPoint const & build_point
1258 ) const
1259 {
1260  { /// scope to test that we have a protein backbone residue
1261 
1262  if ( ! dynamic_cast< ProteinBackboneBuildPoint const * > ( & build_point ) ) {
1263  utility_exit_with_message( "Input to ProteinUpstreamBuilder not castable to ProteinBackboneBuildPoint *" );
1264  }
1265 
1266  }
1267 
1268  ProteinBackboneBuildPoint const & bb( static_cast< ProteinBackboneBuildPoint const & >
1269  ( build_point ) );
1270 
1271  UpstreamResTypeGeometry const & geom( build_sets_[ build_set_id ].restype_geometry() );
1272 
1273  rescoords.seqpos( bb.original_insertion_point() );
1274  rescoords.set_xyz( geom.N_atom_id(), bb.N_pos());
1275  rescoords.set_xyz( geom.CA_atom_id(),bb.CA_pos());
1276  rescoords.set_xyz( geom.C_atom_id(), bb.C_pos());
1277  rescoords.set_xyz( geom.O_atom_id(), bb.O_pos());
1278 
1279  if ( geom.has_H_atom() ) rescoords.set_xyz( geom.H_atom_id(), bb.H_pos() );
1280  if ( geom.has_HA_atom() ) rescoords.set_xyz( geom.HA_atom_id(), bb.HA_pos() );
1281 
1282  if ( geom.has_CB_atom() ) {
1283  HTReal cb_frame = compute_cb_frame( build_set_id, bb );
1284  rescoords.set_xyz( geom.CB_atom_id(), cb_frame.point());
1285  return cb_frame;
1286  } else {
1287  /// GLYCINE
1288  HTReal input_frame( bb.N_pos(), 0.5 * ( bb.N_pos() + bb.C_pos() ), bb.CA_pos() );
1289  runtime_assert( build_sets_[ build_set_id ].restype().has( "1HA" ) );
1290  Size oneHA_index( build_sets_[ build_set_id ].restype().atom_index( "1HA" ));
1291  rescoords.set_xyz( oneHA_index,
1292  input_frame * geom.coordinate_for_nonchi_atom_in_ideal_frame( oneHA_index ));
1293  return input_frame;
1294  }
1295 }
1296 
1297 /// @details Follow Phil's convention for placing CBeta based on halfway point of
1298 /// the ideal N and C positions and the halfway point from the the input N and
1299 /// C positions. In fact, this is barely different from Phil's code except that
1300 /// it uses HT's instead of Stubs. By "Phil's code", I mean
1301 /// core/conformation/Residue.cc::orient_onto_position()
1304  Size build_set_id,
1305  ProteinBackboneBuildPoint const & build_point
1306 ) const
1307 {
1308  UpstreamResTypeGeometry const & geom( build_sets_[ build_set_id ].restype_geometry() );
1309 
1310  Size CB_no = geom.CB_atom_id();
1311  runtime_assert( CB_no != 0 ); // there's no reason that we should be building the CBeta frame if there's no cbeta.
1312 
1313  Vector halfpoint_input = 0.5 * ( build_point.N_pos() + build_point.C_pos() );
1314  HTReal input_frame( build_point.N_pos(), halfpoint_input, build_point.CA_pos() );
1315  Vector CBpos = input_frame * geom.coordinate_for_nonchi_atom_in_ideal_frame( CB_no );
1316 
1317  return HTReal( build_point.N_pos(), build_point.CA_pos(), CBpos );
1318 }
1319 
1320 /// @details Collision detection against the background goes here. "Background"
1321 /// is tricky for atoms near the backbone
1322 bool
1324  Size build_set_id,
1325  core::conformation::Residue const & rescoords,
1326  Size atomno
1327 ) const
1328 {
1329  /// do not run bump-grid collision detection on any atom that's within
1330  /// 4 chemical bonds of CA or you run the danger of wrongfully-detecting
1331  /// a collision with CA
1332 
1333  if ( atomno == 0 ) return false; // glycine CBeta
1334 
1335 
1336  Size const MIN_CHEMBOND_SEP_FROM_CA = 4;
1337  if ( build_sets_[ build_set_id ].nbonds_from_bb_atom( atomno ) > MIN_CHEMBOND_SEP_FROM_CA ) {
1338  return bbgrid().occupied( build_sets_[ build_set_id ].atom_radius( atomno ), rescoords.xyz( atomno ));
1339  } else if ( build_sets_[ build_set_id ].nbonds_from_bb_atom( atomno ) == MIN_CHEMBOND_SEP_FROM_CA ) {
1340  /// check to see if we're not colliding with CA but we are colliding with something else:
1341  /// ASSUMPTION. This atom connects to the backbone at a single point -- CAlpha.
1342  /// This assumes that there are no residues vaguly similar to proline where it would be possible
1343  /// to be 4 bonds from N but futher than four bonds from CA:
1344  /// N -- CA
1345  /// CD CB
1346  /// CD1 CG
1347  /// CD2 CG2
1348  /// CD3-CG3 <--- CD3 is 4 bonds from N. From my above assumption, I would incorrectly dismiss.
1349  /// some conformations where CD3 collided with N
1350 
1351  Size capos = build_sets_[ build_set_id ].restype_geometry().CA_atom_id();
1352  Real const min_d = bbgrid().required_separation_distance(
1353  build_sets_[ build_set_id ].atom_radius( capos ),
1354  build_sets_[ build_set_id ].atom_radius( atomno ) );
1355  Real min_d2 = min_d * min_d;
1356  if ( rescoords.xyz( atomno ).distance_squared( rescoords.xyz( capos )) > min_d2 ) {
1357  return bbgrid().occupied( build_sets_[ build_set_id ].atom_radius( atomno ), rescoords.xyz( atomno ));
1358  }
1359  }
1360 
1361 
1362  return false;
1363 
1364 }
1365 
1366 }
1367 }
1368 }