344 int num_status_lines = 0;
350 bool exception_needs_reset_terminal =
false;
360 std::shared_ptr< HepMC3::GenEvent > buffered_event;
361 std::string cached_generator_state;
363 std::vector< std::shared_ptr<marley::OutputFile> > output_files;
367 std::string config_file_name;
368 if ( !args.empty() ) config_file_name = args.front();
370 bool cfn_empty = config_file_name.empty();
372 if ( cfn_empty || config_file_name.front() ==
'-' )
374 if ( !cfn_empty && config_file_name !=
"-h"
375 && config_file_name !=
"--help" )
377 std::cerr <<
"marley generate: unrecognized option '"
378 << config_file_name <<
"'\n";
381 args.push_front(
"generate" );
386 marley::JSON json = marley::JSON::load_file( config_file_name );
389 std::chrono::system_clock::time_point start_time_point
390 = std::chrono::system_clock::now();
392 std::time_t start_time = std::chrono::system_clock::to_time_t(
395 std::cout <<
"\nMARLEY started on "
396 << put_time( std::localtime(&start_time),
"%c %Z" ) <<
'\n';
398 long num_old_events = 0;
400 marley::JSON ex_set = json.get_object(
"generate",
false );
401 long num_events = ex_set.get_long(
"events", 1e3 );
403 MARLEY_LOG( INFO,
"app" ) <<
"Requested events: " << num_events
404 <<
", configuration file: \"" << config_file_name <<
"\"";
406 int status_update_interval = DEFAULT_STATUS_UPDATE_INTERVAL;
407 if ( ex_set.has_key(
"status_update_interval") ) {
408 const auto& sui = ex_set.at(
"status_update_interval" );
410 int sui_value = sui.to_long( ok );
412 if ( !ok || sui_value < 1 ) {
414 +
" given for the \"status_update_interval\" key in the"
415 " job configuration file" );
417 else status_update_interval = sui_value;
420 if ( ex_set.has_key(
"output") ) {
423 " \"output\" key in the \"generate\" section must have a value that"
424 " is a JSON array." );
425 else for (
const auto& el : output_set.array_range() ) {
426 output_files.push_back( marley::OutputFile::make_OutputFile(el) );
430 std::string out_config_str =
"{ format: \"ascii\","
431 " file: \"events.hepmc3\", mode: \"overwrite\", force: false }";
432 auto out_config = marley::JSON::load( out_config_str );
434 output_files.push_back( marley::OutputFile::make_OutputFile(
440 const int file_lines = ( output_files.size() <= MAX_FILE_STATUS_LINES )
441 ?
static_cast< int >( output_files.size() ) : 1;
442 num_status_lines = 3 + file_lines;
446 terminal_resized =
false;
447 g_fallback_mode =
false;
448 g_status_region_active =
false;
450 std::signal( SIGINT, signal_handler );
451 std::signal( SIGWINCH, sigwinch_handler );
457 std::unique_ptr< marley::Generator > gen;
459 bool need_to_resume =
false;
460 for (
auto& file : output_files ) {
461 if ( file->mode_is_resume() ) {
462 if ( need_to_resume )
throw marley::Error(
"Only one file may be used"
463 " to resume a previous run." );
465 need_to_resume =
true;
466 bool resume_ok = file->resume( gen, num_old_events );
467 if ( !resume_ok )
throw marley::Error(
"Failed to resume previous"
468 " run from the file \"" + file->name() +
'\"' );
473 if ( !need_to_resume ) gen = std::make_unique<marley::Generator>(
474 jc.create_generator() );
478 start_time_point = std::chrono::system_clock::now();
479 start_time = std::chrono::system_clock::to_time_t( start_time_point );
481 exception_needs_reset_terminal =
true;
486 TermSize ts = get_terminal_size();
487 if ( ts.rows == 0 || ts.rows < num_status_lines + 2 ) {
488 enter_fallback_mode();
490 setup_scroll_region( num_status_lines );
494 long ev_count = 1 + num_old_events;
496 auto last_resize_time = std::chrono::steady_clock::time_point{};
498 for (; ev_count <= num_events && !interrupted; ++ev_count) {
504 if ( terminal_resized ) {
505 auto now = std::chrono::steady_clock::now();
506 if ( now - last_resize_time >= RESIZE_DEBOUNCE ) {
507 terminal_resized =
false;
508 last_resize_time = now;
510 TermSize ts = get_terminal_size();
511 if ( ts.rows == 0 || ts.rows < num_status_lines + 2 ) {
512 enter_fallback_mode();
513 }
else if ( g_fallback_mode ) {
514 exit_fallback_mode( num_status_lines );
516 setup_scroll_region( num_status_lines );
521 auto event = gen->create_event();
522 event->set_event_number( ev_count );
530 if ( buffered_event ) {
531 for (
const auto& file : output_files ) {
532 file->write_event( buffered_event.get() );
539 buffered_event = event;
540 cached_generator_state = gen->get_state_string();
542 if ( !g_fallback_mode
543 && ( (ev_count - num_old_events) % status_update_interval == 1
544 || ev_count == num_events
545 || status_update_interval == 1 ) )
547 update_status_bars( ev_count, num_events, num_old_events,
548 start_time_point, output_files, num_status_lines );
560 if ( buffered_event ) {
562 cached_generator_state );
563 for (
const auto& file : output_files ) {
564 file->write_event( buffered_event.get() );
568 reset_terminal( g_fallback_mode ? 0 : num_status_lines );
570 for (
const auto& file : output_files ) {
571 std::cout <<
"Data written to " << file->name() <<
' '
572 << marley_utils::num_bytes_to_string( file->bytes_written() ) <<
'\n';
575 std::chrono::system_clock::time_point end_time_point
576 = std::chrono::system_clock::now();
578 = std::chrono::system_clock::to_time_t( end_time_point );
580 if ( !interrupted ) {
581 MARLEY_LOG( NOTICE,
"app" ) <<
"Generated " << ( ev_count - 1
582 - num_old_events ) <<
" event(s) successfully";
583 std::cout <<
"MARLEY terminated normally on ";
586 MARLEY_LOG( NOTICE,
"app" ) <<
"Generation interrupted after "
587 << ( ev_count - 1 - num_old_events ) <<
" event(s)";
588 std::cout <<
"MARLEY was interrupted by the user on ";
590 std::cout << put_time( std::localtime(&end_time),
"%c %Z" ) <<
'\n';
595 catch (
const std::exception& error ) {
596 if ( exception_needs_reset_terminal && g_status_region_active ) {
597 reset_terminal( g_fallback_mode ? 0 : num_status_lines,
610 if ( buffered_event ) {
612 cached_generator_state );
613 for (
const auto& file : output_files ) {
614 file->write_event( buffered_event.get() );
617 }
catch (
const std::exception& except ) {
618 MARLEY_LOG( WARN,
"app" ) << std::flush <<
"Output of buffered"
619 " MARLEY event and its generator state failed";
620 MARLEY_LOG( ERROR,
"app" ) << except.what();
623 MARLEY_LOG( ERROR,
"app" ) << std::flush << error.what();