Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OptEMultifunc.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/optimization/OptEMultifunc.hh
11 /// @brief OptE mode multifunction class
12 /// @author Jim Havranek
13 
14 // MPI headers
15 #ifdef USEMPI
16 #include <mpi.h>
17 #endif
18 
19 // Package headers
23 
24 // Project headers
25 #include <core/types.hh>
26 
27 // AUTO-REMOVED #include <basic/options/util.hh>
28 
31 
32 #include <basic/Tracer.hh>
33 
35 // AUTO-REMOVED #include <protocols/optimize_weights/NestedEnergyTermOptEData.hh>
36 
37 /// Utility headers
38 #include <utility/exit.hh>
39 #include <utility/string_util.hh>
40 #include <utility/vector1.hh>
41 #include <utility/pointer/owning_ptr.hh>
42 #include <utility/pointer/ReferenceCount.hh>
43 
44 /// ObjexxFCL headers
45 #include <ObjexxFCL/format.hh> // F
46 
47 // C++ headers
48 // AUTO-REMOVED #include <cmath>
49 #include <fstream>
50 #include <ostream>
51 
52 // option key includes
53 #include <basic/options/keys/optE.OptionKeys.gen.hh>
54 
55 //Auto Headers
56 #include <basic/options/option.hh>
57 
58 
59 
60 using namespace core;
61 using namespace scoring;
62 using namespace optimization;
63 
64 namespace protocols {
65 namespace optimize_weights {
66 
67 using namespace ObjexxFCL::fmt;
68 using basic::T;
69 using basic::Error;
70 using basic::Warning;
71 static basic::Tracer TR("protocols.optimize_weights.OptEMultifunc");
72 
73 using namespace numeric::expression_parser;
74 //#undef NDEBUG
75 
76 
77 ///
78 /// @begin OptEMultifunc::OptEMultifunc
79 ///
80 OptEMultifunc::OptEMultifunc(
81  OptEData & opte_data_in,
82  EnergyMap const & fixed_terms_in,
83  int num_free_in,
84  ScoreTypes & score_list_in,
85  ScoreTypes & fixed_score_list_in,
86  Multivec const & component_weights
87 ) :
88  num_energy_dofs_( num_free_in ),
89  num_ref_dofs_( chemical::num_canonical_aas ),
90  num_total_dofs_( num_free_in + chemical::num_canonical_aas ),
91  opte_data_( opte_data_in ),
92  fixed_terms_( fixed_terms_in ),
93  score_list_( score_list_in ),
94  fixed_score_list_( fixed_score_list_in ),
95  fix_reference_energies_( false ),
96  starting_reference_energies_( chemical::num_canonical_aas, 0.0 ),
97  component_weights_( component_weights ),
98  mpi_rank_( 0 ),
99  mpi_nprocs_( 0 ),
100  distribute_over_mpi_( false )
101 {
102 #ifdef USEMPI
103  MPI_Comm_rank( MPI_COMM_WORLD, & mpi_rank_); /* get mpi rank */
104  MPI_Comm_size( MPI_COMM_WORLD, & mpi_nprocs_);/* get number of processes */
105  if ( basic::options::option[ basic::options::OptionKeys::optE::mpi_weight_minimization ] ) {
106  distribute_over_mpi_ = true;
107  }
108  //TR << "OptEMultifunc created on node " << mpi_rank_ << std::endl;
109 #endif
110 }
111 
112 
113 ///
114 /// @begin OptEMultifunc::OptEMultifunc
115 ///
117  OptEData & opte_data_in,
118  EnergyMap const & fixed_terms_in,
119  int num_free_in,
120  ScoreTypes const & score_list_in,
121  ScoreTypes const & fixed_score_list_in,
122  utility::vector1< Real > const & reference_energies_in,
123  Multivec const & component_weights
124 ) :
125  num_energy_dofs_( num_free_in ),
126  num_ref_dofs_( reference_energies_in.size() ),
127  num_total_dofs_( num_free_in + reference_energies_in.size() ),
128  opte_data_( opte_data_in ),
129  fixed_terms_( fixed_terms_in ),
130  score_list_( score_list_in ),
131  fixed_score_list_( fixed_score_list_in ),
132  fix_reference_energies_( false ),
133  starting_reference_energies_( reference_energies_in ),
134  component_weights_( component_weights ),
135  mpi_rank_( 0 ),
136  mpi_nprocs_( 0 ),
137  distribute_over_mpi_( false )
138 {
139 #ifdef USEMPI
140  MPI_Comm_rank( MPI_COMM_WORLD, & mpi_rank_); /* get mpi rank */
141  MPI_Comm_size( MPI_COMM_WORLD, & mpi_nprocs_);/* get number of processes */
142  if ( basic::options::option[ basic::options::OptionKeys::optE::mpi_weight_minimization ] ) {
143  distribute_over_mpi_ = true;
144  }
145  //TR << "OptEMultifunc created on node " << mpi_rank_ << std::endl;
146 #endif
147 }
148 
149 
150 ///
151 /// @begin OptEMultifunc::operator()
152 ///
153 /// @brief
154 /// The objective function for optE. Called in IterativeOptEDriver when optimizing the weights. Sums over all of the
155 /// PositionData objects in the OptEData object, and calls get_score() on each of them. Each PositionData object implements
156 /// print_score() and get_score() methods that print/return how good a weight set is for optimizing the metric that PositionData
157 /// object represents.
158 ///
159 Real
160 OptEMultifunc::operator()( Multivec const & vars ) const
161 {
162 
163  if ( distribute_over_mpi_ && mpi_rank_ == 0 ) {
164  mpi_broadcast_eval_func( vars );
165  }
166 
167  Multivec local_vars( num_total_dofs_ );
168  if ( fix_reference_energies_ ) {
169  for ( Size ii = 1; ii <= vars.size(); ++ii ) {
170  local_vars[ ii ] = vars[ ii ];
171  }
172  for ( Size ii = 1, iipnfree = num_energy_dofs_ + 1; ii <= starting_reference_energies_.size(); ++ii, ++iipnfree ) {
173  local_vars[ iipnfree ] = starting_reference_energies_[ ii ];
174  }
175  } else {
176  local_vars = vars;
177  }
178 
179  // Apply this energy map to the rotamer energies to get the 'score'
180  Real score( 0.0 );
181  Multivec dummy( local_vars.size(), 0.0 );
182 
183  // Summing over positions
184  for( OptEPositionDataOPs::const_iterator itr = opte_data_.position_data_begin(),
185  e_itr = opte_data_.position_data_end() ; itr != e_itr ; ++itr ) {
186  Real const s = (*itr)->get_score( component_weights_, local_vars, dummy,
189 #ifndef WIN32
190  bool bad = false;
191  if( std::isinf(s) ) { std::cerr << "Introduced INF score with " << OptEPositionDataFactory::optE_type_name( (*itr)->type() ) << " " << (*itr)->tag() << std::endl; bad=true; }
192  else if( std::isnan(s) ) { std::cerr << "Introduced NAN score with " << OptEPositionDataFactory::optE_type_name( (*itr)->type() ) << " " << (*itr)->tag() << std::endl; bad=true; }
193  else
194 #endif
195  score += s;
196 #ifndef WIN32
197  if ( bad ) {
198  if ( basic::options::option[ basic::options::OptionKeys::optE::limit_bad_scores ].user() ) //NaN and inf errors can accumulate into the gigabytes if optE is left unattended
199  {
200  static Size count = 0;
201  ++count;
202  if (count > 100000)
203  utility::exit(__FILE__,__LINE__, "Counted over 100,000 inf/NaN scores. Admitting defeat now.");
204  }
205  std::cerr << "vars: " << std::endl;
206  for ( Size ii = 1; ii <= local_vars.size(); ++ii ) {
207  if ( ii != 1 ) std::cerr << ", ";
208  std::cerr << ii << " " << local_vars[ ii ];
209  }
210  std::cerr << std::endl;
211  }
212 #endif
213  }
214 
215  if ( distribute_over_mpi_ && mpi_rank_ == 0 ) {
216  score += mpi_receive_func();
217  }
218 
219 #ifndef NDEBUG
220  if ( TR.visible() && mpi_rank_ == 0 ) {
221  TR << "OptEMultifunc " << score << "\n";
222  TR << "Vars: ";
223  for ( Size ii = 1; ii <= local_vars.size(); ++ii ) {
224  TR << " " << local_vars[ ii ];
225  }
226  TR << std::endl;
227  TR << "dVars: ";
228  for ( Size ii = 1; ii <= local_vars.size(); ++ii ) {
229  TR << " " << dummy[ ii ];
230  }
231  TR << std::endl;
232  }
233 #endif
234 
235 
236  return score;
237 }
238 
239 /// @brief OptE dfunc -- gets the partial derivatives of func for each dimension being minimized
240 void
241 OptEMultifunc::dfunc( Multivec const & vars, Multivec & dE_dvars ) const
242 {
243  if ( distribute_over_mpi_ && mpi_rank_ == 0 ) {
244  mpi_broadcast_eval_dfunc( vars );
245  }
246 
247  Multivec local_vars( num_total_dofs_ );
248  Multivec local_dE_dvars( num_total_dofs_, 0.0 );
249  if ( fix_reference_energies_ ) {
250  for ( Size ii = 1; ii <= vars.size(); ++ii ) {
251  local_vars[ ii ] = vars[ ii ];
252  }
253  for ( Size ii = 1, iipnfree = num_energy_dofs_ + 1; ii <= starting_reference_energies_.size(); ++ii, ++iipnfree ) {
254  local_vars[ iipnfree ] = starting_reference_energies_[ ii ];
255  }
256  } else {
257  local_vars = vars;
258  }
259 
260  for ( Size ii(1); ii <= dE_dvars.size(); ++ii ) dE_dvars[ ii ] = 0.0;
261 
262  // over positions
263  Real score( 0.0 );
264  for( OptEPositionDataOPs::const_iterator itr = opte_data_.position_data_begin(),
265  e_itr = opte_data_.position_data_end() ; itr != e_itr ; ++itr ) {
266  score += (*itr)->get_score( component_weights_, local_vars, local_dE_dvars,
269  for( Size ii = 1 ; ii <= local_dE_dvars.size() ; ++ii ) {
270 #ifndef WIN32
271  if( std::isinf(local_dE_dvars[ ii ]) ) std::cerr << "Introduced INF deriv at " << ii << " with " << OptEPositionDataFactory::optE_type_name( (*itr)->type() ) << " " << (*itr)->tag() << std::endl;
272  else if( std::isnan(local_dE_dvars[ ii ]) ) std::cerr << "Introduced NAN deriv at " << ii << " with " << OptEPositionDataFactory::optE_type_name( (*itr)->type() ) << " " << (*itr)->tag() << std::endl;
273 #endif
274  }
275  }
276 
277  /// Only store the vars that are actually being optimized; local vars will contain the reference energies
278  for ( Size ii = 1; ii <= dE_dvars.size(); ++ii ) {
279  dE_dvars[ ii ] = local_dE_dvars[ ii ];
280  }
281 
282  if ( distribute_over_mpi_ && mpi_rank_ == 0 ) {
283  mpi_receive_dfunc( dE_dvars );
284  }
285 
286 
287  if ( mpi_rank_ == 0 && TR.visible() ) { /// only the master node should output
288  TR << "score: " << F(9,5,score) << std::endl; /// deceptive when scoring across multiple nodes
289  TR << "dfuncs: ";
290  for ( Size ii = 1 ; ii <= dE_dvars.size() ; ++ii ) TR << " " << F(9,3,dE_dvars[ ii ]);
291  TR << std::endl;
292  TR << "vars: ";
293  for ( Size ii = 1; ii <= vars.size(); ++ii ) {
294  TR << " " << F(9,3,vars[ ii ]);
295  }
296  TR << std::endl;
297  }
298 
299 }
300 
301 
302 ///
303 /// @begin OptEMultifunc::get_dofs_from_energy_map()
304 ///
305 /// @brief Extract variable weights from an Energy Map
306 ///
307 Multivec
309 {
311 
312  Size dof_index( 1 );
313  for( ScoreTypes::const_iterator itr = score_list_.begin(),
314  end_itr = score_list_.end(); itr != end_itr; ++itr ) {
315  dofs[ dof_index++ ] = start_vals[ *itr ];
316  }
317  if ( ! fix_reference_energies_ ) {
318  for ( Size ii = 1; ii <= starting_reference_energies_.size(); ++ii ) {
319  dofs[ dof_index++ ] = starting_reference_energies_[ ii ];
320  }
321  }
322  return dofs;
323 }
324 
325 ///
326 /// @begin OptEMultifunc::get_energy_map_from_dofs()
327 ///
328 /// @brief Expand free variables and combine with fixed to make an Energy Map. Used by the IterativeOptEDriver at the
329 /// end of weight minimization to create an EnergyMap that uses the new weight set. This EnergyMap then gets output
330 /// into a optE log file.
331 ///
332 EnergyMap
334 {
335  EnergyMap return_map( fixed_terms_ );
336 
337  // This covers the variable weights
338  Size dof_index( 1 );
339  for( ScoreTypes::const_iterator itr = score_list_.begin(),
340  end_itr = score_list_.end() ;
341  itr != end_itr ; ++itr ) {
342  return_map[ *itr ] = dofs[ dof_index++ ];
343  }
344 
345  // Now the fixed weights - but I think we should have them from the
346  // copy constructor above, so this is probably a total waste....
347  for( ScoreTypes::const_iterator itr = fixed_score_list_.begin(),
348  end_itr = fixed_score_list_.end() ;
349  itr != end_itr ; ++itr ) {
350  return_map[ *itr ] = fixed_terms_[ *itr ];
351  }
352 
353  return return_map;
354 }
355 
358  Multivec const & dofs
359 ) const
360 {
361  if ( fix_reference_energies_ ) {
363  } else {
365  for ( int ii = 1; ii <= num_ref_dofs_; ++ii ) {
366  refEs[ ii ] = dofs[ ii + num_energy_dofs_ ];
367  }
368  return refEs;
369  }
370 }
371 
372 /// @brief Non-driver node wait for MPI vars to evaluate either the func or the dfunc.
373 void
375 {
376 #ifdef USEMPI
377  Multivec vars, dE_dvars;
378  while ( true ) {
379  int message;
380  /// Wait for a message from node 0.
381  MPI_Bcast( &message, 1, MPI_INT, 0, MPI_COMM_WORLD );
382 
383  //TR << "OptEMultifunc::wait_for_remote_vars " << mpi_rank_ << " " << message << std::endl;
384 
385 
386  if ( message == EVAL_FUNC ) {
388  double my_func = operator() ( vars );
389  MPI_Send( & my_func, 1, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD );
390  } else if ( message == EVAL_DFUNC ) {
392  dE_dvars.resize( vars.size() );
393  std::fill( dE_dvars.begin(), dE_dvars.end(), 0.0 );
394  dfunc( vars, dE_dvars );
395  double * dE_dvars_raw = new double[ vars.size() ];
396  for ( Size ii = 1; ii <= vars.size(); ++ii ) { dE_dvars_raw[ ii - 1 ] = dE_dvars[ ii ]; }
397  MPI_Send( dE_dvars_raw, vars.size(), MPI_DOUBLE, 0, 1, MPI_COMM_WORLD );
398  } else if ( message == END_OF_MINIMIZATION ) {
399  break;
400  } else {
401  std::cerr << "ERROR: Unrecognized message from root node: " << message << std::endl;
402  break;
403  }
404  }
405 #endif
406 
407 }
408 
409 /// @brief For driver node: inform the non-driver nodes that minimization is over. Must
410 /// be called before object is destructed (Should not be called in the destructor, as
411 /// dstors should not throw exceptions, and MPI communication can absolutely result in exceptions).
413 {
414 #ifdef USEMPI
415  int message = END_OF_MINIMIZATION;
416  MPI_Bcast( &message, 1, MPI_INT, 0, MPI_COMM_WORLD );
417 #endif
418 
419 }
420 
421 
422 /// @brief send out messages over MPI for remote nodes to evaluate their func given the input vars.
424 #ifdef USEMPI
425  Multivec const & vars
426 #else
427  Multivec const &
428 #endif
429 ) const
430 {
431 #ifdef USEMPI
432  int message = EVAL_FUNC;
433  MPI_Bcast( &message, 1, MPI_INT, 0, MPI_COMM_WORLD );
434 
435  mpi_broadcast_send_vars( vars );
436 
437  //TR << "OptEMultifunc::broadcast eval func" << mpi_rank_ << std::endl;
438 
439 #endif
440 }
441 
442 
443 /// @brief send out messages over MPI for remote nodes to evaluate their dfunc given the input vars.
445 #ifdef USEMPI
446  Multivec const & vars
447 #else
448  Multivec const &
449 #endif
450 ) const
451 {
452 #ifdef USEMPI
453  int message = EVAL_DFUNC;
454  MPI_Bcast( &message, 1, MPI_INT, 0, MPI_COMM_WORLD );
455 
456  mpi_broadcast_send_vars( vars );
457  //TR << "OptEMultifunc::broadcast eval dfunc" << mpi_rank_ << std::endl;
458 #endif
459 }
460 
462 #ifdef USEMPI
463  Multivec const & vars
464 #else
465  Multivec const &
466 #endif
467 ) const
468 {
469 #ifdef USEMPI
470  int vars_size = vars.size();
471  MPI_Bcast( & vars_size, 1, MPI_INT, 0, MPI_COMM_WORLD );
472 
473  double * raw_vars = new double[ vars_size ];
474  for ( int ii = 1; ii <= vars_size; ++ii ) {
475  raw_vars[ ii - 1 ] = vars[ ii ];
476  }
477  MPI_Bcast( raw_vars, vars_size, MPI_DOUBLE, 0, MPI_COMM_WORLD );
478  delete [] raw_vars;
479 #endif
480 }
481 
483 #ifdef USEMPI
484  Multivec & vars
485 #else
486  Multivec &
487 #endif
488 ) const
489 {
490 #ifdef USEMPI
491  int vars_size;
492  MPI_Bcast( & vars_size, 1, MPI_INT, 0, MPI_COMM_WORLD );
493  vars.resize( vars_size );
494 
495  double * raw_vars = new double[ vars_size ];
496  MPI_Bcast( raw_vars, vars_size, MPI_DOUBLE, 0, MPI_COMM_WORLD );
497  for ( int ii = 1; ii <= vars_size; ++ii ) {
498  vars[ ii ] = raw_vars[ ii - 1 ];
499  }
500  delete [] raw_vars;
501 
502 #endif
503 }
504 
505 
506 /// @brief collect func values from remote nodes and return their sum.
507 Real
509 {
510  Real total( 0.0 );
511 #ifdef USEMPI
512  MPI_Status stat;
513 
514  for ( int ii = 1; ii < mpi_nprocs_; ++ii ) {
515  double ii_func( 0 );
516  MPI_Recv( & ii_func, 1, MPI_DOUBLE, ii, 1, MPI_COMM_WORLD, & stat );
517  total += ii_func;
518  }
519 #endif
520  return total;
521 }
522 
523 /// @brief collect dfunc valresultsues from remote nodes and increment the values in the dE_dvars input array.
524 void
526 #ifdef USEMPI
527  Multivec & dE_dvars
528 #else
529  Multivec &
530 #endif
531 ) const
532 {
533 #ifdef USEMPI
534  MPI_Status stat;
535 
536  double * dE_dvars_raw = new double[ dE_dvars.size() ];
537  for ( int ii = 1; ii < mpi_nprocs_; ++ii ) {
538  MPI_Recv( dE_dvars_raw, dE_dvars.size(), MPI_DOUBLE, ii, 1, MPI_COMM_WORLD, & stat );
539  for ( Size jj = 1; jj <= dE_dvars.size(); ++jj ) {
540  dE_dvars[ jj ] += dE_dvars_raw[ jj - 1 ];
541  }
542  }
543  delete [] dE_dvars_raw;
544 #endif
545 }
546 
548  ScoreTypes const & free_score_list,
549  Size free_count,
550  ScoreTypes const & fixed_score_list,
551  EnergyMap const & fixed_scores,
552  OptEMultifuncOP optEfunc
553 )
554 :
555  free_score_list_( free_score_list ),
556  fixed_score_list_( fixed_score_list ),
557  fixed_scores_( fixed_scores ),
558  //optE_dof_expressions_( optEfunc->fix_reference_energies() ? free_count : free_count + chemical::num_canonical_aas, 0 ),
559  //active_variables_( optE_dof_expressions_.size() ),
560  multifunc_( optEfunc ),
561  n_new_dofs_( 0 ),
562  n_real_dofs_( free_count )
563 {
564  using namespace basic::options;
565  using namespace basic::options::OptionKeys;
566  using namespace core::scoring;
567 
568  // XCode doesn't like shorthand if statements in the initializer list
569  optE_dof_expressions_.resize( optEfunc->fix_reference_energies() ? free_count : free_count + chemical::num_canonical_aas, 0 );
570  active_variables_.resize( optE_dof_expressions_.size() );
571 
572  //std::cout << "WrapperOptEMultifunc ctor: free_count= " << free_count << " free_score_list.size()= " << free_score_list.size() << std::endl;
573 
574  if ( ! option[ optE::wrap_dof_optimization ].user() ) {
575  utility_exit_with_message( "Error in WrapperOptEMultifunc constructor. Cannot create WrapperOptEMultifunc if optE::wrap_dof_optimization is not on the command line");
576  }
577 
578  ArithmeticScanner as; // comes built-in with min, max and sqrt.
579 
580  for ( Size ii = 1; ii <= free_score_list.size(); ++ii ) {
581  std::string iiname = ScoreTypeManager::name_from_score_type( free_score_list[ ii ] );
582  free_score_names_.insert( iiname );
583  valid_variable_names_.insert( iiname );
584  optEmultifunc_dof_order_[ iiname ] = ii;
585  as.add_variable( iiname );
586  }
587 
588  for ( Size ii = 1; ii <= fixed_score_list.size(); ++ii ) {
589  std::string iiname = ScoreTypeManager::name_from_score_type( fixed_score_list[ ii ] );
590  valid_variable_names_.insert( iiname );
591  as.add_variable( iiname );
592  }
593 
594  /// This variable absolutely should not ever be held as an owning pointer
595  /// through a member variable of the class, or you will have a cycle
596  /// in the ownership graph and leak memory.
597  WrappedOptEExpressionCreator expression_creator( this );
598 
599  std::ifstream wrapper_file( option[ optE::wrap_dof_optimization ]()().c_str() );
600  bool finished_new_dof_header( false );
601 
602 
603  while ( wrapper_file ) {
604  std::string dof_dec;
605  std::string dof_name;
606  wrapper_file >> dof_dec;
607  if ( dof_dec == "" ) {
608  if ( !wrapper_file ) {
609  break;
610  } else {
611  utility_exit_with_message( "Expected NEW_DOF or DEPENDENT_DOF from " + option[ optE::wrap_dof_optimization ]()() + " but got empty string" );
612  }
613  }
614  wrapper_file >> dof_name;
615  std::cout << "READ: " << dof_dec << " " << dof_name << std::endl;
616  if ( dof_dec == "NEW_DOF" ) {
617  if ( finished_new_dof_header ) {
618  utility_exit_with_message( "Encountered NEW_DOF declaration after a DEPENDENT_DOF delcaration. All NEW_DOF declarations must be at the top of the file" );
619  } else {
620  valid_variable_names_.insert( dof_name );
621  new_dof_names_.insert( dof_name );
622  as.add_variable( dof_name );
623  }
624  } else if ( dof_dec == "DEPENDENT_DOF" ) {
625  if ( ! finished_new_dof_header ) {
626  finished_new_dof_header = true;
627  /// prepare to parse dof dependencies.
628  }
629 
630  if ( valid_variable_names_.find( dof_name ) == valid_variable_names_.end() ) {
631  utility_exit_with_message( "Error in WrapperOptEMultifunc::WrapperOptEMultifunc()\nDid not find dof " + dof_name + " in valid_variable_names_ set; either it is not a free dof or is listed as a dependent dof twice" );
632  }
633  valid_variable_names_.erase( dof_name );
634  std::string equals_sign;
635  wrapper_file >> equals_sign;
636  if ( equals_sign != "=" ) {
637  utility_exit_with_message( "Expected an equals sign after reading 'DEPENDENT_DOF " + dof_name + "' but instead read " + equals_sign );
638  }
639 
640  std::string expression;
641  getline( wrapper_file, expression );
642  std::cout << "READ EXPRESSION: " << expression << std::endl;
643  TokenSetOP tokens = as.scan( expression );
644  ArithmeticASTExpression ast_expression;
645  ast_expression.parse( *tokens );
646 
648  numeric::expression_parser::ExpressionCOP derived_dof_expression = expression_creator.create_expression_tree( ast_expression );
649 
650  Size derived_dof_index = optEmultifunc_dof_order_[ dof_name ];
651  optE_dof_expressions_[ derived_dof_index ] = derived_dof_expression;
653  std::cout << "Created expression for " << dof_name << " index# " << derived_dof_index << std::endl;
654  } else {
655  utility_exit_with_message( "Expected either NEW_DOF or DEPENDENT_DOF, but got " + dof_dec + " from file " + option[ optE::wrap_dof_optimization ]()() );
656  }
657 
658  }
659 
660  for ( Size ii = 1; ii <= optE_dof_expressions_.size(); ++ii ) {
661  if ( optE_dof_expressions_[ ii ] == 0 ) {
662  /// Need to create a variable expression for this dof so that it may be updated
663  /// in each function evaluation
664  /// Two cases: ii is a named dof, or ii is a reference energy.
665  if ( ii <= free_score_list_.size() ) {
668  if ( dof_variables_.find( iiname ) == dof_variables_.end() ) {
669  varexp = new OptEVariableExpression( iiname );
670  dof_variables_[ iiname ] = varexp;
671  } else {
672  varexp = (dof_variables_.find( iiname ))->second;
673  }
674  active_variables_[ ii ].insert( iiname );
675  optE_dof_expressions_[ ii ] = varexp;
676  } else {
677  std::string iiname = "ref" + utility::to_string( ii - free_score_list_.size() );
678  //std::cout << "Adding reference energy dof: " << ii << " " << iiname << std::endl;
679  // Assumption: the reference energy should not alrady be in the dof list
680  assert( dof_variables_.find( iiname ) == dof_variables_.end() );
681  OptEVariableExpressionOP varexp = new OptEVariableExpression( iiname );
682  dof_variables_[ iiname ] = varexp;
683  optE_dof_expressions_[ ii ] = varexp;
684  active_variables_[ ii ].insert( iiname );
685  }
686  }
687  }
688 
689  n_real_dofs_ = dof_variables_.size();
690  Size count_real_dofs( 1 );
691  for ( std::map< std::string, OptEVariableExpressionOP >::iterator
692  iter = dof_variables_.begin(), iter_end = dof_variables_.end();
693  iter != iter_end; ++iter ) {
694  iter->second->set_id( count_real_dofs );
695  ++count_real_dofs;
696  }
698 
699  for ( Size ii = 1; ii <= optE_dof_expressions_.size(); ++ii ) {
700  numeric::expression_parser::ExpressionCOP iiexp = optE_dof_expressions_[ ii ];
701  for ( std::set< std::string >::const_iterator
702  variter = active_variables_[ ii ].begin(),
703  variter_end = active_variables_[ ii ].end();
704  variter != variter_end; ++variter ) {
705  numeric::expression_parser::ExpressionCOP iiexp_dvar = iiexp->differentiate( *variter );
706  if ( iiexp_dvar == 0 ) {
707  utility_exit_with_message( "Error constructing parital derivative for '" +
708  name_from_score_type( free_score_list[ ii ] ) +
709  "' by variable '" + *variter + "'. Null pointer returned." );
710  }
711  Size varindex = dof_variables_.find( *variter )->second->id();
712  std::cout << "Adding dof derivative expression for " << *variter << " index#: " << varindex << " which appears in the expression for optEdof # " << ii << std::endl;
713  real_dof_deriviative_expressions_[ varindex ].push_back( std::make_pair( ii, iiexp_dvar ) );
714  }
715  }
716 }
717 
719 {
720  //std::cout << "WrapperOptEMultifunc::~WrapperOptEMultifunc()" << std::endl;
721 }
722 
723 // @brief OptE func
726 {
727  utility::vector1< Real > optEvars = derived_dofs( vars );
728  Real score = (*multifunc_)( optEvars );
729 
730  TR << "WrapperOptEMultifunc func: " << F(7,2,score) << std::endl;
731  TR << "Vars: ";
732  for ( Size ii = 1; ii <= vars.size(); ++ii ) {
733  TR << " " << vars[ ii ];
734  }
735  TR << std::endl;
736  return score;
737 }
738 
739 /// @brief OptE dfunc
740 void
742  Multivec const & vars,
743  Multivec & dE_dvars
744 ) const
745 {
746  utility::vector1< Real > optEvars = derived_dofs( vars );
747  Multivec dmultifunc_dvars( optEvars.size() );
748  std::fill( dE_dvars.begin(), dE_dvars.end(), 0.0 );
749  multifunc_->dfunc( optEvars, dmultifunc_dvars );
750 
751  for ( Size ii = 1; ii <= real_dof_deriviative_expressions_.size(); ++ii ) {
752  for ( std::list< std::pair< Size, numeric::expression_parser::ExpressionCOP > >::const_iterator
753  iter = real_dof_deriviative_expressions_[ ii ].begin(),
754  iter_end = real_dof_deriviative_expressions_[ ii ].end();
755  iter != iter_end; ++iter ) {
756  dE_dvars[ ii ] += (dmultifunc_dvars[ iter->first ]) * ( (*(iter->second))());
757  //std::cout << "Dof " << ii << " " << iter->first << ": " << (dmultifunc_dvars[ iter->first ]) << " * " << ( (*(iter->second))()) << std::endl;
758  }
759  }
760  if ( TR.visible() ) {
761  TR << "WrapperOptEMultifunc dfuncs:";
762  for( Size ii = 1 ; ii <= dE_dvars.size() ; ++ii ) TR << " " << F(7,2,dE_dvars[ ii ]);
763  TR << std::endl;
764  }
765 }
766 
767 Size
769 {
770  return n_real_dofs_;
771 }
772 
775 {
776  //std::cout << "WrapperOptEMultifunc::derived_dofs()\n";
778  for ( std::map< std::string, OptEVariableExpressionOP >::const_iterator
779  iter = dof_variables_.begin(), iter_end = dof_variables_.end();
780  iter != iter_end; ++iter ) {
781  iter->second->update_value_from_list( vars );
782  //std::cout << "variable: " << iter->first << " " << (*iter->second)() << "\n";
783  }
784  for ( Size ii = 1; ii <= optE_dof_expressions_.size(); ++ii ) {
785  optEvars[ ii ] = (*optE_dof_expressions_[ ii ])();
786  //std::cout << "optEvar " << ii << " = " << optEvars[ ii ] << "\n";
787  }
788  //std::cout << std::endl;
789 
790  return optEvars;
791 }
792 
793 
794 void
796  Multivec const & vars,
797  std::ostream & ostr
798 ) const
799 {
800  ostr << "WrapperOptEMultifunc dofs:\n";
801  for ( std::map< std::string, OptEVariableExpressionOP >::const_iterator
802  iter = dof_variables_.begin(), iter_end = dof_variables_.end();
803  iter != iter_end; ++iter ) {
804  iter->second->update_value_from_list( vars );
805  ostr << iter->first << " : " << (*(iter->second))() << "\n";
806  }
807 }
808 
809 
810 numeric::expression_parser::VariableExpressionOP
812 {
813  if ( valid_variable_names_.find( varname ) != valid_variable_names_.end() ) {
814  /// This is a valid variable name.
815 
816  if ( dof_variables_.find( varname ) != dof_variables_.end() ) {
817  return dof_variables_[ varname ];
818  } else {
819  OptEVariableExpressionOP varexp = new OptEVariableExpression( varname );
820  if ( fixed_score_names_.find( varname ) == fixed_score_names_.end() ) {
821  /// This is not a fixed dof, therefor it must be updated at each score evaluation.
822  dof_variables_[ varname ] = varexp;
823  } else {
824  /// This is a fixed dof, so it does not need updating during scoring. Set its value now,
825  /// and refrain from adding this variable to the dof_variables_ map.
826  ScoreType fixed_variable_scoretype = core::scoring::ScoreTypeManager::score_type_from_name( varname );
827  varexp->set_value( fixed_scores_[ fixed_variable_scoretype ] );
828  }
829  active_variables_this_dependent_dof_.insert( varname );
830  return varexp;
831  }
832  } else {
833  /// We don't have a valid variable name. Why not?
834  if ( dependent_dof_names_.find( varname ) != dependent_dof_names_.end() ) {
835  /// It's no longer a valid variable name because it's a former free-score name but has already
836  /// been listed as a dependent dof.
837  utility_exit_with_message( "Variable '" + varname +"' appearing on the right hand side of a DEPENDENT_DOF statement\nwas previously listed as a dependent variable" );
838  } else {
839  std::cerr << "Error: variable expression with name '" << varname << "' is not a valid variable name." << std::endl;
840  std::cerr << "Free variables:" << std::endl;
841  for ( std::set< std::string >::const_iterator
842  iter = free_score_names_.begin(), iter_end = free_score_names_.end();
843  iter != iter_end; ++iter ) {
844  std::cerr << *iter << std::endl;
845  }
846  std::cerr << "Fixed variables:" << std::endl;
847  for ( std::set< std::string >::const_iterator
848  iter = fixed_score_names_.begin(), iter_end = fixed_score_names_.end();
849  iter != iter_end; ++iter ) {
850  std::cerr << *iter << std::endl;
851  }
852  std::cerr << "New variables:" << std::endl;
853  for ( std::set< std::string >::const_iterator
854  iter = new_dof_names_.begin(), iter_end = new_dof_names_.end();
855  iter != iter_end; ++iter ) {
856  std::cerr << *iter << std::endl;
857  }
858  }
859 
860  utility_exit_with_message("Could not register variable '" + varname + "' as it is neither a valid free, fixed nor new DOF" );
861  }
862  return 0;
863 }
864 
865 void
867 {
868  multifunc_ = multifunc;
869 }
870 
872  numeric::expression_parser::VariableExpression( name ),
873  id_( 0 )
874 {}
875 
877  numeric::expression_parser::VariableExpression( name, value ),
878  id_( 0 )
879 {}
880 
881 void
883 {
884  id_ = id;
885 }
886 
888  utility::vector1< core::Real > const & value_vector
889 )
890 {
891  set_value( value_vector[ id_ ] );
892 }
893 
895 {}
896 
898  WrapperOptEMultifuncAP multifunc
899 )
900  : multifunc_( multifunc )
901 {}
902 
904 
905 numeric::expression_parser::ExpressionCOP
907 {
908  return multifunc_->register_variable_expression( node.variable_name() );
909 }
910 
911 numeric::expression_parser::ExpressionCOP
913  FunctionTokenCOP function,
915 )
916 {
917  utility_exit_with_message( "WrappedOptEExpressionCreator cannot process function " + function->name() );
918  return 0;
919 }
920 
921 void
923 {
924  multifunc_ = multifunc;
925 }
926 
927 
928 } // namespace optimize_weights
929 } // namespace protocols
930 
931 
932