diff --git a/src/cats/cats.c b/src/cats/cats.c index 7ba95d8ea37d87dba57cf1cd5bd2b26c404ee191..543cf9f77adc98781845eeb106a1a2bf99367a56 100644 --- a/src/cats/cats.c +++ b/src/cats/cats.c @@ -83,7 +83,7 @@ int main(int argc, char **argv) print_version_info(); print_runtime_information(argc, argv); struct program_options options = check_cats_main_arguments(argc, argv); - logging_initialize(options.default_log_level, &global.time_info); + logging_initialize(options.default_log_level, &global.time_info, options.log_file, options.quiet); #ifdef USEMPI mpi_update(); #endif @@ -115,7 +115,7 @@ int main(int argc, char **argv) cleanup_debugging(&cats_debug, conf); cleanup_configuration(&conf); - + // FIXME cleanup_logging free(global.program_name); fflush(stdout); diff --git a/src/cats/command_line/command_line_info.c b/src/cats/command_line/command_line_info.c index 705cc33f7dd3f508a3f770f71ff0f1603b84ed88..8f93bdc40e79c7536d933042c492c5a570f45906 100644 --- a/src/cats/command_line/command_line_info.c +++ b/src/cats/command_line/command_line_info.c @@ -61,12 +61,22 @@ void print_usage(const char *name, const char *error_msg) " -h, --help Show this message\n"); fprintf(stderr, " -v, --version Show version information\n"); + fprintf(stderr, + " -q, --quiet Don't output logging output to console (log file is not affected)\n"); fprintf(stderr, " -l, --log-level=<level> Default log level (default info). Allowed values: debug, info, important, warning, error\n"); fprintf(stderr, " --%s Output additional information in JSON format to stderr, prefixed with 'JSON::' ( e.g. for use with a GUI)\n", OPTION_JSON_NAME); + + fprintf(stderr, + " --%s <logfile> Save program output to log file <log-file>\n", + OPTION_LOG_FILE_NAME); + + fprintf(stderr, + " --%s <summary-file> Save a list of output filenames to the csv file <summary-file>\n", + OPTION_SUMMARY_FILE_NAME); fprintf(stderr, "\n"); fprintf(stderr, "[Hybrid mode only] Scale factor options:\n"); @@ -88,8 +98,7 @@ void print_usage(const char *name, const char *error_msg) " --%s <years> Override simulation length of scale factor test " "(default: 10000) \n", OPTION_SCALE_LAMBDA_YEARS_NAME); - fprintf(stderr, " --%s Run a simulation on a virtual suitability grid", OPTION_SCALE_GRADIENT_NAME); - + fprintf(stderr, " --%s Run a simulation on a virtual suitability grid\n", OPTION_SCALE_GRADIENT_NAME); fprintf(stderr, "\nRandom number options:\n"); fprintf(stderr, " --%s Which fraction [0.0, 1.0] of random quantities is rounded instead of drawn from a poisson distribution. Default %f\n", diff --git a/src/cats/command_line/command_line_options.c b/src/cats/command_line/command_line_options.c index 3cfaf27e3bc24f5864f8d4bac5d4e021d1aee271..d49f242f367316dab1b3917ab53c14998e67ce4c 100644 --- a/src/cats/command_line/command_line_options.c +++ b/src/cats/command_line/command_line_options.c @@ -35,10 +35,12 @@ static struct option longopts[] = { {"log-level", required_argument, NULL, 'l',}, {"version", no_argument, NULL, 'v',}, {"help", no_argument, NULL, 'h',}, + {"quiet", no_argument, NULL, 'q'}, {OPTION_SCALE_LAMBDA_ONLY_NAME, no_argument, NULL, OPTION_SCALE_LAMBDA_ONLY}, {OPTION_SCALE_LAMBDA_TEST_NAME, no_argument, NULL, OPTION_SCALE_LAMBDA_TEST}, - {OPTION_SCALE_GRADIENT_NAME, no_argument, NULL, OPTION_SCALE_GRADIENT}, - + {OPTION_SCALE_GRADIENT_NAME, no_argument, NULL, OPTION_SCALE_GRADIENT}, + {OPTION_LOG_FILE_NAME, required_argument, NULL, OPTION_LOG_FILE}, + {OPTION_SUMMARY_FILE_NAME, required_argument, NULL, OPTION_SUMMARY_FILE}, {OPTION_JSON_NAME, no_argument, NULL, OPTION_JSON}, {OPTION_DEBUG_MPI_NAME, no_argument, NULL, OPTION_DEBUG_MPI}, {OPTION_SCALE_LAMBDA_CC_NAME, required_argument, NULL, OPTION_SCALE_LAMBDA_CC}, @@ -47,7 +49,7 @@ static struct option longopts[] = { {OPTION_DEBUG_CONFIG_UNUSED_NAME, no_argument, NULL, OPTION_DEBUG_CONFIG_UNUSED}, {OPTION_DEBUG_CONFIG_UNSPECIFIED_NAME, no_argument, NULL, OPTION_DEBUG_CONFIG_UNSPECIFIED}, {OPTION_DEBUG_LAMBDA_NAME, no_argument, NULL, OPTION_DEBUG_LAMBDA}, - {OPTION_DEBUG_VR_NAME, no_argument, NULL, OPTION_DEBUG_VR}, + {OPTION_DEBUG_VR_NAME, no_argument, NULL, OPTION_DEBUG_VR}, {OPTION_POISSON_DAMPENING_NAME, required_argument, NULL, OPTION_POISSON_DAMPENING}, {OPTION_POISSON_DAMPENING_MIN_NAME, required_argument, NULL, OPTION_POISSON_DAMPENING_MIN}, @@ -63,6 +65,9 @@ struct program_options check_cats_main_arguments(int argc, char **argv) { struct program_options options = { .replicate = 0, + .summary_file = NULL, + .log_file = NULL, + .quiet = false, .direct_scale_factor = -1, .default_log_level = LOG_INFO, .lambda_test = false, @@ -88,7 +93,7 @@ struct program_options check_cats_main_arguments(int argc, char **argv) int error = 0; // FIXME unify error messages, start with Error: - while ((opt = getopt_long(argc, argv, "s:r:l:v:ho:", + while ((opt = getopt_long(argc, argv, "qs:r:l:v:ho:", longopts, &optind)) != -1) { bool success; @@ -107,6 +112,9 @@ struct program_options check_cats_main_arguments(int argc, char **argv) success = string_to_double(optarg, &options.direct_scale_factor); if (!success) { log_message(LOG_WARNING, "unable to convert %s to number", optarg); } break; + case 'q': + options.quiet = true; + break; case 'l': @@ -142,6 +150,9 @@ struct program_options check_cats_main_arguments(int argc, char **argv) case OPTION_SCALE_LAMBDA_TEST: options.lambda_test = true; break; + case OPTION_SUMMARY_FILE: + options.summary_file = strdup(optarg); + break; case OPTION_SCALE_LAMBDA_CC: conversion_success = string_to_integer(optarg, &options.lambda_cc); if (!conversion_success) { @@ -207,6 +218,10 @@ struct program_options check_cats_main_arguments(int argc, char **argv) error += 1; } break; + case OPTION_LOG_FILE: + options.log_file = strdup(optarg); + break; + case OPTION_POISSON_DAMPENING_MIN: conversion_success = string_to_float(optarg, &value); if (conversion_success) { diff --git a/src/cats/command_line/command_line_options.h b/src/cats/command_line/command_line_options.h index 7f12f3623bc0a7e1740a117bd1ea74259e084ada..c8053185e784c9424ec33eae4455011f46a55cd7 100644 --- a/src/cats/command_line/command_line_options.h +++ b/src/cats/command_line/command_line_options.h @@ -47,6 +47,11 @@ #define OPTION_DEBUG_VR 5040 #define OPTION_DEBUG_VR_NAME "debug-vital-rates" +#define OPTION_LOG_FILE 1111 +#define OPTION_LOG_FILE_NAME "log-file" + +#define OPTION_SUMMARY_FILE 1112 +#define OPTION_SUMMARY_FILE_NAME "summary-file" #define OPTION_JSON 8000 #define OPTION_JSON_NAME "json" @@ -81,6 +86,9 @@ struct program_options { + char *summary_file; + char *log_file; + bool quiet; char *configuration_file; int32_t replicate; bool no_input_rasters_required; diff --git a/src/cats/configuration/configuration.c b/src/cats/configuration/configuration.c index 899d6f9e2302479a760da94fb77369028017a6f6..eb3ca901e97a896bd3412c402d91dbf8d647dba9 100644 --- a/src/cats/configuration/configuration.c +++ b/src/cats/configuration/configuration.c @@ -217,6 +217,10 @@ void cleanup_configuration(struct cats_configuration **conf_orig) struct cats_configuration *conf = *conf_orig; // THIS HAS TO BE THE FIRST ENTRY cleanup_module_registry(&conf->modules); + if (conf->summary_file) { + fclose(conf->summary_file); + free(conf->summary_file_name); + } if (conf->statsfile_global) fclose(conf->statsfile_global); free(conf->file_content); diff --git a/src/cats/configuration/configuration.h b/src/cats/configuration/configuration.h index 4d6c1559035180d471168487337da11f0c1a8a02..15542b32603c58d418b5d51d210939d9ec800738 100644 --- a/src/cats/configuration/configuration.h +++ b/src/cats/configuration/configuration.h @@ -124,7 +124,12 @@ struct cats_environment_collection { /// @brief Contains the configuration and state of the simulation struct cats_configuration { + char *output_directory; + char *summary_file_name; + FILE *summary_file; + char *log_file_name; + bool quiet; struct cats_global *global; struct program_options command_line_options; bool debug_enabled; diff --git a/src/cats/configuration/load_configuration.c b/src/cats/configuration/load_configuration.c index 8a8e21fdfef53a93a2168a8a26d30b924612982b..8cb7da8df987b67c0cba6c743f35e107fb8e5a68 100644 --- a/src/cats/configuration/load_configuration.c +++ b/src/cats/configuration/load_configuration.c @@ -66,7 +66,16 @@ load_configuration_from_file(const char *filename, const struct program_options // create empty configuration struct cats_configuration *conf = new_configuration(); - + conf->quiet = command_line_options->quiet; + conf->log_file_name = command_line_options->log_file; + conf->summary_file = NULL; + conf->summary_file_name = command_line_options->summary_file; + if (conf->summary_file_name) { + conf->summary_file = fopen(conf->summary_file_name, "w"); + ENSURE_FILE_OPENED(conf->summary_file, conf->summary_file_name) + fprintf(conf->summary_file, "type,path,year\n"); + if (conf->log_file_name) fprintf(conf->summary_file, "log,%s,\n",conf->log_file_name); + } #ifdef USEMPI mpi_setup(conf); #endif diff --git a/src/cats/data/species_parameters.c b/src/cats/data/species_parameters.c index 1f7d7c237a0e4a6627cc52ba07480b54ed313bba..62b2eca1c0c665418756cfea7a2c7c4d075ec19f 100644 --- a/src/cats/data/species_parameters.c +++ b/src/cats/data/species_parameters.c @@ -54,6 +54,7 @@ void init_cats_species_param(struct cats_species_param *param) param->initial_population.suitability_threshold = 0.0; param->initial_population.set_to_cc = true; param->initial_population.adjusted = false; + init_cats_vital_rates(param->vital_rates); } \ No newline at end of file diff --git a/src/cats/grids/cats_grid.c b/src/cats/grids/cats_grid.c index 5e0fa8ca5119dbeec56b3c1372023bf6494d6332..8f71679196c73908c4664151dc5ec5c6a3ee9249 100644 --- a/src/cats/grids/cats_grid.c +++ b/src/cats/grids/cats_grid.c @@ -343,6 +343,7 @@ void initialize_grid_stats(struct cats_grid *grid, struct cats_configuration *co remove(filename); grid->stats.file = fopen(filename, "a+"); ENSURE_FILE_OPENED(grid->stats.file, filename) + if (conf->summary_file) fprintf(conf->summary_file, "grid-stats,%s,\n",filename); free(filename); write_grid_stats(conf, grid, true); fflush(grid->stats.file); diff --git a/src/cats/grids/gdal_save.c b/src/cats/grids/gdal_save.c index 64479fac0aac2657ce0e39d656bb756c74b47c33..e86cd34f99aa7503e129fd62da29ef80d5bfe657 100644 --- a/src/cats/grids/gdal_save.c +++ b/src/cats/grids/gdal_save.c @@ -70,6 +70,8 @@ void *save_population_to_gdal(struct cats_grid *grid, struct cats_configuration (cats_dt_population) get_vital_rate_maximum(&grid->param.carrying_capacity)); fflush(stderr); } + if (conf->summary_file) fprintf(conf->summary_file, "population,%s,%d\n",filename, conf->time.year_current); + free(filename); return 0; } diff --git a/src/cats/modules/load_module.c b/src/cats/modules/load_module.c index 814b4b13b0d5595b0cb9519f1aa67aed461730fd..a56e9b12a95d7d2b576d1dbdfd4b3e9f4c41617c 100644 --- a/src/cats/modules/load_module.c +++ b/src/cats/modules/load_module.c @@ -107,7 +107,7 @@ int32_t register_module(struct cats_configuration *conf, const char *module_name int32_t module_id = conf->modules.count; CATS_MODULE_ID_INTERNAL = module_id; CATS_MODULE_DATA_INTERNAL = module_data; - logging_initialize(conf->command_line_options.default_log_level, &conf->global->time_info); + logging_initialize(conf->command_line_options.default_log_level, &conf->global->time_info, conf->log_file_name, conf->quiet); logging_set_module_name(module_name); conf->modules.module[module_id].flags = module_flags; diff --git a/src/cats/stats/global_stats.c b/src/cats/stats/global_stats.c index 63e771a614d763661e8c272ce0a97c4641b7f2fa..5e26d55d38610dfe782765e20f6b9f4eb377d9da 100644 --- a/src/cats/stats/global_stats.c +++ b/src/cats/stats/global_stats.c @@ -49,6 +49,8 @@ void initialize_global_stats(struct cats_configuration *conf) conf->statsfile_global = fopen(filename, "a+"); ENSURE_FILE_OPENED(conf->statsfile_global, filename) + if (conf->summary_file) fprintf(conf->summary_file, "global-stats,%s,\n",filename); + write_global_stats(conf, NULL, true); diff --git a/src/logging/logging.c b/src/logging/logging.c index da0973f6dc2e3e348a75a4d9abf6aefa1f16cfa6..bfd77584f85631d704fe620bb238be355d1a27b0 100644 --- a/src/logging/logging.c +++ b/src/logging/logging.c @@ -30,13 +30,17 @@ #include "logging.h" #include "memory/cats_memory.h" #include "cats_time/cats_time.h" +#include "misc/misc.h" enum cats_log_level internal_current_log_level = LOG_INFO; int32_t logging_mpi_rank = -1; struct cats_time cats_logging_start_time; +FILE *cats_log_file = NULL; +char *cats_log_file_name = NULL; const char *logging_module_name = NULL; bool time_initialized = false; +bool logging_quiet = false; const char *get_log_level_name(enum cats_log_level level) @@ -106,15 +110,21 @@ void set_log_level(enum cats_log_level new_level) // - mpi world rank can be added later // FIXME: if start_time is NULL, generate -void logging_initialize(enum cats_log_level level, const struct cats_time *start_time) +void logging_initialize(enum cats_log_level level, const struct cats_time *start_time, const char *log_file_name, bool quiet) { set_log_level(level); - + logging_quiet = quiet; if (start_time != NULL) { cats_logging_start_time = *start_time; time_initialized = true; } + if (log_file_name != NULL) { + cats_log_file_name = strdup(log_file_name); + cats_log_file = fopen(log_file_name, "w"); + ENSURE_FILE_OPENED(cats_log_file, cats_log_file_name) + } + } @@ -185,13 +195,15 @@ void log_msg(const char *msg, enum cats_log_level loglevel) if (loglevel < internal_current_log_level) return; if (loglevel == LOG_EMPTY) { - fprintf(stdout, "\n"); + if (! logging_quiet) fprintf(stdout, "\n"); + if (cats_log_file != NULL) fprintf(stdout, "\n"); return; } const char *color = get_log_level_color(loglevel); if (loglevel == LOG_MARK) { - fprintf(stdout, "%s%s%s\n", color, msg, C_RESET); + if (! logging_quiet) fprintf(stdout, "%s%s%s\n", color, msg, C_RESET); + if (cats_log_file != NULL) fprintf(cats_log_file, "%s%s%s\n", color, msg, C_RESET); return; } const char *log_default = "unknown"; @@ -204,22 +216,31 @@ void log_msg(const char *msg, enum cats_log_level loglevel) if (logging_mpi_rank >= 0) { - fprintf(stdout, "(%02d)::", logging_mpi_rank); + if (! logging_quiet) fprintf(stdout, "(%02d)::", logging_mpi_rank); + if (cats_log_file != NULL) fprintf(cats_log_file, "(%02d)::", logging_mpi_rank); } if (time_initialized) { double secs = seconds_monotonic_since(&cats_logging_start_time); - - fprintf(stdout, "% 16.4f::", secs); + if (cats_log_file != NULL) { + fprintf(cats_log_file, "% 16.4f::", secs); + } + if (! logging_quiet) fprintf(stdout, "% 16.4f::", secs); } else { - fprintf(stdout, " ::"); + if (cats_log_file != NULL) { + fprintf(cats_log_file, " ::"); + } + if (! logging_quiet) fprintf(stdout, " ::"); } if (logging_module_name != NULL) { - fprintf(stdout, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET); + if (! logging_quiet) fprintf(stdout, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET); + if (cats_log_file) fprintf(cats_log_file, "%s%s::[%s] %s%s\n", color, loglevel_name, logging_module_name, msg, C_RESET); } else { - fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); + if (! logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); + if (cats_log_file) fprintf(cats_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); + } } @@ -237,10 +258,13 @@ void log_msg_simple(const char *msg, enum cats_log_level loglevel) const char *color = get_log_level_color(loglevel); if (logging_mpi_rank >= 0) { - fprintf(stdout, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET); + if (! logging_quiet) fprintf(stdout, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET); + if (cats_log_file != NULL) fprintf(cats_log_file, "(%02d)%s%s: %s%s", logging_mpi_rank, color, loglevel_name, msg, C_RESET); + } else { + if (! logging_quiet) fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); + if (cats_log_file != NULL) fprintf(cats_log_file, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); - fprintf(stdout, "%s%s::%s%s\n", color, loglevel_name, msg, C_RESET); } } diff --git a/src/logging/logging.h b/src/logging/logging.h index f030add7e07b03272e51ac5ca0615a36f1d61f2e..4ded5f2637a0a71cfffb5a4e1cfb84fb2c2a3650 100644 --- a/src/logging/logging.h +++ b/src/logging/logging.h @@ -23,7 +23,7 @@ #ifndef CATS_LOGGING_H_ #define CATS_LOGGING_H_ - +#include <stdbool.h> #include "cats_defs.h" #include <time.h> #include "cats_time/cats_time.h" @@ -56,7 +56,7 @@ enum cats_log_level { LOG_UNKNOWN }; -void logging_initialize(enum cats_log_level level, const struct cats_time *start_time); +void logging_initialize(enum cats_log_level level, const struct cats_time *start_time, const char *log_file_name, bool quiet); void logging_set_mpi_rank(int mpi_world_rank);