-
Notifications
You must be signed in to change notification settings - Fork 2
/
DCSCheckWXConvertEnricher.py
executable file
·226 lines (194 loc) · 7.98 KB
/
DCSCheckWXConvertEnricher.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
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
import json
import random
import inspect
class DCSCheckWXConvertEnricher(object):
"""
Enrichment procedures are mostly based on dcs_weather from here https://forums.eagle.ru/showthread.php?t=198402.
Some other things are new, deterministic randomness, temperature correction for sea level, etc.
"""
weatherdata = None
parseddata = None
def __init__(self, weatherdata):
self.weatherdata = weatherdata
self.parseddata = json.loads(weatherdata.text)
def seedRandom(self):
"""
Seeds the PRNG deterministically for repeatable same randoms
:return: None
"""
callingFunc = inspect.stack()[1].function
random.seed(self.getWeatherText() + callingFunc)
def getDeterministicRandomFloat(self, min, max):
"""
Returns a deterministic random value for a given function calling it and the underlaying weather data.
:param min: minimum float
:param max: maximum float
:return: float between min and max randomly chosen in a repeatable way
"""
assert max >= min
randval = random.random()
return min + ((max-min)*randval)
def getDeterministicRandomInt(self, min, max):
"""
Returns a deterministic random value for a given function calling it and the underlaying weather data.
:param min: minimum int
:param max: maximum int
:return: int between min and max randomly chosen in a repeatable way
"""
return random.randint(min, max)
def normalizeDegrees(self, angle):
retangle = angle
if retangle < 0:
retangle += 360
if retangle >= 360:
retangle -= 360
return retangle
def getWeatherText(self):
return self.weatherdata.text
def getWeatherCached(self):
return self.weatherdata.from_cache
def getLastWeather(self):
return self.weatherdata
def getClosestResult(self):
return self.parseddata['data'][0]
def getStationElevation(self):
return self.getClosestResult()['elevation']['meters']
def getBarometerMMHg(self):
return self.getClosestResult()['barometer']['hg'] * 25.4
def getTemperature(self):
closest_data = self.getClosestResult()
if hasattr(closest_data['temperature'],'celsius'):
return closest_data['temperature']['celsius']
if hasattr(closest_data['temperature'],'minimum'):
return closest_data['temperature']['minimum']['celsius']
return 21
def getTemperatureASL(self):
"""
The higher the elevation of the reporting station, the higher the sea level temperature really is.
This is using https://sciencing.com/tutorial-calculate-altitude-temperature-8788701.html as formula
to adjust the temperature for sea level.
:return: estimated temperature at sea level
"""
temperatureDelta = self.getStationElevation() * 0.0065
return self.getTemperature() + temperatureDelta
def getWindASL(self):
self.seedRandom()
try:
return {'direction': self.getClosestResult()['wind']['degrees'], 'speed': self.getClosestResult()['wind']['speed_mps'] }
except:
return {'direction': self.getDeterministicRandomInt(0, 360), 'speed': self.getDeterministicRandomFloat(0, 1)}
def getWind2000(self):
groundWind = self.getWindASL()
self.seedRandom()
newDirection = self.normalizeDegrees(groundWind['direction']+self.getDeterministicRandomInt(-10, 10))
return {'direction': newDirection, 'speed': groundWind['speed']+self.getDeterministicRandomFloat(1, 3)}
def getWind8000(self):
groundWind = self.getWindASL()
self.seedRandom()
newDirection = self.normalizeDegrees(groundWind['direction'] + self.getDeterministicRandomInt(-20, 20))
return {'direction': newDirection, 'speed': groundWind['speed']+self.getDeterministicRandomFloat(2, 8)}
def getGroundTurbulence(self):
try:
return self.getClosestResult()['wind']['gust_kts'] * 0.514444
except:
self.seedRandom()
return self.getDeterministicRandomFloat(0, 3) * 0.514444
def getCloudMinMax(self):
try:
clouds = self.getClosestResult()['clouds']
if len(clouds) == 0:
return {'min': 5000, 'max': 5000}
minClouds = None
maxClouds = None
for cloud in clouds:
if not minClouds or cloud['base_meters_agl'] < minClouds:
minClouds = cloud['base_meters_agl']
if not maxClouds or cloud['base_meters_agl'] > maxClouds:
maxClouds = cloud['base_meters_agl']
return {'min': minClouds + self.getStationElevation(), 'max': maxClouds + self.getStationElevation()}
except:
return {'min': 5000, 'max': 5000}
def getCloudBase(self):
return max(300, self.getCloudMinMax()['min'])
def getCloudThickness(self):
try:
clouds = self.getClosestResult()['clouds']
if len(clouds) == 0:
self.seedRandom()
return self.getDeterministicRandomInt(200, 300)
minmaxclouds = self.getCloudMinMax()
highestclouds = clouds[len(clouds) - 1]
if highestclouds['code'] in ('OVC'):
return max(200, minmaxclouds['max'] - minmaxclouds['min'])
else:
return minmaxclouds['max']-minmaxclouds['min']
except:
self.seedRandom()
return self.getDeterministicRandomInt(200, 300)
def containsAnyCondition(self, conditioncodes):
conditions = self.getClosestResult()['conditions']
for cond in conditions:
if cond['code'] in conditioncodes:
return True
return False
def getCloudDensity(self):
try:
clouds = self.getClosestResult()['clouds']
if len(clouds) == 0:
return 0
if self.containsAnyCondition(['TS']):
return 9
self.seedRandom()
highestclouds = clouds[len(clouds)-1]
if highestclouds['code'] in ('CAVOK', 'CLR', 'SKC', 'NCD', 'NSC'):
return 0
elif highestclouds['code'] in ('FEW'):
return self.getDeterministicRandomInt(1, 2)
elif highestclouds['code'] in ('SCT'):
return self.getDeterministicRandomInt(3, 4)
elif highestclouds['code'] in ('BKN'):
return self.getDeterministicRandomInt(5, 8)
elif highestclouds['code'] in ('OVC'):
return 9
elif highestclouds['code'] in ('VV'):
return self.getDeterministicRandomInt(2, 8)
return 0
except:
return 0
def getWeatherType(self):
if self.containsAnyCondition(['TS']):
return 2
elif self.containsAnyCondition(['RA', 'DZ', 'GR', 'UP']):
return 1
elif self.containsAnyCondition(['SN', 'SG', 'PL', 'IC', 'PL']):
if self.getTemperatureASL() < 2:
if self.getCloudDensity() >= 9:
return 4
else:
return 3
else:
return 1
return 0
def getFogEnabled(self):
return self.containsAnyCondition(['FG'])
def getFogVisibility(self):
if self.getFogEnabled():
self.seedRandom()
return self.getDeterministicRandomInt(800, 1000)
else:
return 0
def getFogThickness(self):
if self.getFogEnabled():
self.seedRandom()
return self.getDeterministicRandomInt(100, 300)
else:
return 0
def getVisibility(self):
try:
visibility = self.getClosestResult()['visibility']['meters_float']
if visibility >= 9000:
return 80000
else:
return visibility
except:
return 80000