Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MultistateFitnessFunction.cc
Go to the documentation of this file.
1 // -*- mode:c++{}tab-width:2{}indent-tabs-mode:t{}show-trailing-whitespace:t{}rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file protocols/pack_daemon/MultistateFitnessFunction.cc
11 /// @brief Implementation of the class MultistateFitnessFunction
12 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com)
13 
14 // Unit headers
16 
17 // Package headers
19 // AUTO-REMOVED #include <protocols/pack_daemon/EntityCorrespondence.hh>
21 
22 // Project headers
23 // AUTO-REMOVED #include <core/io/pdb/pose_io.hh>
24 // AUTO-REMOVED #include <core/pack/task/PackerTask.hh>
25 #include <core/pose/Pose.hh>
26 #include <basic/Tracer.hh>
27 
28 // Utility headers
29 #include <utility/assert.hh>
30 //#include <utility/heap.hh>
31 #include <utility/mpi_util.hh>
32 #include <utility/string_util.hh>
33 
34 // C++ headers
35 // AUTO-REMOVED #include <ctime>
36 #include <iostream>
37 
39 
40 #include <utility/vector0.hh>
41 #include <utility/vector1.hh>
42 
43 
44 
45 static basic::Tracer TR("protocols.pack_daemon.MultistateFitnessFunction");
46 
47 namespace protocols {
48 namespace pack_daemon {
49 
50 
51 /// A struct for compairing entities and state energies for use in the
52 /// STL heap functions
54 {
55 public:
57 
58 public:
59  bool operator () ( EntityAndScore const & a, EntityAndScore const & b ) {
60  return a.first->fitness() < b.first->fitness();
61  }
62 };
63 
64 
66  desired_entity_history_size_( 1 ),
67  n_tied_for_worst_( 0 )
68 {
69  set_history_size( 1 ); // at the very least, store the optimal solution!
70 }
72 
74 {
75  clock_t start_time = clock();
76 
77  std::fill( state_energies_.begin(), state_energies_.end(), 0.0 );
78  if ( TR.visible( basic::t_debug ) ) {
79  TR.Debug << "Evaluating entity " << entity << std::endl;
80  }
81 
82  compute_state_energies( entity );
83 
84  core::Real score = compute_aggregate_score( entity );
85  entity.set_fitness( score );
86  update_entity_history( entity );
87 
88  clock_t stop_time = clock();
89  if ( TR.visible( basic::t_debug )) {
90  TR.Debug << "evaluate() took " << ((double) stop_time - start_time ) / CLOCKS_PER_SEC << " seconds" << std::endl;
91  }
92  return score;
93 }
94 
96 {
97  daemon_set_ = ds;
98  state_energies_.resize( daemon_set_->ndaemons() );
99  npd_properties_.resize( daemon_set_->n_npd_properties() );
100  std::fill( state_energies_.begin(), state_energies_.end(), 0.0 );
101  std::fill( npd_properties_.begin(), npd_properties_.end(), 0.0 );
102 }
103 
105 {
106  aggregate_ = func;
107 }
108 
110 {
111  return daemon_set_;
112 }
113 
115 {
116  return state_energies_;
117 }
118 
120 {
121  return npd_properties_;
122 }
123 
124 
126 {
127  return aggregate_;
128 }
129 
131 {
132  //TR << "Set history size " << history_size << std::endl;
133  desired_entity_history_size_ = history_size;
134  top_entities_.resize( 0 );
135  top_entities_.reserve( 2 * history_size ); // leave extra room for likely ties
136  n_tied_for_worst_ = 0;
137 }
138 
140 {
141  top_entities_.resize( 0 );
142  n_tied_for_worst_ = 0;
143 }
144 
145 std::list< std::pair< MultistateFitnessFunction::Size, MultistateFitnessFunction::PoseOP > >
147 {
148  Size entity_index = which_top_entity( ent );
149  if ( entity_index == 0 ) {
150  std::cerr << "Failed to find desired top entity: " << ent << std::endl;
151  std::cerr << "Top entities:" << std::endl;
152  for ( Size ii = 1; ii <= top_entities_.size(); ++ii ) {
153  std::cerr << ii << " " << *top_entities_[ ii ].first << std::endl;
154  }
155  utility_exit_with_message( "Failed to find desired top entity" );
156  }
158  aggregate_->select_relevant_states(
159  top_entities_[ entity_index ].second.first,
160  top_entities_[ entity_index ].second.second,
161  ent );
162  return recover_poses_from_states( *top_entities_[ entity_index ].first, relevant_states );
163 }
164 
165 
167 {
168  //std::fill( state_energies_.begin(), state_energies_.end(), 1234 );
169  //std::fill( npd_properties_.begin(), npd_properties_.end(), 1234 );
170  DaemonSet::StateEsAndNPDs energies =
171  daemon_set_->compute_energy_for_assignment( entity );
172  for ( DaemonSet::SizeRealPairs::const_iterator
173  iter = energies.first.begin(), iter_end = energies.first.end();
174  iter != iter_end; ++iter ) {
175  state_energies_[ iter->first ] = iter->second;
176  }
177  for ( DaemonSet::SizeRealPairs::const_iterator
178  iter = energies.second.begin(), iter_end = energies.second.end();
179  iter != iter_end; ++iter ) {
180  npd_properties_[ iter->first ] = iter->second;
181  }
182 
183  //for ( Size ii = 1; ii <= state_energies_.size(); ++ii ) {
184  // if ( state_energies_[ ii ] == 1234 ) {
185  // std::cout << "Weird: state_energies_[ " << ii << " ] was not eevaluated" << std::endl;
186  // }
187  //}
188  //for ( Size ii = 1; ii <= npd_properties_.size(); ++ii ) {
189  // if ( npd_properties_[ ii ] == 1234 ) {
190  // std::cout << "Weird: npd_properties_[ " << ii << " ] was not eevaluated" << std::endl;
191  // }
192  //}
193 }
194 
196 {
197  return aggregate_->evaluate( state_energies_, npd_properties_, entity );
198 }
199 
201 {
202  daemon_set_->mark_last_entity_as_important();
203 }
204 
206 {
207  daemon_set_->mark_entity_as_unimportant( entity );
208 }
209 
210 std::list< std::pair< MultistateFitnessFunction::Size, MultistateFitnessFunction::PoseOP > >
212  Entity const & ent,
213  utility::vector1< core::Size > const & which_states
214 )
215 {
216  return daemon_set_->retrieve_relevant_poses_for_entity( ent, which_states );
217 }
218 
219 
222  return state_energies_;
223 }
224 
227 {
228  return npd_properties_;
229 }
230 
232 {
233  return daemon_set_;
234 }
235 
237 {
238  return aggregate_;
239 }
240 
243 {
244  for ( Size ii = 1; ii <= top_entities_.size(); ++ii ) {
245  if ( *top_entities_[ ii ].first == ent ) {
246  return ii;
247  }
248  }
249  return 0;
250 }
251 
252 void
254 {
255 
257  // 1. handle the cases when the heap is not yet full
258 
259  if ( top_entities_.size() == 0 ) {
260  // a. first element added to the heap
261  n_tied_for_worst_ = 1;
262  } else if ( ent.fitness() == top_entities_.front().first->fitness() ) {
263  // b. tied with the worst element in the heap
265  } else if (ent.fitness() > top_entities_.front().first->fitness() ) {
266  // c. worse than the worst element in the heap -- a new low!
267  n_tied_for_worst_ = 1;
268  }
269 
271  top_entities_.push_back( std::make_pair( new Entity( ent ), seanpd ) );
272  std::push_heap( top_entities_.begin(), top_entities_.end(), EntityHistoryLT() );
274 
275  } else if ( ent.fitness() <= top_entities_.front().first->fitness() ) {
276  // 2. handle the cases when the heap is full
277  if ( top_entities_.front().first->fitness() == ent.fitness() ) {
278  // a. Tie between the new entity and the worst entity in the heap
280  } else {
281  // b. Not a tie -- maybe we can remove some of the entities that are tied for worst
282  assert( n_tied_for_worst_ <= top_entities_.size() );
284  // start popping entities from the heap
285  ASSERT_ONLY(Real const old_worst_fitness = top_entities_.front().first->fitness();)
286  for ( Size ii = 1; ii <= n_tied_for_worst_; ++ii ) {
287  assert( top_entities_.front().first->fitness() == old_worst_fitness );
289  std::pop_heap( top_entities_.begin(), top_entities_.end(), EntityHistoryLT() );
290  top_entities_.pop_back();
291  }
292 
293  /// now, determine how many entities are tied for worst.
294  if ( top_entities_.size() != 0 ) {
295  utility::vector1< EntityAndScore > worst_entities; worst_entities.reserve( top_entities_.size() );
296  Real const new_worst_fitness = top_entities_.front().first->fitness();
297  n_tied_for_worst_ = 0;
298  while ( top_entities_.front().first->fitness() == new_worst_fitness ) {
299  worst_entities.push_back( top_entities_.front() );
300  std::pop_heap( top_entities_.begin(), top_entities_.end(), EntityHistoryLT() );
301  top_entities_.pop_back();
303  }
304  /// ok -- we know how many entities are tied for worst. put these entities back
305  /// into the heap
306  for ( Size ii = 1; ii <= n_tied_for_worst_; ++ii ) {
307  top_entities_.push_back( worst_entities[ ii ] );
308  std::push_heap( top_entities_.begin(), top_entities_.end(), EntityHistoryLT() );
309  }
310  } else {
311  /// we just emptied out the history; the element we're about to add
312  /// will be the worst element in the history -- so save the fact that the number
313  /// of entities tied for last place is now 1.
314  n_tied_for_worst_ = 1;
315  }
316  }
317 
318  }
320  top_entities_.push_back( std::make_pair( new Entity( ent ), seanpd ) );
321  std::push_heap( top_entities_.begin(), top_entities_.end(), EntityHistoryLT() );
323  }
324 
325 }
326 
328  MPI_nprocs_( 0 )
329 {
330 #ifdef USEMPI
331  MPI_nprocs_ = static_cast< Size > ( utility::mpi_nprocs() );
332 #endif
333 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
334  utilization_by_node_.resize( MPI_nprocs_ );
335  packing_percentage_.resize( MPI_nprocs_ );
336  npd_percentage_.resize( MPI_nprocs_ );
337 #endif
338 }
339 
341 
343 {
344  state_energies().resize( n_daemons );
345 }
346 
348 {
349  npd_properties().resize( n_npd_properties );
350 }
351 
353 {
354  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
355  utility::send_integer_to_node( ii, spin_down );
356  }
357 }
358 
359 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
360 void MPIMultistateFitnessFunction::print_load_balance_statistics( std::ostream & ostr ) const
361 {
362  for ( Size ii = 0; ii < MPI_nprocs_; ++ii ) {
363  Real ut_sum = 0; Real packing_sum = 0; Real npd_sum = 0; Size count = 0;
364  for ( std::list< core::Real >::const_iterator
365  uiter = utilization_by_node_[ ii ].begin(),
366  uiter_end = utilization_by_node_[ ii ].end(),
367  piter = packing_percentage_[ ii ].begin(),
368  //piter_end = packing_percentage_[ ii ].end(),
369  npditer = npd_percentage_[ ii ].begin() //,
370  //npditer_end = npd_percentage_[ ii ].end
371  ; uiter != uiter_end; ++uiter, ++piter, ++npditer ) {
372  ++count;
373  ut_sum += *uiter;
374  packing_sum += *piter;
375  npd_sum += *npditer;
376  }
377  ut_sum /= count;
378  packing_sum /= count;
379  npd_sum /= count;
380  ostr << "Node " << ii << " average utilization: " << ut_sum << " packing: " << packing_sum << " npd: " << npd_sum << std::endl;
381  }
382 }
383 
384 void MPIMultistateFitnessFunction::reset_load_balance_statistics()
385 {
386  for ( Size ii = 0; ii < MPI_nprocs_; ++ii ) {
387  utilization_by_node_[ ii ].clear();
388  }
389 }
390 #endif
391 
392 
394 {
395  using namespace utility;
396 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
397  std::clock_t start_time = clock();
398  utility::vector0< core::Real > times( MPI_nprocs_ );
399  utility::vector0< core::Real > packing_times( MPI_nprocs_ );
400  utility::vector0< core::Real > npd_times( MPI_nprocs_ );
401 #endif
402 
403  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
404  send_integer_to_node( ii, evaluate_entity );
405  }
406  broadcast_entity_string( entity );
407  std::fill( state_energies().begin(), state_energies().end(), core::Real( 0.0 ) );
408  if ( daemon_set() ) {
409 
411  compute_energy_for_assignment( entity );
412  for ( std::list< std::pair< core::Size, core::Real > >::const_iterator
413  iter = energies.first.begin(), iter_end = energies.first.end();
414  iter != iter_end; ++iter ) {
415  state_energies()[ iter->first ] = iter->second;
416  }
417  for ( std::list< std::pair< core::Size, core::Real > >::const_iterator
418  iter = energies.second.begin(), iter_end = energies.second.end();
419  iter != iter_end; ++iter ) {
420  npd_properties()[ iter->first ] = iter->second;
421  }
422  }
423 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
424  std::clock_t node0_stop_time = clock();
425  times[ 0 ] = ((double) node0_stop_time - start_time ) / CLOCKS_PER_SEC;
426  packing_times[ 0 ] = daemon_set()->last_packing_runtime();
427  npd_times[ 0 ] = daemon_set()->last_npd_runtime();
428 #endif
429 
430  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
431  //TR << "receiving n_results from node " << ii << std::endl;
432  int n_results = receive_integer_from_node( ii );
433  //TR << "received " << n_results << " from node " << ii << std::endl;
434  for ( int jj = 1; jj <= n_results; ++jj ) {
435  int which_pack_daemon = receive_integer_from_node( ii );
436  Real energy_for_daemon = receive_double_from_node( ii );
437  //std::cout << "Received energy of " << energy_for_daemon << " for daemon #" << which_pack_daemon << " on node " << ii << " from a total of " << state_energies().size() << " PackDaemons" << std::endl;
438  state_energies()[ which_pack_daemon ] = energy_for_daemon;
439  }
440  //TR << "receiving n npd properties from node " << ii << std::endl;
441  int n_npd_properties = receive_integer_from_node( ii );
442  //TR << "received " << n_npd_properties << " n_npd_properties from node " << ii << std::endl;
443  for ( int jj = 1; jj <= n_npd_properties; ++jj ) {
444  int which_npd_prop = receive_integer_from_node( ii );
445  Real npd_property = receive_double_from_node( ii );
446  npd_properties()[ which_npd_prop ] = npd_property;
447  //TR << "property " << which_npd_prop << ": " << npd_property << " from node " << ii << std::endl;
448  }
449 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
450  times[ ii ] = utility::receive_double_from_node( ii );
451  packing_times[ ii ] = utility::receive_double_from_node( ii );
452  npd_times[ ii ] = utility::receive_double_from_node( ii );
453 #endif
454  }
455 
456 
457 #ifdef APL_MEASURE_MSD_LOAD_BALANCE
458  std::clock_t final_stop_time = clock();
459  Real runtime = ((double) final_stop_time - start_time ) / CLOCKS_PER_SEC;
460  if (runtime != 0.0 ) {
461  for ( Size ii = 0; ii < MPI_nprocs_; ++ii ) {
462  utilization_by_node_[ ii ].push_back( times[ ii ] / runtime );
463  packing_percentage_[ ii ].push_back( packing_times[ ii ] / runtime );
464  npd_percentage_[ ii ].push_back( npd_times[ ii ] / runtime );
465  }
466  } else {
467  for ( Size ii = 0; ii < MPI_nprocs_; ++ii ) {
468  utilization_by_node_[ ii ].push_back( 1.0 );
469  packing_percentage_[ ii ].push_back( 0.0 );
470  npd_percentage_[ ii ].push_back( 0.0 );
471  }
472  }
473 #endif
474  //TR << "Finished computing state energies" << std::endl;
475 
476 }
477 
479 {
480  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
481  utility::send_integer_to_node( ii, keep_rotamer_assignment_for_last_entity );
482  }
483  if ( daemon_set() ) {
484  daemon_set()->mark_last_entity_as_important();
485  }
486 }
487 
489 {
490  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
491  utility::send_integer_to_node( ii, discard_old_entity );
492  }
493  broadcast_entity_string( entity );
494  if ( daemon_set() ) {
495  daemon_set()->mark_entity_as_unimportant( entity );
496  }
497 }
498 
499 std::list< std::pair< MultistateFitnessFunction::Size, MultistateFitnessFunction::PoseOP > >
501  Entity const & entity,
502  utility::vector1< core::Size > const & which_states
503 )
504 {
505  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
506  utility::send_integer_to_node( ii, geneate_pose_from_old_state );
507  }
508  broadcast_entity_string( entity );
509  utility::vector1< int > which_states_ints( which_states );
510  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
511  utility::send_integers_to_node( ii, which_states_ints );
512  }
513  std::list< std::pair< Size, PoseOP > > return_pose_list;
514  if ( daemon_set() ) {
515  std::list< std::pair< Size, PoseOP > > my_poses = daemon_set()->
516  retrieve_relevant_poses_for_entity( entity, which_states );
517  return_pose_list.splice( return_pose_list.end(), my_poses );
518  }
519  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
520  int n_poses_from_ii = utility::receive_integer_from_node( ii );
521  //std::cout << "Ready to receive " << n_poses_from_ii << " pdb strings from node " << ii << std::endl;
522  std::string pseudo_pdbname = "MPI_pdb_from_node_" + utility::to_string( ii );
523  for ( int jj = 1; jj <= n_poses_from_ii; ++jj ) {
524  //std::cout << "Receiving pose " << jj << " of " << n_poses_from_ii << std::flush;
525  Size pack_daemon_index = utility::receive_integer_from_node( ii );
526  std::string pdb_string = utility::receive_string_from_node( ii );
527 
528  PoseOP pose = new Pose;
529  core::import_pose::pose_from_pdbstring( *pose, pdb_string, pseudo_pdbname );
530 
531  return_pose_list.push_back( std::make_pair( pack_daemon_index, pose ) );
532  //std::cout << "... done" << std::endl;
533  }
534  }
535  return return_pose_list;
536 }
537 
539 {
540  std::ostringstream oss;
541  entity.write_checkpoint( oss );
542  std::string entity_string = oss.str();
543 
544  for ( Size ii = 1; ii < MPI_nprocs_; ++ii ) {
545  utility::send_string_to_node( ii, entity_string );
546  }
547 }
548 
549 
550 
551 }
552 }
553