Aperture & Optics

The NewtonianTelescopeAperture is a POPPY CompoundAnalyticOptic that models the telescope entrance pupil: primary mirror, secondary obscuration, and spider struts.


NewtonianTelescopeAperture

from psfcraft.optics import NewtonianTelescopeAperture

This class is normally instantiated automatically inside NewtonianTelescope, but can be used standalone to inspect or render the pupil mask:

from psfcraft.optics import NewtonianTelescopeAperture
import matplotlib.pyplot as plt

aperture = NewtonianTelescopeAperture(
    optical_system_version="1_3",
    primary_radius=0.5,
    secondary_radius=0.1,
)
aperture.display()
plt.show()

Available versions

optical_system_version Description
"0" Circular aperture only
"1_3" Secondary + 3 evenly-spaced arms
"1_4" Secondary + 4 arms
"1_5" Secondary + 5 arms
"2" Euclid-like asymmetric 3-arm spider
"3" Secondary obscuration, no arms
"5" Hexagonal segmented primary
"6" Annular aperture

NewtonianTelescopeAperture

NewtonianTelescopeAperture(optical_system_version='1', primary_radius=0.5, secondary_radius=0.1, *args, **kwargs)

Bases: CompoundAnalyticOptic

NewtonianTelescopeAperture class, representing the primary and secondary mirrors geometry of Telescopes such as Newtonian. The aperture features a primary circular mirror and a secondary mirror supported by three branches.

This class exclusively describes the pupil geometry and the support struts for the secondary mirror.

Warning: High sampling factors may significantly slow down PSF calculations.

The default configuration assigns values 0 and 1 for transmission. Setting the parameter label_segments=True generates a map indicating the segment numbers and their respective locations.

Initialize the NewtonianTelescopeAperture.

Parameters: - optical_system_version (str): The version of the optical system. - primary_radius (float): Radius of the primary mirror. - secondary_radius (float): Radius of the secondary mirror.

Source code in psfcraft/optics.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def __init__(self, optical_system_version='1',
             primary_radius=0.5,secondary_radius=0.1,
             *args, **kwargs):
    """
    Initialize the NewtonianTelescopeAperture.

    Parameters:
    - optical_system_version (str): The version of the optical system.
    - primary_radius (float): Radius of the primary mirror.
    - secondary_radius (float): Radius of the secondary mirror.
    """
    self.primary_radius = primary_radius
    self.secondary_radius = secondary_radius
    self.primary_diameter = 2*primary_radius  # Diameter of the primary mirror
    self.secondary_diameter = 2*secondary_radius # Diameter of the secondary mirror

    poppy.CompoundAnalyticOptic.__init__(self, self.get_optical_system(optical_system_version=optical_system_version,*args,**kwargs),
                                        name='NewtonianTelescopeAperture V'+optical_system_version)

get_optical_system

get_optical_system(optical_system_version='1', *args, **kwargs)

Wrapper to return the optical system for a given version of a Newtonian Telescope aperture.

Parameters: - optical_system_version (str): The version of the optical system.

Returns: - list: The optical system components.

Source code in psfcraft/optics.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def get_optical_system(self,optical_system_version = '1',*args,**kwargs):
    """
    Wrapper to return the optical system for a given version of a Newtonian Telescope aperture.

    Parameters:
    - optical_system_version (str): The version of the optical system.

    Returns:
    - list: The optical system components.
    """
    if "1_" in optical_system_version: #Thus the number after the version 
        version , N_branches = optical_system_version.split('_')
        return getattr(self, f'optical_compounds_v{version}')(int(N_branches),*args,**kwargs)
    else : 
        return getattr(self, f'optical_compounds_v{optical_system_version}')(*args,**kwargs)

optical_compounds_v0

optical_compounds_v0()

Only circular aperture with no secondary mirror.

Source code in psfcraft/optics.py
84
85
86
87
88
89
def optical_compounds_v0(self):
    '''
    Only circular aperture with no secondary mirror.
    '''
    first = poppy.CircularAperture(name='PrimaryMirror',radius=self.primary_radius)
    return [first]

optical_compounds_v1

optical_compounds_v1(N_branches=3, branches_thickness=0.02)

Secondary held by N_branches rectilinear supports evenly spaced.

Parameters: - N_branches (int): Number of secondary mirror supports. - branches_thickness (float): Thickness of the supports.

Returns: - list: The optical system components.

Source code in psfcraft/optics.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def optical_compounds_v1(self,N_branches = 3,branches_thickness=0.02):
    '''
    Secondary held by N_branches rectilinear supports evenly spaced.

    Parameters:
    - N_branches (int): Number of secondary mirror supports.
    - branches_thickness (float): Thickness of the supports.

    Returns:
    - list: The optical system components.
    '''

    first = poppy.CircularAperture(name='PrimaryMirror',radius=self.primary_radius)
    if N_branches == 0 : 
        second = poppy.SecondaryObscuration(name='SecondaryMirror',secondary_radius=self.secondary_radius,
                                                    n_supports=N_branches,
                                                    )
        return [first,second]
    else :
        second = poppy.AsymmetricSecondaryObscuration(name='SecondaryMirror',secondary_radius=self.secondary_radius,
                                                    support_angle=list(range(0,360,360//N_branches)), # counterclockwise starting from top 
                                                    support_width=N_branches*[branches_thickness],
                                                    )
        return [first,second]

optical_compounds_v2

optical_compounds_v2()

Closest model, using that secondary area is 30% of primary area. Taking primary radius as 0.6m, then secondary radius is 0.199 m There is a doubt about the orientation of the secondary mirror. By default stars diffraction spikes are directed to the right with the angles attribute.

Source code in psfcraft/optics.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def optical_compounds_v2(self):
    '''
    Closest model, using that secondary area is 30% of primary area.
    Taking primary radius as 0.6m, then secondary radius is 0.199 m
    There is a doubt about the orientation of the secondary mirror. By default stars diffraction spikes are directed to the right with the angles attribute.
    '''
    orientation = 'right' # Used to flip the secondary mirror orientation
    angles = (15,135,255) if orientation=='left' else (360-15,360-135,360-255)
    first = poppy.CircularAperture(radius=self.primary_radius,
                            # *args, **kwargs
                            )
    second = poppy.AsymmetricSecondaryObscuration(secondary_radius=self.secondary_radius,
                                                support_angle=(15, 255, 135), # clockwise starting from top 
                                                support_width=3*[0.012],
                                                # support_offset_x=[0.009, 0.042, -0.012],
                                                support_offset_x=[0.15, 0., 0.],
                                                support_offset_y=[0., -0.15, 0.19],
                                                )
    return [first,second]

optical_compounds_v3

optical_compounds_v3(branches_thickness=0.02)

4 branches spider.

Parameters: - branches_thickness (float): Thickness of the supports.

Returns: - list: The optical system components.

Source code in psfcraft/optics.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def optical_compounds_v3(self,branches_thickness=0.02):
    '''
    4 branches spider.

    Parameters:
    - branches_thickness (float): Thickness of the supports.

    Returns:
    - list: The optical system components.
    '''
    N_branches = 4
    first = poppy.CircularAperture(name='PrimaryMirror',radius=self.primary_radius)
    second = poppy.AsymmetricSecondaryObscuration(name='SecondaryMirror',secondary_radius=self.secondary_radius,
                                                support_angle=list(range(0,360,360//N_branches)), # counterclockwise starting from top 
                                                support_width=N_branches*[branches_thickness],
                                                )
    return [first,second]

optical_compounds_v5

optical_compounds_v5(branches_thickness=0.02)

4 branches spider with shifted branches tangent to secondary mirror.

Parameters: - branches_thickness (float): Thickness of the supports.

Returns: - list: The optical system components.

Source code in psfcraft/optics.py
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def optical_compounds_v5(self,branches_thickness=0.02):
    '''
    4 branches spider with shifted branches tangent to secondary mirror.

    Parameters:
    - branches_thickness (float): Thickness of the supports.

    Returns:
    - list: The optical system components.
    '''
    first = poppy.CircularAperture(name='PrimaryMirror',radius=self.primary_radius)
    second = poppy.AsymmetricSecondaryObscuration(name='SecondaryMirror',secondary_radius=self.secondary_radius,
                                                support_angle=[0,90,180,270], # counterclockwise starting from top
                                                support_width=4*[branches_thickness],
                                                support_offset_x=[self.secondary_radius, 0, -self.secondary_radius, 0],
                                                support_offset_y=[0, self.secondary_radius, 0, -self.secondary_radius],
                                                # Considering the thickness of the branches, the offset is not exactly the radius
                                                # support_offset_x=[self.secondary_radius-branches_thickness/2, 0, -self.secondary_radius+branches_thickness/2, 0],
                                                # support_offset_y=[0, self.secondary_radius-branches_thickness/2, 0, -self.secondary_radius+branches_thickness/2],
                                                )
    return [first,second]

optical_compounds_v6

optical_compounds_v6(branches_thickness=0.02)

8 branches spider with shifted branches joining the secondary mirror in 4 distincts and equally spaced points (star shape).

Parameters: - branches_thickness (float): Thickness of the supports.

Returns: - list: The optical system components.

Source code in psfcraft/optics.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
def optical_compounds_v6(self,branches_thickness=0.02):
    '''
    8 branches spider with shifted branches joining the secondary mirror in 4 distincts and equally spaced points (star shape).

    Parameters:
    - branches_thickness (float): Thickness of the supports.

    Returns:
    - list: The optical system components.
    '''
    first = poppy.CircularAperture(name='PrimaryMirror',radius=self.primary_radius)
    alpha = np.rad2deg(np.arctan(1/(np.sqrt(2)*self.primary_radius/self.secondary_radius-1)))
    delta = self.secondary_radius/np.sqrt(2)
    angles = [90*(i//2)+alpha if i%2==0 else 90*(i//2)-alpha for i in range(8)]
    offsets_x = [delta,-delta,-delta,-delta,-delta, delta, delta, delta]
    offsets_y = [delta, delta, delta,-delta,-delta,-delta,-delta, delta]
    second = poppy.AsymmetricSecondaryObscuration(name='SecondaryMirror',secondary_radius=self.secondary_radius,
                                                support_angle=angles, # clockwise starting from top 
                                                support_width=8*[branches_thickness],
                                                support_offset_x=offsets_x,
                                                support_offset_y=offsets_y,
                                                )
    return [first,second]