Source code for lsurf.materials.base.full_inhomogeneous

# The Clear BSD License
#
# Copyright (c) 2026 Tobias Heibges
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted (subject to the limitations in the disclaimer
# below) provided that the following conditions are met:
#
#      * Redistributions of source code must retain the above copyright notice,
#      this list of conditions and the following disclaimer.
#
#      * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#
#      * Neither the name of the copyright holder nor the names of its
#      contributors may be used to endorse or promote products derived from this
#      software without specific prior written permission.
#
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""
Full Inhomogeneous Model (CPU-only, Arbitrary Python)

Base class for arbitrary 3D inhomogeneous materials (CPU-only).
Use this when you need maximum flexibility and cannot express your model
using the other tiers. Any Python code is allowed.
"""

from abc import ABC, abstractmethod

import numpy as np
from numpy.typing import NDArray

from .material_field import MaterialField


[docs] class FullInhomogeneousModel(MaterialField, ABC): """ Base class for arbitrary 3D inhomogeneous materials (CPU-only). Use this when you need maximum flexibility and cannot express your model using the other tiers. Any Python code is allowed, including external libraries, database lookups, or complex computations. GPU acceleration is not available for this tier. Use GradientPropagator for CPU propagation. User must implement: - `get_refractive_index(x, y, z, wavelength)` User may optionally implement: - `get_refractive_index_gradient(x, y, z, wavelength)` (default: numerical) Example ------- >>> class WeatherModel(FullInhomogeneousModel): ... def __init__(self, weather_file): ... super().__init__(name="Weather Model") ... self._data = load_weather_data(weather_file) ... ... def get_refractive_index(self, x, y, z, wavelength): ... return self._data.interpolate(x, y, z) ... >>> model = WeatherModel("weather.nc") >>> propagator = GradientPropagator() # CPU only """
[docs] def __init__(self, name: str = "Full Inhomogeneous"): super().__init__(name) self._is_homogeneous = False
[docs] @abstractmethod def get_refractive_index( self, x: float | NDArray[np.float64], y: float | NDArray[np.float64], z: float | NDArray[np.float64], wavelength: float | NDArray[np.float64], ) -> float | NDArray[np.float64]: """ Get refractive index at position. Any Python code is allowed here. Parameters ---------- x, y, z : float or ndarray Position coordinates in meters wavelength : float or ndarray Wavelength in meters Returns ------- float or ndarray Refractive index n >= 1.0 """ pass
[docs] def get_refractive_index_gradient( self, x: float | NDArray[np.float64], y: float | NDArray[np.float64], z: float | NDArray[np.float64], wavelength: float | NDArray[np.float64], ) -> tuple[ float | NDArray[np.float64], float | NDArray[np.float64], float | NDArray[np.float64], ]: """ Get gradient of n at position. Default implementation uses numerical differentiation. Override for analytical gradients. Parameters ---------- x, y, z : float or ndarray Position coordinates in meters wavelength : float or ndarray Wavelength in meters Returns ------- tuple (dn/dx, dn/dy, dn/dz) in m^-1 """ eps = 1.0 # 1 meter step x = np.asarray(x) y = np.asarray(y) z = np.asarray(z) n = self.get_refractive_index grad_x = (n(x + eps, y, z, wavelength) - n(x - eps, y, z, wavelength)) / ( 2 * eps ) grad_y = (n(x, y + eps, z, wavelength) - n(x, y - eps, z, wavelength)) / ( 2 * eps ) grad_z = (n(x, y, z + eps, wavelength) - n(x, y, z - eps, wavelength)) / ( 2 * eps ) return grad_x, grad_y, grad_z
[docs] def get_absorption_coefficient( self, x: float | NDArray[np.float64], y: float | NDArray[np.float64], z: float | NDArray[np.float64], wavelength: float | NDArray[np.float64], ) -> float | NDArray[np.float64]: """Return absorption coefficient (default: 0).""" if isinstance(x, np.ndarray): return np.zeros_like(x) return 0.0
[docs] def get_scattering_coefficient( self, x: float | NDArray[np.float64], y: float | NDArray[np.float64], z: float | NDArray[np.float64], wavelength: float | NDArray[np.float64], ) -> float | NDArray[np.float64]: """Return scattering coefficient (default: 0).""" if isinstance(x, np.ndarray): return np.zeros_like(x) return 0.0
# ========================================================================= # GPU INTERFACE - NOT SUPPORTED # ========================================================================= @property def gpu_material_id(self) -> int: """GPU is not supported for FullInhomogeneousModel.""" raise NotImplementedError( "FullInhomogeneousModel does not support GPU acceleration. " "Use GradientPropagator for CPU propagation, or consider using " "SimpleInhomogeneousModel or GridInhomogeneousModel for GPU support." )
[docs] def get_gpu_kernels(self) -> dict: """GPU is not supported for FullInhomogeneousModel.""" raise NotImplementedError( "FullInhomogeneousModel does not support GPU acceleration." )
[docs] def get_gpu_parameters(self) -> tuple: """GPU is not supported for FullInhomogeneousModel.""" raise NotImplementedError( "FullInhomogeneousModel does not support GPU acceleration." )