Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JobDistributors.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 // :noTabs=false:tabSize=4:indentSize=4:
4 //
5 // (c) Copyright Rosetta Commons Member Institutions.
6 // (c) This file is part of the Rosetta software suite and is made available under license.
7 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
8 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
9 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
10 
11 /// @file protocols/jobdist/JobDistributors.cc
12 /// @brief
13 /// @author Sergey Lyskov
14 
15 #include <utility/io/izstream.hh>
17 #include <basic/Tracer.hh>
18 
19 #include <core/svn_version.hh>
20 #include <core/types.hh>
21 #include <core/io/pdb/file_data.hh>
24 #include <basic/options/option.hh>
25 #include <core/pose/Pose.hh>
26 #include <core/scoring/Energies.hh>
27 // AUTO-REMOVED #include <core/scoring/ScoreFunction.hh>
28 // AUTO-REMOVED #include <core/scoring/ScoreFunctionFactory.hh>
29 
30 #include <core/io/silent/util.hh>
36 
37 #include <numeric/random/random.hh>
38 #include <numeric/numeric.functions.hh>
39 
40 #include <utility/exit.hh>
41 #include <utility/file/file_sys_util.hh>
42 #include <utility/file/FileName.hh>
43 #include <utility/io/ozstream.hh>
44 #include <utility/vector1.hh>
45 #include <utility/pointer/ReferenceCount.hh>
46 #ifdef USEMPI
47 #include <utility/string_util.hh>
48 #endif
49 
50 // ObjexxFCL headers
51 #include <ObjexxFCL/string.functions.hh>
52 
53 #include <map>
54 #include <set>
55 #include <sstream>
56 #include <string>
57 
58 
59 // option key includes
60 
61 #include <basic/options/keys/out.OptionKeys.gen.hh>
62 #include <basic/options/keys/run.OptionKeys.gen.hh>
63 
65 #include <numeric/random/random.fwd.hh>
66 
67 
68 namespace protocols {
69 namespace jobdist {
70 
71 basic::Tracer JobDistributorTracer("protocols.jobdist.JobDistributors");
72 
74  overwrite_( basic::options::option[ basic::options::OptionKeys::out::overwrite ] ),
75  jobs_(jobs),
76  current_job_(1),
77  current_nstruct_(0),
78  is_started_(false),
79  nproc_( 0 ),
80  proc_id_( 0 ),
81  curr_jobid_( 0 ),
82 #ifdef USEMPI
83  mpi_rank_( 0 ),
84  mpi_nprocs_( 0 ),
85  tag_( 1 ),
86 #endif
87  ignorefinished_( false ),
88  nooutput_( false ),
89  inprogress_( false )
90 {
91  start_time_ = time(NULL);
92 }
93 
95  ReferenceCount(),
96  overwrite_( src.overwrite_ ),
97  jobs_( src.jobs_ ),
98  current_job_( src.current_job_ ),
99  current_nstruct_( src.current_nstruct_ ),
100  is_started_( src.is_started_ ),
101  nproc_( src.nproc_ ),
102  proc_id_( src.proc_id_ ),
103  curr_jobid_( src.curr_jobid_ ),
104 #ifdef USEMPI
105  mpi_rank_( src.mpi_rank_ ),
106  mpi_nprocs_( src.mpi_nprocs_ ),
107  tag_( src.tag_ ),
108 #endif
109  ignorefinished_( src.ignorefinished_ ),
110  nooutput_( src.nooutput_ ),
111  inprogress_( src.inprogress_ ),
112  start_time_( src.start_time_ ),
113  random_counter_( src.random_counter_ ),
114  random_store_( src.random_store_ )
115 {
116 
117 }
118 
119 
121 {
122  if( is_started_ )
123  basic::Error() << "Must call shutdown() when finished using job distributor!" << std::endl;
124 }
125 
126 
127 ///@details
128 /// Deliberately not virtual: should not be overriden.
129 /// This is where to insert ifdefs and code for different cluster architectures!
130 bool BaseJobDistributor::next_job(BasicJobOP & job, int & struct_n)
131 {
132 #ifdef USEMPI
133  JobDistributorTracer << "Node: " << mpi_rank_ << " next_job()" << std::endl;
134 #endif
135 
136  int elapsedtime = time(NULL) - start_time_;
137  if( ( basic::options::option[ basic::options::OptionKeys::run::maxruntime ].user() ) &&
138  ( basic::options::option[ basic::options::OptionKeys::run::maxruntime ]() > 0 ) &&
139  ( basic::options::option[ basic::options::OptionKeys::run::maxruntime ]() < elapsedtime ) )
140  {
141  std::cerr << "JobTerminated because runtime of " << elapsedtime << " s exceeded maxruntime of " << basic::options::option[ basic::options::OptionKeys::run::maxruntime ]() << " s " << std::endl;
142  return false;
143  }
144 
145 
146  if( !is_started_ ) {
147  basic::Error() << "Must call startup() before using job distributor!" << std::endl;
148  return false;
149  }
150 
151 #ifdef USEMPI
152  if ( mpi_rank() == 0 ) {
153  master_node_distribute_jobs();
154  return false;
155  } else {
156  bool const job_recieved = request_job_from_master_node();
157  if ( job_recieved ) {
158  job = jobs_[ current_job_ ];
159  struct_n = current_nstruct_;
160  }
161  job->set_output_file_name( get_output_filename() );
162  return job_recieved;
163  }
164 #else // one machine, Condor cluster, or BOINC
165  bool job_found = find_available_job();
166  if ( ! job_found ) return job_found;
167 
168  job = jobs_[ current_job_ ];
169  struct_n = current_nstruct_;
170 
172  //current_nstruct_ += 1; this should -- and is now -- handled by find_available_job
173  job->set_output_file_name( get_output_filename() );
174  return true;
175 #endif // BOINC vs MPI vs etc
176 
177 }
178 
179 ///@details
180 /// Deliberately not virtual: should not be overriden.
181 /// Iterate over the jobs that exist, check that nothing has been started
182 /// for each, and point the private data current_nstruct_ and current_job_ at
183 /// whichever available job it finds first. Returns false if no job can be found.
185 {
186  bool shuffle_mode = basic::options::option[ basic::options::OptionKeys::run::shuffle ].user() ;
187 
188  while ( current_job_ <= jobs_.size() ) {
189 
190  // if shuffle mode then choose a random job and reset current_nstruct_ to 0. It should then work out which ones it's already done.
191  if( shuffle_mode ){
192 
193  do{
195  }while( (current_job_ < 1) || (current_job_ > jobs_.size()) );
196  current_nstruct_ = 0;
197 
198  // in shuffle mode nstruct means how many structures **in total** not per job.
199  if( (int)curr_jobid_ >= (int)basic::options::option[ basic::options::OptionKeys::out::nstruct]() ) return false;
200  }
201  while ( current_nstruct_ < jobs_[ current_job_ ]->nstruct() ) {
202  ++current_nstruct_; //running number within current job
203  ++curr_jobid_; //running number across all jobs
204  if( shuffle_mode ) current_nstruct_ = curr_jobid_;
205 
206  JobDistributorTracer << "Looking for an available job: "
207  << current_nstruct_ << " "
208  << current_job_ << " "
209  << jobs_[ current_job_ ]->input_tag() << " "
210  << curr_jobid_
211  << std::endl;
212 
213  bool processed( !overwrite_ && is_finished( jobs_[ current_job_ ], current_nstruct_ ) );
214  bool skipped( nproc_ && numeric::mod( curr_jobid_, nproc_ ) != ( proc_id_ - 1 ) );
215  if( shuffle_mode && processed ){ break; }
216  if ( !processed && !skipped ) {
217 #ifdef BOINC
218  if( shuffle_mode ) {
220  }else{
222  }
223 #endif
224  return true;
225  }
226  }
227  ++current_job_;
228  current_nstruct_ = 0;
229  }
230  return false;
231 }
232 
233 #ifdef AN_UNDEFINED_MACRO // never define this! replacing #if 0 for code parsing purposes
234 //............replaced by above because its unecessarily obfuscated...
235  while(true) {
236  JobDistributorTracer << "Looking for an available job: " << current_nstruct_ << " " << current_job_ << " " << curr_jobid_ << std::endl;
237 #ifdef BOINC
238  if (protocols::boinc::Boinc::worker_is_finished( current_nstruct_-1 )) {
239  return false;
240  }
241 #endif
242  if( current_job_ > jobs_.size() ) return false;
243  if( current_nstruct_ > jobs_[ current_job_ ]->nstruct() ) {
244  current_nstruct_ = 1;
245  current_job_ += 1;
246  curr_jobid_ += 1;
247  }
248  if( current_job_ > jobs_.size() ) return false;
249  if( !overwrite_ && is_finished( jobs_[ current_job_ ], current_nstruct_ ) ) {
250  current_nstruct_ += 1;
251  curr_jobid_ += 1;
252  continue;
253  }
254  if ( nproc_ && numeric::mod( curr_jobid_, nproc_ ) != ( proc_id_ - 1 ) ) {
255  current_nstruct_ += 1;
256  continue; //only process stuff that is assigned to this Distributor
257  }
258  return true; // the pair (current_job_, current_nstruct_) represent a job that needs doing.
259  }
260  return false; // make compiler happy
261 }
262 #endif
263 
264 ///@details
265 /// If overriden by a subclass, it MUST call the superclass implementation.
266 void BaseJobDistributor::startup()
267 {
268  if( is_started_ )
269  basic::Error() << "Distributor already started, don't call startup() again!" << std::endl;
270  else {
271  checkpoint_read();
272 
273 #ifdef USEMPI
274  /// assume that a call to core_init(argv,argc) has already happened, and that MPI_Init has happened;
275  runtime_assert( MPI_has_been_initialized() );
276  MPI_Comm_rank (MPI_COMM_WORLD, &mpi_rank_);/* get current process id */
277  MPI_Comm_size (MPI_COMM_WORLD, &mpi_nprocs_);/* get number of processes */
278 #endif
279 
280 #ifdef BOINC
282 #endif
283 
284  is_started_ = true;
285  }
286 }
287 
288 ///@details
289 /// If overriden by a subclass, it MUST call the superclass implementation.
290 void BaseJobDistributor::shutdown()
291 {
292  if( !is_started_ )
293  basic::Error() << "Distributor not started or already stopped, don't call shutdown() again!" << std::endl;
294  else {
295  checkpoint_clear();
296  is_started_ = false;
297  }
298 
299 #ifdef USEMPI
300  JobDistributorTracer << "Node " << mpi_rank_ << " -- ready to call mpi finalize" << std::endl;
301  /// No other MPI calls may be made after this call
302  MPI_Barrier( MPI_COMM_WORLD ); // make all nodes reach this point together.
303  MPI_Finalize();
304 #endif
305 
306 #ifdef BOINC
307  bool shuffle_mode = basic::options::option[ basic::options::OptionKeys::run::shuffle ].user() ;
308  if( shuffle_mode ){
309  protocols::boinc::Boinc::worker_finish_summary( curr_jobid_, curr_jobid_, curr_jobid_ );
310  }else{
311  protocols::boinc::Boinc::worker_finish_summary( current_nstruct_, current_nstruct_, jobs_.size() );
312  }
313  protocols::boinc::Boinc::worker_shutdown(); // Does not return.
314 #endif
315 
316 }
317 
318 
319 ///@details
320 /// If overriden by a subclass, it MUST call the superclass implementation.
321 void BaseJobDistributor::begin_critical_section()
322 {
323 #ifdef BOINC
324  boinc_begin_critical_section();
325 #endif // BOINC
326 }
327 
328 
329 ///@details
330 /// If overriden by a subclass, it MUST call the superclass implementation.
331 void BaseJobDistributor::end_critical_section()
332 {
333 #ifdef BOINC
334  boinc_end_critical_section();
335 #endif // BOINC
336 }
337 
338 
339 ///@details
340 /// Needed to output .in_progress files for multiple processor jobs
341 void BaseJobDistributor::temp_file( std::string const & )
342 {
343 }
344 
345 ///@details
346 /// Needed if a score_map is to be output by the derived class
347 void BaseJobDistributor::dump_pose_and_map( std::string const &, core::pose::Pose & )
348 {
349 }
350 
351 
352 ///@details
353 /// Needed if a score_map is to be output by the derived class
354 void BaseJobDistributor::score_map( std::map < std::string, core::Real > & )
355 {
356 }
357 
358 std::string BaseJobDistributor::get_current_output_tag(){
359  return current_job()->output_tag( current_nstruct() );
360 }
361 
362 std::string BaseJobDistributor::get_output_filename() {
363  return "STUBBED_IN_BASEJOBDISTRIBUTOR";
364 }
365 
366 
367 void BaseJobDistributor::checkpoint_read()
368 {
369  begin_critical_section();
370 #ifdef BOINC
371  if( utility::file::file_exists("rng.state.gz") ) {
372  utility::io::izstream izs("rng.state.gz");
373  numeric::random::RandomGenerator::restoreAllStates(izs);
374  izs.close();
375  }
376 #endif // BOINC
377  end_critical_section();
378 }
379 
380 
381 ///@details Calls to this function are only a suggestion.
382 /// If checkpointing is expensive, this function must track time between calls
383 /// to avoid excessive disk activity, etc.
384 void BaseJobDistributor::checkpoint_write()
385 {
386  begin_critical_section();
387  static time_t last_chkpt_time = time(NULL);
388  time_t time_now = time(NULL);
389  // Refuse to checkpoint more than once a minute, no matter what BOINC wants.
390  // Random number checkpoint files can be large (100k or more uncompressed).
391  if( time_now - last_chkpt_time > 60 ) {
392 #ifdef BOINC
393  // BOINC automatically handles begin/end_critical_section() calls.
394  utility::io::ozstream ozs("rng.state.gz");
395  numeric::random::RandomGenerator::saveAllStates(ozs);
396  ozs.close();
397 #endif // BOINC
399  last_chkpt_time = time_now;
400  }
401  end_critical_section();
402 }
403 
404 
405 void BaseJobDistributor::checkpoint_clear()
406 {
407 #ifdef BOINC
408  if( utility::file::file_exists("rng.state.gz") ) {
409  utility::file::file_delete("rng.state.gz");
410  }
411 #endif // BOINC
412 }
413 
414 BasicJobOP BaseJobDistributor::current_job() { return jobs_[current_job_]; }
415 
416 
417 #ifdef USEMPI
418 
419 /// @brief Check that a call to MPI_Init has occurred already -- for use in runtime_assert statements
420 bool BaseJobDistributor::MPI_has_been_initialized() const {
421  int already_initialized = 0;
422  MPI_Initialized( & already_initialized );
423  return already_initialized != 0;
424 }
425 
426 /// @brief read access to derived classes for MPI related (const) data
427 /// @details must not be called until startup has been called
428 int BaseJobDistributor::mpi_rank() const {
429  runtime_assert( is_started_ );
430  return mpi_rank_;
431 }
432 
433 /// @brief read access to derived classes for MPI related (const) data
434 /// @details must not be called until startup has been called.
435 int BaseJobDistributor::mpi_nprocs() const {
436  runtime_assert( is_started_ );
437  return mpi_nprocs_;
438 }
439 
440 void BaseJobDistributor::master_node_distribute_jobs()
441 {
442  // 1. Accept job requests from other processors, and distribute those jobs
443  // in the form of unsigned integers: job_id and struct_n util all jobs have run out
444 
445  // 2. Accept job requests from other processors, but return job_id "0" as a signal
446  // that no jobs remain, until all mpi_nprocs_ - 1 processors have been informed that no
447  // jobs remain. ie. All of them have finished their jobs.
448 
449  while ( true ) {
450  int node_requesting_job( 0 );
451 
452  JobDistributorTracer << "Master Node -- Waiting for job request; tag_ = " << tag_ << std::endl;
453  MPI_Recv( & node_requesting_job, 1, MPI_INT, MPI_ANY_SOURCE, tag_, MPI_COMM_WORLD, & stat_ );
454  bool const available_job_found = find_available_job();
455 
456  JobDistributorTracer << "Master Node --available job? " << available_job_found << std::endl;
457 
458  Size job_index = ( available_job_found ? current_job_ : 0 );
459  int struct_n = ( available_job_found ? current_nstruct_ : 0 );
460  if ( ! available_job_found ) {
461  JobDistributorTracer << "Master Node -- Spinning down node " << node_requesting_job << std::endl;
462  MPI_Send( & job_index, 1, MPI_UNSIGNED_LONG, node_requesting_job, tag_, MPI_COMM_WORLD );
463  break;
464  } else {
465  JobDistributorTracer << "Master Node -- Assigning job " << job_index << " " << struct_n << " to node " << node_requesting_job << std::endl;
466  MPI_Send( & job_index, 1, MPI_UNSIGNED_LONG, node_requesting_job, tag_, MPI_COMM_WORLD );
467  MPI_Send( & struct_n, 1, MPI_INT, node_requesting_job, tag_, MPI_COMM_WORLD );
468  // ++current_nstruct_; handled now by find_available_job
469  }
470  }
471 
472  // we've just told one node to spin down, and
473  // we don't have to spin ourselves down.
474  Size nodes_left_to_spin_down( mpi_nprocs() - 1 - 1);
475 
476  while ( nodes_left_to_spin_down > 0 ) {
477  int node_requesting_job( 0 );
478  int recieve_from_any( MPI::ANY_SOURCE );
479  MPI_Recv( & node_requesting_job, 1, MPI_INT, recieve_from_any, tag_, MPI_COMM_WORLD, & stat_ );
480  Size job_index( 0 ); // No job left.
481  MPI_Send( & job_index, 1, MPI_UNSIGNED_LONG, node_requesting_job, tag_, MPI_COMM_WORLD );
482  JobDistributorTracer << "Master Node -- Spinning down node " << node_requesting_job << " with " << nodes_left_to_spin_down << " remaining nodes." << std::endl;
483  --nodes_left_to_spin_down;
484  }
485 
486 }
487 
488 bool BaseJobDistributor::request_job_from_master_node()
489 {
490  JobDistributorTracer << "Slave Node " << mpi_rank_ << " -- requesting job from master node; tag_ " << tag_ << std::endl;
491 
492  /// Tell the master node that I'm ready to recieve a new job.
493  MPI_Send( & mpi_rank_, 1, MPI_INT, 0, tag_, MPI_COMM_WORLD );
494 
495  /// Get the index of the job that I'm to perform,
496  MPI_Recv( & current_job_, 1, MPI_UNSIGNED_LONG, 0, tag_, MPI_COMM_WORLD, & stat_ );
497 
498  /// ... and if that job has a valid index, also get the index of the struct_n I'm to work on.
499  /// otherwise, spin down.
500  if ( current_job_ == 0 ) return false;
501 
502  MPI_Recv( & current_nstruct_, 1, MPI_INT, 0, tag_, MPI_COMM_WORLD, & stat_ );
503  runtime_assert( current_nstruct_ != 0 ); // Master node should only return a valid struct_n.
504  return true;
505 }
506 #endif
507 
508 int BaseJobDistributor::get_next_random_range(int low, int high)
509 {
510  // save yourself some random numbers.
511  if ( random_store_.size() == 0 ){
512  for ( int k = 0; k < 1000; k ++ ){
513  random_store_.push_back( numeric::random::uniform() );
514  }
515  random_counter_ = 1;
516  }
517 
518  if( random_counter_ > 1000 ) random_counter_ = 1;
519 
520  if ( low > high ) {
521  int temp;
522  temp = low;
523  low = high;
524  high = temp;
525  }
526 
527  int const range( high - low + 1 );
528 
529  int range_result = static_cast< int >( range * random_store_[random_counter_]) + low;
530  random_counter_ ++;
531  return range_result;
532 }
533 
534 AtomTreeDiffJobDistributor::AtomTreeDiffJobDistributor(JobVector jobs, std::string outfile_name):
535  BaseJobDistributor(jobs),
536  out_(),
537  used_tags_(),
538  last_ref_pose_(NULL),
539  bb_precision_(6),
540  sc_precision_(4),
541  bondlen_precision_(2)
542 {
543  // Add directory path and prefix/suffix (if specified) to plain file name:
544  {
545  utility::file::FileName outfile(outfile_name);
546  std::ostringstream oss;
547  oss << basic::options::option[ basic::options::OptionKeys::out::prefix ]() << outfile.base()
548  << basic::options::option[ basic::options::OptionKeys::out::suffix ]();
549  outfile.base( oss.str() );
550  outfile.path( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() );
551  outfile.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
552  if( basic::options::option[ basic::options::OptionKeys::out::pdb_gz ] && outfile.ext() != "gz" ) {
553  outfile.ext( ".gz" ); // else use input extension
554  }
555  outfile_name = outfile.name();
556  }
557 
558  if( utility::file::file_exists(outfile_name) ) {
559  // load list of tags
560  utility::io::izstream in( outfile_name.c_str() );
561  if ( !in.good() ) {
562  utility_exit_with_message( "Unable to open file: " + outfile_name + "\n" );
563  }
564  while( !in.eof() ) {
565  std::string tmp_tag;
566  std::map< std::string, core::Real > tmp_scores;
567  if( ! core::import_pose::atom_tree_diffs::header_from_atom_tree_diff(in, tmp_tag, tmp_scores) ) break;
568  used_tags_.insert( tmp_tag );
569  }
570  in.close();
571  // re-open for appending (will fail & exit for gzipped files)
572  out_.open_append( outfile_name.c_str() );
573  } else {
574  out_.open( outfile_name.c_str() );
575  if( basic::options::option[ basic::options::OptionKeys::run::version ] ) {
576  out_ << "# Mini-Rosetta version " << core::minirosetta_svn_version() << " from " << core::minirosetta_svn_url() << "\n";
577  }
578  }
579  if ( !out_.good() ) {
580  utility_exit_with_message( "Unable to open file: " + outfile_name + "\n" );
581  }
582 }
583 
585 
587  std::string const & tag,
588  std::map< std::string, core::Real > const & scores,
589  core::pose::Pose const & ref_pose,
590  core::pose::Pose const & pose
591 )
592 {
593  this->begin_critical_section();
594  if( last_ref_pose_ != &ref_pose ) {
595  std::map< std::string, core::Real > empty_scores;
596  core::import_pose::atom_tree_diffs::dump_reference_pose(out_, "%REF%_"+tag, empty_scores, ref_pose);
597  last_ref_pose_ = &ref_pose;
598  }
599  if( used_tags_.find(tag) != used_tags_.end() )
600  basic::Error() << "Tag " << tag << " already exists in silent file; writing structure anyway..." << std::endl;
602  used_tags_.insert(tag);
603  // Can't flush compressed streams -- results in file truncation
604  if ( out_.uncompressed() ) out_.flush();
605  this->end_critical_section();
606 }
607 
608 ///@brief Sets number of digits used in writing atomtree diff.
610  int bb_precision,
611  int sc_precision,
612  int bondlen_precision
613 )
614 {
615  bb_precision_ = bb_precision;
616  sc_precision_ = sc_precision;
617  bondlen_precision_ = bondlen_precision;
618 }
619 
621 {
622  out_.close();
624 }
625 
627 {
628  return ( used_tags_.find(job->output_tag(struct_n)) != used_tags_.end() );
629 }
630 
631 
632 
634  BaseJobDistributor(jobs),
635  scorefile_name_()
636 {
637  if (outfile_name != "none" ) {
638  scorefile_ = true;
639  // set up all the information for the scorefile
640  utility::file::FileName outfile("");
641  std::ostringstream oss;
642  oss << basic::options::option[ basic::options::OptionKeys::out::prefix ]() << outfile.base()
643  << basic::options::option[ basic::options::OptionKeys::out::suffix ]();
644  outfile.base( oss.str() );
645  outfile.path( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() );
646  outfile.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
647  // determine the extension based on fullatom or centroid
648  if( basic::options::option[ basic::options::OptionKeys::out::file::fullatom ] && outfile.ext() != "fasc" ) {
649  outfile.ext( ".fasc" ); // else use input extension
650  } else {
651  outfile.ext( ".sc" );
652  }
653  outfile_name = outfile.name();
654  scorefile_name_ = outfile.name();
655  } else {
656  scorefile_ = false;
657  }
658 }
659 
661 
662 
663 ///@details
664 /// Over riding baseclass to enable inprogress file.
666 {
667  /// this could probably be done with a commandline flag to allow disabling
668  this->enable_inprogress();
669 
670  // calling base class startup
672 }
673 
675 {
676 #ifndef USEMPI
677  utility::file::FileName output_pdb_name;
678  output_pdb_name.path( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() );
679  output_pdb_name.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
680  output_pdb_name.base( tag ); // could contain embedded dots that look ~ like extensions
681  if( basic::options::option[ basic::options::OptionKeys::out::pdb_gz ] ) {
682  output_pdb_name.ext( ".pdb.gz" );
683  } else {
684  output_pdb_name.ext( ".pdb" );
685  }
686  return output_pdb_name.name();
687 
688 #endif
689 #ifdef USEMPI
690  /// Requires that outdir_{0..(nprocs-1)} exist
691  /// burden is on MPI user to create those directories before launching.
692  /// note: node0 does no work, so that dir never gets written to.
693  utility::file::FileName output_pdb_name(tag);
694  output_pdb_name.path(
695  basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() +
696  "/outdir_" + utility::to_string( parent::mpi_rank() ) + "/" );
697  output_pdb_name.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
698  if( basic::options::option[ basic::options::OptionKeys::out::pdb_gz ] ) {
699  output_pdb_name.ext( ".pdb.gz" );
700  } else {
701  output_pdb_name.ext( ".pdb" );
702  }
703  std::cout << "output file name: " << output_pdb_name.name() << std::endl;
704  return output_pdb_name.name();
705 #endif
706 }
707 
708 
710 {
711  utility::io::ozstream tempfile;
712  std::string output_tag = get_output_filename( tag );
713  tempfile.open( output_tag + ".in_progress" );
714 }
715 
717  std::string const & tag,
718  core::pose::Pose & pose
719 )
720 {
721  if( BaseJobDistributor::nooutput() ) return;
722 
723  this->begin_critical_section();
724  std::string outfile_name = this->get_output_filename(tag);
725  utility::io::ozstream out( outfile_name.c_str() );
726  if ( !out.good() ) {
727  utility_exit_with_message( "Unable to open file: " + outfile_name + "\n" );
728  }
730  dump_scores(out, tag, pose);
731  out.close();
732 
733  if ( utility::file::file_exists( outfile_name + ".in_progress" ) ) {
734  utility::file::file_delete( outfile_name + ".in_progress" );
735  }
736 
737  if ( scorefile_ ) {
738  std::string name ("");
739  if ( basic::options::option[ basic::options::OptionKeys::out::file::o ].user() ) {
740  name = scorefile_name_.base()+basic::options::option[ basic::options::OptionKeys::out::file::o ]()+"."+scorefile_name_.ext();
741  } else {
742  name = scorefile_name_.base()+"score."+scorefile_name_.ext();
743  }
745  sfd.write_pose( pose, score_map_, outfile_name );
746  }
747  this->end_critical_section();
748 }
749 
750 bool PlainPdbJobDistributor::is_finished( BasicJobOP const & job, int struct_n )
751 {
752  if( BaseJobDistributor::ignorefinished() ) return false;
753  bool file_exists (false);
754  std::string filename ( get_output_filename(job->output_tag(struct_n))+".in_progress" );
755  if ( utility::file::file_exists(filename) ) {
756  file_exists = true;
757  } else if ( utility::file::file_exists( get_output_filename(job->output_tag(struct_n)) ) ) {
758  file_exists = true;
759  }
760  return file_exists;
761 }
762 
763 
764 /// @details In order for this to work as expected, the Pose's cached energies
765 /// must match up with the (current) conformation.
766 /// A good time to do this is at the end of your protocol's apply() method:
767 /// scorefxn( pose );
768 /// scorefxn.accumulate_residue_total_energies( pose );
770  utility::io::ozstream & out,
771  std::string const & tag,
772  core::pose::Pose & pose
773 )
774 {
775  // Which score terms to use
776  core::scoring::EnergyMap weights = pose.energies().weights();
777  typedef utility::vector1<core::scoring::ScoreType> ScoreTypeVec;
778  ScoreTypeVec score_types;
779  for(int i = 1; i <= core::scoring::n_score_types; ++i) {
781  if ( weights[ii] != 0 ) score_types.push_back(ii);
782  }
783  // This version is formatted for easy parsing by R, Excel, etc.
784  out << "# All scores below are weighted scores, not raw scores.\n";
785  out << "#BEGIN_POSE_ENERGIES_TABLE " << tag << "\n";
786  out << "label";
787  for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
788  out << " " << name_from_score_type(*ii);
789  out << " total\n";
790  out << "weights";
791  for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
792  out << " " << weights[*ii];
793  out << " NA\n";
794  out << "pose";
795  core::Real pose_total = 0.0;
796  for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii) {
797  core::Real score = (weights[*ii] * pose.energies().total_energies()[ *ii ]);
798  out << " " << score;
799  pose_total += score;
800  }
801  out << " " << pose_total << "\n";
802  for(core::Size j = 1, end_j = pose.total_residue(); j <= end_j; ++j) {
803  core::Real rsd_total = 0.0;
804  out << pose.residue(j).name() << "_" << j;
805  for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii) {
806  core::Real score = (weights[*ii] * pose.energies().residue_total_energies(j)[ *ii ]);
807  out << " " << score;
808  rsd_total += score;
809  }
810  out << " " << rsd_total << "\n";
811  }
812  out << "#END_POSE_ENERGIES_TABLE " << tag << "\n";
813  // This version uses YAML instead -- hard to read by eye, requires scripts to process.
814  //basic::EmitterOP yaml = new basic::YamlEmitter(out);
815  //yaml->start_doc(); // This breaks the output into chunks that fit in memory, yay!
816  //yaml->start_map(tag);
817  //yaml->write("tag", tag); // redundant, but Charlie prefers it here too
818  //yaml->write("total_score", total_score);
819  //yaml->start_list("score_names", false);
820  //for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
821  // yaml->write(name_from_score_type(*ii));
822  //yaml->end_list();
823  //yaml->start_list("score_weights", false);
824  //for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
825  // yaml->write(scorefxn.get_weight(*ii));
826  //yaml->end_list();
827  //yaml->start_list("scores_raw", false);
828  //for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
829  // yaml->write(pose.energies().total_energies()[ *ii ]);
830  //yaml->end_list();
831  //yaml->start_list("scores_weighted", false);
832  //for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
833  // yaml->write(scorefxn.get_weight(*ii) * pose.energies().total_energies()[ *ii ]);
834  //yaml->end_list();
835  //yaml->start_map("per_res_weighted");
836  //for(core::Size j = 1, end_j = pose.total_residue(); j <= end_j; ++j) {
837  // std::ostringstream resname; resname << pose.residue(j).name() << " " << j;
838  // yaml->start_list(resname.str(), false);
839  // for(ScoreTypeVec::iterator ii = score_types.begin(), end_ii = score_types.end(); ii != end_ii; ++ii)
840  // yaml->write(scorefxn.get_weight(*ii) * pose.energies().residue_total_energies(j)[ *ii ]);
841  // yaml->end_list();
842  //}
843  //yaml->end_map();
844  //yaml->end_map();
845  ////yaml->end();
846 }
847 
849  BaseJobDistributor(jobs),
850  rawfile_name_(), used_tags_()
851 {
852  utility::file::FileName outfile(outfile_name);
853  std::ostringstream oss;
854  oss << basic::options::option[ basic::options::OptionKeys::out::prefix ]() << outfile.base()
855  << basic::options::option[ basic::options::OptionKeys::out::suffix ]();
856  outfile.base( oss.str() );
857  outfile.path( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() );
858  outfile.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
859  outfile_name = outfile.name();
860  rawfile_name_ = outfile.name();
861 
864  core::io::raw_data::StructureMap::const_iterator iter;
867  for ( i = used_tags_.begin(); i != used_tags_.end(); ++i ) {
868  JobDistributorTracer << *i << std::endl;
869  }
870 }
871 
873 
875  std::string const & tag,
876  core::pose::Pose & pose
877 )
878 {
879  this->begin_critical_section();
880  std::string output_tag = get_output_filename( tag );
881  bool fa = basic::options::option[ basic::options::OptionKeys::out::file::fullatom ];
882 
884  dfd.write_pose( pose, score_map_, output_tag, fa );
885  this->end_critical_section();
886 }
887 
889 {
890 
891 #ifndef USEMPI
892  utility::file::FileName output_pdb_name(tag);
893  output_pdb_name.path( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() );
894  output_pdb_name.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
895  return output_pdb_name.name();
896 #endif
897 #ifdef USEMPI
898  /// Requires that outdir_{0..(nprocs-1)} exist
899  /// burden is on MPI user to create those directories before launching.
900  /// note: node0 does no work, so that dir never gets written to.
901  utility::file::FileName output_pdb_name(tag);
902  output_pdb_name.path(
903  basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().path() +
904  "/outdir_" + utility::to_string( parent::mpi_rank() ) + "/" );
905  output_pdb_name.vol( basic::options::option[ basic::options::OptionKeys::out::path::pdb ]().vol() );
906  std::cout << "output file name: " << output_pdb_name.name() << std::endl;
907  return output_pdb_name.name();
908 #endif
909 }
910 
912 { return "D_" + ObjexxFCL::right_string_of(struct_n, TAG_NUM_FORMAT_LENGTH, '0'); }
913 
914 bool PlainRawJobDistributor::is_finished(BasicJobOP const & job, int struct_n )
915 {
916  std::string output_tag = get_output_filename(job->output_tag(struct_n));
917  bool already_processed = false;
919  for ( i = used_tags_.begin(); i != used_tags_.end(); ++i ) {
920  if( (*i) == output_tag ) {
921  already_processed = true;
922  JobDistributorTracer << "Tag: " << output_tag << " " << job->output_tag(struct_n) <<
923  " - already processed" << std::endl;
924  break;
925  }
926  }
927  return already_processed;
928 }
929 
930 
932  BaseJobDistributor(jobs),
933  used_tags_()
934 {
935  ///... relocated reading of silent files to startup()
936 }
937 
939 
941  BasicJobOP const & job,
942  int const & struct_n,
943  bool const & /*fullatom*/,
944  core::pose::Pose & pose
945 )
946 {
947  if( BaseJobDistributor::nooutput() ) return;
948 
949  this->begin_critical_section();
950  std::string silent_file = get_output_filename();
951  std::string output_tag = get_output_tag( job, struct_n );
952 
953  using namespace core::io::silent;
956  ss->fill_struct( pose, output_tag );
957  sfd->write_silent_struct( *ss, silent_file );
958  this->end_critical_section();
959 }
960 
962  std::string silent_file = basic::options::option[ basic::options::OptionKeys::out::file::silent ]();
963 
964 #ifdef USEMPI
965  // attach mpi rank to out files
966  size_t lastslash = silent_file.find_last_of("/\\");
967  size_t lastdot = silent_file.find_last_of('.');
968 
969  if ( !basic::options::option[ basic::options::OptionKeys::out::path::mpi_rank_dir ]() ) {
970  if ( lastdot == silent_file.npos || (lastslash > lastdot && lastslash != silent_file.npos) ) {
971  silent_file = silent_file+"_"+utility::to_string( parent::mpi_rank() );
972  } else {
973  silent_file = silent_file.substr( 0,lastdot )+"_"+utility::to_string( parent::mpi_rank() )+silent_file.substr( lastdot );
974  }
975  } else {
976  if ( lastslash == silent_file.npos) {
977  silent_file = utility::to_string( parent::mpi_rank() )+"/"+silent_file;
978  } else {
979  silent_file = silent_file.substr( 0,lastslash )+"/"+utility::to_string( parent::mpi_rank() )+silent_file.substr( lastslash );
980  }
981  }
982 #endif
983 
984  return silent_file;
985 }
986 
987 
989 
990  // calling base class startup
992 
993  //this call requires that startup() has been called.... moved from constructor
994  std::string const silent_filename = get_output_filename();
995 
996  if (!utility::file::file_exists( silent_filename )) return;
998  core::io::silent::Structure_Map::const_iterator iter;
999  used_tags_ = sfd.read_tags_fast( silent_filename );
1001  for ( i = used_tags_.begin(); i != used_tags_.end(); ++i ) {
1002  JobDistributorTracer << *i << std::endl;
1003  }
1004 }
1005 
1007 {
1010 }
1011 
1013 {
1014  std::string querytag = job->output_tag(struct_n);
1015  bool found = ( std::find( used_tags_.begin(), used_tags_.end(), querytag ) != used_tags_.end() );
1016  if ( found ) return found;
1017  // compare string without the first two chars as they might be changed from "S_" to "F_"
1018  querytag = get_output_tag( job, struct_n );
1019  // this might cause problems ... if we don't have tags longer than 2 characters...
1020  querytag = querytag.substr(2);
1021  for ( core::Size i = 1; i <= used_tags_.size(); ++i ) {
1022  if ( used_tags_[i].substr(2) == querytag ) {
1023  found = true;
1024  return found;
1025  }
1026  }
1027  return found;
1028 }
1029 
1030 
1032  int const & /*struct_n*/,
1033  core::io::silent::SilentStruct & silent_struct
1034 )
1035 {
1036  this->begin_critical_section();
1037  std::string silent_file = get_output_filename();
1038 
1039  // std::string output_tag = get_output_tag( struct_n );
1040  // silent_struct.decoy_tag( output_tag );
1042  sfd->write_silent_struct( silent_struct, silent_file );
1043  this->end_critical_section();
1044 }
1045 
1048 )
1049 {
1050  this->begin_critical_section();
1051  std::string silent_file = get_output_filename();
1052 
1053  // std::string output_tag = get_output_tag( struct_n );
1054  // silent_struct.decoy_tag( output_tag );
1055  sfd.write_all( silent_file );
1056  this->end_critical_section();
1057 }
1058 
1059 ///@details override base class function to
1062 }
1063 
1064 ///@details returns an output tag generated as follows
1065 /// "S_" + the current jobs tag + "option[ user_tag ]" + nstruct
1067 {
1068  std::string const prefix( "S" );
1069 
1070  std::string number("");
1071  //why not:
1072  // if ( job->nstruct() > 1 ) { causes problems ... probably in query_tag
1073  number = "_"+ ObjexxFCL::right_string_of(struct_n, TAG_NUM_FORMAT_LENGTH, '0');
1074  // }
1075 
1076  std::string itag( job->input_tag() );
1077  if ( itag.size() ) itag = "_" + itag;
1078 
1079  std::string user_tag("");
1080  if ( basic::options::option[ basic::options::OptionKeys::out::user_tag ].user() ) {
1081  user_tag = "_" + basic::options::option[ basic::options::OptionKeys::out::user_tag ];
1082  }
1083 
1084  return prefix + itag + user_tag + number;
1085 
1086 }
1087 
1088 
1089 }
1090 }