Source code for thin_film.optimization.variable.layer_thickness

"""Layer Thickness Variable Module

This module contains the LayerThicknessVariable class, which represents a variable
for the thickness of a layer in a thin film stack. The class provides methods
to get and update the layer thickness for optimization purposes.

Corentin Nannini, 2025
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from optiland.optimization.variable.base import VariableBehavior

if TYPE_CHECKING:
    from optiland.thin_film import ThinFilmStack


[docs] class LayerThicknessVariable(VariableBehavior): """Represents a variable for a thin film layer thickness. This class inherits from VariableBehavior and provides specific functionality for optimizing the thickness of individual layers in a ThinFilmStack. Args: stack (ThinFilmStack): The thin film stack containing the layer. layer_index (int): The index of the layer in the stack (0-based). apply_scaling (bool): Whether to apply scaling for optimization. Defaults to True. **kwargs: Additional keyword arguments passed to parent class. Attributes: stack (ThinFilmStack): The thin film stack. layer_index (int): The index of the target layer. """ def __init__( self, stack: ThinFilmStack, layer_index: int, apply_scaling=True, **kwargs ): # Initialize attributes without calling parent __init__ # since we don't have an optic object self.optic = None # Not used for thin film variables self._surfaces = None # Not used for thin film variables self.surface_number = layer_index # For compatibility self.apply_scaling = apply_scaling # Thin film specific attributes self.stack = stack self.layer_index = layer_index if layer_index < 0 or layer_index >= len(stack.layers): raise ValueError( f"layer_index {layer_index} is out of range for " + f"stack with {len(stack.layers)} layers" )
[docs] def get_value(self) -> float: """Returns the current thickness value of the layer in micrometers. Returns: float: The current thickness value in μm. """ value = self.stack.layers[self.layer_index].thickness_um if self.apply_scaling: return self.scale(value) return value
[docs] def update_value(self, new_value: float) -> None: """Updates the thickness value of the layer. Args: new_value (float): The new thickness value in μm (or scaled units). """ if self.apply_scaling: new_value = self.inverse_scale(new_value) # Ensure positive thickness - clamp to minimum instead of raising exception if new_value <= 0: new_value = 0.000001 # Force minimum thickness of 0.01 nm self.stack.layers[self.layer_index].update_thickness(new_value)
[docs] def scale(self, value: float) -> float: """Scale the thickness value for improved optimization performance. Converts from micrometers to a scaled representation that's better conditioned for numerical optimization. Args: value (float): The thickness value in μm to scale. Returns: float: The scaled value. """ # Scale: μm -> approximately unit scale # Typical thin film thicknesses are 0.01-1 μm, so divide by 0.1 return value / 0.1 - 1.0
[docs] def inverse_scale(self, scaled_value: float) -> float: """Inverse scale the thickness value. Converts from scaled representation back to micrometers. Args: scaled_value (float): The scaled value to inverse scale. Returns: float: The thickness value in μm. """ return (scaled_value + 1.0) * 0.1
@property def thickness_nm(self) -> float: """Get the current thickness in nanometers. Returns: float: The current thickness in nm. """ return self.stack.layers[self.layer_index].thickness_um * 1000.0 def __repr__(self) -> str: """String representation of the variable.""" thickness_nm = self.thickness_nm return ( f"LayerThicknessVariable(layer_index={self.layer_index}" + f", thickness={thickness_nm:.1f} nm)" )