Tutorial 7e - Glass expert
This tutorial aims at demonstrating Optiland’s capabilities in performing optimization on glass materials, in order to suggest a good combination to the user.
A description of GlassExpert’s architecture can be found in the documentation (Developer’s Guide: Categorical Optimization with Glass Expert)
[1]:
import optiland.backend as be
from optiland import optic, optimization
from optiland.materials import glasses_selection
target_focal_length = 100 # [mm]
class SixLensesStartPoint(optic.Optic):
"""A 6 lens design with very poor quality meant to be optimized."""
def __init__(self):
super().__init__()
self.surfaces.add(index=0, radius=be.inf, thickness=be.inf)
self.surfaces.add(index=1, radius=1000, thickness=25, material="N-BK7")
self.surfaces.add(index=2, radius=1000, thickness=5.0)
self.surfaces.add(index=3, radius=1000, thickness=25, material="N-BK7")
self.surfaces.add(index=4, radius=be.inf, thickness=25, material="N-BK7")
self.surfaces.add(index=5, radius=1000, thickness=25)
self.surfaces.add(index=6, radius=be.inf, thickness=25.0, is_stop=True)
self.surfaces.add(index=7, radius=-1000, thickness=25, material="N-BK7")
self.surfaces.add(index=8, radius=be.inf, thickness=25, material="N-BK7")
self.surfaces.add(index=9, radius=-1000, thickness=5.0)
self.surfaces.add(index=10, radius=1000, thickness=25, material="N-BK7")
self.surfaces.add(index=11, radius=-1000, thickness=200)
self.surfaces.add(index=12)
self.set_aperture(aperture_type="imageFNO", value=5)
self.fields.set_type(field_type="angle")
self.fields.add(y=-14)
self.fields.add(y=-10)
self.fields.add(y=0)
self.fields.add(y=10)
self.fields.add(y=14)
self.wavelengths.add(value=0.4861)
self.wavelengths.add(value=0.5876, is_primary=True)
self.wavelengths.add(value=0.6563)
lens = SixLensesStartPoint()
lens.draw(title="Starting lens")
lens.info()
╒════╤═══════════════╤═══════════╤══════════╤═════════════╤════════════╤═════════╤═════════════════╕
│ │ Type │ Comment │ Radius │ Thickness │ Material │ Conic │ Semi-aperture │
╞════╪═══════════════╪═══════════╪══════════╪═════════════╪════════════╪═════════╪═════════════════╡
│ 0 │ Planar │ │ inf │ inf │ Air │ 0 │ 116.634 │
│ 1 │ Standard │ │ 1000 │ 25 │ N-BK7 │ 0 │ 116.634 │
│ 2 │ Standard │ │ 1000 │ 5 │ Air │ 0 │ 111.531 │
│ 3 │ Standard │ │ 1000 │ 25 │ N-BK7 │ 0 │ 110.271 │
│ 4 │ Planar │ │ inf │ 25 │ N-BK7 │ 0 │ 105.179 │
│ 5 │ Standard │ │ 1000 │ 25 │ Air │ 0 │ 100.087 │
│ 6 │ Stop - Planar │ │ inf │ 25 │ Air │ 0 │ 93.6559 │
│ 7 │ Standard │ │ -1000 │ 25 │ N-BK7 │ 0 │ 100.023 │
│ 8 │ Planar │ │ inf │ 25 │ N-BK7 │ 0 │ 105.073 │
│ 9 │ Standard │ │ -1000 │ 5 │ Air │ 0 │ 110.123 │
│ 10 │ Standard │ │ 1000 │ 25 │ N-BK7 │ 0 │ 111.37 │
│ 11 │ Standard │ │ -1000 │ 200 │ Air │ 0 │ 114.533 │
│ 12 │ Planar │ │ inf │ nan │ Air │ 0 │ 141.078 │
╘════╧═══════════════╧═══════════╧══════════╧═════════════╧════════════╧═════════╧═════════════════╛
Operands
[2]:
problem = optimization.OptimizationProblem()
# Real ray height to define the focal length
for k, hy in enumerate([-1, -0.714, 0, 0.714, 1]):
input_data = {
"optic": lens,
"surface_number": 12,
"Hx": 0,
"Hy": hy,
"Px": 0,
"Py": 0,
"wavelength": lens.wavelengths.primary_wavelength.value,
}
problem.add_operand(
operand_type="real_y_intercept_lcs",
target=target_focal_length * be.tan(be.deg2rad(lens.fields.y_fields[k])),
weight=1,
input_data=input_data,
)
# RMS spot size - Minimize the spot size for each field at the primary wavelength.
# We choose a 'uniform' distribution, so the number of rays actually means the rays on
# one axis. Therefore we trace ≈16^2 rays here.
for field in lens.fields.get_field_coords():
input_data = {
"optic": lens,
"surface_number": 12,
"Hx": field[0],
"Hy": field[1],
"num_rays": 16,
"wavelength": lens.wavelengths.primary_wavelength.value,
"distribution": "uniform",
}
problem.add_operand(
operand_type="rms_spot_size",
target=0.0,
weight=10,
input_data=input_data,
)
Variables
[3]:
# Radii
problem.add_variable(lens, "radius", surface_number=1, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=2, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=3, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=5, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=7, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=9, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=10, min_val=-500, max_val=500)
problem.add_variable(lens, "radius", surface_number=11, min_val=-500, max_val=500)
# Thicknesses
problem.add_variable(lens, "thickness", surface_number=1, min_val=8, max_val=20)
problem.add_variable(lens, "thickness", surface_number=2, min_val=0.4, max_val=5)
problem.add_variable(lens, "thickness", surface_number=3, min_val=8, max_val=20)
problem.add_variable(lens, "thickness", surface_number=4, min_val=3, max_val=10)
problem.add_variable(lens, "thickness", surface_number=5, min_val=10, max_val=20)
problem.add_variable(lens, "thickness", surface_number=6, min_val=10, max_val=20)
problem.add_variable(lens, "thickness", surface_number=7, min_val=3, max_val=20)
problem.add_variable(lens, "thickness", surface_number=8, min_val=8, max_val=20)
problem.add_variable(lens, "thickness", surface_number=9, min_val=0.4, max_val=5)
problem.add_variable(lens, "thickness", surface_number=10, min_val=6, max_val=20)
problem.add_variable(lens, "thickness", surface_number=11, min_val=20, max_val=45)
# First option: treat glass indexes as continuous variables
# Fast but produces fictious glasses that later need to be replaced by real glasses
# problem.add_variable(lens, "index", surface_number=1, wavelength=0.5876, min_val=1.4, max_val=2.0)
# problem.add_variable(lens, "index", surface_number=3, wavelength=0.5876, min_val=1.4, max_val=2.0)
# problem.add_variable(lens, "index", surface_number=4, wavelength=0.5876, min_val=1.4, max_val=2.0)
# problem.add_variable(lens, "index", surface_number=7, wavelength=0.5876, min_val=1.4, max_val=2.0)
# problem.add_variable(lens, "index", surface_number=8, wavelength=0.5876, min_val=1.4, max_val=2.0)
# problem.add_variable(lens, "index", surface_number=10, wavelength=0.5876, min_val=1.4, max_val=2.0)
# Second option: use Optiland's Glass Expert to find the best combination
glasses = glasses_selection(0.4, 0.7, catalogs=["schott", "ohara"])
problem.add_variable(lens, "material", surface_number=1, glass_selection=glasses)
problem.add_variable(lens, "material", surface_number=3, glass_selection=glasses)
problem.add_variable(lens, "material", surface_number=4, glass_selection=glasses)
problem.add_variable(lens, "material", surface_number=7, glass_selection=glasses)
problem.add_variable(lens, "material", surface_number=8, glass_selection=glasses)
problem.add_variable(lens, "material", surface_number=10, glass_selection=glasses)
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│ │ Merit Function Value │ Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│ 0 │ 1.30983e+06 │ 0 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤══════════════════════╤══════════╤══════════════╤══════════════╤══════════╤═════════╤═════════╤════════════════╕
│ │ Operand Type │ Target │ Min. Bound │ Max. Bound │ Weight │ Value │ Delta │ Contrib. [%] │
╞════╪══════════════════════╪══════════╪══════════════╪══════════════╪══════════╪═════════╪═════════╪════════════════╡
│ 0 │ real y intercept lcs │ -24.933 │ │ │ 1 │ -66.148 │ -41.215 │ 0.13 │
│ 1 │ real y intercept lcs │ -17.633 │ │ │ 1 │ -46.975 │ -29.342 │ 0.07 │
│ 2 │ real y intercept lcs │ 0 │ │ │ 1 │ 0 │ 0 │ 0 │
│ 3 │ real y intercept lcs │ 17.633 │ │ │ 1 │ 46.975 │ 29.342 │ 0.07 │
│ 4 │ real y intercept lcs │ 24.933 │ │ │ 1 │ 66.148 │ 41.215 │ 0.13 │
│ 5 │ rms spot size │ 0 │ │ │ 10 │ 50.701 │ 50.701 │ 19.63 │
│ 6 │ rms spot size │ 0 │ │ │ 10 │ 51.176 │ 51.176 │ 19.99 │
│ 7 │ rms spot size │ 0 │ │ │ 10 │ 51.653 │ 51.653 │ 20.37 │
│ 8 │ rms spot size │ 0 │ │ │ 10 │ 51.176 │ 51.176 │ 19.99 │
│ 9 │ rms spot size │ 0 │ │ │ 10 │ 50.701 │ 50.701 │ 19.63 │
╘════╧══════════════════════╧══════════╧══════════════╧══════════════╧══════════╧═════════╧═════════╧════════════════╛
╒════╤═════════════════╤═══════════╤═════════╤══════════════╤══════════════╕
│ │ Variable Type │ Surface │ Value │ Min. Bound │ Max. Bound │
╞════╪═════════════════╪═══════════╪═════════╪══════════════╪══════════════╡
│ 0 │ radius │ 1 │ 1000.0 │ -500 │ 500 │
│ 1 │ radius │ 2 │ 1000.0 │ -500 │ 500 │
│ 2 │ radius │ 3 │ 1000.0 │ -500 │ 500 │
│ 3 │ radius │ 5 │ 1000.0 │ -500 │ 500 │
│ 4 │ radius │ 7 │ -1000.0 │ -500 │ 500 │
│ 5 │ radius │ 9 │ -1000.0 │ -500 │ 500 │
│ 6 │ radius │ 10 │ 1000.0 │ -500 │ 500 │
│ 7 │ radius │ 11 │ -1000.0 │ -500 │ 500 │
│ 8 │ thickness │ 1 │ 25.0 │ 8 │ 20 │
│ 9 │ thickness │ 2 │ 5.0 │ 0.4 │ 5 │
│ 10 │ thickness │ 3 │ 25.0 │ 8 │ 20 │
│ 11 │ thickness │ 4 │ 25.0 │ 3 │ 10 │
│ 12 │ thickness │ 5 │ 25.0 │ 10 │ 20 │
│ 13 │ thickness │ 6 │ 25.0 │ 10 │ 20 │
│ 14 │ thickness │ 7 │ 25.0 │ 3 │ 20 │
│ 15 │ thickness │ 8 │ 25.0 │ 8 │ 20 │
│ 16 │ thickness │ 9 │ 5.0 │ 0.4 │ 5 │
│ 17 │ thickness │ 10 │ 25.0 │ 6 │ 20 │
│ 18 │ thickness │ 11 │ 200.0 │ 20 │ 45 │
│ 19 │ material │ 1 │ N-BK7 │ nan │ nan │
│ 20 │ material │ 3 │ N-BK7 │ nan │ nan │
│ 21 │ material │ 4 │ N-BK7 │ nan │ nan │
│ 22 │ material │ 7 │ N-BK7 │ nan │ nan │
│ 23 │ material │ 8 │ N-BK7 │ nan │ nan │
│ 24 │ material │ 10 │ N-BK7 │ nan │ nan │
╘════╧═════════════════╧═══════════╧═════════╧══════════════╧══════════════╛
[ ]:
import matplotlib.pyplot as plt
from IPython.display import display
# As the problem has glass variables, we must use GlassExpert
optimizer = optimization.GlassExpert(problem)
# Create persistent outputs
fig_handle1 = display(display_id=True)
fig_handle2 = display(display_id=True)
fig_handle3 = display(display_id=True)
# Draw the starting lens
lens_fig = lens.draw(title="Starting lens")
fig_handle1.update(lens_fig)
plt.close(lens_fig)
print(f"Initial error function value: {problem.initial_value:.1f}")
# Define a callback that is called at each iteration of the local optimizer run.
# Used for vizualization purposes but is not recommended
# as it greatly slows down the optimization.
history = []
def callback(*args):
# Plot the lens at each merit function call
lens_fig = lens.draw(title="Lens optimization")
fig_handle2.update(lens_fig)
plt.close(lens_fig)
# Plot merit function evolution
f_val = optimizer.problem.sum_squared()
history.append(f_val)
erf_fig, ax = plt.subplots()
ax.plot(history, color="black")
plt.yscale("log")
ax.set_title("Merit function value")
ax.set_xlabel("Iteration")
ax.set_ylabel("Merit function value")
ax.grid(alpha=0.25)
fig_handle3.update(erf_fig)
plt.close(erf_fig)
# Clear the figure to free memory
del lens_fig # Remove Python reference
del erf_fig # Remove Python reference
import gc
gc.collect() # Force garbage collection
# Optimize the 6 lenses starting point
res = optimizer.run(
num_neighbours=7,
maxiter=100,
tol=1e-6,
callback=callback,
verbose=True,
plot_glass_map=False,
)
# Display the optimized lens
lens.draw(title="Optimized lens")
lens.info()
Initial error function value: 1309831.7
Initial glasses combination: ['N-BK7', 'N-BK7', 'N-BK7', 'N-BK7', 'N-BK7', 'N-BK7']
----------------------------------------------------------------------
Global exploration
Selecting Material, Surface 1:
Trying TIH23 as Material, Surface 1. Error function value: 737.92
Trying N-LAK8 as Material, Surface 1. Error function value: 738.41
Trying P-PK53 as Material, Surface 1. Error function value: 19.48
Trying N-FK51 as Material, Surface 1. Error function value: 401.58
Trying S-NBH52V as Material, Surface 1. Error function value: 724.47
Trying L-BAL42 as Material, Surface 1. Error function value: 2917.68
Trying S-LAH65VS as Material, Surface 1. Error function value: 740.22
-> Selected P-PK53 as Material, Surface 1.
New combination: ['P-PK53', 'N-BK7', 'N-BK7', 'N-BK7', 'N-BK7', 'N-BK7']
Best error function value: 19.48 (-100%).
Selecting Material, Surface 3:
Trying TIH23 as Material, Surface 3. Error function value: 1.69
Trying N-LAK8 as Material, Surface 3. Error function value: 1.48
Trying P-PK53 as Material, Surface 3. Error function value: 1.35
Trying N-FK51 as Material, Surface 3. Error function value: 16.87
Trying S-NBH52V as Material, Surface 3. Error function value: 18.13
Trying L-BAL42 as Material, Surface 3. Error function value: 1.47
Trying S-LAH65VS as Material, Surface 3. Error function value: 17.82
-> Selected P-PK53 as Material, Surface 3.
New combination: ['P-PK53', 'P-PK53', 'N-BK7', 'N-BK7', 'N-BK7', 'N-BK7']
Best error function value: 1.35 (-93%).
Selecting Material, Surface 4:
Trying TIH23 as Material, Surface 4. Error function value: 1.32
Trying N-LAK8 as Material, Surface 4. Error function value: 1.36
Trying P-PK53 as Material, Surface 4. Error function value: 1.35
Trying N-FK51 as Material, Surface 4. Error function value: 1.35
Trying S-NBH52V as Material, Surface 4. Error function value: 1.36
Trying L-BAL42 as Material, Surface 4. Error function value: 1.35
Trying S-LAH65VS as Material, Surface 4. Error function value: 1.33
-> Selected TIH23 as Material, Surface 4.
New combination: ['P-PK53', 'P-PK53', 'TIH23', 'N-BK7', 'N-BK7', 'N-BK7']
Best error function value: 1.32 (-2%).
Selecting Material, Surface 7:
Trying TIH23 as Material, Surface 7. Error function value: 1.38
Trying N-LAK8 as Material, Surface 7. Error function value: 1.36
Trying P-PK53 as Material, Surface 7. Error function value: 1.33
Trying N-FK51 as Material, Surface 7. Error function value: 1.32
Trying S-NBH52V as Material, Surface 7. Error function value: 1.35
Trying L-BAL42 as Material, Surface 7. Error function value: 1.33
Trying S-LAH65VS as Material, Surface 7. Error function value: 1.38
-> Selected N-FK51 as Material, Surface 7.
New combination: ['P-PK53', 'P-PK53', 'TIH23', 'N-FK51', 'N-BK7', 'N-BK7']
Best error function value: 1.32 (-0%).
Selecting Material, Surface 8:
Trying TIH23 as Material, Surface 8. Error function value: 1.23
Trying N-LAK8 as Material, Surface 8. Error function value: 1.26
Trying P-PK53 as Material, Surface 8. Error function value: 1.32
Trying N-FK51 as Material, Surface 8. Error function value: 1.33
Trying S-NBH52V as Material, Surface 8. Error function value: 1.25
Trying L-BAL42 as Material, Surface 8. Error function value: 1.30
Trying S-LAH65VS as Material, Surface 8. Error function value: 1.23
-> Selected S-LAH65VS as Material, Surface 8.
New combination: ['P-PK53', 'P-PK53', 'TIH23', 'N-FK51', 'S-LAH65VS', 'N-BK7']
Best error function value: 1.23 (-7%).
Selecting Material, Surface 10:
Trying TIH23 as Material, Surface 10. Error function value: 1.12
Trying N-LAK8 as Material, Surface 10. Error function value: 1.18
Trying P-PK53 as Material, Surface 10. Error function value: 1.22
Trying N-FK51 as Material, Surface 10. Error function value: 1.24
Trying S-NBH52V as Material, Surface 10. Error function value: 1.18
Trying L-BAL42 as Material, Surface 10. Error function value: 1.21
Trying S-LAH65VS as Material, Surface 10. Error function value: 1.13
-> Selected TIH23 as Material, Surface 10.
New combination: ['P-PK53', 'P-PK53', 'TIH23', 'N-FK51', 'S-LAH65VS', 'TIH23']
Best error function value: 1.12 (-9%).
----------------------------------------------------------------------
Local exploration
Selecting Material, Surface 1:
Trying FSL3 as Material, Surface 1. Error function value: 1.14
Trying FK3 as Material, Surface 1. Error function value: 1.26
Trying BSL21 as Material, Surface 1. Error function value: 1.19
Trying N-BK10 as Material, Surface 1. Error function value: 1.18
Trying PHM53 as Material, Surface 1. Error function value: 0.99
Trying S-PHM53 as Material, Surface 1. Error function value: 0.99
Trying BSL22 as Material, Surface 1. Error function value: 1.14
-> Selected S-PHM53 as Material, Surface 1.
New combination: ['S-PHM53', 'P-PK53', 'TIH23', 'N-FK51', 'S-LAH65VS', 'TIH23']
Best error function value: 0.99 (-11%).
Selecting Material, Surface 3:
Trying FSL3 as Material, Surface 3. Error function value: 0.98
Trying FK3 as Material, Surface 3. Error function value: 0.99
Trying BSL21 as Material, Surface 3. Error function value: 0.96
Trying N-BK10 as Material, Surface 3. Error function value: 0.99
Trying PHM53 as Material, Surface 3. Error function value: 0.96
Trying S-PHM53 as Material, Surface 3. Error function value: 0.98
Trying BSL22 as Material, Surface 3. Error function value: 0.98
-> Selected BSL21 as Material, Surface 3.
New combination: ['S-PHM53', 'BSL21', 'TIH23', 'N-FK51', 'S-LAH65VS', 'TIH23']
Best error function value: 0.96 (-4%).
Selecting Material, Surface 4:
Trying S-TIH23 as Material, Surface 4. Error function value: 0.96
Trying PBH23 as Material, Surface 4. Error function value: 0.96
Trying PBH23W as Material, Surface 4. Error function value: 0.96
Trying N-SF56 as Material, Surface 4. Error function value: 0.96
Trying SF56A as Material, Surface 4. Error function value: 0.96
Trying S-TIH14 as Material, Surface 4. Error function value: 0.95
Trying TIH14 as Material, Surface 4. Error function value: 0.95
-> Selected TIH14 as Material, Surface 4.
New combination: ['S-PHM53', 'BSL21', 'TIH14', 'N-FK51', 'S-LAH65VS', 'TIH23']
Best error function value: 0.95 (-0%).
Selecting Material, Surface 7:
Trying N-FK51A as Material, Surface 7. Error function value: 0.95
Trying FPL51 as Material, Surface 7. Error function value: 0.95
Trying N-PK52A as Material, Surface 7. Error function value: 0.95
Trying S-FPL51 as Material, Surface 7. Error function value: 0.95
Trying S-FPL51Y as Material, Surface 7. Error function value: 0.95
Trying S-FPL52 as Material, Surface 7. Error function value: 0.95
Trying FPL52 as Material, Surface 7. Error function value: 0.95
-> Selected S-FPL52 as Material, Surface 7.
New combination: ['S-PHM53', 'BSL21', 'TIH14', 'S-FPL52', 'S-LAH65VS', 'TIH23']
Best error function value: 0.95 (-0%).
Selecting Material, Surface 8:
Trying N-LASF44 as Material, Surface 8. Error function value: 0.95
Trying S-LAH65 as Material, Surface 8. Error function value: 0.95
Trying LAH65 as Material, Surface 8. Error function value: 0.95
Trying S-LAH65V as Material, Surface 8. Error function value: 0.95
Trying S-LAH59 as Material, Surface 8. Error function value: 0.95
Trying LAH59 as Material, Surface 8. Error function value: 0.95
Trying N-BAF52 as Material, Surface 8. Error function value: 0.98
-> Selected LAH59 as Material, Surface 8.
New combination: ['S-PHM53', 'BSL21', 'TIH14', 'S-FPL52', 'LAH59', 'TIH23']
Best error function value: 0.95 (-0%).
Selecting Material, Surface 10:
Trying S-TIH23 as Material, Surface 10. Error function value: 0.95
Trying PBH23 as Material, Surface 10. Error function value: 0.95
Trying PBH23W as Material, Surface 10. Error function value: 0.95
Trying N-SF56 as Material, Surface 10. Error function value: 0.95
Trying SF56A as Material, Surface 10. Error function value: 0.95
Trying S-TIH14 as Material, Surface 10. Error function value: 0.95
Trying TIH14 as Material, Surface 10. Error function value: 0.95
-> Selected N-SF56 as Material, Surface 10.
New combination: ['S-PHM53', 'BSL21', 'TIH14', 'S-FPL52', 'LAH59', 'N-SF56']
Best error function value: 0.95 (-0%).
╒════╤═══════════════╤═══════════╤═══════════╤═════════════╤════════════╤═════════╤═════════════════╕
│ │ Type │ Comment │ Radius │ Thickness │ Material │ Conic │ Semi-aperture │
╞════╪═══════════════╪═══════════╪═══════════╪═════════════╪════════════╪═════════╪═════════════════╡
│ 0 │ Planar │ │ inf │ inf │ Air │ 0 │ 24.2986 │
│ 1 │ Standard │ │ 48.0692 │ 13.736 │ S-PHM53 │ 0 │ 24.2986 │
│ 2 │ Standard │ │ 164.247 │ 0.442024 │ Air │ 0 │ 19.5503 │
│ 3 │ Standard │ │ 372.861 │ 15.5605 │ BSL21 │ 0 │ 19.337 │
│ 4 │ Planar │ │ inf │ 9.89194 │ TIH14 │ 0 │ 14.0754 │
│ 5 │ Standard │ │ 228.955 │ 10.0433 │ Air │ 0 │ 11.2204 │
│ 6 │ Stop - Planar │ │ inf │ 10.0471 │ Air │ 0 │ 6.48839 │
│ 7 │ Standard │ │ -387.184 │ 8.84993 │ S-FPL52 │ 0 │ 9.5793 │
│ 8 │ Planar │ │ inf │ 13.7508 │ LAH59 │ 0 │ 11.5178 │
│ 9 │ Standard │ │ -405.699 │ 0.446604 │ Air │ 0 │ 13.9327 │
│ 10 │ Standard │ │ 406.228 │ 17.1103 │ N-SF56 │ 0 │ 14.0626 │
│ 11 │ Standard │ │ -435.409 │ 35.6867 │ Air │ 0 │ 16.5911 │
│ 12 │ Planar │ │ inf │ nan │ Air │ 0 │ 24.9359 │
╘════╧═══════════════╧═══════════╧═══════════╧═════════════╧════════════╧═════════╧═════════════════╛