All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.imsweb.algorithms.ruralurban.RuralUrbanCsvData Maven / Gradle / Ivy

/*
 * Copyright (C) 2014 Information Management Services, Inc.
 */
package com.imsweb.algorithms.ruralurban;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;

import au.com.bytecode.opencsv.CSVReader;

/**
 * The purpose of this class is to get the rural urban continuum for the provided year category, state of dx, and county of dx
 * from the csv file lookup.  This implementation is memory consumer. If there is a database, it is better to use another implementation.
 * Created on Aug 12, 2014 by HoweW
 * @author howew
 */
public class RuralUrbanCsvData implements RuralUrbanDataProvider {

    // data structure for the values keyed by state+county only
    private static class CountyDataDto {

        private Long _urbanContinuum;
        private Map _censusData;

        public Long getUrbanContinuum() {
            return _urbanContinuum;
        }

        public void setUrbanContinuum(Long urbanContinuum) {
            _urbanContinuum = urbanContinuum;
        }

        public Map getCensusData() {
            if (_censusData == null)
                _censusData = new HashMap<>();
            return _censusData;
        }
    }

    // data structure for the values keyed by state+county+census
    private static class CensusDataDto {

        private Long _urbanCensus;
        private Long _urbanCommuting;
        private Float _urbanPercentage2000;
        private Float _urbanPercentage2010;

        public Long getUrbanCensus() {
            return _urbanCensus;
        }

        public void setUrbanCensus(Long urbanCensus) {
            _urbanCensus = urbanCensus;
        }

        public Long getUrbanCommuting() {
            return _urbanCommuting;
        }

        public void setUrbanCommuting(Long urbanCommuting) {
            _urbanCommuting = urbanCommuting;
        }

        public Float getUrbanPercentage2000() {
            return _urbanPercentage2000;
        }

        public void setUrbanPercentage2000(Float urbanPercentage2000) {
            _urbanPercentage2000 = urbanPercentage2000;
        }

        public Float getUrbanPercentage2010() {
            return _urbanPercentage2010;
        }

        public void setUrbanPercentage2010(Float urbanPercentage2010) {
            _urbanPercentage2010 = urbanPercentage2010;
        }
    }

    // main (and unique) cached data
    private static Map _RURAL_URBAN_LOOK_UP = new HashMap<>();

    // all the data is initialized at once; if we need a more fine-grain initialization, we will need more variables to keep track of which data has been initialized...
    private static synchronized void initializeAllLookups() {
        initializeRuralUrbanCensusLookup();
        initializeRuralUrbanCommutingAreaLookup();
        initializeRuralUrbanContinuumLookup();
    }

    //////////////////////////////////////////////////////////////////////////////////
    // RURAL URBAN CENSUS CODE SECTION STARTS HERE
    //////////////////////////////////////////////////////////////////////////////////

    @Override
    public String getRuralUrbanCensus(String tractCategory, String state, String county, String censusTract) {
        String ruralUrbanCensus = RuralUrbanUtils.RURAL_URBAN_CENSUS_UNKNOWN;

        if (tractCategory == null || state == null || county == null || censusTract == null)
            return ruralUrbanCensus;

        if (_RURAL_URBAN_LOOK_UP.isEmpty())
            initializeAllLookups();

        CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(state + county);
        CensusDataDto censusData = countyData == null ? null : countyData.getCensusData().get(censusTract);
        Long ruralUrbanCensusValue = censusData == null ? null : censusData.getUrbanCensus();

        if (ruralUrbanCensusValue != null) {
            if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_1))
                ruralUrbanCensus = String.valueOf((ruralUrbanCensusValue / 100) % 100);

            else if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_2)) {
                ruralUrbanCensus = String.valueOf(ruralUrbanCensusValue % 100);

                // if you didn't find a match in the 2010 lookup, check the 2000 lookup
                if (ruralUrbanCensus.equals(RuralUrbanUtils.RURAL_URBAN_CENSUS_UNKNOWN))
                    ruralUrbanCensus = String.valueOf((ruralUrbanCensusValue / 100) % 100);
            }
        }

        return StringUtils.isBlank(ruralUrbanCensus) ? RuralUrbanUtils.RURAL_URBAN_CENSUS_UNKNOWN : StringUtils.leftPad(ruralUrbanCensus, 2, '0');
    }

    @Override
    public Float getRuralUrbanCensusPercentage(String tractCategory, String state, String county, String censusTract) {
        if (tractCategory == null || state == null || county == null || censusTract == null)
            return null;

        if (_RURAL_URBAN_LOOK_UP.isEmpty())
            initializeAllLookups();

        CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(state + county);
        if (countyData == null)
            return null;
        CensusDataDto censusData = countyData.getCensusData().get(censusTract);
        if (censusData == null)
            return null;

        if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_1))
            return censusData.getUrbanPercentage2000();
        if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_2))
            return censusData.getUrbanPercentage2010();
        
        return null;
    }

    private static synchronized void initializeRuralUrbanCensusLookup() {
        int year1 = 0, year2 = 1;

        Map tmp = new HashMap<>();
        Map tmp2 = new HashMap<>();

        try {
            Reader reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-census-2000.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], tract = row[2], percent = row[3], census = row[4];
                String key = state + county + "#" + tract; // that will allow us to split the key later in the process...
                byte[] values = tmp.get(key);
                if (values == null) {
                    values = new byte[2];
                    values[0] = values[1] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_CENSUS_UNKNOWN);
                    tmp.put(key, values);
                }
                values[year1] = Byte.valueOf(census);
                if (!".".equals(percent)) {
                    Float[] percentValues = tmp2.get(key);
                    if (percentValues == null) {
                        percentValues = new Float[2];
                        tmp2.put(key, percentValues);
                    }
                    percentValues[year1] = Float.valueOf(percent);
                }
            }
            reader.close();
            reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-census-2010.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], tract = row[2], percent = row[3], census = row[4];
                String key = state + county + "#" + tract; // that will allow us to split the key later in the process...
                byte[] values = tmp.get(key);
                if (values == null) {
                    values = new byte[2];
                    values[0] = values[1] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_CENSUS_UNKNOWN);
                    tmp.put(key, values);
                }
                values[year2] = Byte.valueOf(census);
                if (!".".equals(percent)) {
                    Float[] percentValues = tmp2.get(key);
                    if (percentValues == null) {
                        percentValues = new Float[2];
                        tmp2.put(key, percentValues);
                    }
                    percentValues[year2] = Float.valueOf(percent);
                }
            }
            reader.close();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }

        for (Entry entry : tmp.entrySet()) {
            String[] key = StringUtils.split(entry.getKey(), '#');
            byte[] values = entry.getValue();
            long result = (long)(values[0] * 100 + values[1]);
            CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(key[0]);
            if (countyData == null) {
                countyData = new CountyDataDto();
                _RURAL_URBAN_LOOK_UP.put(key[0], countyData);
            }
            CensusDataDto censusData = countyData.getCensusData().get(key[1]);
            if (censusData == null) {
                censusData = new CensusDataDto();
                countyData.getCensusData().put(key[1], censusData);
            }
            censusData.setUrbanCensus(result);
            Float[] percentValues = tmp2.get(entry.getKey());
            if (percentValues != null) {
                censusData.setUrbanPercentage2000(percentValues[year1]);
                censusData.setUrbanPercentage2010(percentValues[year2]);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////////////
    // RURAL URBAN COMMUTING AREA CODE SECTION STARTS HERE
    //////////////////////////////////////////////////////////////////////////////////

    @Override
    public String getRuralUrbanCommutingArea(String tractCategory, String state, String county, String censusTract) {
        String ruralUrbanCommutingArea = RuralUrbanUtils.RURAL_URBAN_COMMUTING_AREA_UNKNOWN;

        if (tractCategory == null || state == null || county == null || censusTract == null)
            return ruralUrbanCommutingArea;

        if (_RURAL_URBAN_LOOK_UP.isEmpty())
            initializeAllLookups();

        CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(state + county);
        CensusDataDto censusData = countyData == null ? null : countyData.getCensusData().get(censusTract);
        Long ruralUrbanCommutingAreaValue = censusData == null ? null : censusData.getUrbanCommuting();

        if (ruralUrbanCommutingAreaValue != null) {
            if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_1))
                ruralUrbanCommutingArea = String.valueOf((ruralUrbanCommutingAreaValue / 100) % 100);

            else if (tractCategory.equals(RuralUrbanDataProvider.TRACT_CATEGORY_2)) {
                ruralUrbanCommutingArea = String.valueOf(ruralUrbanCommutingAreaValue % 100);

                // if you didn't find a match in the 2010 lookup, check the 2000 lookup
                if (ruralUrbanCommutingArea.equals(RuralUrbanUtils.RURAL_URBAN_COMMUTING_AREA_UNKNOWN))
                    ruralUrbanCommutingArea = String.valueOf((ruralUrbanCommutingAreaValue / 100) % 100);
            }
        }

        return StringUtils.isBlank(ruralUrbanCommutingArea) ? RuralUrbanUtils.RURAL_URBAN_COMMUTING_AREA_UNKNOWN : StringUtils.leftPad(ruralUrbanCommutingArea, 2, '0');
    }

    private static void initializeRuralUrbanCommutingAreaLookup() {
        int year1 = 0, year2 = 1;

        List urbanCommutingAreas = Arrays.asList("1.0", "1.1", "2.0", "2.1", "3.0", "4.1", "5.1", "7.1", "8.1", "10.1");

        Map tmp = new HashMap<>();

        try {
            Reader reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-commuting-area-2000.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], tract = row[2], primary = row[3], secondary = row[4];
                String key = state + county + "#" + tract; // that will allow us to split the key later in the process...
                byte[] values = tmp.get(key);
                if (values == null) {
                    values = new byte[2];
                    values[0] = values[1] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_COMMUTING_AREA_UNKNOWN);
                    tmp.put(key, values);
                }
                if (primary.equals("99"))
                    values[year1] = 9;
                else if (urbanCommutingAreas.contains(secondary))
                    values[year1] = 1;
                else
                    values[year1] = 2;
            }
            reader.close();
            reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-commuting-area-2010.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], tract = row[2], primary = row[3], secondary = row[4];
                String key = state + county + "#" + tract; // that will allow us to split the key later in the process...
                byte[] values = tmp.get(key);
                if (values == null) {
                    values = new byte[2];
                    values[0] = values[1] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_COMMUTING_AREA_UNKNOWN);
                    tmp.put(key, values);
                }
                if (primary.equals("99")) {
                    values[year2] = 9;
                }
                else if (urbanCommutingAreas.contains(secondary)) {
                    values[year2] = 1;
                }
                else {
                    values[year2] = 2;
                }
            }
            reader.close();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }

        for (Entry entry : tmp.entrySet()) {
            String[] key = StringUtils.split(entry.getKey(), '#');
            byte[] values = entry.getValue();
            long result = (long)(values[0] * 100 + values[1]);
            CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(key[0]);
            if (countyData == null) {
                countyData = new CountyDataDto();
                _RURAL_URBAN_LOOK_UP.put(key[0], countyData);
            }
            CensusDataDto censusData = countyData.getCensusData().get(key[1]);
            if (censusData == null) {
                censusData = new CensusDataDto();
                countyData.getCensusData().put(key[1], censusData);
            }
            censusData.setUrbanCommuting(result);
        }
    }

    //////////////////////////////////////////////////////////////////////////////////
    // RURAL URBAN CONTINUUM CODE SECTION STARTS HERE
    //////////////////////////////////////////////////////////////////////////////////

    @Override
    public String getRuralUrbanContinuum(String bealeCategory, String state, String county) {

        String ruralUrbanContinuum = RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN;

        if (bealeCategory == null || state == null || county == null)
            return ruralUrbanContinuum;

        if (_RURAL_URBAN_LOOK_UP.isEmpty())
            initializeAllLookups();

        CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(state + county);
        Long ruralUrbanContinuumValue = countyData == null ? null : countyData.getUrbanContinuum();

        if (ruralUrbanContinuumValue != null) {
            switch (bealeCategory) {
                case RuralUrbanDataProvider.BEALE_CATEGORY_1:
                    ruralUrbanContinuum = String.valueOf((ruralUrbanContinuumValue / 10000) % 100);
                    break;
                case RuralUrbanDataProvider.BEALE_CATEGORY_2:
                    ruralUrbanContinuum = String.valueOf((ruralUrbanContinuumValue / 100) % 100);

                    // if you didn't find a match in the 2003 lookup, check the 1993 lookup
                    if (ruralUrbanContinuum.equals(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN))
                        ruralUrbanContinuum = String.valueOf((ruralUrbanContinuumValue / 10000) % 100);
                    break;
                case RuralUrbanDataProvider.BEALE_CATEGORY_3:
                    ruralUrbanContinuum = String.valueOf(ruralUrbanContinuumValue % 100);

                    // if you didn't find a match in the 2013 lookup, check the 2003 lookup
                    if (ruralUrbanContinuum.equals(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN))
                        ruralUrbanContinuum = String.valueOf((ruralUrbanContinuumValue / 100) % 100);

                    // if you didn't find a match in the 2003 lookup, check the 1993 lookup
                    if (ruralUrbanContinuum.equals(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN))
                        ruralUrbanContinuum = String.valueOf((ruralUrbanContinuumValue / 10000) % 100);
                    break;
                default:
                    throw new RuntimeException("Unsupported category: " + bealeCategory);
            }
        }

        return StringUtils.isBlank(ruralUrbanContinuum) ? RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN : StringUtils.leftPad(ruralUrbanContinuum, 2, '0');
    }

    private static void initializeRuralUrbanContinuumLookup() {
        int year1 = 0, year2 = 1, year3 = 2;

        Map tmp = new HashMap<>();

        try {
            Reader reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-continuum-1993.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], val = row[2];
                byte[] values = tmp.get(state + county);
                if (values == null) {
                    values = new byte[3];
                    values[0] = values[1] = values[2] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN);
                    tmp.put(state + county, values);
                }
                values[year1] = Byte.valueOf(val);
            }
            reader.close();
            reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-continuum-2003.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], val = row[2];
                byte[] values = tmp.get(state + county);
                if (values == null) {
                    values = new byte[3];
                    values[0] = values[1] = values[2] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN);
                    tmp.put(state + county, values);
                }
                values[year2] = Byte.valueOf(val);
            }
            reader.close();
            reader = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream("ruralurban/rural-urban-continuum-2013.csv"), "US-ASCII");
            for (String[] row : new CSVReader(reader, ',', '\"', 1).readAll()) {
                String state = row[0], county = row[1], val = row[2];
                byte[] values = tmp.get(state + county);
                if (values == null) {
                    values = new byte[3];
                    values[0] = values[1] = values[2] = Byte.valueOf(RuralUrbanUtils.RURAL_URBAN_CONTINUUM_UNKNOWN);
                    tmp.put(state + county, values);
                }
                values[year3] = Byte.valueOf(val);
            }
            reader.close();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }

        for (Entry entry : tmp.entrySet()) {
            byte[] values = entry.getValue();
            long result = (long)(values[0] * 10000 + values[1] * 100 + values[2]);
            CountyDataDto countyData = _RURAL_URBAN_LOOK_UP.get(entry.getKey());
            if (countyData == null) {
                countyData = new CountyDataDto();
                _RURAL_URBAN_LOOK_UP.put(entry.getKey(), countyData);
            }
            countyData.setUrbanContinuum(result);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy