Source code for pyradtran.core.input_builder

"""Serialize Scene configuration to uvspec input text."""

from __future__ import annotations

from pyradtran.models.advanced import AdvancedConfig
from pyradtran.models.aerosol import AerosolModel
from pyradtran.models.atmosphere import AtmosphereConfig
from pyradtran.models.cloud import CloudConfig
from pyradtran.models.mc import McConfig
from pyradtran.models.output import OutputConfig
from pyradtran.models.solver import SolverConfig
from pyradtran.models.source import SourceConfig
from pyradtran.models.special import SpecialConfig
from pyradtran.models.sslidar import SslidarConfig
from pyradtran.models.surface import SurfaceConfig
from pyradtran.models.three_d import ThreeDConfig
from pyradtran.models.wavelength import WavelengthConfig


[docs] def 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: """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) """ items: list[tuple[int, str]] = [] # Phase 0: data_files_path and include directives if data_files_path is not None: items.append((0, f"data_files_path {data_files_path}")) if special is not None: for f in special.include_files: items.append((0, f"include {f}")) items.extend(special._scattering_items()) # Collect items from all models (each assigns its own phase) items.extend(atmosphere.to_uvspec_items()) items.extend(source.to_uvspec_items()) if aerosol is not None: items.extend(aerosol.to_uvspec_items()) if cloud is not None: items.extend(cloud.to_uvspec_items()) if surface is not None: items.extend(surface.to_uvspec_items()) items.extend(solver.to_uvspec_items()) items.extend(wavelength.to_uvspec_items()) items.extend(output.to_uvspec_items()) if mc is not None: items.extend(mc.to_uvspec_items()) if sslidar is not None: items.extend(sslidar.to_uvspec_items()) if advanced is not None: items.extend(advanced.to_uvspec_items()) if three_d is not None: items.extend(three_d.to_uvspec_items()) # Phase 13: raw_keywords always last if raw_keywords: for key, value in raw_keywords: if value: items.append((13, f"{key} {value}")) else: items.append((13, key)) # Sort by phase, preserving relative order within the same phase items.sort(key=lambda x: x[0]) return "\n".join(line for _, line in items) + "\n"