Skip to content

Commit b0b8482

Browse files
author
R Bailey
committed
Preparing files to upload to pypi, predstorm_l5 now runs with persistence model (pickled NOAA real-time files) when STEREO-A is not available.
1 parent a305360 commit b0b8482

6 files changed

Lines changed: 96 additions & 86 deletions

File tree

predstorm/data.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def __len__(self):
222222

223223

224224
def __str__(self):
225-
"""Print string describing object."""
225+
"""Return string describing object."""
226226

227227
ostr = "Length of data:\t\t{}\n".format(len(self))
228228
ostr += "Keys in data:\t\t{}\n".format(self.vars)
@@ -1111,7 +1111,7 @@ def make_kp_prediction(self):
11111111
def get_state(self):
11121112
"""Finds state of wind and fills self.state attribute."""
11131113

1114-
print("Coming soon.")
1114+
logger.info("Coming soon.")
11151115

11161116
# -----------------------------------------------------------------------------------
11171117
# Data archiving
@@ -1120,7 +1120,7 @@ def get_state(self):
11201120
def archive(self):
11211121
"""Make archive of long-term data."""
11221122

1123-
print("Not yet implemented.")
1123+
logger.info("Not yet implemented.")
11241124

11251125

11261126
class PositionData():
@@ -1907,7 +1907,6 @@ def get_omni_data(starttime=None, endtime=None, filepath='', download=False, dld
19071907
#check how many rows exist in this file
19081908
f=open(filepath)
19091909
dataset= len(f.readlines())
1910-
#print(dataset)
19111910
#global Variables
19121911
spot=np.zeros(dataset)
19131912
btot=np.zeros(dataset) #floating points
@@ -1939,7 +1938,7 @@ def get_omni_data(starttime=None, endtime=None, filepath='', download=False, dld
19391938
with open('data/omni2_all_years.dat') as f:
19401939
for line in f:
19411940
line = line.split() # to deal with blank
1942-
#print line #41 is Dst index, in nT
1941+
#41 is Dst index, in nT
19431942
dst[j]=line[40]
19441943
ae[j]=line[41]
19451944
kp[j]=line[38]
@@ -2475,7 +2474,6 @@ def merge_Data(satdata1, satdata2, keys=None):
24752474

24762475
def getpositions(filename):
24772476
pos=scipy.io.readsav(filename)
2478-
print
24792477
return pos
24802478

24812479

@@ -2505,15 +2503,12 @@ def converttime():
25052503
http://matplotlib.org/examples/pylab_examples/date_demo2.html
25062504
"""
25072505

2508-
print('convert time start')
25092506
for index in range(0,dataset):
25102507
#first to datetimeobject
25112508
timedum=datetime(int(year[index]), 1, 1) + timedelta(day[index] - 1) +timedelta(hours=hour[index])
25122509
#then to matlibplot dateformat:
25132510
times1[index] = matplotlib.dates.date2num(timedum)
2514-
#print time
2515-
#print year[index], day[index], hour[index]
2516-
print('convert time done') #for time conversion
2511+
logger.info('convert time done') #for time conversion
25172512

25182513

25192514
def round_to_hour(dt):

predstorm/plot.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,14 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
141141

142142
# STEREO-A minute resolution data with timeshift
143143
plt.plot_date(stam['time'][sta_index_future], stam['btot'][sta_index_future],
144-
'-', c=c_sta, linewidth=lw, label='B STEREO-A')
145-
plt.plot_date(stam['time'][sta_index_future], stam['bn'][sta_index_future],
146-
'-', c=c_sta, alpha=0.5, linewidth=lw, label='Bn RTN STEREO-A')
144+
'-', c=c_sta, linewidth=lw, label='B {}'.format(stam.source))
145+
if 'stereo' in stam.source.lower():
146+
plt.plot_date(stam['time'][sta_index_future], stam['bn'][sta_index_future],
147+
'-', c=c_sta, alpha=0.5, linewidth=lw, label='Bn RTN {}'.format(stam.source))
148+
else:
149+
plt.plot_date(stam['time'][sta_index_future], stam['bz'][sta_index_future],
150+
'-', c=c_sta, alpha=0.5, linewidth=lw, label='Bz GSM {}'.format(stam.source))
151+
147152

148153
# Indicate 0 level for Bz
149154
plt.plot_date([plotstart,plotend], [0,0],'--k', alpha=0.5, linewidth=1)
@@ -157,8 +162,8 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
157162

158163
if 'stereo' in stam.source.lower():
159164
pred_source = 'STEREO-Ahead Beacon'
160-
elif 'omni' in stam.source.lower():
161-
pred_source = '27-day SW-Recurrence Model (OMNI)'
165+
elif 'dscovr' in stam.source.lower() or 'noaa' in stam.source.lower():
166+
pred_source = '27-day SW-Recurrence Model (NOAA)'
162167
plt.title('L1 real time solar wind from NOAA SWPC for '+ datetime.strftime(timestamp, "%Y-%m-%d %H:%M")+ ' UT & {}'.format(pred_source), fontsize=fs_title)
163168

164169
# SUBPLOT 2: Solar wind speed
@@ -212,17 +217,17 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
212217
dstplotmin = np.nanmin(np.concatenate((dst['dst'], dst_pred['dst'])))-20
213218

214219
if dstplotmin > -100: # Low activity (normal)
215-
plt.ylim([-100,np.nanmax(dst['dst'])+20])
220+
plt.ylim([-100, dstplotmax + 30])
216221
else: # High activity
217222
plt.ylim([dstplotmin, dstplotmax])
218223

219224
# Plot predicted Dst
220225
if not verification_mode:
221226
plt.plot_date(dst_pred['time'], dst_pred['dst'], '-', c=c_sta_dst, label=dst_label, markersize=3, linewidth=1)
222227
# Add generic error bars of +/-15 nT:
223-
error=15
228+
error=8
224229
plt.fill_between(dst_pred['time'], dst_pred['dst']-error, dst_pred['dst']+error, alpha=0.2,
225-
label='Error for high speed streams')
230+
label='prediction accuracy +/- 8 nT')
226231
else:
227232
#load saved data l prefix is for loaded - WARNING This will crash if called right now
228233
[timenowb, sta_ptime, sta_vr, sta_btime, sta_btot, sta_br,sta_bt, sta_bn, rbtime_num, rbtot, rbzgsm, rptime_num, rpv, rpn, lrdst_time, lrdst, lcom_time, ldst_burton, ldst_obrien,ldst_temerin_li]=pickle.load(open(verify_filename,'rb') )
@@ -240,10 +245,10 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
240245

241246
# Plot solar wind density:
242247
avg_newell_coupling = newell_coupling.get_weighted_average('ec')
243-
plt.plot_date(newell_coupling['time'], avg_newell_coupling/4421., '-', color=c_ec, label='Newell coupling',linewidth=1.5)
248+
plt.plot_date(newell_coupling['time'], avg_newell_coupling/4421., '-', color=c_ec, label='Newell coupling 4h weighted mean',linewidth=1.5)
244249
plt.ylabel('Newell Coupling / 4421\n$\mathregular{[(km/s)^{4/3} nT^{2/3}]}$',fontsize=fs_ylabel)
245250
# For y limits check where the maximum and minimum are for DSCOVR and STEREO taken together:
246-
plt.ylim([0,np.nanmax(avg_newell_coupling/4421.)*1.1])
251+
plt.ylim([0,np.nanmax(avg_newell_coupling/4421.)*1.2])
247252

248253
# Indicate level of interest (Ec/4421 = 1.0)
249254
plt.plot_date([plotstart,plotend], [1,1],'--k', alpha=0.5, linewidth=1)
@@ -288,7 +293,7 @@ def plot_solarwind_and_dst_prediction(DSCOVR_data, STEREOA_data, DST_data, DSTPR
288293
logger.info('Plot saved as png:\n'+ filename)
289294

290295

291-
def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, timestamp=None, past_days=7, future_days=7, outfile='predstorm_science.png', **kwargs):
296+
def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, timestamp=None, past_days=7, future_days=7, plot_step=20, outfile='predstorm_science.png', **kwargs):
292297
"""
293298
Plots solar wind variables, past from DSCOVR and future/predicted from STEREO-A.
294299
Total B-field and Bz (top), solar wind speed (second), particle density (third)
@@ -355,6 +360,7 @@ def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, t
355360
timeutc = mdates.date2num(timestamp)
356361

357362
n_plots = 3
363+
plst = plot_step
358364

359365
plotstart = timeutc - past_days
360366
plotend = timeutc + future_days
@@ -365,10 +371,10 @@ def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, t
365371
axes.append(ax1)
366372

367373
# Total B-field and Bz (DSCOVR)
368-
plt.plot_date(dism['time'], dism['btot'],'-', c='black', label='B', linewidth=lw)
369-
plt.plot_date(dism['time'], dism['bx'],'-', c='teal', label='Bx', linewidth=lw)
370-
plt.plot_date(dism['time'], dism['by'],'-', c='orange', label='By', linewidth=lw)
371-
plt.plot_date(dism['time'], dism['bz'],'-', c='purple', label='Bz', linewidth=lw)
374+
plt.plot_date(dism['time'][::plst], dism['btot'][::plst],'-', c='black', label='B', linewidth=lw)
375+
plt.plot_date(dism['time'][::plst], dism['bx'][::plst],'-', c='teal', label='Bx', linewidth=lw)
376+
plt.plot_date(dism['time'][::plst], dism['by'][::plst],'-', c='orange', label='By', linewidth=lw)
377+
plt.plot_date(dism['time'][::plst], dism['bz'][::plst],'-', c='purple', label='Bz', linewidth=lw)
372378

373379
# STEREO-A minute resolution data with timeshift
374380
plt.plot_date(stam['time'][sta_index_future], stam['btot'][sta_index_future],
@@ -392,8 +398,8 @@ def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, t
392398

393399
if 'stereo' in stam.source.lower():
394400
pred_source = 'STEREO-Ahead Beacon'
395-
elif 'omni' in stam.source.lower():
396-
pred_source = '27-day SW-Recurrence Model (OMNI)'
401+
elif 'dscovr' in stam.source.lower() or 'noaa' in stam.source.lower():
402+
pred_source = '27-day SW-Recurrence Model (NOAA)'
397403
plt.title('L1 real time solar wind from NOAA SWPC for '+ datetime.strftime(timestamp, "%Y-%m-%d %H:%M")+ ' UT & {}'.format(pred_source), fontsize=fs_title)
398404

399405
# SUBPLOT 2: Solar wind speed
@@ -402,7 +408,7 @@ def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, t
402408
axes.append(ax2)
403409

404410
# Plot solar wind speed (DSCOVR):
405-
plt.plot_date(dism['time'], dism['speed'],'-', c='black', label='speed',linewidth=lw)
411+
plt.plot_date(dism['time'][::plst], dism['speed'][::plst],'-', c='black', label='speed',linewidth=lw)
406412
plt.ylabel('Speed $\mathregular{[km \\ s^{-1}]}$', fontsize=fs_ylabel)
407413

408414
# Plot STEREO-A data with timeshift and savgol filter
@@ -425,7 +431,7 @@ def plot_solarwind_science(DSCOVR_data, STEREOA_data, verification_mode=False, t
425431
axes.append(ax3)
426432

427433
# Plot solar wind density:
428-
plt.plot_date(dism['time'], dism['density'],'-k', label='density',linewidth=lw)
434+
plt.plot_date(dism['time'][::plst], dism['density'][::plst],'-k', label='density',linewidth=lw)
429435
plt.ylabel('Density $\mathregular{[ccm^{-3}]}$',fontsize=fs_ylabel)
430436
# For y limits check where the maximum and minimum are for DSCOVR and STEREO taken together:
431437
plt.ylim([0,np.nanmax(np.nanmax(np.concatenate((dism['density'],stam['density'][sta_index_future])))+10)])

predstorm/predict.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,6 @@ def _jit_calc_dst_temerin_li_2002(time, btot, bx, by, bz, speed, speedx, density
412412
bp = (by[i]**2 + bx[i]**2)**0.5
413413
#contains t1, but in cos and sin
414414
dh = bp*np.cos(np.arctan2(bx[i],by[i])+6.10) * (3.59e-2 * np.cos(2*np.pi*t1/yearli + 0.04) - 2.18e-2*np.sin(2*np.pi*t1-1.60))
415-
#print(i, bx[i], by[i], bz[i])
416415
theta_li = -(np.arccos(-bz[i]/bt)-np.pi)/2
417416
exx = 1e-3 * abs(speedx[i]) * bt * np.sin(theta_li)**6.1
418417
#t1 and dt are in days

predstorm_l5.py

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ def main():
173173
rec_new = ps.merge_Data(rec_27days, rec_dism)
174174
rec_new.cut(starttime=num2date(timenow-365)) # don't keep more than 1 year
175175
rec_new.source = 'NOAA-L1'
176+
logger.info("Pickled real-time data contains data from {} till {}".format(num2date(rec_new['time'][0]), num2date(rec_new['time'][-1])))
176177
with open(rec_model_path, 'wb') as f:
177178
pickle.dump(rec_new, f)
178179
elif run_mode == 'historic':
@@ -181,7 +182,6 @@ def main():
181182
logger.info("Using historic mode with current DSCOVR data and {} timestamp".format(timestamp))
182183
dism = ps.get_dscovr_realtime_data()
183184
dism = dism.cut(endtime=timestamp)
184-
dis = dism.make_hourly_data()
185185
else:
186186
logger.info("Using historic mode with archive DSCOVR data")
187187
dism = ps.get_dscovr_data(starttime=timestamp-timedelta(days=plot_past_days+1),
@@ -190,6 +190,7 @@ def main():
190190
timenow = timeutc
191191
dism.interp_nans()
192192
dis = dism.make_hourly_data()
193+
sw_past_min = dism
193194
sw_past = dis
194195

195196
timeutcstr = datetime.strftime(timestamp, tstr_format)
@@ -204,35 +205,36 @@ def main():
204205
#------------------------ (1b) Get real-time STEREO-A beacon data -----------------------
205206

206207
logger.info("(2) Getting STEREO-A data...")
208+
use_recurrence_model = False
207209
if run_mode == 'normal':
208-
stam = ps.get_stereo_beacon_data(starttime=startread, endtime=timestamp-timedelta(minutes=1))
210+
try:
211+
stam = ps.get_stereo_beacon_data(starttime=startread, endtime=timestamp-timedelta(minutes=1))
212+
stam.load_positions()
213+
sta_details = stam.return_position_details(timestamp)
214+
if stam.h['PlasmaDataIntegrity'] == 0: # very low quality data
215+
use_recurrence_model = True
216+
except Exception as e:
217+
logger.info("STEREO-A read failed for reason: {}".format(e))
218+
use_recurrence_model = True
209219
elif run_mode == 'historic':
210220
lag_L1, lag_r = ps.get_time_lag_wrt_earth(timestamp=timestamp, satname='STEREO-A')
211221
est_timelag = lag_L1 + lag_r
212222
stam = ps.get_stereo_beacon_data(starttime=timestamp-timedelta(days=plot_future_days+est_timelag),
213223
endtime=timestamp+timedelta(days=2))
224+
stam.load_positions()
225+
sta_details = stam.return_position_details(timestamp)
214226

215-
logger.info('UTC time of last datapoint in STEREO-A beacon data:')
216-
logger.info('\t{}'.format(num2date(stam['time'][-1])))
217-
logger.info('Time lag in minutes: {}'.format(int(round((timeutc-stam['time'][-1])*24*60))))
218-
219-
# Prepare data:
220-
stam.load_positions()
221-
sta_details = stam.return_position_details(timestamp)
222-
223-
use_recurrence_model = False
224-
if stam.h['PlasmaDataIntegrity'] == 0: # very low quality data
227+
if run_mode == 'normal' and use_recurrence_model:
225228
use_recurrence_model = True
226229
logger.info("STEREO-A plasma data is missing/corrupted, using 27-day recurrence model for plasma data instead.")
227230
rec_start = timestamp - timedelta(days=27)
228231
rec_end = timestamp - timedelta(days=27-plot_future_days)
229-
sw_future = ps.get_omni_data_new(starttime=rec_start, endtime=rec_end)
230-
sw_future['time'] = sw_future['time'] + 27.
231-
sw_future.h['DataSource'] += ' t+27days'
232-
sw_future.source += '+27days'
233-
# Remove OMNI indices, don't need them:
234-
sw_future['kp'], sw_future['ae'], sw_future['dst'] = 0., 0., 0.
235-
sw_future.vars = [v for v in sw_future.vars if v not in ['kp', 'ae', 'dst']]
232+
with open(rec_model_path, 'rb') as f:
233+
sw_future_min = pickle.load(f)
234+
sw_future_min.cut(starttime=rec_start, endtime=rec_end)
235+
sw_future_min['time'] += 27.
236+
sw_future_min.h['DataSource'] += ' t+27days'
237+
sw_future_min.source += '+27days'
236238

237239
#------------------------- (1c) Load NOAA Dst for comparison ----------------------------
238240

@@ -252,39 +254,38 @@ def main():
252254

253255
#========================== (2) PREDICTION CALCULATIONS ==================================
254256

255-
logger.info("\n-------------------------\nL5-to-L1 MAPPING\n-------------------------")
256-
#------------------------ (2a) Corrections to time-shifted STEREO-A data ----------------
257-
logger.info("Doing corrections to STEREO-A data...")
258-
259-
logger.info("(1) Shift time at STEREO-A according to solar wind rotation")
260-
stam.shift_time_to_L1()
261-
logger.info("STA-to-L1 adjusted time of last datapoint in STEREO-A:")
262-
logger.info("\t{}".format(num2date(stam['time'][-1])))
263-
264-
logger.info("(2) Make correction for difference in heliocentric distance")
265-
stam.shift_wind_to_L1()
266-
267-
logger.info("(3) Conversion from RTN to GSE and then to GSM as if STEREO was on Sun-Earth line")
268-
stam['bx'], stam['by'], stam['bz'] = stam['br'], -stam['bt'], stam['bn'] # RTN to quasi-GSE
269-
stam.convert_GSE_to_GSM()
270-
271-
use_recurrence_model = False
272257
if not use_recurrence_model:
258+
logger.info('UTC time of last datapoint in STEREO-A beacon data:')
259+
logger.info('\t{}'.format(num2date(stam['time'][-1])))
260+
logger.info('Time lag in minutes: {}'.format(int(round((timeutc-stam['time'][-1])*24*60))))
261+
logger.info("\n-------------------------\nL5-to-L1 MAPPING\n-------------------------")
262+
#------------------------ (2a) Corrections to time-shifted STEREO-A data ----------------
263+
logger.info("Doing corrections to STEREO-A data...")
264+
265+
logger.info("(1) Shift time at STEREO-A according to solar wind rotation")
266+
stam.shift_time_to_L1()
267+
logger.info("STA-to-L1 adjusted time of last datapoint in STEREO-A:")
268+
logger.info("\t{}".format(num2date(stam['time'][-1])))
269+
270+
logger.info("(2) Make correction for difference in heliocentric distance")
271+
stam.shift_wind_to_L1()
272+
273+
logger.info("(3) Conversion from RTN to GSE and then to GSM as if STEREO was on Sun-Earth line")
274+
stam['bx'], stam['by'], stam['bz'] = stam['br'], -stam['bt'], stam['bn'] # RTN to quasi-GSE
275+
stam.convert_GSE_to_GSM()
273276
sw_future = stam.make_hourly_data()
274277
sw_future_min = stam
275278
else:
276-
sta = stam.interp_to_time(sw_future['time'])
277-
sw_future.vars += ['br', 'bt', 'bn']
278-
for bvar in ['bx', 'by', 'bz', 'btot', 'br', 'bt', 'bn']:
279-
sw_future[bvar] = sta[bvar]
280-
sw_future.interp_nans()
281-
sw_future_min = copy.deepcopy(sw_future)
279+
sw_future_min.vars += ['br', 'bt', 'bn']
280+
sw_future_min['br'], sw_future_min['bt'], sw_future_min['bn'] = sw_future_min['bx'], sw_future_min['by'], sw_future_min['bz']
281+
sw_future_min.interp_nans()
282+
sw_future = sw_future_min.make_hourly_data()
282283

283284
#------------------- (2b) COMBINE DSCOVR and time-shifted STEREO-A data -----------------
284285

285286
sw_merged = ps.merge_Data(sw_past, sw_future)
286287
try:
287-
sw_merged_min = ps.merge_Data(dism, stam)
288+
sw_merged_min = ps.merge_Data(sw_past_min, sw_future_min)
288289
savemindata = True
289290
except:
290291
logger.warning("No minute data available.")
@@ -334,15 +335,15 @@ def main():
334335
logger.info("\n-------------------------\nPLOTTING\n-------------------------")
335336
# ********************************************************************
336337
logger.info("Creating output plot...")
337-
plot_solarwind_and_dst_prediction([dism, sw_past], [sw_future_min, sw_future],
338+
plot_solarwind_and_dst_prediction([sw_past_min, sw_past], [sw_future_min, sw_future],
338339
dst, dst_pred,
339340
newell_coupling=newell_coupling,
340341
past_days=plot_past_days,
341342
future_days=plot_future_days,
342343
dst_label=dst_label,
343344
timestamp=timestamp)
344345
plt.close()
345-
plot_solarwind_science([dism, sw_past], [sw_future_min, sw_future],
346+
plot_solarwind_science([sw_past_min, sw_past], [sw_future_min, sw_future],
346347
timestamp=timestamp)
347348
# ********************************************************************
348349

@@ -373,7 +374,8 @@ def main():
373374

374375
#----------------------------- (4b) CALCULATE FORECAST RESULTS --------------------------
375376

376-
logger.info("\n\nSATELLITE POSITION DETAILS\n--------------------------\n"+sta_details)
377+
if not use_recurrence_model:
378+
logger.info("\n\nSATELLITE POSITION DETAILS\n--------------------------\n"+sta_details)
377379

378380
future_times = np.where(sw_merged['time'] > date2num(timestamp))
379381
past_times = np.where(sw_merged['time'] < date2num(timestamp))

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[metadata]
2+
description-file = README.md

0 commit comments

Comments
 (0)