In [1]:

```
from nbtemplate import display_header, get_path
display_header('DQ36.ipynb')
```

Last revision in version control:

- Author: Hans Moritz Guenther hgunther@mit.edu
- commit 3a117fb18cfbaf02e8407d8130d29699dbc39de3
- Date: Fri Dec 4 07:24:14 2020 -0500

This document is git version controlled. The repository is available at https://github.com/hamogu/arcus. See git commit log for full revision history.

Code was last run with:

- MARXS ray-trace code version 1.2.dev769 (commit hash: 45bf7363f2 from 2020-11-22)
- ARCUS python code version 0.2.dev186 (commit hash: 8c6308a4ec from 2020-10-19)
- ARCUS CALDB version hash: b'b1a9c0f' (commited on b'2020-10-22 ')

*Because the SPO plates are radial (and thus curved) while the CAT gratings need to be aligned to the dispersion axis, it is not possible to align them such that shadows from the SPO plates and the L2 structures of the CAT grating coincide in general. This also means that it is not possible to accidentally hit a configuration where all SPO shadows fall on active CAT area.*

The goal of this notebook is to make a few plots to answer the following question:

Gratings and SPOs have macroscopic opaque structures (SPOs: plate thickness and ribs; Gratings: L2 supports). They are only a short distance from each other along the optical axis. Have you considered relative alignment of these obstructing/blocking structures (in the plane normal to the optical axis), and how much the effective area can be impacted by non-ideal relative alignment?

In [2]:

```
import os
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
```

In [3]:

```
# Hexagon vectors
hex_base = np.array([0.5577, 0])
# Hexagon rotation matrix to make the other sides from the first bases vector
hex_rot = np.array([[0.5, -3.**0.5 / 2], [3**0.5 / 2, 0.5]])
hexagon = np.zeros((6, 2))
for i in range(1, 6):
hexagon[i, :] = hexagon[i - 1] + hex_base
hex_base = hex_rot @ hex_base
hex_row_offset = hexagon[2, :]
hex_col_offset = hexagon[4, :]
```

In [4]:

```
def linewidth_from_data_units(linewidth, axis, reference='y'):
"""
Convert a linewidth in data units to linewidth in points.
Parameters
----------
linewidth: float
Linewidth in data units of the respective reference-axis
axis: matplotlib axis
The axis which is used to extract the relevant transformation
data (data limits and size must not change afterwards)
reference: string
The axis that is taken as a reference for the data width.
Possible values: 'x' and 'y'. Defaults to 'y'.
Returns
-------
linewidth: float
Linewidth in points
From: https://stackoverflow.com/questions/19394505/matplotlib-expand-the-line-with-specified-width-in-data-unit
"""
fig = axis.get_figure()
if reference == 'x':
length = fig.bbox_inches.width * axis.get_position().width
value_range = np.diff(axis.get_xlim())
elif reference == 'y':
length = fig.bbox_inches.height * axis.get_position().height
value_range = np.diff(axis.get_ylim())
# Convert length to points
length *= 72
# Scale linewidth to value range
return linewidth * (length / value_range)
```

In [5]:

```
def spoplate(center, r):
ang = np.arange(-.5, .5, 0.001)
return center[0] + r * np.sin(ang), center[1] + r * np.cos(ang)
def porerim(center, r):
'''I draw there bars converging to the center. I'm not sure that's true or if they are
parallel, but the difference is not actually visible within one SPO plot.'''
dalpha = 1./ r
ang = np.arange(-.1, .1, dalpha)
return center[0] + np.array([0.9 * r, 1.05 * r])[:, None] * np.sin(ang), center[1] + np.array([0.9 * r, 1.05 * r])[:, None] * np.cos(ang)
```

In [6]:

```
hexpatch = mpl.patches.Polygon(hexagon, fc='none', ec='b', lw=20)
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
ax.set_ylim(-0, 8)
ax.set_xlim(-0, 8)
for j in range(-15, 15):
for i in range(-15, 15):
ax.add_patch(mpl.patches.Polygon(i * hex_col_offset + j * hex_row_offset + hexagon,
fc='none', ec='b', lw=linewidth_from_data_units(0.1, ax)))
for i in range(-40, 10):
x, y = spoplate([30, -500], 510 + i * 0.775)
ax.plot(x, y, lw=linewidth_from_data_units(0.17, ax), c='0.2')
x, y = porerim([30, -500], 530)
out = ax.plot(x, y, lw=linewidth_from_data_units(0.17, ax), c='0.2')
ax.set_xlabel('dispersion direction [mm]')
ax.set_ylabel('cross-dispersion direction [mm]')
plt.savefig(os.path.join(get_path("figures"), 'DQ36closein.png'), bbox_inches='tight', dpi=300)
plt.savefig(os.path.join(get_path("figures"), 'DQ36closein.pdf'), bbox_inches='tight', dpi=300)
```

This figure shows SPO structures (plates and ribs, *black*) on top of CAT grating L2 hexagons (*blue*). The SPO plates are slightly curved because their shape is radially around the focal point. In contrast, the CAT gratings are all aligned to the dispersion direction. The image makes it clear that, even if the CAT grating L2 structure was designed to match the spacing of the SPO plates, the dead area caused by both structures cannot be aligned in a special way over the area of the telescope. Instead, both structures have a certain fraction of open area and the total open area is simple the product of the individual factors.

In [7]:

```
hexpatch = mpl.patches.Polygon(hexagon, fc='none', ec='b', lw=20)
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
ax.set_ylim(-0, 2)
ax.set_xlim(-0, 2)
for j in range(-15, 15):
for i in range(-15, 15):
ax.add_patch(mpl.patches.Polygon(i * hex_col_offset + j * hex_row_offset + hexagon,
fc='none', ec='b', lw=linewidth_from_data_units(0.1, ax)))
for i in range(-40, 10):
x, y = spoplate([30, -500], 510 + i * 0.775)
ax.plot(x, y, lw=linewidth_from_data_units(0.17, ax), c='0.2')
x, y = porerim([30, -500], 530)
out = ax.plot(x, y, lw=linewidth_from_data_units(0.17, ax), c='0.2')
ax.set_xlabel('dispersion direction [mm]')
out = ax.set_ylabel('cross-dispersion direction [mm]')
```

This figure shows an enlarged area.