-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpressure_converter.py
More file actions
388 lines (317 loc) · 17.4 KB
/
pressure_converter.py
File metadata and controls
388 lines (317 loc) · 17.4 KB
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#START OF HEADER
#
#This program is designed to output altitude-corrected barometric pressure calculated from the pressure
#of the local NWS nearest to the given latitude and longitude using the user's estimated elevation
#the local NWS barometric pressure and estimated elevation are found by passing the user's lat and lon
#to a generated url for the NWS, which are pulled via BeutifulSoup4 into the program
#This url is provided to the user for them to verify the input data
#
#Cheers! -Kevin Risolo, MMP, DABR (kprisolo@gmail.com / sirlazy4077)
#
#
#For the coders out there:
#
#TODO maybe make a function for the nws or wunderground choice
#TODO have a function take an address and split it into lat and lon for user
#TODO make this... cleaner, or at least something capable of being a webapp
#
#END OF HEADER
#START OF PROGRAM
#
#imports
import urllib.request as ul
from bs4 import BeautifulSoup as soup
#helper functions to take user input, one for y/n, and one for numbers
def get_input(y_n_question):
#return yes as true, no as false
yes_no_bool = False
#check input y/n response is appropriate
flag_loop = True
while(flag_loop):
#strip of whitespace, apply lower case, take only the first letter after that
input_user = input(y_n_question)
input_striplower = input_user.lower().strip()
input_cleaned = input_striplower[:1]
if (input_cleaned == 'y'):
flag_loop = False;
yes_no_bool = True;
elif (input_cleaned == 'n'):
flag_loop = False;
yes_no_bool = False;
else:
print("Please type a valid input of 'y' or 'n'")
return yes_no_bool
# get_input("testing y/n question: ") #DEBUG
def get_num_input(num_input):
#return a clean number input
return_num = 0;
#check input number is appropriate
flag_loop = True
while(flag_loop):
input_num = input(num_input).strip()
try:
float(input_num)
except:
print("Please enter a valid number (example format: 000.00)")
else:
flag_loop = False
return_num = float(input_num)
return return_num
# get_num_input("what number to test: ") #DEBUG
#NOTE: The code below is for DEBUG only with what BS4 pulled from the webpage
def soup_check(pagesoup):
#Use to find all id tags on the page
print("Tag names: ") #DEBUG
tags = [tag.name for tag in pagesoup.find_all()]
print(tags) #DEBUG
#Use to pull a txt file of the html to visually parse
print("HTML data: ") #DEBUG
print(pagesoup) #DEBUG
#Use to find all id tags on the page #DEBUG
ids = [tag['id'] for tag in pagesoup.select('div[id]')]
print(ids) #DEBUG
#Use to find all classes on the page
classes = set()
for tag in tags:
for i in pagesoup.find_all(tag):
if i.has_attr("class"):
if len( i['class'] ) != 0:
classes.add(" ".join( i['class']))
print("Classes: ") #DEBUG
print(classes) #DEBUG
def nws(pagesoup):
current_conditions_detail = [i.text for i in pagesoup.find_all(id='current_conditions_detail')]
#pressure_id = current_conditions_detail #DEBUG
#print(current_conditions_detail[0].split('\n\n')) #DEBUG
curr_cond_det_split = current_conditions_detail[0].split('\n\n')
curr_cond_baro_line = curr_cond_det_split[3].split('\n')
curr_cond_baro_line_split = curr_cond_baro_line[2].split(' ')
#This is the barometric pressure of the local NWS station
curr_cond_baro = curr_cond_baro_line_split[0]
baro = curr_cond_baro
# print(baro) #DEBUG
#altitude = <div id="about_forecast">
about_forecast = [i.text for i in pagesoup.find_all(id='about_forecast')]
about_forecast_split = about_forecast[0].split('\n\n')
about_forecast_elev_line = about_forecast_split[1]
about_forecast_elev_split_elev = about_forecast_elev_line.split('(Elev. ')
about_forecast_elev_space = about_forecast_elev_split_elev[1].split(' ')
#This is the altitude of the given lat+lon
about_forecast_elev = about_forecast_elev_space[0]
elev = about_forecast_elev
# print(elev) #DEBUG
return (baro, elev)
def wunderground(pagesoup):
#finding the class with pressure on the WeatherUnderground page
baro_find = pagesoup.find(class_="test-false wu-unit wu-unit-pressure ng-star-inserted")
# print(baro_find) #DEBUG
baro_find_text = baro_find.text
# print(baro_find_text) #DEBUG
baro_find_split = baro_find_text.split('°')
baro = baro_find_split[0].strip()
# print(baro) #DEBUG
#finding the class with elevation on the WeatherUnderground page
elev_find = pagesoup.find(class_="wx-data ng-star-inserted")
# print(elev_find) #DEBUG
elev_find_text = elev_find.text
# print(elev_find_text) #DEBUG
elev_find_split = elev_find_text.split(' ')
# print(elev_find_split) #DEBUG
elev = elev_find_split[1][:-2].strip()
# print(elev) #DEBUG
return (baro, elev)
def nws_or_wunderground(lat_round, lon_round):
nws_or_wunderground_flag = True
while (nws_or_wunderground_flag):
nws_or_wunderground = get_num_input("Would you like to use the NWS for USA sites or WeatherUnderground for world-wide sites? \n Enter 1 for NWS, 2 for Wunderground: ")
if (nws_or_wunderground == int(1)):
print("Here are the details for the NWS for your given lat and lon: ")
url_head = 'https://forecast.weather.gov/MapClick.php?lat='
url_compiled = url_head + str(lat_round) + "&lon=" + str(lon_round)
print("Pressure is found near the top of the page, under Current Conditions at, next to the bold text Barometer (reported in inHG)")
print("Elevation is found towards the bottom right, below the map, next to the bold text Point Forecast (reported in feet)")
print()
nws_or_wunderground_flag = False
return (1, url_compiled)
elif (nws_or_wunderground == int(2)):
print("Here are the details for Weather Underground for your given lat and lon: ")
url_head = 'https://www.wunderground.com/hourly/'
url_compiled = url_head + str(lat_round) + "," + str(lon_round)
print("Pressure is found near the middle-left of the page (reported in inHG)")
print("Elevation is found towards the top-left (reported in feet)")
print()
nws_or_wunderground_flag = False
return (2, url_compiled)
else:
print("Please enter a valid input")
print()
#the main functions to pull pressure from input lat/lon and return altitude corrected pressure in mmHg,
# and to calc Ctp from that value,
# and to do intercomparsion with that value
#PART 1/3: Get pressure from lat and lon provided, corrected for altitude
def pressure():
pressure_flag = True
while(pressure_flag):
try:
#test_url_raw = 'https://forecast.weather.gov/MapClick.php?lat=40.3100&lon=-75.1305' #DEBUG
#hard_coded_lat = 40.3071 #DEBUG
#hard_coded_lon = -75.1477 #DEBUG
input_lat = round(get_num_input("What is your latitude? (ex: 40.3071): "),4)
input_lon = round(get_num_input("What is your longitude? (ex: -75.1477): "),4)
#lat = hard_coded_lat #DEBUG
#lon = hard_coded_lon #DEBUG
lat = input_lat
lon = input_lon
lat_round = round(lat, 3)
lon_round = round(lon, 3)
#the url which will generate a page for the given lat and lon to pull from, after picking from nws or wunderground
nws_or_wunderground_return = nws_or_wunderground(lat_round, lon_round)
nws_or_wunderground_choice = nws_or_wunderground_return[0]
url_compiled = nws_or_wunderground_return[1]
print("url compiled from given lat and lon, click to verify pressure and altitude/elevation: ")
print(url_compiled)
print()
#BeautifulSoup to extract the barometric pressure and the altitude
url = url_compiled
req = ul.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
client = ul.urlopen(req)
htmldata = client.read()
client.close()
pagesoup = soup(htmldata, "html.parser")
# soup_check(pagesoup) #DEBUG ONLY
if (nws_or_wunderground_choice == 1):
nws_return = nws(pagesoup)
baro = nws_return[0]
elev = nws_return[1]
elif (nws_or_wunderground_choice == 2):
wunderground_return = wunderground(pagesoup)
baro = wunderground_return[0]
elev = wunderground_return[1]
#This code below is common for both, printing the elevation and baro pressure pulled
print("Here is the pulled barometric pressure for the local station at above link: ")
print(baro + " inHG")
print()
print("Here is the pulled altitude for the given lat and lon at above link: ")
print(elev + " feet")
print()
#calculate the local barometric pressure from the input lat+lon
#get station pressure and the elevation from the webpage
#do math and get the local barometric pressure = 25.4 * (NWS_pressure - (local_alt_in_FEET/1000))
baro_lat_lon = round(25.4 * (float(baro) - (float(elev)/1000)), 2)
print("Here is your local barometric pressure provided in mmHg,\n for the given lat " +
str(lat_round) + " and lon " + str(lon) + ",\n whose altitude is " +
str(elev) + "feet,\n converted from NWS pressure of " +
str(baro) + "inHg:")
print(str(baro_lat_lon) + " mmHg")
print()
#conversions from mmHg to other pressure units commonly seen
print("And here is your pressure in different units: ")
print(str(round(baro_lat_lon,2)) + " Tor, kPa")
baro_lat_lon_inHG = baro_lat_lon * 0.03937
print(str(round(baro_lat_lon_inHG,3)) + " inHG")
baro_lat_lon_hPa = baro_lat_lon * 1.33322
print(str(round(baro_lat_lon_hPa,2)) + " hPa, mbar")
baro_lat_lon_bar = baro_lat_lon_hPa * 0.001
print(str(round(baro_lat_lon_bar,4)) + " bar")
baro_lat_lon_Pa = baro_lat_lon * 133.322
print(str(round(baro_lat_lon_Pa,1)) + " Pascal")
print()
except IndexError:
print("There was an error in processing this request.")
print("Please check your lat and lon inputs are entered correctly.")
print("Please note this program only functions for locations in the USA.")
print("If inputs are correct, the NWS may be down. Please use alternative means for pressure readings.")
print()
pressure_question = "Would you like to go back and change your lat/lon, and/or change between NWS and Weather Underground? (y/n): "
pressure_input = get_input(pressure_question)
if (pressure_input):
continue
else:
pressure_flag = False
return baro_lat_lon
#PART 2/3: Calculate CTP from the found pressure and the given vault temperature, return the temp entered
def ctp(baro_lat_lon):
ctp_flag = True
while(ctp_flag):
#hard_coded_temp = 20.0 #DEBUG
input_temp = get_num_input("What is your temperature, in Celsius? (ex: 20.0): ")
temp_round = round(float(input_temp),2)
#temp_raw = hard_coded_temp #DEBUG
temp_raw = temp_round
ctp = round(((273.2 + temp_round) / (273.2 + 20.0)) * (760.0 / baro_lat_lon), 3)
print("Your Ctp for the given temperature of " + str(temp_raw) + "°C and pressure of " +
str(baro_lat_lon) + "mmHg is: ")
print(str(ctp))
print()
ctp_question = "Would you like to go back and change your temperature? (y/n): "
ctp_input = get_input(ctp_question)
if (ctp_input):
continue
else:
ctp_flag = False
return temp_round
#PART 3/3: Intercomparison, return the intercomparison absolute and percent differences for temp and press
def intercomparison(baro_lat_lon, temp_round):
intercomp_flag = True
while(intercomp_flag):
intercomp_temp = get_num_input("What is your temperature for intercomparison, in Celsius? (ex: 20.0): ")
intercomp_temp_round = round(float(intercomp_temp),2)
intercomp_baro = get_num_input("What is your pressure for intercomparison, in mmHg? (ex: 760.0): ")
intercomp_baro_round = round(float(intercomp_baro),2)
intercomp_temps_abs = round((intercomp_temp_round - temp_round),2)
intercomp_temps_percent = round(((intercomp_temp_round - temp_round)/temp_round)*100,2)
intercomp_temps_kelvin = round(((intercomp_temp_round - temp_round)/(temp_round + 273.2))*100,2)
print("The absolute difference in temperatures is " + str(intercomp_temps_abs) + "°C" + "\n " +
"and the percent difference in Celsius is " + str(intercomp_temps_percent) + "%" + "\n " +
"and the percent difference in Kelvin is " + str(intercomp_temps_kelvin) + "%")
intercomp_baro_abs = round((intercomp_baro_round - baro_lat_lon),2)
intercomp_baro_percent = round(((intercomp_baro_round - baro_lat_lon)/baro_lat_lon)*100,2)
print("The absolute difference in pressures is " + str(intercomp_baro_abs) + "mmHg" + "\n " +
"and the percent difference is " + str(intercomp_baro_percent) + "%")
print()
intercomp_question = "Would you like to go back and change your temperature or pressure? (y/n): "
intercomp_input = get_input(intercomp_question)
if (intercomp_input):
continue
else:
intercomp_flag = False
return (intercomp_baro_abs, intercomp_baro_percent, intercomp_temps_abs, intercomp_temps_percent)
def main():
program_flag = True
while(program_flag):
#find your lat and lon here:
print("Find your lat and lon via this website, or another of your choice: ")
print('https://www.latlong.net/')
print()
#run the pressure pull and convert function
baro_lat_lon = pressure()
#ask the user if they want to continue to a Ctp correction
continue_to_ctp_question = "Would you like to do a Ctp factor for the pulled pressure? (y/n): "
continue_to_ctp_input = get_input(continue_to_ctp_question)
if(not continue_to_ctp_input):
break
#else continue to run Ctp function
else:
temp_round = ctp(baro_lat_lon)
#ask the user if they want to continue to an intercomparison
continue_to_inter_question = "Would you like to do an intercomparison for the pulled pressure and input temp? (y/n): "
continue_to_inter_input = get_input(continue_to_inter_question)
if((not continue_to_inter_input) or (not continue_to_ctp_input)):
break
#else continue to intercomparison
else:
intercomparison(baro_lat_lon, temp_round)
#ask user if they want to rerun the program
program_question = "Would you like to rerun the program? (y/n): "
program_input = get_input(program_question)
if (program_input):
continue
else:
program_flag = False
print("Thank you for using BaroMe, powered by Penn! Goodbye and go well!")
print()
#comment out below main call if only calling the functions, not using this as a program
if __name__=="__main__":
main()
#
#END OF PROGRAM