diff --git a/src/cats/actions/process_inter_period_survival.c b/src/cats/actions/process_inter_period_survival.c index 0f6d0509820d51ede8fadfdb39abad906bb07c44..24c48b3000a25ca838e877d9d10e590efec142e9 100644 --- a/src/cats/actions/process_inter_period_survival.c +++ b/src/cats/actions/process_inter_period_survival.c @@ -66,13 +66,9 @@ void write_stats(struct cats_grid *grid, const struct cats_configuration *conf, } } - for (int32_t i = 0; i < max_age_of_maturity + 1; i++) { - if (g->juveniles[0][0]) { - fprintf(f, ",%d", g->juveniles[0][0][i]); - } else { - fprintf(f, ",%d", 0); - } + for (int32_t i = 0; i < max_age_of_maturity + 1; i++) { + fprintf(f, ",%d", get_juveniles(g, 0, 0, i)); } fprintf(f, "\n"); diff --git a/src/cats/grids/cats_grid.c b/src/cats/grids/cats_grid.c index 3ddb38ed12b0caf63ebb524979880918086b7279..b3edba612207830d1238ac09480daa84701def54 100644 --- a/src/cats/grids/cats_grid.c +++ b/src/cats/grids/cats_grid.c @@ -266,7 +266,7 @@ void cleanup_grid_seeds_and_juveniles(struct cats_grid *grid) destroy_juveniles(grid, row, col); } - free(grid->juveniles[row]); + free(grid->juveniles[row]); // clean-up [cleanup_grid_seeds_and_juveniles] } } diff --git a/src/cats/grids/gdal_save.c b/src/cats/grids/gdal_save.c index 89d05a6e264a0931c115cb3520880ff8d74b51d1..6a2e0a244b11a08f903391cce702a10606134692 100644 --- a/src/cats/grids/gdal_save.c +++ b/src/cats/grids/gdal_save.c @@ -221,11 +221,7 @@ void *save_juveniles_to_gdal(struct cats_grid *grid, struct cats_configuration * sizeof(int32_t));//new_int32t_grid(grid->rows, grid->cols); for (cats_dt_coord row = 0; row < rows; row++) { for (cats_dt_coord col = 0; col < cols; col++) { - if (grid->juveniles[row][col]) { - juvs[row][col] = grid->juveniles[row][col][i]; - } else { - juvs[row][col] = 0; - } + juvs[row][col] = get_juveniles(grid, row, col, i); } } struct cats_dimension dim = {.rows = rows, .cols = cols}; diff --git a/src/cats/grids/grid_setup.c b/src/cats/grids/grid_setup.c index 899ce48177ece06f06e2c4f96b07846440a0e0d3..3f879c20afa42ce1dc704d4a1c2a1870667337f9 100644 --- a/src/cats/grids/grid_setup.c +++ b/src/cats/grids/grid_setup.c @@ -98,10 +98,10 @@ void setup_grid_juvenile_structures_opt(struct cats_configuration *conf, struct grid->juveniles = calloc_or_die(grid->dimension.rows, sizeof(cats_dt_population **)); for (cats_dt_coord row = 0; row < grid->dimension.rows; row++) { - grid->juveniles[row] = calloc_or_die(grid->dimension.cols, sizeof(cats_dt_population *)); + grid->juveniles[row] = calloc_or_die(grid->dimension.cols, sizeof(cats_dt_population *)); // initialisation [setup_grid_juvenile_structures_opt] for (cats_dt_coord col = 0; col < grid->dimension.cols; col++) { - grid->juveniles[row][col] = NULL; + grid->juveniles[row][col] = NULL; // initialisation [setup_grid_juvenile_structures_opt] } } } diff --git a/src/cats/inline.h b/src/cats/inline.h index fe3ae806afc01023a11ee094600c41b24e2a5f74..cb0f3b5c0a46255c77760fd78e1753426867c5ce 100644 --- a/src/cats/inline.h +++ b/src/cats/inline.h @@ -319,19 +319,16 @@ static inline cats_dt_population_sum get_juvenile_sum(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) { assert(grid != NULL && grid->juveniles != NULL); - assert(valid_coordinates(&grid->dimension, row, col)); - assert(grid->juveniles[row] != NULL); + if (!juveniles_exist(grid, row, col)) return 0; - const cats_dt_population *juveniles = grid->juveniles[row][col]; - if (juveniles == NULL) return 0; + const cats_dt_population *juveniles = grid->juveniles[row][col]; // getter [get_juvenile_sum] cats_dt_population_sum juvenile_sum = 0; - const int32_t max_stage = - get_vital_age(grid, VA_AGE_OF_MATURITY_MAX) + 1; //grid->param.max_age_of_maturity + 1; + const int32_t max_stage = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX) + 1; + for (int32_t i = 0; i < max_stage; i++) { - juvenile_sum += juveniles[i]; + juvenile_sum += juveniles[i]; // getter [get_juvenile_sum] } - return juvenile_sum; } diff --git a/src/cats/inline_overlays.h b/src/cats/inline_overlays.h index 1de2612958c8c58229d7b91d7716316fa42b0b79..5248ecb2a67bcae8df8a5badcd96b782e0b70df7 100644 --- a/src/cats/inline_overlays.h +++ b/src/cats/inline_overlays.h @@ -39,7 +39,6 @@ cell_excluded_by_habitat(const struct cats_configuration *config, cats_dt_coord return (load_input_2d_array_double(config->overlays.habitat_cc, row, col) == 0.0); } - static inline bool cell_excluded_by_overlay(const struct cats_configuration *config, cats_dt_coord row, cats_dt_coord col) { diff --git a/src/cats/inline_population.h b/src/cats/inline_population.h index 0a1c7d225d29c00f2760c70337131da90cad1255..f537dad855770c1e3312e9b06cdfee01d33cae7d 100644 --- a/src/cats/inline_population.h +++ b/src/cats/inline_population.h @@ -35,13 +35,13 @@ #include "populations/carrying_capacity.h" #include "populations/plant_juveniles.h" #include "grids/dimensions.h" +#include "inline_vital_ages.h" + static inline bool valid_population_grid(const struct cats_grid *grid, cats_dt_coord row) { - if (grid == NULL) return false; - if (grid->population == NULL) return false; - if (grid->population[row] == NULL) return false; // validator [valid_population_grid] - return true; + if (grid && grid->population && grid->population[row]) return true; // validator [valid_population_grid] + return false; } static inline bool valid_juvenile_grid(const struct cats_grid *grid, cats_dt_coord row) @@ -53,12 +53,27 @@ static inline bool valid_juvenile_grid(const struct cats_grid *grid, cats_dt_coo } -static inline cats_dt_population get_juveniles(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, int year) +static inline bool juveniles_exist(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) { - assert(valid_juvenile_grid(grid, row)); assert(valid_coordinates(&grid->dimension, row, col)); - if (grid->juveniles[row][col] == NULL) return 0; - return grid->juveniles[row][col][year]; + assert(valid_juvenile_grid(grid, row)); + return grid->juveniles[row][col] != NULL; // validator [juveniles_exist] +} + +static inline cats_dt_population get_juveniles(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, int year) +{ + if (juveniles_exist(grid, row, col) == false) return 0; + assert(year < get_vital_age(grid, VA_AGE_OF_MATURITY_MAX) + 1); + // FIXME check year + return grid->juveniles[row][col][year]; // getter [get_juveniles] +} + +static inline void set_juveniles(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, int year, cats_dt_population juv) +{ + assert(juveniles_exist(grid, row, col)); + assert(year < get_vital_age(grid, VA_AGE_OF_MATURITY_MAX) + 1); + assert(juv >= 0); + grid->juveniles[row][col][year] = juv; // setter [set_juveniles] } diff --git a/src/cats/misc/debug.c b/src/cats/misc/debug.c index 9683654bf17849cf49f9ca4d343c9f941b5ba8b0..487140b58696b6feb281fcfc7984a82e1deeef61 100644 --- a/src/cats/misc/debug.c +++ b/src/cats/misc/debug.c @@ -30,8 +30,8 @@ static inline cats_dt_population debug_get_juveniles(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, int year) { - if (grid->juveniles[row][col] == NULL) return 0; - return grid->juveniles[row][col][year]; + if (grid->juveniles[row][col] == NULL) return 0; // debug [debug_get_juveniles] + return grid->juveniles[row][col][year]; // debug [debug_get_juveniles] } void diff --git a/src/cats/plants/inter_period.c b/src/cats/plants/inter_period.c index 267c2883d9ab49ed161dd4ab318652e9d6325bfc..c8d4eeb68857495ce3e1593b777dd559e075f797 100644 --- a/src/cats/plants/inter_period.c +++ b/src/cats/plants/inter_period.c @@ -90,7 +90,8 @@ void inter_period_survival_seeds(struct cats_grid *grid, struct cats_configurati void inter_period_survival_juveniles(struct cats_grid *grid, struct cats_configuration *conf, cats_dt_coord row, cats_dt_coord col, struct cats_thread_info *ts) { - if (grid->juveniles[row][col] == NULL) return; + if (juveniles_exist(grid, row, col) == false) return; + const int32_t mat_max = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX); const int32_t mat_min = get_vital_age(grid, VA_AGE_OF_MATURITY_MIN); @@ -103,30 +104,34 @@ void inter_period_survival_juveniles(struct cats_grid *grid, struct cats_configu germination_to_adult_survival, &grid->param); for (int32_t i = 0; i <= mat_max; i++) { + cats_dt_rates modified_juvenile_transition_rate = age_modified_juvenile_survival_rate( juvenile_transition_rate, i, mat_min, mat_max); + cats_dt_rates juvenile_mortality = (1.0 - modified_juvenile_transition_rate); assert(juvenile_mortality >= 0 && juvenile_mortality <= 1.0); - assert(grid->juveniles[row][col][i] >= 0); + cats_dt_population juveniles_i = get_juveniles(grid, row, col, i); + assert(juveniles_i >= 0); + cats_dt_population dying = poisson_population_capped(ts->rng, - (cats_dt_rates) grid->juveniles[row][col][i] * + (cats_dt_rates) juveniles_i * juvenile_mortality, - grid->juveniles[row][col][i]); + juveniles_i); + set_juveniles(grid, row, col, i, juveniles_i - dying); - grid->juveniles[row][col][i] = grid->juveniles[row][col][i] - dying; - assert(grid->juveniles[row][col][i] >= 0); + assert(get_juveniles(grid, row, col, i) >= 0); } // advance juvenile stage (after transition rates have been applied) for (int32_t stage = mat_max; stage > 0; stage--) { - grid->juveniles[row][col][stage] = grid->juveniles[row][col][stage - 1]; + cats_dt_population juveniles_younger = get_juveniles(grid, row, col, stage - 1); + set_juveniles(grid, row, col, stage, juveniles_younger); } // youngest stage now empty - grid->juveniles[row][col][0] = 0; - + set_juveniles(grid, row, col, 0, 0); } diff --git a/src/cats/plants/juveniles.c b/src/cats/plants/juveniles.c index 010876337f050000f6bd887f89553e0c4cf72d7c..a83e1e6e88cf8b2e243cd0e5fe6014f8ef6bd162 100644 --- a/src/cats/plants/juveniles.c +++ b/src/cats/plants/juveniles.c @@ -54,21 +54,23 @@ juvenile_adult_transition(struct cats_grid *g, cats_dt_coord row, cats_dt_coord // once the cell is full, we stop and juveniles have to wait at least until // the next year to have a chance to mature + // FIXME check max age! for (int32_t age = mat_max; age >= mat_min; age--) { - cats_dt_population juveniles = g->juveniles[row][col][age]; + cats_dt_population juveniles = get_juveniles(g, row, col, age); if (juveniles == 0) continue; // the cell_maturation rate depends on the age -- the older the juvenile, the higher the probability to mature cats_dt_rates maturation_rate = age_specific_maturation_rate(age, juvenile_survival_rate, mat_min, mat_max); + cats_dt_population newly_matured = poisson_population_capped(ts->rng, (cats_dt_rates) juveniles * maturation_rate, juveniles); newly_matured = min_population_t(newly_matured, space_left); + set_juveniles(g, row, col, age, juveniles - newly_matured); - g->juveniles[row][col][age] = juveniles - newly_matured; - assert(g->juveniles[row][col][age] >= 0); + assert(get_juveniles(g, row, col, age) >= 0); newly_matured_sum += newly_matured; space_left -= newly_matured; @@ -100,8 +102,7 @@ cell_maturation(struct cats_grid *grid, struct cats_thread_info *ts, cats_dt_coo #else if (__builtin_expect(cell_excluded_by_overlay(conf, row, col), false)) { return 0; } #endif - - if (grid->juveniles[row][col] == NULL) return 0; + if (juveniles_exist(grid, row, col) == false) return 0; const int32_t mat_max = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX); const int32_t mat_min = get_vital_age(grid, VA_AGE_OF_MATURITY_MIN); diff --git a/src/cats/plants/plant_structures.c b/src/cats/plants/plant_structures.c index cd36a398abb9c890df539615c40432c9a368994b..3218cdfcc5cdfe722403939b43b30984601f4316 100644 --- a/src/cats/plants/plant_structures.c +++ b/src/cats/plants/plant_structures.c @@ -85,19 +85,18 @@ inline void create_juvenile_structure_if_needed(struct cats_grid *grid, const cats_dt_coord row, const cats_dt_coord col) { - if (grid->juveniles[row][col]) return; + if (juveniles_exist(grid, row, col)) return; const int32_t max_age_of_maturity = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX); - - grid->juveniles[row][col] = create_juvenile_structure(max_age_of_maturity); + grid->juveniles[row][col] = create_juvenile_structure(max_age_of_maturity); // initialisation [create_juvenile_structure_if_needed] } void destroy_juveniles(const struct cats_grid *grid, const cats_dt_coord row, const cats_dt_coord col) { - assert(grid != NULL); - assert(row >= 0 && row < grid->dimension.rows); - assert(col >= 0 && col < grid->dimension.cols); + assert(grid != NULL); // clean-up [destroy_juveniles] + assert(row >= 0 && row < grid->dimension.rows); // clean-up [destroy_juveniles] + assert(col >= 0 && col < grid->dimension.cols); // clean-up [destroy_juveniles] assert(grid->juveniles != NULL); @@ -106,10 +105,10 @@ void destroy_juveniles(const struct cats_grid *grid, const cats_dt_coord row, co const int32_t stages = max_age_of_maturity + 1; assert(stages >= 0); - if (grid->juveniles[row] && grid->juveniles[row][col]) { - memset(grid->juveniles[row][col], 0, stages * sizeof(cats_dt_population)); - free(grid->juveniles[row][col]); - grid->juveniles[row][col] = NULL; + if (grid->juveniles[row] && grid->juveniles[row][col]) { // clean-up [destroy_juveniles] + memset(grid->juveniles[row][col], 0, stages * sizeof(cats_dt_population)); // clean-up [destroy_juveniles] + free(grid->juveniles[row][col]); // clean-up [destroy_juveniles] + grid->juveniles[row][col] = NULL; // clean-up [destroy_juveniles] } } diff --git a/src/cats/populations/carrying_capacity.c b/src/cats/populations/carrying_capacity.c index 1e45bca313bb56519b3dc56638728912bd6cdc70..6d9ef8c8d30d7f7e4c5c38a82ea272a65ddf5dc4 100644 --- a/src/cats/populations/carrying_capacity.c +++ b/src/cats/populations/carrying_capacity.c @@ -51,7 +51,7 @@ get_carrying_capacity_all_classes(struct cats_grid **grids, cats_dt_coord row, c cats_dt_population get_carrying_capacity(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) { - assert(grid->conf != NULL); + assert(grid != NULL && grid->conf != NULL); const struct cats_configuration *conf = grid->conf; @@ -63,7 +63,6 @@ get_carrying_capacity(const struct cats_grid *grid, cats_dt_coord row, cats_dt_c cats_dt_rates cc; - const struct cats_vital_rate *link = &grid->param.carrying_capacity; cc = calculate_rate(link, NAN, &grid->param, grid, row, col, NULL); @@ -89,7 +88,7 @@ cell_apply_carrying_capacity(struct cats_grid *grid, struct cats_thread_info *ts if (grid->param.default_demographics) { cats_dt_population N = get_adult_population(grid, row, col); - if (N == 0 && grid->juveniles[row][col] == NULL) return; + if (N == 0 && juveniles_exist(grid, row, col) == false) return; if (N > 0) ts->stats[grid_id].stats[CS_POPULATED_BEFORE_CC] += 1; cats_dt_population K_A = get_adult_carrying_capacity_from_cc(grid, K_tot); diff --git a/src/cats/populations/plant_juveniles.c b/src/cats/populations/plant_juveniles.c index e80a9a7c9efadfe6c2e200451d7bdb32ae0f5208..1f41a8532394afe0aa5b3b2d9793a5c2f73ac687 100644 --- a/src/cats/populations/plant_juveniles.c +++ b/src/cats/populations/plant_juveniles.c @@ -87,12 +87,12 @@ scale_down_juveniles2(struct cats_grid *grid, cats_dt_coord row, cats_dt_coord c assert(grid != NULL && grid->juveniles != NULL); assert(row >= 0 && row < grid->dimension.rows); assert(col >= 0 && col < grid->dimension.cols); - assert(grid->juveniles[row] != NULL); + assert(juveniles_exist(grid, row, col)); assert(juvenile_cc > 0); - if (grid->juveniles[row][col] == NULL || weighted_juvenile_sum == 0) return; + if (juveniles_exist(grid, row, col) == false || weighted_juvenile_sum == 0) return; if (weighted_juvenile_sum < juvenile_cc) return; - const int32_t mat_max = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX); // grid->param.max_age_of_maturity; + const int32_t mat_max = get_vital_age(grid, VA_AGE_OF_MATURITY_MAX); cats_dt_rates factor = 1.0; for (int32_t i = 0; i < mat_max + 1; i++) { @@ -121,8 +121,8 @@ scale_down_juveniles2(struct cats_grid *grid, cats_dt_coord row, cats_dt_coord c log_message(LOG_ERROR, "%s: weighted juvenile sum > juvenile CC", __func__); log_message(LOG_RAW, "sum: %"PRId64", cc %"PRId64"\n", weighted_juvenile_sum, juvenile_cc); log_message(LOG_RAW, "factor %f\n", (double) factor); - for (int32_t i = 0; i < mat_max + 1 - 1; i++) { - log_message(LOG_RAW, "juvenile stage %d: %d - multiplier %f\n", i, + for (int32_t i = 0; i < mat_max + 1; i++) { + log_message(LOG_RAW, "juvenile stage %d: %d - multiplier %f\n", i, grid->juveniles[row][col][i], (double) juvenile_cc_multiplier(&grid->param, i)); } @@ -137,7 +137,7 @@ void cell_apply_juvenile_cc(struct cats_grid *g, cats_dt_coord row, cats_dt_coord col, cats_dt_population K_tot, cats_dt_population N) { if (g->juveniles == NULL) return; - if (g->juveniles[row][col] == NULL) return; + if (juveniles_exist(g, row, col) == false) return; cats_dt_population K_J = K_tot - N; diff --git a/src/cats/populations/population.c b/src/cats/populations/population.c index e5143ea6200926e355d00f7725c0ad969b6d75b9..c6509c1443e9b9ae74f228e48b4f8ae68d8843db 100644 --- a/src/cats/populations/population.c +++ b/src/cats/populations/population.c @@ -56,14 +56,15 @@ void adjust_juvenile_populations(struct cats_configuration *conf, struct cats_gr //cats_dt_rates w = juvenile_cc_multiplier(&grid->param, i); cats_dt_rates w = grid->param.juvenile_cc_weights[i]; cats_dt_rates juv_pop = (cats_dt_rates) N * multi / w; + if (juv_pop > CATS_MAX_POPULATION) { juv_pop = CATS_MAX_POPULATION / 2.0; } - grid->juveniles[r][c][i] = round_population_safe(juv_pop); + + set_juveniles(grid, r, c, i, round_population_safe(juv_pop)); } } } - } @@ -153,7 +154,8 @@ void prune_initial_population_under_threshold(struct cats_configuration *conf, s } } - log_message(LOG_INFO, "Species '%s': pruned %"PRId64" of %"PRId64" initial populations (suitability < threshold), %"PRId64" remaining", + log_message(LOG_INFO, + "Species '%s': pruned %"PRId64" of %"PRId64" initial populations (suitability < threshold), %"PRId64" remaining", grid->param.species_name, destroyed, populated, populated - destroyed); }