''' Module to handle WIND data
Simplest way of getting the data is using :class:`WindMoon`.
If you want to take the average key parameter of the solar wind
at the Moon position, use the following syntaxes.
This sample is to get the average between 03:15 and 03:20 on
10 May 2009.
>>> t0 = datetime.datetime(2009, 5, 10, 3, 15, 0)
>>> t1 = datetime.datetime(2009, 5, 10, 3, 20, 0)
>>> tarr, ave, var = WindMoon.get_average(t0, t1)
>>> print(len(tarr))
4
>>> label = WindMoon.label_array()
>>> print('%s %.2f (%.2f)' % (label[0], ave[0], var[0]))
N 2.22 (0.07)
>>> print('%s %.2f (%.2f)' % (label[1], ave[1], var[1]))
V 433.35 (28.05)
>>> print('%s %.2f (%.2f)' % (label[2], ave[2], var[2]))
Vth 27.49 (5.75)
The data file location should be specified by the ``.irfpyrc`` file
using the entry in ``swim`` section with a name of ``windmoonpath``.
The data file should be made beforehand using
``wind2moon.py`` script.
See also the document:
ftp://space.mit.edu/pub/plasma/wind/kp_files/000_README_WIND_P_FILES.TXT
There is an interface for ACE spacecraft.
See :mod:`irfpy.swim.ace`, while the usage is a little bit different.
'''
import os
import datetime
import dateutil.parser
import logging
import io
import numpy as np
import irfpy.util.irfpyrc
import irfpy.util.timeseriesdb
import irfpy.cy1orb.MoonPos
[docs]class WindRawDataTree:
''' WIND's raw data tree
'''
def __init__(self):
rc = irfpy.util.irfpyrc.Rc()
self.rootpath = rc.get('swim', 'windrawpath')
if self.rootpath is None:
raise ValueError('No entry of "swim/windrawpath"')
logging.debug('Rootpath = %s' % self.rootpath)
if not os.path.isdir(self.rootpath):
raise IOError('No path %s found.' % self.rootpath)
self.db = self.__parse_folder(self.rootpath)
def __parse_folder(self, root):
''' Parse the folder.
'''
db = irfpy.util.timeseriesdb.DB()
for path, dirs, files in os.walk(root):
for f in files:
if not f.startswith('rdP'):
continue
fullpath = os.path.join(path, f)
tt = datetime.datetime(int(f[3:7]), 1, 1)
tt = tt + datetime.timedelta(days=int(f[7:10])-1)
logging.debug('%s > %s' % (fullpath, tt.strftime('%FT%T')))
db.append(fullpath, tt)
return db
[docs]class WindMoon:
''' An user interface.
'''
windmoondatatree = None
@classmethod
def __loadtree(cls):
''' Load a data tree. Called internally from other interface.
'''
if cls.windmoondatatree is None:
cls.windmoondatatree = WindMoonDataTree()
[docs] @classmethod
def get_average(cls, t0, t1):
''' Get the average of the parameters.
An interface to the :mod:`WindMoonDataTree.get_average_wind_data_between`.
:returns: Tuple of three arrays.
The returned is 0) the array of time used with shape of (N,) where N is the
number of data in between the time range [t0 t1]; 1) the array of the
average of the key parameters; and 2) the array of the variance of the key parameters.
The order of the key parameters can be referred to :meth:`WindMoonData.label_array`.
>>> t0 = datetime.datetime(2009, 5, 1, 23, 50)
>>> t1 = datetime.datetime(2009, 5, 2, 4, 30)
>>> tarr, average, variance = WindMoon.get_average(t0, t1)
>>> print('N %.1f' % average[0])
N 7.7
>>> print('V %.1f' % average[1])
V 298.2
>>> print('Vth %.1f' % average[2])
Vth 22.4
>>> t0 = datetime.datetime(2009, 6, 15, 23, 59, 59)
>>> t1 = datetime.datetime(2009, 6, 16, 0, 0, 1)
>>> tarr, average, variance = WindMoon.get_average(t0, t1)
>>> print(len(tarr))
0
>>> print(len(average))
7
>>> print(len(variance))
7
>>> print(average[0])
nan
'''
cls.__loadtree()
return cls.windmoondatatree.get_average_wind_data_between(t0, t1)
[docs] @classmethod
def label_array(cls):
return WindMoonData.label_array()
[docs]class WindMoonDataTree:
''' WIND's Moon data tree
'''
def __init__(self):
rc = irfpy.util.irfpyrc.Rc()
self.rootpath = rc.get('swim', 'windmoonpath')
if self.rootpath is None:
raise ValueError('No entry of "swim/windmoonpath"')
logging.debug('Rootpath = %s' % self.rootpath)
if not os.path.isdir(self.rootpath):
raise IOError('No path %s found' % self.rootpath)
self.db = self.__parse_folder(self.rootpath)
self.cache = {}
[docs] def get_filename(self, t):
return self.db.get(t)
[docs] def get_wind_data(self, filename):
''' Get the WIND data as dictionary. 1 day data returned.
'''
if not (filename in self.cache):
dat = self.__readwindmoonfile(filename)
self.cache[filename] = dat
return self.cache[filename]
[docs] def get_average_wind_data_between(self, t0, t1):
''' Get the WIND averaged key parameters.
>>> winddata = WindMoonDataTree()
>>> t0 = datetime.datetime(2009, 4, 30, 23, 50)
>>> t1 = datetime.datetime(2009, 5, 2, 4, 30)
>>> tarr, average, variance = winddata.get_average_wind_data_between(t0, t1)
The returned is 0) the array of time used with shape of (N,) where N is the
number of data in between the time range [t0 t1]; 1) the array of the
average of the key parameters; and 2) the array of the variance of the key parameters.
The order of the key parameters can be referred to :meth:`WindMoonData.label_array`.
'''
tarr, darr = self.get_wind_data_between(t0, t1)
if len(tarr) == 0:
nans = [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]
return [], nans, nans
# darr is an array containing WindMoonData.
data_array = []
for d in darr:
data_array.append(d.as_array())
data_array = np.array(data_array)
mean = data_array.mean(0)
var = data_array.var(0)
return tarr, mean, var
[docs] def get_wind_data_between(self, t0, t1):
''' Get the WIND data in the interval between t0 and t1.
Return the time array and the data array.
Time array is the datetime instance array
and the data array is the WindMoonData instance array.
>>> winddata = WindMoonDataTree()
>>> t0 = datetime.datetime(2009, 4, 30, 23, 50)
>>> t1 = datetime.datetime(2009, 5, 2, 4, 30)
>>> tarr, darr = winddata.get_wind_data_between(t0, t1)
'''
f0 = self.db.get(t0)
dataarray = {}
while True:
logging.info('File to be read: %s' % f0)
data = self.get_wind_data(f0)
time = list(data.keys())
tstart = min(time)
logging.debug('tstart = %s' % tstart)
if tstart > t1:
break
for t in time:
if t >= t0 and t<=t1:
dataarray[t] = data[t]
f0 = self.db.nextof(f0)
timearray = sorted(dataarray.keys())
dataarray2 = []
for t in timearray:
dataarray2.append(dataarray[t])
return timearray, dataarray2
def __readwindmoonfile(self, filename):
windmoondata = {}
fp = open(filename)
for line in fp:
winddata = WindMoonData.parse_string(line)
windmoondata[winddata.tmoon] = winddata
return windmoondata
def __parse_folder(self, root):
db = irfpy.util.timeseriesdb.DB()
for path, dirs, files in os.walk(root):
for f in files:
if not f.startswith('wind_at_moon_'):
continue
if not f.endswith('.txt'):
continue
fullpath = os.path.join(path, f)
tt = datetime.datetime(2000+int(f[13:15]), int(f[15:17]), int(f[17:19]), 0, 0, 0)
db.append(fullpath, tt)
return db
[docs]class WindData:
''' WIND data.
>>> str='2009 354 0.00208993 377.5 -0.9312 -1.351 3.646 19.75 -1.000e+31 -377.3 -6.133 -8.901 246.1 -64.36 20.02'
>>> data = WindData.parse_string(str)
The data is stored as a member in the class.
- yr, doy, dayfrac, t
- v, ewang, nsang
- n
- vth
- alpha
- vx, vy, vz
- gsex, gsey, gsez
'''
def __str__(self):
return self.str
[docs] @classmethod
def parse_string(cls, line):
vals = line.split()
if len(vals) != 15:
raise ValueError('No data: %s' % line)
winddata = WindData()
winddata.str = line.strip()
winddata.yr = int(vals[0])
winddata.doy = int(vals[1])
winddata.dayfrac = float(vals[2])
winddata.t = datetime.datetime(winddata.yr, 1, 1, 0) + datetime.timedelta(days=winddata.doy-1) + datetime.timedelta(days=winddata.dayfrac)
winddata.v = float(vals[3])
winddata.ewang = float(vals[4])
winddata.nsang = float(vals[5])
winddata.n = float(vals[6])
winddata.vth = float(vals[7])
winddata.alpha = float(vals[8])
winddata.vx = float(vals[9])
winddata.vy = float(vals[10])
winddata.vz = float(vals[11])
winddata.gsex = float(vals[12])
winddata.gsey = float(vals[13])
winddata.gsez = float(vals[14])
return winddata
[docs]class WindMoonData:
''' WIND data at the Moon.
>>> str='2009 354 0.00208993 377.5 -0.9312 -1.351 3.646 19.75 -1.000e+31 -377.3 -6.133 -8.901 246.1 -64.36 20.02 2009-01-27 00:15:30 2009-01-27 01:30:44'
>>> data = WindMoonData.parse_string(str)
The data is stored as a member in the class.
- yr, doy, dayfrac, t
- tmoon
- v, ewang, nsang
- n
- vth
- alpha
- vx, vy, vz
- gsex, gsey, gsez
'''
[docs] def as_array(self):
''' Return the data as numpy.array.
Return 1-D array of [n, v, vth, alpha%, vx, vy, vz].
'''
arr = [self.n, self.v, self.vth, self.alpha, self.vx, self.vy, self.vz]
return np.array(arr)
[docs] @classmethod
def label_array(cls):
''' Return the label of the :meth:`as_array`.
:returns: A string array ``['N', 'V', 'Vth', 'Alpha%', 'Vx', 'Vy', 'Vz']``
'''
return ['N', 'V', 'Vth', 'Alpha%', 'Vx', 'Vy', 'Vz']
def __str__(self):
return self.str
def __repr__(self):
return '<WindMoonData instance: ' + str(self.as_array()[:3]) + '>'
[docs] @classmethod
def parse_string(cls, line):
vals = line.split()
if len(vals) != 19:
raise ValueError('No data: %s' % line)
winddata = WindMoonData()
winddata.str = line.strip()
winddata.yr = int(vals[0])
winddata.doy = int(vals[1])
winddata.dayfrac = float(vals[2])
winddata.t = datetime.datetime(winddata.yr, 1, 1, 0) + datetime.timedelta(days=winddata.doy-1) + datetime.timedelta(days=winddata.dayfrac)
winddata.v = float(vals[3])
winddata.ewang = float(vals[4])
winddata.nsang = float(vals[5])
winddata.n = float(vals[6])
winddata.vth = float(vals[7])
winddata.alpha = float(vals[8])
winddata.vx = float(vals[9])
winddata.vy = float(vals[10])
winddata.vz = float(vals[11])
winddata.gsex = float(vals[12])
winddata.gsey = float(vals[13])
winddata.gsez = float(vals[14])
winddata.tmoon = dateutil.parser.parse(vals[17]+'T'+vals[18])
return winddata
[docs]class Wind2Moon:
moonpos = None
[docs] @classmethod
def run(cls):
''' Run the WIND time shift to the Moon position.
'''
w = WindRawDataTree()
t0 = datetime.datetime(2009, 1, 15)
t1 = datetime.datetime(2009, 8, 5)
dt = datetime.timedelta(days=1)
t = t0
db = WindRawDataTree().db
alldata = {}
while t < t1:
filename = db.get(t)
fp = open(filename)
for line in fp:
try:
winddata = WindData.parse_string(line)
except ValueError as e:
continue
if cls.moonpos is None:
cls.moonpos = irfpy.cy1orb.MoonPos.MoonGse()
cls.moonpos.setFromDefaultUri()
moon = cls.moonpos.getGse(winddata.t)
wind2moon = moon[0] - winddata.gsex * 6378. # x distance in km
delt = wind2moon / winddata.vx
tmoon = winddata.t + datetime.timedelta(seconds=delt)
print(tmoon, winddata.t, str(winddata))
alldata[tmoon] = winddata
fp.close()
t += dt
tlist = sorted(alldata.keys())
fp = None
day = None
for t in tlist:
if day != t.strftime('%F'):
day = t.strftime('%F')
if fp is not None:
fp.close()
fp = open('wind_at_moon_%s.txt' % t.strftime('%y%m%d'), 'w')
winddata = alldata[t]
print(str(winddata), winddata.t, t, file=fp)