Source code for taurex.data.profiles.pressure.pressureprofile

"""Base and Concrete pressure profiles."""

import math
import typing as t

import numpy as np
import numpy.typing as npt

from taurex.data.citation import Citable
from taurex.data.fittable import Fittable
from taurex.data.fittable import fitparam
from taurex.log import Logger
from taurex.output import OutputGroup
from taurex.output.writeable import Writeable


[docs] class PressureProfile(Fittable, Logger, Writeable, Citable): """Base pressure class. *Abstract Class* Simple. Defines the layering of the atmosphere. Only requires implementation of: - :func:`compute_pressure_profile` - :func:`profile` """ def __init__(self, name: str, nlayers: int) -> None: """Initialize pressure profile. Parameters ---------- name: str Name used in logging nlayers: int Number of layers in atmosphere """ Fittable.__init__(self) Logger.__init__(self, name) self.pressure_profile_levels: npt.NDArray[np.float64] = None if nlayers <= 0: self.error("Number of layers: [%s] should be greater than 0", nlayers) raise ValueError("Number of layers should be at least 1") self._nlayers = int(nlayers) @property def nLayers(self) -> int: # noqa: N802 """Number of central layers. Returns ------- int """ return self._nlayers @property def nLevels(self) -> int: # noqa: N802 """Number of levels (interface between layers).""" return self.nLayers + 1
[docs] def compute_pressure_profile(self) -> None: """Compute pressure profile in Pa. **Requires implementation** Compute pressure profile and generate pressure array in Pa Returns ------- pressure_profile: :obj:`array` Pressure profile array in Pa """ raise NotImplementedError
@property def profile(self) -> npt.NDArray[np.float64]: """Pressure at each atmospheric layer (Pascal). Returns ------- pressure_profile : :obj:`array` Pressure profile array in Pa """ raise NotImplementedError
[docs] def write(self, output: OutputGroup) -> OutputGroup: """Write pressure profile to output. Parameters ---------- output : :class:`~taurex.output.output.OutputGroup` Output group to write to. Returns ------- :class:`~taurex.output.output.OutputGroup` """ pressure = output.create_group("Pressure") pressure.write_string("pressure_type", self.__class__.__name__) pressure.write_scalar("nlayers", self._nlayers) pressure.write_array("profile", self.profile) return pressure
[docs] @classmethod def input_keywords(cls) -> t.Tuple[str, ...]: """Input keywords for pressure profile.""" raise NotImplementedError
[docs] class SimplePressureProfile(PressureProfile): """A basic pressure profile. .. deprecated:: Use :class:`LogPressureProfile` instead in new code. """ WARN = True def __init__( self, nlayers: t.Optional[int] = 100, atm_min_pressure: t.Optional[float] = 1e-4, atm_max_pressure: t.Optional[float] = 1e6, ): """Initialize pressure profile. Parameters ---------- nlayers : int Number of layers in atmosphere atm_min_pressure : float minimum pressure in Pascal (top of atmosphere) atm_max_pressure : float maximum pressure in Pascal (surface of planet) """ from warnings import warn super().__init__("pressure_profile", nlayers) self.pressure_profile = None if self.WARN: warn( "SimplePressureProfile is deprecated. " "Use LogPressureProfile instead", DeprecationWarning, ) if atm_max_pressure <= atm_min_pressure: self.error( "Max pressure %1.2e should be greater " "than min pressure %1.2e", atm_max_pressure, atm_min_pressure, ) raise ValueError("Max pressure is less than minimum pressure") self._atm_min_pressure = atm_min_pressure self._atm_max_pressure = atm_max_pressure
[docs] def compute_pressure_profile(self) -> None: """Set up the pressure profile for the atmosphere model.""" self.pressure_profile_levels = np.logspace( math.log10(self._atm_min_pressure), math.log10(self._atm_max_pressure), self.nLevels, )[::-1] self.pressure_profile = self.pressure_profile_levels[:-1] * np.sqrt( self.pressure_profile_levels[1:] / self.pressure_profile_levels[:-1] )
@fitparam( param_name="atm_min_pressure", param_latex=r"$P_\mathrm{min}$", default_mode="log", default_fit=False, default_bounds=[0.1, 1.0], ) def minAtmospherePressure(self) -> float: # noqa: N802 """Minimum pressure of atmosphere (top layer) in Pascal.""" return self._atm_min_pressure @minAtmospherePressure.setter def minAtmospherePressure(self, value: float) -> None: # noqa: N802 """Set the minimum pressure of atmosphere (top layer) in Pascal. Parameters ---------- value : float Minimum pressure in Pascal. """ self._atm_min_pressure = value @fitparam( param_name="atm_max_pressure", param_latex=r"$P_\mathrm{max}$", default_mode="log", default_fit=False, default_bounds=[0.1, 1.0], ) def maxAtmospherePressure(self) -> float: # noqa: N802 """Maximum pressure of atmosphere (surface) in Pascal.""" return self._atm_max_pressure @maxAtmospherePressure.setter def maxAtmospherePressure(self, value: float): # noqa: N802 """Set the maximum pressure of the atmosphere (surface) in Pascal. Parameters ---------- value : float Maximum pressure in Pascal. """ self._atm_max_pressure = value @property def profile(self) -> npt.NDArray[np.float64]: """Pressure at each atmospheric layer (Pascal).""" return self.pressure_profile
[docs] def write(self, output: OutputGroup) -> OutputGroup: """Write pressure profile to output. Parameters ---------- output : :class:`~taurex.output.output.OutputGroup` Output group to write to. Returns ------- :class:`~taurex.output.output.OutputGroup` """ pressure = super().write(output) pressure.write_scalar("atm_max_pressure", self._atm_max_pressure) pressure.write_scalar("atm_min_pressure", self._atm_min_pressure) return pressure
[docs] @classmethod def input_keywords(cls) -> t.Tuple[str, ...]: """Input keywords for this pressure profile.""" return ( "simple", "hydrostatic", "logpressure", )
class LogPressureProfile(SimplePressureProfile): """A pressure profile built from a logspace.""" WARN = False pass