Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DnaInterfacePacker.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 // Unit headers
13 
16 #include <protocols/dna/util.hh>
23 
24 #include <core/types.hh>
37 #include <core/pose/Pose.hh>
38 #include <core/pose/PDBInfo.hh>
40 
41 #include <basic/options/option.hh>
42 #include <basic/options/keys/dna.OptionKeys.gen.hh>
43 #include <basic/options/keys/packing.OptionKeys.gen.hh>
44 #include <basic/options/keys/run.OptionKeys.gen.hh>
45 #include <basic/options/keys/out.OptionKeys.gen.hh>
46 
47 #include <basic/Tracer.hh>
48 
49 #include <utility/vector0.hh>
50 #include <utility/vector1.hh>
51 #include <utility/string_util.hh>
52 #include <utility/io/izstream.hh>
53 #include <utility/io/ozstream.hh>
54 #include <utility/tag/Tag.hh>
55 
56 // ObjexxFCL Headers
57 #include <ObjexxFCL/string.functions.hh> // lead_zero_string_of
58 
59 // c++ headers
60 #include <vector> // for rot_to_pack
61 #include <iostream>
62 #include <sstream>
63 
64 //Auto using namespaces
65 namespace ObjexxFCL { namespace fmt { } } using namespace ObjexxFCL::fmt; // AUTO USING NS
66 //Auto using namespaces end
67 
68 
69 namespace protocols {
70 namespace dna {
71 
72 bool ResTypeSequence_lt::operator() ( ResTypeSequence const & a, ResTypeSequence const & b ) const
73 {
74  core::Size const asize( a.size() ), bsize( b.size() );
75  if ( asize < bsize ) return true;
76  if ( asize > bsize ) return false;
77  for ( ResTypeSequence::const_iterator ait( a.begin() ), bit( b.begin() ), aend( a.end() ),
78  bend( b.end() ); ait != aend && bit != bend; ++ait, ++bit ) {
79  if ( ait->first < bit->first ) return true;
80  if ( ait->first > bit->first ) return false;
81  if ( ait->second->name1() < bit->second->name1() ) return true;
82  if ( ait->second->name1() > bit->second->name1() ) return false;
83  }
84  return false;
85 }
86 
87 
88 int const PRECISION(3); // number of decimal places for floating point numbers
89 
90 using utility::vector1;
91 using utility::string_split;
92 using namespace core;
93  using namespace chemical;
94  using namespace conformation;
95  using namespace optimization;
96  using namespace basic::options;
97  using namespace pack;
98  using namespace task;
99  using namespace operation;
100  using namespace pose;
101  using namespace scoring;
102 
103 using namespace ObjexxFCL;
104  using namespace ObjexxFCL::fmt;
105 
106 using basic::t_warning;
107 using basic::t_info;
108 using basic::t_debug;
109 static basic::Tracer TR("protocols.dna.DnaInterfacePacker");
110 static basic::Tracer TR_spec("protocols.dna.Specificity");
111 
112 // for comparing ResTypeSequence, which contain ResidueTypeCOP pointers (must dereference for sorting purposes)
113 
115 DnaInterfacePackerCreator::keyname() const
116 {
117  return DnaInterfacePackerCreator::mover_name();
118 }
119 
121 DnaInterfacePackerCreator::create_mover() const {
122  return new DnaInterfacePacker;
123 }
124 
126 DnaInterfacePackerCreator::mover_name()
127 {
128  return "DnaInterfacePacker";
129 }
130 
131 ////////////////////////////////////////////////////////////////////////////////////////////////////
132 ///@brief lightweight default constructor
133 DnaInterfacePacker::DnaInterfacePacker()
134  : protocols::simple_moves::PackRotamersMover("DnaInterfacePacker"),
135  reference_pose_(0),
136  dna_chains_(0),
137  minimize_(false),
138  filename_root_( option[ OptionKeys::out::prefix ]() ),
139  binding_E_(false),
140  probe_specificity_(false),
141  reversion_scan_(false),
142  protein_scan_(false),
143  base_only_(false),
144  include_dna_potentials_in_specificity_calculations_(false),
145  num_repacks_(1),
146  specificity_repacks_(1),
147  minimize_options_(0),
148  min_movemap_(0),
149  pdboutput_(0),
150  initialization_state_(false),
151  pdbname_("")
152 {}
153 
154 ///@brief functional constructor
156  ScoreFunctionOP scorefxn_in,
157  bool minimize,
158  std::string filename_root
159 ) : protocols::simple_moves::PackRotamersMover("DnaInterfacePacker"),
160  reference_pose_(0),
161  dna_chains_(0),
162  minimize_( minimize ),
163  filename_root_( filename_root ),
164  binding_E_(false),
165  probe_specificity_(false),
166  reversion_scan_(false),
167  protein_scan_(false),
168  base_only_(false),
169  include_dna_potentials_in_specificity_calculations_(false),
170  num_repacks_(1),
171  specificity_repacks_(1),
172  minimize_options_(0),
173  min_movemap_(0),
174  pdboutput_(0),
175  initialization_state_(false),
176  pdbname_("")
177 {
178  score_function( scorefxn_in ); // calls PackRotamersMover setter
179  binding_E_ = option[ OptionKeys::dna::design::binding ]();
180  num_repacks_ = option[ OptionKeys::packing::ndruns ]();
181  if ( option[ OptionKeys::dna::design::probe_specificity ].user() ) {
182  probe_specificity_ = true;
183  specificity_repacks_ = option[ OptionKeys::dna::design::probe_specificity ]();
184  }
185  reversion_scan_ = option[ OptionKeys::dna::design::reversion_scan ]();
186  base_only_ = option[ OptionKeys::dna::design::base_contacts_only ]();
188  option[ OptionKeys::dna::design::specificity::include_dna_potentials ]();
189  if ( option[ OptionKeys::dna::design::protein_scan ].user() ) {
190  protein_scan_ = true;
191  allowed_types_ = option[ OptionKeys::dna::design::protein_scan ]();
192  }
193 }
194 
195 ///@brief destructor
197 
198 ///@brief required in the context of the parser/scripting scheme
201 {
202  return new DnaInterfacePacker;
203 }
204 
205 ///@brief required in the context of the parser/scripting scheme
208 {
209  return new DnaInterfacePacker( *this );
210 }
211 
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////////////////////////
218 /// @begin DnaInterfacePacker::apply
219 /// @brief runs the packer, with support for efficiently looping over multiple explicit DNA sequences (provided that they can be represented by the RotamerSets/InteractionGraph)
220 /// @author ashworth
221 void
223 {
224  if ( ! initialized() ) init_standard( pose );
225  // discard info strings from previous calls to apply
226  info().clear();
227 
228  if ( protein_scan_ ) protein_scan( pose );
229  else standard_packing( pose );
230 }
231 
232 void
234 {
235  // local copy of starting pose
236  Pose starting_pose( pose );
237 
238  // loop over DNA sequences
239  for ( ResTypeSequences::const_iterator dnaseq( dna_sequences_.begin() ),
240  end( dna_sequences_.end() ); dnaseq != end; ++dnaseq ) {
241  TR << "Packing ";
242  print_sequence_pdb_nums( *dnaseq, pose, TR );
243 
244  // pack_rotamers trials
245  for ( Size trial(0); trial < num_repacks_; ++trial ) {
246  // restore starting structure
247  if ( dnaseq != dna_sequences_.begin() ) pose = starting_pose;
248  // cull over-representative rotamers/energies by masking out unspecified rotameric options
249  // (including DNA)
250  utility::vector0<int> rot_to_pack;
251  if ( !dnaseq->empty() ) restrict_dna_rotamers( rotamer_sets(), *dnaseq, rot_to_pack );
252  // run packer (calls PackRotamersMover virtual method)
253  run( pose, rot_to_pack );
254  // run post-packer routines, output, etc.
255  post_packing( pose, *dnaseq, trial );
256  }
257  TR.flush();
258  }
259  TR.flush();
260 }
261 
262 ////////////////////////////////////////////////////////////////////////////////////////////////////
263 /// @begin DnaInterfacePacker::post_packing
264 void
266 {
267  // for collecting information from the various post-packing routines
268  Strings info_lines;
269 
270  // add descriptors to name of (potential) output pdb file
271  std::string seqtag;
272  if ( !dnaseq.empty() ) seqtag = "_" + dna_seq_tag( pose, dnaseq );
273  std::string pdbroot( filename_root_ + "_pack" + seqtag );
274  pdbname_ = pdbroot + "_" + lead_zero_string_of(trial,4);
275 
276  // calculate DNA sequence specificity (if enabled)
277  // first element: bound specificities, second: binding specificities (if enabled)
278  std::pair< SequenceScores, SequenceScores > specificities;
279 
280  if ( probe_specificity_ ) {
281  specificities = measure_bp_specificities( pose );
282  // format specificity results for output
283  for ( SequenceScores::const_iterator bound( specificities.first.begin() ),
284  bound_end( specificities.first.end() ); bound != bound_end; ++bound ) {
285  std::ostringstream os;
286  os << std::showpoint << std::fixed << std::setprecision(PRECISION);
287  os << "Specificities(bound): ";
288  os << seq_pdb_str( bound->first, pose ) << " = " << bound->second;
289  TR << os.str() << '\n';
290  info_lines.push_back( "REMARK " + os.str() );
291  }
292  if ( binding_E_ ) {
293  for ( SequenceScores::const_iterator binding( specificities.second.begin() ),
294  binding_end( specificities.second.end() ); binding != binding_end; ++binding ) {
295  std::ostringstream os;
296  os << std::showpoint << std::fixed << std::setprecision(PRECISION);
297  os << "Specificities(binding): ";
298  os << seq_pdb_str( binding->first, pose ) << " = " << binding->second;
299  TR << os.str() << '\n';
300  info_lines.push_back( "REMARK " + os.str() );
301  }
302  }
303  }
304 
305  // minimize bound structure (if minimization enabled)
306  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
307  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
308  }
309 
310  // score bound structure
311  Real const bound_score( (*score_function())(pose) );
312 
313  // optional binding energy calculation
314  Real binding_score(0.);
315  if ( binding_E_ ) {
316  // if output_unbound_pdb option is true, output first unbound structure
317  bool const output_pdb(
318  trial == 0 && option[ OptionKeys::dna::design::output_unbound_pdb ]() );
319  binding_score = bound_score - unbound_score( pose, output_pdb, pdbname_ );
320  // add binding information to extra pdb info
321  std::ostringstream bindingstream;
322  bindingstream << std::showpoint << std::fixed << std::setprecision(PRECISION)
323  << "Binding energy: " << binding_score;
324  TR << bindingstream.str() << std::endl;
325  info_lines.push_back( "REMARK " + bindingstream.str() );
326  }
327 
328  if ( reversion_scan_ ) {
329  // try to revert 'insignificant' amino acid mutations made during design
330  std::pair< Real, Real > overall_specificities( 0., 0. );
331  ResTypeSequence currseq( current_working_sequence( pose ) );
332  // look up overall specificity scores, pass to reversion routine as baseline
333  if ( specificities.first.find( currseq ) != specificities.first.end() )
334  overall_specificities.first = specificities.first[ currseq ];
335  if ( specificities.second.find( currseq ) != specificities.second.end() )
336  overall_specificities.second = specificities.second[ currseq ];
337  reversion_scan( pose, bound_score, binding_score, overall_specificities );
338  }
339 
340  if ( pdboutput_ ) {
341  // write out pdb if local pdb outputting is enabled
342  // (if using the job distributor, the PDBOutput class should interface with it instead)
343  bool const overwrite_old_info(true);
344  pdboutput_->add_info( "REMARK DnaInterfacePacker " + pdbroot + ":", info_lines, !overwrite_old_info );
345  pdboutput_->note_designed_residues( task() );
346  pdboutput_->score_function( *score_function() );
347  (*pdboutput_)( pose, pdbname_ + ".pdb" );
348  }
349 
350  // store collected information for future reference
351  info().insert( info().end(), info_lines.begin(), info_lines.end() );
352 }
353 
354 ////////////////////////////////////////////////////////////////////////////////////////////////////
355 /// @begin DnaInterfacePacker::init_standard
356 /// @brief standard initialization of the necessary member data
357 /// @author ashworth
358 /// @details pose is nonconst because it is so in pack_rotamers::setup()
359 void
361 {
362 
363  TR << std::showpoint << std::fixed << std::setprecision(PRECISION);
364 
365  reference_residue_types_.clear();
366  if ( reference_pose_ ) {
367  for ( Size index(1), end( reference_pose_->total_residue() ); index <= end; ++index ) {
368  reference_residue_types_.push_back( &reference_pose_->residue_type(index) );
369  }
370  } else {
371  for ( Size index(1), end( pose.total_residue() ); index <= end; ++index ) {
372  reference_residue_types_.push_back( & pose.residue_type(index) );
373  }
374  }
375 
376  dna_chains_ = new DnaChains;
377  find_basepairs( pose, *dna_chains_ );
378 
379  TaskFactoryOP my_tf;
380  // if there is no initialized TaskFactory, create default one here
381  if ( ! task_factory() ) { // PackRotamersMover accessor
382  my_tf = new TaskFactory;
383  my_tf->push_back( new InitializeFromCommandline );
384  if ( option[ OptionKeys::packing::resfile ].user() ) my_tf->push_back( new ReadResfile );
386  rdtpdi->set_reference_pose( reference_pose_ );
387  if ( ! targeted_dna_.empty() ) rdtpdi->copy_targeted_dna( targeted_dna_ );
388  rdtpdi->copy_dna_chains( dna_chains_ );
389  rdtpdi->set_base_only( base_only_ );
390  my_tf->push_back( rdtpdi );
391  } else { // TaskFactory already exists, make copy to tamper with
392  my_tf = new TaskFactory( *task_factory() );
393  }
394  // a protein-DNA hbonding filter for ex rotamers that the PackerTask makes available to the rotamer set during rotamer building (formerly known as 'rotamer explosion')
395  RotamerDNAHBondFilterOP rot_dna_hb_filter( new RotamerDNAHBondFilter( -0.5, base_only_ ) );
396  my_tf->push_back( new AppendRotamer( rot_dna_hb_filter ) );
397 
398  task_factory( my_tf ); // PackRotamersMover setter
399 
400  setup( pose ); // PackRotamersMover method--fills RotamerSets and IG
401 
402  rot_dna_hb_filter->report(); // filtered/accepted statistic for filtered rotamers
403 
404  // set up for looping over multiple DNA sequences if task() has DNA positions set to 'scan'
405  // makes all canonical combinations that can be described by the rotamer set
407 
408  if ( dna_sequences_.empty() ) {
409  // no list of DNA sequences to loop over:
410  // see if the PackerTask is configured to target any particular DNA sequence, and if so store it
411  ResTypeSequence target_seq( get_targeted_sequence( pose ) );
412  if ( !target_seq.empty() ) dna_sequences_.push_back( target_seq );
413  }
414  if ( !dna_sequences_.empty() ) {
415  TR << "DNA sequences to be considered:" << '\n';
417  TR << std::endl;
418  }
419  // no DNA sequences specified by user. add a dummy sequence (placeholder allowing loop)
420  else dna_sequences_.push_back( ResTypeSequence() );
421  // if 'dna_sequences_' is still empty at this point, the SimAnnealer will perform DNA rotamer substitutions using any available DNA rotamers (including mutation). To constrain designed DNA sequences to Watson-Crick pairing, see WatsonCrickRotamerCouplings
422 
423  if ( minimize_ ) {
424  // set up minimizer
425  std::string const min_type( option[ OptionKeys::run::min_type ]() );
426  Real const tolerance( option[ OptionKeys::run::min_tolerance ]() );
427  minimize_options_ = new MinimizerOptions( min_type, tolerance, true );
429  TR << "Chi minimization will be allowed for the following residues:";
430  for ( Size index(1); index <= task()->total_residue(); ++index ) {
431  if ( !pose.residue_type(index).is_protein() ) continue;
432  if ( task()->pack_residue( index ) ) {
433  min_movemap_->set_chi( index, true );
434  if ( pose.pdb_info() ) {
435  TR << " " << pose.pdb_info()->chain(index) << "." << pose.pdb_info()->number(index);
436  } else {
437  TR << " " << pose.chain(index) << "." << index;
438  }
439  }
440  }
441  TR << std::endl;
442  }
443 
444  if ( pdboutput_ ) pdboutput_->reference_pose( pose );
445 
446  initialization_state_ = false;
447  runtime_assert( initialized() );
448 }
449 
450 ////////////////////////////////////////////////////////////////////////////////////////////////////
451 bool
453 {
454  bool is_initialized(
456  && ( task() || task_factory() )
457  && ig()
458  && rotamer_sets()
459  && dna_chains_
460  && !reference_residue_types_.empty()
462  );
463  if ( minimize_ ) is_initialized &= ( minimize_options_ && min_movemap_ );
464  return is_initialized;
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////////////////////////
468 void
470 {
471  initialization_state_ = true;
472 }
473 
474 ////////////////////////////////////////////////////////////////////////////////////////////////////
475 ///@brief parse XML (specifically in the context of the parser/scripting scheme)
477  TagPtr const tag,
478  moves::DataMap & datamap,
479  protocols::filters::Filters_map const & filters,
480  moves::Movers_map const & movers,
481  Pose const & pose
482 )
483 {
484  if ( tag->hasOption("binding") ) binding_E_ = tag->getOption<bool>("binding");
485  if ( tag->hasOption("base_only") ) base_only_ = tag->getOption<bool>("base_only");
486  if ( tag->hasOption("minimize") ) minimize_ = tag->getOption<bool>("minimize");
487  if ( tag->hasOption("reversion_scan") ) reversion_scan_ = tag->getOption<bool>("reversion_scan");
488  if ( tag->hasOption("probe_specificity") ) {
489  probe_specificity_ = true;
490  specificity_repacks_ = tag->getOption< Size >("probe_specificity");
491  }
492  if ( tag->hasOption("pdb_output") ) {
493  if ( tag->getOption<bool>("pdb_output") ) {
494  if ( !pdboutput_ ) pdboutput_ = new PDBOutput;
495  }
496  }
497  if ( tag->hasOption("protein_scan") ) protein_scan_ = tag->getOption<bool>("protein_scan");
498  if ( tag->hasOption("allowed_types") ) allowed_types_ = tag->getOption<std::string>("allowed_types");
499  if ( protein_scan_ ) runtime_assert( !allowed_types_.empty() );
500 
501  // the following are calls to PackRotamersMover methods
502  parse_score_function( tag, datamap, filters, movers, pose );
503  parse_task_operations( tag, datamap, filters, movers, pose );
504 }
505 
506 ////////////////////////////////////////////////////////////////////////////////////////////////////
507 /// @begin DnaInterfacePacker::make_dna_sequence_combinations
508 /// @details looks for rotable DNA positions in the RotamerSets, generates a list of all canonical sequence combinations for them
509 /// @authors ashworth
510 void
512 {
513  runtime_assert( task() );
514  runtime_assert( dna_chains_ );
515  dna_sequences_.clear();
516  vector1< Size > seq_indices;
517  // search the rotamer set for rotable DNA residues
518  for ( Size moltenres(1); moltenres <= rotamer_sets()->nmoltenres(); ++moltenres ) {
519  Size resid( rotamer_sets()->moltenres_2_resid( moltenres ) );
520  if ( !task()->has_behavior( "SCAN", resid ) ) continue;
521  if ( !dna_chains_->is_top( resid ) ) continue;
522  // just make the top-strand combinations, handle complements later
523  seq_indices.push_back( resid );
524  }
525 
526  if ( seq_indices.empty() ) return; // no positions found at which to make combinations
527 
528  ResTypeSequence sequence; // empty starter sequence for the following recursive function
529  make_sequence_combinations( seq_indices.begin(), seq_indices, task(), sequence, dna_sequences_ );
530 
531 // TR << std::flush << "Single-stranded sequences:" << '\n';
532 // print_sequences_pdb_nums( dna_sequences_, pose, TR );
533 // TR << std::endl;
534 
535  for ( ResTypeSequences::iterator sequence( dna_sequences_.begin() ), end( dna_sequences_.end() );
536  sequence != end; ++sequence ) {
537  add_complementary_sequence( *sequence );
538  }
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////////////////////////
542 /// @begin DnaInterfacePacker::add_complementary_sequence
543 /// @details turns single-stranded DNA sequences into double-stranded ones
544 /// @authors ashworth
545 void
547 {
548  runtime_assert( dna_chains_ );
549  // fill a temporary ResTypeSequence, in order to avoid iterator-related issues with std::map
550  ResTypeSequence complement;
551  for ( ResTypeSequence::iterator postype( sequence.begin() ), end( sequence.end() );
552  postype != end; ++postype ) {
553  Size const index( postype->first );
554  DnaPosition const & dnatop( (*dna_chains_)[ index ] );
555  runtime_assert( dnatop.top() == index );
556  if ( !dnatop.paired() ) continue;
557  Size const comppos( dnatop.bottom() );
558  // find the complement type in the current typeset
559  ResidueTypeCOP type( postype->second );
560  ResidueTypeSet const & typeset( type->residue_type_set() );
561  ResidueTypeCOP comptype( typeset.aa_map( dna_base_partner( type->aa() ) ).front() );
562  complement[ comppos ] = comptype;
563  }
564  // append this temporary bottom-stranded sequence to the original top-stranded sequence
565  for ( ResTypeSequence::iterator postype( complement.begin() ), end( complement.end() );
566  postype != end; ++postype ) {
567  sequence.insert( *postype );
568  }
569 }
570 
571 ///////////////////////////////////////////////////////////////////////////////////////////////////
572 /// @begin DnaInterfacePacker::unbound_score
573 /// @brief
574 /// @author ashworth
575 Real
577  Pose const & pose,
578  bool output_pdb, // = false
579  std::string pdbname // = ""
580 )
581 {
582 // TR << "Calculating unbound score..." << std::endl;
583  Pose unbound_pose( pose );
584  SeparateDnaFromNonDna unbind;
585  unbind.apply( unbound_pose );
586  // clone ScoreFunctionCOP so that we can score without distance constraints
587  runtime_assert( score_function() );
588  ScoreFunctionOP nonconst_scorefxn( score_function()->clone() );
589  // set distance constraints weights to zero before scoring unbound structure
590  nonconst_scorefxn->set_weight( atom_pair_constraint, 0.0 );
591  Real const unbound_score( (*nonconst_scorefxn)(unbound_pose) );
592  // optional: write out unbound pose to verify proper interface separation
593  if ( output_pdb ) {
594  PDBOutputOP unbound_outputter;
595  if ( pdboutput_ ) unbound_outputter = pdboutput_;
596  else unbound_outputter = new PDBOutput;
597  unbound_outputter->score_function( *nonconst_scorefxn );
598  (*unbound_outputter)( unbound_pose, pdbname + "_unbound.pdb" );
599  }
600  return unbound_score;
601 }
602 
603 ///////////////////////////////////////////////////////////////////////////////////////////////////
604 /// @begin DnaInterfacePacker::measure_specificity
605 /// @brief This method returns the overall bolztmann probabilities for target bound and binding(if enabled) states vs. all single-basepair variant competitors. (For this + specifities for individual basepair positions, use the measure_bp_specificities method instead.)
606 /// @author ashworth
607 std::pair< Real, Real > DnaInterfacePacker::measure_specificity( Pose & pose )
608 {
609  if ( ! probe_specificity_ ) return std::make_pair( 0., 0. );
610  TR_spec << "\nMeasuring specificity by repacking against other possible DNA states:" << std::endl;
611 
612  // figure out current TOP-STRANDED DNA sequence
613  ResTypeSequence current_sequence( current_working_sequence( pose ) );
614 
615  if ( current_sequence.empty() ) {
616  TR << "No double-stranded DNA positions found!" << std::endl;
617  return std::make_pair( 0., 0. );
618  }
619  ResTypeSequences specificity_sequences;
620  // add current_sequence
621  specificity_sequences.push_back( current_sequence );
622  // add competitor DNA sequences
623  make_single_mutants( current_sequence, task(), specificity_sequences );
624  // add complementary DNA positions to the these top-stranded sequences
625  for ( ResTypeSequences::iterator sequence( specificity_sequences.begin() ),
626  end( specificity_sequences.end() ); sequence != end; ++sequence ) {
627  add_complementary_sequence( *sequence );
628  }
629 
630 // for ( ResTypeSequences::iterator sequence( specificity_sequences.begin() ),
631 // end( specificity_sequences.end() ); sequence != end; ++sequence ) {
632 // print_sequence_pdb_nums( *sequence, pose, TR_spec );
633 // }
634 // TR_spec << std::endl;
635 
636  // first element is bound, second binding if binding_ flag is true
637  std::pair< SequenceScores, SequenceScores > sequence_scores(
638  measure_specificities( pose, specificity_sequences ) );
639 
640  Real bound_specificity(0.), binding_specificity(0.);
641 
642  // calculate_specificity expects complemented target sequence
643  add_complementary_sequence( current_sequence );
644  TR_spec << "\nCalculating bound specificity:";
645  bound_specificity = calculate_specificity( pose, current_sequence, sequence_scores.first );
646  if ( binding_E_ ) {
647  TR_spec << "\nCalculating binding specificity:";
648  binding_specificity = calculate_specificity( pose, current_sequence, sequence_scores.second );
649  }
650  TR_spec << std::endl;
651  return std::make_pair( bound_specificity, binding_specificity );
652 }
653 
654 ///////////////////////////////////////////////////////////////////////////////////////////////////
655 /// @begin DnaInterfacePacker::measure_bp_specificities
656 /// @brief Measures and calculates bound and binding specificities of the current protein sequence for its target DNA sequence, vs. single-basepair variant competitors. Also returns specificity scores for each individual basepair in a multiple-basepair target region.
657 /// @author ashworth
658 // return values: first maps bound specificities, second maps binding specificities
659 std::pair< SequenceScores, SequenceScores >
661 {
662  if ( ! probe_specificity_ ) return std::pair< SequenceScores, SequenceScores >();
663  TR_spec << "\nMeasuring individual basepair specificity by explicitly modeling alternative "
664  << "DNA states:" << std::endl;
665 
666  // figure out current TOP-STRANDED DNA sequence
667  ResTypeSequence const current_sequence( current_working_sequence( pose ) );
668 
669  if ( current_sequence.empty() ) {
670  TR << "No targeted double-stranded DNA positions found!" << std::endl;
671  return std::pair< SequenceScores, SequenceScores >();
672  }
673 
674  SequenceScores bound_scores, binding_scores;
675  SequenceScores binding_specificities, bound_specificities;
676  // separate specificity measurements into individual basepair positions
677  for ( ResTypeSequence::const_iterator bppos( current_sequence.begin() ),
678  end( current_sequence.end() ); bppos != end; ++bppos ) {
679  ResTypeSequences single_bp_variants;
680  single_bp_variants.push_back( current_sequence );
681  Size index( bppos->first );
682  ResidueLevelTask const & rtask( task()->residue_task(index) );
683  // add competitors for this position
685  end_type( rtask.allowed_residue_types_end() ); type != end_type; ++type ) {
686  if ( (*type)->aa() == bppos->second->aa() ) continue; // avoid duplicating input sequence
687  // ignore adduct variant types
688  if ( (*type)->has_variant_type( chemical::ADDUCT ) ) continue;
689  // new copy of current sequence
690  ResTypeSequence single_bp_mutant( current_sequence );
691  // make change
692  single_bp_mutant[ index ] = *type;
693  single_bp_variants.push_back( single_bp_mutant );
694  }
695  // add complements (top-stranded sequences -> double-stranded)
696  for ( ResTypeSequences::iterator sequence( single_bp_variants.begin() ),
697  end( single_bp_variants.end() ); sequence != end; ++sequence ) {
698  add_complementary_sequence( *sequence ); // uses dna_chains_ information
699  }
700  // model/score states, calculate specificities
701  // first element is bound, second binding if binding_ flag is true
702  std::pair< SequenceScores, SequenceScores > sequence_scores(
703  measure_specificities( pose, single_bp_variants ) );
704 
705  if ( current_sequence.size() > 1 ) {
706  // calculate and store specificities for individual basepairs if multiple are involved
707  // use single-bp sequence for annotation,
708  ResTypeSequence current_single_bp;
709  current_single_bp[ bppos->first ] = bppos->second;
710  // but need full complemented target sequence for actual calculation
711  ResTypeSequence complemented_current_sequence( current_sequence );
712  add_complementary_sequence( complemented_current_sequence );
713  TR_spec << "\nCalculating bound specificity for " << seq_pdb_str( current_single_bp, pose );
714  bound_specificities[ current_single_bp ] =
715  calculate_specificity( pose, complemented_current_sequence, sequence_scores.first );
716  if ( binding_E_ ) {
717  TR_spec << "\nCalculating binding specificity for "
718  << seq_pdb_str( current_single_bp, pose );
719  binding_specificities[ current_single_bp ] =
720  calculate_specificity( pose, complemented_current_sequence, sequence_scores.second );
721  }
722  }
723  // accumulate sequence scores for overall calculation
724  for ( SequenceScores::const_iterator ss_it( sequence_scores.first.begin() ),
725  ss_end( sequence_scores.first.end() ); ss_it != ss_end; ++ss_it ) {
726  bound_scores[ ss_it->first ] = ss_it->second;
727  }
728  for ( SequenceScores::const_iterator ss_it( sequence_scores.second.begin() ),
729  ss_end( sequence_scores.second.end() ); ss_it != ss_end; ++ss_it ) {
730  binding_scores[ ss_it->first ] = ss_it->second;
731  }
732  }
733 
734  // compute overall specificity for target sequence vs. all single-bp variants in design region
735  TR_spec << "\nCalculating bound specificity for " << seq_pdb_str( current_sequence, pose );
736  // need full complemented target sequence for calculation
737  ResTypeSequence complemented_current_sequence( current_sequence );
738  add_complementary_sequence( complemented_current_sequence );
739  bound_specificities[ current_sequence ] =
740  calculate_specificity( pose, complemented_current_sequence, bound_scores );
741  if ( binding_E_ ) {
742  TR_spec << "\nCalculating binding specificity for " << seq_pdb_str( current_sequence, pose );
743  binding_specificities[ current_sequence ] =
744  calculate_specificity( pose, complemented_current_sequence, binding_scores );
745  }
746 
747  // store all of the individual scores as info
748  for ( SequenceScores::const_iterator it( bound_scores.begin() ), end( bound_scores.end() );
749  it != end; ++it ) {
750  std::ostringstream os;
751  os << std::showpoint << std::fixed << std::setprecision(PRECISION);
752  os << "REMARK SeqScore(bound): " << seq_pdb_str( it->first, pose ) << " = " << it->second;
753  info().push_back( os.str() );
754  }
755  for ( SequenceScores::const_iterator it( binding_scores.begin() ), end( binding_scores.end() );
756  it != end; ++it ) {
757  std::ostringstream os;
758  os << std::showpoint << std::fixed << std::setprecision(PRECISION);
759  os << "REMARK SeqScore(binding): " << seq_pdb_str( it->first, pose ) << " = " << it->second;
760  info().push_back( os.str() );
761  }
762 
763  return std::make_pair( bound_specificities, binding_specificities );
764 }
765 
766 ///////////////////////////////////////////////////////////////////////////////////////////////////
767 /// @begin DnaInterfacePacker::measure_specificities
768 /// @brief This requires that all DNA states to be searched are already represented in the rotamer set and interaction graph
769 /// @author ashworth
770 std::pair< SequenceScores, SequenceScores >
772 {
773  // save starting pose to avoid permanently altering it
774  Pose starting_pose( pose );
775 
776  SequenceScores sequence_scores, sequence_binding_scores;
777 
778  for ( ResTypeSequences::const_iterator dna_sequence( dna_sequences.begin() ),
779  end( dna_sequences.end() ); dna_sequence != end; ++dna_sequence ) {
780  Real best_trial_E(0), best_trial_binding_E(0);
781  // restrict packer to current protein sequence and this DNA sequence
782  utility::vector0< int > rot_to_pack;
783  vector1< ResidueTypeCOP > single_sequence;
784  for ( Size index(1), end( pose.total_residue() ); index <= end; ++index ) {
785  single_sequence.push_back( & pose.residue_type(index) );
786  }
787  // alter dna types according to this dna sequence
788  for ( ResTypeSequence::const_iterator it( dna_sequence->begin() ),
789  seq_end( dna_sequence->end() ); it != seq_end; ++it ) {
790  single_sequence[ it->first ] = it->second;
791  }
792  // populate rot_to_pack with only the rotamers that reflect single_sequence
793  restrict_to_single_sequence( rotamer_sets(), single_sequence, rot_to_pack );
794 
795  for ( Size trial(0); trial < specificity_repacks_; ++trial ) {
796  run( pose, rot_to_pack ); // calls PackRotamersMover method
797  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
798  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
799  }
800  ScoreFunctionOP nonconst_scorefxn( score_function()->clone() );
802  // temporarily disable dna conformational potentials for assessing specificity
803  nonconst_scorefxn->set_weight( dna_bp, 0. );
804  nonconst_scorefxn->set_weight( dna_bs, 0. );
805  }
806  Real trial_E( (*nonconst_scorefxn)( pose ) );
807  if ( trial == 0 || ( trial_E < best_trial_E ) ) {
808  best_trial_E = trial_E;
809  if ( binding_E_ ) best_trial_binding_E = trial_E - unbound_score( pose );
810  }
811  if ( pdboutput_ && option[ OptionKeys::dna::design::specificity::output_structures ]() ) {
813  filename_root_ + "_" + dna_seq_tag( pose, current_working_sequence(pose) ) +
814  "_spec_" + dna_seq_tag( pose, *dna_sequence ) + ".pdb"
815  );
816  pdboutput_->score_function( *nonconst_scorefxn );
817  (*pdboutput_)( pose, pdbname );
818  }
819  }
820  sequence_scores[ *dna_sequence ] = best_trial_E;
821  sequence_binding_scores[ *dna_sequence ] = best_trial_binding_E;
822  }
823  pose = starting_pose; // restore starting, unaltered pose
824  return std::make_pair( sequence_scores, sequence_binding_scores );
825 }
826 
827 ////////////////////////////////////////////////////////////////////////////////////////////////////
828 /// @begin DnaInterfacePacker::calculate_specificity
829 /// @brief calculates specificity as a Boltzmann probability of the target sequence in the presence of competitors
830 /// @author ashworth
831 Real
833  Pose const & pose,
834  ResTypeSequence const & target_sequence,
835  SequenceScores const & sequence_scores
836 )
837 {
838  TR_spec << std::showpoint << std::fixed << std::setprecision(PRECISION) << '\n';
839  // Boltzmann temperature
840  Real const temp( option[ OptionKeys::dna::design::Boltz_temp ]() );
841 
842  // find low energy
843  Real low(0);
844  for ( SequenceScores::const_iterator iter( sequence_scores.begin() );
845  iter != sequence_scores.end(); ++iter ) {
846  Real score( iter->second );
847  if ( iter == sequence_scores.begin() || ( score < low ) ) low = score;
848  }
849 
850  Real const inv_temp( 1.0 / temp );
851  Real num(0), denom(0);
852  for ( SequenceScores::const_iterator iter( sequence_scores.begin() );
853  iter != sequence_scores.end(); ++iter ) {
854  ResTypeSequence const & sequence( iter->first );
855  Real score( iter->second );
856  TR_spec << "\t";
857  for ( ResTypeSequence::const_iterator pos( sequence.begin() ); pos != sequence.end(); ++pos ) {
858  if ( pos != sequence.begin() ) TR_spec << ", ";
859  if ( pose.pdb_info() ) {
860  TR_spec << pose.pdb_info()->chain( pos->first ) << "."
861  << pose.pdb_info()->number( pos->first ) << "." << dna_full_name3( pos->second->name3() );
862  } else {
863  TR_spec << pose.chain( pos->first ) << "."
864  << pos->first << "." << dna_full_name3( pos->second->name3() );
865  }
866  }
867  TR_spec << ": " << score << '\n';
868  Real term( std::exp( ( low - score ) * inv_temp ) );
869  if ( sequence == target_sequence ) num += term;
870  denom += term;
871  }
872  if ( denom == 0. ) return 0.;
873  Real const spec( num / denom );
874  TR_spec << "\tspecificity: " << spec << std::endl;
875  return spec;
876 }
877 
878 ////////////////////////////////////////////////////////////////////////////////////////////////////
879 
880 class Reversion {
881 public:
883  : index(i), type(t), dscore_bound(0.), dspec_bound(0.), dscore_binding(0.), dspec_binding(0.) {}
885  // assign a number to the effect of this reversion
886  Real reversion_score() const { return -1 * dspec_binding; }
887  // for sorting when looking for the 'most acceptable' reversion in a set of reversions
888  bool operator < ( Reversion const & other ) const
889  { return reversion_score() < other.reversion_score(); }
893 };
895 
896 void
898  Pose & pose,
899  Real starting_bound_score, // = 0.
900  Real starting_binding_score, // = 0.
901  std::pair< Real, Real > starting_specificities // = std::make_pair(0.,0.)
902 )
903 {
904  if ( ! initialized() ) init_standard( pose );
905 
906  TR << std::flush << "Starting reversion scan: using starting scores: " << "bound = "
907  << starting_bound_score << ", binding = " << starting_binding_score
908  << ", specificity.bound = " << starting_specificities.first << ", specificity.binding = "
909  << starting_specificities.second << std::endl << '\n';
910 
911  Real current_bound_score( starting_bound_score ), current_binding_score( starting_binding_score );
912  std::pair< Real, Real > current_specificities( starting_specificities );
913 
914  vector1< ResidueTypeCOP > fixed_residue_types;
915 
916  for ( Size index(1), end( pose.total_residue() ); index <= end; ++index ) {
917  fixed_residue_types.push_back( &pose.residue_type( index ) );
918  }
919 
920  // find mutations (positions to revert) based upon comparison to a starting sequence
921  Reversions reversions;
922  runtime_assert( fixed_residue_types.size() == reference_residue_types_.size() );
923  for ( Size index(1), end( fixed_residue_types.size() ); index != end; ++index ) {
924  ResidueTypeCOP reference_type( reference_residue_types_[index] );
925  if ( reference_type->is_protein() &&
926  fixed_residue_types[index]->name3() != reference_type->name3() ) {
927  reversions.push_back( Reversion( index, reference_type ) );
928  }
929  }
930 
931  Real const dscore_cutoff( option[ OptionKeys::dna::design::reversion::dscore_cutoff ]() ),
932  dspec_cutoff( option[ OptionKeys::dna::design::reversion::dspec_cutoff ]() );
933 
934  // do single reversions to wildtype while they do not harm energy/specificity
935  Size round(0);
936  while ( true ) {
937  // assess changes in energy and specificity for each single revertant in parallel
938  for ( Reversions::iterator rev( reversions.begin() ), end( reversions.end() );
939  rev != end; ++rev ) {
940  Size const index( rev->index );
941  ResidueTypeCOP starting_type( fixed_residue_types[ index ] ),
942  reference_type( reference_residue_types_[ index ] ); // 'reference' == 'native'
943  fixed_residue_types[ index ] = reference_type;
944 
945  Real best_score(0.), best_binding_score(0.);
946  std::pair< Real, Real > best_specificities;
947 
948  for ( Size trial(1); trial <= num_repacks_; ++trial ) {
949  // repack bound pose with this reversion
950  utility::vector0<int> rot_to_pack;
951  restrict_to_single_sequence( rotamer_sets(), fixed_residue_types, rot_to_pack );
952  // calls PackRotamersMover method
953  run( pose, rot_to_pack );
954  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
955  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
956  }
957  Real const score( ( *score_function() )( pose ) );
958  if ( trial == 1 || score < best_score ) {
959  best_score = score;
960  if ( binding_E_ ) best_binding_score = score - unbound_score( pose );
961  best_specificities = measure_specificity( pose );
962  }
963  }
964  // undo the reversion so that it does not affect the others in the same round
965  // (fixed_residue_types will restore the starting type in the next call to the packer)
966  fixed_residue_types[ rev->index ] = starting_type;
967 
968  Real const dscore_bound( best_score - current_bound_score ),
969  dscore_binding( best_binding_score - current_binding_score ),
970  dspec_bound( best_specificities.first - current_specificities.first ),
971  dspec_binding( best_specificities.second - current_specificities.second );
972 
973  TR << "Scores for reversion from " << starting_type->name3() << " to "
974  << reference_type->name3() << " at ";
975  if ( pose.pdb_info() ) {
976  TR << pose.pdb_info()->chain( index ) << "." << pose.pdb_info()->number( index ) << ":";
977  } else {
978  TR << pose.chain( index ) << "." << index << ":";
979  }
980  TR << " bound = " << best_score << " (" << dscore_bound << ")"
981  << ", binding = " << best_binding_score << " (" << dscore_binding << ")"
982  << ", specificity.bound = " << best_specificities.first << " (" << dspec_bound << ")"
983  << ", specificity.binding = " << best_specificities.second << " (" << dspec_binding
984  << ")\n";
985 
986  rev->dscore_bound = dscore_bound;
987  rev->dscore_binding = dscore_binding;
988  rev->dspec_bound = dspec_bound;
989  rev->dspec_binding = dspec_binding;
990  }
991  // sort reversions, and then keep the first acceptable reversion from the current round
992  // (there could have been multiple 'acceptable' reversions)
993  std::sort( reversions.begin(), reversions.end() );
994  Reversions::iterator rev( reversions.begin() );
995  for ( Reversions::const_iterator end( reversions.end() ); rev != end; ++rev ) {
996  // ignore reversion if it results in the loss of too much binding energy or specificity
997  if ( rev->dscore_binding > dscore_cutoff || rev->dspec_binding < dspec_cutoff ) continue;
998  // make 'best' reversion 'permanent'
999  Size const index( rev->index );
1000  ResidueTypeCOP starting_type( fixed_residue_types[ index ] ),
1001  reference_type( reference_residue_types_[ index ] ); // 'reference' == 'native'
1002  fixed_residue_types[ index ] = reference_type;
1003  TR << "(round " << round << ") Reversion from " << starting_type->name3()
1004  << " to " << reference_type->name3() << " at ";
1005  if ( pose.pdb_info() ) {
1006  TR << pose.pdb_info()->chain( index ) << "." << pose.pdb_info()->number( index );
1007  } else {
1008  TR << pose.chain( index ) << "." << index;
1009  }
1010  TR << " is acceptable and is now fixed.\n";
1011  break;
1012  }
1013 
1014  // remove from list of remaining reversions to try
1015  if ( rev != reversions.end() ) reversions.erase( rev );
1016  // no acceptable reversion remains, stop scan
1017  else {
1018  TR << "No (more) acceptable reversions found." << std::endl;
1019  break;
1020  }
1021  // repeat whole process: mst re-assess the rest of the reversions in the new context
1022  ++round;
1023  }
1024  // repack one last time in case the last reversion tried was not acceptable
1025  utility::vector0<int> rot_to_pack;
1026  restrict_to_single_sequence( rotamer_sets(), fixed_residue_types, rot_to_pack );
1027  // calls PackRotamersMover method
1028  run( pose, rot_to_pack );
1029  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
1030  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
1031  }
1032 }
1033 
1036 {
1037  std::string protein("ACDEFGHIKLMNPQRSTVWY");
1038  if ( allowed_types_ == "protein" ) return protein;
1039  if ( allowed_types_ == "PROTEIN" ) return protein;
1040  if ( allowed_types_ == "std" ) return protein;
1041  if ( allowed_types_ == "standard" ) return protein;
1042  if ( allowed_types_ == "" ) return protein;
1043  return allowed_types_;
1044 }
1045 
1046 ////////////////////////////////////////////////////////////////////////////////////////////////////
1047 /// @begin DnaInterfacePacker::protein_scan
1048 /// @brief runs a single-residue scan of user-defined amino acid possibilities to estimate affinity and specificity of single mutants w/ respect to relevant DNA
1049 /// @author ashworth
1050 void
1052 {
1053  std::string const typestring( allowed_types() );
1054  TR << "Starting protein_scan with allowed types " << typestring << "." << std::endl;
1055  // parse allowed_types string into residue types
1056  ResidueTypeCOPs allowed_type_caps;
1057  ResidueTypeSet const & rts( pose.residue(1).residue_type_set() );
1058  for ( std::string::const_iterator typechar( typestring.begin() );
1059  typechar != typestring.end(); ++typechar ) {
1060  ResidueTypeCOPs aas( rts.aa_map( aa_from_oneletter_code( *typechar ) ) );
1061  if ( aas.empty() ) {
1062  TR(t_warning) << "no ResidueType found in ResidueTypeSet for " << *typechar << std::endl;
1063  runtime_assert(false);
1064  }
1065  allowed_type_caps.push_back( aas.front() );
1066  }
1067  runtime_assert( !allowed_type_caps.empty() );
1068 
1069  // get list of positions to scan from PackerTask
1070  std::list< Size > scan_positions;
1071  for ( Size index(1); index <= task()->total_residue(); ++index ) {
1072  if ( !task()->design_residue( index ) ) continue;
1073  if ( pose.residue_type( index ).is_DNA() ) continue; // skip DNA
1074  scan_positions.push_back( index );
1075  }
1076 
1077  if ( option[ OptionKeys::dna::design::checkpoint ].user() ) {
1078  // skip previously completed positions found in log file
1079  utility::io::izstream file;
1080  std::string filename( filename_root_ + ".protein_scan" );
1081  file.open( filename.c_str() );
1082  if ( file ) {
1083  TR << "Reading existing (incomplete?) protein scan results file\n";
1084  // remove completed positions as they are found in file
1085  std::string line;
1086  while ( file.getline( line ) ) {
1087  utility::vector1< std::string > words( string_split( line ) );
1088  if ( words.front() != "Done" ) continue; // skip to next line
1089  // expected line format: "Done scanning at index #"
1090  if ( words.size() < 5 ) continue;
1091  std::istringstream ss_index( words.back() );
1092  Size index;
1093  ss_index >> index;
1094  TR << "skipping previously completed scan position " << index << '\n';
1095  scan_positions.remove( index );
1096  }
1097  file.close();
1098  }
1099  }
1100 
1101  // open file for output
1102  std::string outfilename( filename_root_ + ".protein_scan" );
1103  // APPPEND to file (note: must be careful when parsing results)
1104  utility::io::ozstream outfile( outfilename.c_str(), std::ios::app );
1105  if ( !outfile ) {
1106  std::cerr << "trouble opening file " << outfilename << " for writing" << std::endl;
1107  assert( false ); // die here in debug mode
1108  return;
1109  }
1110 
1111 #ifndef WIN32
1112 // this statement causes a build error on Windows.
1113  outfile << std::showpoint << std::fixed << std::setprecision(PRECISION);
1114 #endif
1115 
1116  Pose const input_pose( pose );
1117 
1118  vector1< ResidueTypeCOP > pose_residue_types;
1119  for ( Size index(1), end( pose.total_residue() ); index <= end; ++index ) {
1120  pose_residue_types.push_back( &pose.residue_type(index) );
1121  }
1122 
1123  // get native energies
1124  Real best_native_score(0.), best_native_dG(0.);
1125  std::pair< Real, Real > best_native_specificities;
1126 
1127  // repack [and minimize] native interface in the relevant region, measure specificity
1128  { // scope
1129  Pose best_pose( pose );
1130  for ( Size trial(1); trial <= num_repacks_; ++trial ) {
1131  // repack bound pose
1132  utility::vector0<int> native_rot_to_pack;
1133  restrict_to_single_sequence( rotamer_sets(), pose_residue_types, native_rot_to_pack );
1134  // calls PackRotamersMover method
1135  run( pose, native_rot_to_pack );
1136 
1137  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
1138  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
1139  }
1140  // native bound score
1141  Real const native_score( ( *score_function() )( pose ) );
1142 
1143  if ( trial == 1 || native_score < best_native_score ) {
1144  best_native_score = native_score;
1145  // native binding score (bound - unbound)
1146  if ( binding_E_ ) best_native_dG = native_score - unbound_score( pose );
1147  best_native_specificities = measure_specificity( pose );
1148  best_pose = pose;
1149  }
1150  }
1151  // the interface is now repacked [and minimized] in the relevant region for subsequent calculations
1152  pose = best_pose;
1153 
1154  outfile << "Scanning protein positions that interface with DNA position(s) "
1155  << dna_seq_tag( pose, current_working_sequence( pose ) ) << '\n';
1156  outfile << "Using native scores from best trial: " << "bound = " << best_native_score
1157  << ", binding = " << best_native_dG << ", specificity.bound = "
1158  << best_native_specificities.first << ", specificity.binding = "
1159  << best_native_specificities.second << '\n';
1160 
1161  } // end scope
1162 
1163  // for each designing protein residue (in the interface)
1164  for ( std::list< Size >::const_iterator index( scan_positions.begin() ),
1165  end( scan_positions.end() ); index != end; ++index ) {
1166 
1167  outfile << "current designable residues are";
1168  for ( Size i(1); i <= task()->total_residue(); ++i ) {
1169  if ( !task()->design_residue(i) ) continue;
1170  if ( pose.pdb_info() ) {
1171  outfile << " " << pose.pdb_info()->chain(i) << "." << pose.pdb_info()->number(i);
1172  } else {
1173  outfile << " " << pose.chain(i) << "." << i;
1174  }
1175  outfile << " " << dna_full_name3( pose.residue_type(i).name3() );
1176  }
1177  outfile << '\n';
1178  // save the native type
1179  ResidueTypeCOP native_type( pose_residue_types[ *index ] );
1180 
1181  for ( ResidueTypeCOPs::const_iterator scan_type( allowed_type_caps.begin() );
1182  scan_type != allowed_type_caps.end(); ++scan_type ) {
1183 
1184  // ensure that this type was allowed by the PackerTask/RotamerSets/I.G. before proceeding
1185  ResidueLevelTask const & rtask( task()->residue_task(*index) );
1187  // maybe this should be a ResidueLevelTask method, and maybe the ResidueLevelTask should clear
1188  // its allowed_residue_types if !being_packed
1189  if ( !rtask.being_packed() ) {
1190  TR << "packing was disabled at " << pose.pdb_info()->chain(*index) << "."
1191  << pose.pdb_info()->number(*index) << std::endl;
1192  runtime_assert(false);
1193  }
1194  if ( std::find( art.begin(), art.end(), *scan_type ) == art.end() ) {
1195  TR << (*scan_type)->name() << " not allowed at " << pose.pdb_info()->chain(*index) << "."
1196  << pose.pdb_info()->number(*index) << std::endl;
1197  //runtime_assert(false);
1198  continue;
1199  }
1200  // set scan type at this residue
1201  pose_residue_types[ *index ] = *scan_type;
1202 
1203  Real best_score(0.), best_dG(0.);
1204  std::pair< Real, Real > best_specificities;
1205 
1206  for ( Size trial(1); trial <= num_repacks_; ++trial ) {
1207  utility::vector0<int> rot_to_pack;
1208  restrict_to_single_sequence( rotamer_sets(), pose_residue_types, rot_to_pack );
1209  // calls PackRotamersMover method
1210  run( pose, rot_to_pack );
1211  if ( min_movemap_ != 0 && minimize_options_ != 0 ) {
1212  AtomTreeMinimizer().run( pose, *min_movemap_, *score_function(), *minimize_options_ );
1213  }
1214  Real const score( ( *score_function() )( pose ) );
1215  if ( trial == 1 || score < best_score ) {
1216  best_score = score;
1217  if ( binding_E_ ) best_dG = score - unbound_score( pose );
1218  best_specificities = measure_specificity( pose );
1219  }
1220  }
1221  outfile << "Scores for mutation to " << pose_residue_types[ *index ]->name3() << " at ";
1222  if ( pose.pdb_info() ) {
1223  outfile << pose.pdb_info()->chain( *index ) << "." << pose.pdb_info()->number( *index );
1224  } else {
1225  outfile << pose.chain( *index ) << "." << *index;
1226  }
1227  outfile << "." << native_type->name() << ":" << " bound = " << best_score << " ("
1228  << best_score - best_native_score << ")" << ", binding = " << best_dG << " ("
1229  << best_dG - best_native_dG << ")" << ", specificity.bound = "
1230  << best_specificities.first << " ("
1231  << best_specificities.first - best_native_specificities.first << ")"
1232  << ", specificity.binding = " << best_specificities.second
1233  << " (" << best_specificities.second - best_native_specificities.second << ")\n";
1234  }
1235  // restore pose_residue_types to native state at this position
1236  pose_residue_types[ *index ] = native_type;
1237  outfile << "Done scanning at index " << *index << '\n';
1238  }
1239  outfile.close();
1240  // rename output file so that future runs do not read/append to it accidentally
1241  std::string newname( outfilename + ".done" );
1242  std::rename( outfilename.c_str(), newname.c_str() );
1243 
1244  pose = input_pose;
1245  TR.flush();
1246 }
1247 
1248 ////////////////////////////////////////////////////////////////////////////////////////////////////
1249 ///@brief makes hard copy to guarantee that the reference pose isn't changed from elsewhere
1250 void DnaInterfacePacker::reference_pose( Pose const & pose ) { reference_pose_ = new Pose( pose ); }
1252 
1255 
1257 
1258 ////////////////////////////////////////////////////////////////////////////////////////////////////
1259 /// @begin DnaInterfacePacker::dna_seq_tag
1260 /// @details similar to basic::dna_seq_str, but returns only top stranded sequence, delimited by "_". (safe for filenames)
1261 /// @authors ashworth
1263 DnaInterfacePacker::dna_seq_tag( Pose const & pose, ResTypeSequence const & sequence ) const
1264 {
1265  std::ostringstream ss;
1266  bool sep(false);
1267  for ( ResTypeSequence::const_iterator pos( sequence.begin() ); pos != sequence.end(); ++pos ) {
1268  Size const seqpos( pos->first );
1269  if ( !dna_chains_->is_top( seqpos ) ) continue;
1270  if ( sep ) ss << "_";
1271  if ( pose.pdb_info() ) {
1272  ss << pose.pdb_info()->chain( seqpos ) << "." << pose.pdb_info()->number( seqpos );
1273  } else {
1274  ss << pose.chain( seqpos ) << "." << seqpos;
1275  }
1276  ss << "." << dna_full_name3( pos->second->name3() );
1277  sep = true;
1278  }
1279  return ss.str();
1280 }
1281 
1282 ////////////////////////////////////////////////////////////////////////////////////////////////////
1283 /// @begin DnaInterfacePacker::get_targeted_sequence()
1284 /// @details returns DNA sequence that the PackerTask is configured to target (if any)
1285 /// @authors ashworth
1288 {
1289  runtime_assert( task() );
1290  runtime_assert( dna_chains_ );
1291  ResTypeSequence sequence;
1292  for ( DnaPositions::const_iterator it( dna_chains_->begin() ), end( dna_chains_->end() );
1293  it != end; ++it ) {
1294  DnaPosition const & pos( it->second );
1295  Size const resid( pos.top() );
1296  ResidueLevelTask const & rtask( task()->residue_task(resid) );
1297  if ( rtask.has_behavior("TARGET") ) {
1298  // dna position whose PackerTask behavior is 'targeted'
1299  // if PackerTask indicates nucleotide type to target, add this to local targeted sequence
1300  if ( rtask.target_type() != 0 ) sequence[ resid ] = rtask.target_type();
1301  // otherwise use the residue type at this position in the current pose
1302  else sequence[ resid ] = & pose.residue_type( resid );
1303 
1304  if ( !pos.paired() ) continue;
1305  // similar treatment for paired 'lower-strand' nucleotides
1306  Size const comp_resid( pos.bottom() );
1307  ResidueLevelTask const & comp_rtask( task()->residue_task(comp_resid) );
1308  if ( comp_rtask.target_type() != 0 ) sequence[ comp_resid ] = comp_rtask.target_type();
1309  else sequence[ comp_resid ] = & pose.residue_type( comp_resid );
1310  }
1311  }
1312  return sequence;
1313 }
1314 
1315 ////////////////////////////////////////////////////////////////////////////////////////////////////
1316 /// @begin current_working_sequence
1317 /// @brief current TOP-STRANDED DNA sequence of the pose, at PackerTask's 'targeted' or 'scan' positions
1318 /// @author ashworth
1321 {
1322  ResTypeSequence current_sequence;
1323  for ( DnaPositions::const_iterator it( dna_chains_->begin() ); it != dna_chains_->end(); ++it ) {
1324  if ( ! it->second.paired() ) continue; // skip unpaired DNA positions
1325  Size const resid( it->first );
1326  ResidueLevelTask const & rtask( task()->residue_task(resid) );
1327  if ( !rtask.has_behavior("TARGET") && !rtask.has_behavior("SCAN") ) continue;
1328  current_sequence[ resid ] = pose.residue( resid ).type();
1329  }
1330  return current_sequence;
1331 }
1332 
1335 {
1336  return dna_seq_tag( pose, current_working_sequence( pose ) );
1337 }
1338 
1339 } // namespace dna
1340 } // namespace protocols
1341