From f94dacf1cba1e912c02d6903d61ac41d4618ecb1 Mon Sep 17 00:00:00 2001 From: Andreas Gattringer <andreas.gattringer@univie.ac.at> Date: Wed, 19 Jul 2023 08:58:56 +0200 Subject: [PATCH] preparations for multi-scale simulations - new functions to access input grids (overlay, environment) these will be used to translate between input layer coordinates and population grid coordinates - overdue helper function to set environment values - helper function to check to copy and verify grid dimension info --- src/cats/CMakeLists.txt | 2 +- src/cats/actions/setup.c | 6 +++-- src/cats/debug/debug_vital_rates.c | 6 ++--- src/cats/environment/environment.c | 14 +++++----- src/cats/environment/environment_rasters.c | 4 +-- src/cats/grids/dimensions.c | 29 +++++++++++++++++++++ src/cats/grids/dimensions.h | 12 +++++++++ src/cats/grids/direct_access.c | 28 ++++++++++++++++++++ src/cats/grids/direct_access.h | 10 +++++++ src/cats/inline.h | 18 +++++++++---- src/cats/inline_overlays.h | 9 ++++--- src/cats/inline_population.h | 16 ++++-------- src/cats/overlays/overlay_habitat_type_cc.c | 18 +++++++++++++ src/cats/overlays/overlay_habitat_type_cc.h | 3 +++ src/cats/populations/carrying_capacity.c | 8 +++--- src/cats/vital_rates/direct_functions.c | 3 ++- src/cats/vital_rates/glm_functions.c | 4 +-- 17 files changed, 148 insertions(+), 42 deletions(-) create mode 100644 src/cats/grids/dimensions.c create mode 100644 src/cats/grids/dimensions.h create mode 100644 src/cats/grids/direct_access.c create mode 100644 src/cats/grids/direct_access.h diff --git a/src/cats/CMakeLists.txt b/src/cats/CMakeLists.txt index 00239ae..fb05cbc 100644 --- a/src/cats/CMakeLists.txt +++ b/src/cats/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories(${GDAL_INCLUDE_DIR}) include_directories(${GSL_INCLUDE_DIR}) include_directories(${MPI_C_INCLUDE_PATH}) -add_library(libcats STATIC "" stats/statistics.c stats/statistics.h data/cats_global.c ../cats_windows.h test/test_ini.c test/test_ini.h debug/debug_vital_rates.c debug/debug_vital_rates.h overlays/overlay_resources.c overlays/overlay_resources.h paths/path_patterns.c paths/path_patterns.h) +add_library(libcats STATIC "" stats/statistics.c stats/statistics.h data/cats_global.c ../cats_windows.h test/test_ini.c test/test_ini.h debug/debug_vital_rates.c debug/debug_vital_rates.h overlays/overlay_resources.c overlays/overlay_resources.h paths/path_patterns.c paths/path_patterns.h grids/dimensions.c grids/dimensions.h grids/direct_access.c grids/direct_access.h) target_include_directories(libcats PUBLIC ".") target_sources(libcats PRIVATE diff --git a/src/cats/actions/setup.c b/src/cats/actions/setup.c index d88079d..7252e60 100644 --- a/src/cats/actions/setup.c +++ b/src/cats/actions/setup.c @@ -37,6 +37,7 @@ #include "temporal/simulation_time.h" #include "populations/population.h" #include "dispersal/dispersal.h" +#include "inline.h" void setup_lambda_test_simulation(struct cats_configuration *conf, struct cats_grid *grid) // FIXME MAYBE MOVE @@ -55,7 +56,7 @@ void setup_lambda_test_simulation(struct cats_configuration *conf, struct cats_g cats_dt_coord row = 0; cats_dt_coord col = 0; - grid->suitability->environments[0]->current.values[row][col] = (cats_dt_environment) grid->param.OT; // FIXME -> set suitability + set_suitability(grid, row, col, (cats_dt_environment) grid->param.OT); cats_dt_population target_pop = get_adult_carrying_capacity(grid, row, col) / 5; set_population_ignore_cc(grid, row, col, target_pop); @@ -94,7 +95,8 @@ void setup_lambda_gradient_simulation(struct cats_configuration *conf, struct ca cats_dt_environment diff = 1.0f / ((cats_dt_environment) conf->geometry.dimension.cols - 1.0f); for (cats_dt_coord row = 0; row < rows; row++) { for (cats_dt_coord col = 0; col < cols; col++) { - grid->suitability->environments[0]->current.values[row][col] = (cats_dt_environment) col * diff; + cats_dt_environment value = (cats_dt_environment) col * diff; + set_suitability(grid, row, col, value); } } diff --git a/src/cats/debug/debug_vital_rates.c b/src/cats/debug/debug_vital_rates.c index ec6f362..4e3de11 100644 --- a/src/cats/debug/debug_vital_rates.c +++ b/src/cats/debug/debug_vital_rates.c @@ -90,7 +90,7 @@ struct cats_grid *minimal_grid(struct cats_configuration *conf, struct cats_envi } -void set_suitability(struct cats_environment *env, cats_dt_environment suit) +void debug_set_suitability(struct cats_environment *env, cats_dt_environment suit) { env->environments[0]->current.values[0][0] = suit; } @@ -138,7 +138,7 @@ static inline cats_dt_rates attempt_rate_calculation(cats_dt_environment suit, c } - set_suitability(grid->suitability, suit); + debug_set_suitability(grid->suitability, suit); *K_suit = get_adult_carrying_capacity(grid, 0, 0); if (N > *K_suit) return NAN; @@ -209,7 +209,7 @@ void debug_vital_rate(struct cats_vital_rate *vr, struct cats_vital_rate *cc, st void debug_vital_rates(struct cats_configuration *conf, const struct program_options *command_line_options) { struct cats_environment *env = minimal_suitability_environment(); - set_suitability(env, 0.5f); + debug_set_suitability(env, 0.5f); struct cats_grid *grid = minimal_grid(conf, env); struct cats_species_param *param = &grid->param; set_param_values(param, 0.5, 0.25, 0.5); diff --git a/src/cats/environment/environment.c b/src/cats/environment/environment.c index 0f85e76..290fe3d 100644 --- a/src/cats/environment/environment.c +++ b/src/cats/environment/environment.c @@ -38,6 +38,7 @@ #include "environment.h" #include "grids/gdal_load.h" #include "environment/environment_rasters.h" +#include "grids/dimensions.h" #ifdef USEMPI #include "mpi/mpi_save.h" @@ -69,10 +70,10 @@ void interpolate_environment(const struct cats_configuration *conf, const cats_dt_coord rows = environment->current.dimension.rows; const cats_dt_coord cols = environment->current.dimension.cols; - if (environment->start.dimension.rows != environment->end.dimension.rows - || environment->start.dimension.cols != environment->end.dimension.cols - || environment->start.dimension.rows != environment->current.dimension.rows - || environment->start.dimension.cols != environment->current.dimension.cols) { + bool matching_dimensions = dimensions_match(&environment->start.dimension, &environment->end.dimension) + && dimensions_match(&environment->start.dimension, &environment->current.dimension); + + if (!matching_dimensions) { log_message(LOG_ERROR, "%s: dimension mismatch", __func__); log_message(LOG_ERROR, "environment (start): %d x %d", environment->start.dimension.rows, environment->start.dimension.cols); @@ -149,8 +150,9 @@ load_environment_raster(struct cats_configuration *conf, struct cats_environment } unload_environment_raster(raster); - raster->dimension.rows = conf->geometry.dimension.rows; - raster->dimension.cols = conf->geometry.dimension.cols; + + copy_dimensions_from_to(&conf->geometry.dimension, &raster->dimension); + raster->interpolation_type = type; raster->environment_type = environment_type; if (raster->values == NULL) { diff --git a/src/cats/environment/environment_rasters.c b/src/cats/environment/environment_rasters.c index e7a3a12..7abcda8 100644 --- a/src/cats/environment/environment_rasters.c +++ b/src/cats/environment/environment_rasters.c @@ -27,6 +27,7 @@ #include "logging.h" #include "environment_rasters.h" #include "environment.h" +#include "grids/dimensions.h" void print_raster_quick_info(struct cats_environment_raster *gr) @@ -53,9 +54,8 @@ void create_raster_if_needed(struct cats_configuration *conf, struct cats_enviro log_message(LOG_INFO, "\tinitializing empty grid for <%s>", get_raster_type_name_specific(raster)); log_message(LOG_DEBUG, "%s: ALLOCATING NEW GRID NOW", __func__); raster->values = new_raw_2d_array_from_dimension(conf->geometry.dimension, sizeof(cats_dt_environment)); - raster->dimension.rows = conf->geometry.dimension.rows; - raster->dimension.cols = conf->geometry.dimension.cols; + copy_dimensions_from_to(&conf->geometry.dimension, &raster->dimension); } diff --git a/src/cats/grids/dimensions.c b/src/cats/grids/dimensions.c new file mode 100644 index 0000000..7445ed5 --- /dev/null +++ b/src/cats/grids/dimensions.c @@ -0,0 +1,29 @@ +#include <assert.h> +#include "dimensions.h" + + +void copy_dimensions_from_to(const struct cats_dimension *from, struct cats_dimension *to) +{ + to->rows = from->rows; + to->cols = from->cols; +} + + +bool valid_coordinates(const struct cats_dimension *dim, cats_dt_coord row, cats_dt_coord col) +{ + assert(dim != NULL); + assert(row >= 0 && row < dim->rows); + assert(col >= 0 && col < dim->cols); + if (row < 0 || col < 0) return false; + if (row >= dim->rows || col >= dim->cols) return false; + return true; +} + + +bool dimensions_match(const struct cats_dimension *dim1, const struct cats_dimension *dim2) +{ + if (dim1->rows == dim2->rows && dim1->cols == dim2->cols) { + return true; + } + return false; +} \ No newline at end of file diff --git a/src/cats/grids/dimensions.h b/src/cats/grids/dimensions.h new file mode 100644 index 0000000..b25912c --- /dev/null +++ b/src/cats/grids/dimensions.h @@ -0,0 +1,12 @@ +#ifndef CATS_DIMENSIONS_H +#define CATS_DIMENSIONS_H + +#include "memory/arrays.h" + +void copy_dimensions_from_to(const struct cats_dimension *from, struct cats_dimension *to); + +bool dimensions_match(const struct cats_dimension *dim1, const struct cats_dimension *dim2); + +bool valid_coordinates(const struct cats_dimension *dim, cats_dt_coord row, cats_dt_coord col); + +#endif //CATS_DIMENSIONS_H diff --git a/src/cats/grids/direct_access.c b/src/cats/grids/direct_access.c new file mode 100644 index 0000000..dfcefa1 --- /dev/null +++ b/src/cats/grids/direct_access.c @@ -0,0 +1,28 @@ +#include <assert.h> +#include "direct_access.h" +#include "dimensions.h" + + +double load_input_2d_array_double(const struct cats_2d_array_double *raster, cats_dt_coord row, cats_dt_coord col) +{ + valid_coordinates(&raster->dimension, row, col); + return raster->data[row][col]; +} + +char load_input_2d_array_char(const struct cats_2d_array_char *raster, cats_dt_coord row, cats_dt_coord col) +{ + valid_coordinates(&raster->dimension, row, col); + return raster->data[row][col]; +} + +cats_dt_environment load_input_environment_raster(struct cats_environment_raster *raster, cats_dt_coord row, cats_dt_coord col) +{ + valid_coordinates(&raster->dimension, row, col); + return raster->values[row][col]; +} + +void set_input_environment_raster(struct cats_environment_raster *raster, cats_dt_coord row, cats_dt_coord col, cats_dt_environment value) +{ + valid_coordinates(&raster->dimension, row, col); + raster->values[row][col] = value; +} \ No newline at end of file diff --git a/src/cats/grids/direct_access.h b/src/cats/grids/direct_access.h new file mode 100644 index 0000000..147dab2 --- /dev/null +++ b/src/cats/grids/direct_access.h @@ -0,0 +1,10 @@ +#ifndef CATS_DIRECT_ACCESS_H +#define CATS_DIRECT_ACCESS_H +#include "memory/arrays.h" +#include "environment/environment.h" + +double load_input_2d_array_double(const struct cats_2d_array_double *raster, cats_dt_coord row, cats_dt_coord col); +cats_dt_environment load_input_environment_raster(struct cats_environment_raster *raster, cats_dt_coord row, cats_dt_coord col); +void set_input_environment_raster(struct cats_environment_raster *raster, cats_dt_coord row, cats_dt_coord col, cats_dt_environment value); +char load_input_2d_array_char(const struct cats_2d_array_char *raster, cats_dt_coord row, cats_dt_coord col); +#endif //CATS_DIRECT_ACCESS_H diff --git a/src/cats/inline.h b/src/cats/inline.h index da78d77..1e3606b 100644 --- a/src/cats/inline.h +++ b/src/cats/inline.h @@ -42,6 +42,7 @@ #include "inline_carrying_capacity.h" #include "inline_population.h" #include "inline_vital_ages.h" +#include "grids/dimensions.h" static inline cats_dt_environment @@ -53,7 +54,16 @@ get_suitability_from_env(const struct cats_environment *set, cats_dt_coord row, assert(col >= 0); assert(row < set->environments[0]->current.dimension.rows); assert(col < set->environments[0]->current.dimension.cols); - return set->environments[0]->current.values[row][col]; + return load_input_environment_raster(&set->environments[0]->current, row, col); +} + + +static inline void +set_suitability(struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col, cats_dt_environment value) +{ + assert(value >= 0.0f); + assert(value <= 1.0f); + set_input_environment_raster(&grid->suitability->environments[0]->current, row, col, value); } @@ -171,8 +181,7 @@ static inline cats_dt_environment get_suitability(const struct cats_grid *grid, static inline double get_seed_sum(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) { assert(grid != NULL && grid->juveniles != NULL); - assert(row >= 0 && row < grid->dimension.rows); - assert(col >= 0 && col < grid->dimension.cols); + assert(valid_coordinates(&grid->dimension, row, col)); const int32_t max_sp = get_vital_age(grid, VA_SEED_PERSISTENCE); //grid->param.seed_persistence; double sum = grid->dispersed_seeds[row][col]; if (grid->seed_bank[row][col] == NULL) return sum; @@ -187,8 +196,7 @@ 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(row >= 0 && row < grid->dimension.rows); - assert(col >= 0 && col < grid->dimension.cols); + assert(valid_coordinates(&grid->dimension, row, col)); assert(grid->juveniles[row] != NULL); const cats_dt_population *juveniles = grid->juveniles[row][col]; diff --git a/src/cats/inline_overlays.h b/src/cats/inline_overlays.h index 519689e..5f73167 100644 --- a/src/cats/inline_overlays.h +++ b/src/cats/inline_overlays.h @@ -28,6 +28,7 @@ #include "assert.h" #include "overlays/overlays.h" #include "configuration/configuration.h" +#include "grids/direct_access.h" static inline bool @@ -35,8 +36,7 @@ cell_excluded_by_habitat(const struct cats_configuration *config, cats_dt_coord { if (!config->overlays.have_overlays) return false; if (!config->overlays.overlay[OL_HABITAT_TYPE_CC].enabled) return false; - - return (config->overlays.habitat_cc->data[row][col] == 0.0); + return (load_input_2d_array_double(config->overlays.habitat_cc, row, col) == 0.0); } @@ -45,11 +45,12 @@ cell_excluded_by_overlay(const struct cats_configuration *config, cats_dt_coord { assert(config != NULL); - if (config->overlays.have_overlays == false || config->overlays.overlay[OL_EXCLUSION].enabled == false) return false; + if (config->overlays.have_overlays == false || config->overlays.overlay[OL_EXCLUSION].enabled == false) + return false; assert(config->overlays.exclusion->data != NULL); - const char value = config->overlays.exclusion->data[row][col]; + const char value = load_input_2d_array_char(config->overlays.exclusion, row, col); switch (value) { // NOLINT(hicpp-multiway-paths-covered) case OL_EXCLUSION_NOT_EXCLUDED: diff --git a/src/cats/inline_population.h b/src/cats/inline_population.h index 933b3d0..ef61806 100644 --- a/src/cats/inline_population.h +++ b/src/cats/inline_population.h @@ -34,14 +34,14 @@ #include "inline_overlays.h" #include "populations/carrying_capacity.h" #include "populations/plant_juveniles.h" +#include "grids/dimensions.h" static inline cats_dt_population get_adult_population(const struct cats_grid *grid, cats_dt_coord row, cats_dt_coord col) { assert(grid != NULL && grid->population != NULL); - assert(row >= 0 && row < grid->dimension.rows); - assert(col >= 0 && col < grid->dimension.cols); + assert(valid_coordinates(&grid->dimension, row, col)); assert(grid->population[row] != NULL); assert(grid->population[row][col] >= 0); return grid->population[row][col]; // getter @@ -83,10 +83,7 @@ reduce_population_by(const struct cats_grid *grid, cats_dt_coord row, cats_dt_co assert(to_reduce >= 0); assert(grid != NULL); assert(grid->population != NULL); - assert(row < grid->dimension.rows); - assert(col < grid->dimension.cols); - assert(row >= 0); - assert(col >= 0); + assert(valid_coordinates(&grid->dimension, row, col)); assert(grid->population[row] != NULL); //cats_dt_population cc = get_carrying_capacity(grid, row, col); @@ -105,7 +102,7 @@ set_population_ignore_cc(const struct cats_grid *grid, const cats_dt_coord row, const cats_dt_population pop) { assert(grid != NULL && grid->population != NULL); - assert(row >= 0 && row < grid->dimension.rows && col >= 0 && col < grid->dimension.cols); + assert(valid_coordinates(&grid->dimension, row, col)); assert(grid->population[row] != NULL); if (pop > CATS_MAX_POPULATION || pop < 0.0) { @@ -171,10 +168,7 @@ get_population_ts(const struct cats_grid *grid, const cats_dt_coord row, const c { assert(grid != NULL); assert(grid->population != NULL); - assert(row < grid->dimension.rows); - assert(col < grid->dimension.cols); - assert(row >= 0); - assert(col >= 0); + assert(valid_coordinates(&grid->dimension, row, col)); assert(grid->population[row] != NULL); cats_dt_population tmp = grid->population[row][col]; // getter diff --git a/src/cats/overlays/overlay_habitat_type_cc.c b/src/cats/overlays/overlay_habitat_type_cc.c index e98c258..8752843 100644 --- a/src/cats/overlays/overlay_habitat_type_cc.c +++ b/src/cats/overlays/overlay_habitat_type_cc.c @@ -30,6 +30,7 @@ #include "cats_csv/cats_csv.h" #include "logging.h" #include "memory/cats_memory.h" +#include "grids/direct_access.h" void cleanup_habitat_layer_cc_aux(void **data) @@ -139,3 +140,20 @@ struct cats_2d_array_double *translate_habitat(const struct cats_2d_array_double return result; } + + +double get_overlay_cc_multiplier(const struct cats_configuration *conf, cats_dt_coord row, cats_dt_coord col) +{ + + if (!conf->overlays.overlay[OL_HABITAT_TYPE_CC].enabled) { + return 1.0; + } + + double multiplier = load_input_2d_array_double(conf->overlays.habitat_cc, row, col); + + if (multiplier <= 0.0) { + return 0.0; + } + + return multiplier; +} \ No newline at end of file diff --git a/src/cats/overlays/overlay_habitat_type_cc.h b/src/cats/overlays/overlay_habitat_type_cc.h index c355afb..89b2997 100644 --- a/src/cats/overlays/overlay_habitat_type_cc.h +++ b/src/cats/overlays/overlay_habitat_type_cc.h @@ -26,6 +26,7 @@ #include <stdint.h> #include "../../memory/arrays.h" +#include "configuration/configuration.h" #define MAX_HABITAT_TYPE_CODES 1024 @@ -43,4 +44,6 @@ struct cats_2d_array_double *translate_habitat(const struct cats_2d_array_double struct habitat_layer_cc_aux *load_habitat_layer_cc_aux(const char *csv_file, double default_value); +double get_overlay_cc_multiplier(const struct cats_configuration *conf, cats_dt_coord row, cats_dt_coord col); + #endif //CATS_OVERLAY_HABITAT_TYPE_CC_H diff --git a/src/cats/populations/carrying_capacity.c b/src/cats/populations/carrying_capacity.c index a285ee5..1e45bca 100644 --- a/src/cats/populations/carrying_capacity.c +++ b/src/cats/populations/carrying_capacity.c @@ -28,6 +28,7 @@ #include "plants/juveniles.h" #include "inline_overlays.h" #include "inline_population.h" +#include "overlays/overlay_habitat_type_cc.h" void @@ -57,12 +58,9 @@ get_carrying_capacity(const struct cats_grid *grid, cats_dt_coord row, cats_dt_c // if we have an exclusion mask AND it is set the CC is 0 if (cell_excluded_by_overlay(conf, row, col)) { return 0; } - double multiplier = 1.0; + double multiplier = get_overlay_cc_multiplier(conf, row, col); + if (multiplier <= 0.0) { return 0; } - if (conf->overlays.overlay[OL_HABITAT_TYPE_CC].enabled) { - multiplier *= conf->overlays.habitat_cc->data[row][col]; - if (multiplier <= 0.0) { return 0; } - } cats_dt_rates cc; diff --git a/src/cats/vital_rates/direct_functions.c b/src/cats/vital_rates/direct_functions.c index a421048..1599ad0 100644 --- a/src/cats/vital_rates/direct_functions.c +++ b/src/cats/vital_rates/direct_functions.c @@ -45,7 +45,8 @@ cats_dt_rates get_direct_rate(const struct cats_vital_rate *rate_info, log_message(LOG_ERROR, "%s: wrong environment set type for set '%s'", __func__, set->name); exit(EXIT_FAILURE); } - cats_dt_rates rate = set->environments[0]->current.values[row][col] * rate_info->environment_multiplier; + cats_dt_environment value = load_input_environment_raster(&set->environments[0]->current, row, col); + cats_dt_rates rate = value * rate_info->environment_multiplier; if (isnan(rate)) return 0.0f; cats_dt_rates dens_multiplier = density_multiplier(density_type, N, K, rate_info->density_ts); diff --git a/src/cats/vital_rates/glm_functions.c b/src/cats/vital_rates/glm_functions.c index 60a9c3e..0be349a 100644 --- a/src/cats/vital_rates/glm_functions.c +++ b/src/cats/vital_rates/glm_functions.c @@ -45,13 +45,13 @@ cats_dt_rates get_glm(const struct cats_vital_rate *rate_info, if (set->glm.type == GLM_QUADRATIC) { for (int32_t i = 0; i < set->count; i++) { - const cats_dt_rates predictor = set->environments[i]->current.values[row][col]; + const cats_dt_rates predictor = load_input_environment_raster(&set->environments[i]->current, row, col); result += predictor * set->glm.linear[i] + predictor * predictor * set->glm.quadratic[i]; } } else if (set->glm.type == GLM_LINEAR) { for (int32_t i = 0; i < set->count; i++) { - const cats_dt_rates predictor = set->environments[i]->current.values[row][col]; + const cats_dt_rates predictor = load_input_environment_raster(&set->environments[i]->current, row, col); result += predictor * set->glm.linear[i]; } } else { -- GitLab