Importer
BrailsPlusPlus is a modular python framework for creating workflows that create data for SimCenter applications. In order to allow applications to be built w/o the need to hard code every possible case within if blocks, there is a class in BrailsPlusPlus that will return the class given the class name. This is the Importer class. It’s has one method, get_class(), which will return the python class with that given name from which an object can be instantiated.
The following example shows a more typical python example.
1# Written: fmk 4/23
2# License: BSD-2
3
4import argparse
5
6from brails.types.asset_inventory import AssetInventory
7from brails.types.region_boundary import RegionBoundary
8from brails.scrapers.osm_footprint_scraper.osm_footprint_scraper import OSM_FootprintScraper
9from brails.scrapers.ms_footprint_scraper.ms_footprint_handler import MS_FootprintScraper
10from brails.scrapers.usa_footprint_scraper.usa_footprint_scraper import USA_FootprintScraper
11
12def main():
13
14 # Create the argument parser
15 parser = argparse.ArgumentParser(description="Demonstrate Importer.")
16 parser.add_argument('scraper', type=str, help="Location")
17 parser.add_argument('location', type=str, help="Location")
18
19 # Parse the arguments
20 args = parser.parse_args()
21
22 # create a RegionBoundary
23 region_boundary_object = RegionBoundary({"type": "locationName", "data": args.location})
24
25 scraper_type = args.scraper
26 if scraper_type == "OSM_FootprintScraper":
27 scraper = OSM_FootprintScraper({"length": "ft"})
28 elif scraper_type == "MS_FootprintScraper":
29 scraper = MS_FootprintScraper({"length": "ft"})
30 elif scraper_type == "USA_FootprintScraper":
31 scraper = USA_FootprintScraper({"length": "ft"})
32 else:
33 print(f"Unknown Scraper Type: {scraper_type}")
34
35 inventory = scraper.get_footprints(region_boundary_object)
36
37 print(f"num assets found: {len(inventory.inventory)} for {args.location} using {args.scraper}")
38
39 small_inventory = inventory.get_random_sample(4, 200)
40 small_inventory.print_info()
41
42# Run the main function if this script is executed directly
43if __name__ == "__main__":
44 main()
The following example shows it re-written using the Importer class.
1# Written: fmk 09/24
2# License: BSD-2
3
4"""
5importer.py
6================
7
8This is a simple example to demonstrate the Importer class in BRAILS++
9
10"""
11
12import argparse
13import sys
14
15# the following line is not neeeded if brails is imported from pypi
16# .. it is included here as it allows us to test the code on a nightly basis
17sys.path.insert(1, "../../")
18
19
20from brails.utils.importer import Importer
21
22
23def main():
24 # Create the argument parser
25 parser = argparse.ArgumentParser(description="Demonstrate Importer.")
26 parser.add_argument('scraper', type=str, help="Footprint Scraper")
27 parser.add_argument('location', type=str, help="Location")
28
29 # Parse the arguments
30 args = parser.parse_args()
31
32 importer = Importer()
33
34 region_boundary_class = importer.get_class("RegionBoundary")
35 region_boundary_object = region_boundary_class({"type": "locationName", "data": args.location})
36 scraper_class = importer.get_class(args.scraper)
37 scraper = scraper_class({"length": "ft"})
38 inventory = scraper.get_footprints(region_boundary_object)
39 print(f"num assets found: {len(inventory.inventory)} for {args.location} using {args.scraper}")
40
41
42# Run the main function if this script is executed directly
43if __name__ == "__main__":
44 main()
45
To run for example the importer.py script for Berkeley, CA the following would be issued frm a terminal window:
python3 importer.py USA_FootprintScraper "Berkeley, CA"
and the application would produce:
1
2Searching for Berkeley, CA...
3Found Berkeley, Alameda County, California, United States
4
5Meshing the defined area...
6
7Meshing complete. Split Berkeley into 76 cells
8
9Found a total of 28404 building footprints in Berkeley
10num assets found: 28404 for Berkeley, CA using USA_FootprintScraper
11AssetInventory
12Inventory stored in: dict
13Key: 1494 Asset:
14 Coordinates: [[-122.251349037992, 37.8918864620566], [-122.251516845084, 37.8918428029327], [-122.251549765644, 37.8919222669851], [-122.251381955857, 37.891965925353], [-122.251349037992, 37.8918864620566]]
15 Features: {'type': 'Building', 'buildingheight': 17.4, 'fpAreas': 1554}
16Key: 6666 Asset:
17 Coordinates: [[-122.249638045616, 37.8518085710136], [-122.249704555083, 37.8517353439222], [-122.249817801199, 37.8518000117672], [-122.249751291732, 37.8518732380851], [-122.249638045616, 37.8518085710136]]
18 Features: {'type': 'Building', 'buildingheight': 21.6, 'fpAreas': 1326}
19Key: 24068 Asset:
20 Coordinates: [[-122.286804056442, 37.8794971468902], [-122.286829349408, 37.8794214649434], [-122.286967954066, 37.8794505676668], [-122.286942660203, 37.8795262510017], [-122.286804056442, 37.8794971468902]]
21 Features: {'type': 'Building', 'buildingheight': 20.4, 'fpAreas': 1181}
22Key: 23236 Asset:
23 Coordinates: [[-122.260463864989, 37.8783452637543], [-122.260597977173, 37.8783233546667], [-122.260614329206, 37.8783862371837], [-122.260480216124, 37.8784081469617], [-122.260463864989, 37.8783452637543]]
24 Features: {'type': 'Building', 'buildingheight': 25.6, 'fpAreas': 925}
Note
When constructing an Importer object, the constructor code automatically searches through all directories within the brails codebase to locate every available class. This setup allows developers to add their code seamlessly, without needing to modify this class.
The purpose of the Importer class is to allow applications to be developed for building workflows. Consider developing an application that would parse the following JSON input file to such an application. By using the Importer class, this application can avoid a complex series of if-else statements to handle different types. Instead, it reads the type information and retrieves the appropriate class directly from the Importer. This approach is made possible because BrailsPlusPlus is an object-oriented framework that leverages abstract base classes (ABCs), defined using Python’s abc module.
1{
2 "workflow": {
3 "type":"Building",
4 "Description":"Inventory for NoWhere, FL",
5 "location":{
6 "classType":"namedLocation",
7 "appData":{
8 "coordinates":"Fort Meyers, FL"
9 }
10 },
11 "footprintSource":{
12 "classType":"USA Structures",
13 "appData":{
14 "length":"ft"
15 }
16 },
17 "augmentFiles":[
18 {
19 "classType": "csv",
20 "appData": {
21 "fileName":"assessor.csv",
22 "colMapping":"mapAssessor.json"
23 }
24 },
25 {
26 "classType": "csv",
27 "appData":{
28 "fileName":"myData.csv",
29 "colMapping":"None"
30 }
31 }
32 ],
33 "satelliteImageSource":{
34 "classType":"Google",
35 "appData":{
36 "gcpKey":"qg;lgqlgj"
37 }
38 },
39 "streetImagesSource":{
40 "classType":"Google",
41 "appData":{
42 "gcpKey":"qg;lgqlgj"
43 }
44 }
45 "streetFilters":[
46 "classType":"VanishingPoint",
47 "appData":{
48 },
49 "classType":"ClipVIT",
50 "appData":{
51 "prompt":"Remove trees occluding this image of a house"
52 }
53 "classType":"RemoveBackgroundNoise",
54 "appData":{
55 "model":"zenodo://blha.blah.blah"
56 }
57 ],
58 "arialFilters":[
59 "classType":"",
60 "classType":"RemoveTrees",
61 "appData":{
62 },
63 ],
64 "predictionsArial"=[
65 {
66 "classType":"BrailsRoofType",
67 "appData":{
68 "model"::"zenodo://blah/blah/blah"
69 },
70 "heading":"roofShape"
71 },
72 {
73 "classType":"Clip",
74 "appData":{
75 "prompts"::"this is a pricture of a roof, is it a gabled roof, hiiped roof or flat roof?"
76 }
77 "heading":"roofShapeClip"
78 },
79 },
80 "predictionsStreet"=[
81 {
82 "classType":"BrailsNOS",
83 "appData":{
84 "model"::"zenodo://blah/blah/blah"
85 },
86 "heading":"numberOfStories"
87 },
88 {
89 "classType":"Clip_NumberOfFloors",
90 "appData":{
91 "fileName"::"promptsForNumFloors.txt"
92 "segmenter": {
93 "classType":"SAM",
94 "appData":{
95 }
96 }
97 }
98 "heading":"roofShape"
99 },
100 {
101 "classType":"FirstFloorElevation",
102 "appData":{
103 }
104 "heading":"firstFloorElevation"
105 }
106 ]
107 {
108 "imputer": {
109 "classType":"KNN",
110 "appData":{
111 }
112 }
113 }
114 }
115}
116
117
118
119
120
121
122
An additional advantage of this approach is that as developers add new subclasses, they do not have to search through the code to see all the places that need the if-else statements modified for their classes to be used.