Source code for nirs4all.data.synthetic.environmental

"""
Environmental effects configuration for synthetic NIRS data generation.

This module provides configuration classes for environmental and matrix effects
on NIR spectra, including temperature-induced changes and moisture/water activity
effects.

Note:
    For applying environmental effects to spectra, use the operators in
    `nirs4all.operators.augmentation.environmental`:
    - TemperatureAugmenter: Temperature-induced spectral changes
    - MoistureAugmenter: Moisture/water activity effects

Key Features:
    - Temperature-dependent peak shifts (especially O-H bands)
    - Temperature-dependent intensity changes (hydrogen bonding effects)
    - Temperature-dependent band broadening (thermal motion)
    - Region-specific temperature effects (water vs. C-H bands)
    - Moisture/water activity effects on hydrogen bonding
    - Free water vs. bound water band differentiation

References:
    - Maeda, H., Ozaki, Y., Tanaka, M., Hayashi, N., & Kojima, T. (1995).
      Near infrared spectroscopy and chemometrics studies of temperature-dependent
      spectral variations of water. Journal of Near Infrared Spectroscopy, 3(4), 191-201.
    - Segtnan, V. H., Šašić, Š., Isaksson, T., & Ozaki, Y. (2001). Studies on the
      structure of water using two-dimensional near-infrared correlation spectroscopy
      and principal component analysis. Analytical Chemistry, 73(13), 3153-3161.
    - Büning-Pfaue, H. (2003). Analysis of water in food by near infrared spectroscopy.
      Food Chemistry, 82(1), 107-115.
    - Luck, W. A. P. (1998). The importance of cooperativity for the properties of
      liquid water. Journal of Molecular Structure, 448(2-3), 131-142.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, Optional, Tuple


# ============================================================================
# Temperature Effect Parameters by Spectral Region
# ============================================================================

[docs] class SpectralRegion(str, Enum): """NIR spectral regions with distinct temperature responses.""" OH_FIRST_OVERTONE = "oh_1st_overtone" # ~1400-1500 nm (O-H stretch 1st overtone) OH_COMBINATION = "oh_combination" # ~1900-2000 nm (O-H stretch + bend) CH_FIRST_OVERTONE = "ch_1st_overtone" # ~1650-1750 nm (C-H stretch 1st overtone) CH_COMBINATION = "ch_combination" # ~2200-2400 nm (C-H combinations) NH_FIRST_OVERTONE = "nh_1st_overtone" # ~1500-1550 nm (N-H stretch 1st overtone) NH_COMBINATION = "nh_combination" # ~2000-2100 nm (N-H combinations) WATER_FREE = "water_free" # Free water O-H WATER_BOUND = "water_bound" # Hydrogen-bonded water O-H
[docs] @dataclass class TemperatureEffectParams: """ Temperature effect parameters for a spectral region. Based on literature values for temperature-induced spectral changes in NIR. Attributes: wavelength_range: Affected wavelength range (nm). shift_per_degree: Peak position shift per °C (nm). Negative = blue shift. intensity_change_per_degree: Fractional intensity change per °C. broadening_per_degree: Fractional bandwidth increase per °C. reference: Literature reference for values. """ wavelength_range: Tuple[float, float] shift_per_degree: float # nm/°C intensity_change_per_degree: float # fraction/°C (e.g., -0.002 = -0.2%/°C) broadening_per_degree: float # fraction/°C reference: str = ""
# Literature-based temperature effect parameters TEMPERATURE_EFFECT_PARAMS: Dict[SpectralRegion, TemperatureEffectParams] = { SpectralRegion.OH_FIRST_OVERTONE: TemperatureEffectParams( wavelength_range=(1400, 1520), shift_per_degree=-0.30, # Blue shift with increasing temperature intensity_change_per_degree=-0.002, # Decreased H-bonding = lower intensity broadening_per_degree=0.001, reference="Maeda et al. (1995), Segtnan et al. (2001)" ), SpectralRegion.OH_COMBINATION: TemperatureEffectParams( wavelength_range=(1900, 2000), shift_per_degree=-0.40, # Stronger shift in combination region intensity_change_per_degree=-0.003, broadening_per_degree=0.0012, reference="Segtnan et al. (2001)" ), SpectralRegion.CH_FIRST_OVERTONE: TemperatureEffectParams( wavelength_range=(1650, 1780), shift_per_degree=-0.05, # Small shift for non-H-bonding groups intensity_change_per_degree=-0.0005, broadening_per_degree=0.0008, reference="Workman & Weyer (2012)" ), SpectralRegion.CH_COMBINATION: TemperatureEffectParams( wavelength_range=(2200, 2400), shift_per_degree=-0.08, intensity_change_per_degree=-0.0006, broadening_per_degree=0.0006, reference="Workman & Weyer (2012)" ), SpectralRegion.NH_FIRST_OVERTONE: TemperatureEffectParams( wavelength_range=(1490, 1560), shift_per_degree=-0.20, # Moderate shift for N-H intensity_change_per_degree=-0.0015, broadening_per_degree=0.001, reference="Burns & Ciurczak (2007)" ), SpectralRegion.NH_COMBINATION: TemperatureEffectParams( wavelength_range=(2000, 2150), shift_per_degree=-0.25, intensity_change_per_degree=-0.002, broadening_per_degree=0.001, reference="Burns & Ciurczak (2007)" ), SpectralRegion.WATER_FREE: TemperatureEffectParams( wavelength_range=(1380, 1420), # Free O-H peak shift_per_degree=-0.10, # Small shift for free water intensity_change_per_degree=0.003, # Increases with temperature broadening_per_degree=0.0008, reference="Luck (1998)" ), SpectralRegion.WATER_BOUND: TemperatureEffectParams( wavelength_range=(1440, 1500), # Bound O-H peak shift_per_degree=-0.35, # Larger shift for H-bonded water intensity_change_per_degree=-0.004, # Decreases with temperature broadening_per_degree=0.0015, reference="Luck (1998), Segtnan et al. (2001)" ), } # ============================================================================ # Configuration Classes # ============================================================================
[docs] @dataclass class TemperatureConfig: """ Configuration for temperature effect simulation. Attributes: reference_temperature: Reference temperature in °C (typically 25°C). sample_temperature: Actual sample temperature in °C. temperature_variation: Sample-to-sample temperature variation (std dev in °C). enable_shift: Whether to apply wavelength shifts. enable_intensity: Whether to apply intensity changes. enable_broadening: Whether to apply band broadening. region_specific: Whether to use region-specific parameters. custom_regions: Optional custom region parameters to override defaults. """ reference_temperature: float = 25.0 sample_temperature: float = 25.0 temperature_variation: float = 0.0 # Sample-to-sample variation enable_shift: bool = True enable_intensity: bool = True enable_broadening: bool = True region_specific: bool = True custom_regions: Optional[Dict[SpectralRegion, TemperatureEffectParams]] = None @property def delta_temperature(self) -> float: """Temperature difference from reference.""" return self.sample_temperature - self.reference_temperature
[docs] @dataclass class MoistureConfig: """ Configuration for moisture/water activity effect simulation. Moisture affects NIR spectra through: - Direct water absorption bands - Hydrogen bonding with sample matrix - Free vs. bound water ratio Attributes: water_activity: Water activity (a_w) value (0.0 to 1.0). moisture_content: Moisture content as fraction (optional, for intensity). free_water_fraction: Fraction of water that is "free" vs. bound (0-1). bound_water_shift: Wavelength shift for bound water relative to free (nm). temperature_interaction: Whether moisture effects interact with temperature. reference_aw: Reference water activity for baseline. """ water_activity: float = 0.5 moisture_content: float = 0.10 # 10% moisture by default free_water_fraction: float = 0.3 bound_water_shift: float = 25.0 # nm shift for bound vs free water temperature_interaction: bool = True reference_aw: float = 0.5
[docs] def __post_init__(self): """Validate water activity range.""" if not 0.0 <= self.water_activity <= 1.0: raise ValueError(f"water_activity must be 0-1, got {self.water_activity}") if not 0.0 <= self.free_water_fraction <= 1.0: raise ValueError(f"free_water_fraction must be 0-1, got {self.free_water_fraction}")
[docs] @dataclass class EnvironmentalEffectsConfig: """ Combined configuration for all environmental effects. Attributes: temperature: Temperature effect configuration. moisture: Moisture effect configuration. enable_temperature: Whether to apply temperature effects. enable_moisture: Whether to apply moisture effects. """ temperature: TemperatureConfig = field(default_factory=TemperatureConfig) moisture: MoistureConfig = field(default_factory=MoistureConfig) enable_temperature: bool = True enable_moisture: bool = True
# ============================================================================ # Utility Functions # ============================================================================
[docs] def get_temperature_effect_regions() -> Dict[str, Tuple[float, float]]: """ Get the wavelength regions with significant temperature effects. Returns: Dictionary mapping region names to (start, end) wavelength tuples. """ return { region.value: params.wavelength_range for region, params in TEMPERATURE_EFFECT_PARAMS.items() }
# ============================================================================ # Module-level exports # ============================================================================ __all__ = [ # Enums "SpectralRegion", # Dataclasses "TemperatureEffectParams", "TemperatureConfig", "MoistureConfig", "EnvironmentalEffectsConfig", # Constants "TEMPERATURE_EFFECT_PARAMS", # Utility functions "get_temperature_effect_regions", ]