Skip to content

Commit

Permalink
Merge branch 'develop' into release_0.9.2
Browse files Browse the repository at this point in the history
  • Loading branch information
mperrin committed Feb 11, 2021
2 parents 8c668fa + 3f3fd28 commit fd8f2c6
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 7 deletions.
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: monthly
time: "10:00"
open-pull-requests-limit: 10
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ matrix:
# Try Astropy development version
- env: TOXENV='py38-astropydev-test'

# Try latest versions of all dependencies
- env: TOXENV='py38-latest-test'

# Try Astropy & numpy minimum supported versions,
# and older Python versions
- env: TOXENV='py36-legacy-test'
Expand Down
34 changes: 30 additions & 4 deletions poppy/dms.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,14 @@ class ContinuousDeformableMirror(optics.AnalyticOpticalElement):
Flip the orientation of the X or Y axes of the DM actuators. Useful if your
device is not oriented such that the origin is at lower left as seen in the
pupil.
include_factor_of_two : Bool
include the factor of two due to reflection in the OPD function (optional, default False)
include the factor of two due to reflection in the OPD function (optional, default False).
If this is set False (default), actuator commands are interpreted as being in units of
desired wavefront error directly; the returned WFE will be directly proportional to the requested
values (convolved with the actuator response function etc).
If this is set to True, then the actuator commands are interpreted as being in physical surface
units, and the WFE is therefore a factor of two larger. The returned WFE will be twice the
amplitude of the requested values (convolved with the actuator response function etc.)
Additionally, the standard parameters for shift_x and shift_y can be accepted and
will be handled by the **kwargs mechanism. Note, rotation is not yet supported for DMs,
Expand Down Expand Up @@ -340,7 +345,7 @@ def get_opd(self, wave):
shift_y_pix = int(np.round(self.shift_y /pixscale_m))
interpolated_surface = np.roll(interpolated_surface, shift_y_pix, axis=0)

# account for DM being reflective (opitonal, governed by include_factor_of_two parameter)
# account for DM being reflective (optional, governed by include_factor_of_two parameter)
coefficient = 2 if self.include_factor_of_two else 1

return coefficient*interpolated_surface # note optional *2 coefficient to account for DM being reflective surface
Expand Down Expand Up @@ -671,10 +676,24 @@ def display_influence_fn(self):
class HexSegmentedDeformableMirror(optics.MultiHexagonAperture):
""" Hexagonally segmented DM. Each actuator is controlalble in piston, tip, and tilt
Parameters
----------
rings, flattoflat, gap, center : various
All keywords for defining the segmented aperture geometry are inherited from
the MultiHexagonAperture class. See that class for details.
include_factor_of_two : Bool
include the factor of two due to reflection in the OPD function (optional, default False).
If this is set False (default), actuator commands are interpreted as being in units of
desired wavefront error directly; the returned WFE will be directly proportional to the requested
values (convolved with the actuator response function etc).
If this is set to True, then the actuator commands are interpreted as being in physical surface
units, and the WFE is therefore a factor of two larger. The returned WFE will be twice the
amplitude of the requested values (convolved with the actuator response function etc.)
"""

def __init__(self, rings=3, flattoflat=1.0 * u.m, gap=0.01 * u.m,
name='HexDM', center=True, **kwargs):
name='HexDM', center=True, include_factor_of_two=False, **kwargs):
optics.MultiHexagonAperture.__init__(self, name=name, rings=rings, flattoflat=flattoflat,
gap=gap, center=center, **kwargs)
self._surface = np.zeros((self._n_hexes_inside_ring(rings+1), 3))
Expand All @@ -683,6 +702,8 @@ def __init__(self, rings=3, flattoflat=1.0 * u.m, gap=0.01 * u.m,
self._last_npix = np.nan
self._last_pixelscale = np.nan * u.meter / u.pixel

self.include_factor_of_two = include_factor_of_two

@property
def dm_shape(self):
""" DM actuator geometry - i.e. how many actuators """
Expand Down Expand Up @@ -761,6 +782,11 @@ def get_opd(self, wave):
self.opd[wseg] = (self._surface[i, 0] +
self._surface[i, 1] * self._seg_x[wseg] +
self._surface[i, 2] * self._seg_y[wseg])

# account for DM being reflective (optional, governed by include_factor_of_two parameter)
if self.include_factor_of_two:
self.opd *= 2

return self.opd

def get_transmission(self, wave):
Expand Down
25 changes: 25 additions & 0 deletions poppy/tests/test_dms.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,28 @@ def test_hex_dm_rotation(npix=128, ptt = (0, 1e-6, 0), plot=False):
if plot:
plt.figure()
dm.display(what='opd', npix=npix, opd_vmax=1e-6, title=f'DM with {rot} rotation', colorbar_orientation='vertical')


def test_factor_of_two_surface_vs_wfe():
"""For both types of DM, test the factor of two option
"""

# Create two DMs, one commanded in WFE and the other in surface
dm = dms.ContinuousDeformableMirror()
dm2 = dms.ContinuousDeformableMirror(include_factor_of_two=True)

for actx, acty in ( (3,7), (7,3)):
dm2.set_actuator(actx, acty, 1e-6) # 1000 nm = 1 micron
dm.set_actuator(actx, acty, 1e-6) # 1000 nm = 1 micron

w = poppy_core.Wavefront(npix=128, diam=dm._aperture.radius*2)
assert np.allclose(dm.get_opd(w)*2, dm2.get_opd(w)), "The continuous DM response should be 2x greater if include_factor_of_two is set"

# Now repeat for the hex dm
hexdm = dms.HexSegmentedDeformableMirror(rings=1)
hexdm2 = dms.HexSegmentedDeformableMirror(rings=1, include_factor_of_two=True)
for act in ( 3,6):
hexdm.set_actuator(act, 1e-6, 0, 1e-4) # 1000 nm = 1 micron
hexdm2.set_actuator(act, 1e-6, 0, 1e-4) # 1000 nm = 1 micron
w = poppy_core.Wavefront(npix=128, diam=hexdm.pupil_diam)
assert np.allclose(hexdm.get_opd(w)*2, hexdm2.get_opd(w)), "The hexagonal DM response should be 2x greater if include_factor_of_two is set"
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ max-line-length = 120
zip_safe = False
packages = find:
install_requires =
numpy>=1.13.0
numpy>=1.16.0
scipy>=1.0.0
matplotlib>=2.0.0
astropy>=3.0.0
astropy>=3.2.0
python_requires = >=3.6
setup_requires = setuptools_scm
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
envlist =
py{36,37,38}-test
py{36,37,38}-{astropydev,legacy}-test
py{36,37,38}-{astropydev,legacy,latest}-test
py{36,37,38}-cov
py37-numexpr-cov

Expand All @@ -15,6 +15,7 @@ deps =
cov: codecov
legacy: numpy==1.16.*
legacy: astropy==3.2.*
latest: -rrequirements.txt
astropydev: git+git://github.com/astropy/astropy
numexpr: numexpr>=2.0.0
conda deps =
Expand Down

0 comments on commit fd8f2c6

Please sign in to comment.