From 6c59d14bd40c7a49a182eff8de4a6b4021004fc7 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Mon, 13 Mar 2023 16:16:53 -0400 Subject: [PATCH] Python: added Atmosphere function. --- demo/python/astronomy.py | 66 ++++++++++++++++++++++++++++ generate/template/astronomy.py | 66 ++++++++++++++++++++++++++++ generate/test.py | 50 +++++++++++++++++++++ source/python/README.md | 35 +++++++++++++++ source/python/astronomy/astronomy.py | 66 ++++++++++++++++++++++++++++ 5 files changed, 283 insertions(+) diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py index 9ca546f7..ab3d5451 100644 --- a/demo/python/astronomy.py +++ b/demo/python/astronomy.py @@ -5761,6 +5761,72 @@ def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter: return next_mq +class AtmosphereInfo: + """Information about idealized atmospheric variables at a given elevation. + + Attributes + ---------- + pressure : float + Atmospheric pressure in pascals. + temperature : float + Atmospheric temperature in kelvins. + density : float + Atmospheric densitive relative to sea level. + """ + def __init__(self, pressure:float, temperature:float, density:float) -> None: + self.pressure = pressure + self.temperature = temperature + self.density = density + + def __repr__(self) -> str: + return 'AtmosphereInfo({} Pa, {} K, {})'.format(self.pressure, self.temperature, self.density) + + +def Atmosphere(elevationMeters: float) -> AtmosphereInfo: + """Calculates U.S. Standard Atmosphere (1976) variables as a function of elevation. + + This function calculates idealized values of pressure, temperature, and density + using the U.S. Standard Atmosphere (1976) model. + 1. COESA, U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, DC, 1976. + 2. Jursa, A. S., Ed., Handbook of Geophysics and the Space Environment, Air Force Geophysics Laboratory, 1985. + See: + https://hbcp.chemnetbase.com/faces/documents/14_12/14_12_0001.xhtml + https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf + https://www.ngdc.noaa.gov/stp/space-weather/online-publications/miscellaneous/us-standard-atmosphere-1976/us-standard-atmosphere_st76-1562_noaa.pdf + + Parameters + ---------- + elevationMeters : float + The elevation above sea level at which to calculate atmospheric variables. + Must be in the range -500 to +100000, or an exception will occur. + + Returns + ------- + AtmosphereInfo + """ + P0 = 101325.0 # pressure at sea level [pascals] + T0 = 288.15 # temperature at sea level [kelvins] + T1 = 216.65 # temperature between 20 km and 32 km [kelvins] + + if elevationMeters < -500.0 or elevationMeters > 100000.0: + raise Error('Invalid elevationMeters value: {}'.format(elevationMeters)) + + if elevationMeters <= 11000.0: + temperature = T0 - 0.0065*elevationMeters + pressure = P0 * (T0 / temperature)**(-5.25577) + elif elevationMeters <= 20000.0: + temperature = T1 + pressure = 22632.0 * math.exp(-0.00015768832 * (elevationMeters - 11000.0)) + else: + temperature = T1 + 0.001*(elevationMeters - 20000.0) + pressure = 5474.87 * (T1 / temperature)**(34.16319) + + # The density is calculated relative to the sea level value. + # Using the ideal gas law PV=nRT, we deduce that density is proportional to P/T. + density = (pressure / temperature) / (P0 / T0) + return AtmosphereInfo(pressure, temperature, density) + + class IlluminationInfo: """Information about the brightness and illuminated shape of a celestial body. diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index 35440d1a..a511ccbf 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -4255,6 +4255,72 @@ def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter: return next_mq +class AtmosphereInfo: + """Information about idealized atmospheric variables at a given elevation. + + Attributes + ---------- + pressure : float + Atmospheric pressure in pascals. + temperature : float + Atmospheric temperature in kelvins. + density : float + Atmospheric densitive relative to sea level. + """ + def __init__(self, pressure:float, temperature:float, density:float) -> None: + self.pressure = pressure + self.temperature = temperature + self.density = density + + def __repr__(self) -> str: + return 'AtmosphereInfo({} Pa, {} K, {})'.format(self.pressure, self.temperature, self.density) + + +def Atmosphere(elevationMeters: float) -> AtmosphereInfo: + """Calculates U.S. Standard Atmosphere (1976) variables as a function of elevation. + + This function calculates idealized values of pressure, temperature, and density + using the U.S. Standard Atmosphere (1976) model. + 1. COESA, U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, DC, 1976. + 2. Jursa, A. S., Ed., Handbook of Geophysics and the Space Environment, Air Force Geophysics Laboratory, 1985. + See: + https://hbcp.chemnetbase.com/faces/documents/14_12/14_12_0001.xhtml + https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf + https://www.ngdc.noaa.gov/stp/space-weather/online-publications/miscellaneous/us-standard-atmosphere-1976/us-standard-atmosphere_st76-1562_noaa.pdf + + Parameters + ---------- + elevationMeters : float + The elevation above sea level at which to calculate atmospheric variables. + Must be in the range -500 to +100000, or an exception will occur. + + Returns + ------- + AtmosphereInfo + """ + P0 = 101325.0 # pressure at sea level [pascals] + T0 = 288.15 # temperature at sea level [kelvins] + T1 = 216.65 # temperature between 20 km and 32 km [kelvins] + + if elevationMeters < -500.0 or elevationMeters > 100000.0: + raise Error('Invalid elevationMeters value: {}'.format(elevationMeters)) + + if elevationMeters <= 11000.0: + temperature = T0 - 0.0065*elevationMeters + pressure = P0 * (T0 / temperature)**(-5.25577) + elif elevationMeters <= 20000.0: + temperature = T1 + pressure = 22632.0 * math.exp(-0.00015768832 * (elevationMeters - 11000.0)) + else: + temperature = T1 + 0.001*(elevationMeters - 20000.0) + pressure = 5474.87 * (T1 / temperature)**(34.16319) + + # The density is calculated relative to the sea level value. + # Using the ideal gas law PV=nRT, we deduce that density is proportional to P/T. + density = (pressure / temperature) / (P0 / T0) + return AtmosphereInfo(pressure, temperature, density) + + class IlluminationInfo: """Information about the brightness and illuminated shape of a celestial body. diff --git a/generate/test.py b/generate/test.py index db416314..5ff16208 100755 --- a/generate/test.py +++ b/generate/test.py @@ -3215,8 +3215,58 @@ def HourAngle(): #----------------------------------------------------------------------------------------------------------- +def Atmosphere(): + filename = 'riseset/atmosphere.csv' + maxdiff = 0.0 + ncases = 0 + tolerance = 8.8e-11 + with open(filename, 'rt') as infile: + lnum = 0 + for line in infile: + line = line.strip() + lnum += 1 + if lnum == 1: + if line != 'elevation,temperature,pressure,density,relative_density': + return Fail('Atmosphere', 'Expected header line but found [{}]'.format(line)) + else: + tokens = line.split(',') + if len(tokens) != 5: + return Fail('Atmosphere({} line {})'.format(filename, lnum), 'expected 5 numeric tokens but found {}'.format(len(tokens))) + elevation = v(float(tokens[0])) + temperature = v(float(tokens[1])) + pressure = v(float(tokens[2])) + # ignore tokens[3] = absolute_density + relative_density = v(float(tokens[4])) + + atmos = astronomy.Atmosphere(elevation) + + diff = vabs(atmos.temperature - temperature) + maxdiff = max(maxdiff, diff) + if diff > tolerance: + return Fail('Atmosphere', 'EXCESSIVE temperature difference = {}'.format(diff)) + + diff = vabs(atmos.pressure - pressure) + maxdiff = max(maxdiff, diff) + if diff > tolerance: + return Fail('Atmosphere', 'EXCESSIVE pressure difference = {}'.format(diff)) + + diff = vabs(atmos.density - relative_density) + maxdiff = max(maxdiff, diff) + if diff > tolerance: + return Fail('Atmosphere', 'EXCESSIVE density difference = {}'.format(diff)) + + ncases += 1 + + if ncases != 34: + return Fail('Atmosphere', 'expected 34 cases but found {}'.format(ncases)) + + return Pass('Atmosphere') + +#----------------------------------------------------------------------------------------------------------- + UnitTests = { 'aberration': Aberration, + 'atmosphere': Atmosphere, 'axis': Axis, 'barystate': BaryState, 'constellation': Constellation, diff --git a/source/python/README.md b/source/python/README.md index 73011fc2..26d49857 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -302,6 +302,19 @@ to iterate through consecutive alternating perigees and apogees. --- + +### class AtmosphereInfo + +**Information about idealized atmospheric variables at a given elevation.** + +| Type | Attribute | Description | +| --- | --- | --- | +| `float` | `pressure` | Atmospheric pressure in pascals. | +| `float` | `temperature` | Atmospheric temperature in kelvins. | +| `float` | `density` | Atmospheric densitive relative to sea level. | + +--- + ### class AxisInfo @@ -1317,6 +1330,28 @@ and the specified body as seen from the center of the Earth. --- + +### Atmosphere(elevationMeters: float) → [`AtmosphereInfo`](#AtmosphereInfo) + +**Calculates U.S. Standard Atmosphere (1976) variables as a function of elevation.** + +This function calculates idealized values of pressure, temperature, and density +using the U.S. Standard Atmosphere (1976) model. +1. COESA, U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, DC, 1976. +2. Jursa, A. S., Ed., Handbook of Geophysics and the Space Environment, Air Force Geophysics Laboratory, 1985. +See: +https://hbcp.chemnetbase.com/faces/documents/14_12/14_12_0001.xhtml +https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf +https://www.ngdc.noaa.gov/stp/space-weather/online-publications/miscellaneous/us-standard-atmosphere-1976/us-standard-atmosphere_st76-1562_noaa.pdf + +| Type | Parameter | Description | +| --- | --- | --- | +| `float` | `elevationMeters` | The elevation above sea level at which to calculate atmospheric variables. Must be in the range -500 to +100000, or an exception will occur. | + +**Returns**: [`AtmosphereInfo`](#AtmosphereInfo) + +--- + ### BackdatePosition(time: [`Time`](#Time), observerBody: [`Body`](#Body), targetBody: [`Body`](#Body), aberration: bool) → [`Vector`](#Vector) diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py index 9ca546f7..ab3d5451 100644 --- a/source/python/astronomy/astronomy.py +++ b/source/python/astronomy/astronomy.py @@ -5761,6 +5761,72 @@ def NextMoonQuarter(mq: MoonQuarter) -> MoonQuarter: return next_mq +class AtmosphereInfo: + """Information about idealized atmospheric variables at a given elevation. + + Attributes + ---------- + pressure : float + Atmospheric pressure in pascals. + temperature : float + Atmospheric temperature in kelvins. + density : float + Atmospheric densitive relative to sea level. + """ + def __init__(self, pressure:float, temperature:float, density:float) -> None: + self.pressure = pressure + self.temperature = temperature + self.density = density + + def __repr__(self) -> str: + return 'AtmosphereInfo({} Pa, {} K, {})'.format(self.pressure, self.temperature, self.density) + + +def Atmosphere(elevationMeters: float) -> AtmosphereInfo: + """Calculates U.S. Standard Atmosphere (1976) variables as a function of elevation. + + This function calculates idealized values of pressure, temperature, and density + using the U.S. Standard Atmosphere (1976) model. + 1. COESA, U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, DC, 1976. + 2. Jursa, A. S., Ed., Handbook of Geophysics and the Space Environment, Air Force Geophysics Laboratory, 1985. + See: + https://hbcp.chemnetbase.com/faces/documents/14_12/14_12_0001.xhtml + https://ntrs.nasa.gov/api/citations/19770009539/downloads/19770009539.pdf + https://www.ngdc.noaa.gov/stp/space-weather/online-publications/miscellaneous/us-standard-atmosphere-1976/us-standard-atmosphere_st76-1562_noaa.pdf + + Parameters + ---------- + elevationMeters : float + The elevation above sea level at which to calculate atmospheric variables. + Must be in the range -500 to +100000, or an exception will occur. + + Returns + ------- + AtmosphereInfo + """ + P0 = 101325.0 # pressure at sea level [pascals] + T0 = 288.15 # temperature at sea level [kelvins] + T1 = 216.65 # temperature between 20 km and 32 km [kelvins] + + if elevationMeters < -500.0 or elevationMeters > 100000.0: + raise Error('Invalid elevationMeters value: {}'.format(elevationMeters)) + + if elevationMeters <= 11000.0: + temperature = T0 - 0.0065*elevationMeters + pressure = P0 * (T0 / temperature)**(-5.25577) + elif elevationMeters <= 20000.0: + temperature = T1 + pressure = 22632.0 * math.exp(-0.00015768832 * (elevationMeters - 11000.0)) + else: + temperature = T1 + 0.001*(elevationMeters - 20000.0) + pressure = 5474.87 * (T1 / temperature)**(34.16319) + + # The density is calculated relative to the sea level value. + # Using the ideal gas law PV=nRT, we deduce that density is proportional to P/T. + density = (pressure / temperature) / (P0 / T0) + return AtmosphereInfo(pressure, temperature, density) + + class IlluminationInfo: """Information about the brightness and illuminated shape of a celestial body.