diff --git a/src/modules/butterflies/CMakeLists.txt b/src/modules/butterflies/CMakeLists.txt
index e99e173564e7ec84e560963f8ed394201ff04832..5eb11b6d5a4452081c285adf236b7c305d7e2a6d 100644
--- a/src/modules/butterflies/CMakeLists.txt
+++ b/src/modules/butterflies/CMakeLists.txt
@@ -1,4 +1,16 @@
-add_library(cats-butterflies SHARED "" butterflies_actions.c butterflies_actions.h butterflies_vital_rates.c butterflies_vital_rates.h module.h butterflies_dispersal.c butterflies_dispersal.h butterflies_populations.c butterflies_populations.h butterflies_inline.h butterflies_generations.c butterflies_generations.h butterflies_stats.c butterflies_overlays.c butterflies_overlays.h)
+add_library(cats-butterflies SHARED ""
+        butterflies_actions.c butterflies_actions.h
+        butterflies_vital_rates.c butterflies_vital_rates.h
+        module.h
+        butterflies_dispersal.c butterflies_dispersal.h
+        butterflies_populations.c butterflies_populations.h
+        butterflies_inline.h
+        butterflies_generations.c butterflies_generations.h
+        butterflies_stats.c
+        butterflies_overlays.c butterflies_overlays.h
+        butterflies_filenames.c butterflies_filenames.h
+        butterflies_action_helpers.c
+        butterflies_action_helpers.h)
 
 target_include_directories(cats-butterflies PUBLIC ".")
 
@@ -8,10 +20,8 @@ target_sources(cats-butterflies
 
         PUBLIC
 
-
         )
 
 
-
 set_property(TARGET cats-butterflies PROPERTY POSITION_INDEPENDENT_CODE ON)
 target_link_libraries(cats-butterflies cats_logging libcats)
diff --git a/src/modules/butterflies/butterflies_action_helpers.c b/src/modules/butterflies/butterflies_action_helpers.c
new file mode 100644
index 0000000000000000000000000000000000000000..22db214e7612f21d498e094706af134f4e1deaae
--- /dev/null
+++ b/src/modules/butterflies/butterflies_action_helpers.c
@@ -0,0 +1,75 @@
+
+#include "butterflies_action_helpers.h"
+#include "configuration/configuration.h"
+#include "actions/setup_actions.h"
+#include "module.h"
+#include "modules/module_header.h"
+#include "butterflies_actions.h"
+#include "butterflies_main.h"
+
+void bf_add_generation_action(struct cats_configuration *conf, action_function function, const char *name,
+                              int generation)
+{
+        char *result = NULL;
+        int rc = asprintf(&result, "%s (generation %d)", name, generation);
+        asprintf_check(rc);
+        append_action(conf, function, ALL_STAGES, result, module_name);
+        free(result);
+}
+
+void bf_register_actions(struct cats_configuration *conf)
+{
+
+        register_action_function(conf, bf_action_stats_reset, "butterfly_action_reset_stats",
+                                 "resetting butterfly statistics");
+        register_action_function(conf, bf_action_generation_update, "butterfly_action_update_generations",
+                                 "update generations");
+
+        register_action_function(conf, bf_action_generation_finish, "bf_action_generation_finish",
+                                 "update generation");
+        register_action_function(conf, bf_action_generation_start, "bf_action_generation_start",
+                                 "start generation");
+
+
+        register_action_function(conf, bf_action_maturation, "butterfly_action_egg_to_adult",
+                                 "transition eggs to adults");
+
+        register_action_function(conf, bf_action_overlay_update, "butterfly_action_overlay_update",
+                                 "updating overlays");
+
+        register_action_function(conf, bf_action_dispersal, "butterfly_action_dispersal", "egg dispersal");
+        register_action_function(conf, bf_action_save_grid, "bf_action_save_grid", "output");
+        register_action_function(conf, bf_action_stats_gather, "bf_action_stats_gather", "gather stats");
+        register_action_function(conf, bf_action_stats_reset, "bf_action_stats_reset", "reset stats");
+        register_action_function(conf, bf_action_stats_write, "bf_action_stats_write", "write stats");
+}
+
+
+void bf_add_actions(struct cats_configuration *conf)
+{
+        struct conf_data_butterflies *data = CATS_MODULE_DATA;
+
+        printf("MAXIMUM GENERATIONS %d\n", data->generations_max);
+        bf_register_actions(conf);
+
+        list_actions_full(conf);
+
+        append_action(conf, bf_action_stats_reset, ALL_STAGES, "resetting butterfly statistics", module_name);
+        append_action_by_name(conf, "action_load_environments", ALL_STAGES, "environment update", module_name);
+        append_action_by_name(conf, "action_overlay_update", ALL_STAGES, "overlay update", module_name);
+        append_action(conf, bf_action_overlay_update, ALL_STAGES, "updating resource layer", module_name);
+        append_action(conf, bf_action_generation_update, ALL_STAGES, "update generations", module_name);
+
+        for (int32_t generation = data->generations_max; generation > 0; generation--) {
+
+                bf_add_generation_action(conf, bf_action_stats_reset, "reset stats", generation);
+                bf_add_generation_action(conf, bf_action_generation_start, "start generation", generation);
+                bf_add_generation_action(conf, bf_action_maturation, "transition eggs to adults",
+                                         generation);
+                bf_add_generation_action(conf, bf_action_stats_gather, "gather stats", generation);
+                bf_add_generation_action(conf, bf_action_dispersal, "dispersal", generation);
+                bf_add_generation_action(conf, bf_action_save_grid, "output", generation);
+                bf_add_generation_action(conf, bf_action_generation_finish, "finish generation", generation);
+                bf_add_generation_action(conf, bf_action_stats_write, "write stats", generation);
+        }
+}
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_action_helpers.h b/src/modules/butterflies/butterflies_action_helpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd75bfabe5480e05580a0b123f0da838260afae1
--- /dev/null
+++ b/src/modules/butterflies/butterflies_action_helpers.h
@@ -0,0 +1,9 @@
+#ifndef CATS_BUTTERFLIES_ACTION_HELPERS_H
+#define CATS_BUTTERFLIES_ACTION_HELPERS_H
+
+#include "configuration/configuration.h"
+
+void bf_register_actions(struct cats_configuration *conf);
+void bf_add_actions(struct cats_configuration *conf);
+
+#endif //CATS_BUTTERFLIES_ACTION_HELPERS_H
diff --git a/src/modules/butterflies/butterflies_actions.c b/src/modules/butterflies/butterflies_actions.c
index 0fe97aa6b989a6689f20f2386a55d624e1e04ae6..9ae122262f298e669f601a976340181f6df72dcd 100644
--- a/src/modules/butterflies/butterflies_actions.c
+++ b/src/modules/butterflies/butterflies_actions.c
@@ -1,9 +1,6 @@
-
 #include "actions/cats_actions.h"
-#include "actions/setup_actions.h"
 #include "modules/module_header.h"
 #include "butterflies_actions.h"
-#include "module.h"
 #include "butterflies_main.h"
 #include "inline_overlays.h"
 #include "butterflies_populations.h"
@@ -11,29 +8,17 @@
 #include "butterflies_inline.h"
 #include "grids/grid_wrapper.h"
 #include "grids/gdal_save.h"
-#include "paths/output_paths.h"
 #include "paths/paths.h"
 #include "populations/population.h"
-#include "inline_population.h"
 #include "butterflies_generations.h"
 #include "butterflies_dispersal.h"
 #include "butterflies_overlays.h"
+#include "butterflies_filenames.h"
 
 
-inline void increase_custom_stat(struct statistics stats, int64_t stat_id, int64_t by)
-{
-
-}
-
-
-inline void ensure_valid_stat_id(struct statistics stats, int64_t stat_id)
+enum action_status bf_action_stats_reset(struct cats_grid *grid, struct cats_configuration *conf)
 {
-
-}
-
-enum action_status action_butterfly_stats_reset(struct cats_grid *grid, struct cats_configuration *conf)
-{
-        return ACTION_RUN;
+        return action_grid_stats_reset(grid, conf);
 }
 
 
@@ -46,25 +31,22 @@ void grid_butterflies_maturation(struct cats_grid *grid, struct cats_thread_info
         const cats_dt_coord start_col = ts->area.start_col;
         const cats_dt_coord end_col = ts->area.end_col;
 
-
         ts->temp = 0;
         for (cats_dt_coord row = start_row; row < end_row; row++) {
                 for (cats_dt_coord col = start_col; col < end_col; col++) {
 
                         if (cell_excluded_by_overlay(conf, row, col)
-                            || cell_excluded_by_generation(grid, row, col)) {
+                            || bf_cell_excluded_by_generation(grid, row, col)) {
                                 continue;
                         }
-                        butterflies_cell_maturation(grid, ts, row, col, false);
-
-
+                        bf_cell_maturation(grid, ts, row, col, false);
                 }
         }
 
 }
 
 
-void grid_butterflies_dispersal(struct cats_grid *grid, struct cats_thread_info *ts)
+void butterflies_area_dispersal(struct cats_grid *grid, struct cats_thread_info *ts)
 {
         struct cats_configuration *conf = ts->conf;
         const cats_dt_coord start_row = ts->area.start_row;
@@ -73,18 +55,16 @@ void grid_butterflies_dispersal(struct cats_grid *grid, struct cats_thread_info
         const cats_dt_coord start_col = ts->area.start_col;
         const cats_dt_coord end_col = ts->area.end_col;
 
-        // struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
-        //const int module_id = CATS_MODULE_ID;
-        //struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-
         ts->temp = 0;
         ts->temp1 = 0;
         ts->temp2 = 0;
+
+
         for (cats_dt_coord row = start_row; row < end_row; row++) {
                 for (cats_dt_coord col = start_col; col < end_col; col++) {
 
                         if (cell_excluded_by_overlay(conf, row, col)
-                            || cell_excluded_by_generation(grid, row, col)) {
+                            || bf_cell_excluded_by_generation(grid, row, col)) {
                                 continue;
                         }
 
@@ -95,62 +75,18 @@ void grid_butterflies_dispersal(struct cats_grid *grid, struct cats_thread_info
 }
 
 
-void grid_butterflies_kill_adults(struct cats_grid *grid, struct cats_thread_info *ts)
-{
-        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++) {
-                        set_population_ignore_cc(grid, row, col, 0);
-                }
-        }
-}
-
-
-enum action_status action_butterflies_maturation(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_maturation(struct cats_grid *grid, struct cats_configuration *conf)
 {
         threaded_action(&grid_butterflies_maturation, grid, conf, TS_DEFAULT);
 
         return ACTION_RUN;
 }
 
-char *get_butterfly_population_filename(struct cats_configuration *conf, struct cats_grid *grid)
-{
-
-        assert(grid != NULL);
-        assert(conf != NULL);
-        assert(conf->grid_count == 1);
-
-        int module_id = CATS_MODULE_ID;
-        struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-
-
-        struct string_array *path = get_output_directory(conf, "butterfly-adults"); // FIXME MAKE DIRECTORY
-
-        char *extension = get_extension(conf, "adults");
-        struct string_array *name = standard_output_file_name(conf, NULL, NULL, NULL);
-        string_array_add_int(name, data->generation_current, "g%03d");
-
-        char *filename = assemble_filename(path, name, "_", extension);
-
-        free_string_array(&path);
-        free_string_array(&name);
-        free(extension);
-
-        return filename;
-
-
-}
-
 
-enum action_status action_butterflies_save_grid(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_save_grid(struct cats_grid *grid, struct cats_configuration *conf)
 {
         int32_t id = grid->id;
-        char *filename = get_butterfly_population_filename(conf, grid);
+        char *filename = bf_population_filename(conf, grid);
         struct grid_wrapper data = gridwrapper(grid->population, grid->dimension);
         save_grid_to_gdal(&data, GDT_Int32, conf, filename, conf->param[id].species_name);
         free(filename);
@@ -158,57 +94,37 @@ enum action_status action_butterflies_save_grid(struct cats_grid *grid, struct c
 }
 
 
-enum action_status action_butterflies_kill_adults(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_dispersal(struct cats_grid *grid, struct cats_configuration *conf)
 {
-        threaded_action(&grid_butterflies_kill_adults, grid, conf, TS_DEFAULT);
-
-        return ACTION_RUN;
-}
-
+        threaded_action(&butterflies_area_dispersal, grid, conf, TS_DISPERSAL);
+        struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
 
-enum action_status action_butterflies_dispersal(struct cats_grid *grid, struct cats_configuration *conf)
-{
-        threaded_action(&grid_butterflies_dispersal, grid, conf, TS_DISPERSAL);
+        for (enum butterfly_stats which = BF_POPULATED_AT_DISPERSAL; which < BF_STAT_MAX; which++) {
+                int64_t stat_id = module_conf->stat_ids[which];
+                printf("%s: %ld\n", bf_get_stats_field_name(which), grid->stats.stats[stat_id]);
+        }
 
+        exit_cats(EXIT_SUCCESS);
         return ACTION_RUN;
 }
 
 
-enum action_status action_butterflies_output(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_stats_gather(struct cats_grid *grid, struct cats_configuration *conf)
 {
+        threaded_action(&bf_area_stats_gather, grid, conf, TS_DEFAULT);
         return ACTION_RUN;
 }
 
 
-enum action_status action_butterfly_stats_gather(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_stats_write(__attribute__((unused)) struct cats_grid *grid, __attribute__((unused)) struct cats_configuration *conf)
 {
-        struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
-        int64_t excluded_id = module_conf->stat_ids[BF_STAT_EXCLUDED];
-
-        const cats_dt_coord rows = grid->dimension.rows;
-        const cats_dt_coord cols = grid->dimension.cols;
-        for (cats_dt_coord row = 0; row < rows; row++) {
-                for (cats_dt_coord col = 0; col < cols; col++) {
-                        if (cell_excluded_by_overlay(conf, row, col)) {
-                                increase_custom_stat(grid->stats, excluded_id, 1);
-                                continue;
-                        }
-
+        bf_stats_write(conf, grid);
 
-
-                }
-        }
         return ACTION_RUN;
 }
 
-
-enum action_status action_butterfly_stats_write(struct cats_grid *grid, struct cats_configuration *conf)
-{
-        return ACTION_RUN;
-}
-
-
-enum action_status action_butterfly_update_generations(struct cats_grid *grid, struct cats_configuration *conf)
+// only run at the start of the year
+enum action_status bf_action_generation_update(struct cats_grid *grid, struct cats_configuration *conf)
 {
         int module_id = CATS_MODULE_ID;
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
@@ -224,117 +140,38 @@ enum action_status action_butterfly_update_generations(struct cats_grid *grid, s
                 grid->param.initial_population.adjusted = true;
         }
 
-        threaded_action(&area_update_generations, grid, conf, TS_DEFAULT);
+        threaded_action(&bf_area_generation_update, grid, conf, TS_DEFAULT);
         return ACTION_RUN;
 }
 
 
-void reset_info_layer(const struct cats_grid *grid, struct grid_data_butterflies *data)
+enum action_status bf_action_overlay_update(struct cats_grid *grid, struct cats_configuration *conf)
 {
-        const cats_dt_coord rows = grid->dimension.rows;
-        const cats_dt_coord cols = grid->dimension.cols;
-
-        for (cats_dt_coord row = 0; row < rows; row++) {
-                for (cats_dt_coord col = 0; col < cols; col++) {
-                        data->info_layer[row][col] = 0;
-                }
-        }
+        return bf_grid_overlay_update(conf, grid);
 }
 
 
-enum action_status action_butterflies_update_overlays(struct cats_grid *grid, struct cats_configuration *conf)
-{
-        return butterflies_update_overlays(conf, grid);
-}
-
-
-enum action_status action_finish_generation(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_generation_finish(struct cats_grid *grid, struct cats_configuration *conf)
 {
         const int module_id = CATS_MODULE_ID;
 
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
 
+        threaded_action(&bf_area_kill_adults, grid, conf, TS_DEFAULT);
+
+
         data->generation_current--;
-        log_message(LOG_IMPORTANT, "Setting generation to %d\n", data->generation_current);
         assert(data->generation_current >= 0);
         // struct conf_data_butterflies *data = CATS_MODULE_DATA;
         return ACTION_RUN;
 }
 
-enum action_status action_start_generation(struct cats_grid *grid, struct cats_configuration *conf)
+enum action_status bf_action_generation_start(struct cats_grid *grid, __attribute__((unused)) struct cats_configuration *conf)
 {
         int module_id = CATS_MODULE_ID;
 
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-
         log_message(LOG_IMPORTANT, "Starting generation to %d\n", data->generation_current);
         assert(data->generation_current >= 0);
-        // struct conf_data_butterflies *data = CATS_MODULE_DATA;
         return ACTION_RUN;
 }
-
-
-void add_butterfly_generation_action(struct cats_configuration *conf, action_function function, const char *name,
-                                     int generation)
-{
-        char *result = NULL;
-        int rc = asprintf(&result, "%s (generation %d)", name, generation);
-        asprintf_check(rc);
-        append_action(conf, function, ALL_STAGES, result, module_name);
-        free(result);
-}
-
-
-void add_actions(struct cats_configuration *conf)
-{
-        struct conf_data_butterflies *data = CATS_MODULE_DATA;
-
-        printf("MAXIMUM GENERATIONS %d\n", data->generations_max);
-
-        register_action_function(conf, action_butterfly_stats_reset, "butterfly_action_reset_stats",
-                                 "resetting butterfly statistics");
-        register_action_function(conf, action_butterfly_update_generations, "butterfly_action_update_generations",
-                                 "update generations");
-
-        register_action_function(conf, action_finish_generation, "action_finish_generation",
-                                 "update generation");
-        register_action_function(conf, action_start_generation, "action_start_generation",
-                                 "start generation");
-
-
-        register_action_function(conf, action_butterflies_maturation, "butterfly_action_egg_to_adult",
-                                 "transition eggs to adults");
-
-        register_action_function(conf, action_butterflies_update_overlays, "butterfly_action_overlay_update",
-                                 "updating overlays");
-
-        register_action_function(conf, action_butterflies_dispersal, "butterfly_action_dispersal", "egg dispersal");
-        register_action_function(conf, action_butterflies_kill_adults, "butterfly_kill_adults", "kill adults");
-        register_action_function(conf, action_butterflies_save_grid, "action_butterflies_save_grid", "output");
-        register_action_function(conf, action_butterfly_stats_gather, "action_butterfly_stats_gather", "gather stats");
-        register_action_function(conf, action_butterfly_stats_reset, "action_butterfly_stats_reset", "reset stats");
-        register_action_function(conf, action_butterfly_stats_write, "action_butterfly_stats_write", "write stats");
-        list_actions_full(conf);
-
-
-        append_action(conf, action_butterfly_stats_reset, ALL_STAGES, "resetting butterfly statistics", module_name);
-        append_action_by_name(conf, "action_load_environments", ALL_STAGES, "environment update", module_name);
-        append_action_by_name(conf, "action_overlay_update", ALL_STAGES, "overlay update", module_name);
-        append_action(conf, action_butterflies_update_overlays, ALL_STAGES, "updating resource layer", module_name);
-        append_action(conf, action_butterfly_update_generations, ALL_STAGES, "update generations", module_name);
-
-        for (int32_t generation = data->generations_max; generation > 0; generation--) {
-
-                add_butterfly_generation_action(conf, action_butterfly_stats_reset, "reset stats", generation);
-                add_butterfly_generation_action(conf, action_start_generation, "start generation", generation);
-                add_butterfly_generation_action(conf, action_butterflies_maturation, "transition eggs to adults",
-                                                generation);
-                add_butterfly_generation_action(conf, action_butterfly_stats_gather, "gather stats", generation);
-                add_butterfly_generation_action(conf, action_butterflies_dispersal, "dispersal", generation);
-                add_butterfly_generation_action(conf, action_butterflies_save_grid, "output", generation);
-                add_butterfly_generation_action(conf, action_butterflies_kill_adults, "kill adults", generation);
-                add_butterfly_generation_action(conf, action_finish_generation, "finish generation", generation);
-                add_butterfly_generation_action(conf, action_butterfly_stats_write, "write stats", generation);
-        }
-
-}
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_actions.h b/src/modules/butterflies/butterflies_actions.h
index 5b785bc5e96d9d249d5d71f7d645b138186e1cbb..69a0c17268dd9a89412e1c155f663d8311b21955 100644
--- a/src/modules/butterflies/butterflies_actions.h
+++ b/src/modules/butterflies/butterflies_actions.h
@@ -1,6 +1,26 @@
-
 #ifndef CATS_BUTTERFLIES_ACTIONS_H
 #define CATS_BUTTERFLIES_ACTIONS_H
+
 #include "configuration/configuration.h"
-void add_actions(struct cats_configuration *conf);
+
+enum action_status bf_action_maturation(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_save_grid(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_dispersal(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_stats_gather(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_stats_reset(__attribute__((unused)) struct cats_grid *grid, __attribute__((unused)) struct cats_configuration *conf);
+
+enum action_status bf_action_stats_write(__attribute__((unused)) struct cats_grid *grid, __attribute__((unused)) struct cats_configuration *conf);
+
+enum action_status bf_action_overlay_update(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_generation_finish(struct cats_grid *grid, struct cats_configuration *conf);
+
+enum action_status bf_action_generation_start(struct cats_grid *grid, __attribute__((unused)) struct cats_configuration *conf);
+
+enum action_status bf_action_generation_update(struct cats_grid *grid, struct cats_configuration *conf);
+
 #endif //CATS_BUTTERFLIES_ACTIONS_H
diff --git a/src/modules/butterflies/butterflies_dispersal.c b/src/modules/butterflies/butterflies_dispersal.c
index dcff01f41c4082ad09c1fe75523b1a04a190ca75..d136ecdb932327e9e5bc129d992167bfd47f65b9 100644
--- a/src/modules/butterflies/butterflies_dispersal.c
+++ b/src/modules/butterflies/butterflies_dispersal.c
@@ -1,6 +1,3 @@
-//
-// Created by gattringera on 21/11/22.
-//
 #include "inline_population.h"
 #include "butterflies_inline.h"
 #include "misc/cats_random.h"
@@ -23,26 +20,21 @@ const int N_DIRECTIONS = 9;
  */
 
 const cats_dt_coord DIRECTION_OFFSETS[9][2] = {
-        {+0, +0}, {+0, +1}, {-1, +1},
-        {-1, +0}, {-1, -1}, {+0, -1},
-        {+1, -1}, {+1, +0}, {+1, +1}
+        {+0, +0},
+        {+0, +1},
+        {-1, +1},
+        {-1, +0},
+        {-1, -1},
+        {+0, -1},
+        {+1, -1},
+        {+1, +0},
+        {+1, +1}
 };
 
 
-
-
-void add_dispersed_eggs(struct cats_configuration *conf, struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, float eggs)
-{
-        //struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
-        const int module_id = CATS_MODULE_ID;
-        struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-        assert(eggs >= 0);
-        data->eggs[row][col] += eggs;
-}
-
-
-
-static void inline single_random_walk(struct cats_thread_info *ts, struct cats_grid *grid, cats_dt_coord source_row, cats_dt_coord source_col, int32_t eggs, cats_dt_rates egg_fraction_step, int32_t rw_num)
+static void inline single_random_walk(struct cats_thread_info *ts, struct cats_grid *grid, cats_dt_coord source_row,
+                                      cats_dt_coord source_col, int32_t eggs, cats_dt_rates egg_fraction_step,
+                                      __attribute__((unused)) int32_t rw_num)
 {
 
         const int module_id = CATS_MODULE_ID;
@@ -62,9 +54,10 @@ static void inline single_random_walk(struct cats_thread_info *ts, struct cats_g
 
         while (steps < max_steps) {
                 const unsigned long int direction = gsl_rng_uniform_int(ts->rng, N_DIRECTIONS);
-                const cats_dt_coord *offsets = DIRECTION_OFFSETS[direction];
 
 
+
+                const cats_dt_coord *offsets = DIRECTION_OFFSETS[direction];
                 const cats_dt_coord row_offset = offsets[0];
                 const cats_dt_coord col_offset = offsets[1];
 
@@ -74,14 +67,12 @@ static void inline single_random_walk(struct cats_thread_info *ts, struct cats_g
                 row += row_offset;
                 col += col_offset;
 
-                if (row >=  rows || row < 0 || col >= cols || col < 0) {
+                if (row >= rows || row < 0 || col >= cols || col < 0) {
                         return; // we escaped the simulation extent and got lost
                 }
 
-
-
                 // is the cell a valid dispersal target location?
-                if (! (data->info_layer[row][col] & BF_CELL_VALID_DISPERSAL_TARGET)) {
+                if (!(data->info_layer[row][col] & BF_CELL_VALID_DISPERSAL_TARGET)) {
                         continue;
                 }
 
@@ -94,10 +85,7 @@ static void inline single_random_walk(struct cats_thread_info *ts, struct cats_g
 
                 eggs_left -= eggs_to_deposit;
                 data->eggs[row][col] += (float) eggs_to_deposit;
-
-
-
-
+                ts->temp2++;
 
                 if (eggs_left == 0) break;
                 steps++;
@@ -107,31 +95,36 @@ static void inline single_random_walk(struct cats_thread_info *ts, struct cats_g
 }
 
 
-void butterflies_cell_dispersal(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion)
+void
+butterflies_cell_dispersal(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col,
+                           bool check_exclusion)
 {
         const struct cats_configuration *conf = ts->conf;
         if (check_exclusion
-            && (cell_excluded_by_overlay(conf, row, col) ||cell_excluded_by_generation(grid, row, col))) return;
+            && (cell_excluded_by_overlay(conf, row, col) || bf_cell_excluded_by_generation(grid, row, col)))
+                return;
 
 
         // total adults: the number of adults that became adult in this cell, possibly exceeding the carrying capacity (thanks to poisson processes)
-        cats_dt_population total_adults = get_adult_population(grid, row, col);
-        cats_dt_population cc = get_carrying_capacity(grid, row, col);
+        const cats_dt_population total_adults = get_adult_population(grid, row, col);
+        if (total_adults == 0) return;
+        ts->temp++;
 
         // total females: how many of the total adults are female, as drawn from a binomial distribution with p = 0.5
         // can be safely cast, because gsl_ran_binomial will return a number <= total_adults
-        cats_dt_population total_females = (cats_dt_population) gsl_ran_binomial(ts->rng, 0.5, total_adults);
-        assert(total_females > 0 && total_females <= total_adults);
+        const cats_dt_population total_females = (cats_dt_population) gsl_ran_binomial(ts->rng, 0.5, total_adults);
+        assert(total_females >= 0 && total_females <= total_adults);
 
         // total males: the rest
-        cats_dt_population total_males = total_adults - total_females;
+        const cats_dt_population total_males = total_adults - total_females;
 
         // we need at least one female and one male
         if (total_females == 0 || total_males == 0) return;
 
         // here we calculate the number of eggs per female, so we can return early if the cell is unsuitable
         struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
-        cats_dt_rates eggs_per_f = calculate_rate(&module_conf->eggs_per_female, total_adults, &grid->param, grid, row, col, NULL);
+        cats_dt_rates eggs_per_f = calculate_rate(&module_conf->eggs_per_female, total_adults, &grid->param, grid, row,
+                                                  col, NULL);
         int32_t eggs_per_female = (int32_t) ceill(eggs_per_f);
         assert(eggs_per_female >= 0);
 
@@ -139,7 +132,8 @@ void butterflies_cell_dispersal(struct cats_grid *grid, struct cats_thread_info
 
 
         // supernumerous_adults: the number of adults exceeding the carrying capacity
-        cats_dt_population supernumerous_adults = total_adults - cc;
+        const cats_dt_population cc = get_carrying_capacity(grid, row, col);
+        const cats_dt_population supernumerous_adults = total_adults - cc;
 
         // supernumerous_females: the (randomly assigned, drawn from a hypergeometric distribution) number of females
         // in the number of supernumerous adults
@@ -150,55 +144,57 @@ void butterflies_cell_dispersal(struct cats_grid *grid, struct cats_thread_info
                 // Too many adults in the cell. These must leave the cell, either to be added to the number of
                 // * dispersing females
                 // * discarded (males)
-                supernumerous_females = (cats_dt_population) gsl_ran_hypergeometric(ts->rng, total_females, total_males, supernumerous_adults);
+                supernumerous_females = (cats_dt_population) gsl_ran_hypergeometric(ts->rng, total_females, total_males,
+                                                                                    supernumerous_adults);
+
         }
 
-        // remaining_females: the number of females within the carrying capacity
-        cats_dt_population remaining_females = total_females - supernumerous_females;
-        // at this point the number of 'remaining' adults in the cell is equal or less than the carrying capacity
 
+        // females_within_cc: the number of females within the carrying capacity
+        cats_dt_population females_within_cc = total_females - supernumerous_females;
+
+        // at this point the number of 'remaining' adults in the cell is equal or less than the carrying capacity
 
         // how many females will leave the cell (not counting the number of supernumerous ones)?
         // wandering_females: the number of females that will leave the cell and do a random walk
-        // we draw from a Poisson distribution with a species-specific parameter, the probability to leave times the
-        // number of females
-        cats_dt_rates probability_to_leave = 1.0 - module_conf->probability_to_stay;
-        cats_dt_population wandering_females = poisson(ts->rng, remaining_females * probability_to_leave);
-
-        // but cap the number of females actually available
-        if (wandering_females > remaining_females) {
-                wandering_females = remaining_females;
+        cats_dt_population wandering_females =
+                (cats_dt_population) (females_within_cc * (1.0 - module_conf->probability_to_stay));
+
+        // stationary_females: the number of females that will not leave the cell, and leave all their eggs here
+        cats_dt_population stationary_females = females_within_cc - wandering_females;
+
+        if (wandering_females < 0) {
+                wandering_females = 0;
         }
 
         // we need to add the previously subtracted supernumerous females
         wandering_females += supernumerous_females;
 
-        // stationary_females: the number of females that will not leave the cell, and leave all their eggs here
-        cats_dt_population stationary_females = total_females - wandering_females;
-
-
         const int module_id = CATS_MODULE_ID;
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
 
-        // how many eggs are deposited in the local cell?
-        // all the eggs of all the stationary females
-        cats_dt_rates local_eggs = (stationary_females * eggs_per_female);
-        // plus the local fraction of the eggs for the wandering females
-        cats_dt_rates wandering_local_eggs = (module_conf->egg_fraction_source * eggs_per_female);
-        local_eggs +=  (wandering_females * wandering_local_eggs);
-        data->eggs[row][col] += (float) ceill(local_eggs);
+        int32_t eggs_to_disperse_per_female = (int32_t) ceill(
+                eggs_per_female * (1.0 - module_conf->egg_fraction_source));
+
+        // all the eggs of all the stationary females + the eggs the wandering females leave in the source cell
+        const cats_dt_rates source_cell_eggs = stationary_females * eggs_per_female +
+                                               wandering_females * (eggs_per_female - eggs_to_disperse_per_female);
 
-        int32_t wandering_eggs = (int32_t) ceill(eggs_per_female - wandering_local_eggs);
+        // add source cell eggs to the source cell
+        data->eggs[row][col] += (float) ceill(source_cell_eggs);
 
-        if (wandering_eggs == 0) {
+        if (eggs_to_disperse_per_female == 0) {
                 log_message(LOG_ERROR, "%s: random walk with no eggs to distribute in cell %d %d", __func__, row, col);
                 return;
         }
 
-        // fixme maybe define threshold over which the random walks are bundled
+        // FIXME: define threshold over which the random walks are bundled
         const cats_dt_rates egg_fraction_step = module_conf->egg_fraction_step;
+        //printf("thread %d: row %d col %d: doing %d rws\n", ts->id, row, col, wandering_females);
+
         for (int32_t rw_number = 0; rw_number < wandering_females; rw_number++) {
-                single_random_walk(ts, grid, row, col, wandering_eggs, egg_fraction_step, rw_number);
+                single_random_walk(ts, grid, row, col, eggs_to_disperse_per_female, egg_fraction_step, rw_number);
+                ts->temp1++;
         }
 
 }
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_filenames.c b/src/modules/butterflies/butterflies_filenames.c
new file mode 100644
index 0000000000000000000000000000000000000000..56f0323f93ba4757e30f507285235b588f124fa6
--- /dev/null
+++ b/src/modules/butterflies/butterflies_filenames.c
@@ -0,0 +1,52 @@
+#include "butterflies_generations.h"
+#include "paths/paths.h"
+#include "paths/output_paths.h"
+#include "butterflies_populations.h"
+#include "inline_overlays.h"
+#include "butterflies_main.h"
+#include "butterflies_actions.h"
+#include "modules/module_header.h"
+#include "actions/cats_actions.h"
+#include "butterflies_filenames.h"
+#include "module.h"
+
+
+char *bf_population_filename(struct cats_configuration *conf, struct cats_grid *grid)
+{
+        assert(grid != NULL);
+        assert(conf != NULL);
+        assert(conf->grid_count == 1);
+
+        int module_id = CATS_MODULE_ID;
+        struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
+
+
+        struct string_array *path = get_output_directory(conf, "butterfly-adults"); // FIXME MAKE DIRECTORY
+
+        char *extension = get_extension(conf, "adults");
+        struct string_array *name = standard_output_file_name(conf, NULL, NULL, NULL);
+        string_array_add_int(name, data->generation_current, "g%03d");
+
+        char *filename = assemble_filename(path, name, "_", extension);
+
+        free_string_array(&path);
+        free_string_array(&name);
+        free(extension);
+
+        return filename;
+}
+
+char *bf_stats_filename(struct cats_configuration *conf, struct cats_grid *grid)
+{
+        struct string_array *path = get_output_directory(conf, "stats");
+
+        struct string_array *name = new_string_array();
+        string_array_add(name, module_name);
+        string_array_add(name, conf->run_name);
+        string_array_add_int(name, conf->simulation.replicate, "r%03d");
+        char *filename = assemble_filename(path, name, "_", "csv");
+        free_string_array(&path);
+        free_string_array(&name);
+
+        return filename;
+}
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_filenames.h b/src/modules/butterflies/butterflies_filenames.h
new file mode 100644
index 0000000000000000000000000000000000000000..92a3cd36a34b2082ab82d6b4f2e756903dc5f5b5
--- /dev/null
+++ b/src/modules/butterflies/butterflies_filenames.h
@@ -0,0 +1,8 @@
+#ifndef CATS_BUTTERFLIES_FILENAMES_H
+#define CATS_BUTTERFLIES_FILENAMES_H
+
+#include "configuration/configuration.h"
+
+char *bf_population_filename(struct cats_configuration *conf, struct cats_grid *grid);
+char *bf_stats_filename(struct cats_configuration *conf, struct cats_grid *grid);
+#endif //CATS_BUTTERFLIES_FILENAMES_H
diff --git a/src/modules/butterflies/butterflies_generations.c b/src/modules/butterflies/butterflies_generations.c
index c349f7959f31b4d2789576fb004e302600443303..f466eb2266da7aef766c7869b975051d7dd8d19f 100644
--- a/src/modules/butterflies/butterflies_generations.c
+++ b/src/modules/butterflies/butterflies_generations.c
@@ -1,4 +1,3 @@
-
 #include "butterflies_populations.h"
 #include "inline_overlays.h"
 #include "butterflies_main.h"
@@ -7,7 +6,8 @@
 #include "butterflies_generations.h"
 #include "inline.h"
 
-void area_update_generations(struct cats_grid *grid, struct cats_thread_info *ts)
+// only run at the start of the year
+void bf_area_generation_update(struct cats_grid *grid, struct cats_thread_info *ts)
 {
         struct cats_configuration *conf = ts->conf;
         struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
@@ -21,14 +21,15 @@ void area_update_generations(struct cats_grid *grid, struct cats_thread_info *ts
         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++) {
 
-                        if (cell_excluded_by_overlay(conf, row, col)) {
+                        if (cell_excluded_by_overlay(conf, row, col)
+                            ||  (data->info_layer[row][col] & BF_CELL_VALID_DISPERSAL_TARGET) == false) {
                                 data->eggs[row][col] = 0.0f;
-                                set_population_ignore_cc(grid, row, col, 0);
-
                                 data->generations[row][col] = 0.0f;
+                                set_population_ignore_cc(grid, row, col, 0);
                                 continue;
                         }
 
diff --git a/src/modules/butterflies/butterflies_generations.h b/src/modules/butterflies/butterflies_generations.h
index 343d78e641969c4bcba3226ab7026778ac313dba..5df061be22cd4cf788a65ed00eab4d09ba65f98a 100644
--- a/src/modules/butterflies/butterflies_generations.h
+++ b/src/modules/butterflies/butterflies_generations.h
@@ -1,6 +1,9 @@
 #ifndef CATS_BUTTERFLIES_GENERATIONS_H
 #define CATS_BUTTERFLIES_GENERATIONS_H
+
 #include "data/cats_grid.h"
 #include "threading/threading.h"
-void area_update_generations(struct cats_grid *grid, struct cats_thread_info *ts);
-#endif //CATS_BUTTERFLIES_GENERATIONS_H
+
+void bf_area_generation_update(struct cats_grid *grid, struct cats_thread_info *ts);
+
+#endif //CATS_BUTTERFLIES_GENERATIONS_H
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_inline.h b/src/modules/butterflies/butterflies_inline.h
index 2574b22ae0502da3806fbcdded6a45e2b66b1efd..2551ab7c3d6894228886493398ed61fdeb0c9482 100644
--- a/src/modules/butterflies/butterflies_inline.h
+++ b/src/modules/butterflies/butterflies_inline.h
@@ -8,12 +8,11 @@
 #include "modules/module_header.h"
 
 
-
-static inline bool cell_excluded_by_generation (const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col)
+static inline bool bf_cell_excluded_by_generation(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col)
 {
         const int module_id = CATS_MODULE_ID;
         const struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-        if (data->generation_current > (int32_t) ceilf(data->generations[row][col])) return true;
+        if (data->generation_current == 0.0 || data->generation_current > (int32_t) ceilf(data->generations[row][col])) return true;
         return false;
 }
 
diff --git a/src/modules/butterflies/butterflies_main.c b/src/modules/butterflies/butterflies_main.c
index 91809b744520bc856362600bed79de8597fec94f..108f378e35185a53360a3d9249069c15cf5d21fc 100644
--- a/src/modules/butterflies/butterflies_main.c
+++ b/src/modules/butterflies/butterflies_main.c
@@ -7,12 +7,13 @@
 #include "butterflies_actions.h"
 #include "butterflies_vital_rates.h"
 #include "cats_ini/cats_ini.h"
+#include "butterflies_action_helpers.h"
 
 struct cats_global global;
 struct cats_debug_options cats_debug;
 
 
-void *butterfly_grid_init(struct cats_configuration *conf, struct cats_grid *grid, void *ignored)
+void *butterfly_grid_init(__attribute__((unused)) struct cats_configuration *conf, struct cats_grid *grid, __attribute__((unused)) void *ignored)
 {
         log_message(LOG_INFO, "%s: %s: grid init", module_name, __func__);
         printf("%d %d\n", grid->dimension.cols, grid->dimension.rows);
@@ -36,7 +37,7 @@ void *butterfly_grid_init(struct cats_configuration *conf, struct cats_grid *gri
 }
 
 
-void *butterfly_grid_cleanup(struct cats_configuration *conf, struct cats_grid *grid, void *data)
+void *butterfly_grid_cleanup(__attribute__((unused)) struct cats_configuration *conf, struct cats_grid *grid, void *data)
 {
         log_message(LOG_INFO, "%s: grid cleanup", module_name);
         assert(grid != NULL);
@@ -58,13 +59,12 @@ void load_butterflies_species_params(struct cats_configuration *conf, struct cat
 {
         struct conf_data_butterflies *data = CATS_MODULE_DATA;
 
-
         load_conf_vital_rate(&data->eggs_per_female, conf, ini, section_name, param);
         load_conf_vital_rate(&data->butterfly_generations, conf, ini, section_name, param);
-        load_conf_vital_rate(&data->butterfly_egg_to_adult_survival, conf, ini, section_name, param);
 
 
-        cats_dt_rates female_percentage;
+        load_conf_vital_rate(&data->butterfly_egg_to_adult_survival, conf, ini, section_name, param);
+
         load_conf_value(true, ini, section_name, "butterflies random walk steps maximum", &data->animal_dispersal_max_radius);
 
         if (data->animal_dispersal_max_radius <= 0) {
@@ -72,16 +72,23 @@ void load_butterflies_species_params(struct cats_configuration *conf, struct cat
                 exit_cats(EXIT_FAILURE);
         }
 
-        load_conf_value(true, ini, section_name, "butterflies female fraction", &female_percentage);
+        load_conf_value(true, ini, section_name, "butterflies probability to stay", &data->probability_to_stay);
+
+        if (data->probability_to_stay < 0.0 || data->probability_to_stay > 1.0) {
+                log_message(LOG_ERROR, "butterflies probability to stay has to be in range [0, 1]");
+                exit_cats(EXIT_FAILURE);
+        }
+
         data->generations_max = (int32_t) ceill(data->butterfly_generations.max_rate);
+        data->generations_min = (int32_t) ceill(data->butterfly_generations.min_rate);
         param->plant_dispersal_max_radius = data->animal_dispersal_max_radius;
+
         if (! data->actions_added) {
-                add_actions(conf);
+                bf_register_actions(conf);
+                bf_add_actions(conf);
                 data->actions_added = true;
         }
 
-
-
 }
 
 
@@ -92,12 +99,11 @@ void cats_module_init(struct cats_configuration *conf)
         int32_t id = register_module(conf, module_name, data, flags);
         register_cats_grid_init_function(conf, butterfly_grid_init, butterfly_grid_cleanup);
         register_load_species_param_config_func(conf, load_butterflies_species_params);
-        add_vital_rates(conf, data);
+        bf_add_vital_rates(conf, data);
         log_message(LOG_INFO, "Hello from %s (id: %d)\n", module_name, id);
 
 
         for (enum butterfly_stats which = BF_STAT_MIN; which < BF_STAT_MAX; which++) {
-                data->stat_ids[which] = add_custom_stat(&conf->stats_registry, get_butterfly_stats_name(which));
+                data->stat_ids[which] = add_custom_stat(&conf->stats_registry, bf_get_stats_field_name(which));
         }
 }
-
diff --git a/src/modules/butterflies/butterflies_main.h b/src/modules/butterflies/butterflies_main.h
index 3e9496eab5164ea55fe4b23542239a5c372b220f..0170209bfdded5f4759fed9f085740281cb8e22c 100644
--- a/src/modules/butterflies/butterflies_main.h
+++ b/src/modules/butterflies/butterflies_main.h
@@ -33,23 +33,27 @@ enum butterfly_cell_info {
 struct conf_data_butterflies {
 
     // fixme -> move to grid data;
-    int32_t generations_max;
+
     int32_t current_generation;
+    int32_t generations_max;
+    int32_t generations_min;
     int32_t animal_dispersal_max_radius; ///< maximal flight/dispersal distance
     cats_dt_rates egg_to_adult_survival_rate_maximum;
     cats_dt_rates egg_per_female_maximum;
     cats_dt_rates probability_to_stay;
     cats_dt_rates egg_fraction_source;
     cats_dt_rates egg_fraction_step;
-
-
-
-    bool actions_added;
     cats_dt_rates stationary_females;
     struct cats_vital_rate eggs_per_female;
     struct cats_vital_rate butterfly_egg_to_adult_survival;
     struct cats_vital_rate butterfly_generations;
+
+
+    bool actions_added;
+
     int64_t stat_ids[BF_STAT_MAX];
+    FILE *stats_file;
+
 
 };
 
diff --git a/src/modules/butterflies/butterflies_overlays.c b/src/modules/butterflies/butterflies_overlays.c
index 050de1a59a8c2dd4c1af66d1a476ab0dd6faedee..dfc589bc364298ac44bdc44b5b9d1fe41bd0fba0 100644
--- a/src/modules/butterflies/butterflies_overlays.c
+++ b/src/modules/butterflies/butterflies_overlays.c
@@ -1,16 +1,15 @@
-
-
-
+#include "paths/paths.h"
+#include "butterflies_populations.h"
 #include "modules/module_header.h"
 #include "actions/cats_actions.h"
+
+#include "butterflies_overlays.h"
 #include "butterflies_main.h"
 #include "inline_overlays.h"
 
 
-enum action_status butterflies_update_overlays(struct cats_configuration *conf, struct cats_grid *grid)
+enum action_status bf_grid_overlay_update(const struct cats_configuration *conf, struct cats_grid *grid)
 {
-
-
         if (conf->overlays.have_overlays == false) {
                 return ACTION_NOT_RUN;
         }
@@ -18,6 +17,7 @@ enum action_status butterflies_update_overlays(struct cats_configuration *conf,
         int module_id = CATS_MODULE_ID;
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
 
+
         const cats_dt_coord rows = grid->dimension.rows;
         const cats_dt_coord cols = grid->dimension.cols;
 
@@ -28,8 +28,11 @@ enum action_status butterflies_update_overlays(struct cats_configuration *conf,
 
                         if (cell_excluded_by_overlay(conf, row, col)) {
                                 data->info_layer[row][col] |= BF_CELL_EXCLUDED;
+                                continue;
                         }
 
+                        data->info_layer[row][col] = BF_CELL_VALID_DISPERSAL_TARGET;
+
                         if (conf->overlays.overlay[OL_HABITAT_TYPE_CC].enabled &&
                             conf->overlays.habitat_cc->data[row][col] > 0) {
                                 data->info_layer[row][col] |= BF_CELL_HABITAT_OK;
@@ -49,4 +52,4 @@ enum action_status butterflies_update_overlays(struct cats_configuration *conf,
         }
 
         return ACTION_RUN;
-}
\ No newline at end of file
+}
diff --git a/src/modules/butterflies/butterflies_overlays.h b/src/modules/butterflies/butterflies_overlays.h
index f1e3f26e2d07b517ddbfd68ab96f5411577a6354..4d9b11970130425f3d71cbcc161e4c70646e1c72 100644
--- a/src/modules/butterflies/butterflies_overlays.h
+++ b/src/modules/butterflies/butterflies_overlays.h
@@ -1,10 +1,7 @@
-//
-// Created by andreas on 20/03/23.
-//
-
 #ifndef CATS_BUTTERFLIES_OVERLAYS_H
 #define CATS_BUTTERFLIES_OVERLAYS_H
 #include "configuration/configuration.h"
 
-enum action_status butterflies_update_overlays(struct cats_configuration *conf, struct cats_grid *grid);
+enum action_status bf_grid_overlay_update(const struct cats_configuration *conf, struct cats_grid *grid);
+
 #endif //CATS_BUTTERFLIES_OVERLAYS_H
diff --git a/src/modules/butterflies/butterflies_populations.c b/src/modules/butterflies/butterflies_populations.c
index cf8999044cbc98ad0e2c7f2c26b5c322bbda654b..f960967e86edf224f6fcf74a2e90426985a3aa6a 100644
--- a/src/modules/butterflies/butterflies_populations.c
+++ b/src/modules/butterflies/butterflies_populations.c
@@ -1,49 +1,73 @@
 #include <assert.h>
 #include <math.h>
-#include "butterflies_populations.h"
+
+#include "paths/paths.h"
+#include "paths/output_paths.h"
+#include "actions/cats_actions.h"
+#include "misc/cats_random.h"
 #include "data/cats_grid.h"
-#include "overlays/overlay_exclusion.h"
-#include "inline_overlays.h"
 #include "threading/threading-helpers.h"
 #include "modules/module_header.h"
+
+#include "butterflies_populations.h"
 #include "butterflies_main.h"
-#include "inline_population.h"
-#include "misc/cats_random.h"
-#include "populations/population.h"
 #include "butterflies_inline.h"
+#include "inline_population.h"
 
 
-
-void butterflies_cell_maturation(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion)
+void bf_cell_maturation(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col,
+                        bool check_exclusion)
 {
+
         const struct cats_configuration *conf = ts->conf;
-        if (check_exclusion
-            && (cell_excluded_by_overlay(conf, row, col) ||cell_excluded_by_generation(grid, row, col))) return;
+        assert (conf->grid_count == 1);
+
+        if (check_exclusion) {
+                if (bf_cell_excluded_by_generation(grid, row, col)) return;
+        }
+
+
 
-        struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
         const int module_id = CATS_MODULE_ID;
         struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data;
-        int32_t local_max_generation = (int32_t) ceilf(data->generations[row][col]);
+
+        if (data->eggs[row][col] == 0) return;
         if (data->eggs[row][col] < 0) {
                 log_message(LOG_ERROR, "Number of eggs < 0: row %d col %d: %f", row, col, data->eggs[row][col]);
                 exit(EXIT_FAILURE);
         }
 
 
-        float proportion = 1.0f;
-        if (data->generation_current == local_max_generation && (float) local_max_generation > proportion) {
-                proportion =  (float) local_max_generation-  data->generations[row][col];
+        // the number of generations per cell is usually not an integer value
+        // the non-integer part of the number of generations is used in the generation which is
+        // one greater than the integer part of the number of generations
+        // i.e. if the number of generations is 2.4, 40% of all eggs in the cell
+        // will be considered as if they belonged to generation 3
+        // the minimum number of generations is 1 if the cell is climatically viable (and the host species is present)
+        // if the number of generations is 0, the cell will be ignored
+        //
+        // note that the generations are processed backwards
+        // i.e. if the maximum number of generations is 5, individual cells will have 1 ... 5 generations
+        // first the all cells which have 5 (> 4) generations are modelled
+        // then all the cells with have at least 4 (> 3) generations are modelled
+        // ...
+        // at last all cells with have at least 1 generations are modelled
+
+        float this_generation_fraction = 1.0f;
+        int32_t local_max_generation = (int32_t) ceilf(data->generations[row][col]);
 
+        if (data->generation_current == local_max_generation) {
+                this_generation_fraction = (float) local_max_generation - data->generations[row][col];
+                assert(this_generation_fraction >= 0);
+                assert(this_generation_fraction <= 1.0);
         }
-        assert(proportion >= 0);
-        assert(proportion <= 1.0);
-        if (data->eggs[row][col] == 0) return; // FIXME MOVE UP
 
-        assert (conf->grid_count == 1);
-        float eggs = proportion * data->eggs[row][col];
+
+        float eggs = this_generation_fraction * data->eggs[row][col];
 
         if (eggs > data->eggs[row][col]) {
-                log_message(LOG_ERROR, "Removing more eggs than present: %d %d: %f/%f", row, col, data->eggs[row][col], eggs);
+                log_message(LOG_ERROR, "Removing more eggs than present: %d %d: %f/%f", row, col, data->eggs[row][col],
+                            eggs);
                 exit(EXIT_FAILURE);
         }
 
@@ -51,15 +75,27 @@ void butterflies_cell_maturation(struct cats_grid *grid, struct cats_thread_info
 
         assert(data->eggs[row][col] >= 0);
 
+        struct conf_data_butterflies *module_conf = CATS_MODULE_DATA;
+        cats_dt_rates maturation_rate = calculate_rate(&module_conf->butterfly_egg_to_adult_survival, NAN, &grid->param,
+                                                       grid, row, col, NULL);
 
-        cats_dt_rates maturation_rate = calculate_rate(&module_conf->butterfly_egg_to_adult_survival, NAN, &grid->param, grid, row, col, NULL);
-        cats_dt_population K = get_carrying_capacity(grid, row, col);
-        cats_dt_population adults = poisson_population_capped(ts->rng, eggs * proportion * maturation_rate, K);
-        /*
-        if (adults >0 ) {
-                printf("adults %d %d: %d\n", row, col, adults);
-        }*/
-        set_population(grid, row, col, adults);
+        // not capped, we can have more adults than CC
+        cats_dt_population adults = poisson(ts->rng, eggs * maturation_rate);
+        assert(adults >= 0);
+        set_population_ignore_cc(grid, row, col, adults);
 }
 
 
+void bf_area_kill_adults(struct cats_grid *grid, struct cats_thread_info *ts)
+{
+        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++) {
+                        set_population_ignore_cc(grid, row, col, 0);
+                }
+        }
+}
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_populations.h b/src/modules/butterflies/butterflies_populations.h
index 5babb7ec7ca98f7ef8d82479158e816c9d62cc61..20c6488a39ad28bf14b9280ae1283d6871591e1b 100644
--- a/src/modules/butterflies/butterflies_populations.h
+++ b/src/modules/butterflies/butterflies_populations.h
@@ -5,5 +5,6 @@
 #ifndef CATS_BUTTERFLIES_POPULATIONS_H
 #define CATS_BUTTERFLIES_POPULATIONS_H
 #include "data/cats_grid.h"
-void butterflies_cell_maturation(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion);
+void bf_cell_maturation(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion);
+void bf_area_kill_adults(struct cats_grid *grid, struct cats_thread_info *ts);
 #endif //CATS_BUTTERFLIES_POPULATIONS_H
diff --git a/src/modules/butterflies/butterflies_stats.c b/src/modules/butterflies/butterflies_stats.c
index 9a08c6752600b9cf95c0f123653be56cc000ee3f..6fe9fd29bfcc0359d6cbbc8b67530fef20b99ce2 100644
--- a/src/modules/butterflies/butterflies_stats.c
+++ b/src/modules/butterflies/butterflies_stats.c
@@ -1,12 +1,18 @@
-//
-// Created by gattringera on 16/03/23.
-//
 
 #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_filenames.h"
+#include "temporal/phase_names.h"
+#include "temporal/years.h"
 
-const char *get_butterfly_stats_name(enum butterfly_stats which)
+const char *bf_get_stats_field_name(enum butterfly_stats which)
 {
         switch (which) {
                 case BF_STAT_POPULATED_FIT:
@@ -19,6 +25,19 @@ const char *get_butterfly_stats_name(enum butterfly_stats which)
                         return "unpopulated_unfit";
                 case BF_STAT_EXCLUDED:
                         return "excluded";
+                case BF_STAT_GENERATION_ACTIVE:
+                        return "generation_active";
+                case BF_POPULATED_AT_DISPERSAL:
+                        return "populated_at_dispersal";
+
+                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;
         }
@@ -26,3 +45,139 @@ const char *get_butterfly_stats_name(enum butterfly_stats which)
         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);
+
+        } else {
+
+                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);
+
+        exit_cats(EXIT_FAILURE);
+
+
+
+
+}
+
+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 zt = grid->param.ZT;
+        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;
+                                }
+
+                        }
+                }
+        }
+
+}
\ No newline at end of file
diff --git a/src/modules/butterflies/butterflies_stats.h b/src/modules/butterflies/butterflies_stats.h
index a3bb6a1fda2499a893044a65ebf8f4848ddeb503..2a198419603c92e8b090e793a83cba3b1e4e0366 100644
--- a/src/modules/butterflies/butterflies_stats.h
+++ b/src/modules/butterflies/butterflies_stats.h
@@ -1,10 +1,11 @@
-//
-// Created by gattringera on 16/03/23.
-//
 
 #ifndef CATS_BUTTERFLIES_STATS_H
 #define CATS_BUTTERFLIES_STATS_H
 
+#include <assert.h>
+#include "stats/statistics.h"
+#include "threading/threading.h"
+
 enum butterfly_stats {
     BF_STAT_MIN = 0,
     BF_STAT_POPULATED_FIT = 0,
@@ -12,10 +13,25 @@ enum butterfly_stats {
     BF_STAT_UNPOPULATED_FIT,
     BF_STAT_UNPOPULATED_UNFIT,
     BF_STAT_EXCLUDED,
+    BF_STAT_GENERATION_ACTIVE,
+    BF_OUTPUT_STAT_MAX,
+    BF_POPULATED_AT_DISPERSAL,
+    BF_RANDOM_WALK_COUNT,
+    BF_RANDOM_WALK_STEP_COUNT,
     BF_STAT_MAX
 };
 
-const char *get_butterfly_stats_name(enum butterfly_stats which);
+const char *bf_get_stats_field_name(enum butterfly_stats which);
+void bf_area_stats_gather(struct cats_grid *grid, struct cats_thread_info *ts);
+void bf_stats_write(struct cats_configuration *conf, struct cats_grid *grid);
+
+static inline void increase_custom_stat(struct statistics *stats, int64_t stat_id, int64_t by)
+{
+        assert(stats != NULL);
+        assert(stat_id >= 0 && stat_id < stats->custom_stat_count);
+        stats->custom_stats[stat_id] += by;
+
+}
 
 
 
diff --git a/src/modules/butterflies/butterflies_vital_rates.c b/src/modules/butterflies/butterflies_vital_rates.c
index 5af6b76793ad3fd39b9e5289d24cb91ab9cbbedc..3f0e67855a1f147e366ada43fe052b730399862c 100644
--- a/src/modules/butterflies/butterflies_vital_rates.c
+++ b/src/modules/butterflies/butterflies_vital_rates.c
@@ -1,28 +1,26 @@
-
-
 #include "butterflies_vital_rates.h"
 
-void add_vital_rates(struct cats_configuration *conf,  struct conf_data_butterflies *data)
+void bf_add_vital_rates(struct cats_configuration *conf, struct conf_data_butterflies *data)
 {
         // generations
         register_module_vital_rate(conf, &data->butterfly_generations,"butterflies generations");
         set_vital_rate_name(&data->butterfly_generations, "butterflies generations");
-
         set_vital_rate_suitability_cutoff_hint(&data->butterfly_generations, HYBRID_SUIT_TS_ZT);
         set_vital_rate_link_hybrid_function(&data->butterfly_generations, conf, LINK_SUITABILITY_SIGMOID);
         set_vital_density(&data->butterfly_generations, NO_DENSITY_DEP);
 
 
-        // eggs
+        // adult to eggs
         register_module_vital_rate(conf, &data->eggs_per_female, "butterflies eggs per female");
         set_vital_rate_name(&data->eggs_per_female, "butterflies eggs per female");
         set_vital_rate_suitability_cutoff_hint(&data->eggs_per_female, HYBRID_SUIT_TS_ZT);
         set_vital_rate_link_hybrid_function(&data->eggs_per_female, conf, LINK_SUITABILITY_SIGMOID);
 
+
         // egg to adult survival
         register_module_vital_rate(conf, &data->butterfly_egg_to_adult_survival,"butterflies egg to adult survival rate");
         set_vital_rate_name(&data->butterfly_egg_to_adult_survival, "butterflies eggs to adult survival rate");
         set_vital_rate_suitability_cutoff_hint(&data->butterfly_egg_to_adult_survival, HYBRID_SUIT_TS_ZT);
         set_vital_rate_link_hybrid_function(&data->butterfly_egg_to_adult_survival, conf, LINK_SUITABILITY_SIGMOID);
-        set_vital_density(&data->butterfly_egg_to_adult_survival, DENSITY_DEP_NEGATIVE);
+        set_vital_density(&data->butterfly_egg_to_adult_survival, NO_DENSITY_DEP);
 }
diff --git a/src/modules/butterflies/butterflies_vital_rates.h b/src/modules/butterflies/butterflies_vital_rates.h
index 968f550198ecd29d6cce1bb1f24776d1b8b467b7..1a1d097bc9b7e5b57376102937c6a8cc34f3d99c 100644
--- a/src/modules/butterflies/butterflies_vital_rates.h
+++ b/src/modules/butterflies/butterflies_vital_rates.h
@@ -6,5 +6,5 @@
 #include "vital_rates/setup_rates.h"
 #include "modules/module_header.h"
 
-void add_vital_rates(struct cats_configuration *conf,  struct conf_data_butterflies *data) ;
+void bf_add_vital_rates(struct cats_configuration *conf, struct conf_data_butterflies *data) ;
 #endif //CATS_BUTTERFLIES_VITAL_RATES_H
diff --git a/src/modules/butterflies/module.h b/src/modules/butterflies/module.h
index 02ce2be565ffc98fe6d576ff673ef7857bd8217b..6da8133282863e8ada0fc405c2893b82d98540de 100644
--- a/src/modules/butterflies/module.h
+++ b/src/modules/butterflies/module.h
@@ -1,6 +1,6 @@
-
-
 #ifndef CATS_MODULE_H
 #define CATS_MODULE_H
+
 static const char *module_name = "cats-butterflies";
+
 #endif //CATS_MODULE_H