diff --git a/NEWS.md b/NEWS.md index 393c2bfa..fbe5e79e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ -# naomi 2.10.2 +naomi 2.10.3 +* Improve error generated when user fits model at admin level where no population data exists. + +naomi 2.10.2 * Add ANC testing outputs to T4 projection period for including in PEPFAR datapack output. * Rename Datapack input CSV in the output ZIP folder for 2025 to `"pepfar_datapack_indicators_2025.csv"`. * Add ANC testing indicators to T4 projection reprsenting the end of one year COP planning diff --git a/R/model.R b/R/model.R index a21d8f6e..663813fe 100644 --- a/R/model.R +++ b/R/model.R @@ -329,6 +329,24 @@ naomi_model_frame <- function(area_merged, ## of a Spectrum file and then calibrated. Currently no way to know if areas ## comparise only part of a Spectrum file, so can't address. + if (!all(mf_areas[["area_id"]] %in% unique(population_agesex$area_id))) { + + area_label <- area_merged |> sf::st_drop_geometry() |> + dplyr::select(area_level_label, area_level, area_id) + + # Get level label for pop data + pop_label <- population_agesex |> + dplyr::left_join(area_label, by = dplyr::join_by(area_id)) + pop_level <- unique(pop_label$area_level_label) + + # Get area level label for model estimates + model_level <- unique(area_label[area_label$area_level== level,]$area_level_label) + + stop(t_("MISSING_POP_LEVEL", + list(pop_level = paste(pop_level, collapse = ", "), + model_level = model_level))) + } + pop_subset <- dplyr::filter(population_agesex, area_id %in% mf_areas[["area_id"]]) pop_t1 <- interpolate_population_agesex(pop_subset, calendar_quarter1) pop_t2 <- interpolate_population_agesex(pop_subset, calendar_quarter2) diff --git a/inst/traduire/en-translation.json b/inst/traduire/en-translation.json index 84b9ef28..a21d59fb 100644 --- a/inst/traduire/en-translation.json +++ b/inst/traduire/en-translation.json @@ -43,7 +43,7 @@ "PROGRESS_CALIBRATE": "Calibrating outputs - {{elapsed}} elapsed", "PROGRESS_CALIBRATE_SAVE_OUTPUT": "Saving outputs - {{elapsed}} elapsed", "PROGRESS_CALIBRATE_GENERATE_REPORT": "Generating report - {{elapsed}} elapsed", - "NO_ART_DATA_FOR_QUARTER": "No ART data found for quarter {{calendar_quarter}}.\nSet 'Include ART data' to 'No' if you intend to include no ART data.", + "NO_ART_DATA_FOR_QUARTER": "No ART data found for quarter {{calendar_quarter}}.\nIf you do not intend to include ART data set 'Include ART data' to 'No'.", "ANC_ON_ART_GREATER_THAN_TOTAL_POSITIVE": "ANC testing on ART greater than ANC testing total positive.", "ANC_DATA_MISSING_FOR_YEAR": "ANC testing data not found for year {{missing_year}}.", "ANC_DATA_MISSING_FOR_YEAR_PLURAL": "ANC testing data not found for years {{missing_year}}.", @@ -276,5 +276,6 @@ "DOWNLOAD_AGYW_DESCRIPTION": "Naomi AGYW tool uploaded from Naomi web app", "NUMBER_ON_ART": "Number on ART", "NUMBER_ON_ART_DESC": "Number on ART description", + "MISSING_POP_LEVEL": "Unable to generate model estimates at the {{model_level}} level because population data only available at the {{pop_level}} level/s. Please review model options or population data inputs.", "POPULATION_PROPORTION": "Population proportion" } diff --git a/inst/traduire/fr-translation.json b/inst/traduire/fr-translation.json index db8c5e35..7b8e5a72 100644 --- a/inst/traduire/fr-translation.json +++ b/inst/traduire/fr-translation.json @@ -273,5 +273,7 @@ "DOWNLOAD_COMPARISON_DESCRIPTION": "Rapport de comparaison Naomi téléchargé à partir de l'application web Naomi", "NUMBER_ON_ART": "Nombre de personnes sous TARV", "NUMBER_ON_ART_DESC": "Number on ART description", + "MISSING_POP_LEVEL": "Impossible de générer des estimations de modèle au niveau {{model_level}} car les données de population ne sont disponibles qu'au niveau {{pop_level}}. Veuillez revoir les options du modèle ou les données démographiques.", "POPULATION_PROPORTION": "Proportion de la population" + } diff --git a/inst/traduire/pt-translation.json b/inst/traduire/pt-translation.json index fdaa15e0..c2d31675 100644 --- a/inst/traduire/pt-translation.json +++ b/inst/traduire/pt-translation.json @@ -273,5 +273,6 @@ "DOWNLOAD_COMPARISON_DESCRIPTION": "Relatório de comparação Naomi carregado a partir da aplicação web Naomi", "NUMBER_ON_ART": "Nombre de personnes sous TARV", "NUMBER_ON_ART_DESC": "Number on ART description", + "MISSING_POP_LEVEL": "Não é possível gerar estimativas do modelo ao nível {{model_level}} porque os dados da população só estão disponíveis ao nível {{pop_level}}. Reveja as opções do modelo ou as entradas de dados da população.", "POPULATION_PROPORTION": "Proporção da população" } diff --git a/tests/testthat/test-02-model-options.R b/tests/testthat/test-02-model-options.R index e96f421c..47b057fe 100644 --- a/tests/testthat/test-02-model-options.R +++ b/tests/testthat/test-02-model-options.R @@ -298,3 +298,26 @@ test_that("Handle backwards regression when T4 and T5 options are missing", { expect_equal(t5 - t3, 9) }) + +test_that("Population data available for area level set in model options", { + + expect_error(naomi_model_frame(a_area_merged, + demo_population_agesex, + a_spec, + scope = "MWI_1_1_demo", + level = 3, + calendar_quarter1 = "CY2016Q1", + calendar_quarter2 = "CY2018Q4", + calendar_quarter3 = "CY2019Q2", + calendar_quarter4 = "CY2022Q3", + calendar_quarter5 = "CY2023Q3", + artattend = FALSE, + spectrum_population_calibration = "none", + psnu_level = NULL), + paste("Unable to generate model estimates at the District level because", + "population data only available at the District + Metro level/s.", + "Please review model options or population data inputs."), + fixed = TRUE) + + +}) diff --git a/tests/testthat/test-04-model-frame.R b/tests/testthat/test-04-model-frame.R index 591312e3..bdfe451e 100644 --- a/tests/testthat/test-04-model-frame.R +++ b/tests/testthat/test-04-model-frame.R @@ -41,7 +41,7 @@ test_that("artnum_mf() returns expected number of records", { test_that("artnum_mf() throws errors for invalid inputs", { expect_error(artnum_mf("CY1924Q4", demo_art_number, a_naomi_mf), - "No ART data found for quarter CY1924Q4.\nSet 'Include ART data' to 'No' if you intend to include no ART data.") + "No ART data found for quarter CY1924Q4.\nIf you do not intend to include ART data set 'Include ART data' to 'No'.") expect_error(artnum_mf("CY2016Q1", demo_art_number, "jibberish")) expect_error(artnum_mf(c("CY2016Q1", "CY2016Q2"), demo_art_number, "jibberish")) }) @@ -53,7 +53,26 @@ test_that("artnum_mf() works with single quarter ART data", { }) +test_that("Informative error displayed when model run to admin level higher/lower than population data supplied", { + x <- expect_error( + naomi_model_frame(a_area_merged, + demo_population_agesex, + a_spec, + scope = "MWI", + level = 3, + calendar_quarter1 = "CY2016Q1", + calendar_quarter2 = "CY2018Q4", + calendar_quarter3 = "CY2019Q2", + calendar_quarter4 = "CY2022Q3", + calendar_quarter5 = "CY2023Q3")) + expect_equal( + x$message, + paste("Population data not available for admin level selected", + "for model projections. Please review model options", + "selection to ensure that area level selection is correct.") + ) +}) test_that("population calibration options", { @@ -85,7 +104,7 @@ test_that("population calibration options", { mf_none$mf_model$population_t2 + mf_none$mf_model$population_t3 + mf_none$mf_model$population_t4 + - mf_none$mf_model$population_t5 + mf_none$mf_model$population_t5 ), sum(mf_none$spectrum_calibration$population_raw)) @@ -102,7 +121,7 @@ test_that("population calibration options", { calendar_quarter2 = "CY2018Q4", calendar_quarter3 = "CY2019Q2", calendar_quarter4 = "CY2022Q3", - calendar_quarter5 = "CY2023Q3", + calendar_quarter5 = "CY2023Q3", spectrum_population_calibration = "national") expect_false(sum(mf_nat$spectrum_calibration$population_raw) == @@ -132,7 +151,7 @@ test_that("population calibration options", { calendar_quarter2 = "CY2018Q4", calendar_quarter3 = "CY2019Q2", calendar_quarter4 = "CY2022Q3", - calendar_quarter5 = "CY2023Q3", + calendar_quarter5 = "CY2023Q3", spectrum_population_calibration = "subnational") expect_false(sum(mf_subnat$spectrum_calibration$population_raw) == @@ -162,7 +181,7 @@ test_that("population calibration options", { calendar_quarter2 = "CY2018Q4", calendar_quarter3 = "CY2019Q2", calendar_quarter4 = "CY2022Q3", - calendar_quarter5 = "CY2023Q3", + calendar_quarter5 = "CY2023Q3", spectrum_population_calibration = "jibberish"), "spectrum_calibration_option \"jibberish\" not found." ) @@ -319,7 +338,7 @@ test_that("naomi_model_frame() interpolated population depends on quarter specif calendar_quarter2 = "CY2018Q4", calendar_quarter3 = "CY2019Q2", calendar_quarter4 = "CY2022Q3", - calendar_quarter5 = "CY2023Q3", + calendar_quarter5 = "CY2023Q3", spectrum_population_calibration = "subnational")