NSI Integration

This is an example to demonstrate how BrailsPlusPlus integrates with the National Structures Inventory. There are two ways to integrate:

  1. Create an inventory that does not include footprint information directly from NSI.

  2. Integrate an existing AssetInventory with NSI. For each Asset in the asset inventory, the features from NSI are obtained and merged with the asset’s existing features. This is done by finding an asset in the NSI located in the footprint.

  1# written: fmk, bacetiner
  2# Last updated: 03-12-2025
  3# License: BSD-2
  4
  5"""
  6brails_nsi.py
  7=============
  8Example demonstrating the use of NSI scraper module.
  9
 10 Purpose: Testing 1) get_class method of Importer
 11                  2) get_raw_data_given_boundary and
 12                     get_filtered_data_given_inventory methods of NSI_Parser
 13                  3) get_footprints method from scraper
 14                  4) print_info and write_to_geojson method of AssetInventory
 15                     objects
 16"""
 17
 18import argparse
 19import sys
 20import os
 21
 22from brails import Importer
 23
 24# the following line is not neeeded if brails is imported from pypi
 25#   .. it is included here as it allows us to test the code on a nightly basis
 26sys.path.insert(1, "../../")
 27
 28FILE_PATH = 'tmp/smallinv.geojson'
 29
 30
 31def main(location, scraper):
 32    # Create an importer to get the required classes:
 33    importer = Importer()
 34
 35    # Select a region and create its RegionBoundary:
 36    region_boundary_class = importer.get_class('RegionBoundary')
 37    region_boundary_object = region_boundary_class(
 38        {'type': 'locationName', 'data': location})
 39
 40    #
 41    # Use NSI_Parser to get the NSI raw data for the specified region
 42    #
 43
 44    nsi_class = importer.get_class('NSI_Parser')
 45    nsi = nsi_class()
 46    nsi_inventory = nsi.get_raw_data(region_boundary_object)
 47    print('Total number of assets detected using NSI is '
 48          f'{len(nsi_inventory.inventory)}')
 49
 50    print('\n******** SMALL NSI INVENTORY  *********')
 51    nsi_inventory_subset = nsi_inventory.get_random_sample(2, 200)
 52    nsi_inventory_subset.print_info()
 53
 54    # Now Use the FootprintScraper to get footprints and integrate NSI
 55    # inventory data - will integrate on smaller inventory set:
 56
 57    scraper_class = importer.get_class(scraper)
 58    scraper = scraper_class({'length': 'ft'})
 59    scraper_inventory = scraper.get_footprints(region_boundary_object)
 60    print(f'Total number of assets detected using {scraper} '
 61          f'is {len(scraper_inventory.inventory)}')
 62
 63    # Create inventories that are a small subset of the obtained footprints &
 64    # print:
 65    inventory_subset = scraper_inventory.get_random_sample(5, 200)
 66
 67    print('\n******** SMALL INVENTORY WITH NO NSI_DATA *********')
 68    inventory_subset.print_info()
 69
 70    # integrate subset with raw and filtered NSI data
 71    subset_nsi_processed_data = nsi.get_filtered_data_given_inventory(
 72        inventory_subset, 'ft')
 73
 74    # Print the inventories:
 75    print('\n******** SMALL INVENTORY WITH PROCESSES NSI DATA*********')
 76    subset_nsi_processed_data.print_info()
 77
 78    # Write the extracted inventory to a GeoJSON file:
 79    directory = os.path.dirname(FILE_PATH)
 80    os.makedirs(directory, exist_ok=True)
 81
 82    _ = subset_nsi_processed_data.write_to_geojson(FILE_PATH)
 83
 84
 85# Run the main function if this script is executed directly:
 86if __name__ == "__main__":
 87    # Set up command-line arguments:
 88    parser = argparse.ArgumentParser(description='Get NSI inventory for a '
 89                                     'location using the specified footprint '
 90                                     'scraper.')
 91    parser.add_argument('scraper', type=str, nargs='?',
 92                        default='OSM_FootprintScraper',
 93                        help="Name of the footprint scraper.")
 94    parser.add_argument('location', type=str, nargs='?', default='Tiburon, CA',
 95                        help="Name of the location to analyze.")
 96
 97    # Parse the command-line arguments:
 98    args = parser.parse_args()
 99    print(args)
100    try:
101        # Run the main function
102        main(args.location, args.scraper)
103    except Exception as e:
104        print(f'Error{e}')

The script is executed by entering the following command in a terminal window:

python3 brails_nsi.py OSM_FootprintScraper "Berkeley, CA"

As shown in the print_output() of the smaller NSI inventory, the coordinates for such an inventory only contain points instead of the building footprints.

1******** SMALL NSI INVENTORY  *********
2AssetInventory
3Inventory stored in:  dict
4Key:  474740175 Asset:
5	 Coordinates:  [[-122.262559, 37.879117]]
6	 Features:  {'fd_id': 474740175, 'bid': '849VVPHP+JXW-2-1-2-2', 'occtype': 'RES1-2SWB', 'st_damcat': 'RES', 'bldgtype': 'M', 'found_type': 'B', 'cbfips': '060014225001003', 'pop2amu65': 2, 'pop2amo65': 1, 'pop2pmu65': 2, 'pop2pmo65': 1, 'sqft': 1773, 'num_story': 2, 'ftprntid': '06001_559590', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 2, 'val_struct': 359933.479, 'val_cont': 179966.739, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1939, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2625592, 'y': 37.879116732, 'ground_elv': 350.8512103598022, 'ground_elv_m': 106.93944549560547, 'type': 'Building'}
7Key:  475206003 Asset:
8	 Coordinates:  [[-122.279912, 37.894081]]
9	 Features:  {'fd_id': 475206003, 'bid': '849VVPVC+J2P-4-4-4-3', 'occtype': 'RES1-2SNB', 'st_damcat': 'RES', 'bldgtype': 'W', 'found_type': 'C', 'cbfips': '060014213001020', 'pop2amu65': 2, 'pop2amo65': 0, 'pop2pmu65': 1, 'pop2pmo65': 0, 'sqft': 2341, 'num_story': 2, 'ftprntid': '06001_730116', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 1.5, 'val_struct': 378037.886, 'val_cont': 189018.943, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1939, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2799116, 'y': 37.894081399, 'ground_elv': 195.71405070861817, 'ground_elv_m': 59.65364074707031, 'type': 'Building'}

The output also shows that the number of buildings in the two inventories, nsi_inventory and scraper_inventory, are different:

Total number of assets detected using NSI is 27705
Total number of assets detected using OSM_FootprintScraper is 35547

As there are different numbers of buildings in the two inventories, when integrating NSI dataset into the footprint inventory, there will be assets for which no NSI data exists. In the merge performed with the example run, 2 out of the 5 assets in the subset inventories do not have data available in NSI. This is shown in the output lines:


The original and integrated inventories are as shown:

 1******** SMALL INVENTORY WITH NO NSI_DATA *********
 2AssetInventory
 3Inventory stored in:  dict
 4Key:  2989 Asset:
 5	 Coordinates:  [[-122.2539358, 37.8823889], [-122.2538841, 37.8822577], [-122.2538636, 37.882258], [-122.2538454, 37.8821659], [-122.2540379, 37.8821623], [-122.2540337, 37.8822459], [-122.2539784, 37.882245], [-122.2540264, 37.8823667], [-122.2539358, 37.8823889]]
 6	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 2973}
 7Key:  13333 Asset:
 8	 Coordinates:  [[-122.2743673, 37.8721826], [-122.2743469, 37.8720391], [-122.2743897, 37.8720353], [-122.2743867, 37.8720143], [-122.2744387, 37.8720097], [-122.2744416, 37.8720305], [-122.2744612, 37.8720287], [-122.2744816, 37.8721725], [-122.2743673, 37.8721826]]
 9	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 1866}
10Key:  1989 Asset:
11	 Coordinates:  [[-122.2534638, 37.856443], [-122.2534705, 37.856479], [-122.2535403, 37.8564711], [-122.253547, 37.8564912], [-122.2535946, 37.8565177], [-122.2535993, 37.8565277], [-122.2536127, 37.8565272], [-122.2535939, 37.8564404], [-122.253494, 37.8564531], [-122.2534913, 37.8564399], [-122.2534638, 37.856443]]
12	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 625}
13Key:  9361 Asset:
14	 Coordinates:  [[-122.2654248, 37.8550534], [-122.2654134, 37.854993], [-122.2654737, 37.8549859], [-122.2654851, 37.8550463], [-122.2654248, 37.8550534]]
15	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 392}
16Key:  17479 Asset:
17	 Coordinates:  [[-122.292788, 37.8763201], [-122.2927717, 37.8762696], [-122.2928486, 37.8762541], [-122.2928649, 37.8763047], [-122.292788, 37.8763201]]
18	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 435}
19
20Getting National Structure Inventory (NSI) building data for the entered location input...
21Found a total of 3 building points in NSI that are within the entered region of interest
22keys:  [2989, 13333, 1989, 9361, 17479]  index    [0, 1, 2]
23
24Getting National Structure Inventory (NSI) building data for the entered location input...
25Found a total of 3 building points in NSI that match the footprint data.
26keys:  [2989, 13333, 1989, 9361, 17479]  index    [0, 1, 2]
27
28******** SMALL INVENTORY WITH RAW NSI DATA *********
29AssetInventory
30Inventory stored in:  dict
31Key:  2989 Asset:
32	 Coordinates:  [[-122.2539358, 37.8823889], [-122.2538841, 37.8822577], [-122.2538636, 37.882258], [-122.2538454, 37.8821659], [-122.2540379, 37.8821623], [-122.2540337, 37.8822459], [-122.2539784, 37.882245], [-122.2540264, 37.8823667], [-122.2539358, 37.8823889]]
33	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1954, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 2973, 'fd_id': 475445345, 'bid': '849VVP4W+HHW-2-2-2-2', 'occtype': 'IND6', 'st_damcat': 'IND', 'bldgtype': 'W', 'found_type': 'S', 'cbfips': '060014239021001', 'pop2amu65': 0, 'pop2amo65': 0, 'pop2pmu65': 4, 'pop2pmo65': 0, 'sqft': 6506.02409, 'num_story': 1, 'ftprntid': '06001_548222', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 0.5, 'val_struct': 958384.635, 'val_cont': 958384.635, 'val_vehic': 81000, 'source': 'E', 'med_yr_blt': 1939, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2535494, 'y': 37.85648153, 'ground_elv': 239.3753899307251, 'ground_elv_m': 72.96161651611328, 'lon': -122.2539358, 'lat': 37.882252355, 'fparea': 1592, 'repaircost': 389506.045, 'constype': 'RM1', 'occupancy': 'RES1'}
34Key:  13333 Asset:
35	 Coordinates:  [[-122.2743673, 37.8721826], [-122.2743469, 37.8720391], [-122.2743897, 37.8720353], [-122.2743867, 37.8720143], [-122.2744387, 37.8720097], [-122.2744416, 37.8720305], [-122.2744612, 37.8720287], [-122.2744816, 37.8721725], [-122.2743673, 37.8721826]]
36	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1992, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 1866, 'fd_id': 473584913, 'bid': '849VVPJW+WC4-6-2-5-3', 'occtype': 'RES1-1SWB', 'st_damcat': 'RES', 'bldgtype': 'M', 'found_type': 'B', 'cbfips': '060014216002007', 'pop2amu65': 2, 'pop2amo65': 1, 'pop2pmu65': 2, 'pop2pmo65': 1, 'sqft': 1592, 'num_story': 1, 'ftprntid': '06001_813170', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 2, 'val_struct': 389506.045, 'val_cont': 194753.022, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1954, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2539358, 'y': 37.882252355, 'ground_elv': 1004.1034449096679, 'ground_elv_m': 306.05072021484375, 'lon': -122.2743974, 'lat': 37.872097621, 'fparea': 1539.29, 'repaircost': 320524.48, 'constype': 'W1', 'occupancy': 'RES3A'}
37Key:  1989 Asset:
38	 Coordinates:  [[-122.2534638, 37.856443], [-122.2534705, 37.856479], [-122.2535403, 37.8564711], [-122.253547, 37.8564912], [-122.2535946, 37.8565177], [-122.2535993, 37.8565277], [-122.2536127, 37.8565272], [-122.2535939, 37.8564404], [-122.253494, 37.8564531], [-122.2534913, 37.8564399], [-122.2534638, 37.856443]]
39	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1939, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 625, 'fd_id': 474705763, 'bid': '849VVPCG+R6Q-4-2-3-2', 'occtype': 'RES3A', 'st_damcat': 'RES', 'bldgtype': 'W', 'found_type': 'S', 'cbfips': '060014223003010', 'pop2amu65': 1, 'pop2amo65': 0, 'pop2pmu65': 0, 'pop2pmo65': 0, 'sqft': 1539.29, 'num_story': 1, 'ftprntid': '06001_34778', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 0.5, 'val_struct': 320524.48, 'val_cont': 160262.24, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1992, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2743974, 'y': 37.872097621, 'ground_elv': 165.9004509815979, 'ground_elv_m': 50.56645584106445, 'lon': -122.2535494, 'lat': 37.85648153, 'fparea': 6506.02409, 'repaircost': 958384.635, 'constype': 'W1', 'occupancy': 'IND6'}
40Key:  9361 Asset:
41	 Coordinates:  [[-122.2654248, 37.8550534], [-122.2654134, 37.854993], [-122.2654737, 37.8549859], [-122.2654851, 37.8550463], [-122.2654248, 37.8550534]]
42	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 392}
43Key:  17479 Asset:
44	 Coordinates:  [[-122.292788, 37.8763201], [-122.2927717, 37.8762696], [-122.2928486, 37.8762541], [-122.2928649, 37.8763047], [-122.292788, 37.8763201]]
45	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 435}
46
47******** SMALL INVENTORY WITH PROCESSES NSI DATA*********
48AssetInventory
49Inventory stored in:  dict
50Key:  2989 Asset:
51	 Coordinates:  [[-122.2539358, 37.8823889], [-122.2538841, 37.8822577], [-122.2538636, 37.882258], [-122.2538454, 37.8821659], [-122.2540379, 37.8821623], [-122.2540337, 37.8822459], [-122.2539784, 37.882245], [-122.2540264, 37.8823667], [-122.2539358, 37.8823889]]
52	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1954, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 2973, 'fd_id': 475445345, 'bid': '849VVP4W+HHW-2-2-2-2', 'occtype': 'IND6', 'st_damcat': 'IND', 'bldgtype': 'W', 'found_type': 'S', 'cbfips': '060014239021001', 'pop2amu65': 0, 'pop2amo65': 0, 'pop2pmu65': 4, 'pop2pmo65': 0, 'sqft': 6506.02409, 'num_story': 1, 'ftprntid': '06001_548222', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 0.5, 'val_struct': 958384.635, 'val_cont': 958384.635, 'val_vehic': 81000, 'source': 'E', 'med_yr_blt': 1939, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2535494, 'y': 37.85648153, 'ground_elv': 239.3753899307251, 'ground_elv_m': 72.96161651611328, 'lon': -122.2539358, 'lat': 37.882252355, 'fparea': 1592, 'repaircost': 389506.045, 'constype': 'RM1', 'occupancy': 'RES1'}
53Key:  13333 Asset:
54	 Coordinates:  [[-122.2743673, 37.8721826], [-122.2743469, 37.8720391], [-122.2743897, 37.8720353], [-122.2743867, 37.8720143], [-122.2744387, 37.8720097], [-122.2744416, 37.8720305], [-122.2744612, 37.8720287], [-122.2744816, 37.8721725], [-122.2743673, 37.8721826]]
55	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1992, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 1866, 'fd_id': 473584913, 'bid': '849VVPJW+WC4-6-2-5-3', 'occtype': 'RES1-1SWB', 'st_damcat': 'RES', 'bldgtype': 'M', 'found_type': 'B', 'cbfips': '060014216002007', 'pop2amu65': 2, 'pop2amo65': 1, 'pop2pmu65': 2, 'pop2pmo65': 1, 'sqft': 1592, 'num_story': 1, 'ftprntid': '06001_813170', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 2, 'val_struct': 389506.045, 'val_cont': 194753.022, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1954, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2539358, 'y': 37.882252355, 'ground_elv': 1004.1034449096679, 'ground_elv_m': 306.05072021484375, 'lon': -122.2743974, 'lat': 37.872097621, 'fparea': 1539.29, 'repaircost': 320524.48, 'constype': 'W1', 'occupancy': 'RES3A'}
56Key:  1989 Asset:
57	 Coordinates:  [[-122.2534638, 37.856443], [-122.2534705, 37.856479], [-122.2535403, 37.8564711], [-122.253547, 37.8564912], [-122.2535946, 37.8565177], [-122.2535993, 37.8565277], [-122.2536127, 37.8565272], [-122.2535939, 37.8564404], [-122.253494, 37.8564531], [-122.2534913, 37.8564399], [-122.2534638, 37.856443]]
58	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 1939, 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 625, 'fd_id': 474705763, 'bid': '849VVPCG+R6Q-4-2-3-2', 'occtype': 'RES3A', 'st_damcat': 'RES', 'bldgtype': 'W', 'found_type': 'S', 'cbfips': '060014223003010', 'pop2amu65': 1, 'pop2amo65': 0, 'pop2pmu65': 0, 'pop2pmo65': 0, 'sqft': 1539.29, 'num_story': 1, 'ftprntid': '06001_34778', 'ftprntsrc': 'NGA', 'students': 0, 'found_ht': 0.5, 'val_struct': 320524.48, 'val_cont': 160262.24, 'val_vehic': 27000, 'source': 'P', 'med_yr_blt': 1992, 'firmzone': 'NA', 'o65disable': 0.22, 'u65disable': 0.03, 'x': -122.2743974, 'y': 37.872097621, 'ground_elv': 165.9004509815979, 'ground_elv_m': 50.56645584106445, 'lon': -122.2535494, 'lat': 37.85648153, 'fparea': 6506.02409, 'repaircost': 958384.635, 'constype': 'W1', 'occupancy': 'IND6'}
59Key:  9361 Asset:
60	 Coordinates:  [[-122.2654248, 37.8550534], [-122.2654134, 37.854993], [-122.2654737, 37.8549859], [-122.2654851, 37.8550463], [-122.2654248, 37.8550534]]
61	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 392}
62Key:  17479 Asset:
63	 Coordinates:  [[-122.292788, 37.8763201], [-122.2927717, 37.8762696], [-122.2928486, 37.8762541], [-122.2928649, 37.8763047], [-122.292788, 37.8763201]]
64	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 435}

NSI Integration Notebook

Here is a link to a Jupyter Notebook that runs the basic code, accompanied by graphics to better illustrate the output.

Note

  1. Information on the fields output for NSI can be found here

  2. When the number of buildings in the NSI differs from the inventory it is being merged with, imputation may be required during the integration process.

  3. The NSI is new and under development and as a consequence is not perfect.