API Reference

Package Interface

pyRadtran — A complete Python wrapper for libRadtran radiative transfer.

class pyradtran.AerosolBlock(*args, **kwargs)[source]

Bases: Protocol

A mass-normalized aerosol species that can report its intensive optics.

intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]
property mass_per_particle_kg: float
name: str
class pyradtran.AerosolModel(*, modify: list[AerosolModifyEntry] = <factory>)[source]

Bases: UvspecOption

Abstract base class for all aerosol configurations.

Subclasses implement mode-specific to_uvspec_lines(). The common modify capability is handled here.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

modify: list[AerosolModifyEntry]
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

abstractmethod to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

class pyradtran.AerosolModifyEntry(*, variable: str, action: str, value: float)[source]

Bases: UvspecOption

A single aerosol_modify directive.

variable

Property to modify (gg, ssa, tau, tau550).

Type:

str

action

How to modify (scale or set).

Type:

str

value

Numeric value.

Type:

float

action: str
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

validate_entry() AerosolModifyEntry[source]
value: float
variable: str
class pyradtran.AttributionResult(full: Dataset, contributions: dict[str, Dataset])[source]

Bases: object

Full-field run plus per-block contribution datasets.

contributions: dict[str, Dataset]
full: Dataset
class pyradtran.BudgetResult(transmittance: ndarray, reflectance: ndarray, absorptance: ndarray, wavelength: ndarray)[source]

Bases: object

Spectral transmittance / reflectance / absorptance of the column.

absorptance: ndarray
reflectance: ndarray
transmittance: ndarray
wavelength: ndarray
class pyradtran.BulkSpecies(*, bulk: Any, name: str = 'BulkSpecies')[source]

Bases: BaseModel

Species backed by an aerosol3D BulkAerosolOpticsData.

The size-distribution integration is already done in aerosol3D; this class only rescales cross-sections to per-mass, resamples wavelength, and selects the Legendre convention. Duck-typed: accepts any object exposing the BulkAerosolOpticsData attributes (no hard aerosol3D import).

bulk: Any
intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]
property mass_per_particle_kg: float

Volume-weighted per-particle mass from the bulk size distribution.

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
class pyradtran.CompositeAerosol(*, modify: list[~pyradtran.models.aerosol.AerosolModifyEntry] = <factory>, pieces: ~typing.Annotated[list, ~annotated_types.MinLen(min_length=1)], wavelength_grid_um: ~typing.Annotated[list[float], ~annotated_types.MinLen(min_length=1)], altitude_grid_km: ~typing.Annotated[list[float], ~annotated_types.MinLen(min_length=2)], n_legendre: int = 32, output_dir: ~pathlib.Path | None = None)[source]

Bases: AerosolModel

Externally mix any number of Piece blocks via a single explicit-file path.

Each item in pieces is a Piece (e.g. PlacedBlock or DirectLayerOpticsBlock). They are combined with scattering-optical-depth weighting and written as one explicit .master/.LAYER set. The old mutual-exclusion rules and the single-source shortcut are gone: one path regardless of piece count or type.

altitude_grid_km: list[float]
evaluate(wl_um=None, z_km=None, n_legendre=None) LayerOptics[source]

Return the mixed (externally combined) LayerOptics without writing files.

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
output_dir: Path | None
pieces: list
to_uvspec_lines() list[str][source]

Single execution path: every Piece -> LayerOptics -> combine -> explicit file.

validate_grids() CompositeAerosol[source]
wavelength_grid_um: list[float]
class pyradtran.DataResolver(*, data_root: str | PathLike | None = None, bundled_only: bool = False)[source]

Bases: object

Resolve logical data references to absolute paths under the data root.

property data_root: Path

The effective data_files_path used for this resolver.

is_available(category: str, name: str) bool[source]

True if the asset is present on disk.

Unknown (category, name) – not in the bundled manifest – are treated as permissively available (assumed resolvable via an external data root).

list_bundled(category: str | None = None) list[Asset][source]

List bundled assets, optionally filtered by category.

resolve(category: str, name: str) Path[source]

Return the absolute path of an asset’s first file.

Raises FileNotFoundError if the (category, name) is unknown to the bundled manifest or its file is missing on disk.

validate_scene(scene) list[ValidationIssue][source]

Check high-value data references in a Scene against available data.

Returns a list of ValidationIssue for references whose bundled-asset files are missing under the current data root. References absent from the bundled manifest are treated as permissively available (externally).

First batch covers: atmosphere profile, solar_flux_file, mol_abs_param, and OPAC aerosol library.

class pyradtran.DirectLayerOpticsBlock(master_path: str, name: str = 'explicit_file')[source]

Bases: object

Direct-route piece: a pre-computed explicit aerosol file set (.master + .LAYER).

The file already contains per-layer tau/ssa/pmom, so no VerticalProfile is needed — to_layer_optics parses the file directly. Wavelength resampling is not performed (v1): the requested grid must match the file’s grid.

master_path: str
name: str = 'explicit_file'
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.ExponentialProfile(rho0_kg_m3: float, scale_height_km: float)[source]

Bases: object

rho(z) = rho0 * exp(-z / H), evaluated at the requested altitudes (km).

evaluate(altitude_km) ndarray[source]
rho0_kg_m3: float
scale_height_km: float
class pyradtran.IntegrationConfig(*, n_radius_grid: int = 200, radius_min_um: float = 0.001, radius_max_um: float = 100.0)[source]

Bases: BaseModel

Configuration for size-distribution numerical integration.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_radius_grid: int
radius_max_um: float
radius_min_um: float
class pyradtran.LayerOptics(tau: ndarray[tuple[Any, ...], dtype[_ScalarT]], ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]], g: ndarray[tuple[Any, ...], dtype[_ScalarT]], legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]])[source]

Bases: object

Extensive optical properties per layer.

g: ndarray[tuple[Any, ...], dtype[_ScalarT]]
legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]]
tau: ndarray[tuple[Any, ...], dtype[_ScalarT]]
class pyradtran.MassProfile(kg_m3_per_layer: tuple[float, ...])[source]

Bases: object

Explicit per-layer mass concentration (kg/m^3).

Values are stored in descending-altitude layer order (matching the altitude_grid_km convention used by CompositeAerosol). evaluate returns them verbatim; the altitude argument is accepted only for interface compatibility with ExponentialProfile.

evaluate(altitude_km) ndarray[source]
kg_m3_per_layer: tuple[float, ...]
class pyradtran.MieSpecies(*, refractive_index: ~pyradtran.models.aerosol_composite.RefractiveIndex, size_distribution: ~pyradtran.models.aerosol_composite.SizeDistribution, particle_density_kg_m3: ~typing.Annotated[float, ~annotated_types.Gt(gt=0)], integration_config: ~pyradtran.models.aerosol_composite.IntegrationConfig = <factory>, phase_function: ~typing.Literal['hg', 'mie'] = 'hg', name: str = 'MieSpecies')[source]

Bases: BaseModel

Mie-computed species from refractive index + size distribution.

integration_config: IntegrationConfig
intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]

Compute mass-normalized intensive optical properties.

Parameters:
  • wl_um – Wavelengths in micrometers.

  • n_legendre – Number of Legendre moments to generate. When phase_function='mie', moments are projected from the real Mie phase function (S1/S2 -> Legendre); the default 'hg' derives them from the Henyey-Greenstein approximation g**l.

Returns:

SpeciesOptics with beta_ext_per_mass, ssa, g, and legendre_moments.

property mass_per_particle_kg: float

Average particle mass = density * mean volume over the size distribution.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
particle_density_kg_m3: float
phase_function: Literal['hg', 'mie']
refractive_index: RefractiveIndex
size_distribution: SizeDistribution
class pyradtran.OpacCustom(*, species_file: Annotated[str, MinLen(min_length=1)], rh_pct: float = 50.0, species_names: list[str] | None = None, data_path: str | None = None, n_legendre: int = 32)[source]

Bases: BaseModel

Factory: fold a user OPAC species profile file into PlacedBlock pieces.

Like OpacPreset but the mass-concentration profile is a user-supplied ASCII file (same format as standard_aerosol_files).

data_path: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
rh_pct: float
species_file: str
species_names: list[str] | None
to_composite(wavelength_grid_um, output_dir=None)[source]

Wrap to_placed_blocks() in a CompositeAerosol on the profile grid.

to_placed_blocks() list[source]

Return one PlacedBlock per profile species with nonzero mass.

validate_species() OpacCustom[source]
class pyradtran.OpacPreset(*, name: OpacPresetName, rh_pct: float = 50.0, species_names: list[str] | None = None, data_path: str | None = None, n_legendre: int = 32)[source]

Bases: BaseModel

Factory: fold an OPAC preset mixture into LEGO PlacedBlock pieces.

Each species with nonzero mass in the preset profile becomes one MieSpecies (OPAC refractive index + OPAC lognormal at rh_pct) using the real Mie phase function, placed via its preset mass column. The pieces drop into CompositeAerosol(pieces=...) – the same path as bulk/Mie blocks. No precomputed OPAC tables are read; libRadtran ships only the ingredients (refractive index, size distribution, mass profile).

data_path: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
name: OpacPresetName
rh_pct: float
species_names: list[str] | None
to_composite(wavelength_grid_um, output_dir=None)[source]

Wrap to_placed_blocks() in a CompositeAerosol on the preset grid.

to_placed_blocks() list[source]

Return one PlacedBlock per preset species with nonzero mass.

validate_species() OpacPreset[source]
class pyradtran.OpacPresetName(value)[source]

Bases: StrEnum

OPAC preset mixture profile names.

These correspond to files in data/aerosol/OPAC/standard_aerosol_files/.

ANTARCTIC = 'antarctic'
CONTINENTAL_AVERAGE = 'continental_average'
CONTINENTAL_CLEAN = 'continental_clean'
CONTINENTAL_POLLUTED = 'continental_polluted'
DESERT = 'desert'
DESERT_SPHEROIDS = 'desert_spheroids'
MARITIME_CLEAN = 'maritime_clean'
MARITIME_POLLUTED = 'maritime_polluted'
MARITIME_TROPICAL = 'maritime_tropical'
URBAN = 'urban'
class pyradtran.Piece(*args, **kwargs)[source]

Bases: Protocol

The mixing contract: anything CompositeAerosol accepts produces per-layer LayerOptics on the shared (wavelength, altitude) grid.

name: str
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.PlacedBlock(block: AerosolBlock, profile: VerticalProfile, modify: tuple[AerosolModifyEntry, ...] = ())[source]

Bases: object

Intensity-route piece: a mass-normalized species placed in the column.

Ports the non-OPAC path of LoadedSpecies.evaluate: the block’s intensive optics are weighted by the profile’s per-layer mass and the layer thickness to give extensive per-layer optical properties.

block: AerosolBlock
modify: tuple[AerosolModifyEntry, ...] = ()
property name: str
profile: VerticalProfile
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.RefractiveIndex(*, wavelength_um: Annotated[list[float], MinLen(min_length=2)], n_real: list[float], k_imag: Annotated[list[float], MinLen(min_length=1)])[source]

Bases: BaseModel

Wavelength-dependent complex refractive index.

Interpolation is log-linear in wavelength.

at(wl_um: ndarray) ndarray[source]

Interpolate refractive index to requested wavelengths.

k_imag: list[float]
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_real: list[float]
validate_lengths_and_sorted() RefractiveIndex[source]
wavelength_um: list[float]
class pyradtran.Runner[source]

Bases: object

Execute uvspec simulations.

Usage:

result = Runner.execute(scene, data_path="/path/to/data")
results = Runner.execute_many(scenes, max_workers=4)

Global defaults may be set once via configure() so that uvspec_exe and data_path do not need to be repeated on every call:

Runner.configure(uvspec_exe="/opt/libRadtran/bin/uvspec",
                 data_path="/opt/libRadtran/data")
result = Runner.execute(scene)
classmethod configure(config: RunnerConfig | None = None, **kwargs) RunnerConfig[source]

Set global default configuration for all Runner executions.

Parameters:
  • config – A complete RunnerConfig instance, or None.

  • **kwargs – Individual fields (e.g. uvspec_exe=..., data_path=...).

Returns:

The newly set configuration.

static execute(scene: Scene, uvspec_exe: str | None = None, data_path: str | None = None, keep_temp: bool | None = None, timeout: int | None = None, strict: bool | None = None, config: RunnerConfig | None = None) xr.Dataset[source]

Execute a single uvspec simulation.

Parameters:
  • scene – Configured Scene object.

  • uvspec_exe – Path to uvspec binary. Auto-detected if None.

  • data_path – Path to libRadtran data directory. Auto-detected if None.

  • keep_temp – Keep temporary files after execution.

  • timeout – Maximum execution time in seconds.

  • strict – If True, raise on missing data references; if None, defaults to bundled_only (warnings only otherwise).

  • config – Optional RunnerConfig overriding global defaults for this call only.

Returns:

xarray.Dataset with simulation results.

static execute_many(scenes: list[Scene], uvspec_exe: str | None = None, data_path: str | None = None, max_workers: int | None = None, keep_temp: bool | None = None, timeout: int | None = None, config: RunnerConfig | None = None) list[xr.Dataset][source]

Execute multiple uvspec simulations in parallel.

Parameters:
  • scenes – List of configured Scene objects.

  • uvspec_exe – Path to uvspec binary. Auto-detected if None.

  • data_path – Path to libRadtran data directory. Auto-detected if None.

  • max_workers – Maximum parallel workers.

  • keep_temp – Keep temporary files after execution.

  • timeout – Maximum execution time in seconds per scene.

  • config – Optional RunnerConfig overriding global defaults.

Returns:

List of xarray.Dataset results, one per scene.

class pyradtran.RunnerConfig(uvspec_exe: str | None = None, data_path: str | None = None, max_workers: int = 4, keep_temp: bool = False, timeout: int | None = None, bundled_only: bool = False)[source]

Bases: object

Configuration for uvspec execution.

uvspec_exe

Path to uvspec binary. Auto-detected via PATH if None.

Type:

str | None

data_path

Path to libRadtran data directory. Uses env vars if None.

Type:

str | None

max_workers

Maximum parallel workers for execute_many().

Type:

int

keep_temp

Keep temporary files after execution (for debugging).

Type:

bool

timeout

Maximum uvspec execution time in seconds. None = no timeout.

Type:

int | None

bundled_only

Force use of the bundled data subset, ignoring env vars and explicit data_path. For reproducible runs / CI.

Type:

bool

bundled_only: bool = False
data_path: str | None = None
keep_temp: bool = False
max_workers: int = 4
timeout: int | None = None
uvspec_exe: str | None = None
class pyradtran.Scene(atmosphere: AtmosphereConfig | None = None, source: SourceConfig | None = None, wavelength: WavelengthConfig | None = None, solver: SolverConfig | None = None, output: OutputConfig | None = None, surface: SurfaceConfig | None = None, aerosol: AerosolModel | None = None, cloud: CloudConfig | None = None, mc: McConfig | None = None, sslidar: SslidarConfig | None = None, advanced: AdvancedConfig | None = None, three_d: ThreeDConfig | None = None, special: SpecialConfig | None = None, raw_keywords: list[tuple[str, str]] | None = None)[source]

Bases: object

Immutable scene builder composing all uvspec configuration models.

Each set_*() method returns a new Scene via deepcopy. Use .clone() for an explicit copy.

Usage:

scene = (
    Scene()
    .set_atmosphere(profile="us", altitude=2.663)
    .set_source_solar(sza=30.0)
    .set_wavelength(250.0, 1200.0)
    .set_solver(method="disort", streams=16)
    .set_output(quantities=["lambda", "edir"])
)
add_raw_keyword(key: str, value: str = '') Scene[source]
build_input(data_files_path: str | None = None) str[source]

Build complete uvspec input text from this Scene.

Raises:

ValueError – If required components are missing.

clone() Scene[source]

Create a deep copy of this Scene.

set_advanced(**kwargs) Scene[source]
set_aerosol(aerosol: AerosolModel) Scene[source]

Set aerosol configuration from an AerosolModel instance.

set_aerosol_modify(variable: str, action: str, value: float) Scene[source]

Add an aerosol modification directive.

Parameters:
  • variable – Property to modify (gg, ssa, tau, tau550).

  • action – Modification type (scale or set).

  • value – Numeric value.

set_atmosphere(**kwargs) Scene[source]
set_cloud(**kwargs) Scene[source]
set_dynamic(method: str = 'dynamic_tenstream', iterations: int | None = None, **kwargs) Scene[source]
set_mc(**kwargs) Scene[source]
set_mol_modify(species: str, value: float, unit: str) Scene[source]
set_output(**kwargs) Scene[source]
set_satellite(geometry: str | None = None, pixel: tuple[int, int] | None = None, **source_kwargs) Scene[source]
set_solver(method: str = 'disort', streams: int = 16, **kwargs) Scene[source]
set_source_solar(sza: float, **kwargs) Scene[source]
set_source_thermal(**kwargs) Scene[source]
set_special(**kwargs) Scene[source]
set_sslidar(**kwargs) Scene[source]
set_surface(**kwargs) Scene[source]
set_three_d(**kwargs) Scene[source]
set_wavelength(wl_min: float, wl_max: float | None = None, **kwargs) Scene[source]
class pyradtran.SizeDistribution(*, kind: Literal['lognormal', 'modified_gamma', 'discrete', 'monodisperse'], params: dict, number_density_per_m3: float = 1.0)[source]

Bases: BaseModel

Aerosol particle size distribution.

evaluate(r_grid_um: ndarray) ndarray[source]
kind: Literal['lognormal', 'modified_gamma', 'discrete', 'monodisperse']
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

number_density_per_m3: float
params: dict
validate_params() SizeDistribution[source]
class pyradtran.SpeciesOptics(beta_ext_per_mass: ndarray[tuple[Any, ...], dtype[_ScalarT]], ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]], g: ndarray[tuple[Any, ...], dtype[_ScalarT]], legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None)[source]

Bases: object

Mass-normalized intensive optical properties of an aerosol species.

beta_ext_per_mass: ndarray[tuple[Any, ...], dtype[_ScalarT]]
g: ndarray[tuple[Any, ...], dtype[_ScalarT]]
legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None
ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]]
class pyradtran.TabulatedProfile(z_km: tuple[float, ...], kg_m3: tuple[float, ...])[source]

Bases: object

Mass concentration (kg/m^3) tabulated vs altitude (km).

Linear interpolation in altitude; outside [z_min, z_max] the value is clipped to the nearest table entry. z_km may be ascending or descending. Used to place OPAC preset mass columns, which come on the preset’s own grid.

evaluate(altitude_km) ndarray[source]
kg_m3: tuple[float, ...]
z_km: tuple[float, ...]
class pyradtran.ThreeDConfig(*, atmosphere_file: str | None = None)[source]

Bases: UvspecOption

3D atmospheric field configuration.

Configures 3D atmospheric input fields for MYSTIC and dynamic tenstream solvers.

atmosphere_file

Path to 3D atmospheric field NetCDF file.

Type:

str | None

Note

3D cloud fields are specified through CloudConfig: scene.set_cloud(wc_file=(“3D”, “/path/to/cloud3d.nc”)) or scene.set_cloud(ic_file=(“3D”, “/path/to/ic3d.nc”)).

The ipa (independent pixel approximation) for 3D is enabled via McConfig.ipa=True or McConfig.tipa=”dir”/”dir3d”.

atmosphere_file: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

class pyradtran.VerticalProfile(*args, **kwargs)[source]

Bases: Protocol

Column placement: returns mass concentration (kg/m^3) at each altitude.

evaluate(altitude_km) ndarray[source]
pyradtran.add_budget_vars(ds: Dataset, *, f_incident: str = 'edir') Dataset[source]

Return a copy of ds with transmittance/reflectance/absorptance.

Conventions: T = (edir+edn)@surface / f_incident@TOA, R = eup@TOA / f_incident@TOA, A = 1 - T - R. Surface = lowest zout level, TOA = highest zout level.

pyradtran.compute_budget(ds: Dataset, *, f_incident: str = 'edir') BudgetResult[source]

Typed companion to add_budget_vars() returning a BudgetResult.

pyradtran.compute_component_attribution(build_scene: Callable, composite, execute_many: Callable[[list], list[Dataset]]) AttributionResult[source]

Compute per-block RT contributions by leave-one-out subtraction.

Parameters:
  • build_scene – Callable mapping a (possibly leave-one-out) composite to a runnable Scene.

  • composite – A composite with .pieces and .model_copy(update=...).

  • execute_many – Callable running a list of scenes in parallel and returning the parsed datasets in the same order (e.g. lambda scenes: Runner.execute_many(scenes, uvspec_exe=..., data_path=...)).

Returns:

AttributionResult whose contributions[piece.name] is full - leave_piece_out.

pyradtran.evaluate_blocks_on_grid(comp, wl_um, z_km, n_legendre: int = 32) dict[str, Dataset][source]

Per-piece (tau, rho) on the grid; one dataset per block name.

tau comes from each piece’s to_layer_optics; rho_kg_m3 is added only for pieces that carry a profile (e.g. PlacedBlock).

pyradtran.evaluate_composite_on_grid(comp, wl_um, z_km, n_legendre: int = 32) Dataset[source]

Evaluate the mixed composite optics on a (wavelength, layer) grid.

Calls comp.evaluate(...) (pure analytic mixing — no RT) and wraps the resulting LayerOptics as an xarray.Dataset with a layer dimension indexed by layer-center altitude.

pyradtran.od_to_mass_profile(block: AerosolBlock, tau_ref: float, ref_nm: float, altitude_km, scale_height_km: float) MassProfile[source]

Invert a target column optical depth into an exponential MassProfile.

The returned per-layer masses are chosen so that, evaluated on altitude_km with the block’s beta_ext_per_mass at ref_nm, they sum to exactly tau_ref:

tau_ref = beta_ext_per_mass(ref) * sum_layers( rho_layer * dz )

This is the discrete, grid-exact inversion (the column OD the RT solver will actually see), replacing the example-side compute_mass_profile glue.

Parameters:
  • block – An AerosolBlock with a positive beta_ext_per_mass at ref.

  • tau_ref – Target column optical depth at ref_nm (dimensionless).

  • ref_nm – Reference wavelength in nm.

  • altitude_km – Layer-boundary altitudes in km, strictly descending.

  • scale_height_km – Exponential scale height H (km).

Returns:

A MassProfile whose layers follow the exponential shape and whose column OD equals tau_ref.

pyradtran.run_3d(atmosphere_file: str | None = None, profile: str = 'us', altitude: float = 0.0, sza: float = 30.0, wl_min: float = 300.0, wl_max: float = 2500.0, photons: int = 100000, ipa: bool = False, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run 3D Monte Carlo radiative transfer simulation.

Parameters:
  • atmosphere_file – Path to 3D atmospheric field file.

  • profile – Standard atmosphere profile (for 1D fallback).

  • altitude – Surface altitude in km.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • photons – Number of Monte Carlo photons.

  • ipa – Use independent pixel approximation.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with 3D radiative transfer results.

pyradtran.run_cloudy_scene(ic_properties: str = 'fu', ic_tau: float | None = None, ic_habit: str | None = None, wc_properties: str | None = None, wc_tau: float | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with cloud layer.

Parameters:
  • ic_properties – Ice cloud parameterization (fu, yang, key, baum, etc.).

  • ic_tau – Ice cloud optical thickness (set via ic_modify).

  • ic_habit – Ice crystal habit type.

  • wc_properties – Water cloud parameterization (hu, echam4).

  • wc_tau – Water cloud optical thickness.

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

pyradtran.run_lidar(area: float = 1.0, E0: float = 0.1, efficiency: float = 0.5, position: float = 0.0, range_bin: float = 0.1, n_ranges: int = 100, profile: str = 'us', altitude: float = 0.0, wl_min: float = 300.0, wl_max: float = 1100.0, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run single scattering lidar simulation.

Parameters:
  • area – Telescope area in m^2.

  • E0 – Pulse energy in Joules.

  • efficiency – Detector efficiency.

  • position – Lidar position in km.

  • range_bin – Range bin width in km.

  • n_ranges – Number of range bins.

  • profile – Atmospheric profile.

  • altitude – Surface altitude in km.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with lidar signal vs range.

pyradtran.run_polarized(profile: str = 'us', altitude: float = 0.0, sza: float = 30.0, wl_min: float = 250.0, wl_max: float = 1200.0, photons: int = 100000, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None, output_dir: str | None = None) Dataset[source]

Run polarized Monte Carlo simulation.

Parameters:
  • profile – Atmospheric profile.

  • altitude – Surface altitude in km.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • photons – Number of Monte Carlo photons.

  • streams – Number of streams (for correlated-k).

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with polarized radiance.

pyradtran.run_satellite(geometry: str = 'MPS', pixel: tuple[int, int] | None = None, profile: str = 'us', sza: float = 60.0, wl_min: float = 300.0, wl_max: float = 2500.0, solver: str = 'disort', streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run satellite-viewing radiative transfer simulation.

Parameters:
  • geometry – Satellite geometry name (e.g., MPS, SENTINEL2A).

  • pixel – Optional (x, y) pixel coordinates for satellite_geometry file.

  • profile – Standard atmosphere profile.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • solver – RTE solver name.

  • streams – Number of angular streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with satellite-view radiance/irradiance.

pyradtran.run_solar_radiance(sza: float = 30.0, airmass: float | None = None, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 250.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, solver: str = 'disort', uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate solar spectral radiance (direct + diffuse irradiance).

Parameters:
  • sza – Solar zenith angle in degrees. Ignored if airmass is set.

  • airmass – Relative airmass. Overrides sza if provided.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km, or a preset name.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • solver – RTE solver name.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength at TOA and surface.

pyradtran.run_solar_transmittance(airmass: float = 1.0, pwv: float = 5.0, ozone: float = 300.0, profile: str = 'us', altitude: float | str = 0.0, wl_min: float = 250.0, wl_max: float = 1200.0, albedo: float = 0.0, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate solar spectral transmittance.

Parameters:
  • airmass – Relative airmass (1.0 = zenith).

  • pwv – Precipitable water vapor in mm (mol_modify H2O).

  • ozone – Ozone column in DU (mol_modify O3).

  • profile – Atmospheric profile name (us, ms, mw, tp, ss, sw).

  • altitude – Surface altitude in km, or a preset name (“LSST”, “CTIO”).

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with transmittance vs wavelength.

pyradtran.run_thermal_brightness(pwv: float = 10.0, profile: str = 'ms', altitude: float = 0.0, wl_min: float = 2500.0, wl_max: float = 50000.0, sur_temperature: float | None = None, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate thermal infrared brightness temperature.

pyradtran.run_with_opac_custom(species_file: str, rh_pct: float = 50.0, species_names: list[str] | None = None, aerosol_wavelength_step_nm: float = 50.0, output_dir: str | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with OPAC custom species profile.

Parameters:
  • species_file – Path to an ASCII species mass concentration profile file.

  • rh_pct – Relative humidity (%) for hygroscopic species; snapped to nearest OPAC level.

  • aerosol_wavelength_step_nm – Spacing of the folded aerosol wavelength grid (nm).

  • output_dir – Directory for the folded explicit aerosol files (default cwd/aerosol).

  • species_names – Optional species filter.

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

pyradtran.run_with_opac_preset(preset: str | OpacPresetName, rh_pct: float = 50.0, species_names: list[str] | None = None, aerosol_wavelength_step_nm: float = 50.0, output_dir: str | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with OPAC preset mixture profile.

Parameters:
  • preset – OPAC preset name (e.g. “continental_average”) or OpacPresetName enum.

  • rh_pct – Relative humidity (%) for hygroscopic species; snapped to nearest OPAC level.

  • aerosol_wavelength_step_nm – Spacing of the folded aerosol wavelength grid (nm).

  • output_dir – Directory for the folded explicit aerosol files (default cwd/aerosol).

  • species_names – Optional species filter (e.g. [“inso”, “soot”]).

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

Scene

Scene builder with immutable chain API.

Scene composes all Pydantic models into a complete uvspec configuration. Each set_*() method returns a NEW Scene via copy.deepcopy() to avoid mutability traps.

class pyradtran.scene.Scene(atmosphere: AtmosphereConfig | None = None, source: SourceConfig | None = None, wavelength: WavelengthConfig | None = None, solver: SolverConfig | None = None, output: OutputConfig | None = None, surface: SurfaceConfig | None = None, aerosol: AerosolModel | None = None, cloud: CloudConfig | None = None, mc: McConfig | None = None, sslidar: SslidarConfig | None = None, advanced: AdvancedConfig | None = None, three_d: ThreeDConfig | None = None, special: SpecialConfig | None = None, raw_keywords: list[tuple[str, str]] | None = None)[source]

Bases: object

Immutable scene builder composing all uvspec configuration models.

Each set_*() method returns a new Scene via deepcopy. Use .clone() for an explicit copy.

Usage:

scene = (
    Scene()
    .set_atmosphere(profile="us", altitude=2.663)
    .set_source_solar(sza=30.0)
    .set_wavelength(250.0, 1200.0)
    .set_solver(method="disort", streams=16)
    .set_output(quantities=["lambda", "edir"])
)
add_raw_keyword(key: str, value: str = '') Scene[source]
build_input(data_files_path: str | None = None) str[source]

Build complete uvspec input text from this Scene.

Raises:

ValueError – If required components are missing.

clone() Scene[source]

Create a deep copy of this Scene.

set_advanced(**kwargs) Scene[source]
set_aerosol(aerosol: AerosolModel) Scene[source]

Set aerosol configuration from an AerosolModel instance.

set_aerosol_modify(variable: str, action: str, value: float) Scene[source]

Add an aerosol modification directive.

Parameters:
  • variable – Property to modify (gg, ssa, tau, tau550).

  • action – Modification type (scale or set).

  • value – Numeric value.

set_atmosphere(**kwargs) Scene[source]
set_cloud(**kwargs) Scene[source]
set_dynamic(method: str = 'dynamic_tenstream', iterations: int | None = None, **kwargs) Scene[source]
set_mc(**kwargs) Scene[source]
set_mol_modify(species: str, value: float, unit: str) Scene[source]
set_output(**kwargs) Scene[source]
set_satellite(geometry: str | None = None, pixel: tuple[int, int] | None = None, **source_kwargs) Scene[source]
set_solver(method: str = 'disort', streams: int = 16, **kwargs) Scene[source]
set_source_solar(sza: float, **kwargs) Scene[source]
set_source_thermal(**kwargs) Scene[source]
set_special(**kwargs) Scene[source]
set_sslidar(**kwargs) Scene[source]
set_surface(**kwargs) Scene[source]
set_three_d(**kwargs) Scene[source]
set_wavelength(wl_min: float, wl_max: float | None = None, **kwargs) Scene[source]

Runner

Subprocess execution engine for uvspec.

Runner is decoupled from Scene. Scene holds configuration; Runner executes it by building input, running uvspec, and parsing output.

class pyradtran.core.runner.Runner[source]

Bases: object

Execute uvspec simulations.

Usage:

result = Runner.execute(scene, data_path="/path/to/data")
results = Runner.execute_many(scenes, max_workers=4)

Global defaults may be set once via configure() so that uvspec_exe and data_path do not need to be repeated on every call:

Runner.configure(uvspec_exe="/opt/libRadtran/bin/uvspec",
                 data_path="/opt/libRadtran/data")
result = Runner.execute(scene)
classmethod configure(config: RunnerConfig | None = None, **kwargs) RunnerConfig[source]

Set global default configuration for all Runner executions.

Parameters:
  • config – A complete RunnerConfig instance, or None.

  • **kwargs – Individual fields (e.g. uvspec_exe=..., data_path=...).

Returns:

The newly set configuration.

static execute(scene: Scene, uvspec_exe: str | None = None, data_path: str | None = None, keep_temp: bool | None = None, timeout: int | None = None, strict: bool | None = None, config: RunnerConfig | None = None) xr.Dataset[source]

Execute a single uvspec simulation.

Parameters:
  • scene – Configured Scene object.

  • uvspec_exe – Path to uvspec binary. Auto-detected if None.

  • data_path – Path to libRadtran data directory. Auto-detected if None.

  • keep_temp – Keep temporary files after execution.

  • timeout – Maximum execution time in seconds.

  • strict – If True, raise on missing data references; if None, defaults to bundled_only (warnings only otherwise).

  • config – Optional RunnerConfig overriding global defaults for this call only.

Returns:

xarray.Dataset with simulation results.

static execute_many(scenes: list[Scene], uvspec_exe: str | None = None, data_path: str | None = None, max_workers: int | None = None, keep_temp: bool | None = None, timeout: int | None = None, config: RunnerConfig | None = None) list[xr.Dataset][source]

Execute multiple uvspec simulations in parallel.

Parameters:
  • scenes – List of configured Scene objects.

  • uvspec_exe – Path to uvspec binary. Auto-detected if None.

  • data_path – Path to libRadtran data directory. Auto-detected if None.

  • max_workers – Maximum parallel workers.

  • keep_temp – Keep temporary files after execution.

  • timeout – Maximum execution time in seconds per scene.

  • config – Optional RunnerConfig overriding global defaults.

Returns:

List of xarray.Dataset results, one per scene.

class pyradtran.core.runner.RunnerConfig(uvspec_exe: str | None = None, data_path: str | None = None, max_workers: int = 4, keep_temp: bool = False, timeout: int | None = None, bundled_only: bool = False)[source]

Bases: object

Configuration for uvspec execution.

uvspec_exe

Path to uvspec binary. Auto-detected via PATH if None.

Type:

str | None

data_path

Path to libRadtran data directory. Uses env vars if None.

Type:

str | None

max_workers

Maximum parallel workers for execute_many().

Type:

int

keep_temp

Keep temporary files after execution (for debugging).

Type:

bool

timeout

Maximum uvspec execution time in seconds. None = no timeout.

Type:

int | None

bundled_only

Force use of the bundled data subset, ignoring env vars and explicit data_path. For reproducible runs / CI.

Type:

bool

bundled_only: bool = False
data_path: str | None = None
keep_temp: bool = False
max_workers: int = 4
timeout: int | None = None
uvspec_exe: str | None = None

Core Utilities

Serialize Scene configuration to uvspec input text.

pyradtran.core.input_builder.build_input_text(atmosphere: AtmosphereConfig, source: SourceConfig, wavelength: WavelengthConfig, solver: SolverConfig, output: OutputConfig, surface: SurfaceConfig | None = None, aerosol: AerosolModel | None = None, cloud: CloudConfig | None = None, mc: McConfig | None = None, sslidar: SslidarConfig | None = None, advanced: AdvancedConfig | None = None, three_d: ThreeDConfig | None = None, raw_keywords: list[tuple[str, str]] | None = None, data_files_path: str | None = None, special: SpecialConfig | None = None) str[source]

Build a complete uvspec input string from configuration models.

Keywords are collected as (phase, line) pairs from each model’s to_uvspec_items() method, then sorted by phase to guarantee correct uvspec keyword ordering.

Phase assignments:

0 - data_files_path, include directives 1 - atmosphere 2 - source 3 - wavelength 4 - scattering/absorption switches (no_absorption, no_scattering) 5 - aerosol 6 - cloud 7 - surface 8 - solver 9 - output 10 - mc, sslidar 11 - three_d 12 - advanced 13 - raw_keywords (user-supplied, always last)

Parse uvspec output files into xarray.Dataset.

Supports both ASCII (default DISORT 7-column and output_user custom) and NetCDF output formats.

pyradtran.core.output_parser.HEATING_RATE_COLUMN = 'heating_rate'

Name of the heating-rate data variable when libRadtran’s heat output is requested (e.g. via solver.dynamic_heat_unit). The ASCII parser handles arbitrary column names; this constant pins the convention used across pyRadtran so callers and the viz layer agree on the variable name.

pyradtran.core.output_parser.parse_output(output_path: str | Path, format: str = 'netcdf', n_zout: int = 1, column_names: list[str] | None = None, zout_levels_km: Sequence[float] | None = None) Dataset[source]

Parse uvspec output file into xarray.Dataset.

Parameters:
  • output_path – Path to uvspec output file.

  • format – Output format — “netcdf” or “ascii”.

  • n_zout – Number of zout levels in output (for ASCII multi-level).

  • column_names – Custom column names for output_user ASCII output.

  • zout_levels_km – Physical zout altitudes in km. When provided (ASCII path), used as the zout coordinate instead of an integer index.

Returns:

xarray.Dataset with wavelength (and optionally zout) as coordinates.

pyradtran.core.output_parser.resolve_zout_tokens(zout: Sequence[float | str], atmosphere_top_km: float = 120.0) list[float][source]

Resolve uvspec zout tokens (which may contain "toa"/"surface") into numeric altitudes in km above ground level.

Parameters:
  • zout – Output levels as given to uvspec (floats and/or keyword strings).

  • atmosphere_top_km – Altitude (km) to which "toa"/"top" resolve.

Returns:

List of float altitudes in km, same length and order as zout.

Temporary file lifecycle management for uvspec data files.

class pyradtran.core.tempfile_manager.TempFileManager(temp_dir: str | None = None, keep_temp: bool = False)[source]

Bases: object

Manage temporary data files for uvspec execution.

Parameters:
  • temp_dir – Directory for temporary files. Defaults to system temp.

  • keep_temp – If True, don’t delete files on cleanup (for debugging).

Usage:

with TempFileManager() as mgr:
    path = mgr.write_array("extinction.dat", extinction_data)
# files cleaned up on exit
cleanup() None[source]

Delete all tracked temporary files.

property files: list[str]

List of tracked temporary file paths.

write_array(name: str, data: ndarray) str[source]

Write numpy array to a temporary file, return the path.

write_text(name: str, content: str) str[source]

Write text content to a temporary file, return the path.

Convenience Functions

High-level convenience functions for common radiative transfer tasks.

pyradtran.convenience.run_3d(atmosphere_file: str | None = None, profile: str = 'us', altitude: float = 0.0, sza: float = 30.0, wl_min: float = 300.0, wl_max: float = 2500.0, photons: int = 100000, ipa: bool = False, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run 3D Monte Carlo radiative transfer simulation.

Parameters:
  • atmosphere_file – Path to 3D atmospheric field file.

  • profile – Standard atmosphere profile (for 1D fallback).

  • altitude – Surface altitude in km.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • photons – Number of Monte Carlo photons.

  • ipa – Use independent pixel approximation.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with 3D radiative transfer results.

pyradtran.convenience.run_cloudy_scene(ic_properties: str = 'fu', ic_tau: float | None = None, ic_habit: str | None = None, wc_properties: str | None = None, wc_tau: float | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with cloud layer.

Parameters:
  • ic_properties – Ice cloud parameterization (fu, yang, key, baum, etc.).

  • ic_tau – Ice cloud optical thickness (set via ic_modify).

  • ic_habit – Ice crystal habit type.

  • wc_properties – Water cloud parameterization (hu, echam4).

  • wc_tau – Water cloud optical thickness.

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

pyradtran.convenience.run_lidar(area: float = 1.0, E0: float = 0.1, efficiency: float = 0.5, position: float = 0.0, range_bin: float = 0.1, n_ranges: int = 100, profile: str = 'us', altitude: float = 0.0, wl_min: float = 300.0, wl_max: float = 1100.0, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run single scattering lidar simulation.

Parameters:
  • area – Telescope area in m^2.

  • E0 – Pulse energy in Joules.

  • efficiency – Detector efficiency.

  • position – Lidar position in km.

  • range_bin – Range bin width in km.

  • n_ranges – Number of range bins.

  • profile – Atmospheric profile.

  • altitude – Surface altitude in km.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with lidar signal vs range.

pyradtran.convenience.run_polarized(profile: str = 'us', altitude: float = 0.0, sza: float = 30.0, wl_min: float = 250.0, wl_max: float = 1200.0, photons: int = 100000, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None, output_dir: str | None = None) Dataset[source]

Run polarized Monte Carlo simulation.

Parameters:
  • profile – Atmospheric profile.

  • altitude – Surface altitude in km.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • photons – Number of Monte Carlo photons.

  • streams – Number of streams (for correlated-k).

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with polarized radiance.

pyradtran.convenience.run_satellite(geometry: str = 'MPS', pixel: tuple[int, int] | None = None, profile: str = 'us', sza: float = 60.0, wl_min: float = 300.0, wl_max: float = 2500.0, solver: str = 'disort', streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run satellite-viewing radiative transfer simulation.

Parameters:
  • geometry – Satellite geometry name (e.g., MPS, SENTINEL2A).

  • pixel – Optional (x, y) pixel coordinates for satellite_geometry file.

  • profile – Standard atmosphere profile.

  • sza – Solar zenith angle in degrees.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • solver – RTE solver name.

  • streams – Number of angular streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with satellite-view radiance/irradiance.

pyradtran.convenience.run_solar_radiance(sza: float = 30.0, airmass: float | None = None, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 250.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, solver: str = 'disort', uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate solar spectral radiance (direct + diffuse irradiance).

Parameters:
  • sza – Solar zenith angle in degrees. Ignored if airmass is set.

  • airmass – Relative airmass. Overrides sza if provided.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km, or a preset name.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • solver – RTE solver name.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength at TOA and surface.

pyradtran.convenience.run_solar_transmittance(airmass: float = 1.0, pwv: float = 5.0, ozone: float = 300.0, profile: str = 'us', altitude: float | str = 0.0, wl_min: float = 250.0, wl_max: float = 1200.0, albedo: float = 0.0, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate solar spectral transmittance.

Parameters:
  • airmass – Relative airmass (1.0 = zenith).

  • pwv – Precipitable water vapor in mm (mol_modify H2O).

  • ozone – Ozone column in DU (mol_modify O3).

  • profile – Atmospheric profile name (us, ms, mw, tp, ss, sw).

  • altitude – Surface altitude in km, or a preset name (“LSST”, “CTIO”).

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with transmittance vs wavelength.

pyradtran.convenience.run_thermal_brightness(pwv: float = 10.0, profile: str = 'ms', altitude: float = 0.0, wl_min: float = 2500.0, wl_max: float = 50000.0, sur_temperature: float | None = None, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Calculate thermal infrared brightness temperature.

pyradtran.convenience.run_with_opac_custom(species_file: str, rh_pct: float = 50.0, species_names: list[str] | None = None, aerosol_wavelength_step_nm: float = 50.0, output_dir: str | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with OPAC custom species profile.

Parameters:
  • species_file – Path to an ASCII species mass concentration profile file.

  • rh_pct – Relative humidity (%) for hygroscopic species; snapped to nearest OPAC level.

  • aerosol_wavelength_step_nm – Spacing of the folded aerosol wavelength grid (nm).

  • output_dir – Directory for the folded explicit aerosol files (default cwd/aerosol).

  • species_names – Optional species filter.

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

pyradtran.convenience.run_with_opac_preset(preset: str | OpacPresetName, rh_pct: float = 50.0, species_names: list[str] | None = None, aerosol_wavelength_step_nm: float = 50.0, output_dir: str | None = None, sza: float = 30.0, profile: str = 'us', altitude: float | str = 0.0, pwv: float = 5.0, ozone: float = 300.0, wl_min: float = 300.0, wl_max: float = 2500.0, albedo: float = 0.2, streams: int = 16, uvspec_exe: str | None = None, data_path: str | None = None) Dataset[source]

Run uvspec with OPAC preset mixture profile.

Parameters:
  • preset – OPAC preset name (e.g. “continental_average”) or OpacPresetName enum.

  • rh_pct – Relative humidity (%) for hygroscopic species; snapped to nearest OPAC level.

  • aerosol_wavelength_step_nm – Spacing of the folded aerosol wavelength grid (nm).

  • output_dir – Directory for the folded explicit aerosol files (default cwd/aerosol).

  • species_names – Optional species filter (e.g. [“inso”, “soot”]).

  • sza – Solar zenith angle in degrees.

  • profile – Atmospheric profile name.

  • altitude – Surface altitude in km.

  • pwv – Precipitable water vapor in mm.

  • ozone – Ozone column in DU.

  • wl_min – Minimum wavelength in nm.

  • wl_max – Maximum wavelength in nm.

  • albedo – Surface albedo.

  • streams – Number of DISORT streams.

  • uvspec_exe – Path to uvspec binary.

  • data_path – Path to libRadtran data directory.

Returns:

xarray.Dataset with irradiance vs wavelength.

Configuration Models

Base

Base class for all uvspec option models.

class pyradtran.models.base.UvspecOption[source]

Bases: BaseModel

Base class for uvspec keyword group models.

All models are frozen (immutable) and reject extra fields to catch typos at the Python level rather than at uvspec runtime.

Subclasses must implement to_uvspec_lines() to serialize their configuration to uvspec input file format.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

Atmosphere

Atmosphere configuration model.

Maps to uvspec keywords: atmosphere_file, altitude, pressure, mol_modify, mol_abs_param.

Reference: libRadtran src_py/molecular_options.py, src_py/surface_options.py

class pyradtran.models.atmosphere.AtmosphereConfig(*, profile: ~typing.Annotated[str, ~annotated_types.MinLen(min_length=1)], altitude: ~typing.Annotated[float, ~annotated_types.Ge(ge=-1000000.0), ~annotated_types.Le(le=1000000.0)] = 0.0, pressure: ~types.Annotated[float | None, ~annotated_types.Ge(ge=0), ~annotated_types.Le(le=1000000.0)] = None, mol_modify: list[tuple[str, float, str]] = <factory>, mol_abs_param: str | None = None, crs_model: dict[str, str] | list[dict[str, str]] | None = None, atm_z_grid: list[float] | None = None, radiosonde: bool = False, radiosonde_levels_only: bool = False, mol_file: list[dict[str, str]] | None = None, mol_tau_file: tuple[str, str] | None = None, rayleigh_depol: ~types.Annotated[float | None, ~annotated_types.Ge(ge=0.0), ~annotated_types.Le(le=1.0)] = None, raman: bool = False)[source]

Bases: UvspecOption

Atmospheric profile and molecular absorption configuration.

profile

Named AFGL atmosphere or path to custom atmosphere file. Shorthands: us, ms, mw, tp, ss, sw. Full names: US-standard, midlatitude_summer, midlatitude_winter, tropics, subarctic_summer, subarctic_winter.

Type:

str

altitude

Surface altitude above sea level in km. Default: 0.0.

Type:

float

pressure

Surface pressure in hPa. Scales pressure, air, O2, CO2 profiles.

Type:

float | None

mol_modify

List of (species, column_value, unit) tuples. Species: O3, O2, H2O, CO2, NO2, BRO, OCLO, HCHO, O4, SO2, CH4, N2O, CO, N2. Units: DU, CM_2, MM.

Type:

list[tuple[str, float, str]]

mol_abs_param

Molecular absorption parameterization scheme string. Default is reptran coarse (handled by uvspec internally).

Type:

str | None

atm_z_grid

Custom altitude grid in km.

Type:

list[float] | None

radiosonde

Use radiosonde profile data.

Type:

bool

radiosonde_levels_only

Use only radiosonde levels (requires radiosonde=True).

Type:

bool

mol_file

List of molecular VMR profile files, each a dict with keys “species”, “file”, and optional “unit”.

Type:

list[dict[str, str]] | None

mol_tau_file

Molecular optical thickness file as (kind, filepath) tuple.

Type:

tuple[str, str] | None

rayleigh_depol

Rayleigh scattering depolarization factor.

Type:

float | None

raman

Enable Raman scattering.

Type:

bool

altitude: float
atm_z_grid: list[float] | None
crs_model: dict[str, str] | list[dict[str, str]] | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(context: Any, /) None

This function is meant to behave like a BaseModel method to initialize private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Parameters:
  • self – The BaseModel instance.

  • context – The context.

mol_abs_param: str | None
mol_file: list[dict[str, str]] | None
mol_modify: list[tuple[str, float, str]]
mol_tau_file: tuple[str, str] | None
pressure: float | None
profile: str
radiosonde: bool
radiosonde_levels_only: bool
raman: bool
rayleigh_depol: float | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_crs_model() AtmosphereConfig[source]
validate_mol_modify_entries() AtmosphereConfig[source]
validate_radiosonde() AtmosphereConfig[source]

Source

Source configuration model.

Maps to uvspec keywords: source, sza, phi0, day_of_year, solar_flux_file, umu, phi, latitude, longitude, time, time_interpolate, time_interval, earth_radius, sza_file, isotropic_source_toa.

Reference: libRadtran src_py/geometry_options.py, src_py/spectral_options.py

class pyradtran.models.source.SourceConfig(*, source: ~typing.Annotated[str, _PydanticGeneralMetadata(pattern='^(solar|thermal)$')], sza: ~types.Annotated[float | None, ~annotated_types.Ge(ge=0.0), ~annotated_types.Le(le=180.0)] = None, phi0: ~types.Annotated[float | None, ~annotated_types.Ge(ge=-360.0), ~annotated_types.Le(le=360.0)] = None, day_of_year: ~types.Annotated[int | None, ~annotated_types.Ge(ge=1), ~annotated_types.Le(le=366)] = None, solar_flux_file: str | None = None, umu: list[float] = <factory>, phi: list[float] = <factory>, satellite_geometry: str | None = None, satellite_pixel: tuple[int, int] | None = None, latitude: tuple[str, int, int, int] | None = None, longitude: tuple[str, int, int, int] | None = None, time: str | None = None, time_interpolate: bool = False, time_interval: tuple[str, str] | None = None, earth_radius: ~types.Annotated[float | None, ~annotated_types.Ge(ge=0.0)] = None, sza_file: str | None = None, isotropic_source_toa: bool = False)[source]

Bases: UvspecOption

Solar or thermal radiation source configuration.

source

Radiation source type – “solar” or “thermal”.

Type:

str

sza

Solar zenith angle in degrees [0, 180]. Required for solar source (unless sza_file or isotropic_source_toa is set).

Type:

float | None

phi0

Solar azimuth angle in degrees [-360, 360].

Type:

float | None

day_of_year

Day of year [1, 366].

Type:

int | None

solar_flux_file

Path to solar flux file (e.g. kurudz_0.1nm.dat).

Type:

str | None

umu

Viewing zenith angles (cosines). Positive = upward, negative = downward.

Type:

list[float]

phi

Viewing azimuth angles in degrees.

Type:

list[float]

satellite_geometry

Satellite geometry specification (e.g., SENTINEL2A, MPS).

Type:

str | None

satellite_pixel

Pixel coordinates (x, y) for satellite pixel-based geometry.

Type:

tuple[int, int] | None

latitude

Geographic latitude as (hemisphere, degrees, minutes, seconds).

Type:

tuple[str, int, int, int] | None

longitude

Geographic longitude as (hemisphere, degrees, minutes, seconds).

Type:

tuple[str, int, int, int] | None

time

Time of day string (e.g. “10:30:00”).

Type:

str | None

time_interpolate

Enable time interpolation.

Type:

bool

time_interval

Tuple of (start_time, end_time) for time range.

Type:

tuple[str, str] | None

earth_radius

Earth radius in km.

Type:

float | None

sza_file

Path to file containing solar zenith angle data.

Type:

str | None

isotropic_source_toa

Use isotropic source at top of atmosphere.

Type:

bool

check_satellite_consistency() SourceConfig[source]
check_sza_for_solar() SourceConfig[source]
check_sza_mutual_exclusion() SourceConfig[source]
day_of_year: int | None
earth_radius: float | None
isotropic_source_toa: bool
latitude: tuple[str, int, int, int] | None
longitude: tuple[str, int, int, int] | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

phi: list[float]
phi0: float | None
satellite_geometry: str | None
satellite_pixel: tuple[int, int] | None
solar_flux_file: str | None
source: str
sza: float | None
sza_file: str | None
time: str | None
time_interpolate: bool
time_interval: tuple[str, str] | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

umu: list[float]

Wavelength

Wavelength configuration model.

Maps to uvspec keywords: wavelength, spline, filter_function_file, wavelength_grid_file, wavelength_index, slit_function_file, spline_file, fluorescence, fluorescence_file, thermal_bands_file, thermal_bandwidth.

Reference: libRadtran src_py/spectral_options.py

class pyradtran.models.wavelength.WavelengthConfig(*, wavelength_min: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, wavelength_max: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, unit: Annotated[str, _PydanticGeneralMetadata(pattern='^(nm|cm-1)$')] = 'nm', spline: str | None = None, filter_function_file: str | None = None, wavelength_grid_file: str | None = None, wavelength_index: tuple[int, int] | None = None, slit_function_file: str | None = None, spline_file: str | None = None, fluorescence: bool = False, fluorescence_file: str | None = None, thermal_bands_file: str | None = None, thermal_bandwidth: tuple[float, str] | None = None)[source]

Bases: UvspecOption

Spectral range configuration.

wavelength_min

Shortest wavelength (nm or cm-1), or single wavelength when wavelength_max is not set.

Type:

float | None

wavelength_max

Longest wavelength (nm or cm-1). Optional; when None, wavelength_min is treated as a single wavelength value.

Type:

float | None

unit

Wavelength unit – “nm” (default) or “cm-1” for wavenumbers.

Type:

str

spline

Spline smoothing arguments string (3 floats).

Type:

str | None

filter_function_file

Path to filter function file.

Type:

str | None

wavelength_grid_file

Path to wavelength grid file (alternative to wavelength_min).

Type:

str | None

wavelength_index

Tuple of (start_index, end_index) for wavelength subset.

Type:

tuple[int, int] | None

slit_function_file

Path to slit function file.

Type:

str | None

spline_file

Path to spline file.

Type:

str | None

fluorescence

Enable fluorescence calculation.

Type:

bool

fluorescence_file

Path to fluorescence data file.

Type:

str | None

thermal_bands_file

Path to thermal bands file.

Type:

str | None

thermal_bandwidth

Tuple of (width, unit) for thermal bandwidth.

Type:

tuple[float, str] | None

filter_function_file: str | None
fluorescence: bool
fluorescence_file: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

slit_function_file: str | None
spline: str | None
spline_file: str | None
thermal_bands_file: str | None
thermal_bandwidth: tuple[float, str] | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

unit: str
validate_wavelength_set() WavelengthConfig[source]
wavelength_grid_file: str | None
wavelength_index: tuple[int, int] | None
wavelength_max: float | None
wavelength_min: float | None

Solver

Solver configuration model.

Maps to uvspec keywords: rte_solver, number_of_streams, pseudospherical, deltam.

Reference: libRadtran src_py/solver_options.py

class pyradtran.models.solver.SolverConfig(*, method: str, streams: Annotated[int, Ge(ge=1)] = 6, pseudospherical: bool = False, deltam: bool = False, dynamic_iterations: Annotated[int | None, Ge(ge=0)] = None, dynamic_history: bool = False, dynamic_heat_unit: str | None = None, disort_intcor: str | None = None, disort_spherical_albedo: bool = False, schwarzschild_streams: Annotated[int | None, Ge(ge=1)] = None)[source]

Bases: UvspecOption

Radiative transfer solver configuration.

method

Solver name (disort, twostr, mystic, etc.).

Type:

str

streams

Number of streams for discrete ordinates solvers. Default: 6.

Type:

int

pseudospherical

Enable pseudo-spherical correction (disort/twostr only).

Type:

bool

deltam

Enable delta-M scaling.

Type:

bool

dynamic_iterations

Number of iterations for dynamic solvers.

Type:

int | None

dynamic_history

Enable history tracking for dynamic solvers.

Type:

bool

dynamic_heat_unit

Heat unit for dynamic solvers.

Type:

str | None

deltam: bool
disort_intcor: str | None
disort_spherical_albedo: bool
dynamic_heat_unit: str | None
dynamic_history: bool
dynamic_iterations: int | None
method: str
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

pseudospherical: bool
schwarzschild_streams: int | None
streams: int
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_solver() SolverConfig[source]

Output

Output configuration model.

Maps to uvspec keywords: output_user, output_quantity, output_process, output_format, quiet, verbose, zout, output_file.

Reference: libRadtran src_py/output_options.py

class pyradtran.models.output.OutputConfig(*, quantities: list[str] = <factory>, quantity: str | None = None, process: str | None = None, format: str = 'ascii', quiet: bool = True, verbose: bool = False, zout: list[float | str] = <factory>, output_file: str | None = None, heating_rate: str | None = None, write_optical_properties: bool = False)[source]

Bases: UvspecOption

Output format and content configuration.

quantities

Output column quantities (e.g. [“lambda”, “edir”, “edn”, “eup”]).

Type:

list[str]

quantity

Output quantity type (transmittance, reflectivity, brightness).

Type:

str | None

process

Output processing (e.g. ‘integrate’, ‘per_nm’, ‘sum’).

Type:

str | None

format

Output file format – “netcdf” (default), “ascii”, “flexstor”.

Type:

str

quiet

Suppress uvspec stdout messages. Default: True.

Type:

bool

verbose

Enable verbose uvspec output.

Type:

bool

zout

Output altitudes in km above ground level. Supports float values and special strings like “toa” and “boa”.

Type:

list[float | str]

output_file

Path for output file (overrides auto-generated name).

Type:

str | None

heating_rate

Heating rate calculation mode (e.g. ‘local’, ‘layer_fd’).

Type:

str | None

write_optical_properties

Write optical properties to output file.

Type:

bool

format: str
heating_rate: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

output_file: str | None
process: str | None
quantities: list[str]
quantity: str | None
quiet: bool
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_output() OutputConfig[source]
verbose: bool
write_optical_properties: bool
zout: list[float | str]

Surface

Surface configuration model.

Maps to uvspec keywords: albedo, albedo_file, albedo_map, albedo_library, sur_temperature, brdf_ambrals, brdf_hapke, brdf_rpv, brdf_cam, bpdf_litvinov, bpdf_maignan, bpdf_tsang_u10.

Reference: libRadtran src/uvspec_lex.l (surface/BRDF options)

class pyradtran.models.surface.SurfaceConfig(*, albedo: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, albedo_file: str | None = None, albedo_map: str | tuple[str, str] | None = None, albedo_library: str | None = None, sur_temperature: float | None = None, brdf_ambrals: dict[str, float] | None = None, brdf_hapke: dict[str, float] | None = None, brdf_rpv: dict[str, float] | None = None, brdf_cam: dict[str, float] | None = None, bpdf_litvinov: dict[str, float] | None = None, bpdf_maignan: dict[str, float] | None = None, bpdf_tsang_u10: Annotated[float | None, Ge(ge=0.0), Le(le=100.0)] = None, brdf_rossli_file: str | None = None, brdf_rossli_hotspot: bool = False, brdf_rpv_file: str | None = None, surface_type_map: str | None = None, surface_temperature_map: str | tuple[str, str, float] | None = None)[source]

Bases: UvspecOption

Surface reflection and temperature configuration.

albedo

Constant Lambertian albedo [0, 1]. Mutually exclusive with BRDF/BPDF.

Type:

float | None

albedo_file

Path to wavelength-dependent albedo file.

Type:

str | None

albedo_map

Path to spatial albedo map NetCDF file, or tuple (path, variable).

Type:

str | tuple[str, str] | None

albedo_library

Albedo library name or path (“IGBP”).

Type:

str | None

sur_temperature

Surface temperature in Kelvin (for thermal IR).

Type:

float | None

brdf_ambrals

Dict of AMBRALS BRDF parameters (iso, vol, geo).

Type:

dict[str, float] | None

brdf_hapke

Dict of Hapke BRDF parameters (w, b0, h).

Type:

dict[str, float] | None

brdf_rpv

Dict of RPV BRDF parameters (rho0, k, theta, scale).

Type:

dict[str, float] | None

brdf_cam

Dict of CAM BRDF parameters (pcl, sal, u10).

Type:

dict[str, float] | None

bpdf_litvinov

Dict of Litvinov BPDF parameters.

Type:

dict[str, float] | None

bpdf_maignan

Dict of Maignan BPDF parameters.

Type:

dict[str, float] | None

bpdf_tsang_u10

Wind speed for Tsang BPDF (m/s).

Type:

float | None

albedo: float | None
albedo_file: str | None
albedo_library: str | None
albedo_map: str | tuple[str, str] | None
bpdf_litvinov: dict[str, float] | None
bpdf_maignan: dict[str, float] | None
bpdf_tsang_u10: float | None
brdf_ambrals: dict[str, float] | None
brdf_cam: dict[str, float] | None
brdf_hapke: dict[str, float] | None
brdf_rossli_file: str | None
brdf_rossli_hotspot: bool
brdf_rpv: dict[str, float] | None
brdf_rpv_file: str | None
check_mutual_exclusion() SurfaceConfig[source]
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

sur_temperature: float | None
surface_temperature_map: str | tuple[str, str, float] | None
surface_type_map: str | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

Cloud

Cloud configuration model (Phase 2).

Maps to uvspec keywords: ic_file, ic_properties, ic_habit, ic_habit_yang2013, ic_modify, wc_file, wc_properties, wc_modify, cloudcover, cloud_overlap.

Reference: libRadtran src/uvspec_lex.l (cloud options)

class pyradtran.models.cloud.CloudConfig(*, ic_properties: str | None = None, ic_file: tuple[str, str] | None=None, ic_habit: str | None = None, ic_habit_roughness: str | None = None, ic_modify: list[CloudModifyEntry] = <factory>, wc_properties: str | None = None, wc_file: tuple[str, str] | None=None, wc_modify: list[CloudModifyEntry] = <factory>, modify: list[CloudModifyEntry] = <factory>, cloud_cover_type: str | None = None, cloud_cover: Annotated[float | None, ~annotated_types.Ge(ge=0.0), ~annotated_types.Le(le=1.0)] = None, cloud_overlap: str | None = None, interpolate: bool = False, cloud_fraction_file: str | None = None, cloud_fraction_map: str | tuple[str, str, float] | None=None, wc_saturate: bool = False, ic_saturate: bool = False, wc_ipa: bool = False, wc_layer: Annotated[int | None, ~annotated_types.Ge(ge=0)] = None)[source]

Bases: UvspecOption

Cloud configuration for water and ice clouds.

ic_properties

Ice cloud optical property parameterization.

Type:

str | None

ic_file

Tuple of (dimension, path) for ice cloud external file.

Type:

tuple[str, str] | None

ic_habit

Ice crystal habit type.

Type:

str | None

ic_habit_roughness

Roughness for yang2013 (“smooth”, “moderate”, “severe”).

Type:

str | None

ic_modify

List of ice cloud modification directives.

Type:

list[CloudModifyEntry]

wc_properties

Water cloud optical property parameterization.

Type:

str | None

wc_file

Tuple of (dimension, path) for water cloud external file.

Type:

tuple[str, str] | None

wc_modify

List of water cloud modification directives.

Type:

list[CloudModifyEntry]

cloud_cover_type

Cloud type for cloud cover (“ic” or “wc”).

Type:

str | None

cloud_cover

Cloud cover fraction [0, 1].

Type:

float | None

cloud_overlap

Cloud overlap method.

Type:

str | None

interpolate

Append ‘interpolate’ to ic/wc_properties for spectral mode.

Type:

bool

cloud_cover: float | None
cloud_cover_type: str | None
cloud_fraction_file: str | None
cloud_fraction_map: str | tuple[str, str, float] | None
cloud_overlap: str | None
ic_file: tuple[str, str] | None
ic_habit: str | None
ic_habit_roughness: str | None
ic_modify: list[CloudModifyEntry]
ic_properties: str | None
ic_saturate: bool
interpolate: bool
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

modify: list[CloudModifyEntry]
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_cloud() CloudConfig[source]
wc_file: tuple[str, str] | None
wc_ipa: bool
wc_layer: int | None
wc_modify: list[CloudModifyEntry]
wc_properties: str | None
wc_saturate: bool
class pyradtran.models.cloud.CloudModifyEntry(*, variable: str, action: str, value: float)[source]

Bases: UvspecOption

A single cloud modify directive (wc_modify or ic_modify).

action: str
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

validate_entry() CloudModifyEntry[source]
value: float
variable: str

Monte Carlo

Monte Carlo (MYSTIC) configuration model.

Maps to uvspec keywords: mc_photons, mc_backward, mc_escape, mc_vroom, mc_polarisation, mc_randomseed, mc_minphotons, mc_maxscatters, mc_spectral_is, mc_delta_scaling, mc_rad_alpha, mc_backward_output, mc_forward_output, mc_backward_heat, mc_std, mc_jacobian, mc_progressbar, mc_surface_reflectalways, mc_spherical, mc_tenstream, mc_ipa, mc_tipa, mc_sensordirection, mc_sensorposition, mc_spherical3D_scene, mc_basename, mc_minscatters, mc_sun_angular_size.

Reference: libRadtran src_py/mc_options.py

class pyradtran.models.mc.McConfig(*, photons: Annotated[int | None, Ge(ge=0)] = None, min_photons: Annotated[int | None, Ge(ge=0)] = None, backward: bool = False, backward_pixel_range: tuple[int, int, int, int] | None = None, escape: str | None = None, vroom: str | None = None, polarisation: bool = False, polarisation_state: Annotated[int | None, Ge(ge=-3), Le(le=4)] = None, random_seed: Annotated[int | None, Ge(ge=0), Le(le=1000000000000000)] = None, max_scatters: Annotated[int | None, Ge(ge=0)] = None, spectral_is: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, delta_scaling_mucut: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, delta_scaling_n_start: Annotated[int | None, Ge(ge=0)] = None, rad_alpha: Annotated[float | None, Ge(ge=0.0), Le(le=90.0)] = None, backward_output: str | None = None, backward_output_unit: str | None = None, forward_output: str | None = None, backward_heat: str | None = None, std: Annotated[float | None, Ge(ge=0.0)] = None, jacobian: str | None = None, jacobian_std: bool = False, progressbar: Annotated[int | None, Ge(ge=0), Le(le=3)] = None, surface_reflect_always: bool = False, photons_file: str | None = None, albedo_file: str | None = None, albedo_spectral_file: str | None = None, rossli_file: str | None = None, ambrals_spectral_file: str | None = None, rpv_spectral_file: str | None = None, bpdf: str | None = None, surface_parallel: bool = False, elevation_file: str | None = None, lidar_file: str | None = None, triangular_surface_file: str | None = None, spherical: str | None = None, tenstream: bool = False, ipa: bool = False, tipa: str | None = None, sensor_direction: tuple[float, float, float] | None = None, sensor_position: tuple[float, float, float] | None = None, spherical3d_scene: tuple[float, float, float, float] | None = None, basename: str | None = None, min_scatters: Annotated[int | None, Ge(ge=0)] = None, sun_angular_size: Annotated[float | None, Ge(ge=0.0), Le(le=10.0)] = None, relerr: Annotated[float | None, Ge(ge=0.0)] = None, coherent_backscatter: bool = False, nca: bool = False, aerosol_is: bool = False, bcond: str | None = None)[source]

Bases: UvspecOption

Monte Carlo (MYSTIC) solver configuration.

photons

Total number of photons to trace. Required for MYSTIC.

Type:

int | None

min_photons

Minimum photons per spectral band (correlated-k).

Type:

int | None

backward

Enable backward photon tracing. Required for most MC output.

Type:

bool

backward_pixel_range

Optional (ix_start, iy_start, ix_end, iy_end).

Type:

tuple[int, int, int, int] | None

escape

Calculate radiances via escape probabilities – “on” or “off”.

Type:

str | None

vroom

Variance Reduction Optimal Options Method – “on” or “off”.

Type:

str | None

polarisation

Enable polarisation calculations.

Type:

bool

polarisation_state

Initial Stokes vector (-3 to 4, default 0).

Type:

int | None

random_seed

Random seed for reproducibility.

Type:

int | None

max_scatters

Maximum scatters before photon destruction (testing).

Type:

int | None

spectral_is

Wavelength for spectral importance sampling.

Type:

float | None

delta_scaling_mucut

Truncation threshold for delta-M scaling.

Type:

float | None

delta_scaling_n_start

Stream number for delta-M scaling start.

Type:

int | None

rad_alpha

Opening angle for all-sky radiance (degrees).

Type:

float | None

backward_output

Output quantity for backward MC (e.g. “edn”).

Type:

str | None

backward_output_unit

Unit for backward MC output.

Type:

str | None

forward_output

Output quantity for forward MC (e.g. “heating”).

Type:

str | None

backward_heat

Thermal heating method – “HYBRID”, “EMABS”, etc.

Type:

str | None

std

Target standard deviation (stop when reached).

Type:

float | None

jacobian

Jacobian calculation mode – “1D” or “3D”.

Type:

str | None

jacobian_std

Calculate Jacobian standard deviation.

Type:

bool

progressbar

MC progress bar mode (0=off, 2, 3).

Type:

int | None

surface_reflect_always

Always reflect at surface, weight via albedo.

Type:

bool

photons_file

Path to photon distribution file.

Type:

str | None

spherical

3D geometry mode - “1D” or “3D”.

Type:

str | None

tenstream

Enable tenstream approximation.

Type:

bool

ipa

Importance photon acceleration.

Type:

bool

tipa

Tracked importance photon acceleration - “dir” or “dir3d”.

Type:

str | None

sensor_direction

Sensor viewing direction (dx, dy, dz).

Type:

tuple[float, float, float] | None

sensor_position

Sensor position (x, y, z).

Type:

tuple[float, float, float] | None

spherical3d_scene

Spherical 3D scene bounds (lon_min, lat_min, lon_max, lat_max).

Type:

tuple[float, float, float, float] | None

basename

Basename for output files.

Type:

str | None

min_scatters

Minimum number of scatters before stopping.

Type:

int | None

sun_angular_size

Sun angular size in degrees.

Type:

float | None

aerosol_is: bool
albedo_file: str | None
albedo_spectral_file: str | None
ambrals_spectral_file: str | None
backward: bool
backward_heat: str | None
backward_output: str | None
backward_output_unit: str | None
backward_pixel_range: tuple[int, int, int, int] | None
basename: str | None
bcond: str | None
bpdf: str | None
coherent_backscatter: bool
delta_scaling_mucut: float | None
delta_scaling_n_start: int | None
elevation_file: str | None
escape: str | None
forward_output: str | None
ipa: bool
jacobian: str | None
jacobian_std: bool
lidar_file: str | None
max_scatters: int | None
min_photons: int | None
min_scatters: int | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

nca: bool
photons: int | None
photons_file: str | None
polarisation: bool
polarisation_state: int | None
progressbar: int | None
rad_alpha: float | None
random_seed: int | None
relerr: float | None
rossli_file: str | None
rpv_spectral_file: str | None
sensor_direction: tuple[float, float, float] | None
sensor_position: tuple[float, float, float] | None
spectral_is: float | None
spherical: str | None
spherical3d_scene: tuple[float, float, float, float] | None
std: float | None
sun_angular_size: float | None
surface_parallel: bool
surface_reflect_always: bool
tenstream: bool
tipa: str | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

triangular_surface_file: str | None
validate_mc() McConfig[source]
vroom: str | None

SSLidar

SSLidar (Single Scattering Lidar) configuration model.

Maps to uvspec keywords: sslidar, sslidar_nranges, sslidar_polarisation.

Reference: libRadtran src_py/geometry_options.py, src_py/solver_options.py

class pyradtran.models.sslidar.SslidarConfig(*, area: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, E0: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, efficiency: Annotated[float | None, Ge(ge=0.0), Le(le=1.0)] = None, position: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, range_bin: Annotated[float | None, Ge(ge=0), Le(le=1000000.0)] = None, n_ranges: Annotated[int | None, Ge(ge=1)] = None, polarisation: bool = False)[source]

Bases: UvspecOption

Single scattering lidar configuration.

Requires rte_solver sslidar.

area

Telescope area in m^2.

Type:

float | None

E0

Pulse energy in Joules.

Type:

float | None

efficiency

Detector efficiency.

Type:

float | None

position

Lidar position above ground in km.

Type:

float | None

range_bin

Range bin width in km.

Type:

float | None

n_ranges

Number of range bins.

Type:

int | None

polarisation

Enable polarisation measurement.

Type:

bool

E0: float | None
area: float | None
efficiency: float | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_ranges: int | None
polarisation: bool
position: float | None
range_bin: float | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

3D Fields

3D atmosphere and cloud configuration model.

Maps to uvspec keywords: atmosphere_file (3D NetCDF fields).

Note: 3D cloud fields are specified via CloudConfig using wc_file=(“3D”, path) or ic_file=(“3D”, path), not through a separate keyword. The ipa_3d and output3D flags are set automatically by uvspec when tipa or MYSTIC is enabled.

Reference: libRadtran src/uvspec_lex.l (MYSTIC 3D options)

class pyradtran.models.three_d.ThreeDConfig(*, atmosphere_file: str | None = None)[source]

Bases: UvspecOption

3D atmospheric field configuration.

Configures 3D atmospheric input fields for MYSTIC and dynamic tenstream solvers.

atmosphere_file

Path to 3D atmospheric field NetCDF file.

Type:

str | None

Note

3D cloud fields are specified through CloudConfig: scene.set_cloud(wc_file=(“3D”, “/path/to/cloud3d.nc”)) or scene.set_cloud(ic_file=(“3D”, “/path/to/ic3d.nc”)).

The ipa (independent pixel approximation) for 3D is enabled via McConfig.ipa=True or McConfig.tipa=”dir”/”dir3d”.

atmosphere_file: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

Advanced

Advanced options model.

Maps to uvspec keywords: fluorescence, fluorescence_file, raman.

Phase 3 scope. Phase 4 may add 3D, satellite geometry, dynamic solvers, etc.

Reference: libRadtran src_py/surface_options.py, src_py/solver_options.py

class pyradtran.models.advanced.AdvancedConfig(*, fluorescence: Annotated[float | None, Ge(ge=0.0)] = None, fluorescence_file: str | None = None, raman: bool = False, raman_variant: str | None = None)[source]

Bases: UvspecOption

Advanced radiative transfer options.

fluorescence

Isotropic surface fluorescence emission (W/m^2/nm).

Type:

float | None

fluorescence_file

Path to wavelength-dependent fluorescence file. Mutually exclusive with fluorescence.

Type:

str | None

raman

Enable first-order rotational Raman scattering. Requires rte_solver disort.

Type:

bool

raman_variant

Raman variant – “original” (default: standard).

Type:

str | None

fluorescence: float | None
fluorescence_file: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

raman: bool
raman_variant: str | None
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_advanced() AdvancedConfig[source]

Special

Special options model for scattering/absorption control and file includes.

Maps to uvspec keywords: no_absorption, no_scattering, no_scattering mol, include.

Reference: libRadtran src/uvspec_lex.l

class pyradtran.models.special.SpecialConfig(*, no_absorption: bool = False, no_scattering: bool = False, no_scattering_mol: bool = False, include_files: list[str] = <factory>)[source]

Bases: UvspecOption

Special options: scattering/absorption toggles and include files.

no_absorption

Disable all absorption.

Type:

bool

no_scattering

Disable all scattering.

Type:

bool

no_scattering_mol

Disable molecular scattering only.

Type:

bool

include_files

Paths to additional input files to include (Phase 0).

Type:

list[str]

include_files: list[str]
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

no_absorption: bool
no_scattering: bool
no_scattering_mol: bool
to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

validate_scattering() SpecialConfig[source]

Aerosol Models

Standard Aerosol

Aerosol configuration models.

Provides a strict class hierarchy for aerosol configuration:

  • OpacPreset: OPAC preset mixture profiles (continental_average, maritime_clean, etc.)

  • OpacCustom: OPAC custom species profile files

Reference: libRadtran src/uvspec_lex.l (aerosol options) Reference: Hess et al. (1998), Bull. Amer. Meteor. Soc., 79, 831-844

class pyradtran.models.aerosol.AerosolModel(*, modify: list[AerosolModifyEntry] = <factory>)[source]

Bases: UvspecOption

Abstract base class for all aerosol configurations.

Subclasses implement mode-specific to_uvspec_lines(). The common modify capability is handled here.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

modify: list[AerosolModifyEntry]
to_uvspec_items() list[tuple[int, str]][source]

Return (phase, keyword_line) pairs for priority-sorted output.

Subclasses may override to assign different phases to different keywords. Default phase is 9 (output section).

abstractmethod to_uvspec_lines() list[str][source]

Serialize this configuration to uvspec input file lines.

Returns:

List of strings, each being one line of a uvspec input file.

class pyradtran.models.aerosol.AerosolModifyEntry(*, variable: str, action: str, value: float)[source]

Bases: UvspecOption

A single aerosol_modify directive.

variable

Property to modify (gg, ssa, tau, tau550).

Type:

str

action

How to modify (scale or set).

Type:

str

value

Numeric value.

Type:

float

action: str
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

validate_entry() AerosolModifyEntry[source]
value: float
variable: str
class pyradtran.models.aerosol.OpacCustom(*, species_file: Annotated[str, MinLen(min_length=1)], rh_pct: float = 50.0, species_names: list[str] | None = None, data_path: str | None = None, n_legendre: int = 32)[source]

Bases: BaseModel

Factory: fold a user OPAC species profile file into PlacedBlock pieces.

Like OpacPreset but the mass-concentration profile is a user-supplied ASCII file (same format as standard_aerosol_files).

data_path: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
rh_pct: float
species_file: str
species_names: list[str] | None
to_composite(wavelength_grid_um, output_dir=None)[source]

Wrap to_placed_blocks() in a CompositeAerosol on the profile grid.

to_placed_blocks() list[source]

Return one PlacedBlock per profile species with nonzero mass.

validate_species() OpacCustom[source]
class pyradtran.models.aerosol.OpacPreset(*, name: OpacPresetName, rh_pct: float = 50.0, species_names: list[str] | None = None, data_path: str | None = None, n_legendre: int = 32)[source]

Bases: BaseModel

Factory: fold an OPAC preset mixture into LEGO PlacedBlock pieces.

Each species with nonzero mass in the preset profile becomes one MieSpecies (OPAC refractive index + OPAC lognormal at rh_pct) using the real Mie phase function, placed via its preset mass column. The pieces drop into CompositeAerosol(pieces=...) – the same path as bulk/Mie blocks. No precomputed OPAC tables are read; libRadtran ships only the ingredients (refractive index, size distribution, mass profile).

data_path: str | None
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
name: OpacPresetName
rh_pct: float
species_names: list[str] | None
to_composite(wavelength_grid_um, output_dir=None)[source]

Wrap to_placed_blocks() in a CompositeAerosol on the preset grid.

to_placed_blocks() list[source]

Return one PlacedBlock per preset species with nonzero mass.

validate_species() OpacPreset[source]
class pyradtran.models.aerosol.OpacPresetName(value)[source]

Bases: StrEnum

OPAC preset mixture profile names.

These correspond to files in data/aerosol/OPAC/standard_aerosol_files/.

ANTARCTIC = 'antarctic'
CONTINENTAL_AVERAGE = 'continental_average'
CONTINENTAL_CLEAN = 'continental_clean'
CONTINENTAL_POLLUTED = 'continental_polluted'
DESERT = 'desert'
DESERT_SPHEROIDS = 'desert_spheroids'
MARITIME_CLEAN = 'maritime_clean'
MARITIME_POLLUTED = 'maritime_polluted'
MARITIME_TROPICAL = 'maritime_tropical'
URBAN = 'urban'

Composite Aerosol

Composable aerosol optical-property models (Tier 1–4).

See design spec: docs/superpowers/specs/2026-04-27-composite-aerosol-design.md

class pyradtran.models.aerosol_composite.BulkSpecies(*, bulk: Any, name: str = 'BulkSpecies')[source]

Bases: BaseModel

Species backed by an aerosol3D BulkAerosolOpticsData.

The size-distribution integration is already done in aerosol3D; this class only rescales cross-sections to per-mass, resamples wavelength, and selects the Legendre convention. Duck-typed: accepts any object exposing the BulkAerosolOpticsData attributes (no hard aerosol3D import).

bulk: Any
intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]
property mass_per_particle_kg: float

Volume-weighted per-particle mass from the bulk size distribution.

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
class pyradtran.models.aerosol_composite.CompositeAerosol(*, modify: list[~pyradtran.models.aerosol.AerosolModifyEntry] = <factory>, pieces: ~typing.Annotated[list, ~annotated_types.MinLen(min_length=1)], wavelength_grid_um: ~typing.Annotated[list[float], ~annotated_types.MinLen(min_length=1)], altitude_grid_km: ~typing.Annotated[list[float], ~annotated_types.MinLen(min_length=2)], n_legendre: int = 32, output_dir: ~pathlib.Path | None = None)[source]

Bases: AerosolModel

Externally mix any number of Piece blocks via a single explicit-file path.

Each item in pieces is a Piece (e.g. PlacedBlock or DirectLayerOpticsBlock). They are combined with scattering-optical-depth weighting and written as one explicit .master/.LAYER set. The old mutual-exclusion rules and the single-source shortcut are gone: one path regardless of piece count or type.

altitude_grid_km: list[float]
evaluate(wl_um=None, z_km=None, n_legendre=None) LayerOptics[source]

Return the mixed (externally combined) LayerOptics without writing files.

model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_legendre: int
output_dir: Path | None
pieces: list
to_uvspec_lines() list[str][source]

Single execution path: every Piece -> LayerOptics -> combine -> explicit file.

validate_grids() CompositeAerosol[source]
wavelength_grid_um: list[float]
class pyradtran.models.aerosol_composite.IntegrationConfig(*, n_radius_grid: int = 200, radius_min_um: float = 0.001, radius_max_um: float = 100.0)[source]

Bases: BaseModel

Configuration for size-distribution numerical integration.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_radius_grid: int
radius_max_um: float
radius_min_um: float
class pyradtran.models.aerosol_composite.LayerOptics(tau: ndarray[tuple[Any, ...], dtype[_ScalarT]], ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]], g: ndarray[tuple[Any, ...], dtype[_ScalarT]], legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]])[source]

Bases: object

Extensive optical properties per layer.

g: ndarray[tuple[Any, ...], dtype[_ScalarT]]
legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]]
tau: ndarray[tuple[Any, ...], dtype[_ScalarT]]
class pyradtran.models.aerosol_composite.MieSpecies(*, refractive_index: ~pyradtran.models.aerosol_composite.RefractiveIndex, size_distribution: ~pyradtran.models.aerosol_composite.SizeDistribution, particle_density_kg_m3: ~typing.Annotated[float, ~annotated_types.Gt(gt=0)], integration_config: ~pyradtran.models.aerosol_composite.IntegrationConfig = <factory>, phase_function: ~typing.Literal['hg', 'mie'] = 'hg', name: str = 'MieSpecies')[source]

Bases: BaseModel

Mie-computed species from refractive index + size distribution.

integration_config: IntegrationConfig
intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]

Compute mass-normalized intensive optical properties.

Parameters:
  • wl_um – Wavelengths in micrometers.

  • n_legendre – Number of Legendre moments to generate. When phase_function='mie', moments are projected from the real Mie phase function (S1/S2 -> Legendre); the default 'hg' derives them from the Henyey-Greenstein approximation g**l.

Returns:

SpeciesOptics with beta_ext_per_mass, ssa, g, and legendre_moments.

property mass_per_particle_kg: float

Average particle mass = density * mean volume over the size distribution.

model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str
particle_density_kg_m3: float
phase_function: Literal['hg', 'mie']
refractive_index: RefractiveIndex
size_distribution: SizeDistribution
class pyradtran.models.aerosol_composite.RefractiveIndex(*, wavelength_um: Annotated[list[float], MinLen(min_length=2)], n_real: list[float], k_imag: Annotated[list[float], MinLen(min_length=1)])[source]

Bases: BaseModel

Wavelength-dependent complex refractive index.

Interpolation is log-linear in wavelength.

at(wl_um: ndarray) ndarray[source]

Interpolate refractive index to requested wavelengths.

k_imag: list[float]
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_real: list[float]
validate_lengths_and_sorted() RefractiveIndex[source]
wavelength_um: list[float]
class pyradtran.models.aerosol_composite.SizeDistribution(*, kind: Literal['lognormal', 'modified_gamma', 'discrete', 'monodisperse'], params: dict, number_density_per_m3: float = 1.0)[source]

Bases: BaseModel

Aerosol particle size distribution.

evaluate(r_grid_um: ndarray) ndarray[source]
kind: Literal['lognormal', 'modified_gamma', 'discrete', 'monodisperse']
model_config = {'extra': 'forbid', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

number_density_per_m3: float
params: dict
validate_params() SizeDistribution[source]
class pyradtran.models.aerosol_composite.SpeciesOptics(beta_ext_per_mass: ndarray[tuple[Any, ...], dtype[_ScalarT]], ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]], g: ndarray[tuple[Any, ...], dtype[_ScalarT]], legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None)[source]

Bases: object

Mass-normalized intensive optical properties of an aerosol species.

beta_ext_per_mass: ndarray[tuple[Any, ...], dtype[_ScalarT]]
g: ndarray[tuple[Any, ...], dtype[_ScalarT]]
legendre_moments: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None
ssa: ndarray[tuple[Any, ...], dtype[_ScalarT]]

Aerosol Optics

Pure-NumPy Mie scattering (Bohren-Huffman algorithm).

No scipy dependency — uses only numpy for all computations.

pyradtran.optics.mie.bhmie(x: float, m: complex, n_angles: int = 0) dict[source]

Compute Mie scattering for a single homogeneous sphere.

Parameters:
  • x – Size parameter 2*pi*r/lambda.

  • m – Complex refractive index relative to surrounding medium.

  • n_angles – Number of equally-spaced scattering angles between 0 and 180° for phase-function output. 0 = skip angular computation.

Returns:

  • Qext: Extinction efficiency.

  • Qsca: Scattering efficiency.

  • Qback: Backscatter efficiency.

  • g: Asymmetry parameter <cos(theta)>.

  • S1, S2 (if n_angles > 0): Complex amplitude functions.

  • angles_deg (if n_angles > 0): Angle grid in degrees.

Return type:

Dictionary with keys

Reference:

Bohren & Huffman, Absorption and Scattering of Light by Small Particles, Wiley, 1983. Fortran code bhmie.f translated to Python/NumPy.

pyradtran.optics.mie.integrate_size_distribution(*, wavelength_um: list[float], radius_um: list[float], Qext: ndarray, Qsca: ndarray, g: ndarray, legendre_moments: ndarray | None, size_distribution: SizeDistribution, particle_density_kg_m3: float, config: IntegrationConfig, n_legendre: int = 32) _SpeciesOptics[source]

Integrate Q-factors over size distribution to get intensive species optics.

pyradtran.optics.mie.phase_function_to_legendre(s1: ndarray, s2: ndarray, angles_deg: ndarray, n_legendre: int) ndarray[source]

Project the unpolarised Mie phase function onto Legendre polynomials.

P(mu) |S1|^2 + |S2|^2, normalised so (1/2) ∫_{-1}^{1} P(mu) dmu = 1. Returns beta_l = (1/2) ∫_{-1}^{1} P(mu) P_l(mu) dmu for l = 0..n_legendre-1 — the PMOM / g_l form (beta_0 = 1, beta_1 = asymmetry parameter). Pure numpy (no scipy): Legendre polynomials via the Bonnet recurrence.

External mixing rules for aerosol optical properties.

pyradtran.optics.mixing.combine_sources(sources: list, n_legendre: int) dict[source]

Externally mix N aerosol sources into a single LayerOptics-like dict.

Parameters:
  • sources – List of LayerOptics objects.

  • n_legendre – Number of Legendre moments.

Returns:

Dict with keys tau, ssa, g, legendre_moments. All arrays have shape (n_wl, n_layer, …).

Writer for libRadtran aerosol_file explicit format.

Produces:
  • master file: maps altitudes to .LAYER filenames

  • per-layer .LAYER files: wavelength_nm beta_ext_per_km ssa k_0 k_1 …

  • NULL.LAYER: zero-optical-depth placeholder

pyradtran.optics.layer_writer.read_explicit_aerosol(master_path)[source]

Read a libRadtran explicit aerosol master + per-layer files.

Inverse of write_explicit_aerosol(). Returns a 6-tuple (tau, ssa, g, legendre_moments, wavelength_um, altitude_km) where tau/ssa/g have shape (n_wl, n_layer) and legendre_moments has shape (n_wl, n_layer, n_legendre). The top NULL layer (zero optical thickness) is dropped.

pyradtran.optics.layer_writer.write_explicit_aerosol(*, tau: ndarray, ssa: ndarray, g: ndarray, legendre_moments: ndarray, wavelength_um: ndarray, altitude_km: ndarray, output_dir: Path, source_signatures: list[str]) Path[source]

Write explicit aerosol files for libRadtran.

Parameters:
  • tau – Optical depth per layer, shape (n_wl, n_layer).

  • ssa – Single-scattering albedo, shape (n_wl, n_layer).

  • g – Asymmetry parameter, shape (n_wl, n_layer).

  • legendre_moments – Legendre expansion coefficients, shape (n_wl, n_layer, n_legendre).

  • wavelength_um – Wavelength grid in um, shape (n_wl,).

  • altitude_km – Altitude boundaries in km, strictly descending, shape (n_layer+1,).

  • output_dir – Directory to write files.

  • source_signatures – Strings identifying sources (for hashing).

Returns:

Path to the master file.

Readers for libRadtran OPAC ASCII ingredients.

OPAC ships only ingredients (no precomputed tables); libRadtran computes optics at runtime via internal Mie. These parsers return pyRadtran data structures so the existing MieSpecies path can fold OPAC species. Files live under <data_root>/aerosol/OPAC/:

  • refractive_indices/<sp><rh>_refr.dat : 3-col (lambda_um n_real n_imag), 61 wl

  • size_distr.cfg : 7-col (no rh Rmin Rmax Rmod Rho Sigma)

  • standard_aerosol_files/<preset>.dat : z(km) x per-species mass columns (g/m^3)

pyradtran.optics.opac.read_opac_preset_profile(name: str, *, data_path: str | Path | None = None) dict[str, tuple[ndarray, ndarray]][source]

Read standard_aerosol_files/<name>.dat (wrapper over the file parser).

pyradtran.optics.opac.read_opac_profile_file(path: str | Path) dict[str, tuple[ndarray, ndarray]][source]

Parse a standard aerosol profile file -> {species: (z_km, mass_g_m3)}.

The file is altitude (km) followed by one mass-concentration column (g/m^3) per OPAC species. A # header line lists the species codes (after a z(km) label); its species tokens map columns. If no header is found, the canonical 10-species order is assumed for the columns present. Altitude is returned in file order (standard presets are descending).

pyradtran.optics.opac.read_opac_refractive_index(species: str, rh_pct: float = 50.0, *, data_path: str | Path | None = None) RefractiveIndex[source]

Read <sp><rh>_refr.dat -> RefractiveIndex.

OPAC stores the imaginary part negative (its sign convention is m = n - i*kappa); bhmie/Bohren-Huffman use Im(m) > 0 for absorption, and RefractiveIndex rejects k < 0. We therefore return the absolute value, so RefractiveIndex.at() yields m = n + i*k (k>0).

pyradtran.optics.opac.read_opac_size_distribution(species: str, rh_pct: float = 50.0, *, data_path: str | Path | None = None) tuple[SizeDistribution, float][source]

Read the matching size_distr.cfg row.

Columns: no rh Rmin Rmax Rmod[um] Rho Sigma. Rho is treated as g/cm^3 (the values are physical densities; the cfg header label [g/m**3] is misleading) and returned as kg/m^3. Returns (lognormal SizeDistribution, density_kg_m3).

pyradtran.optics.opac.snap_rh(species: str, rh_pct: float) int[source]

Snap a requested RH to the nearest available OPAC level for species.

Non-hygroscopic species only have RH=0 (the 00 file); the request is ignored. Hygroscopic species snap to the nearest of the tabulated levels (ties round down to the lower level).

Presets

Site altitudes, standard atmosphere profiles, and common configurations.

pyradtran.presets.resolve_altitude(altitude: float | str) float[source]

Resolve altitude – accepts km float or site preset name.

Data Layer

Bundled libRadtran data + access layer.

Provides DataResolver for locating data files with a three-tier priority (explicit path > environment variable > bundled subset) and an optional bundled_only mode for reproducible runs.

class pyradtran.data.Asset(category: str, name: str, uvspec_keyword: str, paths: tuple[str, ...])[source]

Bases: object

A single bundled data asset.

category

Logical group (atmosphere_profile, solar_flux, ckd, …).

Type:

str

name

The user-facing reference value for the consuming uvspec keyword (e.g. “US-standard”, “kurudz_1.0nm.dat”, “reptran coarse”).

Type:

str

uvspec_keyword

The uvspec keyword that consumes this asset.

Type:

str

paths

One or more paths relative to the data root.

Type:

tuple[str, …]

category: str
name: str
paths: tuple[str, ...]
uvspec_keyword: str
class pyradtran.data.DataResolver(*, data_root: str | PathLike | None = None, bundled_only: bool = False)[source]

Bases: object

Resolve logical data references to absolute paths under the data root.

property data_root: Path

The effective data_files_path used for this resolver.

is_available(category: str, name: str) bool[source]

True if the asset is present on disk.

Unknown (category, name) – not in the bundled manifest – are treated as permissively available (assumed resolvable via an external data root).

list_bundled(category: str | None = None) list[Asset][source]

List bundled assets, optionally filtered by category.

resolve(category: str, name: str) Path[source]

Return the absolute path of an asset’s first file.

Raises FileNotFoundError if the (category, name) is unknown to the bundled manifest or its file is missing on disk.

validate_scene(scene) list[ValidationIssue][source]

Check high-value data references in a Scene against available data.

Returns a list of ValidationIssue for references whose bundled-asset files are missing under the current data root. References absent from the bundled manifest are treated as permissively available (externally).

First batch covers: atmosphere profile, solar_flux_file, mol_abs_param, and OPAC aerosol library.

class pyradtran.data.ValidationIssue(severity: str, category: str, name: str, message: str)[source]

Bases: object

A single data-reference problem found when validating a Scene.

severity

“warning” (default) or “error”.

Type:

str

category

Manifest category of the missing/referenced asset.

Type:

str

name

The user-facing reference value that could not be satisfied.

Type:

str

message

Human-readable explanation.

Type:

str

category: str
message: str
name: str
severity: str
pyradtran.data.get_data_root(*, bundled_only: bool = False)[source]

Return the effective data_files_path (convenience wrapper).

pyradtran.data.list_bundled(category: str | None = None)[source]

List bundled assets (convenience wrapper).

pyradtran.data.load_manifest() list[Asset][source]

Load bundled MANIFEST.toml into a list of Asset objects.

Returns an empty list when the manifest contains no [[assets]] entries.

pyradtran.data.resolve(category: str, name: str, *, bundled_only: bool = False)[source]

Resolve a logical reference to an absolute path (convenience wrapper).

DataResolver: locate libRadtran data files with tiered fallback.

Resolution priority for the data root (data_files_path):
  1. explicit data_root argument (user is most explicit)

  2. LIBRADTRAN_DATA_FILES environment variable

  3. LIBRADTRANDIR environment variable (its data/ subdir)

  4. bundled subset at pyradtran/data/assets

bundled_only=True overrides 1-3 and always uses the bundled root (for reproducible runs / CI).

class pyradtran.data.resolver.DataResolver(*, data_root: str | PathLike | None = None, bundled_only: bool = False)[source]

Bases: object

Resolve logical data references to absolute paths under the data root.

property data_root: Path

The effective data_files_path used for this resolver.

is_available(category: str, name: str) bool[source]

True if the asset is present on disk.

Unknown (category, name) – not in the bundled manifest – are treated as permissively available (assumed resolvable via an external data root).

list_bundled(category: str | None = None) list[Asset][source]

List bundled assets, optionally filtered by category.

resolve(category: str, name: str) Path[source]

Return the absolute path of an asset’s first file.

Raises FileNotFoundError if the (category, name) is unknown to the bundled manifest or its file is missing on disk.

validate_scene(scene) list[ValidationIssue][source]

Check high-value data references in a Scene against available data.

Returns a list of ValidationIssue for references whose bundled-asset files are missing under the current data root. References absent from the bundled manifest are treated as permissively available (externally).

First batch covers: atmosphere profile, solar_flux_file, mol_abs_param, and OPAC aerosol library.

Aerosol Building Blocks (LEGO)

LEGO aerosol blocks: unified interface for mixing any aerosol source.

Three-layer protocol (see spec 2026-06-18-lego-aerosol-blocks-design.md §4.2):

  • AerosolBlockintensive(): the mass-normalized optical identity.

  • VerticalProfile — column placement (per-layer kg/m^3).

  • Pieceto_layer_optics(): the mixing contract (added in Task 3).

This module imports SpeciesOptics (and, from Task 3, LayerOptics) from aerosol_composite; the reverse dependency is deferred (inside CompositeAerosol methods) to avoid a circular import.

class pyradtran.models.blocks.AerosolBlock(*args, **kwargs)[source]

Bases: Protocol

A mass-normalized aerosol species that can report its intensive optics.

intensive(wl_um: ndarray, n_legendre: int = 32) SpeciesOptics[source]
property mass_per_particle_kg: float
name: str
class pyradtran.models.blocks.DirectLayerOpticsBlock(master_path: str, name: str = 'explicit_file')[source]

Bases: object

Direct-route piece: a pre-computed explicit aerosol file set (.master + .LAYER).

The file already contains per-layer tau/ssa/pmom, so no VerticalProfile is needed — to_layer_optics parses the file directly. Wavelength resampling is not performed (v1): the requested grid must match the file’s grid.

master_path: str
name: str = 'explicit_file'
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.models.blocks.ExponentialProfile(rho0_kg_m3: float, scale_height_km: float)[source]

Bases: object

rho(z) = rho0 * exp(-z / H), evaluated at the requested altitudes (km).

evaluate(altitude_km) ndarray[source]
rho0_kg_m3: float
scale_height_km: float
class pyradtran.models.blocks.MassProfile(kg_m3_per_layer: tuple[float, ...])[source]

Bases: object

Explicit per-layer mass concentration (kg/m^3).

Values are stored in descending-altitude layer order (matching the altitude_grid_km convention used by CompositeAerosol). evaluate returns them verbatim; the altitude argument is accepted only for interface compatibility with ExponentialProfile.

evaluate(altitude_km) ndarray[source]
kg_m3_per_layer: tuple[float, ...]
class pyradtran.models.blocks.Piece(*args, **kwargs)[source]

Bases: Protocol

The mixing contract: anything CompositeAerosol accepts produces per-layer LayerOptics on the shared (wavelength, altitude) grid.

name: str
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.models.blocks.PlacedBlock(block: AerosolBlock, profile: VerticalProfile, modify: tuple[AerosolModifyEntry, ...] = ())[source]

Bases: object

Intensity-route piece: a mass-normalized species placed in the column.

Ports the non-OPAC path of LoadedSpecies.evaluate: the block’s intensive optics are weighted by the profile’s per-layer mass and the layer thickness to give extensive per-layer optical properties.

block: AerosolBlock
modify: tuple[AerosolModifyEntry, ...] = ()
property name: str
profile: VerticalProfile
to_layer_optics(wl_um: ndarray, altitude_km, n_legendre: int = 32) LayerOptics[source]
class pyradtran.models.blocks.TabulatedProfile(z_km: tuple[float, ...], kg_m3: tuple[float, ...])[source]

Bases: object

Mass concentration (kg/m^3) tabulated vs altitude (km).

Linear interpolation in altitude; outside [z_min, z_max] the value is clipped to the nearest table entry. z_km may be ascending or descending. Used to place OPAC preset mass columns, which come on the preset’s own grid.

evaluate(altitude_km) ndarray[source]
kg_m3: tuple[float, ...]
z_km: tuple[float, ...]
class pyradtran.models.blocks.VerticalProfile(*args, **kwargs)[source]

Bases: Protocol

Column placement: returns mass concentration (kg/m^3) at each altitude.

evaluate(altitude_km) ndarray[source]
pyradtran.models.blocks.od_to_mass_profile(block: AerosolBlock, tau_ref: float, ref_nm: float, altitude_km, scale_height_km: float) MassProfile[source]

Invert a target column optical depth into an exponential MassProfile.

The returned per-layer masses are chosen so that, evaluated on altitude_km with the block’s beta_ext_per_mass at ref_nm, they sum to exactly tau_ref:

tau_ref = beta_ext_per_mass(ref) * sum_layers( rho_layer * dz )

This is the discrete, grid-exact inversion (the column OD the RT solver will actually see), replacing the example-side compute_mass_profile glue.

Parameters:
  • block – An AerosolBlock with a positive beta_ext_per_mass at ref.

  • tau_ref – Target column optical depth at ref_nm (dimensionless).

  • ref_nm – Reference wavelength in nm.

  • altitude_km – Layer-boundary altitudes in km, strictly descending.

  • scale_height_km – Exponential scale height H (km).

Returns:

A MassProfile whose layers follow the exponential shape and whose column OD equals tau_ref.

Postprocessing

Pure dataset post-processing for RT outputs (no Runner / no libRadtran).

Transforms raw parsed flux datasets into physically meaningful quantities. Kept separate from pyradtran.viz so the same derivations serve numeric use (logging, NetCDF export, comparisons) without importing matplotlib.

class pyradtran.core.postprocess.BudgetResult(transmittance: ndarray, reflectance: ndarray, absorptance: ndarray, wavelength: ndarray)[source]

Bases: object

Spectral transmittance / reflectance / absorptance of the column.

absorptance: ndarray
reflectance: ndarray
transmittance: ndarray
wavelength: ndarray
pyradtran.core.postprocess.add_budget_vars(ds: Dataset, *, f_incident: str = 'edir') Dataset[source]

Return a copy of ds with transmittance/reflectance/absorptance.

Conventions: T = (edir+edn)@surface / f_incident@TOA, R = eup@TOA / f_incident@TOA, A = 1 - T - R. Surface = lowest zout level, TOA = highest zout level.

pyradtran.core.postprocess.compute_budget(ds: Dataset, *, f_incident: str = 'edir') BudgetResult[source]

Typed companion to add_budget_vars() returning a BudgetResult.

pyradtran.core.postprocess.evaluate_blocks_on_grid(comp, wl_um, z_km, n_legendre: int = 32) dict[str, Dataset][source]

Per-piece (tau, rho) on the grid; one dataset per block name.

tau comes from each piece’s to_layer_optics; rho_kg_m3 is added only for pieces that carry a profile (e.g. PlacedBlock).

pyradtran.core.postprocess.evaluate_composite_on_grid(comp, wl_um, z_km, n_legendre: int = 32) Dataset[source]

Evaluate the mixed composite optics on a (wavelength, layer) grid.

Calls comp.evaluate(...) (pure analytic mixing — no RT) and wraps the resulting LayerOptics as an xarray.Dataset with a layer dimension indexed by layer-center altitude.

Visualization

pyRadtran visualization layer (pure data-in -> fig-out; lazy matplotlib).

class pyradtran.viz.AttributionLike(*args, **kwargs)[source]

Bases: Protocol

property contributions: dict[str, Dataset]
property full: Dataset
pyradtran.viz.get_palette(n: int) list[str][source]

Return n colorblind-safe colors (cycling the Okabe-Ito set).

pyradtran.viz.plot_block_profiles(per_block_ds_dict: dict[str, Dataset], *, quantity: str = 'tau', ax=None, save_path=None)[source]

Per-block τ(z) (spectrally summed over wavelength) or ρ(z) vs altitude.

The τ curve is tau.sum(axis=0) — the per-layer sum over wavelength, a rough “spectral optical burden per layer” overview. For a physically meaningful τ(z) at a specific band, slice the block dataset to that wavelength before passing it in.

pyradtran.viz.plot_budget(ds: Dataset, *, components=('transmittance', 'reflectance', 'absorptance'), ax=None, save_path=None)[source]

Stacked-area plot of T/R/A vs wavelength. Requires a budget-enriched dataset.

pyradtran.viz.plot_component_attribution(result: AttributionLike, *, variable: str = 'edir', level='surface', ax=None, save_path=None)[source]

Plot per-block contributions (full - leave_one_out) plus the full curve.

pyradtran.viz.plot_composite_optics(ds: Dataset, *, quantity: str = 'tau', ax=None, save_path=None)[source]

pcolormesh of τ / ssa / g over (wavelength, altitude) for the mixed composite.

pyradtran.viz.plot_flux_profile(ds: Dataset, *, variable: str = 'edir', wavelength_nm: float = 550.0, ax=None, save_path=None)[source]

Plot a flux variable vs altitude (km) at the wavelength nearest wavelength_nm.

pyradtran.viz.plot_heating_rate(ds: Dataset, *, wavelength_nm: float | None = None, ax=None, save_path=None)[source]

Plot heating rate vs altitude (km).

If wavelength_nm is None, plot all wavelengths as faint background lines; otherwise plot the nearest-wavelength line bold.

pyradtran.viz.plot_rt_overview(ds: Dataset, *, wavelength_nm: float = 550.0)[source]

Convenience multi-panel: spectral (surface) + flux profile + budget.

pyradtran.viz.plot_spectral(ds: Dataset, *, variables=('edir', 'edn', 'eup'), level='surface', ax=None, save_path=None)[source]

Plot selected flux variables vs wavelength at a single zout level.

For 2-D datasets, level="surface" selects the lowest-altitude zout level.

pyradtran.viz.save(fig, path, *, formats=('pdf', 'png')) None[source]

Save fig to path with each extension in formats appended.

pyradtran.viz.set_theme(style: str = 'publication') None[source]

Apply rcParams for the requested style.

publication (default): higher DPI, larger fonts, tighter layout. diagnostic: lighter settings for quick iteration.

Workflow

RT orchestration workflows (drive the Runner to produce structured results).

class pyradtran.workflow.AttributionResult(full: Dataset, contributions: dict[str, Dataset])[source]

Bases: object

Full-field run plus per-block contribution datasets.

contributions: dict[str, Dataset]
full: Dataset
pyradtran.workflow.compute_component_attribution(build_scene: Callable, composite, execute_many: Callable[[list], list[Dataset]]) AttributionResult[source]

Compute per-block RT contributions by leave-one-out subtraction.

Parameters:
  • build_scene – Callable mapping a (possibly leave-one-out) composite to a runnable Scene.

  • composite – A composite with .pieces and .model_copy(update=...).

  • execute_many – Callable running a list of scenes in parallel and returning the parsed datasets in the same order (e.g. lambda scenes: Runner.execute_many(scenes, uvspec_exe=..., data_path=...)).

Returns:

AttributionResult whose contributions[piece.name] is full - leave_piece_out.