Interaction Models#

Interaction models define how rays interact with a surface. Each Surface object has an InteractionModel that determines whether a ray is refracted, reflected, or diffracted.

BaseInteractionModel#

The BaseInteractionModel is an abstract base class that defines the interface for all interaction models. Its main abstract methods are:

  • interact_real_rays(rays): Interacts with real rays.

  • interact_paraxial_rays(rays): Interacts with paraxial rays.

  • flip(): Flips the interaction model (used when a surface’s orientation is reversed).

RefractiveReflectiveModel#

The RefractiveReflectiveModel is the most common interaction model. It handles both refraction and reflection based on the is_reflective flag.

ThinLensInteractionModel#

The ThinLensInteractionModel is used for paraxial surfaces. It simplifies the surface to an ideal thin lens with a given focal length.

DiffractiveModel#

The DiffractiveModel is used for surfaces with diffraction gratings. It calculates the new direction of the ray based on the grating equation.

PhaseInteractionModel#

The PhaseInteractionModel is a powerful and flexible model that can be used to create surfaces with arbitrary phase profiles. It uses the Strategy pattern to delegate the phase calculation to a BasePhaseProfile object. This allows you to create custom phase profiles by subclassing BasePhaseProfile and implementing the get_phase and get_gradient methods.

The PhaseInteractionModel can be used to create a wide variety of optical components, such as:

  • Lenses with complex aspheric or freeform surfaces

  • Diffractive optical elements (DOEs)

  • Metasurfaces

To create a surface with a phase profile, you need to create a BasePhaseProfile object and pass it to the SurfaceFactory using the phase_profile argument. The interaction_type will be automatically set to phase.

How to Extend This#

Scenario: Add a new surface interaction model to Optiland.

Step 1: Create a new file in optiland/interactions/my_interaction.py. Step 2: Subclass BaseInteractionModel and implement interact_real_rays(rays), interact_paraxial_rays(rays), and flip(). The owning surface is available via self.parent_surface (set in the base constructor), so it does not need to be passed in. Step 3: Register in optiland/interactions/__init__.py. Step 4: Add tests in tests/test_interactions/test_my_interaction.py.

For step-by-step guidance, see Extension Recipes.