diff --git a/src/modules/butterflies/CMakeLists.txt b/src/modules/butterflies/CMakeLists.txt index b74426a554c7935df7c46671dbcc7f4ee05a5107..e99e173564e7ec84e560963f8ed394201ff04832 100644 --- a/src/modules/butterflies/CMakeLists.txt +++ b/src/modules/butterflies/CMakeLists.txt @@ -1,10 +1,10 @@ -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) +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) target_include_directories(cats-butterflies PUBLIC ".") target_sources(cats-butterflies PRIVATE - butterflies_main.c butterflies_main.h random_walk.c random_walk.h + butterflies_main.c butterflies_main.h PUBLIC diff --git a/src/modules/butterflies/butterflies_dispersal.c b/src/modules/butterflies/butterflies_dispersal.c index 8cc7b964cb8eb3a833c6654e5f18d90ed2ffac00..dcff01f41c4082ad09c1fe75523b1a04a190ca75 100644 --- a/src/modules/butterflies/butterflies_dispersal.c +++ b/src/modules/butterflies/butterflies_dispersal.c @@ -1,12 +1,36 @@ // // Created by gattringera on 21/11/22. // +#include "inline_population.h" +#include "butterflies_inline.h" +#include "misc/cats_random.h" +#include "populations/carrying_capacity.h" +#include "inline_overlays.h" + #include <math.h> +#include <gsl/gsl_randist.h> #include "butterflies_main.h" #include "butterflies_dispersal.h" #include "configuration/configuration.h" #include "modules/module_header.h" +const int N_DIRECTIONS = 9; +/* + * directions + * 4 3 2 + * 5 0 1 + * 6 7 8 + */ + +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} +}; + + + + 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; @@ -14,4 +38,167 @@ void add_dispersed_eggs(struct cats_configuration *conf, struct cats_grid *grid, 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) +{ + + const int module_id = CATS_MODULE_ID; + const struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data; + const struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; + + + int32_t eggs_left = eggs; + const cats_dt_coord max_steps = module_conf->animal_dispersal_max_radius; + + cats_dt_coord steps = 0; + cats_dt_coord row = source_row; + cats_dt_coord col = source_col; + + const cats_dt_coord rows = grid->dimension.rows; + const cats_dt_coord cols = grid->dimension.cols; + + 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 row_offset = offsets[0]; + const cats_dt_coord col_offset = offsets[1]; + + assert(row_offset >= -1 && row_offset <= 1); + assert(col_offset >= -1 && col_offset <= 1); + + row += row_offset; + col += col_offset; + + 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)) { + continue; + } + + int32_t eggs_to_deposit = (int32_t) ceilf((float) (eggs_left * egg_fraction_step)); + assert(eggs_to_deposit >= 0); + + if (eggs_to_deposit > eggs_left) { + eggs_to_deposit = eggs_left; + } + + eggs_left -= eggs_to_deposit; + data->eggs[row][col] += (float) eggs_to_deposit; + + + + + + if (eggs_left == 0) break; + steps++; + } + + assert(eggs_left >= 0); +} + + +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; + + + // 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); + + // 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); + + // total males: the rest + 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); + int32_t eggs_per_female = (int32_t) ceill(eggs_per_f); + assert(eggs_per_female >= 0); + + if (eggs_per_female == 0) return; + + + // supernumerous_adults: the number of adults exceeding the carrying capacity + 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 + cats_dt_population supernumerous_females = 0; + + + if (supernumerous_adults > 0) { + // 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); + } + + // 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 + + + // 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; + } + + // 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 wandering_eggs = (int32_t) ceill(eggs_per_female - wandering_local_eggs); + + if (wandering_eggs == 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 + const cats_dt_rates egg_fraction_step = module_conf->egg_fraction_step; + 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); + } + } \ No newline at end of file diff --git a/src/modules/butterflies/butterflies_dispersal.h b/src/modules/butterflies/butterflies_dispersal.h index 4017a409fb645905a05f0a7ab6a89f4dd153cad0..6385792ccd2b7055dbc0ad4fa0dac2bf2d07898c 100644 --- a/src/modules/butterflies/butterflies_dispersal.h +++ b/src/modules/butterflies/butterflies_dispersal.h @@ -5,4 +5,8 @@ #ifndef CATS_BUTTERFLIES_DISPERSAL_H #define CATS_BUTTERFLIES_DISPERSAL_H +#include "threading/threading.h" +#include "cats/configuration/configuration.h" +void butterflies_cell_dispersal(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion); + #endif //CATS_BUTTERFLIES_DISPERSAL_H diff --git a/src/modules/butterflies/random_walk.c b/src/modules/butterflies/random_walk.c deleted file mode 100644 index e4e4c976473a4af8e1fdd7f60e7e1230f6559cd7..0000000000000000000000000000000000000000 --- a/src/modules/butterflies/random_walk.c +++ /dev/null @@ -1,156 +0,0 @@ -// -// Created by gattringera on 22/06/22. -// -#include <math.h> -#include "random_walk.h" -#include "inline_overlays.h" -#include "modules/module_header.h" -#include "populations/carrying_capacity.h" -#include "misc/cats_random.h" -#include "populations/population.h" -#include "butterflies_main.h" -#include "butterflies_inline.h" -#include "inline_population.h" - -const int N_DIRECTIONS = 9; -/* - * directions - * 4 3 2 - * 5 0 1 - * 6 7 8 - */ - -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} -}; - -static inline bool suitable_for_egg_laying(const struct cats_configuration *conf, struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) -{ - - if (cell_excluded_by_overlay(conf, row, col)) return false; - - if (conf->overlays.overlay[OL_RESOURCE].enabled) { - double resources = conf->overlays.resources->data[row][col]; - if (resources <= 0) return false; - - } - - if (conf->overlays.overlay[OL_HABITAT_TYPE_CC].enabled) { - double multiplier = conf->overlays.habitat_cc->data[row][col]; - if (multiplier < 0.0) { return false; } - } - - - return true; -} - -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, int32_t rw_num) -{ - const struct cats_configuration *conf = ts->conf; - - const int module_id = CATS_MODULE_ID; - struct grid_data_butterflies *data = grid->grid_modules[module_id].module_data; - struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; - - int32_t eggs_left = eggs; - cats_dt_coord max_steps = module_conf->animal_dispersal_max_radius; - //double max_distance = 0; - //double distance = 0; - cats_dt_coord steps = 0; - bool done = false; - cats_dt_coord row = source_row; - cats_dt_coord col = source_col; - int32_t deposition_count = 0; - /* - if (row == BF_DEBUG_ROW && col == BF_DEBUG_COL ) { - printf("rw,run,row,col,step,deposit,eggs_left,thread_id\n"); - printf("rw,%d,%d,%d,%d,%d,%d,%d\n", rw_num, row, col, 0, 0, eggs_left,ts->id); - } - */ - while (! done) { - //bool accepted = false; - unsigned long int direction = gsl_rng_uniform_int(ts->rng, N_DIRECTIONS); - cats_dt_coord *offsets = DIRECTION_OFFSETS[direction]; - cats_dt_coord row_offset = offsets[0]; - cats_dt_coord col_offset = offsets[1]; - assert(row_offset >= -1 && row_offset <= 1); - assert(col_offset >= -1 && col_offset <= 1); - row += row_offset; - col += col_offset; - if (row >= grid->dimension.rows || row < 0 || col >= grid->dimension.cols || col < 0) { - //printf("out of bounds %d %d - %d %d\n", row, col, grid->dimension.rows, grid->dimension.cols); - return; // we escaped the simulation extent and got lost - } - steps++; -/* - double this_distance = sqrt((row_offset * row_offset) + (col_offset * col_offset)); - if (distance + this_distance <= max_distance) { - accepted = true; - distance += this_distance; - } else { - accepted = false; - done = true; - } - if (!accepted) return; -*/ - - int32_t eggs_to_deposit = 0; - if (suitable_for_egg_laying(conf, grid, row, col)) { - deposition_count++; - eggs_to_deposit = (int32_t) ceilf((float) eggs_left/(2.0f)); - assert(eggs_to_deposit >= 0); - - if (eggs_to_deposit > eggs_left) { - eggs_to_deposit = eggs_left; - } - eggs_left -= eggs_to_deposit; - data->eggs[row][col] += (float) eggs_to_deposit; - - - } - /* - if (source_row == BF_DEBUG_ROW && source_col == BF_DEBUG_COL ) { - printf("rw,%d,%d,%d,%d,%d,%d,%d\n", rw_num, row, col, steps, eggs_to_deposit,eggs_left,ts->id); - } - */ - - if (steps >= max_steps || eggs_left == 0) done = true; - } - //printf("rw,%d,%d,%d,%d,%d,%d,%d\n", rw_num, row, col, steps, 0,eggs_left,ts->id); - fflush(stdout); - assert(eggs_left >= 0); -} - - -void butterflies_random_walk(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; - - // 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 population = get_adult_population(grid, row, col); - int32_t dispersing_population = population; - struct conf_data_butterflies *module_conf = CATS_MODULE_DATA; - cats_dt_population N = get_adult_population(grid, row, col); - cats_dt_rates eggs = calculate_rate(&module_conf->eggs_per_female, N, &grid->param, grid, row, col, NULL); - int32_t e = (int32_t) ceill(eggs); - assert(e >= 0); - if (e == 0) return; - if (dispersing_population > 0) ts->temp1++; - if (dispersing_population == 0) return; - - for (int32_t p = 0; p < dispersing_population; p++) { - - single_random_walk(ts, grid, row, col, e, p); - ts->temp++; - - - } - //exit_cats(EXIT_SUCCESS); -} diff --git a/src/modules/butterflies/random_walk.h b/src/modules/butterflies/random_walk.h deleted file mode 100644 index f2cdafb486b3c69c118b73e6680b7e2065656905..0000000000000000000000000000000000000000 --- a/src/modules/butterflies/random_walk.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef CATS_RANDOM_WALK_H -#define CATS_RANDOM_WALK_H -#include "cats/configuration/configuration.h" -#include "threading/threading.h" - -void butterflies_random_walk(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coord row, cats_dt_coord col, bool check_exclusion); -#endif //CATS_RANDOM_WALK_H