-
Notifications
You must be signed in to change notification settings - Fork 3
/
ads_b_tool_6.py
194 lines (170 loc) · 11.6 KB
/
ads_b_tool_6.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# -*- coding: utf-8 -*-
#!/usr/bin/env python
"""
File name: ads_b_tool_6.py
Author: Shawn Hutchinson
Credits: Shawn Hutchinson, Brian Peterson
Description: Generates output tables summarizing waypoint frequencies by day, hour, month/year, aircraft operator, and aircraft type.
Status: Development
Date created: 1/24/2022
Date last modified: 12/16/2022
Python Version: 3.9.16
"""
# Import libraries
import arcpy, time
# User-specified local variable(s) for ArcGIS script tool
parkName = arcpy.GetParameterAsText(0)
inputWaypoints = arcpy.GetParameterAsText(1)
faaTable = arcpy.GetParameterAsText(2)
# Set local environments
arcpy.env.workspace = arcpy.Describe(inputWaypoints).path
arcpy.env.overwriteOutput = True
# Fixed local variables
inField1 = "ICAO_address"
joinTable1 = faaTable + "/MASTER"
joinField1 = "MODE_S_CODE_HEX"
fieldList1 = ["TYPE_AIRCRAFT", "TYPE_REGISTRANT"]
operator_reclassTable = [[1, "Individual"], [2, "Partnership"], [3, "Corporation"], [4, "Co-Owned"], [5, "Government"], [7, "LLC"], [8, "Non-Citizen Corporation"], [9, "Non-Citizen Co-Owned"]]
type_reclassTable = [[1, "Glider"], [2, "Balloon"], [3, "Blimp/Dirigible"], [4, "Fixed Wing Single Engine"], [5, "Fixed Wing Multi Engine"], [6, "Rotorcraft"], [7, "Weight-Shift-Control"], [8, "Powered Parachute"], [9, "Gyroplane"]]
# Define function for determining the type of day - weekday or weekend
codeblock1 = """
def getDayType(labelday):
daynum = labelday.weekday()
if daynum < 5:
return "Weekday"
else:
return "Weekend"
"""
try:
# Start timer and create progressor
start = time.time()
arcpy.SetProgressor("step", "Creating the buffer and clipping screened waypoints..", 0, 6, 1)
# Copy input waypoint file to a temp file and delete identical flight_id's to represent flights
arcpy.SetProgressorLabel("Creating a temporary copy of the input waypoint file...")
arcpy.SetProgressorPosition()
arcpy.management.CopyFeatures(inputWaypoints, "temp1")
arcpy.management.DeleteIdentical("temp1", "flight_id")
print("Input waypoint feature class copied.")
arcpy.AddMessage("Input waypoint feature class copied.")
# Convert local DateTime field to text, then parse into HOUR and MONTH fields for later summarization
arcpy.SetProgressorLabel("Converting DateTime to local time and creating new hour and month fields...")
arcpy.SetProgressorPosition()
arcpy.management.ConvertTimeField("temp1", 'TIME', "", "TIME_TEXT", 'TEXT', "yyyy/MM/dd HH:mm:ss")
arcpy.management.CalculateField("temp1", "DAY", "!TIME!.strftime('%A')", "PYTHON3")
arcpy.management.CalculateField("temp1", "HOUR", "!TIME_TEXT![-8:-6]", 'PYTHON3')
arcpy.management.CalculateField("temp1", "MONTH", "!TIME_TEXT![-14:-12]", 'PYTHON3')
arcpy.management.CalculateField("temp1", "YEAR", "!TIME_TEXT![0:4]", 'PYTHON3')
arcpy.management.CalculateField("temp1", "MOYEAR", "!MONTH! + '/' + !YEAR!", 'PYTHON3')
print("Local time conversion complete; hour and month fields calculated.")
arcpy.AddMessage("Local time conversion complete; hour and month fields calculated.")
# Calculate frequencies and percentages for day, hour, and month/year tables
arcpy.SetProgressorLabel("Calculating day, hour, and month frequencies and percentages...")
arcpy.SetProgressorPosition()
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_HR", "HOUR")
totalWaypoints = 0
with arcpy.da.SearchCursor(parkName + "_" + "FlightSummary_HR", "FREQUENCY") as cursor:
for row in cursor:
totalWaypoints += row[0]
arcpy.management.AddField(parkName + "_" + "FlightSummary_HR", "PERCENTAGE", "DOUBLE")
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_HR", ("FREQUENCY", "PERCENTAGE")) as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWaypoints * 100, 1)])
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_DAY", "DAY")
arcpy.management.AddField(parkName + "_" + "FlightSummary_DAY", "PERCENTAGE", "DOUBLE")
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_DAY", ("FREQUENCY", "PERCENTAGE")) as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWaypoints * 100, 1)])
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_MOYR", "MOYEAR")
arcpy.management.AddField(parkName + "_" + "FlightSummary_MOYR", "PERCENTAGE", "DOUBLE")
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_MOYR", ("FREQUENCY", "PERCENTAGE")) as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWaypoints * 100, 1)])
print("Day, hour, and month flight summaries calculated.")
arcpy.AddMessage("Day, hour, and month flight summaries calculated.")
# Calculate frequencies and percentages for flights by hour for weekdays and weekends
arcpy.management.CalculateField("temp1", "DAYTYPE", "getDayType(!TIME!)", "PYTHON3", codeblock1)
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_DAYTYPE2", ["HOUR", "DAYTYPE"])
arcpy.management.Sort(parkName + "_" + "FlightSummary_DAYTYPE2", parkName + "_" + "FlightSummary_DAYTYPE", "DAYTYPE")
arcpy.management.Delete(parkName + "_" + "FlightSummary_DAYTYPE2")
arcpy.management.AddField(parkName + "_" + "FlightSummary_DAYTYPE", "PERCENTAGE", "DOUBLE")
totalWeekdays = 0
with arcpy.da.SearchCursor(parkName + "_" + "FlightSummary_DAYTYPE", "FREQUENCY", "DAYTYPE = 'Weekday'") as cursor:
for row in cursor:
totalWeekdays += row[0]
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_DAYTYPE", ("FREQUENCY", "PERCENTAGE"), "DAYTYPE = 'Weekday'") as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWeekdays * 100, 1)])
print("{0} weekday flights identified and hourly summaries calculated.".format(totalWeekdays))
arcpy.AddMessage("{0} weekday flights identified and hourly summaries calculated.".format(totalWeekdays))
totalWeekends = 0
with arcpy.da.SearchCursor(parkName + "_" + "FlightSummary_DAYTYPE", "FREQUENCY", "DAYTYPE = 'Weekend'") as cursor:
for row in cursor:
totalWeekends += row[0]
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_DAYTYPE", ("FREQUENCY", "PERCENTAGE"), "DAYTYPE = 'Weekend'") as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWeekends * 100, 1)])
arcpy.management.DeleteField(parkName + "_" + "FlightSummary_DAYTYPE", "ORIG_FID")
print("{0} weekend flights identified and hourly summaries calculated.".format(totalWeekends))
arcpy.AddMessage("{0} weekend flights identified and hourly summaries calculated.".format(totalWeekends))
# Strip whitespace from the MODE_S_CODE_HEX field in the FAA MASTER file
arcpy.SetProgressorLabel("Joining select fields from MASTER table of FAA Releaseable Database...")
arcpy.SetProgressorPosition()
arcpy.management.CalculateField(joinTable1, joinField1, "!MODE_S_CODE_HEX!.strip()", "PYTHON3")
# Perform a table join to add FAA database variables from MASTER file
arcpy.management.JoinField("temp1", inField1, joinTable1, joinField1, fieldList1)
print("Type_Aircraft and Type_Registrant fields joined from FAA MASTER table.")
arcpy.AddMessage("Type_Aircraft and Type_Registrant fields joined from FAA MASTER table.")
# Need to make TYPE_REGISTRANT field in temp1 an INT to allow for later reclassification
arcpy.management.AddField("temp1", "TYPE_OPERATOR", "SHORT")
arcpy.management.CalculateField("temp1", "TYPE_OPERATOR", "!TYPE_REGISTRANT!", "PYTHON3")
# Calculate frequencies and percentages for flight operators and aircraft types
arcpy.SetProgressorLabel("Calculating flight operator and type frequencies and percentages...")
arcpy.SetProgressorPosition()
totalWaypoints = 0
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_Operators", "TYPE_OPERATOR")
arcpy.analysis.Frequency("temp1", parkName + "_" + "FlightSummary_Type", "TYPE_AIRCRAFT")
with arcpy.da.SearchCursor(parkName + "_" + "FlightSummary_Operators", "FREQUENCY") as cursor:
for row in cursor:
totalWaypoints += row[0]
arcpy.management.AddField(parkName + "_" + "FlightSummary_Operators", "PERCENTAGE", "DOUBLE")
arcpy.management.AddField(parkName + "_" + "FlightSummary_Type", "PERCENTAGE", "DOUBLE")
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_Operators", ("FREQUENCY", "PERCENTAGE")) as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWaypoints * 100, 1)])
with arcpy.da.UpdateCursor(parkName + "_" + "FlightSummary_Type", ("FREQUENCY", "PERCENTAGE")) as cursor:
for frequency, percentage in cursor:
cursor.updateRow([frequency, round(frequency / totalWaypoints * 100, 1)])
print("Aircraft operator and type summaries calculated.")
arcpy.AddMessage("Aircraft operator and type summaries calculated.")
# Reclassify operator and aircraft type numeric codes into descriptive text fields
arcpy.SetProgressorLabel("Reclassifying aircraft operators and types...")
arcpy.SetProgressorPosition()
arcpy.management.ReclassifyField(parkName + "_" + "FlightSummary_Operators", "TYPE_OPERATOR", "MANUAL", "", "", "", operator_reclassTable, "", "Aircraft_Operator")
arcpy.management.ReclassifyField(parkName + "_" + "FlightSummary_Type", "TYPE_AIRCRAFT", "MANUAL", "", "", "", type_reclassTable, "", "Aircraft_Type")
arcpy.management.DeleteField(parkName + "_" + "FlightSummary_Operators", "Aircraft_Operator_RANGE")
arcpy.management.DeleteField(parkName + "_" + "FlightSummary_Type", "Aircraft_Type_RANGE")
print("Reclassification of aircraft operators and types complete.")
arcpy.AddMessage("Reclassification of aircraft operators and types complete.")
# Report final aircraft summaries
print("Success... Aircraft flights summarized!")
arcpy.AddMessage("Success... Aircraft flight summarized!")
print("A total of {0} flights were used to generate the summary data.".format(str(totalWaypoints)))
arcpy.AddMessage("A total of {0} flights were used to generate the summary data.".format(str(totalWaypoints)))
except arcpy.ExecuteError:
for i in range(0, arcpy.GetMessageCount()):
arcpy.AddError("{0}: {1}".format(arcpy.GetSeverity(i), arcpy.GetMessage(i)))
except:
print("An unexpected error occurred processing the input file {0}".format(inputWaypoints))
arcpy.AddWarning("An unexpected error occurred processing the input file {0}".format(inputWaypoints))
finally:
# Delete files no longer needed
delList = arcpy.ListFeatureClasses("temp*")
for i in delList:
arcpy.management.Delete(i)
print("Temporary files deleted.")
# Report execution time
end = time.time()
print("Total Execution Time (secs) = {0}".format(str(round(end - start, 1))))
arcpy.AddMessage("Total Execution Time (secs) = {0}".format(str(round(end - start, 1))))
# Reset the progressor
arcpy.ResetProgressor()