From 551fccba17bc548cb1e030f83475f13ef57960f7 Mon Sep 17 00:00:00 2001 From: howew Date: Thu, 13 Aug 2026 10:09:15 -0400 Subject: [PATCH 1/4] #222 - Updated the Yost/ACS algorithm to extend the second-to-last range of the "year for lookup" by one year and to implement the A,B,C,D codes that are found in other census tract lookups. Also corrected a capitalization error in the isInvalidCounty function ("v" should have been lowercase). --- CHANGELOG.md | 1 + .../algorithms/StateCountyInputDto.java | 4 +- .../algorithms/StateCountyTractInputDto.java | 4 +- .../YostAcsPovertyInputDto.java | 77 +++-- .../YostAcsPovertyOutputDto.java | 12 + .../yostacspoverty/YostAcsPovertyUtils.java | 108 +++++-- .../YostAcsPovertyUtilsTest.java | 290 ++++++++++++++---- 7 files changed, 379 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c2a073..94b1c139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ **Changes in version 5.11 (not released yet)** +- Updated the Yost/ACS algorithm to extend the second-to-last range of the "year for lookup" by one year and to implement the A,B,C,D codes that are found in other census tract lookups. - Added 2023 calculated field for Rural Urban Continuum algorithm. - Updated the lookup for item #194 in the PRCDA algorithm to use 2024 PRCDA counties - Removed the 2017 calculated field from the PRCDA algorithm. diff --git a/src/main/java/com/imsweb/algorithms/StateCountyInputDto.java b/src/main/java/com/imsweb/algorithms/StateCountyInputDto.java index e1bf554d..a4761c34 100644 --- a/src/main/java/com/imsweb/algorithms/StateCountyInputDto.java +++ b/src/main/java/com/imsweb/algorithms/StateCountyInputDto.java @@ -57,7 +57,7 @@ public boolean hasUnknownStateOrCounty() { return isUnknownStateOrCounty(_addressAtDxState, _countyAtDxAnalysis); } - public static boolean isInValidCounty(String county) { + public static boolean isInvalidCounty(String county) { return !(isValidCounty(county) || isUnknownCounty(county)); } @@ -66,7 +66,7 @@ public static boolean isInvalidState(String state) { } public static boolean isInvalidStateOrCounty(String state, String county) { - return isInvalidState(state) || isInValidCounty(county); + return isInvalidState(state) || isInvalidCounty(county); } public static boolean isUnknownCounty(String county) { diff --git a/src/main/java/com/imsweb/algorithms/StateCountyTractInputDto.java b/src/main/java/com/imsweb/algorithms/StateCountyTractInputDto.java index 93c06491..cc376679 100644 --- a/src/main/java/com/imsweb/algorithms/StateCountyTractInputDto.java +++ b/src/main/java/com/imsweb/algorithms/StateCountyTractInputDto.java @@ -30,7 +30,7 @@ public void applyRecodes() { _censusTract2020 = _censusTract2020 == null ? "" : _censusTract2020.trim(); } - private String getCensusTractVariable(CensusTract censusTract) { + protected String getCensusTractVariable(CensusTract censusTract) { if (CensusTract.CENSUS_2000.equals(censusTract)) return _censusTract2000; if (CensusTract.CENSUS_2010.equals(censusTract)) @@ -53,7 +53,7 @@ public static boolean isInvalidCensusTract(String censusTract) { } public static boolean isInvalidStateCountyOrCensusTract(String state, String county, String censusTract) { - return isInvalidState(state) || isInValidCounty(county) || isInvalidCensusTract(censusTract); + return isInvalidState(state) || isInvalidCounty(county) || isInvalidCensusTract(censusTract); } public static boolean isUnknownCensusTract(String censusTract) { diff --git a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyInputDto.java b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyInputDto.java index 7518c3a5..c521c051 100644 --- a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyInputDto.java +++ b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyInputDto.java @@ -1,54 +1,77 @@ package com.imsweb.algorithms.yostacspoverty; -public class YostAcsPovertyInputDto { +import com.imsweb.algorithms.StateCountyTractInputDto; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; - private String _addressAtDxState; +import static com.imsweb.algorithms.yostacspoverty.YostAcsPovertyUtils.YOST_ACS_CENSUS_TRACT_PIVOT_YEAR; - private String _countyAtDxAnalysis; +public class YostAcsPovertyInputDto extends StateCountyTractInputDto { - private String _censusTract2010; - - private String _censusTract2020; + private static final String MISSING_YEAR = ""; private String _dateOfDiagnosis; + private String _yearOfDiagnosis; - public String getAddressAtDxState() { - return _addressAtDxState; + @Override + public void applyRecodes() { + super.applyRecodes(); + _dateOfDiagnosis = _dateOfDiagnosis == null ? "" : _dateOfDiagnosis.trim(); + _yearOfDiagnosis = _yearOfDiagnosis == null ? "" : _yearOfDiagnosis.trim(); } - public void setAddressAtDxState(String addressAtDxState) { - _addressAtDxState = addressAtDxState; + public int computeYearOfDiagnosis() { + if (isValidYear(_yearOfDiagnosis)) { + return Integer.parseInt(_yearOfDiagnosis); + } + return -1; } - public String getCountyAtDxAnalysis() { - return _countyAtDxAnalysis; + public String getDateOfDiagnosis() { + return _dateOfDiagnosis; } - public void setCountyAtDxAnalysis(String countyAtDxAnalysis) { - _countyAtDxAnalysis = countyAtDxAnalysis; + public void setDateOfDiagnosis(String dateOfDiagnosis) { + _dateOfDiagnosis = dateOfDiagnosis; + _yearOfDiagnosis = dateOfDiagnosis == null ? null : StringUtils.rightPad(dateOfDiagnosis, 4).substring(0, 4).trim(); } - public String getCensusTract2010() { - return _censusTract2010; + public boolean hasInvalidStateCountyCensusTractOrYear() { + if (isInvalidState(getAddressAtDxState()) || isInvalidCounty(getCountyAtDxAnalysis()) || isInvalidYear(_yearOfDiagnosis)) + return true; + // if year is missing we don't know which census tract is the right one to use, so just check both + if (isUnknownYear(_yearOfDiagnosis)) + return isInvalidCensusTract(getCensusTract2010()) || isInvalidCensusTract(getCensusTract2020()); + // year isn't missing, so check the census tract we'll end up using for the lookup + int dxYear = Integer.parseInt(_yearOfDiagnosis); + CensusTract censusTract = dxYear <= YOST_ACS_CENSUS_TRACT_PIVOT_YEAR ? CensusTract.CENSUS_2010 : CensusTract.CENSUS_2020; + return isInvalidCensusTract(getCensusTractVariable(censusTract)); } - public void setCensusTract2010(String censusTract2010) { - _censusTract2010 = censusTract2010; + public boolean hasUnknownStateCountyCensusTractOrYear() { + if (isUnknownState(getAddressAtDxState()) || isUnknownCounty(getCountyAtDxAnalysis()) || isUnknownYear(_yearOfDiagnosis)) + return true; + // if year is invalid we don't know which census tract is the right one to use, so just check both + if (isInvalidYear(_yearOfDiagnosis)) + return isUnknownCensusTract(getCensusTract2010()) || isUnknownCensusTract(getCensusTract2020()); + // year isn't invalid, so check the census tract we'll end up using for the lookup + int dxYear = Integer.parseInt(_yearOfDiagnosis); + CensusTract censusTract = dxYear <= YOST_ACS_CENSUS_TRACT_PIVOT_YEAR ? CensusTract.CENSUS_2010 : CensusTract.CENSUS_2020; + return isUnknownCensusTract(getCensusTractVariable(censusTract)); } - public String getCensusTract2020() { - return _censusTract2020; + public static boolean isInvalidYear(String year) { + return !(isValidYear(year) || isUnknownYear(year)); } - public void setCensusTract2020(String censusTract2020) { - _censusTract2020 = censusTract2020; + public static boolean isUnknownYear(String year) { + return MISSING_YEAR.equals(year); } - public String getDateOfDiagnosis() { - return _dateOfDiagnosis; + // this is private because it's meant to be more of a helper function + // I want users of this class to use the "Invalid" and "Unknown" functions + private static boolean isValidYear(String year) { + return year != null && year.length() == 4 && NumberUtils.isDigits(year); } - public void setDateOfDiagnosis(String dateOfDiagnosis) { - _dateOfDiagnosis = dateOfDiagnosis; - } } diff --git a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyOutputDto.java b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyOutputDto.java index 91bf669e..3004989e 100644 --- a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyOutputDto.java +++ b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyOutputDto.java @@ -24,6 +24,18 @@ public String getYostQuintileUS() { return _yostQuintileUS; } + public void setAllFields(String value) { + _yostQuintileUS = value; + _yostQuintileState = value; + _acsPctPovAllRaces = value; + _acsPctPovWhite = value; + _acsPctPovBlack = value; + _acsPctPovAIAN = value; + _acsPctPovAsianNHOPI = value; + _acsPctPovWhiteNonHisp = value; + _acsPctPovHispanic = value; + } + public void setYostQuintileUS(String yostQuintileUS) { _yostQuintileUS = yostQuintileUS; } diff --git a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java index 35bea004..26fa5d67 100644 --- a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java +++ b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java @@ -1,16 +1,13 @@ package com.imsweb.algorithms.yostacspoverty; -import java.time.LocalDate; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; - import com.imsweb.algorithms.internal.CensusData; import com.imsweb.algorithms.internal.CountryData; import com.imsweb.algorithms.internal.CountyData; import com.imsweb.algorithms.internal.StateData; import com.imsweb.algorithms.internal.YearData; +import java.time.LocalDate; + /** * This class can be used to calculate ACS Linkage variables. * Created on Oct 13, 2017 by howew @@ -19,16 +16,54 @@ public final class YostAcsPovertyUtils { public static final String ALG_NAME = "NAACCR Yost Quintile & Area-Based Social Measures Linkage Program"; - public static final String ALG_VERSION = "released in September 2025"; + public static final String ALG_VERSION = "August 13, 2026"; + + public static final int YOST_ACS_CENSUS_TRACT_PIVOT_YEAR = 2015; + + //Unknown values for each code + public static final String YOST_ACS_UNK_A = "A"; + public static final String YOST_ACS_UNK_B = "B"; + public static final String YOST_ACS_UNK_C = "C"; + public static final String YOST_ACS_UNK_D = "D"; private YostAcsPovertyUtils() { // no instances of this class allowed! } + /** + * Helper method to compute the lookup year. + * The algorithm uses data from 2006 to 2024, but it uses 5-years estimate data points, meaning it only has data points from 2008 to 2022. + * Different DX years use different data points: + * - 2006-2007 use the 2008 data point from 2010 census + * - 2008-2015 use the provided year data point for 2010 census (so 2008 uses the 2008 data point, 2009 uses the 2009 data point, etc...) + * - 2016-2017 use the 2018 data point from 2020 census + * - 2018-2022 use the provided year data point for 2020 census (so 2018 uses the 2018 data point, etc...) + * - 2023+ use the 2022 data point from 2020 census + * @param dxYear the year of diagnosis from the input dto + * @return the dx year to use for the lookup + */ + private static int computeYearForLookup(int dxYear) { + int yearForLookup = dxYear; + if (dxYear == 2006 || dxYear == 2007) + yearForLookup = 2008; + else if (dxYear == 2016 || dxYear == 2017) + yearForLookup = 2018; + else if (dxYear >= 2023) + yearForLookup = 2022; + return yearForLookup; + } + /** * Calculates the ACS data for the provided ACS data input dto *

* The returned dto will contain yost indices and acs poverty percentages across a number of time periods + * or one of the unknown values listed below: + * *

* @param input a ACSLinkageInputDto input object * @return the computed ACS data @@ -36,24 +71,21 @@ private YostAcsPovertyUtils() { public static YostAcsPovertyOutputDto computeYostAcsPovertyData(YostAcsPovertyInputDto input) { YostAcsPovertyOutputDto result = new YostAcsPovertyOutputDto(); - String state = input.getAddressAtDxState(); - String county = input.getCountyAtDxAnalysis(); - String census2010 = input.getCensusTract2010(); - String census2020 = input.getCensusTract2020(); - String year = input.getDateOfDiagnosis() == null ? null : StringUtils.rightPad(input.getDateOfDiagnosis(), 4).substring(0, 4).trim(); - - if (state != null && county != null && (census2010 != null || census2020 != null) && NumberUtils.isDigits(year)) { - int dxYear = Integer.parseInt(year); - - // The algorithm uses data from 2006 to 2023, but it uses 5-years estimate data points, meaning it only has data points from 2008 to 2021. - // Different DX years use different data points: - // - 2006-2007 use the 2008 data point from 2010 census - // - 2008-2015 use the provided year data point for 2010 census (so 2008 uses the 2008 data point, 2009 uses the 2009 data point, etc...) - // - 2016-2017 use the 2018 data point from 2020 census - // - 2018-2021 use the provided year data point for 2020 census (so 2018 uses the 2018 data point, etc...) - // - 2022+ use the 2021 data point from 2020 census + input.applyRecodes(); + if (input.hasInvalidStateCountyCensusTractOrYear()) + result.setAllFields(YOST_ACS_UNK_A); + else if (input.hasUnknownStateCountyCensusTractOrYear()) + result.setAllFields(YOST_ACS_UNK_D); + else if (input.countyIsNotReported()) + result.setAllFields(YOST_ACS_UNK_B); + else { + int dxYear = input.computeYearOfDiagnosis(); if (dxYear >= 2006 && dxYear <= LocalDate.now().getYear()) { + String state = input.getAddressAtDxState(); + String county = input.getCountyAtDxAnalysis(); + String census2010 = input.getCensusTract2010(); + String census2020 = input.getCensusTract2020(); if (!CountryData.getInstance().isYearBasedTractDataInitialized(state)) CountryData.getInstance().initializeYearBasedTractData(state); @@ -62,17 +94,9 @@ public static YostAcsPovertyOutputDto computeYostAcsPovertyData(YostAcsPovertyIn if (stateData != null) { CountyData countyData = stateData.getCountyData(county); if (countyData != null) { - CensusData censusData = countyData.getCensusData(dxYear <= 2015 ? census2010 : census2020); + CensusData censusData = countyData.getCensusData(dxYear <= YOST_ACS_CENSUS_TRACT_PIVOT_YEAR ? census2010 : census2020); if (censusData != null) { - - int yearForLookup = dxYear; - if (dxYear == 2006 || dxYear == 2007) - yearForLookup = 2008; - else if (dxYear == 2016 || dxYear == 2017) - yearForLookup = 2018; - else if (dxYear >= 2022) - yearForLookup = 2021; - + int yearForLookup = computeYearForLookup(dxYear); YearData yearData = censusData.getYearData(String.valueOf(yearForLookup)); if (yearData != null) { result.setYostQuintileUS(yearData.getYostQuintileUS()); @@ -90,7 +114,25 @@ else if (dxYear >= 2022) } } } + if (result.getYostQuintileUS() == null) + result.setYostQuintileUS(YOST_ACS_UNK_C); + if (result.getYostQuintileState() == null) + result.setYostQuintileState(YOST_ACS_UNK_C); + if (result.getAcsPctPovAllRaces() == null) + result.setAcsPctPovAllRaces(YOST_ACS_UNK_C); + if (result.getAcsPctPovWhite() == null) + result.setAcsPctPovWhite(YOST_ACS_UNK_C); + if (result.getAcsPctPovBlack() == null) + result.setAcsPctPovBlack(YOST_ACS_UNK_C); + if (result.getAcsPctPovAsianNHOPI() == null) + result.setAcsPctPovAsianNHOPI(YOST_ACS_UNK_C); + if (result.getAcsPctPovAIAN() == null) + result.setAcsPctPovAIAN(YOST_ACS_UNK_C); + if (result.getAcsPctPovWhiteNonHisp() == null) + result.setAcsPctPovWhiteNonHisp(YOST_ACS_UNK_C); + if (result.getAcsPctPovHispanic() == null) + result.setAcsPctPovHispanic(YOST_ACS_UNK_C); return result; } -} +} \ No newline at end of file diff --git a/src/test/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtilsTest.java b/src/test/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtilsTest.java index b519492d..a2afe924 100644 --- a/src/test/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtilsTest.java +++ b/src/test/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtilsTest.java @@ -11,27 +11,234 @@ public class YostAcsPovertyUtilsTest { @Test public void testYostAcsPoverty() { YostAcsPovertyInputDto idto = new YostAcsPovertyInputDto(); + YostAcsPovertyOutputDto odto; + + // invalid state + idto.setAddressAtDxState("12345"); + idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2021"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("A", odto.getYostQuintileUS()); + Assert.assertEquals("A", odto.getYostQuintileState()); + Assert.assertEquals("A", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("A", odto.getAcsPctPovWhite()); + Assert.assertEquals("A", odto.getAcsPctPovBlack()); + Assert.assertEquals("A", odto.getAcsPctPovAIAN()); + Assert.assertEquals("A", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("A", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("A", odto.getAcsPctPovHispanic()); + + // invalid county + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("ABCDE"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2021"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("A", odto.getYostQuintileUS()); + Assert.assertEquals("A", odto.getYostQuintileState()); + Assert.assertEquals("A", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("A", odto.getAcsPctPovWhite()); + Assert.assertEquals("A", odto.getAcsPctPovBlack()); + Assert.assertEquals("A", odto.getAcsPctPovAIAN()); + Assert.assertEquals("A", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("A", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("A", odto.getAcsPctPovHispanic()); + + // invalid 2010 census tract + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("001"); + idto.setCensusTract2010("ABCDEF"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2012"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("A", odto.getYostQuintileUS()); + Assert.assertEquals("A", odto.getYostQuintileState()); + Assert.assertEquals("A", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("A", odto.getAcsPctPovWhite()); + Assert.assertEquals("A", odto.getAcsPctPovBlack()); + Assert.assertEquals("A", odto.getAcsPctPovAIAN()); + Assert.assertEquals("A", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("A", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("A", odto.getAcsPctPovHispanic()); + + // invalid 2020 census tract + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("001"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("ABCDEF"); + idto.setDateOfDiagnosis("2020"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("A", odto.getYostQuintileUS()); + Assert.assertEquals("A", odto.getYostQuintileState()); + Assert.assertEquals("A", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("A", odto.getAcsPctPovWhite()); + Assert.assertEquals("A", odto.getAcsPctPovBlack()); + Assert.assertEquals("A", odto.getAcsPctPovAIAN()); + Assert.assertEquals("A", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("A", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("A", odto.getAcsPctPovHispanic()); + + // invalid date of dx + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("001"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("ABCDEF"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("A", odto.getYostQuintileUS()); + Assert.assertEquals("A", odto.getYostQuintileState()); + Assert.assertEquals("A", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("A", odto.getAcsPctPovWhite()); + Assert.assertEquals("A", odto.getAcsPctPovBlack()); + Assert.assertEquals("A", odto.getAcsPctPovAIAN()); + Assert.assertEquals("A", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("A", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("A", odto.getAcsPctPovHispanic()); + + // county not reported (ie, 000) + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("000"); + idto.setCensusTract2010(""); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2020"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("B", odto.getYostQuintileUS()); + Assert.assertEquals("B", odto.getYostQuintileState()); + Assert.assertEquals("B", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("B", odto.getAcsPctPovWhite()); + Assert.assertEquals("B", odto.getAcsPctPovBlack()); + Assert.assertEquals("B", odto.getAcsPctPovAIAN()); + Assert.assertEquals("B", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("B", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("B", odto.getAcsPctPovHispanic()); + + // blank state + idto.setAddressAtDxState(""); + idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2018"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("D", odto.getYostQuintileUS()); + Assert.assertEquals("D", odto.getYostQuintileState()); + Assert.assertEquals("D", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("D", odto.getAcsPctPovWhite()); + Assert.assertEquals("D", odto.getAcsPctPovBlack()); + Assert.assertEquals("D", odto.getAcsPctPovAIAN()); + Assert.assertEquals("D", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("D", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("D", odto.getAcsPctPovHispanic()); + + // blank county + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis(""); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2018"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("D", odto.getYostQuintileUS()); + Assert.assertEquals("D", odto.getYostQuintileState()); + Assert.assertEquals("D", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("D", odto.getAcsPctPovWhite()); + Assert.assertEquals("D", odto.getAcsPctPovBlack()); + Assert.assertEquals("D", odto.getAcsPctPovAIAN()); + Assert.assertEquals("D", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("D", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("D", odto.getAcsPctPovHispanic()); + + // blank census tract 2010 + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010(""); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis("2012"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("D", odto.getYostQuintileUS()); + Assert.assertEquals("D", odto.getYostQuintileState()); + Assert.assertEquals("D", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("D", odto.getAcsPctPovWhite()); + Assert.assertEquals("D", odto.getAcsPctPovBlack()); + Assert.assertEquals("D", odto.getAcsPctPovAIAN()); + Assert.assertEquals("D", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("D", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("D", odto.getAcsPctPovHispanic()); + + // blank census tract 2020 + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020(""); + idto.setDateOfDiagnosis("2018"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("D", odto.getYostQuintileUS()); + Assert.assertEquals("D", odto.getYostQuintileState()); + Assert.assertEquals("D", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("D", odto.getAcsPctPovWhite()); + Assert.assertEquals("D", odto.getAcsPctPovBlack()); + Assert.assertEquals("D", odto.getAcsPctPovAIAN()); + Assert.assertEquals("D", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("D", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("D", odto.getAcsPctPovHispanic()); + + // blank date of diagnosis + idto.setAddressAtDxState("AK"); + idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010("001702"); + idto.setCensusTract2020("001702"); + idto.setDateOfDiagnosis(""); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("D", odto.getYostQuintileUS()); + Assert.assertEquals("D", odto.getYostQuintileState()); + Assert.assertEquals("D", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("D", odto.getAcsPctPovWhite()); + Assert.assertEquals("D", odto.getAcsPctPovBlack()); + Assert.assertEquals("D", odto.getAcsPctPovAIAN()); + Assert.assertEquals("D", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("D", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("D", odto.getAcsPctPovHispanic()); // 2005 -> no data available idto.setAddressAtDxState("AL"); idto.setCountyAtDxAnalysis("001"); idto.setCensusTract2010("020200"); + idto.setCensusTract2020(""); idto.setDateOfDiagnosis("2005"); - YostAcsPovertyOutputDto odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); - Assert.assertNull(odto.getYostQuintileUS()); - Assert.assertNull(odto.getYostQuintileState()); - Assert.assertNull(odto.getAcsPctPovAllRaces()); - Assert.assertNull(odto.getAcsPctPovWhite()); - Assert.assertNull(odto.getAcsPctPovBlack()); - Assert.assertNull(odto.getAcsPctPovAIAN()); - Assert.assertNull(odto.getAcsPctPovAsianNHOPI()); - Assert.assertNull(odto.getAcsPctPovWhiteNonHisp()); - Assert.assertNull(odto.getAcsPctPovHispanic()); - - // 2007 using census2010 with year 2008 + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("C", odto.getYostQuintileUS()); + Assert.assertEquals("C", odto.getYostQuintileState()); + Assert.assertEquals("C", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("C", odto.getAcsPctPovWhite()); + Assert.assertEquals("C", odto.getAcsPctPovBlack()); + Assert.assertEquals("C", odto.getAcsPctPovAIAN()); + Assert.assertEquals("C", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("C", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("C", odto.getAcsPctPovHispanic()); + + // test a SEER recode + idto.setAddressAtDxState("LO"); + idto.setCountyAtDxAnalysis("071"); + idto.setCensusTract2010("007903"); + idto.setCensusTract2020(""); + idto.setDateOfDiagnosis("2010"); + odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); + Assert.assertEquals("5", odto.getYostQuintileUS()); + Assert.assertEquals("4", odto.getYostQuintileState()); + Assert.assertEquals("3.03", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("3.81", odto.getAcsPctPovWhite()); + Assert.assertEquals("4.71", odto.getAcsPctPovBlack()); + Assert.assertEquals("", odto.getAcsPctPovAIAN()); + Assert.assertEquals("0.00", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("4.93", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("0.70", odto.getAcsPctPovHispanic()); + + // 2007 using census2010 with yearForLookup 2008 idto.setAddressAtDxState("AL"); idto.setCountyAtDxAnalysis("001"); idto.setCensusTract2010("020200"); + idto.setCensusTract2020(""); idto.setDateOfDiagnosis("2007"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); Assert.assertEquals("2", odto.getYostQuintileUS()); @@ -48,6 +255,7 @@ public void testYostAcsPoverty() { idto.setAddressAtDxState("AL"); idto.setCountyAtDxAnalysis("001"); idto.setCensusTract2010("020200"); + idto.setCensusTract2020(""); idto.setDateOfDiagnosis("2008"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); Assert.assertEquals("2", odto.getYostQuintileUS()); @@ -64,6 +272,7 @@ public void testYostAcsPoverty() { idto.setAddressAtDxState("AL"); idto.setCountyAtDxAnalysis("001"); idto.setCensusTract2010("020200"); + idto.setCensusTract2020(""); idto.setDateOfDiagnosis("2010"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); Assert.assertEquals("2", odto.getYostQuintileUS()); @@ -80,6 +289,7 @@ public void testYostAcsPoverty() { idto.setAddressAtDxState("AK"); idto.setCountyAtDxAnalysis("020"); idto.setCensusTract2010("001702"); + idto.setCensusTract2020(""); idto.setDateOfDiagnosis("20150101"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); Assert.assertEquals("5", odto.getYostQuintileUS()); @@ -92,39 +302,10 @@ public void testYostAcsPoverty() { Assert.assertEquals("3.23", odto.getAcsPctPovWhiteNonHisp()); Assert.assertEquals("0.00", odto.getAcsPctPovHispanic()); - // 2016 using census2020 with year 2018 - idto.setAddressAtDxState("AK"); - idto.setCountyAtDxAnalysis("020"); - idto.setCensusTract2010("001702"); - idto.setDateOfDiagnosis("2016"); - odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); - Assert.assertNull(odto.getYostQuintileState()); - Assert.assertNull(odto.getAcsPctPovAllRaces()); - Assert.assertNull(odto.getAcsPctPovWhite()); - Assert.assertNull(odto.getAcsPctPovBlack()); - Assert.assertNull(odto.getAcsPctPovAIAN()); - Assert.assertNull(odto.getAcsPctPovAsianNHOPI()); - Assert.assertNull(odto.getAcsPctPovWhiteNonHisp()); - Assert.assertNull(odto.getAcsPctPovHispanic()); - - // 2018 using census2020 - idto.setAddressAtDxState("AK"); - idto.setCountyAtDxAnalysis("020"); - idto.setCensusTract2010("001702"); - idto.setDateOfDiagnosis("2018"); - odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); - Assert.assertNull(odto.getYostQuintileState()); - Assert.assertNull(odto.getAcsPctPovAllRaces()); - Assert.assertNull(odto.getAcsPctPovWhite()); - Assert.assertNull(odto.getAcsPctPovBlack()); - Assert.assertNull(odto.getAcsPctPovAIAN()); - Assert.assertNull(odto.getAcsPctPovAsianNHOPI()); - Assert.assertNull(odto.getAcsPctPovWhiteNonHisp()); - Assert.assertNull(odto.getAcsPctPovHispanic()); - // 2020 using census2020 idto.setAddressAtDxState("AK"); idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010(""); idto.setCensusTract2020("001702"); idto.setDateOfDiagnosis("2020"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); @@ -141,7 +322,8 @@ public void testYostAcsPoverty() { // 2021 using census2020 idto.setAddressAtDxState("AK"); idto.setCountyAtDxAnalysis("020"); - idto.setCensusTract2010("001702"); + idto.setCensusTract2010(""); + idto.setCensusTract2020("001702"); idto.setDateOfDiagnosis("2021"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); Assert.assertEquals("4", odto.getYostQuintileUS()); @@ -154,20 +336,22 @@ public void testYostAcsPoverty() { Assert.assertEquals("3.09", odto.getAcsPctPovWhiteNonHisp()); Assert.assertEquals("8.09", odto.getAcsPctPovHispanic()); - // 2025 using census2020 with year 2021 + // 2025 using census2020 with yearForLookup 2022 + // note: this may fail once 2022 data is added to the big SEER data file idto.setAddressAtDxState("AK"); idto.setCountyAtDxAnalysis("020"); + idto.setCensusTract2010(""); idto.setCensusTract2020("001702"); idto.setDateOfDiagnosis("2025"); odto = YostAcsPovertyUtils.computeYostAcsPovertyData(idto); - Assert.assertEquals("4", odto.getYostQuintileUS()); - Assert.assertEquals("5", odto.getYostQuintileState()); - Assert.assertEquals("7.12", odto.getAcsPctPovAllRaces()); - Assert.assertEquals("3.03", odto.getAcsPctPovWhite()); - Assert.assertEquals("13.46", odto.getAcsPctPovBlack()); - Assert.assertEquals("34.10", odto.getAcsPctPovAIAN()); - Assert.assertEquals("0.00", odto.getAcsPctPovAsianNHOPI()); - Assert.assertEquals("3.09", odto.getAcsPctPovWhiteNonHisp()); - Assert.assertEquals("8.09", odto.getAcsPctPovHispanic()); + Assert.assertEquals("C", odto.getYostQuintileUS()); + Assert.assertEquals("C", odto.getYostQuintileState()); + Assert.assertEquals("C", odto.getAcsPctPovAllRaces()); + Assert.assertEquals("C", odto.getAcsPctPovWhite()); + Assert.assertEquals("C", odto.getAcsPctPovBlack()); + Assert.assertEquals("C", odto.getAcsPctPovAIAN()); + Assert.assertEquals("C", odto.getAcsPctPovAsianNHOPI()); + Assert.assertEquals("C", odto.getAcsPctPovWhiteNonHisp()); + Assert.assertEquals("C", odto.getAcsPctPovHispanic()); } } From c4a9038e103bd2f79f72d4a0e064c1480931d325 Mon Sep 17 00:00:00 2001 From: howew Date: Thu, 13 Aug 2026 10:26:35 -0400 Subject: [PATCH 2/4] #222 - fixed a unit test, see comment --- .../CensusTractPovertyIndicatorUtilsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java index 68fd010d..97ebdc66 100644 --- a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java +++ b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java @@ -107,10 +107,10 @@ public void testComputePovertyIndicator() { rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2021"); Assert.assertEquals("2", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); - // test 2025 (census2020) + // test 2025 (census2020) - this may fail once 2022 data is added to the SEER big data file rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2025"); - Assert.assertEquals("2", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); + Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); //test unknown year rec.put("dateOfDiagnosisYear", "9999"); Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); From e5e5a2996c2a1df096fbb77586e35cdad19adfe3 Mon Sep 17 00:00:00 2001 From: howew Date: Thu, 13 Aug 2026 10:30:10 -0400 Subject: [PATCH 3/4] #222 - fixed a unit test, see comment --- .../CensusTractPovertyIndicatorUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java index 97ebdc66..d29891aa 100644 --- a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java +++ b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java @@ -107,7 +107,7 @@ public void testComputePovertyIndicator() { rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2021"); Assert.assertEquals("2", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); - // test 2025 (census2020) - this may fail once 2022 data is added to the SEER big data file + // test 2025 (census2020) - note: this may fail once 2022 data is added to the SEER big data file rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2025"); Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); From b10b303b601988d98e627bd80d583d3bdcdc6943 Mon Sep 17 00:00:00 2001 From: howew Date: Thu, 13 Aug 2026 13:18:26 -0400 Subject: [PATCH 4/4] #222 - changed the pivot year to 2017 and updated the logic for computeYearForLookup. 2016 and 2017 now use the provided year instead of 2018 and they now use the 2010 census --- .../yostacspoverty/YostAcsPovertyUtils.java | 7 ++----- .../CensusTractPovertyIndicatorUtilsTest.java | 17 +++++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java index 26fa5d67..d1cccd14 100644 --- a/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java +++ b/src/main/java/com/imsweb/algorithms/yostacspoverty/YostAcsPovertyUtils.java @@ -18,7 +18,7 @@ public final class YostAcsPovertyUtils { public static final String ALG_NAME = "NAACCR Yost Quintile & Area-Based Social Measures Linkage Program"; public static final String ALG_VERSION = "August 13, 2026"; - public static final int YOST_ACS_CENSUS_TRACT_PIVOT_YEAR = 2015; + public static final int YOST_ACS_CENSUS_TRACT_PIVOT_YEAR = 2017; //Unknown values for each code public static final String YOST_ACS_UNK_A = "A"; @@ -35,8 +35,7 @@ private YostAcsPovertyUtils() { * The algorithm uses data from 2006 to 2024, but it uses 5-years estimate data points, meaning it only has data points from 2008 to 2022. * Different DX years use different data points: * - 2006-2007 use the 2008 data point from 2010 census - * - 2008-2015 use the provided year data point for 2010 census (so 2008 uses the 2008 data point, 2009 uses the 2009 data point, etc...) - * - 2016-2017 use the 2018 data point from 2020 census + * - 2008-2017 use the provided year data point for 2010 census (so 2008 uses the 2008 data point, 2009 uses the 2009 data point, etc...) * - 2018-2022 use the provided year data point for 2020 census (so 2018 uses the 2018 data point, etc...) * - 2023+ use the 2022 data point from 2020 census * @param dxYear the year of diagnosis from the input dto @@ -46,8 +45,6 @@ private static int computeYearForLookup(int dxYear) { int yearForLookup = dxYear; if (dxYear == 2006 || dxYear == 2007) yearForLookup = 2008; - else if (dxYear == 2016 || dxYear == 2017) - yearForLookup = 2018; else if (dxYear >= 2023) yearForLookup = 2022; return yearForLookup; diff --git a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java index d29891aa..16ad7a4b 100644 --- a/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java +++ b/src/test/java/com/imsweb/algorithms/censustractpovertyindicator/CensusTractPovertyIndicatorUtilsTest.java @@ -95,19 +95,24 @@ public void testComputePovertyIndicator() { rec.put("censusTract2010", "020600"); rec.put("dateOfDiagnosisYear", "2015"); Assert.assertEquals("3", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); - // test 2016 (census2020) - rec.put("censusTract2020", "020600"); + // test 2016 (census2010) - note: this may fail if 2017 data is added to the SEER big data file (2010 geographies) + rec.put("censusTract2010", "020600"); rec.put("dateOfDiagnosisYear", "2016"); - Assert.assertEquals("4", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); - // test 2017 (census2020) - rec.put("censusTract2020", "020600"); + Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); + // test 2017 (census2010) - note: this may fail if 2017 data is added to the SEER big data file (2010 geographies) + rec.put("censusTract2010", "020600"); rec.put("dateOfDiagnosisYear", "2017"); + Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); + // test 2018 (census2020) + rec.put("censusTract2010", ""); + rec.put("censusTract2020", "020600"); + rec.put("dateOfDiagnosisYear", "2018"); Assert.assertEquals("4", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); // test 2021 (census2020) rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2021"); Assert.assertEquals("2", computePovertyIndicator(rec).getCensusTractPovertyIndicator()); - // test 2025 (census2020) - note: this may fail once 2022 data is added to the SEER big data file + // test 2025 (census2020) - note: this may fail once 2022 data is added to the SEER big data file (2020 geographies) rec.put("censusTract2020", "020600"); rec.put("dateOfDiagnosisYear", "2025"); Assert.assertEquals("9", computePovertyIndicator(rec).getCensusTractPovertyIndicator());