A framework for simulating and researching the LSST Active Optics system. We hope to document and transfer much of the functionality in bxin/IM (latest fork: davidthomas5412/IM) and bxin/cwfs (latest fork: davidthomas5412/cwfs) into this new framework, as well as make it easy to explore alternative approaches. We will also be introducing the following software practices:
- Testing: unit tests, continuous integration, track code coverage.
- Documentation: numpy docstrings, no magic interpolations - all hardcoded matrices etc. must be derived or explained in corresponding notebooks.
- Modular design: we strive to make it easy and natural for users to try new alternatives and swap out parts of the pipeline.
- Switch simulators: zemax+phosim -> batoid+galsim.
- Open source: public github repo, issue tracking, pull requests welcome.
This project has two dependencies that must be installed separately. First, you will need to install galsim. Then, you will need to install batoid. batoid must be installed from source because we depend on a functions (batoid.utils.fieldToDirCos and batoid.utils.dirCosToZemax) that have not made it into the PyPI release. Then you should be able to clone this repo and run setup.py:
git clone https://github.com/davidthomas5412/ActiveOpticsSimulator
cd ActiveOpticsSimulator
python setup.py install
To run the unit tests, from the ActiveOpticsSimulator directory, first install the testing requirements:
pip install -r test_requirements.txt
And then run the tests using setup.py:
python setup.py test
We started off with a minimal viable product (MVP) that supports the following workflow:
- create nominal telescope
- create perturbed optical state and apply it to telescope
- simulate wavefront at the field center
- estimate wavefront at field center from wavefront image
- use wavefront estimate to solve for optical correction by minimizing metric
- apply new optical state to telescope
- repeat
The snippet below runs two iterations of this primitive version of the active optics system:
from aos.simulator import WavefrontSimulator
from aos.estimator import WavefrontEstimator
from aos.metric import SumOfSquares
from aos.control import GainController
from aos.telescope import BendingTelescope
from aos.state import BendingState
from aos.solver import SensitivitySolver
telescope = BendingTelescope.nominal(band='g')
simulator = WavefrontSimulator()
estimator = WavefrontEstimator()
solver = SensitivitySolver()
metric = SumOfSquares()
controller = GainController(metric, gain=0.3)
fieldx, fieldy = 0, 0
x = BendingState()
# add 1 micron of the third bending mode to M2.
x['m2b3'] = 1e-6
telescope.update(x)
wavefront = simulator.simulateWavefront(telescope.optic, fieldx, fieldy)
yest = estimator.estimate(wavefront)
xest = solver.solve(yest)
xprime, xdelta = controller.nextState(xest)
# start second iteration
telescope.update(xdelta)
wavefront = simulator.simulateWavefront(telescope.optic, fieldx, fieldy)
yest = estimator.estimate(wavefront)
xest = solver.solve(yest)
xprime, xdelta = controller.nextState(xest)
There are a lot of degeneracies in the optical system at the field center, so the convergence is not great ... yet.