diff --git a/Jenkinsfile b/Jenkinsfile index 3eeefb339..fa25caf3b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ @Library('JenkinsShared')_ DevelopPipeline( - name: "ts_standardscripts", - module_name: "lsst.ts.standardscripts", - extra_packages: ["lsst-ts/ts_cRIOpy", "lsst-ts/ts_observatory_control"], + name: "ts_auxtel_standardscripts", + module_name: "lsst.ts.auxtel.standardscripts", + extra_packages: ["lsst-ts/ts_cRIOpy", "lsst-ts/ts_observatory_control", "lsst-ts/ts_standardscripts"], build_all_idl: true ) diff --git a/Jenkinsfile.conda b/Jenkinsfile.conda index cb5636b74..1267112cf 100644 --- a/Jenkinsfile.conda +++ b/Jenkinsfile.conda @@ -1,2 +1,2 @@ @Library('JenkinsShared')_ -CondaPipeline(["ts_config_ocs","ts_config_attcs"], "ts-standardscripts", "lsst.ts.standardscripts", "noarch") +CondaPipeline(["ts_config_ocs","ts_config_attcs"], "ts-auxtel-standardscripts", "lsst.ts.auxtel.standardscripts", "noarch") diff --git a/README.rst b/README.rst index bfdb0a46b..90433bd33 100644 --- a/README.rst +++ b/README.rst @@ -1,11 +1,11 @@ ################## -ts_standardscripts +ts_auxtel_standardscripts ################## -Standard SAL scripts for operating the LSST via the `lsst.ts.scriptqueue.ScriptQueue`. +Auxiliary Telescope Standard SAL scripts for operating the LSST via the `lsst.ts.scriptqueue.ScriptQueue`. Each script is a subclass of `lsst.ts.scriptqueue.ScriptBase`. -`Documentation `_ +`Documentation `_ This code uses ``pre-commit`` to maintain ``black`` formatting and ``flake8`` compliance. To enable this: diff --git a/SConstruct b/SConstruct index 33c551321..2f54fc10e 100644 --- a/SConstruct +++ b/SConstruct @@ -2,4 +2,4 @@ from lsst.sconsUtils import scripts # Python-only package -scripts.BasicSConstruct("ts_standardscripts", disableCc=True, noCfgFile=True) +scripts.BasicSConstruct("ts_auxtel_standardscripts", disableCc=True, noCfgFile=True) diff --git a/conda/meta.yaml b/conda/meta.yaml index b93a0bdc4..ab24c8516 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,6 +1,6 @@ {% set data= load_setup_py_data() %} package: - name: ts-standardscripts + name: ts-auxtel-standardscripts version: {{ data.get('version') }} source: @@ -18,13 +18,14 @@ test: - ts-idl {{ idl_version }} - ts-salobj {{ salobj_version }} - ts-observatory-control + - ts-standardscripts source_files: - python - tests - setup.cfg - pyproject.toml imports: - - lsst.ts.standardscripts + - lsst.ts.auxtel.standardscripts requirements: host: @@ -40,6 +41,7 @@ requirements: - astroquery - astroplan - ts-observatory-control + - ts-standardscripts run: - python {{ python }} - setuptools @@ -49,3 +51,4 @@ requirements: - astroquery - astroplan - ts-observatory-control + - ts-standardscripts diff --git a/doc/conf.py b/doc/conf.py index 6e9d99764..2148dacf1 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -2,15 +2,16 @@ This configuration only affects single-package Sphinx documentation builds. """ -import lsst.ts.standardscripts # noqa +import lsst.ts.auxtel.standardscripts # noqa from documenteer.conf.pipelinespkg import * # type: ignore # noqa -project = "ts_standardscripts" +project = "ts_auxtel_standardscripts" html_theme_options["logotext"] = project # type: ignore # noqa html_title = project html_short_title = project doxylink = {} # Avoid warning: Could not find tag file _doxygen/doxygen.tag +intersphinx_mapping["ts_standardscripts"] = ("https://ts-standardscripts.lsst.io", None) # type: ignore # noqa intersphinx_mapping["ts_observatory_control"] = ( # type: ignore # noqa "https://ts-observatory-control.lsst.io", None, diff --git a/doc/developer_guide.rst b/doc/developer_guide.rst index b1e3392f9..8378c4c71 100644 --- a/doc/developer_guide.rst +++ b/doc/developer_guide.rst @@ -1,25 +1,25 @@ -.. py:currentmodule:: lsst.ts.standardscripts +.. py:currentmodule:: lsst.ts.auxtel.standardscripts -.. _lsst.ts.standardscripts.developer_guide: +.. _lsst.ts.auxtel.standardscripts.developer_guide: ############### Developer Guide ############### -.. image:: https://img.shields.io/badge/GitHub-ts_standardscripts-green.svg - :target: https://github.com/lsst-ts/ts_standardscripts -.. image:: https://img.shields.io/badge/Jenkins-ts_standardscripts-green.svg - :target: https://tssw-ci.lsst.org/job/LSST_Telescope-and-Site/job/ts_standardscripts/ -.. image:: https://img.shields.io/badge/Jira-ts_standardscripts-green.svg - :target: https://jira.lsstcorp.org/issues/?jql=project%3DDM%20AND%20labels%3Dts_standardscripts +.. image:: https://img.shields.io/badge/GitHub-ts_auxtel_standardscripts-green.svg + :target: https://github.com/lsst-ts/ts_auxtel_standardscripts +.. image:: https://img.shields.io/badge/Jenkins-ts_auxtel_standardscripts-green.svg + :target: https://tssw-ci.lsst.org/job/LSST_Telescope-and-Site/job/ts_auxtel_standardscripts/ +.. image:: https://img.shields.io/badge/Jira-ts_auxtel_standardscripts-green.svg + :target: https://jira.lsstcorp.org/issues/?jql=project%3DDM%20AND%20labels%3Dts_auxtel_standardscripts .. _contributing: -Contributing +Contributing: ============ -``lsst.ts.standardscripts`` is developed at https://github.com/lsst-ts/ts_standardscripts. -You can find Jira issues for this package using `project=DM and labels=ts_standardscripts `_. +``lsst.ts.auxtel_standardscripts`` is developed at https://github.com/lsst-ts/ts_auxtel_standardscripts. +You can find Jira issues for this package using `project=DM and labels=ts_auxtel_standardscripts `_. .. _api_ref: @@ -29,8 +29,8 @@ Python API reference .. automodapi:: lsst.ts.standardscripts :no-main-docstr: -.. automodapi:: lsst.ts.standardscripts.auxtel +.. automodapi:: lsst.ts.auxtel.standardscripts :no-main-docstr: -.. automodapi:: lsst.ts.standardscripts.maintel +.. automodapi:: lsst.ts.auxtel.standardscripts :no-main-docstr: diff --git a/doc/index.rst b/doc/index.rst index f420445c9..840f8a8fd 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,17 +1,17 @@ -.. py:currentmodule:: lsst.ts.standardscripts +.. py:currentmodule:: lsst.ts.auxtel.standardscripts -.. _standardscripts: +.. _auxtel_standardscripts: ################ Standard Scripts ################ -.. image:: https://img.shields.io/badge/GitHub-ts_standardscripts-green.svg - :target: https://github.com/lsst-ts/ts_standardscripts -.. image:: https://img.shields.io/badge/Jenkins-ts_standardscripts-green.svg - :target: https://tssw-ci.lsst.org/job/LSST_Telescope-and-Site/job/ts_standardscripts/ -.. image:: https://img.shields.io/badge/Jira-ts_standardscripts-green.svg - :target: https://jira.lsstcorp.org/issues/?jql=project%3DDM%20AND%20labels%3Dts_standardscripts +.. image:: https://img.shields.io/badge/GitHub-ts_auxtel_standardscripts-green.svg + :target: https://github.com/lsst-ts/ts_auxtel_standardscripts +.. image:: https://img.shields.io/badge/Jenkins-ts_auxtel_standardscripts-green.svg + :target: https://tssw-ci.lsst.org/job/LSST_Telescope-and-Site/job/ts_auxtel_standardscripts/ +.. image:: https://img.shields.io/badge/Jira-ts_auxtel_standardscripts-green.svg + :target: https://jira.lsstcorp.org/issues/?jql=project%3DDM%20AND%20labels%3Dts_auxtel_standardscripts Overview ======== @@ -24,9 +24,9 @@ User Documentation To add a script to this package: * Read `SAL Scripts `_ to learn the basics of writing a SAL script. -* Add your script implementation to the library: ``python/lsst/ts/standardscripts``. +* Add your script implementation to the library: ``python/lsst/ts/auxtel/standardscripts``. * Add a test suite to the ``tests`` directory. -* Add a bin script to the ``python/lsst/ts/standardscripts/data/scripts`` directory. +* Add a bin script to the ``python/lsst/ts/auxtel/standardscripts/data/scripts`` directory. Developer Documentation ======================= diff --git a/doc/manifest.yaml b/doc/manifest.yaml index 9fd4e74e0..49a163218 100644 --- a/doc/manifest.yaml +++ b/doc/manifest.yaml @@ -3,10 +3,10 @@ # List of names of Python modules in this package. # For each module there is a corresponding module doc subdirectory. modules: - - "lsst.ts.standardscripts" + - "lsst.ts.auxtel.standardscripts" # Name of the static content directories (subdirectories of `_static`). # Static content directories are usually named after the package. # Most packages do not need a static content directory (leave commented out). # statics: -# - "_static/ts_standardscripts" +# - "_static/ts_auxtel_standardscripts" diff --git a/doc/news/DM-48003.feature.rst b/doc/news/DM-48003.feature.rst new file mode 100644 index 000000000..d47d3c0f4 --- /dev/null +++ b/doc/news/DM-48003.feature.rst @@ -0,0 +1,2 @@ +Split `ts_auxtel_standardscripts` repo from `ts_standardscripts` +to focus exclusively on auxiliary telescope logic. diff --git a/doc/version_history.rst b/doc/version_history.rst index 4e60c4609..2dcb78e8f 100644 --- a/doc/version_history.rst +++ b/doc/version_history.rst @@ -1,6 +1,6 @@ -.. py:currentmodule:: lsst.ts.standardscripts +.. py:currentmodule:: lsst.ts.auxtel.standardscripts -.. _lsst.ts.standardscripts.version_history: +.. _lsst.ts.auxtel.standardscripts.version_history: =============== Version History diff --git a/pyproject.toml b/pyproject.toml index e984b2d2f..697f5f32b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,11 @@ requires = [ "setuptools", "setuptools_scm" ] build-backend = "setuptools.build_meta" [project] -name = "ts_standardscripts" -description = "Standard SAL scripts for LSST observing with the script queue." +name = "ts_auxtel_standardscripts" +description = "Auxiliary telescope specific standard SAL scripts for LSST observing with the script queue." license = { text = "GPL" } classifiers = [ "Programming Language :: Python :: 3" ] -urls = { documentation = "https://ts-standardscripts.lsst.io", repository = "https://github.com/lsst-ts/ts_standardscripts" } +urls = { documentation = "https://ts-auxtel-standardscripts.lsst.io", repository = "https://github.com/lsst-ts/ts_auxtel_standardscripts" } dynamic = [ "version" ] [tool.setuptools.dynamic] @@ -17,7 +17,7 @@ version = { attr = "setuptools_scm.get_version" } where = [ "python" ] [tool.setuptools_scm] -write_to = "python/lsst/ts/standardscripts/version.py" +write_to = "python/lsst/ts/auxtel/standardscripts/version.py" write_to_template = """ # Generated by setuptools_scm __all__ = ["__version__"] @@ -35,7 +35,7 @@ src_paths = ["python", "test"] dev = ["documenteer[pipelines]"] [tool.towncrier] - package = "lsst.ts.standardscripts" + package = "lsst.ts.auxtel.standardscripts" package_dir = "python" filename = "doc/version_history.rst" directory = "doc/news" diff --git a/python/lsst/ts/standardscripts/auxtel/__init__.py b/python/lsst/ts/auxtel/standardscripts/__init__.py similarity index 87% rename from python/lsst/ts/standardscripts/auxtel/__init__.py rename to python/lsst/ts/auxtel/standardscripts/__init__.py index 1c22ac5c7..747d476a2 100644 --- a/python/lsst/ts/standardscripts/auxtel/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -42,3 +42,12 @@ from .take_stuttered_latiss import * from .track_target import * from .track_target_and_take_image import * +from .utils import * + +try: + from .version import * +except ImportError: + __version__ = "?" + __repo_version__ = "?" + __fingerprint__ = "? *" + __dependency_versions__ = {} diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/__init__.py b/python/lsst/ts/auxtel/standardscripts/atdome/__init__.py similarity index 95% rename from python/lsst/ts/standardscripts/auxtel/atdome/__init__.py rename to python/lsst/ts/auxtel/standardscripts/atdome/__init__.py index 1295f8c78..a038227a7 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/close_dome.py b/python/lsst/ts/auxtel/standardscripts/atdome/close_dome.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/close_dome.py rename to python/lsst/ts/auxtel/standardscripts/atdome/close_dome.py index 52bc0567a..776e4c24e 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/close_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/close_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/close_dropout_door.py b/python/lsst/ts/auxtel/standardscripts/atdome/close_dropout_door.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/close_dropout_door.py rename to python/lsst/ts/auxtel/standardscripts/atdome/close_dropout_door.py index 2b0c0469d..c4b587e6f 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/close_dropout_door.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/close_dropout_door.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/disable_dome_following.py b/python/lsst/ts/auxtel/standardscripts/atdome/disable_dome_following.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/disable_dome_following.py rename to python/lsst/ts/auxtel/standardscripts/atdome/disable_dome_following.py index 6f47d31e1..ce56e2f38 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/disable_dome_following.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/disable_dome_following.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/enable_dome_following.py b/python/lsst/ts/auxtel/standardscripts/atdome/enable_dome_following.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/enable_dome_following.py rename to python/lsst/ts/auxtel/standardscripts/atdome/enable_dome_following.py index ce585cc26..9aa22362e 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/enable_dome_following.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/enable_dome_following.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/home_dome.py b/python/lsst/ts/auxtel/standardscripts/atdome/home_dome.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/home_dome.py rename to python/lsst/ts/auxtel/standardscripts/atdome/home_dome.py index ac13dc672..3b0044e8b 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/home_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/home_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/open_dome.py b/python/lsst/ts/auxtel/standardscripts/atdome/open_dome.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/atdome/open_dome.py rename to python/lsst/ts/auxtel/standardscripts/atdome/open_dome.py index 2bc751f92..f152b62f2 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/open_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/open_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/open_dropout_door.py b/python/lsst/ts/auxtel/standardscripts/atdome/open_dropout_door.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/atdome/open_dropout_door.py rename to python/lsst/ts/auxtel/standardscripts/atdome/open_dropout_door.py index 2e62be953..af9c7d0fa 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/open_dropout_door.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/open_dropout_door.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/atdome/slew_dome.py b/python/lsst/ts/auxtel/standardscripts/atdome/slew_dome.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/atdome/slew_dome.py rename to python/lsst/ts/auxtel/standardscripts/atdome/slew_dome.py index a7e657e90..a80718c14 100644 --- a/python/lsst/ts/standardscripts/auxtel/atdome/slew_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/atdome/slew_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/calibrations/__init__.py b/python/lsst/ts/auxtel/standardscripts/calibrations/__init__.py similarity index 95% rename from python/lsst/ts/standardscripts/auxtel/calibrations/__init__.py rename to python/lsst/ts/auxtel/standardscripts/calibrations/__init__.py index f95255a73..404b70981 100644 --- a/python/lsst/ts/standardscripts/auxtel/calibrations/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/calibrations/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/calibrations/power_off_atcalsys.py b/python/lsst/ts/auxtel/standardscripts/calibrations/power_off_atcalsys.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/calibrations/power_off_atcalsys.py rename to python/lsst/ts/auxtel/standardscripts/calibrations/power_off_atcalsys.py index e1855c2e3..22952a0b5 100644 --- a/python/lsst/ts/standardscripts/auxtel/calibrations/power_off_atcalsys.py +++ b/python/lsst/ts/auxtel/standardscripts/calibrations/power_off_atcalsys.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/calibrations/power_on_atcalsys.py b/python/lsst/ts/auxtel/standardscripts/calibrations/power_on_atcalsys.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/calibrations/power_on_atcalsys.py rename to python/lsst/ts/auxtel/standardscripts/calibrations/power_on_atcalsys.py index 0cec462fb..3cff3aba2 100644 --- a/python/lsst/ts/standardscripts/auxtel/calibrations/power_on_atcalsys.py +++ b/python/lsst/ts/auxtel/standardscripts/calibrations/power_on_atcalsys.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/calibrations/run_calibration_sequence.py b/python/lsst/ts/auxtel/standardscripts/calibrations/run_calibration_sequence.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/calibrations/run_calibration_sequence.py rename to python/lsst/ts/auxtel/standardscripts/calibrations/run_calibration_sequence.py index 26207429c..792c99c05 100644 --- a/python/lsst/ts/standardscripts/auxtel/calibrations/run_calibration_sequence.py +++ b/python/lsst/ts/auxtel/standardscripts/calibrations/run_calibration_sequence.py @@ -32,8 +32,7 @@ from lsst.ts.observatory.control.auxtel.atcalsys import ATCalsys from lsst.ts.observatory.control.auxtel.latiss import LATISS from lsst.ts.standardscripts import BaseBlockScript - -from ...utils import get_s3_bucket +from lsst.ts.standardscripts.utils import get_s3_bucket class RunCalibrationSequence(BaseBlockScript): diff --git a/python/lsst/ts/standardscripts/auxtel/calsys_takedata.py b/python/lsst/ts/auxtel/standardscripts/calsys_takedata.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/calsys_takedata.py rename to python/lsst/ts/auxtel/standardscripts/calsys_takedata.py index 4ace17879..2a08962eb 100644 --- a/python/lsst/ts/standardscripts/auxtel/calsys_takedata.py +++ b/python/lsst/ts/auxtel/standardscripts/calsys_takedata.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/auxtel/standardscripts/data/scripts/README.md b/python/lsst/ts/auxtel/standardscripts/data/scripts/README.md new file mode 100644 index 000000000..45406acd8 --- /dev/null +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/README.md @@ -0,0 +1,7 @@ +LSST auxiliary telescope specific SAL scripts to operate the LSST. + +`Documentation `_ + +Scripts may be grouped by putting them in suitable subdirectories. +Scripts must be command-line executables that take a single +command-line argument: the SAL index for the script. \ No newline at end of file diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dome.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dome.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dome.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dome.py index 543de61fe..6f0456a1a 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dome.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import CloseDome +from lsst.ts.auxtel.standardscripts.atdome import CloseDome asyncio.run(CloseDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dropout_door.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dropout_door.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dropout_door.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dropout_door.py index bb9bda1bb..5a969f917 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/close_dropout_door.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/close_dropout_door.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import CloseDropoutDoor +from lsst.ts.auxtel.standardscripts.atdome import CloseDropoutDoor asyncio.run(CloseDropoutDoor.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/disable_dome_following.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/disable_dome_following.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/disable_dome_following.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/disable_dome_following.py index 8c20f6bd1..822888624 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/disable_dome_following.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/disable_dome_following.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import DisableDomeFollowing +from lsst.ts.auxtel.standardscripts.atdome import DisableDomeFollowing asyncio.run(DisableDomeFollowing.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/enable_dome_following.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/enable_dome_following.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/enable_dome_following.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/enable_dome_following.py index 88718e720..98a8e2394 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/enable_dome_following.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/enable_dome_following.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import EnableDomeFollowing +from lsst.ts.auxtel.standardscripts.atdome import EnableDomeFollowing asyncio.run(EnableDomeFollowing.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/home_dome.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/home_dome.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/home_dome.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/home_dome.py index 66e362fd5..b1dd469ca 100755 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/home_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/home_dome.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.maintel.mtdome import HomeDome +from lsst.ts.auxtel.standardscripts.atdome import HomeDome asyncio.run(HomeDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dome.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dome.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dome.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dome.py index b61514774..ebce40155 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dome.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import OpenDome +from lsst.ts.auxtel.standardscripts.atdome import OpenDome asyncio.run(OpenDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dropout_door.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dropout_door.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dropout_door.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dropout_door.py index cfff8864d..54f356225 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/open_dropout_door.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/open_dropout_door.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import OpenDropoutDoor +from lsst.ts.auxtel.standardscripts.atdome import OpenDropoutDoor asyncio.run(OpenDropoutDoor.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/slew_dome.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/slew_dome.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/slew_dome.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/slew_dome.py index d60b28d04..dc4edf6a4 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/slew_dome.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/atdome/slew_dome.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.atdome import SlewDome +from lsst.ts.auxtel.standardscripts.atdome import SlewDome asyncio.run(SlewDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_off_atcalsys.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_off_atcalsys.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_off_atcalsys.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_off_atcalsys.py index 61e040bb8..43ce453ab 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_off_atcalsys.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_off_atcalsys.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.calibrations import PowerOffATCalSys +from lsst.ts.auxtel.standardscripts.calibrations import PowerOffATCalSys asyncio.run(PowerOffATCalSys.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_on_atcalsys.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_on_atcalsys.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_on_atcalsys.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_on_atcalsys.py index a740c65ad..ac6589134 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/power_on_atcalsys.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/power_on_atcalsys.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.calibrations import PowerOnATCalSys +from lsst.ts.auxtel.standardscripts.calibrations import PowerOnATCalSys asyncio.run(PowerOnATCalSys.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/run_calibration_sequence.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/run_calibration_sequence.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/run_calibration_sequence.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/run_calibration_sequence.py index 869e058c6..6a251b5fc 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/calibrations/run_calibration_sequence.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/calibrations/run_calibration_sequence.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,7 +22,7 @@ import asyncio -from lsst.ts.standardscripts.auxtel.calibrations.run_calibration_sequence import ( +from lsst.ts.auxtel.standardscripts.calibrations.run_calibration_sequence import ( RunCalibrationSequence, ) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/calsys_takedata.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/calsys_takedata.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/calsys_takedata.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/calsys_takedata.py index abbea85ef..b141dba11 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/calsys_takedata.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/calsys_takedata.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import CalSysTakeData +from lsst.ts.auxtel.standardscripts import CalSysTakeData asyncio.run(CalSysTakeData.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/atpneumatics_checkout.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/atpneumatics_checkout.py similarity index 94% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/atpneumatics_checkout.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/atpneumatics_checkout.py index 0ab3374b2..a58a6fb70 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/atpneumatics_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/atpneumatics_checkout.py @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.daytime_checkout import ATPneumaticsCheckout +from lsst.ts.auxtel.standardscripts.daytime_checkout import ATPneumaticsCheckout asyncio.run(ATPneumaticsCheckout.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/latiss_checkout.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/latiss_checkout.py similarity index 94% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/latiss_checkout.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/latiss_checkout.py index c5a4ab1c7..ffbe7e425 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/latiss_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/latiss_checkout.py @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.daytime_checkout import LatissCheckout +from lsst.ts.auxtel.standardscripts.daytime_checkout import LatissCheckout asyncio.run(LatissCheckout.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/slew_and_take_image_checkout.py similarity index 94% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/slew_and_take_image_checkout.py index 67835509a..d10076447 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/slew_and_take_image_checkout.py @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.daytime_checkout import SlewAndTakeImageCheckout +from lsst.ts.auxtel.standardscripts.daytime_checkout import SlewAndTakeImageCheckout asyncio.run(SlewAndTakeImageCheckout.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/telescope_and_dome_checkout.py similarity index 94% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/telescope_and_dome_checkout.py index 9701b836e..e3e554e50 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/daytime_checkout/telescope_and_dome_checkout.py @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.daytime_checkout import TelescopeAndDomeCheckout +from lsst.ts.auxtel.standardscripts.daytime_checkout import TelescopeAndDomeCheckout asyncio.run(TelescopeAndDomeCheckout.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/detector_characterization/get_std_flat_dataset.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/detector_characterization/get_std_flat_dataset.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/detector_characterization/get_std_flat_dataset.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/detector_characterization/get_std_flat_dataset.py index a01ca7957..01b46ca37 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/detector_characterization/get_std_flat_dataset.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/detector_characterization/get_std_flat_dataset.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.detector_characterization import ATGetStdFlatDataset +from lsst.ts.auxtel.standardscripts.detector_characterization import ATGetStdFlatDataset asyncio.run(ATGetStdFlatDataset.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/disable_ataos_corrections.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/disable_ataos_corrections.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/disable_ataos_corrections.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/disable_ataos_corrections.py index 492c81fcd..9634e3fd2 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/disable_ataos_corrections.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/disable_ataos_corrections.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import DisableATAOSCorrections +from lsst.ts.auxtel.standardscripts import DisableATAOSCorrections asyncio.run(DisableATAOSCorrections.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_ataos_corrections.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_ataos_corrections.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/enable_ataos_corrections.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/enable_ataos_corrections.py index 816aae265..a01ccc635 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_ataos_corrections.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_ataos_corrections.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import EnableATAOSCorrections +from lsst.ts.auxtel.standardscripts import EnableATAOSCorrections asyncio.run(EnableATAOSCorrections.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_atcs.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_atcs.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/enable_atcs.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/enable_atcs.py index c4be1b938..6836078a3 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_atcs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import EnableATTCS +from lsst.ts.auxtel.standardscripts import EnableATTCS asyncio.run(EnableATTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_latiss.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/enable_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/enable_latiss.py index df4e34005..f2d435c4a 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/enable_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/enable_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import EnableLATISS +from lsst.ts.auxtel.standardscripts import EnableLATISS asyncio.run(EnableLATISS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/focus_sweep_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/focus_sweep_latiss.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/focus_sweep_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/focus_sweep_latiss.py index c840b6c99..39b34d2bc 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/focus_sweep_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/focus_sweep_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import FocusSweepLatiss +from lsst.ts.auxtel.standardscripts import FocusSweepLatiss asyncio.run(FocusSweepLatiss.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/latiss_take_sequence.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/latiss_take_sequence.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/latiss_take_sequence.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/latiss_take_sequence.py index cf3df84ac..e25776c1d 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/latiss_take_sequence.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/latiss_take_sequence.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import LatissTakeSequence +from lsst.ts.auxtel.standardscripts import LatissTakeSequence asyncio.run(LatissTakeSequence.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/offline_atcs.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/offline_atcs.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/offline_atcs.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/offline_atcs.py index 8f1459be6..ea73c0703 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/offline_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/offline_atcs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import OfflineATCS +from lsst.ts.auxtel.standardscripts import OfflineATCS asyncio.run(OfflineATCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/offline_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/offline_latiss.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/offline_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/offline_latiss.py index 1aa80460f..00a79c9e1 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/offline_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/offline_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import OfflineLATISS +from lsst.ts.auxtel.standardscripts import OfflineLATISS asyncio.run(OfflineLATISS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/offset_ataos.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/offset_ataos.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/offset_ataos.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/offset_ataos.py index c3c33f6c6..ae3a7bbb6 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/offset_ataos.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/offset_ataos.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import OffsetATAOS +from lsst.ts.auxtel.standardscripts import OffsetATAOS asyncio.run(OffsetATAOS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/offset_atcs.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/offset_atcs.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/offset_atcs.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/offset_atcs.py index e12641001..25b27b4c8 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/offset_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/offset_atcs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import OffsetATCS +from lsst.ts.auxtel.standardscripts import OffsetATCS asyncio.run(OffsetATCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/point_azel.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/point_azel.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/point_azel.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/point_azel.py index 3c47011bf..5bac708ec 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/point_azel.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/point_azel.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import PointAzEl +from lsst.ts.auxtel.standardscripts import PointAzEl asyncio.run(PointAzEl.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/co2_cleanup.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/co2_cleanup.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/co2_cleanup.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/co2_cleanup.py index dac88484b..9cb262c1a 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/co2_cleanup.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/co2_cleanup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForCO2Cleanup +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForCO2Cleanup asyncio.run(PrepareForCO2Cleanup.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/flat.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/flat.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/flat.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/flat.py index e96f14a1d..4ff79bcd4 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/flat.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/flat.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForFlat +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForFlat asyncio.run(PrepareForFlat.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/onsky.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/onsky.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/onsky.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/onsky.py index b236b81a6..63e403cec 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/onsky.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/onsky.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForOnSky +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForOnSky asyncio.run(PrepareForOnSky.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/vent.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/vent.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/vent.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/vent.py index 923609b9d..c7890626c 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/prepare_for/vent.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/prepare_for/vent.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForVent +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForVent asyncio.run(PrepareForVent.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/add_block.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/add_block.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/add_block.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/add_block.py index 3bd5c4403..48f9ebf9e 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/add_block.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/add_block.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/enable.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/enable.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/enable.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/enable.py index db6435799..f4263b7f6 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/enable.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/enable.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/load_snapshot.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/load_snapshot.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/load_snapshot.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/load_snapshot.py index 21877efde..e9077617d 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/load_snapshot.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/load_snapshot.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/resume.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/resume.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/resume.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/resume.py index a221ffe61..7b7cc7343 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/resume.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/resume.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/standby.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/standby.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/standby.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/standby.py index 04e75961e..93b86a9e2 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/standby.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/standby.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/stop.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/stop.py similarity index 96% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/stop.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/stop.py index 7ba16d3d3..eceafdbb8 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/scheduler/stop.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/scheduler/stop.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/shutdown.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/shutdown.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/shutdown.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/shutdown.py index f7aeb03a0..fb4dd304b 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/shutdown.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/shutdown.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import Shutdown +from lsst.ts.auxtel.standardscripts import Shutdown asyncio.run(Shutdown.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/standby_atcs.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/standby_atcs.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/standby_atcs.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/standby_atcs.py index 96a12cee7..dbfa0129e 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/standby_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/standby_atcs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import StandbyATCS +from lsst.ts.auxtel.standardscripts import StandbyATCS asyncio.run(StandbyATCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/standby_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/standby_latiss.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/standby_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/standby_latiss.py index ae27959ee..430bb3870 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/standby_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/standby_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import StandbyLATISS +from lsst.ts.auxtel.standardscripts import StandbyLATISS asyncio.run(StandbyLATISS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/stop.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/stop.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/stop.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/stop.py index b92d89206..31001d5d0 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/stop.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/stop.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import Stop +from lsst.ts.auxtel.standardscripts import Stop asyncio.run(Stop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/stop_tracking.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/stop_tracking.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/stop_tracking.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/stop_tracking.py index ef871d679..db3dcc054 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/stop_tracking.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/stop_tracking.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import StopTracking +from lsst.ts.auxtel.standardscripts import StopTracking asyncio.run(StopTracking.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/take_image_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/take_image_latiss.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/take_image_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/take_image_latiss.py index 28fac7f5e..475d32bb2 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/take_image_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/take_image_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import TakeImageLatiss +from lsst.ts.auxtel.standardscripts import TakeImageLatiss asyncio.run(TakeImageLatiss.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/take_stuttered_latiss.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/take_stuttered_latiss.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/take_stuttered_latiss.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/take_stuttered_latiss.py index 676be8af7..6371b5aa1 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/take_stuttered_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/take_stuttered_latiss.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import TakeStutteredLatiss +from lsst.ts.auxtel.standardscripts import TakeStutteredLatiss asyncio.run(TakeStutteredLatiss.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/track_target.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/track_target.py similarity index 90% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/track_target.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/track_target.py index 8e8222624..c3221edd8 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/track_target.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/track_target.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import TrackTarget +from lsst.ts.auxtel.standardscripts import TrackTarget asyncio.run(TrackTarget.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/track_target_and_take_image.py b/python/lsst/ts/auxtel/standardscripts/data/scripts/track_target_and_take_image.py similarity index 89% rename from python/lsst/ts/standardscripts/data/scripts/auxtel/track_target_and_take_image.py rename to python/lsst/ts/auxtel/standardscripts/data/scripts/track_target_and_take_image.py index 14ceab993..3fb77d994 100755 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/track_target_and_take_image.py +++ b/python/lsst/ts/auxtel/standardscripts/data/scripts/track_target_and_take_image.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,6 @@ import asyncio -from lsst.ts.standardscripts.auxtel import TrackTargetAndTakeImage +from lsst.ts.auxtel.standardscripts import TrackTargetAndTakeImage asyncio.run(TrackTargetAndTakeImage.amain()) diff --git a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/__init__.py b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/__init__.py similarity index 95% rename from python/lsst/ts/standardscripts/auxtel/daytime_checkout/__init__.py rename to python/lsst/ts/auxtel/standardscripts/daytime_checkout/__init__.py index af52e8c62..9b4d43e44 100644 --- a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/atpneumatics_checkout.py b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/atpneumatics_checkout.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/daytime_checkout/atpneumatics_checkout.py rename to python/lsst/ts/auxtel/standardscripts/daytime_checkout/atpneumatics_checkout.py index d0dab59cf..f1158e322 100644 --- a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/atpneumatics_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/atpneumatics_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/latiss_checkout.py b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/latiss_checkout.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/daytime_checkout/latiss_checkout.py rename to python/lsst/ts/auxtel/standardscripts/daytime_checkout/latiss_checkout.py index d5e97e71a..060df25a3 100644 --- a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/latiss_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/latiss_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -25,8 +25,7 @@ from lsst.ts import salobj from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages - -from ...utils import get_topic_time_utc +from lsst.ts.standardscripts.utils import get_topic_time_utc STD_TIMEOUT = 10 # seconds diff --git a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/slew_and_take_image_checkout.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py rename to python/lsst/ts/auxtel/standardscripts/daytime_checkout/slew_and_take_image_checkout.py index f8b0b142f..eaa743704 100644 --- a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/slew_and_take_image_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/slew_and_take_image_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -29,8 +29,7 @@ from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages from lsst.ts.observatory.control.utils.enums import RotType - -from ...utils import get_topic_time_utc +from lsst.ts.standardscripts.utils import get_topic_time_utc STD_TIMEOUT = 10 # seconds diff --git a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/telescope_and_dome_checkout.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py rename to python/lsst/ts/auxtel/standardscripts/daytime_checkout/telescope_and_dome_checkout.py index 84577ded4..88f9ec3f7 100644 --- a/python/lsst/ts/standardscripts/auxtel/daytime_checkout/telescope_and_dome_checkout.py +++ b/python/lsst/ts/auxtel/standardscripts/daytime_checkout/telescope_and_dome_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/detector_characterization/__init__.py b/python/lsst/ts/auxtel/standardscripts/detector_characterization/__init__.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/detector_characterization/__init__.py rename to python/lsst/ts/auxtel/standardscripts/detector_characterization/__init__.py index b74258190..ed2aa3a42 100644 --- a/python/lsst/ts/standardscripts/auxtel/detector_characterization/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/detector_characterization/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/detector_characterization/get_std_flat_dataset.py b/python/lsst/ts/auxtel/standardscripts/detector_characterization/get_std_flat_dataset.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/detector_characterization/get_std_flat_dataset.py rename to python/lsst/ts/auxtel/standardscripts/detector_characterization/get_std_flat_dataset.py index da20afe8e..bb2b0deeb 100644 --- a/python/lsst/ts/standardscripts/auxtel/detector_characterization/get_std_flat_dataset.py +++ b/python/lsst/ts/auxtel/standardscripts/detector_characterization/get_std_flat_dataset.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/disable_ataos_corrections.py b/python/lsst/ts/auxtel/standardscripts/disable_ataos_corrections.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/disable_ataos_corrections.py rename to python/lsst/ts/auxtel/standardscripts/disable_ataos_corrections.py index 2de91e593..f145424a3 100644 --- a/python/lsst/ts/standardscripts/auxtel/disable_ataos_corrections.py +++ b/python/lsst/ts/auxtel/standardscripts/disable_ataos_corrections.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/enable_ataos_corrections.py b/python/lsst/ts/auxtel/standardscripts/enable_ataos_corrections.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/enable_ataos_corrections.py rename to python/lsst/ts/auxtel/standardscripts/enable_ataos_corrections.py index 9fef2547d..1d8d57558 100644 --- a/python/lsst/ts/standardscripts/auxtel/enable_ataos_corrections.py +++ b/python/lsst/ts/auxtel/standardscripts/enable_ataos_corrections.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/enable_atcs.py b/python/lsst/ts/auxtel/standardscripts/enable_atcs.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/enable_atcs.py rename to python/lsst/ts/auxtel/standardscripts/enable_atcs.py index 8e046b68e..1948c7c28 100644 --- a/python/lsst/ts/standardscripts/auxtel/enable_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/enable_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,8 +23,7 @@ import yaml from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages - -from ..enable_group import EnableGroup +from lsst.ts.standardscripts.enable_group import EnableGroup class EnableATTCS(EnableGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/enable_latiss.py b/python/lsst/ts/auxtel/standardscripts/enable_latiss.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/enable_latiss.py rename to python/lsst/ts/auxtel/standardscripts/enable_latiss.py index ede4cb158..cd793306e 100644 --- a/python/lsst/ts/standardscripts/auxtel/enable_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/enable_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,8 +23,7 @@ import yaml from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages - -from ..enable_group import EnableGroup +from lsst.ts.standardscripts.enable_group import EnableGroup class EnableLATISS(EnableGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/focus_sweep_latiss.py b/python/lsst/ts/auxtel/standardscripts/focus_sweep_latiss.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/focus_sweep_latiss.py rename to python/lsst/ts/auxtel/standardscripts/focus_sweep_latiss.py index 7cdcd05f1..ca9ffb45d 100644 --- a/python/lsst/ts/standardscripts/auxtel/focus_sweep_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/focus_sweep_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,7 @@ import yaml from lsst.ts.observatory.control.auxtel.atcs import ATCS from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages - -from ..base_focus_sweep import BaseFocusSweep +from lsst.ts.standardscripts.base_focus_sweep import BaseFocusSweep class FocusSweepLatiss(BaseFocusSweep): diff --git a/python/lsst/ts/standardscripts/auxtel/latiss_take_sequence.py b/python/lsst/ts/auxtel/standardscripts/latiss_take_sequence.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/latiss_take_sequence.py rename to python/lsst/ts/auxtel/standardscripts/latiss_take_sequence.py index 58d7705c8..0dfd87106 100644 --- a/python/lsst/ts/standardscripts/auxtel/latiss_take_sequence.py +++ b/python/lsst/ts/auxtel/standardscripts/latiss_take_sequence.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/offline_atcs.py b/python/lsst/ts/auxtel/standardscripts/offline_atcs.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/offline_atcs.py rename to python/lsst/ts/auxtel/standardscripts/offline_atcs.py index 3d6761bed..3e9c4e733 100644 --- a/python/lsst/ts/standardscripts/auxtel/offline_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/offline_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["OfflineATCS"] from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages - -from ..offline_group import OfflineGroup +from lsst.ts.standardscripts.offline_group import OfflineGroup class OfflineATCS(OfflineGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/offline_latiss.py b/python/lsst/ts/auxtel/standardscripts/offline_latiss.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/offline_latiss.py rename to python/lsst/ts/auxtel/standardscripts/offline_latiss.py index 2e65053d6..f6fa5c166 100644 --- a/python/lsst/ts/standardscripts/auxtel/offline_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/offline_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["OfflineLATISS"] from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages - -from ..offline_group import OfflineGroup +from lsst.ts.standardscripts.offline_group import OfflineGroup class OfflineLATISS(OfflineGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/offset_ataos.py b/python/lsst/ts/auxtel/standardscripts/offset_ataos.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/offset_ataos.py rename to python/lsst/ts/auxtel/standardscripts/offset_ataos.py index 1d0dc9a6d..323baf229 100644 --- a/python/lsst/ts/standardscripts/auxtel/offset_ataos.py +++ b/python/lsst/ts/auxtel/standardscripts/offset_ataos.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/offset_atcs.py b/python/lsst/ts/auxtel/standardscripts/offset_atcs.py similarity index 92% rename from python/lsst/ts/standardscripts/auxtel/offset_atcs.py rename to python/lsst/ts/auxtel/standardscripts/offset_atcs.py index c98e1b537..1a4df1d44 100644 --- a/python/lsst/ts/standardscripts/auxtel/offset_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/offset_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["OffsetATCS"] from lsst.ts.observatory.control.auxtel import ATCS, ATCSUsages - -from ..base_offset_tcs import BaseOffsetTCS +from lsst.ts.standardscripts.base_offset_tcs import BaseOffsetTCS class OffsetATCS(BaseOffsetTCS): diff --git a/python/lsst/ts/standardscripts/auxtel/point_azel.py b/python/lsst/ts/auxtel/standardscripts/point_azel.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/point_azel.py rename to python/lsst/ts/auxtel/standardscripts/point_azel.py index 264fcf40f..cb7bac4a4 100644 --- a/python/lsst/ts/standardscripts/auxtel/point_azel.py +++ b/python/lsst/ts/auxtel/standardscripts/point_azel.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["PointAzEl"] from lsst.ts.observatory.control.auxtel.atcs import ATCS - -from ..base_point_azel import BasePointAzEl +from lsst.ts.standardscripts.base_point_azel import BasePointAzEl class PointAzEl(BasePointAzEl): diff --git a/python/lsst/ts/standardscripts/auxtel/prepare_for/__init__.py b/python/lsst/ts/auxtel/standardscripts/prepare_for/__init__.py similarity index 95% rename from python/lsst/ts/standardscripts/auxtel/prepare_for/__init__.py rename to python/lsst/ts/auxtel/standardscripts/prepare_for/__init__.py index e7a57d226..a386bba06 100644 --- a/python/lsst/ts/standardscripts/auxtel/prepare_for/__init__.py +++ b/python/lsst/ts/auxtel/standardscripts/prepare_for/__init__.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/prepare_for/co2_cleanup.py b/python/lsst/ts/auxtel/standardscripts/prepare_for/co2_cleanup.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/prepare_for/co2_cleanup.py rename to python/lsst/ts/auxtel/standardscripts/prepare_for/co2_cleanup.py index 9ece52621..8593ba6dd 100644 --- a/python/lsst/ts/standardscripts/auxtel/prepare_for/co2_cleanup.py +++ b/python/lsst/ts/auxtel/standardscripts/prepare_for/co2_cleanup.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/prepare_for/flats.py b/python/lsst/ts/auxtel/standardscripts/prepare_for/flats.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/prepare_for/flats.py rename to python/lsst/ts/auxtel/standardscripts/prepare_for/flats.py index 79aa98f0d..09ea4f095 100644 --- a/python/lsst/ts/standardscripts/auxtel/prepare_for/flats.py +++ b/python/lsst/ts/auxtel/standardscripts/prepare_for/flats.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/prepare_for/onsky.py b/python/lsst/ts/auxtel/standardscripts/prepare_for/onsky.py similarity index 98% rename from python/lsst/ts/standardscripts/auxtel/prepare_for/onsky.py rename to python/lsst/ts/auxtel/standardscripts/prepare_for/onsky.py index 93b5f40b7..00587e668 100644 --- a/python/lsst/ts/standardscripts/auxtel/prepare_for/onsky.py +++ b/python/lsst/ts/auxtel/standardscripts/prepare_for/onsky.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the Vera Rubin Observatory. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/prepare_for/vent.py b/python/lsst/ts/auxtel/standardscripts/prepare_for/vent.py similarity index 99% rename from python/lsst/ts/standardscripts/auxtel/prepare_for/vent.py rename to python/lsst/ts/auxtel/standardscripts/prepare_for/vent.py index a6ca238ba..72cd356da 100644 --- a/python/lsst/ts/standardscripts/auxtel/prepare_for/vent.py +++ b/python/lsst/ts/auxtel/standardscripts/prepare_for/vent.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/shutdown.py b/python/lsst/ts/auxtel/standardscripts/shutdown.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/shutdown.py rename to python/lsst/ts/auxtel/standardscripts/shutdown.py index 92c5e876f..7a3cd3aa4 100644 --- a/python/lsst/ts/standardscripts/auxtel/shutdown.py +++ b/python/lsst/ts/auxtel/standardscripts/shutdown.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/standby_atcs.py b/python/lsst/ts/auxtel/standardscripts/standby_atcs.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/standby_atcs.py rename to python/lsst/ts/auxtel/standardscripts/standby_atcs.py index 09a336bf3..41d63015b 100644 --- a/python/lsst/ts/standardscripts/auxtel/standby_atcs.py +++ b/python/lsst/ts/auxtel/standardscripts/standby_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["StandbyATCS"] from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages - -from ..standby_group import StandbyGroup +from lsst.ts.standardscripts.standby_group import StandbyGroup class StandbyATCS(StandbyGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/standby_latiss.py b/python/lsst/ts/auxtel/standardscripts/standby_latiss.py similarity index 94% rename from python/lsst/ts/standardscripts/auxtel/standby_latiss.py rename to python/lsst/ts/auxtel/standardscripts/standby_latiss.py index 054ddf1ca..6ecfbd1ac 100644 --- a/python/lsst/ts/standardscripts/auxtel/standby_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/standby_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["StandbyLATISS"] from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages - -from ..standby_group import StandbyGroup +from lsst.ts.standardscripts.standby_group import StandbyGroup class StandbyLATISS(StandbyGroup): diff --git a/python/lsst/ts/standardscripts/auxtel/stop.py b/python/lsst/ts/auxtel/standardscripts/stop.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/stop.py rename to python/lsst/ts/auxtel/standardscripts/stop.py index b24688800..663f3e2fb 100644 --- a/python/lsst/ts/standardscripts/auxtel/stop.py +++ b/python/lsst/ts/auxtel/standardscripts/stop.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project diff --git a/python/lsst/ts/standardscripts/auxtel/stop_tracking.py b/python/lsst/ts/auxtel/standardscripts/stop_tracking.py similarity index 92% rename from python/lsst/ts/standardscripts/auxtel/stop_tracking.py rename to python/lsst/ts/auxtel/standardscripts/stop_tracking.py index 4aa68f9da..a33ff043c 100644 --- a/python/lsst/ts/standardscripts/auxtel/stop_tracking.py +++ b/python/lsst/ts/auxtel/standardscripts/stop_tracking.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["StopTracking"] from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages - -from ..base_stop_tracking import BaseStopTracking +from lsst.ts.standardscripts.base_stop_tracking import BaseStopTracking class StopTracking(BaseStopTracking): diff --git a/python/lsst/ts/standardscripts/auxtel/take_image_latiss.py b/python/lsst/ts/auxtel/standardscripts/take_image_latiss.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/take_image_latiss.py rename to python/lsst/ts/auxtel/standardscripts/take_image_latiss.py index 8b6c2b6aa..d8849952e 100644 --- a/python/lsst/ts/standardscripts/auxtel/take_image_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/take_image_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,8 +23,7 @@ import yaml from lsst.ts.observatory.control.auxtel import ATCS, LATISS, ATCSUsages, LATISSUsages - -from ..base_take_image import BaseTakeImage +from lsst.ts.standardscripts.base_take_image import BaseTakeImage class TakeImageLatiss(BaseTakeImage): diff --git a/python/lsst/ts/standardscripts/auxtel/take_stuttered_latiss.py b/python/lsst/ts/auxtel/standardscripts/take_stuttered_latiss.py similarity index 96% rename from python/lsst/ts/standardscripts/auxtel/take_stuttered_latiss.py rename to python/lsst/ts/auxtel/standardscripts/take_stuttered_latiss.py index bb0320258..93216f27d 100644 --- a/python/lsst/ts/standardscripts/auxtel/take_stuttered_latiss.py +++ b/python/lsst/ts/auxtel/standardscripts/take_stuttered_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,8 +23,7 @@ import yaml from lsst.ts.observatory.control.auxtel import LATISS, LATISSUsages - -from ..base_take_stuttered import BaseTakeStuttered +from lsst.ts.standardscripts.base_take_stuttered import BaseTakeStuttered class TakeStutteredLatiss(BaseTakeStuttered): diff --git a/python/lsst/ts/standardscripts/auxtel/track_target.py b/python/lsst/ts/auxtel/standardscripts/track_target.py similarity index 92% rename from python/lsst/ts/standardscripts/auxtel/track_target.py rename to python/lsst/ts/auxtel/standardscripts/track_target.py index 6b1150468..feae0f596 100644 --- a/python/lsst/ts/standardscripts/auxtel/track_target.py +++ b/python/lsst/ts/auxtel/standardscripts/track_target.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,7 @@ __all__ = ["TrackTarget"] from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages - -from ..base_track_target import BaseTrackTarget +from lsst.ts.standardscripts.base_track_target import BaseTrackTarget class TrackTarget(BaseTrackTarget): diff --git a/python/lsst/ts/standardscripts/auxtel/track_target_and_take_image.py b/python/lsst/ts/auxtel/standardscripts/track_target_and_take_image.py similarity index 97% rename from python/lsst/ts/standardscripts/auxtel/track_target_and_take_image.py rename to python/lsst/ts/auxtel/standardscripts/track_target_and_take_image.py index f886f4c82..b03fce5e2 100644 --- a/python/lsst/ts/standardscripts/auxtel/track_target_and_take_image.py +++ b/python/lsst/ts/auxtel/standardscripts/track_target_and_take_image.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,9 +26,10 @@ import yaml from lsst.ts.observatory.control.auxtel import ATCS, LATISS, ATCSUsages, LATISSUsages from lsst.ts.observatory.control.utils import RotType - -from ..base_track_target_and_take_image import BaseTrackTargetAndTakeImage -from ..utils import format_as_list +from lsst.ts.standardscripts.base_track_target_and_take_image import ( + BaseTrackTargetAndTakeImage, +) +from lsst.ts.standardscripts.utils import format_as_list class TrackTargetAndTakeImage(BaseTrackTargetAndTakeImage): diff --git a/python/lsst/ts/auxtel/standardscripts/utils.py b/python/lsst/ts/auxtel/standardscripts/utils.py new file mode 100644 index 000000000..bd4ea4204 --- /dev/null +++ b/python/lsst/ts/auxtel/standardscripts/utils.py @@ -0,0 +1,13 @@ +from lsst.ts.standardscripts.utils import get_scripts_dir as core_get_scripts_dir + + +def get_scripts_dir(): + """ + Override the core get_scripts_dir function for Auxtel usage. + + Returns + ------- + pathlib.Path + Path to Auxtel's data/scripts directory + """ + return core_get_scripts_dir(file_path=__file__) diff --git a/python/lsst/ts/standardscripts/__init__.py b/python/lsst/ts/standardscripts/__init__.py deleted file mode 100644 index 182664843..000000000 --- a/python/lsst/ts/standardscripts/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# This file is part of ts_standardscripts. -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .base_block_script import * -from .base_point_azel import * -from .base_script_test_case import * -from .mute_alarms import * -from .pause_queue import * -from .run_command import * -from .set_summary_state import * -from .sleep import * -from .system_wide_shutdown import * -from .utils import * - -try: - from .version import * -except ImportError: - __version__ = "?" - __repo_version__ = "?" - __fingerprint__ = "? *" - __dependency_versions__ = {} diff --git a/python/lsst/ts/standardscripts/base_block_script.py b/python/lsst/ts/standardscripts/base_block_script.py deleted file mode 100644 index 74b3122a6..000000000 --- a/python/lsst/ts/standardscripts/base_block_script.py +++ /dev/null @@ -1,306 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseBlockScript"] - -import abc -import contextlib -import hashlib -import io -import json -import os -import re -from datetime import datetime - -import yaml -from lsst.ts import salobj, utils - -from .utils import get_s3_bucket - -IMAGE_SERVER_URL = dict( - tucson="http://comcam-mcm.tu.lsst.org", - base="http://lsstcam-mcm.ls.lsst.org", - summit="http://ccs.lsst.org", -) - - -class BaseBlockScript(salobj.BaseScript, metaclass=abc.ABCMeta): - """Extend BaseScript to add support for executing blocks. - - This base class adds a default configuration with reason and program that - can be provided when executing the script. - """ - - def __init__(self, index: int, descr: str, help: str = "") -> None: - super().__init__(index, descr, help) - - self.program = None - self.reason = None - self.obs_id = None - self.checkpoint_message = None - - self.test_case = None - - # Index generator. - self.step_counter = None - - self.step_results = [] - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/base_block_script.py - title: BaseBlockScript v1 - description: Configuration for Base Block Script. - type: object - properties: - program: - type: string - description: >- - Program this script is related to. If this has the format of a block program (e.g. - BLOCK-NNNN, where N is an integer value), it will be used to generate an ID for the - script execution. A warning message is issued if this is provided in with any different - format. If this is not provided but test_case name is provided, it will be used here - instead. - reason: - type: string - description: Reason for executing this script. - test_case: - type: object - description: Test case information. - additionalProperties: false - properties: - name: - type: string - description: Test case related to this script execution. - execution: - type: string - description: Test case execution this script is related to. - version: - type: string - description: Version of the test case. - initial_step: - type: integer - description: >- - Initial step of the test case. If not given, use 1. - project: - type: string - description: >- - Name of the project hosting the test cases. If not given use LVV. - required: - - name - - execution - - version - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.program = getattr(config, "program", None) - self.reason = getattr(config, "reason", None) - self.test_case = getattr(config, "test_case", None) - self.step_counter = ( - utils.index_generator(imin=self.test_case.get("initial_step", 1)) - if self.test_case is not None - else None - ) - - if self.program is not None: - self.checkpoint_message = f"{type(self).__name__} {self.program} " - self.obs_id = await self.get_obs_id() - if self.obs_id is not None: - self.checkpoint_message += f"{self.obs_id}" - if self.reason is not None: - self.checkpoint_message += f" {self.reason}" - - async def get_obs_id(self) -> str | None: - """Get obs id from camera obs id server. - - Returns - ------- - `str` or None - Id generated from camera server. - """ - block_regex = re.compile( - r"(?PBLOCK-T)?(?PBLOCK-)?(?P[0-9]*)" - ) - match = block_regex.match(self.program) - - if match.span()[1] == 0: - raise RuntimeError( - f"{self.program} has the wrong format, should be BLOCK-N or BLOCK-TN..." - ) - - block_id = match.groupdict()["id"] - - site = os.environ.get("LSST_SITE") - if ( - site is None - or site not in IMAGE_SERVER_URL - or not self.program.startswith("BLOCK") - ): - message = ( - "LSST_SITE environment variable not defined" - if site is None - else ( - f"No image server url for {site=}." - if site not in IMAGE_SERVER_URL - else f"Ids are only generated for BLOCK programs, got {self.program}." - ) - ) - self.log.warning(f"Not generating obs id. {message}") - return None - - try: - ticket_id = abs(int(block_id)) - image_server_url = IMAGE_SERVER_URL[site] - - # Determine if it's a Block test case or Block ticket - if match.groupdict()["block_test_case"] is not None: - block_type = "BlockT" - else: - block_type = "Block" - - image_server_client = utils.ImageNameServiceClient( - image_server_url, ticket_id, block_type - ) - _, data = await image_server_client.get_next_obs_id(num_images=1) - return data[0] - except ValueError: - raise RuntimeError( - f"Invalid {block_type} id. Got {block_id}, expected an integer type id." - ) - except Exception: - self.log.exception(f"Failed to generate obs id for {self.program}.") - return None - - @contextlib.asynccontextmanager - async def program_reason(self): - """Context manager to publish appropriate checkpoints with program - and reason. - """ - try: - if self.checkpoint_message is not None: - await self.checkpoint(f"{self.checkpoint_message}: Start") - yield - finally: - if self.checkpoint_message is not None: - await self.checkpoint(f"{self.checkpoint_message}: Done") - - await self.save_test_case() - - @contextlib.asynccontextmanager - async def test_case_step(self, comment: str | None = None) -> None: - """Context manager to handle test case steps.""" - - if self.step_counter is None: - yield dict() - else: - step_result = dict( - id=next(self.step_counter), - executionTime=datetime.now().isoformat(), - ) - if comment is not None: - step_result["comment"] = comment - try: - yield step_result - except Exception: - step_result["status"] = "FAILED" - self.step_results.append(step_result) - raise - else: - step_result["status"] = "PASSED" - self.step_results.append(step_result) - - async def save_test_case(self) -> None: - """Save test case to the LFA.""" - - if self.test_case is None: - return - - if len(self.step_results) == 0: - self.log.warning( - "No test case step registered, no test case results to store. Skipping." - ) - return - - self.log.info("Saving test case metadata to LFA.") - - test_case_payload = json.dumps( - dict( - projectId=self.test_case.get("project", "LVV"), - issueId=self.test_case["name"], - executionId=self.test_case["execution"], - versionId=self.test_case["version"], - stepResults=self.step_results, - ) - ).encode() - - test_case_output = io.BytesIO() - byte_size = test_case_output.write(test_case_payload) - test_case_output.seek(0) - - s3bucket = get_s3_bucket() - - key = s3bucket.make_key( - salname=self.salinfo.name, - salindexname=self.salinfo.index, - generator=self.test_case["name"], - date=utils.astropy_time_from_tai_unix(utils.current_tai()), - other=self.obs_id, - suffix=".json", - ) - - await s3bucket.upload(fileobj=test_case_output, key=key) - - url = f"{s3bucket.service_resource.meta.client.meta.endpoint_url}/{s3bucket.name}/{key}" - - md5 = hashlib.md5() - md5.update(test_case_payload) - - await self.evt_largeFileObjectAvailable.set_write( - id=self.obs_id, - url=url, - generator=self.test_case["name"], - mimeType="JSON", - byteSize=byte_size, - checkSum=md5.hexdigest(), - version=1, - ) - - async def run(self): - """Override base script run to encapsulate execution with appropriate - checkpoints. - """ - async with self.program_reason(): - await self.run_block() - - @abc.abstractmethod - async def run_block(self): - raise NotImplementedError() diff --git a/python/lsst/ts/standardscripts/base_focus_sweep.py b/python/lsst/ts/standardscripts/base_focus_sweep.py deleted file mode 100644 index 021b3635f..000000000 --- a/python/lsst/ts/standardscripts/base_focus_sweep.py +++ /dev/null @@ -1,384 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseFocusSweep"] - -import abc -import asyncio -import json -import types - -import yaml -from lsst.ts import salobj - -from .base_block_script import BaseBlockScript - - -class BaseFocusSweep(BaseBlockScript): - """Perform a focus sweep by taking images at different focus positions. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * Step 1/n_steps axis: axis starting position: start_position. - * Step n/n_steps axis: axis. - """ - - def __init__(self, index, descr="Perform a focus sweep.") -> None: - super().__init__(index=index, descr=descr) - - self.ocps = None - - self.config = None - - self.total_focus_offset = 0.0 - self.iterations_started = False - self.focus_visit_ids = [] - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - @abc.abstractmethod - async def configure_tcs(self): - """Abstract method to configure the TCS.""" - raise NotImplementedError() - - @property - @abc.abstractmethod - def camera(self): - raise NotImplementedError() - - @abc.abstractmethod - async def configure_camera(self): - """Abstract method to configure the Camera.""" - raise NotImplementedError() - - async def configure_ocps(self): - """Configure the OCPS remote object.""" - if self.ocps is None: - self.log.debug("Configuring remote for OCPS:101") - self.ocps = salobj.Remote(self.domain, "OCPS", 101) - await self.ocps.start_task - else: - self.log.debug("OCPS already configured. Ignoring.") - - @classmethod - def get_schema(cls) -> dict: - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/base_focus_sweep.yaml - title: BaseFocusSweep v1 - description: Configuration for BaseFocusSweep. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - exp_time: - description: The exposure time to use when taking images (sec). - type: number - default: 10. - axis: - description: Axis to perform the focus sweep. Should be one of "x", "y", "z", "u" and "v". - type: string - enum: ["x", "y", "z", "u", "v"] - focus_window: - description: Total range (window) measured in um for the focus sweep. - type: number - n_steps: - description: Number of steps to take inside the focus window. - type: number - minimum: 2 - focus_step_sequence: - description: >- - User-provided sequence of focus steps measured in um to take for the focus sweep, - used for unevenly spaced steps. - type: array - items: - type: number - minItems: 2 - n_images_per_step: - description: Number of images to take at each focus position. - type: integer - default: 1 - program: - description: >- - Optional name of the program this dataset belongs to. - type: string - default: FOCUS_SWEEP - reason: - description: Optional reason for taking the data. - anyOf: - - type: string - - type: "null" - default: null - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - oneOf: - - required: - - axis - - focus_window - - n_steps - - required: - - axis - - focus_step_sequence - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - await self.configure_tcs() - await self.configure_camera() - await self.configure_ocps() - - if hasattr(config, "ignore"): - for comp in config.ignore: - if comp in self.tcs.components_attr: - self.log.debug(f"Ignoring TCS component {comp}.") - setattr(self.tcs.check, comp, False) - elif comp in self.camera.components_attr: - self.log.debug(f"Ignoring Camera component {comp}.") - setattr(self.camera.check, comp, False) - else: - self.log.warning( - f"Component {comp} not in CSC Groups. " - f"Must be one of {self.tcs.components_attr} or " - f"{self.camera.components_attr}. Ignoring." - ) - - if hasattr(config, "focus_step_sequence"): - config.focus_window = ( - config.focus_step_sequence[-1] - config.focus_step_sequence[0] - ) - config.n_steps = len(config.focus_step_sequence) - elif hasattr(config, "focus_window"): - config.focus_step_sequence = [ - i * config.focus_window / (config.n_steps - 1) - for i in range(config.n_steps) - ] - config.focus_step_sequence = [ - s - config.focus_window * 0.5 for s in config.focus_step_sequence - ] - - self.config = config - - await super().configure(config=config) - - def set_metadata(self, metadata: salobj.type_hints.BaseMsgType) -> None: - """Sets script metadata. - - Parameters - ---------- - metadata : `salobj.type_hints.BaseMsgType` - Script metadata topic. - """ - - metadata.duration = ( - self.config.n_steps - * self.config.n_images_per_step - * ( - self.config.exp_time - + self.camera.read_out_time - + self.camera.shutter_time - ) - ) - - metadata.instrument = self.get_instrument_name() - metadata.filter = self.get_instrument_filter() - - async def assert_feasibility(self) -> None: - """Verify that the telescope and camera are in a feasible state to - execute the script. - """ - await asyncio.gather( - self.tcs.assert_all_enabled(), self.camera.assert_all_enabled() - ) - - async def focus_sweep(self) -> None: - """Perform the focus sweep operation.""" - - axis = self.config.axis - - start_position = self.config.focus_step_sequence[0] - - offset_display_value = ( - f"{start_position:+0.2} um" - if axis in "xyz" - else f"{start_position*60.*60.:+0.2} arcsec" - ) - - await self.checkpoint( - f"Step 1/{self.config.n_steps} {axis=} starting position: {offset_display_value}." - ) - self.log.info("Offset hexapod to starting position.") - await self.move_hexapod(axis, start_position) - self.total_focus_offset += start_position - self.iterations_started = True - - visit_ids = await self.camera.take_focus( - exptime=self.config.exp_time, - n=self.config.n_images_per_step, - group_id=self.group_id, - program=self.program, - reason=self.reason, - note=f"Focus Sweep Camera d{axis.upper()} {offset_display_value}", - **self.get_instrument_configuration(), - ) - - self.focus_visit_ids.extend(visit_ids) - - try: - for self.iterations_executed in range(1, self.config.n_steps): - await self.checkpoint( - f"Step {self.iterations_executed+1}/{self.config.n_steps} {axis=}." - ) - hexapod_offset = ( - self.config.focus_step_sequence[self.iterations_executed] - - self.config.focus_step_sequence[self.iterations_executed - 1] - ) - await self.move_hexapod(axis, hexapod_offset) - self.total_focus_offset += hexapod_offset - offset_display_value = ( - f"{self.total_focus_offset:+0.2} um" - if axis in "xyz" - else f"{self.total_focus_offset*60.*60.:+0.2} arcsec" - ) - visit_ids = await self.camera.take_focus( - exptime=self.config.exp_time, - n=self.config.n_images_per_step, - group_id=self.group_id, - program=self.program, - reason=self.reason, - note=f"Focus Sweep Camera d{axis.upper()} {offset_display_value}", - **self.get_instrument_configuration(), - ) - - self.focus_visit_ids.extend(visit_ids) - finally: - - if len(self.focus_visit_ids) > 2: - - instrument = self.get_instrument_name() - config = { - f"{instrument}-FROM-OCS_FOCUSSWEEP": ",".join( - [str(visit_id) for visit_id in self.focus_visit_ids] - ) - } - - self.log.info("Starting focus sweep pipeline.") - try: - await self.ocps.cmd_execute.set_start( - config=json.dumps(config), - timeout=self.camera.fast_timeout, - ) - except Exception: - self.log.exception( - "Failed to execute focus sweep through OCPS. Ignoring." - ) - else: - self.log.warning( - "Not enough exposures taken to process focus sweep. Ignoring." - ) - - @abc.abstractmethod - async def move_hexapod(self, axis: str, value: float) -> None: - """Move hexapod to a specific position along a specified axis.""" - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_configuration(self) -> dict: - """Get the instrument configuration. - - Returns - ------- - dict - Dictionary with instrument configuration. - """ - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_filter(self) -> str: - """Get the instrument filter configuration. - - Returns - ------- - str - Instrument filter configuration. - """ - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_name(self) -> str: - raise NotImplementedError() - - async def run_block(self) -> None: - """Execute script operations.""" - - await self.assert_feasibility() - await self.focus_sweep() - - async def cleanup(self): - try: - if self.iterations_started: - - self.log.info( - f"Returning hexapod to original position by moving " - f"{self.total_focus_offset} back along axis {self.config.axis}." - ) - await self.move_hexapod(self.config.axis, -self.total_focus_offset) - except Exception: - self.log.exception( - "Error while trying to return hexapod to its original position." - ) diff --git a/python/lsst/ts/standardscripts/base_offset_tcs.py b/python/lsst/ts/standardscripts/base_offset_tcs.py deleted file mode 100644 index 21609d868..000000000 --- a/python/lsst/ts/standardscripts/base_offset_tcs.py +++ /dev/null @@ -1,226 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseOffsetTCS"] - -import abc - -import yaml -from lsst.ts import salobj - - -class BaseOffsetTCS(salobj.BaseScript, metaclass=abc.ABCMeta): - """Base TCS offset script. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - - This class requires one of the following properties ["offset_azel", - "offset_radec", "offset_xy", "offset_rot", "reset_offsets"] to be provided - in the yaml in order to be configured. Providing more than one of the above - properties will result in a Validation Error and the script will fail in - the Configuration State. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/auxtel/offset_atcs.yaml - title: OffsetATCS v1 - description: Configuration for OffsetATCS Script. - type: object - properties: - offset_azel: - type: object - description: Offset in local AzEl coordinates. - properties: - az: - description: Offset in azimuth (arcsec). - type: number - el: - description: Offset in elevation (arcsec). - type: number - required: ["az","el"] - offset_radec: - type: object - description: Offset telescope in RA and Dec. - properties: - ra: - description: Offset in ra (arcsec). - type: number - dec: - description: Offset in dec (arcsec). - type: number - required: ["ra","dec"] - offset_xy: - type: object - description: Offset in the detector X/Y plane. - properties: - x: - description: Offset in camera x-axis (arcsec). - type: number - y: - description: Offset in camera y-axis (arcsec). - type: number - required: ["x","y"] - offset_rot: - type: object - description: Offset rotator angle. - properties: - rot: - description: Offset rotator (degrees). - type: number - required: ["rot"] - offset_pa: - type: object - description: >- - Offset the telescope based on a position angle and radius - to the current target position. - properties: - angle: - description: Offset position angle, clockwise from North (degrees). - type: number - radius: - description: Radial offset relative to target position (arcsec). - type: number - required: ["angle", "radius"] - additionalProperties: false - reset_offsets: - type: object - description: Reset offsets - properties: - reset_absorbed: - description: Reset absorbed offset? If unsure, set True - type: boolean - reset_non_absorbed: - description: Reset non-absorbed offset? If unsure, set True - type: boolean - required: ["reset_absorbed","reset_non_absorbed"] - relative: - description: If `True` (default) offset is applied relative to the current - position, if `False` offset replaces any existing offsets. - type: boolean - default: True - absorb: - description: If `True`, offset should be absorbed and persisted between - slews. - type: boolean - default: False - additionalProperties: false - oneOf: - - required: ["offset_azel"] - - required: ["offset_radec"] - - required: ["offset_xy"] - - required: ["offset_rot"] - - required: ["reset_offsets"] - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - - self.offset_azel = getattr(config, "offset_azel", None) - self.offset_radec = getattr(config, "offset_radec", None) - self.offset_xy = getattr(config, "offset_xy", None) - self.offset_rot = getattr(config, "offset_rot", None) - self.offset_pa = getattr(config, "offset_pa", None) - self.reset_offsets = getattr(config, "reset_offsets", None) - - self.relative = config.relative - self.absorb = config.absorb - - def set_metadata(self, metadata): - metadata.duration = 10 - - async def assert_feasibility(self) -> None: - """Verify that the telescope is in a feasible state to - execute the script. - """ - - await self.tcs.assert_all_enabled() - - async def run(self): - await self.assert_feasibility() - - if self.offset_azel is not None: - await self.checkpoint(f"Offset azel: {self.offset_azel}") - await self.tcs.offset_azel( - az=self.offset_azel["az"], - el=self.offset_azel["el"], - relative=self.relative, - absorb=self.absorb, - ) - - if self.offset_radec is not None: - await self.checkpoint(f"Offset radec: {self.offset_radec}") - await self.tcs.offset_radec( - ra=self.offset_radec["ra"], - dec=self.offset_radec["dec"], - ) - - if self.offset_xy is not None: - await self.checkpoint(f"Offset xy: {self.offset_xy}") - await self.tcs.offset_xy( - x=self.offset_xy["x"], - y=self.offset_xy["y"], - relative=self.relative, - absorb=self.absorb, - ) - - if self.offset_rot is not None: - await self.checkpoint(f"Offset rot: {self.offset_rot}") - await self.tcs.offset_rot( - rot=self.offset_rot["rot"], - ) - - if self.offset_pa is not None: - await self.checkpoint(f"Offset pa: {self.offset_pa}") - await self.tcs.offset_pa(**self.offset_pa) - - if self.reset_offsets is not None: - await self.checkpoint(f"Reset offsets: {self.reset_offsets}") - await self.tcs.reset_offsets( - absorbed=self.reset_offsets["reset_absorbed"], - non_absorbed=self.reset_offsets["reset_non_absorbed"], - ) diff --git a/python/lsst/ts/standardscripts/base_point_azel.py b/python/lsst/ts/standardscripts/base_point_azel.py deleted file mode 100644 index 057f7c450..000000000 --- a/python/lsst/ts/standardscripts/base_point_azel.py +++ /dev/null @@ -1,188 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BasePointAzEl"] - -import abc -import asyncio -import time - -import yaml -from lsst.ts.idl.enums.Script import ScriptState - -from .base_block_script import BaseBlockScript - - -class BasePointAzEl(BaseBlockScript, metaclass=abc.ABCMeta): - """A base Script that implements pointing the telescope - to a fixed Az/El/Rot position. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - @abc.abstractmethod - async def configure_tcs(self): - """Abstract method to configure the TCS.""" - raise NotImplementedError() - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/BasePointAzEl.yaml - title: PointAzEl v1 - description: Configuration for PointAzEl command. - type: object - properties: - az: - description: >- - Target Azimuth in degrees. - type: number - el: - description: >- - Target Elevation in degrees. - type: number - minimum: 0.0 - maximum: 90.0 - rot_tel: - description: >- - Rotator angle in mount physical coordinates (degrees). - type: number - default: 0.0 - target_name: - description: Name of the position. - type: string - default: "AzEl" - wait_dome: - description: >- - Wait for dome to be in sync with the telescope? - type: boolean - default: false - slew_timeout: - description: Timeout for slew procedure (in seconds). - type: number - default: 240.0 - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - required: - - az - - el - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - - await self.configure_tcs() - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.tcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.tcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.tcs.check, comp, False) - - await super().configure(config=config) - - async def assert_feasibility(self) -> None: - """Verify that the telescope is in a feasible state to - execute the script. - """ - - await self.tcs.assert_all_enabled() - - async def run_block(self): - await self.assert_feasibility() - - start_time = time.monotonic() - self.log.info( - f"Start slew to Az: {self.config.az}, El: {self.config.el} and " - f"Rot: {self.config.rot_tel}" - ) - - await self.tcs.point_azel( - az=self.config.az, - el=self.config.el, - rot_tel=self.config.rot_tel, - target_name=self.config.target_name, - wait_dome=self.config.wait_dome, - slew_timeout=self.config.slew_timeout, - ) - await self.tcs.stop_tracking() - - elapsed_time = time.monotonic() - start_time - - self.log.info(f"Slew finished in {elapsed_time}.") - - async def cleanup(self): - if self.state.state != ScriptState.STOPPING: - # abnormal termination - self.log.warning( - f"Terminating with state={self.state.state}: stop telescope." - ) - try: - await self.tcs.stop_tracking() - except asyncio.TimeoutError: - self.log.exception( - "Stop tracking command timed out during cleanup procedure." - ) - except Exception: - self.log.exception("Unexpected exception while stopping telescope.") diff --git a/python/lsst/ts/standardscripts/base_script_test_case.py b/python/lsst/ts/standardscripts/base_script_test_case.py deleted file mode 100644 index 4bda1c477..000000000 --- a/python/lsst/ts/standardscripts/base_script_test_case.py +++ /dev/null @@ -1,274 +0,0 @@ -# This file is part of ts_standardscripts. -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseScriptTestCase"] - -import abc -import asyncio -import contextlib -import logging -import os -import pathlib -import time -import types - -import astropy.time -import yaml -from lsst.ts import salobj, utils -from lsst.ts.idl.enums import Script - -MAKE_TIMEOUT = 90 # Default time for make_script (seconds) - - -class BaseScriptTestCase(metaclass=abc.ABCMeta): - """Base class for Script tests. - - Subclasses must: - - * Inherit both from this and `unittest.IsolatedAsyncioTestCase`. - * Override `basic_make_script` to make the script and any other - controllers, remotes and such, and return a list of scripts, - controllers and remotes that you made. - - A typical test will look like this: - - async def test_something(self): - async with make_script(): - await self.configure_script(...) - # ... test the results of configuring the script (self.script) - - await self.run_script() # (unless only testing configuration) - # ... test the results of running the script - """ - - _index_iter = utils.index_generator() - - @abc.abstractmethod - async def basic_make_script(self, index): - """Make a script as self.script. - - Make all other controllers and remotes, as well - and return a list of the items made. - - Parameters - ---------- - index : `int` - The SAL index of the script. - - Returns - ------- - items : `List` [``any``] - Controllers, Remotes and Script, or any other items - for which to initially wait for ``item.start_task`` - and finally wait for ``item.close()``. - - Notes - ----- - This is a coroutine in the unlikely case that you might - want to wait for something. - """ - raise NotImplementedError() - - async def close(self): - """Optional cleanup before closing the scripts and etc.""" - pass - - async def check_executable(self, script_path): - """Check that an executable script can be launched. - - Parameter - --------- - script_path : `str` - Full path to script. - """ - - # TODO (DM-41494): remove forward compatibility once salobj-kafka is - # released. - if hasattr(salobj, "set_test_topic_subname"): - salobj.set_test_topic_subname() - else: - salobj.set_random_lsst_dds_partition_prefix() - - index = self.next_index() - - script_path = pathlib.Path(script_path).resolve() - - assert script_path.is_file() - - async with salobj.Domain() as domain, salobj.Remote( - domain=domain, name="Script", index=index - ) as remote: - initial_path = os.environ["PATH"] - process = None - try: - os.environ["PATH"] = str(script_path.parent) + ":" + initial_path - process = await asyncio.create_subprocess_exec( - str(script_path), str(index) - ) - - state = await remote.evt_state.next(flush=False, timeout=MAKE_TIMEOUT) - assert state.state == Script.ScriptState.UNCONFIGURED - finally: - if process is not None: - process.terminate() - os.environ["PATH"] = initial_path - - async def configure_script(self, **kwargs): - """Configure the script and set the group ID (if using ts_salobj - 4.5 or later). - - Sets the script state to UNCONFIGURED. - This allows you to call configure_script multiple times. - - Parameters - ---------- - kwargs : `dict` - Keyword arguments for configuration. - - Returns - ------- - config : `types.SimpleNamespace` - ``kwargs`` expressed as a SimpleNamespace. - This is provided as a convenience, to avoid boilerplate - and duplication in your unit tests. The data is strictly - based on the input arguments; it has nothing to do - with the script. - """ - await self.script.set_state(Script.ScriptState.UNCONFIGURED) - config = types.SimpleNamespace(**kwargs) - config_data = self.script.cmd_configure.DataType() - if kwargs: - config_data.config = yaml.safe_dump(kwargs) - await self.script.do_configure(config_data) - assert self.script.state.state == Script.ScriptState.CONFIGURED - if hasattr(self.script, "cmd_setGroupId"): - group_id_data = self.script.cmd_setGroupId.DataType( - groupId=astropy.time.Time.now().isot - ) - await self.script.do_setGroupId(group_id_data) - return config - - @contextlib.asynccontextmanager - async def make_script( - self, - log_level=logging.INFO, - timeout=MAKE_TIMEOUT, - verbose=False, - randomize_topic_subname=False, - ): - """Create a Script. - - The script is accessed as ``self.script``. - - Parameters - ---------- - name : `str` - Name of SAL component. - log_level : `int` (optional) - Logging level, such as `logging.INFO`. - timeout : `float` - Timeout (sec) for waiting for ``item.start_task`` and - ``item.close()`` for each item returned by `basic_make_script`, - and `self.close`. - verbose : `bool` - Log data? This can be helpful for setting ``timeout``. - randomize_topic_subname : `bool` - Randomize topic subname? - """ - - # TODO (DM-41494): remove forward compatibility once salobj-kafka is - # released. - if hasattr(salobj, "set_test_topic_subname"): - salobj.set_test_topic_subname(randomize=randomize_topic_subname) - else: - salobj.set_random_lsst_dds_partition_prefix() - - items_to_await = await self.wait_for( - self.basic_make_script(index=self.next_index()), - timeout=timeout, - description="self.basic_make_script()", - verbose=verbose, - ) - try: - await self.wait_for( - asyncio.gather(*[item.start_task for item in items_to_await]), - timeout=timeout, - description=f"item.start_task for {len(items_to_await)} items", - verbose=verbose, - ) - yield - finally: - await self.wait_for( - self.close(), - timeout=timeout, - description="self.close()", - verbose=verbose, - ) - await self.wait_for( - asyncio.gather(*[item.close() for item in items_to_await]), - timeout=timeout, - description=f"item.close() for {len(items_to_await)} items", - verbose=verbose, - ) - - def next_index(self): - return next(self._index_iter) - - async def run_script(self, expected_final_state=Script.ScriptState.DONE): - """Run the script. - - Requires that the script be configured and the group ID set - (if using ts_salobj 4.5 or later). - """ - run_data = self.script.cmd_run.DataType() - await self.script.do_run(run_data) - await self.script.done_task - assert self.script.state.state == expected_final_state - - async def wait_for(self, coro, timeout, description, verbose): - """A wrapper around asyncio.wait_for that prints timing information. - - Parameters - ---------- - coro : ``awaitable`` - Coroutine or task to await. - timeout : `float` - Timeout (seconds) - description : `str` - Description of what is being awaited. - verbose : `bool` - If True then print a message before waiting - and another after that includes how long it waited. - If False only print a message if the wait times out. - """ - t0 = time.monotonic() - if verbose: - print(f"wait for {description}") - try: - result = await asyncio.wait_for(coro, timeout=timeout) - except asyncio.TimeoutError: - dt = time.monotonic() - t0 - print(f"{description} timed out after {dt:0.1f} seconds") - raise - if verbose: - dt = time.monotonic() - t0 - print(f"{description} took {dt:0.1f} seconds") - return result diff --git a/python/lsst/ts/standardscripts/base_stop_tracking.py b/python/lsst/ts/standardscripts/base_stop_tracking.py deleted file mode 100644 index 41073f979..000000000 --- a/python/lsst/ts/standardscripts/base_stop_tracking.py +++ /dev/null @@ -1,67 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseStopTracking"] - -import abc - -from lsst.ts import salobj - - -class BaseStopTracking(salobj.BaseScript): - """A base script that implements stop_tracking functionality for `BaseTCS` - classes. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - Stop tracking: Before issuing stop tracking. - Done: After issuing stop tracking. - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - @classmethod - def get_schema(cls): - return None - - async def configure(self, config): - pass - - def set_metadata(self, metadata): - metadata.duration = self.tcs.tel_settle_time - - async def run(self): - await self.checkpoint("Stop tracking") - await self.tcs.stop_tracking() - await self.checkpoint("Done") diff --git a/python/lsst/ts/standardscripts/base_take_image.py b/python/lsst/ts/standardscripts/base_take_image.py deleted file mode 100644 index feac26f1a..000000000 --- a/python/lsst/ts/standardscripts/base_take_image.py +++ /dev/null @@ -1,258 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseTakeImage"] - -import abc -import asyncio -import collections - -import astropy.units -import numpy as np -import yaml -from astropy.coordinates import ICRS, Angle -from lsst.ts import salobj -from lsst.ts.xml.enums.Script import MetadataCoordSys, MetadataRotSys - - -class BaseTakeImage(salobj.BaseScript, metaclass=abc.ABCMeta): - """Base take images script. - - Parameters - ---------- - index : `int` - SAL index of this Script - - Notes - ----- - **Checkpoints** - - * exposure {n} of {m}: before sending the ``takeImages`` command - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - self.instrument_setup_time = 0.0 - - @property - @abc.abstractmethod - def camera(self): - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_configuration(self): - """Get instrument configuration. - - Returns - ------- - instrument_configuration: `dict` - Dictionary with instrument configuration. - """ - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_name(self): - """Get instrument name. - - Returns - ------- - instrument_name: `string` - """ - raise NotImplementedError() - - def get_instrument_filter(self): - """Get instrument filter configuration. - Returns - ------- - instrument_filter: `string` - """ - return self.get_instrument_configuration().get("filter", "") - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/auxtel/LatissTakeImage.yaml - title: BaseTakeImage v2 - description: Configuration for BaseTakeImage. - type: object - properties: - nimages: - description: The number of images to take; if omitted then use the length of - exp_times or take a single exposure if exp_times is a scalar. - anyOf: - - type: integer - minimum: 1 - - type: "null" - default: null - exp_times: - description: The exposure time of each image (sec). If a single value, - then the same exposure time is used for each exposure. - anyOf: - - type: array - minItems: 1 - items: - type: number - minimum: 0 - - type: number - minimum: 0 - default: 0 - image_type: - description: Image type (a.k.a. IMGTYPE) (e.g. BIAS, DARK, FLAT, OBJECT) - type: string - enum: ["BIAS", "DARK", "FLAT", "OBJECT", "ENGTEST", "ACQ", "SPOT", "CWFS", "FOCUS"] - reason: - description: Optional reason for taking the data. - type: string - program: - description: Name of the program this data belongs to, e.g. WFD, DD, etc. - type: string - note: - description: A descriptive note about the image being taken. - type: string - slew_time: - description: Emulate a slewttime by sleeping before taking data. - type: number - default: 0 - visit_metadata: - type: object - properties: - ra: - description: ICRS right ascension (hour). Note this is ONLY used for script queue. - anyOf: - - type: number - minimum: 0 - maximum: 24 - - type: string - dec: - description: ICRS declination (deg). Note this is ONLY used for script queue metadata. - anyOf: - - type: number - minimum: -90 - maximum: 90 - - type: string - rot_sky: - description: >- - The position angle in the Sky. 0 deg means that North is pointing up - in the images. Note this is ONLY used for script queue metadata. - type: number - required: [ra, dec, rot_sky] - required: [image_type] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - - nimages = self.config.nimages - if isinstance(self.config.exp_times, collections.abc.Iterable): - if nimages is not None: - if len(self.config.exp_times) != nimages: - raise ValueError( - f"nimages={nimages} specified and " - f"exp_times={self.config.exp_times} is an array, " - f"but the length does not match nimages" - ) - else: - # exp_time is a scalar; if nimages is specified then - # take that many images, else take 1 image - if nimages is None: - nimages = 1 - self.config.exp_times = [self.config.exp_times] * nimages - - def set_metadata(self, metadata): - nimages = len(self.config.exp_times) - mean_exptime = np.mean(self.config.exp_times) - metadata.duration = ( - self.instrument_setup_time - + self.config.slew_time - + ( - mean_exptime + self.camera.read_out_time + self.camera.shutter_time * 2 - if self.camera.shutter_time - else 0 - ) - * nimages - ) - metadata.nimages = len(self.config.exp_times) - metadata.instrument = self.get_instrument_name() - - if hasattr(self.config, "program"): - metadata.survey = self.config.program - - if hasattr(self.config, "visit_metadata"): - metadata.coordinateSystem = MetadataCoordSys.ICRS - radec_icrs = ICRS( - Angle(self.config.visit_metadata["ra"], unit=astropy.units.hourangle), - Angle(self.config.visit_metadata["dec"], unit=astropy.units.deg), - ) - metadata.position = [radec_icrs.ra.deg, radec_icrs.dec.deg] - metadata.rotationSystem = MetadataRotSys.SKY - metadata.cameraAngle = self.config.visit_metadata["rot_sky"] - - if self.get_instrument_filter() is not None: - metadata.filters = str(self.get_instrument_filter()) - - async def run(self): - nimages = len(self.config.exp_times) - note = getattr(self.config, "note", None) - reason = getattr(self.config, "reason", None) - program = getattr(self.config, "program", None) - - setup_tasks = [ - self.camera.setup_instrument(**self.get_instrument_configuration()) - ] - - if self.config.slew_time > 0: - await self.checkpoint( - f"Setup instrument and concurrently sleep for {self.config.slew_time}s " - "before data acquisition." - ) - setup_tasks.append(asyncio.sleep(self.config.slew_time)) - else: - await self.checkpoint("setup instrument") - - await asyncio.gather(*setup_tasks) - for i, exposure in enumerate(self.config.exp_times): - self.log.debug( - f"Exposing image {i+1} of {nimages} with exp_time={exposure}s." - ) - await self.checkpoint(f"exposure {i+1} of {nimages}") - await self.camera.take_imgtype( - self.config.image_type, - exposure, - 1, - n_snaps=1, - reason=reason, - program=program, - group_id=self.group_id, - note=note, - ) diff --git a/python/lsst/ts/standardscripts/base_take_stuttered.py b/python/lsst/ts/standardscripts/base_take_stuttered.py deleted file mode 100644 index 0f62f0a11..000000000 --- a/python/lsst/ts/standardscripts/base_take_stuttered.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseTakeStuttered"] - -import abc - -import yaml -from lsst.ts import salobj - - -class BaseTakeStuttered(salobj.BaseScript, metaclass=abc.ABCMeta): - """Base class for take stuttered images script. - - Parameters - ---------- - index : `int` - SAL index of this Script - - Notes - ----- - **Checkpoints** - - * exposure {n} of {m}: before sending the ``takeImages`` command - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - self.instrument_setup_time = 0.0 - - @property - @abc.abstractmethod - def camera(self): - raise NotImplementedError() - - @abc.abstractmethod - def get_instrument_configuration(self): - """Get instrument configuration. - - Returns - ------- - instrument_configuration: `dict` - Dictionary with instrument configuration. - """ - raise NotImplementedError() - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/base_take_stuttered.py - title: BaseTakeImage v2 - description: Configuration for BaseTakeImage. - type: object - properties: - n_images: - description: The number of images to take. - minimum: 0 - type: integer - default: 1 - n_shift: - description: Number of shift-expose sequences. - minimum: 1 - type: integer - default: 20 - row_shift: - description: How many rows to shift at each sequence. - minimum: 1 - type: integer - default: 100 - exp_time: - description: The exposure time (sec). - type: number - minimum: 0 - reason: - description: Optional reason for taking the data. - type: string - program: - description: Name of the program this data belongs to, e.g. WFD, DD, etc. - type: string - note: - description: A descriptive note about the image being taken. - type: string - required: [exp_time] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - - def set_metadata(self, metadata): - metadata.duration = self.instrument_setup_time + ( - self.config.n_shift - * self.config.row_shift - * self.config.n_images - * self.config.exp_time - ) - - async def run(self): - note = getattr(self.config, "note", None) - reason = getattr(self.config, "reason", None) - program = getattr(self.config, "program", None) - - await self.checkpoint("setup instrument") - await self.camera.setup_instrument(**self.get_instrument_configuration()) - - await self.checkpoint("Take stuttered") - await self.camera.take_stuttered( - exptime=self.config.exp_time, - n_shift=self.config.n_shift, - row_shift=self.config.row_shift, - n=self.config.n_images, - reason=reason, - program=program, - group_id=self.group_id, - note=note, - ) diff --git a/python/lsst/ts/standardscripts/base_track_target.py b/python/lsst/ts/standardscripts/base_track_target.py deleted file mode 100644 index cea6901a1..000000000 --- a/python/lsst/ts/standardscripts/base_track_target.py +++ /dev/null @@ -1,555 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseTrackTarget"] - -import abc -import asyncio -import enum - -import yaml -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.observatory.control.utils import RotType -from lsst.ts.xml.enums.MTPtg import Planets - -from .base_block_script import BaseBlockScript - - -class SlewType(enum.IntEnum): - OBJECT = enum.auto() - ICRS = enum.auto() - AZEL = enum.auto() - PLANET = enum.auto() - EPHEM = enum.auto() - TRACK_AZEL = enum.auto() - - -class BaseTrackTarget(BaseBlockScript, metaclass=abc.ABCMeta): - """Base track target script. - - This script implements the basic configuration and run procedures for - slewing and tracking a target, either by using ICRS coordinates or the - object name. It is a base class for both the Main and Auxiliary Telescope. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - descr : `str` - Short Script description. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - # Flag to monitor if tracking started for cleanup task. - self.tracking_started = False - - # Flag to specify which type of slew will be performend: - # slew_icrs, slew_object, slew_planet or slew_ephem - self.slew_type = SlewType.OBJECT - - # Timeout for slewing (in seconds). - self.slew_timeout = 240.0 - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - async def configure_tcs(self): - if self.tcs is not None: - await self.tcs.start_task - - @classmethod - def get_schema(cls): - planet_names = ", ".join([f'"{planet.name}"' for planet in Planets]) - - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/base_slew.yaml - title: BaseTrackTarget v1 - description: Configuration for BaseTrackTarget. - type: object - properties: - slew_icrs: - type: object - description: >- - Optional configuration section. Slew to icrs ra/dec coordinates. - If not specified it will be ignored. - additionalProperties: false - required: - - ra - - dec - properties: - ra: - description: ICRS right ascension (hour). - anyOf: - - type: number - minimum: 0 - maximum: 24 - - type: string - dec: - description: ICRS declination (deg). - anyOf: - - type: number - minimum: -90 - maximum: 90 - - type: string - track_azel: - type: object - description: >- - Optional configuration section. Slew to az/el and start tracking. - If not specified it will be ignored. - additionalProperties: false - required: - - az - - el - properties: - az: - description: Azimuth (deg). - anyOf: - - type: number - - type: string - el: - description: Elevation (deg). - anyOf: - - type: number - minimum: 0 - maximum: 90 - - type: string - slew_planet: - type: object - description: >- - Optional configuration section. Slew to a Solar system planet. - If not specified it will be ignored. If specified, the rot_type - propertie must be Sky. - additionalProperties: false - properties: - planet_name: - description: The name of a Solar system planet. - type: string - enum: [{planet_names}] - slew_ephem: - type: object - description: >- - Optional configuration section. Slew to a target based on - ephemeris data. If not specified it will be ignored. - additionalProperties: false - properties: - ephem_file: - description: Ephemeris filename to be used for the slew. - type: string - object_name: - description: The name of object. - type: string - find_target: - type: object - additionalProperties: false - required: - - az - - el - - mag_limit - description: >- - Optional configuration section. Find a target to perform CWFS in the given - position and magnitude range. If not specified, the step is ignored. - properties: - az: - type: number - description: Azimuth (in degrees) to find a target. - el: - type: number - description: Elevation (in degrees) to find a target. - mag_limit: - type: number - description: Minimum (brightest) V-magnitude limit. - mag_range: - type: number - description: >- - Magnitude range. The maximum/faintest limit is defined as - mag_limit+mag_range. - radius: - type: number - description: Radius of the cone search (in degrees). - offset: - type: object - additionalProperties: false - description: >- - Optional configuration section. Apply offset in xy to the original - pointing position. - properties: - x: - type: number - description: Offset the field in the x-axis (arcsec). - default: 0 - y: - type: number - description: Offset the field in the y-axis (arcsec). - default: 0 - differential_tracking: - description: Differential tracking rates. - type: object - additionalProperties: false - properties: - dra: - description: Differential tracking rate in RA (sec/sec). - type: number - default: 0.0 - ddec: - description: Differential tracking rate in Declination (arcsec/sec). - type: number - default: 0.0 - rot_value: - description: >- - Rotator position value. Actual meaning depends on rot_type. - type: number - default: 0 - rot_type: - description: >- - Rotator strategy. Options are: - Sky: Sky position angle strategy. The rotator is positioned with respect - to the North axis so rot_angle=0. means y-axis is aligned with North. - Angle grows clock-wise. - - SkyAuto: Same as sky position angle but it will verify that the requested - angle is achievable and wrap it to a valid range. - - Parallactic: This strategy is required for taking optimum spectra with - LATISS. If set to zero, the rotator is positioned so that the - y-axis (dispersion axis) is aligned with the parallactic - angle. - - PhysicalSky: This strategy allows users to select the **initial** position - of the rotator in terms of the physical rotator angle (in the - reference frame of the telescope). Note that the telescope - will resume tracking the sky rotation. - - Physical: Select a fixed position for the rotator in the reference frame of - the telescope. Rotator will not track in this mode. - type: string - enum: ["Sky", "SkyAuto", "Parallactic", "PhysicalSky", "Physical"] - default: SkyAuto - target_name: - description: Target name - type: string - track_for: - description: >- - How long to track target for (in seconds). If zero, the default, - finish script as soon as in position, otherwise, continue tracking - target until time expires. - type: number - minimum: 0 - default: 0 - stop_when_done: - description: >- - Stop tracking once tracking time expires. Only valid if - `track_for` is larger than zero. - type: boolean - default: False - az_wrap_strategy: - description: >- - Azimuth wrapping strategy. Options are: - MAXTIMEONTARGET: Maximize the tracking time on the target. - - NOUNWRAP: Do not attempt to unwrap. If target is unreachable - without unwrapping, command will be rejected. - - OPTIMIZE: Use `track_for` to determine if there is - enough time left without unwrapping and only unwrap if - needed. - type: string - enum: ["MAXTIMEONTARGET", "NOUNWRAP", "OPTIMIZE"] - default: OPTIMIZE - slew_timeout: - description: Timeout for slew procedure (in seconds). - type: number - default: 240.0 - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - if: - properties: - slew_icrs: - const: null - track_azel: - const: null - slew_planet: - const: null - slew_ephem: - const: null - then: - oneOf: - - required: - - target_name - - required: - - find_target - else: - oneOf: - - required: - - slew_icrs - - required: - - track_azel - - required: - - slew_planet - - required: - - slew_ephem - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - - self.config = config - - if hasattr(self.config, "slew_icrs"): - self.slew_type = SlewType.ICRS - elif hasattr(self.config, "track_azel"): - self.slew_type = SlewType.TRACK_AZEL - elif hasattr(self.config, "slew_planet"): - self.slew_type = SlewType.PLANET - elif hasattr(self.config, "slew_ephem"): - self.slew_type = SlewType.EPHEM - elif hasattr(self.config, "find_target"): - self.slew_type = SlewType.AZEL - - self.log.debug(f"Slew type: {self.slew_type!r}.") - - await self.configure_tcs() - - self.config.rot_type = getattr(RotType, self.config.rot_type) - - if ( - self.slew_type == SlewType.PLANET or self.slew_type == SlewType.EPHEM - ) and self.config.rot_type != RotType.Sky: - self.log.warning( - f"Slew_type={self.slew_type!r} only works for {RotType.Sky!r}, " - f"got {self.config.rot_type!r}. Ignoring." - ) - - self.config.az_wrap_strategy = getattr( - self.tcs.WrapStrategy, self.config.az_wrap_strategy - ) - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.tcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.tcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.tcs.check, comp, False) - else: - self.log.info(f"Not ignoring TCS components: {self.tcs.components_attr}.") - - await super().configure(config=config) - - def set_metadata(self, metadata): - """Compute estimated duration. - - Parameters - ---------- - metadata : `Script_logevent_metadata` - """ - metadata.duration = 10.0 + self.config.track_for - - async def run_block(self): - target_name = getattr(self.config, "target_name", "slew_icrs") - - self.tracking_started = True - - offset_x = self.config.offset["x"] - offset_y = self.config.offset["y"] - dra = self.config.differential_tracking["dra"] - ddec = self.config.differential_tracking["ddec"] - - if self.slew_type == SlewType.ICRS: - ra = self.config.slew_icrs["ra"] - dec = self.config.slew_icrs["dec"] - - self.log.info( - f"Slew and track target_name={target_name}; " - f"ra={ra}, dec={dec}; " - f"rot={self.config.rot_value}; rot_type={self.config.rot_type}; " - f"offset by; x={offset_x}; y={offset_y}" - ) - - await self.tcs.slew_icrs( - ra=ra, - dec=dec, - rot=self.config.rot_value, - rot_type=self.config.rot_type, - target_name=target_name, - dra=dra, - ddec=ddec, - offset_x=offset_x, - offset_y=offset_y, - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.config.track_for, - slew_timeout=self.slew_timeout, - ) - - elif self.slew_type == SlewType.TRACK_AZEL: - az = self.config.track_azel["az"] - el = self.config.track_azel["el"] - - self.log.info( - f"Slew and track at " - f"az={az}, el={el}; " - f"rot={self.config.rot_value}; rot_type={self.config.rot_type}; " - f"offset by; x={offset_x}; y={offset_y}" - ) - - await self.tcs.point_azel( - az=az, - el=el, - rot_tel=self.config.rot_value, - ) - await self.tcs.start_tracking() - - elif self.slew_type == SlewType.PLANET: - planet_name = self.config.slew_planet["planet_name"] - planet_enum = Planets[planet_name] - - self.log.info( - f"Slew and track planet_name={planet_name}; rot_sky={self.config.rot_value}." - f"offset by; x={offset_x}; y={offset_y}" - ) - - await self.tcs.slew_to_planet( - planet=planet_enum, - rot_sky=self.config.rot_value, - slew_timeout=self.slew_timeout, - ) - - elif self.slew_type == SlewType.EPHEM: - ephem_file = self.config.slew_ephem["ephem_file"] - object_name = self.config.slew_ephem["object_name"] - - self.log.info( - f"Slew and track object_name={object_name}; " - f"ephem_file={ephem_file}; rot_sky={self.config.rot_value}; " - f"offset by; x={offset_x}; y={offset_y}" - ) - - await self.tcs.slew_ephem_target( - ephem_file=self.config.slew_ephem["ephem_file"], - target_name=self.config.slew_ephem["object_name"], - rot_sky=self.config.rot_value, - slew_timeout=self.slew_timeout, - ) - - elif self.slew_type == SlewType.AZEL: - az = self.config.find_target["az"] - el = self.config.find_target["el"] - - self.log.info( - "Find target around azel; " - f"az={az}, el={el}; " - f"rot={self.config.rot_value}; rot_type={self.config.rot_type}; " - f"offset by; x={offset_x}; y={offset_y}" - ) - try: - self.tcs.load_catalog("HD_cwfs_stars") - except Exception: - self.log.exception("Failed to load local star catalog. Ignoring.") - - target_name = await self.tcs.find_target(**self.config.find_target) - - await self.tcs.slew_object( - name=target_name, - rot=self.config.rot_value, - rot_type=self.config.rot_type, - dra=dra, - ddec=ddec, - offset_x=offset_x, - offset_y=offset_y, - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.config.track_for, - slew_timeout=self.slew_timeout, - ) - else: - self.log.info( - f"Slew and track target_name={target_name}; " - f"rot={self.config.rot_value}; rot_type={self.config.rot_type}; " - f"offset by; x={offset_x}; y={offset_y}" - ) - await self.tcs.slew_object( - name=target_name, - rot=self.config.rot_value, - rot_type=self.config.rot_type, - dra=dra, - ddec=ddec, - offset_x=offset_x, - offset_y=offset_y, - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.config.track_for, - slew_timeout=self.slew_timeout, - ) - - if self.config.track_for > 0.0: - self.log.info(f"Tracking for {self.config.track_for}s .") - await self.tcs.check_tracking(self.config.track_for) - if self.config.stop_when_done: - self.log.info("Tracking completed. Stop tracking.") - await self.tcs.stop_tracking() - else: - self.log.info("Tracking completed.") - - async def cleanup(self): - if self.state.state != ScriptState.ENDING: - # abnormal termination - if self.tracking_started: - self.log.warning( - f"Terminating with state={self.state.state}: stop tracking." - ) - try: - await asyncio.wait_for(self.tcs.stop_tracking(), timeout=5) - except asyncio.TimeoutError: - self.log.exception( - "Stop tracking command timed out during cleanup procedure." - ) - except Exception: - self.log.exception("Unexpected exception in stop_tracking.") diff --git a/python/lsst/ts/standardscripts/base_track_target_and_take_image.py b/python/lsst/ts/standardscripts/base_track_target_and_take_image.py deleted file mode 100644 index 1eb8dfcc4..000000000 --- a/python/lsst/ts/standardscripts/base_track_target_and_take_image.py +++ /dev/null @@ -1,321 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseTrackTargetAndTakeImage"] - -import abc -import asyncio - -import astropy.units -import yaml -from astropy.coordinates import ICRS, Angle -from lsst.ts import salobj -from lsst.ts.idl.enums.Script import ( - MetadataCoordSys, - MetadataDome, - MetadataRotSys, - ScriptState, -) - - -class BaseTrackTargetAndTakeImage(salobj.BaseScript): - """Track target and take image script. - - This script implements a simple visit consisting of slewing to a target, - start tracking and take image. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - add_remotes : `bool` (optional) - Create remotes to control components (default: `True`)? If False, the - script will not work for normal operations. Useful for unit testing. - """ - - def __init__(self, index: int, descr: str, add_remotes: bool = True): - super().__init__(index=index, descr=descr) - - self.config = None - - # Flag to monitor if tracking started for cleanup task. - self.tracking_started = False - self.run_started = False - - @classmethod - def get_base_schema(cls): - schema_yaml = """ -$schema: http://json-schema.org/draft-07/schema# -$id: https://github.com/lsst-ts/ts_standardscripts/base_track_target_and_take_image.py -title: BaseTrackTargetAndTakeImage v1 -description: Configuration for BaseTrackTargetAndTakeImage. -type: object -properties: - targetid: - description: Id of the target. - type: integer - ra: - description: ICRS right ascension (hour). - anyOf: - - type: number - minimum: 0 - maximum: 24 - - type: string - dec: - description: ICRS declination (deg). - anyOf: - - type: number - minimum: -90 - maximum: 90 - - type: string - rot_sky: - description: >- - The position angle in the Sky. 0 deg means that North is pointing up - in the images. - type: number - name: - description: Target name. - type: string - obs_time: - type: number - description: When should slew start. - estimated_slew_time: - type: number - description: An estimative of how much a slew will take. - default: 0 - az_wrap_strategy: - description: >- - Azimuth wrapping strategy. Options are: - MAXTIMEONTARGET: Maximize the tracking time on the target. - - NOUNWRAP: Do not attempt to unwrap. If target is unreachable - without unwrapping, command will be rejected. - - OPTIMIZE: Use `track_for` to determine if there is - enough time left without unwrapping and only unwrap if - needed. - type: string - enum: ["MAXTIMEONTARGET", "NOUNWRAP", "OPTIMIZE"] - default: OPTIMIZE - num_exp: - type: integer - description: Number of exposures. - exp_times: - description: Exposure times in seconds. - type: array - minItems: 1 - items: - type: number - minimum: 0 - band_filter: - description: Name of the filter for observation. - anyOf: - - type: array - minItems: 1 - items: - type: string - - type: string - reason: - description: Optional reason for taking the data. - anyOf: - - type: string - - type: "null" - default: null - program: - description: Optional name of the program this data belongs to, e.g. WFD, DD, etc. - anyOf: - - type: string - - type: "null" - default: null - camera_playlist: - description: >- - Optional name a camera playlist to load before running the script. - This parameter is mostly designed to use for integration tests and is - switched off by default (e.g. null). - anyOf: - - type: string - - type: "null" - default: null -required: - - ra - - dec - - rot_sky - - name - - obs_time - - num_exp - - exp_times - - band_filter - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - - self.log.debug(f"Configured with {config}.") - self.config = config - self.config.az_wrap_strategy = getattr( - self.tcs.WrapStrategy, self.config.az_wrap_strategy - ) - - def set_metadata(self, metadata): - """Compute estimated duration. - - Parameters - ---------- - metadata : `Script_logevent_metadata` - """ - metadata.duration = self.get_estimated_time_on_target() - metadata.coordinateSystem = MetadataCoordSys.ICRS - radec_icrs = ICRS( - Angle(self.config.ra, unit=astropy.units.hourangle), - Angle(self.config.dec, unit=astropy.units.deg), - ) - metadata.position = [radec_icrs.ra.deg, radec_icrs.dec.deg] - metadata.rotationSystem = MetadataRotSys.SKY - metadata.cameraAngle = self.config.rot_sky - metadata.filters = ( - self.config.band_filter - if isinstance(self.config.band_filter, str) - else ",".join(self.config.band_filter) - ) - metadata.dome = MetadataDome.OPEN - metadata.nimages = self.config.num_exp - metadata.survey = self.config.program - metadata.totalCheckpoints = 3 if self.config.camera_playlist is None else 4 - metadata.instrument = self.get_instrument_name() - - def get_estimated_time_on_target(self): - """Get the estimated time on target. - - Returns - ------- - float - Estimated time on targets (in sec). - """ - return sum(self.config.exp_times) + self.config.estimated_slew_time - - async def run(self): - self.run_started = True - - await self.assert_feasibility() - - if self.config.camera_playlist is not None: - await self.checkpoint(f"Loading playlist: {self.config.camera_playlist}.") - self.log.warning( - f"Running script with playlist: {self.config.camera_playlist}. " - "This is only suitable for test-type run and should not be used for " - "on-sky observations. If you are on sky, check your script configuration." - ) - await self.load_playlist() - - await self.checkpoint( - f"[{self.config.name}; " - f"ra={self.config.ra}, dec={self.config.dec};" - f"rot={self.config.rot_sky:0.2f}]::" - "Track target and setup instrument." - ) - - await self.track_target_and_setup_instrument() - - await self.checkpoint( - f"[{self.config.name}; " - f"ra={self.config.ra}, dec={self.config.dec};" - f"rot={self.config.rot_sky:0.2f}]::" - "Take data." - ) - - await self.take_data() - - await self.checkpoint( - f"[{self.config.name}; " - f"ra={self.config.ra}, dec={self.config.dec};" - f"rot={self.config.rot_sky:0.2f}]::" - "done" - ) - - @property - @abc.abstractmethod - def tcs(self): - raise NotImplementedError() - - @abc.abstractstaticmethod - async def load_playlist(self): - """Load playlist.""" - raise NotImplementedError() - - @abc.abstractstaticmethod - async def assert_feasibility(self): - """Verify that the system is in a feasible state to execute the - script. - """ - raise NotImplementedError() - - @abc.abstractstaticmethod - async def track_target_and_setup_instrument(self): - """slewing of telescope and setting up of instrument. - - Ideally this would be done in parallel to save time. - """ - raise NotImplementedError() - - @abc.abstractstaticmethod - async def take_data(self): - """Implement method to take data.""" - raise NotImplementedError() - - @abc.abstractstaticmethod - async def stop_tracking(self): - """Implement method to stop tracking.""" - raise RuntimeError() - - @abc.abstractmethod - def get_instrument_name(self): - """Get instrument name. - - Returns - ------- - instrument_name: `string` - """ - raise NotImplementedError() - - async def cleanup(self): - if self.state.state != ScriptState.ENDING: - # abnormal termination - if self.run_started or self.tracking_started: - self.log.warning( - f"Terminating with state={self.state.state}: stop tracking. " - f"Run started: {self.run_started}. " - f"Tracking started: {self.tracking_started}." - ) - try: - await asyncio.wait_for(self.stop_tracking(), timeout=5) - except asyncio.TimeoutError: - self.log.exception( - "Stop tracking command timed out during cleanup procedure." - ) - except Exception: - self.log.exception("Unexpected exception in stop_tracking.") diff --git a/python/lsst/ts/standardscripts/data/scripts/README.md b/python/lsst/ts/standardscripts/data/scripts/README.md deleted file mode 100644 index 9d7544d05..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/README.md +++ /dev/null @@ -1,7 +0,0 @@ -SAL scripts to operate the LSST. - -`Documentation `_ - -Scripts may be grouped by putting them in suitable subdirectories. -Scripts must be command-line executables that take a single -command-line argument: the SAL index for the script. diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/README.md b/python/lsst/ts/standardscripts/data/scripts/auxtel/README.md deleted file mode 100644 index 2276d43d2..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/README.md +++ /dev/null @@ -1 +0,0 @@ -Scripts specific to the LSST auxiliary telescope. diff --git a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/home_dome.py b/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/home_dome.py deleted file mode 100755 index 89680741f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/auxtel/atdome/home_dome.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.auxtel.atdome import HomeDome - -asyncio.run(HomeDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/README.md b/python/lsst/ts/standardscripts/data/scripts/maintel/README.md deleted file mode 100644 index 99bd457a9..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/README.md +++ /dev/null @@ -1 +0,0 @@ -Scripts specific to the LSST main telescope. diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/apply_dof.py b/python/lsst/ts/standardscripts/data/scripts/maintel/apply_dof.py deleted file mode 100755 index bc1f53b8b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/apply_dof.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import ApplyDOF - -asyncio.run(ApplyDOF.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/calibration/power_on_tunablelaser.py b/python/lsst/ts/standardscripts/data/scripts/maintel/calibration/power_on_tunablelaser.py deleted file mode 100755 index 1ce19e9f8..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/calibration/power_on_tunablelaser.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.calibration import PowerOnTunableLaser - -asyncio.run(PowerOnTunableLaser.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_comcam.py deleted file mode 100755 index f010952da..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import CloseLoopComCam - -asyncio.run(CloseLoopComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_lsstcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_lsstcam.py deleted file mode 100755 index 153a433a7..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/close_loop_lsstcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import CloseLoopLSSTCam - -asyncio.run(CloseLoopLSSTCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/close_mirror_covers.py b/python/lsst/ts/standardscripts/data/scripts/maintel/close_mirror_covers.py deleted file mode 100755 index 61056b363..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/close_mirror_covers.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import CloseMirrorCovers - -asyncio.run(CloseMirrorCovers.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/disable_hexapod_compensation_mode.py b/python/lsst/ts/standardscripts/data/scripts/maintel/disable_hexapod_compensation_mode.py deleted file mode 100755 index 9eec5a39f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/disable_hexapod_compensation_mode.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import DisableHexapodCompensationMode - -asyncio.run(DisableHexapodCompensationMode.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/enable_comcam.py deleted file mode 100755 index 4e082ecdf..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import EnableComCam - -asyncio.run(EnableComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_hexapod_compensation_mode.py b/python/lsst/ts/standardscripts/data/scripts/maintel/enable_hexapod_compensation_mode.py deleted file mode 100755 index cd051c5d7..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_hexapod_compensation_mode.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import EnableHexapodCompensationMode - -asyncio.run(EnableHexapodCompensationMode.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_mtcs.py b/python/lsst/ts/standardscripts/data/scripts/maintel/enable_mtcs.py deleted file mode 100755 index 4af75820b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/enable_mtcs.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import EnableMTCS - -asyncio.run(EnableMTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_comcam.py deleted file mode 100755 index 6935f2a1e..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import FocusSweepComCam - -asyncio.run(FocusSweepComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_lsstcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_lsstcam.py deleted file mode 100755 index a57edfad1..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/focus_sweep_lsstcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import FocusSweepLSSTCam - -asyncio.run(FocusSweepLSSTCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/home_both_axes.py b/python/lsst/ts/standardscripts/data/scripts/maintel/home_both_axes.py deleted file mode 100755 index 048a54523..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/home_both_axes.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import HomeBothAxes - -asyncio.run(HomeBothAxes.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/align.py b/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/align.py deleted file mode 100755 index a92ef68a8..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/align.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.laser_tracker import Align - -asyncio.run(Align.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/measure.py b/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/measure.py deleted file mode 100755 index 14d43484b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/measure.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.laser_tracker import Measure - -asyncio.run(Measure.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/set_up.py b/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/set_up.py deleted file mode 100755 index f54cc0a6b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/set_up.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.laser_tracker import SetUp - -asyncio.run(SetUp.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/shut_down.py b/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/shut_down.py deleted file mode 100755 index e77c0a02f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/laser_tracker/shut_down.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.laser_tracker import ShutDown - -asyncio.run(ShutDown.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_actuators.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_actuators.py deleted file mode 100755 index 0c2d91c10..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_actuators.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import CheckActuators - -asyncio.run(CheckActuators.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_hardpoint.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_hardpoint.py deleted file mode 100755 index bc238d779..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/check_hardpoint.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import CheckHardpoint - -asyncio.run(CheckHardpoint.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/disable_m1m3_balance_system.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/disable_m1m3_balance_system.py deleted file mode 100755 index c1f13c447..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/disable_m1m3_balance_system.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import DisableM1M3BalanceSystem - -asyncio.run(DisableM1M3BalanceSystem.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_balance_system.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_balance_system.py deleted file mode 100755 index f62b7ad52..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_balance_system.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import EnableM1M3BalanceSystem - -asyncio.run(EnableM1M3BalanceSystem.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py deleted file mode 100755 index 734396a29..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import EnableM1M3SlewControllerFlags - -asyncio.run(EnableM1M3SlewControllerFlags.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/lower_m1m3.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/lower_m1m3.py deleted file mode 100755 index a2f41b89a..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/lower_m1m3.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import LowerM1M3 - -asyncio.run(LowerM1M3.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/raise_m1m3.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/raise_m1m3.py deleted file mode 100755 index 69357dfc6..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m1m3/raise_m1m3.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.m1m3 import RaiseM1M3 - -asyncio.run(RaiseM1M3.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/check_actuators.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m2/check_actuators.py deleted file mode 100755 index acaeeb2f3..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/check_actuators.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License - -import asyncio - -from lsst.ts.standardscripts.maintel.m2 import CheckActuators - -asyncio.run(CheckActuators.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/disable_closed_loop.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m2/disable_closed_loop.py deleted file mode 100755 index 814a82bea..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/disable_closed_loop.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License - -import asyncio - -from lsst.ts.standardscripts.maintel.m2 import DisableM2ClosedLoop - -asyncio.run(DisableM2ClosedLoop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/enable_closed_loop.py b/python/lsst/ts/standardscripts/data/scripts/maintel/m2/enable_closed_loop.py deleted file mode 100755 index 8b7d89543..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/m2/enable_closed_loop.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License - -import asyncio - -from lsst.ts.standardscripts.maintel.m2 import EnableM2ClosedLoop - -asyncio.run(EnableM2ClosedLoop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/move_p2p.py b/python/lsst/ts/standardscripts/data/scripts/maintel/move_p2p.py deleted file mode 100755 index 98abdff27..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/move_p2p.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import MoveP2P - -asyncio.run(MoveP2P.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/crawl_az.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/crawl_az.py deleted file mode 100755 index 745e79e85..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/crawl_az.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import CrawlAz - -asyncio.run(CrawlAz.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/disable_dome_following.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/disable_dome_following.py deleted file mode 100755 index b497bd374..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/disable_dome_following.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import DisableDomeFollowing - -asyncio.run(DisableDomeFollowing.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/enable_dome_following.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/enable_dome_following.py deleted file mode 100755 index 8fe76b055..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/enable_dome_following.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import EnableDomeFollowing - -asyncio.run(EnableDomeFollowing.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/park_dome.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/park_dome.py deleted file mode 100755 index 0d29bb203..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/park_dome.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import ParkDome - -asyncio.run(ParkDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/slew_dome.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/slew_dome.py deleted file mode 100755 index 55d98fbd3..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/slew_dome.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import SlewDome - -asyncio.run(SlewDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/unpark_dome.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/unpark_dome.py deleted file mode 100755 index d41059bb9..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtdome/unpark_dome.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtdome import UnparkDome - -asyncio.run(UnparkDome.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/park_mount.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/park_mount.py deleted file mode 100755 index 1c65929d5..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/park_mount.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtmount import ParkMount - -asyncio.run(ParkMount.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/unpark_mount.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/unpark_mount.py deleted file mode 100755 index e2604bdad..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtmount/unpark_mount.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtmount import UnparkMount - -asyncio.run(UnparkMount.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/mtrotator/move_rotator.py b/python/lsst/ts/standardscripts/data/scripts/maintel/mtrotator/move_rotator.py deleted file mode 100755 index bbe388ee5..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/mtrotator/move_rotator.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.mtrotator import MoveRotator - -asyncio.run(MoveRotator.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/offline_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/offline_comcam.py deleted file mode 100755 index 8e8f74e8d..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/offline_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OfflineComCam - -asyncio.run(OfflineComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/offline_mtcs.py b/python/lsst/ts/standardscripts/data/scripts/maintel/offline_mtcs.py deleted file mode 100755 index 34042f498..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/offline_mtcs.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OfflineMTCS - -asyncio.run(OfflineMTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_camera_hexapod.py b/python/lsst/ts/standardscripts/data/scripts/maintel/offset_camera_hexapod.py deleted file mode 100755 index 9506f058f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_camera_hexapod.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OffsetCameraHexapod - -asyncio.run(OffsetCameraHexapod.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_m2_hexapod.py b/python/lsst/ts/standardscripts/data/scripts/maintel/offset_m2_hexapod.py deleted file mode 100755 index 89ede544e..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_m2_hexapod.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OffsetM2Hexapod - -asyncio.run(OffsetM2Hexapod.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_mtcs.py b/python/lsst/ts/standardscripts/data/scripts/maintel/offset_mtcs.py deleted file mode 100755 index 76491d04b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/offset_mtcs.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OffsetMTCS - -asyncio.run(OffsetMTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/open_mirror_covers.py b/python/lsst/ts/standardscripts/data/scripts/maintel/open_mirror_covers.py deleted file mode 100755 index 68b3ac641..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/open_mirror_covers.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import OpenMirrorCovers - -asyncio.run(OpenMirrorCovers.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/point_azel.py b/python/lsst/ts/standardscripts/data/scripts/maintel/point_azel.py deleted file mode 100755 index 198fe32f2..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/point_azel.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import PointAzEl - -asyncio.run(PointAzEl.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/prepare_for/align.py b/python/lsst/ts/standardscripts/data/scripts/maintel/prepare_for/align.py deleted file mode 100755 index 0be9498c6..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/prepare_for/align.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.prepare_for import PrepareForAlign - -asyncio.run(PrepareForAlign.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/add_block.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/add_block.py deleted file mode 100755 index 4672ebbec..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/add_block.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.add_block import AddBlock - - -class MTSchedulerAddBlock(AddBlock): - """Add BLOCK to the MTScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerAddBlock.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/enable.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/enable.py deleted file mode 100755 index e33c964be..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/enable.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.enable import Enable - - -class MTSchedulerEnable(Enable): - """Enable the MTScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerEnable.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/load_snapshot.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/load_snapshot.py deleted file mode 100755 index eaa7223ee..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/load_snapshot.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.load_snapshot import LoadSnapshot - - -class MTSchedulerLoadSnapshot(LoadSnapshot): - """Load snapshot for MTScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerLoadSnapshot.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/resume.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/resume.py deleted file mode 100755 index 18d677d80..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/resume.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.resume import Resume - - -class MTSchedulerResume(Resume): - """Resume MTScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerResume.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/standby.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/standby.py deleted file mode 100755 index 5699f9ddb..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/standby.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler import SetDesiredState - - -class MTSchedulerStandby(SetDesiredState): - """Send MTScheduler to STANDBY state.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - desired_state=salobj.State.STANDBY, - descr="Send MainTel Scheduler to standby state", - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerStandby.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/stop.py b/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/stop.py deleted file mode 100755 index 62e19b87a..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/scheduler/stop.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.stop import Stop - - -class MTSchedulerStop(Stop): - """Stop MTScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.MAIN_TEL, - ) - - -asyncio.run(MTSchedulerStop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/set_dof.py b/python/lsst/ts/standardscripts/data/scripts/maintel/set_dof.py deleted file mode 100755 index f3c48b07d..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/set_dof.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import SetDOF - -asyncio.run(SetDOF.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/setup_mtcs.py b/python/lsst/ts/standardscripts/data/scripts/maintel/setup_mtcs.py deleted file mode 100755 index 3bfe4163b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/setup_mtcs.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import SetupMTCS - -asyncio.run(SetupMTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/standby_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/standby_comcam.py deleted file mode 100755 index ed4e63346..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/standby_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import StandbyComCam - -asyncio.run(StandbyComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/standby_mtcs.py b/python/lsst/ts/standardscripts/data/scripts/maintel/standby_mtcs.py deleted file mode 100755 index 6d7f7887e..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/standby_mtcs.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import StandbyMTCS - -asyncio.run(StandbyMTCS.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/stop.py b/python/lsst/ts/standardscripts/data/scripts/maintel/stop.py deleted file mode 100755 index cee68a6cf..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/stop.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import Stop - -asyncio.run(Stop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/stop_rotator.py b/python/lsst/ts/standardscripts/data/scripts/maintel/stop_rotator.py deleted file mode 100755 index aab0d3cd6..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/stop_rotator.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.stop_rotator import StopRotator - -asyncio.run(StopRotator.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/stop_tracking.py b/python/lsst/ts/standardscripts/data/scripts/maintel/stop_tracking.py deleted file mode 100755 index 2179c068a..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/stop_tracking.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel.stop_tracking import StopTracking - -asyncio.run(StopTracking.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_aos_sequence_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_aos_sequence_comcam.py deleted file mode 100755 index 247c4d568..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_aos_sequence_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeAOSSequenceComCam - -asyncio.run(TakeAOSSequenceComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_anycam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_anycam.py deleted file mode 100755 index 842a8a4a1..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_anycam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeImageAnyCam - -asyncio.run(TakeImageAnyCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_comcam.py deleted file mode 100755 index c79719db5..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeImageComCam - -asyncio.run(TakeImageComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_lsstcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_lsstcam.py deleted file mode 100755 index 827d3697d..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_image_lsstcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeImageLSSTCam - -asyncio.run(TakeImageLSSTCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_comcam.py deleted file mode 100755 index 50d435455..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeStutteredComCam - -asyncio.run(TakeStutteredComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_lsstcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_lsstcam.py deleted file mode 100755 index 6b9ae5885..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/take_stuttered_lsstcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TakeStutteredLSSTCam - -asyncio.run(TakeStutteredLSSTCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target.py b/python/lsst/ts/standardscripts/data/scripts/maintel/track_target.py deleted file mode 100755 index 456beb81c..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TrackTarget - -asyncio.run(TrackTarget.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_comcam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_comcam.py deleted file mode 100755 index 1bf508f46..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_comcam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TrackTargetAndTakeImageComCam - -asyncio.run(TrackTargetAndTakeImageComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_gencam.py b/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_gencam.py deleted file mode 100755 index 1bf508f46..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/maintel/track_target_and_take_image_gencam.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts.maintel import TrackTargetAndTakeImageComCam - -asyncio.run(TrackTargetAndTakeImageComCam.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/mute_alarms.py b/python/lsst/ts/standardscripts/data/scripts/mute_alarms.py deleted file mode 100755 index 1ab2a4620..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/mute_alarms.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import MuteAlarms - -asyncio.run(MuteAlarms.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/add_block.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/add_block.py deleted file mode 100755 index 0cf458b4f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/add_block.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.add_block import AddBlock - - -class OCSSchedulerAddBlock(AddBlock): - """Add BLOCK to the OCSScheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerAddBlock.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/enable.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/enable.py deleted file mode 100755 index 593be4acc..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/enable.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.enable import Enable - - -class OCSSchedulerEnable(Enable): - """Enable the OCS Scheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerEnable.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/load_snapshot.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/load_snapshot.py deleted file mode 100755 index 54c059342..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/load_snapshot.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.load_snapshot import LoadSnapshot - - -class OCSSchedulerLoadSnapshot(LoadSnapshot): - """Load snapshot for OCS Scheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerLoadSnapshot.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/resume.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/resume.py deleted file mode 100755 index fc63c129f..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/resume.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.resume import Resume - - -class OCSSchedulerResume(Resume): - """Resume OCS Scheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerResume.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/standby.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/standby.py deleted file mode 100755 index 096947c4d..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/standby.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler import SetDesiredState - - -class OCSSchedulerStandby(SetDesiredState): - """Send OCS Scheduler to STANDBY state.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - desired_state=salobj.State.STANDBY, - descr="Send OCS Scheduler to standby state", - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerStandby.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/stop.py b/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/stop.py deleted file mode 100755 index 84b6b85bb..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/ocs/scheduler/stop.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts.scheduler.stop import Stop - - -class OCSSchedulerStop(Stop): - """Stop OCS Scheduler.""" - - def __init__(self, index: int) -> None: - super().__init__( - index, - scheduler_index=SalIndex.OCS, - ) - - -asyncio.run(OCSSchedulerStop.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/pause_queue.py b/python/lsst/ts/standardscripts/data/scripts/pause_queue.py deleted file mode 100755 index 19c26ce30..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/pause_queue.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import PauseQueue - -asyncio.run(PauseQueue.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/run_command.py b/python/lsst/ts/standardscripts/data/scripts/run_command.py deleted file mode 100755 index 96d974f58..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/run_command.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import RunCommand - -asyncio.run(RunCommand.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/set_summary_state.py b/python/lsst/ts/standardscripts/data/scripts/set_summary_state.py deleted file mode 100755 index 630d33a6b..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/set_summary_state.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import SetSummaryState - -asyncio.run(SetSummaryState.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/sleep.py b/python/lsst/ts/standardscripts/data/scripts/sleep.py deleted file mode 100755 index beb7d6230..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/sleep.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import Sleep - -asyncio.run(Sleep.amain()) diff --git a/python/lsst/ts/standardscripts/data/scripts/system_wide_shutdown.py b/python/lsst/ts/standardscripts/data/scripts/system_wide_shutdown.py deleted file mode 100755 index 8d648f81a..000000000 --- a/python/lsst/ts/standardscripts/data/scripts/system_wide_shutdown.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# This file is part of ts_standardscripts. -# -# Developed for the Vera C. Rubin Observatory Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -from lsst.ts.standardscripts import SystemWideShutdown - -asyncio.run(SystemWideShutdown.amain()) diff --git a/python/lsst/ts/standardscripts/enable_group.py b/python/lsst/ts/standardscripts/enable_group.py deleted file mode 100644 index 8e828495c..000000000 --- a/python/lsst/ts/standardscripts/enable_group.py +++ /dev/null @@ -1,141 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableGroup"] - -import abc - -from lsst.ts import salobj - - -class EnableGroup(salobj.BaseScript, metaclass=abc.ABCMeta): - """Base Script for enabling groups of CSCs. - - This base class is setup to operate with minimum configuration. By default - it will try to access an attribute `self.config.ignore`, which is supposed - to contain a list of CSCs from the group to be ignored in the process. - The name of the CSC must match the name of the CSC in `group.components`, - which is the name of the CSC in lowercase, replacing the ":" with "_" for - indexed components. For example, - - * ATMCS -> atmcs - * NewMTMount -> newmtmount - * Hexapod:1 -> hexapod_1 - - For instance, if one wants to ignore the MTDomeTrajectory and the Hexapod:1 - (Hexapod with index=1) components from the MTCS the ignore field would look - like: - - ignore: - - mtdometrajectory - - hexapod_1 - - Nevertheless, if the parent class does not provide an `ignore` property the - class will skip it. - - In addition, when subclassing this base class, users can provide settings - for the configurable CSCs in the group. The naming *must* also follow the - same guidelines as for the ignore field, matching the value in - `group.components`. Following the example above, to pass in the labels - `special_configuration` and `lut_with_temperature` to configure the - MTDomeTrajectory and Hexapod:1, respectively, one would do; - - mtdometrajectory: special_configuration - hexapod_1: lut_with_temperature - - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - descr : `str` - Short Script description. - - Notes - ----- - - **Checkpoints** - - None - - **Details** - - All CSCs will be enabled concurrently. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - @property - @abc.abstractmethod - def group(self): - """Return group of CSC attribute. - - Returns - ------- - group - This property must return a subclass of `RemoteGroup` from - `lsst.ts.observatory.control`, e.g. `ATCS` or `MTCS`. - - """ - raise NotImplementedError() - - @staticmethod - @abc.abstractmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - raise NotImplementedError() - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - metadata.duration = 60.0 - - async def run(self): - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.components(): - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.components()}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.group.check, comp, False) - - overrides = ( - dict([(comp, getattr(self.config, comp, "")) for comp in self.components()]) - if self.config is not None - else None - ) - await self.group.enable(overrides=overrides) diff --git a/python/lsst/ts/standardscripts/maintel/__init__.py b/python/lsst/ts/standardscripts/maintel/__init__.py deleted file mode 100644 index 27c01a834..000000000 --- a/python/lsst/ts/standardscripts/maintel/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .apply_dof import * -from .base_close_loop import * -from .close_loop_comcam import * -from .close_loop_lsstcam import * -from .close_mirror_covers import * -from .disable_hexapod_compensation_mode import * -from .enable_comcam import * -from .enable_hexapod_compensation_mode import * -from .enable_mtcs import * -from .focus_sweep_comcam import * -from .focus_sweep_lsstcam import * -from .home_both_axes import * -from .move_p2p import * -from .offline_comcam import * -from .offline_mtcs import * -from .offset_camera_hexapod import * -from .offset_m2_hexapod import * -from .offset_mtcs import * -from .open_mirror_covers import * -from .point_azel import * -from .set_dof import * -from .setup_mtcs import * -from .standby_comcam import * -from .standby_mtcs import * -from .stop import * -from .stop_rotator import * -from .take_aos_sequence_comcam import * -from .take_image_anycam import * -from .take_image_comcam import * -from .take_image_lsstcam import * -from .take_stuttered_comcam import * -from .take_stuttered_lsstcam import * -from .track_target import * -from .track_target_and_take_image_comcam import * -from .track_target_and_take_image_gencam import * diff --git a/python/lsst/ts/standardscripts/maintel/apply_dof.py b/python/lsst/ts/standardscripts/maintel/apply_dof.py deleted file mode 100644 index ea86c5661..000000000 --- a/python/lsst/ts/standardscripts/maintel/apply_dof.py +++ /dev/null @@ -1,462 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["ApplyDOF"] - -import typing - -import numpy as np -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS -from lsst.ts.observatory.control.utils.enums import DOFName - - -class ApplyDOF(salobj.BaseScript): - """Apply a DOF to the main telescope, either bending - mode or hexapod offset. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - "Applying DOF offset..." - The DOF offset is being applied. - - """ - - def __init__(self, index) -> None: - super().__init__( - index=index, - descr="Apply an offset to the degrees of freedom of the main telescope.", - ) - - # Create the MTCS object - self.mtcs = None - - # Create the DOF vector - self.dofs = np.zeros(len(DOFName)) - - async def configure_tcs(self) -> None: - """Handle creating MTCS object and waiting for remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @classmethod - def get_schema(cls) -> typing.Dict[str, typing.Any]: - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/ApplyDOF.yaml - title: ApplyDOF v1 - description: Configuration for ApplyDOF Script. - type: object - properties: - dofs: - type: array - description: >- - Defines a 50-dimensional vector for all DOFs, combining M2, - Camera, M1M3, and M2 bending modes. This overrides individual DOF inputs. - First 5 elements for M2, next 5 for Camera, next 20 for M1M3 bending modes, - last 20 for M2 bending modes. Units: microns or arcsec. - items: - type: number - minItems: 50 - maxItems: 50 - M2_dz: - type: number - description: >- - Defines the offset applied to the M2 hexapod in the z direction. - Units in um. - default: 0.0 - M2_dx: - type: number - description: >- - Defines the offset applied to the M2 hexapod in the x direction. - Units in um. - default: 0.0 - M2_dy: - type: number - description: >- - Defines the offset applied to the M2 hexapod in the y direction. - Units in um. - default: 0.0 - M2_rx: - type: number - description: >- - Defines the offset applied to the M2 hexapod in rx. - Units in arcsec. - default: 0.0 - M2_ry: - type: number - description: >- - Defines the offset applied to the M2 hexapod in ry. - Units in arcsec. - default: 0.0 - Cam_dz: - type: number - description: >- - Defines the offset applied to the Camera hexapod in - the z direction. Units in um. - default: 0.0 - Cam_dx: - type: number - description: >- - Defines the offset applied to the Camera hexapod - in the x direction. Units in um. - default: 0.0 - Cam_dy: - type: number - description: >- - Defines the offset applied to the Camera hexapod in - the y direction. Units in um. - default: 0.0 - Cam_rx: - type: number - description: >- - Defines the offset applied to the Camera hexapod in rx. - Units in arcsec. - default: 0.0 - Cam_ry: - type: number - description: >- - Defines the offset applied to the Camera hexapod in ry. - Units in arcsec. - default: 0.0 - M1M3_B1: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 1. - Units in um. - default: 0.0 - M1M3_B2: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 2. - Units in um. - default: 0.0 - M1M3_B3: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 3. - Units in um. - default: 0.0 - M1M3_B4: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 4. - Units in um. - default: 0.0 - M1M3_B5: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 5. - Units in um. - default: 0.0 - M1M3_B6: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 6. - Units in um. - default: 0.0 - M1M3_B7: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 7. - Units in um. - default: 0.0 - M1M3_B8: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 8. - Units in um. - default: 0.0 - M1M3_B9: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 9. - Units in um. - default: 0.0 - M1M3_B10: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 10. - Units in um. - default: 0.0 - M1M3_B11: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 11. - Units in um. - default: 0.0 - M1M3_B12: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 12. - Units in um. - default: 0.0 - M1M3_B13: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 13. - Units in um. - default: 0.0 - M1M3_B14: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 14. - Units in um. - default: 0.0 - M1M3_B15: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 15. - Units in um. - default: 0.0 - M1M3_B16: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 16. - Units in um. - default: 0.0 - M1M3_B17: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 17. - Units in um. - default: 0.0 - M1M3_B18: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 18. - Units in um. - default: 0.0 - M1M3_B19: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 19. - Units in um. - default: 0.0 - M1M3_B20: - type: number - description: >- - Defines the offset applied to the M1M3 bending mode 20. - Units in um. - default: 0.0 - M2_B1: - type: number - description: >- - Defines the offset applied to the M2 bending mode 1. - Units in um. - default: 0.0 - M2_B2: - type: number - description: >- - Defines the offset applied to the M2 bending mode 2. - Units in um. - default: 0.0 - M2_B3: - type: number - description: >- - Defines the offset applied to the M2 bending mode 3. - Units in um. - default: 0.0 - M2_B4: - type: number - description: >- - Defines the offset applied to the M2 bending mode 4. - Units in um. - default: 0.0 - M2_B5: - type: number - description: >- - Defines the offset applied to the M2 bending mode 5. - Units in um. - default: 0.0 - M2_B6: - type: number - description: >- - Defines the offset applied to the M2 bending mode 6. - Units in um. - default: 0.0 - M2_B7: - type: number - description: >- - Defines the offset applied to the M2 bending mode 7. - Units in um. - default: 0.0 - M2_B8: - type: number - description: >- - Defines the offset applied to the M2 bending mode 8. - Units in um. - default: 0.0 - M2_B9: - type: number - description: >- - Defines the offset applied to the M2 bending mode 9. - Units in um. - default: 0.0 - M2_B10: - type: number - description: >- - Defines the offset applied to the M2 bending mode 10. - Units in um. - default: 0.0 - M2_B11: - type: number - description: >- - Defines the offset applied to the M2 bending mode 11. - Units in um. - default: 0.0 - M2_B12: - type: number - description: >- - Defines the offset applied to the M2 bending mode 12. - Units in um. - default: 0.0 - M2_B13: - type: number - description: >- - Defines the offset applied to the M2 bending mode 13. - Units in um. - default: 0.0 - M2_B14: - type: number - description: >- - Defines the offset applied to the M2 bending mode 14. - Units in um. - default: 0.0 - M2_B15: - type: number - description: >- - Defines the offset applied to the M2 bending mode 15. - Units in um. - default: 0.0 - M2_B16: - type: number - description: >- - Defines the offset applied to the M2 bending mode 16. - Units in um. - default: 0.0 - M2_B17: - type: number - description: >- - Defines the offset applied to the M2 bending mode 17. - Units in um. - default: 0.0 - M2_B18: - type: number - description: >- - Defines the offset applied to the M2 bending mode 18. - Units in um. - default: 0.0 - M2_B19: - type: number - description: >- - Defines the offset applied to the M2 bending mode 19. - Units in um. - default: 0.0 - M2_B20: - type: number - description: >- - Defines the offset applied to the M2 bending mode 20. - Units in um. - default: 0.0 - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config) -> None: - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - - # Configure tcs and camera - await self.configure_tcs() - - if hasattr(config, "dofs"): - self.dofs = config.dofs - else: - # Loop through properties and assign their values to the vector - for key, value in vars(config).items(): - if hasattr(DOFName, key): - self.dofs[getattr(DOFName, key)] = value - else: - self.log.warning(f"{key} is not a DOFName, ignoring.") - - for comp in getattr(config, "ignore", []): - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata) -> None: - """Set script metadata. - - Parameters - ---------- - metadata : `lsst.ts.salobj.base.ScriptMetadata` - Script metadata. - """ - metadata.duration = 10 - - async def assert_feasibility(self) -> None: - """Verify that the telescope is in a feasible state to - execute the script. - """ - - await self.mtcs.assert_all_enabled() - - async def run(self) -> None: - """Run script.""" - # Assert feasibility - await self.assert_feasibility() - - await self.checkpoint("Applying DOF offset...") - offset_dof_data = self.mtcs.rem.mtaos.cmd_offsetDOF.DataType() - for i, dof_offset in enumerate(self.dofs): - offset_dof_data.value[i] = dof_offset - await self.mtcs.rem.mtaos.cmd_offsetDOF.start(data=offset_dof_data) diff --git a/python/lsst/ts/standardscripts/maintel/base_close_loop.py b/python/lsst/ts/standardscripts/maintel/base_close_loop.py deleted file mode 100644 index 406f8df60..000000000 --- a/python/lsst/ts/standardscripts/maintel/base_close_loop.py +++ /dev/null @@ -1,627 +0,0 @@ -# This file is part of ts_externalcripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseCloseLoop"] - -import abc -import asyncio -import types -import typing - -import numpy as np -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control import BaseCamera -from lsst.ts.observatory.control.maintel.mtcs import MTCS -from lsst.ts.observatory.control.utils.enums import ClosedLoopMode, DOFName - -STD_TIMEOUT = 10 -CMD_TIMEOUT = 400 - - -class BaseCloseLoop(salobj.BaseScript, metaclass=abc.ABCMeta): - """Closed loop script. This script is used to perform measurements of - the wavefront error, then propose dof offsets based on ts_ofc. - - Parameters - ---------- - index : `int`, optional - Index of Script SAL component (default=1). - descr : `str`, optional - Short description of the script. - - Notes - ----- - **Checkpoints** - - - "Taking image...": If taking in-focus detection image. - - "[N/MAX_ITER]: Closed loop starting...": Before each closed loop - iteration, where "N" is the iteration number and "MAX_ITER" - is the maximum number of iterations. - - "[N/MAX_ITER]: Closed converged.": Once Closed Loop reaches convergence. - - "[N/MAX_ITER]: Closed applying correction.": Just before - corrections are applied. - - **Details** - - This script is used to perform measurements of the wavefront error, then - propose dof offsets based on ts_ofc. The offsets are not applied - automatically and must be turned on by the user through - apply_corrections attribute. if apply_corrections is off, the script - will take a series of intra/extra focal data instead, and the number - of pairs is the number of maximum iterations. - """ - - def __init__(self, index=1, descr="") -> None: - super().__init__( - index=index, - descr=descr, - ) - - self.mtcs = None - self._camera = None - - # The following attributes are set via the configuration - self.filter = None - - # exposure time for the intra/extra images (in seconds) - self.exposure_time = None - self.n_images = 9 - - # Define operation mode handler function - self.operation_model_handlers = { - ClosedLoopMode.CWFS: self.handle_cwfs_mode, - ClosedLoopMode.FAM: self.handle_fam_mode, - } - - @property - def camera(self) -> BaseCamera: - if self._camera is not None: - return self._camera - else: - raise RuntimeError("Camera not defined.") - - @camera.setter - def camera(self, value: BaseCamera | None) -> None: - self._camera = value - - @abc.abstractmethod - def configure_camera(self) -> None: - raise NotImplementedError() - - @property - @abc.abstractmethod - def oods(self) -> None: - raise NotImplementedError() - - async def configure_tcs(self) -> None: - """Handle creating MTCS object and waiting for remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @classmethod - def get_schema(cls) -> typing.Dict[str, typing.Any]: - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/auxtel/BaseClosedLoop.yaml - title: BaseClosedLoop v1 - description: Configuration for BaseClosedLoop Script. - type: object - properties: - mode: - description: >- - Mode to use for the script. If set to "cwfs", the script will - use the corner wavefront sensors, if set to "fam" the script - will use the full array mode. - type: string - enum: ["CWFS", "FAM"] - default: CWFS - filter: - description: Which filter to use when taking intra/extra focal images. - type: string - exposure_time: - description: The exposure time to use when taking images (sec). - type: number - default: 30. - dz: - description: De-focus to apply when acquiring the intra/extra focal images (microns). - type: number - default: 1500. - threshold: - description: >- - DOF threshold for convergence (um). If DOF offsets are - smaller than this value, the script will stop. - type: array - items: - type: number - minimum: 0 - minItems: 50 - maxItems: 50 - default: {[0.004]*50} - max_iter: - description: >- - Maximum number of iterations. - Note, if apply_corrections is False, the script - will take [max_iter] pairs of images. - type: integer - default: 5 - program: - description: >- - Optional name of the program this dataset belongs to. - type: string - default: CWFS - reason: - description: Optional reason for taking the data. - anyOf: - - type: string - - type: "null" - default: null - note: - description: A descriptive note about the image being taken. - anyOf: - - type: string - - type: "null" - default: null - wep_config: - description: Configuration for WEP pipeline. Optional. - type: object - additionalProperties: true - used_dofs: - oneOf: - - type: array - items: - type: integer - minimum: 0 - maximum: 49 - - type: array - items: - type: string - enum: {[dof_name.name for dof_name in DOFName]} - default: [1, 2, 3, 4, 5] - gain_sequence: - description: >- - Gain sequence to apply to the offsets. - oneOf: - - type: array - items: - type: number - - type: number - default: 0 - apply_corrections: - description: >- - Apply OFC corrections after each iteration. - type: boolean - default: true - use_ocps: - description: >- - Use OCPS to run the wavefront estimation pipeline. - type: boolean - default: true - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - required: - - filter - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - - # Configure tcs and camera - await self.configure_tcs() - await self.configure_camera() - - # Set mode - self.mode = getattr(ClosedLoopMode, config.mode) - - # Set filter - self.filter = config.filter - - # Set exposure time - self.exposure_time = config.exposure_time - - # Set intra/extra focal offsets - self.dz = config.dz - - # Set threshold - self.threshold = config.threshold - - # Set maximum number of iterations - self.max_iter = config.max_iter - - # Set program and reason - self.reason = config.reason - self.program = config.program - self.note = config.note - - # Set WEP configuration string in yaml format - self.wep_config = yaml.dump(getattr(config, "wep_config", {})) - self.use_ocps = config.use_ocps - - # Set used dofs - selected_dofs = config.used_dofs - if isinstance(selected_dofs[0], str): - selected_dofs = [getattr(DOFName, dof) for dof in selected_dofs] - self.used_dofs = np.zeros(50) - self.used_dofs[selected_dofs] = 1 - - # Set apply_corrections - self.apply_corrections = config.apply_corrections - - self.gain_sequence = config.gain_sequence - - for comp in getattr(config, "ignore", []): - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata: salobj.type_hints.BaseMsgType) -> None: - """Sets script metadata. - - Parameters - ---------- - metadata : `salobj.type_hints.BaseMsgType` - Script metadata topic. The information is set on the topic - directly. - """ - # Estimated duration is maximum number of iterations multiplied by - # the time it takes to take the data (2 images) plus estimation on - # processing the data (10s), plus time it takes to take final - # acquisition image - - metadata.duration = ( - self.camera.filter_change_timeout - + self.max_iter - * ( - self.exposure_time - + self.camera.read_out_time - + self.camera.shutter_time - ) - * (2 if self.mode == ClosedLoopMode.CWFS else 1) - + self.camera.read_out_time - + self.camera.shutter_time - ) - metadata.filter = f"{self.filter}" - - async def take_intra_extra_focal_images( - self, - supplemented_group_id: str, - ) -> typing.Tuple[typing.Any, typing.Any]: - """Take intra and extra focal images. - - Returns - ------- - intra_image : `typing.Any` - Intra focal image. - extra_image : `typing.Any` - Extra focal image. - """ - - # Take intra focal image - self.log.debug("Moving to intra-focal position") - - await self.mtcs.offset_camera_hexapod(x=0, y=0, z=-self.dz, u=0, v=0) - - self.log.debug("Taking intra-focal image") - - intra_image = await self.camera.take_cwfs( - exptime=self.exposure_time, - n=1, - group_id=supplemented_group_id, - filter=self.filter, - reason="INTRA" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - note=self.note, - ) - - self.log.debug("Moving to extra-focal position") - - # Hexapod offsets are relative, so need to move 2x the offset - # to get from the intra- to the extra-focal position. - z_offset = self.dz * 2.0 - await self.mtcs.offset_camera_hexapod(x=0, y=0, z=z_offset, u=0, v=0) - - self.log.debug("Taking extra-focal image") - - self.oods.evt_imageInOODS.flush() - # Take extra-focal iamge - extra_image = await self.camera.take_cwfs( - exptime=self.exposure_time, - n=1, - group_id=supplemented_group_id, - filter=self.filter, - reason="EXTRA" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - note=self.note, - ) - - task1 = self.wait_for_images_in_oods() - # Move the hexapod back to in focus position - task2 = self.mtcs.offset_camera_hexapod(x=0, y=0, z=-self.dz, u=0, v=0) - await asyncio.gather(task1, task2) - - return intra_image, extra_image - - async def wait_for_images_in_oods(self): - - for _ in range(self.n_images): - try: - image_in_oods = await self.oods.evt_imageInOODS.next( - flush=False, timeout=self.exposure_time - ) - self.log.info( - f"Image {image_in_oods.obsid} {image_in_oods.raft} {image_in_oods.sensor} ingested." - ) - except asyncio.TimeoutError: - self.log.warning("Timeout waiting for images in OODS.") - - async def handle_fam_mode(self, supplemented_group_id: str) -> None: - """Handle Full Array Mode.""" - - # Take intra and extra focal images - intra_image, extra_image = await self.take_intra_extra_focal_images( - supplemented_group_id - ) - - # Set intra and extra visit id - intra_visit_id = int(intra_image[0]) - extra_visit_id = int(extra_image[0]) - - take_infocus_image_task = asyncio.create_task( - self.camera.take_acq( - self.exposure_time, - group_id=supplemented_group_id, - reason="INFOCUS" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - filter=self.filter, - note=self.note, - ) - ) - - # Run WEP - await self.mtcs.rem.mtaos.cmd_runWEP.set_start( - visitId=intra_visit_id, - extraId=extra_visit_id, - useOCPS=self.use_ocps, - config=self.wep_config, - timeout=2 * CMD_TIMEOUT, - ) - await take_infocus_image_task - - async def handle_cwfs_mode(self, supplemented_group_id: str) -> None: - """Handle CWFS mode.""" - - # Take in-focus image - image = await self.camera.take_acq( - self.exposure_time, - group_id=supplemented_group_id, - reason="INFOCUS" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - filter=self.filter, - note=self.note, - ) - - # Set visit id - visit_id = int(image[0]) - - # Run WEP - await self.mtcs.rem.mtaos.cmd_runWEP.set_start( - visitId=visit_id, timeout=2 * CMD_TIMEOUT, config=self.wep_config - ) - - async def compute_ofc_offsets(self, rotation_angle: float, gain: float) -> None: - """Compute offsets using ts_ofc. - - Parameters - ---------- - rotation_angle : `float` - Rotation angle of the camera in deg. - gain : `float` - Gain to apply to the offsets. - """ - # Create the config to run OFC - config = { - "filter_name": self.filter, - "rotation_angle": rotation_angle, - "comp_dof_idx": { - "m2HexPos": [float(val) for val in self.used_dofs[:5]], - "camHexPos": [float(val) for val in self.used_dofs[5:10]], - "M1M3Bend": [float(val) for val in self.used_dofs[10:30]], - "M2Bend": [float(val) for val in self.used_dofs[30:]], - }, - } - config_yaml = yaml.safe_dump(config) - - # Run OFC - self.mtcs.rem.mtaos.evt_degreeOfFreedom.flush() - await self.mtcs.rem.mtaos.cmd_runOFC.set_start( - config=config_yaml, timeout=CMD_TIMEOUT, userGain=gain - ) - - # Return offsets - return await self.mtcs.rem.mtaos.evt_degreeOfFreedom.next( - flush=False, timeout=STD_TIMEOUT - ) - - def get_gain(self, iteration: int) -> float: - """Get the gain to apply to the offsets. - - Parameters - ---------- - iteration : `int` - Iteration number. - - Returns - ------- - gain : `float` - Gain to apply to the offsets. - """ - if isinstance(self.gain_sequence, float) or isinstance(self.gain_sequence, int): - return float(self.gain_sequence) - else: - if iteration >= len(self.gain_sequence): - self.log.warning( - "Iteration is greater than the length of the gain sequence. " - "Using the last value of the gains sequence." - ) - return self.gain_sequence[-1] - return self.gain_sequence[iteration] - - async def arun(self, checkpoint: bool = False) -> None: - """Perform wavefront error measurements and DOF adjustments until the - thresholds are reached. - - Parameters - ---------- - checkpoint : `bool`, optional - Should issue checkpoints - - Raises - ------ - RuntimeError: - If coordinates are malformed. - """ - - for i in range(self.max_iter): - self.log.debug(f"Closed Loop iteration {i + 1} starting...") - - if checkpoint: - await self.checkpoint( - f"[{i + 1}/{self.max_iter}]: Closed Loop loop starting..." - ) - - await self.checkpoint(f"[{i + 1}/{self.max_iter}]: Taking image...") - - # Flush wavefront error topic - self.mtcs.rem.mtaos.evt_wavefrontError.flush() - - # Retrieve the rotation angle before taking data. - start_rotation_angle = await self.mtcs.rem.mtrotator.tel_rotation.next( - flush=True, timeout=STD_TIMEOUT - ) - - # Run the operational mode handler function. - await self.operation_model_handlers[self.mode]( - self.next_supplemented_group_id() - ) - - # Retrieve the rotation angle after taking data. - end_rotation_angle = await self.mtcs.rem.mtrotator.tel_rotation.next( - flush=True, timeout=STD_TIMEOUT - ) - - # Compute average rotation angle while taking data - rotation_angle = ( - start_rotation_angle.actualPosition + end_rotation_angle.actualPosition - ) / 2 - - # Save the wavefront error - wavefront_error = await self.mtcs.rem.mtaos.evt_wavefrontError.next( - flush=False, timeout=STD_TIMEOUT - ) - - self.log.info( - f"Wavefront error zernike coefficients: {wavefront_error} in um." - ) - - # Compute ts_ofc offsets - dof_offset = await self.compute_ofc_offsets( - rotation_angle, self.get_gain(i) - ) - - # If apply_corrections is true, - # then we apply the corrections - if self.apply_corrections: - self.log.info("Applying corrections...") - - if checkpoint: - await self.checkpoint( - f"[{i + 1}/{self.max_iter}]: Applying correction." - ) - - # Apply ts_ofc corrections - await self.mtcs.rem.mtaos.cmd_issueCorrection.start(timeout=CMD_TIMEOUT) - - # Check if corrections have converged. If they have, then we stop. - if all(np.abs(dof_offset.visitDoF) < self.threshold): - self.log.info(f"OFC offsets are inside tolerance ({self.threshold}). ") - if checkpoint: - await self.checkpoint( - f"[{i + 1}/{self.max_iter}]: Closed Loop converged." - ) - - self.log.info("Closed Loop completed successfully!") - return - - # If we reach the maximum number of iterations without - # converging, then we stop. - self.log.warning( - f"Reached maximum iteration ({self.max_iter}) without convergence.\n" - ) - - async def assert_feasibility(self) -> None: - """Verify that the telescope and camera are in a feasible state to - execute the script. - """ - await self.mtcs.assert_all_enabled() - await self.camera.assert_all_enabled() - - async def assert_mode_compatibility(self) -> None: - """Verify that the script mode is compatible with the camera. - Defaults to pass. It is only overriden by ComCam, since it - only allows for FAM.""" - - pass - - async def run(self) -> None: - """Execute script. - - This method simply call `arun` with `checkpoint=True`. - """ - - await self.assert_feasibility() - await self.assert_mode_compatibility() - - await self.arun(True) diff --git a/python/lsst/ts/standardscripts/maintel/calibration/__init__.py b/python/lsst/ts/standardscripts/maintel/calibration/__init__.py deleted file mode 100644 index 5728d764b..000000000 --- a/python/lsst/ts/standardscripts/maintel/calibration/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .power_on_tunablelaser import * diff --git a/python/lsst/ts/standardscripts/maintel/calibration/power_on_tunablelaser.py b/python/lsst/ts/standardscripts/maintel/calibration/power_on_tunablelaser.py deleted file mode 100644 index 06eafe8d4..000000000 --- a/python/lsst/ts/standardscripts/maintel/calibration/power_on_tunablelaser.py +++ /dev/null @@ -1,154 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["PowerOnTunableLaser"] - - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcalsys import MTCalsys - - -class PowerOnTunableLaser(salobj.BaseScript): - """Starts propagating the Tunable Laser for functional - testing. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - """ - - def __init__(self, index): - super().__init__( - index=index, - descr="Power On Tunable Laser", - ) - - self.laser = None - self.mtcalsys = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/calibrations/power_on_tunablelaser.yaml - title: PowerOnTunableLaser v1 - description: Configuration for PowerOnTunableLaser. - Each attribute can be specified as a scalar or array. - All arrays must have the same length (one item per image). - type: object - properties: - sequence_name: - description: Name of sequence in MTCalsys - type: string - default: laser_functional - - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - def set_metadata(self, metadata): - metadata.duration = 30 - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : ``self.cmd_configure.DataType`` - - """ - self.log.info("Configure started") - if self.mtcalsys is None: - self.log.debug("Creating MTCalSys.") - self.mtcalsys = MTCalsys(domain=self.domain, log=self.log) - await self.mtcalsys.start_task - - self.sequence_name = config.sequence_name - self.mtcalsys.load_calibration_config_file() - self.mtcalsys.assert_valid_configuration_option(name=self.sequence_name) - - self.config_data = self.mtcalsys.get_calibration_configuration( - self.sequence_name - ) - - self.laser_mode = self.config_data["laser_mode"] - self.optical_configuration = self.config_data["optical_configuration"] - self.wavelength = self.config_data["wavelength"] - - if self.laser is None: - self.laser = salobj.Remote( - domain=self.domain, - name="TunableLaser", - ) - - self.laser.start_task - - self.log.info("Configure completed") - - async def run(self): - """Run script.""" - await self.assert_components_enabled() - - await self.checkpoint("Configuring TunableLaser") - await self.mtcalsys.setup_laser( - mode=self.laser_mode, - wavelength=self.wavelength, - optical_configuration=self.optical_configuration, - use_projector=False, - ) - - params = await self.mtcalsys.get_laser_parameters() - - self.log.info( - f"Laser Configuration is {params[0]}, \n" - f"wavelength is {params[1]}, \n" - f"Interlock is {params[2]}, \n" - f"Burst mode is {params[3]}, \n" - f"Cont. mode is {params[4]}" - ) - - await self.checkpoint("Starting laser propagation") - await self.start_propagation_on() - - async def start_propagation_on(self): - """Starts propagation of the laser""" - - await self.mtcalsys.laser_start_propagate() - - async def assert_components_enabled(self): - """Checks if TunableLaser is ENABLED - - Raises - ------ - RunTimeError: - If either component is not ENABLED""" - - comps = [self.laser] - - for comp in comps: - summary_state = await comp.evt_summaryState.aget() - if salobj.State(summary_state.summaryState) != salobj.State( - salobj.State.ENABLED - ): - raise RuntimeError(f"{comp} is not ENABLED") diff --git a/python/lsst/ts/standardscripts/maintel/close_loop_comcam.py b/python/lsst/ts/standardscripts/maintel/close_loop_comcam.py deleted file mode 100644 index 2dfaa7cbd..000000000 --- a/python/lsst/ts/standardscripts/maintel/close_loop_comcam.py +++ /dev/null @@ -1,81 +0,0 @@ -# This file is part of ts_externalcripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CloseLoopComCam"] - -from lsst.ts.observatory.control.maintel.comcam import ComCam -from lsst.ts.observatory.control.utils.enums import ClosedLoopMode - -from .base_close_loop import BaseCloseLoop - -STD_TIMEOUT = 10 - - -class CloseLoopComCam(BaseCloseLoop): - """Run Closed Loop with ComCam. - - Parameters - ---------- - index : `int`, optional - Index of Script SAL component (default=1). - remotes : `bool`, optional - Should the remotes be created (default=True)? For unit testing this - can be set to False, which allows one to mock the remotes behaviour. - descr : `str`, optional - Short description of the script. - """ - - def __init__(self, index, descr="") -> None: - super().__init__(index=index, descr=descr) - - self.config = None - - self._camera = None - - @property - def oods(self): - return self._camera.rem.ccoods - - async def configure_camera(self) -> None: - """Handle creating Camera object and waiting for remote to start.""" - if self._camera is None: - self.log.debug("Creating Camera.") - - self._camera = ComCam( - self.domain, - log=self.log, - tcs_ready_to_take_data=self.mtcs.ready_to_take_data, - ) - await self._camera.start_task - else: - self.log.debug("Camera already defined, skipping.") - - async def assert_mode_compatibility(self) -> None: - """Assert that the mode is compatible with ComCam. - - Raises - ------ - RuntimeError - If the mode is not compatible with ComCam. - """ - - if self.mode == ClosedLoopMode.CWFS: - raise RuntimeError("ComCam does not support CWFS mode.") diff --git a/python/lsst/ts/standardscripts/maintel/close_loop_lsstcam.py b/python/lsst/ts/standardscripts/maintel/close_loop_lsstcam.py deleted file mode 100644 index e1912b73d..000000000 --- a/python/lsst/ts/standardscripts/maintel/close_loop_lsstcam.py +++ /dev/null @@ -1,68 +0,0 @@ -# This file is part of ts_externalcripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CloseLoopLSSTCam"] - -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam - -from .base_close_loop import BaseCloseLoop - -STD_TIMEOUT = 10 - - -class CloseLoopLSSTCam(BaseCloseLoop): - """Run closed loop with LSSTCam. - - Parameters - ---------- - index : `int`, optional - Index of Script SAL component (default=1). - remotes : `bool`, optional - Should the remotes be created (default=True)? For unit testing this - can be set to False, which allows one to mock the remotes behaviour. - descr : `str`, optional - Short description of the script. - """ - - def __init__(self, index, descr="") -> None: - super().__init__(index=index, descr=descr) - - self.config = None - - self._camera = None - - @property - def oods(self): - return self._camera.rem.mtoods - - async def configure_camera(self) -> None: - """Handle creating Camera object and waiting for remote to start.""" - if self._camera is None: - self.log.debug("Creating Camera.") - - self._camera = LSSTCam( - self.domain, - log=self.log, - tcs_ready_to_take_data=self.mtcs.ready_to_take_data, - ) - await self._camera.start_task - else: - self.log.debug("Camera already defined, skipping.") diff --git a/python/lsst/ts/standardscripts/maintel/close_mirror_covers.py b/python/lsst/ts/standardscripts/maintel/close_mirror_covers.py deleted file mode 100644 index fbc471dac..000000000 --- a/python/lsst/ts/standardscripts/maintel/close_mirror_covers.py +++ /dev/null @@ -1,101 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CloseMirrorCovers"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class CloseMirrorCovers(salobj.BaseScript): - """Run open mirror covers on MTCS. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - Closing mirror covers: before issuing close mirror covers command. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Close the MT mirror covers.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/close_mirror_covers.yaml - title: CloseMirrorCovers v1 - description: Configuration for CloseMirrorCovers. - type: object - properties: - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, intended_usage=MTCSUsages.All, log=self.log - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = self.mtcs.mirror_covers_timeout - - async def run(self): - await self.mtcs.assert_all_enabled() - await self.checkpoint("Closing mirror covers.") - await self.mtcs.close_m1_cover() diff --git a/python/lsst/ts/standardscripts/maintel/disable_hexapod_compensation_mode.py b/python/lsst/ts/standardscripts/maintel/disable_hexapod_compensation_mode.py deleted file mode 100644 index d6a387f41..000000000 --- a/python/lsst/ts/standardscripts/maintel/disable_hexapod_compensation_mode.py +++ /dev/null @@ -1,126 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["DisableHexapodCompensationMode"] - -import asyncio - -import yaml -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_block_script import BaseBlockScript - - -class DisableHexapodCompensationMode(BaseBlockScript): - """Disable compensation mode for M2 and/or Camera Hexapods. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Disabling compensation mode": Before disabling compensation mode. - - **Details** - - This script disables the compensation mode for selected hexapods of the - Simonyi Survey Telescope. - - """ - - def __init__(self, index: int) -> None: - super().__init__( - index=index, - descr="Disable Hexapod Compensation Mode.", - ) - self.mtcs = None - - async def configure_tcs(self) -> None: - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @staticmethod - def component_to_hexapod(component): - hexapod_map = {"M2Hexapod": "mthexapod_2", "CameraHexapod": "mthexapod_1"} - return hexapod_map.get(component) - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/disable_hexapod_compensation_mode.yaml - title: DisableHexapodCompensationMode v1 - description: Configuration for DisableHexapodCompensationMode - type: object - properties: - components: - description: List of hexapods to disable compensation mode for. - type: array - items: - type: string - enum: ["M2Hexapod", "CameraHexapod"] - minItems: 1 - default: ["M2Hexapod", "CameraHexapod"] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - self.config = config - self.components = config.components - await self.configure_tcs() - - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 15.0 - - async def disable_compensation_for_hexapod(self, hexapod, component): - await self.checkpoint(f"Disabling compensation mode for {component}") - await self.mtcs.disable_compensation_mode(hexapod) - self.log.info(f"Compensation mode disabled for {component}") - - async def run_block(self): - tasks = [] - for component in self.config.components: - hexapod = self.component_to_hexapod(component) - task = asyncio.create_task( - self.disable_compensation_for_hexapod(hexapod, component) - ) - tasks.append(task) - await asyncio.gather(*tasks) diff --git a/python/lsst/ts/standardscripts/maintel/enable_comcam.py b/python/lsst/ts/standardscripts/maintel/enable_comcam.py deleted file mode 100644 index 6dae76ce5..000000000 --- a/python/lsst/ts/standardscripts/maintel/enable_comcam.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableComCam"] - -import yaml -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages - -from ..enable_group import EnableGroup - - -class EnableComCam(EnableGroup): - """Enable all ComCam components. - - The Script configuration only accepts settings values for the CSCs that - are configurable. - - The following CSCs will be enabled: - - - CCCamera - - CCHeaderService: not configurable - - CCOODS - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable ComCam.") - - self.config = None - - self._comcam = ComCam( - self.domain, intended_usage=ComCamUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._comcam - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return set(["cccamera", "ccheaderservice", "ccoods"]) - - @classmethod - def get_schema(cls): - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/enable_mtcs.yaml - title: EnableComCam v1 - description: Configuration for EnableComCam - type: object - properties: - cccamera: - description: Configuration for the CCCamera component. - anyOf: - - type: string - - type: "null" - default: null - ccoods: - description: Configuration for the CCOODS component. - anyOf: - - type: string - - type: "null" - default: null - ignore: - description: >- - CSCs from the group to ignore. Name must match those in - self.group.components, e.g.; ccoods. - Valid options are: {cls.components()}. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) diff --git a/python/lsst/ts/standardscripts/maintel/enable_hexapod_compensation_mode.py b/python/lsst/ts/standardscripts/maintel/enable_hexapod_compensation_mode.py deleted file mode 100644 index dedf2c2f9..000000000 --- a/python/lsst/ts/standardscripts/maintel/enable_hexapod_compensation_mode.py +++ /dev/null @@ -1,126 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableHexapodCompensationMode"] - -import asyncio - -import yaml -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_block_script import BaseBlockScript - - -class EnableHexapodCompensationMode(BaseBlockScript): - """Enable compensation mode for M2 and/or Camera Hexapods. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Enabling compensation mode": Before enabling compensation mode. - - **Details** - - This script enables the compensation mode for selected hexapods of the - Simonyi Survey Telescope. - - """ - - def __init__(self, index: int) -> None: - super().__init__( - index=index, - descr="Enable Hexapod Compensation Mode.", - ) - self.mtcs = None - - async def configure_tcs(self) -> None: - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @staticmethod - def component_to_hexapod(component): - hexapod_map = {"M2Hexapod": "mthexapod_2", "CameraHexapod": "mthexapod_1"} - return hexapod_map.get(component) - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/enable_hexapod_compensation_mode.yaml - title: EnableHexapodCompensationMode v1 - description: Configuration for EnableHexapodCompensationMode - type: object - properties: - components: - description: List of hexapods to enable compensation mode for. - type: array - items: - type: string - enum: ["M2Hexapod", "CameraHexapod"] - minItems: 1 - default: ["M2Hexapod", "CameraHexapod"] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - self.config = config - self.components = config.components - await self.configure_tcs() - - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 15.0 - - async def enable_compensation_for_hexapod(self, hexapod, component): - await self.checkpoint(f"Enabling compensation mode for {component}") - await self.mtcs.enable_compensation_mode(hexapod) - self.log.info(f"Compensation mode enabled for {component}") - - async def run_block(self): - tasks = [] - for component in self.config.components: - hexapod = self.component_to_hexapod(component) - task = asyncio.create_task( - self.enable_compensation_for_hexapod(hexapod, component) - ) - tasks.append(task) - await asyncio.gather(*tasks) diff --git a/python/lsst/ts/standardscripts/maintel/enable_mtcs.py b/python/lsst/ts/standardscripts/maintel/enable_mtcs.py deleted file mode 100644 index 5b172b811..000000000 --- a/python/lsst/ts/standardscripts/maintel/enable_mtcs.py +++ /dev/null @@ -1,167 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableMTCS"] - -import yaml -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..enable_group import EnableGroup - - -class EnableMTCS(EnableGroup): - """Enable all MTCS components. - - The Script configuration only accepts settings values for the CSCs that - are configurable. - - The following CSCs will be enabled: - - - MTMount - - MTPtg: not configurable - - MTAOS - - MTM1M3 - - MTM2 - - MTHexapod:1 - - MTHexapod:2 - - MTRotator: not configurable - - MTDome - - MTDomeTrajectory - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable MTCS.") - - self.config = None - - self._mtcs = MTCS( - self.domain, intended_usage=MTCSUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._mtcs - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return set( - [ - "mtmount", - "mtptg", - "mtaos", - "mtm1m3", - "mtm2", - "mthexapod_1", - "mthexapod_2", - "mtrotator", - "mtdome", - "mtdometrajectory", - ] - ) - - @classmethod - def get_schema(cls): - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/enable_mtcs.yaml - title: EnableMTCS v1 - description: Configuration for EnableMTCS - type: object - properties: - mtmount: - description: Configuration for the MTMount component. - anyOf: - - type: string - - type: "null" - default: null - mtaos: - description: Configuration for the ATAOS component. - anyOf: - - type: string - - type: "null" - default: null - mtm1m3: - description: Configuration for the M1M3 component. - anyOf: - - type: string - - type: "null" - default: null - mtm2: - description: Configuration for the MTM2 component. - anyOf: - - type: string - - type: "null" - default: null - mthexapod_1: - description: Configuration for the Camera Hexapod component. - anyOf: - - type: string - - type: "null" - default: null - mthexapod_2: - description: Configuration for the M2 Hexapod component. - anyOf: - - type: string - - type: "null" - default: null - mtdome: - description: Configuration for the MTDome component. - anyOf: - - type: string - - type: "null" - default: null - mtdometrajectory: - description: Configuration for the MTDomeTrajectory component. - anyOf: - - type: string - - type: "null" - default: null - ignore: - description: >- - CSCs from the group to ignore. Name must match those in - self.group.components, e.g.; mthexapod_1. - Valid options are: {cls.components()}. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) diff --git a/python/lsst/ts/standardscripts/maintel/focus_sweep_comcam.py b/python/lsst/ts/standardscripts/maintel/focus_sweep_comcam.py deleted file mode 100644 index fc85a6449..000000000 --- a/python/lsst/ts/standardscripts/maintel/focus_sweep_comcam.py +++ /dev/null @@ -1,149 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["FocusSweepComCam"] - -import types - -import yaml -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_focus_sweep import BaseFocusSweep - - -class FocusSweepComCam(BaseFocusSweep): - """Perform a focus sweep by taking images at different focus positions - with ComCam. - - Parameters - ---------- - index : int - Index of Script SAL component. - """ - - def __init__(self, index, descr="Perform a focus sweep with ComCam.") -> None: - super().__init__(index=index, descr=descr) - - self.mtcs = None - self.comcam = None - - self.instrument_name = "LSSTComCam" - - @property - def tcs(self): - return self.mtcs - - @property - def camera(self): - return self.comcam - - async def configure_tcs(self) -> None: - """Handle creating the MTCS object and waiting remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - async def configure_camera(self) -> None: - """Handle creating the camera object and waiting remote to start.""" - if self.comcam is None: - self.log.debug("Creating Camera.") - self.comcam = ComCam( - self.domain, - intended_usage=ComCamUsages.TakeImage | ComCamUsages.StateTransition, - log=self.log, - ) - await self.comcam.start_task - else: - self.log.debug("Camera already defined, skipping.") - - @classmethod - def get_schema(cls) -> dict: - schema_dict = super().get_schema() - additional_properties = yaml.safe_load( - """ - sim: - description: Is ComCam in simulation mode? This mode is used for tests. - type: boolean - default: false - hexapod: - description: Which hexapod to use? - type: string - enum: - - Camera - - M2 - default: Camera - - """ - ) - schema_dict["properties"].update(additional_properties) - return schema_dict - - def get_instrument_configuration(self) -> dict: - return dict(filter=self.config.filter) - - def get_instrument_filter(self) -> str: - return f"{self.config.filter}" - - def get_instrument_name(self) -> str: - """Get instrument name. - - Returns - ------- - instrument_name: `string` - """ - return self.instrument_name - - async def move_hexapod(self, axis: str, value: float) -> None: - """Move hexapod to a position along an axis for ComCam.""" - offset_args = {"x": 0, "y": 0, "z": 0, "u": 0, "v": 0, "w": 0} - offset_args[axis] = value - if self.hexapod == "Camera": - await self.mtcs.offset_camera_hexapod( - x=offset_args["x"], - y=offset_args["y"], - z=offset_args["z"], - u=offset_args["u"], - v=offset_args["v"], - w=offset_args["w"], - ) - else: - await self.mtcs.offset_m2_hexapod( - x=offset_args["x"], - y=offset_args["y"], - z=offset_args["z"], - u=offset_args["u"], - v=offset_args["v"], - w=offset_args["w"], - ) - - async def configure(self, config: types.SimpleNamespace) -> None: - await super().configure(config) - if hasattr(config, "sim") and config.sim: - self.comcam.simulation_mode = config.sim - self.instrument_name += "Sim" - self.hexapod = config.hexapod diff --git a/python/lsst/ts/standardscripts/maintel/focus_sweep_lsstcam.py b/python/lsst/ts/standardscripts/maintel/focus_sweep_lsstcam.py deleted file mode 100644 index 910fb69e6..000000000 --- a/python/lsst/ts/standardscripts/maintel/focus_sweep_lsstcam.py +++ /dev/null @@ -1,147 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["FocusSweepLSSTCam"] - -import types - -import yaml -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam, LSSTCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_focus_sweep import BaseFocusSweep - - -class FocusSweepLSSTCam(BaseFocusSweep): - """Perform a focus sweep by taking images at different focus positions - with LSSTCam. - - Parameters - ---------- - index : int - Index of Script SAL component. - """ - - def __init__(self, index, descr="Perform a focus sweep with LSSTCam.") -> None: - super().__init__(index=index, descr=descr) - - self.mtcs = None - self.LSSTCam = None - - self.instrument_name = "LSSTCam" - - @property - def tcs(self): - return self.mtcs - - @property - def camera(self): - return self.lsstcam - - async def configure_tcs(self) -> None: - """Handle creating the MTCS object and waiting remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - async def configure_camera(self) -> None: - """Handle creating the camera object and waiting remote to start.""" - if self.lsstcam is None: - self.log.debug("Creating Camera.") - self.lsstcam = LSSTCam( - self.domain, intended_usage=LSSTCamUsages.TakeImage, log=self.log - ) - await self.lsstcam.start_task - else: - self.log.debug("Camera already defined, skipping.") - - @classmethod - def get_schema(cls) -> dict: - schema_dict = super().get_schema() - additional_properties = yaml.safe_load( - """ - sim: - description: Is LSSTCam in simulation mode? This mode is used for tests. - type: boolean - default: false - hexapod: - description: Which hexapod to use? - type: string - enum: - - Camera - - M2 - default: Camera - - """ - ) - schema_dict["properties"].update(additional_properties) - return schema_dict - - def get_instrument_configuration(self) -> dict: - return dict(filter=self.config.filter) - - def get_instrument_filter(self) -> str: - return f"{self.config.filter}" - - def get_instrument_name(self) -> str: - """Get instrument name. - - Returns - ------- - instrument_name: `string` - """ - return self.instrument_name - - async def move_hexapod(self, axis: str, value: float) -> None: - """Move hexapod to a position along an axis for LSSTCam.""" - offset_args = {"x": 0, "y": 0, "z": 0, "u": 0, "v": 0, "w": 0} - offset_args[axis] = value - if self.hexapod == "Camera": - await self.mtcs.offset_camera_hexapod( - x=offset_args["x"], - y=offset_args["y"], - z=offset_args["z"], - u=offset_args["u"], - v=offset_args["v"], - w=offset_args["w"], - ) - else: - await self.mtcs.offset_m2_hexapod( - x=offset_args["x"], - y=offset_args["y"], - z=offset_args["z"], - u=offset_args["u"], - v=offset_args["v"], - w=offset_args["w"], - ) - - async def configure(self, config: types.SimpleNamespace) -> None: - await super().configure(config) - if hasattr(config, "sim") and config.sim: - self.lsstcam.simulation_mode = config.sim - self.instrument_name += "Sim" - self.hexapod = config.hexapod diff --git a/python/lsst/ts/standardscripts/maintel/home_both_axes.py b/python/lsst/ts/standardscripts/maintel/home_both_axes.py deleted file mode 100644 index c9ea12921..000000000 --- a/python/lsst/ts/standardscripts/maintel/home_both_axes.py +++ /dev/null @@ -1,117 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see .`` - -__all__ = ["HomeBothAxes"] - -import time - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class HomeBothAxes(salobj.BaseScript): - """Home azimuth and elevation axes of the MTMount. - Must call this after powering on the main axis and - BEFORE you move them. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Homing Both Axes": Before commanding both axes to be homed. - - **Details** - - This script homes both aximuth and elevation axes of - the Simonyi Main Telescope mount. - - - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__(index=index, descr="Home both TMA axis.") - - self.disable_m1m3_force_balance = False - self.home_both_axes_timeout = 300.0 # timeout to home both MTMount axes. - self.mtcs = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/enable_mtcs.yaml - title: HomeBothAxes v1 - description: Configuration for HomeBothAxes. - type: object - properties: - ignore_m1m3: - description: Ignore the m1m3 component? (Deprecated property) - type: boolean - disable_m1m3_force_balance: - description: Disable m1m3 force balance? - type: boolean - default: false - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - - if hasattr(config, "ignore_m1m3"): - self.log.warning( - "The 'ignore_m1m3' configuration property is deprecated and will be removed" - " in future releases. Please use 'disable_m1m3_force_balance' instead.", - DeprecationWarning, - stacklevel=2, - ) - self.disable_m1m3_force_balance = config.disable_m1m3_force_balance - - def set_metadata(self, metadata): - metadata.duration = self.home_both_axes_timeout - - async def run(self): - - if self.disable_m1m3_force_balance: - await self.checkpoint("Disable M1M3 balance system.") - await self.mtcs.disable_m1m3_balance_system() - - await self.checkpoint("Homing Both Axes") - start_time = time.time() - await self.mtcs.rem.mtmount.cmd_homeBothAxes.start( - timeout=self.home_both_axes_timeout - ) - end_time = time.time() - elapsed_time = end_time - start_time - - self.log.info(f"Homing both axes took {elapsed_time:.2f} seconds") - - if not self.disable_m1m3_force_balance: - self.log.info("Enabling M1M3 balance system.") - await self.mtcs.enable_m1m3_balance_system() diff --git a/python/lsst/ts/standardscripts/maintel/laser_tracker/__init__.py b/python/lsst/ts/standardscripts/maintel/laser_tracker/__init__.py deleted file mode 100644 index 37868a3b2..000000000 --- a/python/lsst/ts/standardscripts/maintel/laser_tracker/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .align import * -from .measure import * -from .set_up import * -from .shut_down import * diff --git a/python/lsst/ts/standardscripts/maintel/laser_tracker/align.py b/python/lsst/ts/standardscripts/maintel/laser_tracker/align.py deleted file mode 100644 index 14e91ea54..000000000 --- a/python/lsst/ts/standardscripts/maintel/laser_tracker/align.py +++ /dev/null @@ -1,259 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Align", "AlignComponent"] - -import asyncio -import enum - -import numpy as np -import yaml -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.observatory.control import RemoteGroup -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -# TODO (DM-38880) - Subsitute by class in idl.enum when available -class AlignComponent(enum.IntEnum): - M2 = 1 - Camera = 3 - TMA_CENTRAL = 4 - TMA_UPPER = 5 - - -class Align(BaseBlockScript): - """Align component using laser tracker. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - "Starting alignment procedure.": Starting alignment with laser tracker. - - "M2 Hexapod aligned with laser tracker.": M2 aligned. - - "Camera Hexapod aligned with laser tracker.": Camera aligned. - """ - - def __init__(self, index: int): - super().__init__(index, descr="Align MTCS components with laser tracker.") - - self.laser_tracker = None - self.mtcs = None - - self.timeout_align = 120 - self.timeout_std = 60 - self.timeout_short = 5 - - self.max_iter = 10 - self.tolerance_linear = 1.0e-7 # meter - self.tolerance_angular = 5.0 / 3600.0 # degrees - self.target = None - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/laser_tracker/align.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: MaintelLaserTrackerAlign v1 - description: Configuration for Maintel laser tracker alignment SAL Script. - type: object - properties: - max_iter: - description: maximum number of iterations to align components. - type: integer - default: 10 - minimum: 1 - tolerance_linear: - description: tolerance for rigid body degrees of freedom corrections (mm). - type: number - default: 0.0001 - minimum: 0.0 - tolerance_angular: - description: tolerance for tip/tilt degrees of freedom corrections (deg). - type: number - default: 0.00138 - minimum: 0.0 - target: - description: >- - Target to align. Options are: - M2: Secondary mirror. - Camera: LSST Camera. - type: string - enum: ["Camera", "M2"] - additionalProperties: false - required: - - target - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - if self.laser_tracker is None: - self.laser_tracker = RemoteGroup( - domain=self.domain, - components=["LaserTracker:1"], - log=self.log, - ) - await self.laser_tracker.start_task - await super().configure(config=config) - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - self.max_iter = config.max_iter - self.target = getattr(AlignComponent, config.target) - self.tolerance_linear = config.tolerance_linear - self.tolerance_angular = config.tolerance_angular - - def set_metadata(self, metadata): - """Set estimated duration of the script.""" - - metadata.duration = (self.timeout_align + self.timeout_std) * self.max_iter - - def get_align_func(self): - """Get function to align target.""" - - if self.target == AlignComponent.M2: - return self.mtcs.offset_m2_hexapod - elif self.target == AlignComponent.Camera: - return self.mtcs.offset_camera_hexapod - else: - raise RuntimeError(f"Invalid target {self.target!r}.") - - async def align_target(self): - """Align target with laser tracker. - - Notes - ----- - **Checkpoints** - - "Starting alignment procedure.": Starting alignment. - - "{...} aligned with laser tracker.": Component aligned. - - Raises - ------ - RuntimeError - If not aligned after max_iter iterations. - """ - - # Set function to align target. - align_func = self.get_align_func() - - for n_iter in range(self.max_iter): - self.laser_tracker.rem.lasertracker_1.evt_offsetsPublish.flush() - await self.laser_tracker.rem.lasertracker_1.cmd_align.set_start( - target=self.target, - timeout=self.timeout_align, - ) - if self.tolerance_linear == 0.0 and self.tolerance_angular == 0.0: - self.log.info("Tolerances are zero, skipping alignment.") - return - - try: - offset = ( - await self.laser_tracker.rem.lasertracker_1.evt_offsetsPublish.next( - flush=False, timeout=self.timeout_short - ) - ) - except asyncio.TimeoutError: - self.log.warning("Cannot get new offset, using last data published.") - offset = ( - await self.laser_tracker.rem.lasertracker_1.evt_offsetsPublish.aget( - timeout=self.timeout_short - ) - ) - - corrections = np.array( - [ - offset.dX * 1e3 if abs(offset.dX) > self.tolerance_linear else 0.0, - offset.dY * 1e3 if abs(offset.dY) > self.tolerance_linear else 0.0, - offset.dZ * 1e3 if abs(offset.dZ) > self.tolerance_linear else 0.0, - offset.dRX if abs(offset.dRX) > self.tolerance_angular else 0.0, - offset.dRY if abs(offset.dRY) > self.tolerance_angular else 0.0, - ] - ) - - if any(corrections): - self.log.info( - f"[{n_iter+1:02d}:{self.max_iter:02d}]: Applying corrections: " - f"dX={corrections[0]}, " - f"dY={corrections[1]}, " - f"dZ={corrections[2]}, " - f"dRX={corrections[3]}, " - f"dRY={corrections[4]}." - ) - await align_func(*-corrections) - - else: - self.log.info( - f"[{n_iter+1:02d}:{self.max_iter:02d}]: Corrections completed." - ) - return - - raise RuntimeError( - f"Failed to align {self.target} after {self.max_iter} iterations." - ) - - async def check_laser_status_ok(self): - """Check that laser status is ON.""" - try: - laser_status = ( - await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.aget( - timeout=self.timeout_short, - ) - ) - - if laser_status.status != LaserStatus.ON: - raise RuntimeError( - f"Laser status is {LaserStatus(laser_status.status)!r}, expected {LaserStatus.ON!r}." - ) - except asyncio.TimeoutError: - self.log.warning("Cannot determine Laser Tracker state, continuing.") - - async def run_block(self): - """Run the script.""" - - await self.check_laser_status_ok() - - await self.checkpoint("Starting alignment procedure.") - - # Align component - await self.align_target() - await self.checkpoint(f"{self.target} aligned with laser tracker.") diff --git a/python/lsst/ts/standardscripts/maintel/laser_tracker/measure.py b/python/lsst/ts/standardscripts/maintel/laser_tracker/measure.py deleted file mode 100644 index 5463d9e50..000000000 --- a/python/lsst/ts/standardscripts/maintel/laser_tracker/measure.py +++ /dev/null @@ -1,144 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Measure"] - -import asyncio - -import yaml -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.observatory.control import RemoteGroup -from lsst.ts.observatory.control.remote_group import Usages - -from ...base_block_script import BaseBlockScript -from .align import AlignComponent - - -class Measure(BaseBlockScript): - """Measure component using laser tracker. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - "Starting measure procedure.": Starting measurement with laser tracker. - - "M2 Hexapod measured with laser tracker.": M2 measured. - - "Camera Hexapod measured with laser tracker.": Camera measured. - """ - - def __init__(self, index: int, add_remotes: bool = True): - super().__init__(index, descr="Measure MTCS components with laser tracker.") - - self.laser_tracker = RemoteGroup( - domain=self.domain, - components=["LaserTracker:1"], - intended_usage=None if add_remotes else Usages.DryTest, - log=self.log, - ) - - self.timeout_measure = 120 - self.timeout_std = 130 - self.timeout_short = 10 - - self.target = None - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/laser_tracker/measure.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: MaintelLaserTrackerAlign v1 - description: Configuration for Maintel laser tracker measurement SAL Script. - type: object - properties: - target: - description: Target to measure. - type: string - enum: {[target.name for target in AlignComponent]} - additionalProperties: false - required: - - target - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - self.target = getattr(AlignComponent, config.target) - await super().configure(config=config) - - def set_metadata(self, metadata): - """Set estimated duration of the script.""" - - metadata.duration = self.timeout_measure + self.timeout_std - - async def measure_target(self): - """Measure target with laser tracker.""" - - self.laser_tracker.rem.lasertracker_1.evt_offsetsPublish.flush() - - await self.laser_tracker.rem.lasertracker_1.cmd_align.set_start( - target=self.target, - timeout=self.timeout_measure, - ) - - async def check_laser_status_ok(self): - """Check that laser status is ON.""" - try: - laser_status = ( - await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.aget( - timeout=self.timeout_short, - ) - ) - - if laser_status.status != LaserStatus.ON: - raise RuntimeError( - f"Laser status is {LaserStatus(laser_status.status)!r}, expected {LaserStatus.ON!r}." - ) - except asyncio.TimeoutError: - self.log.warning("Cannot determine Laser Tracker state, continuing.") - - async def run_block(self): - """Run the script.""" - - await self.check_laser_status_ok() - - await self.checkpoint("Starting measuring procedure.") - - # Align component - await self.measure_target() - await self.checkpoint(f"{self.target} measured with laser tracker.") diff --git a/python/lsst/ts/standardscripts/maintel/laser_tracker/set_up.py b/python/lsst/ts/standardscripts/maintel/laser_tracker/set_up.py deleted file mode 100644 index 06df7a1f2..000000000 --- a/python/lsst/ts/standardscripts/maintel/laser_tracker/set_up.py +++ /dev/null @@ -1,118 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SetUp"] - -import asyncio - -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.observatory.control import RemoteGroup -from lsst.ts.observatory.control.remote_group import Usages - -from ...base_block_script import BaseBlockScript - - -class SetUp(BaseBlockScript): - """Set up Laser Tracker. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - "Power up Laser Tracker.": Turning laser power on. - - "Waiting for laser to warm up.": Waiting for laser to warm up. - - """ - - def __init__(self, index: int, add_remotes: bool = True): - super().__init__(index, descr="Set up laser tracker.") - - self.config = None - - self.laser_tracker = RemoteGroup( - domain=self.domain, - components=["LaserTracker:1"], - intended_usage=None if add_remotes else Usages.DryTest, - log=self.log, - ) - self.timeout_laser_warmup = 60 - self.timeout_laser_power = 30 - self.timeout_std = 60 - - @classmethod - def get_schema(cls): - return None - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - """Set estimated duration of the script.""" - - metadata.duration = self.timeout_laser_warmup + self.timeout_laser_power - - async def start_up(self): - """Start up the Laser Tracker and check it is alived and enabled.""" - - if self.laser_tracker.start_task is not None: - await self.laser_tracker.start_task - - await asyncio.gather( - self.laser_tracker.assert_liveliness(), - self.laser_tracker.assert_all_enabled(), - ) - - async def wait_laser_status_ok(self): - """Wait for the laser to warm up and be ready to be used.""" - - self.log.info("Checking if the laser is ready to be used.") - - self.laser_tracker.rem.lasertracker_1.evt_laserStatus.flush() - laser_status = await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.aget( - timeout=self.timeout_std, - ) - - while laser_status.status != LaserStatus.ON: - laser_status = ( - await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.next( - flush=False, - timeout=self.timeout_laser_warmup, - ) - ) - - async def run_block(self): - """Run the script.""" - await self.start_up() - - await self.checkpoint("Power up Laser Tracker.") - await self.laser_tracker.rem.lasertracker_1.cmd_laserPower.set_start( - power=1, - timeout=self.timeout_laser_power, - ) - - await self.checkpoint("Waiting for laser to warm up.") - await self.wait_laser_status_ok() - - self.log.info("Laser Tracker is warmed up and ready to be used.") diff --git a/python/lsst/ts/standardscripts/maintel/laser_tracker/shut_down.py b/python/lsst/ts/standardscripts/maintel/laser_tracker/shut_down.py deleted file mode 100644 index 87c80c32d..000000000 --- a/python/lsst/ts/standardscripts/maintel/laser_tracker/shut_down.py +++ /dev/null @@ -1,104 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["ShutDown"] - -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.observatory.control import RemoteGroup -from lsst.ts.observatory.control.remote_group import Usages - -from ...base_block_script import BaseBlockScript - - -class ShutDown(BaseBlockScript): - """Shut down Laser Tracker. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - "Shutting down Laser Tracker.": Turning laser power off. - - "Waiting for laser to switch off.": Waiting laser to switch off. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__(index, descr="Shut down laser tracker.") - - self.config = None - - self.laser_tracker = RemoteGroup( - domain=self.domain, - components=["LaserTracker:1"], - intended_usage=None if add_remotes else Usages.DryTest, - log=self.log, - ) - - self.timeout_laser_warmdown = 60 - self.timeout_laser_power = 30 - self.timeout_std = 60 - - @classmethod - def get_schema(cls): - return None - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - """Set estimated duration of the script.""" - - metadata.duration = self.timeout_laser_power + self.timeout_laser_warmdown - - async def wait_laser_status_off(self): - """Wait for the laser to turn power off.""" - - self.log.info("Checking if the laser is turned off.") - - self.laser_tracker.rem.lasertracker_1.evt_laserStatus.flush() - laser_status = await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.aget( - timeout=self.timeout_std, - ) - - while laser_status.status != LaserStatus.OFF: - laser_status = ( - await self.laser_tracker.rem.lasertracker_1.evt_laserStatus.next( - flush=False, - timeout=self.timeout_laser_warmdown, - ) - ) - - async def run_block(self): - """Run the script.""" - - await self.checkpoint("Shutting down Laser Tracker.") - await self.laser_tracker.rem.lasertracker_1.cmd_laserPower.set_start( - power=0, - timeout=self.timeout_laser_power, - ) - - await self.checkpoint("Waiting for laser to switch off.") - await self.wait_laser_status_off() - - self.log.info("Laser Tracker is off.") diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/__init__.py b/python/lsst/ts/standardscripts/maintel/m1m3/__init__.py deleted file mode 100644 index 35bad8b41..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .check_actuators import * -from .check_hardpoint import * -from .disable_m1m3_balance_system import * -from .enable_m1m3_balance_system import * -from .enable_m1m3_slew_controller_flags import * -from .lower_m1m3 import * -from .raise_m1m3 import * diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/check_actuators.py b/python/lsst/ts/standardscripts/maintel/m1m3/check_actuators.py deleted file mode 100644 index adf719aab..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/check_actuators.py +++ /dev/null @@ -1,467 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CheckActuators"] - - -import asyncio -import time -import warnings - -import yaml - -try: - from lsst.ts.xml.tables.m1m3 import FATable -except ImportError: - from lsst.ts.criopy.M1M3FATable import FATABLE as FATable - -from lsst.ts.idl.enums.MTM1M3 import BumpTest -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.observatory.control.maintel.mtcs import MTCS -from lsst.ts.utils import make_done_future -from lsst.ts.xml.tables.m1m3 import force_actuator_from_id - -from ...base_block_script import BaseBlockScript - -try: - from lsst.ts.idl.enums.MTM1M3 import DetailedState -except ImportError: - warnings.warn( - "Could not import MTM1M3 from lsst.ts.idl; importing from lsst.ts.xml", - UserWarning, - ) - from lsst.ts.xml.enums.MTM1M3 import DetailedStates as DetailedState - - -class CheckActuators(BaseBlockScript): - """Perform a M1M3 bump test on either a selection of individual - actuators or on all actuators. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - - In case of dual actuators both cylinders will be tested consecutively. - The Script will fail if M1M3 mirror is raised. - - **Checkpoints** - - - "Running bump test on FA ID: {id}.": Check individual actuator. - - "M1M3 bump test completed.": Check complete. - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Bump Test on M1M3 Actuators") - - self.mtcs = None - - # Average duration (seconds) of a bump test on a single actuator - self.time_one_bump = 25 - - # Getting list of actuator ids from mtcs - self.m1m3_actuator_ids = None - self.m1m3_secondary_actuator_ids = None - - # Actuators that will be effectively tested - self.actuators_to_test = None - - async def assert_feasibility(self): - """Verify that the system is in a feasible state before - running bump test. Note that M1M3 mirror should be in lowered - position. - """ - - for comp in self.mtcs.components_attr: - if comp != "mtm1m3": - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - # Check all enabled and liveliness - await asyncio.gather( - self.mtcs.assert_all_enabled(), - self.mtcs.assert_liveliness(), - ) - # Check if m1m3 detailed state is either PARKED or PARKEDENGINEERING - expected_states = {DetailedState.PARKED, DetailedState.PARKEDENGINEERING} - try: - await self.mtcs.assert_m1m3_detailed_state(expected_states) - except AssertionError: - raise RuntimeError( - "Please park M1M3 before proceeding with the bump test. This can be done " - "by lowering the mirror or enabling the M1M3 CSC." - ) - - @classmethod - def get_schema(cls): - m1m3_actuator_ids_str = ",".join([str(fa.actuator_id) for fa in FATable]) - - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/m1m3/check_actuators.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: CheckAcutators v1 - description: Configuration for Maintel bump test SAL Script. - type: object - properties: - actuators: - description: Actuators to run the bump test. - oneOf: - - type: array - items: - type: number - enum: [{m1m3_actuator_ids_str}] - minItems: 1 - uniqueItems: true - additionalItems: false - - type: string - enum: ["all", "last_failed"] - default: "all" - ignore_actuators: - description: Actuators to ignore during the bump test. - type: array - items: - type: number - enum: [{m1m3_actuator_ids_str}] - default: [] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - - self.config = config - - await self.configure_tcs() - - # Get actuators to be tested. - # (if "last_failed" is used, select all actuators for later filtering) - self.actuators_to_test = ( - self.m1m3_actuator_ids - if config.actuators in ["all", "last_failed"] - else config.actuators - ) - if config.ignore_actuators: - self.actuators_to_test = [ - actuator_id - for actuator_id in self.actuators_to_test - if actuator_id not in config.ignore_actuators - ] - - await super().configure(config=config) - - async def configure_tcs(self): - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - - # Getting list of actuator ids from mtcs - self.m1m3_actuator_ids = self.mtcs.get_m1m3_actuator_ids() - self.m1m3_secondary_actuator_ids = self.mtcs.get_m1m3_actuator_secondary_ids() - - self.actuators_to_test = self.m1m3_actuator_ids.copy() - - def set_metadata(self, metadata): - """Set metadata.""" - - # Getting total number of secondary actuators to be tested - total_tested_secondary = sum( - [ - 1 - for actuator in self.actuators_to_test - if self.has_secondary_actuator(actuator) - ] - ) - - # Setting metadata - metadata.duration = self.time_one_bump * ( - len(self.actuators_to_test) + total_tested_secondary - ) - - def has_secondary_actuator(self, actuator_id: int) -> bool: - """Determines whether a given actuator has a - secondary axis or not. - """ - - return actuator_id in self.m1m3_secondary_actuator_ids - - async def actuator_last_test_failed(self, actuator_id: int) -> bool: - """Determines whether the last bump test for a given actuator - failed.""" - primary, secondary = await self.mtcs.get_m1m3_bump_test_status(actuator_id) - return primary == BumpTest.FAILED or secondary == BumpTest.FAILED - - async def run_block(self): - await self.assert_feasibility() - start_time = time.monotonic() - - # Get M1M3 detailed state - detailed_state = DetailedState( - ( - await self.mtcs.rem.mtm1m3.evt_detailedState.aget( - timeout=self.mtcs.fast_timeout, - ) - ).detailedState - ) - self.log.info(f"Current M1M3 detailed state: {detailed_state!r}.") - - # Filter actuator_to_test when the last_failed option is used - if self.config.actuators == "last_failed": - actuators_mask = await asyncio.gather( - *[ - self.actuator_last_test_failed(actuator_id) - for actuator_id in self.actuators_to_test - ] - ) - self.actuators_to_test = [ - actuator_id - for actuator_id, mask in zip(self.actuators_to_test, actuators_mask) - if mask - ] - self.log.info( - f"Selecting actuators that failed the last bump test: {self.actuators_to_test!r}." - ) - - # Put M1M3 in engineering mode - await self.mtcs.enter_m1m3_engineering_mode() - - # List to capture failures with full details - list_of_failures = [] - - timer_task = make_done_future() - - for i, actuator_id in enumerate(self.actuators_to_test): - await self.mtcs.assert_all_enabled() - - # Get the actuator type (SAA or DAA) - actuator_type = force_actuator_from_id(actuator_id).actuator_type.name - secondary_exist = self.has_secondary_actuator(actuator_id) - - # Get primary and secondary indexes - primary_index = self.m1m3_actuator_ids.index(actuator_id) - secondary_index = None - if secondary_exist: - secondary_index = self.m1m3_secondary_actuator_ids.index(actuator_id) - - # Checkpoint before running the bump test - if secondary_exist: - await self.checkpoint( - f"Running bump test on DAA FA ID: {actuator_id} " - f"(Primary/Secondary: {primary_index}/{secondary_index})" - ) - else: - await self.checkpoint( - f"Running bump test on SAA FA ID: {actuator_id} " - f"(Primary {primary_index})" - ) - - # Run the bump test - try: - if not timer_task.done(): - self.log.debug("Waiting timer task before running bump test.") - await timer_task - self.log.debug("Timer task done. Running bump test.") - - await self.mtcs.run_m1m3_actuator_bump_test( - actuator_id=actuator_id, - primary=True, - secondary=secondary_exist, - ) - except RuntimeError: - list_of_failures.append( - (actuator_id, actuator_type, primary_index, None) - ) - self.log.exception( - f"Failed to run bump test on FA ID {actuator_id}. Creating timer task for next test." - ) - timer_task = asyncio.create_task(asyncio.sleep(self.time_one_bump)) - - # Getting test status - primary_status, secondary_status = ( - await self.mtcs.get_m1m3_bump_test_status(actuator_id=actuator_id) - ) - - # Log status update after bump test - secondary_status_text = ( - f"Secondary FA (Index {secondary_index}): {secondary_status.name.upper()}." - if secondary_exist - else "" - ) - self.log.info( - f"Bump test done for {i + 1} of {len(self.actuators_to_test)}. " - f"FA ID {actuator_id} ({actuator_type}). Primary FA (Index {primary_index}): " - f"{primary_status.name.upper()}. {secondary_status_text}" - ) - - # Check primary failure - if primary_status == BumpTest.FAILED: - self.log.debug( - f"Primary failed for Actuator ID {actuator_id}, Pri Index {primary_index}" - ) - primary_index_of_failure = primary_index - else: - primary_index_of_failure = None - - # Check secondary failure - if secondary_exist and secondary_status == BumpTest.FAILED: - self.log.debug( - f"Secondary failed for Actuator ID {actuator_id}, Sec Index {secondary_index}" - ) - secondary_index_of_failure = secondary_index - else: - secondary_index_of_failure = None - - # Find if actuator is already in list_of_failures - actuator_failure = next( - (item for item in list_of_failures if item[0] == actuator_id), None - ) - - # Append or update failures in list_of_failures - if ( - primary_index_of_failure is not None - or secondary_index_of_failure is not None - ): - if actuator_failure: - # Update primary or secondary failure only if they failed - updated_primary_index = ( - primary_index_of_failure - if primary_index_of_failure is None - else actuator_failure[2] # Keep the original (None or failure) - ) - updated_secondary_index = ( - secondary_index_of_failure - if secondary_index_of_failure is not None - else actuator_failure[3] # Keep the original (None or failure) - ) - - # Only update the entry if the failure has changed - list_of_failures[list_of_failures.index(actuator_failure)] = ( - actuator_id, - actuator_type, - updated_primary_index, - updated_secondary_index, - ) - self.log.debug( - f"Updated in list_of_failures: Actuator ID {actuator_id}, Type {actuator_type}, " - f"Primary Index {updated_primary_index}, Secondary Index {updated_secondary_index}" - ) - else: - # Add new entry only with failure information - # (ignores passed tests) - list_of_failures.append( - ( - actuator_id, - actuator_type, - primary_index_of_failure, - secondary_index_of_failure, - ) - ) - self.log.debug( - f"Appending to list_of_failures: Actuator ID {actuator_id}, Type {actuator_type}, " - f"Primary Index {primary_index_of_failure}, Secondary Index " - f"{secondary_index_of_failure}." - ) - - end_time = time.monotonic() - elapsed_time = end_time - start_time - - # Final checkpoint - await self.checkpoint( - f"M1M3 bump test completed. It took {elapsed_time:.2f} seconds." - ) - - # Generating final report from list_of_failures - if not list_of_failures: - self.log.info("All actuators PASSED the bump test.") - else: - # Collect the failed actuator IDs for the header - failed_actuators_id = [fail[0] for fail in list_of_failures] - - # Create formatted output for SAA and DAA failures - failed_saa_str = "\n".join( - f" - Actuator ID {actuator_id}: Pri Index {primary_index}" - for actuator_id, actuator_type, primary_index, _ in list_of_failures - if actuator_type == "SAA" and primary_index is not None - ) - - failed_daa_str = "\n".join( - f" - Actuator ID {actuator_id}: " - + (f"Pri Index {primary_index}" if primary_index is not None else "") - + ( - ", " - if primary_index is not None and secondary_index is not None - else "" - ) - + ( - f"Sec Index {secondary_index}" - if secondary_index is not None - else "" - ) - for actuator_id, actuator_type, primary_index, secondary_index in list_of_failures - if actuator_type == "DAA" - ) - - # Combine the header and the detailed report - error_message = ( - f"Actuators {sorted(set(failed_actuators_id))} FAILED the bump test.\n\n" - f"SAA (Single Actuator Axes) Failures:\n{failed_saa_str or ' None'}\n" - f"DAA (Dual Actuator Axes) Failures:\n{failed_daa_str or ' None'}" - ) - - self.log.error(error_message) - raise RuntimeError(error_message) - - async def cleanup(self): - if self.state.state != ScriptState.ENDING: - try: - self.log.warning("M1M3 bump test stopped. Killing actuator forces.") - - await self.mtcs.stop_m1m3_bump_test() - - except Exception: - self.log.exception("Unexpected exception in stop_m1m3_bump_test.") - - # Exiting engineering mode - await self.mtcs.exit_m1m3_engineering_mode() diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/check_hardpoint.py b/python/lsst/ts/standardscripts/maintel/m1m3/check_hardpoint.py deleted file mode 100644 index bfc215509..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/check_hardpoint.py +++ /dev/null @@ -1,166 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CheckHardpoint"] - -import asyncio -import warnings - -import yaml -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - -try: - from lsst.ts.idl.enums.MTM1M3 import DetailedState -except ImportError: - warnings.warn( - "Could not import MTM1M3 from lsst.ts.idl; importing from lsst.ts.xml", - UserWarning, - ) - from lsst.ts.xml.enums.MTM1M3 import DetailedStates as DetailedState - - -class CheckHardpoint(BaseBlockScript): - """Check M1M3 Individual hardpoint breakaway. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Testing hardpoint {id}.": Check hardpoint. - - "Hardpoint breakaway check complete.": Check complete. - - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__(index=index, descr="Check M1M3 Hardpoint") - - self.mtcs = None - - self.timeout_check = 60 - self.timeout_std = 60 - - self.hardpoints = range(1, 7) - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/m1m3/check_hardpoint.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: CheckHardpoint v1 - description: Configuration for Maintel check hardpoint breakaway test SAL Script. - type: object - properties: - hardpoints: - description: Hardpoints to run the breakway test. - oneOf: - - type: array - minItems: 1 - items: - type: number - minimum: 1 - maximum: 6 - - type: string - enum: ["all"] - default: "all" - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - self.hardpoints = ( - range(1, 7) if config.hardpoints == "all" else config.hardpoints - ) - - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - - for comp in self.mtcs.components_attr: - if comp != "mtm1m3": - setattr(self.mtcs.check, comp, False) - - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = self.timeout_check * 2 + self.timeout_std - - async def run_individual_test(self, idx, hp): - await self.checkpoint(f"Testing hardpoint {hp}.") - await self.mtcs.run_m1m3_hard_point_test(hp=hp) - self.log.info(f"Tests complete: {idx + 1}/{len(self.hardpoints)}") - - async def run_block(self): - # Check that the MTCS is in the right state - await asyncio.gather( - self.mtcs.assert_all_enabled(), - self.mtcs.assert_liveliness(), - self.mtcs.assert_m1m3_detailed_state( - {DetailedState.PARKED, DetailedState.PARKEDENGINEERING} - ), - ) - - await self.mtcs.enter_m1m3_engineering_mode() - - tasks = [ - self.run_individual_test(idx, hp) - for (idx, hp) in enumerate(self.hardpoints) - ] - return_values = await asyncio.gather(*tasks, return_exceptions=True) - exceptions = [ - (hp, value) - for (hp, value) in zip(self.hardpoints, return_values) - if isinstance(value, Exception) - ] - - if exceptions: - err_message = f"{len(exceptions)} out of {len(self.hardpoints)} hard point tests failed.\n" - for hp, exception in exceptions: - err_message += f"Hardpoint {hp} test failed with {exception!r}.\n" - raise RuntimeError(err_message) - - await self.checkpoint("Hardpoint breakaway check complete.") - - async def cleanup(self): - self.log.info( - f"Terminating with state={self.state.state}: exit engineering mode." - ) - await self.mtcs.exit_m1m3_engineering_mode() diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/disable_m1m3_balance_system.py b/python/lsst/ts/standardscripts/maintel/m1m3/disable_m1m3_balance_system.py deleted file mode 100644 index 9b009a330..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/disable_m1m3_balance_system.py +++ /dev/null @@ -1,76 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["DisableM1M3BalanceSystem"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class DisableM1M3BalanceSystem(BaseBlockScript): - """Disable M1M3 force balance system. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Disabling M1M3 force balance system": Before disabling M1M3 force - balance system. - - **Details** - - This script disables the M1M3 force balance system of the Simonyi Main - Telescope. - - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Disable M1M3 force balance system") - - self.mtcs = None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 180.0 - - async def run_block(self): - await self.checkpoint("Disabling M1M3 force balance system") - start_time = time.time() - await self.mtcs.disable_m1m3_balance_system() - end_time = time.time() - elapsed_time = end_time - start_time - self.log.info( - f"Disabling M1M3 force balance system took {elapsed_time:.2f} seconds" - ) diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_balance_system.py b/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_balance_system.py deleted file mode 100644 index 0bb9aafbd..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_balance_system.py +++ /dev/null @@ -1,76 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableM1M3BalanceSystem"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class EnableM1M3BalanceSystem(BaseBlockScript): - """Enable M1M3 force balance system. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Enabling M1M3 force balance system": Before enabling M1M3 force balance - system. - - **Details** - - This script enables the M1M3 force balance system of the Simonyi Main - Telescope. - - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable M1M3 force balance system") - - self.mtcs = None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 180.0 - - async def run_block(self): - await self.checkpoint("Enabling M1M3 force balance system") - start_time = time.time() - await self.mtcs.enable_m1m3_balance_system() - end_time = time.time() - elapsed_time = end_time - start_time - self.log.info( - f"Enabling M1M3 force balance system took {elapsed_time:.2f} seconds" - ) diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py b/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py deleted file mode 100644 index 5837905d8..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/enable_m1m3_slew_controller_flags.py +++ /dev/null @@ -1,170 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableM1M3SlewControllerFlags"] - - -import yaml -from lsst.ts.observatory.control.maintel import MTCS -from lsst.ts.salobj import type_hints -from lsst.ts.xml.enums import MTM1M3 - -from ...base_block_script import BaseBlockScript - - -class EnableM1M3SlewControllerFlags(BaseBlockScript): - """Set M1M3 Slew Controller Settings for the main telescope. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - flag_names : `list`[`str`] - List of M1M3 slew controller flags names to change. - enable : `list`[`bool`] - Corresponding booleans to enable or disable each flag. - - Returns - ------- - `list`[`MTM1M3.SetSlewControllerSettings`] - List of enum values associated with the flag names. - """ - - def __init__(self, index: int) -> None: - super().__init__( - index, descr="Set M1M3 Slew Controller Settings for the main telescope." - ) - self.mtcs = None - self.config = None - - async def configure_tcs(self) -> None: - """Handle creating MTCS object and waiting for remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/EnableM1M3SlewControllerFlags/v1 - title: EnableM1M3SlewControllerFlags v1 - description: Configuration for EnableM1M3SlewControllerFlags script. - type: object - properties: - slew_flags: - description: >- - List of M1M3 slew controller flags to change or "default" for a - predefined combination of flags. - oneOf: - - type: string - enum: ["default"] - - type: array - items: - type: string - enum: ["ACCELERATIONFORCES", "BALANCEFORCES", "VELOCITYFORCES", "BOOSTERVALVES"] - enable: - description: >- - Corresponding booleans to enable or disable each flag. It will be - [True, True, False, True] if the slew_flag is "default". - type: array - items: - type: boolean - required: - - slew_flags - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - def set_metadata(self, metadata: type_hints.BaseMsgType) -> None: - """Set script metadata.""" - - # Estimate time per flag setting operation - time_per_operation = 3.0 # Adjust this based on empirical data - - metadata.duration = time_per_operation * len(self.config.slew_flags) - - def get_default_slew_flags(self): - """Return the default slew flags and enables. - - Returns - ------- - `tuple`[`list`[`MTM1M3.SetSlewControllerSettings`], `list`[`bool`]] - Default slew flags and enables. - """ - default_flags = [ - MTM1M3.SetSlewControllerSettings.ACCELERATIONFORCES, - MTM1M3.SetSlewControllerSettings.BALANCEFORCES, - MTM1M3.SetSlewControllerSettings.VELOCITYFORCES, - MTM1M3.SetSlewControllerSettings.BOOSTERVALVES, - ] - default_enables = [True, True, False, True] - - return default_flags, default_enables - - def convert_flag_names_to_enum(self, flag_names): - """Convert flag names to enumeration values.""" - return [MTM1M3.SetSlewControllerSettings[flag_name] for flag_name in flag_names] - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - self.config = config - - if self.config.slew_flags == "default": - self.config.slew_flags, self.config.enable = self.get_default_slew_flags() - else: - if len(self.config.slew_flags) != len(self.config.enable): - raise ValueError( - "slew_flags and enable arrays must have the same length." - ) - # Convert flag names to enumeration values and - # store them back in config - self.config.slew_flags = self.convert_flag_names_to_enum( - self.config.slew_flags - ) - - await self.configure_tcs() - - await super().configure(config=config) - - async def run_block(self): - - async with self.mtcs.m1m3_in_engineering_mode(): - for flag, enable in zip(self.config.slew_flags, self.config.enable): - self.log.info(f"Setting m1m3 slew flag {flag.name} to {enable}.") - await self.mtcs.set_m1m3_slew_controller_settings(flag, enable) diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/lower_m1m3.py b/python/lsst/ts/standardscripts/maintel/m1m3/lower_m1m3.py deleted file mode 100644 index feff16209..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/lower_m1m3.py +++ /dev/null @@ -1,72 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["LowerM1M3"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class LowerM1M3(BaseBlockScript): - """Lower M1M3 mirror. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Lowering M1M3": Before commanding the M1M3 mirror to lower. - - **Details** - - This script lowers the M1M3 mirror of the Simonyi Main Telescope. - - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Lower M1M3") - - self.mtcs = None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 180.0 - - async def run_block(self): - await self.checkpoint("Lowering M1M3") - start_time = time.time() - await self.mtcs.lower_m1m3() - end_time = time.time() - elapsed_time = end_time - start_time - self.log.info(f"Lowering M1M3 took {elapsed_time:.2f} seconds") diff --git a/python/lsst/ts/standardscripts/maintel/m1m3/raise_m1m3.py b/python/lsst/ts/standardscripts/maintel/m1m3/raise_m1m3.py deleted file mode 100644 index 52a7a71cd..000000000 --- a/python/lsst/ts/standardscripts/maintel/m1m3/raise_m1m3.py +++ /dev/null @@ -1,72 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["RaiseM1M3"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class RaiseM1M3(BaseBlockScript): - """Raise M1M3 mirror. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Raising M1M3": Before commanding the M1M3 mirror to raise. - - **Details** - - This script raises the M1M3 mirror of the Simonyi Main Telescope. - - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Raise M1M3") - - self.mtcs = None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 180.0 - - async def run_block(self): - await self.checkpoint("Raising M1M3") - start_time = time.time() - await self.mtcs.raise_m1m3() - end_time = time.time() - elapsed_time = end_time - start_time - self.log.info(f"M1M3 Raise took {elapsed_time:.2f} seconds") diff --git a/python/lsst/ts/standardscripts/maintel/m2/__init__.py b/python/lsst/ts/standardscripts/maintel/m2/__init__.py deleted file mode 100644 index 9db9bad4d..000000000 --- a/python/lsst/ts/standardscripts/maintel/m2/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .check_actuators import * -from .disable_closed_loop import * -from .enable_closed_loop import * diff --git a/python/lsst/ts/standardscripts/maintel/m2/check_actuators.py b/python/lsst/ts/standardscripts/maintel/m2/check_actuators.py deleted file mode 100644 index 632f7d246..000000000 --- a/python/lsst/ts/standardscripts/maintel/m2/check_actuators.py +++ /dev/null @@ -1,262 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["CheckActuators"] - - -import asyncio -import time - -import numpy as np -import yaml -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.observatory.control.maintel.mtcs import MTCS -from lsst.ts.salobj import AckError, AckTimeoutError - -from ...base_block_script import BaseBlockScript - -# TODO: DM-41592 move constants from lsst.ts.m2com to ts-xml -NUM_ACTUATOR = 78 -NUM_TANGENT_LINK = 6 - - -class CheckActuators(BaseBlockScript): - """Perform a M2 bump test on either a selection of individual - actuators or on all axial actuators. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - - **Checkpoints** - - - "Running bump test on FA ID: {id}.": Check individual actuator. - - "M2 bump test completed.": Check complete. - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Bump Test on M2 Axial Actuators") - - self.mtcs = None - - # Average duration (seconds) of a bump test on a single actuator - self.time_one_bump = 120 - - # default period of bump test in seconds - self.period = 60 - - # default +/- force to apply during bump test in N - self.force = 10 - - async def assert_feasibility(self): - """Verify that the system is in a feasible state before - running bump test. - """ - - for comp in self.mtcs.components_attr: - if comp != "mtm2": - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - # Check all enabled and liveliness - await asyncio.gather( - self.mtcs.assert_all_enabled(), - self.mtcs.assert_liveliness(), - ) - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/m2/check_actuators.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: CheckAcutators v1 - description: Configuration for Maintel M2 bump test SAL Script. - type: object - properties: - period: - description: Period, in seconds, for each step of bump test, two steps total. - type: number - default: 60 - force: - description: Force, in N, the +/- force to apply during bump test. - type: number - default: 10 - actuators: - description: Actuators to run the bump test. - oneOf: - - type: array - items: - type: number - minimum: 0 - maximum: {NUM_ACTUATOR - NUM_TANGENT_LINK} - minItems: 1 - uniqueItems: true - additionalItems: false - - type: string - enum: ["all"] - default: "all" - ignore_actuators: - description: Actuators to ignore during the bump test. - type: array - items: - type: number - minimum: 0 - maximum: {NUM_ACTUATOR - NUM_TANGENT_LINK} - default: [] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - - # Get list of M2 hardpoints from mtcs - self.hardpoint_ids = await self.mtcs.get_m2_hardpoints() - - # Getting list of actuator ids - num_axial_actuator = NUM_ACTUATOR - NUM_TANGENT_LINK - self.axial_actuator_ids = list( - [ - actuator - for actuator in np.arange(num_axial_actuator) - if actuator + 1 not in self.hardpoint_ids - ] - ) - - # Actuators that will be effectively tested, filtering out hardpoints - # (which are 1 indexed, csc is 0 indexed) - if config.actuators == "all": - self.actuators_to_test = self.axial_actuator_ids - else: - # check that no actuators are hardpoints - for actuator in config.actuators: - if actuator + 1 in self.hardpoint_ids: - raise ValueError( - f"Cannot run bump test on actuator {actuator}," - "it is currently configured as a hardpoint" - ) - elif actuator + 1 not in self.axial_actuator_ids: - raise ValueError( - f"Cannot run bump test on actuator {actuator}, it is not a valid axial actuator." - ) - - self.actuators_to_test = config.actuators - - if config.ignore_actuators: - self.actuators_to_test = [ - actuator - for actuator in self.actuators_to_test - if actuator not in config.ignore_actuators - ] - if hasattr(config, "period"): - self.period = config.period - if hasattr(config, "force"): - self.force = config.force - - await super().configure(config=config) - - def set_metadata(self, metadata): - """Set metadata.""" - - metadata.duration = self.time_one_bump * (len(self.actuators_to_test)) - - async def run_block(self): - await self.assert_feasibility() - start_time = time.monotonic() - - self.failed_actuator_ids = [] - for actuator in self.actuators_to_test: - await self.mtcs.assert_all_enabled() - - # Checkpoint - await self.checkpoint(f"Running bump test on M2 Axial FA ID: {actuator} ") - - try: - await self.mtcs.run_m2_actuator_bump_test( - actuator=actuator, - period=self.period, - force=self.force, - ) - except (AckError, AckTimeoutError): - self.failed_actuator_ids.append(actuator) - self.log.exception( - f"Failed to run bump test on AXIAL FA ID {actuator}." - ) - - end_time = time.monotonic() - elapsed_time = end_time - start_time - - # Final checkpoint - await self.checkpoint( - f"M2 bump test completed. It took {elapsed_time:.2f} seconds." - ) - - # Final message with bump test results/status - if not self.failed_actuator_ids: - self.log.info("All actuators PASSED the bump test.") - else: - error_message = ( - f"Actuators {self.failed_actuator_ids} FAILED the bump test." - ) - self.log.error(error_message) - raise RuntimeError(error_message) - - async def cleanup(self): - if self.state.state != ScriptState.ENDING: - try: - self.log.warning("M2 bump test stopped. Killing actuator forces.") - - await self.mtcs.stop_m2_bump_test() - - except Exception: - self.log.exception("Unexpected exception in stop_m2_bump_test.") diff --git a/python/lsst/ts/standardscripts/maintel/m2/disable_closed_loop.py b/python/lsst/ts/standardscripts/maintel/m2/disable_closed_loop.py deleted file mode 100644 index b5b106098..000000000 --- a/python/lsst/ts/standardscripts/maintel/m2/disable_closed_loop.py +++ /dev/null @@ -1,74 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["DisableM2ClosedLoop"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class DisableM2ClosedLoop(BaseBlockScript): - """Disable M2 closed-loop. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Disabling M1M2 closed-loop": Before disabling M2 closed-loop. - - **Details** - - This script disables M2 closed-loop for the Simonyi Survey Telescope. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Disable M2 closed-loop.") - self.mtcs = None - - async def configure_tcs(self) -> None: - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - async def configure(self, config): - await self.configure_tcs() - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 15.0 - - async def run_block(self): - await self.checkpoint("Disabling M2 closed-loop.") - start_time = time.monotonic() - await self.mtcs.disable_m2_balance_system() - elapsed_time = time.monotonic() - start_time - self.log.info(f"Disabling M2 closed-loop took {elapsed_time:.2f} seconds.") diff --git a/python/lsst/ts/standardscripts/maintel/m2/enable_closed_loop.py b/python/lsst/ts/standardscripts/maintel/m2/enable_closed_loop.py deleted file mode 100644 index 95144f207..000000000 --- a/python/lsst/ts/standardscripts/maintel/m2/enable_closed_loop.py +++ /dev/null @@ -1,74 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableM2ClosedLoop"] - -import time - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class EnableM2ClosedLoop(BaseBlockScript): - """Enable M2 closed-loop. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Enabling M1M2 closed-loop": Before enabling M2 closed-loop. - - **Details** - - This script enables M2 closed-loop for the Simonyi Survey Telescope. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable M2 closed-loop.") - self.mtcs = None - - async def configure_tcs(self) -> None: - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - async def configure(self, config): - await self.configure_tcs() - await super().configure(config=config) - - def set_metadata(self, metadata): - metadata.duration = 15.0 - - async def run_block(self): - await self.checkpoint("Enabling M2 closed-loop.") - start_time = time.monotonic() - await self.mtcs.enable_m2_balance_system() - elapsed_time = time.monotonic() - start_time - self.log.info(f"Enabling M2 closed-loop took {elapsed_time:.2f} seconds.") diff --git a/python/lsst/ts/standardscripts/maintel/move_p2p.py b/python/lsst/ts/standardscripts/maintel/move_p2p.py deleted file mode 100644 index 7a4c86cc4..000000000 --- a/python/lsst/ts/standardscripts/maintel/move_p2p.py +++ /dev/null @@ -1,221 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio - -import yaml -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.observatory.control.maintel import MTCS -from lsst.ts.salobj import type_hints - -from ..base_block_script import BaseBlockScript -from ..utils import format_grid - - -class MoveP2P(BaseBlockScript): - """Move Telescope using point to point trajectory instead of traditional - slew/tracking. - """ - - def __init__(self, index: int) -> None: - super().__init__(index, descr="Move Telescope using point to point trajectory.") - - self.mtcs = None - self.grid = dict() - self.pause_for = 0.0 - # A guess to average slew time. - self.slew_time_average_guess = 15.0 - self.move_timeout = 120.0 - - async def configure_tcs(self) -> None: - """Handle creating MTCS object and waiting for remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/move_p2p.py - title: MoveP2P v1 - description: Configuration for BaseTrackTarget. - type: object - additionalProperties: false - properties: - az: - description: Azimuth (deg). Must be used alongside el. - oneOf: - - type: number - - type: array - values: - type: number - el: - description: Elevation (deg). Must be used alongside az. - oneOf: - - type: number - - type: array - values: - type: number - ra: - description: Right ascension (hour). Must be used alongside dec. - oneOf: - - type: number - - type: array - values: - type: number - dec: - description: Declination (deg). Must be used alongside ra. - oneOf: - - type: number - - type: array - values: - type: number - pause_for: - description: >- - If slewing to more than one target, how long to pause - between positions (in seconds). - type: number - default: 0.0 - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - move_timeout: - description: Timeout for move command. - type: number - default: 120.0 - oneOf: - - required: - - az - - el - - required: - - ra - - dec - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure script.""" - - if hasattr(config, "az") and hasattr(config, "el"): - az, el = format_grid(config.az, config.el) - self.grid["azel"] = dict(az=az, el=el) - - if hasattr(config, "ra") and hasattr(config, "dec"): - ra, dec = format_grid(config.ra, config.dec) - self.grid["radec"] = dict(ra=ra, dec=dec) - - self.pause_for = config.pause_for - self.move_timeout = config.move_timeout - - await self.configure_tcs() - - for comp in getattr(config, "ignore", []): - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - await super().configure(config=config) - - def set_metadata(self, metadata: type_hints.BaseMsgType) -> None: - """Set script metadata.""" - metadata.duration = self.slew_time_average_guess + self.pause_for * ( - len(self.grid.get("azel", dict(az=[]))["az"]) - + len(self.grid.get("radec", dict(ra=[]))["ra"]) - ) - - async def run_block(self): - """Execute script operations.""" - - if "azel" in self.grid: - grid_size = len(self.grid["azel"]["az"]) - for i, az, el in zip( - range(grid_size), self.grid["azel"]["az"], self.grid["azel"]["el"] - ): - await self.checkpoint( - f"{self.checkpoint_message}: azel grid {az}/{el} {i+1}/{grid_size}" - ) - self.log.info(f"Moving telescope to {az=},{el=}.") - async with self.test_case_step(): - await self.mtcs.move_p2p_azel( - az=az, - el=el, - timeout=self.move_timeout, - ) - self.log.info(f"Pausing for {self.pause_for}s.") - await asyncio.sleep(self.pause_for) - - if "radec" in self.grid: - grid_size = len(self.grid["radec"]["ra"]) - for i, ra, dec in zip( - range(grid_size), self.grid["radec"]["ra"], self.grid["radec"]["dec"] - ): - await self.checkpoint( - f"{self.checkpoint_message}: radec grid {ra}/{dec} {i+1}/{grid_size}" - ) - self.log.info(f"Moving telescope to {ra=},{dec=}.") - async with self.test_case_step(): - await self.mtcs.move_p2p_radec( - ra=ra, - dec=dec, - timeout=self.move_timeout, - ) - self.log.info(f"Pausing for {self.pause_for}s.") - await asyncio.sleep(self.pause_for) - - async def cleanup(self): - if self.state.state != ScriptState.ENDING: - # abnormal termination - self.log.warning( - f"Terminating with state={self.state.state}: stop telescope." - ) - try: - await self.mtcs.rem.mtmount.cmd_stop.start( - timeout=self.mtcs.long_timeout - ) - except asyncio.TimeoutError: - self.log.exception("Stop command timed out during cleanup procedure.") - except Exception: - self.log.exception("Unexpected exception while stopping telescope.") diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/__init__.py b/python/lsst/ts/standardscripts/maintel/mtdome/__init__.py deleted file mode 100644 index 0b67cd067..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .crawl_az import * -from .disable_dome_following import * -from .enable_dome_following import * -from .home_dome import * -from .park_dome import * -from .slew_dome import * -from .unpark_dome import * diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/crawl_az.py b/python/lsst/ts/standardscripts/maintel/mtdome/crawl_az.py deleted file mode 100644 index 0b4c34ebf..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/crawl_az.py +++ /dev/null @@ -1,155 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -__all__ = ["CrawlAz", "Direction"] - -import asyncio -import enum - -import yaml -from lsst.ts import salobj -from lsst.ts.xml.enums.MTDome import SubSystemId - - -class Direction(enum.IntEnum): - ClockWise = enum.auto() - CounterClockWise = enum.auto() - - -class CrawlAz(salobj.BaseScript): - """Script that makes the MTDome crawl. - - This script is desined to be used by the day crew to move the dome - around. - - Basically they pick a direction they want the dome to move and the - dome will start moving in that direction. When they are happy with - the position, just stops the script and it will take care of - stopping the dome. - """ - - TIMEOUT_CMD = 60.0 - TIMEOUT_STD = 10.0 - - def __init__(self, index): - super().__init__(index=index, descr="MTDome CrawlAz.") - - self.mtdome = None - self.direction = Direction.ClockWise - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtdome/crawl_az.py - title: CrawlAz v1 - description: Configuration for CrawlAz - type: object - properties: - direction: - description: Which direction to move the dome? - type: string - default: ClockWise - enum: ["ClockWise", "CounterClockWise"] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - self.direction = Direction[getattr(config, "direction", "ClockWise")] - if self.mtdome is None: - self.mtdome = salobj.Remote( - self.domain, - "MTDome", - include=["summaryState"], - ) - - await self.mtdome.start_task - - def set_metadata(self, metadata) -> None: - """Set script metadata. - - Parameters - ---------- - metadata : `lsst.ts.salobj.base.ScriptMetadata` - Script metadata. - """ - pass - - async def run(self): - - self.log.info(f"Starting dome movement in the {self.direction!r} direction.") - - summary_state = await self.mtdome.evt_summaryState.aget( - timeout=self.TIMEOUT_STD - ) - - current_state = salobj.State(summary_state.summaryState) - - if current_state != salobj.State.ENABLED: - raise RuntimeError( - "Dome must be in ENABLED, current state {current_state.name}." - ) - - self.mtdome.evt_summaryState.flush() - - await self.mtdome.cmd_crawlAz.set_start( - velocity=0.5 * (1 if self.direction == Direction.ClockWise else -1), - timeout=self.TIMEOUT_CMD, - ) - - while True: - try: - summary_state = await self.mtdome.evt_summaryState.next( - timeout=self.TIMEOUT_STD, flush=False - ) - - if summary_state.summaryState != salobj.State.ENABLED: - raise RuntimeError("Dome must be ENABLED.") - except asyncio.TimeoutError: - self.log.debug("Ignoring timeout error.") - except asyncio.CancelledError: - self.log.debug("Run method cancelled. Finishing.") - return - - async def cleanup(self): - - self.log.info("Stopping dome.") - - try: - await self.mtdome.cmd_crawlAz.set_start( - velocity=0, - timeout=self.TIMEOUT_CMD, - ) - except Exception: - self.log.exception("Error stopping dome crawl. Ignoring.") - - self.log.info("Waiting for dome to stop moving.") - await asyncio.sleep(self.TIMEOUT_STD) - - try: - await self.mtdome.cmd_stop.set_start( - subSystemIds=SubSystemId.AMCS, - timeout=self.TIMEOUT_CMD, - ) - except Exception: - self.log.exception("Error stopping the dome. Ignoring.") diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/disable_dome_following.py b/python/lsst/ts/standardscripts/maintel/mtdome/disable_dome_following.py deleted file mode 100644 index 217484375..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/disable_dome_following.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["DisableDomeFollowing"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class DisableDomeFollowing(salobj.BaseScript): - """Disable Dome Following for the MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Disable Dome Following for the MTDome.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - # This script does not require any configuration - return None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - - def set_metadata(self, metadata): - metadata.duration = 5.0 - - async def run(self): - await self.mtcs.disable_dome_following() diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/enable_dome_following.py b/python/lsst/ts/standardscripts/maintel/mtdome/enable_dome_following.py deleted file mode 100644 index 6ea798a66..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/enable_dome_following.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["EnableDomeFollowing"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class EnableDomeFollowing(salobj.BaseScript): - """Enable Dome Following for the MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable Dome Following for the MTDome.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - # This script does not require any configuration - return None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - - def set_metadata(self, metadata): - metadata.duration = 5.0 - - async def run(self): - await self.mtcs.enable_dome_following() diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/home_dome.py b/python/lsst/ts/standardscripts/maintel/mtdome/home_dome.py deleted file mode 100644 index af661a597..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/home_dome.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see .`` - -__all__ = ["HomeDome"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class HomeDome(salobj.BaseScript): - """Home azimuth of the MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - Homing dome: Before commanding azimuth dome to be homed. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__(index=index, descr="Home MT dome.") - - self.mtcs = None - self.physical_az = None - self.home_dome_duration = 60.0 - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtdome/home_dome.yaml - title: HomeDome v1 - description: Configuration for HomeDome. - type: object - properties: - physical_az: - description: Physical azimuth position for the dome as read by markings. - type: number - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - required: [physical_az] - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - self.physical_az = config.physical_az - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, - intended_usage=MTCSUsages.Slew | MTCSUsages.StateTransition, - log=self.log, - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = self.home_dome_duration - - async def run(self): - await self.mtcs.assert_all_enabled() - await self.checkpoint("Homing dome") - await self.mtcs.home_dome(physical_az=self.physical_az) diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/park_dome.py b/python/lsst/ts/standardscripts/maintel/mtdome/park_dome.py deleted file mode 100644 index e283128c0..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/park_dome.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["ParkDome"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class ParkDome(salobj.BaseScript): - """Park Dome for the MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Park Dome for the MTDome.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - # This script does not require any configuration - return None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - - def set_metadata(self, metadata): - metadata.duration = 5.0 - - async def run(self): - await self.mtcs.park_dome() diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/slew_dome.py b/python/lsst/ts/standardscripts/maintel/mtdome/slew_dome.py deleted file mode 100644 index bb4dd7a19..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/slew_dome.py +++ /dev/null @@ -1,106 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -__all__ = ["SlewDome"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class SlewDome(salobj.BaseScript): - """Slew main telescope dome to desired azimuth. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - """ - - def __init__(self, index): - super().__init__( - index=index, - descr="Slew the MTDome.", - ) - - self.mtcs = None - self.az = None - self.slew_time_guess = 180 - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtdome/slew_dome.yaml - title: SlewDome v1 - description: Configuration for SlewDome. - type: object - properties: - az: - description: Target Azimuth (in degrees) to slew the dome to. - type: number - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - required: [az] - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - self.az = config.az - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, intended_usage=MTCSUsages.Slew, log=self.log - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = self.slew_time_guess - - async def run(self): - await self.mtcs.enable() - await self.mtcs.assert_all_enabled() - self.log.info(f"Slew MT dome to Az: {self.az}.") - await self.mtcs.slew_dome_to(az=self.az) diff --git a/python/lsst/ts/standardscripts/maintel/mtdome/unpark_dome.py b/python/lsst/ts/standardscripts/maintel/mtdome/unpark_dome.py deleted file mode 100644 index 0b24edd2b..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtdome/unpark_dome.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["UnparkDome"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class UnparkDome(salobj.BaseScript): - """Unpark Dome for the MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Unpark Dome for the MTDome.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - # This script does not require any configuration - return None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - - def set_metadata(self, metadata): - metadata.duration = 5.0 - - async def run(self): - await self.mtcs.unpark_dome() diff --git a/python/lsst/ts/standardscripts/maintel/mtmount/__init__.py b/python/lsst/ts/standardscripts/maintel/mtmount/__init__.py deleted file mode 100644 index 7d4e0f359..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtmount/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .park_mount import * -from .unpark_mount import * diff --git a/python/lsst/ts/standardscripts/maintel/mtmount/park_mount.py b/python/lsst/ts/standardscripts/maintel/mtmount/park_mount.py deleted file mode 100644 index 03300847f..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtmount/park_mount.py +++ /dev/null @@ -1,109 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see .`` - -__all__ = ["ParkMount"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.xml.enums import MTMount - - -class ParkMount(salobj.BaseScript): - """Park Mount for the MTMount. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - """ - - def __init__(self, index): - super().__init__(index=index, descr="Park Mount for the MTMount.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtmount/park_mount.yaml - title: ParkMount v1 - description: Configuration for ParkMount. - type: object - properties: - position: - description: The position to park the MTMount. - type: string - enum: ["ZENITH", "HORIZON"] - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - required: [position] - """ - return yaml.safe_load(schema_yaml) - - def set_metadata(self, metadata): - pass - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - self.position = MTMount.ParkPosition[config.position] - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, - intended_usage=MTCSUsages.Slew | MTCSUsages.StateTransition, - log=self.log, - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - async def run(self): - await self.mtcs.park_mount(position=self.position) diff --git a/python/lsst/ts/standardscripts/maintel/mtmount/unpark_mount.py b/python/lsst/ts/standardscripts/maintel/mtmount/unpark_mount.py deleted file mode 100644 index e098b1c96..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtmount/unpark_mount.py +++ /dev/null @@ -1,101 +0,0 @@ -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see .`` - -__all__ = ["UnparkMount"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class UnparkMount(salobj.BaseScript): - """Un-park Mount for the MTMount. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - """ - - def __init__(self, index): - super().__init__(index=index, descr="Unpark Mount for the MTMount.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/mtmount/unpark_mount.yaml - title: UnparkMount v1 - description: Configuration for UnparkMount. - type: object - properties: - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - def set_metadata(self, metadata): - pass - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, - intended_usage=MTCSUsages.Slew | MTCSUsages.StateTransition, - log=self.log, - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - async def run(self): - await self.mtcs.unpark_mount() diff --git a/python/lsst/ts/standardscripts/maintel/mtrotator/__init__.py b/python/lsst/ts/standardscripts/maintel/mtrotator/__init__.py deleted file mode 100644 index b18a2f0b6..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtrotator/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .move_rotator import MoveRotator diff --git a/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py b/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py deleted file mode 100644 index ef200dd57..000000000 --- a/python/lsst/ts/standardscripts/maintel/mtrotator/move_rotator.py +++ /dev/null @@ -1,141 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["MoveRotator"] - -import yaml -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ...base_block_script import BaseBlockScript - - -class MoveRotator(BaseBlockScript): - """Move the rotator to a given angle. It has the option of completing the - script before the rotator reaches the desired angle. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - - "Start moving rotator to {angle} degrees.": Start moving rotator. - - "Stop script and keep rotator moving.": Stop script. - - "Rotator reached {angle} degrees.": Rotator reached angle. - - """ - - def __init__(self, index: int) -> None: - super().__init__(index=index, descr="Move Rotator") - - self.mtcs = None - - self.rotator_velocity = 3.5 # degrees per second - self.short_timeout = 10 # seconds - self.long_timeout = 120 # seconds - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_standardscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/mtrotator/move_rotator.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: MoveRotator v1 - description: Configuration for Maintel move rotator SAL Script. - type: object - properties: - angle: - description: final angle of the rotator. - type: number - minimum: -90 - maximum: 90 - wait_for_complete: - description: >- - whether wait for the rotator to reach the desired angle or - complete the script before the rotator reaches the desired - angle. - type: boolean - default: true - required: - - angle - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """ - Configure the script. - - Parameters - ---------- - config : `dict` - Dictionary containing the configuration parameters. - """ - await self.configure_tcs() - - self.target_angle = config.angle - self.wait_for_complete = config.wait_for_complete - - await super().configure(config=config) - - async def configure_tcs(self) -> None: - """ - Handle creating MTCS object and waiting for remote to start. - """ - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - def set_metadata(self, metadata): - """Set the metadata for the script.""" - metadata.duration = self.long_timeout - - async def run_block(self): - """Run the script.""" - await self.checkpoint(f"Start moving rotator to {self.target_angle} degrees.") - await self.mtcs.move_rotator( - position=self.target_angle, wait_for_in_position=self.wait_for_complete - ) - await self.checkpoint( - f"Move rotator returned. Wait for complete: {self.wait_for_complete}." - ) diff --git a/python/lsst/ts/standardscripts/maintel/offline_comcam.py b/python/lsst/ts/standardscripts/maintel/offline_comcam.py deleted file mode 100644 index 37b5aeec5..000000000 --- a/python/lsst/ts/standardscripts/maintel/offline_comcam.py +++ /dev/null @@ -1,68 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OfflineComCam"] - -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages - -from ..offline_group import OfflineGroup - - -class OfflineComCam(OfflineGroup): - """Put ComCam components in offline. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__( - index=index, descr="Put all ComCam components in offline state." - ) - - self._comcam = ComCam( - self.domain, intended_usage=ComCamUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._comcam - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return {"cccamera", "ccheaderservice", "ccoods"} diff --git a/python/lsst/ts/standardscripts/maintel/offline_mtcs.py b/python/lsst/ts/standardscripts/maintel/offline_mtcs.py deleted file mode 100644 index c1f413824..000000000 --- a/python/lsst/ts/standardscripts/maintel/offline_mtcs.py +++ /dev/null @@ -1,77 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OfflineMTCS"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..offline_group import OfflineGroup - - -class OfflineMTCS(OfflineGroup): - """Put MTCS components in offline. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Put all MTCS components in offline state.") - - self._mtcs = MTCS( - self.domain, intended_usage=MTCSUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._mtcs - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return { - "mtmount", - "mtptg", - "mtaos", - "mtm1m3", - "mtm2", - "mthexapod_1", - "mthexapod_2", - "mtrotator", - "mtdome", - "mtdometrajectory", - } diff --git a/python/lsst/ts/standardscripts/maintel/offset_camera_hexapod.py b/python/lsst/ts/standardscripts/maintel/offset_camera_hexapod.py deleted file mode 100644 index f099126d2..000000000 --- a/python/lsst/ts/standardscripts/maintel/offset_camera_hexapod.py +++ /dev/null @@ -1,220 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OffsetCameraHexapod"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class OffsetCameraHexapod(salobj.BaseScript): - """Perform a camera hexapod offset or reset operation. - - This script allows for precise control over the Camera Hexapod - by either applying user-specified offsets to its axes and/or resetting - the position of specified axes. - - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Details** - - This script can be used to either apply a user-specified offset to any of - the Camera Hexapod axes or to reset the position of the provided axes. It - can either reset the positions before applying the offsets or just apply - a reset without applying offsets. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__( - index=index, - descr="Perform a camera hexapod offset or reset the position of the provided axes.", - ) - - mtcs_usage = None if add_remotes else MTCSUsages.DryTest - - self.mtcs = MTCS(domain=self.domain, intended_usage=mtcs_usage, log=self.log) - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/offset_camera_hexapod.yaml - title: OffsetCameraHexapod v1 - description: Configuration for OffsetCameraHexapod Script. - type: object - properties: - x: - type: number - description: Offset hexapod in x axis (micron). - y: - type: number - description: Offset hexapod in y axis (micron). - z: - type: number - description: Offset hexapod in z axis (micron). - u: - type: number - description: Rx offset (deg). - v: - type: number - description: Ry offset (deg). - reset_axes: - default: false - oneOf: - - type: boolean - description: >- - If true, resets the axes provided in the offsets before applying the offsets. - If false or not provided, no reset is performed. - - type: string - enum: ["all"] - description: Reset all axes. - - type: array - items: - minItems: 1 - type: string - enum: ["x", "y", "z", "u", "v"] - description: List of axes to reset. - description: >- - Axes to reset before applying offsets. Use true to reset axes provided in offsets, - "all" to reset all axes, or a list of axes to reset specific axes. Default is false. - sync: - type: boolean - default: true - description: Synchronize hexapod movement. Default true. - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - anyOf: - - required: ["reset_axes"] - - anyOf: - - required: ["x"] - - required: ["y"] - - required: ["z"] - - required: ["u"] - - required: ["v"] - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - - Raises - ------ - ValueError - If neither non-zero offsets nor a reset operation is provided - in the configuration. - - If reset_axes is set to true, but no non-zero axis offsets - are provided to reset. - """ - - # Initialize offsets with 0.0 - self.offsets = { - axis: getattr(config, axis, 0.0) for axis in ["x", "y", "z", "u", "v"] - } - - self.sync = config.sync - - # Handle reset_axes - self.reset_axes = [] - reset_axes_config = getattr(config, "reset_axes", False) - if reset_axes_config is True: - # Reset axes provided in the offsets - self.reset_axes = [ - axis for axis, value in self.offsets.items() if value != 0.0 - ] - if not self.reset_axes: - raise ValueError( - "reset_axes is set to true, but no non-zero axis offsets are provided to reset." - ) - elif reset_axes_config == "all": - self.reset_axes = ["x", "y", "z", "u", "v"] - elif isinstance(reset_axes_config, list): - self.reset_axes = reset_axes_config - - # Validate configuration - offsets_provided = any(value != 0.0 for value in self.offsets.values()) - reset_operation = bool(self.reset_axes) - - if not offsets_provided and not reset_operation: - raise ValueError( - "Configuration must provide at least one non-zero axis offset or a reset operation." - ) - - for comp in getattr(config, "ignore", []): - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = 10 - - async def assert_feasibility(self) -> None: - """Verify that the telescope is in a feasible state to - execute the script. - """ - await self.mtcs.assert_all_enabled() - - async def run(self): - await self.assert_feasibility() - - # Perform reset operation if specified - if self.reset_axes: - reset_values = {axis: 0.0 for axis in self.reset_axes} - await self.checkpoint( - f"Resetting the following axes: {list(reset_values.keys())}" - ) - await self.mtcs.move_camera_hexapod(**reset_values, sync=self.sync) - - # Dictionary with offsets to apply - offsets_to_apply = {axis: 0.0 for axis in ["x", "y", "z", "u", "v"]} - offsets_to_apply.update( - {axis: value for axis, value in self.offsets.items() if value != 0.0} - ) - - # Check if at least one value in offsets_to_apply is not zero - if any(offsets_to_apply.values()): - await self.checkpoint( - f"Applying Camera Hexapod offsets to the following axes: {list(offsets_to_apply.keys())}." - ) - await self.mtcs.offset_camera_hexapod(**offsets_to_apply, sync=self.sync) diff --git a/python/lsst/ts/standardscripts/maintel/offset_m2_hexapod.py b/python/lsst/ts/standardscripts/maintel/offset_m2_hexapod.py deleted file mode 100755 index f64646429..000000000 --- a/python/lsst/ts/standardscripts/maintel/offset_m2_hexapod.py +++ /dev/null @@ -1,219 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OffsetM2Hexapod"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class OffsetM2Hexapod(salobj.BaseScript): - """Perform a m2 hexapod offset or reset operation.. - - This script allows for precise control over the M2 Hexapod by either - applying user-specified offsets to its axes and/or resetting the position - of specified axes. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Details** - - This script can be used to either apply a user-specified offset to any of - the M2 Hexapod axes or to reset the position of the provided axes. It - can either reset the positions before applying the offsets or just apply - a reset without applying offsets. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__( - index=index, - descr="Perform a M2 hexapod offset or reset the position of the provided axes.", - ) - - mtcs_usage = None if add_remotes else MTCSUsages.DryTest - - self.mtcs = MTCS(domain=self.domain, intended_usage=mtcs_usage, log=self.log) - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/offset_m2_hexapod.yaml - title: OffsetM2Hexapod v1 - description: Configuration for OffsetM2Hexapod Script. - type: object - properties: - x: - type: number - description: Offset hexapod in x axis (micron). - y: - type: number - description: Offset hexapod in y axis (micron). - z: - type: number - description: Offset hexapod in z axis (micron). - u: - type: number - description: Rx offset (deg). - v: - type: number - description: Ry offset (deg). - reset_axes: - default: false - oneOf: - - type: boolean - description: >- - If true, resets the axes provided in the offsets before applying the offsets. - If false or not provided, no reset is performed. - - type: string - enum: ["all"] - description: Reset all axes. - - type: array - items: - minItems: 1 - type: string - enum: ["x", "y", "z", "u", "v"] - description: List of axes to reset. - description: >- - Axes to reset before applying offsets. Use true to reset axes provided in offsets, - "all" to reset all axes, or a list of axes to reset specific axes. Default is false. - sync: - type: boolean - default: true - description: Synchronize hexapod movement. Default true. - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - anyOf: - - required: ["reset_axes"] - - anyOf: - - required: ["x"] - - required: ["y"] - - required: ["z"] - - required: ["u"] - - required: ["v"] - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - - Raises - ------ - ValueError - If neither non-zero offsets nor a reset operation is provided - in the configuration. - - If reset_axes is set to true, but no non-zero axis offsets - are provided to reset. - """ - - # Initialize offsets with 0.0 - self.offsets = { - axis: getattr(config, axis, 0.0) for axis in ["x", "y", "z", "u", "v"] - } - - self.sync = config.sync - - # Handle reset_axes - self.reset_axes = [] - reset_axes_config = getattr(config, "reset_axes", False) - if reset_axes_config is True: - # Reset axes provided in the offsets - self.reset_axes = [ - axis for axis, value in self.offsets.items() if value != 0.0 - ] - if not self.reset_axes: - raise ValueError( - "reset_axes is set to true, but no non-zero axis offsets are provided to reset." - ) - elif reset_axes_config == "all": - self.reset_axes = ["x", "y", "z", "u", "v"] - elif isinstance(reset_axes_config, list): - self.reset_axes = reset_axes_config - - # Validate configuration - offsets_provided = any(value != 0.0 for value in self.offsets.values()) - reset_operation = bool(self.reset_axes) - - if not offsets_provided and not reset_operation: - raise ValueError( - "Configuration must provide at least one non-zero axis offset or a reset operation." - ) - - for comp in getattr(config, "ignore", []): - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = 10 - - async def assert_feasibility(self) -> None: - """Verify that the telescope is in a feasible state to - execute the script. - """ - await self.mtcs.assert_all_enabled() - - async def run(self): - await self.assert_feasibility() - - # Perform reset operation if specified - if self.reset_axes: - reset_values = {axis: 0.0 for axis in self.reset_axes} - await self.checkpoint( - f"Resetting the following axes: {list(reset_values.keys())}" - ) - await self.mtcs.move_m2_hexapod(**reset_values, sync=self.sync) - - # Dictionary with offsets to apply - offsets_to_apply = {axis: 0.0 for axis in ["x", "y", "z", "u", "v"]} - offsets_to_apply.update( - {axis: value for axis, value in self.offsets.items() if value != 0.0} - ) - - # Check if at least one value in offsets_to_apply is not zero - if any(offsets_to_apply.values()): - await self.checkpoint( - f"Applying M2 Hexapod offsets to the following axes: {list(offsets_to_apply.keys())}." - ) - await self.mtcs.offset_m2_hexapod(**offsets_to_apply, sync=self.sync) diff --git a/python/lsst/ts/standardscripts/maintel/offset_mtcs.py b/python/lsst/ts/standardscripts/maintel/offset_mtcs.py deleted file mode 100644 index c2913611c..000000000 --- a/python/lsst/ts/standardscripts/maintel/offset_mtcs.py +++ /dev/null @@ -1,51 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OffsetMTCS"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..base_offset_tcs import BaseOffsetTCS - - -class OffsetMTCS(BaseOffsetTCS): - """Perform an MTCS offset. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__( - index=index, - descr="Perform an MTCS offset", - ) - - mtcs_usage = None if add_remotes else MTCSUsages.DryTest - - self.mtcs = MTCS(domain=self.domain, intended_usage=mtcs_usage, log=self.log) - self.mtcs.check.mtm1m3 = False - - @property - def tcs(self): - return self.mtcs diff --git a/python/lsst/ts/standardscripts/maintel/open_mirror_covers.py b/python/lsst/ts/standardscripts/maintel/open_mirror_covers.py deleted file mode 100644 index c863d2229..000000000 --- a/python/lsst/ts/standardscripts/maintel/open_mirror_covers.py +++ /dev/null @@ -1,101 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OpenMirrorCovers"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class OpenMirrorCovers(salobj.BaseScript): - """Run open mirror covers on MTCS. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * Opening mirror covers: before issuing open mirror covers command. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Open the MT mirror covers.") - - self.mtcs = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/open_mirror_covers.yaml - title: OpenMirrorCovers v1 - description: Configuration for OpenMirrorCovers. - type: object - properties: - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - self.config = config - if self.mtcs is None: - self.mtcs = MTCS( - domain=self.domain, intended_usage=MTCSUsages.All, log=self.log - ) - await self.mtcs.start_task - - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. Ignoring." - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - def set_metadata(self, metadata): - metadata.duration = self.mtcs.mirror_covers_timeout - - async def run(self): - await self.mtcs.assert_all_enabled() - await self.checkpoint("Opening mirror covers.") - await self.mtcs.open_m1_cover() diff --git a/python/lsst/ts/standardscripts/maintel/point_azel.py b/python/lsst/ts/standardscripts/maintel/point_azel.py deleted file mode 100644 index d721c0b5b..000000000 --- a/python/lsst/ts/standardscripts/maintel/point_azel.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["PointAzEl"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_point_azel import BasePointAzEl - - -class PointAzEl(BasePointAzEl): - """Main Telescope point_azel script. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - """ - - def __init__(self, index): - super().__init__( - index=index, - descr="Slew the main telescope to a pair of (az, el) coordinates.", - ) - - self.mtcs = None - self.slew_time_guess = 15 - - @property - def tcs(self): - return self.mtcs - - async def configure_tcs(self): - """Handle creating MTCS object and waiting for remote to start.""" - - if self.mtcs is None: - self.log.debug("Creating MTCS") - self.mtcs = MTCS(self.domain, log=self.log) - await self.mtcs.start_task - - def set_metadata(self, metadata): - metadata.duration = self.slew_time_guess diff --git a/python/lsst/ts/standardscripts/maintel/prepare_for/__init__.py b/python/lsst/ts/standardscripts/maintel/prepare_for/__init__.py deleted file mode 100644 index fee18761c..000000000 --- a/python/lsst/ts/standardscripts/maintel/prepare_for/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .align import * diff --git a/python/lsst/ts/standardscripts/maintel/prepare_for/align.py b/python/lsst/ts/standardscripts/maintel/prepare_for/align.py deleted file mode 100644 index 17608ad00..000000000 --- a/python/lsst/ts/standardscripts/maintel/prepare_for/align.py +++ /dev/null @@ -1,119 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the Vera Rubin Observatory. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["PrepareForAlign"] - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class PrepareForAlign(salobj.BaseScript): - """Run prepare for align on MTCS. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - "Positioning telescope.": Set position at which to perform alignment. - "Checking components...": Check all components have the right LUT. - "MTCS Ready for...": MTCS is ready to start alignment. - - """ - - def __init__(self, index: int, add_remotes: bool = True): - super().__init__(index=index, descr="Prepare for MTCS laser tracker alignment.") - - self.config = None - - self.mtcs = MTCS( - domain=self.domain, - intended_usage=None if add_remotes else MTCSUsages.DryTest, - log=self.log, - ) - - @classmethod - def get_schema(cls): - url = "https://github.com/lsst-ts/" - path = ( - "ts_externalscripts/blob/main/python/lsst/ts/standardscripts/" - "maintel/prepare_for/align.py" - ) - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {url}{path} - title: PrepareForAlign v1 - description: Configuration for Prepare for alignment with laser tracker. - type: object - properties: - tel_align_az: - description: telescope azimuth angle at which alignment will be performed in deg. - type: number - default: 0.0 - minimum: 0.0 - maximum: 360.0 - tel_align_el: - description: telescope elevation angle at which alignment will be performed in deg. - type: number - default: 60.0 - minimum: 16.0 - maximum: 86.0 - tel_align_rot: - description: telescope rotation angle at which alignment will be performed in deg. - type: number - default: 0.0 - minimum: 0.0 - maximum: 360.0 - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - self.tel_align_az = config.tel_align_az - self.tel_align_el = config.tel_align_el - self.tel_align_rot = config.tel_align_rot - - def set_metadata(self, metadata): - metadata.duration = 600.0 - - async def run(self): - """Run the script.""" - - await self.checkpoint("Checking components LUT.") - await self.mtcs.reset_m1m3_forces() - await self.mtcs.reset_m2_forces() - await self.mtcs.reset_camera_hexapod_position() - await self.mtcs.reset_m2_hexapod_position() - - await self.checkpoint("Positioning Telescope.") - await self.mtcs.point_azel( - az=self.tel_align_az, - el=self.tel_align_el, - rot_tel=self.tel_align_rot, - wait_dome=False, - ) - - await self.checkpoint("MTCS Ready for alignment.") diff --git a/python/lsst/ts/standardscripts/maintel/set_dof.py b/python/lsst/ts/standardscripts/maintel/set_dof.py deleted file mode 100644 index 2024bde82..000000000 --- a/python/lsst/ts/standardscripts/maintel/set_dof.py +++ /dev/null @@ -1,57 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SetDOF"] - -from .apply_dof import ApplyDOF - -STD_TIMEOUT = 30 - - -class SetDOF(ApplyDOF): - """Set absolute positions DOF to the main telescope, either bending - mode or hexapod position. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - "Setting DOF..." - The DOF absolute position is being applied. - - """ - - async def run(self) -> None: - """Run script.""" - # Assert feasibility - await self.assert_feasibility() - - await self.checkpoint("Setting DOF...") - current_dof = await self.mtcs.rem.mtaos.evt_degreeOfFreedom.aget( - timeout=STD_TIMEOUT - ) - dof_data = self.mtcs.rem.mtaos.cmd_offsetDOF.DataType() - for i, dof_absolute in enumerate(self.dofs): - dof_data.value[i] = dof_absolute - current_dof.aggregatedDoF[i] - await self.mtcs.rem.mtaos.cmd_offsetDOF.start(data=dof_data) diff --git a/python/lsst/ts/standardscripts/maintel/setup_mtcs.py b/python/lsst/ts/standardscripts/maintel/setup_mtcs.py deleted file mode 100644 index b698298a2..000000000 --- a/python/lsst/ts/standardscripts/maintel/setup_mtcs.py +++ /dev/null @@ -1,409 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SetupMTCS"] - -import pandas as pd -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class SetupMTCS(salobj.BaseScript): - """Setup MTCS components so they are ready for operation. - - The script starts with MTPtg, MTMount, and MTRotator. - Then, checks if the camera-cable-wrap (CCW) is following the Rotator. - It also checks the telemetry from these components. - - After that, it points the mount to the Zenith so we can raise M1M3 safely. - M1M3 is enabled, raised and the corrections are enabled and reset. - We do the same for M2, Camera Hexapod and Rotator Hexapod. - - Finally, it enables MTAOS, MTDomeTrajectory and MTDome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - (none) - - **Details** - - This script starts them in the following order: - - mtptg - - mtmount - - mtrotator - - mtm1m3 - - mtm2 - - mthexapod_1 (camera hexpapod) - - mthexapod_2 (m2 hexapod) - - all the other components (mtaos / mtdome / mtdometrajectory) - - """ - - def __init__(self, index=1, remotes: bool = True): - super().__init__( - index=index, - descr="Setup MTCS components for operations.", - ) - self.activity_estimated_duration = dict( - enable_components=dict(time=5.0, repeats=8), # Enable components - move_to_zenith=dict(time=10.0, repeats=1), # Move mount to zenith - raise_m1m3=dict(time=600.0, repeats=1), # Raise m1m3 - enable_corrections=dict(time=5.0, repeats=4), # Enable/reset corrections - get_telemetry=dict(time=5.0, repeats=6), # Timeout extracting telemetries - ) - - self.config = None - self.mtcs = ( - MTCS(domain=self.domain, log=self.log) - if remotes - else MTCS( - domain=self.domain, log=self.log, intended_usage=MTCSUsages.DryTest - ) - ) - - self.checkpoints_activities = [ - ("Check that MTCS Components have heartbeats", self.mtcs.assert_liveliness), - ("Start MTPtg", self.start_mtptg), - ("Prepare MTMount and MTRotator", self.prepare_mtmount_and_mtrotator), - ("Start MTMount", self.start_mtmount), - ("Start MTRotator", self.start_mtrotator), - ("Check Rotator and CCW", self.check_rotator_and_ccw), - ("Start MTM1M3", self.start_mtm1m3), - ("Start MTM2", self.start_mtm2), - ("Start Camera Hexapod", self.start_camera_hexapod), - ("Start M2 Hexapod", self.start_m2_hexapod), - ("Enable remaining components", self.mtcs.enable), - ] - - @classmethod - def get_schema(cls): - id_url = ( - "https://github.com/lsst-ts/ts_stardardscripts/blob/master/" - "python/lsst/ts/externalscripts/maintel/setup_mtcs.py" - ) - - schema = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: {id_url} - title: SetupMTCS v1 - description: Configuration for SetupMTCS SAL Script. - type: object - additionalProperties: false - properties: - ccw_following: - description: >- - enable ccw following mode? (default: True) - type: boolean - default: true - overrides: - description: Overrides configurations for different components. - type: object - additionalProperties: false - properties: - mtptg: - description: Override configuration for MTPtg. - anyOf: - - type: string - - type: "null" - default: null - mtmount: - description: Override configuration for MTMount. - anyOf: - - type: string - - type: "null" - default: null - mtrotator: - description: Override configuration for MTRotator. - anyOf: - - type: string - - type: "null" - default: null - mtm1m3: - description: Override configuration for MTM1M3. - anyOf: - - type: string - - type: "null" - default: Default - mtm2: - description: Override configuration for MTM2. - anyOf: - - type: string - - type: "null" - default: null - mthexapod_1: - description: Override configuration for Camera Hexapod. - anyOf: - - type: string - - type: "null" - default: null - mthexapod_2: - description: Override configuration for M2 Hexapod. - anyOf: - - type: string - - type: "null" - default: null - """ - return yaml.safe_load(schema) - - async def configure(self, config): - """Handle script input configuration. - - Parameters - ---------- - config: `types.SimpleNamespace` - Configuration data. See `get_schema` for information about data - structure. - """ - self.log.debug(f"Enable CCW following: {config.ccw_following}") - self.config = config - - def set_metadata(self, metadata): - """Set estimated duration of the script.""" - metadata.duration = sum( - [ - self.activity_estimated_duration[action]["time"] - * self.activity_estimated_duration[action]["repeats"] - for action in self.activity_estimated_duration - ] - ) - - async def run(self): - """Runs the script""" - for checkpoint, activity in self.checkpoints_activities: - await self.checkpoint(checkpoint) - await activity() - - await self.checkpoint("Done") - - async def start_mtptg(self): - """Starts mtptg""" - self.log.info("Start mtptg") - await self.mtcs.set_state( - salobj.State.ENABLED, - components=["mtptg"], - overrides=dict(mtptg=self.config.overrides["mtptg"]), - ) - - async def prepare_mtmount_and_mtrotator(self): - """Put both mtmount and mtrotator in DISABLED state. This is required - before enabling them because they share telemetry.""" - self.log.info("Putting mtmount to DISABLED state") - await self.mtcs.set_state( - salobj.State.DISABLED, - components=["mtmount"], - overrides=dict(mtmount=self.config.overrides["mtmount"]), - ) - self.log.info("Putting mtrotator to DISABLED state") - await self.mtcs.set_state( - salobj.State.DISABLED, - components=["mtrotator"], - overrides=dict(mtmount=self.config.overrides["mtmount"]), - ) - - async def start_mtmount(self): - """Starts mtmount""" - self.log.info("Start mtmount") - await self.mtcs.set_state( - salobj.State.ENABLED, - components=["mtmount"], - overrides=dict(mtmount=self.config.overrides["mtmount"]), - ) - # TODO: DM-36932 - self.log.info("Home mtmount") - await self.mtcs.rem.mtmount.cmd_homeBothAxes.start(timeout=300) - - async def start_mtrotator(self): - """Start mtrotator""" - self.log.info("Start mtrotator") - await self.mtcs.set_state( - salobj.State.ENABLED, - components=["mtrotator"], - overrides=dict(mtmount=self.config.overrides["mtrotator"]), - ) - - state = await self.mtcs.get_state("mtrotator") - self.log.info(f" mtrotator is now in {state.name}") - - async def check_rotator_and_ccw(self): - """Check the telemetry from the Rotator and the Camera-Cable-Wrap to - make sure that they can be operated together.""" - timeout = self.activity_estimated_duration["get_telemetry"]["time"] - - elevation = await self.mtcs.rem.mtmount.tel_elevation.next( - flush=True, timeout=timeout - ) - azimuth = await self.mtcs.rem.mtmount.tel_azimuth.next( - flush=True, timeout=timeout - ) - ccw = await self.mtcs.rem.mtmount.tel_cameraCableWrap.next( - flush=True, timeout=timeout - ) - rotator = await self.mtcs.rem.mtrotator.tel_rotation.next( - flush=True, timeout=timeout - ) - - self.log.info( - f"mount elevation Angle = {elevation.actualPosition} \n" - f"mount azimuth angle = {azimuth.actualPosition}\n" - f"CCW angle = {ccw.actualPosition}.\n" - f"rot angle = {rotator.actualPosition}\n" - f"diff = {rotator.actualPosition - ccw.actualPosition}\n" - ) - - ccw_following = await self.mtcs.rem.mtmount.evt_cameraCableWrapFollowing.aget( - timeout=timeout - ) - - timestamp = pd.to_datetime(ccw_following.private_sndStamp, unit="s") - - # We actually want CCW following - if self.config.ccw_following: - # If as expected - if ccw_following.enabled: - self.log.info( - f"CCW following mode enabled: " - f"{ccw_following.enabled} @ {timestamp}." - ) - - # Otherwise - else: - await self.mtcs.set_state(salobj.State.DISABLED, components=["mtmount"]) - raise RuntimeError( - "CCW following mode not enabled. " - "Usually this means that the MTMount could not see" - " telemetry from the rotator when it was enabled. " - "To correct this condition make sure the MTRotator telemetry" - " is being published, then execute the procedure again. " - "MTMount CSC will be left in DISABLED state." - ) - - # We decided *not* to use CCW following - else: - await self.mtcs.disable_ccw_following() - - ccw = await self.mtcs.rem.mtmount.tel_cameraCableWrap.next( - flush=True, timeout=timeout - ) - - rotator = await self.mtcs.rem.mtrotator.tel_rotation.next( - flush=True, timeout=timeout - ) - - ccw_snd_stamp = pd.to_datetime(ccw.private_sndStamp, unit="s") - ccw_timestamp = pd.to_datetime(ccw.timestamp, unit="s") - ccw_actual_position = ccw.actualPosition - - rotator_snd_stamp = pd.to_datetime(rotator.private_sndStamp, unit="s") - rotator_timestamp = pd.to_datetime(rotator.timestamp, unit="s") - rotator_actual_position = rotator.actualPosition - - self.log.info( - f"CCW:: snd_stamp={ccw_snd_stamp} " - f"timestamp={ccw_timestamp} " - f"actual position={ccw_actual_position}" - ) - - self.log.info( - f"Rotator:: snd_stamp={rotator_snd_stamp} " - f"timestamp={rotator_timestamp} " - f"actual position={rotator_actual_position}" - ) - - ccw_telemetry_maximum_age = pd.to_timedelta(1.0, unit="s") - - if abs(ccw_snd_stamp - ccw_timestamp) > ccw_telemetry_maximum_age: - self.log.warning( - f"CCW timestamp out of sync by " - f"{abs(ccw_snd_stamp - ccw_timestamp)}s. " - f"System may not work. Check clock synchronization in MTMount " - f"low level controller." - ) - - async def start_mtm1m3(self): - """Start mtm1m3""" - self.log.info("Starting M1M3") - self.log.info("Moving telescope to zenith to safely raise the mirror.") - await self.mtcs.rem.mtmount.cmd_moveToTarget.set_start(azimuth=0, elevation=90) - - await self.mtcs.set_state( - state=salobj.State.ENABLED, - components=["mtm1m3"], - overrides=dict(mtm1m3="Default"), - ) - - self.log.info("Raising M1M3") - await self.mtcs.raise_m1m3() - - self.log.info("M1M3 - Enable and reset balance forces") - await self.mtcs.enable_m1m3_balance_system() - await self.mtcs.reset_m1m3_forces() - - async def start_mtm2(self): - """Start MTM2""" - await self.mtcs.set_state( - state=salobj.State.ENABLED, - components=["mtm2"], - overrides=dict(mtm2=self.config.overrides["mtm2"]), - ) - await self.mtcs.enable_m2_balance_system() - await self.mtcs.reset_m2_forces() - - async def start_mthexapod(self, index): - """Start MTHexapod for the Camera or for M2 - - Parameters - ---------- - index : int, {1, 2} - Index associated to the hexapod CSC. - 1 = camera hexapod - 2 = m2 hexapod - """ - assert index in [1, 2] - component = f"mthexapod_{index}" - - await self.mtcs.set_state( - state=salobj.State.ENABLED, - components=[component], - overrides={component: self.config.overrides[component]}, - ) - - await self.mtcs.enable_compensation_mode(component=component) - - if index == 1: - await self.mtcs.reset_camera_hexapod_position() - else: - await self.mtcs.reset_m2_hexapod_position() - - async def start_camera_hexapod(self): - """Starts the Camera Hexapod""" - await self.start_mthexapod(index=1) - - async def start_m2_hexapod(self): - """Starts the M2 Hexapod""" - await self.start_mthexapod(index=2) diff --git a/python/lsst/ts/standardscripts/maintel/standby_comcam.py b/python/lsst/ts/standardscripts/maintel/standby_comcam.py deleted file mode 100644 index 2dd4e8cee..000000000 --- a/python/lsst/ts/standardscripts/maintel/standby_comcam.py +++ /dev/null @@ -1,68 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["StandbyComCam"] - -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages - -from ..standby_group import StandbyGroup - - -class StandbyComCam(StandbyGroup): - """Put ComCam components in standby. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__( - index=index, descr="Put all ComCam components in standby state." - ) - - self._comcam = ComCam( - self.domain, intended_usage=ComCamUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._comcam - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return set(["cccamera", "ccheaderservice", "ccoods"]) diff --git a/python/lsst/ts/standardscripts/maintel/standby_mtcs.py b/python/lsst/ts/standardscripts/maintel/standby_mtcs.py deleted file mode 100644 index 647fe88aa..000000000 --- a/python/lsst/ts/standardscripts/maintel/standby_mtcs.py +++ /dev/null @@ -1,79 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["StandbyMTCS"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..standby_group import StandbyGroup - - -class StandbyMTCS(StandbyGroup): - """Put MTCS components in standby. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Put all MTCS components in standby state.") - - self._mtcs = MTCS( - self.domain, intended_usage=MTCSUsages.StateTransition, log=self.log - ) - - @property - def group(self): - return self._mtcs - - @staticmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - return set( - [ - "mtmount", - "mtptg", - "mtaos", - "mtm1m3", - "mtm2", - "mthexapod_1", - "mthexapod_2", - "mtrotator", - "mtdome", - "mtdometrajectory", - ] - ) diff --git a/python/lsst/ts/standardscripts/maintel/stop.py b/python/lsst/ts/standardscripts/maintel/stop.py deleted file mode 100644 index 219b125ab..000000000 --- a/python/lsst/ts/standardscripts/maintel/stop.py +++ /dev/null @@ -1,66 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Stop"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - - -class Stop(salobj.BaseScript): - """Stop telescope and dome. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - TBD - - **Details** - - TBD - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Enable MTCS.") - - self.config = None - - self.mttcs = MTCS(self.domain, intended_usage=MTCSUsages.Shutdown, log=self.log) - - @classmethod - def get_schema(cls): - return None - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - metadata.duration = 60.0 - - async def run(self): - await self.mttcs.stop_all() diff --git a/python/lsst/ts/standardscripts/maintel/stop_rotator.py b/python/lsst/ts/standardscripts/maintel/stop_rotator.py deleted file mode 100644 index f36e421ff..000000000 --- a/python/lsst/ts/standardscripts/maintel/stop_rotator.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["StopRotator"] - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS - - -class StopRotator(salobj.BaseScript): - """A script that executes stop_rotator method for `MTCS` - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - Stopping rotator: Before issuing stop command. - Done: After issuing stop command. - """ - - def __init__(self, index): - super().__init__(index=index, descr="MTCS stop rotator.") - self.mtcs = None - - @classmethod - def get_schema(cls): - return None - - async def configure(self, config): - if self.mtcs is None: - self.mtcs = MTCS(domain=self.domain, log=self.log) - - def set_metadata(self, metadata): - metadata.duration = self.mtcs.tel_settle_time - - async def run(self): - await self.checkpoint("Stopping rotator...") - await self.mtcs.stop_rotator() - await self.checkpoint("Done") diff --git a/python/lsst/ts/standardscripts/maintel/stop_tracking.py b/python/lsst/ts/standardscripts/maintel/stop_tracking.py deleted file mode 100644 index ba9c20d32..000000000 --- a/python/lsst/ts/standardscripts/maintel/stop_tracking.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["StopTracking"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..base_stop_tracking import BaseStopTracking - - -class StopTracking(BaseStopTracking): - """Stop telescope and dome tracking. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - """ - - def __init__(self, index): - super().__init__(index=index, descr="MTCS stop tracking.") - - self._mtcs = MTCS(self.domain, intended_usage=MTCSUsages.Slew, log=self.log) - - @property - def tcs(self): - return self._mtcs diff --git a/python/lsst/ts/standardscripts/maintel/take_aos_sequence_comcam.py b/python/lsst/ts/standardscripts/maintel/take_aos_sequence_comcam.py deleted file mode 100644 index aa26a98fb..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_aos_sequence_comcam.py +++ /dev/null @@ -1,373 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeAOSSequenceComCam", "Mode"] - -import asyncio -import enum -import json -import types - -import yaml -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.comcam import ComCam -from lsst.ts.observatory.control.maintel.mtcs import MTCS - -from ..base_block_script import BaseBlockScript - - -class Mode(enum.IntEnum): - TRIPLET = enum.auto() - INTRA = enum.auto() - EXTRA = enum.auto() - PAIR = enum.auto() - - -class TakeAOSSequenceComCam(BaseBlockScript): - """Take aos sequence, either triplet (intra-focal, extra-focal - and in-focus images), intra doublets (intra and in-focus) or extra - doublets (extra and in-focus) sequences with ComCam. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * sequence {n} of {m}: before taking a sequence. - - """ - - def __init__(self, index, descr="Take AOS sequence with ComCam.") -> None: - super().__init__(index=index, descr=descr) - - self.config = None - self.mtcs = None - self.camera = None - self.ocps = None - self.current_z_position = 0 - self.n_images = 9 - - @classmethod - def get_schema(cls) -> dict: - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/TakeAOSSequenceComCam.yaml - title: TakeAOSSequenceComCam v1 - description: Configuration for TakeAOSSequenceComCam. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - exposure_time: - description: The exposure time to use when taking images (sec). - type: number - default: 30. - dz: - description: De-focus to apply when acquiring the intra/extra focal images (microns). - type: number - default: 1500. - n_sequences: - description: Number of aos sequences. - type: integer - default: 1 - mode: - description: >- - Mode of operation. Options are 'triplet' (default), 'intra' or 'extra'. - type: string - default: TRIPLET - enum: {[mode.name for mode in Mode]} - program: - description: >- - Optional name of the program this dataset belongs to. - type: string - default: AOSSEQUENCE - reason: - description: Optional reason for taking the data. - anyOf: - - type: string - - type: "null" - default: null - note: - description: A descriptive note about the image being taken. - anyOf: - - type: string - - type: "null" - default: null - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Script configuration, as defined by `schema`. - """ - # Configure tcs and camera - await self.configure_tcs() - await self.configure_camera() - - if hasattr(config, "ignore"): - for comp in config.ignore: - if comp in self.mtcs.components_attr: - self.log.debug(f"Ignoring MTCS component {comp}.") - setattr(self.mtcs.check, comp, False) - elif comp in self.camera.components_attr: - self.log.debug(f"Ignoring Camera component {comp}.") - setattr(self.camera.check, comp, False) - else: - self.log.warning( - f"Component {comp} not in CSC Groups. " - f"Must be one of {self.mtcs.components_attr} or " - f"{self.camera.components_attr}. Ignoring." - ) - - # Set filter - self.filter = config.filter - - # Set exposure time - self.exposure_time = config.exposure_time - - # Set intra/extra focal offsets - self.dz = config.dz - - # Set maximum number of iterations - self.n_sequences = config.n_sequences - - self.mode = getattr(Mode, config.mode) - - # Set program, reason and note - self.program = config.program - self.reason = config.reason - self.note = config.note - - def set_metadata(self, metadata: salobj.type_hints.BaseMsgType) -> None: - """Sets script metadata. - - Parameters - ---------- - metadata : `salobj.type_hints.BaseMsgType` - Script metadata topic. The information is set on the topic - directly. - """ - # Estimated duration is maximum number of iterations multiplied by - # 3 or 2 multiplied by the time it takes to take an image - # plus estimation on reading out the images (10s) - number_of_images = 3 if self.mode == Mode.TRIPLET else 2 - - metadata.duration = ( - self.n_sequences - * number_of_images - * ( - self.exposure_time - + self.camera.read_out_time - + self.camera.shutter_time - ) - ) - metadata.filter = f"{self.filter}" - - async def assert_feasibility(self) -> None: - """Verify that the telescope and camera are in a feasible state to - execute the script. - """ - await asyncio.gather( - self.mtcs.assert_all_enabled(), self.camera.assert_all_enabled() - ) - - async def configure_camera(self) -> None: - """Handle creating ComCam object and waiting for remote to start.""" - if self.camera is None: - self.log.debug("Creating Camera.") - - self.camera = ComCam( - self.domain, - log=self.log, - tcs_ready_to_take_data=self.mtcs.ready_to_take_data, - ) - await self.camera.start_task - else: - self.log.debug("Camera already defined, skipping.") - - if self.ocps is None: - self.log.debug("Create OCPS remote.") - - self.ocps = salobj.Remote(self.domain, "OCPS", 101) - - await self.ocps.start_task - - async def configure_tcs(self) -> None: - """Handle creating MTCS object and waiting for remote to start.""" - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - ) - await self.mtcs.start_task - else: - self.log.debug("MTCS already defined, skipping.") - - async def take_aos_sequence(self) -> None: - """Take out-of-focus sequence images.""" - supplemented_group_id = self.next_supplemented_group_id() - - if ( - self.mode == Mode.TRIPLET - or self.mode == Mode.INTRA - or self.mode == Mode.PAIR - ): - self.log.debug("Moving to intra-focal position") - - # Move the hexapod to the target z position - z_offset = -self.dz - self.current_z_position - await self.mtcs.offset_camera_hexapod(x=0, y=0, z=z_offset, u=0, v=0) - self.current_z_position = -self.dz - - self.log.info("Taking in-focus image") - self.camera.rem.ccoods.evt_imageInOODS.flush() - intra_visit_id = await self.camera.take_cwfs( - exptime=self.exposure_time, - n=1, - group_id=supplemented_group_id, - filter=self.filter, - reason="INTRA" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - note=self.note, - ) - - if ( - self.mode == Mode.TRIPLET - or self.mode == Mode.EXTRA - or self.mode == Mode.PAIR - ): - self.log.debug("Moving to extra-focal position") - - # Move the hexapod to the target z position - z_offset = self.dz - self.current_z_position - await self.mtcs.offset_camera_hexapod(x=0, y=0, z=z_offset, u=0, v=0) - self.current_z_position = self.dz - - self.log.info("Taking extra-focal image") - - self.camera.rem.ccoods.evt_imageInOODS.flush() - extra_visit_id = await self.camera.take_cwfs( - exptime=self.exposure_time, - n=1, - group_id=supplemented_group_id, - filter=self.filter, - reason="EXTRA" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - note=self.note, - ) - - if self.mode == Mode.TRIPLET or self.mode == Mode.PAIR: - self.log.debug("Waiting for images to be ingested in OODS.") - extra_image_ingested = False - while not extra_image_ingested: - try: - image_in_oods = await self.camera.rem.ccoods.evt_imageInOODS.next( - flush=False, timeout=self.exposure_time - ) - try: - image_name_split = image_in_oods.obsid.split("_") - image_index = int( - f"{image_name_split[-2]}{image_name_split[-1][1:]}" - ) - extra_image_ingested = image_index == extra_visit_id[0] - except Exception: - self.log.exception( - "Failed to parse image name into index for {image_in_oods.obsid}." - ) - - self.log.info( - f"Image {image_in_oods.obsid} {image_in_oods.raft} {image_in_oods.sensor} ingested." - ) - - except asyncio.TimeoutError: - self.log.warning( - "Timeout waiting for images to ingest. Continuing." - ) - break - self.log.info("Send processing request to RA OCPS.") - config = { - "LSSTComCam-FROM-OCS_DONUTPAIR": f"{intra_visit_id[0]},{extra_visit_id[0]}" - } - ocps_execute_task = asyncio.create_task( - self.ocps.cmd_execute.set_start( - config=json.dumps(config), - timeout=self.camera.fast_timeout, - ) - ) - - self.log.debug("Moving to in-focus position") - - # Move the hexapod to the target z position - z_offset = -self.current_z_position - await self.mtcs.offset_camera_hexapod(x=0, y=0, z=z_offset, u=0, v=0) - self.current_z_position = 0 - - if self.mode != Mode.PAIR: - self.log.info("Taking in-focus image") - self.camera.rem.ccoods.evt_imageInOODS.flush() - await self.camera.take_acq( - exptime=self.exposure_time, - n=1, - group_id=self.group_id, - filter=self.filter, - reason="INFOCUS" + ("" if self.reason is None else f"_{self.reason}"), - program=self.program, - note=self.note, - ) - - if self.mode == Mode.TRIPLET: - try: - await ocps_execute_task - except Exception: - self.log.exception("Executing OCPS task failed. Ignoring.") - - async def run_block(self) -> None: - """Execute script operations.""" - await self.assert_feasibility() - - for i in range(self.n_sequences): - self.log.info(f"Starting aos sequence {i+1} of {self.n_sequences}") - await self.checkpoint(f"out-of-focus sequence {i+1} of {self.n_sequences}") - - await self.take_aos_sequence() diff --git a/python/lsst/ts/standardscripts/maintel/take_image_anycam.py b/python/lsst/ts/standardscripts/maintel/take_image_anycam.py deleted file mode 100644 index f616485ca..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_image_anycam.py +++ /dev/null @@ -1,507 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeImageAnyCam", "CameraSetup"] - -import asyncio - -import yaml -from lsst.ts.observatory.control.generic_camera import GenericCamera -from lsst.ts.observatory.control.maintel import MTCS -from lsst.ts.observatory.control.maintel.comcam import ComCam -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam -from lsst.ts.salobj import type_hints - -from ..base_block_script import BaseBlockScript - - -class CameraSetup: - """ - Encapsulates camera object, its configuration, - and a unique identifier. - """ - - def __init__(self, camera, config, identifier, normalize=True): - self.camera = camera - self.identifier = identifier - if normalize: - self.config = self.normalize_config(config) - else: - self.config = config - - @staticmethod - def normalize_config(config): - """Normalize the camera configuration for consistent processing.""" - - # If 'nimages' is provided along with 'exp_times' as a list, - # raise an error. - if isinstance(config.get("exp_times"), list) and "nimages" in config: - raise ValueError("If 'nimages' is provided, 'exp_times' must be a scalar.") - - # If 'exp_times' is a scalar (including 0 or positive values) and - # 'nimages' is specified, expand 'exp_times' into a list with 'nimages' - # repetitions. - elif not isinstance(config.get("exp_times"), list) and "nimages" in config: - nimages = config["nimages"] - exp_times = config.get("exp_times", 0) # Default to 0 if not provided - config["exp_times"] = [exp_times] * nimages - - # If 'exp_times' is a scalar and 'nimages' is not provided, - # transform 'exp_times' into a list with a single element. - elif not isinstance(config.get("exp_times"), list): - exp_times = config.get("exp_times", 0) # Default to 0 if not provided - config["exp_times"] = [exp_times] - - return config - - -class TakeImageAnyCam(BaseBlockScript): - """ - A script for taking images concurrently with ComCam, - LSSTCam, and/or one or more Generic Cameras. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * Setup instrument: before sending the ``setup_instrument`` command - for each configure camera. - - * Total expected duration: {x}s for {longest_camera_duration} taking - {total_exposures} images: before starting exposures. - - * Exposing image {i} of {n} with exp_time={exp_time}s for {camera}: before - each exposure for the longest duration camera." - - """ - - def __init__(self, index: int) -> None: - super().__init__( - index, - descr="Concurrently take images with either ComCam or LSSTCam, " - "and Generic Cameras.", - ) - - self.mtcs = None - self.camera_setups = {} - - self.camera_longest = None - self.camera_longest_duration = 0.0 - self.instrument_setup_time = 0.0 - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/take_image_anycam.yaml - title: TakeImageAnyCam - description: Configuration schema for TakeImageAnyCam. - type: object - properties: - comcam: - description: Configuration for ComCam. - type: object - properties: - exp_times: - description: A list of exposure time of each image (sec). - oneOf: - - type: number - minimum: 0 - - type: array - items: - type: number - minimum: 0 - minItems: 1 - nimages: - description: Optional number of images to take. If given, exp_times must be a scalar. - If given and exp_times is a list, it raises an error. - anyOf: - - type: integer - minimum: 1 - - type: "null" - image_type: - description: Image type (a.k.a. IMGTYPE) (e.g. e.g. BIAS, DARK, FLAT, OBJECT) - type: string - enum: ["BIAS", "DARK", "FLAT", "OBJECT", "ENGTEST", "ACQ", "CWFS", "FOCUS", "STUTTERED"] - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - required: - - exp_times - - image_type - lsstcam: - description: Configuration for ComCam. - type: object - properties: - exp_times: - description: A list of exposure time of each image (sec). - oneOf: - - type: number - minimum: 0 - - type: array - items: - type: number - minimum: 0 - minItems: 1 - nimages: - description: Optional number of images to take. If given, exp_times must be a scalar. - If given and exp_times is a list, it raises an error. - anyOf: - - type: integer - minimum: 1 - - type: "null" - image_type: - description: Image type (a.k.a. IMGTYPE) (e.g. e.g. BIAS, DARK, FLAT, OBJECT) - type: string - enum: ["BIAS", "DARK", "FLAT", "OBJECT", "ENGTEST", "ACQ", "CWFS", "FOCUS", "STUTTERED"] - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - required: - - exp_times - - image_type - gencam: - description: Configuration for generic cameras. - type: array - items: - description: Configuration for each generic camera. - type: object - properties: - index: - description: Index of the Generic Camera SAL component. - type: integer - enum: [101, 102, 103] - exp_times: - description: A list of exposure time of each image (sec). - oneOf: - - type: number - minimum: 0 - - type: array - items: - type: number - minimum: 0 - minItems: 1 - nimages: - description: Optional number of images to take. If given, exp_times must be a scalar. - If given and exp_times is a list, it raises an error. - anyOf: - - type: integer - minimum: 1 - - type: "null" - image_type: - description: Image type (a.k.a. IMGTYPE) (e.g. e.g. BIAS, DARK, FLAT, OBJECT) - type: string - enum: ["BIAS", "DARK", "FLAT", "OBJECT", "ENGTEST", "ACQ", "CWFS", "FOCUS", "STUTTERED"] - required: - - index - - exp_times - - image_type - ignore: - description: >- - CSCs from the group to ignore in status check. Name must - match those in self.group.components, e.g.; hexapod_1. - type: array - items: - type: string - reason: - description: Optional reason for taking the data (e.g. SITCOM-321). - type: string - program: - description: Name of the program this data belongs to. Program name - requires a dash separaing program from id number (e.g. BLOCK-123). - type: string - note: - description: A descriptive note about the image being taken. - type: string - additionalProperties: false - required: [] - anyOf: - - required: ["gencam"] - - required: ["comcam"] - - required: ["lsstcam"] - - required: ["comcam", "gencam"] - - required: ["lsstcam", "gencam"] - """ - - schema_dict = yaml.safe_load(schema_yaml) - - # ComCam and LTTScam are mutually exclusive - if "comcam" in schema_dict and "filter" not in schema_dict["comcam"]: - schema_dict["comcam"]["filter"] = None - - if "lsstcam" in schema_dict and "filter" not in schema_dict["lsstcam"]: - schema_dict["lsstcam"]["filter"] = None - - base_schema_dict = super().get_schema() - - for properties in base_schema_dict["properties"]: - schema_dict["properties"][properties] = base_schema_dict["properties"][ - properties - ] - - return schema_dict - - async def configure(self, config): - """Configure the script based on the provided configuration. - - This method initializes the MTCS and any cameras specified in the - configuration (`config`). It supports initializing ComCam, LSSTCam, - and the Generic Cameras. - - Raises - ------ - ValueError - If `nimages` is provided and `exp_times` is not a scalar. - """ - - self.config = config - - # Check that program configuration has a dash - if hasattr(config, "program") and "-" not in config.program: - raise ValueError( - "Program name requires a dash separating program from id number " - "(e.g. BLOCK-123)." - ) - - # Initialize MTCS if not already done - if self.mtcs is None: - self.log.debug("Creating MTCS.") - self.mtcs = MTCS(domain=self.domain, log=self.log) - if hasattr(self.config, "ignore"): - self.ignore_components(config) - await self.mtcs.start_task - else: - # Ignoring components if already defined (for unit test) - if hasattr(self.config, "ignore"): - self.ignore_components(config) - self.log.debug("MTCS already defined, skipping.") - - # Initialize cameras and set configuration - await self.configure_cameras(config) - - await super().configure(config=config) - - def ignore_components(self, config): - - for comp in self.config.ignore: - if comp not in self.mtcs.components_attr: - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.mtcs.components_attr}. " - ) - else: - self.log.debug(f"Ignoring component {comp}.") - setattr(self.mtcs.check, comp, False) - - async def configure_cameras(self, config): - """Configure all cameras based on the script configuration, - with asynchronous setup for generic cameras.""" - tasks = [] - if hasattr(config, "lsstcam"): - tasks.append( - self.configure_camera( - CameraClass=LSSTCam, - cam_key="lsstcam", - cam_config=config.lsstcam, - cam_identifier="LSSTCam", - ) - ) - if hasattr(config, "comcam"): - tasks.append( - self.configure_camera( - CameraClass=ComCam, - cam_key="comcam", - cam_config=config.comcam, - cam_identifier="ComCam", - ) - ) - if hasattr(config, "gencam"): - for gencam_config in config.gencam: - gencam_key = f"generic_camera_{gencam_config['index']}" - gen_cam_identifier = f"GenericCam_{gencam_config['index']}" - tasks.append( - self.configure_camera( - CameraClass=GenericCamera, - cam_key=gencam_key, - cam_config=gencam_config, - cam_identifier=gen_cam_identifier, - is_generic=True, - ) - ) - await asyncio.gather(*tasks) - - async def configure_camera( - self, CameraClass, cam_key, cam_config, cam_identifier, is_generic=False - ): - """Configure a specific camera.""" - - if cam_key not in self.camera_setups: - camera = ( - CameraClass(domain=self.domain, log=self.log) - if not is_generic - else CameraClass(cam_config["index"], domain=self.domain, log=self.log) - ) - await camera.start_task - # Setting up the camera. - self.camera_setups[cam_key] = CameraSetup( - camera, cam_config, cam_identifier - ) - else: - # upating the camera configuration if already defined. - self.camera_setups[cam_key].config = CameraSetup.normalize_config( - cam_config - ) - - def set_metadata(self, metadata: type_hints.BaseMsgType) -> None: - """Set script metadata.""" - if not self.camera_setups: # Ensure we have camera setups - metadata.duration = 0 - return - - camera_durations = {} - for camera_setup in self.camera_setups.values(): - if camera_setup.config: - self.log.info( - f"{camera_setup.identifier} configuration: {camera_setup.config}" - ) - exp_times = camera_setup.config["exp_times"] - nimages = len(exp_times) - total_exptime = sum(exp_times) - read_out_time = getattr(camera_setup.camera, "read_out_time", 0) - shutter_time = getattr(camera_setup.camera, "shutter_time", 0) - - duration = ( - self.instrument_setup_time - + total_exptime - + (read_out_time + shutter_time * 2) * nimages - ) - camera_durations[camera_setup.identifier] = duration - self.log.info( - f"{camera_setup.identifier} will take {nimages} images. Total duration: {duration}." - ) - - if camera_durations: - self.camera_longest, self.camera_longest_duration = max( - camera_durations.items(), key=lambda item: item[1] - ) - else: - self.camera_longest, self.camera_longest_duration = None, 0 - - metadata.duration = self.camera_longest_duration - - def get_instrument_configuration(self, camera_config: dict) -> dict: - # Ensure the return value is always a dictionary - instrument_config = {} - if "filter" in camera_config: - instrument_config["filter"] = camera_config["filter"] - return instrument_config - - async def assert_feasibility(self): - """Verify that the system and all configured cameras are in - a feasible state to execute the script.""" - checks = [self.mtcs.assert_liveliness()] - for camera_setup in self.camera_setups.values(): - if hasattr(camera_setup.camera, "assert_all_enabled"): - checks.append(camera_setup.camera.assert_all_enabled()) - if hasattr(camera_setup.camera, "assert_liveliness"): - checks.append(camera_setup.camera.assert_liveliness()) - await asyncio.gather(*checks) - - async def take_images_with_camera(self, camera_setup: CameraSetup): - """ - Commands a specified camera to take images according to - its configuration. - - Parameters - ---------- - camera_config : CameraSetup - An object containing the camera instance, its configuration, - and a unique identifier. - """ - - if len(camera_setup.config) != 0: - exp_times = camera_setup.config["exp_times"] - image_type = camera_setup.config["image_type"] - note = getattr(self.config, "note", None) - reason = getattr(self.config, "reason", None) - program = getattr(self.config, "program", None) - - # Assert feasibility before taking images with the camera - await self.assert_feasibility() - - instrument_config = self.get_instrument_configuration(camera_setup.config) - if hasattr(camera_setup.camera, "setup_instrument"): - await self.checkpoint( - f"Setup instrument for {camera_setup.identifier}." - ) - await camera_setup.camera.setup_instrument(**instrument_config) - - for i, exp_time in enumerate(exp_times): - if camera_setup.identifier == self.camera_longest: - await self.checkpoint( - f"Exposing image {i+1} of {len(exp_times)} with " - f"exp_time={exp_time}s for {camera_setup.identifier}." - ) - await camera_setup.camera.take_imgtype( - imgtype=image_type, - exptime=exp_time, - n=1, - program=program, - reason=reason, - note=note, - group_id=self.group_id, - ) - - async def run_block(self): - """ - Executes the image capture tasks concurrently for all - configured cameras. - """ - tasks = [] - - longest_camera_setup = self.camera_setups.get(self.camera_longest, None) - - if longest_camera_setup: - total_exposures = len(longest_camera_setup.config["exp_times"]) - self.checkpoint( - f"Total expected duration: {self.camera_longest_duration:.2f} s " - f"for {self.camera_longest} taking {total_exposures} images." - ) - - # Prepare tasks for each configured camera - for camera_setup in self.camera_setups.values(): - tasks.append(self.take_images_with_camera(camera_setup)) - - # Execute all image capture tasks simultaneously - await asyncio.gather(*tasks) diff --git a/python/lsst/ts/standardscripts/maintel/take_image_comcam.py b/python/lsst/ts/standardscripts/maintel/take_image_comcam.py deleted file mode 100644 index f0b7eaaec..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_image_comcam.py +++ /dev/null @@ -1,106 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeImageComCam"] - -import yaml -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..base_take_image import BaseTakeImage - - -class TakeImageComCam(BaseTakeImage): - """Take images with ComCam. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * exposure {n} of {m}: before sending the CCCamera ``takeImages`` command - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Take images with ComCam.") - - self.config = None - - self.mtcs = MTCS(self.domain, log=self.log, intended_usage=MTCSUsages.Slew) - - self._comcam = ComCam( - self.domain, - intended_usage=ComCamUsages.TakeImage, - log=self.log, - tcs_ready_to_take_data=self.mtcs.ready_to_take_data, - ) - - self.instrument_name = "LSSTComCam" - - @property - def camera(self): - return self._comcam - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/ComCamTakeImage.yaml - title: ComCamTakeImage v1 - description: Configuration for ComCamTakeImage. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - sim: - description: Is ComCam in simulation mode? This mode is used for tests. - type: boolean - default: false - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super(TakeImageComCam, cls).get_schema() - - for prop in base_schema_dict["properties"]: - schema_dict["properties"][prop] = base_schema_dict["properties"][prop] - - return schema_dict - - def get_instrument_name(self): - if self.config is not None and self.config.sim: - return self.instrument_name + "Sim" - - return self.instrument_name - - def get_instrument_configuration(self): - return dict(filter=self.config.filter) diff --git a/python/lsst/ts/standardscripts/maintel/take_image_lsstcam.py b/python/lsst/ts/standardscripts/maintel/take_image_lsstcam.py deleted file mode 100644 index b7872bae7..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_image_lsstcam.py +++ /dev/null @@ -1,163 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeImageLSSTCam"] - -import yaml -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam, LSSTCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils.roi_spec import ROISpec - -from ..base_take_image import BaseTakeImage - - -class TakeImageLSSTCam(BaseTakeImage): - """Take images with LSSTCam. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - * exposure {n} of {m}: before sending the CCCamera ``takeImages`` command - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Take images with LSSTCam.") - - self.config = None - - self.mtcs = MTCS(self.domain, log=self.log, intended_usage=MTCSUsages.Slew) - - self._lsstcam = LSSTCam( - self.domain, - intended_usage=LSSTCamUsages.TakeImage, - log=self.log, - tcs_ready_to_take_data=self.mtcs.ready_to_take_data, - ) - - self.instrument_setup_time = self._lsstcam.filter_change_timeout - - self.instrument_name = "LSSTCam" - - @property - def camera(self): - return self._lsstcam - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/maintel/LSSTCamTakeImage.yaml - title: LSSTCamTakeImage v1 - description: Configuration for LSSTCamTakeImage. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - roi_spec: - description: Definition of the ROI Specification. - type: object - additionalProperties: false - required: - - common - - roi - properties: - common: - description: Common properties to all ROIs. - type: object - additionalProperties: false - required: - - rows - - cols - - integration_time_millis - properties: - rows: - description: Number of rows for each ROI. - type: number - minimum: 10 - maximum: 400 - cols: - description: Number of columns for each ROI. - type: number - minimum: 10 - maximum: 400 - integration_time_millis: - description: Guider exposure integration time in milliseconds. - type: number - minimum: 5 - maximum: 200 - roi: - description: Definition of the ROIs regions. - minProperties: 1 - additionalProperties: false - patternProperties: - "^[a-zA-Z0-9]+$": - type: object - additionalProperties: false - required: - - segment - - start_row - - start_col - properties: - segment: - type: number - description: Segment of the CCD where the center of the ROI is located. - start_row: - type: number - description: The bottom-left row origin of the ROI. - start_col: - type: number - description: The bottom-left column origin of the ROI. - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super(TakeImageLSSTCam, cls).get_schema() - - for prop in base_schema_dict["properties"]: - schema_dict["properties"][prop] = base_schema_dict["properties"][prop] - - return schema_dict - - def get_instrument_name(self): - return self.instrument_name - - def get_instrument_configuration(self): - return dict(filter=self.config.filter) - - async def run(self): - if (roi_spec := getattr(self.config, "roi_spec", None)) is not None: - roi_spec = ROISpec.parse_obj(roi_spec) - await self.camera.init_guider(roi_spec=roi_spec) - - await super(TakeImageLSSTCam, self).run() diff --git a/python/lsst/ts/standardscripts/maintel/take_stuttered_comcam.py b/python/lsst/ts/standardscripts/maintel/take_stuttered_comcam.py deleted file mode 100644 index 869d73d88..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_stuttered_comcam.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeStutteredComCam"] - -import yaml -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages - -from ..base_take_stuttered import BaseTakeStuttered - - -class TakeStutteredComCam(BaseTakeStuttered): - """Take a series of stuttered images with ComCam. - - Parameters - ---------- - index : `int` - SAL index of this Script - """ - - def __init__(self, index): - super().__init__(index=index, descr="Take stuttered images with ComCam") - - self._comcam = ComCam( - self.domain, intended_usage=ComCamUsages.TakeImageFull, log=self.log - ) - - @property - def camera(self): - return self._comcam - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/auxtel/comcam_take_stuttered.py - title: TakeStutteredComCam v1 - description: Configuration for TakeStutteredComCam. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - required: [exp_time, n_images] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super(TakeStutteredComCam, cls).get_schema() - - for prop in base_schema_dict["properties"]: - schema_dict["properties"][prop] = base_schema_dict["properties"][prop] - - return schema_dict - - def get_instrument_configuration(self): - return dict( - filter=self.config.filter, - ) diff --git a/python/lsst/ts/standardscripts/maintel/take_stuttered_lsstcam.py b/python/lsst/ts/standardscripts/maintel/take_stuttered_lsstcam.py deleted file mode 100644 index c6c01c1bc..000000000 --- a/python/lsst/ts/standardscripts/maintel/take_stuttered_lsstcam.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TakeStutteredLSSTCam"] - -import yaml -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam, LSSTCamUsages - -from ..base_take_stuttered import BaseTakeStuttered - - -class TakeStutteredLSSTCam(BaseTakeStuttered): - """Take a series of stuttered images with LSSTCam. - - Parameters - ---------- - index : `int` - SAL index of this Script - """ - - def __init__(self, index): - super().__init__(index=index, descr="Take stuttered images with LSSTCam") - - self._lsstcam = LSSTCam( - self.domain, intended_usage=LSSTCamUsages.TakeImageFull, log=self.log - ) - - @property - def camera(self): - return self._lsstcam - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/auxtel/lsstcam_take_stuttered.py - title: TakeStutteredLSSTCam v1 - description: Configuration for TakeStutteredLSSTCam. - type: object - properties: - filter: - description: Filter name or ID; if omitted the filter is not changed. - anyOf: - - type: string - - type: integer - minimum: 1 - - type: "null" - default: null - required: [exp_time, n_images] - additionalProperties: false - """ - schema_dict = yaml.safe_load(schema_yaml) - - base_schema_dict = super(TakeStutteredLSSTCam, cls).get_schema() - - for prop in base_schema_dict["properties"]: - schema_dict["properties"][prop] = base_schema_dict["properties"][prop] - - return schema_dict - - def get_instrument_configuration(self): - return dict( - filter=self.config.filter, - ) diff --git a/python/lsst/ts/standardscripts/maintel/track_target.py b/python/lsst/ts/standardscripts/maintel/track_target.py deleted file mode 100644 index d7fef42ed..000000000 --- a/python/lsst/ts/standardscripts/maintel/track_target.py +++ /dev/null @@ -1,58 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TrackTarget"] - -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages - -from ..base_track_target import BaseTrackTarget - - -class TrackTarget(BaseTrackTarget): - """Execute a Slew/Track operation with the Main Telescope. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Checkpoints** - - None - - """ - - def __init__(self, index): - super().__init__( - index=index, descr="Slew and track a target with the main telescope." - ) - self._mtcs = None - - @property - def tcs(self): - return self._mtcs - - async def configure_tcs(self): - if self._mtcs is None: - self._mtcs = MTCS(self.domain, intended_usage=MTCSUsages.Slew, log=self.log) - await super().configure_tcs() diff --git a/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_comcam.py b/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_comcam.py deleted file mode 100644 index 6e6a41a81..000000000 --- a/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_comcam.py +++ /dev/null @@ -1,195 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TrackTargetAndTakeImageComCam"] - -import asyncio - -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils import RotType - -from ..base_track_target_and_take_image import BaseTrackTargetAndTakeImage - - -class TrackTargetAndTakeImageComCam(BaseTrackTargetAndTakeImage): - """Track target and take image script. - - This script implements a simple visit consistig of slewing to a target, - start tracking and take image. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - add_remotes : `bool` (optional) - Create remotes to control components (default: `True`)? If False, the - script will not work for normal operations. Useful for unit testing. - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__( - index=index, descr="Track target and take image with MainTel and ComCam." - ) - - mtcs_usage, comcam_usage = ( - ( - MTCSUsages.Slew | MTCSUsages.StateTransition, - ComCamUsages.TakeImageFull | ComCamUsages.StateTransition, - ) - if add_remotes - else (MTCSUsages.DryTest, ComCamUsages.DryTest) - ) - - self.angle_filter_change = 0.0 - self.tolerance_angle_filter_change = 1e-2 - - self.mtcs = MTCS(self.domain, intended_usage=mtcs_usage, log=self.log) - self.comcam = ComCam(self.domain, intended_usage=comcam_usage, log=self.log) - - self.instrument_name = "LSSTComCam" - - @property - def tcs(self): - return self.mtcs - - @classmethod - def get_schema(cls): - schema_dict = cls.get_base_schema() - schema_dict["$id"] = ( - "https://github.com/lsst-ts/ts_standardscripts/maintel/track_target_and_take_image_comcam.py" - ) - schema_dict["title"] = "TrackTargetAndTakeImageComCam v1" - schema_dict["description"] = "Configuration for TrackTargetAndTakeImageComCam." - - return schema_dict - - def get_instrument_name(self): - return self.instrument_name - - async def load_playlist(self): - """Load playlist.""" - await self.comcam.rem.cccamera.cmd_play.set_start( - playlist=self.config.camera_playlist, - repeat=True, - timeout=self.comcam.fast_timeout, - ) - - async def assert_feasibility(self): - """Verify that the system is in a feasible state to execute the - script. - """ - await asyncio.gather( - self.mtcs.assert_all_enabled(), - self.comcam.assert_all_enabled(), - ) - - async def track_target_and_setup_instrument(self): - """Track target and setup instrument in parallel.""" - - current_filter = await self.comcam.get_current_filter() - - self.tracking_started = True - - if current_filter != self.config.band_filter: - self.log.debug( - f"Filter change required: {current_filter} -> {self.config.band_filter}" - ) - await self._handle_slew_and_change_filter() - else: - self.log.debug( - f"Already in the desired filter ({current_filter}), slewing and tracking." - ) - - await self.mtcs.slew_icrs( - ra=self.config.ra, - dec=self.config.dec, - rot=self.config.rot_sky, - rot_type=RotType.Sky, - target_name=self.config.name, - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.get_estimated_time_on_target(), - ) - - async def _handle_slew_and_change_filter(self): - """Handle slewing and changing filter at the same time. - - For ComCam (and MainCam) we need to send the rotator to zero and keep - it there while the filter is changing. - """ - - await self.mtcs.slew_icrs( - ra=self.config.ra, - dec=self.config.dec, - rot=self.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{self.config.name} - filter change", - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.get_estimated_time_on_target(), - ) - - await self.comcam.setup_filter(filter=self.config.band_filter) - - async def _wait_rotator_reach_filter_change_angle(self): - """Wait until the rotator reach the filter change angle.""" - - while True: - rotator_position = await self.mtcs.rem.mtrotator.tel_rotation.next( - flush=True, timeout=self.mtcs.fast_timeout - ) - - if ( - abs(rotator_position.actualPosition - self.angle_filter_change) - < self.tolerance_angle_filter_change - ): - self.log.debug("Rotator inside tolerance range.") - break - else: - self.log.debug( - "Rotator not in position: " - f"{rotator_position.actualPosition} -> {self.angle_filter_change}" - ) - await asyncio.sleep(self.mtcs.tel_settle_time) - - async def take_data(self): - """Take data while making sure ATCS is tracking.""" - - tasks = [ - asyncio.create_task(self._take_data()), - asyncio.create_task(self.mtcs.check_tracking()), - ] - - await self.mtcs.process_as_completed(tasks) - - async def _take_data(self): - """Take data.""" - - for exptime in self.config.exp_times: - await self.comcam.take_object( - exptime=exptime, - group_id=self.group_id, - reason=self.config.reason, - program=self.config.program, - ) - - async def stop_tracking(self): - """Execute stop tracking on MTCS.""" - await self.mtcs.stop_tracking() diff --git a/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_gencam.py b/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_gencam.py deleted file mode 100644 index c3f999e5e..000000000 --- a/python/lsst/ts/standardscripts/maintel/track_target_and_take_image_gencam.py +++ /dev/null @@ -1,227 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["TrackTargetAndTakeImageGenCam"] - -import asyncio - -from lsst.ts.observatory.control import Usages -from lsst.ts.observatory.control.generic_camera import GenericCamera -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils import RotType - -from ..base_track_target_and_take_image import BaseTrackTargetAndTakeImage - - -class TrackTargetAndTakeImageGenCam(BaseTrackTargetAndTakeImage): - """Track target and take image script with one more Generic Cameras. - - This script implements a simple visit consistig of slewing to a target, - start tracking and take image. - - This class configuration is inherited from ``BaseTrackTargetAndTakeImage``. - The only applied changes are: - - - The addition of the ``generic_camera`` configuration parameter. - This parameter is a list of objects with the following structure: - - ``index``: Index of the Generic Camera SAL component. - - ``exp_times``: Exposure times (seconds) for each camera. - - - The ``exp_times`` and ``num_exp`` parameters are ignored by this script. - However, we keep them to keep compatibility with the Scheduler. - Instead, use the ``exp_times`` parameter in the ``generic_camera``. - - See below for an example of configuration. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - add_remotes : `bool` (optional) - Create remotes to control components (default: `True`)? If False, the - script will not work for normal operations. Useful for unit testing. - - Examples - -------- - Here is an example of configuration for this script: - - .. code-block:: yaml - - targetid: MY_TARGET_ID - ra: "10:00:00" - dec: "-10:00:00" - rot_sky: 0.0 - name: "config_example_target" - obs_time: 1.0 - estimated_slew_time: 5.0 - num_exp: 2 - exp_times: [0] - reason: "Configuration Example" - program: "CFG_EXAMPLE" - generic_camera: - - index: 101 - exp_times: [2.5, 2.5, 2.5] - - index: 102 - exp_times: [5, 5] - band_filter: "" - - """ - - def __init__(self, index, add_remotes: bool = True): - super().__init__( - index=index, descr="Track target and take image with MainTel and ComCam." - ) - - # Is there a better way to define this? - Usages.TakeImageFull = 1 << 4 - - self.mtcs_usage, self.gencam_usage = ( - (MTCSUsages.Slew, Usages.TakeImageFull) - if add_remotes - else (MTCSUsages.DryTest, Usages.DryTest) - ) - - self.mtcs = MTCS( - domain=self.domain, - log=self.log, - intended_usage=self.mtcs_usage, - ) - - self.gencam = None - - self.instrument_name = "GenCam" - - @property - def tcs(self): - return self.mtcs - - async def load_playlist(self): - """Load playlist.""" - raise NotImplementedError() - - async def assert_feasibility(self): - """Verify that the system is in a feasible state to execute the - script. - """ - await asyncio.gather( - self.mtcs.assert_all_enabled(), - self.mtcs.assert_liveliness(), - *(gencam.assert_all_enabled() for gencam in self.gencam), - *(gencam.assert_liveliness() for gencam in self.gencam), - ) - - def get_instrument_name(self): - return self.instrument_name - - async def configure(self, config): - await super().configure(config) - - self.gencam = [ - GenericCamera( - gencam["index"], - domain=self.domain, - log=self.log, - intended_usage=self.gencam_usage, - ) - for gencam in self.config.generic_camera - ] - - @classmethod - def get_schema(cls): - schema_dict = cls.get_base_schema() - schema_dict["$id"] = ( - "https://github.com/lsst-ts/ts_standardscripts/maintel/track_target_and_take_image_gencam.py" - ) - schema_dict["title"] = "TrackTargetAndTakeImageGenCam v1" - schema_dict["description"] = "Configuration for TrackTargetAndTakeImageGenCam." - - schema_dict["properties"]["generic_camera"] = dict( - type="array", - description="Information associated with the Generic Cameras", - minItems=1, - index=dict( - type="integer", - description="Index of the Generic Camera SAL component.", - ), - exp_times=dict( - type="array", - description="Exposure times (seconds) for each camera.", - items=dict( - type="number", - minimum=0, - ), - ), - ) - - schema_dict["properties"]["exp_times"]["description"] = ( - "Exposure times (seconds). Ignored by the Generic Cameras. " - "Kept only for code compatibility." - ) - - schema_dict["required"].append("generic_camera") - - return schema_dict - - async def track_target_and_setup_instrument(self): - """Track target and setup instrument in parallel.""" - - self.tracking_started = True - - await self.mtcs.slew_icrs( - ra=self.config.ra, - dec=self.config.dec, - rot=self.config.rot_sky, - rot_type=RotType.Sky, - target_name=self.config.name, - az_wrap_strategy=self.config.az_wrap_strategy, - time_on_target=self.get_estimated_time_on_target(), - ) - - async def take_data(self): - """Take data while making sure ATCS is tracking.""" - tasks = [ - asyncio.create_task(self._take_data(idx)) - for idx, _ in enumerate(self.gencam) - ] - tasks.append(asyncio.create_task(self.mtcs.check_tracking())) - await self.mtcs.process_as_completed(tasks) - - async def _take_data(self, cam_arr_index): - """ - Take data. - - Parameters - ---------- - cam_arr_index : int - Camera array index. This is used to index the ``generic_camera``. - """ - - for exptime in self.config.generic_camera[cam_arr_index]["exp_times"]: - await self.gencam[cam_arr_index].take_object( - exptime=exptime, - group_id=self.group_id, - reason=self.config.reason, - program=self.config.program, - ) - - async def stop_tracking(self): - """Execute stop tracking on MTCS.""" - await self.mtcs.stop_tracking() diff --git a/python/lsst/ts/standardscripts/mute_alarms.py b/python/lsst/ts/standardscripts/mute_alarms.py deleted file mode 100644 index a2a803f4e..000000000 --- a/python/lsst/ts/standardscripts/mute_alarms.py +++ /dev/null @@ -1,117 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["MuteAlarms"] - -import yaml -from lsst.ts import salobj -from lsst.ts.xml.enums.Watcher import AlarmSeverity - - -class MuteAlarms(salobj.BaseScript): - """ - Mute Watcher alarm(s) for a given amount of time. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - """ - - def __init__(self, index): - super().__init__( - index=index, descr="Mute Watcher alarm(s) for a given amount of time." - ) - self.watcher = None - self.std_timeout = 60.0 - - @classmethod - def get_schema(cls): - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/sleep.yaml - title: MuteAlarms v1 - description: Configuration for MuteAlarms command. - type: object - properties: - name: - description: >- - Name of alarm or alarms to mute. - Specify a regular expression for multiple alarms. - type: string - mutedBy: - description: User who muted the alarm(s). - type: string - duration: - description: Duration of the mute command in seconds. - type: number - minimum: 0 - default: 300 - severity: - description: >- - Severity level being muted. - An AlarmSeverity enum. - type: string - enum: {[e.name for e in AlarmSeverity]} - default: "None" - additionalProperties: false - required: - - name - - mutedBy - - duration - - severity - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - self.name = config.name - self.mutedBy = config.mutedBy - self.duration = config.duration - self.severity = AlarmSeverity[config.severity] - - # Create the Watcher remote - if self.watcher is None: - self.watcher = salobj.Remote( - domain=self.domain, - name="Watcher", - ) - await self.watcher.start_task - - def set_metadata(self, metadata): - metadata.duration = self.duration - - async def run(self): - """Run the script.""" - self.log.info(f"Muting alarm(s) {self.name} for {self.duration} seconds.") - await self.watcher.cmd_mute.set_start( - name=self.name, - duration=self.duration, - severity=self.severity, - mutedBy=self.mutedBy, - timeout=self.std_timeout, - ) diff --git a/python/lsst/ts/standardscripts/offline_group.py b/python/lsst/ts/standardscripts/offline_group.py deleted file mode 100644 index 833389195..000000000 --- a/python/lsst/ts/standardscripts/offline_group.py +++ /dev/null @@ -1,112 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["OfflineGroup"] - -import abc - -import yaml -from lsst.ts import salobj - - -class OfflineGroup(salobj.BaseScript, metaclass=abc.ABCMeta): - """Put components of a group in offline. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - @property - @abc.abstractmethod - def group(self): - """Return group of CSC attribute. - - Returns - ------- - group - This property must return a subclass of `RemoteGroup` from - `lsst.ts.observatory.control`, e.g. `ATCS` or `MTCS`. - - """ - raise NotImplementedError() - - @staticmethod - @abc.abstractmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - raise NotImplementedError() - - @classmethod - def get_schema(cls): - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/offline_group.yaml - title: OfflineGroup v1 - description: Configuration for OfflineGroup. - type: object - properties: - ignore: - description: >- - CSCs from the group to ignore. Name must match those in - self.group.components, e.g.; mtdometrajectory or hexapod_1 - for the MTDomeTrajectory and Hexapod:1 components, respectively. - Valid options are: {cls.components}. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - metadata.duration = 60.0 - - async def run(self): - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.components(): - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.components()}. Ignoring." - ) - else: - self.log.debug(f"Ignoring {comp}.") - setattr(self.group.check, comp, False) - - await self.group.offline() diff --git a/python/lsst/ts/standardscripts/pause_queue.py b/python/lsst/ts/standardscripts/pause_queue.py deleted file mode 100644 index efce909aa..000000000 --- a/python/lsst/ts/standardscripts/pause_queue.py +++ /dev/null @@ -1,95 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["PauseQueue"] - -import types - -import yaml -from lsst.ts.idl.enums.ScriptQueue import SalIndex -from lsst.ts.observatory.control.script_queue import ScriptQueue -from lsst.ts.salobj import BaseScript - - -class PauseQueue(BaseScript): - """A script to pause the script queue. - - This script will send a command to the script queue to pause it. - The script will then wait indefinitely until it receives a signal - to continue. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Pause the script queue.") - - self.queue_index = None - self.script_queue = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/pause_queue.yaml - title: PauseQueue v1 - description: Configuration for PauseQueue script. - type: object - properties: - queue: - description: >- - Which ScriptQueue to pause? - type: string - enum: ["MAIN_TEL", "AUX_TEL"] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - self.queue_index = getattr(SalIndex, config.queue) - - # Initialize the script queue with the selected index - if self.script_queue is None: - self.script_queue = ScriptQueue( - queue_index=self.queue_index, domain=self.domain, log=self.log - ) - await self.script_queue.start_task - - def set_metadata(self, metadata): - pass - - async def run(self): - """Run the script.""" - - self.log.info( - f"Pausing {self.queue_index!r} script queue. Resume the queue when you are ready..." - ) - await self.script_queue.pause() diff --git a/python/lsst/ts/standardscripts/run_command.py b/python/lsst/ts/standardscripts/run_command.py deleted file mode 100644 index 7e26036d0..000000000 --- a/python/lsst/ts/standardscripts/run_command.py +++ /dev/null @@ -1,181 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["RunCommand"] - -import yaml -from lsst.ts import salobj - - -class RunCommand(salobj.BaseScript): - """Run a command from a CSC and, optionally, wait for an event once the - command finishes. - - Notes - ----- - **Checkpoints** - - * "run {csc_name}:{index}:{cmd}" before commanding a CSC. - - * "wait {csc_name}:{index}:{event}" after commanding a CSC and before - waiting for the event. - - **Details** - - * Dynamically loads IDL files as needed. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Run command from CSC.") - - # approximate time to construct a Remote for a CSC (sec) - self.create_remote_time = 15 - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/RunCommand.yaml - title: RunCommand v1 - description: Configuration for RunCommand. - type: object - properties: - component: - description: Name of the CSC to run command, format is - CSC_name[:index]; the default index is 0. - type: string - cmd: - description: Name of the command to run. - type: string - event: - description: >- - Name of the event to wait after the command is sent. - type: string - flush: - description: Flush event before sending command? - type: boolean - default: True - event_timeout: - description: Timeout (seconds) to wait for the event to arrive. - type: number - default: 30 - parameters: - description: Parameters for the command. - type: object - properties: - timeout: - description: Timeout (seconds) to wait for the command to complete. - type: number - default: 30 - additionalProperties: true - required: [component, cmd] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure the script. - - Specify the CSCs to command, the command to run, the parameters for - the command. Optionally, specify an event to wait and if the event - should be flushed before sending the command. - - Parameters - ---------- - config : `types.SimpleNamespace` - - Raises - ------ - RuntimeError: - If `config.command` is not a valid command from the CSC. - - """ - self.log.info("Configure started") - - self.config = config - - self.name, self.index = salobj.name_to_name_index(config.component) - self.event = config.event if hasattr(config, "event") else None - - self.remote = salobj.Remote( - domain=self.domain, - name=self.name, - index=self.index, - include=[self.event] if self.event is not None else [], - ) - - if config.cmd in self.remote.salinfo.command_names: - self.cmd = config.cmd - else: - raise RuntimeError( - f"Command {config.cmd} not a valid command for {self.name}." - ) - - getattr(self.remote, f"cmd_{self.cmd}").set( - **dict( - [(k, config.parameters[k]) for k in config.parameters if k != "timeout"] - ) - ) - - self.flush = config.flush if self.event is not None else False - - if self.event is not None and self.event not in self.remote.salinfo.event_names: - raise RuntimeError(f"Event {self.event} not a valid event for {self.name}.") - - def set_metadata(self, metadata): - """Compute estimated duration. - - Parameters - ---------- - metadata : `Script_logevent_metadata` - - """ - # a crude estimate using command and event timeouts. - metadata.duration = ( - self.config.parameters["timeout"] + self.config.event_timeout - if self.flush - else 0.0 - ) - - async def run(self): - """Run script.""" - - if not self.remote.start_task.done(): - self.log.debug("Waiting for remote start_task to complete.") - await self.remote.start_task - - if self.flush: - getattr(self.remote, f"evt_{self.event}").flush() - - await self.checkpoint(f"run {self.name}:{self.index}:{self.cmd}") - - await getattr(self.remote, f"cmd_{self.cmd}").start( - timeout=self.config.parameters["timeout"] - ) - - if self.event is not None: - await self.checkpoint(f"wait {self.name}:{self.index}:{self.event}") - - evt = await getattr(self.remote, f"evt_{self.event}").next( - flush=False, timeout=self.config.event_timeout - ) - - self.log.info(evt) diff --git a/python/lsst/ts/standardscripts/scheduler/__init__.py b/python/lsst/ts/standardscripts/scheduler/__init__.py deleted file mode 100644 index 65ae18b3d..000000000 --- a/python/lsst/ts/standardscripts/scheduler/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of ts_standardscripts. -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .set_desired_state import * diff --git a/python/lsst/ts/standardscripts/scheduler/add_block.py b/python/lsst/ts/standardscripts/scheduler/add_block.py deleted file mode 100644 index bb9f77025..000000000 --- a/python/lsst/ts/standardscripts/scheduler/add_block.py +++ /dev/null @@ -1,115 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["AddBlock"] - -import types - -import yaml -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - - -class AddBlock(salobj.BaseScript): - """A base script that implements loading BLOCKS to the Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__(self, index: int, scheduler_index: SalIndex) -> None: - super().__init__( - index=index, - descr=f"Load block to the {scheduler_index.name} Scheduler", - ) - - self.scheduler_remote = salobj.Remote( - domain=self.domain, - name="Scheduler", - index=scheduler_index, - ) - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/scheduler/base_load_snapshot.py - title: BaseAddBlock v1 - description: Configuration for adding BLOCK to scheduler. - type: object - properties: - id: - type: string - description: id of BLOCK to load. This must be a valid BLOCK-ID. - override: - type: object - description: >- - Configuration overrides to pass to the BLOCK to be loaded. Must be - provided in YAML format. This feature is not yet implemented in the - Scheduler CSC. - additionalProperties: true - required: [id] - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - - self.id = config.id - self.override = getattr(config, "override", None) - self.timeout_start = 30.0 - - def set_metadata(self, metadata: salobj.type_hints.BaseDdsDataType) -> None: - """Set metadata fields in the provided struct, given the - current configuration. - - Parameters - ---------- - metadata : ``self.evt_metadata.DataType()`` - Metadata to update. Set those fields for which - you have useful information. - - Notes - ----- - This method is called after `configure` by `do_configure`. - The script state will be `ScriptState.UNCONFIGURED`. - """ - metadata.duration = self.timeout_start - - async def run(self) -> None: - await self.checkpoint(f"Loading {self.id} into scheduler") - await self.scheduler_remote.cmd_addBlock.set_start( - id=self.id, - override=yaml.safe_dump(self.override), - timeout=self.timeout_start, - ) - await self.checkpoint("BLOCK successfully loaded") diff --git a/python/lsst/ts/standardscripts/scheduler/enable.py b/python/lsst/ts/standardscripts/scheduler/enable.py deleted file mode 100644 index 05a1c08b4..000000000 --- a/python/lsst/ts/standardscripts/scheduler/enable.py +++ /dev/null @@ -1,83 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Enable"] - -import types -import typing - -import yaml -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - -from .set_desired_state import SetDesiredState - - -class Enable(SetDesiredState): - """A base script that implements enable functionality for the Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__(self, index: int, scheduler_index: SalIndex) -> None: - super().__init__( - index=index, - descr=f"Enable {scheduler_index.name} Scheduler", - scheduler_index=scheduler_index, - desired_state=salobj.State.ENABLED, - ) - - @classmethod - def get_schema(cls) -> typing.Optional[typing.Dict[str, typing.Any]]: - return yaml.safe_load( - """ -$schema: http://json-schema.org/draft-07/schema# -$id: https://github.com/lsst-ts/ts_standardscripts/scheduler/base_enable.py -title: BaseEnable v1 -description: Configuration for enable scheduler. -type: object -properties: - config: - description: Scheduler configuration. - type: string -required: - - config -additionalProperties: false - """ - ) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - - self.log.info(f"Scheduler configuration: {config.config}") - - self.configuration = config.config diff --git a/python/lsst/ts/standardscripts/scheduler/load_snapshot.py b/python/lsst/ts/standardscripts/scheduler/load_snapshot.py deleted file mode 100644 index ae1d80b0f..000000000 --- a/python/lsst/ts/standardscripts/scheduler/load_snapshot.py +++ /dev/null @@ -1,138 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["LoadSnapshot"] - -import types -import typing - -import yaml -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - - -class LoadSnapshot(salobj.BaseScript): - """A base script that implements loading snapshots for the Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__(self, index: int, scheduler_index: SalIndex) -> None: - super().__init__( - index=index, - descr=f"Load snapshot for {scheduler_index.name} Scheduler", - ) - - self.scheduler_remote = salobj.Remote( - domain=self.domain, - name="Scheduler", - index=scheduler_index, - include=[ - "summaryState", - "heartbeat", - "largeFileObjectAvailable", - ], - ) - - self.timeout_start = 30.0 - - self.snapshot_uri: typing.Optional[str] = None - - @classmethod - def get_schema(cls) -> typing.Optional[typing.Dict[str, typing.Any]]: - return yaml.safe_load( - """ -$schema: http://json-schema.org/draft-07/schema# -$id: https://github.com/lsst-ts/ts_standardscripts/scheduler/base_load_snapshot.py -title: BaseLoadSnapshot v2 -description: Configuration for loading scheduler snapshot. -type: object -properties: - snapshot: - description: >- - Snapshot to load. This must be either a valid uri or the - keyword "latest", which will cause it to load the last published - snapshot. - type: string -required: - - snapshot -additionalProperties: false - """ - ) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - - self.log.info(f"Snapshot: {config.snapshot}.") - - if config.snapshot == "latest": - self.log.debug("Loading latest snapshot.") - latest_snapshot = ( - await self.scheduler_remote.evt_largeFileObjectAvailable.aget( - timeout=self.timeout_start - ) - ) - if latest_snapshot is None: - raise RuntimeError( - "No snapshot information from the Scheduler. " - "In order to load a snapshot with the 'latest' option, the " - "Scheduler must have published at least one snapshot." - ) - else: - self.log.info(f"Latest snapshot uri: {latest_snapshot.url}") - self.snapshot_uri = latest_snapshot.url - else: - self.snapshot_uri = config.snapshot - - def set_metadata(self, metadata: salobj.type_hints.BaseDdsDataType) -> None: - """Set metadata fields in the provided struct, given the - current configuration. - - Parameters - ---------- - metadata : ``self.evt_metadata.DataType()`` - Metadata to update. Set those fields for which - you have useful information. - - Notes - ----- - This method is called after `configure` by `do_configure`. - The script state will be `ScriptState.UNCONFIGURED`. - """ - metadata.duration = self.timeout_start - - async def run(self) -> None: - await self.checkpoint("Loading snapshot") - await self.scheduler_remote.cmd_load.set_start( - uri=self.snapshot_uri, timeout=self.timeout_start - ) - await self.checkpoint("Snapshot loaded") diff --git a/python/lsst/ts/standardscripts/scheduler/resume.py b/python/lsst/ts/standardscripts/scheduler/resume.py deleted file mode 100644 index 235e30657..000000000 --- a/python/lsst/ts/standardscripts/scheduler/resume.py +++ /dev/null @@ -1,89 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Resume"] - -import types -import typing - -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - - -class Resume(salobj.BaseScript): - """A base script that implements resuming the Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__(self, index: int, scheduler_index: SalIndex) -> None: - super().__init__( - index=index, - descr=f"Resume {scheduler_index.name} Scheduler", - ) - - self.scheduler_remote = salobj.Remote( - domain=self.domain, - name="Scheduler", - index=scheduler_index, - include=[], - ) - - self.timeout_start = 30.0 - - @classmethod - def get_schema(cls) -> typing.Optional[typing.Dict[str, typing.Any]]: - return None - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - pass - - def set_metadata(self, metadata: salobj.type_hints.BaseDdsDataType) -> None: - """Set metadata fields in the provided struct, given the - current configuration. - - Parameters - ---------- - metadata : ``self.evt_metadata.DataType()`` - Metadata to update. Set those fields for which - you have useful information. - - Notes - ----- - This method is called after `configure` by `do_configure`. - The script state will be `ScriptState.UNCONFIGURED`. - """ - metadata.duration = self.timeout_start - - async def run(self) -> None: - await self.scheduler_remote.cmd_resume.set_start(timeout=self.timeout_start) diff --git a/python/lsst/ts/standardscripts/scheduler/set_desired_state.py b/python/lsst/ts/standardscripts/scheduler/set_desired_state.py deleted file mode 100644 index ad6810b8b..000000000 --- a/python/lsst/ts/standardscripts/scheduler/set_desired_state.py +++ /dev/null @@ -1,224 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SetDesiredState"] - -import asyncio -import types -import typing - -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - - -class SetDesiredState(salobj.BaseScript): - """A base script that implements setting the desired state for the - Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - descr : `str` - Script description. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__( - self, - index: int, - descr: str, - scheduler_index: SalIndex, - desired_state: salobj.State, - ) -> None: - super().__init__(index=index, descr=descr) - - self.scheduler_remote = salobj.Remote( - domain=self.domain, - name="Scheduler", - index=scheduler_index, - include=["summaryState", "heartbeat"], - ) - - self.desired_state = desired_state - - self.timeout_start = 30.0 - - self.configuration = "" - - self._state_transition_methods_to_try = ( - self._handle_csc_in_standby, - self._handle_csc_in_disabled_or_fault, - self._handle_csc_in_enabled, - ) - - @classmethod - def get_schema(cls) -> typing.Optional[typing.Dict[str, typing.Any]]: - return None - - async def configure(self, config: types.SimpleNamespace) -> None: - pass - - def set_metadata(self, metadata: salobj.type_hints.BaseDdsDataType) -> None: - """Set metadata fields in the provided struct, given the - current configuration. - - Parameters - ---------- - metadata : ``self.evt_metadata.DataType()`` - Metadata to update. Set those fields for which - you have useful information. - - Notes - ----- - This method is called after `configure` by `do_configure`. - The script state will be `ScriptState.UNCONFIGURED`. - """ - metadata.duration = self.timeout_start - - async def assert_liveliness(self) -> None: - """Assert that the Scheduler is alive.""" - - try: - await self.scheduler_remote.evt_heartbeat.next( - flush=True, - timeout=salobj.base_script.HEARTBEAT_INTERVAL, - ) - except asyncio.TimeoutError: - raise AssertionError( - f"No heartbeat from Scheduler in the last {salobj.base_script.HEARTBEAT_INTERVAL}s. " - "Make sure it is running before trying to enable." - ) - - def get_summary_state(self) -> typing.Optional[salobj.State]: - """Get Scheduler summary state.""" - current_summary_state = self.scheduler_remote.evt_summaryState.get() - - return ( - None - if current_summary_state is None - else salobj.State(current_summary_state.summaryState) - ) - - async def handle_no_summary_state_data(self) -> None: - """Handle condition where no information about Scheduler summary state - is available. - - Start by assuming Scheduler is in STANDBY, if this fails, assume it is - in DISABLED and finally in ENABLED. - """ - - for coro in self._state_transition_methods_to_try: - if await coro(): - return - - raise RuntimeError(f"Failed to transition CSC to {self.desired_state!r}.") - - async def _handle_csc_in_standby(self) -> bool: - """Handle condition where CSC is in STANDBY.""" - - try: - await self.scheduler_remote.cmd_start.set_start( - configurationOverride=self.configuration, - timeout=self.timeout_start, - ) - except salobj.AckError: - self.log.warning("Sending start command failed. CSC not in STANDBY") - return False - else: - await self.set_desired_state() - return True - - async def _handle_csc_in_disabled_or_fault(self) -> bool: - """Handle condition where CSC is either in DISABLED or FAULT.""" - try: - await self.scheduler_remote.cmd_standby.set_start( - timeout=self.timeout_start, - ) - except salobj.AckError: - self.log.warning( - "Sending standby command failed. CSC not in DISABLED or FAULT." - ) - return False - else: - await self.set_desired_state() - return True - - async def _handle_csc_in_enabled(self) -> bool: - """Handler condition where CSC is in ENABLED.""" - try: - await self.scheduler_remote.cmd_disable.set_start( - timeout=self.timeout_start, - ) - except salobj.AckError: - self.log.warning("Sending disabled command failed. CSC not in ENABLED.") - return False - else: - await self.set_state_to_standby() - await self.set_desired_state() - return True - - async def set_state_to_standby(self) -> None: - """Set Scheduler state to standby.""" - await salobj.set_summary_state( - self.scheduler_remote, - salobj.State.STANDBY, - ) - - async def set_desired_state(self) -> None: - """Enable CSC.""" - await salobj.set_summary_state( - self.scheduler_remote, - self.desired_state, - override=self.configuration, - ) - - async def run(self) -> None: - """Enable the Scheduler and exit.""" - - await self.checkpoint("Assert liveliness") - await self.assert_liveliness() - - current_summary_state = self.get_summary_state() - - if current_summary_state is None: - await self.checkpoint("Handling no summary state information") - await self.handle_no_summary_state_data() - elif ( - current_summary_state in {salobj.State.ENABLED, salobj.State.DISABLED} - and self.desired_state != salobj.State.STANDBY - ): - await self.checkpoint( - f"Reset summary state to STANDBY before setting to {self.desired_state}" - ) - self.log.warning( - f"Scheduler in {current_summary_state}, sending CSC to STANDBY then to {self.desired_state}." - ) - await self.set_state_to_standby() - await self.set_desired_state() - else: - await self.checkpoint( - f"Setting desired state: {current_summary_state!r} -> {self.desired_state!r}" - ) - await self.set_desired_state() - - await self.checkpoint(f"Scheduler {self.desired_state}") diff --git a/python/lsst/ts/standardscripts/scheduler/stop.py b/python/lsst/ts/standardscripts/scheduler/stop.py deleted file mode 100644 index fcc33bb6e..000000000 --- a/python/lsst/ts/standardscripts/scheduler/stop.py +++ /dev/null @@ -1,110 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Stop"] - -import types -import typing - -import yaml -from lsst.ts import salobj -from lsst.ts.idl.enums.Scheduler import SalIndex - - -class Stop(salobj.BaseScript): - """A base script that implements resuming the Scheduler. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - scheduler_index : `int` - Index of the Scheduler to enable. - """ - - def __init__(self, index: int, scheduler_index: SalIndex) -> None: - super().__init__( - index=index, - descr=f"Stop {scheduler_index.name} Scheduler", - ) - - self.scheduler_remote = salobj.Remote( - domain=self.domain, - name="Scheduler", - index=scheduler_index, - include=[], - ) - - self.timeout_start = 30.0 - self.stop = False - - @classmethod - def get_schema(cls) -> typing.Optional[typing.Dict[str, typing.Any]]: - return yaml.safe_load( - """ -$schema: http://json-schema.org/draft-07/schema# -$id: https://github.com/lsst-ts/ts_standardscripts/scheduler/base_stop.py -title: BaseStop v2 -description: Configuration for stopping scheduler. -type: object -properties: - stop: - description: >- - Should the Scheduler stop current observations in the queue? - type: boolean - default: false -additionalProperties: false - """ - ) - - async def configure(self, config: types.SimpleNamespace) -> None: - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration. - """ - self.stop = config.stop - - def set_metadata(self, metadata: salobj.type_hints.BaseDdsDataType) -> None: - """Set metadata fields in the provided struct, given the - current configuration. - - Parameters - ---------- - metadata : ``self.evt_metadata.DataType()`` - Metadata to update. Set those fields for which - you have useful information. - - Notes - ----- - This method is called after `configure` by `do_configure`. - The script state will be `ScriptState.UNCONFIGURED`. - """ - metadata.duration = self.timeout_start - - async def run(self) -> None: - await self.checkpoint("Stopping scheduler") - await self.scheduler_remote.cmd_stop.set_start( - abort=self.stop, timeout=self.timeout_start - ) - await self.checkpoint("Scheduler stopped") diff --git a/python/lsst/ts/standardscripts/scheduler/testutils/__init__.py b/python/lsst/ts/standardscripts/scheduler/testutils/__init__.py deleted file mode 100644 index f06269084..000000000 --- a/python/lsst/ts/standardscripts/scheduler/testutils/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from .base_scheduler_test_case import * -from .mock_scheduler import * diff --git a/python/lsst/ts/standardscripts/scheduler/testutils/base_scheduler_test_case.py b/python/lsst/ts/standardscripts/scheduler/testutils/base_scheduler_test_case.py deleted file mode 100644 index d945c42bc..000000000 --- a/python/lsst/ts/standardscripts/scheduler/testutils/base_scheduler_test_case.py +++ /dev/null @@ -1,91 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["BaseSchedulerTestCase"] - -import contextlib -import random -import typing -import unittest - -from lsst.ts import salobj -from lsst.ts.idl.enums.Script import ScriptState - -from ...base_script_test_case import BaseScriptTestCase -from .mock_scheduler import MockScheduler - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class BaseSchedulerTestCase(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - @contextlib.asynccontextmanager - async def make_controller( - self, initial_state: salobj.State, publish_initial_state: bool - ): - """Add a Test controller""" - async with MockScheduler( - index=1, - initial_state=initial_state, - publish_initial_state=publish_initial_state, - ) as self.controller: - yield - - def assert_run( - self, - expected_commands: typing.Dict[str, int], - expected_overrides: typing.List[str], - expected_script_state: ScriptState, - expected_csc_state: salobj.State, - ) -> None: - for command in expected_commands: - with self.subTest( - f"successfull command execution {command}", command=command - ): - assert self.controller.n_commands[command] == expected_commands[command] - - assert len(self.controller.overrides) == len( - expected_overrides - ), f"Expected overrides, {len(expected_overrides)} got {len(self.controller.overrides)}." - - for expected_override, controller_override in zip( - expected_overrides, self.controller.overrides - ): - with self.subTest( - "expected overrides", - expected_override=expected_override, - controller_override=controller_override, - ): - assert expected_override == controller_override - - assert self.script.state.state == expected_script_state - assert self.controller.evt_summaryState.data.summaryState == expected_csc_state - - def assert_loaded_snapshots(self, snapshots: typing.List[str]) -> None: - assert len(self.controller.snapshots) == len(snapshots) - for snapshot in snapshots: - assert snapshot in self.controller.snapshots - - def assert_loaded_observing_blocks( - self, observing_blocks: typing.List[str] - ) -> None: - assert len(self.controller.observing_blocks) == len(observing_blocks) - for observing_block in observing_blocks: - assert observing_block in self.controller.observing_blocks diff --git a/python/lsst/ts/standardscripts/scheduler/testutils/mock_scheduler.py b/python/lsst/ts/standardscripts/scheduler/testutils/mock_scheduler.py deleted file mode 100644 index cb3a81597..000000000 --- a/python/lsst/ts/standardscripts/scheduler/testutils/mock_scheduler.py +++ /dev/null @@ -1,148 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["MockScheduler"] - -import asyncio - -from lsst.ts import salobj - - -class MockScheduler(salobj.Controller): - """A simple Scheduler CSC simulator.""" - - def __init__( - self, index, initial_state=salobj.State.STANDBY, publish_initial_state=True - ): - super().__init__(name="Scheduler", index=index, do_callbacks=False) - - self.n_commands = dict( - disable=0, - enable=0, - exitControl=0, - standby=0, - start=0, - ) - - self.running = False - - self.overrides = [] - self.snapshots = [] - self.abort_observations = [] - - self.publish_initial_state = publish_initial_state - - self.valid_configuration_overrides = ["valid_test_config.yaml", ""] - self.valid_snapshot = ( - "https://s3.cp.lsst.org/rubinobs-lfa-cp/Scheduler:2/" - "Scheduler:2/2022/04/07/Scheduler:2_Scheduler:2_2022-04-08T09:56:57.726.p" - ) - - self.observing_blocks = [] - self.valid_observing_block_id = "valid-block" - - self.cmd_disable.callback = self.do_disable - self.cmd_enable.callback = self.do_enable - self.cmd_standby.callback = self.do_standby - self.cmd_start.callback = self.do_start - self.cmd_load.callback = self.do_load - self.cmd_resume.callback = self.do_resume - self.cmd_stop.callback = self.do_stop - self.cmd_addBlock.callback = self.do_add_block - self.evt_summaryState.set(summaryState=initial_state) - - async def start(self): - await super().start() - if self.publish_initial_state: - await self.evt_summaryState.write() - await self.evt_largeFileObjectAvailable.set_write(url=self.valid_snapshot) - - self._heartbeat_task = asyncio.create_task(self.publish_heartbeat()) - - async def publish_heartbeat(self): - while self.isopen: - await self.evt_heartbeat.write() - await asyncio.sleep(1.0) - - async def do_disable(self, data): - await self._do_change_state( - cmd_name="disable", - allowed_current_states={salobj.State.ENABLED}, - new_state=salobj.State.DISABLED, - ) - - async def do_enable(self, data): - await self._do_change_state( - cmd_name="enable", - allowed_current_states={salobj.State.DISABLED}, - new_state=salobj.State.ENABLED, - ) - - async def do_standby(self, data): - await self._do_change_state( - cmd_name="standby", - allowed_current_states={salobj.State.DISABLED, salobj.State.FAULT}, - new_state=salobj.State.STANDBY, - ) - - async def do_start(self, data): - if data.configurationOverride not in self.valid_configuration_overrides: - raise salobj.base.ExpectedError( - f"Config file {data.configurationOverride} does not exist." - ) - await self._do_change_state( - cmd_name="start", - allowed_current_states={salobj.State.STANDBY}, - new_state=salobj.State.DISABLED, - ) - - self.overrides.append(data.configurationOverride) - - async def do_load(self, data): - assert self.evt_summaryState.data.summaryState == salobj.State.ENABLED - assert not self.running - assert data.uri == self.valid_snapshot - - self.snapshots.append(data.uri) - - async def do_resume(self, data): - assert self.evt_summaryState.data.summaryState == salobj.State.ENABLED - self.running = True - - async def do_stop(self, data): - assert self.evt_summaryState.data.summaryState == salobj.State.ENABLED - self.abort_observations.append(data.abort) - self.running = False - - async def do_add_block(self, data): - assert self.evt_summaryState.data.summaryState == salobj.State.ENABLED - assert data.id == self.valid_observing_block_id - - self.observing_blocks.append(data.id) - - async def _do_change_state(self, cmd_name, allowed_current_states, new_state): - current_state = self.evt_summaryState.data.summaryState - if current_state not in allowed_current_states: - raise salobj.base.ExpectedError( - f"{cmd_name} not allowed in state {current_state!r}" - ) - self.n_commands[cmd_name] += 1 - await self.evt_summaryState.set_write(summaryState=new_state) diff --git a/python/lsst/ts/standardscripts/set_summary_state.py b/python/lsst/ts/standardscripts/set_summary_state.py deleted file mode 100755 index dd282d631..000000000 --- a/python/lsst/ts/standardscripts/set_summary_state.py +++ /dev/null @@ -1,256 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SetSummaryState"] - -import asyncio - -import yaml -from lsst.ts import salobj - -try: - from lsst.ts.salobj import WildcardIndexError, name_to_name_index -except ImportError: - # If not available in ts_salobj, use the local fallback from utils - from lsst.ts.standardscripts.utils import name_to_name_index, WildcardIndexError - -from lsst.ts.standardscripts.utils import find_running_instances -from lsst.ts.xml.enums.Watcher import AlarmSeverity - - -class SetSummaryState(salobj.BaseScript): - """Set the summary state for one or more CSCs. - - Notes - ----- - **Checkpoints** - - * "set {csc_name}:{index}" before commanding a CSC. - - **Details** - - * Takes the shortest path from the current state to the requested state. - Thus if you want to configure a CSC you should specify it twice: - - * First with state "STANDBY". - * Next with state "DISABLED" or "ENABLED" and the desired override. - - * Dynamically loads IDL files as needed. - """ - - def __init__(self, index): - super().__init__(index=index, descr="Put CSCs into specified states") - - self.valid_transitions = ["start", "enable", "disable", "standby"] - - # approximate time to construct a Remote for a CSC (sec) - self.create_remote_time = 15 - # time limit for each state transition command (sec); - # make it generous enough to handle any CSC - self.cmd_timeout = 60 - - self.watcher = None - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/SetSummaryState.yaml - title: SetSummaryState v1 - description: Configuration for SetSummaryState - type: object - properties: - data: - description: List of (CSC_name[:index], state_name [, override_to_apply]); - the default index is 0; - the default override_to_apply is "" - If the index is '*', the script will discover all running instances. - type: array - minItems: 1 - items: - type: array - minItems: 2 - maxItems: 3 - items: - type: string - mute_alarms: - description: If true, temporarily mute watcher alarms for components being sent to Offline. - type: boolean - default: false - mute_duration: - description: Duration in minutes to mute the alarms. Default is 30.0 minutes. - type: number - minimum: 0 - default: 30.0 - required: [data] - additionalProperties: false - - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure the script. - - Specify the CSCs to command, and for each CSC, - specify the desired summary state optionally the override. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration with one attribute: - - * data : a list, where each element is a tuple - with two or three entries: - - * CSC name and optional index as ``csc_name:index`` (a `str`). - For a CSC that is not indexed you may omit ``:index`` - or specify ``:0``, as you prefer. - * Name of desired summary state, case blind, e.g. "enabled" - or "STANDBY". The "fault" state is not supported. - * The value of ``configurationOverride`` in the ``start`` - command for each CSC. Ignored unless the ``start`` command - is issued (i.e. the CSC transitions from "STANDBY" to - "DISABLED"). If omitted then "" is used. - - Notes - ----- - Saves the results as two attributes: - - * ``nameind_state_override``: a list, each element of which is a tuple - with three elements: - - * (csc_name, index) - * desired summary state, as an `lsst.ts.salobj.State` - * override, or "" if none specified - - * remotes: a dict of (csc_name, index): remote, - an `lsst.ts.salobj.Remote` - - Constructing a `salobj.Remote` is slow (DM-17904), so configuration - may take a 10s or 100s of seconds per CSC. - """ - self.log.info("Configure started") - - # parse the data - nameind_state_override = [] - for elt in config.data: - - try: - # Try to parse the name and index - name, index = name_to_name_index(elt[0]) - except WildcardIndexError as e: - name = e.name - index = "*" # Mark as wildcard - - state_name = elt[1] - if not isinstance(state_name, str): - raise ValueError(f"{elt} summary state {state_name!r} is not a string") - try: - state = getattr(salobj.State, state_name.upper()) - except AttributeError: - raise ValueError(f"{elt} has unknown summary state {state_name!r}") - if state == salobj.State.FAULT: - raise ValueError(f"{elt} state cannot be FAULT") - if len(elt) == 3: - override = elt[2] - if not isinstance(override, str): - raise ValueError(f"{elt} override {override!r} is not a string") - else: - override = "" - - # If wildcard index is used, enter discovery mode - if index == "*": - component, discovered_indices = await find_running_instances( - self.domain, name - ) - - for idx in discovered_indices: - nameind_state_override.append(((name, idx), state, override)) - else: - nameind_state_override.append(((name, index), state, override)) - - # construct remotes - remotes = dict() - for elt in nameind_state_override: - name_index = elt[0] - name, index = name_index - self.log.debug(f"Create remote {name}:{index}") - if name_index not in remotes: - remote = salobj.Remote( - domain=self.domain, name=name, index=index, include=["summaryState"] - ) - remotes[name_index] = remote - - self.nameind_state_override = nameind_state_override - self.remotes = remotes - - self.mute_alarms = getattr(config, "mute_alarms", False) - self.mute_duration = getattr(config, "mute_duration", 30.0) - - if self.mute_alarms and self.watcher is None: - self.watcher = salobj.Remote(self.domain, "Watcher") - await self.watcher.start_task - - def set_metadata(self, metadata): - """Compute estimated duration. - - Parameters - ---------- - metadata : SAPY_Script.Script_logevent_metadataC - """ - # a crude estimate; state transitions are typically quick - # but we don't know how many of them there will be - metadata.duration = len(self.nameind_state_override) * 2 - - async def run(self): - """Run script.""" - tasks = [ - remote.start_task - for remote in self.remotes.values() - if not remote.start_task.done() - ] - if tasks: - self.log.info(f"Waiting for {len(tasks)} remotes to be ready") - await asyncio.gather(*tasks) - - for name_index, state, override in self.nameind_state_override: - name, index = name_index - remote = self.remotes[(name, index)] - if self.mute_alarms and state == salobj.State.OFFLINE: - self.log.info( - f"Muting alarms for (Enabled|Heartbeat).{name}:{index} Severity " - f"{AlarmSeverity.CRITICAL.name} for {self.mute_duration} minutes" - ) - try: - alarm_name_pattern = rf"^(Enabled|Heartbeat)\.{name}:{index}" - await self.watcher.cmd_mute.set_start( - name=alarm_name_pattern, - duration=self.mute_duration * 60, # Convert to seconds - severity=AlarmSeverity.CRITICAL, - mutedBy="set_summary_state script", - ) - except Exception as e: - self.log.warning(f"Failed to mute alarms for {name}:{index}: {e}") - - await self.checkpoint(f"set {name}:{index}") - await salobj.set_summary_state( - remote=remote, state=state, override=override, timeout=self.cmd_timeout - ) diff --git a/python/lsst/ts/standardscripts/sleep.py b/python/lsst/ts/standardscripts/sleep.py deleted file mode 100644 index 25042b468..000000000 --- a/python/lsst/ts/standardscripts/sleep.py +++ /dev/null @@ -1,87 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["Sleep"] - -import asyncio - -import yaml -from lsst.ts.salobj import BaseScript - - -class Sleep(BaseScript): - """Sleep for a given amount of time. - - This script pauses the script queue for a specified amount of time. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - Notes - ----- - **Details** - - This script sends a sleep command to the script queue, which pauses - the script queue for a specified amount of time. - - """ - - def __init__(self, index): - super().__init__(index=index, descr="Pause the script queue.") - - self.sleep_for = 0 - - @classmethod - def get_schema(cls): - schema_yaml = """ - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/sleep.yaml - title: Sleep v1 - description: Configuration for Sleep command. - type: object - properties: - sleep_for: - description: >- - Duration of the sleep command in seconds. - type: number - minimum: 0 - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - """Configure the script. - - Parameters - ---------- - config : `types.SimpleNamespace` - Configuration - """ - self.sleep_for = config.sleep_for - - def set_metadata(self, metadata): - metadata.duration = self.sleep_for - - async def run(self): - self.log.info(f"Sleep queue for {self.sleep_for} seconds...") - await asyncio.sleep(self.sleep_for) diff --git a/python/lsst/ts/standardscripts/standby_group.py b/python/lsst/ts/standardscripts/standby_group.py deleted file mode 100644 index 3e8e9a29a..000000000 --- a/python/lsst/ts/standardscripts/standby_group.py +++ /dev/null @@ -1,112 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["StandbyGroup"] - -import abc - -import yaml -from lsst.ts import salobj - - -class StandbyGroup(salobj.BaseScript, metaclass=abc.ABCMeta): - """Put components of a group in standby. - - Parameters - ---------- - index : `int` - Index of Script SAL component. - - """ - - def __init__(self, index, descr): - super().__init__(index=index, descr=descr) - - self.config = None - - @property - @abc.abstractmethod - def group(self): - """Return group of CSC attribute. - - Returns - ------- - group - This property must return a subclass of `RemoteGroup` from - `lsst.ts.observatory.control`, e.g. `ATCS` or `MTCS`. - - """ - raise NotImplementedError() - - @staticmethod - @abc.abstractmethod - def components(): - """Return list of components name as appeared in - `self.group.components`. - - Returns - ------- - components : `list` of `str`. - - """ - raise NotImplementedError() - - @classmethod - def get_schema(cls): - schema_yaml = f""" - $schema: http://json-schema.org/draft-07/schema# - $id: https://github.com/lsst-ts/ts_standardscripts/standby_group.yaml - title: StandbyGroup v1 - description: Configuration for StandbyGroup. - type: object - properties: - ignore: - description: >- - CSCs from the group to ignore. Name must match those in - self.group.components, e.g.; mtdometrajectory or hexapod_1 - for the MTDomeTrajectory and Hexapod:1 components, respectively. - Valid options are: {cls.components}. - type: array - items: - type: string - additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config): - self.config = config - - def set_metadata(self, metadata): - metadata.duration = 60.0 - - async def run(self): - if hasattr(self.config, "ignore"): - for comp in self.config.ignore: - if comp not in self.components(): - self.log.warning( - f"Component {comp} not in CSC Group. " - f"Must be one of {self.components()}. Ignoring." - ) - else: - self.log.debug(f"Ignoring {comp}.") - setattr(self.group.check, comp, False) - - await self.group.standby() diff --git a/python/lsst/ts/standardscripts/system_wide_shutdown.py b/python/lsst/ts/standardscripts/system_wide_shutdown.py deleted file mode 100644 index 9190701ba..000000000 --- a/python/lsst/ts/standardscripts/system_wide_shutdown.py +++ /dev/null @@ -1,231 +0,0 @@ -# This file is part of ts_standardscripts. -# -# Developed for the Vera C. Rubin Observatory Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = ["SystemWideShutdown"] - -import asyncio -import types -import typing - -import yaml -from lsst.ts import salobj, xml -from lsst.ts.standardscripts.utils import find_running_instances - - -class SystemWideShutdown(salobj.BaseScript): - """Discover all running CSCs and send them all to OFFLINE state. - - Notes - ----- - - This SAL Script works by getting a list of components from the IDL - directory, then finds which components are running by listening in to - heartbeats. For indexed components, the script will accumulate indices - until it receives at least 3 heartbeats from 1 of the components. This - gives enough time to find all running instances of a particular CSC. - - After discovering the runnings CSCs, and their indices, the Script attempts - to send them all to OFFLINE. The user can control the order in which the - shutdown happens by providing the names of the components to start with and - to end with. In any case, the Script will always finish with the - ScriptQueue and ignore Scripts. Users can also provide a list of CSCs to be - ignored. - - In order to prevent accidental execution of this Script, users must provide - two required configuration parameters; user and reason. This also helps - keep track of who is executing the shutdown and why. - """ - - def __init__(self, index: int) -> None: - super().__init__(index=index, descr="Send all CSCs to OFFLINE.") - - self.failed: dict[str, str] = dict() - self.components_to_ignore = ["Script", "ScriptQueue"] - self.components_to_end_with = ["ScriptQueue"] - - self._max_concurrency = 10 - self._concurrent_capacity = asyncio.Semaphore(self._max_concurrency) - - @classmethod - def get_schema(cls) -> None | dict[str, typing.Any]: - schema_yaml = """ -$schema: http://json-schema.org/draft-07/schema# -$id: https://github.com/lsst-ts/ts_standardscripts/python/lsst/ts/standardscripts/system_wide_shutdown.py -title: SystemWideShutdown v1 -description: Configuration for SystemWideShutdown script. -type: object -properties: - user: - description: Name of the user that is executing the script. - type: string - reason: - description: Reason for running the system wide shutdown. - type: string - ignore: - description: CSCs to ignore. - type: array - items: - type: string - default: [] - start_with: - description: CSCs to start with. - type: array - items: - type: string - default: [] - end_with: - description: CSCs to end with. - type: array - items: - type: string - default: [] -required: [user, reason] -additionalProperties: false - """ - return yaml.safe_load(schema_yaml) - - async def configure(self, config: types.SimpleNamespace) -> None: - self.config = config - - def set_metadata(self, metadata: salobj.type_hints.BaseMsgType) -> None: - metadata.duration = 60.0 - - async def run(self) -> None: - components_running = await self.discover_components() - - self.log.info( - f"Shutting down {len(components_running)} components as requested by {self.config.user}. " - f"Reason: {self.config.reason}" - ) - - await self.checkpoint( - f"Shutdown :: Requested by {self.config.user}. " - f"Reason: {self.config.reason}. " - f"Found {len(components_running)} running components." - ) - - for component in self.config.ignore: - if component in components_running: - self.log.debug(f"Excluding {component} from the list.") - components_running.pop(component) - - await self.checkpoint("Shutdown :: Start with components.") - for component in self.config.start_with: - if component in components_running: - component_indices = components_running.pop(component) - await self.shutdown(component, component_indices) - - await self.checkpoint("Shutdown :: Running components.") - for component in components_running: - if component not in self.config.end_with: - component_indices = components_running[component] - await self.shutdown(component, component_indices) - - await self.checkpoint("Shutdown :: End with components.") - for component in self.config.end_with: - if component in components_running: - component_indices = components_running.pop(component) - await self.shutdown(component, component_indices) - - for component in self.components_to_end_with: - if component in components_running: - component_indices = components_running.pop(component) - await self.shutdown(component, component_indices) - - if len(self.failed) > 0: - error_message = ( - "The following components failed to transition to offline:\n" - ) - - for component in self.failed: - error_message += f"{component}::{self.failed[component]}\n" - - self.log.error(error_message) - raise RuntimeError( - f"A total of {len(self.failed)} components failed to transition to offline." - ) - - async def discover_components(self) -> dict[str, list[int]]: - """Discover components running in the system. - - Returns - ------- - dict[str, list[int]] - Dictionary with the name of the component as key and list of - indices as values. - """ - - components_running: dict[str, list[int]] = dict() - - components = self._get_all_components() - - task_find_running_instances = [ - asyncio.create_task(find_running_instances(self.domain, component)) - for component in components - ] - - for task in asyncio.as_completed(task_find_running_instances): - component, component_indices = await task - if component_indices: - components_running[component] = component_indices - - return components_running - - def _get_all_components(self) -> list[str]: - """Get the name of all components in the system. - - Returns - ------- - list[str] - Name of all components in the system. - """ - - components: list[str] = xml.subsystems.copy() - - for component in self.components_to_ignore: - if component in components: - components.remove(component) - - return components - - async def shutdown(self, component: str, indices: list[int]) -> None: - """Shutdown component with given indices. - - Parameters - ---------- - component : str - Name of the component. - indices : list[int] - List of indices. - """ - - for index in indices: - self.log.info(f"Shutdown {component}:{index}.") - async with salobj.Remote( - self.domain, component, index=index, include=["summaryState"] - ) as remote: - try: - await salobj.set_summary_state(remote, salobj.State.OFFLINE) - except Exception as e: - self.log.debug(f"Failed to shutdown {component}:{index}::{e}") - self.failed[f"{component}:{index}"] = f"{e}" - else: - self.log.debug(f"{component}:{index} offline.") diff --git a/python/lsst/ts/standardscripts/utils.py b/python/lsst/ts/standardscripts/utils.py deleted file mode 100644 index 70bd105f8..000000000 --- a/python/lsst/ts/standardscripts/utils.py +++ /dev/null @@ -1,292 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = [ - "get_scripts_dir", - "get_s3_bucket", - "get_topic_time_utc", - "format_as_list", - "format_grid", -] - -import asyncio -import collections.abc -import os -import pathlib -import re -import warnings - -import numpy as np -from lsst.ts import salobj -from lsst.ts.salobj import name_to_name_index as salobj_name_to_name_index -from lsst.ts.utils import astropy_time_from_tai_unix - -S3_INSTANCES = dict( - tucson="tuc", - base="ls", - summit="cp", -) - - -def get_scripts_dir(): - """Get the absolute path to the scripts directory. - - Returns - ------- - scripts_dir : `pathlib.Path` - Absolute path to the specified scripts directory. - - """ - return pathlib.Path(__file__).resolve().parent / "data" / "scripts" - - -def get_s3_bucket() -> salobj.AsyncS3Bucket: - """Generate an s3 bucket object. - - The method will try to determine the s3 instance from the LSST_SITE - environment variable. If it can't it will use "mock" as the instance - value and will also mock the s3 bucket. This is useful for unit testing. - """ - - site = os.environ.get("LSST_SITE") - do_mock = site not in S3_INSTANCES - s3instance = S3_INSTANCES.get(site, "mock") - - s3bucket_name = salobj.AsyncS3Bucket.make_bucket_name( - s3instance=s3instance, - ) - - return salobj.AsyncS3Bucket( - name=s3bucket_name, - domock=do_mock, - create=do_mock, - ) - - -def format_as_list(value, recurrences): - """ - Reformat single instance of the attribute `value` as a list with - a specified number of recurrences . - - Configurations often allow a single value for an attribute to be passed - that needs to be replicated as a list. This occurs when the (YAML) type - is specified as an array but a user provides a single value - (as a float/int/string etc). For example, an instrument setup for 5 - different exposure times may only be given a single value for filter. - However, often the single filter value needs to be reformatted of a - list of length 5. - - This function returns the input as a list, with the desired - of recurrences. - - Parameters - ---------- - value: `str, float, int, boolean` - A single element of any type. Must not be a list. - recurrences: `int` - An integer specifying the number of occurrences and length of the - returned list - - Returns - ------- - value_as_list: `list` - A list of length `recurrences`, where all elements are the input - parameter `value` - """ - - # Check to see if the input data is iterable (not a scalar) - # Strings are iterable, so check if it's a string as well - if isinstance(value, collections.abc.Iterable) and not isinstance(value, str): - # Verify that the array is the correct number of recurrences - # if specified as a list then it should already have the - # correct number of instances. - if len(value) != recurrences: - raise ValueError( - f"The input data {value} is already an array of " - f"length {len(value)}, " - "but the length does not match the number of " - f"desired reccurences ({recurrences}). " - "Verify that all inputs are singular values or" - "have the correct length(s) values." - ) - else: - # input already an iterable array with correct - # number of elements, so just return the array - return value - - # value is a scalar, convert to a list repeating the scalar value - value_as_list = [value] * recurrences - - return value_as_list - - -def format_grid( - axis1: float | list[float], axis2: float | list[float] -) -> tuple[list[float], list[float]]: - """Format two input values into lists with the same lengths. - - If both values are scalars, the return value will be a pair of lists with - a single value. - - If one of the inputs is a scalar and the other is a list, the return value - is a list with the scalar value with the same length as the list and the - list itself. - - If both are lists with the same dimension, the return value is the same as - the input. However, if the lists have different dimensions an exception is - raised. - - Parameters - ---------- - axis1 : `float` or `list`[`float`] - Input value for the first axis. - axis2 : `float` or `list`[`float`] - Input value for the second axis. - - Returns - ------- - `tuple`[`list`[`float`], `list`[`float`]]] - Pair of lists with the same length. - - Raises - ------ - RuntimeError - If both inputs are lists of different lengths. - """ - if np.isscalar(axis1) and np.isscalar(axis2): - return [axis1], [axis2] - elif np.isscalar(axis1): - return format_as_list(axis1, len(axis2)), axis2 - elif np.isscalar(axis2): - return axis1, format_as_list(axis2, len(axis1)) - else: - if len(axis1) != len(axis2): - raise RuntimeError( - f"Array sizes must be the same. Got {len(axis1)} and {len(axis2)}." - ) - return axis1, axis2 - - -def get_topic_time_utc(topic): - """Reformat a topic command time from TAI unix to UTC. - - Parameters - ---------- - topic: `salobj.BaseMsgType` - A single event message. - - Returns - ------- - topic_time_utc: `str` - Value of salobj.BaseMsgType.private_sndStamp in UTC str time. - """ - - topic_time = astropy_time_from_tai_unix(topic.private_sndStamp) - topic_time.format = "iso" - topic_time_utc = topic_time.utc - return topic_time_utc - - -async def find_running_instances( - domain, component: str, min_heartbeat=3, hb_timeout=5 -) -> tuple[str, list[int]]: - """Find indices of any running instance for the component. - - Parameters - ---------- - domain : Domain object - The SAL domain. - component : str - Name of the component. - min_heartbeat : int, optional - Minimum number of heartbeats to consider the component running - (default=3). - hb_timeout : int, optional - Timeout for waiting on heartbeats in seconds (default=5). - - Returns - ------- - tuple[str, list[int]] - Name of the component and list of indices for running instances. - """ - indices = [] - heartbeats = {} - - async with salobj.Remote( - domain, component, index=0, include=["heartbeat"], readonly=True - ) as remote: - # Flush old heartbeats to avoid historical data. - remote.evt_heartbeat.flush() - - while all([value < min_heartbeat for value in heartbeats.values()]): - try: - hb = await remote.evt_heartbeat.next(timeout=hb_timeout, flush=False) - sal_index = hb.salIndex if hasattr(hb, "salIndex") else 0 - - if sal_index not in heartbeats: - heartbeats[sal_index] = 1 - else: - heartbeats[sal_index] += 1 - except asyncio.TimeoutError: - break - - indices = list(heartbeats.keys()) - - return component, indices - - -# Define WildcardIndexError if it doesn't exist in ts_salobj yet -try: - from lsst.ts.salobj import WildcardIndexError -except ImportError: - - class WildcardIndexError(ValueError): - """Custom exception to signify that the index is a wildcard ('*').""" - - def __init__(self, name: str): - warnings.warn( - "The local implementation of `WildcardIndexError` in ts_standardscripts.utils is deprecated. " - "Please use `WildcardIndexError` from ts_salobj once it is available.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(f"The index for component '{name}' is a wildcard ('*').") - self.name = name - - -def name_to_name_index(name: str) -> tuple[str, int]: - warnings.warn( - "The local implementation of `name_to_name_index` in ts_standardscripts.utils is deprecated. " - "Please use `name_to_name_index` from ts_salobj once it is available.", - DeprecationWarning, - stacklevel=2, - ) - - NAME_REGEX = re.compile(r"(?P[a-zA-Z_-][a-zA-Z0-9_-]*)(:(?P\d+|\*))?$") - - try: - return salobj_name_to_name_index(name) - except ValueError: - match = NAME_REGEX.match(name) - if match and match["index"] == "*": - raise WildcardIndexError(match["name"]) - else: - raise ValueError(f"name {name!r} is not of the form 'name' or 'name:index'") diff --git a/tests/test_auxtel_atpneumatics_checkout.py b/tests/test_auxtel_atpneumatics_checkout.py index 7dd1b79eb..43b56356c 100644 --- a/tests/test_auxtel_atpneumatics_checkout.py +++ b/tests/test_auxtel_atpneumatics_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,9 +26,10 @@ import unittest import pytest +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.daytime_checkout import ATPneumaticsCheckout from lsst.ts.observatory.control.auxtel.atcs import ATCS, ATCSUsages -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel.daytime_checkout import ATPneumaticsCheckout +from lsst.ts.standardscripts import BaseScriptTestCase class TestATPneumaticsCheckout(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -50,9 +51,7 @@ async def basic_make_script(self, index): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = ( - scripts_dir / "auxtel" / "daytime_checkout" / "atpneumatics_checkout.py" - ) + script_path = scripts_dir / "daytime_checkout" / "atpneumatics_checkout.py" print(script_path) await self.check_executable(script_path) diff --git a/tests/test_auxtel_calsys_takedata.py b/tests/test_auxtel_calsys_takedata.py index c4a7641c9..337506f72 100644 --- a/tests/test_auxtel_calsys_takedata.py +++ b/tests/test_auxtel_calsys_takedata.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -27,8 +27,8 @@ import numpy as np import pytest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import CalSysTakeData, get_scripts_dir from lsst.ts.idl.enums import ATMonochromator, Script -from lsst.ts.standardscripts.auxtel import CalSysTakeData from numpy.testing import assert_array_almost_equal, assert_array_equal random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -199,8 +199,8 @@ async def test_run(self): assert self.grating_types == config.grating_types async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "calsys_takedata.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "calsys_takedata.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_close_dome.py b/tests/test_auxtel_close_dome.py index ad22c7bad..eefa0bbbb 100644 --- a/tests/test_auxtel_close_dome.py +++ b/tests/test_auxtel_close_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import CloseDome from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import CloseDome class TestCloseDome( @@ -36,8 +37,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "close_dome.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "close_dome.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_close_dropout_door.py b/tests/test_auxtel_close_dropout_door.py index 1f7834259..3de0bfaf8 100644 --- a/tests/test_auxtel_close_dropout_door.py +++ b/tests/test_auxtel_close_dropout_door.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,7 +22,8 @@ import unittest from lsst.ts import standardscripts -from lsst.ts.standardscripts.auxtel.atdome import CloseDropoutDoor +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import CloseDropoutDoor class TestCloseDropoutDoor( @@ -44,6 +45,6 @@ async def test_run(self): self.script.atcs.close_dropout_door.assert_called_once() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "close_dropout_door.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "close_dropout_door.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_detector_characterization_std_flat_dataset.py b/tests/test_auxtel_detector_characterization_std_flat_dataset.py index 892829fc9..872dd84c7 100644 --- a/tests/test_auxtel_detector_characterization_std_flat_dataset.py +++ b/tests/test_auxtel_detector_characterization_std_flat_dataset.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -27,7 +27,8 @@ import astropy from lsst.ts import salobj, standardscripts, utils -from lsst.ts.standardscripts.auxtel.detector_characterization import ATGetStdFlatDataset +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.detector_characterization import ATGetStdFlatDataset random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -146,12 +147,9 @@ async def test_script(self): assert self.linear_stage == config.linear_stage async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() + scripts_dir = get_scripts_dir() script_path = ( - scripts_dir - / "auxtel" - / "detector_characterization" - / "get_std_flat_dataset.py" + scripts_dir / "detector_characterization" / "get_std_flat_dataset.py" ) await self.check_executable(script_path) diff --git a/tests/test_auxtel_disable_ataos_corrections.py b/tests/test_auxtel_disable_ataos_corrections.py index 051994cfc..706834198 100644 --- a/tests/test_auxtel_disable_ataos_corrections.py +++ b/tests/test_auxtel_disable_ataos_corrections.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import DisableATAOSCorrections, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import DisableATAOSCorrections random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -94,8 +94,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "disable_ataos_corrections.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "disable_ataos_corrections.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_disable_dome_following.py b/tests/test_auxtel_disable_dome_following.py index f5f20385b..0cac5212f 100644 --- a/tests/test_auxtel_disable_dome_following.py +++ b/tests/test_auxtel_disable_dome_following.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import DisableDomeFollowing from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import DisableDomeFollowing class TestDisableDomeFollowing( @@ -36,8 +37,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "disable_dome_following.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "disable_dome_following.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_enable_ataos_corrections.py b/tests/test_auxtel_enable_ataos_corrections.py index bb5f1c28a..ce3b26830 100644 --- a/tests/test_auxtel_enable_ataos_corrections.py +++ b/tests/test_auxtel_enable_ataos_corrections.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import EnableATAOSCorrections, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import EnableATAOSCorrections random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -54,8 +54,8 @@ async def test_run(self): assert self.atcs_mock.ataos.evt_correctionEnabled.data.atspectrograph async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "enable_ataos_corrections.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "enable_ataos_corrections.py" await self.check_executable(script_path) async def test_configure_ignore(self): diff --git a/tests/test_auxtel_enable_atcs.py b/tests/test_auxtel_enable_atcs.py index 9426f8e41..1b1f4971a 100644 --- a/tests/test_auxtel_enable_atcs.py +++ b/tests/test_auxtel_enable_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import EnableATTCS, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import EnableATTCS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_components(self): assert component in self.script.components() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "enable_atcs.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "enable_atcs.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_enable_dome_following.py b/tests/test_auxtel_enable_dome_following.py index bd658ceb8..3a61663b6 100644 --- a/tests/test_auxtel_enable_dome_following.py +++ b/tests/test_auxtel_enable_dome_following.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import EnableDomeFollowing from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import EnableDomeFollowing class TestEnableDomeFollowing( @@ -36,8 +37,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "enable_dome_following.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "enable_dome_following.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_enable_latiss.py b/tests/test_auxtel_enable_latiss.py index ffeaafc5e..6b7982521 100644 --- a/tests/test_auxtel_enable_latiss.py +++ b/tests/test_auxtel_enable_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import EnableLATISS, get_scripts_dir from lsst.ts.observatory.control.mock import LATISSMock -from lsst.ts.standardscripts.auxtel import EnableLATISS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "enable_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "enable_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_focus_sweep_latiss.py b/tests/test_auxtel_focus_sweep_latiss.py index f9811625f..9963fbd87 100644 --- a/tests/test_auxtel_focus_sweep_latiss.py +++ b/tests/test_auxtel_focus_sweep_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,7 +24,8 @@ import pytest from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.auxtel.focus_sweep_latiss import FocusSweepLatiss +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.focus_sweep_latiss import FocusSweepLatiss class TestFocusSweepLatiss( @@ -271,6 +272,6 @@ async def test_cleanup(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "focus_sweep_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "focus_sweep_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_home_dome.py b/tests/test_auxtel_home_dome.py index 5f0ee1fe5..9a8845b06 100644 --- a/tests/test_auxtel_home_dome.py +++ b/tests/test_auxtel_home_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import HomeDome from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import HomeDome class TestHomeDome( @@ -36,8 +37,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "home_dome.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "home_dome.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_latiss_checkout.py b/tests/test_auxtel_latiss_checkout.py index 12b8d6ca8..ed47de9ce 100644 --- a/tests/test_auxtel_latiss_checkout.py +++ b/tests/test_auxtel_latiss_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,8 +26,9 @@ import unittest import pytest -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel.daytime_checkout import LatissCheckout +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.daytime_checkout import LatissCheckout +from lsst.ts.standardscripts import BaseScriptTestCase class TestLatissCheckout(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -46,7 +47,7 @@ async def basic_make_script(self, index): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "daytime_checkout" / "latiss_checkout.py" + script_path = scripts_dir / "daytime_checkout" / "latiss_checkout.py" print(script_path) await self.check_executable(script_path) diff --git a/tests/test_auxtel_latiss_take_sequence.py b/tests/test_auxtel_latiss_take_sequence.py index d1aca0295..585803821 100644 --- a/tests/test_auxtel_latiss_take_sequence.py +++ b/tests/test_auxtel_latiss_take_sequence.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,8 +26,8 @@ import pytest from lsst.ts import salobj -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel import LatissTakeSequence +from lsst.ts.auxtel.standardscripts import LatissTakeSequence, get_scripts_dir +from lsst.ts.standardscripts import BaseScriptTestCase class TestLatissTakeSequence(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -81,7 +81,7 @@ async def setup_mocks(self): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "latiss_take_sequence.py" + script_path = scripts_dir / "latiss_take_sequence.py" self.log.debug(f"Checking for script in {script_path}") await self.check_executable(script_path) diff --git a/tests/test_auxtel_offline_atcs.py b/tests/test_auxtel_offline_atcs.py index 570fad561..dbdb536d6 100644 --- a/tests/test_auxtel_offline_atcs.py +++ b/tests/test_auxtel_offline_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import OfflineATCS, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import OfflineATCS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "offline_atcs.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "offline_atcs.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_offline_latiss.py b/tests/test_auxtel_offline_latiss.py index e6d0b205c..26fda28bd 100644 --- a/tests/test_auxtel_offline_latiss.py +++ b/tests/test_auxtel_offline_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import OfflineLATISS, get_scripts_dir from lsst.ts.observatory.control.mock import LATISSMock -from lsst.ts.standardscripts.auxtel import OfflineLATISS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "offline_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "offline_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_offset_ataos.py b/tests/test_auxtel_offset_ataos.py index 69680b703..dca7aa8c9 100644 --- a/tests/test_auxtel_offset_ataos.py +++ b/tests/test_auxtel_offset_ataos.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,9 +24,9 @@ import pytest from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import OffsetATAOS, get_scripts_dir from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel import OffsetATAOS +from lsst.ts.standardscripts import BaseScriptTestCase class TestOffsetATAOS(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -48,7 +48,7 @@ async def setup_mocks(self): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "offset_ataos.py" + script_path = scripts_dir / "offset_ataos.py" self.log.debug(f"Checking for script in {script_path}") await self.check_executable(script_path) diff --git a/tests/test_auxtel_offset_atcs.py b/tests/test_auxtel_offset_atcs.py index f671c7e00..2e735f982 100644 --- a/tests/test_auxtel_offset_atcs.py +++ b/tests/test_auxtel_offset_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,9 +23,9 @@ import pytest from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import OffsetATCS, get_scripts_dir from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel import OffsetATCS +from lsst.ts.standardscripts import BaseScriptTestCase class TestOffsetATCS(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -40,7 +40,7 @@ async def basic_make_script(self, index): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "offset_atcs.py" + script_path = scripts_dir / "offset_atcs.py" self.log.debug(f"Checking for script in {script_path}") await self.check_executable(script_path) diff --git a/tests/test_auxtel_open_dome.py b/tests/test_auxtel_open_dome.py index e6253901a..6b2674e8e 100644 --- a/tests/test_auxtel_open_dome.py +++ b/tests/test_auxtel_open_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,8 +22,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import OpenDome from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import OpenDome class TestOpenDome( @@ -36,8 +37,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "open_dome.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "open_dome.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_open_dropout_door.py b/tests/test_auxtel_open_dropout_door.py index 301afda82..4437aefc4 100644 --- a/tests/test_auxtel_open_dropout_door.py +++ b/tests/test_auxtel_open_dropout_door.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -25,7 +25,8 @@ import pytest from lsst.ts import standardscripts -from lsst.ts.standardscripts.auxtel.atdome import OpenDropoutDoor +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import OpenDropoutDoor class TestOpenDropoutDoor( @@ -110,6 +111,6 @@ async def test_run_script_cannot_determine_wind_speed(self): self.script.atcs.open_dropout_door.assert_awaited_once() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "open_dropout_door.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "open_dropout_door.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_point_azel.py b/tests/test_auxtel_point_azel.py index ec51aca21..dcb4a728e 100644 --- a/tests/test_auxtel_point_azel.py +++ b/tests/test_auxtel_point_azel.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,9 +23,9 @@ import unittest import pytest -from lsst.ts import salobj, standardscripts +from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import PointAzEl, get_scripts_dir from lsst.ts.standardscripts import BaseScriptTestCase -from lsst.ts.standardscripts.auxtel import PointAzEl class TestPointAzEl(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -183,8 +183,8 @@ async def test_run_point_azel_fails(self): self.script.tcs.stop_tracking.assert_awaited_once() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "point_azel.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "point_azel.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_power_off_atcalsys.py b/tests/test_auxtel_power_off_atcalsys.py index 67950c462..f8a433f43 100644 --- a/tests/test_auxtel_power_off_atcalsys.py +++ b/tests/test_auxtel_power_off_atcalsys.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,8 +26,9 @@ import unittest from lsst.ts import salobj, standardscripts, utils +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.calibrations import PowerOffATCalSys from lsst.ts.idl.enums import ATWhiteLight -from lsst.ts.standardscripts.auxtel.calibrations import PowerOffATCalSys random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -129,8 +130,8 @@ async def test_run_without_without_failures(self): assert self.shutter_status.shutterState == ATWhiteLight.ShutterState.CLOSED async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "calibrations" / "power_off_atcalsys.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "calibrations" / "power_off_atcalsys.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_power_on_atcalsys.py b/tests/test_auxtel_power_on_atcalsys.py index 83c47e621..98db5b3b3 100644 --- a/tests/test_auxtel_power_on_atcalsys.py +++ b/tests/test_auxtel_power_on_atcalsys.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,8 +26,9 @@ import unittest from lsst.ts import salobj, standardscripts, utils +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.calibrations import PowerOnATCalSys from lsst.ts.idl.enums import ATMonochromator, ATWhiteLight -from lsst.ts.standardscripts.auxtel.calibrations import PowerOnATCalSys random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -257,8 +258,8 @@ async def test_run_without_atmonochromator_without_failures(self): assert self.shutter_status.shutterState == ATWhiteLight.ShutterState.OPEN async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "calibrations" / "power_on_atcalsys.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "calibrations" / "power_on_atcalsys.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_prepare_for_co2_cleanup.py b/tests/test_auxtel_prepare_for_co2_cleanup.py index 86cd4b41a..4c0ac2eeb 100644 --- a/tests/test_auxtel_prepare_for_co2_cleanup.py +++ b/tests/test_auxtel_prepare_for_co2_cleanup.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,7 +26,8 @@ import pytest from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForCO2Cleanup +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForCO2Cleanup random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -103,8 +104,8 @@ async def test_run_all_defaults(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "prepare_for" / "co2_cleanup.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "prepare_for" / "co2_cleanup.py" await self.check_executable(script_path) async def test_configure_fail_invalid_el_min(self): diff --git a/tests/test_auxtel_prepare_for_flat.py b/tests/test_auxtel_prepare_for_flat.py index 0d29a0e39..093c3b6ae 100644 --- a/tests/test_auxtel_prepare_for_flat.py +++ b/tests/test_auxtel_prepare_for_flat.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForFlat from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForFlat random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -50,8 +51,8 @@ async def test_run(self): # await self.run_script() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "prepare_for" / "flat.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "prepare_for" / "flat.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_prepare_for_onsky.py b/tests/test_auxtel_prepare_for_onsky.py index fc050bd61..0f7f4e306 100644 --- a/tests/test_auxtel_prepare_for_onsky.py +++ b/tests/test_auxtel_prepare_for_onsky.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,9 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForOnSky from lsst.ts.observatory.control.auxtel import ATCS, LATISS, ATCSUsages, LATISSUsages -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForOnSky random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -79,8 +80,8 @@ async def test_configure_ignore_inexistent(self): assert expected_warning_msg in script_logs.output async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "prepare_for" / "onsky.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "prepare_for" / "onsky.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_prepare_for_vent.py b/tests/test_auxtel_prepare_for_vent.py index 4622f2ee0..1db2d9814 100644 --- a/tests/test_auxtel_prepare_for_vent.py +++ b/tests/test_auxtel_prepare_for_vent.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,7 +23,8 @@ from unittest.mock import AsyncMock, Mock, patch from lsst.ts import standardscripts -from lsst.ts.standardscripts.auxtel.prepare_for import PrepareForVent +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.prepare_for import PrepareForVent class TestPrepareForOnSky( @@ -116,8 +117,8 @@ async def test_run(self): self.script.reposition_telescope_and_dome.assert_awaited() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "prepare_for" / "vent.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "prepare_for" / "vent.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_run_calibration_sequence.py b/tests/test_auxtel_run_calibration_sequence.py index 14fa0e67b..2b1f2306d 100644 --- a/tests/test_auxtel_run_calibration_sequence.py +++ b/tests/test_auxtel_run_calibration_sequence.py @@ -23,10 +23,11 @@ import pytest from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.calibrations import RunCalibrationSequence from lsst.ts.observatory.control.auxtel.atcalsys import ATCalsys, ATCalsysUsages from lsst.ts.observatory.control.auxtel.latiss import LATISS, LATISSUsages -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel.calibrations import RunCalibrationSequence +from lsst.ts.standardscripts import BaseScriptTestCase class TestRunCalibrationSequence(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): @@ -60,7 +61,5 @@ async def test_config_fail_if_empty(self): async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = ( - scripts_dir / "auxtel" / "calibrations" / "run_calibration_sequence.py" - ) + script_path = scripts_dir / "calibrations" / "run_calibration_sequence.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_shutdown.py b/tests/test_auxtel_shutdown.py index 0bf50d6d5..eb939b76d 100644 --- a/tests/test_auxtel_shutdown.py +++ b/tests/test_auxtel_shutdown.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import Shutdown, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import Shutdown random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -50,8 +50,8 @@ async def test_run(self): # await self.run_script() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "shutdown.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "shutdown.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_slew_and_take_image_checkout.py b/tests/test_auxtel_slew_and_take_image_checkout.py index 0c7f00442..068314ff0 100644 --- a/tests/test_auxtel_slew_and_take_image_checkout.py +++ b/tests/test_auxtel_slew_and_take_image_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,9 +26,10 @@ import unittest import pytest +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.daytime_checkout import SlewAndTakeImageCheckout from lsst.ts.idl.enums.ATMCS import M3State -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel.daytime_checkout import SlewAndTakeImageCheckout +from lsst.ts.standardscripts import BaseScriptTestCase class TestSlewAndTakeImageCheckout( @@ -113,10 +114,7 @@ async def setup_mocks(self): async def test_executable(self): scripts_dir = get_scripts_dir() script_path = ( - scripts_dir - / "auxtel" - / "daytime_checkout" - / "slew_and_take_image_checkout.py" + scripts_dir / "daytime_checkout" / "slew_and_take_image_checkout.py" ) print(script_path) await self.check_executable(script_path) diff --git a/tests/test_auxtel_slew_dome.py b/tests/test_auxtel_slew_dome.py index e15082e10..d93174cf5 100644 --- a/tests/test_auxtel_slew_dome.py +++ b/tests/test_auxtel_slew_dome.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,9 +23,10 @@ import pytest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.atdome import SlewDome from lsst.ts.idl.enums.Script import ScriptState from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel.atdome import SlewDome class TestSlewDome( @@ -38,8 +39,8 @@ async def basic_make_script(self, index): return (self.script, self.atcs_mock) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "atdome" / "slew_dome.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "atdome" / "slew_dome.py" await self.check_executable(script_path) async def test_config(self): diff --git a/tests/test_auxtel_standby_atcs.py b/tests/test_auxtel_standby_atcs.py index af2ba0523..aa81199f5 100644 --- a/tests/test_auxtel_standby_atcs.py +++ b/tests/test_auxtel_standby_atcs.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import StandbyATCS, get_scripts_dir from lsst.ts.observatory.control.mock import ATCSMock -from lsst.ts.standardscripts.auxtel import StandbyATCS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "standby_atcs.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "standby_atcs.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_standby_latiss.py b/tests/test_auxtel_standby_latiss.py index b286c5054..3f1924528 100644 --- a/tests/test_auxtel_standby_latiss.py +++ b/tests/test_auxtel_standby_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import StandbyLATISS, get_scripts_dir from lsst.ts.observatory.control.mock import LATISSMock -from lsst.ts.standardscripts.auxtel import StandbyLATISS random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -64,8 +64,8 @@ async def test_run(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "standby_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "standby_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_startup.py b/tests/test_auxtel_startup.py index 89499f13a..2957533f5 100644 --- a/tests/test_auxtel_startup.py +++ b/tests/test_auxtel_startup.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,8 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import PrepareForOnSky, get_scripts_dir from lsst.ts.observatory.control.auxtel import ATCS, LATISS, ATCSUsages, LATISSUsages -from lsst.ts.standardscripts.auxtel import PrepareForOnSky random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -57,8 +57,8 @@ async def test_run(self): # await self.run_script() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "prepare_for" / "onsky.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "prepare_for" / "onsky.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_stop.py b/tests/test_auxtel_stop.py index 093772eec..7aa4682fb 100644 --- a/tests/test_auxtel_stop.py +++ b/tests/test_auxtel_stop.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -25,7 +25,7 @@ import unittest from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.auxtel import Stop +from lsst.ts.auxtel.standardscripts import Stop, get_scripts_dir random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -79,8 +79,8 @@ async def test_run(self): assert self.num_calls[name] == 1 async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "stop.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "stop.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_stop_tracking.py b/tests/test_auxtel_stop_tracking.py index 693f94292..f1ea2e782 100644 --- a/tests/test_auxtel_stop_tracking.py +++ b/tests/test_auxtel_stop_tracking.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -22,6 +22,7 @@ import unittest from lsst.ts import standardscripts +from lsst.ts.auxtel.standardscripts import get_scripts_dir class TestStopTracking( @@ -31,8 +32,8 @@ async def basic_make_script(self, index): pass async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "stop_tracking.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "stop_tracking.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_take_image_latiss.py b/tests/test_auxtel_take_image_latiss.py index 8a9e8ffca..4cc7a62a3 100644 --- a/tests/test_auxtel_take_image_latiss.py +++ b/tests/test_auxtel_take_image_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -26,7 +26,7 @@ import pytest from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.auxtel import TakeImageLatiss +from lsst.ts.auxtel.standardscripts import TakeImageLatiss, get_scripts_dir from lsst.ts.xml.enums import Script random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -224,8 +224,8 @@ async def test_take_images_tcs_not_ready(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "take_image_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "take_image_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_take_stuttered_latiss.py b/tests/test_auxtel_take_stuttered_latiss.py index 3f124e249..2e3696efd 100644 --- a/tests/test_auxtel_take_stuttered_latiss.py +++ b/tests/test_auxtel_take_stuttered_latiss.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -23,8 +23,8 @@ import unittest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import TakeStutteredLatiss, get_scripts_dir from lsst.ts.observatory.control.mock import LATISSMock -from lsst.ts.standardscripts.auxtel import TakeStutteredLatiss random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -106,8 +106,8 @@ async def test_run(self): assert self.latiss_mock.nimages == self.script.config.n_images async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "take_stuttered_latiss.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "take_stuttered_latiss.py" await self.check_executable(script_path) diff --git a/tests/test_auxtel_telescope_and_dome_checkout.py b/tests/test_auxtel_telescope_and_dome_checkout.py index a177490d3..b705ef7a2 100644 --- a/tests/test_auxtel_telescope_and_dome_checkout.py +++ b/tests/test_auxtel_telescope_and_dome_checkout.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,8 +24,9 @@ import types import unittest -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.auxtel.daytime_checkout import TelescopeAndDomeCheckout +from lsst.ts.auxtel.standardscripts import get_scripts_dir +from lsst.ts.auxtel.standardscripts.daytime_checkout import TelescopeAndDomeCheckout +from lsst.ts.standardscripts import BaseScriptTestCase class TestTelescopeAndDomeCheckout( @@ -72,10 +73,7 @@ async def setup_mocks(self): async def test_executable(self): scripts_dir = get_scripts_dir() script_path = ( - scripts_dir - / "auxtel" - / "daytime_checkout" - / "telescope_and_dome_checkout.py" + scripts_dir / "daytime_checkout" / "telescope_and_dome_checkout.py" ) print(script_path) await self.check_executable(script_path) diff --git a/tests/test_auxtel_track_target.py b/tests/test_auxtel_track_target.py index a38e7cc4a..2e00abaf9 100644 --- a/tests/test_auxtel_track_target.py +++ b/tests/test_auxtel_track_target.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -24,7 +24,7 @@ import unittest from lsst.ts import standardscripts, utils -from lsst.ts.standardscripts.auxtel import TrackTarget +from lsst.ts.auxtel.standardscripts import TrackTarget, get_scripts_dir from lsst.ts.xml.enums.MTPtg import Planets random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -156,8 +156,8 @@ async def test_run_slew_ephem(self): ) async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "track_target.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "track_target.py" await self.check_executable(script_path) def assert_slew_radec(self): diff --git a/tests/test_auxtel_track_target_and_take_image.py b/tests/test_auxtel_track_target_and_take_image.py index 5554cfff6..0187ac933 100644 --- a/tests/test_auxtel_track_target_and_take_image.py +++ b/tests/test_auxtel_track_target_and_take_image.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -29,8 +29,8 @@ import pytest from lsst.ts import salobj, standardscripts +from lsst.ts.auxtel.standardscripts import TrackTargetAndTakeImage, get_scripts_dir from lsst.ts.observatory.control.utils import RotType -from lsst.ts.standardscripts.auxtel import TrackTargetAndTakeImage random.seed(47) # for set_random_lsst_dds_partition_prefix @@ -340,8 +340,8 @@ async def test_run_fail_assert_feasibility(self): self.script.atcs.stop_tracking.assert_awaited_once() async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "track_target_and_take_image.py" + scripts_dir = get_scripts_dir() + script_path = scripts_dir / "track_target_and_take_image.py" await self.check_executable(script_path) @contextlib.asynccontextmanager diff --git a/tests/test_base_block_script.py b/tests/test_base_block_script.py deleted file mode 100644 index 91dc18ec7..000000000 --- a/tests/test_base_block_script.py +++ /dev/null @@ -1,574 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import os -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel import MoveP2P -from lsst.ts.utils import ImageNameServiceClient - - -class TestBaseBlockScript( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - """Test BaseBlockScript using the MoveP2P script.""" - - async def basic_make_script(self, index): - self.script = MoveP2P(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.components_attr = ["mtm1m3"] - yield - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_name_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(name="LVV-T2190") - with pytest.raises( - salobj.ExpectedError, match="'execution' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_execution_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(execution="LVV-E2390") - with pytest.raises( - salobj.ExpectedError, match="'name' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_version_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(version="1.0") - with pytest.raises( - salobj.ExpectedError, match="'name' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_name_execution_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(name="LVV-T2190", execution="LVV-E2390") - with pytest.raises( - salobj.ExpectedError, match="'version' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_name_version_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(name="LVV-T2190", version="1.0") - with pytest.raises( - salobj.ExpectedError, match="'execution' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_fail_test_case_program_version_only(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(execution="LVV-E2390", version="1.0") - with pytest.raises( - salobj.ExpectedError, match="'name' is a required property" - ): - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_reason_program(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert self.script.test_case is None - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-123 202306060001 SITCOM-321" - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_reason_program_test_case(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict(name="LVV-T2190", execution="LVV-E2390", version="1.0") - - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert self.script.test_case["name"] == test_case["name"] - assert self.script.test_case["execution"] == test_case["execution"] - assert self.script.test_case["version"] == test_case["version"] - assert "initial_step" not in self.script.test_case - assert "project" not in self.script.test_case - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-123 202306060001 SITCOM-321" - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_reason_program_test_case_initial_step(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict( - name="LVV-T2190", execution="LVV-E2390", version="1.0", initial_step=10 - ) - - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert self.script.test_case["name"] == test_case["name"] - assert self.script.test_case["execution"] == test_case["execution"] - assert self.script.test_case["version"] == test_case["version"] - assert self.script.test_case["initial_step"] == test_case["initial_step"] - assert "project" not in self.script.test_case - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-123 202306060001 SITCOM-321" - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_reason_program_test_case_project(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - test_case = dict( - name="LVV-T2190", execution="LVV-E2390", version="1.0", project="SITCOM" - ) - - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert self.script.test_case["name"] == test_case["name"] - assert self.script.test_case["execution"] == test_case["execution"] - assert self.script.test_case["version"] == test_case["version"] - assert "initial_step" not in self.script.test_case - assert self.script.test_case["project"] == test_case["project"] - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-123 202306060001 SITCOM-321" - ) - - @unittest.mock.patch.dict(os.environ, {"LSST_SITE": "summit"}) - @unittest.mock.patch.object( - ImageNameServiceClient, - "get_next_obs_id", - return_value=(None, ["BL123-202306060001"]), - ) - async def test_get_obs_id_block_ticket(self, mock_get_next_obs_id): - async with self.make_dry_script(): - program = "BLOCK-123" - self.script.program = program - - obs_id = await self.script.get_obs_id() - assert obs_id is not None - assert obs_id.startswith("BL123") - - # Assuming obs_is for test cases will start with BT - @unittest.mock.patch.dict(os.environ, {"LSST_SITE": "summit"}) - @unittest.mock.patch.object( - ImageNameServiceClient, - "get_next_obs_id", - return_value=(None, ["BT123-202306060001"]), - ) - async def test_get_obs_id_block_test_case(self, mock_get_next_obs_id): - async with self.make_dry_script(): - program = "BLOCK-T123" - self.script.program = program - - obs_id = await self.script.get_obs_id() - assert obs_id is not None - assert obs_id.startswith("BT123") - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_reason_program_block_test_case(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-T123" - reason = "SITCOM-321" - test_case = dict( - name="BLOCK-T2190", - execution="BLOCK-E2390", - version="1.0", - project="SITCOM", - ) - - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - test_case=test_case, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert self.script.test_case["name"] == test_case["name"] - assert self.script.test_case["execution"] == test_case["execution"] - assert self.script.test_case["version"] == test_case["version"] - assert "initial_step" not in self.script.test_case - assert self.script.test_case["project"] == test_case["project"] - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-T123 202306060001 SITCOM-321" - ) - - async def test_run_no_test_case(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - ra = [0.0, 10.0, 20.0] - dec = [80.0, 70.0, 60.0] - timeout = 100.0 - program = "BLOCK-T123" - reason = "SITCOM-321" - - await self.configure_script( - ra=ra, - dec=dec, - program=program, - reason=reason, - move_timeout=timeout, - ) - - await self.run_script() - - expected_calls = [ - unittest.mock.call(ra=_ra, dec=_dec, timeout=timeout) - for _ra, _dec in zip(ra, dec) - ] - self.script.mtcs.move_p2p_radec.assert_has_awaits(expected_calls) - - assert not self.script.evt_largeFileObjectAvailable.has_data - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_run_with_test_case(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - ra = [0.0, 10.0, 20.0] - dec = [80.0, 70.0, 60.0] - program = "BLOCK-T123" - reason = "SITCOM-321" - timeout = 100.0 - test_case = dict( - name="BLOCK-T2190", - execution="BLOCK-E2390", - version="1.0", - project="BLOCK", - ) - - await self.configure_script( - ra=ra, - dec=dec, - program=program, - reason=reason, - test_case=test_case, - move_timeout=timeout, - ) - - await self.run_script() - - expected_calls = [ - unittest.mock.call(ra=_ra, dec=_dec, timeout=timeout) - for _ra, _dec in zip(ra, dec) - ] - self.script.mtcs.move_p2p_radec.assert_has_awaits(expected_calls) - - assert len(self.script.step_results) == len(ra) - assert self.script.evt_largeFileObjectAvailable.has_data - assert self.script.evt_largeFileObjectAvailable.data.id == "202306060001" - assert self.script.evt_largeFileObjectAvailable.data.url.endswith( - f"{test_case['name']}_202306060001.json" - ) - assert ( - self.script.evt_largeFileObjectAvailable.data.generator - == test_case["name"] - ) - assert self.script.evt_largeFileObjectAvailable.data.mimeType == "JSON" - assert self.script.evt_largeFileObjectAvailable.data.byteSize > 0 - - for test_step in self.script.step_results: - assert test_step["status"] == "PASSED" - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_run_fail_with_test_case(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - self.script.mtcs.configure_mock( - **{ - "move_p2p_radec.side_effect": [ - None, - RuntimeError("Something went wrong."), - ] - } - ) - - ra = [0.0, 10.0, 20.0] - dec = [80.0, 70.0, 60.0] - program = "BLOCK-123" - reason = "SITCOM-321" - timeout = 1200.0 - test_case = dict( - name="LVV-T2190", execution="LVV-E2390", version="1.0", project="SITCOM" - ) - - await self.configure_script( - ra=ra, - dec=dec, - program=program, - reason=reason, - test_case=test_case, - move_timeout=timeout, - ) - - with pytest.raises(AssertionError): - await self.run_script() - - expected_calls = [ - unittest.mock.call(ra=_ra, dec=_dec, timeout=timeout) - for _ra, _dec in zip(ra, dec) - ] - expected_calls.pop(-1) - self.script.mtcs.move_p2p_radec.assert_has_awaits(expected_calls) - - assert len(self.script.step_results) == len(ra) - 1 - assert self.script.evt_largeFileObjectAvailable.has_data - assert self.script.evt_largeFileObjectAvailable.data.id == "202306060001" - assert self.script.evt_largeFileObjectAvailable.data.url.endswith( - f"{test_case['name']}_202306060001.json" - ) - assert ( - self.script.evt_largeFileObjectAvailable.data.generator - == test_case["name"] - ) - assert self.script.evt_largeFileObjectAvailable.data.mimeType == "JSON" - assert self.script.evt_largeFileObjectAvailable.data.byteSize > 0 - - for test_step, expected_status in zip( - self.script.step_results, ["PASSED", "FAILED"] - ): - assert test_step["status"] == expected_status diff --git a/tests/test_maintel_apply_dof.py b/tests/test_maintel_apply_dof.py deleted file mode 100644 index cec7c05f1..000000000 --- a/tests/test_maintel_apply_dof.py +++ /dev/null @@ -1,107 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import types -import unittest - -import numpy as np -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils.enums import DOFName -from lsst.ts.standardscripts.maintel import ApplyDOF - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestApplyDOF( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = ApplyDOF(index=index) - - # Mock the MTCS - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - self.script.mtcs.rem.mtaos = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtaos.cmd_offsetDOF.attach_mock( - unittest.mock.Mock( - return_value=types.SimpleNamespace(value=np.zeros(len(DOFName))) - ), - "DataType", - ) - - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_configure(self) -> None: - # Try configure with minimum set of parameters declared - async with self.make_script(): - config_dofs = {"M2_dz": 0.2, "Cam_dy": 0.3, "M1M3_B1": 0.5, "M2_B14": 0.7} - - await self.configure_script(**config_dofs) - - dofs = np.zeros(len(DOFName)) - for key, value in config_dofs.items(): - dofs[getattr(DOFName, key)] = value - - assert all(self.script.dofs == dofs) - - async def test_configure_with_dofs_vector(self) -> None: - async with self.make_script(): - dofs = [0] * len(DOFName) - config_dofs = { - "M2_dz": 0.2, - "Cam_dy": 0.3, - "M1M3_B1": 0.5, - "M2_B14": 0.7, - "dofs": dofs, - } - - await self.configure_script(**config_dofs) - - assert self.script.dofs == dofs - - async def test_run(self) -> None: - # Start the test itself - async with self.make_script(): - config_dofs = {"M2_dz": 0.2, "Cam_dy": 0.3, "M1M3_B1": 0.5, "M2_B14": 0.7} - - await self.configure_script(**config_dofs) - - # Run the script - await self.run_script() - - self.script.mtcs.rem.mtaos.cmd_offsetDOF.DataType.assert_called() - self.script.mtcs.rem.mtaos.cmd_offsetDOF.start.assert_awaited_once() - - async def test_executable(self) -> None: - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "apply_dof.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_close_loop_lsstcam.py b/tests/test_maintel_close_loop_lsstcam.py deleted file mode 100644 index a9f868cb6..000000000 --- a/tests/test_maintel_close_loop_lsstcam.py +++ /dev/null @@ -1,179 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -import numpy as np -import yaml -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.lsstcam import LSSTCam, LSSTCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils.enums import ClosedLoopMode -from lsst.ts.standardscripts.maintel import CloseLoopLSSTCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestCloseLoopLSSTCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = CloseLoopLSSTCam(index=index) - - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - - self.script._camera = LSSTCam( - domain=self.script.domain, - intended_usage=LSSTCamUsages.DryTest, - log=self.script.log, - ) - - # MTCS mocks - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.offset_camera_hexapod = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtrotator = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtrotator.configure_mock( - **{ - "tel_rotation.next.return_value": types.SimpleNamespace( - actualPosition=0.0 - ), - } - ) - - # MTAOS mocks - self.script.mtcs.rem.mtaos = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtaos.configure_mock( - **{ - "cmd_runWEP.set_start": unittest.mock.AsyncMock(), - "cmd_runOFC.set_start": self.get_offsets, - "evt_wavefrontError.next": self.return_zernikes, - "evt_degreeOfFreedom.next": self.return_offsets, - "cmd_issueCorrection.start": self.apply_offsets, - "evt_wavefrontError.flush": unittest.mock.AsyncMock(), - } - ) - - # Camera mocks - self.script.camera.assert_all_enabled = unittest.mock.AsyncMock() - self.script.camera.take_acq = unittest.mock.AsyncMock() - self.script.camera.take_cwfs = unittest.mock.AsyncMock() - - self.script.assert_mode_compatibility = unittest.mock.AsyncMock() - - self.state_0 = np.zeros(50) - self.state_0[:5] += 1 - - self.corrections = types.SimpleNamespace(visitDoF=np.zeros(50)) - - return (self.script,) - - async def return_zernikes(self, *args, **kwargs): - return np.random.rand(19) - - async def return_offsets(self, *args, **kwargs): - return self.corrections - - async def apply_offsets(self, *args, **kwags): - await asyncio.sleep(0.5) - self.state_0 += self.corrections.visitDoF - - async def get_offsets(self, *args, **kwags): - # return corrections to be non zero the first time this is called - await asyncio.sleep(0.5) - self.corrections = types.SimpleNamespace(visitDoF=np.zeros(50)) - - if any(self.state_0): - self.corrections.visitDoF[:5] -= 0.5 - - async def test_configure(self): - # Try configure with minimum set of parameters declared - async with self.make_script(): - mode = "CWFS" - max_iter = 10 - exposure_time = 30 - filter = "r" - used_dofs = ["M2_dz", "M2_dx", "M2_dy", "M2_rx", "M2_ry"] - threshold = [0.005] * 50 - apply_corrections = True - - await self.configure_script( - mode=mode, - max_iter=max_iter, - exposure_time=exposure_time, - filter=filter, - used_dofs=used_dofs, - threshold=threshold, - apply_corrections=apply_corrections, - ) - - assert self.script.mode == ClosedLoopMode.CWFS - assert self.script.max_iter == max_iter - assert self.script.exposure_time == exposure_time - assert self.script.filter == filter - - configured_dofs = np.zeros(50) - configured_dofs[:5] += 1 - assert all(self.script.used_dofs == configured_dofs) - assert self.script.threshold == threshold - assert self.script.apply_corrections == apply_corrections - - async def test_configure_wep_config(self): - async with self.make_script(): - wep_config_dic = {"field1": "val1", "field2": "val2"} - await self.configure_script(wep_config=wep_config_dic, filter="r") - assert self.script.wep_config == yaml.dump(wep_config_dic) - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script( - max_iter=10, - filter="r", - used_dofs=[0, 1, 2, 3, 4], - ) - - # Run the script - await self.run_script() - - assert all(self.state_0 == np.zeros(50)) - - async def test_executable_close_loop_lsstcam(self) -> None: - """Test that the script is executable for LSSTCam.""" - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "close_loop_lsstcam.py" - await self.check_executable(script_path) - - async def test_executable_close_loop_comcam(self) -> None: - """Test that the script is executable for ComCam.""" - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "close_loop_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_close_mirror_covers.py b/tests/test_maintel_close_mirror_covers.py deleted file mode 100644 index cdc155977..000000000 --- a/tests/test_maintel_close_mirror_covers.py +++ /dev/null @@ -1,75 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import CloseMirrorCovers - - -class TestCloseMirrorCovers( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = CloseMirrorCovers(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.close_m1_cover = unittest.mock.AsyncMock() - yield - - async def test_run(self): - async with self.make_dry_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.assert_all_enabled.assert_awaited_once() - self.script.mtcs.close_m1_cover.assert_awaited_once() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "close_mirror_covers.py" - await self.check_executable(script_path) - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(ignore=components) - - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_csc_component(self): - async with self.make_script(): - components = ["not_csc_comp", "mtptg"] - await self.configure_script(ignore=components) - - assert hasattr(self.script.mtcs, "not_csc_comp") is False - assert self.script.mtcs.check.mtptg is False - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_disable_dome_following.py b/tests/test_maintel_disable_dome_following.py deleted file mode 100644 index 4d4bc8cdc..000000000 --- a/tests/test_maintel_disable_dome_following.py +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtdome import DisableDomeFollowing - - -class TestDisableDomeFollowing( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = DisableDomeFollowing(index=index) - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "disable_dome_following.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_disable_hexapod_compensation_mode.py b/tests/test_maintel_disable_hexapod_compensation_mode.py deleted file mode 100644 index f38e9bcc1..000000000 --- a/tests/test_maintel_disable_hexapod_compensation_mode.py +++ /dev/null @@ -1,117 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts, utils -from lsst.ts.standardscripts.maintel.disable_hexapod_compensation_mode import ( - DisableHexapodCompensationMode, -) - - -class TestDisableHexapodCompensationMode( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = DisableHexapodCompensationMode(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.start_task = utils.make_done_future() - self.script.mtcs.disable_compensation_mode = unittest.mock.AsyncMock() - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.disable_compensation_for_hexapod = ( - unittest.mock.AsyncMock() - ) - yield - - async def test_configure_good(self): - async with self.make_dry_script(): - components = ["M2Hexapod", "CameraHexapod"] - await self.configure_script(components=components) - - async def test_configure_invalid(self): - async with self.make_dry_script(): - components = ["InvalidComponent"] - with pytest.raises(salobj.ExpectedError): - await self.configure_script(components=components) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - components = ["M2Hexapod", "CameraHexapod"] - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - components=components, - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "DisableHexapodCompensationMode BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run(self): - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - components = ["M2Hexapod", "CameraHexapod"] - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - components=components, - program=program, - reason=reason, - ) - await self.run_script() - - hexapods = [self.script.component_to_hexapod(comp) for comp in components] - expected_calls = [unittest.mock.call(hexapod) for hexapod in hexapods] - - self.script.mtcs.disable_compensation_mode.assert_has_awaits( - expected_calls, any_order=True - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "disable_hexapod_compensation_mode.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_disable_m1m3_balance_system.py b/tests/test_maintel_disable_m1m3_balance_system.py deleted file mode 100644 index e758372de..000000000 --- a/tests/test_maintel_disable_m1m3_balance_system.py +++ /dev/null @@ -1,86 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.m1m3 import DisableM1M3BalanceSystem - - -class TestDisableM1M3BalanceSystem( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = DisableM1M3BalanceSystem(index=index) - - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - - self.script.mtcs.disable_m1m3_balance_system = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.disable_m1m3_balance_system.assert_awaited_once() - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "DisableM1M3BalanceSystem BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = ( - scripts_dir / "maintel" / "m1m3" / "disable_m1m3_balance_system.py" - ) - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_enable_comcam.py b/tests/test_maintel_enable_comcam.py deleted file mode 100644 index e6b033760..000000000 --- a/tests/test_maintel_enable_comcam.py +++ /dev/null @@ -1,74 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import random -import unittest - -from lsst.ts import salobj, standardscripts -from lsst.ts.observatory.control.mock import ComCamMock -from lsst.ts.standardscripts.maintel import EnableComCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestEnableComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableComCam(index=index) - self.mock = ComCamMock() - - return (self.script, self.mock) - - async def test_components(self): - async with self.make_script(): - for component in self.script.group.components_attr: - with self.subTest(f"Check {component}", component=component): - if getattr(self.script.group.check, component): - assert component in self.script.components() - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - - for comp in self.script.group.components_attr: - if getattr(self.script.group.check, comp): - with self.subTest(f"{comp} summary state", comp=comp): - assert ( - getattr( - self.mock.controllers, comp - ).evt_summaryState.data.summaryState - == salobj.State.ENABLED - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "enable_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_enable_dome_following.py b/tests/test_maintel_enable_dome_following.py deleted file mode 100644 index 4780ece69..000000000 --- a/tests/test_maintel_enable_dome_following.py +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtdome import EnableDomeFollowing - - -class TestEnableDomeFollowing( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableDomeFollowing(index=index) - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "enable_dome_following.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_enable_hexapod_compensation_mode.py b/tests/test_maintel_enable_hexapod_compensation_mode.py deleted file mode 100644 index 56e725672..000000000 --- a/tests/test_maintel_enable_hexapod_compensation_mode.py +++ /dev/null @@ -1,115 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts, utils -from lsst.ts.standardscripts.maintel.enable_hexapod_compensation_mode import ( - EnableHexapodCompensationMode, -) - - -class TestEnableHexapodCompensationMode( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableHexapodCompensationMode(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.start_task = utils.make_done_future() - self.script.mtcs.enable_compensation_mode = unittest.mock.AsyncMock() - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.enable_compensation_for_hexapod = unittest.mock.AsyncMock() - yield - - async def test_configure_good(self): - async with self.make_dry_script(): - components = ["M2Hexapod", "CameraHexapod"] - await self.configure_script(components=components) - - async def test_configure_invalid(self): - async with self.make_dry_script(): - components = ["InvalidComponent"] - with pytest.raises(salobj.ExpectedError): - await self.configure_script(components=components) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060002"] - ) - components = ["M2Hexapod", "CameraHexapod"] - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - components=components, - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "EnableHexapodCompensationMode BLOCK-123 202306060002 SITCOM-321" - ) - - async def test_run(self): - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060002"] - ) - components = ["M2Hexapod", "CameraHexapod"] - program = "BLOCK-124" - reason = "SITCOM-322" - await self.configure_script( - components=components, - program=program, - reason=reason, - ) - await self.run_script() - - hexapods = [self.script.component_to_hexapod(comp) for comp in components] - expected_calls = [unittest.mock.call(hexapod) for hexapod in hexapods] - - self.script.mtcs.enable_compensation_mode.assert_has_awaits( - expected_calls, any_order=True - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "enable_hexapod_compensation_mode.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_enable_m1m3_balance_system.py b/tests/test_maintel_enable_m1m3_balance_system.py deleted file mode 100644 index f42ae1df3..000000000 --- a/tests/test_maintel_enable_m1m3_balance_system.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.m1m3 import EnableM1M3BalanceSystem - - -class TestEnableM1M3BalanceSystem( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableM1M3BalanceSystem(index=index) - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - - self.script.mtcs.enable_m1m3_balance_system = unittest.mock.AsyncMock() - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.enable_m1m3_balance_system.assert_awaited_once() - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "EnableM1M3BalanceSystem BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m1m3" / "enable_m1m3_balance_system.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_enable_mtcs.py b/tests/test_maintel_enable_mtcs.py deleted file mode 100644 index 48112ccab..000000000 --- a/tests/test_maintel_enable_mtcs.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import EnableMTCS - - -class TestEnableMTCS( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableMTCS(index=index) - - return (self.script,) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "enable_mtcs.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_focus_sweep_comcam.py b/tests/test_maintel_focus_sweep_comcam.py deleted file mode 100644 index 55944a0b8..000000000 --- a/tests/test_maintel_focus_sweep_comcam.py +++ /dev/null @@ -1,302 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest -import unittest.mock as mock - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel.focus_sweep_comcam import FocusSweepComCam - - -class TestFocusSweepComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = FocusSweepComCam(index=index) - - self.mock_mtcs() - self.mock_camera() - self.mock_ocps() - - return (self.script,) - - def mock_mtcs(self): - """Mock MTCS instances and its methods.""" - self.script.mtcs = mock.AsyncMock() - self.script.mtcs.assert_liveliness = mock.AsyncMock() - self.script.mtcs.assert_all_enabled = mock.AsyncMock() - self.script.mtcs.offset_camera_hexapod = mock.AsyncMock() - self.script.mtcs.offset_m2_hexapod = mock.AsyncMock() - - def mock_camera(self): - """Mock camera instance and its methods.""" - self.script.comcam = mock.AsyncMock() - self.script.comcam.assert_liveliness = mock.AsyncMock() - self.script.comcam.assert_all_enabled = mock.AsyncMock() - self.script.comcam.take_focus = mock.AsyncMock(return_value=[1234]) - - def mock_ocps(self): - """Mock OCPS instance and its methods.""" - self.script.ocps = mock.Mock() - self.script.ocps.cmd_execute = mock.Mock() - self.script.ocps.cmd_execute.set_start = mock.AsyncMock() - - async def test_configure(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 1000 - assert self.script.config.n_steps == 11 - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_focus_step_sequence(self): - config = { - "axis": "z", - "focus_step_sequence": [-200, -100, 0, 100, 200], - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - expected_step_sequence = [-200, -100, 0, 100, 200] - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 400 - assert self.script.config.n_steps == 5 - assert self.script.config.focus_step_sequence == expected_step_sequence - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_focus_step_sequence_with_window(self): - config = { - "axis": "z", - "focus_window": 400, - "n_steps": 5, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - expected_step_sequence = [-200, -100, 0, 100, 200] - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 400 - assert self.script.config.n_steps == 5 - assert self.script.config.focus_step_sequence == expected_step_sequence - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_ignore(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - "ignore": ["mtm1m3", "mtrotator"], - } - - async with self.make_script(): - # Mock the components_attr to contain the ignored components - self.script.mtcs.components_attr = ["mtm1m3", "mtrotator"] - self.script.camera.components_attr = [] - - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 1000 - assert self.script.config.n_steps == 11 - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - # Verify that the ignored components are correctly set to False - assert not self.script.mtcs.check.mtm1m3 - assert not self.script.mtcs.check.mtrotator - - async def test_invalid_configuration(self): - bad_configs = [ - { - "axis": "invalid_axis", - "focus_window": 1000, - "n_steps": 100, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - }, - { - "axis": "z", - "focus_window": 1000, - "n_steps": 1, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - }, - ] - - async with self.make_script(): - for bad_config in bad_configs: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_invalid_configuration_steps_and_window(self): - bad_config = { - "axis": "z", - "focus_window": 400, - "n_steps": 5, - "focus_step_sequence": [-200, -100, 0, 100, 200], - "exp_time": 15, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_focus_sweep(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - await self.run_script() - - # Check if the hexapod moved the expected number of times - assert ( - self.script.mtcs.offset_camera_hexapod.call_count - == config["n_steps"] + 1 - ) - - # Assert the offset_m2_hexapod was not called - self.script.mtcs.offset_m2_hexapod.assert_not_called() - - # Check if the camera took the expected number of images - assert self.script.comcam.take_focus.call_count == config["n_steps"] - - # Check if the OCPS command was called - self.script.ocps.cmd_execute.set_start.assert_called_once() - - async def test_focus_sweep_sim_mode(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 3, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "M2", - "sim": True, - } - - async with self.make_script(): - await self.configure_script(**config) - await self.run_script() - - # Check if the hexapod moved the expected number of times - assert ( - self.script.mtcs.offset_m2_hexapod.call_count == config["n_steps"] + 1 - ) - - # Asert that the offset_camera_hexapod was not called - self.script.mtcs.offset_camera_hexapod.assert_not_called() - - # Check if the camera took the expected number of images - assert self.script.comcam.take_focus.call_count == config["n_steps"] - - # Check if the OCPS command was called - self.script.ocps.cmd_execute.set_start.assert_called_once() - - # Verify that simulation mode is set correctly - assert self.script.comcam.simulation_mode - - async def test_cleanup(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - - # Simulate an error during the focus sweep to trigger cleanup - self.script.iterations_started = True - self.script.total_focus_offset = 1000 # Simulate some offset - with mock.patch.object( - self.script, "focus_sweep", side_effect=Exception("Test exception") - ): - with pytest.raises(Exception): - await self.script.run_block() - - await self.script.cleanup() - - # Ensure the hexapod is returned to the original position - self.script.mtcs.offset_camera_hexapod.assert_any_call( - x=0, y=0, z=-self.script.total_focus_offset, u=0, v=0, w=0 - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "focus_sweep_comcam.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_focus_sweep_lsstcam.py b/tests/test_maintel_focus_sweep_lsstcam.py deleted file mode 100644 index 2aac0d366..000000000 --- a/tests/test_maintel_focus_sweep_lsstcam.py +++ /dev/null @@ -1,302 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest -import unittest.mock as mock - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel.focus_sweep_lsstcam import FocusSweepLSSTCam - - -class TestFocusSweepLSSTCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = FocusSweepLSSTCam(index=index) - - self.mock_mtcs() - self.mock_camera() - self.mock_ocps() - - return (self.script,) - - def mock_mtcs(self): - """Mock MTCS instances and its methods.""" - self.script.mtcs = mock.AsyncMock() - self.script.mtcs.assert_liveliness = mock.AsyncMock() - self.script.mtcs.assert_all_enabled = mock.AsyncMock() - self.script.mtcs.offset_camera_hexapod = mock.AsyncMock() - self.script.mtcs.offset_m2_hexapod = mock.AsyncMock() - - def mock_camera(self): - """Mock camera instance and its methods.""" - self.script.lsstcam = mock.AsyncMock() - self.script.lsstcam.assert_liveliness = mock.AsyncMock() - self.script.lsstcam.assert_all_enabled = mock.AsyncMock() - self.script.lsstcam.take_focus = mock.AsyncMock(return_value=[1234]) - - def mock_ocps(self): - """Mock OCPS instance and its methods.""" - self.script.ocps = mock.Mock() - self.script.ocps.cmd_execute = mock.Mock() - self.script.ocps.cmd_execute.set_start = mock.AsyncMock() - - async def test_configure(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 1000 - assert self.script.config.n_steps == 11 - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_focus_step_sequence(self): - config = { - "axis": "z", - "focus_step_sequence": [-200, -100, 0, 100, 200], - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - expected_step_sequence = [-200, -100, 0, 100, 200] - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 400 - assert self.script.config.n_steps == 5 - assert self.script.config.focus_step_sequence == expected_step_sequence - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_focus_step_sequence_with_window(self): - config = { - "axis": "z", - "focus_window": 400, - "n_steps": 5, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - expected_step_sequence = [-200, -100, 0, 100, 200] - async with self.make_script(): - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 400 - assert self.script.config.n_steps == 5 - assert self.script.config.focus_step_sequence == expected_step_sequence - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - async def test_configure_ignore(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - "ignore": ["mtm1m3", "mtrotator"], - } - - async with self.make_script(): - # Mock the components_attr to contain the ignored components - self.script.mtcs.components_attr = ["mtm1m3", "mtrotator"] - self.script.camera.components_attr = [] - - await self.configure_script(**config) - - assert self.script.config.axis == "z" - assert self.script.config.focus_window == 1000 - assert self.script.config.n_steps == 11 - assert self.script.config.exp_time == 15.0 - assert self.script.config.filter == "g" - assert self.script.config.n_images_per_step == 1 - assert self.script.hexapod == "Camera" - - # Verify that the ignored components are correctly set to False - assert not self.script.mtcs.check.mtm1m3 - assert not self.script.mtcs.check.mtrotator - - async def test_invalid_configuration(self): - bad_configs = [ - { - "axis": "invalid_axis", - "focus_window": 1000, - "n_steps": 100, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - }, - { - "axis": "z", - "focus_window": 1000, - "n_steps": 1, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - }, - ] - - async with self.make_script(): - for bad_config in bad_configs: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_invalid_configuration_steps_and_window(self): - bad_config = { - "axis": "z", - "focus_window": 400, - "n_steps": 5, - "focus_step_sequence": [-200, -100, 0, 100, 200], - "exp_time": 15, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_focus_sweep(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - await self.run_script() - - # Check if the hexapod moved the expected number of times - assert ( - self.script.mtcs.offset_camera_hexapod.call_count - == config["n_steps"] + 1 - ) - - # Assert the offset_m2_hexapod was not called - self.script.mtcs.offset_m2_hexapod.assert_not_called() - - # Check if the camera took the expected number of images - assert self.script.lsstcam.take_focus.call_count == config["n_steps"] - - # Check if the OCPS command was called - self.script.ocps.cmd_execute.set_start.assert_called_once() - - async def test_focus_sweep_sim_mode(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 3, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "M2", - "sim": True, - } - - async with self.make_script(): - await self.configure_script(**config) - await self.run_script() - - # Check if the hexapod moved the expected number of times - assert ( - self.script.mtcs.offset_m2_hexapod.call_count == config["n_steps"] + 1 - ) - - # Asert that the offset_camera_hexapod was not called - self.script.mtcs.offset_camera_hexapod.assert_not_called() - - # Check if the camera took the expected number of images - assert self.script.lsstcam.take_focus.call_count == config["n_steps"] - - # Check if the OCPS command was called - self.script.ocps.cmd_execute.set_start.assert_called_once() - - # Verify that simulation mode is set correctly - assert self.script.lsstcam.simulation_mode - - async def test_cleanup(self): - config = { - "axis": "z", - "focus_window": 1000, - "n_steps": 11, - "exp_time": 15.0, - "filter": "g", - "n_images_per_step": 1, - "hexapod": "Camera", - } - - async with self.make_script(): - await self.configure_script(**config) - - # Simulate an error during the focus sweep to trigger cleanup - self.script.iterations_started = True - self.script.total_focus_offset = 1000 # Simulate some offset - with mock.patch.object( - self.script, "focus_sweep", side_effect=Exception("Test exception") - ): - with pytest.raises(Exception): - await self.script.run_block() - - await self.script.cleanup() - - # Ensure the hexapod is returned to the original position - self.script.mtcs.offset_camera_hexapod.assert_any_call( - x=0, y=0, z=-self.script.total_focus_offset, u=0, v=0, w=0 - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "focus_sweep_lsstcam.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_home_both_axes.py b/tests/test_maintel_home_both_axes.py deleted file mode 100644 index 3d083c284..000000000 --- a/tests/test_maintel_home_both_axes.py +++ /dev/null @@ -1,119 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest -from unittest.mock import patch - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel import HomeBothAxes - - -class TestHomeBothAxes( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = HomeBothAxes(index=index) - - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - self.script.mtcs.rem.mtmount = unittest.mock.AsyncMock() - self.script.mtcs.lower_m1m3 = unittest.mock.AsyncMock() - self.script.mtcs.disable_m1m3_balance_system = unittest.mock.AsyncMock() - self.script.mtcs.enable_m1m3_balance_system = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - - self.script.mtcs.disable_m1m3_balance_system.assert_not_called() - self.script.mtcs.rem.mtmount.cmd_homeBothAxes.start.assert_awaited_once_with( - timeout=self.script.home_both_axes_timeout - ) - - async def test_run_with_balance_disabled(self): - async with self.make_script(): - await self.configure_script(disable_m1m3_force_balance=True) - - await self.run_script() - - self.script.mtcs.disable_m1m3_balance_system.assert_awaited_once() - - self.script.mtcs.rem.mtmount.cmd_homeBothAxes.start.assert_awaited_once_with( - timeout=self.script.home_both_axes_timeout - ) - - async def test_deprecated_ignore_m1m3_usage(self): - async with self.make_script(): - - with patch.object(self.script.log, "warning") as mock_log_warning: - await self.configure_script(ignore_m1m3=True) - - mock_log_warning.assert_called_once_with( - "The 'ignore_m1m3' configuration property is deprecated and will be removed" - " in future releases. Please use 'disable_m1m3_force_balance' instead.", - DeprecationWarning, - stacklevel=2, - ) - - await self.run_script() - - self.script.mtcs.disable_m1m3_balance_system.assert_not_called() - - self.script.mtcs.rem.mtmount.cmd_homeBothAxes.start.assert_awaited_once_with( - timeout=self.script.home_both_axes_timeout - ) - - async def ttest_deprecated_ignore_m1m3_usage(self): - async with self.make_script(): - - with self.assertWarns(DeprecationWarning) as cm: - await self.configure_script(ignore_m1m3=True) - - self.assertIn( - "The 'ignore_m1m3' configuration property is deprecated and will be removed" - " in future releases. Please use 'disable_m1m3_force_balance' instead.", - str(cm.warning), - ) - - await self.run_script() - - # Assert that homeBothAxes command was called - self.script.mtcs.rem.mtmount.cmd_homeBothAxes.start.assert_awaited_once_with( - timeout=self.script.home_both_axes_timeout - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "home_both_axes.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_lasertracker_align.py b/tests/test_maintel_lasertracker_align.py deleted file mode 100644 index 65b5755ed..000000000 --- a/tests/test_maintel_lasertracker_align.py +++ /dev/null @@ -1,151 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.remote_group import RemoteGroup, Usages -from lsst.ts.salobj import State -from lsst.ts.standardscripts.maintel.laser_tracker import Align, AlignComponent - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestAlign(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = Align(index=index) - self.script.laser_tracker = RemoteGroup( - domain=self.script.domain, - components=["LaserTracker:1"], - intended_usage=Usages.DryTest, - log=self.script.log, - ) - - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.configure_mock( - **{ - "offset_m2_hexapod": self.apply_offsets, - "offset_camera_hexapod": self.apply_offsets, - } - ) - - self.script.laser_tracker.rem.lasertracker_1 = unittest.mock.AsyncMock() - self.script.laser_tracker.rem.lasertracker_1.configure_mock( - **{ - "evt_offsetsPublish.next": self.get_offsets, - "evt_laserStatus.aget": self.get_laser_status, - "evt_summaryState.aget": self.get_summary_state, - "evt_summaryState.next": self.get_summary_state, - } - ) - - self.state_0 = [1, 1, 1, 1, 1] - self.laser_status = types.SimpleNamespace(status=LaserStatus.ON) - return (self.script,) - - async def get_summary_state(self, *args, **kwargs): - return types.SimpleNamespace(summaryState=State.ENABLED) - - async def get_laser_status(self, *args, **kwags): - await asyncio.sleep(0.5) - return self.laser_status - - async def apply_offsets(self, *args, **kwags): - await asyncio.sleep(0.5) - self.state_0 = [ - self.state_0[idx] + correction for idx, correction in enumerate(args) - ] - - async def get_offsets(self, *args, **kwags): - # return corrections to be non zero the first time this is called - await asyncio.sleep(0.5) - if any(self.state_0): - offsets = types.SimpleNamespace( - dX=0.5e-3, - dY=0.5e-3, - dZ=0.5e-3, - dRX=0.5, - dRY=0.5, - ) - else: - offsets = types.SimpleNamespace( - dX=0.0, - dY=0.0, - dZ=0.0, - dRX=0.0, - dRY=0.0, - ) - - return offsets - - async def test_configure(self): - # Try configure with minimum set of parameters declared - async with self.make_script(): - max_iter = 10 - target = "M2" - tolerance_linear = 1.0e-7 - tolerance_angular = 5.0 / 3600.0 - - await self.configure_script( - max_iter=max_iter, - target=target, - tolerance_linear=tolerance_linear, - tolerance_angular=tolerance_angular, - ) - - assert self.script.max_iter == max_iter - assert self.script.target == getattr(AlignComponent, target) - assert self.script.tolerance_linear == tolerance_linear - assert self.script.tolerance_angular == tolerance_angular - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script( - max_iter=10, - target="M2", - tolerance_angular=5.0 / 3600.0, - ) - - # Run the script - await self.run_script() - - assert self.state_0 == [0, 0, 0, 0, 0] - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "laser_tracker" / "align.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_lasertracker_measure.py b/tests/test_maintel_lasertracker_measure.py deleted file mode 100644 index 80cd8d58f..000000000 --- a/tests/test_maintel_lasertracker_measure.py +++ /dev/null @@ -1,100 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.salobj import State -from lsst.ts.standardscripts.maintel.laser_tracker import AlignComponent, Measure - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestMeasure(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = Measure(index=index, add_remotes=False) - self.script.mtcs = unittest.mock.AsyncMock() - - self.script.laser_tracker.rem.lasertracker_1 = unittest.mock.AsyncMock() - self.script.laser_tracker.rem.lasertracker_1.configure_mock( - **{ - "evt_offsetsPublish.next": self.get_offsets, - "evt_laserStatus.aget": self.get_laser_status, - "evt_summaryState.aget": self.get_summary_state, - "evt_summaryState.next": self.get_summary_state, - } - ) - - self.state_0 = [1, 2, 0, 0, 0] - self.laser_status = types.SimpleNamespace(status=LaserStatus.ON) - return (self.script,) - - async def get_summary_state(self, *args, **kwargs): - return types.SimpleNamespace(summaryState=State.ENABLED) - - async def get_laser_status(self, *args, **kwags): - await asyncio.sleep(0.5) - return self.laser_status - - async def get_offsets(self, *args, **kwags): - # return measured offsets - await asyncio.sleep(0.5) - self.offsets = types.SimpleNamespace( - dX=1.0, - dY=2.0, - dZ=0.0, - dRX=0.0, - dRY=0.0, - ) - - return self.offsets - - async def test_configure(self): - # Try configure with minimum set of parameters declared - async with self.make_script(): - target = "M2" - - await self.configure_script(target=target) - - assert self.script.target == getattr(AlignComponent, target) - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script(target="M2") - - # Run the script - await self.run_script() - - assert self.state_0 == [1, 2, 0, 0, 0] - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "laser_tracker" / "measure.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_lasertracker_set_up.py b/tests/test_maintel_lasertracker_set_up.py deleted file mode 100644 index 750df46e4..000000000 --- a/tests/test_maintel_lasertracker_set_up.py +++ /dev/null @@ -1,84 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.salobj import State -from lsst.ts.standardscripts.maintel.laser_tracker import SetUp - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestSetUp(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = SetUp(index=index, add_remotes=False) - self.script.laser_tracker.rem.lasertracker_1 = unittest.mock.AsyncMock() - self.script.laser_tracker.rem.lasertracker_1.configure_mock( - **{ - "cmd_laserPower.set_start": self.mock_laser_power, - "evt_laserStatus.aget": self.get_laser_status, - "evt_laserStatus.next": self.get_laser_status, - "evt_summaryState.aget": self.get_summary_state, - "evt_summaryState.next": self.get_summary_state, - } - ) - - self.laser_status = types.SimpleNamespace(status=LaserStatus.OFF) - return (self.script,) - - async def get_summary_state(self, *args, **kwargs): - return types.SimpleNamespace(summaryState=State.ENABLED) - - async def mock_laser_power(self, power, timeout): - self._laser_power_task = asyncio.create_task(self._mock_laser_power()) - - async def _mock_laser_power(self): - self.laser_status.status = LaserStatus.WARMING - await asyncio.sleep(5.0) - self.laser_status.status = LaserStatus.ON - - async def get_laser_status(self, *args, **kwags): - await asyncio.sleep(0.5) - return self.laser_status - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script() - - # Run the script - await self.run_script() - - assert self.laser_status.status == LaserStatus.ON - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "laser_tracker" / "set_up.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_lasertracker_shut_down.py b/tests/test_maintel_lasertracker_shut_down.py deleted file mode 100644 index 2becafaf7..000000000 --- a/tests/test_maintel_lasertracker_shut_down.py +++ /dev/null @@ -1,86 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.LaserTracker import LaserStatus -from lsst.ts.salobj import State -from lsst.ts.standardscripts.maintel.laser_tracker import ShutDown - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestShutDown( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = ShutDown(index=index, add_remotes=False) - self.script.laser_tracker.rem.lasertracker_1 = unittest.mock.AsyncMock() - self.script.laser_tracker.rem.lasertracker_1.configure_mock( - **{ - "cmd_laserPower.set_start": self.mock_laser_power, - "evt_laserStatus.aget": self.get_laser_status, - "evt_laserStatus.next": self.get_laser_status, - "evt_summaryState.aget": self.get_summary_state, - "evt_summaryState.next": self.get_summary_state, - } - ) - - self.laser_status = types.SimpleNamespace(status=LaserStatus.ON) - return (self.script,) - - async def get_summary_state(self, *args, **kwargs): - return types.SimpleNamespace(summaryState=State.ENABLED) - - async def mock_laser_power(self, power, timeout): - self._laser_power_task = asyncio.create_task(self._mock_laser_power()) - - async def _mock_laser_power(self): - self.laser_status.status = LaserStatus.WARMING - await asyncio.sleep(5.0) - self.laser_status.status = LaserStatus.OFF - - async def get_laser_status(self, *args, **kwags): - await asyncio.sleep(0.5) - return self.laser_status - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script() - - # Run the script - await self.run_script() - - assert self.laser_status.status == LaserStatus.OFF - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "laser_tracker" / "shut_down.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_lower_m1m3.py b/tests/test_maintel_lower_m1m3.py deleted file mode 100644 index ce5ebad4c..000000000 --- a/tests/test_maintel_lower_m1m3.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.m1m3 import LowerM1M3 - - -class TestLowerM1M3( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = LowerM1M3(index=index) - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - self.script.mtcs.lower_m1m3 = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.lower_m1m3.assert_awaited_once() - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "LowerM1M3 BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m1m3" / "lower_m1m3.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_m1m3_check_actuators.py b/tests/test_maintel_m1m3_check_actuators.py deleted file mode 100644 index 89477f397..000000000 --- a/tests/test_maintel_m1m3_check_actuators.py +++ /dev/null @@ -1,361 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import logging -import types -import unittest -import warnings - -from lsst.ts import salobj -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel.m1m3 import CheckActuators -from lsst.ts.xml.enums.MTM1M3 import BumpTest - -try: - from lsst.ts.idl.enums.MTM1M3 import DetailedState -except ImportError: - warnings.warn( - "Could not import MTM1M3 from lsst.ts.idl; importing from lsst.ts.xml", - UserWarning, - ) - from lsst.ts.xml.enums.MTM1M3 import DetailedStates as DetailedState - - -class TestCheckActuators(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - @classmethod - def setUpClass(cls): - cls.log = logging.getLogger(cls.__name__) - - async def basic_make_script(self, index): - self.script = CheckActuators(index=index) - - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - await self.script.configure_tcs() - self.script.mtcs.run_m1m3_actuator_bump_test = unittest.mock.AsyncMock( - side_effect=self.mock_test_bump - ) - self.script.mtcs.stop_m1m3_bump_test = unittest.mock.AsyncMock() - self.script.mtcs.enter_m1m3_engineering_mode = unittest.mock.AsyncMock() - self.script.mtcs.exit_m1m3_engineering_mode = unittest.mock.AsyncMock() - self.script.mtcs.assert_liveliness = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.assert_m1m3_detailed_state = unittest.mock.AsyncMock() - - self.script.mtcs.get_m1m3_bump_test_status = unittest.mock.AsyncMock( - side_effect=self.mock_get_m1m3_bump_test_status - ) - - self.script.mtcs.rem.mtm1m3 = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtm1m3.configure_mock( - **{ - "evt_detailedState.aget": self.get_m1m3_detailed_state, - } - ) - - self.bump_test_status = types.SimpleNamespace( - testState=[BumpTest.NOTTESTED] * len(self.script.m1m3_actuator_ids) - ) - - self.failed_primary_test = set() - self.failed_secondary_test = set() - - return (self.script,) - - async def get_m1m3_detailed_state(self, *args, **kwags): - return types.SimpleNamespace(detailedState=DetailedState.PARKED) - - # Side effects - async def mock_test_bump(self, actuator_id, primary, secondary): - await asyncio.sleep(0.5) - actuator_index = self.script.mtcs.get_m1m3_actuator_index(actuator_id) - self.bump_test_status.testState[actuator_index] = ( - BumpTest.PASSED - if actuator_id not in self.failed_primary_test - and actuator_id not in self.failed_secondary_test - else BumpTest.FAILED - ) - self.log.info(f"{self.bump_test_status.testState[actuator_index]!r}") - if self.bump_test_status.testState[actuator_index] == BumpTest.FAILED: - raise RuntimeError(f"Actuator {actuator_id} bump test failed.") - - # Create a side effect function for mock_bump_test_status method from mcts - # object. This function will be called when mock_bump_test_status method is - # called - async def mock_get_m1m3_bump_test_status(self, actuator_id): - primary_test_status = ( - BumpTest.PASSED - if actuator_id not in self.failed_primary_test - else BumpTest.FAILED - ) - secondary_test_status = ( - None - if actuator_id not in self.script.mtcs.get_m1m3_actuator_secondary_ids() - else ( - BumpTest.PASSED - if actuator_id not in self.failed_secondary_test - else BumpTest.FAILED - ) - ) - - return (primary_test_status, secondary_test_status) - - async def test_configure_all(self): - """Testing a valid configuration: all actuators""" - - # Configure with "all" actuators - async with self.make_script(): - actuators = "all" - - await self.configure_script(actuators=actuators) - - assert self.script.actuators_to_test == self.script.m1m3_actuator_ids - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_last_failed(self): - """Testing a valid configuration: last failed actuators""" - - # Configure with "last_failed" actuators - async with self.make_script(): - actuators = "last_failed" - - await self.configure_script(actuators=actuators) - - # At configuration stage all actuators are selected - # for later filtering - assert self.script.actuators_to_test == self.script.m1m3_actuator_ids - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_valid_ids(self): - """Testing a valid configuration: valid actuators ids""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - actuators = [101, 210, 301, 410] - - await self.configure_script( - actuators=actuators, - ) - - assert self.script.actuators_to_test == actuators - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_bad(self): - """Testing an invalid configuration: bad actuators ids""" - - async with self.make_script(): - # Invalid actuators: 501 and 505 - actuators = [501, 505] - - # If actuators_bad_ids is not empty, it should raise a ValueError - actuators_bad_ids = [ - actuator - for actuator in actuators - if actuator not in self.script.m1m3_actuator_ids - ] - if actuators_bad_ids: - with self.assertRaises(salobj.ExpectedError): - await self.configure_script( - actuators=actuators_bad_ids, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "CheckActuators BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run(self): - # Run the script - async with self.make_script(): - actuators = "all" - await self.configure_script(actuators=actuators) - - # Run the script - await self.run_script() - - # Assert all passed on mocked bump test. Had to get indexes. - actuators_to_test_index = [ - self.script.mtcs.get_m1m3_actuator_index(actuator_id) - for actuator_id in self.script.actuators_to_test - ] - - assert all( - [ - self.bump_test_status.testState[actuator_index] == BumpTest.PASSED - for actuator_index in actuators_to_test_index - ] - ) - # Expected awaint for assert_all_enabled method - expected_awaits = len(self.script.actuators_to_test) + 1 - - # Assert we await once for all mock methods defined above - self.script.mtcs.enter_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.exit_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.assert_liveliness.assert_awaited_once() - self.script.mtcs.assert_m1m3_detailed_state.assert_awaited_once() - assert self.script.mtcs.assert_all_enabled.await_count == expected_awaits - - expected_calls = [ - unittest.mock.call( - actuator_id=actuator_id, - primary=True, - secondary=self.script.has_secondary_actuator(actuator_id), - ) - for actuator_id in self.script.m1m3_actuator_ids - ] - - self.script.mtcs.run_m1m3_actuator_bump_test.assert_has_calls( - expected_calls - ) - - async def test_run_with_failed_actuators(self): - # Run the script - async with self.make_script(): - actuators = "all" - await self.configure_script(actuators=actuators) - self.failed_primary_test = {101, 220, 218} - self.failed_secondary_test = {220, 330} - # Run the script - with self.assertRaises(AssertionError, msg="FAILED the bump test"): - await self.run_script() - - # Assert all passed on mocked bump test. Had to get indexes. - actuators_to_test_index = [ - self.script.mtcs.get_m1m3_actuator_index(actuator_id) - for actuator_id in self.script.actuators_to_test - if actuator_id not in self.failed_primary_test - and actuator_id not in self.failed_secondary_test - ] - - assert all( - [ - self.bump_test_status.testState[actuator_index] == BumpTest.PASSED - for actuator_index in actuators_to_test_index - ] - ) - # Expected awaint for assert_all_enabled method - expected_awaits = len(self.script.actuators_to_test) + 1 - - # Assert we await once for all mock methods defined above - self.script.mtcs.enter_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.exit_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.assert_liveliness.assert_awaited_once() - self.script.mtcs.assert_m1m3_detailed_state.assert_awaited_once() - assert self.script.mtcs.assert_all_enabled.await_count == expected_awaits - - expected_calls = [ - unittest.mock.call( - actuator_id=actuator_id, - primary=True, - secondary=self.script.has_secondary_actuator(actuator_id), - ) - for actuator_id in self.script.m1m3_actuator_ids - ] - - self.script.mtcs.run_m1m3_actuator_bump_test.assert_has_calls( - expected_calls - ) - - async def test_run_last_failed_actuators(self): - # Run the script - async with self.make_script(): - await self.configure_script(actuators="last_failed") - # Sets up the actuators that will report a failed last bump test - self.failed_primary_test = {101, 220, 218} - self.failed_secondary_test = {220, 330} - # Actuators that must be tested by the script - expected_to_test = self.failed_primary_test | self.failed_secondary_test - # Run the script - # (assertion errors expected, as failed actuators will fail again) - with self.assertRaises(AssertionError, msg="FAILED the bump test"): - await self.run_script() - - # Expected awaint for assert_all_enabled method - expected_awaits = len(self.script.actuators_to_test) + 1 - - # Assert we await once for all mock methods defined above - self.script.mtcs.enter_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.exit_m1m3_engineering_mode.assert_awaited_once() - self.script.mtcs.assert_liveliness.assert_awaited_once() - self.script.mtcs.assert_m1m3_detailed_state.assert_awaited_once() - assert self.script.mtcs.assert_all_enabled.await_count == expected_awaits - - # Check that the last failed actuators were tested - expected_calls = [ - unittest.mock.call( - actuator_id=actuator_id, - primary=True, - secondary=self.script.has_secondary_actuator(actuator_id), - ) - for actuator_id in expected_to_test - ] - - self.script.mtcs.run_m1m3_actuator_bump_test.assert_has_calls( - expected_calls - ) - - # Check that no other actuators were tested - not_expected_to_test_indexes = [ - self.script.mtcs.get_m1m3_actuator_index(actuator_id) - for actuator_id in self.script.m1m3_actuator_ids - if actuator_id not in expected_to_test - ] - - assert all( - self.bump_test_status.testState[actuator_index] == BumpTest.NOTTESTED - for actuator_index in not_expected_to_test_indexes - ) - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "m1m3" / "check_actuators.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_m1m3_check_hardpoint.py b/tests/test_maintel_m1m3_check_hardpoint.py deleted file mode 100644 index d14da90b4..000000000 --- a/tests/test_maintel_m1m3_check_hardpoint.py +++ /dev/null @@ -1,137 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import random -import types -import unittest - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.MTM1M3 import HardpointTest -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.m1m3 import CheckHardpoint - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestCheckHardpoint( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = CheckHardpoint(index=index, add_remotes=False) - - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - - self.script.mtcs.run_m1m3_hard_point_test = unittest.mock.AsyncMock( - side_effect=self.mock_test_hardpoint - ) - self.script.mtcs.enter_m1m3_engineering_mode = unittest.mock.AsyncMock() - self.script.mtcs.exit_m1m3_engineering_mode = unittest.mock.AsyncMock() - self.script.mtcs.assert_liveliness = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.assert_m1m3_detailed_state = unittest.mock.AsyncMock() - - self.hardpoint_test_status = types.SimpleNamespace( - testState=[HardpointTest.NOTTESTED] * 6 - ) - - return (self.script,) - - async def mock_test_hardpoint(self, hp): - await asyncio.sleep(5.0) - self.hardpoint_test_status.testState[hp - 1] = HardpointTest.PASSED - - async def test_configure(self): - # Try configure with "all" for hardpoints - async with self.make_script(): - hardpoints = "all" - - await self.configure_script( - hardpoints=hardpoints, - ) - - assert self.script.hardpoints == range(1, 7) - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_with_hardpoints(self): - # Try configure with a vector of hardpoints for hardpoints - async with self.make_script(): - hardpoints = [1, 2, 5] - - await self.configure_script( - hardpoints=hardpoints, - ) - - assert self.script.hardpoints == hardpoints - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "CheckHardpoint BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run(self): - # Start the test itself - async with self.make_script(): - await self.configure_script() - - # Run the script - await self.run_script() - - assert all( - [ - self.hardpoint_test_status.testState[i - 1] == HardpointTest.PASSED - for i in self.script.hardpoints - ] - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m1m3" / "check_hardpoint.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_m1m3_enable_m1m3_controller_flags.py b/tests/test_maintel_m1m3_enable_m1m3_controller_flags.py deleted file mode 100644 index 6a795d3c5..000000000 --- a/tests/test_maintel_m1m3_enable_m1m3_controller_flags.py +++ /dev/null @@ -1,156 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts, utils -from lsst.ts.standardscripts.maintel.m1m3 import EnableM1M3SlewControllerFlags - - -class TestEnableM1M3SlewControllerFlags( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableM1M3SlewControllerFlags(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.start_task = utils.make_done_future() - self.script.mtcs.set_m1m3_slew_controller_settings = unittest.mock.AsyncMock() - self.script.mtcs.configure_mock( - m1m3_in_engineering_mode=self.mock_m1m3_in_engineering_mode - ) - - return (self.script,) - - @contextlib.asynccontextmanager - async def mock_m1m3_in_engineering_mode(self): - yield - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.enable_m1m3_slew_controller_flags = ( - unittest.mock.AsyncMock() - ) - yield - - async def test_configure_default(self): - async with self.make_dry_script(): - await self.configure_script(slew_flags="default") - default_flags, default_enables = self.script.get_default_slew_flags() - assert self.script.config.slew_flags == default_flags - assert self.script.config.enable == default_enables - - async def test_configure_custom(self): - custom_settings = { - "slew_flags": ["ACCELERATIONFORCES", "BALANCEFORCES"], - "enable": [True, False], - } - async with self.make_dry_script(): - await self.configure_script( - slew_flags=custom_settings["slew_flags"], - enable=custom_settings["enable"], - ) - for flag, enable in zip( - custom_settings["slew_flags"], custom_settings["enable"] - ): - assert flag in [f.name for f in self.script.config.slew_flags] - assert enable in self.script.config.enable - - async def test_invalid_configuration(self): - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="slew_flags and enable arrays must have the same length.", - ): - await self.configure_script( - slew_flags=["ACCELERATIONFORCES"], enable=[True, False] - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - program = "BLOCK-123" - reason = "SITCOM-321" - custom_settings = { - "slew_flags": ["ACCELERATIONFORCES", "BALANCEFORCES"], - "enable": [True, False], - } - await self.configure_script( - slew_flags=custom_settings["slew_flags"], - enable=custom_settings["enable"], - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "EnableM1M3SlewControllerFlags BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run(self): - - async with self.make_script(): - custom_settings = { - "slew_flags": ["ACCELERATIONFORCES", "BALANCEFORCES"], - "enable": [True, False], - } - program = "BLOCK-123" - reason = "SITCOM-321" - - await self.configure_script( - slew_flags=custom_settings["slew_flags"], - enable=custom_settings["enable"], - program=program, - reason=reason, - ) - - await self.run_script() - - # Convert flags to enumeration for assertion - expected_enum_flags = self.script.convert_flag_names_to_enum( - custom_settings["slew_flags"] - ) - - # Verify mock calls - expected_calls = [ - unittest.mock.call(flag, enable) - for flag, enable in zip(expected_enum_flags, custom_settings["enable"]) - ] - self.script.mtcs.set_m1m3_slew_controller_settings.assert_has_awaits( - expected_calls - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = ( - scripts_dir / "maintel" / "m1m3" / "enable_m1m3_slew_controller_flags.py" - ) - await self.check_executable(script_path) diff --git a/tests/test_maintel_m2_check_actuators.py b/tests/test_maintel_m2_check_actuators.py deleted file mode 100644 index 5fed66962..000000000 --- a/tests/test_maintel_m2_check_actuators.py +++ /dev/null @@ -1,212 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import unittest - -import numpy as np -from lsst.ts import salobj -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel.m2 import CheckActuators - -# TODO: DM-41592 move constants from lsst.ts.m2com to ts-xml -NUM_ACTUATOR = 78 -NUM_TANGENT_LINK = 6 - - -class TestCheckActuators(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = CheckActuators(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.components_attr = ["mtm2"] - self.script.mtcs.run_m2_actuator_bump_test = unittest.mock.AsyncMock( - side_effect=self.mock_test_bump - ) - self.script.mtcs.stop_m2_bump_test = unittest.mock.AsyncMock() - self.script.mtcs.assert_liveliness = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.get_m2_hardpoints = unittest.mock.AsyncMock( - side_effect=self.mock_get_m2_hardpoints - ) - self.script.mtcs.run_m2_actuator_bump_test_with_error = unittest.mock.AsyncMock( - side_effect=self.mock_test_bump_with_error - ) - self.hardpoint_ids = list([6, 16, 26, 74, 76, 78]) - num_axial_actuator = NUM_ACTUATOR - NUM_TANGENT_LINK - self.axial_actuator_ids = list( - [ - actuator - for actuator in np.arange(num_axial_actuator) - if actuator + 1 not in self.hardpoint_ids - ] - ) - self.script.mtcs.rem.mtm2 = unittest.mock.AsyncMock() - - return (self.script,) - - # Side effects - async def mock_test_bump(self, actuator, period, force): - await asyncio.sleep(0.5) - - async def mock_test_bump_with_error(self, actuator, period, force): - if actuator == 10: - raise salobj.base.AckError("Testing command Error", None) - await asyncio.sleep(0.5) - - # Create a side effect function for mock_bump_test_status method from mcts - # object. This function will be called when mock_bump_test_status method is - # called - async def mock_get_m2_hardpoints(self): - return self.hardpoint_ids - - async def test_configure_all(self): - """Testing a valid configuration: all actuators""" - - # Configure with "all" actuators - async with self.make_script(): - actuators = "all" - - await self.configure_script(actuators=actuators) - assert self.script.actuators_to_test == self.axial_actuator_ids - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_valid_ids(self): - """Testing a valid configuration: valid actuators ids""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - actuators = [7, 8, 9, 10] - - await self.configure_script( - actuators=actuators, - ) - - assert self.script.actuators_to_test == actuators - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_bad_hardpoint(self): - """Testing an invalid configuration: bad actuators ids""" - - async with self.make_script(): - # Invalid actuators: actuator is a hardpoint - actuators = [5] - - with self.assertRaises(salobj.ExpectedError): - await self.configure_script( - actuators=actuators, - ) - - async def test_configure_bad_invalid_id(self): - """Testing an invalid configuration: bad actuators ids""" - - async with self.make_script(): - # Invalid actuators: value greater than max id - actuators = [105] - - with self.assertRaises(salobj.ExpectedError): - await self.configure_script( - actuators=actuators, - ) - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "CheckActuators BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run_with_error(self): - # Run the script - async with self.make_script(): - run_m2_actuator_bump_test_side_effect = ( - self.script.mtcs.run_m2_actuator_bump_test.side_effect - ) - self.script.mtcs.run_m2_actuator_bump_test.side_effect = ( - self.mock_test_bump_with_error - ) - actuators = [7, 8, 9, 10, 11] - await self.configure_script(actuators=actuators) - - # Run the script - run_data = self.script.cmd_run.DataType() - await self.script.do_run(run_data) - await self.script.done_task - - assert self.script.failed_actuator_ids == list([10]) - self.script.mtcs.run_m2_actuator_bump_test.side_effect = ( - run_m2_actuator_bump_test_side_effect - ) - - async def test_run(self): - # Run the script - async with self.make_script(): - actuators = "all" - await self.configure_script(actuators=actuators) - - # Run the script - await self.run_script() - - # Expected awaint for assert_all_enabled method - expected_awaits = len(self.script.actuators_to_test) + 1 - - # Assert we await once for all mock methods defined above - self.script.mtcs.assert_liveliness.assert_awaited_once() - assert self.script.mtcs.assert_all_enabled.await_count == expected_awaits - - expected_calls = [ - unittest.mock.call( - actuator=actuator, - period=self.script.period, - force=self.script.force, - ) - for actuator in self.axial_actuator_ids - ] - - self.script.mtcs.run_m2_actuator_bump_test.assert_has_calls(expected_calls) - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "m2" / "check_actuators.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_m2_disable_closed_loop.py b/tests/test_maintel_m2_disable_closed_loop.py deleted file mode 100644 index cede02476..000000000 --- a/tests/test_maintel_m2_disable_closed_loop.py +++ /dev/null @@ -1,88 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts, utils -from lsst.ts.standardscripts.maintel.m2.disable_closed_loop import DisableM2ClosedLoop - - -class TestDisableM2ClosedLoop( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = DisableM2ClosedLoop(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.start_task = utils.make_done_future() - self.script.mtcs.disable_m2_balance_system = unittest.mock.AsyncMock() - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.disable_m2_balance_system = unittest.mock.AsyncMock() - yield - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202312190001"] - ) - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "DisableM2ClosedLoop BLOCK-123 202312190001 SITCOM-321" - ) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - await self.run_script() - - self.script.mtcs.disable_m2_balance_system.assert_awaited_once() - - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m2" / "disable_closed_loop.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_m2_enable_closed_loop.py b/tests/test_maintel_m2_enable_closed_loop.py deleted file mode 100644 index 03b5e323f..000000000 --- a/tests/test_maintel_m2_enable_closed_loop.py +++ /dev/null @@ -1,88 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts, utils -from lsst.ts.standardscripts.maintel.m2.enable_closed_loop import EnableM2ClosedLoop - - -class TestEnableM2ClosedLoop( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = EnableM2ClosedLoop(index=index) - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.start_task = utils.make_done_future() - self.script.mtcs.enable_m2_balance_system = unittest.mock.AsyncMock() - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.enable_m2_balance_system = unittest.mock.AsyncMock() - yield - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202312190001"] - ) - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "EnableM2ClosedLoop BLOCK-123 202312190001 SITCOM-321" - ) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - await self.run_script() - - self.script.mtcs.enable_m2_balance_system.assert_awaited_once() - - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m2" / "enable_closed_loop.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_move_p2p.py b/tests/test_maintel_move_p2p.py deleted file mode 100644 index 2cb88fc2f..000000000 --- a/tests/test_maintel_move_p2p.py +++ /dev/null @@ -1,364 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel import MoveP2P - - -class TestMoveP2P(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = MoveP2P(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.components_attr = ["mtm1m3"] - yield - - async def test_config_fail_az_no_el(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="is not valid under any of the given schemas", - ): - await self.configure_script(az=0.0) - - async def test_config_fail_el_no_az(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="is not valid under any of the given schemas", - ): - await self.configure_script(el=0.0) - - async def test_config_fail_ra_no_dec(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="is not valid under any of the given schemas", - ): - await self.configure_script(ra=0.0) - - async def test_config_fail_dec_no_ra(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="is not valid under any of the given schemas", - ): - await self.configure_script(dec=0.0) - - async def test_config_fail_no_defaults(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, - match="is not valid under any of the given schemas", - ): - await self.configure_script() - - async def test_config_fail_azel_radec(self) -> None: - async with self.make_dry_script(): - az = 0.0 - el = 80.0 - ra = 0.0 - dec = -30.0 - with pytest.raises( - salobj.ExpectedError, - match="Failed validating 'oneOf' in schema", - ): - await self.configure_script( - az=az, - el=el, - ra=ra, - dec=dec, - ) - - async def test_config_az_el_scalars(self) -> None: - async with self.make_dry_script(): - az = 0.0 - el = 80.0 - self.script.configure_tcs = unittest.mock.AsyncMock() - - await self.configure_script( - az=az, - el=el, - ) - - self.script.configure_tcs.assert_awaited_once() - assert "azel" in self.script.grid - assert "az" in self.script.grid["azel"] - assert "el" in self.script.grid["azel"] - assert len(self.script.grid["azel"]["az"]) == 1 - assert len(self.script.grid["azel"]["el"]) == 1 - assert az in self.script.grid["azel"]["az"] - assert el in self.script.grid["azel"]["el"] - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_ignore(self) -> None: - async with self.make_dry_script(): - az = 0.0 - el = 80.0 - - await self.configure_script(az=az, el=el, ignore=["mtm1m3", "no_comp"]) - assert self.script.mtcs.check.mtm1m3 is False - self.script.mtcs.check.no_comp.assert_not_called() - - async def test_config_az_el_arrays(self) -> None: - async with self.make_dry_script(): - az = [0.0, 10.0, 20.0] - el = [80.0, 70.0, 60.0] - await self.configure_script( - az=az, - el=el, - ) - - assert "azel" in self.script.grid - assert "az" in self.script.grid["azel"] - assert "el" in self.script.grid["azel"] - assert self.script.grid["azel"]["az"] == az - assert self.script.grid["azel"]["el"] == el - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_az_scalar_el_array(self) -> None: - async with self.make_dry_script(): - az = 0.0 - el = [80.0, 70.0, 60.0] - await self.configure_script( - az=az, - el=el, - ) - - assert "azel" in self.script.grid - assert "az" in self.script.grid["azel"] - assert "el" in self.script.grid["azel"] - assert self.script.grid["azel"]["az"] == [az] * len(el) - assert self.script.grid["azel"]["el"] == el - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_az_array_el_scalar(self) -> None: - async with self.make_dry_script(): - az = [0.0, 10.0, 20.0] - el = 80.0 - await self.configure_script( - az=az, - el=el, - ) - - assert "azel" in self.script.grid - assert "az" in self.script.grid["azel"] - assert "el" in self.script.grid["azel"] - assert self.script.grid["azel"]["az"] == az - assert self.script.grid["azel"]["el"] == [el] * len(az) - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_ra_dec_scalars(self) -> None: - async with self.make_dry_script(): - ra = 0.0 - dec = -30.0 - await self.configure_script( - ra=ra, - dec=dec, - ) - - assert "radec" in self.script.grid - assert "ra" in self.script.grid["radec"] - assert "dec" in self.script.grid["radec"] - assert len(self.script.grid["radec"]["ra"]) == 1 - assert len(self.script.grid["radec"]["dec"]) == 1 - assert ra in self.script.grid["radec"]["ra"] - assert dec in self.script.grid["radec"]["dec"] - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_ra_dec_arrays(self) -> None: - async with self.make_dry_script(): - ra = [0.0, 10.0, 20.0] - dec = [80.0, 70.0, 60.0] - await self.configure_script( - ra=ra, - dec=dec, - ) - - assert "radec" in self.script.grid - assert "ra" in self.script.grid["radec"] - assert "dec" in self.script.grid["radec"] - assert self.script.grid["radec"]["ra"] == ra - assert self.script.grid["radec"]["dec"] == dec - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_ra_scalar_dec_array(self) -> None: - async with self.make_dry_script(): - ra = 0.0 - dec = [80.0, 70.0, 60.0] - await self.configure_script( - ra=ra, - dec=dec, - ) - - assert "radec" in self.script.grid - assert "ra" in self.script.grid["radec"] - assert "dec" in self.script.grid["radec"] - assert self.script.grid["radec"]["ra"] == [ra] * len(dec) - assert self.script.grid["radec"]["dec"] == dec - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_config_ra_array_dec_scalar(self) -> None: - async with self.make_dry_script(): - ra = [0.0, 10.0, 20.0] - dec = 80.0 - await self.configure_script( - ra=ra, - dec=dec, - ) - - assert "radec" in self.script.grid - assert "ra" in self.script.grid["radec"] - assert "dec" in self.script.grid["radec"] - assert self.script.grid["radec"]["ra"] == ra - assert self.script.grid["radec"]["dec"] == [dec] * len(ra) - assert self.script.pause_for == 0 - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_config_pause_for_reason_program(self) -> None: - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - pause_for = 10.0 - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - az=az, - el=el, - pause_for=pause_for, - program=program, - reason=reason, - ) - - assert "azel" in self.script.grid - assert "az" in self.script.grid["azel"] - assert "el" in self.script.grid["azel"] - assert len(self.script.grid["azel"]["az"]) == 1 - assert len(self.script.grid["azel"]["el"]) == 1 - assert az in self.script.grid["azel"]["az"] - assert el in self.script.grid["azel"]["el"] - assert self.script.pause_for == pause_for - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "MoveP2P BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run_azel(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = [0.0, 10.0, 20.0] - el = [80.0, 70.0, 60.0] - timeout = 321.0 - program = "BLOCK-123" - reason = "SITCOM-321" - - await self.configure_script( - az=az, - el=el, - program=program, - reason=reason, - move_timeout=timeout, - ) - - await self.run_script() - - expected_calls = [ - unittest.mock.call(az=_az, el=_el, timeout=timeout) - for _az, _el in zip(az, el) - ] - self.script.mtcs.move_p2p_azel.assert_has_awaits(expected_calls) - - async def test_run_radec(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - ra = [0.0, 10.0, 20.0] - dec = [80.0, 70.0, 60.0] - program = "BLOCK-123" - reason = "SITCOM-321" - timeout = 321.0 - - await self.configure_script( - ra=ra, - dec=dec, - program=program, - reason=reason, - move_timeout=timeout, - ) - - await self.run_script() - - expected_calls = [ - unittest.mock.call(ra=_ra, dec=_dec, timeout=timeout) - for _ra, _dec in zip(ra, dec) - ] - self.script.mtcs.move_p2p_radec.assert_has_awaits(expected_calls) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "move_p2p.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_mtdome_crawl_az.py b/tests/test_maintel_mtdome_crawl_az.py deleted file mode 100644 index fc9fdd042..000000000 --- a/tests/test_maintel_mtdome_crawl_az.py +++ /dev/null @@ -1,129 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import unittest -from types import SimpleNamespace - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel.mtdome import CrawlAz, Direction -from lsst.ts.xml.enums.MTDome import SubSystemId - - -class TestCrawlAz(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = CrawlAz(index=index) - - self.script.mtdome = unittest.mock.AsyncMock() - self.script.mtdome.configure_mock( - **{ - "evt_summaryState.aget.side_effect": self.get_mtdome_summary_state, - "evt_summaryState.next.side_effect": self.get_mtdome_summary_state, - }, - ) - - return (self.script,) - - async def get_mtdome_summary_state(self, timeout=0.0, flush=False): - await asyncio.sleep(1.0) - return SimpleNamespace(summaryState=salobj.State.ENABLED.value) - - async def test_configure_default(self): - """Test the default configuration""" - - async with self.make_script(): - - await self.configure_script() - - assert self.script.direction == Direction.ClockWise - - async def test_configure_clock_wise(self): - """Test the default configuration""" - - async with self.make_script(): - - await self.configure_script(direction="ClockWise") - - assert self.script.direction == Direction.ClockWise - - async def test_configure_counter_clock_wise(self): - """Test the default configuration""" - - async with self.make_script(): - - await self.configure_script(direction="CounterClockWise") - - assert self.script.direction == Direction.CounterClockWise - - async def test_configure_invalid_direction(self): - """Test the default configuration""" - - async with self.make_script(): - - with pytest.raises( - salobj.ExpectedError, match="failed: 'InvalidDirection' is not one of" - ): - await self.configure_script(direction="InvalidDirection") - - async def test_run_with_default_config(self): - async with self.make_script(): - - await self.configure_script() - - # Once the script starts it will run forever until - # stopped. - run_script_task = asyncio.create_task(self.run_script()) - - # wait a couple seconds than stop the script - await asyncio.sleep(5.0) - - stop_data = self.script.cmd_stop.DataType() - - await self.script.do_stop(stop_data) - - await run_script_task - - expected_calls = [ - unittest.mock.call( - velocity=0.5, - timeout=self.script.TIMEOUT_CMD, - ), - unittest.mock.call( - velocity=0.0, - timeout=self.script.TIMEOUT_CMD, - ), - ] - self.script.mtdome.cmd_crawlAz.set_start.assert_has_awaits(expected_calls) - - self.script.mtdome.cmd_stop.set_start.assert_awaited_with( - subSystemIds=SubSystemId.AMCS, - timeout=self.script.TIMEOUT_CMD, - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "crawl_az.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_mtdome_home_dome.py b/tests/test_maintel_mtdome_home_dome.py deleted file mode 100644 index bfbc23a60..000000000 --- a/tests/test_maintel_mtdome_home_dome.py +++ /dev/null @@ -1,97 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts.maintel.mtdome import HomeDome - - -class TestHomeDome( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = HomeDome(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.home_dome = unittest.mock.AsyncMock() - yield - - async def test_run(self): - async with self.make_dry_script(): - await self.configure_script(physical_az=300.0) - - await self.run_script() - self.script.mtcs.assert_all_enabled.assert_awaited_once() - self.script.mtcs.home_dome.assert_awaited_once() - self.script.mtcs.home_dome.assert_called_with(physical_az=300.0) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "home_dome.py" - await self.check_executable(script_path) - - async def test_config(self): - async with self.make_script(): - await self.configure_script(physical_az=300.0) - assert self.script.physical_az == 300.0 - - async def test_invalid_configurations(self): - # Set of invalid configurations to test, all should fail to configure - configs_bad = [ - dict(physical_az="not_valid"), - dict(physical_az=[1, 3]), - dict(physical_az=None), - ] - - async with self.make_script(): - for config in configs_bad: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - assert self.script.state == ScriptState.CONFIGURE_FAILED - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(physical_az=300.0, ignore=components) - - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_csc_component(self): - async with self.make_script(): - components = ["not_csc_comp", "mtptg"] - await self.configure_script(physical_az=300.0, ignore=components) - - assert hasattr(self.script.mtcs, "not_csc_comp") is False - assert self.script.mtcs.check.mtptg is False - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_mtdome_slew_dome.py b/tests/test_maintel_mtdome_slew_dome.py deleted file mode 100644 index 7e559f8ce..000000000 --- a/tests/test_maintel_mtdome_slew_dome.py +++ /dev/null @@ -1,95 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts.maintel.mtdome import SlewDome - - -class TestSlewDome( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = SlewDome(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.enable = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.slew_dome_to = unittest.mock.AsyncMock() - yield - - async def test_run(self): - async with self.make_dry_script(): - await self.configure_script(az=0.0) - - await self.run_script() - self.script.mtcs.enable.assert_awaited_once() - self.script.mtcs.assert_all_enabled.assert_awaited_once() - self.script.mtcs.slew_dome_to.assert_awaited_once() - self.script.mtcs.slew_dome_to.assert_called_with(az=0.0) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "slew_dome.py" - await self.check_executable(script_path) - - async def test_config(self): - async with self.make_script(): - await self.configure_script(az=0.0) - assert self.script.az == 0.0 - - async def test_invalid_configurations(self): - # Set of invalid configurations to test, all should fail to configure - configs_bad = [dict(az="not_valid"), dict(az=[1, 3]), dict(az=None)] - - async with self.make_script(): - for config in configs_bad: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - assert self.script.state == ScriptState.CONFIGURE_FAILED - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(az=0.0, ignore=components) - - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_csc_component(self): - async with self.make_script(): - components = ["not_csc_comp", "mtptg"] - await self.configure_script(az=0.0, ignore=components) - - assert hasattr(self.script.mtcs, "not_csc_comp") is False - assert self.script.mtcs.check.mtptg is False - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_mtmount_park_mount.py b/tests/test_maintel_mtmount_park_mount.py deleted file mode 100644 index 632666b46..000000000 --- a/tests/test_maintel_mtmount_park_mount.py +++ /dev/null @@ -1,78 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtmount import ParkMount -from lsst.ts.xml.enums import MTMount - - -class TestParkMount( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = ParkMount(index=index) - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.park_mount = unittest.mock.AsyncMock() - yield - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtmount" / "park_mount.py" - await self.check_executable(script_path) - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(position="ZENITH", ignore=components) - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_mtcs_component(self): - async with self.make_script(): - # Test the ignore feature with one non-MTCS component. - components = ["not_mtcs_comp", "mtptg"] - await self.configure_script(position="ZENITH", ignore=components) - assert not hasattr(self.script.mtcs.check, "not_mtcs_comp") - assert self.script.mtcs.check.mtptg is False - - async def test_park_zenith(self): - async with self.make_dry_script(): - await self.configure_script(position="ZENITH") - await self.run_script() - self.script.mtcs.park_mount.assert_called_with( - position=MTMount.ParkPosition.ZENITH - ) - - async def test_park_horizon(self): - async with self.make_dry_script(): - await self.configure_script(position="HORIZON") - await self.run_script() - self.script.mtcs.park_mount.assert_called_with( - position=MTMount.ParkPosition.HORIZON - ) diff --git a/tests/test_maintel_mtmount_unpark_mount.py b/tests/test_maintel_mtmount_unpark_mount.py deleted file mode 100644 index d3812ce25..000000000 --- a/tests/test_maintel_mtmount_unpark_mount.py +++ /dev/null @@ -1,67 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtmount import UnparkMount - - -class TestUnparkMount( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = UnparkMount(index=index) - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.unpark_mount = unittest.mock.AsyncMock() - yield - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtmount" / "unpark_mount.py" - await self.check_executable(script_path) - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(ignore=components) - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_mtcs_component(self): - async with self.make_script(): - # Test the ignore feature with one non-MTCS component. - components = ["not_mtcs_comp", "mtptg"] - await self.configure_script(ignore=components) - assert not hasattr(self.script.mtcs.check, "not_mtcs_comp") - assert self.script.mtcs.check.mtptg is False - - async def test_run(self): - async with self.make_dry_script(): - await self.configure_script() - await self.run_script() - self.script.mtcs.unpark_mount.assert_called_once() diff --git a/tests/test_maintel_mtrotator_move_rotator.py b/tests/test_maintel_mtrotator_move_rotator.py deleted file mode 100644 index 3e14abdc7..000000000 --- a/tests/test_maintel_mtrotator_move_rotator.py +++ /dev/null @@ -1,121 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.mtrotator import MoveRotator - - -class TestMoveRotator( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = MoveRotator(index=index) - - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - - self.start_angle = 0.0 # degrees - self.very_short_sleep = 0.1 # seconds - self.script.mtcs.move_rotator = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_configure_default(self): - """Test the default configuration""" - - async with self.make_script(): - target_angle = 45.0 - - await self.configure_script(angle=target_angle) - - assert self.script.target_angle == target_angle - assert self.script.wait_for_complete is True - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - async def test_configure_dont_wait_for_complete(self): - """Test with the configuration where ``wait_for_complete`` is False""" - - async with self.make_script(): - target_angle = 45.0 - wait_for_complete = False - - await self.configure_script(angle=target_angle, wait_for_complete=False) - - assert self.script.target_angle == target_angle - assert self.script.wait_for_complete is wait_for_complete - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - angle=10.0, - wait_for_complete=True, - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "MoveRotator BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run_with_default_config(self): - async with self.make_script(): - target_angle = 45.0 - - await self.configure_script(angle=target_angle) - - await self.run_script() - - self.script.mtcs.move_rotator.assert_called_once_with( - position=target_angle, wait_for_in_position=True - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtrotator" / "move_rotator.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_offline_comcam.py b/tests/test_maintel_offline_comcam.py deleted file mode 100644 index c0293446e..000000000 --- a/tests/test_maintel_offline_comcam.py +++ /dev/null @@ -1,75 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import random -import unittest - -from lsst.ts import salobj, standardscripts -from lsst.ts.observatory.control.mock import ComCamMock -from lsst.ts.standardscripts.maintel import OfflineComCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestOfflineComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = OfflineComCam(index=index) - self.comcam_mock = ComCamMock() - - return (self.script, self.comcam_mock) - - async def test_components(self): - async with self.make_script(): - for component in self.script.group.components_attr: - with self.subTest(f"Check {component}", component=component): - if getattr(self.script.group.check, component): - assert component in self.script.components() - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - - for comp in self.script.group.components_attr: - if getattr(self.script.group.check, comp): - current_state = salobj.State( - getattr( - self.comcam_mock.controllers, comp - ).evt_summaryState.data.summaryState - ) - - with self.subTest(f"{comp} summary state", comp=comp): - assert current_state == salobj.State.OFFLINE - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "offline_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_offline_mtcs.py b/tests/test_maintel_offline_mtcs.py deleted file mode 100644 index f0eca9319..000000000 --- a/tests/test_maintel_offline_mtcs.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import OfflineMTCS - - -class TestOfflineMTCS( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = OfflineMTCS(index=index) - - return (self.script,) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "offline_mtcs.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_offset_camera_hexapod.py b/tests/test_maintel_offset_camera_hexapod.py deleted file mode 100644 index 8116859e8..000000000 --- a/tests/test_maintel_offset_camera_hexapod.py +++ /dev/null @@ -1,195 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import contextlib -import logging -import unittest - -import pytest -from lsst.ts import salobj -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel import OffsetCameraHexapod - - -class TestOffsetCameraHexapod(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - @classmethod - def setUpClass(cls) -> None: - cls.log = logging.getLogger(type(cls).__name__) - - async def basic_make_script(self, index): - self.script = OffsetCameraHexapod(index=index, add_remotes=False) - - return (self.script,) - - @contextlib.asynccontextmanager - async def setup_mocks(self): - self.script.mtcs.offset_camera_hexapod = unittest.mock.AsyncMock() - self.script.mtcs.move_camera_hexapod = unittest.mock.AsyncMock() - yield - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "offset_camera_hexapod.py" - self.log.debug(f"Checking for script in {script_path}") - await self.check_executable(script_path) - - async def test_valid_configurations(self): - # Set of valid configurations to test, considering different possible - # combinations of configuration parameters - configs_good = [ - dict(z=0.1), # reset_axes defaults to False - dict(x=0.1, y=0.2), - dict(x=0.1, u=0.1, v=-0.1, sync=False), - dict(x=0.1, y=0.2, reset_axes=True), - dict(reset_axes=["x", "y"]), - dict(reset_axes="all"), - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_good: - await self.configure_script(**config) - - default_values = dict( - x=0, - y=0, - z=0, - u=0, - v=0, - sync=True, - reset_axes=[], - ) - - self.assert_config(default_values, config) - - async def test_invalid_configurations(self): - # Set of invalid configurations to test, all should fail to configure - configs_bad = [ - dict(), # No offsets or reset operation - dict(x=0.0, y=0.0, reset_axes=False), # All offsets zero, no reset - dict(reset_axes=True), # reset_axes is True but no offsets provided - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_bad: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - - assert self.state.state == ScriptState.CONFIGURE_FAILED - - def assert_config(self, default_values, config): - configured_values = dict( - x=self.script.offsets["x"], - y=self.script.offsets["y"], - z=self.script.offsets["z"], - u=self.script.offsets["u"], - v=self.script.offsets["v"], - sync=self.script.sync, - reset_axes=self.script.reset_axes, - ) - - for parameter in default_values: - with self.subTest(config=config, parameter=parameter): - if parameter == "reset_axes": - # Determine the expected reset_axes based on the config - reset_axes_config = config.get("reset_axes", False) - if reset_axes_config is True: - expected_reset_axes = [ - axis - for axis, value in configured_values.items() - if axis in ["x", "y", "z", "u", "v"] and value != 0.0 - ] - elif reset_axes_config == "all": - expected_reset_axes = ["x", "y", "z", "u", "v"] - elif isinstance(reset_axes_config, list): - expected_reset_axes = reset_axes_config - else: - expected_reset_axes = default_values["reset_axes"] - expected_value = expected_reset_axes - else: - expected_value = config.get( - parameter, default_values.get(parameter) - ) - - assert expected_value == configured_values[parameter] - - async def test_offset_camera_hexapod(self): - async with self.make_script(), self.setup_mocks(): - config = dict(x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False) - - await self.configure_script(**config) - - await self.run_script() - - self.script.mtcs.offset_camera_hexapod.assert_awaited_once_with( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False - ) - - async def test_offset_camera_hexapod_with_a_reset(self): - async with self.make_script(), self.setup_mocks(): - config = dict( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, reset_axes=True, sync=False - ) - - await self.configure_script(**config) - - await self.run_script() - - self.script.mtcs.move_camera_hexapod.assert_awaited_once_with( - x=0.0, y=0.0, z=0.0, u=0.0, v=0.0, sync=False - ) - - self.script.mtcs.offset_camera_hexapod.assert_awaited_once_with( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False - ) - - async def test_reset_only(self): - async with self.make_script(), self.setup_mocks(): - config = dict(reset_axes=["x", "z"]) - - await self.configure_script(**config) - - await self.run_script() - - # Check if only the reset happened without any offset - self.script.mtcs.move_camera_hexapod.assert_awaited_once_with( - x=0.0, z=0.0, sync=True - ) - - # Ensure that offset method was not called - self.script.mtcs.offset_camera_hexapod.assert_not_awaited() - - async def test_reset_all_axes_only(self): - async with self.make_script(), self.setup_mocks(): - config = dict(reset_axes="all") - - await self.configure_script(**config) - - await self.run_script() - - # Check if all axes were reset without applying any offsets - self.script.mtcs.move_camera_hexapod.assert_awaited_once_with( - x=0.0, y=0.0, z=0.0, u=0.0, v=0.0, sync=True - ) - - # Ensure that offset method was not called - self.script.mtcs.offset_camera_hexapod.assert_not_awaited() diff --git a/tests/test_maintel_offset_m2_hexapod.py b/tests/test_maintel_offset_m2_hexapod.py deleted file mode 100644 index 8e88ee3d6..000000000 --- a/tests/test_maintel_offset_m2_hexapod.py +++ /dev/null @@ -1,195 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import contextlib -import logging -import unittest - -import pytest -from lsst.ts import salobj -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel import OffsetM2Hexapod - - -class TestOffsetM2Hexapod(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - @classmethod - def setUpClass(cls) -> None: - cls.log = logging.getLogger(type(cls).__name__) - - async def basic_make_script(self, index): - self.script = OffsetM2Hexapod(index=index, add_remotes=False) - - return (self.script,) - - @contextlib.asynccontextmanager - async def setup_mocks(self): - self.script.mtcs.offset_m2_hexapod = unittest.mock.AsyncMock() - self.script.mtcs.move_m2_hexapod = unittest.mock.AsyncMock() - yield - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "offset_m2_hexapod.py" - self.log.debug(f"Checking for script in {script_path}") - await self.check_executable(script_path) - - async def test_valid_configurations(self): - # Set of valid configurations to test, considering different possible - # combinations of configuration parameters - configs_good = [ - dict(z=0.1), # reset_axes defaults to False - dict(x=0.1, y=0.2), - dict(x=0.1, u=0.1, v=-0.1, sync=False), - dict(x=0.1, y=0.2, reset_axes=True), - dict(reset_axes=["x", "y"]), - dict(reset_axes="all"), - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_good: - await self.configure_script(**config) - - default_values = dict( - x=0, - y=0, - z=0, - u=0, - v=0, - sync=True, - reset_axes=[], - ) - - self.assert_config(default_values, config) - - async def test_invalid_configurations(self): - # Set of invalid configurations to test, all should fail to configure - configs_bad = [ - dict(), # No offsets or reset operation - dict(x=0.0, y=0.0, reset_axes=False), # All offsets zero, no reset - dict(reset_axes=True), # reset_axes is True but no offsets provided - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_bad: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - - assert self.state.state == ScriptState.CONFIGURE_FAILED - - def assert_config(self, default_values, config): - configured_values = dict( - x=self.script.offsets["x"], - y=self.script.offsets["y"], - z=self.script.offsets["z"], - u=self.script.offsets["u"], - v=self.script.offsets["v"], - sync=self.script.sync, - reset_axes=self.script.reset_axes, - ) - - for parameter in default_values: - with self.subTest(config=config, parameter=parameter): - if parameter == "reset_axes": - # Determine the expected reset_axes based on the config - reset_axes_config = config.get("reset_axes", False) - if reset_axes_config is True: - expected_reset_axes = [ - axis - for axis, value in configured_values.items() - if axis in ["x", "y", "z", "u", "v"] and value != 0.0 - ] - elif reset_axes_config == "all": - expected_reset_axes = ["x", "y", "z", "u", "v"] - elif isinstance(reset_axes_config, list): - expected_reset_axes = reset_axes_config - else: - expected_reset_axes = default_values["reset_axes"] - expected_value = expected_reset_axes - else: - expected_value = config.get( - parameter, default_values.get(parameter) - ) - - assert expected_value == configured_values[parameter] - - async def test_offset_m2_hexapod(self): - async with self.make_script(), self.setup_mocks(): - config = dict(x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False) - - await self.configure_script(**config) - - await self.run_script() - - self.script.mtcs.offset_m2_hexapod.assert_awaited_once_with( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False - ) - - async def test_offset_m2_hexapod_with_a_reset(self): - async with self.make_script(), self.setup_mocks(): - config = dict( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, reset_axes=True, sync=False - ) - - await self.configure_script(**config) - - await self.run_script() - - self.script.mtcs.move_m2_hexapod.assert_awaited_once_with( - x=0.0, y=0.0, z=0.0, u=0.0, v=0.0, sync=False - ) - - self.script.mtcs.offset_m2_hexapod.assert_awaited_once_with( - x=-0.1, y=0.2, z=0.1, u=-1.0, v=1.0, sync=False - ) - - async def test_reset_only(self): - async with self.make_script(), self.setup_mocks(): - config = dict(reset_axes=["x", "z"]) - - await self.configure_script(**config) - - await self.run_script() - - # Check if only the reset happened without any offset - self.script.mtcs.move_m2_hexapod.assert_awaited_once_with( - x=0.0, z=0.0, sync=True - ) - - # Ensure that offset method was not called - self.script.mtcs.offset_m2_hexapod.assert_not_awaited() - - async def test_reset_all_axes_only(self): - async with self.make_script(), self.setup_mocks(): - config = dict(reset_axes="all") - - await self.configure_script(**config) - - await self.run_script() - - # Check if all axes were reset without applying any offsets - self.script.mtcs.move_m2_hexapod.assert_awaited_once_with( - x=0.0, y=0.0, z=0.0, u=0.0, v=0.0, sync=True - ) - - # Ensure that offset method was not called - self.script.mtcs.offset_m2_hexapod.assert_not_awaited() diff --git a/tests/test_maintel_offset_mtcs.py b/tests/test_maintel_offset_mtcs.py deleted file mode 100644 index 0f9d01432..000000000 --- a/tests/test_maintel_offset_mtcs.py +++ /dev/null @@ -1,184 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import logging -import unittest - -import pytest -from lsst.ts import salobj -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel import OffsetMTCS - - -class TestOffsetMTCS(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - @classmethod - def setUpClass(cls) -> None: - cls.log = logging.getLogger(type(cls).__name__) - - async def basic_make_script(self, index): - self.script = OffsetMTCS(index=index, add_remotes=False) - - return (self.script,) - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "offset_mtcs.py" - self.log.debug(f"Checking for script in {script_path}") - await self.check_executable(script_path) - - async def test_valid_configurations(self): - # Set of valid configurations to test, considering different possible - # combinations of configuration parameters - configs_good = [ - dict(offset_azel=dict(az=180, el=60)), - dict(offset_radec=dict(ra=15, dec=-30)), - dict(offset_xy=dict(x=10, y=30)), - dict(offset_rot=dict(rot=10)), - dict(reset_offsets=dict(reset_absorbed=True, reset_non_absorbed=True)), - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_good: - await self.configure_script(**config) - - default_values = dict( - absorb=False, - relative=True, - ) - - self.assert_config(default_values, config) - - async def test_invalid_configurations(self): - # Set of invalid configurations to test, all should fail to configure - configs_bad = [ - dict(), - dict(offset_xy=dict(x=0)), - dict(offset_azel=dict(az=180)), - dict(offset_radec=dict(ra=15)), - dict(offset_xy=dict(x=10, y=30), offset_azel=dict(az=180, el=60)), - dict(offset_xy=dict(x=10, y=30), reset_offsets=dict()), - ] - - self.remotes_needed = False - async with self.make_script(): - for config in configs_bad: - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - - assert self.state.state == ScriptState.CONFIGURE_FAILED - - def assert_config(self, default_values, config): - configured_values = dict( - offset_azel=self.script.offset_azel, - offset_radec=self.script.offset_radec, - offset_xy=self.script.offset_xy, - offset_rot=self.script.offset_rot, - reset_offsets=self.script.reset_offsets, - absorb=self.script.absorb, - relative=self.script.relative, - ) - - for parameter in default_values: - with self.subTest(config=config, parameter=parameter): - assert ( - config.get(parameter, default_values.get(parameter)) - == configured_values[parameter] - ) - - async def test_offset_azel(self): - async with self.make_script(): - config = dict(offset_azel=dict(az=10, el=-10), absorb=False, relative=False) - - await self.configure_script(**config) - - self.script.mtcs.offset_azel = unittest.mock.AsyncMock() - - await self.run_script() - - self.script.mtcs.offset_azel.assert_awaited_once_with( - az=10, el=-10, absorb=False, relative=False - ) - - async def test_offset_radec(self): - async with self.make_script(): - config = dict(offset_radec=dict(ra=1, dec=-1)) - - await self.configure_script(**config) - - self.script.mtcs.offset_radec = unittest.mock.AsyncMock() - - await self.run_script() - - self.script.mtcs.offset_radec.assert_awaited_once_with( - ra=1, - dec=-1, - ) - - async def test_offset_xy(self): - async with self.make_script(): - config = dict(offset_xy=dict(x=10, y=-10)) - - await self.configure_script(**config) - - self.script.mtcs.offset_xy = unittest.mock.AsyncMock() - - await self.run_script() - - self.script.mtcs.offset_xy.assert_awaited_once_with( - x=10, - y=-10, - absorb=False, - relative=True, - ) - - async def test_offset_rot(self): - async with self.make_script(): - config = dict(offset_rot=dict(rot=10)) - - await self.configure_script(**config) - - self.script.mtcs.offset_rot = unittest.mock.AsyncMock() - - await self.run_script() - - self.script.mtcs.offset_rot.assert_awaited_once_with(rot=10) - - async def test_reset_offsets(self): - async with self.make_script(): - config = dict( - reset_offsets=dict(reset_absorbed=True, reset_non_absorbed=True) - ) - - await self.configure_script(**config) - - self.script.mtcs.reset_offsets = unittest.mock.AsyncMock() - - await self.run_script() - - self.script.mtcs.reset_offsets.assert_awaited_once_with( - absorbed=True, - non_absorbed=True, - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_open_mirror_covers.py b/tests/test_maintel_open_mirror_covers.py deleted file mode 100644 index 95c40d420..000000000 --- a/tests/test_maintel_open_mirror_covers.py +++ /dev/null @@ -1,75 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import OpenMirrorCovers - - -class TestOpenMirrorCovers( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = OpenMirrorCovers(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(self): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.open_m1_cover = unittest.mock.AsyncMock() - yield - - async def test_run(self): - async with self.make_dry_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.assert_all_enabled.assert_awaited_once() - self.script.mtcs.open_m1_cover.assert_awaited_once() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "open_mirror_covers.py" - await self.check_executable(script_path) - - async def test_configure_ignore(self): - async with self.make_script(): - components = ["mtptg"] - await self.configure_script(ignore=components) - - assert self.script.mtcs.check.mtptg is False - - async def test_configure_ignore_not_csc_component(self): - async with self.make_script(): - components = ["not_csc_comp", "mtptg"] - await self.configure_script(ignore=components) - - assert hasattr(self.script.mtcs, "not_csc_comp") is False - assert self.script.mtcs.check.mtptg is False - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_park_dome.py b/tests/test_maintel_park_dome.py deleted file mode 100644 index f0938373f..000000000 --- a/tests/test_maintel_park_dome.py +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtdome import ParkDome - - -class TestParkDome( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = ParkDome(index=index) - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "park_dome.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_point_azel.py b/tests/test_maintel_point_azel.py deleted file mode 100644 index 7c8142a83..000000000 --- a/tests/test_maintel_point_azel.py +++ /dev/null @@ -1,180 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import contextlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts import BaseScriptTestCase -from lsst.ts.standardscripts.maintel import PointAzEl - - -class TestPointAzEl(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = PointAzEl(index=index) - - return (self.script,) - - @contextlib.asynccontextmanager - async def make_dry_script(self): - async with self.make_script(): - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.components_attr = ["mtdometrajectory"] - - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - self.script.mtcs.point_azel = unittest.mock.AsyncMock() - self.script.mtcs.stop_tracking = unittest.mock.AsyncMock() - - yield - - async def test_config_fail_no_defaults(self) -> None: - async with self.make_dry_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script() - - async def test_config_fail_az_no_el(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, match="'el' is a required property" - ): - await self.configure_script(az=0.0) - - async def test_config_fail_el_no_az(self) -> None: - async with self.make_dry_script(): - with pytest.raises( - salobj.ExpectedError, match="'az' is a required property" - ): - await self.configure_script(el=0.0) - - async def test_configure_fail_invalid_el_min(self): - az = 0.0 - el = -0.1 - async with self.make_dry_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(el=el, az=az) - - async def test_configure_fail_invalid_el_max(self): - az = 0.0 - el = 90.1 - async with self.make_dry_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(el=el, az=az) - - async def test_config_ignore(self) -> None: - async with self.make_dry_script(): - az = 0.0 - el = 80.0 - ignore = ["mtdometrajectory", "no_comp"] - - await self.configure_script(az=az, el=el, ignore=ignore) - assert self.script.mtcs.check.mtdometrajectory is False - self.script.mtcs.check.no_comp.assert_not_called() - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - program = "BLOCK-123" - reason = "SITCOM-321" - await self.configure_script( - az=az, - el=el, - program=program, - reason=reason, - ) - - assert self.script.program == program - assert self.script.reason == reason - assert ( - self.script.checkpoint_message - == "PointAzEl BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_run_azel(self): - async with self.make_dry_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - - az = 0.0 - el = 80.0 - rot_tel = 0.0 - target_name = "eta Car" - wait_dome = False - slew_timeout = 240.0 - program = "BLOCK-123" - reason = "SITCOM-321" - - await self.configure_script( - az=az, - el=el, - rot_tel=rot_tel, - target_name=target_name, - wait_dome=wait_dome, - slew_timeout=slew_timeout, - program=program, - reason=reason, - ) - - await self.run_script() - - self.script.mtcs.point_azel.assert_awaited_once() - self.script.mtcs.point_azel.assert_called_with( - az=az, - el=el, - rot_tel=rot_tel, - target_name=target_name, - wait_dome=wait_dome, - slew_timeout=slew_timeout, - ) - - async def test_run_point_azel_fails(self): - async with self.make_dry_script(): - self.script.mtcs.point_azel = unittest.mock.AsyncMock( - side_effect=RuntimeError - ) - - await self.configure_script(az=0.0, el=80.0) - - with pytest.raises(AssertionError): - await self.run_script() - - self.script.mtcs.point_azel.assert_awaited_once() - self.script.tcs.stop_tracking.assert_awaited_once() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "point_azel.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_power_on_tunablelaser.py b/tests/test_maintel_power_on_tunablelaser.py deleted file mode 100644 index 4eeadd691..000000000 --- a/tests/test_maintel_power_on_tunablelaser.py +++ /dev/null @@ -1,208 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import os -import random -import types -import unittest -import warnings - -from lsst.ts import salobj, standardscripts, utils -from lsst.ts.standardscripts.maintel.calibration import PowerOnTunableLaser -from lsst.ts.xml.enums.TunableLaser import LaserDetailedState - -# TODO: (DM-46168) Revert workaround for TunableLaser XML changes -try: - from lsst.ts.xml.enums.TunableLaser import ( - OpticalConfiguration as LaserOpticalConfiguration, - ) -except ImportError: - warnings.warn( - "OpticalConfiguration enumeration not availble in ts-xml. Using local version." - ) - from lsst.ts.observatory.control.utils.enums import LaserOpticalConfiguration - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestPowerOnTunableLaser( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = PowerOnTunableLaser(index=index) - - self.laser_state = types.SimpleNamespace( - detailedState=LaserDetailedState.NONPROPAGATING_CONTINUOUS_MODE - ) - self.optical_config_state = types.SimpleNamespace( - configuration=LaserOpticalConfiguration.NO_SCU - ) - - await self.configure_mocks() - - return [ - self.script, - ] - - async def mock_setup_laser( - self, mode, wavelength, optical_configuration, use_projector - ): - self.laser_state = types.SimpleNamespace(detailedState=mode) - self.optical_config_state = types.SimpleNamespace( - configuration=optical_configuration - ) - self.script.optical_configuration = optical_configuration - self.script.wavelength = wavelength - - async def mock_laser_start_propagate(self, *args, **kwargs): - self.laser_state = types.SimpleNamespace( - detailedState=LaserDetailedState.PROPAGATING_CONTINUOUS_MODE - ) - - async def configure_mocks(self): - self.script.laser = unittest.mock.AsyncMock() - self.script.laser.start_task = utils.make_done_future() - # Mock evt_summaryState.aget to return ENABLED state - self.script.laser.evt_summaryState = unittest.mock.MagicMock() - self.script.laser.evt_summaryState.aget = unittest.mock.AsyncMock( - return_value=types.SimpleNamespace(summaryState=salobj.State.ENABLED) - ) - - # Mock MTCalsys - self.script.mtcalsys = unittest.mock.MagicMock() - self.script.mtcalsys.start_task = utils.make_done_future() - self.script.mtcalsys.load_calibration_config_file = unittest.mock.MagicMock() - self.script.mtcalsys.assert_valid_configuration_option = ( - unittest.mock.MagicMock() - ) - self.script.mtcalsys.get_calibration_configuration = unittest.mock.MagicMock( - return_value={ - "laser_mode": LaserDetailedState.NONPROPAGATING_CONTINUOUS_MODE, - "optical_configuration": LaserOpticalConfiguration.SCU.name, - "wavelength": 500.0, - } - ) - self.script.mtcalsys.setup_laser = unittest.mock.AsyncMock( - side_effect=self.mock_setup_laser - ) - self.script.mtcalsys.get_laser_parameters = unittest.mock.AsyncMock( - return_value=[ - "optical_configuration", - 500.0, - "interlock", - "burst_mode", - "cont_mode", - ] - ) - self.script.mtcalsys.laser_start_propagate = unittest.mock.AsyncMock( - side_effect=self.mock_laser_start_propagate - ) - - # async def configure_mocks(self): - # self.script.laser = unittest.mock.AsyncMock() - # self.script.laser.start_task = utils.make_done_future() - - # # Configure mocks - - self.script.laser.configure_mock( - **{ - "evt_summaryState.aget.side_effect": self.mock_get_laser_summary_state, - "cmd_setOpticalConfiguration.set_start.side_effect": self.mock_set_optical_config, - "cmd_setContinuousMode.start.side_effect": self.mock_set_continuous_mode, - "cmd_startPropagateLaser.start.side_effect": self.mock_start_laser, - } - ) - - async def mock_get_laser_summary_state(self, **kwargs): - return types.SimpleNamespace(summaryState=salobj.State.ENABLED) - - async def mock_set_optical_config(self, **kwargs): - self.optical_config_state = types.SimpleNamespace(configuration="SCU") - - async def mock_set_continuous_mode(self, **kwargs): - self.laser_state = types.SimpleNamespace( - detailedState=LaserDetailedState.NONPROPAGATING_CONTINUOUS_MODE - ) - - async def mock_start_laser(self, **kwargs): - self.laser_state = types.SimpleNamespace( - detailedState=LaserDetailedState.PROPAGATING_CONTINUOUS_MODE - ) - - async def test_configure(self): - # Try to configure with only some of the optional parameters - async with self.make_script(): - mode = LaserDetailedState.NONPROPAGATING_CONTINUOUS_MODE - optical_configuration = LaserOpticalConfiguration.SCU.name - wavelength = 500.0 - - await self.configure_script() - - assert self.script.laser_mode == mode - assert self.script.optical_configuration == optical_configuration - assert self.script.wavelength == wavelength - - async def test_run_without_failures(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - - # self.script.laser.cmd_changeWavelength.set_start.assert_awaited_once_with( - # wavelength=self.script.wavelength, - # ) - - # self.script.laser.cmd_setOpticalConfiguration.start.assert_awaited_once_with( - # configuration=self.script.optical_configuration, - # ) - - # self.script.laser.cmd_setContinuousMode.assert_awaited_once( - # ) - - # self.script.laser.cmd_startPropagateLaser.start.assert_awaited_with( - # ) - - # Summary State - self.script.laser.evt_summaryState.aget.assert_awaited_once_with() - - # Assert states are OK - assert ( - self.laser_state.detailedState - == LaserDetailedState.PROPAGATING_CONTINUOUS_MODE - ) - assert ( - self.script.optical_configuration == LaserOpticalConfiguration.SCU.name - ) - assert self.script.wavelength == 500.0 - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = os.path.join( - scripts_dir, "maintel", "calibration", "power_on_tunablelaser.py" - ) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_prepare_for_align.py b/tests/test_maintel_prepare_for_align.py deleted file mode 100644 index 357b88905..000000000 --- a/tests/test_maintel_prepare_for_align.py +++ /dev/null @@ -1,66 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.prepare_for import PrepareForAlign - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestPrepareForAlign( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = PrepareForAlign(index=index) - - return (self.script,) - - async def test_configure(self): - async with self.make_script(): - # Check it work with no configuration - await self.configure_script() - - async with self.make_script(): - tel_align_az = 0 - tel_align_el = 70 - tel_align_rot = 0 - - await self.configure_script( - tel_align_az=tel_align_az, - tel_align_el=tel_align_el, - tel_align_rot=tel_align_rot, - ) - - assert self.script.tel_align_az == tel_align_az - assert self.script.tel_align_el == tel_align_el - assert self.script.tel_align_rot == tel_align_rot - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "prepare_for" / "align.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_raise_m1m3.py b/tests/test_maintel_raise_m1m3.py deleted file mode 100644 index 7c03c33b3..000000000 --- a/tests/test_maintel_raise_m1m3.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel.m1m3 import RaiseM1M3 - - -class TestRaiseM1M3( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = RaiseM1M3(index=index) - self.script.mtcs = MTCS( - self.script.domain, intended_usage=MTCSUsages.DryTest, log=self.script.log - ) - self.script.mtcs.raise_m1m3 = unittest.mock.AsyncMock() - - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - self.script.mtcs.raise_m1m3.assert_awaited_once() - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "RaiseM1M3 BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "m1m3" / "raise_m1m3.py" - print(script_path) - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_set_dof.py b/tests/test_maintel_set_dof.py deleted file mode 100644 index 453e7040f..000000000 --- a/tests/test_maintel_set_dof.py +++ /dev/null @@ -1,83 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import types -import unittest - -import numpy as np -from lsst.ts import standardscripts -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.observatory.control.utils.enums import DOFName -from lsst.ts.standardscripts.maintel import SetDOF - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestSetDOF(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = SetDOF(index=index) - - # Mock the MTCS - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - self.script.mtcs.rem.mtaos = unittest.mock.AsyncMock() - self.script.mtcs.rem.mtaos.cmd_offsetDOF.attach_mock( - unittest.mock.Mock( - return_value=types.SimpleNamespace(value=np.zeros(len(DOFName))) - ), - "DataType", - ) - self.script.mtcs.rem.mtaos.configure_mock( - **{"evt_degreeOfFreedom.aget.side_effect": self.mock_get_degrees_of_freedom} - ) - - self.script.mtcs.assert_all_enabled = unittest.mock.AsyncMock() - - return (self.script,) - - async def mock_get_degrees_of_freedom(self, **kwargs): - return types.SimpleNamespace(aggregatedDoF=np.zeros(len(DOFName))) - - async def test_run(self) -> None: - # Start the test itself - async with self.make_script(): - config_dofs = {"M2_dz": 0.2, "Cam_dy": 0.3, "M1M3_B1": 0.5, "M2_B14": 0.7} - - await self.configure_script(**config_dofs) - - # Run the script - await self.run_script() - - self.script.mtcs.rem.mtaos.cmd_offsetDOF.DataType.assert_called() - self.script.mtcs.rem.mtaos.cmd_offsetDOF.start.assert_awaited_once() - - async def test_executable(self) -> None: - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "set_dof.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_setup_mtcs.py b/tests/test_maintel_setup_mtcs.py deleted file mode 100644 index 9de5c3e64..000000000 --- a/tests/test_maintel_setup_mtcs.py +++ /dev/null @@ -1,97 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest.mock - -from lsst.ts import salobj, utils -from lsst.ts.idl.enums import Script -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.maintel import SetupMTCS - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -index_gen = utils.index_generator() - - -class TestSetupMTCS(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = SetupMTCS(index=index, remotes=False) - self.script.checkpoints_activities = [ - (checkpoint, unittest.mock.AsyncMock()) - for checkpoint, _ in self.script.checkpoints_activities - ] - return (self.script,) - - async def test_configure_errors(self): - """Test error handling in the do_configure method.""" - # Check schema validation. - for bad_config in ( - # The only *bad* case is that ccw_following has invalid value - {"ccw_following": "BADVALUE"}, - ): - with self.subTest(bad_config=bad_config): - async with self.make_script(): - with self.assertRaises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_configure_good(self): - """Test configure method with valid configurations.""" - async with self.make_script(): - # Start with default configuration - await self.configure_script() - - # The default value for `ccw_following` is True - self.assertEqual(self.script.config.ccw_following, True) - - async with self.make_script(): - # Now try to change that to False - ccw_following = False - await self.configure_script( - ccw_following=ccw_following, - ) - - # Check configuration was correctly loaded - self.assertEqual(self.script.config.ccw_following, ccw_following) - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "setup_mtcs.py" - await self.check_executable(script_path) - - async def test_run(self): - # Start the test itself - async with self.make_script(): - # Configure the script - await self.configure_script() - assert self.script.state.state == Script.ScriptState.CONFIGURED - - # Run the script - await self.run_script() - assert self.script.state.state == Script.ScriptState.DONE - - # Check that runs the activities only once - for checkpoint, activity in self.script.checkpoints_activities: - activity.assert_awaited_once() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_standby_comcam.py b/tests/test_maintel_standby_comcam.py deleted file mode 100644 index 20de247dc..000000000 --- a/tests/test_maintel_standby_comcam.py +++ /dev/null @@ -1,75 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import random -import unittest - -from lsst.ts import salobj, standardscripts -from lsst.ts.observatory.control.mock import ComCamMock -from lsst.ts.standardscripts.maintel import StandbyComCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestStandbyComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = StandbyComCam(index=index) - self.comcam_mock = ComCamMock() - - return (self.script, self.comcam_mock) - - async def test_components(self): - async with self.make_script(): - for component in self.script.group.components_attr: - with self.subTest(f"Check {component}", component=component): - if getattr(self.script.group.check, component): - assert component in self.script.components() - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - - await self.run_script() - - for comp in self.script.group.components_attr: - if getattr(self.script.group.check, comp): - current_state = salobj.State( - getattr( - self.comcam_mock.controllers, comp - ).evt_summaryState.data.summaryState - ) - - with self.subTest(f"{comp} summary state", comp=comp): - assert current_state == salobj.State.STANDBY - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "standby_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_standby_mtcs.py b/tests/test_maintel_standby_mtcs.py deleted file mode 100644 index 7c63fc1a3..000000000 --- a/tests/test_maintel_standby_mtcs.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import StandbyMTCS - - -class TestStandbyMTCS( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = StandbyMTCS(index=index) - - return (self.script,) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "standby_mtcs.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_stop.py b/tests/test_maintel_stop.py deleted file mode 100644 index 77864fe85..000000000 --- a/tests/test_maintel_stop.py +++ /dev/null @@ -1,57 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import random -import unittest - -import pytest -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import Stop - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestStartup(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = Stop(index=index) - - # TODO DM-25731 - # Update this code to match auxtel/test_stop.py once - # MCS.stop_all is implemented. - return (self.script,) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - with pytest.raises(AssertionError): - await self.run_script() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "stop.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_stop_rotator.py b/tests/test_maintel_stop_rotator.py deleted file mode 100644 index 9f21cfdad..000000000 --- a/tests/test_maintel_stop_rotator.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import StopRotator - - -class TestStopRotator( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = StopRotator(index=index) - - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.configure_mock( - tel_settle_time=3.0 - ) # need this for the set_metadata method. - return (self.script,) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "stop_rotator.py" - await self.check_executable(script_path) - - async def test_run(self): - async with self.make_script(): - await self.configure_script() - await self.run_script() - - self.script.mtcs.stop_rotator.assert_awaited_once() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_stop_tracking.py b/tests/test_maintel_stop_tracking.py deleted file mode 100644 index 4569e05a0..000000000 --- a/tests/test_maintel_stop_tracking.py +++ /dev/null @@ -1,40 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts - - -class TestStopTracking( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - pass - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "stop_tracking.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_take_aos_sequence_comcam.py b/tests/test_maintel_take_aos_sequence_comcam.py deleted file mode 100644 index 128dbade6..000000000 --- a/tests/test_maintel_take_aos_sequence_comcam.py +++ /dev/null @@ -1,268 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import types -import unittest -from unittest.mock import patch - -from lsst.ts import standardscripts -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.observatory.control.maintel.comcam import ComCam, ComCamUsages -from lsst.ts.observatory.control.maintel.mtcs import MTCS, MTCSUsages -from lsst.ts.standardscripts.maintel import Mode, TakeAOSSequenceComCam -from lsst.ts.utils import index_generator - -index_gen = index_generator() - - -class TestTakeAOSSequenceComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = TakeAOSSequenceComCam(index=index) - - self.script.mtcs = MTCS( - domain=self.script.domain, - intended_usage=MTCSUsages.DryTest, - log=self.script.log, - ) - - self.script.camera = ComCam( - domain=self.script.domain, - intended_usage=ComCamUsages.DryTest, - log=self.script.log, - ) - - self.script.ocps = unittest.mock.AsyncMock() - - self.script.mtcs.offset_camera_hexapod = unittest.mock.AsyncMock() - self.script.camera.expose = unittest.mock.AsyncMock( - side_effect=self._get_visit_id - ) - self.script.camera.setup_instrument = unittest.mock.AsyncMock() - self.script.camera.rem.ccoods = unittest.mock.AsyncMock() - self.script.camera.rem.ccoods.configure_mock( - **{ - "evt_imageInOODS.next.side_effect": self._get_next_image_in_oods, - } - ) - - self._dayobs = 2024111900000 - self._visit_index = next(index_gen) - - return (self.script,) - - async def _get_visit_id(self, *args, **kwargs): - self._visit_index = next(index_gen) - return [self._dayobs + self._visit_index] - - async def _get_next_image_in_oods(self, *args, **kwargs): - return types.SimpleNamespace( - obsid=f"CC_O_{int(self._dayobs/100000)}_{self._visit_index:06d}", - raft=0, - sensor=0, - ) - - async def test_configure(self): - async with self.make_script(): - exposure_time = 15.0 - filter = "g" - dz = 2000.0 - n_sequences = 15 - mode = "INTRA" - - await self.configure_script( - filter=filter, - exposure_time=exposure_time, - dz=dz, - n_sequences=n_sequences, - mode=mode, - ) - assert self.script.exposure_time == exposure_time - assert self.script.filter == filter - assert self.script.dz == 2000.0 - assert self.script.n_sequences == n_sequences - assert self.script.mode == Mode.INTRA - - async def test_configure_ignore(self): - async with self.make_script(): - self.script.mtcs.check.mtmount = True - self.script.mtcs.check.mtrotator = True - self.script.mtcs.check.mtm2 = True - self.script.camera.check.ccoods = True - - exposure_time = 15.0 - filter = "g" - dz = 2000.0 - n_sequences = 15 - mode = "INTRA" - ignore = ["mtrotator", "mtm2", "ccoods"] - - await self.configure_script( - filter=filter, - exposure_time=exposure_time, - dz=dz, - n_sequences=n_sequences, - ignore=ignore, - mode=mode, - ) - assert self.script.exposure_time == exposure_time - assert self.script.filter == filter - assert self.script.dz == 2000.0 - assert self.script.n_sequences == n_sequences - assert self.script.mode == Mode.INTRA - assert self.script.mtcs.check.mtmount - assert not self.script.mtcs.check.mtrotator - assert not self.script.mtcs.check.mtm2 - assert not self.script.camera.check.ccoods - - async def run_take_triplets_test( - self, mock_ready_to_take_data=None, expect_exception=None - ): - async with self.make_script(): - self.script.camera.ready_to_take_data = mock_ready_to_take_data - - exposure_time = 15.0 - filter = "g" - dz = 2000.0 - n_sequences = 3 - mode = "TRIPLET" - - await self.configure_script( - filter=filter, - exposure_time=exposure_time, - dz=dz, - n_sequences=n_sequences, - mode=mode, - ) - - # Wrap `take_cwfs` and `take_acq` to count calls - with patch.object( - self.script.camera, "take_cwfs", wraps=self.script.camera.take_cwfs - ) as mock_take_cwfs, patch.object( - self.script.camera, "take_acq", wraps=self.script.camera.take_acq - ) as mock_take_acq: - - if expect_exception is not None: - await self.run_script(expected_final_state=ScriptState.FAILED) - self.assertEqual(self.script.state.state, ScriptState.FAILED) - self.assertIn( - str(mock_ready_to_take_data.side_effect), - self.script.state.reason, - ) - # the first image taken is type cwfs and in this case - # it should throw and exception for TCS not being ready - expected_take_cwfs_calls = 1 - expected_take_acq_calls = 0 - else: - await self.run_script() - self.assertEqual(self.script.state.state, ScriptState.DONE) - expected_take_cwfs_calls = n_sequences * 2 - expected_take_acq_calls = n_sequences - - expected_tcs_ready_calls = ( - expected_take_cwfs_calls + expected_take_acq_calls - ) - if expected_take_acq_calls > 0: - # number of calls to the expose method - # in BaseCamera.take_imgtype - expected_expose_calls = expected_tcs_ready_calls - else: - expected_expose_calls = 0 - - if mock_ready_to_take_data is not None: - self.assertEqual( - mock_ready_to_take_data.await_count, - expected_tcs_ready_calls, - f"ready_to_take_data was called {mock_ready_to_take_data.await_count} times, " - f"expected {expected_tcs_ready_calls}", - ) - else: - with self.assertRaises(AttributeError): - self.script.camera.ready_to_take_data.assert_not_called() - - self.assertEqual( - self.script.camera.expose.await_count, - expected_expose_calls, - f"expose was called {self.script.camera.expose.await_count} times, " - f"expected {expected_expose_calls}", - ) - self.assertEqual( - mock_take_cwfs.await_count, - expected_take_cwfs_calls, - f"take_cwfs was called {mock_take_cwfs.await_count} times, " - f"expected {expected_take_cwfs_calls}", - ) - self.assertEqual( - mock_take_acq.await_count, - expected_take_acq_calls, - f"take_acq was called {mock_take_acq.await_count} times, " - f"expected {expected_take_acq_calls}", - ) - - async def test_take_triplets(self): - await self.run_take_triplets_test() - - async def test_take_triplets_tcs_ready(self): - mock_ready = unittest.mock.AsyncMock(return_value=None) - await self.run_take_triplets_test( - mock_ready_to_take_data=mock_ready, - ) - - async def test_take_triplets_tcs_not_ready(self): - mock_ready = unittest.mock.AsyncMock(side_effect=RuntimeError("TCS not ready")) - await self.run_take_triplets_test( - mock_ready_to_take_data=mock_ready, expect_exception=RuntimeError - ) - - async def test_take_doublet(self): - async with self.make_script(): - self.script.camera.take_cwfs = unittest.mock.AsyncMock() - self.script.camera.take_acq = unittest.mock.AsyncMock() - - exposure_time = 15.0 - filter = "g" - dz = 2000.0 - n_sequences = 3 - mode = "INTRA" - - await self.configure_script( - filter=filter, - exposure_time=exposure_time, - dz=dz, - n_sequences=n_sequences, - mode=mode, - ) - - await self.run_script() - - assert n_sequences == self.script.camera.take_cwfs.await_count - assert n_sequences == self.script.camera.take_acq.await_count - - async def test_executable_lsstcam(self) -> None: - """Test that the script is executable.""" - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_aos_sequence_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_take_image_anycam.py b/tests/test_maintel_take_image_anycam.py deleted file mode 100644 index 9d249ef7a..000000000 --- a/tests/test_maintel_take_image_anycam.py +++ /dev/null @@ -1,423 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel import CameraSetup, TakeImageAnyCam - - -class TestTakeImageAnyCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = TakeImageAnyCam(index=index) - - self.mock_mtcs() - self.mock_cameras() - - return (self.script,) - - def mock_mtcs(self): - """Mock MTCS instances and its methods.""" - self.script.mtcs = unittest.mock.AsyncMock() - self.script.mtcs.assert_liveliness = unittest.mock.AsyncMock() - self.script.mtcs.components_attr = ["mtm1m3"] - - # Initialize camera_setups with mock cameras - self.script.camera_setups = {} - - def mock_cameras(self): - """Mock cameras (ComCam, LSSTCam, Generic Cameras) with - their methods and attributes - """ - # Mocking main cameras - for cam in ["LSSTCam", "ComCam"]: - camera = unittest.mock.AsyncMock(name=f"{cam}") - camera.assert_liveliness = unittest.mock.AsyncMock() - camera.assert_all_enabled = unittest.mock.AsyncMock() - camera.take_imgtype = unittest.mock.AsyncMock() - camera.setup_instrument = unittest.mock.AsyncMock() - camera.read_out_time = 2 - camera.shutter_time = 0.1 - self.script.camera_setups[cam.lower()] = CameraSetup( - camera=camera, - config=dict(), - identifier=cam, - normalize=False, - ) - - # Mocking generic cameras - for i in [101, 102, 103]: - gen_cam_key = f"generic_camera_{i}" - camera = unittest.mock.AsyncMock(name=f"GenericCam_{i}") - camera.assert_liveliness = unittest.mock.AsyncMock() - camera.assert_all_enabled = unittest.mock.AsyncMock() - camera.take_imgtype = unittest.mock.AsyncMock() - camera.read_out_time = 1 - camera.shutter_time = 0.1 - self.script.camera_setups[gen_cam_key] = CameraSetup( - camera=camera, - config=dict(), - identifier=f"GenericCam_{i}", - normalize=False, - ) - - async def assert_camera_setup(self, camera_setup_key, expected_config): - """ - Helper method to assert that a CameraSetup for a given camera - identifier has been correctly configured. - - Parameters - ---------- - camera_setup_key : str - The camera setup key of the camera to check ("lsstcam", "comcam", - "generic_camera_1", "generic_camera_2", "generic_camera_3"). - expected_config : dict - The expected configuration dictionary for the camera, before - normalization. - """ - camera_setup_found = False - - # Normalize the expected configuration to ensure it matches - # the format stored within CameraSetup objects. - normalized_expected_config = CameraSetup.normalize_config(expected_config) - - camera_setup = self.script.camera_setups.get(camera_setup_key) - if camera_setup: - camera_setup_config = camera_setup.config - assert camera_setup_config == normalized_expected_config, ( - f"Configuration mismatch for {camera_setup_key}: expected " - f"{normalized_expected_config}, got {camera_setup_config}" - ) - camera_setup_found = True - - assert ( - camera_setup_found - ), f"{camera_setup_key} setup missing or incorrect in camera_setups." - - async def test_config_ignore(self): - # Testing ignored components - lsstcam_config = { - "exp_times": 5, - "nimages": 5, - "image_type": "OBJECT", - "filter": "r", - } - config = { - "lsstcam": lsstcam_config, - "reason": "SITCOM-321", - "program": "BLOCK-123", - "note": "Test image", - "ignore": ["mtm1m3", "no_comp"], - } - async with self.make_script(): - await self.configure_script(**config) - - # Asserting that component were ignored - assert self.script.mtcs.check.mtm1m3 is False - self.script.mtcs.check.no_comp.assert_not_called() - - async def test_invalid_program_name(self): - # Testing invalid program name - bad_config = { - "comcam": { - "exp_times": [5, 15, 20], - "nimages": 10, - "image_type": "OBJECT", - "filter": None, - }, - "reason": "SITCOM-321", - "program": "BLOCK123", - "note": "Test image", - } - - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_invalid_config_comcam(self): - # Testing invalid exp_times and nimages entry - bad_config = { - "comcam": { - "exp_times": [5, 15, 20], - "nimages": 10, - "image_type": "OBJECT", - "filter": None, - }, - } - - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_configure_with_only_lsstcam(self): - lsstcam_config = { - "exp_times": [15, 30, 45, 60, 75, 90], - "image_type": "OBJECT", - "filter": "r", - } - config = { - "lsstcam": lsstcam_config, - "reason": "SITCOM-321", - "program": "BLOCK-123", - "note": "Test image", - "ignore": ["mtm1m3", "no_comp"], - } - - async with self.make_script(): - await self.configure_script(**config) - - # Asserting LSSTCam setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="lsstcam", expected_config=config["lsstcam"] - ) - - # Assert that ComCam config is empty - comcam_setup = self.script.camera_setups.get("comcam") - if comcam_setup: - assert comcam_setup.config == dict() - - async def test_configure_with_only_comcam(self): - comcam_config = { - "exp_times": 15, - "nimages": 10, - "image_type": "OBJECT", - "filter": 1, - } - config = { - "comcam": comcam_config, - "reason": "SITCOM-321", - "program": "BLOCK-123", - "note": "Test image", - } - - async with self.make_script(): - await self.configure_script(**config) - - # Asserting ComCam setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="comcam", expected_config=config["comcam"] - ) - - # Assert that LSSTCam config is empty - lsstcam_setup = self.script.camera_setups.get("lsstcam") - if lsstcam_setup: - assert lsstcam_setup.config == dict() - - async def test_configure_with_lsstcam_and_generic_cams(self): - config = { - "lsstcam": { - "exp_times": 0, - "nimages": 30, - "image_type": "BIAS", - }, - "gencam": [ - {"index": 101, "exp_times": 5, "nimages": 10, "image_type": "OBJECT"}, - {"index": 102, "exp_times": 30, "nimages": 1, "image_type": "DARK"}, - { - "index": 103, - "exp_times": [5, 10, 20, 40, 60, 120], - "image_type": "FLAT", - }, - ], - "reason": "SITCOM-321", - "program": "BLOCK-123", - "note": "Test image", - } - - async with self.make_script(): - await self.configure_script(**config) - - # Asserting LSSTCam setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="lsstcam", expected_config=config["lsstcam"] - ) - - # Asserting GenericCam_101 setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="generic_camera_101", - expected_config=config["gencam"][0], - ) - - # Asserting GenericCam_102 setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="generic_camera_102", - expected_config=config["gencam"][1], - ) - - # Assert that ComCam config is empty - comcam_setup = self.script.camera_setups.get("comcam") - if comcam_setup: - assert comcam_setup.config == dict() - - async def test_configure_with_comcam_and_generic_cams(self): - config = { - "comcam": { - "exp_times": 30, - "image_type": "OBJECT", - "filter": None, - }, - "gencam": [ - {"index": 101, "exp_times": 5, "image_type": "OBJECT"}, - {"index": 102, "exp_times": [15, 30, 60], "image_type": "OBJECT"}, - {"index": 103, "exp_times": 30, "nimages": 10, "image_type": "OBJECT"}, - ], - "ignore": ["mtm1m3", "no_comp"], - } - - async with self.make_script(): - await self.configure_script(**config) - - # Asserting ComCam setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="comcam", expected_config=config["comcam"] - ) - - # Asserting GenericCam_101 setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="generic_camera_101", - expected_config=config["gencam"][0], - ) - - # Asserting GenericCam_102 setup is correctly configured - await self.assert_camera_setup( - camera_setup_key="generic_camera_102", - expected_config=config["gencam"][1], - ) - - # Assert that LSSTCam config is empty - lsstcam_setup = self.script.camera_setups.get("lsstcam") - if lsstcam_setup: - assert lsstcam_setup.config == dict() - - async def test_configure_with_only_generic_cams(self): - config = { - "gencam": [ - {"index": 101, "exp_times": [15], "image_type": "OBJECT"}, - {"index": 102, "exp_times": 5, "nimages": 10, "image_type": "OBJECT"}, - {"index": 103, "exp_times": 0, "image_type": "BIAS"}, - ], - "ignore": ["mtm1m3", "no_comp"], - } - - async with self.make_script(): - await self.configure_script(**config) - - # Asserting Generic Cameras setup are correctly configured - await self.assert_camera_setup( - camera_setup_key="generic_camera_101", - expected_config=config["gencam"][0], - ) - - await self.assert_camera_setup( - camera_setup_key="generic_camera_102", - expected_config=config["gencam"][1], - ) - - await self.assert_camera_setup( - camera_setup_key="generic_camera_103", - expected_config=config["gencam"][2], - ) - - # Assert tha both LSSTCam and ComCam config are empty - lsstcam_setup = self.script.camera_setups.get("lsstcam") - if lsstcam_setup: - assert lsstcam_setup.config == dict() - - comcam_setup = self.script.camera_setups.get("comcam") - if comcam_setup: - assert comcam_setup.config == dict() - - async def validate_camera_configuration(self, cam_config, cam_key=None): - """Validates the camera setup and call counts based on its - configuration, ensuring that expected configuration is - normalized. - """ - if "exp_times" not in cam_config: - raise ValueError( - f"Invalid configuration for {cam_key}. Configuration must include 'exp_times'." - ) - - # Normalize the expected configuration to match the script's - # internal representation. - normalized_cam_config = CameraSetup.normalize_config(cam_config.copy()) - - # Calculate expected calls considering zero as valid exposure time - expected_calls = len( - [exp for exp in normalized_cam_config["exp_times"] if exp >= 0] - ) - - camera_key = cam_key if cam_key else f"generic_camera_{cam_config.get('index')}" - camera_setup = self.script.camera_setups.get(camera_key) - - if not camera_setup: - raise AssertionError(f"Camera setup for {camera_key} not found.") - - actual_calls = camera_setup.camera.take_imgtype.await_count - assert ( - actual_calls == expected_calls - ), f"Expected {expected_calls} calls for {camera_key}, got {actual_calls}." - - # Validate the filter setup if applicable - if "filter" in normalized_cam_config: - camera_setup.camera.setup_instrument.assert_awaited_once_with( - filter=normalized_cam_config["filter"] - ) - - async def test_run_block(self): - async with self.make_script(): - # Cnfiguration for LSSTCam, ComCam, and generic cameras - config = { - "lsstcam": { - "exp_times": 30, - "nimages": 10, - "image_type": "OBJECT", - "filter": None, - }, - "gencam": [ - {"index": 101, "exp_times": 30, "image_type": "DARK"}, - {"index": 102, "exp_times": [15, 30, 60], "image_type": "OBJECT"}, - { - "index": 103, - "exp_times": 30, - "nimages": 10, - "image_type": "OBJECT", - }, - ], - } - - await self.configure_script(**config) - await self.run_script() - - # Validate configurations and calls for each configured camera - for cam_key, cam_config in config.items(): - if cam_key == "gencam": # gencam is a list of dictionaries - for gencam_config in cam_config: - await self.validate_camera_configuration(gencam_config) - else: # lsstcam and comcam are dictionaries - await self.validate_camera_configuration(cam_config, cam_key) - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_image_anycam.py" - await self.check_executable(script_path) diff --git a/tests/test_maintel_take_image_comcam.py b/tests/test_maintel_take_image_comcam.py deleted file mode 100644 index 745dbc53b..000000000 --- a/tests/test_maintel_take_image_comcam.py +++ /dev/null @@ -1,196 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.maintel import TakeImageComCam -from lsst.ts.xml.enums import Script - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestTakeImageComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = TakeImageComCam(index=index) - - return (self.script,) - - async def test_configure_with_metadata_and_slew_time_sim(self): - async with self.make_script(): - exp_times = 1.1 - image_type = "OBJECT" - visit_metadata = dict(ra=10.0, dec=-90.0, rot_sky=5.0) - slew_time = 10 - - await self.configure_script( - exp_times=exp_times, - image_type=image_type, - visit_metadata=visit_metadata, - slew_time=slew_time, - sim=True, - ) - assert self.script.config.exp_times == [exp_times] - assert self.script.config.image_type == image_type - assert self.script.config.filter is None - assert self.script.config.visit_metadata == visit_metadata - assert self.script.config.slew_time == slew_time - assert self.script.get_instrument_name() == "LSSTComCamSim" - - async def test_configure_no_filter(self): - async with self.make_script(): - exp_times = 1.1 - image_type = "OBJECT" - nimages = 2 - filter = None - await self.configure_script( - exp_times=exp_times, - image_type=image_type, - nimages=nimages, - filter=filter, - ) - assert self.script.config.exp_times == [exp_times, exp_times] - assert self.script.config.image_type == image_type - assert self.script.config.filter == filter - - async def test_configure_filter_as_str(self): - async with self.make_script(): - exp_times = 1.1 - nimages = 2 - filter = "blue" - image_type = "OBJECT" - await self.configure_script( - exp_times=exp_times, - image_type=image_type, - nimages=nimages, - filter=filter, - ) - assert self.script.config.exp_times == [exp_times, exp_times] - assert self.script.config.image_type == image_type - assert self.script.config.filter == filter - - async def test_configure_filter_as_number(self): - async with self.make_script(): - exp_times = [0, 2, 0.5] - filter = 2 - image_type = "OBJECT" - await self.configure_script( - exp_times=exp_times, - image_type=image_type, - filter=filter, - ) - assert self.script.config.exp_times == exp_times - assert self.script.config.image_type == image_type - assert self.script.config.filter == filter - - async def test_configure_fails_missing_image_type(self): - async with self.make_script(): - exp_times = [0, 2, 0.5] - image_type = "OBJECT" - nimages = len(exp_times) + 1 - with pytest.raises(salobj.ExpectedError): - await self.configure_script( - exp_times=exp_times, image_type=image_type, nimages=nimages - ) - - async def run_take_images_test( - self, mock_ready_to_take_data=None, expect_exception=None - ): - async with self.make_script(): - self.script.camera.ready_to_take_data = mock_ready_to_take_data - # instead of mocking camera.take_imgtype mock expose - self.script.camera.expose = unittest.mock.AsyncMock() - self.script.camera.setup_instrument = unittest.mock.AsyncMock() - - nimages = 5 - - config = await self.configure_script( - nimages=nimages, - exp_times=1.0, - image_type="OBJECT", - filter=1, - ) - - if expect_exception is not None: - await self.run_script(expected_final_state=Script.ScriptState.FAILED) - self.assertEqual(self.script.state.state, Script.ScriptState.FAILED) - self.assertIn( - str(mock_ready_to_take_data.side_effect), self.script.state.reason - ) - else: - await self.run_script() - self.assertEqual(self.script.state.state, Script.ScriptState.DONE) - - if mock_ready_to_take_data is not None: - if expect_exception: - mock_ready_to_take_data.assert_awaited_once() - else: - self.assertEqual(mock_ready_to_take_data.await_count, nimages) - else: - with self.assertRaises(AttributeError): - self.script.camera.ready_to_take_data.assert_not_called() - - if expect_exception is None: - assert nimages == config.nimages - - # Define the expected calls: first with filter=1 which is - # first called in BaseTakeImage run method, the rest - # happens in (take_imgtype x nimages) without arguments - expected_calls = [unittest.mock.call(filter=1)] + [ - unittest.mock.call() - ] * nimages - - self.script.camera.setup_instrument.assert_has_awaits( - expected_calls, any_order=False - ) - - async def test_take_images(self): - await self.run_take_images_test() - - async def test_take_images_tcs_ready(self): - mock_ready = unittest.mock.AsyncMock(return_value=None) - await self.run_take_images_test(mock_ready_to_take_data=mock_ready) - - async def test_take_images_tcs_not_ready(self): - mock_ready = unittest.mock.AsyncMock(side_effect=RuntimeError("TCS not ready")) - await self.run_take_images_test( - mock_ready_to_take_data=mock_ready, expect_exception=RuntimeError - ) - - async def test_executable_comcam(self): - """Test that the script is executable for ComCam.""" - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_image_comcam.py" - await self.check_executable(script_path) - - async def test_executable_lsstcam(self) -> None: - """Test that the script is executable for LSSTCam.""" - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_image_lsstcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_take_stuttered_comcam.py b/tests/test_maintel_take_stuttered_comcam.py deleted file mode 100644 index 0c4b677da..000000000 --- a/tests/test_maintel_take_stuttered_comcam.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import TakeStutteredComCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestTakeStutteredComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = TakeStutteredComCam(index=index) - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_stuttered_comcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_take_stuttered_lsstcam.py b/tests/test_maintel_take_stuttered_lsstcam.py deleted file mode 100644 index c744ce11b..000000000 --- a/tests/test_maintel_take_stuttered_lsstcam.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel import TakeStutteredLSSTCam - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestTakeStutteredLSSTCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = TakeStutteredLSSTCam(index=index) - - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "take_stuttered_lsstcam.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_track_target.py b/tests/test_maintel_track_target.py deleted file mode 100644 index 9c388129d..000000000 --- a/tests/test_maintel_track_target.py +++ /dev/null @@ -1,415 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import random -import unittest - -import pytest -from lsst.ts import salobj, standardscripts, utils -from lsst.ts.idl.enums.MTPtg import WrapStrategy -from lsst.ts.observatory.control import RotType -from lsst.ts.standardscripts.maintel import TrackTarget -from lsst.ts.xml.enums.MTPtg import Planets - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestMTSlew(standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = TrackTarget(index=index) - - return (self.script,) - - async def test_configure_fail_no_defaults(self): - """Test different configuration scenarios.""" - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Test no default configuration. User must provide something. - with pytest.raises(salobj.ExpectedError): - await self.configure_script() - - async def test_configure_fail_ra_no_dec(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # If RA is given Dec must be given too. - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(ra=10.0)) - - async def test_configure_fail_dec_no_ra(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # If Dec is given ra must be given too. - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(dec=-10.0)) - - async def test_configure_fail_invalid_ra_min(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Invalid RA - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(ra=-0.1, dec=0.0)) - - async def test_configure_fail_invalid_ra_max(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Invalid RA - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(ra=24.1, dec=0.0)) - - async def test_configure_fail_invalid_dec_min(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Invalid Dec - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(ra=1.0, dec=-90.1)) - - async def test_configure_fail_invalid_dec_max(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Invalid Dec - with pytest.raises(salobj.ExpectedError): - await self.configure_script(slew_icrs=dict(ra=1.0, dec=90.1)) - - async def test_configure_fail_invalid_rot_type(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Invalid rot_type - with pytest.raises(salobj.ExpectedError): - await self.configure_script( - slew_icrs=dict( - ra=1.0, - dec=-10.0, - ), - rot_type="invalid", - ) - - async def test_configure_with_target_name(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Script can be configured with target name only - await self.configure_script(target_name="eta Car") - assert self.script.program is None - assert self.script.reason is None - assert self.script.checkpoint_message is None - - @unittest.mock.patch( - "lsst.ts.standardscripts.BaseBlockScript.obs_id", "202306060001" - ) - async def test_configure_with_target_name_program_reason(self): - """Testing a valid configuration: with program and reason""" - - # Try configure with a list of valid actuators ids - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.get_obs_id = unittest.mock.AsyncMock( - side_effect=["202306060001"] - ) - await self.configure_script( - target_name="eta Car", - program="BLOCK-123", - reason="SITCOM-321", - ) - - assert self.script.program == "BLOCK-123" - assert self.script.reason == "SITCOM-321" - assert ( - self.script.checkpoint_message - == "TrackTarget BLOCK-123 202306060001 SITCOM-321" - ) - - async def test_configure_with_slew_planet(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - - # Script can be configured with slew_planet - await self.configure_script(slew_planet=dict(planet_name="PLUTO")) - - async def test_configure_with_slew_ephem(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - - # Script can be configured with slew_ephem - await self.configure_script( - slew_ephem=dict(ephem_file="filename.txt", object_name="Chariklo") - ) - - async def test_configure_with_ra_dec(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Script can be configured with ra, dec only - await self.configure_script(slew_icrs=dict(ra=1.0, dec=-10.0)) - - async def test_configure_with_ra_dec_sexagesimal(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - # Script can be configured with ra, dec only - await self.configure_script( - slew_icrs=dict(ra="+0:00:00", dec="-10:00:00.0") - ) - - async def test_configure_with_azel(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - - # Script can be configured with az/el - await self.configure_script( - find_target=dict(az=1.0, el=80.0, mag_limit=8.0) - ) - - async def test_configure_rot_strategies(self): - # Configure passing rotator angle and all rotator strategies - for rot_type in RotType: - with self.subTest(f"rot_type={rot_type.name}", rot_type=rot_type.name): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - - await self.configure_script( - slew_icrs=dict(ra=1.0, dec=-10.0), - rot_value=10, - rot_type=rot_type.name, - ) - - async def test_configure_with_ignore(self): - async with self.make_script(): - # Test ignore feature. - await self.configure_script( - target_name="eta Car", ignore=["mtdometrajectory", "mthexapod_1"] - ) - - assert not self.script.tcs.check.mtdometrajectory - assert not self.script.tcs.check.mthexapod_1 - - async def test_configure_with_az_wrap_strategy(self): - # Configure passing az_wrap_strategy - for az_wrap_strategy in WrapStrategy: - with self.subTest(f"az_wrap_strategy={az_wrap_strategy.name}"): - async with self.make_script(): - await self.configure_script( - slew_icrs=dict(ra=1.0, dec=-10.0), - az_wrap_strategy=az_wrap_strategy.name, - ) - assert self.script.config.az_wrap_strategy == az_wrap_strategy - - async def test_run_slew_target_name(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_icrs = unittest.mock.AsyncMock() - self.script.tcs.slew_object = unittest.mock.AsyncMock() - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - # Check running with target_name only - await self.configure_script(target_name="eta Car") - - await self.run_script() - - self.assert_slew_target_name() - - async def test_run_slew_planet(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_to_planet = unittest.mock.AsyncMock() - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - # Get planet name - planet_name = Planets["PLUTO"].name - - # Check running with planet name - config = dict(slew_planet=dict(planet_name=planet_name)) - - await self.configure_script(**config) - - await self.run_script() - - self.assert_slew_planet(planet_name) - - async def test_run_slew_ephem(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_ephem_target = unittest.mock.AsyncMock() - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - # Check running with ephem file - config = dict( - slew_ephem=dict(ephem_file="filename.txt", object_name="Chariklo") - ) - - await self.configure_script(**config) - - await self.run_script() - - self.assert_slew_ephem_target( - ephem_file=config["slew_ephem"]["ephem_file"], - object_name=config["slew_ephem"]["object_name"], - ) - - async def test_run_slew_azel(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_icrs = unittest.mock.AsyncMock() - self.script.tcs.slew_object = unittest.mock.AsyncMock() - self.script.tcs.find_target = unittest.mock.AsyncMock( - return_value="eta Car" - ) - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - self.script.tcs.slew_object.reset_mock() - self.script.tcs.slew_icrs.reset_mock() - - # Check running with ra dec only - config = dict(find_target=dict(az=0.0, el=80.0, mag_limit=1.0)) - - await self.configure_script(**config) - - await self.run_script() - - self.assert_slew_azel(find_target_config=config["find_target"]) - - async def test_run_slew_radec(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_icrs = unittest.mock.AsyncMock() - self.script.tcs.slew_object = unittest.mock.AsyncMock() - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - # Check running with ra dec only - await self.configure_script(slew_icrs=dict(ra=1.0, dec=-10.0)) - - await self.run_script() - - self.assert_slew_radec() - - async def test_run_slew_fails(self): - async with self.make_script(): - self.script._mtcs = unittest.mock.AsyncMock() - self.script._mtcs.start_task = utils.make_done_future() - self.script.tcs.slew_icrs = unittest.mock.AsyncMock( - side_effect=RuntimeError - ) - self.script.tcs.slew_object = unittest.mock.AsyncMock() - self.script.tcs.stop_tracking = unittest.mock.AsyncMock() - - # Check running with ra dec only - await self.configure_script(slew_icrs=dict(ra=1.0, dec=-10.0)) - - with pytest.raises(AssertionError): - await self.run_script() - - self.assert_slew_fails() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "track_target.py" - await self.check_executable(script_path) - - def assert_slew_radec(self): - self.script.tcs.slew_icrs.assert_awaited_once() - self.script.tcs.slew_icrs.assert_awaited_with( - ra=self.script.config.slew_icrs["ra"], - dec=self.script.config.slew_icrs["dec"], - rot=self.script.config.rot_value, - rot_type=self.script.config.rot_type, - target_name=getattr(self.script.config, "target_name", "slew_icrs"), - dra=self.script.config.differential_tracking["dra"], - ddec=self.script.config.differential_tracking["ddec"], - offset_x=self.script.config.offset["x"], - offset_y=self.script.config.offset["y"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.config.track_for, - slew_timeout=240.0, - ) - self.script.tcs.slew_object.assert_not_awaited() - self.script.tcs.stop_tracking.assert_not_awaited() - - def assert_slew_target_name(self): - self.script.tcs.slew_object.assert_awaited_once() - self.script.tcs.slew_object.assert_awaited_with( - name="eta Car", - rot=0.0, - rot_type=RotType.SkyAuto, - dra=0.0, - ddec=0.0, - offset_x=0.0, - offset_y=0.0, - az_wrap_strategy=self.script.tcs.WrapStrategy.OPTIMIZE, - time_on_target=0.0, - slew_timeout=240.0, - ) - self.script.tcs.slew_icrs.assert_not_awaited() - self.script.tcs.stop_tracking.assert_not_awaited() - - def assert_slew_azel(self, find_target_config): - self.script.tcs.find_target.assert_awaited_once() - self.script.tcs.find_target.assert_awaited_with(**find_target_config) - self.assert_slew_target_name() - - def assert_slew_fails(self): - self.script.tcs.slew_icrs.assert_awaited_once() - self.script.tcs.slew_object.assert_not_awaited() - self.script.tcs.stop_tracking.assert_awaited_once() - - def assert_slew_planet(self, planet_name): - planet_enum = Planets[planet_name] - self.script.tcs.slew_to_planet.assert_awaited_once() - self.script.tcs.slew_to_planet.assert_awaited_with( - planet=planet_enum, - rot_sky=self.script.config.rot_value, - slew_timeout=self.script.config.slew_timeout, - ) - self.script.tcs.stop_tracking.assert_not_awaited() - - def assert_slew_ephem_target(self, ephem_file, object_name): - self.script.tcs.slew_ephem_target.assert_awaited_once() - self.script.tcs.slew_ephem_target.assert_awaited_with( - ephem_file=ephem_file, - target_name=object_name, - rot_sky=self.script.config.rot_value, - slew_timeout=self.script.config.slew_timeout, - ) - - self.script.tcs.stop_tracking.assert_not_awaited() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_track_target_and_take_image_comcam.py b/tests/test_maintel_track_target_and_take_image_comcam.py deleted file mode 100644 index f66ccb17f..000000000 --- a/tests/test_maintel_track_target_and_take_image_comcam.py +++ /dev/null @@ -1,457 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import contextlib -import copy -import logging -import random -import types -import unittest - -import numpy -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.observatory.control.utils import RotType -from lsst.ts.standardscripts.maintel.track_target_and_take_image_comcam import ( - TrackTargetAndTakeImageComCam, -) - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestMainTelTrackTargetAndTakeImageComCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - """Test Main Telescope track target and take image with ComCam script. - - Both AT and MT Slew scripts uses the same base script class. This unit - test performs the basic checks on Script integrity. For a more detailed - unit testing routine check the MT version. - """ - - @classmethod - def setUpClass(cls) -> None: - cls.log = logging.getLogger("TestMainTelTrackTargetAndTakeImageComCam") - return super().setUpClass() - - def setUp(self) -> None: - self.current_filter = "r" - self.available_filters = ["g", "r", "i"] - self.rotator_position = 0.0 # deg - self.rotator_velocity = 10.0 # deg/s - self.rot_sky_emulate_zero = 45.0 - self._handle_slew_calls = 0 - self._fail_handle_slew_after = 0 - return super().setUp() - - async def basic_make_script(self, index): - self.script = TrackTargetAndTakeImageComCam(index=index, add_remotes=False) - - return (self.script,) - - async def test_configure(self): - async with self.make_script(): - configuration_full = await self.configure_script_full() - - for key in configuration_full: - assert configuration_full[key] == getattr(self.script.config, key) - - required_fields = { - "ra", - "dec", - "rot_sky", - "name", - "obs_time", - "num_exp", - "exp_times", - "band_filter", - } - - for required_field in required_fields: - bad_configuration = copy.deepcopy(configuration_full) - bad_configuration.pop(required_field) - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_configuration) - - async def test_run_already_in_filter(self): - async with self.make_script(), self.setup_mocks(): - self.script.mtcs.check_tracking.side_effect = ( - self.check_tracking_forever_side_effect - ) - - configuration_full = await self.configure_script_full() - - await self.run_script() - - self.script.mtcs.slew_icrs.assert_awaited_once_with( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=configuration_full["rot_sky"], - rot_type=RotType.Sky, - target_name=configuration_full["name"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ) - - comcam_take_object_calls = [ - unittest.mock.call( - exptime=exptime, - group_id=self.script.group_id, - reason=configuration_full["reason"], - program=configuration_full["program"], - ) - for exptime in configuration_full["exp_times"] - ] - - self.script.comcam.take_object.assert_has_awaits(comcam_take_object_calls) - self.script.mtcs.check_tracking.assert_awaited_once() - - self.script.mtcs.stop_tracking.assert_not_awaited() - - async def test_run_with_filter_change(self): - async with self.make_script(), self.setup_mocks(): - self.current_filter = "g" - self.rotator_position = -15.0 - - self.script.mtcs.check_tracking.side_effect = ( - self.check_tracking_forever_side_effect - ) - - configuration_full = await self.configure_script_full() - - await self.run_script() - - slew_icrs_expected_calls = [ - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=self.script.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{configuration_full['name']} - filter change", - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=configuration_full["rot_sky"], - rot_type=RotType.Sky, - target_name=configuration_full["name"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - ] - - self.script.mtcs.slew_icrs.assert_has_awaits(slew_icrs_expected_calls) - - comcam_take_object_calls = [ - unittest.mock.call( - exptime=exptime, - group_id=self.script.group_id, - reason=configuration_full["reason"], - program=configuration_full["program"], - ) - for exptime in configuration_full["exp_times"] - ] - - self.script.comcam.take_object.assert_has_awaits(comcam_take_object_calls) - self.script.mtcs.check_tracking.assert_awaited_once() - - self.script.mtcs.stop_tracking.assert_not_awaited() - - async def test_run_fail_setup_filter(self): - async with self.make_script(), self.setup_mocks(): - configuration_full = await self.configure_script_full(band_filter="z") - - with pytest.raises(AssertionError): - await self.run_script() - - self.script.mtcs.slew_icrs.assert_awaited_once_with( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=self.script.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{configuration_full['name']} - filter change", - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ) - self.script.comcam.setup_filter.assert_awaited_once_with( - filter=configuration_full["band_filter"], - ) - - self.script.comcam.take_object.assert_not_awaited() - self.script.mtcs.check_tracking.assert_not_awaited() - - self.script.mtcs.stop_tracking.assert_awaited_once() - - async def test_run_fail_slew_during_rotator_wait(self): - async with self.make_script(), self.setup_mocks(): - self.script.mtcs.slew_icrs.side_effect = RuntimeError("Slew failed") - - self.rotator_position = -15.0 - - configuration_full = await self.configure_script_full(band_filter="g") - - with pytest.raises(AssertionError): - await self.run_script() - - slew_icrs_expected_calls = [ - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=self.script.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{configuration_full['name']} - filter change", - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ) - ] - - self.script.mtcs.slew_icrs.assert_has_awaits(slew_icrs_expected_calls) - - self.script.comcam.setup_filter.assert_not_awaited() - self.script.comcam.take_object.assert_not_awaited() - self.script.mtcs.check_tracking.assert_not_awaited() - - self.script.mtcs.stop_tracking.assert_awaited_once() - - async def test_run_fail_slew_after_filter_change(self): - async with self.make_script(), self.setup_mocks(): - self._fail_handle_slew_after = 1 - self.rotator_position = -15.0 - - configuration_full = await self.configure_script_full(band_filter="g") - - with pytest.raises(AssertionError): - await self.run_script() - - slew_icrs_expected_calls = [ - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=self.script.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{configuration_full['name']} - filter change", - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=configuration_full["rot_sky"], - rot_type=RotType.Sky, - target_name=configuration_full["name"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - ] - - self.script.mtcs.slew_icrs.assert_has_awaits(slew_icrs_expected_calls) - - self.script.comcam.setup_filter.assert_awaited_once_with( - filter=configuration_full["band_filter"], - ) - - self.script.comcam.take_object.assert_not_awaited() - self.script.mtcs.check_tracking.assert_not_awaited() - - self.script.mtcs.stop_tracking.assert_awaited_once() - - async def test_run_fail_check_tracking(self): - async with self.make_script(), self.setup_mocks(): - self.script.mtcs.check_tracking.side_effect = ( - self.check_tracking_fail_after_1s_side_effect - ) - - self.rotator_position = -15.0 - - configuration_full = await self.configure_script_full(band_filter="g") - - with pytest.raises(AssertionError): - await self.run_script() - - slew_icrs_expected_calls = [ - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=self.script.angle_filter_change, - rot_type=RotType.Physical, - target_name=f"{configuration_full['name']} - filter change", - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=configuration_full["rot_sky"], - rot_type=RotType.Sky, - target_name=configuration_full["name"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - ] - - self.script.mtcs.slew_icrs.assert_has_awaits(slew_icrs_expected_calls) - - self.script.comcam.setup_filter.assert_awaited_once_with( - filter=configuration_full["band_filter"], - ) - comcam_take_object_calls = [ - unittest.mock.call( - exptime=configuration_full["exp_times"][0], - group_id=self.script.group_id, - reason=configuration_full["reason"], - program=configuration_full["program"], - ) - ] - - self.script.comcam.take_object.assert_has_awaits(comcam_take_object_calls) - - self.script.mtcs.check_tracking.assert_awaited_once() - - self.script.mtcs.stop_tracking.assert_awaited_once() - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "auxtel" / "track_target_and_take_image.py" - await self.check_executable(script_path) - - @contextlib.asynccontextmanager - async def setup_mocks(self): - self.script.mtcs.slew_icrs = unittest.mock.AsyncMock( - side_effect=self.handle_slew_icrs - ) - self.script.mtcs.stop_tracking = unittest.mock.AsyncMock() - self.script.mtcs.check_tracking = unittest.mock.AsyncMock() - self.script.mtcs.rem = types.SimpleNamespace( - mtrotator=unittest.mock.AsyncMock() - ) - self.script.comcam.setup_filter = unittest.mock.AsyncMock( - side_effect=self.set_filter - ) - self.script.comcam.get_current_filter = unittest.mock.AsyncMock( - side_effect=self.get_current_filter - ) - self.script.comcam.take_object = unittest.mock.AsyncMock( - side_effect=self.take_object_side_effect - ) - - self.script.mtcs.rem.mtrotator.configure_mock( - **{"tel_rotation.next.side_effect": self.get_rotator_position} - ) - - yield - - async def configure_script_full(self, band_filter="r"): - configuration_full = dict( - targetid=10, - ra="10:00:00", - dec="-10:00:00", - rot_sky=0.0, - name="unit_test_target", - obs_time=7.0, - estimated_slew_time=5.0, - num_exp=2, - exp_times=[2.0, 1.0], - band_filter=band_filter, - reason="Unit testing", - program="UTEST", - ) - - await self.configure_script(**configuration_full) - - return configuration_full - - async def check_tracking_forever_side_effect(self): - """Emulates a check tracking routine.""" - self.log.debug("Wait for ever.") - future = asyncio.Future() - await future - - async def check_tracking_fail_after_1s_side_effect(self): - self.log.debug("Wait 1 second and raise runtime error.") - await asyncio.sleep(1.0) - raise RuntimeError("Check tracking failed.") - - async def take_object_side_effect( - self, - exptime, - group_id, - reason, - program, - ): - self.log.debug( - f"exptime: {exptime}s, group_id: {group_id}, reason: {reason}, program: {program}" - ) - await asyncio.sleep(exptime) - - async def get_current_filter(self): - return self.current_filter - - async def set_filter(self, filter): - if filter not in self.available_filters: - raise RuntimeError( - f"Filter {filter} not available. Must be one of {self.available_filters}." - ) - else: - await asyncio.sleep(0.5) - self.log.debug(f"{self.current_filter} -> {filter}") - self.current_filter = filter - - async def get_rotator_position(self, flush, timeout): - if flush: - await asyncio.sleep(timeout / 2.0) - return types.SimpleNamespace(actualPosition=self.rotator_position) - - async def handle_slew_icrs(self, rot, rot_type, **kwargs): - self._handle_slew_calls += 1 - if ( - self._fail_handle_slew_after > 0 - and self._handle_slew_calls > self._fail_handle_slew_after - ): - raise RuntimeError( - f"Failing slew after {self._fail_handle_slew_after} calls." - ) - await asyncio.sleep(0.5) - if rot_type == RotType.Physical: - self.log.debug(f"Slew with rot_type = {RotType.Physical!r}") - rotator_velocity = self.rotator_velocity * ( - 1.0 if rot > self.rotator_position else -1.0 - ) - rotator_positions = numpy.arange( - self.rotator_position, rot, rotator_velocity - ) - for _rot in rotator_positions: - self.log.debug(f"Rotator position: {self.rotator_position} -> {_rot}") - self.rotator_position = _rot - await asyncio.sleep(1.0) - self.rotator_position = rot - else: - self.rotator_position = rot + self.rot_sky_emulate_zero - await asyncio.sleep(0.5) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_track_target_and_take_image_gencam.py b/tests/test_maintel_track_target_and_take_image_gencam.py deleted file mode 100644 index 3c95a0932..000000000 --- a/tests/test_maintel_track_target_and_take_image_gencam.py +++ /dev/null @@ -1,308 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import contextlib -import copy -import logging -import random -import types -import unittest - -import numpy -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.observatory.control.utils import RotType -from lsst.ts.standardscripts.maintel.track_target_and_take_image_gencam import ( - TrackTargetAndTakeImageGenCam, -) - -random.seed(42) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TestMainTelTrackTargetAndTakeImageGenCam( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - """ - Test Main Telescope track target and take image with GenCam script. - - Both AT and MT Slew scripts uses the same base script class. This unit - test performs the basic checks on Script integrity. For a more detailed - unit testing routine check the MT version. - """ - - @classmethod - def setUpClass(cls) -> None: - cls.log = logging.getLogger("TestMainTelTrackTargetAndTakeImageGenCam") - return super().setUpClass() - - def setUp(self) -> None: - self.rotator_position = 0.0 # deg - self.rotator_velocity = 10.0 # deg/s - self.rot_sky_emulate_zero = 45.0 - self._handle_slew_calls = 0 - self._fail_handle_slew_after = 0 - return super().setUp() - - async def basic_make_script(self, index): - self.script = TrackTargetAndTakeImageGenCam(index=index, add_remotes=False) - return (self.script,) - - async def check_tracking_fail_after_1s_side_effect(self): - self.log.debug("Wait 1 second and raise runtime error.") - await asyncio.sleep(1.0) - raise RuntimeError("Check tracking failed.") - - async def check_tracking_forever_side_effect(self): - """Emulates a check tracking routine.""" - self.log.debug("Wait for ever.") - future = asyncio.Future() - await future - - async def configure_script_full( - self, - generic_camera: list | None = None, - ) -> None: - if generic_camera is None: - generic_camera = [ - dict( - index=random.randint(1, 10), - exp_times=[random.randint(1, 10) for _ in range(2)], - ), - ] - - configuration_full = dict( - targetid=10, - ra="10:00:00", - dec="-10:00:00", - rot_sky=0.0, - name="unit_test_target", - obs_time=7.0, - estimated_slew_time=5.0, - # Instead of num_exp, the number of exposures is definve by the - # number of elements in generic_camera.exp_times. - num_exp=2, - # exp_times is ignored in this script. - # Use generic_camera.exp_times instead. - exp_times=[0, 0], - reason="Unit testing", - program="UTEST", - generic_camera=generic_camera, - band_filter="", - ) - - await self.configure_script(**configuration_full) - self.log.debug(f"Parsed configuration:\n {self.script.config}") - - return configuration_full - - async def get_rotator_position(self, flush, timeout): - if flush: - await asyncio.sleep(timeout / 2.0) - return types.SimpleNamespace(actualPosition=self.rotator_position) - - async def handle_slew_icrs( - self, - rot, - rot_type, - **kwargs, - ): - self._handle_slew_calls += 1 - if ( - self._fail_handle_slew_after > 0 - and self._handle_slew_calls > self._fail_handle_slew_after - ): - raise RuntimeError( - f"Failing slew after {self._fail_handle_slew_after} calls." - ) - await asyncio.sleep(0.5) - if rot_type == RotType.Physical: - self.log.debug(f"Slew with rot_type = {RotType.Physical!r}") - rotator_velocity = self.rotator_velocity * ( - 1.0 if rot > self.rotator_position else -1.0 - ) - rotator_positions = numpy.arange( - self.rotator_position, rot, rotator_velocity - ) - for _rot in rotator_positions: - self.log.debug(f"Rotator position: {self.rotator_position} -> {_rot}") - self.rotator_position = _rot - await asyncio.sleep(1.0) - self.rotator_position = rot - else: - self.rotator_position = rot + self.rot_sky_emulate_zero - await asyncio.sleep(0.5) - - @contextlib.asynccontextmanager - async def setup_mocks(self): - self.script.mtcs.slew_icrs = unittest.mock.AsyncMock( - side_effect=self.handle_slew_icrs - ) - self.script.mtcs.stop_tracking = unittest.mock.AsyncMock() - self.script.mtcs.check_tracking = unittest.mock.AsyncMock() - self.script.mtcs.rem = types.SimpleNamespace( - mtrotator=unittest.mock.AsyncMock() - ) - - for cam in self.script.gencam: - cam.take_object = unittest.mock.AsyncMock( - side_effect=self.take_object_side_effect - ) - - self.script.mtcs.rem.mtrotator.configure_mock( - **{"tel_rotation.next.side_effect": self.get_rotator_position} - ) - - yield - - async def take_object_side_effect( - self, - exptime, - group_id, - reason, - program, - ): - self.log.debug( - f"exptime: {exptime}s, group_id: {group_id}, reason: {reason}, program: {program}" - ) - await asyncio.sleep(exptime) - - async def test_configure_single_camera(self): - """Test a successful configuration for a single camera""" - async with self.make_script(): - configuration_full = await self.configure_script_full() - self.log.debug(configuration_full) - - # Try/Except help identify which key is not matching - try: - for key in configuration_full: - if key == "exp_times": - continue - assert configuration_full[key] == getattr(self.script.config, key) - except AssertionError as err: - raise AssertionError( - f"Configuration for {key} does not match." - ) from err - - async def test_configure_bad(self) -> None: - """Test a bad configuration for a single camera""" - async with self.make_script(): - configuration_full = await self.configure_script_full() - - required_fields = { - "ra", - "dec", - "rot_sky", - "name", - "obs_time", - "num_exp", - "exp_times", - "generic_camera", - "band_filter", - } - - for required_field in required_fields: - bad_configuration = copy.deepcopy(configuration_full) - bad_configuration.pop(required_field) - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_configuration) - - async def test_configure_multiple_cameras(self) -> None: - """Test a successful configuration for multiple cameras""" - async with self.make_script(): - configuration_full = await self.configure_script_full( - generic_camera=[ - dict( - index=random.randint(1, 10), - exp_times=[random.randint(1, 10) for _ in range(2)], - ) - for _ in range(3) - ] - ) - - self.log.debug(configuration_full) - - # Try/Except help identify which key is not matching - try: - for key in configuration_full: - if key == "exp_times": - continue - assert configuration_full[key] == getattr(self.script.config, key) - except AssertionError as err: - raise AssertionError( - f"Configuration for {key} does not match." - ) from err - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "track_target_and_take_image_gencam.py" - await self.check_executable(script_path) - - async def test_run_fail_check_tracking(self): - async with self.make_script(): - # New GemCam is stanciated during configuration - configuration_full = await self.configure_script_full() - - async with self.setup_mocks(): - self.script.mtcs.check_tracking.side_effect = ( - self.check_tracking_fail_after_1s_side_effect - ) - - self.rotator_position = -15.0 - - with pytest.raises(AssertionError): - await self.run_script() - - slew_icrs_expected_calls = [ - unittest.mock.call( - ra=configuration_full["ra"], - dec=configuration_full["dec"], - rot=configuration_full["rot_sky"], - rot_type=RotType.Sky, - target_name=configuration_full["name"], - az_wrap_strategy=self.script.config.az_wrap_strategy, - time_on_target=self.script.get_estimated_time_on_target(), - ), - ] - - self.script.mtcs.slew_icrs.assert_has_awaits(slew_icrs_expected_calls) - - for i, cam in enumerate(self.script.gencam): - gencam_dict = configuration_full["generic_camera"][i] - gencam_take_object_calls = [ - unittest.mock.call( - exptime=gencam_dict["exp_times"][0], - group_id=self.script.group_id, - reason=configuration_full["reason"], - program=configuration_full["program"], - ) - ] - cam.take_object.assert_has_awaits(gencam_take_object_calls) - - self.script.mtcs.check_tracking.assert_awaited_once() - - self.script.mtcs.stop_tracking.assert_awaited_once() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_maintel_unpark_dome.py b/tests/test_maintel_unpark_dome.py deleted file mode 100644 index d243c6a29..000000000 --- a/tests/test_maintel_unpark_dome.py +++ /dev/null @@ -1,38 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts import standardscripts -from lsst.ts.standardscripts.maintel.mtdome import UnparkDome - - -class TestUnparkDome( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = UnparkDome(index=index) - return self.script - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "maintel" / "mtdome" / "unpark_dome.py" - await self.check_executable(script_path) diff --git a/tests/test_mute_alarms.py b/tests/test_mute_alarms.py deleted file mode 100644 index da337f9af..000000000 --- a/tests/test_mute_alarms.py +++ /dev/null @@ -1,86 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import types -import unittest - -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.mute_alarms import MuteAlarms -from lsst.ts.xml.enums.Watcher import AlarmSeverity - - -class TestMuteAlarms(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = MuteAlarms(index=index) - self.script.watcher = unittest.mock.AsyncMock() - return (self.script,) - - async def test_configure(self): - async with self.make_script(): - config = types.SimpleNamespace( - name=".*", - mutedBy="test", - duration=10, - severity="WARNING", - ) - await self.script.configure(config) - pass - - async def test_run(self): - """ - Test that the script is paused for the selected queue. - """ - async with self.make_script(): - config = types.SimpleNamespace( - name=".*", - mutedBy="test", - duration=10, - severity="WARNING", - ) - - # Configure the script - await self.configure_script( - name=config.name, - mutedBy=config.mutedBy, - duration=config.duration, - severity=config.severity, - ) - - # Run the script - await self.run_script() - - # Assert the command was called properly - self.script.watcher.cmd_mute.set_start.assert_awaited_with( - name=config.name, - duration=config.duration, - severity=AlarmSeverity[config.severity], - mutedBy=config.mutedBy, - timeout=self.script.std_timeout, - ) - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "pause_queue.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_pause_queue.py b/tests/test_pause_queue.py deleted file mode 100644 index 3f27dd33d..000000000 --- a/tests/test_pause_queue.py +++ /dev/null @@ -1,71 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import types -import unittest - -from lsst.ts.idl.enums.ScriptQueue import SalIndex -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.pause_queue import PauseQueue - - -class TestPauseQueue(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = PauseQueue(index=index) - - # Mock the script queue and its pause method - self.script.script_queue = unittest.mock.MagicMock() - self.script.script_queue.pause = unittest.mock.AsyncMock(return_value=None) - - return (self.script,) - - async def test_configure(self): - async with self.make_script(): - queue = "MAIN_TEL" - expected_queue_index = SalIndex.MAIN_TEL - - config = types.SimpleNamespace(queue=queue) - await self.script.configure(config) - - assert self.script.queue_index == expected_queue_index - - async def test_run(self): - """ - Test that the script is paused for the selected queue. - """ - async with self.make_script(): - # Configure the script - queue = "MAIN_TEL" - await self.configure_script(queue=queue) - - # Run the script - await self.run_script() - - self.script.script_queue.pause.assert_awaited_once() - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "pause_queue.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_run_command.py b/tests/test_run_command.py deleted file mode 100644 index 394ab3a86..000000000 --- a/tests/test_run_command.py +++ /dev/null @@ -1,143 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import random -import unittest - -import pytest -from lsst.ts import salobj, standardscripts - -random.seed(47) # for set_random_lsst_dds_partition_prefix - - -class TestRunCommand( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - async def basic_make_script(self, index): - self.script = standardscripts.RunCommand(index=index) - await self.script.start_task - self.controller = salobj.Controller("Test", index=1) - self.controller.cmd_setScalars.callback = self.set_scalars_callback - await self.controller.start_task - return [self.script, self.controller] - - async def set_scalars_callback(self, data): - await self.controller.evt_scalars.set_write( - float0=data.float0, string0=data.string0 - ) - - async def test_configure_errors(self): - """Test error handling in the do_configure method.""" - for bad_config in ( - {}, # need component name and command name - {"component": "Test:1"}, # need command name - {"cmd": "setScalars"}, # need component name - ): - with self.subTest(bad_config=bad_config): - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_configure_good_set_scalars(self): - """Test the configure method with a valid configuration.""" - async with self.make_script(): - # Basic providing only component and command - await self.configure_script(component="Test:1", cmd="setScalars") - - assert self.script.name == "Test" - assert self.script.index == 1 - assert self.script.cmd == "setScalars" - assert self.script.event is None - assert not self.script.flush - - async def test_configure_good_set_scalars_wait_event(self): - async with self.make_script(): - # Provide event - await self.configure_script( - component="Test:1", cmd="setScalars", event="scalars" - ) - - assert self.script.name == "Test" - assert self.script.index == 1 - assert self.script.cmd == "setScalars" - assert self.script.event == "scalars" - assert self.script.flush - - async def test_configure_good_set_scalars_wait_event_no_flush(self): - async with self.make_script(): - # Provide event with flush = False - await self.configure_script( - component="Test:1", cmd="setScalars", event="scalars", flush=False - ) - - assert self.script.name == "Test" - assert self.script.index == 1 - assert self.script.cmd == "setScalars" - assert self.script.event == "scalars" - assert not self.script.flush - - async def test_configure_good_set_scalars_with_parameters(self): - async with self.make_script(): - # Provide parameter for the command - await self.configure_script( - component="Test:1", - cmd="setScalars", - event="scalars", - parameters={"float0": 1.2345, "string0": "12345"}, - ) - - assert self.script.name == "Test" - assert self.script.index == 1 - assert self.script.cmd == "setScalars" - assert self.script.event == "scalars" - assert self.script.flush - assert self.script.remote.cmd_setScalars.data.float0 == pytest.approx( - 1.2345, abs=0.00005 - ) - assert self.script.remote.cmd_setScalars.data.string0 == "12345" - - async def test_run(self): - """Run test with Test component.""" - - async with self.make_script(): - # Provide parameter for the command - await self.configure_script( - component="Test:1", - cmd="setScalars", - event="scalars", - parameters={"float0": 1.2345, "string0": "12345"}, - ) - - await self.run_script() - - assert self.controller.evt_scalars.data.float0 == pytest.approx( - 1.2345, abs=0.00005 - ) - assert self.controller.evt_scalars.data.string0 == "12345" - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "set_summary_state.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_scheduler_add_block.py b/tests/test_scheduler_add_block.py index 1120d3e7d..fe2efb9dc 100644 --- a/tests/test_scheduler_add_block.py +++ b/tests/test_scheduler_add_block.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,9 +19,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler.add_block import AddBlock from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -34,39 +33,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_valid_block(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(id=self.controller.valid_observing_block_id) - await self.run_script() - - self.assert_loaded_observing_blocks( - observing_blocks=[self.controller.valid_observing_block_id] - ) - - async def test_invalid_block(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(id="invalid_block") - - with self.assertRaises(AssertionError): - await self.run_script() - - self.assert_loaded_observing_blocks(observing_blocks=[]) - - async def test_auxtel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "add_block.py" - await self.check_executable(script_path) - - async def test_maintel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "scheduler" / "add_block.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "add_block.py" + script_path = scripts_dir / "scheduler" / "add_block.py" await self.check_executable(script_path) diff --git a/tests/test_scheduler_enable.py b/tests/test_scheduler_enable.py index dbdbf969a..4d62f8d3d 100644 --- a/tests/test_scheduler_enable.py +++ b/tests/test_scheduler_enable.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,14 +19,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import logging -import unittest - -import pytest -from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler.enable import Enable from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -39,250 +33,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_configure_errors(self): - """Test error handling in the do_configure method.""" - for bad_config in ( - dict(), # need a config - dict(confog="valid_test_config.yaml"), # typo in "config" - ): - with self.subTest(bad_config=bad_config): - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_configure_good(self): - """Test the configure method. - - Also exercise verbose=True for make_script. - """ - async with self.make_script(verbose=True): - with self.assertLogs(self.script.log, level=logging.DEBUG) as script_logs: - await self.configure_script(config="valid_test_config.yaml") - - assert ( - "INFO:Script:Scheduler configuration: valid_test_config.yaml" - in script_logs.output - ) - - async def test_run_fail_invalid_config(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=True - ): - await self.configure_script(config="invalid_test_config.yaml") - - with self.assertRaises(AssertionError): - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=0, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.FAILED, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_fail_invalid_config_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=True - ): - await self.configure_script(config="invalid_test_config.yaml") - - with self.assertRaises(AssertionError): - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=0, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.FAILED, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_standby(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=True - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=0, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_standby_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=False - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=0, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_disabled(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.DISABLED, publish_initial_state=True - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_disabled_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.DISABLED, publish_initial_state=False - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_enabled(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=1, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_enabled_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=1, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_fault(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.FAULT, publish_initial_state=True - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_run_csc_in_fault_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.FAULT, publish_initial_state=False - ): - await self.configure_script(config="valid_test_config.yaml") - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=1, - disable=0, - ), - expected_overrides=["valid_test_config.yaml"], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.ENABLED, - ) - - async def test_auxtel_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "enable.py" + script_path = scripts_dir / "scheduler" / "enable.py" await self.check_executable(script_path) - - async def test_maintel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "scheduler" / "enable.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "enable.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_scheduler_load_snapshot.py b/tests/test_scheduler_load_snapshot.py index 4bba2ba91..b2060903a 100644 --- a/tests/test_scheduler_load_snapshot.py +++ b/tests/test_scheduler_load_snapshot.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,10 +19,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import pytest -from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler.load_snapshot import LoadSnapshot from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -35,53 +33,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_valid_uri(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(snapshot=self.controller.valid_snapshot) - await self.run_script() - - self.assert_loaded_snapshots(snapshots=[self.controller.valid_snapshot]) - - async def test_latest(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(snapshot="latest") - await self.run_script() - - self.assert_loaded_snapshots(snapshots=[self.controller.valid_snapshot]) - - async def test_invalid_uri(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(snapshot="invalid") - - with self.assertRaises(AssertionError): - await self.run_script() - - self.assert_loaded_snapshots(snapshots=[]) - - async def test_fail_config_latest_not_published(self) -> None: - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=False - ): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(snapshot="latest") - - async def test_auxtel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "load_snapshot.py" - await self.check_executable(script_path) - - async def test_maintel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "scheduler" / "load_snapshot.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "load_snapshot.py" + script_path = scripts_dir / "scheduler" / "load_snapshot.py" await self.check_executable(script_path) diff --git a/tests/test_scheduler_resume.py b/tests/test_scheduler_resume.py index bdf0462e7..05f64ba7b 100644 --- a/tests/test_scheduler_resume.py +++ b/tests/test_scheduler_resume.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,9 +19,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler.resume import Resume from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -34,26 +33,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_run(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - assert self.controller.running - - async def test_auxtel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "resume.py" - await self.check_executable(script_path) - - async def test_maintel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "scheduler" / "resume.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "resume.py" + script_path = scripts_dir / "scheduler" / "resume.py" await self.check_executable(script_path) diff --git a/tests/test_scheduler_standby.py b/tests/test_scheduler_standby.py index 38d0aa048..18534bbf9 100644 --- a/tests/test_scheduler_standby.py +++ b/tests/test_scheduler_standby.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,12 +19,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import unittest from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.idl.enums.Script import ScriptState -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler import SetDesiredState from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -39,181 +37,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_run_csc_in_standby(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=0, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_standby_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.STANDBY, publish_initial_state=False - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=1, - enable=0, - disable=0, - ), - expected_overrides=[""], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_disabled(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.DISABLED, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_disabled_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.DISABLED, publish_initial_state=False - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_enabled(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=1, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_enabled_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=1, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_fault(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(), self.make_controller( - initial_state=salobj.State.FAULT, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_run_csc_in_fault_no_historical_data(self): - """Set one remote to two states, including overrides.""" - async with self.make_script(randomize_topic_subname=True), self.make_controller( - initial_state=salobj.State.FAULT, publish_initial_state=False - ): - await self.configure_script() - await self.run_script() - - self.assert_run( - expected_commands=dict( - standby=1, - start=0, - enable=0, - disable=0, - ), - expected_overrides=[], - expected_script_state=ScriptState.DONE, - expected_csc_state=salobj.State.STANDBY, - ) - - async def test_auxtel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "standby.py" - await self.check_executable(script_path) - - async def test_maintel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "maintel" / "scheduler" / "standby.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "standby.py" + script_path = scripts_dir / "scheduler" / "standby.py" await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_scheduler_stop.py b/tests/test_scheduler_stop.py index c7d492e88..e6d0827aa 100644 --- a/tests/test_scheduler_stop.py +++ b/tests/test_scheduler_stop.py @@ -1,4 +1,4 @@ -# This file is part of ts_standardscripts +# This file is part of ts_auxtel_standardscripts # # Developed for the LSST Telescope and Site Systems. # This product includes software developed by the LSST Project @@ -19,9 +19,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from lsst.ts import salobj +from lsst.ts.auxtel.standardscripts import get_scripts_dir from lsst.ts.idl.enums.Scheduler import SalIndex -from lsst.ts.standardscripts import get_scripts_dir from lsst.ts.standardscripts.scheduler.stop import Stop from lsst.ts.standardscripts.scheduler.testutils import BaseSchedulerTestCase @@ -34,42 +33,7 @@ async def basic_make_script(self, index): ) return [self.script] - async def test_no_stop_default(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script() - await self.run_script() - - assert len(self.controller.abort_observations) == 1 - assert not self.controller.abort_observations[0] - - async def test_no_stop_explicit(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(stop=False) - await self.run_script() - - assert len(self.controller.abort_observations) == 1 - assert not self.controller.abort_observations[0] - - async def test_stop(self) -> None: - async with self.make_script(), self.make_controller( - initial_state=salobj.State.ENABLED, publish_initial_state=True - ): - await self.configure_script(stop=True) - await self.run_script() - - assert len(self.controller.abort_observations) == 1 - assert self.controller.abort_observations[0] - - async def test_auxtel_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "auxtel" / "scheduler" / "stop.py" - await self.check_executable(script_path) - - async def test_ocs_executable(self): + async def test_executable(self): scripts_dir = get_scripts_dir() - script_path = scripts_dir / "ocs" / "scheduler" / "stop.py" + script_path = scripts_dir / "scheduler" / "stop.py" await self.check_executable(script_path) diff --git a/tests/test_set_summary_state.py b/tests/test_set_summary_state.py deleted file mode 100644 index 8c0dc555c..000000000 --- a/tests/test_set_summary_state.py +++ /dev/null @@ -1,374 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import asyncio -import logging -import os -import random -import unittest -from unittest import mock - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.xml.enums.Script import ScriptState -from lsst.ts.xml.enums.Watcher import AlarmSeverity - -random.seed(47) # for set_random_lsst_dds_partition_prefix - -logging.basicConfig() - - -class TrivialController(salobj.Controller): - def __init__(self, index, initial_state=salobj.State.STANDBY): - super().__init__(name="Test", index=index, do_callbacks=False) - self.n_disable = 0 - self.n_enable = 0 - self.n_exitControl = 0 - self.n_standby = 0 - self.n_start = 0 - self.overrides = [] - self.cmd_disable.callback = self.do_disable - self.cmd_enable.callback = self.do_enable - self.cmd_exitControl.callback = self.do_exitControl - self.cmd_standby.callback = self.do_standby - self.cmd_start.callback = self.do_start - self.evt_summaryState.set(summaryState=initial_state) - - async def start(self): - await super().start() - await self.evt_summaryState.write() - - async def do_disable(self, data): - self.n_disable += 1 - await self.evt_summaryState.set_write(summaryState=salobj.State.DISABLED) - - async def do_enable(self, data): - self.n_enable += 1 - await self.evt_summaryState.set_write(summaryState=salobj.State.ENABLED) - - async def do_exitControl(self, data): - self.n_exitControl += 1 - await self.evt_summaryState.set_write(summaryState=salobj.State.OFFLINE) - - async def do_standby(self, data): - self.n_standby += 1 - await self.evt_summaryState.set_write(summaryState=salobj.State.STANDBY) - - async def do_start(self, data): - self.n_start += 1 - self.overrides.append(data.configurationOverride) - await self.evt_summaryState.set_write(summaryState=salobj.State.DISABLED) - - -class TestSetSummaryState( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - - @classmethod - def setUpClass(cls) -> None: - os.environ["LSST_SITE"] = "test" - - async def basic_make_script(self, index): - self.script = standardscripts.SetSummaryState(index=index) - - self.controllers = [] - - return [self.script] - - async def add_test_cscs(self, initial_state=salobj.State.STANDBY): - """Add a Test controller""" - index = self.next_index() - - controller = salobj.TestCsc(index=index, initial_state=initial_state) - await controller.start_task - self.controllers.append(controller) - - async def add_controller(self, initial_state=salobj.State.STANDBY): - """Add a Test controller""" - index = self.next_index() - - controller = TrivialController(index=index, initial_state=initial_state) - await controller.start_task - self.controllers.append(controller) - - async def close(self): - await asyncio.gather(*[controller.close() for controller in self.controllers]) - - async def test_configure_errors(self): - """Test error handling in the do_configure method.""" - name_ind = "Test:1" - for bad_data in ( - "[]", # need at least one tuple - "[[]]", # tuple has 0 items; need 2 or 3 - f'[["{name_ind}"]]', # tuple has 1 item; need 2 or 3 - # tuple has 4 items; need 2 or 3: - f'[["{name_ind}", "enabled", "", "4th field not allowed"]]', - '[("invalid csc name:5", "enabled")]', # bad CSC name format - '[("invalid*csc*name:5", "enabled")]', # bad CSC name format - '[("no_such_CSC:5", "enabled")]', # no such CSC - '[(name_ind, "invalid_state")]', # no such state - '[(name_ind, "fault")]', # fault state is not supported - "[(name_ind, 1)]", # integer states are not supported - ): - bad_config = dict(data=bad_data) - with self.subTest(bad_config=bad_config): - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**bad_config) - - async def test_configure_good(self): - """Test the configure method with a valid configuration. - - Also exercise verbose=True for make_script. - """ - async with self.make_script(verbose=True): - await self.add_controller() - await self.add_controller() - # add a 3rd controller that has the same index as the first one - self.controllers.append(self.controllers[0]) - state_enums = ( - salobj.State.ENABLED, - salobj.State.DISABLED, - salobj.State.STANDBY, - ) - state_names = [elt.name for elt in state_enums] - override_list = ("foo", None, "") - - data = [] - name_index_list = [] - for controller, state, override in zip( - self.controllers, state_names, override_list - ): - index = controller.salinfo.index - name_index = f"Test:{index}" - if override is None: - data.append((name_index, state)) - else: - data.append((name_index, state, override)) - name_index_list.append(("Test", index)) - - await self.configure_script(data=data) - - # There are three controllers but two have the same index - assert len(self.script.remotes) == 2 - - for i in range(len(data)): - desired_override = "" if override_list[i] is None else override_list[i] - assert self.script.nameind_state_override[i] == ( - name_index_list[i], - state_enums[i], - desired_override, - ) - - async def test_do_run(self): - """Set one remote to two states, including overrides. - - Transition FAULT -standby> STANDBY -start> DISABLED -enable> ENABLED - """ - async with self.make_script(): - await self.add_controller(initial_state=salobj.State.FAULT) - test_index = self.controllers[0].salinfo.index - name_ind = f"Test:{test_index}" - override = "foo" - - data = ((name_ind, "standby"), (name_ind, "enabled", override)) - await self.configure_script(data=data) - assert len(self.controllers) == 1 - assert len(self.script.remotes) == 1 - - await self.run_script() - controller = self.controllers[0] - assert controller.n_standby == 1 - assert controller.n_start == 1 - assert controller.n_enable == 1 - assert controller.n_disable == 0 - assert controller.n_exitControl == 0 - assert len(controller.overrides) == 1 - assert controller.overrides[0] == override - assert self.script.state.state == ScriptState.DONE - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "set_summary_state.py" - await self.check_executable(script_path) - - async def run_configure_wildcard_index_test(self): - """Test the configure method with a wildcard (*) index. - - This simulates the discovery of multiple instances of a CSC - and setting their states. - """ - async with self.make_script(verbose=True): - await self.add_test_cscs(initial_state=salobj.State.OFFLINE) - await self.add_test_cscs(initial_state=salobj.State.STANDBY) - await self.add_test_cscs(initial_state=salobj.State.STANDBY) - await self.add_test_cscs(initial_state=salobj.State.DISABLED) - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - - name_ind = [("Test:*", "ENABLED")] - - await self.configure_script(data=name_ind) - - # Assert that all controllers are present (4 total) - assert ( - len(self.controllers) == 5 - ), f"Expected 4 controllers, found {len(self.controllers)}" - - # Assert that the remotes (excluding OFFLINE controllers) - # are present (4 remotes) - assert ( - len(self.script.remotes) == 4 - ), f"Expected 4 remotes, found {len(self.script.remotes)}" - - await self.run_script() - - # Assert that all controllers (except OFFLINE) have transitioned - # to ENABLED - for controller in self.controllers: - name_index = (controller.salinfo.name, controller.salinfo.index) - - if ( - controller.evt_summaryState.data.summaryState - != salobj.State.OFFLINE - ): - assert ( - controller.evt_summaryState.data.summaryState - == salobj.State.ENABLED - ), ( - f"Controller {name_index} did not transition to ENABLED. " - f"Current state: {controller.evt_summaryState.data.summaryState}" - ) - else: - # Verify that OFFLINE controllers remain OFFLINE - assert ( - controller.evt_summaryState.data.summaryState - == salobj.State.OFFLINE - ), ( - f"Controller {name_index} was expected to remain OFFLINE but is in state " - f"{controller.evt_summaryState.data.summaryState}" - ) - - async def test_configure_wildcard_index_local_fallback(self): - """Test the configure method with a wildcard (*) index - using the local fallback for wildcard handling. - """ - from lsst.ts.standardscripts.utils import ( - WildcardIndexError as LocalWildcardIndexError, - ) - from lsst.ts.standardscripts.utils import ( - name_to_name_index as local_name_to_name_index, - ) - - with mock.patch( - "lsst.ts.standardscripts.set_summary_state.name_to_name_index", - local_name_to_name_index, - ), mock.patch( - "lsst.ts.standardscripts.set_summary_state.WildcardIndexError", - LocalWildcardIndexError, - ): - await self.run_configure_wildcard_index_test() - - async def test_configure_wildcard_index_salobj(self): - """Test the configure method with ts_salobj's native wildcard - handling.""" - try: - # Check if WildcardIndexError exists in ts_salobj - from lsst.ts.salobj import WildcardIndexError # noqa: F401 - except ImportError: - pytest.skip("ts_salobj does not yet support WildcardIndexError") - - await self.run_configure_wildcard_index_test() - - async def test_mute_alarms_when_offline(self): - """Test that alarms are muted when CSCs are set to OFFLINE with - mute_alarms=True.""" - async with self.make_script(): - self.script.watcher = unittest.mock.AsyncMock() - - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - - controllers = self.controllers - csc_info = [] - for controller in controllers: - name = controller.salinfo.name - index = controller.salinfo.index - name_ind = f"{name}:{index}" - csc_info.append((controller, name, index, name_ind)) - - offline_cscs = [csc_info[0][0], csc_info[2][0]] - - config_data = [] - for controller, name, index, name_ind in csc_info: - if controller in offline_cscs: - config_data.append((name_ind, "OFFLINE")) - else: - config_data.append((name_ind, "STANDBY")) - - await self.configure_script( - data=config_data, mute_alarms=True, mute_duration=31.0 - ) - - await self.run_script() - - expected_mute_calls = [ - mock.call( - name=rf"^(Enabled|Heartbeat)\.{name}:{index}", - duration=1860.0, # mute_duration * 60 secs` - severity=AlarmSeverity.CRITICAL, - mutedBy="set_summary_state script", - ) - for controller, name, index, name_ind in csc_info - if controller in offline_cscs - ] - - self.script.watcher.cmd_mute.set_start.assert_has_awaits( - expected_mute_calls, any_order=True - ) - - expected_mute_calls_count = len(offline_cscs) - actual_mute_calls_count = self.script.watcher.cmd_mute.set_start.await_count - self.assertEqual( - actual_mute_calls_count, - expected_mute_calls_count, - f"Expected {expected_mute_calls_count} mute command(s), but got {actual_mute_calls_count}", - ) - - # Verify that CSCs have transitioned to the correct states - for controller, name, index, name_ind in csc_info: - expected_state = ( - salobj.State.OFFLINE - if controller in offline_cscs - else salobj.State.STANDBY - ) - actual_state = controller.evt_summaryState.data.summaryState - self.assertEqual( - actual_state, - expected_state, - f"CSC {name_ind} expected to be in state {expected_state.name}, but found " - f"{actual_state.name}", - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_sleep.py b/tests/test_sleep.py deleted file mode 100644 index 2778fcac7..000000000 --- a/tests/test_sleep.py +++ /dev/null @@ -1,60 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import unittest - -from lsst.ts.standardscripts import BaseScriptTestCase, get_scripts_dir -from lsst.ts.standardscripts.sleep import Sleep - - -class TestSleep(BaseScriptTestCase, unittest.IsolatedAsyncioTestCase): - async def basic_make_script(self, index): - self.script = Sleep(index=index) - return (self.script,) - - async def test_configure(self): - # Test that the sleep time is set correctly - async with self.make_script(): - sleep_for = 5 - - await self.configure_script(sleep_for=sleep_for) - - self.assertEqual(self.script.sleep_for, sleep_for) - - async def test_run(self): - """ - Test that the script sleeps for the correct amount of time. - """ - async with self.make_script(): - sleep_for = 5 - await self.configure_script(sleep_for=sleep_for) - - # Run the script - await self.run_script() - - async def test_executable(self): - scripts_dir = get_scripts_dir() - script_path = scripts_dir / "sleep.py" - await self.check_executable(script_path) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_system_wide_shutdown.py b/tests/test_system_wide_shutdown.py deleted file mode 100644 index 1e3683456..000000000 --- a/tests/test_system_wide_shutdown.py +++ /dev/null @@ -1,159 +0,0 @@ -# This file is part of ts_standardscripts. -# -# Developed for the Vera C. Rubin Observatory Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts import SystemWideShutdown -from lsst.ts.standardscripts.utils import find_running_instances - - -class TestSystemWideShutdown( - standardscripts.BaseScriptTestCase, unittest.IsolatedAsyncioTestCase -): - @classmethod - def setUpClass(cls) -> None: - os.environ["LSST_SITE"] = "test" - - def setUp(self) -> None: - self.make_test_cscs = False - self.ntest = 3 - return super().setUp() - - async def basic_make_script(self, index): - self.script = SystemWideShutdown(index=index) - - self.mock_test = ( - [salobj.TestCsc(index=c_id + 1) for c_id in range(self.ntest)] - if self.make_test_cscs - else [] - ) - - return (self.script, *self.mock_test) - - async def test_shutdown(self): - self.make_test_cscs = True - - async with self.make_script(): - components_running = dict( - Test=[i + 1 for i in range(self.ntest)], - ) - for component in components_running: - indices = components_running[component] - await self.script.shutdown(component=component, indices=indices) - - assert len(self.script.failed) == 0.0 - for mock_test in self.mock_test: - assert mock_test.summary_state == salobj.State.OFFLINE - - async def test_discover(self): - self.make_test_cscs = True - - async with self.make_script(): - components_alive = await self.script.discover_components() - - assert "Test" in components_alive - assert set(components_alive.pop("Test")) == { - i + 1 for i in range(self.ntest) - } - assert len(components_alive) == 0 - - async def test_find_running_instances(self): - self.make_test_cscs = True - - async with self.make_script(): - component, component_indices = await find_running_instances( - self.script.domain, "Test" - ) - - assert component == "Test" - assert set(component_indices) == {i + 1 for i in range(self.ntest)} - - async def test_find_running_instances_not_running(self): - async with self.make_script(): - component, component_indices = await find_running_instances( - self.script.domain, "Test" - ) - - assert component == "Test" - assert component_indices == [] - - async def test_configure(self): - configs_good = [ - dict( - user="Tester", - reason="Unit test", - ), - dict(user="Tester", reason="Unit test", ignore=["Test"]), - dict(user="Tester", reason="Unit test", start_with=["Test"]), - dict(user="Tester", reason="Unit test", end_with=["Test"]), - dict( - user="Tester", - reason="Unit test", - ignore=["Test"], - start_with=["Watcher"], - end_with=["ScriptQueue"], - ), - ] - - for config in configs_good: - with self.subTest(config=config): - async with self.make_script(): - await self.configure_script(**config) - assert self.script.config.user == config.get("user") - assert self.script.config.reason == config.get("reason") - assert self.script.config.ignore == config.get("ignore", []) - assert self.script.config.start_with == config.get("start_with", []) - assert self.script.config.end_with == config.get("end_with", []) - - configs_bad = [ - dict( - reason="No user", - ), - dict( - user="Test", - ), - ] - - for config in configs_bad: - with self.subTest(config=config): - async with self.make_script(): - with pytest.raises(salobj.ExpectedError): - await self.configure_script(**config) - - async def test_run(self): - self.make_test_cscs = True - - async with self.make_script(): - await self.configure_script(user="Tester", reason="Unit test.") - - await self.run_script() - - assert len(self.script.failed) == 0.0 - for mock_test in self.mock_test: - assert mock_test.summary_state == salobj.State.OFFLINE - - async def test_executable(self): - scripts_dir = standardscripts.get_scripts_dir() - script_path = scripts_dir / "system_wide_shutdown.py" - await self.check_executable(script_path) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 11c224a6f..000000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,106 +0,0 @@ -# This file is part of ts_standardscripts -# -# Developed for the LSST Telescope and Site Systems. -# This product includes software developed by the LSST Project -# (https://www.lsst.org). -# See the COPYRIGHT file at the top-level directory of this distribution -# for details of code ownership. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import pathlib -import unittest - -import pytest -from lsst.ts import salobj, standardscripts -from lsst.ts.standardscripts.utils import find_running_instances - - -# class TestUtils(unittest.TestCase): -class TestUtils( - unittest.IsolatedAsyncioTestCase -): # Use IsolatedAsyncioTestCase for async tests - - @classmethod - def setUpClass(cls) -> None: - salobj.set_random_lsst_dds_partition_prefix() - os.environ["LSST_SITE"] = "test" - - async def add_test_cscs(self, initial_state=salobj.State.STANDBY): - """Add a Test controller""" - if not hasattr(self, "mock_cscs"): - self.mock_cscs = [] - index = len(self.mock_cscs) + 1 # Ensure indices are unique - mock_csc = salobj.TestCsc(index=index, initial_state=initial_state) - await mock_csc.start_task # Start the controller asynchronously - self.mock_cscs.append(mock_csc) - - def test_get_scripts_dir(self): - scripts_dir = standardscripts.get_scripts_dir() - print(f"*** script dir: {scripts_dir}") - assert scripts_dir.is_dir() - - pkg_path = pathlib.Path(__file__).resolve().parent.parent - predicted_path = ( - pkg_path / "python" / "lsst" / "ts" / "standardscripts" / "data" / "scripts" - ) - print(f"*** predicted path: {predicted_path}") - assert scripts_dir.samefile(predicted_path) - - def test_format_as_list(self): - recurrences = 4 - # Check case of single values sent - test_case = ["string", 2, 2.0] - for test in test_case: - new_list = standardscripts.utils.format_as_list(test, recurrences) - print(new_list) - assert new_list.count(test) == recurrences - - # Verify that if input is correct it just returns - test_case = ["test", "test"] - recurrences = 2 - new_list = standardscripts.utils.format_as_list(test_case, recurrences) - assert new_list is test_case - - # Verify that it will fail if a list is provided with the wrong number - # of occurrences - with pytest.raises(ValueError): - recurrences = 3 - new_list = standardscripts.utils.format_as_list(test_case, recurrences) - - async def test_find_running_instances(self): - """Test find_running_instances utility function.""" - # Create multiple CSCs with same name but different states - await self.add_test_cscs(initial_state=salobj.State.OFFLINE) - await self.add_test_cscs(initial_state=salobj.State.STANDBY) - await self.add_test_cscs(initial_state=salobj.State.STANDBY) - await self.add_test_cscs(initial_state=salobj.State.DISABLED) - await self.add_test_cscs(initial_state=salobj.State.ENABLED) - - # Note: Skip the OFFLINE CSC domain as it is not set. Hence, - # mock_cscs[1], is skipped. Any valid domain would work. - component, component_indices = await find_running_instances( - self.mock_cscs[1].domain, "Test" - ) - - # Verify the results - assert component == "Test" - assert ( - len(component_indices) == 4 - ) # Note: An OFFLINE CSC doesn't have a remote, hence is not discoverable - - -if __name__ == "__main__": - unittest.main() diff --git a/ups/ts_standardscripts.table b/ups/ts_auxtel_standardscripts.table similarity index 82% rename from ups/ts_standardscripts.table rename to ups/ts_auxtel_standardscripts.table index 408febc5f..4e5c1210f 100644 --- a/ups/ts_standardscripts.table +++ b/ups/ts_auxtel_standardscripts.table @@ -2,5 +2,6 @@ setupRequired(sconsUtils) setupRequired(ts_salobj) setupRequired(ts_utils) setupRequired(ts_observatory_control) +setupRequired(ts_standardscripts) envPrepend(PYTHONPATH, ${PRODUCT_DIR}/python)