Updated documentation, descriptions for v1.0 release.

This commit is contained in:
yosata committed 2020-06-24 16:47:25 +02:00
1 parent 56051bb6a5
commit 8d50899db6
31 files changed
+17833 -192

No files matched your search

+208 -19
View File
@@ -16,6 +16,53 @@ from scipy import integrate
'''
class Observatory:
'''
Class used for all function to calculate the refractive index
and the corresponding uncertainties.
...
Attributes
----------
dT : float (optional)
Uncertainty in the atmospheric temperature in Kelvin
dP : float (optional)
Uncertainty in the atmospheric pressure in Pascal
dH : float (optional)
Uncertainty in the atmospheric relative humidity
dCO2: float (optional)
Uncertianty in the atmospheric CO2 density in parts
per million.
dl : float (optional)
Uncertainty in the wavelengths in micron
Methods
-------
n_as(l)
Returns the refractive index for standard atmospheric conditions.
n_axs(l, xc)
Same as n_as(l), but with a different CO2 density given by xc
n_ws(l)
Returns the refractive index of air for standard moist contions.
f(p,T)
Returns the enchancement factor of water vapour in air.
svp(T)
Returns the saturation vapour pressure in Pa.
svp2(T)
Returns the saturation vapour pressure in Pa.
From IAPWS formula, based on documentation by NIST toolbox.
xw(p, T, RH)
Returns the molar fraction of water vapour in moist air.
Z(p, T, RH, xw='')
Returns the compressibility of moist air
rho(p, T, RH, xc, xw='')
Returns the density of atmospheric air at the given parameters.
n_tph(l, T, p, RH, xc)
Returns the refractive index for any atmospheric conditions.
dn_tph(l, T, p, RH, xc, dl=None, dT=None, dP=None, dRH=None, dCO2=None)
Returns the uncertainty in the refractive index for any atmospheric
conditions, given the parameters.
'''
def __init__(self, dT=0.2, dP=20, dH=0.02, dCO2=20, dl=0.001):
self.dT = dT # in K
self.dP = dP # in Pa
@@ -28,6 +75,17 @@ class Observatory:
Formula that calculate the refractive index for standard atmospheric
conditions, i.e. 15 C, 101,325 Pa, 0% RH, 450 ppm CO2.
It returns n_as, not (n_as - 1) * 1e8!
Parameters
----------
l : float
Wavelength of light in microns
Returns
-------
n : float
Refractive index of air at standard atmospheric conditions.
'''
_s = 1 / l
_k0 = 238.0185 # um^-2
@@ -42,6 +100,18 @@ class Observatory:
Formula that calculate the refractive index for standard atmospheric
conditions, i.e. 15 C, 101,325 Pa, 0% RH, but with xc ppm of CO2.
It returns n_axs, not (n_axs - 1)
Parameters
----------
l : float
Wavelength of light in microns
xc : float
CO2 density in parts per million
Returns
-------
n : float
Refractive index of air
'''
_n_as = self.n_as(l)
return ( (_n_as - 1) * (1 + 0.534e-6 * (xc - 450) ) ) + 1
@@ -52,6 +122,16 @@ class Observatory:
Formula that calculates the refractivity of air for standard moist conditions
as defined by B&S (1939), i.e. 20 C, 1333 Pa
Returns n_ws, not (n_ws - 1) * 1e8
Parameters
----------
l : float
Wavelength of light in microns
Returns
-------
n : float
Refractive index of standard moist air.
'''
_s = 1 / l
_cf = 1.022
@@ -65,8 +145,18 @@ class Observatory:
def f(self, p, T):
'''
Enhancement factor of water vapour in air
t in degrees celsius
p in Pascal (Pa)
Parameters
----------
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
Returns
-------
f : float
Enhancement factor of water vapour in air
'''
_t = T - 273.15
_a = 1.00062
@@ -78,6 +168,16 @@ class Observatory:
def svp(self, T):
'''
Saturation vapour pressure in Pa.
Parameters
----------
T : float
Atmospheric temperature in Kelvin
Returns
-------
svp : float
Saturation vapour pressure
'''
_A = 1.2378847e-5 # K^-2
_B = -1.9121316e-2 # K^-2
@@ -88,7 +188,18 @@ class Observatory:
def svp2(self, T):
'''
Calculation of svp from IAPWS formula, based on documentation by NIST toolbox.
Calculation of svp from IAPWS formula, based on documentation
by NIST toolbox.
Parameters
----------
T : float
Atmospheric temperature in Kelvin
Returns
-------
svp : float
Saturation vapour pressure
'''
K1 = 1.16705214528e+03
K2 = -7.24213167032e+05
@@ -111,6 +222,20 @@ class Observatory:
def xw(self, p, T, RH):
'''
Molar fraction of water vapour in moist air.
Parameters
----------
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
RH : float
Atmospheric relative humidity (0<=RH<=1)
Returns
-------
xw : float
Molar fraction of water vapour in moist air
'''
_f = self.f(p, T)
_svp = self.svp(T)
@@ -120,6 +245,20 @@ class Observatory:
def Z(self, p, T, RH, xw=''):
'''
Compressibility of moist air
Parameters
----------
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
RH : float
Atmospheric relative humidity (0<=RH<=1)
Returns
-------
Z : float
Compressibility of moist air
'''
_a0 = 1.58123e-6 # K Pa^-1
_a1 = -2.9331e-8 # Pa^-1
@@ -142,10 +281,25 @@ class Observatory:
def rho(self, p, T, RH, xc, xw=''):
'''
Calculates the density of air for the given parameters.
T in Kelvin
p in Pascal
RH between 0 and 1
xc in ppm
Parameters
----------
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
RH : float
Atmospheric relative humidity (0<=RH<=1)
xc : float
CO2 density in parts per million
xw : str or float
Placeholder for molar fraction of water vapour in moist air.
Used to pass the function along where it should go.
Returns
-------
rho : float
Density of air
'''
_Ma = 1e-3 * (28.9635 + 12.011e-6 * (xc - 400) ) # Molar mass in kg/mol of dry air containing xc ppm of CO2
_Mw = 0.018015 # kg/mol
@@ -161,6 +315,25 @@ class Observatory:
def n_tph(self, l, T, p, RH, xc):
'''
Calculates the refraction of the atmosphere for any conditions.
Follows the equations by Ciddor (1996).
Parameters
----------
l : float
Wavelength of light in microns
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
RH : float
Atmospheric relative humidity (0<=RH<=1)
xc : float
CO2 density in parts per million
Returns
-------
n : float
Refractive index of air
'''
_n_a = self.n_axs(l, xc)
_n_w = self.n_ws(l)
@@ -193,18 +366,34 @@ class Observatory:
by using fully propagated error analysis.
This involves almost endless use of the chain rule and evaluation of both the moist
air and dry air components. Note: dry air does not contain any water, i.e. H=0, x_w=0, etc.
Parameters:
l - Wavelength in micron (0.4 - 2.5 micron)
T - Temperature in Kelvin
p - Pressure in Pascals
RH - Relative humidity (no units, don't use percentage but value 0<x<1)
xc - CO2 density in ppm
dl - Uncertainty in the blue wavelength
dT - Uncertainty in the temperature, default: 0.2 K
dP - Uncertainty in the pressure, default: 20 Pa
dRH - Uncertainty in the relative humidity, default: 0.02
dCO2- Uncertainty in the CO2 density, default: 20
Parameters
----------
l : float
Wavelength of light in microns
p : float
Atmospheric pressure in Pascal
T : float
Atmospheric temperature in Kelvin
RH : float
Atmospheric relative humidity (0<=RH<=1)
xc : float
CO2 density in parts per million
dl : float
Uncertainty in the wavelength in microns
dT : float (default: 0.2)
Uncertainty in the atmospheric temperature in Kelvin
dP : float (default: 20)
Uncertainty in the atmospheric pressure in Pascal
dRH : float (default: 0.02)
Uncertainty in the atmospheric relative humidity
dCO2: float (default: 20)
Uncertainty in the atmospheric CO2 density in parts per million
Returns
-------
dn : float
Uncertainty in the refractive index of air
'''
if dP == None:
+296 -38
View File
@@ -3,6 +3,7 @@ import numpy as np
from scipy import integrate
import os
from .ciddorModel import Observatory
'''
@ Author: Joost van den Born
@ Contact: born@astron.nl
@@ -17,19 +18,99 @@ from .ciddorModel import Observatory
'''
class dispersion(Observatory):
'''
Class that sets the observer location.
These location attributes are then used to calculate the
appropriate atmospheric dispersion.
See also:
Observatory()
refraction()
...
Attributes
-----------
lat : float
Latitude of the observer in degrees
h : float
Altitude above mean sea level of the observer in meters
Other Observatory() attributes
Methods
-------
setReducedHeight(p, rho)
Sets the reduced atmospheric height.
planeParallel(n1, n2, zenith)
Returns the atmospheric dispersion assuming a plane parallel
atmosphere
cassini(n1, n2, zenith, reduced_height=None)
Returns the atmospheric dispersion asusming Cassini's homegeneous
atmosphere model
tan5(n1, n2, zenith, reduced_height=None)
Returns the atmospheric dispersion following Oriani's theorem,
including a fifth order term in the expansion.
oriani(n1, n2, zenith, reduced_height=None)
Returns the atmospheric dispersion following the classic version
of Oriani's theorem.
corbard(n1, n2, zenith, reduced_height=None)
Returns the atmospheric dispersion following the method described
in Corbard et al., 2019.
refractionIntegral(n1, n2, z0, R0=None, useStandardAtmosphere=True, heightData=None, rhoData=None)
Returns the atmospheric dispersion following the refraction integral.
psi(x)
Submethod for corbard()
set_rc()
Sets the local radius of curvature of the Earth at the observer.
set_H(p, rho)
Sets the reduced height for the conditions at the observer, assuming
an adiabatic atmosphere.
H_isotherm(T)
Sets the reduced height for the conditions at the observer, assuming
an isothermal atmosphere.
cassiniError(z, l1, l2, T, p, RH, xc, dl1=0, dl2=0, dT=0.2, dP=20,
dRH=0.02, dCO2=20, dz=0, lat=None, h=None)
Returns the uncertainty in the atmospheric dispersion, assuming
Cassini's homegeneous atmosphere model and the given parameters.
Other Observatory() methods
'''
def __init__(self, lat, h):
Observatory.__init__(self)
self.h = h # height above sea level in meters
self.lat = lat # Latitude of the observer in degrees
self.rc = self.set_rc() * 1000 # Radius of curvature of the earth at the observer
def setReducedHeight(self, P, rho):
self.H = self.set_H(P, rho) # Reduced height of the atmosphere assuming ideal gas law
def setReducedHeight(self, p, rho):
'''
Sets the reduced atmospheric height.
Parameters
----------
p : float
Atmospheric pressure in Pascal
rho : float
Density of the atmospheric air at the observer
'''
self.H = self.set_H(p, rho) # Reduced height of the atmosphere assuming ideal gas law
def planeParallel(self, n1, n2, zenith):
'''
Refraction based on a flat atmosphere, easily derived from Snell's law.
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
_R1 = np.arcsin(n1 * np.sin( np.deg2rad(zenith) )) - np.deg2rad(zenith)
_R2 = np.arcsin(n2 * np.sin( np.deg2rad(zenith) )) - np.deg2rad(zenith)
@@ -40,6 +121,24 @@ class dispersion(Observatory):
def cassini(self, n1, n2, zenith, reduced_height=None):
'''
Refraction of spherical atmosphere, derived from geometry using Sine law
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if reduced_height:
H = reduced_height
@@ -56,6 +155,24 @@ class dispersion(Observatory):
'''
Same as oriani's theorem, but including a higher order term.
Found in Corbard et al., 2019.
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if reduced_height:
H = reduced_height
@@ -74,8 +191,27 @@ class dispersion(Observatory):
def oriani(self, n1, n2, zenith, reduced_height=None):
'''
Classic refraction formula with two tan(z) terms. This does not assume any
information about the structure of the atmosphere. Found with Oriani's theorem.
Classic refraction formula with two tan(z) terms.
This does not assume any information about the structure
of the atmosphere. Found with Oriani's theorem.
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if reduced_height:
H = reduced_height
@@ -94,9 +230,28 @@ class dispersion(Observatory):
def corbard(self, n1, n2, zenith, reduced_height=None):
'''
Corbard et al., 2019, mention an additional formula based on the error function.
Oriani's theorem can be derived from this equation by 'keeping only the three first
terms of its asymptotic expansion'.
Corbard et al., 2019, mention an additional formula based on
the error function. Oriani's theorem can be derived from this
equation by 'keeping only the three first terms of its
asymptotic expansion'.
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if reduced_height:
H = reduced_height
@@ -113,15 +268,46 @@ class dispersion(Observatory):
def refractionIntegral(self, n1, n2, z0, R0=None, useStandardAtmosphere=True, heightData=None, rhoData=None):
def refractionIntegral(self, n1, n2, z0, R0=None, useStandardAtmosphere=True,
heightData=None, rhoData=None):
'''
Using data that gives temperature, pressure and density as a function of height,
the gladstone-dale relation is invoked to calculate the path of a light ray
along the atmosphere. This is allows us to also include atmospheric activity in
Using data that gives temperature, pressure and density as a
function of height, the gladstone-dale relation is invoked to
calculate the path of a light ray along the atmosphere.
This is allows us to also include atmospheric activity in
different atmosphere layers.
Recommended use with the US Standard Atmosphere from 1976.
USSA1976 data generated from code supplied by http://www.pdas.com/atmos.html
The method described in eq. 3 in Auer & Standish (2000) is used for the calculation.
The method described in eq. 3 in Auer & Standish (2000) is used for the
calculation.
Parameters
----------
n1 : float
Refractive index at the shortest wavelength of interest
n2 : float
Refractive index at the longest wavelength of interest
z0 : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
R0 : float (optional)
Local radius of curvature of the Earth in km.
useStandardAtmosphere : bool
Flag to use the included USSA1976 data
heightData : 1D Array
If "useStandardAtmosphere" is False, the function will ask
for alternative atmospheric data to integrate over. This
gives the altitudinal points
rhoData : 1D Array
If useStandardAtmosphere is False, the function will ask
for alternative atmospheric data to integrate over. This
gives the atmospheric density at the points defined by
"heightData".
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if not R0:
R0 = self.rc
@@ -163,6 +349,19 @@ class dispersion(Observatory):
def psi(self, x):
'''
Submethod for corbard(). Described explicitly in Corbard et al.,2019.
Parameters
----------
x : float
Input of the function
Returns
-------
y : float
Output of the function
'''
_f = lambda a: np.exp(-a**2)
_int = integrate.quad(_f, x, np.inf)
return np.exp(x**2) * _int[0]
@@ -173,6 +372,11 @@ class dispersion(Observatory):
Returns the radius of the curvature at the observer in km,
taking into account the latitude of the observer and the corresponding
ellipsoidality of the earth.
Returns
-------
rc : float
Local radius of curvature of the Earth in kilometers.
'''
_A = 6378.137 # km
_B = 6356.752 # km
@@ -182,9 +386,21 @@ class dispersion(Observatory):
return _rc0 + self.h/1000
def set_H(self, P, rho):
def set_H(self, p, rho):
'''
Calculates the reduced height of the atmosphere, assuming ideal gas law.
Parameters
----------
p : float
Atmospheric pressure in Pascal
rho : float
Density of the atmospheric air at the observer
Returns
-------
H : float
Reduced height of the atmosphere in meters
'''
_phi = np.deg2rad(self.lat)
_c1 = 5.2790414e-3
@@ -194,11 +410,22 @@ class dispersion(Observatory):
_g0 = 9.780327 # m/s^2
_g0_local = _g0 * (1 + _c1 * np.sin(_phi)**2 + _c2 * np.sin(_phi)**4 + _c3 * np.sin(_phi)**6 + _c4 * np.sin(_phi)**8)
_g = _g0_local - (3.0877e-6 - 4.3e-9 * np.sin(_phi)**2) * self.h + 7.2e-13 * self.h**2
return P / (rho * _g)
return p / (rho * _g)
def H_isotherm(self, T):
'''
Calculates the reduced height of the atmosphere, assuming an isotherm distribution.
Calculates the reduced height of the atmosphere,
assuming an isotherm distribution.
Parameters
----------
T : float
Atmospheric temperature in Kelvin
Returns
-------
H : float
Reduced height of the atmosphere in meters
'''
_kb = 1.38064852e-23 # kg m2 s-2 K-1
_m = 4.809651698e-26 # kg (weight per molecule of air, assuming dry air)
@@ -213,32 +440,63 @@ class dispersion(Observatory):
return (_kb*T) / (_m * _g0_local)
def cassiniError(self, z, l1, l2, T, p, RH, xc, dl1=0, dl2=0, dT=0.2, dP=20, dRH=0.02, dCO2=20, dz=0, lat=None, h=None):
def cassiniError(self, z, l1, l2, T, p, RH, xc, dl1=0, dl2=0, dT=0.2, dP=20,
dRH=0.02, dCO2=20, dz=0, lat=None, h=None):
'''
Calculates the uncertainty in the atmospheric dispersion, following the Cassini model,
by using fully propagated error analysis.
This involves almost endless use of the chain rule and evaluation of both the moist
air and dry air components. Note: dry air does not contain any water, i.e. H=0, x_w=0, etc.
Calculates the uncertainty in the atmospheric dispersion,
following the Cassini model, by using fully propagated error analysis.
This involves almost endless use of the chain rule and evaluation
of both the moist air and dry air components.
Note: dry air does not contain any water, i.e. H=0, x_w=0, etc.
Not taken into account is the errror propagation in the scale height of the atmosphere or
the zenith error, from my results this should give a small or even negligible difference.
Not taken into account is the errror propagation in the scale height
of the atmosphere, from my results this should give a small or even
negligible difference.
Parameters:
z - Zenith angle in degrees
l1 - Bluest wavelength in micron (0.4 - 2.5 micron)
l2 - Reddest wavelength in micron (0.4 - 2.5 micron)
T - Temperature in Kelvin
p - Pressure in Pascals
RH - Relative humidity (no units, don't use percentage but value 0<x<1)
xc - CO2 density in ppm
dl1 - Uncertainty in the blue wavelength
dl2 - Uncertainty in the red wavelength
dT - Uncertainty in the temperature, default: 0.2 K
dP - Uncertainty in the pressure, default: 20 Pa
dRH - Uncertainty in the relative humidity, default: 0.02
dCO2- Uncertainty in the CO2 density, default: 20
lat - [Optional] Latitude of the observatory in degrees
h - [Optional] Height in m of the observatory
Parameters
----------
z : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
l1 : float
Wavelength of light in microns, at the shortest wavelength
of interest
l2 : float
Wavelength of light in microns, at the longest wavelength
of interest
T : float
Atmospheric temperature in Kelvin
p : float
Atmospheric pressure in Pascal
RH : float
Atmospheric relative humidity (0<=RH<=1)
xc : float
CO2 density in parts per million
dl1 : float
Uncertainty in the wavelength in microns, at the shortest
wavelength of interest
dl2 : float
Uncertainty in the wavelength in microns, at the longest
wavelength of interest
dT : float (default: 0.2)
Uncertainty in the atmospheric temperature in Kelvin
dP : float (default: 20)
Uncertainty in the atmospheric pressure in Pascal
dRH : float (default: 0.02)
Uncertainty in the atmospheric relative humidity
dCO2: float (default: 20)
Uncertainty in the atmospheric CO2 density in parts per million
dz : float (default: 0)
Uncertainty in the zenith angle, in degrees.
lat : float (default: None)
If entered, overrides the latitude attribute of the class.
h : float (default=None)
If entered, overrides the altitude attribute of the class.
Returns
-------
dRR : float
Uncertainty in the atmospheric dispersion in degrees.
'''
if lat == None:
lat = self.lat
+122 -23
View File
@@ -2,55 +2,119 @@
from .ciddorModel import Observatory
from .refractionModels import refraction
from .dispersionModels import dispersion
'''
Author: Joost van den Born
Some functions for quick testing.
@ Author: Joost van den Born
@ Contact: born@astron.nl
@ Description: Some functions for quick testing.
'''
def quick_refractive_index(l, conditions='STANDARD'):
def quick_refractive_index(l, conditions='STANDARD', T=288.15, p=101325,
H=0.0, xc=450, lat=0, h=0):
'''
Function to quickly calculate the refractive index
of atmospheric air at reference conditions, given
a wavelength l.
Parameters
----------
l : float
Wavelength in microns
conditions: string
'STANDARD' or 'CERRO_ARMAZONES', refers
to the standard atmospheric conditions.
T : float (optional)
Temperature in Kelvin
p : float (optional)
Atmospheric pressure in Pa
H : float (optional)
Relative humidity
xc : float (optional)
CO2 density in parts per million
lat : float (optional)
Latitude of the observer in degrees
h : float (optional)
Altitude of the observer in meters
Returns
-------
n : float
Refractive index for the given conditions.
'''
if conditions == 'STANDARD':
# Parameters at Cerro Armazones
T = 288.15 # k
P = 101325 # Pa
p = 101325 # Pa
H = 0.0
xc = 450 # ppm
lat = 0 # degrees
h = 0 # m
elif conditions == 'CERRO_ARMAZONES':
# Parameters at Cerro Armazones
T = 279.65 # k
P = 71200 # Pa
p = 71200 # Pa
H = 0.22
xc = 450 # ppm
lat = -24.5983 # degrees
h = 3064 # m
# Initializing dispersion model
at = Observatory()
# Calculating indices of refraction for l
n = at.n_tph(l=l, T=T, p=P, RH=H, xc=xc)
n = at.n_tph(l=l, T=T, p=p, RH=H, xc=xc)
return n
def quick_refraction(l, z, conditions='STANDARD'):
def quick_refraction(l, z, conditions='STANDARD', T=288.15, p=101325,
H=0.0, xc=450, lat=0, h=0):
'''
Function to quickly calculate the refraction
of atmospheric air at reference conditions,
given a wavelength l.
Parameters
----------
l : float
Wavelength in microns
z : float
Zenith angle of the observation
conditions : string
'STANDARD' or 'CERRO_ARMAZONES', refers
to the standard atmospheric conditions.
T : float (optional)
Temperature in Kelvin
p : float (optional)
Atmospheric pressure in Pa
H : float (optional)
Relative humidity
xc : float (optional)
CO2 density in parts per million
lat : float (optional)
Latitude of the observer in degrees
h : float (optional)
Altitude of the observer in meters
Returns
-------
R : float
Refraction in degrees
'''
if conditions == 'STANDARD':
# Parameters at Cerro Armazones
T = 288.15 # k
P = 101325 # Pa
p = 101325 # Pa
H = 0.0
xc = 450 # ppm
lat = 0 # degrees
h = 0 # m
elif conditions == 'CERRO_ARMAZONES':
# Parameters at Cerro Armazones
T = 279.65 # k
P = 71200 # Pa
p = 71200 # Pa
H = 0.22
xc = 450 # ppm
lat = -24.5983 # degrees
@@ -60,31 +124,66 @@ def quick_refraction(l, z, conditions='STANDARD'):
at = Observatory()
# Calculating indices of refraction for l
n = at.n_tph(l=l, T=T, p=P, RH=H, xc=xc)
n = at.n_tph(l=l, T=T, p=p, RH=H, xc=xc)
# Density of the atmosphere (following CIPM-81/91 equations)
rho = at.rho(p=P, T=T, RH=H, xc=xc)
rho = at.rho(p=p, T=T, RH=H, xc=xc)
# Initializing refraction model and setting the reduced height
ref = refraction(lat, h)
ref.setReducedHeight(P, rho)
ref.setReducedHeight(p, rho)
return ref.cassini(n, z)
def quick_dispersion(l1, l2, z, conditions='STANDARD'):
def quick_dispersion(l1, l2, z, conditions='STANDARD', T=288.15,
p=101325, H=0.0, xc=450, lat=0, h=0):
'''
Function to quickly calculate the dispersion
of atmospheric air at reference conditions,
given a wavelength l.
Parameters
----------
l1 : float
Shortest wavelength of interest in micron.
l2 : float
Longest wavelength of interest in micron.
z : float
Zenith angle of the observation
conditions : string
'STANDARD' or 'CERRO_ARMAZONES', refers
to the standard atmospheric conditions.
T : float (optional)
Temperature in Kelvin
p : float (optional)
Atmospheric pressure in Pa
H : float (optional)
Relative humidity
xc : float (optional)
CO2 density in parts per million
lat : float (optional)
Latitude of the observer in degrees
h : float (optional)
Altitude of the observer in meters
Returns
-------
dR : float
Atmospheric dispersion in degrees
'''
if conditions == 'STANDARD':
# Parameters at Cerro Armazones
T = 288.15 # k
P = 101325 # Pa
p = 101325 # Pa
H = 0.0
xc = 450 # ppm
lat = 0 # degrees
h = 0 # m
elif conditions == 'CERRO_ARMAZONES':
# Parameters at Cerro Armazones
T = 279.65 # k
P = 71200 # Pa
p = 71200 # Pa
H = 0.22
xc = 450 # ppm
lat = -24.5983 # degrees
@@ -94,13 +193,13 @@ def quick_dispersion(l1, l2, z, conditions='STANDARD'):
at = Observatory()
# Calculating indices of refraction for l1 and l2
n1 = at.n_tph(l=l1, T=T, p=P, RH=H, xc=xc)
n2 = at.n_tph(l=l2, T=T, p=P, RH=H, xc=xc)
n1 = at.n_tph(l=l1, T=T, p=p, RH=H, xc=xc)
n2 = at.n_tph(l=l2, T=T, p=p, RH=H, xc=xc)
# Density of the atmosphere (following CIPM-81/91 equations)
rho = at.rho(p=P, T=T, RH=H, xc=xc)
rho = at.rho(p=p, T=T, RH=H, xc=xc)
# Initializing refraction model and setting the reduced height
disp = dispersion(lat, h)
disp.setReducedHeight(P, rho)
disp.setReducedHeight(p, rho)
return disp.cassini(n1, n2, z)
+249 -12
View File
@@ -3,6 +3,7 @@ import numpy as np
from scipy import integrate
import os
from .ciddorModel import Observatory
'''
@ Author: Joost van den Born
@ Contact: born@astron.nl
@@ -17,6 +18,61 @@ from .ciddorModel import Observatory
'''
class refraction(Observatory):
'''
Class that sets the observer location.
These location attributes are then used to calculate the
appropriate atmospheric refraction.
See also:
Observatory()
dispersion()
...
Attributes
-----------
lat : float
Latitude of the observer in degrees
h : float
Altitude above mean sea level of the observer in meters
Other Observatory() attributes
Methods
-------
setReducedHeight(p, rho)
Sets the reduced atmospheric height.
planeParallel(n1, n2, zenith)
Returns the atmospheric refraction assuming a plane parallel
atmosphere
cassini(n1, n2, zenith, reduced_height=None)
Returns the atmospheric refraction asusming Cassini's homegeneous
atmosphere model
tan5(n1, n2, zenith, reduced_height=None)
Returns the atmospheric refraction following Oriani's theorem,
including a fifth order term in the expansion.
oriani(n1, n2, zenith, reduced_height=None)
Returns the atmospheric refraction following the classic version
of Oriani's theorem.
corbard(n1, n2, zenith, reduced_height=None)
Returns the atmospheric refraction following the method described
in Corbard et al., 2019.
refractionIntegral(n1, n2, z0, R0=None, useStandardAtmosphere=True, heightData=None, rhoData=None)
Returns the atmospheric refraction following the refraction integral.
psi(x)
Submethod for corbard()
set_rc()
Sets the local radius of curvature of the Earth at the observer.
set_H(p, rho)
Sets the reduced height for the conditions at the observer, assuming
an adiabatic atmosphere.
H_isotherm(T)
Sets the reduced height for the conditions at the observer, assuming
an isothermal atmosphere.
cassiniError(z, l1, l2, T, p, RH, xc, dl1=0, dl2=0, dT=0.2, dP=20,
dRH=0.02, dCO2=20, dz=0, lat=None, h=None)
Returns the uncertainty in the atmospheric refraction, assuming
Cassini's homegeneous atmosphere model and the given parameters.
Other Observatory() methods
'''
def __init__(self, lat, h):
Observatory.__init__(self)
self.h = h # height above sea level in meters
@@ -24,13 +80,36 @@ class refraction(Observatory):
self.rc = self.set_rc() * 1000 # Radius of curvature of the earth at the observer
# self.H2 = self.H_isotherm(T) # Reduced height of isotherm atmosphere
def setReducedHeight(self, P, rho):
self.H = self.set_H(P, rho) # Reduced height of the atmosphere assuming ideal gas law
def setReducedHeight(self, p, rho):
'''
Sets the reduced atmospheric height.
Parameters
----------
p : float
Atmospheric pressure in Pascal
rho : float
Density of the atmospheric air at the observer
'''
self.H = self.set_H(p, rho) # Reduced height of the atmosphere assuming ideal gas law
def planeParallel(self, n, zenith):
def planeParallel(self, n1, zenith):
'''
Refraction based on a flat atmosphere, easily derived from Snell's law.
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
Returns
-------
R : float
Atmospheric refraction in degrees
'''
_R = np.arcsin(n * np.sin( np.deg2rad(zenith) )) - np.deg2rad(zenith)
return np.degrees(_R)
@@ -40,6 +119,22 @@ class refraction(Observatory):
def cassini(self, n1, zenith, reduced_height=None):
'''
Refraction of spherical atmosphere, derived from geometry using Sine law
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
R : float
Atmospheric refraction in degrees
'''
if reduced_height:
H = reduced_height
@@ -55,6 +150,22 @@ class refraction(Observatory):
'''
Same as oriani's theorem, but including a higher order term.
Found in Corbard et al., 2019.
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
R : float
Atmospheric refraction in degrees
'''
if reduced_height:
H = reduced_height
@@ -70,8 +181,25 @@ class refraction(Observatory):
def oriani(self, n1, zenith, reduced_height=None):
'''
Classic refraction formula with two tan(z) terms. This does not assume any
information about the structure of the atmosphere. Found with Oriani's theorem.
Classic refraction formula with two tan(z) terms. This does not
assume any information about the structure of the atmosphere.
Found with Oriani's theorem.
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
R : float
Atmospheric refraction in degrees
'''
if reduced_height:
H = reduced_height
@@ -90,6 +218,22 @@ class refraction(Observatory):
Corbard et al., 2019, mention an additional formula based on the error function.
Oriani's theorem can be derived from this equation by 'keeping only the three first
terms of its asymptotic expansion'.
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
R : float
Atmospheric refraction in degrees
'''
if reduced_height:
H = reduced_height
@@ -103,14 +247,44 @@ class refraction(Observatory):
def refractionIntegral(self, n0, z0, R0=None, useStandardAtmosphere=True, heightData=None, rhoData=None):
def refractionIntegral(self, n1, z0, R0=None, useStandardAtmosphere=True, heightData=None, rhoData=None):
'''
Using data that gives temperature, pressure and density as a function of height,
the gladstone-dale relation is invoked to calculate the path of a light ray
along the atmosphere. This is allows us to also include atmospheric activity in
Using data that gives temperature, pressure and density as a
function of height, the gladstone-dale relation is invoked to
calculate the path of a light ray along the atmosphere.
This is allows us to also include atmospheric activity in
different atmosphere layers.
Recommended use with the US Standard Atmosphere from 1976.
USSA1976 data generated from code supplied by http://www.pdas.com/atmos.html
The method described in eq. 3 in Auer & Standish (2000) is used for the
calculation.
Parameters
----------
n1 : float
Refractive index at the wavelength of interest
z0 : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
R0 : float (optional)
Local radius of curvature of the Earth in km.
useStandardAtmosphere : bool
Flag to use the included USSA1976 data
heightData : 1D Array
If "useStandardAtmosphere" is False, the function will ask
for alternative atmospheric data to integrate over. This
gives the altitudinal points
rhoData : 1D Array
If useStandardAtmosphere is False, the function will ask
for alternative atmospheric data to integrate over. This
gives the atmospheric density at the points defined by
"heightData".
Returns
-------
R : float
Atmospheric refraction in degrees
'''
if not R0:
R0 = self.rc
@@ -148,6 +322,19 @@ class refraction(Observatory):
def psi(self, x):
'''
Submethod for corbard(). Described explicitly in Corbard et al.,2019.
Parameters
----------
x : float
Input of the function
Returns
-------
y : float
Output of the function
'''
_f = lambda a: np.exp(-a**2)
_int = integrate.quad(_f, x, np.inf)
return np.exp(x**2) * _int[0]
@@ -159,6 +346,11 @@ class refraction(Observatory):
Returns the radius of the curvature at the observer in km,
taking into account the latitude of the observer and the corresponding
ellipsoidality of the earth.
Returns
-------
rc : float
Local radius of curvature of the Earth in kilometers.
'''
_A = 6378.137 # km
_B = 6356.752 # km
@@ -169,9 +361,21 @@ class refraction(Observatory):
def set_H(self, P, rho):
def set_H(self, p, rho):
'''
Calculates the reduced height of the atmosphere, assuming ideal gas law.
Parameters
----------
p : float
Atmospheric pressure in Pascal
rho : float
Density of the atmospheric air at the observer
Returns
-------
H : float
Reduced height of the atmosphere in meters
'''
_phi = np.deg2rad(self.lat)
_c1 = 5.2790414e-3
@@ -181,11 +385,22 @@ class refraction(Observatory):
_g0 = 9.780327 # m/s^2
_g0_local = _g0 * (1 + _c1 * np.sin(_phi)**2 + _c2 * np.sin(_phi)**4 + _c3 * np.sin(_phi)**6 + _c4 * np.sin(_phi)**8)
_g = _g0_local - (3.0877e-6 - 4.3e-9 * np.sin(_phi)**2) * self.h + 7.2e-13 * self.h**2
return P / (rho * _g)
return p / (rho * _g)
def H_isotherm(self, T):
'''
Calculates the reduced height of the atmosphere, assuming an isotherm distribution.
Calculates the reduced height of the atmosphere,
assuming an isotherm distribution.
Parameters
----------
T : float
Atmospheric temperature in Kelvin
Returns
-------
H : float
Reduced height of the atmosphere in meters
'''
_kb = 1.38064852e-23 # kg m2 s-2 K-1
_m = 4.809651698e-26 # kg (weight per molecule of air, assuming dry air)
@@ -203,6 +418,28 @@ class refraction(Observatory):
def cassiniError(self, n, dn, zenith, dz=0, reduced_height=None):
'''
Calculates the uncertainty in the refraction angle in degrees.
See Observatory().n_tph() and Observatory().dn_tph() on how to
calculate the refractive index and it's uncertainty.
Parameters
----------
n : float
Refractive index of air
dn : float
Uncertainty in the refractive index of air
zenith : float
Angle of observation in degrees.
zenith = 0 means the observation is directly overhead.
dz : float (optional)
Uncertainty in the zenith angle, in degrees.
reduced_height : float (optional)
Reduced height of the atmosphere. Default value is calculated
from the object attributes.
Returns
-------
dR : float
Uncertainty in the atmospheric refraction in degrees.
'''
if reduced_height:
_H = reduced_height
+144 -62
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env Python3
import numpy as np
'''
@ Author: Joost van den Born
@ Contact: born@astron.nl
@@ -17,14 +16,21 @@ def BarrellAndSears(l, T=288.15, p=101325, H=0):
For atmospheric air (i.e. CO2 = 300 ppm)
This equation is applicable for the ranges T=10-30C and p=720-800 mmHg.
Input:
l - Wavelength in microns
T - Temperature in Kelvin
p - Atmospheric pressure in Pa
H - fractional humidity (0=<H=<1)
Parameters
----------
l : float
Wavelength in microns
T : float
Temperature in Kelvin
p : float
Atmospheric pressure in Pascal
H : float
Relative humidity (0=<H=<1)
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
T = K2C(T)
P = hPA2mmHg(p/100)
@@ -39,11 +45,15 @@ def Ciddor(l, CO2=450):
At default conditions only. For more flexibility use
Observatory.n_tph()
Input:
l - Wavelength in microns
Parameters
----------
l : float
Wavelength in microns
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
s = 1 / l
R = 5792105 / (238.0185 - s**2) + 167917 / (57.362 - s**2)
@@ -59,11 +69,15 @@ def Edlen1953(l):
At standard conditions only
Input:
l - Wavelength in microns
Parameters
----------
l : float
Wavelength in microns
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
s = 1 / l
R = 6432.8 + 2949810 / (146 - s**2) + 25540/(41-s**2)
@@ -77,11 +91,15 @@ def Edlen1966(l):
At standard conditions only
Input:
l - Wavelength in microns
Parameters
----------
l : float
Wavelength in microns
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
s = 1 / l
R = 8342.13 + 2406030 / (130 - s**2) + 15997 / (38.9 - s**2)
@@ -95,14 +113,21 @@ def Owens(l, T=288.15, p=101325, H=0):
Note that the pressure P and H are in torricelli (Torr),
however, this is almost precisely 1 Torr = 1 mmHg
Input:
l - wavelength in micron
T - Temperature in Kelvin
p - Atmospheric pressure in Pa
H - Humdity (0<=H<=1)
Parameters
----------
l : float
wavelength in micron
T : float
Temperature in Kelvin
p : float
Atmospheric pressure in Pa
H : float
Humdity (0<=H<=1)
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
P = hPA2mmHg(p/100)
T = K2C(T)
@@ -116,14 +141,21 @@ def BonschPotulski(l, T=288.15, p=101325, CO2=450):
From Bonsch & Potulski, 1998
Equations 6, 7, 8
Input:
l - Wavelength in microns
T - Temperature in Kelvin
p - Atmospheric pressure in Pa
CO2 - Particles per million of CO2
Parameters
----------
l : float
Wavelength in microns
T : float
Temperature in Kelvin
p : float
Atmospheric pressure in Pa
CO2 : float
Particles per million of CO2
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
x = CO2 / 1e6
T = K2C(T)
@@ -143,11 +175,15 @@ def BirchDowns(l):
Only at standard conditions
Input:
l - wavelength in micron
Parameters
----------
l : float
wavelength in micron
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
s = 1 / l
R = 8342.54 + 2406147 / (130 - s**2) + 15998 / (38.9-s**2)
@@ -161,11 +197,15 @@ def PeckReeder(l):
Only at standard conditions
Input:
l - wavelength in micron
Parameters
----------
l : float
wavelength in micron
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
s = 1 / l
R = 8060.51 + 2480990 / (132.274 - s**2) + 17455.7 / (39.32957 - s**2)
@@ -180,18 +220,29 @@ def slalib(l, T=288.15, p=101325, H=0, h=0, lat=-24, tlr=0.0065, eps=1e-10):
They take the B&S refraction formula as a basis.
Requires the pySLALIB package to work.
Input:
l - Wavelength in microns
T - Temperature in Kelvin
p - Atmospheric pressure in Pa
H - fractional humidity (0=<H=<1)
h - Altitude of the observer (default=0 m)
lat - Latitude of the observer (default=-24)
tlr - temperature lapse rate (default=0.0065)
eps - precision at which the calculation is aborted (default=1e-10)
Parameters
----------
l : float
Wavelength in microns
T : float
Temperature in Kelvin
p : float
Atmospheric pressure in Pa
H : float
fractional humidity (0=<H=<1)
h : float
Altitude of the observer (default=0 m)
lat : float
Latitude of the observer (default=-24)
tlr : float
temperature lapse rate (default=0.0065)
eps : float
precision at which the calculation is aborted (default=1e-10)
Returns:
n - Refractive index of atmospheric air at the given conditions
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
try:
from pyslalib import slalib
@@ -215,17 +266,27 @@ def slalib(l, T=288.15, p=101325, H=0, h=0, lat=-24, tlr=0.0065, eps=1e-10):
def Mathar(l, T=288.15, p=101325, H=0):
'''
Refractivity model by Mathar (2007), valid above 1.4 microns
Code taken and modified from:
Code taken from
https://github.com/polyanskiy/refractiveindex.info-scripts/blob/master/scripts/Mathar%202007%20-%20Air%201.3-2.5um.py
(better known from refractiveindex.info). The code was subsequently
minimally modified to make it suitable for this package.
Input:
l - Wavelength in microns
T - Temperature in Kelvin
p - Atmospheric pressure in Pa
H - fractional humidity (0=<H=<1)
Returns:
n - Refractive index of atmospheric air at the given conditions
Parameters
----------
l : float
Wavelength in microns
T : float
Temperature in Kelvin
p : float
Atmospheric pressure in Pa
H : float
fractional humidity (0=<H=<1)
Returns
-------
n : float
Refractive index of atmospheric air at the given conditions
'''
if l < 1.3 or l > 24:
print('Using the Mathar model at this wavelength (l={:.3f}) is not recommended!'.format(l))
@@ -346,11 +407,32 @@ def Mathar(l, T=288.15, p=101325, H=0):
def K2C(K):
'''
Kelvin to Celsius conversion
Parameters
----------
K : float
Temperature in Kelvin
Returns
-------
C : float
Temperature in Celsius
'''
return K - 273.15
def hPA2mmHg(hPa):
'''
hPa to mmHg conversion
Parameters
----------
hPa : float
Atmospheric pressure in hPa (hecto Pascal)
Returns
-------
mmHg : float
Atmospheric pressure in mmHg
'''
return 0.7500616827 * hPa
return 0.7500616827 * hPa