Commit b296cd78 authored by Scott Griffiths's avatar Scott Griffiths
Browse files

Incremental progress on gdas_entry and msis_entry. Added preliminary msis_reader.

parent 11ecd72b
......@@ -47,6 +47,7 @@ class AtcaWizard:
self.fMSIS = None
self.fGDAS = None
# TODO: This function needs revision
def LoadWeather(self, filename="WS2013.root"):
if self.fWeather:
delete self.fWeather
......@@ -87,6 +88,7 @@ class AtcaWizard:
print(args[0], " ", args[1], " ", args[2])
return (args)
# TODO: This function needs revision
def LoadMSIS(self, filename="msis2013.root", verbose=False):
if self.fMSIS:
delete self.fMSIS
......@@ -121,6 +123,7 @@ class AtcaWizard:
if verbose:
self.fMSIS.Print()
# TODO: This function needs revision
def CreateGDAS(self, files="gdas1.*13.w*_magic1", outfile="GDAS1.root"):
tlist = []
MGDASFileRead r(files)
......@@ -132,6 +135,7 @@ class AtcaWizard:
tlist.append(w)
w.Close()
# TODO: This function needs revision
def LoadGDAS(self, filename="gdas2013_magic1.root", verbose=False):
if self.fGDAS:
delete self.fGDAS
......@@ -170,6 +174,7 @@ class AtcaWizard:
b = self.fGDAS.GetBranch("MGDASEntry.")
b.SetAutoDelete(False)
# TODO: This function needs revision
def GetWeather(self, mjd, verbose=False):
if not self.fWeather:
raise RuntimeError("No weather file 'WS*.root' has been loaded, please use LoadWeather first.")
......@@ -224,6 +229,7 @@ class AtcaWizard:
dust = args[10]
return temperature, pressure, humidity, dust
# TODO: This function needs revision
def GetMSIS(self, mjd, verbose=False):
if not self.fMSIS:
raise RuntimeError("No MSIS file 'MSIS*.root' has been loaded, please use LoadMSIS first.")
......@@ -268,6 +274,7 @@ class AtcaWizard:
break
return msis_entry
# TODO: This function needs revision
def GetGDAS(self, mjd, verbose=False):
if not self.fGDAS:
raise RuntimeError("No GDAS file 'GDAS*.root' has been loaded, please use LoadGDAS first.")
......
This diff is collapsed.
......@@ -5,6 +5,7 @@ Copyright: MAGIC Software Development, 2000-2013
from __future__ import division, print_function
from math import pi, sqrt, atan2, log, exp
from collections import namedtuple
from datetime import datetime
from astropy.time import Time
import numpy as np
......@@ -17,16 +18,6 @@ class MSISEntry:
gkLoschmidt = 2.079153E25 # Na divided by molar mass of air: 0.0289644
def __init__(self):
self.fLatitude(-99)
self.fLongitude(-99)
self.fDebug(False)
self.fHeight = []
self.fDensity = []
self.fLogDensity = []
self.fMassOverburden = []
self.fLogMassOverburden = []
self.fTemperature = []
self.clear()
def fill_date(self, line):
......@@ -35,12 +26,12 @@ class MSISEntry:
where YYYY is the year, MM is the month, DD is the day, and HH is the hour.
"""
dt = datetime.strptime(line, "%Y %m %d %H")
apt = Time(dt) # use astropy for mjd conversion
self.fMJD = apt.mjd
self.fHour = dt.hour
self.fDay = dt.day
self.fMonth = dt.month
self.fYear = dt.year
astropy_time = Time(dt) # use astropy for mjd conversion
self.mjd = astropy_time.mjd
self.hour = dt.hour
self.day = dt.day
self.month = dt.month
self.year = dt.year
def fill_observatory(self, line):
n = sscanf(line.Data(), "latitude=%f, longitude=%f, %n", lat, lon, len)
......@@ -49,8 +40,8 @@ class MSISEntry:
print(lat, "-", lon, "-")
print(" n is:", n, " instead of 2\n")
return False
self.fLatitude = lat
self.fLongitude = lon
self.latitude = lat
self.longitude = lon
def fill_profile(self, line, obs, ver=0):
n = sscanf(line.Data(), "%f %g %f %n", height, rho, T, len)
......@@ -62,188 +53,180 @@ class MSISEntry:
rho *= self.gkLoschmidt*1e3 # multiply by Na, and divide by molecular weight of dry air, transform from g/cm^3 to kg/m^3
rho /= self.gkNs # transform in units of n_s
height = self.get_altitude_from_geopotential_height(height)
size = len(self.fHeight)
self.height.append(height)
self.density.append(rho)
self.log_density.append(log(rho) if rho > 0 else -1)
self.temperature.append(T)
self.fHeight = np.zeros(size + 1)
self.fDensity = np.zeros(size + 1)
self.fLogDensity = np.zeros(size + 1)
self.fTemperature = np.zeros(size + 1)
def get_altitude_from_geopotential_height(self, geop_height):
"""
Convert from geopotential height to geometric altitude.
height = obs.GetAltitudeFromGeopotentialHeight(height*1000)/1000 # use internally km, for precision of fit
geop_height : height in km
"""
# TODO: FIXME: Using magic1_latitude for testing.
magic1_latitude = 5.01988021533642415e-01 # obtained from MARS
self.fHeight[size] = height
self.fDensity[size] = rho
self.fLogDensity[size] = log(rho) if rho > 0 else -1
self.fTemperature[size] = T
cos2lat = cos(2*magic1_latitude)
Z = (1 + 0.002644*cos2lat)*geop_height + (1 + 0.0089*cos2lat)*geop_height**2/6245
return Z
def clear(self):
self.fHeight = []
self.fDensity = []
self.fLogDensity = []
self.fMassOverburden = []
self.fLogMassOverburden = []
self.fTemperature = []
self.fMJD = -1
self.fHour = -1
self.fDay = -1
self.fMonth = -1
self.fYear = -1
self.fP0Tot = -99
self.fP1Tot = -99
self.fP2Tot = -99
self.fChi2Tot = -99
self.fP00to4km = -99
self.fP10to4km = -99
self.fP20to4km = -99
self.fChi20to4km = -99
self.fP04to10km = -99
self.fP14to10km = -99
self.fP24to10km = -99
self.fChi24to10km = -99
self.fP010to40km = -99
self.fP110to40km = -99
self.fP210to40km = -99
self.fChi210to40km = -99
self.fP040to100km = -99
self.fP140to100km = -99
self.fP240to100km = -99
self.fChi240to100km = -99
def fit(self, g, low, up, o="RWMQ0+", go="goff"):
g.Fit(fQuad, o, go, low, up)
p0 = self.fQuad.GetParameter(0)
p1 = self.fQuad.GetParameter(1)/10.
p2 = self.fQuad.GetParameter(2)/100.
chi2 = self.fQuad.GetChisquare() / self.fQuad.GetNDF()
return p0, p1, p2, chi2
self.height = []
self.density = []
self.log_density = []
self.mass_overburden = []
self.log_mass_overburden = []
self.temperature = []
self.params_total = {}
self.params_0_to_4_km = {}
self.params_4_to_10_km = {}
self.params_10_to_40_km = {}
self.params_40_to_100_km = {}
def fit(self, lower=None, upper=None, param_guess=None):
def quadratic(x, c0, c1, c2):
return c0 + c1*x/10 + c2*x*x/100
xdata, ydata = self.select_in_xrange(lower, upper)
popt, pcov = curve_fit(quadratic, xdata, ydata, p0=param_guess)
chi2 = np.sum((quadratic(xdata, *popt) - ydata)**2)
ndf = len(xdata) - len(popt)
popt[1] /= 10
popt[2] /= 100
return tuple(popt) + (chi2/ndf,)
def select_in_xrange(lower, upper):
"""
Select a subset of xdata, ydata for a given range of x values.
Args:
lower, upper : bounds for x (inclusive)
Returns:
x, y data over the interval lower <= x <= upper
"""
if lower is None:
lower = -np.inf
if upper is None:
upper = np.inf
xdata = self.height
ydata = self.log_density
idx = np.where((xdata >= lower) & (xdata <= upper))
return xdata[idx], ydata[idx]
def fit_profiles(self):
grho = new TGraph(len(self.fHeight) - 1, self.fHeight, self.fLogDensity)
self.fit(grho, 0, 25, self.fP0Tot, self.fP1Tot, self.fP2Tot, self.fChi2Tot)
self.fit(grho, 0, 4, self.fP00to4km, self.fP10to4km, self.fP20to4km, self.fChi20to4km)
self.fit(grho, 4, 10, self.fP04to10km, self.fP14to10km, self.fP24to10km, self.fChi24to10km)
self.fit(grho, 10, 40, self.fP010to40km, self.fP110to40km, self.fP210to40km, self.fChi210to40km)
self.fit(grho, 40, 100, self.fP040to100km, self.fP140to100km, self.fP240to100km, self.fChi240to100km)
param_names = ['p0', 'p1', 'p2', 'chi2']
# grho = new TGraph(len(self.height) - 1, self.height, self.log_density)
TSpline3 sst("spline", self.fHeight, self.fTemperature, len(self.fHeight))
self.fTemperatureMAGIC = sst.Eval(AtcaWizard.H0_WS/1000)
self.params_total = zip(param_names, self.fit(lower=0, upper=25))
self.params_0_to_4_km = zip(param_names, self.fit(lower=0, upper=4))
self.params_4_to_10_km = zip(param_names, self.fit(lower=4, upper=10))
self.params_10_to_40_km = zip(param_names, self.fit(lower=10, upper=40))
self.params_40_to_100_km = zip(param_names, self.fit(lower=40, upper=100))
TSpline3 ss("spline", self.fHeight, self.fLogDensity, len(self.fHeight))
overburden = 0
self.temperature_MAGIC = get_temperature(AtcaWizard.H0_WS/1000) # TODO: do we need this?
size = len(self.height)
self.mass_overburden = np.zeros(size)
self.mass_overburden[size-1] = 0
self.log_mass_overburden = np.zeros(size)
self.log_mass_overburden[size-1] = 0
nbins = 100
size = len(self.fHeight)
self.fMassOverburden = np.zeros(size)
self.fMassOverburden[size-1] = 0
self.fLogMassOverburden = np.zeros(size)
self.fLogMassOverburden[size-1] = 0
for i in range(size - 2)[::-1]:
dheight = (self.fHeight[i+1] - fHeight[i]) / nbins
overburden = 0
for i in range(size-2)[::-1]:
delta_height = (self.height[i+1] - self.height[i]) / nbins
for j in range(nbins):
overburden += exp(ss.Eval(self.fHeight[i] + dheight*j)) * (self.gkNs/self.gkLoschmidt) * dheight * 100 # calculate mass overburden in g/cm^2
self.fMassOverburden[i] = overburden
self.fLogMassOverburden[i] = log(overburden)
h = self.height[i] + j*delta_height
overburden += self.get_density(h)*(self.gkNs/self.gkLoschmidt)*delta_height*100 # calculate mass overburden in g/cm^2
self.mass_overburden[i] = overburden
self.log_mass_overburden[i] = log(overburden)
def get_density(self, height):
if height < self.fHeight[0]:
return -1
size = len(self.fHeight)
TSpline3 ss("spline", self.fHeight, self.fLogDensity, size)
return exp(ss.Eval(height))
f = interp1d(self.height, self.log_density, kind='cubic')
return exp(f(height))
def get_temperature(self, height):
if height < self.fHeight[0]:
return -1
size = len(self.fHeight)
for i in range(size):
if height < self.fHeight[i]:
return self.fTemperature[i-1] + (self.fTemperature[i] - self.fTemperature[i-1])*(height - self.fHeight[i-1])/(self.fHeight[i] - fHeight[i-1])
return -1
f = interp1d(self.height, self.temperature, kind='cubic') # NOTE: Changed from linear
return f(height)
def get_mass_overburden(self, height):
if height < self.fHeight[0]:
return -1
size = len(self.fHeight)
# interpolate logarithm of mass overburden, which behaves more linearly than exponential decay
TSpline3 ss("spline", self.fHeight, self.fLogMassOverburden, size)
return exp(ss.Eval(height))
"""
Interpolate logarithm of mass overburden, which behaves more linearly
than exponential decay.
"""
f = interp1d(self.height, self.log_mass_overburden, kind='cubic')
return exp(f(height))
# TODO: This isn't working yet...
def height_at_mass_overburden(self, overburden):
size = len(self.fMassOverburden)
if overburden > self.fMassOverburden[0]:
size = len(self.mass_overburden)
if overburden > self.mass_overburden[0]:
return -1
if overburden < self.fMassOverburden[size-1]:
if overburden < self.mass_overburden[size-1]:
return 99
# search for the next pivot point
i = 0
for j in range(size):
if self.fMassOverburden[j] < overburden:
i = j
break
TSpline3 ss("spline", self.fHeight, self.fLogMassOverburden, size)
ss.GetCoeff(i-1, x, y, b, c, d)
delta = self.fHeight[i] - self.fHeight[i-1]
nbins = 1000
for j in range(nbins):
dx = j * delta / nbins
res = exp(y + dx*(b + dx*(c + dx*d)))
if res < overburden:
return self.fHeight[i-1] + dx
return -1
def plot(self, lowlim=2.2, uplim=19):
c = new TCanvas("c", "c", 1000, 500)
c.Divide(2, 1)
c.cd(1)
grho = new TGraph(len(self.fHeight) - 1, self.fHeight, self.fLogDensity)
grho.SetTitle("Density;altitude a.s.l. (km);ln (n / n_s)")
grho.SetMarkerStyle(7)
grho.Draw("AP")
flin = new TF1("flin", "[0]+[1]*x/10", 0, 19)
flin.SetParameter(0, -6.69)
flin.SetParameter(1, -1.06)
grho.Fit(flin, "RW", "same", lowlim, uplim)
self.fQuad.SetLineColor(kBlue)
self.fQuad.SetParameter(0, flin.GetParameter(0))
self.fQuad.SetParameter(1, -0.95)
self.fQuad.SetParameter(2, -0.17)
p0, p1, p2, chi2 = self.fit(grho, lowlim, uplim, "RWM+", "same")
print(p0, " ", p1, " ", p2, " ", chi2)
gPad.SetGridx()
gPad.SetGridy()
c.cd(2)
gtemp = new TGraph(len(self.fHeight)-1, self.fHeight, self.fTemperature)
gtemp.SetTitle("Temperature;altitude a.s.l. (km);T (K)")
gtemp.SetMarkerStyle(7)
gtemp.Draw("AP")
gtemp.self.fit(flin, "RW", "same", lowlim, uplim)
self.fQuad.SetParameter(0, flin.GetParameter(0))
self.fQuad.SetParameter(1, flin.GetParameter(1))
self.fQuad.SetParameter(2, -0.17)
p0, p1, p2, chi2 = self.fit(gtemp, lowlim, uplim, "RWM+", "same")
gPad.SetGridx()
gPad.SetGridy()
# i = 0
# for j in range(size):
# if self.mass_overburden[j] < overburden:
# i = j
# break
#
# TSpline3 ss("spline", self.height, self.log_mass_overburden, size)
# ss.GetCoeff(i-1, x, y, b, c, d)
#
# delta = self.height[i] - self.height[i-1]
# nbins = 1000
# for j in range(nbins):
# dx = j * delta / nbins
# res = exp(y + dx*(b + dx*(c + dx*d)))
# if res < overburden:
# return self.height[i-1] + dx
# return -1
# TODO: FIXME!
# def plot(self, lowlim=2.2, uplim=19):
# c = new TCanvas("c", "c", 1000, 500)
# c.Divide(2, 1)
# c.cd(1)
#
# grho = new TGraph(len(self.height) - 1, self.height, self.log_density)
# grho.SetTitle("Density;altitude a.s.l. (km);ln (n / n_s)")
# grho.SetMarkerStyle(7)
# grho.Draw("AP")
#
# flin = new TF1("flin", "[0]+[1]*x/10", 0, 19)
# flin.SetParameter(0, -6.69)
# flin.SetParameter(1, -1.06)
# grho.Fit(flin, "RW", "same", lowlim, uplim)
#
# self.fQuad.SetLineColor(kBlue)
# self.fQuad.SetParameter(0, flin.GetParameter(0))
# self.fQuad.SetParameter(1, -0.95)
# self.fQuad.SetParameter(2, -0.17)
#
# p0, p1, p2, chi2 = self.fit(grho, lowlim, uplim, "RWM+", "same")
# print(p0, " ", p1, " ", p2, " ", chi2)
#
# gPad.SetGridx()
# gPad.SetGridy()
#
# c.cd(2)
#
# gtemp = new TGraph(len(self.height)-1, self.height, self.temperature)
# gtemp.SetTitle("Temperature;altitude a.s.l. (km);T (K)")
# gtemp.SetMarkerStyle(7)
# gtemp.Draw("AP")
#
# gtemp.self.fit(flin, "RW", "same", lowlim, uplim)
# self.fQuad.SetParameter(0, flin.GetParameter(0))
# self.fQuad.SetParameter(1, flin.GetParameter(1))
# self.fQuad.SetParameter(2, -0.17)
# p0, p1, p2, chi2 = self.fit(gtemp, lowlim, uplim, "RWM+", "same")
#
# gPad.SetGridx()
# gPad.SetGridy()
import re
class MSISReader:
def __init__(self, filename):
fObservatory.SetLocation(MObservatory::kMagic1)
def PreProcess(self, pList):
"""Check for correct file names format."""
TRegexp reg("[a-z]+msis[a-z0]+_[0-9]+_[0-9]+_[0-9]+_[0-9]+.dat")
TObject o
TIter Next(fFileNames)
TString file
while o=Next():
filename = o.GetName()
if reg not in filename:
print(file, " is not a valid MSIS file, it does not contain the string msis_[0-9]+_[0-9]+_[0-9]+_[0-9]+.dat")
return False
fReport = (MSISEntry*)pList.FindCreateObj("MSISEntry")
if not fReport:
return False
return True
def Process(self):
"""Read the files line by line and fill the MSISEntry class."""
if not OpenNextFile():
return False
print("NEXT FILE:", GetFullFileName())
line = fIn.readline()
# get rid of the possible inherent java-scripts and HTML-code
is_script = False
while line.startswith("<") or is_script:
if line.startswith("<script"):
is_script = True
if line.startswith("</script"):
is_script = False
line = fIn.readline()
fReport.Clear()
fReport.SetReadyToSave(False)
if not fReport.FillDate(line):
return kCONTINUE
line = fIn.readline()
line = fIn.readline()
line = fIn.readline()
if not fReport.FillObservatory(line):
return kCONTINUE
line = fIn.readline()
line = fIn.readline()
while line[0] == "<" or line.isspace():
line = fIn.readline()
if not line.startswith("1 Height, km"):
print("File ", GetFullFileName(), " does not include height as a first parameter, cannot interpret")
print(dbg, line)
return kCONTINUE
line = fIn.readline()
if not line.startswith("2 Mass_density, g/cm-3"):
print("File ", GetFullFileName(), " does not include mass density as a second parameter, cannot interpret")
print(dbg, line)
return kCONTINUE
line = fIn.readline()
if not line.startswith("3 Temperature_neutral, K"):
print("File ", GetFullFileName(), " does not include temperature as a third parameter, cannot interpret")
print(dbg, line)
return kCONTINUE
line = fIn.readline()
while line.isspace():
line = fIn.readline()
line = fIn.readline()
while not line.isspace() and not fIn.eof() and not line.startswith("<"):
if not fReport.FillProfile(line,fObservatory):
return kCONTINUE
line = fIn.readline()
fReport.FitProfiles()
print("READY")
fReport.SetReadyToSave()
return True
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment