#include "butterflies_stats.h" #include "logging.h" #include "cats_global.h" #include "data/cats_grid.h" #include "modules/module_header.h" #include "butterflies_main.h" #include "inline_overlays.h" #include "inline_population.h" #include "inline.h" #include "butterflies_paths.h" #include "temporal/phase_names.h" #include "temporal/years.h" const char *bf_get_stats_field_name(enum butterfly_stats which) { switch (which) { case BF_STAT_POPULATED_FIT: return "populated_fit"; case BF_STAT_POPULATED_UNFIT: return "populated_unfit"; case BF_STAT_UNPOPULATED_FIT: return "unpopulated_fit"; case BF_STAT_UNPOPULATED_UNFIT: return "unpopulated_unfit"; case BF_STAT_EXCLUDED: return "excluded"; case BF_RANDOM_WALK_DEPOSIT_COUNT: return "random_walk_deposit_count"; case BF_RANDOM_WALK_COUNT: return "random_walk_count"; case BF_RANDOM_WALK_STEP_COUNT: return "random_walk_step_count"; case BF_OUTPUT_STAT_MAX: return "<guard value>"; case BF_STAT_MAX: break; case BF_CELLS_WITH_EGGS: return "cells with eggs"; case BF_CELLS_WITH_EGGS_REMOVED: return "removed cells with eggs"; } log_message(LOG_ERROR, "unknown butterfly stats name with id %d", which); exit_cats(EXIT_FAILURE); } struct string_array *bf_assemble_stats(struct cats_configuration *conf, struct cats_grid *grid, bool header) { struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; assert(module_conf->stats_file != NULL); const int32_t grid_id = grid->id; int module_id = CATS_MODULE_ID; struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data; struct string_array *x = new_string_array(); if (header) { string_array_add(x, "phase"); string_array_add(x, "year"); string_array_add(x, "run"); string_array_add(x, "replicate"); string_array_add(x, "species"); string_array_add(x, "id"); string_array_add(x, "generation"); for (enum butterfly_stats which = BF_STAT_MIN; which < BF_OUTPUT_STAT_MAX; which++) { const char *name = bf_get_stats_field_name(which); string_array_add(x, name); } } else { string_array_add(x, get_phase_shortname(conf->time.phase)); string_array_add_int64(x, get_phase_year_abs(conf), NULL); string_array_add(x, conf->run_name); string_array_add_int64(x, conf->simulation.replicate, NULL); string_array_add(x, conf->param[grid_id].species_name); string_array_add_int64(x, grid_id, NULL); string_array_add_int(x, data->generation_current, NULL); for (enum butterfly_stats which = BF_STAT_MIN; which < BF_OUTPUT_STAT_MAX; which++) { int64_t stat_id = module_conf->stat_ids[which]; string_array_add_int64(x, grid->stats.custom_stats[stat_id], NULL); } } return x; } void bf_stats_write(struct cats_configuration *conf, struct cats_grid *grid) { struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; struct string_array *data = NULL; if (module_conf->stats_file == NULL) { char *fn = bf_stats_filename(conf, grid); module_conf->stats_file = fopen(fn, "w"); ENSURE_FILE_OPENED(module_conf->stats_file, fn); free(fn); data = bf_assemble_stats(conf, grid, true); char *string = string_array_paste(data, ","); fprintf(module_conf->stats_file, "%s\n", string); free(string); free_string_array(&data); } data = bf_assemble_stats(conf, grid, false); char *string = string_array_paste(data, ","); fprintf(module_conf->stats_file, "%s\n", string); free(string); free_string_array(&data); } void bf_area_stats_gather(struct cats_grid *grid, struct cats_thread_info *ts) { struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; struct cats_configuration *conf = ts->conf; const int64_t id_excluded = module_conf->stat_ids[BF_STAT_EXCLUDED]; const int64_t id_pop_fit = module_conf->stat_ids[BF_STAT_POPULATED_FIT]; const int64_t id_pop_unfit = module_conf->stat_ids[BF_STAT_POPULATED_UNFIT]; const int64_t id_unpop_fit = module_conf->stat_ids[BF_STAT_UNPOPULATED_FIT]; const int64_t id_unpop_unfit = module_conf->stat_ids[BF_STAT_UNPOPULATED_UNFIT]; const int32_t grid_id = grid->id; const cats_dt_rates ot = grid->param.OT; struct statistics *stats = &ts->stats[grid_id]; const cats_dt_coord start_row = ts->area.start_row; const cats_dt_coord end_row = ts->area.end_row; const cats_dt_coord start_col = ts->area.start_col; const cats_dt_coord end_col = ts->area.end_col; for (cats_dt_coord row = start_row; row < end_row; row++) { for (cats_dt_coord col = start_col; col < end_col; col++) { cats_dt_population pop = get_adult_population(grid, row, col); if (cell_excluded_by_overlay(conf, row, col)) { stats->custom_stats[id_excluded] += 1; if (pop > 0) { log_message(LOG_ERROR, "%s: population > 0 (%d) in excluded cell %d %d", __func__, pop, row, col); exit_cats(EXIT_FAILURE); } continue; } cats_dt_environment suit = get_suitability(grid, row, col); if (pop > 0) { if (suit >= ot) { stats->custom_stats[id_pop_fit] += 1; } else { stats->custom_stats[id_pop_unfit] += 1; } } else { if (suit >= ot) { stats->custom_stats[id_unpop_fit] += 1; } else { stats->custom_stats[id_unpop_unfit] += 1; } } } } }