././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1188734 specreduce-1.4.1/0000755000175100001770000000000014635037364013257 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.flake80000644000175100001770000000003714635037352014427 0ustar00runnerdocker[flake8] max-line-length = 100 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1028733 specreduce-1.4.1/.github/0000755000175100001770000000000014635037364014617 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1068733 specreduce-1.4.1/.github/workflows/0000755000175100001770000000000014635037364016654 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.github/workflows/cron-tests.yml0000644000175100001770000000204114635037352021472 0ustar00runnerdocker# GitHub Actions workflow for testing and continuous integration. # # This file performs testing using tox and tox.ini to define and configure the test environments. name: Weekly Tests on: pull_request: # We also want this workflow triggered if the 'Extra CI' label is added # or present when PR is updated types: - synchronize - labeled schedule: # run every Monday at 6am UTC - cron: '0 6 * * 1' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: tests: if: (github.repository == 'astropy/specreduce' && (github.event_name == 'schedule' || github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'Extra CI'))) uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 with: submodules: false coverage: '' envs: | - name: Check URLs in docs linux: linkcheck - name: Python 3.12 on Linux with pre-releases linux: py312-test-alldeps-predeps toxargs: -v ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.github/workflows/publish-to-pypi.yml0000644000175100001770000000105414635037352022441 0ustar00runnerdockername: Release on: pull_request: push: tags: - '*' jobs: publish: uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish_pure_python.yml@v1 # NOTE: Uncomment "if" if you do not want this to run for every PR. # if: ((github.event_name == 'push' && startsWith(github.ref, 'refs/tags')) || contains(github.event.pull_request.labels.*.name, 'Build wheels')) with: test_extras: test test_command: pytest $GITHUB_WORKSPACE/specreduce/tests secrets: pypi_token: ${{ secrets.PYPI_API_TOKEN }} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.github/workflows/tox-tests.yml0000644000175100001770000000260214635037352021346 0ustar00runnerdocker# GitHub Actions workflow for testing and continuous integration. # # This file performs testing using tox and tox.ini to define and configure the test environments. name: Python Tests on: push: branches: - main tags: - '*' pull_request: schedule: # run every Monday at 6am UTC - cron: '0 6 * * 1' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: tests: uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1 secrets: CODECOV_TOKEN: ${{ secrets.CODECOV }} with: submodules: false coverage: '' envs: | - name: Codestyle linux: codestyle - name: Python 3.10 on Linux with oldest supported dependencies linux: py310-test-oldestdeps toxargs: -v - name: Python 3.10 on Windows with minimal dependencies windows: py310-test toxargs: -v - name: Python 3.10 on OSX with minimal dependencies macos: py310-test toxargs: -v - name: Python 3.11 on Linux with all dependencies, remote data, and coverage linux: py311-test-alldeps-cov coverage: codecov toxargs: -v posargs: --remote-data=any - name: (Allowed Failure) Python 3.12 on Linux with dev dependencies linux: py312-test-devdeps toxargs: -v ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.gitignore0000644000175100001770000000133714635037352015250 0ustar00runnerdocker# Compiled files *.py[cod] *.a *.o *.so __pycache__ # Ignore .c files by default to avoid including generated code. If you want to # add a non-generated .c extension, use `git add -f filename.c`. *.c # Other generated files */version.py */cython_version.py htmlcov .coverage MANIFEST .ipynb_checkpoints # Sphinx docs/api docs/_build # Eclipse editor project files .project .pydevproject .settings .vscode/ # Pycharm editor project files .idea # Floobits project files .floo .flooignore # Packages/installer info .eggs/ *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg distribute-*.tar.gz # Other .cache .tox .*.sw[op] *~ .project .pydevproject .settings pip-wheel-metadata/ # Mac OSX .DS_Store ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/.readthedocs.yaml0000644000175100001770000000045014635037352016502 0ustar00runnerdockerversion: 2 build: os: ubuntu-22.04 apt_packages: - graphviz tools: python: "3.11" sphinx: builder: html configuration: docs/conf.py fail_on_warning: true python: install: - method: pip path: . extra_requirements: - docs - all formats: [] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/CHANGES.rst0000644000175100001770000001230014635037352015052 0ustar00runnerdocker1.5.0 (unreleased) ------------------ New Features ^^^^^^^^^^^^ API Changes ^^^^^^^^^^^ Bug Fixes ^^^^^^^^^ Other changes 1.4.1 (2024-06-20) ------------------ New Features ^^^^^^^^^^^^ API Changes ^^^^^^^^^^^ Bug Fixes ^^^^^^^^^ - Fix bug where Background one sided / two sided was not correctly assigning units to data. [#221] Other changes ^^^^^^^^^^^^^ 1.4.0 (2024-05-29) ------------------ New Features ^^^^^^^^^^^^ - Added 'interpolated_profile' option for HorneExtract. If The ``interpolated_profile`` option is used, the image will be sampled in various wavelength bins (set by ``n_bins_interpolated_profile``), averaged in those bins, and samples are then interpolated between (linear by default, interpolation degree can be set with the ``interp_degree_interpolated_profile`` parameter) to generate a continuously varying spatial profile that can be evaluated at any wavelength. [#173] - Added a function to measure a cross-dispersion profile. A profile can be obtained at a single pixel/wavelength, or an average profile can be obtained from a range/set of wavelengths. [#214] API Changes ^^^^^^^^^^^ - Fit residuals exposed for wavelength calibration in ``WavelengthCalibration1D.fit_residuals``. [#446] Bug Fixes ^^^^^^^^^ - Output 1D spectra from Background no longer include NaNs. Output 1D spectra from BoxcarExtract no longer include NaNs when none are present in the extraction window. NaNs in the window will still propagate to BoxcarExtract's extracted 1D spectrum. [#159] - Backgrounds using median statistic properly ignore zero-weighted pixels. [#159] - HorneExtract now accepts 'None' as a vaild option for ``bkgrd_prof``. [#171] - Fix in FitTrace to set fully-masked column bin peaks to NaN. Previously, for peak_method='max' these were set to 0.0, and for peak_method='centroid' they were set to the number of rows in the image, biasing the final fit to all bin peaks. Previously for Gaussian, the entire fit failed. [#205, #206] - Fixed input of `traces` in `Background`. Added a condition to 'FlatTrace' that trace position must be a positive number. [#211] Other changes ^^^^^^^^^^^^^ - The following packages are now optional dependencies because they are not required for core functionality: ``matplotlib``, ``photutils``, ``synphot``. To install them anyway, use the ``[all]`` specifier when you install specreduce; e.g.: ``pip install specreduce[all]`` [#202] 1.3.0 (2022-12-05) ------------------ New Features ^^^^^^^^^^^^ - The new FitTrace class (see "API Changes" below) introduces the ability to take a polynomial trace of an image [#128] API Changes ^^^^^^^^^^^ - Renamed KosmosTrace as FitTrace, a conglomerate class for traces that are fit to images instead of predetermined [#128] - The default number of bins for FitTrace is now its associated image's number of dispersion pixels instead of 20. Its default peak_method is now 'max' [#128] - All operations now accept Spectrum1D and Quantity-type images. All accepted image types are now processed internally as Spectrum1D objects [#144, #154] - All operations' ``image`` attributes are now coerced Spectrum1D objects [#144, #154] - HorneExtract can now handle non-flat traces [#148] Bug Fixes ^^^^^^^^^ - Fixed passing a single ``Trace`` object to ``Background`` [#146] - Moved away from creating image masks with numpy's ``mask_invalid()`` function after change to upstream API. This will make specreduce be compatible with numpy 1.24 or later. [#155] 1.2.0 (2022-10-04) ------------------ New Features ^^^^^^^^^^^^ - ``Background`` has new methods for exposing the 1D spectrum of the background or background-subtracted regions [#143] Bug Fixes ^^^^^^^^^ - Improved errors/warnings when background region extends beyond bounds of image [#127] - Fixed boxcar weighting bug that often resulted in peak pixels having weight above 1 and erroneously triggered overlapping background errors [#125] - Fixed boxcar weighting to handle zero width and edge of image cases [#141] 1.1.0 (2022-08-18) ------------------ New Features ^^^^^^^^^^^^ - ``peak_method`` as an optional argument to ``KosmosTrace`` [#115] API Changes ^^^^^^^^^^^ - ``HorneExtract`` no longer requires ``mask`` and ``unit`` arguments [#105] - ``BoxcarExtract`` and ``HorneExtract`` now accept parameters (and require the image and trace) at initialization, and allow overriding any input parameters when calling [#117] Bug Fixes ^^^^^^^^^ - Corrected the default mask created in ``HorneExtract``/``OptimalExtract`` when a user doesn't specify one and gives their image as a numpy array [#118] 1.0.0 (2022-03-29) ------------------ New Features ^^^^^^^^^^^^ - Added ``Trace`` classes - Added basic synthetic data routines - Added ``BoxcarExtract`` - Added ``HorneExtract``, a.k.a. ``OptimalExtract`` - Added basic ``Background`` subtraction Bug Fixes ^^^^^^^^^ - Update ``codecov-action`` to ``v2`` - Change default branch from ``master`` to ``main`` - Test fixes; bump CI to python 3.8 and 3.9 and deprecate support for 3.7 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/CITATION.cff0000755000175100001770000000245114635037352015153 0ustar00runnerdocker# This CITATION.cff file was generated with cffinit. # Visit https://bit.ly/cffinit to generate yours today! cff-version: 1.2.0 title: Specreduce message: >- If you use Specreduce for work/research presented in a publication (whether directly, or as a dependency to another package), please cite the Zenodo DOI for the appropriate version of Specreduce. type: software authors: - given-names: Timothy family-names: Pickering email: te.pickering@gmail.com affiliation: MMT Observatory orcid: 'https://orcid.org/0000-0002-9427-5448' - given-names: Kyle family-names: Conroy affiliation: STScI orcid: 'https://orcid.org/0000-0002-5442-8550' - given-names: O. Justin family-names: Otor affiliation: Space Telescope Science Institute orcid: 'https://orcid.org/0000-0002-4679-5692' - given-names: Erik family-names: Tollerud email: erik.tollerud@gmail.com affiliation: Space Telescope Science Institute orcid: 'https://orcid.org/0000-0002-9599-310X' - given-names: Clare family-names: Shanahan email: cshanahan@stsci.edu affiliation: Space Telescope Science Institute orcid: 'https://orcid.org/0009-0008-4112-7418X' identifiers: - type: doi value: 10.5281/zenodo.6608788 description: 'Version 1.0.0: First Official Release' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/MANIFEST.in0000644000175100001770000000027214635037352015013 0ustar00runnerdockerinclude README.rst include CHANGES.rst include pyproject.toml recursive-include docs * recursive-include licenses * prune notebook_sandbox prune build prune docs/_build prune docs/api ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1188734 specreduce-1.4.1/PKG-INFO0000644000175100001770000000747114635037364014365 0ustar00runnerdockerMetadata-Version: 2.1 Name: specreduce Version: 1.4.1 Summary: Astropy coordinated package for Spectroscopic Reductions Author-email: Astropy Specreduce contributors License: Copyright (c) 2017, Astropy-specreduce Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Astropy Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Project-URL: Homepage, http://astropy.org/ Project-URL: Repository, https://github.com/astropy/specreduce.git Project-URL: Documentation, https://specreduce.readthedocs.io/ Requires-Python: >=3.10 Description-Content-Type: text/x-rst Requires-Dist: numpy Requires-Dist: astropy Requires-Dist: scipy Requires-Dist: specutils>=1.9.1 Requires-Dist: gwcs Provides-Extra: test Requires-Dist: pytest-astropy; extra == "test" Requires-Dist: photutils; extra == "test" Requires-Dist: tox; extra == "test" Provides-Extra: docs Requires-Dist: sphinx-astropy; extra == "docs" Requires-Dist: matplotlib; extra == "docs" Requires-Dist: photutils; extra == "docs" Requires-Dist: synphot; extra == "docs" Provides-Extra: all Requires-Dist: matplotlib; extra == "all" Requires-Dist: photutils; extra == "all" Requires-Dist: synphot; extra == "all" Specreduce ========== .. image:: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml/badge.svg?branch=main :target: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml :alt: CI Status .. image:: https://codecov.io/gh/astropy/specreduce/graph/badge.svg?token=3fLGjZ2Pe0 :target: https://codecov.io/gh/astropy/specreduce :alt: Coverage .. image:: https://readthedocs.org/projects/specreduce/badge/?version=latest :target: http://specreduce.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6608787.svg :target: https://zenodo.org/doi/10.5281/zenodo.6608787 :alt: Zenodo DOI 10.5281/zenodo.6608787 .. image:: http://img.shields.io/badge/powered%20by-AstroPy-orange.svg?style=flat :target: http://www.astropy.org/ :alt: Powered by Astropy Specreduce is an Astropy coordinated package with the goal of providing a shared set of Python utilities that can be used to reduce and calibrate spectroscopic data. License ------- Specreduce is licensed under a 3-clause BSD style license. Please see the licenses/LICENSE.rst file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/README.rst0000644000175100001770000000220414635037352014741 0ustar00runnerdockerSpecreduce ========== .. image:: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml/badge.svg?branch=main :target: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml :alt: CI Status .. image:: https://codecov.io/gh/astropy/specreduce/graph/badge.svg?token=3fLGjZ2Pe0 :target: https://codecov.io/gh/astropy/specreduce :alt: Coverage .. image:: https://readthedocs.org/projects/specreduce/badge/?version=latest :target: http://specreduce.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6608787.svg :target: https://zenodo.org/doi/10.5281/zenodo.6608787 :alt: Zenodo DOI 10.5281/zenodo.6608787 .. image:: http://img.shields.io/badge/powered%20by-AstroPy-orange.svg?style=flat :target: http://www.astropy.org/ :alt: Powered by Astropy Specreduce is an Astropy coordinated package with the goal of providing a shared set of Python utilities that can be used to reduce and calibrate spectroscopic data. License ------- Specreduce is licensed under a 3-clause BSD style license. Please see the licenses/LICENSE.rst file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/conftest.py0000644000175100001770000000160714635037352015457 0ustar00runnerdocker"""Need to repeat the astropy header config here for tox.""" try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS ASTROPY_HEADER = True except ImportError: ASTROPY_HEADER = False def pytest_configure(config): if ASTROPY_HEADER: config.option.astropy_header = True # Customize the following lines to add/remove entries from the list of # packages for which version numbers are displayed when running the tests. PYTEST_HEADER_MODULES.pop('Pandas', None) PYTEST_HEADER_MODULES.pop('h5py', None) PYTEST_HEADER_MODULES['astropy'] = 'astropy' PYTEST_HEADER_MODULES['specutils'] = 'specutils' PYTEST_HEADER_MODULES['photutils'] = 'photutils' PYTEST_HEADER_MODULES['synphot'] = 'synphot' from specreduce import __version__ TESTED_VERSIONS["specreduce"] = __version__ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1068733 specreduce-1.4.1/docs/0000755000175100001770000000000014635037364014207 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/Makefile0000644000175100001770000001074514635037352015653 0ustar00runnerdocker# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest #This is needed with git because git doesn't create a dir if it's empty $(shell [ -d "_static" ] || mkdir -p _static) help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" clean: -rm -rf $(BUILDDIR) -rm -rf api -rm -rf generated html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Astropy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Astropy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Astropy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Astropy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: @echo "Run 'python setup.py test' in the root directory to run doctests " \ @echo "in the documentation." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1068733 specreduce-1.4.1/docs/_static/0000755000175100001770000000000014635037364015635 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_static/logo_icon.ico0000644000175100001770000001047614635037352020306 0ustar00runnerdocker  (( @   ߿߾Oضn}ڷsٵpڹx׳iZ۶s*Uյo7Գiٺ|ʍtypɆ͏uڷsٶpݽŒ#̙fUͰg׷mݻm׹xؽұjѮ[ǚհbضrߺn̍ݼֱgֵcU yϴrϴoԺ~бiؾӰb׹{ضs‹ݿ}ڹzܽtUθ~ԢѺѻѺƘеp׾ؾؽǗœڿϒ‹Ȥ@ĬcԺjι~Ī^ī`ĩ\ʱoй5”Լ˫[ͮcԹ}ӷwϯcҳmѯcȇپϟ8 êd3Įcd̺bìeªaȲr͹OǭbϯƩS˯iҺѸ{̯fˬ]ίfջ‚бhع|!Sư][Ƕ{X[Vïkdzsìgϰ5=ū`ζy̳rȬaƝ˯gжwзwԴdήe㴇̿s²r²s̾±ròt±qɹʹ˜Ɲí_Ưgʵw͸z̩Էк}϶xăӼgHĵrmpȼnpmƷĴvҷƶ}cƳtŰoϿȴr͸zѾ˴tͶzĀθz}TtVOSvPTNiUDOбijyFƴx]ƱmDzrXë_¨ZϺҿ(U[UYyVYTl`1dŠ?Ĵy°pʹűq^d_ćưnULPJOrKOJ^nԽ dpֿoõ}bV[Uȶz¬c7.cmfhfhgm™ǤT{sN|Şϱбrorm̾ijthvnfifijcպa{obsѴźmprnʽǸ{m⟟@>NFBGmCGI*8F_U l?BDRSLt[U\:M!IKNqKNNCSaho¡)NWYSxa]ZnCǛACj>D4dĦHUkSHOHqWRObroliqU̱ekvKy5ӻmupüz¹yujKHnGA "YOat=$6YNu]WUTftXcF;QeBAF;AbZ{fbbƩPBE?Tg?DCͳ.Sƨd׻I'_*91J`.?.=K8>8L¤˯ŧЯɮqRHHWqy\c_m|^e_}v`g`{mEOGrYJ2UєSH[iDMHZlGPGicJRJhjSZTwd\UYf}0၎*HX{%5~,G])9*YQ.;.XV1=4eL)^@Iy+ՐN[y+9}1I^~.3ZX5A7kM@O^w(|6y-G\z+9|+YQ/;/XV2=8brUfl`c\ky[b[wq]d^vu`ifh1@v7v1s)H]r%z6u'VNx+~8y*UU099@f3fu#IUs'~6y%YPz)8}*QUsY@@u00x1bnUKr$v1w/g@,././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_static/logo_icon.png0000644000175100001770000017126614635037352020325 0ustar00runnerdockerPNG  IHDR9JgAMA a cHRMz&u0`:pQ<eXIfMM*JR(iZ,,K pHYs.#.#x?vYiTXtXML:com.adobe.xmp 1 ^@IDATx ]E?~{/BJBXPpTEg>? ("8aOD23ttVe\q6q]pA@VYd [^u>]]]}-IN'VuշUݷwZmkgvhgvhgvhgvhg`Bg3d 3l֭:t3\u9Ӧufm*fGͽiud<4Ӟ{_<>.3 @aH8`;vg,m޼KSR.EYfYJx˚MlŽ?~ƢS<^' ;Nѻ}Ϳ׭{$m7#[ߐ303p2mc V :+{`EWa7zb(fݮ1WLdsf1$\IFQTMYPpžPm --Enw{0 ƶ8SVwVsbyp@"[ь܊`(v\74R{O喢ۻ6ouԋ"];Q;E-xusGf> ͹su6/ włmN'g z_;F򞛋^:ser]gsy-Wby30,jg`}_24\hw+7~MZᱝ"e30A3_V m2Boyh9(`9AiΆ!*d+ xt]^N_ݑonONB23?SĶv;wCMל_a6d C>5V3u~|< ߵ7o_mT ]`og`Kp;z9t2ϻ>1|̍mp/ĿK}޽*>ޓ NsX2Q(B&omCđw]S>5ONO hm71qsfXu{zךlm!6 [!M5 fybKg7 D@aLl>]LsG'ÁW0Vxtg O- ^Pghh8q \(~|~$Uy c' uۯy O=}Ʊsg} 68ņٰGxt'&Jd Q4|։'/7>0Ǥ!7]pykG{_kҎ\&[bA'ȉ \XN'B)NK|橪U?8cj7xNZ't;EooBl55)'j_bMEJQ9A]rnf1' urІ3 W~sod ,NnF௶X"뗭Pά']I٘'BQR&V<3͕ɽnfǕ+wʺ|@ahqU2\uhCx\\l55('6f L13E$ˣ"E@;u͛|駆ɺuqPm{ n9*iGuo' 2[slg~cH~=;YūjD'ґeS$< xWeުݻt_pwg `Nw-5X'pH:jpb@k%E$kͣ2{i({2XZ2i/3?;6>g=+׿we{kt&$P>֪ $[rJАʫ'D,wEј" 5G*f:lQ]g_ mn?v?-?6Ãa4|xtgrNVnL2 HM֚GUjIKA*EU](ןj6h_AwO~yrY|dnSd |C-irwWbp9+:9A@O7Z'qr@d+roeG3j:5Prn?_wtۘA w9>7RdO ApDP N @HL~9yZLrlAꞔLO&nnl|Ѻ#7w[por۠n;ݺCCo3/aͼ_dQNH?aS j9@bUe{k ͢^qz'[0x#o{vGu;2l(sC6wMC#.'NYH 'bI.%)̆J /3 sqS:lݖ5=wu7e>tw!^zCÇ6xnV9֜/"Q#u"$o ^i| ODr9™JEctxεm8p6 3zO9/5Q\9", 'i˻ړs}}8"*Qj$Pco'HchQVvRi\CqkZHqpq횋>:)mqn%5<cw?uOO`[l 8IӛL\kW@BA*i9q zPzM G ηӫ$Bnnt^rXTrcpH0eP|f =.ZO`;톱?M_}iWw_z5f}qQZPx<9Zx^m0Y>- EG%kp:MA JkJOLj1pcNTYtXQ0ZمCE祽Or9kkVa\mg_̛5#C#;HCM.,Eْ9D*=bYK6m-?VNUbS"oc( t?geWP VIctE/(V?' c} 38l4i/E~~gN=5o_׾1UqQ g9oY47(G͛99mPpQ'%$O/F͚] u|YHJ*QمQIxyG ǘ•܊YK W.G7=iC=gN2#?):娝/i(lώn*MZrP<&c*4>9gGan)|~Iu$(.ŌQ,&_bS!3sW'rr{z?ICÖ"JR*nfk^5ooo={F?a GRylT84 VQsPQ Å$Poe9MM/~=ڧ#VSv ?ߥS09@fgXw Ũ#5ƠShY6ߝ/^˜RG}1 C#ך<UDL*uay졅z QTEJ!ju%%-nñG;/f͉!H5衒5m3@TC^GŠҨߩcCG-ĔHsG }S盯8OP HGdtՅS%DG&hhuNO[AsھQN*Vd ђx.I(CUN. Y靡NY_oy c*< 55çxZ4nH?P76-S:"?~z/SpW2/1q< 7yR*fٓI4*!(U+(rs"e GƐkD;<͂@?d< =cdd1W^2N?TWk&.h NKOг3 +Jm(*> 'Tߔ&-Wlk0ʹe+puuŏsGͫ Xӕ*;d+qg>|׿&pWaL Oo]bz4 qsL&V jr{8#lobNz@Ϲ˯'XăRBL/3fR>O}hsW^ED0㡯Dp!BqtLG\~ƌ70{} (iots4D}S<JcDr9(_faG¼aւ*f•1p$!*`BPYD1L1b xP8S̃T/۠ڏ}l'<}}ټ=7ȥRkĦElid+螔KʯA6%w9=%Z[ 3EÅIJ Wa:דe:Tx?u%qA*dywRddzs6gMl|-]]p~ˏԮJ+R<|(P'nA Dq)f{S-9=sh }n{4VGC)IW iGM!Dǫeҟc)yL8GuрƁ0Ć2;.qe69ZaLμ?5CϙeKjکD()pkOt\Q0WE܂PR5bӓpGB ʃ]>@1h4"9JDzD;@(GGe p cg},3!%_xw )JShAYyK"4(9U% gyŠ:5l~n /7Y0<܏G5`t j\JJgܒGOh'aQ.5h ԣ B] nt3G|蒗i7ۀYpo眉u0BGpxEWqEE=e HLe&MʜֈҲE%jbp3@PjD;Ix"T0Ntx4ZԽ#jZAigTx4w|R5/ٰa&JaLL7b2UZˑd+D랔煃&)1y^W-T&9@"UEfyY4ud:Tx?R & wSwLUg0qvלwΣ#Ly(d+ND'*"SR=AK0U̺GKd|*CG*fIu *kfq Yp5 Ӹ1i=`.Hje \]E(%)fA)kDi/*!'5VR+ 5CcIJO֠@6kՅp7q𒐓,<7imrpq=V)Џ+bAp׊6+Δtrܟj77tq p3-\na$#sW,xuTE;\ŠJCp'$&KDю+c@K')4|y<z]h@Y@J  4p|'B<PB)+-ΐ /򲃸}mcן^8.FVXMLV=F%OӀW@DRÐP5)*\u(%#$Tcaȡ贗%Pʟo̥WdluARFLT7g]2K{1yŦmej0b}2^gT| 30uO ުjB c^bQaΏ(CSHe8*b+/7A!#h5&hOz+ý9h5&֩3Ǭ-8VUUZ5xy>!%IZU4Cz ƢK W>UxZ:=kA&DqBX2@DP R1M"RyQSզ6أY:;.ZD #cCoASJoU5ΐ` A(G,VJؐDHe8*bW1gB A`BJJ*KgdC1X_뽢0dթ2b̈ţndAq7"|8CԵq8*B@x_6tm0L歳5 D .Tͧ2)B+QFR3J1@:9 ɝ'5E->Po+db[^[+[kF%7O1С;x-2g |љ+;gPxxBQ f{$ cq4R GQ,*0hv È4y-TZSC1TW]xPnu,a-;d+q/V❙A_o0ќ{dMVEZp"PCä]=@}|JvQW|M;^a(S撳nKU&4lGJbxMx3J<0;I);d+T{xU $qIxlT[?! zUgEWxZF<'Ś vvY>j#"6ZPH)ĠJ%W!.Jax3Fq~$%7OޜV*^HaCe^(6x 7ۙYI\_arc*3c6WhXXjÕ']ycEAYg/{WWl^nPnl oJbx>?G1ky-<36fcbKY"(`kH,ü8q!kUM+?6x8+jhEf357TL> &ƋAQSǠ[)+<@?d<:3Us?۬bEd 2Hss 78<$8pk"us'%EF~PYA?xC gekx^-w8+Xfv+ 3a_t[ Ns:jtI!x1]b1Nh>H[1ItDLt\ܺSE[񁞇sC@Qvxl#[Β^ l jϔ[EgV!V^7gϏ7L,uXsYsÿo`iF)`-֊DHu ޚ')OZ 5PŬw 6OR"輱"cekZXEڋ(')6wpI%}qiM. Y?8-v7!F ^E);RI(rE/)1LaDm r'K+ LxE/N;;̞ki\?VrPg=qŲt)-V/C%/>!k^^nsvGu/\yF l7O"*Eޘ5 /9w2NkԘ!+JL=}xXXYӵ-{J,*Zu\ұ+< .|* WY]0c˂A}i)BЛ޸ioȴUnUOoz-7όn64m(*\u(ede^^<ϼ[9w~u፣b #5t]2!?l؞ٴ[~^u/[1",< 3F'9s?:5"sn8^0D?ފ]+3sLx d|f9%!Ie)y=_vzM}C׏SRV3d`JTxX&5/[ uu:#`=c%Éc#'Js]"9DBq(-{(ċ* !gy,6ƥPYFdf,~̲5UpίgU#3fZ#0"Õ3Wt,֭k4)5LI󑗯?o̙5;flEo'pzXp@ A ^#5$FI]<-[1FzQb@$PaWKL|>+L̺™lUg)=enap@mV @h$4e.i N9@M$"*vpt,=fekݪ:sLrBoI&e w9Ѥ! ~4Ap`ٟ+2tQQ:e#t0O/UfَBfqgNq2>$C + Q 3A@ѡ?bl/w{%v϶0sycbGB<\U 2ni^mZb^T-3%5" jc)T~ڨsd. =)6˒`Wby{')no6GAf& ћŢ25PY:7.DT7!QBXZNVԈ3Z &,I䀁`xY}J<>VyZ 6dJzsƓ1o/&e&q$Kġ.쐭X] fN}hs#<.J5Q*k 4wqAUg ~[= Hutn2ֲ.•0D*59~j5R[SR^zqf Ln2=\gt˘kY22s'7!Kk[ҋBD s u F3l˖d+(fuMrL` :a QG1<0 J &ff]&Z5d\?4-r8w2_5s"k0xR[hpK!H,]U!#/[ 0QߜU# :cN09|8貨F(u =%'p| P<_{ }?Orآ^>CtՅ`Ԉe4ނ`P>ER(Y,?zR"SBJ/  q4^|4&ko ~_Ngcke> )g0٪P937燾m11Ӳ8n<"{TVxj+A@>i*5n\Ri#b#ɄmüqGMc8n̜{9Bp8֥1sO/V*s7ixr/Zsl00FN.ԉ_,[̆7|V l:(nyl`6=[tyh6\ggnT1/N?JzM*`00 K{*d|t(i2^PՋȲ?~͋Qљc*8s13Cu|fI^播PQo@IDAT3uQݸ]8lws[{1wtci۠f` wҸ c%}ǝhJvP7qv~qkqmAȎ2"uG^Z*EU-v ͮh(䥹NqVOz39橬gvKYn$'=PzdY- QOs1j͛~%ў\jDZ Nm~˧W62-okɒWLXIΘQ7xf%,jz1*zPDT*V9nE+yN@ܿr % wݵ{gT:6sOO"W_ُYdVRG|dad֖v ISg1Mq̭ _Бc2K2 OvdBCi=h~b3693%噲~/_oޚlqkRxGETYKSr~kq,od Q3LH7e$Z B%dIF zqK- 7K=C5oL"O[(fGnfnԅF n (#@dy 'H'isH[wcNC™٬;$yln 9tO%|PsWb~K5 ?[ef`Hq 7N 7^d!/t[N? P %n T#G;pLΛ}FLO\H3{>1Tj FH%d¼őq.뒭S< DkD|yKRZ̡A6dt>oߚS1'<-uq6_C`%Ɛ*:;/T)Q+qe9u[B3|r%n>H կ]{ U!(%ACO>eO ٛREOMtN&<oH9̓WW)͙GN/㛖Z>n*y*K_G[\e6'$k [1V4/v_S8Uڌi#+x-S){ lEyM>='&G+K .Ñ/&}lԣ˂;FC4F 4^S?yś:v\:☽%0O/9( b6,fo3F-㙧̆ǎ>k~JkR)i*:k*!H&r&_mfIsE1} p#'vjj8&H K,޽v ̛1}G^ǔ0>w.nƋiG'"(Dg9+[͟A[V4Z 궚S<۠1{Un7Ҡi({TY1.&VsgΜ>\s5_'G}?%m6f:^`/Ց7شys#WSy x Flq=/??WHEY0xݣ$̭9,\z(HrQ}YaӸG*$l⁃*jsj`n47y ۏ⦏ GXjـoݜ = E$sz( vS ya>YL/^ɍxf4yc,_p ^[XlM- 쇯أ}+)B Nhʯe2C2>$GtЁYT ^,I#}YM^tw7x Cƨ&wA;dlid+Ҥ saމT(|'?P<;\'畭Gƚs͏~tg&uXs;-n[KWjQΓzXn.\H'숗ϑ$1 n(Jfn{x_/c2K2 x8ԈA85w][?kLTJ#S=\|[Kk2$ 4=O@]uRs3=1D;T N)Ϥ1n콾02~,x#~3Cuկˏ (Ʊ5ɆL9[b]LJJ"*=.> `sV{.K:pU} T-~+C?O4ſV<"<$8"kossUH:G[D:70zf [8 0594zyРO ^d c _Bf#{<~,<jy9*3Q >ZpDkNEWҗɃ˟oLKy/Dm*qo:;<Яk<&^ qԈsF o&,a RRiCɽX WĿ3?:O4;p:oIp餳_&i\[.yjs}w8[6TF/6ccph@tD% a^&鹓a2_82[HB͖NGh F̈́|1*:LlϐJ_6ǠڑAa>osb ru e &x,e [nt5W1k5+հ'8|&b*c cH֐v澦Vu{qͭ.Vu"tz:*=w@?]Mo2`UVY'Me|$O^:FEJD1ސ3}6 `:H){j:e8W >[G3+ʳ-U+k! >M6e !<(T8ؼ+oPM `M/9_̛"V%ɦP;l/\$EWoibMl疀;]v n@ ie+pCn` zZQt  cpdT(tL94Ef De};SSkdېZ3NJ<Ǐ{ BDTY>s:"`y< *yǝy[|>5{sPd0b0OGm4Dh'Wŭ.;Apx8&I;%d8]`i cO苏0W0)\Y`y@6A*iNЫvׯCuL1rUJ)Jc|<5C?aX`x*ACޑ4Eݱo0R܃ !T" ={|4@0.|^xn땭*\p1Xk3F /(ٸ' 05cp릊 S ֯Kedz@\Dw綬 dy~t=7nm~->xl%UQs/V(fjbm'iYryW[ s8Z2أSQ+r}rDl<-"y3M-|]x`z>vr }^5=C>?fxx\=y'L]$Qzd4~6:(̒ ݀%6<$/b m4Q壦pw-ލ4W_n_%q|*[==v=5=7^P %3*҄+3QNntyj ܚ3PŹ}tʫ < xD™V1 8x_?7A{1Vd+)ŬiXk QEЂ{d q(-꘽_~; Bؿ^Xa^p7f-]]{MK[x>(Kvtzuig("WD^p! eCDUauX G"Ee +JKU zmk8ϡ{v)֚5=v|[jk^\تtOjqMꞈxu%}lr$x6 >G<@|<2r"<CAl7GBzVd`-2 uTz~<^Жo?/n<])=tHF0o;/P7jE{# !(+@8$AYWkTMi UWW #nX2%H~TBY@MW9{Uwtx>5|UEHU.+2^ Й\͎({eb`TzcuP*uu^$ZOc^נM>4DCuk1i'=[S^a4mʬͥsÇZhC} PCߥq0Ep%:AomÜ(khƐ_Ȕoٰ <+x-b{W܊ٖ$o=\:x^*"\ftjT~c\b 6 j}͛5wc{i\༡K8+W.ٹ.Ǟ0_uxZ%Fn I{)98jPR2_lehWZN6q0׀1T-8ґ`e -g+3Ue%wX':xC-}Œp$ؑcY;$X7+?t)b!02t8@?t<}\T?{3xODdx^^2 8_ϋ) (itDZcm@4)p -A + 6 塩` 1 .Xx졬c "U c\]襠ڱѪ3*.fEYC-߄r'IxOKAw}10PzQ7XT( ttP V6.+J gm87(lѷ[w6Z 7eY8Vƭ.;,zKC;+ U͉#C?tT :aD,z>͏H Qg"Aq|$5;.xG(]Z^_6y,)U5'p>{rQŇxdU0MC#7GDe:sG4@C0aSA{'/)?B&Wuco{%3vFd ź? З'ql@~#Mw'A b0$Ҟ޴SΚ⬡ bTҸpHyztJ@syF/7|(Є Q&9QS5Xv5 QӟϸR|̒L[Bţ}e3za#OKo6}w{"ҠṳNsI=kgf YjrWFҟ߽S?Q ׯ2wB!._.2/g7+>Mп?{l >Г~'!jnY2uO+6QO~^-T}Sm#O?mR ~1^{vhsxc59l6ţ҉7< li; zIGW/G /p& }TLj0w?(dn䅧=l=c _2Pp;L|eNZ*8u>LX?]>rǠ͜) f?pZAZ #Ĕd\ ^l{ 㑵Ggv/мq-Z &#05*AS鞈T+0? yw!lU!Ơq[ GzSÝCqn=hyT&Tz_?; η ?=͵ݷocluʃCWX^\}=.Hjce}M٬7C (uQHPi_z:Soc Ie+7C?p1PO<y皷VZPh}F3f~Y<2ZR9CTфVVmgX-y[kZ~1,o)=ϷZݘ/%jeC$(FT5fE csG=6+rSsa` TڄԂ:-Eb2]:GRdhx*S P2LZ HWRx~us^:נ7Gsa8i*G"^pȇ^n%|v|kԢÏaW4)vQԎ!ZVFD"M'QJnZ?{T*܂yك>r)g-0x 8(CsYlf'_OD<Z9<9/94Tc0p cc?p>{9o 5jS5Y\eJW5acWnltجd\+ e&Pp:Q 4/UǠ{0H7( 5_L:|Z(+iOmӸqi% Nmcc0[@kVBŐk3$QJV^kOh[,1o/ʃ o}\Xrc*/%\眪BAZoq@:lcKҥmБМ&V$J{2<?4ח/vWhOϦUu4=9Jrh@IWK}_]<|kDiJ_E"7nͣeQz~PMr &wAa2Em8?TOrV`@. >YGb* vQҚGe66xThNcZA5 G@=ZuoN: `]Qѣs F50^DJVLj܋ k}nBHmpnZeI&JOB:=LeF[ 00J[}\sVGYQ+p3qX"8QX$ٗhc>jKӁ H,9 =>Nxk/+C>cZNVZ_ttد0N+ rڧ\PS A:f__Uj6MA [jeM7ẊFt:C0^kh~ waqTj4=JJD~4ꂔ܊ظg=C?1 aӟ+Pg).,rB7Ic8OP ÄN-z+=+JS8a~{cʘJ+ sGB2_ m ee=ȚִfyeI&ŽޓэaWPqv6+|8ԲG1W"^"y\UjxdD8hp,|Pm+v4_AK`?f dcT|.\qͭ.Bp ystܹ2 wAHjy])l >|CժaN'-GslUN(Yxt67J/|B=RamɂG50="\"Md0z]-(GҢtx*o<_&Q+NiNԓg2d=>ޏTzQ,q5֚rEs7㎵?7IRNn 0oHΏ-;sHQu?Q {hWX0{ў'qSpW'#Y{0oq+d%^2[1QVnRi]Ԃ:㌺CY1.}|Ȁ(#3 O0cN6PzG#;JiŢsFֹr'vxJ*Hrc>*C(xf?<*_GYC}UuC*0@ &P?Fn&A|s(rht״j/ W]¤^譪P\kېJ471TxF桙gSG;o2u"-ZP]|>< ^YXrWIgv ti1N A<{YnBۗ>cnuY6!cҗF1qD(}ZPzO7f +D|5T|:ppr|RrnšQԊ(+vaFG5cJu)tcv]<[ؿVd`ea-hEzi}x#k?huh@e :g{_~y]5A'{?ꖣ8E# Ebil6 `:v{鶻Y9=^ac nc: mCX ==ғNFf}==7"#"2+[ֽy2w%T5Y~3.sOVl_$ szN9'O8#n =FqG45ו"F0V_߷e´p9 7=, ć]n!g)+4ԙke|xB)VI|S Ȏ'*f\ ۇnݯ0W:A&V(&rdCnv^!Q%2_FCsMSDK&XY&X?@Z7u%^Z2ɥ#((f="3߸B!My3ݻ @.G}OJ]j*6>X"0s_]MwP1=T,\&T͏$ڱ<'f'ιͅF<,7Mjx7 7jQ;5cͶZ/}T 3!mQ20ťX}/6*.=F +߳~[e[ǹjEĺ:^0AU'9cǤxo6f^Gũajw1:s[.q6C3g빧1ۿbKW^E-U4B^VԚ<㔞[Gj }E씕hn #4'ɚ4Ε*Ѵ9_I& =1S.Ti)dY48tAFJB!TW# ._XcҚ!mZC!\Pe;2l*[wk[|;<*zЌ.>oi; ȴ֫eNx;tU\Ōf.+ytMg@*y_orFK5Hz \n$ePƑJGnQbηv*}锖g.ЏӧxlL򪒃[I Ү|ܹGuͰ/ж' ):_IU4>ռK:=|*d ͼ}zKjuh5˦0W=:+LKTΣ6ìb]2_Yn(ɝ%Иde A_xuJ/86;SQ% }K~rEL6#ܛnr6 DwkBoԫK2;z~_lܔf{PH.u'sAVgּύ"o9U(& 22$IOFa\#г2wЭ~Zqٔ=N$ȥqIAܼJDqWy'% ȢXGB_~Hqy䷤j{Phi"Zw[FFat+X^ <=iՒyYufH] GC;^Z81rp~C>4ow'hg5ᘇj/_#%PJVG#Or]Ɠ?X7Uif2f-BʊR.)a C1h'0U|uQ'by,4ӤĉوFҭb=ey{ZnJH;`% Z0EPjEo"weťe螹RrBF;4!'K$0=Y49Xmk8AY<&Rr`4: +Q)9>2ye4qN&cX||"+ z9ecp[-a㴭~fhpo}ͻў+\w@`L;}*hsѣ*g.U`ӈJ A"=5 2ACaj gQ' wDW(E(1x.4N AATB^=<;߽|~>۔x\:SZs7Jh@IPߞ;8csYOpb"=X+`=qL@!jc2F&t81;.=%7: @ֹ_:#F%̛<ڱθɗdڵ_Whk G>#:d-ʸ+KG5!7}>k@ vDW} L:ar‘K 2"9ͦVս@/<ԯ5/A:2zQ^m_ 7&e"+KzI(BzZ`A 0xB,8riK\%AIm5DO\K:Êrog¦H^9bһ C20V-wZ"zZƔ4ԯ6;@ztt/YHxCnI ˙#OlA,* c 2b C z .8sr೥N[u%ގuY.qN1$?Úl}NǁsOQ&n: 1 u|rRE ѡ*@A&,\p}>ּwaa4JS6ìbQЭ`R'is5/& ֪3OWgݏmQ-j0)` oH\(#s?0}# Ihmzy,KziUHkd<1N(&_~weތ2TcĒ,dӭE%C\d[O ^:Hӕ1 &k@2P^e]`Gyə>Rq",k%a;-[VLb,@U 2`rr鱕i}ʿy0B\rdKzuUVVZ"K^:YYZ.EA;St. j)齽{ ˜%}0&vP'W%N]>T6G¤Ƌ.\j#=z2c{^ R F|5CP we(@@t.n8ld/MzuA!k#WQ z=lOnUu 7D]ufr:p٩Gsoc:X VI oE`PgVL?V~͔,I):-k?DI Q.FqEACD)Tc ;p3,n J"Rs D {y/+#@IDAT ɏx5  = dt#d:VxZ=D";!EﲳgFԊ eQEn".\&h;[c$gcY ӡFiop$~I 4Zmc\JEPϝWzZM=mIӧ҂g(H7}:@dH QfI^yK<}q:хM6僤1ukʢk2*%[gmYkTs;m m2' qtb|Y9B蠅0BV〃`#{ a1W/q{u,//IHқ<]?1аcM޻{@ON~a]rm9w)q;%Am&9sHFFvS?Y].+x#dDV70ttv !;À;2rW|NZͷ^pE\)cYٽckhO/awUf"̆S`S"3涳\VV$3ʘIN50vH'Z|V8ā~קy3G:rDꝰ3_o3MÅ;OIv'I'XDseiY$ Y ;1?:bCu8o]ǒ #R;ǩQJGpJkͱ2<,5.ZGY/X^u,nX!h5z/([E;cH[S%jzYjV2>)tCp$V͆90Ⲙ.Mk<5 MKєư\:K&I,eéyyȔ=nt 䂱pCWU_zVVj^59<ёWЭMh%wE=*+ c{SO~wz3 .HMounU n->>xs,:^BQ$tit G =F|w}SuL?ҳi7 q{N<1;Ajm|?ν?>|{4y^{n3 @}S.>v^h KJ;Qs]+wݦUlYe{$Gߺcr,{mVJm'}{X=t}z¸{Oʙ^T}<_rDw)瞝n}`o vܺU%Fk OH`'Ϻ3؎Nɗ* Mԏ1ObPH0 .>MA%x^Ee~.^5}rk q+Hyμӡm\ ~_oೣUj(84]wV>ί~{'1SH^{+8ɢ0s1K0ݡ[\e*1׭2}@_Tu1Rji D&}z(/.{byD|_ /Po)Bfh7~^'=9PI璳]O`oJ.HRޔo)*15%ZP -I3iw%^\M*eѫ;t+I+MGh0&M,*F 6cYF71rV=q* $71<˝<ŽMOY]'-(Y3La:lQ( F~uA gdO dIRiM5JO' x0TD*]=L&q ɱYM0c*\osV(Mt16`_t^)iH&Sn.c0F(UgqQ=矅E=t2{ }xC˖D qr3 jȶ#"p2yt I:C#;*qM<}K{hF2mľUDeaf*SzS%~L)S^D|sC^K~CjtF316SNN`LX=5$bBLSO2@|y[ Ŧ,j?쳪'ztwN2Ԃ 3`6&׭&/"bFn9"'ƍJvVw2:ezG^`Z[= ۫M?q-;ZUsMf ӡ&ѶG%ϭn4ȳ@WOTFҀW7(N[cPP?cO쯵L-ƂB^g KK-fʘYi|K~:,X @SDKoIpݵUњor j1uuTn޹ZSaW+1 K_/8 VxM?I 9tdg^']XsxBFg(e90B-B01$.!]p90B4 R%q,lScK%.@.m:m-cL3E#{׾3t0\K\$7qj5،r)$L[Kfj.~f 1KrYsx4PI1/w?+hNdD#AT7W<ɘ֙-@L$CrHMBʈ= ôl_pcj2YT7pq, j{Wį%0\@(K/N+8tnY\iZ vcc=ek1d^ZoEl~B:Ȋ}4ijb vn^=1'A2X։i[O?}iF;]ЕtXOhyIHZomJDń$[XB8L8۾?gƙ;}=^5vVj8֘iRZ{Zc* 7t/_Xl}nc3ce_99r##O z!kj7}_ӻ1S*9}X?<Pա(ۣxݪ2 "-ZR7][d ݧR|@_+yelz5uo#ct/! WI?':]q>]ଛ0ުQp6FAveǞN=F ^ p2W.?QR;jhۣqۣ֗YH1!Ր'?yk:8B=8G8Ph"F;EbAz&(т* 2w &zU%e:#Keyҵ+=~p*n+w%ݝ,r78k#=ͥ 0?1z@Bjdþ}L>kk!nW>/J ^!jry0XHTUZ}Oh3bMFm)-"oU]oFfK\à^n53X*G>5Yo;o$-ډ^,6 cgk/};v^(Jc0潢`l,'b`v 1EzqD=])V[s(2E?I,z_APÕ _WcK}qL O3oJjĸ[G0/fԅTor ,N4{*5T^qx'%~#]se]\PS!L[v0:Fo+[XͶj`F^<}~MTBo]6h(ֻ*.SRT/8&"/MSSe 9.W#=wJJ`am##ѩRz3 t-T |fr@kNtUshFDI~귛 dfK|VܷYn|BF"/վ'Ӓi,@-C#N}j_af- V4`z-G_nmj2Y!=V6S} ZlueQ6!s`}w roO~]cT6>-sN91ugΉ74 =q;[ u#]yAmGzm/?BzXWO81If==5 /'{zMf٪{YDLcIJD3TC*ũF/U;{T-q;P&<`:PDI<~x%󿷕^a'/[yr( c}zoDu}A ۣv8.Pzp[!q@UiL=\Sͣ8F_*R7mT2*RIeY%?jbttIƚ0֫ |S)qz-uYjdj:5NMFsža ,gp!$tDWmXXrgSX^&nȗտ29Mײ8*A~'iO%<=y\N:Iz@AF~,_ WZP dRhQxRϳą+wv1rBF@@tAHzZo -5>y'VGBØc̨o].tp zƓ̂#9@X{[Ip}c8ܛRpunY"xT#7;ϊwD2 4 I,PSP{ H m!syDc` 8Ѷ'81u|( _+)ԋ[ݨD'_089pY -.*^ i%e#Ϋ s#՞9'T];ԓM*ܺH${*tV-[Y,-w|l;Pm4R9N3MshŘ1U.Sn"w`dqA2ۣWpoI6?6Z7=[uKe:ʨ֭ P_FS!M#w"FGxiAQ-q.V;j,*{%M4tyOvw~PI)4їЪ )qK|Al&,#%z1vyw%GQQ_al[iô> YQ,4PW 27คO1Bp;~h:D/cV!"-yʾq^h[n;ƲZ--=1E>4৲+풳NJcS;'a!h/`w A}4%[G*_al;X@r &h8-;vĕP;]SۖLPGM |F׮%Ho].tpbUۗm[szu/:_|\wNb|v&5cz1A`σQ\,#u_T85(UY4qTL+ϗiD"iN d| xL?@y)Go/Odz$ K{0_49I s b;Eb8)*f*+M$c" G20%Ȁa=9O8iQŘi앆qZ1gȑEɈz 2iu yUn2'^F2zT%ʤ(+J[!L&cGAM!YQjj @@tt%.|u89 r*^[gK\w0ʑ!"|"Q{{s" Kpi̔%7 U_*rD޻R_7&D=aP6WܭVV9m٘7C|J3ZU^8)L85tχd= P\n!5ӕ;@,[Mgӥ|yހN5HLh^P)d@YF+A*ءݟIc+ =hLFKa:"lf;u߃X҅o?atʦ 5(fI2eI"_o89@Z& {IO-2x{\hǁxA(1R8v {',e6 hRi:.vHĄ9t+ZoAyi:I&=K%NnrfB &Qq6c~~^sޛ/ʜ>W[ctpzhHOI+_PcMse=Es#fqIO![5qȀscH JǷfnؤ1yb-ةӰ%H_lR^va twoQ{Gv hPi4@`FMl;उx.W_Xvlh+9dTjټUw9(*Z fS]dT*Mix ׄQV sp7&𷾎)҈ :- X ~MNes_ߓ)ӆTNRzxq:o]5L6>2BQzn^gw|sC+P9"\@؁2u)BzztNW "arrIcpVXRF9wc ikoB L@A&4,\&y{OOp ^5@u_ R\iU'M妸1A ip}B\_KJsDZlPd@"L y;v&Wx^ܾUzk˝00/(<=Z$B/ƃ;2F GAO X G\z7nW2"py{s,hot&yygBUrqm<'oI181@L`!E1Ae~L\qOHYU)D3ď>HEB&^XH6[\Ͷy'j'5߱`0~\2#TFK&]gK8MxQuL!!}1FgC;jBORsbBam,m]nHn\lr̍(Sɽ&QZoG**P 4emdo,3UC*dɕd~]nS2ݼG~q7|$W27!U2HZʙP$WIYR{*@ǐuە՛l0|2bӑбLOCyOVեsʉ=L*(HK%'<ga aF")Is piGPmeRG2խ9\nVf:Z﶐Rbפ (J {9Vפ{֜}:xxЄkTb>ʹ|CV+.~b$[ԐNJXgL$F۞qH$^U]=^:m e6z P ECRs纟E5~e_?%~)?Er{0xG={tyalfPԊ?u_+X7_awݳp2F}b0:Zz(i)Yz =к`rٛLxddнCzA.qsh-[;̣BzWb8Y?6KuXA G&2|1uol>SNMOnY| 3$ ӴJty,d2cOsslZ0|߸m4IѶG?xnzWt$["H PK>.ӡRhCD*yh%2Z{^y±WY[6r4Fua3 )ECĿ= Lhn%}l]d!Z3ܲgn>q=F \@/3-Kύxֿo˔g|T&=7F K,Ej*ՂOq_Oc^ 1Ez;@#tc;}RJu  [`aУf|f3]Ch;*.:'pˇ-~'1M?M<-l(X/"Su/jݡ%Ș1Tmexzd[Evhc'0OŎd@l&/省FO8wԾ{|@&|{7g?mc=8z)[ &w'Z޵#pʮ]#'l < sܹ>0dno[\v=iĝ$f +z{?u"1KGJY׿U7oo[ 0s⢬taݱ$x|pxBYq)hdz6O' S~9ov{ed:u&]LCnAO ?r$ps'}m[[ٳmr'O*8h};ٽI!kͽ{\zbS Y[ <75Ca#ÿ8I/dbj؞&l8:s*e{vWTƍM4 ݦ}6Ք@zu&sJDKJ x.&wcO?ph^/ިxne4᭪K5fZwqUO4s 7lc0%hۣ]+8>Gos]E)jZDhs/<7Fk67?uUEqq0r)'/h}Ľ ΊMMCQiw7={n ?XLw {í֑/=qt-еѕgͬcju_Vز8ziR$@B1@&2 9t=|Bc<ތ|Izj'aI2$KGuvR@E[ 1AR]FKpxE~zN7Ę\HҺq/m d`CFC*/mړ' =Q _o믜nȘC(d>JL4;>!-+ I \z'70| N'g`=>M2n˾?G.NԾ]< Ku|rdOMzgω>E,o@SmI |eFt1DP:!4mO/F'"_w~L.1瘼'#׏=:,E2Q`8֫=[Qv0E' PNj,MU `Ÿj ‘f{k_LH9syʹw?V #>N^י,΍|\QBӳz{|D,ɣj9+11Ȏo㲓rvLzj6:oK}]7*-Dc8M2ѭ6K[Q1:acm'?iހf3jȶ#"p2ytŊh.xnh HQ Kխyd֓/jx/}xw}Gl*HzlrkF鈡\Ѷg\0cM)Q;2b$R4i\?7dLgϹxp Ü'b`KBz"t3p2yTX0hH563e:~\n~]3=N!˾`2/]E2QsȘ̨r1Kx{ RR'[rB[E<[[[? }D× W>&h.R?6lE.>抍+ %T'eKz)M;(0[h#iQzni"b' $ {, NNsڧ?|>H丣RpAZ.B M@հkUcܹ Ƽ^;;9[lvC( ͭu㴸pEFsvЬF'_.; ȶ+ ?m2*w^?RK92i v\iT3)K 53oRZ{? 9[f>]+}ky~mmy' p}پC.himLǂ)%p+ݾMvP%7B*vc)GFr/.'vɤ87$OpּGfۀk,wMMvjOz,7ߎc痹ZVٛX\/ʔY7sx.oNFfp#T.>/*UPQ0e``0IDAT1M}kW$wK .&jh6?Ӈ^|e \Uu$$g坉5{F*331PGj//!|L^Z8Gˑ5 9J5"3V>`zT@Sjf9cXo ?kgE<6qo;4ǒGhl7nG}QKRr#Yq%ikI6^2޲AO_vֱV)B"roP+dV;Wf AG_˚Mz܍)ٚY @Llk2Fۯ+3Ap'C3`h[MG Bz\&$:_숹䡈J;? έ7Z1!eLnSl1EH8 _-[m)Kj<'䝪ɓô|l@AF\a)`2wn8_{2J*5^<ނ@ ]\ RsNgv7֭,L!'t#Ghp%]փpKѺ|zB:6zWo|{9adlǤ HzvJHQW.`7ANRL9c܁$#uUߒ{w HWu1K Xw5laT\Q=aK2Ѓ]wsjŎ #=qȼeai(0?B:4GvP!c`dsGt.1eUAn 25.қMn`@6\z@64U6x2WlmW+:idݜ]씐>UJ\f;Ic+[Io4{w(A$g93/I*cr. a%e_&tSXwZUet-] d n*ByWC5ÁfB:X bѶ'ۅ2z3O{˯|V;a,׻iƎ F(wKpVYAyedQHrZ%hX/i[ñ[񧟜\jmeZfWŚh9fnjխZ%&s3kFWl֜ëJцG[Xv~^{W0\r{!5N \+e41r}n젝,XFPyTuML|nnuL)GCIϏ߿șe^ۭ6t6Yȼԯ0|TUW΂q!P!# \Fgpr ` Vo?㊟󸵵}z;Ʒݰc@6 G2E3iDN"+!0۞aZk,P|L! 2o} tqx/ ooܲvK¸~8Yeb j٤cLJJ; +AP7@&Cх0@zΕ]_zOD&i 5 +,\&oy{~ ݎv d9G䩵%.|?WK|n NT^ʄG2Ѓu4stp4ԗE vDW|d{7:\b dlo֝ǭ4Gou- _vQowe=e2yTy)._tF #rB 7D>Sэp` >=sIh+4EgLXaLA'1-/\$9 ;YcPx{KTNcD4%gaBSrt;\&4>6׭yd7ſ1{r <}[;~7e>V`G)P v*+X^ɄTl;gjfb@ P/rBx[n?;f2уld'6Vf"CC&,\:/BA0@61N*^̯[~ٲGqwe2brqQTiL(n%xN.eL>Z%c@H36υN \cSU>skI򦕒4Ry{\ YedF&9ZzG\YbWGC7s[y?FqY#v <w`XQ6~@ld423U)#&wPG3Rˠj?PAwQ}t˽t[ft;yBEomõ6ߖҎ (ep62уqQ| ŭOkK|R= ssƎ<(? d+.ڋG vWK趇E9h՚oHW(,G: Bf>C|MxuyL ,=-z5}sG[dCh0h,JK F@*`]=P}itf㘗~Ac0hC\3Vy56<92 /RR\ybL3p_aP-Ɨ;ZXYIkg1j@o Z~/ yi6>]g`L_&BO94:.ɶ|Ku뽕/aEJ=6m9 ̭U 4 -ʘЭ1HQd]3rF|j>ɢ9QQ9aP6Y-|DŽNX?S;2JE\z!sK7 ڔ`Hd<))Rpb[:gb~ᚏAu󿰗]A>H#/` 3grCgS:lf;t+b,)FiNsd1N{q,~r8ʚv¸_1|?w@ʖ+v HMREȀ%VtI$O"JzaюNyn;PE0n!'8V<&^aLkZr̥ Y`2: ',]dp$̻н94\kwOv ZO`9'TYzLOפc4(6q<8PCH^ xxJD;VNK0-s^]^+Ԑ=U 9[-d\A8d¥.txJhfc7Y!հ7O;Q+X ;~zJ=l^Z>ZE#b.phR('eTi)a#vNXJ|z[:Q~;~-m7 3M<빇砦Ä\5"fÙO<9Zw#|;c+ ]o|W+v/ZQqC+צ4tDp PK /[Lht>p+"#@ vDW}Ak K>p4c3rX b%Cv]%:{usݫ<~HvOT]ܫէæ\|#Ҧ1(p\|Lzcsb . Yo+W-.2=)몳ᇰ.?]U6'|a.]\. .ZcǓnW2"qi:)uMNQl.u|̓o?gy}\[j/D *2'0&Yٺ+bT}1eI).G+Ohz!ǝjdn7&"޵@7=\+0ȉj;"+&,K6i=: |d !C8@Idxכ_}ŋ_~7,2 *9㈰ R$I 2#V+E7:\V$#S/e[_[$h~bCt#\}OU s' /V@c$2o}WYKNMZ4.9!+Ako|}nw_ꘟ};l`b0'PwDWj2U;Y2IaCP 8$9ndC黟w6Q' w~ _[%M.zNeyu6Z#syCs}v+ z+]Ȇ [=&}l9AL-A_%FK+[,w~_Ϲ㮣<̧q?q^}[tߩjFĎp%7v="9un-\v))&ܽcˍQ,)8˽S';P]vVmiou(>ťtچ2=iM2,ZtRa?㿎7cTh: 3xً=?8vvSw:aKtԪ(F}'ܑhOv' ImګHv#vީ' /ǟ6Xzp;n6Hel#5t" R{JQ.mvmOȡxG~@~d=vꊕ_g{|{('e2`RPL7W sxchp5*^Z^>飿Ht䶳LdAɣ10/1rslw??Y̙#{̟0h?xݷ?o0ѦC2]·r 9qнGr{[jn;t8]îitwx/&Zo.8N ,H4?Iov^Ÿ,><[p;}]}[H:0l!v\zJ=xI^'75÷51\cy PhUZ]A@?w?̙ϝٝOr<͝{?<;ѕx;ɻCEk..Q: G *c<xkj2z q sRD_Jc:]"Mω|SukHor#LEvMt9,c+N1Զk(6~\>;}QnGnI\zk;A`Uf̓`yj nAbA[a `h~2;տBJ37yfhrʣQXX3掸FMh Opp3kG=3j<=4썍+/I* Ri*%3o;tut[t,j rv?q*$zFzߙN#N1fQp[ H!@2V+# -k4t):i}Fp/͍R]jhSũnB RrAVN#F[Tw\t<Oc`H2w|:?b#Dʏ)B:-4MBZYZ #U:zvtk}uR4ǡ&CW8)èH Jt14ҽh4f!#4uwuƁm/N&  ' .1'T(ڈi).@9N.|4 Fhc):,}x口Dhp#-mbIv:ULNB^٠X9 RQ!i|+!IN ;)j$(LYH I]5-tԏeɇT:C[rBn@I(U Vm~IUm# eqK 'cL/mV/ \=XaUqZWQOۍX4M;.?wOuf!FLYm4 %E|&(FIu+(t&&0 M OQȻ~) nwttdkSK)i( -g^'7@$[Z{)pAG`ǺGa]8^<}yf#'hoҾ4TaA0)-RD4M)CɌiA y-cffhx}ҚPJ,쑲yUTUDtk},\Ѩ{͎@S0v :_L~W2.&B|HREvAWyz3h0Hl(iuyK5ySx|U\Uq {ᬩt|+@(l;mMkFL%S0DnR("IDWJZ&_.%WesFZ! iyjcGOw@7TA!-suWjx4_]Xuq&48LaWإqD%WYKUa1L |C7 Q)(l(9"ڕO[0?ٶ#5G` tw:q:kvښf0(Щ`NKhqȣ@d+ʐ`ȍ rQRh60 oZgW_+m 7Fi ̚bzI.zj 4XKͮKчf%_nfy@yvj&GeU5`pUI~z}0C $e:+dx{NvGݍTS.$To&NwzWu^N t#F )ƏX>]:Gp׀x.u!]>~q!ywT(MެRo[r,ll6?AGNsbA{-yTo휼 ~rCkW9k+ɆPO`vA/:YgSg7ÝS_Ə%}[]Q=9YZI ~.80i F \0*3gʲy+7~w܂{pB[ɞT^yښR ތ$f+W n|, Y Pred|.!B|ã)wuwfrApF` cy&Yyx>InE9FjFd=6<8$a}[|[9THXKo]2 X!\ @Rvw->{ڝ҅aA F.t' b8Nljwz n8TbGew}SS#cvAw1@{XT./rϗ>ui yipK: k|+kzui?n#` X8ߑÛ wa;/6F`SxP}`Z{Gq|.#P3` &W;P8:&B =8 n&)M]Zq4>\0 ! (w/{b~}C1&M |E}(dp>~rmSn[|濱fLJ/2cҎPd!!cHLV܀?nl3n```(1zlƹ0 ?3. 2 ~8'eqcvƌ4؆`F`F`F`F`F`F`F&j'‘U]IENDB`././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_static/specreduce.css0000644000175100001770000000042214635037352020464 0ustar00runnerdocker@import url("bootstrap-astropy.css"); div.topbar a.brand { background: transparent url("logo_icon.png") no-repeat 8px 3px; background-image: url("logo_icon.png"), none; background-size: 32px 32px; } #logotext1 { color: #519EA8; } #logotext2 { color: #FF5000; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1028733 specreduce-1.4.1/docs/_templates/0000755000175100001770000000000014635037364016344 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1068733 specreduce-1.4.1/docs/_templates/autosummary/0000755000175100001770000000000014635037364020732 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_templates/autosummary/base.rst0000644000175100001770000000037214635037352022375 0ustar00runnerdocker{% extends "autosummary_core/base.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_templates/autosummary/class.rst0000644000175100001770000000037314635037352022571 0ustar00runnerdocker{% extends "autosummary_core/class.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/_templates/autosummary/module.rst0000644000175100001770000000037414635037352022752 0ustar00runnerdocker{% extends "autosummary_core/module.rst" %} {# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/api.rst0000644000175100001770000000101714635037352015506 0ustar00runnerdocker.. _api_index: API Index ========= .. automodapi:: specreduce :no-inheritance-diagram: .. automodapi:: specreduce.core :no-inheritance-diagram: .. automodapi:: specreduce.utils.synth_data :no-inheritance-diagram: .. automodapi:: specreduce.tracing :no-inheritance-diagram: .. automodapi:: specreduce.background :no-inheritance-diagram: .. automodapi:: specreduce.extract :no-inheritance-diagram: .. automodapi:: specreduce.calibration_data :no-inheritance-diagram: :include-all-objects: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/atm_transmission_secz1.5_1.6mm.dat0000644000175100001770000063672014635037352022474 0ustar00runnerdocker0.900000 0.948654 0.900500 0.942270 0.901000 0.947468 0.901500 0.946108 0.902000 0.941138 0.902500 0.944661 0.903000 0.956764 0.903500 0.978545 0.904000 0.987198 0.904500 0.985155 0.905000 0.985933 0.905500 0.983675 0.906000 0.980373 0.906500 0.967384 0.907000 0.943643 0.907500 0.936187 0.908000 0.947027 0.908500 0.948955 0.909000 0.954411 0.909500 0.960169 0.910000 0.955615 0.910500 0.950850 0.911000 0.957920 0.911500 0.968951 0.912000 0.960049 0.912500 0.962144 0.913000 0.951225 0.913500 0.932353 0.914000 0.942717 0.914500 0.969754 0.915000 0.965365 0.915500 0.932753 0.916000 0.937585 0.916500 0.969009 0.917000 0.970596 0.917500 0.948742 0.918000 0.949352 0.918500 0.965726 0.919000 0.975516 0.919500 0.976791 0.920000 0.980078 0.920500 0.988850 0.921000 0.987226 0.921500 0.981262 0.922000 0.979548 0.922500 0.985318 0.923000 0.986866 0.923500 0.984321 0.924000 0.980954 0.924500 0.978778 0.925000 0.978388 0.925500 0.982463 0.926000 0.983853 0.926500 0.984372 0.927000 0.987250 0.927500 0.977302 0.928000 0.957896 0.928500 0.950821 0.929000 0.949588 0.929500 0.936239 0.930000 0.912281 0.930500 0.895657 0.931000 0.871601 0.931500 0.836746 0.932000 0.796466 0.932500 0.784504 0.933000 0.791712 0.933500 0.778925 0.934000 0.730238 0.934500 0.689957 0.935000 0.748015 0.935500 0.756215 0.936000 0.724900 0.936500 0.771703 0.937000 0.754404 0.937500 0.751159 0.938000 0.763841 0.938500 0.779592 0.939000 0.846616 0.939500 0.916115 0.940000 0.918993 0.940500 0.902259 0.941000 0.889363 0.941500 0.881720 0.942000 0.883934 0.942500 0.846681 0.943000 0.785517 0.943500 0.814545 0.944000 0.775153 0.944500 0.749129 0.945000 0.842947 0.945500 0.847050 0.946000 0.793236 0.946500 0.813635 0.947000 0.860710 0.947500 0.867957 0.948000 0.836124 0.948500 0.831939 0.949000 0.887025 0.949500 0.837512 0.950000 0.765804 0.950500 0.804802 0.951000 0.899172 0.951500 0.898838 0.952000 0.828835 0.952500 0.814234 0.953000 0.860126 0.953500 0.894153 0.954000 0.882984 0.954500 0.849349 0.955000 0.859827 0.955500 0.865675 0.956000 0.861372 0.956500 0.858717 0.957000 0.855468 0.957500 0.904725 0.958000 0.905174 0.958500 0.880795 0.959000 0.859772 0.959500 0.853298 0.960000 0.893632 0.960500 0.912352 0.961000 0.920746 0.961500 0.934287 0.962000 0.916878 0.962500 0.900972 0.963000 0.926794 0.963500 0.938201 0.964000 0.909834 0.964500 0.906022 0.965000 0.925492 0.965500 0.953079 0.966000 0.945531 0.966500 0.926942 0.967000 0.939247 0.967500 0.963107 0.968000 0.970026 0.968500 0.969073 0.969000 0.982198 0.969500 0.985010 0.970000 0.977449 0.970500 0.973962 0.971000 0.981516 0.971500 0.977721 0.972000 0.974243 0.972500 0.973712 0.973000 0.972839 0.973500 0.963881 0.974000 0.953921 0.974500 0.955559 0.975000 0.956370 0.975500 0.954694 0.976000 0.952368 0.976500 0.960257 0.977000 0.976785 0.977500 0.983021 0.978000 0.975044 0.978500 0.970744 0.979000 0.973373 0.979500 0.970194 0.980000 0.972061 0.980500 0.976089 0.981000 0.987769 0.981500 0.991617 0.982000 0.989496 0.982500 0.985568 0.983000 0.985701 0.983500 0.991358 0.984000 0.994686 0.984500 0.993137 0.985000 0.991633 0.985500 0.994589 0.986000 0.997970 0.986500 0.998532 0.987000 0.997169 0.987500 0.996260 0.988000 0.997617 0.988500 0.999203 0.989000 0.999440 0.989500 0.998697 0.990000 0.997875 0.990500 0.998411 0.991000 0.999130 0.991500 0.999395 0.992000 0.999422 0.992500 0.998854 0.993000 0.998370 0.993500 0.999084 0.994000 0.999641 0.994500 0.999782 0.995000 0.999814 0.995500 0.999674 0.996000 0.999664 0.996500 0.999777 0.997000 0.999731 0.997500 0.999677 0.998000 0.999590 0.998500 0.999655 0.999000 0.999624 0.999500 0.999449 1.00000 0.999452 1.00050 0.999674 1.00100 0.999647 1.00150 0.998836 1.00200 0.997946 1.00250 0.998486 1.00300 0.999449 1.00350 0.999617 1.00400 0.999258 1.00450 0.999361 1.00500 0.999567 1.00550 0.999433 1.00600 0.999526 1.00650 0.999679 1.00700 0.999666 1.00750 0.999518 1.00800 0.999270 1.00850 0.999172 1.00900 0.998637 1.00950 0.998235 1.01000 0.998769 1.01050 0.999405 1.01100 0.999681 1.01150 0.999602 1.01200 0.999323 1.01250 0.999492 1.01300 0.999763 1.01350 0.999849 1.01400 0.999809 1.01450 0.999670 1.01500 0.999663 1.01550 0.999578 1.01600 0.999730 1.01650 0.999822 1.01700 0.999707 1.01750 0.999713 1.01800 0.999864 1.01850 0.999851 1.01900 0.999416 1.01950 0.999160 1.02000 0.999603 1.02050 0.999814 1.02100 0.999849 1.02150 0.999711 1.02200 0.999722 1.02250 0.999716 1.02300 0.999454 1.02350 0.999075 1.02400 0.998936 1.02450 0.999573 1.02500 0.999873 1.02550 0.999826 1.02600 0.999803 1.02650 0.999840 1.02700 0.999711 1.02750 0.999519 1.02800 0.999688 1.02850 0.999762 1.02900 0.999815 1.02950 0.999908 1.03000 0.999946 1.03050 0.999960 1.03100 0.999918 1.03150 0.999883 1.03200 0.999949 1.03250 0.999990 1.03300 0.999977 1.03350 0.999966 1.03400 0.999988 1.03450 0.999999 1.03500 0.999999 1.03550 0.999987 1.03600 0.999960 1.03650 0.999907 1.03700 0.999857 1.03750 0.999883 1.03800 0.999949 1.03850 0.999970 1.03900 0.999952 1.03950 0.999942 1.04000 0.999944 1.04050 0.999959 1.04100 0.999978 1.04150 0.999992 1.04200 0.999999 1.04250 1.000000 1.04300 1.00000 1.04350 1.00000 1.04400 1.00000 1.04450 1.00000 1.04500 1.00000 1.04550 1.00000 1.04600 1.00000 1.04650 1.00000 1.04700 1.00000 1.04750 1.000000 1.04800 0.999996 1.04850 0.999938 1.04900 0.999708 1.04950 0.999489 1.05000 0.999585 1.05050 0.999812 1.05100 0.999888 1.05150 0.999833 1.05200 0.999792 1.05250 0.999806 1.05300 0.999850 1.05350 0.999895 1.05400 0.999930 1.05450 0.999956 1.05500 0.999975 1.05550 0.999986 1.05600 0.999991 1.05650 0.999991 1.05700 0.999987 1.05750 0.999984 1.05800 0.999975 1.05850 0.999968 1.05900 0.999953 1.05950 0.999961 1.06000 0.999953 1.06050 0.999954 1.06100 0.999937 1.06150 0.999924 1.06200 0.999833 1.06250 0.999689 1.06300 0.999630 1.06350 0.999551 1.06400 0.999452 1.06450 0.999223 1.06500 0.999143 1.06550 0.999265 1.06600 0.999358 1.06650 0.999460 1.06700 0.999320 1.06750 0.998738 1.06800 0.998397 1.06850 0.998842 1.06900 0.999116 1.06950 0.999013 1.07000 0.999058 1.07050 0.999346 1.07100 0.999615 1.07150 0.999471 1.07200 0.999014 1.07250 0.998782 1.07300 0.999174 1.07350 0.999633 1.07400 0.999161 1.07450 0.997460 1.07500 0.997703 1.07550 0.999305 1.07600 0.999643 1.07650 0.999299 1.07700 0.997739 1.07750 0.995892 1.07800 0.997439 1.07850 0.998967 1.07900 0.999435 1.07950 0.998522 1.08000 0.996039 1.08050 0.995377 1.08100 0.996175 1.08150 0.996278 1.08200 0.997916 1.08250 0.999084 1.08300 0.997164 1.08350 0.993476 1.08400 0.994690 1.08450 0.996819 1.08500 0.997534 1.08550 0.994862 1.08600 0.986948 1.08650 0.986943 1.08700 0.993688 1.08750 0.996690 1.08800 0.997774 1.08850 0.996961 1.08900 0.994510 1.08950 0.993157 1.09000 0.991080 1.09050 0.989124 1.09100 0.994849 1.09150 0.998258 1.09200 0.993379 1.09250 0.980956 1.09300 0.982794 1.09350 0.992623 1.09400 0.994362 1.09450 0.989816 1.09500 0.987046 1.09550 0.986598 1.09600 0.982533 1.09650 0.989097 1.09700 0.994809 1.09750 0.988697 1.09800 0.983299 1.09850 0.984920 1.09900 0.981452 1.09950 0.972369 1.10000 0.972351 1.10050 0.977640 1.10100 0.977123 1.10150 0.977883 1.10200 0.971043 1.10250 0.968623 1.10300 0.970545 1.10350 0.975563 1.10400 0.970007 1.10450 0.963794 1.10500 0.973415 1.10550 0.971069 1.10600 0.958290 1.10650 0.956328 1.10700 0.973571 1.10750 0.975610 1.10800 0.955917 1.10850 0.945755 1.10900 0.956992 1.10950 0.969107 1.11000 0.966012 1.11050 0.939959 1.11100 0.920135 1.11150 0.925545 1.11200 0.948692 1.11250 0.933251 1.11300 0.876186 1.11350 0.851763 1.11400 0.889769 1.11450 0.910296 1.11500 0.841800 1.11550 0.817737 1.11600 0.789890 1.11650 0.686181 1.11700 0.699684 1.11750 0.783042 1.11800 0.833176 1.11850 0.788880 1.11900 0.720396 1.11950 0.728391 1.12000 0.757344 1.12050 0.779253 1.12100 0.815802 1.12150 0.748593 1.12200 0.625861 1.12250 0.579093 1.12300 0.686282 1.12350 0.703119 1.12400 0.724877 1.12450 0.818729 1.12500 0.739023 1.12550 0.575220 1.12600 0.623246 1.12650 0.750044 1.12700 0.792277 1.12750 0.721815 1.12800 0.708645 1.12850 0.743655 1.12900 0.732202 1.12950 0.691436 1.13000 0.704174 1.13050 0.828487 1.13100 0.910727 1.13150 0.912520 1.13200 0.886162 1.13250 0.842981 1.13300 0.782162 1.13350 0.667562 1.13400 0.569252 1.13450 0.425347 1.13500 0.430525 1.13550 0.638204 1.13600 0.726293 1.13650 0.826607 1.13700 0.907367 1.13750 0.875251 1.13800 0.848953 1.13850 0.836608 1.13900 0.897902 1.13950 0.908410 1.14000 0.857842 1.14050 0.844483 1.14100 0.809568 1.14150 0.820806 1.14200 0.854212 1.14250 0.892016 1.14300 0.918704 1.14350 0.869072 1.14400 0.761278 1.14450 0.729615 1.14500 0.757038 1.14550 0.768671 1.14600 0.772257 1.14650 0.719294 1.14700 0.680704 1.14750 0.730166 1.14800 0.853410 1.14850 0.870374 1.14900 0.825745 1.14950 0.776315 1.15000 0.763452 1.15050 0.841766 1.15100 0.853065 1.15150 0.852384 1.15200 0.817911 1.15250 0.766774 1.15300 0.821260 1.15350 0.864742 1.15400 0.826659 1.15450 0.847765 1.15500 0.885408 1.15550 0.868207 1.15600 0.874482 1.15650 0.913144 1.15700 0.924995 1.15750 0.900897 1.15800 0.897519 1.15850 0.915011 1.15900 0.906591 1.15950 0.918299 1.16000 0.911739 1.16050 0.907733 1.16100 0.936403 1.16150 0.949203 1.16200 0.944764 1.16250 0.948642 1.16300 0.972327 1.16350 0.969878 1.16400 0.969258 1.16450 0.974017 1.16500 0.958576 1.16550 0.945447 1.16600 0.950553 1.16650 0.961556 1.16700 0.966523 1.16750 0.973922 1.16800 0.973221 1.16850 0.972920 1.16900 0.978206 1.16950 0.980222 1.17000 0.981184 1.17050 0.976008 1.17100 0.976547 1.17150 0.982596 1.17200 0.979140 1.17250 0.974704 1.17300 0.974501 1.17350 0.958697 1.17400 0.938513 1.17450 0.958885 1.17500 0.975557 1.17550 0.975021 1.17600 0.988260 1.17650 0.994002 1.17700 0.980372 1.17750 0.949508 1.17800 0.949525 1.17850 0.972612 1.17900 0.981544 1.17950 0.969594 1.18000 0.975340 1.18050 0.987625 1.18100 0.977929 1.18150 0.941932 1.18200 0.916442 1.18250 0.949461 1.18300 0.982671 1.18350 0.986757 1.18400 0.969196 1.18450 0.951621 1.18500 0.956697 1.18550 0.978990 1.18600 0.988531 1.18650 0.985182 1.18700 0.976861 1.18750 0.954704 1.18800 0.939069 1.18850 0.951637 1.18900 0.971985 1.18950 0.982253 1.19000 0.984752 1.19050 0.980359 1.19100 0.981037 1.19150 0.985026 1.19200 0.987986 1.19250 0.991293 1.19300 0.983971 1.19350 0.974746 1.19400 0.984188 1.19450 0.988584 1.19500 0.983569 1.19550 0.980270 1.19600 0.982935 1.19650 0.987270 1.19700 0.986618 1.19750 0.978813 1.19800 0.980855 1.19850 0.971897 1.19900 0.961843 1.19950 0.974741 1.20000 0.983190 1.20050 0.981964 1.20100 0.978773 1.20150 0.973377 1.20200 0.974917 1.20250 0.985326 1.20300 0.977496 1.20350 0.944434 1.20400 0.936448 1.20450 0.961981 1.20500 0.968605 1.20550 0.981381 1.20600 0.989106 1.20650 0.982717 1.20700 0.977013 1.20750 0.976124 1.20800 0.976634 1.20850 0.978362 1.20900 0.976562 1.20950 0.977756 1.21000 0.982973 1.21050 0.989250 1.21100 0.982825 1.21150 0.975368 1.21200 0.980099 1.21250 0.985002 1.21300 0.991563 1.21350 0.991791 1.21400 0.985006 1.21450 0.981860 1.21500 0.983106 1.21550 0.988560 1.21600 0.993286 1.21650 0.990601 1.21700 0.990397 1.21750 0.993539 1.21800 0.990053 1.21850 0.986350 1.21900 0.983398 1.21950 0.984957 1.22000 0.988633 1.22050 0.991860 1.22100 0.992328 1.22150 0.986436 1.22200 0.985590 1.22250 0.987027 1.22300 0.988197 1.22350 0.988667 1.22400 0.990009 1.22450 0.993038 1.22500 0.994105 1.22550 0.994089 1.22600 0.995171 1.22650 0.993444 1.22700 0.990217 1.22750 0.992936 1.22800 0.996877 1.22850 0.997753 1.22900 0.996750 1.22950 0.995914 1.23000 0.996826 1.23050 0.998364 1.23100 0.998967 1.23150 0.998883 1.23200 0.998834 1.23250 0.997977 1.23300 0.996776 1.23350 0.997367 1.23400 0.999008 1.23450 0.999468 1.23500 0.999303 1.23550 0.999318 1.23600 0.999496 1.23650 0.999138 1.23700 0.999013 1.23750 0.999507 1.23800 0.999662 1.23850 0.999657 1.23900 0.999799 1.23950 0.999921 1.24000 0.999819 1.24050 0.999496 1.24100 0.999474 1.24150 0.999785 1.24200 0.999937 1.24250 0.999972 1.24300 0.999982 1.24350 0.999936 1.24400 0.999796 1.24450 0.999773 1.24500 0.999830 1.24550 0.999858 1.24600 0.999864 1.24650 0.999655 1.24700 0.999669 1.24750 0.999586 1.24800 0.998969 1.24850 0.999182 1.24900 0.999223 1.24950 0.998261 1.25000 0.998700 1.25050 0.998587 1.25100 0.996748 1.25150 0.997608 1.25200 0.997834 1.25250 0.994814 1.25300 0.995997 1.25350 0.997178 1.25400 0.992464 1.25450 0.993117 1.25500 0.996493 1.25550 0.991123 1.25600 0.989697 1.25650 0.995638 1.25700 0.991237 1.25750 0.985451 1.25800 0.992316 1.25850 0.990902 1.25900 0.979553 1.25950 0.981838 1.26000 0.983431 1.26050 0.968600 1.26100 0.960381 1.26150 0.963959 1.26200 0.953670 1.26250 0.937863 1.26300 0.940169 1.26350 0.939693 1.26400 0.924447 1.26450 0.920700 1.26500 0.930985 1.26550 0.928900 1.26600 0.919060 1.26650 0.929692 1.26700 0.945111 1.26750 0.945282 1.26800 0.899087 1.26850 0.784339 1.26900 0.758176 1.26950 0.853277 1.27000 0.930262 1.27050 0.957934 1.27100 0.963815 1.27150 0.964836 1.27200 0.961788 1.27250 0.961196 1.27300 0.961872 1.27350 0.967564 1.27400 0.963418 1.27450 0.966112 1.27500 0.969241 1.27550 0.976962 1.27600 0.973136 1.27650 0.973427 1.27700 0.980372 1.27750 0.984600 1.27800 0.985305 1.27850 0.982528 1.27900 0.989911 1.27950 0.992007 1.28000 0.990550 1.28050 0.989450 1.28100 0.993592 1.28150 0.997412 1.28200 0.995688 1.28250 0.993663 1.28300 0.996647 1.28350 0.998384 1.28400 0.997067 1.28450 0.994882 1.28500 0.996985 1.28550 0.999208 1.28600 0.998780 1.28650 0.997108 1.28700 0.997172 1.28750 0.998351 1.28800 0.997678 1.28850 0.995288 1.28900 0.994508 1.28950 0.996863 1.29000 0.998151 1.29050 0.998247 1.29100 0.997249 1.29150 0.994203 1.29200 0.993317 1.29250 0.995928 1.29300 0.997616 1.29350 0.997860 1.29400 0.997272 1.29450 0.997292 1.29500 0.995935 1.29550 0.993070 1.29600 0.993259 1.29650 0.993791 1.29700 0.989695 1.29750 0.988357 1.29800 0.993488 1.29850 0.996987 1.29900 0.995085 1.29950 0.988373 1.30000 0.985354 1.30050 0.982596 1.30100 0.984381 1.30150 0.992523 1.30200 0.994774 1.30250 0.988664 1.30300 0.980634 1.30350 0.971293 1.30400 0.962918 1.30450 0.969263 1.30500 0.987720 1.30550 0.991306 1.30600 0.985716 1.30650 0.968053 1.30700 0.967671 1.30750 0.978376 1.30800 0.971561 1.30850 0.979002 1.30900 0.984302 1.30950 0.962535 1.31000 0.950377 1.31050 0.956719 1.31100 0.976448 1.31150 0.990140 1.31200 0.978798 1.31250 0.966486 1.31300 0.956840 1.31350 0.934889 1.31400 0.939970 1.31450 0.958249 1.31500 0.960607 1.31550 0.962254 1.31600 0.974172 1.31650 0.970949 1.31700 0.954463 1.31750 0.971178 1.31800 0.968766 1.31850 0.946931 1.31900 0.945659 1.31950 0.942867 1.32000 0.918592 1.32050 0.929011 1.32100 0.950730 1.32150 0.945695 1.32200 0.955817 1.32250 0.946827 1.32300 0.926178 1.32350 0.936737 1.32400 0.941362 1.32450 0.956181 1.32500 0.965625 1.32550 0.949400 1.32600 0.957974 1.32650 0.958642 1.32700 0.939564 1.32750 0.937278 1.32800 0.916788 1.32850 0.879224 1.32900 0.878624 1.32950 0.913538 1.33000 0.924358 1.33050 0.907027 1.33100 0.864149 1.33150 0.834164 1.33200 0.830201 1.33250 0.843688 1.33300 0.889382 1.33350 0.871627 1.33400 0.859372 1.33450 0.904001 1.33500 0.918914 1.33550 0.905105 1.33600 0.866219 1.33650 0.897052 1.33700 0.880653 1.33750 0.842492 1.33800 0.866221 1.33850 0.905274 1.33900 0.903538 1.33950 0.903040 1.34000 0.857331 1.34050 0.827196 1.34100 0.874881 1.34150 0.881135 1.34200 0.912678 1.34250 0.918185 1.34300 0.902951 1.34350 0.859701 1.34400 0.738835 1.34450 0.709692 1.34500 0.798344 1.34550 0.816491 1.34600 0.786334 1.34650 0.762971 1.34700 0.768541 1.34750 0.643887 1.34800 0.491810 1.34850 0.508059 1.34900 0.629390 1.34950 0.706715 1.35000 0.576285 1.35050 0.462633 1.35100 0.527266 1.35150 0.509747 1.35200 0.483102 1.35250 0.445504 1.35300 0.356107 1.35350 0.342676 1.35400 0.328445 1.35450 0.197219 1.35500 0.164488 1.35550 0.218198 1.35600 0.276226 1.35650 0.365766 1.35700 0.283954 1.35750 0.194598 1.35800 0.208406 1.35850 0.205095 1.35900 0.199447 1.35950 0.156136 1.36000 0.177611 1.36050 0.153180 1.36100 6.62577E-02 1.36150 2.66995E-02 1.36200 1.51404E-02 1.36250 5.98374E-02 1.36300 0.209144 1.36350 0.297767 1.36400 0.196222 1.36450 6.98286E-02 1.36500 4.96920E-02 1.36550 0.135551 1.36600 0.302574 1.36650 0.337787 1.36700 0.217834 1.36750 1.00855E-01 1.36800 4.70564E-02 1.36850 6.26280E-02 1.36900 0.149675 1.36950 0.198916 1.37000 0.149135 1.37050 0.118841 1.37100 9.56551E-02 1.37150 0.140676 1.37200 0.195606 1.37250 0.283089 1.37300 0.326103 1.37350 0.354299 1.37400 0.386147 1.37450 0.322281 1.37500 0.360891 1.37550 0.453086 1.37600 0.377087 1.37650 0.327164 1.37700 0.320174 1.37750 0.495142 1.37800 0.519425 1.37850 0.294434 1.37900 0.276679 1.37950 0.407687 1.38000 0.299731 1.38050 1.03512E-01 1.38100 0.109494 1.38150 0.214145 1.38200 0.162237 1.38250 6.52233E-02 1.38300 6.09866E-02 1.38350 0.109256 1.38400 0.178010 1.38450 0.220932 1.38500 0.158425 1.38550 0.168395 1.38600 0.233275 1.38650 0.331220 1.38700 0.442871 1.38750 0.345280 1.38800 0.172340 1.38850 0.275885 1.38900 0.499047 1.38950 0.535737 1.39000 0.472701 1.39050 0.478809 1.39100 0.483321 1.39150 0.449178 1.39200 0.237272 1.39250 0.132192 1.39300 0.295937 1.39350 0.433298 1.39400 0.392175 1.39450 0.258722 1.39500 1.01425E-01 1.39550 5.64375E-02 1.39600 7.69295E-02 1.39650 0.126794 1.39700 0.284888 1.39750 0.501226 1.39800 0.592373 1.39850 0.580968 1.39900 0.481826 1.39950 0.249707 1.40000 0.114295 1.40050 6.69293E-02 1.40100 7.63803E-02 1.40150 0.167137 1.40200 0.417217 1.40250 0.602445 1.40300 0.547245 1.40350 0.490765 1.40400 0.338334 1.40450 0.167855 1.40500 0.142995 1.40550 0.336699 1.40600 0.535478 1.40650 0.441941 1.40700 0.209916 1.40750 0.264541 1.40800 0.480982 1.40850 0.469298 1.40900 0.267194 1.40950 0.176476 1.41000 0.328066 1.41050 0.466136 1.41100 0.497142 1.41150 0.517930 1.41200 0.494083 1.41250 0.528470 1.41300 0.670770 1.41350 0.543994 1.41400 0.315460 1.41450 0.215553 1.41500 0.281061 1.41550 0.462164 1.41600 0.679135 1.41650 0.731140 1.41700 0.647579 1.41750 0.573938 1.41800 0.580755 1.41850 0.508240 1.41900 0.292362 1.41950 0.289450 1.42000 0.447425 1.42050 0.533599 1.42100 0.596804 1.42150 0.673366 1.42200 0.744543 1.42250 0.689326 1.42300 0.530980 1.42350 0.431204 1.42400 0.491623 1.42450 0.675004 1.42500 0.674831 1.42550 0.558107 1.42600 0.613803 1.42650 0.753543 1.42700 0.695788 1.42750 0.561568 1.42800 0.504341 1.42850 0.511057 1.42900 0.608029 1.42950 0.705028 1.43000 0.748174 1.43050 0.790472 1.43100 0.613405 1.43150 0.423867 1.43200 0.373470 1.43250 0.385777 1.43300 0.555137 1.43350 0.672079 1.43400 0.582412 1.43450 0.536952 1.43500 0.644952 1.43550 0.689954 1.43600 0.636357 1.43650 0.633261 1.43700 0.588406 1.43750 0.429183 1.43800 0.480450 1.43850 0.686126 1.43900 0.692260 1.43950 0.588509 1.44000 0.660672 1.44050 0.723990 1.44100 0.676157 1.44150 0.617975 1.44200 0.686400 1.44250 0.661564 1.44300 0.628641 1.44350 0.763524 1.44400 0.785264 1.44450 0.759266 1.44500 0.672885 1.44550 0.438539 1.44600 0.472890 1.44650 0.673442 1.44700 0.705155 1.44750 0.771982 1.44800 0.831514 1.44850 0.835559 1.44900 0.856568 1.44950 0.796607 1.45000 0.602390 1.45050 0.417076 1.45100 0.460663 1.45150 0.674837 1.45200 0.740778 1.45250 0.746815 1.45300 0.790204 1.45350 0.875651 1.45400 0.906380 1.45450 0.855457 1.45500 0.740161 1.45550 0.706508 1.45600 0.833406 1.45650 0.890081 1.45700 0.867164 1.45750 0.829506 1.45800 0.862152 1.45850 0.921453 1.45900 0.933240 1.45950 0.903528 1.46000 0.796659 1.46050 0.751729 1.46100 0.795446 1.46150 0.818978 1.46200 0.886126 1.46250 0.854437 1.46300 0.714736 1.46350 0.744172 1.46400 0.885306 1.46450 0.899101 1.46500 0.749455 1.46550 0.696033 1.46600 0.719099 1.46650 0.670840 1.46700 0.677860 1.46750 0.741448 1.46800 0.811650 1.46850 0.882057 1.46900 0.821356 1.46950 0.689987 1.47000 0.681842 1.47050 0.596856 1.47100 0.555473 1.47150 0.693104 1.47200 0.692504 1.47250 0.643489 1.47300 0.730927 1.47350 0.761093 1.47400 0.825224 1.47450 0.926959 1.47500 0.933974 1.47550 0.829277 1.47600 0.768126 1.47650 0.807752 1.47700 0.773674 1.47750 0.737137 1.47800 0.728135 1.47850 0.838802 1.47900 0.856256 1.47950 0.790548 1.48000 0.731276 1.48050 0.698974 1.48100 0.796290 1.48150 0.777120 1.48200 0.738904 1.48250 0.846352 1.48300 0.913145 1.48350 0.922818 1.48400 0.878982 1.48450 0.829555 1.48500 0.866690 1.48550 0.882665 1.48600 0.858853 1.48650 0.794350 1.48700 0.795396 1.48750 0.832984 1.48800 0.842272 1.48850 0.892043 1.48900 0.925376 1.48950 0.895341 1.49000 0.918729 1.49050 0.964423 1.49100 0.923781 1.49150 0.867480 1.49200 0.900942 1.49250 0.930368 1.49300 0.941320 1.49350 0.958792 1.49400 0.955063 1.49450 0.939097 1.49500 0.915747 1.49550 0.911000 1.49600 0.912630 1.49650 0.914039 1.49700 0.951242 1.49750 0.962185 1.49800 0.942913 1.49850 0.953168 1.49900 0.962683 1.49950 0.962687 1.50000 0.976127 1.50050 0.987873 1.50100 0.988915 1.50150 0.978267 1.50200 0.968245 1.50250 0.964149 1.50300 0.952026 1.50350 0.930347 1.50400 0.910647 1.50450 0.921950 1.50500 0.949984 1.50550 0.978659 1.50600 0.990180 1.50650 0.994654 1.50700 0.989170 1.50750 0.984464 1.50800 0.970488 1.50850 0.939241 1.50900 0.940464 1.50950 0.975258 1.51000 0.989160 1.51050 0.988591 1.51100 0.989222 1.51150 0.991763 1.51200 0.989753 1.51250 0.982265 1.51300 0.980492 1.51350 0.978270 1.51400 0.977114 1.51450 0.983816 1.51500 0.989752 1.51550 0.993510 1.51600 0.987815 1.51650 0.981240 1.51700 0.981664 1.51750 0.982419 1.51800 0.986983 1.51850 0.987771 1.51900 0.984376 1.51950 0.988020 1.52000 0.992537 1.52050 0.993898 1.52100 0.996880 1.52150 0.995895 1.52200 0.995165 1.52250 0.998102 1.52300 0.998530 1.52350 0.997494 1.52400 0.996642 1.52450 0.994038 1.52500 0.993946 1.52550 0.993713 1.52600 0.993061 1.52650 0.992550 1.52700 0.992221 1.52750 0.994028 1.52800 0.996662 1.52850 0.996541 1.52900 0.996339 1.52950 0.996204 1.53000 0.995676 1.53050 0.996101 1.53100 0.994965 1.53150 0.994058 1.53200 0.995719 1.53250 0.995789 1.53300 0.994631 1.53350 0.993077 1.53400 0.991478 1.53450 0.990239 1.53500 0.989070 1.53550 0.989680 1.53600 0.991399 1.53650 0.993151 1.53700 0.994556 1.53750 0.996615 1.53800 0.997626 1.53850 0.996225 1.53900 0.994022 1.53950 0.992960 1.54000 0.992898 1.54050 0.992830 1.54100 0.993067 1.54150 0.993408 1.54200 0.993820 1.54250 0.994946 1.54300 0.996148 1.54350 0.997009 1.54400 0.997002 1.54450 0.997351 1.54500 0.998492 1.54550 0.998804 1.54600 0.998827 1.54650 0.999161 1.54700 0.999538 1.54750 0.999680 1.54800 0.999747 1.54850 0.999898 1.54900 0.999957 1.54950 0.999908 1.55000 0.999905 1.55050 0.999869 1.55100 0.999727 1.55150 0.999531 1.55200 0.999232 1.55250 0.999521 1.55300 0.999876 1.55350 0.999927 1.55400 0.999782 1.55450 0.999738 1.55500 0.999903 1.55550 0.999961 1.55600 0.999858 1.55650 0.999794 1.55700 0.999909 1.55750 0.999950 1.55800 0.999853 1.55850 0.999752 1.55900 0.999777 1.55950 0.999810 1.56000 0.999819 1.56050 0.999835 1.56100 0.999836 1.56150 0.999811 1.56200 0.999451 1.56250 0.999325 1.56300 0.999658 1.56350 0.999748 1.56400 0.999556 1.56450 0.999502 1.56500 0.999757 1.56550 0.999748 1.56600 0.999569 1.56650 0.999419 1.56700 0.998895 1.56750 0.997646 1.56800 0.995226 1.56850 0.991109 1.56900 0.984467 1.56950 0.975234 1.57000 0.964163 1.57050 0.952727 1.57100 0.942431 1.57150 0.934682 1.57200 0.930290 1.57250 0.929652 1.57300 0.932669 1.57350 0.939408 1.57400 0.950297 1.57450 0.964999 1.57500 0.979779 1.57550 0.983609 1.57600 0.974103 1.57650 0.962790 1.57700 0.955258 1.57750 0.951500 1.57800 0.950629 1.57850 0.951747 1.57900 0.954432 1.57950 0.958269 1.58000 0.962654 1.58050 0.967323 1.58100 0.972054 1.58150 0.976600 1.58200 0.980834 1.58250 0.984497 1.58300 0.987513 1.58350 0.990428 1.58400 0.992995 1.58450 0.994813 1.58500 0.996168 1.58550 0.997180 1.58600 0.997703 1.58650 0.998076 1.58700 0.998400 1.58750 0.998924 1.58800 0.999493 1.58850 0.999719 1.58900 0.999806 1.58950 0.999795 1.59000 0.999626 1.59050 0.999606 1.59100 0.999684 1.59150 0.999478 1.59200 0.999361 1.59250 0.999411 1.59300 0.999673 1.59350 0.999755 1.59400 0.999421 1.59450 0.999211 1.59500 0.999479 1.59550 0.999537 1.59600 0.999160 1.59650 0.998724 1.59700 0.998103 1.59750 0.997171 1.59800 0.995456 1.59850 0.991753 1.59900 0.985847 1.59950 0.977709 1.60000 0.967902 1.60050 0.957382 1.60100 0.947361 1.60150 0.939081 1.60200 0.933282 1.60250 0.930844 1.60300 0.931917 1.60350 0.936357 1.60400 0.944567 1.60450 0.956796 1.60500 0.972188 1.60550 0.984489 1.60600 0.983245 1.60650 0.972040 1.60700 0.961620 1.60750 0.954897 1.60800 0.951228 1.60850 0.950145 1.60900 0.951139 1.60950 0.953324 1.61000 0.956358 1.61050 0.960237 1.61100 0.964884 1.61150 0.969655 1.61200 0.974316 1.61250 0.978735 1.61300 0.982687 1.61350 0.986299 1.61400 0.989509 1.61450 0.991717 1.61500 0.993204 1.61550 0.994340 1.61600 0.995103 1.61650 0.995492 1.61700 0.996078 1.61750 0.996861 1.61800 0.997288 1.61850 0.997381 1.61900 0.997678 1.61950 0.998421 1.62000 0.998802 1.62050 0.998776 1.62100 0.998729 1.62150 0.998804 1.62200 0.998989 1.62250 0.999105 1.62300 0.999097 1.62350 0.998694 1.62400 0.998469 1.62450 0.999025 1.62500 0.999183 1.62550 0.998587 1.62600 0.998171 1.62650 0.998464 1.62700 0.998196 1.62750 0.997820 1.62800 0.997434 1.62850 0.997274 1.62900 0.997993 1.62950 0.998421 1.63000 0.997172 1.63050 0.994920 1.63100 0.996114 1.63150 0.997760 1.63200 0.997498 1.63250 0.995306 1.63300 0.993580 1.63350 0.995311 1.63400 0.997154 1.63450 0.997027 1.63500 0.993315 1.63550 0.990432 1.63600 0.994459 1.63650 0.996644 1.63700 0.994306 1.63750 0.986407 1.63800 0.986976 1.63850 0.994173 1.63900 0.994776 1.63950 0.991007 1.64000 0.980729 1.64050 0.976942 1.64100 0.986842 1.64150 0.990721 1.64200 0.988497 1.64250 0.976916 1.64300 0.968928 1.64350 0.982052 1.64400 0.991232 1.64450 0.992525 1.64500 0.982766 1.64550 0.967816 1.64600 0.980126 1.64650 0.993557 1.64700 0.994296 1.64750 0.988097 1.64800 0.973328 1.64850 0.972751 1.64900 0.984921 1.64950 0.989340 1.65000 0.989238 1.65050 0.978063 1.65100 0.967990 1.65150 0.981931 1.65200 0.992765 1.65250 0.995613 1.65300 0.991795 1.65350 0.978515 1.65400 0.980623 1.65450 0.993565 1.65500 0.995874 1.65550 0.995054 1.65600 0.991908 1.65650 0.987227 1.65700 0.991630 1.65750 0.997000 1.65800 0.998547 1.65850 0.998189 1.65900 0.995499 1.65950 0.993695 1.66000 0.996784 1.66050 0.999005 1.66100 0.998375 1.66150 0.996868 1.66200 0.994010 1.66250 0.993167 1.66300 0.996674 1.66350 0.997982 1.66400 0.998521 1.66450 0.995489 1.66500 0.971076 1.66550 0.927306 1.66600 0.923475 1.66650 0.952526 1.66700 0.975791 1.66750 0.989480 1.66800 0.994668 1.66850 0.995675 1.66900 0.997153 1.66950 0.998042 1.67000 0.998188 1.67050 0.997299 1.67100 0.995376 1.67150 0.995133 1.67200 0.997900 1.67250 0.999163 1.67300 0.999223 1.67350 0.998118 1.67400 0.992682 1.67450 0.988228 1.67500 0.994055 1.67550 0.997917 1.67600 0.998936 1.67650 0.998614 1.67700 0.993459 1.67750 0.984968 1.67800 0.989630 1.67850 0.997209 1.67900 0.999228 1.67950 0.999313 1.68000 0.997405 1.68050 0.990808 1.68100 0.989273 1.68150 0.995740 1.68200 0.998706 1.68250 0.999319 1.68300 0.998376 1.68350 0.990795 1.68400 0.980805 1.68450 0.988967 1.68500 0.997343 1.68550 0.998664 1.68600 0.998913 1.68650 0.997086 1.68700 0.990052 1.68750 0.988390 1.68800 0.995657 1.68850 0.998457 1.68900 0.998063 1.68950 0.997635 1.69000 0.994119 1.69050 0.985778 1.69100 0.987120 1.69150 0.992654 1.69200 0.994602 1.69250 0.996123 1.69300 0.997699 1.69350 0.995098 1.69400 0.990797 1.69450 0.992972 1.69500 0.996296 1.69550 0.998484 1.69600 0.998157 1.69650 0.992445 1.69700 0.984021 1.69750 0.985571 1.69800 0.994299 1.69850 0.997533 1.69900 0.997159 1.69950 0.994233 1.70000 0.992502 1.70050 0.990767 1.70100 0.988779 1.70150 0.993147 1.70200 0.994740 1.70250 0.991910 1.70300 0.990486 1.70350 0.991295 1.70400 0.993332 1.70450 0.994203 1.70500 0.991526 1.70550 0.988988 1.70600 0.989099 1.70650 0.987328 1.70700 0.986778 1.70750 0.985875 1.70800 0.981381 1.70850 0.972679 1.70900 0.977266 1.70950 0.989928 1.71000 0.992930 1.71050 0.991058 1.71100 0.993445 1.71150 0.996543 1.71200 0.996317 1.71250 0.995869 1.71300 0.995553 1.71350 0.990737 1.71400 0.979007 1.71450 0.976442 1.71500 0.988320 1.71550 0.991714 1.71600 0.986361 1.71650 0.989698 1.71700 0.995886 1.71750 0.997766 1.71800 0.998281 1.71850 0.998016 1.71900 0.998005 1.71950 0.997728 1.72000 0.995841 1.72050 0.988585 1.72100 0.967241 1.72150 0.961070 1.72200 0.981616 1.72250 0.989215 1.72300 0.983622 1.72350 0.971844 1.72400 0.970175 1.72450 0.969362 1.72500 0.978757 1.72550 0.988441 1.72600 0.986625 1.72650 0.987573 1.72700 0.990403 1.72750 0.991697 1.72800 0.989576 1.72850 0.980966 1.72900 0.981130 1.72950 0.991560 1.73000 0.995457 1.73050 0.993014 1.73100 0.990766 1.73150 0.976093 1.73200 0.939757 1.73250 0.941933 1.73300 0.980472 1.73350 0.995811 1.73400 0.996484 1.73450 0.994913 1.73500 0.989011 1.73550 0.973590 1.73600 0.962304 1.73650 0.961789 1.73700 0.973036 1.73750 0.990482 1.73800 0.994329 1.73850 0.994816 1.73900 0.993127 1.73950 0.979801 1.74000 0.973763 1.74050 0.978315 1.74100 0.951173 1.74150 0.940155 1.74200 0.973486 1.74250 0.993695 1.74300 0.997225 1.74350 0.994541 1.74400 0.974627 1.74450 0.957539 1.74500 0.980048 1.74550 0.994150 1.74600 0.978571 1.74650 0.918166 1.74700 0.877017 1.74750 0.922594 1.74800 0.978262 1.74850 0.995971 1.74900 0.996797 1.74950 0.996542 1.75000 0.996631 1.75050 0.992819 1.75100 0.967950 1.75150 0.934713 1.75200 0.961233 1.75250 0.989495 1.75300 0.994754 1.75350 0.997510 1.75400 0.995987 1.75450 0.977098 1.75500 0.936040 1.75550 0.947272 1.75600 0.977622 1.75650 0.954346 1.75700 0.918975 1.75750 0.923623 1.75800 0.968881 1.75850 0.994627 1.75900 0.998502 1.75950 0.998742 1.76000 0.995493 1.76050 0.976922 1.76100 0.952603 1.76150 0.970133 1.76200 0.975319 1.76250 0.948511 1.76300 0.940851 1.76350 0.969066 1.76400 0.991622 1.76450 0.992540 1.76500 0.959453 1.76550 0.834546 1.76600 0.772715 1.76650 0.901742 1.76700 0.980070 1.76750 0.990129 1.76800 0.986865 1.76850 0.985082 1.76900 0.979604 1.76950 0.962794 1.77000 0.950618 1.77050 0.931784 1.77100 0.942754 1.77150 0.981390 1.77200 0.990495 1.77250 0.987907 1.77300 0.984096 1.77350 0.951467 1.77400 0.894844 1.77450 0.907695 1.77500 0.952940 1.77550 0.943479 1.77600 0.884594 1.77650 0.894857 1.77700 0.957899 1.77750 0.974114 1.77800 0.934478 1.77850 0.844515 1.77900 0.832301 1.77950 0.927918 1.78000 0.974862 1.78050 0.948595 1.78100 0.846457 1.78150 0.831929 1.78200 0.931842 1.78250 0.978378 1.78300 0.979546 1.78350 0.958535 1.78400 0.889102 1.78450 0.758125 1.78500 0.738123 1.78550 0.830661 1.78600 0.854463 1.78650 0.886765 1.78700 0.868959 1.78750 0.899529 1.78800 0.959811 1.78850 0.951439 1.78900 0.943822 1.78950 0.969998 1.79000 0.936923 1.79050 0.847680 1.79100 0.819047 1.79150 0.858394 1.79200 0.860120 1.79250 0.835251 1.79300 0.812922 1.79350 0.739816 1.79400 0.755525 1.79450 0.858164 1.79500 0.856749 1.79550 0.841673 1.79600 0.841466 1.79650 0.803639 1.79700 0.784590 1.79750 0.847177 1.79800 0.840571 1.79850 0.885013 1.79900 0.922763 1.79950 0.780291 1.80000 0.584666 1.80050 0.506150 1.80100 0.471652 1.80150 0.512914 1.80200 0.568489 1.80250 0.591665 1.80300 0.677113 1.80350 0.699647 1.80400 0.736619 1.80450 0.830771 1.80500 0.855857 1.80550 0.690749 1.80600 0.438181 1.80650 0.411676 1.80700 0.566936 1.80750 0.610007 1.80800 0.732577 1.80850 0.782688 1.80900 0.726123 1.80950 0.764853 1.81000 0.711491 1.81050 0.489735 1.81100 0.388435 1.81150 0.506124 1.81200 0.510681 1.81250 0.387894 1.81300 0.388558 1.81350 0.579377 1.81400 0.761626 1.81450 0.764149 1.81500 0.537874 1.81550 0.332955 1.81600 0.358867 1.81650 0.495185 1.81700 0.572971 1.81750 0.679194 1.81800 0.647414 1.81850 0.448197 1.81900 0.502743 1.81950 0.529272 1.82000 0.283356 1.82050 0.116465 1.82100 0.180236 1.82150 0.217103 1.82200 0.180477 1.82250 0.254541 1.82300 0.503638 1.82350 0.767083 1.82400 0.841912 1.82450 0.745811 1.82500 0.595845 1.82550 0.484293 1.82600 0.267268 1.82650 0.176834 1.82700 0.368454 1.82750 0.478558 1.82800 0.339694 1.82850 0.171749 1.82900 0.173364 1.82950 0.276971 1.83000 0.240067 1.83050 0.207665 1.83100 0.176644 1.83150 0.227948 1.83200 0.341251 1.83250 0.261043 1.83300 0.258407 1.83350 0.412062 1.83400 0.408319 1.83450 0.219426 1.83500 8.46848E-02 1.83550 6.81353E-02 1.83600 4.97111E-02 1.83650 5.47538E-02 1.83700 8.75217E-02 1.83750 5.25519E-02 1.83800 4.88797E-02 1.83850 0.154729 1.83900 0.245404 1.83950 0.154266 1.84000 5.04592E-02 1.84050 8.40258E-02 1.84100 0.134459 1.84150 7.03485E-02 1.84200 2.09530E-02 1.84250 8.08668E-02 1.84300 0.224701 1.84350 0.273863 1.84400 0.325278 1.84450 0.504203 1.84500 0.597827 1.84550 0.501915 1.84600 0.292331 1.84650 1.03795E-01 1.84700 1.76967E-02 1.84750 5.70865E-03 1.84800 5.19340E-03 1.84850 1.80083E-02 1.84900 8.55736E-02 1.84950 0.206820 1.85000 0.212377 1.85050 0.132717 1.85100 0.228723 1.85150 0.463528 1.85200 0.513124 1.85250 0.312798 1.85300 9.91987E-02 1.85350 2.73874E-02 1.85400 3.10382E-02 1.85450 1.03641E-01 1.85500 0.240103 1.85550 0.348119 1.85600 0.256409 1.85650 9.17837E-02 1.85700 4.44364E-02 1.85750 0.139329 1.85800 0.331460 1.85850 0.386931 1.85900 0.255882 1.85950 8.92806E-02 1.86000 1.56786E-02 1.86050 2.36687E-02 1.86100 0.136774 1.86150 0.388707 1.86200 0.562145 1.86250 0.481994 1.86300 0.365988 1.86350 0.376995 1.86400 0.258770 1.86450 0.144683 1.86500 0.229582 1.86550 0.439161 1.86600 0.595415 1.86650 0.513722 1.86700 0.269665 1.86750 7.28503E-02 1.86800 2.86421E-02 1.86850 8.05517E-02 1.86900 0.106550 1.86950 5.89996E-02 1.87000 2.42958E-02 1.87050 1.71540E-02 1.87100 8.70671E-03 1.87150 2.33764E-02 1.87200 7.93091E-02 1.87250 8.55701E-02 1.87300 2.92135E-02 1.87350 7.85538E-03 1.87400 3.38997E-02 1.87450 8.69694E-02 1.87500 8.87879E-02 1.87550 7.36377E-02 1.87600 1.00062E-01 1.87650 8.17879E-02 1.87700 4.91521E-02 1.87750 0.122091 1.87800 0.243875 1.87850 0.389643 1.87900 0.517754 1.87950 0.519130 1.88000 0.508667 1.88050 0.316157 1.88100 0.173518 1.88150 0.255371 1.88200 0.476100 1.88250 0.588994 1.88300 0.520819 1.88350 0.331499 1.88400 0.131395 1.88450 0.178703 1.88500 0.342564 1.88550 0.387104 1.88600 0.440294 1.88650 0.384287 1.88700 0.327282 1.88750 0.542175 1.88800 0.729578 1.88850 0.729931 1.88900 0.615871 1.88950 0.370293 1.89000 0.125563 1.89050 0.128184 1.89100 0.288727 1.89150 0.297685 1.89200 0.169225 1.89250 0.147100 1.89300 0.200545 1.89350 0.190246 1.89400 0.234055 1.89450 0.413328 1.89500 0.578752 1.89550 0.660335 1.89600 0.579465 1.89650 0.531565 1.89700 0.494070 1.89750 0.293291 1.89800 0.159377 1.89850 0.145070 1.89900 6.59336E-02 1.89950 1.57474E-02 1.90000 1.26247E-02 1.90050 4.09072E-02 1.90100 0.158473 1.90150 0.322464 1.90200 0.362018 1.90250 0.205565 1.90300 8.48610E-02 1.90350 0.183224 1.90400 0.316524 1.90450 0.236446 1.90500 8.30411E-02 1.90550 2.20497E-02 1.90600 2.54519E-02 1.90650 3.64896E-02 1.90700 0.108216 1.90750 0.337190 1.90800 0.525159 1.90850 0.482315 1.90900 0.405334 1.90950 0.483618 1.91000 0.439805 1.91050 0.287100 1.91100 0.198571 1.91150 0.122362 1.91200 0.149485 1.91250 0.219584 1.91300 0.168011 1.91350 6.53308E-02 1.91400 5.08557E-02 1.91450 0.134771 1.91500 0.310537 1.91550 0.422834 1.91600 0.266148 1.91650 0.137026 1.91700 0.274917 1.91750 0.568813 1.91800 0.756328 1.91850 0.740929 1.91900 0.553928 1.91950 0.250883 1.92000 6.11322E-02 1.92050 2.58625E-02 1.92100 8.31992E-02 1.92150 0.277266 1.92200 0.546590 1.92250 0.703957 1.92300 0.704167 1.92350 0.512093 1.92400 0.218637 1.92450 0.234665 1.92500 0.542120 1.92550 0.734648 1.92600 0.669011 1.92650 0.491648 1.92700 0.257205 1.92750 0.264051 1.92800 0.369206 1.92850 0.302842 1.92900 0.418468 1.92950 0.602152 1.93000 0.487219 1.93050 0.306640 1.93100 0.260635 1.93150 0.339334 1.93200 0.500856 1.93250 0.616774 1.93300 0.619693 1.93350 0.580344 1.93400 0.431508 1.93450 0.531992 1.93500 0.757475 1.93550 0.771910 1.93600 0.624667 1.93650 0.478980 1.93700 0.540739 1.93750 0.577286 1.93800 0.488617 1.93850 0.497161 1.93900 0.399613 1.93950 0.306515 1.94000 0.457610 1.94050 0.614259 1.94100 0.521632 1.94150 0.479325 1.94200 0.665395 1.94250 0.836420 1.94300 0.804259 1.94350 0.650314 1.94400 0.558456 1.94450 0.491433 1.94500 0.504787 1.94550 0.649515 1.94600 0.704404 1.94650 0.721354 1.94700 0.671476 1.94750 0.628802 1.94800 0.613201 1.94850 0.603658 1.94900 0.633286 1.94950 0.638534 1.95000 0.663765 1.95050 0.655430 1.95100 0.669548 1.95150 0.720225 1.95200 0.682669 1.95250 0.608920 1.95300 0.526445 1.95350 0.486591 1.95400 0.496520 1.95450 0.484241 1.95500 0.491300 1.95550 0.451325 1.95600 0.437327 1.95650 0.432061 1.95700 0.448548 1.95750 0.454386 1.95800 0.446968 1.95850 0.465756 1.95900 0.446269 1.95950 0.508316 1.96000 0.660921 1.96050 0.700766 1.96100 0.664026 1.96150 0.697099 1.96200 0.687160 1.96250 0.614468 1.96300 0.547593 1.96350 0.536336 1.96400 0.562797 1.96450 0.588990 1.96500 0.627330 1.96550 0.635671 1.96600 0.647841 1.96650 0.683231 1.96700 0.704657 1.96750 0.699117 1.96800 0.691477 1.96850 0.723825 1.96900 0.752994 1.96950 0.771480 1.97000 0.796069 1.97050 0.797955 1.97100 0.757150 1.97150 0.716151 1.97200 0.733529 1.97250 0.802412 1.97300 0.856930 1.97350 0.849135 1.97400 0.795526 1.97450 0.821585 1.97500 0.894606 1.97550 0.895768 1.97600 0.892699 1.97650 0.931530 1.97700 0.948029 1.97750 0.940579 1.97800 0.946013 1.97850 0.952906 1.97900 0.935200 1.97950 0.830717 1.98000 0.741971 1.98050 0.802358 1.98100 0.916834 1.98150 0.974485 1.98200 0.981750 1.98250 0.964425 1.98300 0.944212 1.98350 0.967332 1.98400 0.986558 1.98450 0.977321 1.98500 0.947129 1.98550 0.949520 1.98600 0.968415 1.98650 0.906401 1.98700 0.824194 1.98750 0.891949 1.98800 0.966978 1.98850 0.984228 1.98900 0.981862 1.98950 0.942798 1.99000 0.867579 1.99050 0.864036 1.99100 0.932131 1.99150 0.978125 1.99200 0.985413 1.99250 0.987140 1.99300 0.986963 1.99350 0.969279 1.99400 0.925177 1.99450 0.922377 1.99500 0.940895 1.99550 0.916483 1.99600 0.897388 1.99650 0.867044 1.99700 0.827800 1.99750 0.787334 1.99800 0.706908 1.99850 0.662155 1.99900 0.639285 1.99950 0.596910 2.00000 0.556002 2.00050 0.508995 2.00100 0.454164 2.00150 0.417463 2.00200 0.387244 2.00250 0.345502 2.00300 0.327869 2.00350 0.337062 2.00400 0.337982 2.00450 0.331677 2.00500 0.321837 2.00550 0.315961 2.00600 0.334940 2.00650 0.384449 2.00700 0.431995 2.00750 0.468816 2.00800 0.514937 2.00850 0.593274 2.00900 0.657419 2.00950 0.609583 2.01000 0.521058 2.01050 0.468812 2.01100 0.449696 2.01150 0.444837 2.01200 0.440626 2.01250 0.439943 2.01300 0.445357 2.01350 0.449248 2.01400 0.458862 2.01450 0.476211 2.01500 0.484873 2.01550 0.493869 2.01600 0.504679 2.01650 0.506091 2.01700 0.512109 2.01750 0.535956 2.01800 0.553449 2.01850 0.575841 2.01900 0.600710 2.01950 0.632571 2.02000 0.659412 2.02050 0.675746 2.02100 0.690374 2.02150 0.714045 2.02200 0.744452 2.02250 0.771781 2.02300 0.787411 2.02350 0.803735 2.02400 0.820653 2.02450 0.841601 2.02500 0.856356 2.02550 0.875177 2.02600 0.891883 2.02650 0.904355 2.02700 0.916050 2.02750 0.915351 2.02800 0.908367 2.02850 0.909366 2.02900 0.931483 2.02950 0.949025 2.03000 0.956729 2.03050 0.954635 2.03100 0.958649 2.03150 0.962757 2.03200 0.964469 2.03250 0.960821 2.03300 0.951341 2.03350 0.950733 2.03400 0.960386 2.03450 0.963544 2.03500 0.964312 2.03550 0.964373 2.03600 0.964186 2.03650 0.964009 2.03700 0.963889 2.03750 0.963145 2.03800 0.959963 2.03850 0.957111 2.03900 0.956403 2.03950 0.947628 2.04000 0.930549 2.04050 0.927770 2.04100 0.935863 2.04150 0.938058 2.04200 0.938262 2.04250 0.938662 2.04300 0.938092 2.04350 0.937561 2.04400 0.937251 2.04450 0.942568 2.04500 0.950601 2.04550 0.954354 2.04600 0.951335 2.04650 0.938762 2.04700 0.920234 2.04750 0.898897 2.04800 0.875485 2.04850 0.853501 2.04900 0.832114 2.04950 0.809014 2.05000 0.785837 2.05050 0.768295 2.05100 0.755254 2.05150 0.733945 2.05200 0.714702 2.05250 0.702360 2.05300 0.697071 2.05350 0.683016 2.05400 0.665835 2.05450 0.659634 2.05500 0.662759 2.05550 0.669362 2.05600 0.666639 2.05650 0.662827 2.05700 0.674628 2.05750 0.695444 2.05800 0.719976 2.05850 0.745888 2.05900 0.778991 2.05950 0.827200 2.06000 0.877946 2.06050 0.889037 2.06100 0.842994 2.06150 0.802663 2.06200 0.776576 2.06250 0.753178 2.06300 0.739510 2.06350 0.735301 2.06400 0.732821 2.06450 0.731170 2.06500 0.732417 2.06550 0.734088 2.06600 0.734408 2.06650 0.743096 2.06700 0.754927 2.06750 0.763885 2.06800 0.772236 2.06850 0.781575 2.06900 0.789880 2.06950 0.797068 2.07000 0.806938 2.07050 0.815498 2.07100 0.824557 2.07150 0.836803 2.07200 0.847271 2.07250 0.860418 2.07300 0.865582 2.07350 0.867764 2.07400 0.876762 2.07450 0.883734 2.07500 0.889187 2.07550 0.899364 2.07600 0.908583 2.07650 0.917289 2.07700 0.922241 2.07750 0.920770 2.07800 0.929780 2.07850 0.948897 2.07900 0.963711 2.07950 0.970740 2.08000 0.971610 2.08050 0.972781 2.08100 0.970019 2.08150 0.964121 2.08200 0.958987 2.08250 0.955405 2.08300 0.952902 2.08350 0.952600 2.08400 0.950460 2.08450 0.942934 2.08500 0.941579 2.08550 0.951750 2.08600 0.957638 2.08650 0.961765 2.08700 0.965898 2.08750 0.968015 2.08800 0.968744 2.08850 0.969073 2.08900 0.970050 2.08950 0.969301 2.09000 0.967523 2.09050 0.971590 2.09100 0.975703 2.09150 0.977484 2.09200 0.978377 2.09250 0.978491 2.09300 0.978757 2.09350 0.972654 2.09400 0.969828 2.09450 0.980094 2.09500 0.986052 2.09550 0.987759 2.09600 0.988737 2.09650 0.989196 2.09700 0.988857 2.09750 0.988783 2.09800 0.984599 2.09850 0.971005 2.09900 0.970741 2.09950 0.983968 2.10000 0.985586 2.10050 0.984140 2.10100 0.982791 2.10150 0.969959 2.10200 0.971298 2.10250 0.986679 2.10300 0.991906 2.10350 0.992403 2.10400 0.992585 2.10450 0.991891 2.10500 0.990666 2.10550 0.991320 2.10600 0.991978 2.10650 0.990860 2.10700 0.990089 2.10750 0.989484 2.10800 0.988603 2.10850 0.987929 2.10900 0.986920 2.10950 0.983884 2.11000 0.982689 2.11050 0.986071 2.11100 0.986735 2.11150 0.981447 2.11200 0.979408 2.11250 0.985626 2.11300 0.991021 2.11350 0.993767 2.11400 0.994487 2.11450 0.994103 2.11500 0.993010 2.11550 0.991964 2.11600 0.990991 2.11650 0.991483 2.11700 0.992698 2.11750 0.991889 2.11800 0.983970 2.11850 0.971855 2.11900 0.979086 2.11950 0.986677 2.12000 0.986021 2.12050 0.988951 2.12100 0.992599 2.12150 0.993930 2.12200 0.995124 2.12250 0.995836 2.12300 0.996118 2.12350 0.995328 2.12400 0.989318 2.12450 0.982217 2.12500 0.988202 2.12550 0.995557 2.12600 0.997300 2.12650 0.997113 2.12700 0.992464 2.12750 0.977895 2.12800 0.977083 2.12850 0.992157 2.12900 0.997727 2.12950 0.998401 2.13000 0.998534 2.13050 0.998556 2.13100 0.998703 2.13150 0.998836 2.13200 0.998842 2.13250 0.998855 2.13300 0.998938 2.13350 0.999044 2.13400 0.999137 2.13450 0.999175 2.13500 0.998478 2.13550 0.995184 2.13600 0.993312 2.13650 0.996881 2.13700 0.999013 2.13750 0.999248 2.13800 0.999150 2.13850 0.998895 2.13900 0.998691 2.13950 0.998646 2.14000 0.998875 2.14050 0.999125 2.14100 0.999183 2.14150 0.999165 2.14200 0.998968 2.14250 0.998034 2.14300 0.997102 2.14350 0.997802 2.14400 0.998546 2.14450 0.998475 2.14500 0.998611 2.14550 0.998569 2.14600 0.998272 2.14650 0.998110 2.14700 0.997262 2.14750 0.996111 2.14800 0.995171 2.14850 0.994371 2.14900 0.993065 2.14950 0.991842 2.15000 0.991835 2.15050 0.991803 2.15100 0.983901 2.15150 0.975700 2.15200 0.980254 2.15250 0.984396 2.15300 0.985028 2.15350 0.987872 2.15400 0.989390 2.15450 0.989185 2.15500 0.989151 2.15550 0.990972 2.15600 0.994613 2.15650 0.995879 2.15700 0.996363 2.15750 0.996285 2.15800 0.995721 2.15850 0.993083 2.15900 0.987623 2.15950 0.988481 2.16000 0.990452 2.16050 0.987673 2.16100 0.980903 2.16150 0.985045 2.16200 0.992109 2.16250 0.989632 2.16300 0.973865 2.16350 0.958663 2.16400 0.977795 2.16450 0.993738 2.16500 0.995623 2.16550 0.994897 2.16600 0.992859 2.16650 0.986264 2.16700 0.982185 2.16750 0.988255 2.16800 0.987906 2.16850 0.976416 2.16900 0.980153 2.16950 0.993003 2.17000 0.995129 2.17050 0.995134 2.17100 0.997341 2.17150 0.997671 2.17200 0.991474 2.17250 0.977741 2.17300 0.980152 2.17350 0.990936 2.17400 0.989441 2.17450 0.984273 2.17500 0.988683 2.17550 0.992322 2.17600 0.987212 2.17650 0.987250 2.17700 0.995416 2.17750 0.996183 2.17800 0.984596 2.17850 0.973010 2.17900 0.977554 2.17950 0.983870 2.18000 0.993351 2.18050 0.998100 2.18100 0.998929 2.18150 0.999065 2.18200 0.998138 2.18250 0.991366 2.18300 0.971275 2.18350 0.960062 2.18400 0.969308 2.18450 0.964133 2.18500 0.959404 2.18550 0.981925 2.18600 0.996161 2.18650 0.996612 2.18700 0.991580 2.18750 0.986871 2.18800 0.984696 2.18850 0.989740 2.18900 0.994335 2.18950 0.991143 2.19000 0.988768 2.19050 0.987144 2.19100 0.993016 2.19150 0.998238 2.19200 0.999085 2.19250 0.999107 2.19300 0.999104 2.19350 0.998684 2.19400 0.993953 2.19450 0.979371 2.19500 0.972930 2.19550 0.986936 2.19600 0.995153 2.19650 0.993627 2.19700 0.993788 2.19750 0.989778 2.19800 0.969747 2.19850 0.958481 2.19900 0.959772 2.19950 0.936635 2.20000 0.904162 2.20050 0.908416 2.20100 0.952181 2.20150 0.968994 2.20200 0.961742 2.20250 0.961983 2.20300 0.972796 2.20350 0.982878 2.20400 0.981270 2.20450 0.966098 2.20500 0.958580 2.20550 0.976865 2.20600 0.989844 2.20650 0.991440 2.20700 0.990608 2.20750 0.992038 2.20800 0.995536 2.20850 0.998074 2.20900 0.998375 2.20950 0.998150 2.21000 0.996682 2.21050 0.993781 2.21100 0.989655 2.21150 0.991445 2.21200 0.997280 2.21250 0.998798 2.21300 0.998861 2.21350 0.998463 2.21400 0.996766 2.21450 0.993372 2.21500 0.991418 2.21550 0.987521 2.21600 0.971367 2.21650 0.963606 2.21700 0.980334 2.21750 0.994027 2.21800 0.994988 2.21850 0.994404 2.21900 0.996066 2.21950 0.996900 2.22000 0.995557 2.22050 0.991455 2.22100 0.979036 2.22150 0.963817 2.22200 0.973502 2.22250 0.989688 2.22300 0.994425 2.22350 0.993828 2.22400 0.992148 2.22450 0.990939 2.22500 0.988860 2.22550 0.988802 2.22600 0.985367 2.22650 0.973255 2.22700 0.967869 2.22750 0.977822 2.22800 0.988426 2.22850 0.992117 2.22900 0.993506 2.22950 0.994752 2.23000 0.994718 2.23050 0.991141 2.23100 0.982207 2.23150 0.966953 2.23200 0.960961 2.23250 0.964296 2.23300 0.976815 2.23350 0.978526 2.23400 0.981932 2.23450 0.987778 2.23500 0.987859 2.23550 0.985300 2.23600 0.977612 2.23650 0.972477 2.23700 0.975502 2.23750 0.971001 2.23800 0.971979 2.23850 0.984863 2.23900 0.991374 2.23950 0.987579 2.24000 0.979151 2.24050 0.974810 2.24100 0.974257 2.24150 0.972455 2.24200 0.981710 2.24250 0.984980 2.24300 0.983033 2.24350 0.973910 2.24400 0.961679 2.24450 0.973755 2.24500 0.989035 2.24550 0.984345 2.24600 0.967868 2.24650 0.956469 2.24700 0.944037 2.24750 0.955394 2.24800 0.983178 2.24850 0.990925 2.24900 0.986336 2.24950 0.979128 2.25000 0.972989 2.25050 0.969456 2.25100 0.974776 2.25150 0.982455 2.25200 0.979486 2.25250 0.974909 2.25300 0.971611 2.25350 0.958053 2.25400 0.946224 2.25450 0.959704 2.25500 0.971204 2.25550 0.960936 2.25600 0.952730 2.25650 0.943552 2.25700 0.938235 2.25750 0.957662 2.25800 0.967147 2.25850 0.969626 2.25900 0.979161 2.25950 0.978685 2.26000 0.967217 2.26050 0.953147 2.26100 0.930291 2.26150 0.915995 2.26200 0.914730 2.26250 0.940945 2.26300 0.968367 2.26350 0.958359 2.26400 0.950043 2.26450 0.940373 2.26500 0.943509 2.26550 0.974245 2.26600 0.988689 2.26650 0.988223 2.26700 0.979713 2.26750 0.963261 2.26800 0.932784 2.26850 0.899877 2.26900 0.921958 2.26950 0.963219 2.27000 0.958127 2.27050 0.947918 2.27100 0.969175 2.27150 0.969777 2.27200 0.948723 2.27250 0.935947 2.27300 0.959925 2.27350 0.974447 2.27400 0.979633 2.27450 0.968265 2.27500 0.927595 2.27550 0.872848 2.27600 0.881464 2.27650 0.921859 2.27700 0.935959 2.27750 0.954508 2.27800 0.971933 2.27850 0.978674 2.27900 0.987011 2.27950 0.990485 2.28000 0.975465 2.28050 0.934239 2.28100 0.930259 2.28150 0.963877 2.28200 0.967130 2.28250 0.918723 2.28300 0.880540 2.28350 0.910531 2.28400 0.918914 2.28450 0.946450 2.28500 0.946472 2.28550 0.940926 2.28600 0.970154 2.28650 0.977190 2.28700 0.975369 2.28750 0.974304 2.28800 0.974016 2.28850 0.976595 2.28900 0.953052 2.28950 0.896540 2.29000 0.882249 2.29050 0.932530 2.29100 0.963816 2.29150 0.967471 2.29200 0.951108 2.29250 0.937592 2.29300 0.959022 2.29350 0.956944 2.29400 0.947137 2.29450 0.941898 2.29500 0.919981 2.29550 0.910921 2.29600 0.915713 2.29650 0.946151 2.29700 0.973374 2.29750 0.974277 2.29800 0.931860 2.29850 0.891625 2.29900 0.903607 2.29950 0.918032 2.30000 0.904420 2.30050 0.893896 2.30100 0.923603 2.30150 0.956751 2.30200 0.954860 2.30250 0.945079 2.30300 0.939584 2.30350 0.913138 2.30400 0.895780 2.30450 0.901001 2.30500 0.924654 2.30550 0.938239 2.30600 0.943688 2.30650 0.944019 2.30700 0.934959 2.30750 0.913497 2.30800 0.938670 2.30850 0.965929 2.30900 0.964231 2.30950 0.963499 2.31000 0.973815 2.31050 0.987864 2.31100 0.994375 2.31150 0.988675 2.31200 0.975269 2.31250 0.980292 2.31300 0.993809 2.31350 0.997085 2.31400 0.997118 2.31450 0.996271 2.31500 0.992056 2.31550 0.968407 2.31600 0.905904 2.31650 0.813697 2.31700 0.741154 2.31750 0.762081 2.31800 0.807843 2.31850 0.853012 2.31900 0.898999 2.31950 0.917139 2.32000 0.927846 2.32050 0.936867 2.32100 0.942031 2.32150 0.938965 2.32200 0.925964 2.32250 0.929202 2.32300 0.938148 2.32350 0.950685 2.32400 0.963227 2.32450 0.975641 2.32500 0.960537 2.32550 0.940908 2.32600 0.953554 2.32650 0.962983 2.32700 0.978302 2.32750 0.984367 2.32800 0.957858 2.32850 0.914691 2.32900 0.927635 2.32950 0.958990 2.33000 0.977835 2.33050 0.972343 2.33100 0.953465 2.33150 0.932278 2.33200 0.926684 2.33250 0.946931 2.33300 0.965216 2.33350 0.963410 2.33400 0.946427 2.33450 0.939448 2.33500 0.937441 2.33550 0.946345 2.33600 0.941163 2.33650 0.953312 2.33700 0.969662 2.33750 0.964027 2.33800 0.933469 2.33850 0.908774 2.33900 0.917623 2.33950 0.899535 2.34000 0.849853 2.34050 0.859787 2.34100 0.886399 2.34150 0.902342 2.34200 0.923683 2.34250 0.939823 2.34300 0.939325 2.34350 0.927649 2.34400 0.937298 2.34450 0.929117 2.34500 0.905541 2.34550 0.911958 2.34600 0.922879 2.34650 0.908866 2.34700 0.901061 2.34750 0.886318 2.34800 0.861221 2.34850 0.883943 2.34900 0.913045 2.34950 0.905750 2.35000 0.884418 2.35050 0.846103 2.35100 0.848492 2.35150 0.872819 2.35200 0.858068 2.35250 0.855305 2.35300 0.877964 2.35350 0.882434 2.35400 0.926982 2.35450 0.943698 2.35500 0.931073 2.35550 0.882179 2.35600 0.833487 2.35650 0.895704 2.35700 0.941379 2.35750 0.942649 2.35800 0.898892 2.35850 0.811805 2.35900 0.839390 2.35950 0.948189 2.36000 0.985150 2.36050 0.984192 2.36100 0.962659 2.36150 0.916173 2.36200 0.931674 2.36250 0.974088 2.36300 0.977077 2.36350 0.946484 2.36400 0.908475 2.36450 0.921383 2.36500 0.959631 2.36550 0.973592 2.36600 0.954171 2.36650 0.942535 2.36700 0.907596 2.36750 0.858218 2.36800 0.896493 2.36850 0.921080 2.36900 0.912123 2.36950 0.903999 2.37000 0.782742 2.37050 0.628936 2.37100 0.618359 2.37150 0.672108 2.37200 0.764363 2.37250 0.828775 2.37300 0.876091 2.37350 0.914529 2.37400 0.937871 2.37450 0.944311 2.37500 0.937856 2.37550 0.945167 2.37600 0.916955 2.37650 0.844378 2.37700 0.847027 2.37750 0.888169 2.37800 0.848238 2.37850 0.868077 2.37900 0.941370 2.37950 0.935210 2.38000 0.897067 2.38050 0.899442 2.38100 0.945207 2.38150 0.975747 2.38200 0.975352 2.38250 0.936696 2.38300 0.843852 2.38350 0.777218 2.38400 0.777523 2.38450 0.861230 2.38500 0.938573 2.38550 0.912114 2.38600 0.837304 2.38650 0.854894 2.38700 0.908215 2.38750 0.895066 2.38800 0.848374 2.38850 0.893604 2.38900 0.958882 2.38950 0.944031 2.39000 0.918148 2.39050 0.919918 2.39100 0.847690 2.39150 0.780647 2.39200 0.880173 2.39250 0.953289 2.39300 0.948335 2.39350 0.944433 2.39400 0.938653 2.39450 0.923676 2.39500 0.932864 2.39550 0.939643 2.39600 0.918608 2.39650 0.830222 2.39700 0.808714 2.39750 0.887448 2.39800 0.938626 2.39850 0.952752 2.39900 0.957573 2.39950 0.948458 2.40000 0.911583 2.40050 0.892039 2.40100 0.943568 2.40150 0.969052 2.40200 0.962411 2.40250 0.965630 2.40300 0.961690 2.40350 0.919130 2.40400 0.805536 2.40450 0.800888 2.40500 0.913866 2.40550 0.938582 2.40600 0.923120 2.40650 0.881429 2.40700 0.815630 2.40750 0.824301 2.40800 0.888851 2.40850 0.952288 2.40900 0.946111 2.40950 0.862613 2.41000 0.821815 2.41050 0.912370 2.41100 0.955188 2.41150 0.911764 2.41200 0.898795 2.41250 0.945079 2.41300 0.963990 2.41350 0.921457 2.41400 0.833355 2.41450 0.827269 2.41500 0.890472 2.41550 0.782933 2.41600 0.623885 2.41650 0.744560 2.41700 0.913734 2.41750 0.942810 2.41800 0.857536 2.41850 0.669586 2.41900 0.568041 2.41950 0.669188 2.42000 0.867286 2.42050 0.956546 2.42100 0.970454 2.42150 0.958259 2.42200 0.932975 2.42250 0.944180 2.42300 0.958509 2.42350 0.913936 2.42400 0.828977 2.42450 0.862245 2.42500 0.918503 2.42550 0.923287 2.42600 0.861337 2.42650 0.827370 2.42700 0.914487 2.42750 0.958499 2.42800 0.969334 2.42850 0.977016 2.42900 0.974032 2.42950 0.968545 2.43000 0.967515 2.43050 0.974601 2.43100 0.977684 2.43150 0.977794 2.43200 0.974221 2.43250 0.939977 2.43300 0.847345 2.43350 0.817170 2.43400 0.885587 2.43450 0.819872 2.43500 0.587468 2.43550 0.423735 2.43600 0.450873 2.43650 0.573688 2.43700 0.803187 2.43750 0.933509 2.43800 0.963263 2.43850 0.972448 2.43900 0.977902 2.43950 0.980418 2.44000 0.978676 2.44050 0.977528 2.44100 0.979516 2.44150 0.979711 2.44200 0.970300 2.44250 0.926485 2.44300 0.891714 2.44350 0.932442 2.44400 0.963169 2.44450 0.961123 2.44500 0.925630 2.44550 0.767493 2.44600 0.557422 2.44650 0.622374 2.44700 0.690174 2.44750 0.691813 2.44800 0.763652 2.44850 0.872282 2.44900 0.938356 2.44950 0.877507 2.45000 0.694134 2.45050 0.607990 2.45100 0.548934 2.45150 0.564526 2.45200 0.787022 2.45250 0.923653 2.45300 0.933530 2.45350 0.855869 2.45400 0.768594 2.45450 0.687864 2.45500 0.758187 2.45550 0.915924 2.45600 0.960811 2.45650 0.957282 2.45700 0.962986 2.45750 0.972367 2.45800 0.975347 2.45850 0.973874 2.45900 0.965308 2.45950 0.960711 2.46000 0.970417 2.46050 0.974221 2.46100 0.964829 2.46150 0.940391 2.46200 0.833780 2.46250 0.592366 2.46300 0.578570 2.46350 0.808207 2.46400 0.878948 2.46450 0.870326 2.46500 0.930417 2.46550 0.963790 2.46600 0.960592 2.46650 0.959658 2.46700 0.934625 2.46750 0.832232 2.46800 0.803242 2.46850 0.893985 2.46900 0.940032 2.46950 0.953463 2.47000 0.947762 2.47050 0.931176 2.47100 0.882532 2.47150 0.707245 2.47200 0.386032 2.47250 0.230481 2.47300 0.387630 2.47350 0.702714 2.47400 0.892005 2.47450 0.931527 2.47500 0.911206 2.47550 0.900902 2.47600 0.931180 2.47650 0.951266 2.47700 0.923727 2.47750 0.888870 2.47800 0.891582 2.47850 0.868052 2.47900 0.864266 2.47950 0.822565 2.48000 0.708235 2.48050 0.596334 2.48100 0.577294 2.48150 0.572595 2.48200 0.727780 2.48250 0.858553 2.48300 0.841080 2.48350 0.683533 2.48400 0.415841 2.48450 0.417153 2.48500 0.700256 2.48550 0.861003 2.48600 0.862802 2.48650 0.760302 2.48700 0.625782 2.48750 0.462789 2.48800 0.320126 2.48850 0.454396 2.48900 0.669309 2.48950 0.755920 2.49000 0.798100 2.49050 0.788546 2.49100 0.787778 2.49150 0.697324 2.49200 0.528836 2.49250 0.589910 2.49300 0.698714 2.49350 0.706435 2.49400 0.566537 2.49450 0.289364 2.49500 0.250413 2.49550 0.512559 2.49600 0.739590 2.49650 0.762701 2.49700 0.806569 2.49750 0.839128 2.49800 0.816082 2.49850 0.836141 2.49900 0.825863 2.49950 0.812290 2.50000 0.859637 2.50050 0.880342 2.50100 0.881045 2.50150 0.861771 2.50200 0.800617 2.50250 0.629906 2.50300 0.392314 2.50350 0.484261 2.50400 0.674368 2.50450 0.648110 2.50500 0.632014 2.50550 0.494431 2.50600 0.358292 2.50650 0.528584 2.50700 0.782765 2.50750 0.902050 2.50800 0.890074 2.50850 0.768570 2.50900 0.651085 2.50950 0.666175 2.51000 0.697582 2.51050 0.470949 2.51100 0.277624 2.51150 0.433166 2.51200 0.563810 2.51250 0.544119 2.51300 0.578282 2.51350 0.710885 2.51400 0.776085 2.51450 0.579143 2.51500 0.337549 2.51550 0.248457 2.51600 0.173012 2.51650 0.146515 2.51700 0.140888 2.51750 0.206415 2.51800 0.462253 2.51850 0.621524 2.51900 0.526686 2.51950 0.416277 2.52000 0.530547 2.52050 0.642531 2.52100 0.770596 2.52150 0.785093 2.52200 0.633073 2.52250 0.541423 2.52300 0.597740 2.52350 0.521539 2.52400 0.292984 2.52450 0.330189 2.52500 0.435927 2.52550 0.405049 2.52600 0.382376 2.52650 0.316188 2.52700 0.275948 2.52750 0.336176 2.52800 0.414042 2.52850 0.426600 2.52900 0.371080 2.52950 0.173469 2.53000 0.129927 2.53050 0.217549 2.53100 0.159081 2.53150 5.42837E-02 2.53200 7.36881E-02 2.53250 1.04730E-01 2.53300 8.87523E-02 2.53350 0.214393 2.53400 0.448291 2.53450 0.481634 2.53500 0.281284 2.53550 0.106706 2.53600 4.10849E-02 2.53650 5.17446E-02 2.53700 0.168290 2.53750 0.289895 2.53800 0.361603 2.53850 0.307732 2.53900 0.230749 2.53950 0.377892 2.54000 0.566428 2.54050 0.509028 2.54100 0.277028 2.54150 0.132388 2.54200 1.00939E-01 2.54250 7.86398E-02 2.54300 3.17442E-02 2.54350 2.29503E-02 2.54400 1.71456E-02 2.54450 6.21574E-03 2.54500 1.48122E-02 2.54550 6.53314E-02 2.54600 0.167322 2.54650 0.211016 2.54700 0.119869 2.54750 2.79078E-02 2.54800 3.07616E-03 2.54850 1.27496E-02 2.54900 7.94431E-02 2.54950 0.180338 2.55000 0.164326 2.55050 6.64017E-02 2.55100 2.36729E-02 2.55150 5.29800E-02 2.55200 7.37960E-02 2.55250 3.58386E-02 2.55300 1.27467E-02 2.55350 6.23339E-02 2.55400 0.200682 2.55450 0.286113 2.55500 0.287589 2.55550 0.344045 2.55600 0.433375 2.55650 0.468968 2.55700 0.392275 2.55750 0.310678 2.55800 0.281874 2.55850 0.236204 2.55900 0.155075 2.55950 6.06339E-02 2.56000 1.12537E-02 2.56050 8.22040E-04 2.56100 1.99218E-05 2.56150 5.31712E-08 2.56200 7.04277E-08 2.56250 2.83073E-06 2.56300 3.04938E-05 2.56350 8.86269E-05 2.56400 6.98677E-05 2.56450 4.31127E-05 2.56500 8.69180E-04 2.56550 8.53199E-03 2.56600 3.50122E-02 2.56650 7.84159E-02 2.56700 9.29130E-02 2.56750 5.37144E-02 2.56800 1.51688E-02 2.56850 2.63614E-03 2.56900 4.80369E-04 2.56950 4.89174E-05 2.57000 1.90489E-04 2.57050 2.33284E-03 2.57100 1.08536E-02 2.57150 1.96635E-02 2.57200 1.53896E-02 2.57250 5.76536E-03 2.57300 9.72730E-04 2.57350 7.02864E-05 2.57400 6.76498E-05 2.57450 1.50234E-04 2.57500 4.64435E-04 2.57550 1.48849E-03 2.57600 1.51976E-03 2.57650 4.39861E-04 2.57700 1.25036E-04 2.57750 1.49480E-03 2.57800 9.01993E-03 2.57850 2.27736E-02 2.57900 2.94524E-02 2.57950 2.04180E-02 2.58000 7.44139E-03 2.58050 1.78394E-03 2.58100 2.24446E-04 2.58150 7.36249E-05 2.58200 2.50571E-04 2.58250 2.92329E-04 2.58300 1.00811E-04 2.58350 9.96234E-06 2.58400 5.73564E-07 2.58450 1.01644E-05 2.58500 1.04099E-04 2.58550 3.47114E-04 2.58600 3.83984E-04 2.58650 1.34896E-04 2.58700 1.41135E-05 2.58750 4.15259E-07 2.58800 7.73058E-10 2.58850 6.14685E-08 2.58900 5.82730E-06 2.58950 1.37129E-04 2.59000 1.03550E-03 2.59050 2.55482E-03 2.59100 2.28052E-03 2.59150 1.26387E-03 2.59200 5.39003E-04 2.59250 8.89576E-05 2.59300 4.33847E-06 2.59350 5.14225E-08 2.59400 0. 2.59450 0. 2.59500 0. 2.59550 0. 2.59600 0. 2.59650 1.29516E-08 2.59700 2.36268E-06 2.59750 8.43206E-05 2.59800 1.03404E-03 2.59850 4.75963E-03 2.59900 9.11354E-03 2.59950 7.86873E-03 2.60000 4.64774E-03 2.60050 2.75123E-03 2.60100 7.50119E-04 2.60150 6.49983E-05 2.60200 5.84982E-06 2.60250 9.52441E-06 2.60300 5.50399E-06 2.60350 8.13932E-07 2.60400 3.07099E-08 2.60450 1.22151E-10 2.60500 0. 2.60550 0. 2.60600 0. 2.60650 0. 2.60700 0. 2.60750 0. 2.60800 0. 2.60850 0. 2.60900 2.69301E-09 2.60950 5.82116E-07 2.61000 2.21126E-05 2.61050 2.66238E-04 2.61100 1.08433E-03 2.61150 1.57924E-03 2.61200 7.90820E-04 2.61250 1.22123E-04 2.61300 5.76671E-06 2.61350 9.44120E-06 2.61400 5.49874E-05 2.61450 8.50224E-05 2.61500 3.46907E-05 2.61550 3.73304E-06 2.61600 1.05655E-07 2.61650 1.85436E-11 2.61700 0. 2.61750 0. 2.61800 0. 2.61850 0. 2.61900 0. 2.61950 0. 2.62000 0. 2.62050 4.94590E-08 2.62100 3.39033E-06 2.62150 6.77962E-05 2.62200 5.25843E-04 2.62250 2.23750E-03 2.62300 6.41913E-03 2.62350 1.08452E-02 2.62400 1.01490E-02 2.62450 5.37306E-03 2.62500 1.82351E-03 2.62550 4.08479E-04 2.62600 4.60204E-05 2.62650 1.97978E-06 2.62700 2.37133E-08 2.62750 0. 2.62800 0. 2.62850 0. 2.62900 0. 2.62950 0. 2.63000 0. 2.63050 0. 2.63100 0. 2.63150 0. 2.63200 0. 2.63250 0. 2.63300 8.50751E-10 2.63350 1.08282E-06 2.63400 6.21755E-05 2.63450 1.10571E-03 2.63500 7.21401E-03 2.63550 2.18695E-02 2.63600 4.42830E-02 2.63650 7.04138E-02 2.63700 0.123779 2.63750 0.185466 2.63800 0.198941 2.63850 0.139015 2.63900 9.40803E-02 2.63950 0.135771 2.64000 0.128158 2.64050 5.31014E-02 2.64100 1.37403E-02 2.64150 3.48079E-03 2.64200 1.29076E-03 2.64250 9.07881E-03 2.64300 3.61677E-02 2.64350 5.35005E-02 2.64400 3.25188E-02 2.64450 1.32081E-02 2.64500 5.22988E-03 2.64550 9.54610E-04 2.64600 9.78894E-05 2.64650 1.05753E-03 2.64700 1.02039E-02 2.64750 4.47219E-02 2.64800 0.105665 2.64850 0.158865 2.64900 0.167898 2.64950 0.124930 2.65000 9.27436E-02 2.65050 7.01388E-02 2.65100 2.98892E-02 2.65150 5.70136E-03 2.65200 4.31643E-04 2.65250 1.46558E-05 2.65300 5.84877E-05 2.65350 5.05101E-04 2.65400 1.48995E-03 2.65450 1.45131E-03 2.65500 4.61932E-04 2.65550 7.52919E-05 2.65600 3.15886E-04 2.65650 1.25352E-03 2.65700 2.92523E-03 2.65750 3.58311E-03 2.65800 2.34480E-03 2.65850 1.58906E-03 2.65900 5.66940E-04 2.65950 6.46782E-05 2.66000 2.23259E-06 2.66050 1.33573E-08 2.66100 0. 2.66150 0. 2.66200 0. 2.66250 0. 2.66300 0. 2.66350 0. 2.66400 0. 2.66450 0. 2.66500 0. 2.66550 0. 2.66600 0. 2.66650 0. 2.66700 0. 2.66750 0. 2.66800 0. 2.66850 0. 2.66900 0. 2.66950 0. 2.67000 0. 2.67050 0. 2.67100 0. 2.67150 0. 2.67200 0. 2.67250 0. 2.67300 0. 2.67350 0. 2.67400 0. 2.67450 0. 2.67500 0. 2.67550 0. 2.67600 0. 2.67650 0. 2.67700 0. 2.67750 0. 2.67800 0. 2.67850 0. 2.67900 0. 2.67950 0. 2.68000 0. 2.68050 0. 2.68100 0. 2.68150 0. 2.68200 0. 2.68250 0. 2.68300 0. 2.68350 0. 2.68400 0. 2.68450 0. 2.68500 0. 2.68550 0. 2.68600 0. 2.68650 0. 2.68700 0. 2.68750 0. 2.68800 0. 2.68850 0. 2.68900 0. 2.68950 0. 2.69000 0. 2.69050 0. 2.69100 0. 2.69150 0. 2.69200 0. 2.69250 0. 2.69300 0. 2.69350 0. 2.69400 0. 2.69450 0. 2.69500 0. 2.69550 0. 2.69600 0. 2.69650 0. 2.69700 0. 2.69750 0. 2.69800 0. 2.69850 0. 2.69900 0. 2.69950 0. 2.70000 0. 2.70050 0. 2.70100 0. 2.70150 0. 2.70200 0. 2.70250 0. 2.70300 0. 2.70350 0. 2.70400 0. 2.70450 0. 2.70500 0. 2.70550 0. 2.70600 0. 2.70650 0. 2.70700 0. 2.70750 0. 2.70800 0. 2.70850 0. 2.70900 0. 2.70950 0. 2.71000 0. 2.71050 0. 2.71100 0. 2.71150 7.46271E-09 2.71200 4.08152E-07 2.71250 5.77449E-06 2.71300 2.24869E-05 2.71350 3.24894E-05 2.71400 1.18316E-04 2.71450 4.45578E-04 2.71500 6.04868E-04 2.71550 7.04037E-04 2.71600 9.45985E-04 2.71650 4.97751E-04 2.71700 8.49472E-05 2.71750 4.81223E-06 2.71800 7.95806E-08 2.71850 0. 2.71900 0. 2.71950 0. 2.72000 0. 2.72050 0. 2.72100 0. 2.72150 0. 2.72200 0. 2.72250 0. 2.72300 0. 2.72350 0. 2.72400 0. 2.72450 0. 2.72500 3.43786E-09 2.72550 8.05882E-07 2.72600 2.99542E-05 2.72650 3.76366E-04 2.72700 1.75447E-03 2.72750 3.64936E-03 2.72800 7.77668E-03 2.72850 2.18814E-02 2.72900 3.50740E-02 2.72950 3.32743E-02 2.73000 3.91123E-02 2.73050 4.55297E-02 2.73100 3.12457E-02 2.73150 1.84191E-02 2.73200 7.97910E-03 2.73250 7.04690E-03 2.73300 1.02623E-02 2.73350 6.63580E-03 2.73400 1.88625E-03 2.73450 2.15843E-04 2.73500 9.37679E-06 2.73550 2.99425E-05 2.73600 2.76024E-04 2.73650 8.22255E-04 2.73700 7.91828E-04 2.73750 2.57058E-04 2.73800 3.09913E-05 2.73850 1.38114E-06 2.73900 1.82239E-08 2.73950 0. 2.74000 0. 2.74050 0. 2.74100 0. 2.74150 0. 2.74200 2.85219E-07 2.74250 1.67434E-05 2.74300 2.59645E-04 2.74350 1.12757E-03 2.74400 1.50164E-03 2.74450 7.08162E-04 2.74500 1.34187E-04 2.74550 7.26413E-05 2.74600 8.19766E-04 2.74650 3.45077E-03 2.74700 4.11042E-03 2.74750 1.62636E-03 2.74800 4.64222E-04 2.74850 9.91428E-05 2.74900 3.97107E-05 2.74950 1.12449E-04 2.75000 2.72961E-04 2.75050 2.25304E-04 2.75100 5.04539E-05 2.75150 2.98142E-06 2.75200 4.50252E-08 2.75250 0. 2.75300 0. 2.75350 0. 2.75400 0. 2.75450 0. 2.75500 0. 2.75550 0. 2.75600 0. 2.75650 0. 2.75700 0. 2.75750 0. 2.75800 0. 2.75850 0. 2.75900 0. 2.75950 0. 2.76000 0. 2.76050 0. 2.76100 0. 2.76150 0. 2.76200 0. 2.76250 0. 2.76300 0. 2.76350 0. 2.76400 0. 2.76450 0. 2.76500 0. 2.76550 0. 2.76600 0. 2.76650 0. 2.76700 0. 2.76750 0. 2.76800 0. 2.76850 0. 2.76900 0. 2.76950 0. 2.77000 0. 2.77050 0. 2.77100 0. 2.77150 0. 2.77200 0. 2.77250 0. 2.77300 2.66520E-10 2.77350 2.00496E-08 2.77400 3.77809E-07 2.77450 1.78330E-06 2.77500 2.10791E-06 2.77550 6.24441E-07 2.77600 4.62515E-08 2.77650 8.58907E-10 2.77700 0. 2.77750 0. 2.77800 0. 2.77850 0. 2.77900 0. 2.77950 0. 2.78000 0. 2.78050 0. 2.78100 0. 2.78150 0. 2.78200 0. 2.78250 8.38924E-08 2.78300 3.80616E-06 2.78350 4.40936E-05 2.78400 1.31333E-04 2.78450 1.02332E-04 2.78500 2.46771E-05 2.78550 1.28573E-05 2.78600 1.06914E-05 2.78650 2.52232E-06 2.78700 1.52624E-07 2.78750 2.36056E-09 2.78800 1.07191E-07 2.78850 8.13460E-06 2.78900 1.52285E-04 2.78950 7.39647E-04 2.79000 9.33600E-04 2.79050 4.01153E-04 2.79100 1.25820E-03 2.79150 4.57812E-03 2.79200 6.13691E-03 2.79250 7.91617E-03 2.79300 8.07466E-03 2.79350 4.18372E-03 2.79400 1.12827E-02 2.79450 2.18905E-02 2.79500 1.30209E-02 2.79550 4.06567E-03 2.79600 9.17343E-03 2.79650 1.58233E-02 2.79700 7.69597E-03 2.79750 1.12372E-03 2.79800 8.26521E-04 2.79850 7.00086E-03 2.79900 2.90093E-02 2.79950 5.35208E-02 2.80000 3.99908E-02 2.80050 1.41603E-02 2.80100 8.16306E-03 2.80150 5.25740E-03 2.80200 1.37133E-03 2.80250 1.26905E-04 2.80300 3.67799E-06 2.80350 2.16667E-08 2.80400 4.15539E-07 2.80450 3.28079E-06 2.80500 1.15962E-05 2.80550 3.18687E-05 2.80600 1.51171E-04 2.80650 6.66623E-04 2.80700 3.75033E-03 2.80750 1.17382E-02 2.80800 1.12231E-02 2.80850 5.55076E-03 2.80900 1.34713E-02 2.80950 3.77404E-02 2.81000 5.26864E-02 2.81050 4.92516E-02 2.81100 3.47226E-02 2.81150 4.87988E-02 2.81200 0.125513 2.81250 0.158933 2.81300 1.01133E-01 2.81350 4.69394E-02 2.81400 2.35216E-02 2.81450 1.63181E-02 2.81500 7.15731E-03 2.81550 1.02543E-02 2.81600 2.30568E-02 2.81650 3.81845E-02 2.81700 6.91011E-02 2.81750 7.17183E-02 2.81800 3.48098E-02 2.81850 1.57872E-02 2.81900 1.17363E-02 2.81950 2.27773E-02 2.82000 3.28932E-02 2.82050 1.39404E-02 2.82100 2.00513E-03 2.82150 9.62986E-04 2.82200 6.04452E-03 2.82250 4.37365E-02 2.82300 0.138730 2.82350 0.224456 2.82400 0.249512 2.82450 0.192406 2.82500 0.172525 2.82550 0.190434 2.82600 0.289760 2.82650 0.308545 2.82700 0.165275 2.82750 6.59645E-02 2.82800 0.117027 2.82850 0.277408 2.82900 0.348433 2.82950 0.405702 2.83000 0.453038 2.83050 0.433093 2.83100 0.406940 2.83150 0.220348 2.83200 6.20016E-02 2.83250 4.59858E-02 2.83300 5.01135E-02 2.83350 2.19248E-02 2.83400 4.36578E-03 2.83450 1.49209E-03 2.83500 3.76535E-03 2.83550 2.38627E-02 2.83600 6.65644E-02 2.83650 9.23693E-02 2.83700 7.02928E-02 2.83750 3.86315E-02 2.83800 2.22160E-02 2.83850 1.25131E-02 2.83900 4.10920E-02 2.83950 0.113036 2.84000 0.209938 2.84050 0.289646 2.84100 0.200746 2.84150 1.02646E-01 2.84200 0.128186 2.84250 0.228789 2.84300 0.346488 2.84350 0.448027 2.84400 0.513021 2.84450 0.581912 2.84500 0.472795 2.84550 0.301061 2.84600 0.224535 2.84650 0.178578 2.84700 0.168988 2.84750 0.112529 2.84800 9.13010E-02 2.84850 1.00960E-01 2.84900 6.80385E-02 2.84950 3.76179E-02 2.85000 0.118412 2.85050 0.286894 2.85100 0.387376 2.85150 0.332130 2.85200 0.204127 2.85250 0.122805 2.85300 6.86505E-02 2.85350 2.26740E-02 2.85400 1.05554E-02 2.85450 5.94908E-03 2.85500 1.02322E-02 2.85550 2.43368E-02 2.85600 7.77783E-02 2.85650 0.204824 2.85700 0.272392 2.85750 0.319424 2.85800 0.392779 2.85850 0.412704 2.85900 0.336409 2.85950 0.168226 2.86000 0.105973 2.86050 0.160466 2.86100 0.184883 2.86150 0.323649 2.86200 0.474922 2.86250 0.496971 2.86300 0.544977 2.86350 0.548370 2.86400 0.442921 2.86450 0.366866 2.86500 0.469400 2.86550 0.558558 2.86600 0.450554 2.86650 0.233590 2.86700 0.175106 2.86750 0.305468 2.86800 0.320947 2.86850 0.282038 2.86900 0.299453 2.86950 0.344015 2.87000 0.385138 2.87050 0.387361 2.87100 0.269768 2.87150 9.75122E-02 2.87200 6.28070E-02 2.87250 9.56696E-02 2.87300 0.126041 2.87350 0.286362 2.87400 0.478362 2.87450 0.649139 2.87500 0.729783 2.87550 0.721234 2.87600 0.692020 2.87650 0.634344 2.87700 0.469409 2.87750 0.235782 2.87800 0.262597 2.87850 0.400127 2.87900 0.403897 2.87950 0.540406 2.88000 0.642782 2.88050 0.616171 2.88100 0.542903 2.88150 0.441903 2.88200 0.546196 2.88250 0.599684 2.88300 0.524222 2.88350 0.477117 2.88400 0.346084 2.88450 0.289478 2.88500 0.434816 2.88550 0.616555 2.88600 0.654299 2.88650 0.620983 2.88700 0.575662 2.88750 0.346760 2.88800 0.146877 2.88850 0.135701 2.88900 0.154779 2.88950 0.283967 2.89000 0.492082 2.89050 0.673564 2.89100 0.638540 2.89150 0.547495 2.89200 0.524884 2.89250 0.575575 2.89300 0.549092 2.89350 0.451469 2.89400 0.585078 2.89450 0.782930 2.89500 0.832595 2.89550 0.824502 2.89600 0.823092 2.89650 0.842020 2.89700 0.851538 2.89750 0.848143 2.89800 0.819554 2.89850 0.767634 2.89900 0.681430 2.89950 0.436780 2.90000 0.190966 2.90050 8.04939E-02 2.90100 5.22625E-02 2.90150 0.177364 2.90200 0.366965 2.90250 0.439223 2.90300 0.562444 2.90350 0.635965 2.90400 0.454733 2.90450 0.179353 2.90500 0.133475 2.90550 0.350234 2.90600 0.504669 2.90650 0.449374 2.90700 0.481131 2.90750 0.620807 2.90800 0.614649 2.90850 0.554749 2.90900 0.648051 2.90950 0.759177 2.91000 0.772661 2.91050 0.811187 2.91100 0.891973 2.91150 0.906852 2.91200 0.843808 2.91250 0.708414 2.91300 0.549391 2.91350 0.593320 2.91400 0.532625 2.91450 0.345238 2.91500 0.495452 2.91550 0.769385 2.91600 0.864587 2.91650 0.777137 2.91700 0.555704 2.91750 0.560811 2.91800 0.767043 2.91850 0.875260 2.91900 0.912828 2.91950 0.913540 2.92000 0.850900 2.92050 0.738098 2.92100 0.602366 2.92150 0.410188 2.92200 0.198998 2.92250 0.133223 2.92300 0.149814 2.92350 8.80086E-02 2.92400 0.106390 2.92450 0.278048 2.92500 0.421402 2.92550 0.553195 2.92600 0.759390 2.92650 0.855360 2.92700 0.895248 2.92750 0.894276 2.92800 0.896422 2.92850 0.919440 2.92900 0.878229 2.92950 0.728081 2.93000 0.634454 2.93050 0.775061 2.93100 0.905109 2.93150 0.948339 2.93200 0.952087 2.93250 0.921270 2.93300 0.798097 2.93350 0.660756 2.93400 0.776352 2.93450 0.902821 2.93500 0.868471 2.93550 0.830116 2.93600 0.901471 2.93650 0.929039 2.93700 0.852116 2.93750 0.612270 2.93800 0.412329 2.93850 0.535266 2.93900 0.582152 2.93950 0.526606 2.94000 0.625587 2.94050 0.752818 2.94100 0.842912 2.94150 0.852848 2.94200 0.776636 2.94250 0.701950 2.94300 0.524318 2.94350 0.293954 2.94400 0.386065 2.94450 0.627858 2.94500 0.813171 2.94550 0.886154 2.94600 0.857624 2.94650 0.694996 2.94700 0.365423 2.94750 0.169441 2.94800 0.328133 2.94850 0.600225 2.94900 0.814623 2.94950 0.901854 2.95000 0.906888 2.95050 0.921669 2.95100 0.934276 2.95150 0.912625 2.95200 0.884223 2.95250 0.827627 2.95300 0.608257 2.95350 0.336159 2.95400 0.329959 2.95450 0.354751 2.95500 0.422713 2.95550 0.546026 2.95600 0.614572 2.95650 0.806454 2.95700 0.912714 2.95750 0.872883 2.95800 0.748171 2.95850 0.755293 2.95900 0.782054 2.95950 0.756888 2.96000 0.789198 2.96050 0.781476 2.96100 0.807608 2.96150 0.856365 2.96200 0.852847 2.96250 0.796962 2.96300 0.704986 2.96350 0.728750 2.96400 0.872661 2.96450 0.942164 2.96500 0.950822 2.96550 0.931343 2.96600 0.836771 2.96650 0.755112 2.96700 0.788955 2.96750 0.716179 2.96800 0.546853 2.96850 0.501973 2.96900 0.501303 2.96950 0.410558 2.97000 0.441363 2.97050 0.335326 2.97100 0.189865 2.97150 0.193803 2.97200 0.204897 2.97250 0.289943 2.97300 0.514177 2.97350 0.547055 2.97400 0.401034 2.97450 0.308716 2.97500 0.468761 2.97550 0.610235 2.97600 0.488289 2.97650 0.448675 2.97700 0.646504 2.97750 0.830525 2.97800 0.809276 2.97850 0.587379 2.97900 0.459506 2.97950 0.475649 2.98000 0.419790 2.98050 0.542393 2.98100 0.642221 2.98150 0.565400 2.98200 0.547219 2.98250 0.740329 2.98300 0.874824 2.98350 0.816548 2.98400 0.731269 2.98450 0.814366 2.98500 0.859664 2.98550 0.878881 2.98600 0.882006 2.98650 0.834952 2.98700 0.867769 2.98750 0.923849 2.98800 0.899121 2.98850 0.823156 2.98900 0.869983 2.98950 0.948497 2.99000 0.967438 2.99050 0.960395 2.99100 0.910352 2.99150 0.816810 2.99200 0.760632 2.99250 0.792270 2.99300 0.822826 2.99350 0.788582 2.99400 0.762209 2.99450 0.786309 2.99500 0.807097 2.99550 0.876326 2.99600 0.806686 2.99650 0.528090 2.99700 0.388324 2.99750 0.623353 2.99800 0.771542 2.99850 0.629423 2.99900 0.585653 2.99950 0.804276 3.00000 0.929646 3.00050 0.942570 3.00100 0.947215 3.00150 0.959289 3.00200 0.958495 3.00250 0.923474 3.00300 0.809707 3.00350 0.766460 3.00400 0.856123 3.00450 0.828962 3.00500 0.587872 3.00550 0.398067 3.00600 0.366364 3.00650 0.473768 3.00700 0.693656 3.00750 0.672690 3.00800 0.597106 3.00850 0.650113 3.00900 0.589731 3.00950 0.602968 3.01000 0.810882 3.01050 0.926795 3.01100 0.943991 3.01150 0.919944 3.01200 0.930757 3.01250 0.920965 3.01300 0.801026 3.01350 0.726411 3.01400 0.741368 3.01450 0.727163 3.01500 0.843827 3.01550 0.932749 3.01600 0.928417 3.01650 0.891623 3.01700 0.823873 3.01750 0.614397 3.01800 0.335038 3.01850 0.345331 3.01900 0.478746 3.01950 0.597397 3.02000 0.703785 3.02050 0.630770 3.02100 0.639982 3.02150 0.583434 3.02200 0.286108 3.02250 0.162272 3.02300 0.378514 3.02350 0.697134 3.02400 0.885020 3.02450 0.936965 3.02500 0.951402 3.02550 0.955922 3.02600 0.944999 3.02650 0.886838 3.02700 0.709125 3.02750 0.648019 3.02800 0.834275 3.02850 0.944127 3.02900 0.944823 3.02950 0.853488 3.03000 0.745710 3.03050 0.815749 3.03100 0.893278 3.03150 0.798308 3.03200 0.526720 3.03250 0.325800 3.03300 0.396732 3.03350 0.641157 3.03400 0.828016 3.03450 0.891895 3.03500 0.805095 3.03550 0.605020 3.03600 0.544893 3.03650 0.405090 3.03700 0.219819 3.03750 0.304842 3.03800 0.375178 3.03850 0.490531 3.03900 0.720450 3.03950 0.809840 3.04000 0.681576 3.04050 0.388538 3.04100 0.377474 3.04150 0.686453 3.04200 0.886411 3.04250 0.914064 3.04300 0.884316 3.04350 0.894000 3.04400 0.876974 3.04450 0.763228 3.04500 0.616480 3.04550 0.549638 3.04600 0.528105 3.04650 0.716960 3.04700 0.882602 3.04750 0.863702 3.04800 0.672534 3.04850 0.429857 3.04900 0.442974 3.04950 0.574243 3.05000 0.662228 3.05050 0.775589 3.05100 0.745945 3.05150 0.488669 3.05200 0.228848 3.05250 0.312351 3.05300 0.514118 3.05350 0.550209 3.05400 0.392843 3.05450 0.173134 3.05500 0.242303 3.05550 0.490824 3.05600 0.561583 3.05650 0.558221 3.05700 0.577959 3.05750 0.580034 3.05800 0.722199 3.05850 0.886487 3.05900 0.946118 3.05950 0.957915 3.06000 0.949489 3.06050 0.910814 3.06100 0.806656 3.06150 0.670848 3.06200 0.628784 3.06250 0.510712 3.06300 0.555131 3.06350 0.734077 3.06400 0.717293 3.06450 0.672201 3.06500 0.783790 3.06550 0.879181 3.06600 0.865132 3.06650 0.671782 3.06700 0.448464 3.06750 0.573635 3.06800 0.810794 3.06850 0.878719 3.06900 0.789325 3.06950 0.583334 3.07000 0.393161 3.07050 0.501137 3.07100 0.683033 3.07150 0.764032 3.07200 0.711630 3.07250 0.435874 3.07300 0.255076 3.07350 0.463547 3.07400 0.752790 3.07450 0.884441 3.07500 0.909237 3.07550 0.904012 3.07600 0.932161 3.07650 0.949669 3.07700 0.926702 3.07750 0.905748 3.07800 0.929640 3.07850 0.933432 3.07900 0.873124 3.07950 0.808809 3.08000 0.795530 3.08050 0.672448 3.08100 0.371499 3.08150 0.120289 3.08200 0.170776 3.08250 0.469912 3.08300 0.702139 3.08350 0.750228 3.08400 0.768389 3.08450 0.695536 3.08500 0.694485 3.08550 0.730422 3.08600 0.543921 3.08650 0.499174 3.08700 0.741970 3.08750 0.878165 3.08800 0.852257 3.08850 0.767106 3.08900 0.591507 3.08950 0.359219 3.09000 0.473547 3.09050 0.756501 3.09100 0.863031 3.09150 0.849549 3.09200 0.806784 3.09250 0.624109 3.09300 0.357632 3.09350 0.345891 3.09400 0.550098 3.09450 0.721833 3.09500 0.691413 3.09550 0.495141 3.09600 0.317136 3.09650 0.461954 3.09700 0.698846 3.09750 0.737930 3.09800 0.521011 3.09850 0.398638 3.09900 0.615255 3.09950 0.744053 3.10000 0.761172 3.10050 0.863257 3.10100 0.934657 3.10150 0.941478 3.10200 0.915058 3.10250 0.862052 3.10300 0.712737 3.10350 0.493344 3.10400 0.543438 3.10450 0.607589 3.10500 0.396912 3.10550 0.232055 3.10600 0.177360 3.10650 0.309727 3.10700 0.614369 3.10750 0.807379 3.10800 0.813168 3.10850 0.632031 3.10900 0.494410 3.10950 0.638528 3.11000 0.690316 3.11050 0.487546 3.11100 0.217134 3.11150 0.223265 3.11200 0.510849 3.11250 0.754984 3.11300 0.850735 3.11350 0.862128 3.11400 0.809751 3.11450 0.653167 3.11500 0.391053 3.11550 0.222784 3.11600 0.406256 3.11650 0.700836 3.11700 0.851481 3.11750 0.883193 3.11800 0.893441 3.11850 0.930656 3.11900 0.951940 3.11950 0.952509 3.12000 0.955137 3.12050 0.960361 3.12100 0.947260 3.12150 0.926064 3.12200 0.935413 3.12250 0.945236 3.12300 0.935014 3.12350 0.920014 3.12400 0.849780 3.12450 0.664957 3.12500 0.471656 3.12550 0.506267 3.12600 0.610925 3.12650 0.441280 3.12700 0.217590 3.12750 0.301135 3.12800 0.427994 3.12850 0.346078 3.12900 0.408404 3.12950 0.698124 3.13000 0.878433 3.13050 0.932687 3.13100 0.948588 3.13150 0.950539 3.13200 0.943832 3.13250 0.915022 3.13300 0.909595 3.13350 0.938049 3.13400 0.953228 3.13450 0.960945 3.13500 0.963910 3.13550 0.967775 3.13600 0.966440 3.13650 0.960633 3.13700 0.954688 3.13750 0.943391 3.13800 0.909201 3.13850 0.790486 3.13900 0.495492 3.13950 0.212668 3.14000 0.308207 3.14050 0.641106 3.14100 0.837688 3.14150 0.851917 3.14200 0.786948 3.14250 0.814790 3.14300 0.903018 3.14350 0.925465 3.14400 0.910338 3.14450 0.836187 3.14500 0.719173 3.14550 0.595188 3.14600 0.340259 3.14650 0.165420 3.14700 0.331235 3.14750 0.636826 3.14800 0.820410 3.14850 0.882916 3.14900 0.862171 3.14950 0.775146 3.15000 0.800311 3.15050 0.905639 3.15100 0.915005 3.15150 0.894647 3.15200 0.929168 3.15250 0.955631 3.15300 0.955992 3.15350 0.936237 3.15400 0.877351 3.15450 0.692855 3.15500 0.573704 3.15550 0.730442 3.15600 0.806578 3.15650 0.679334 3.15700 0.702454 3.15750 0.812218 3.15800 0.828099 3.15850 0.846559 3.15900 0.905479 3.15950 0.921914 3.16000 0.883593 3.16050 0.829500 3.16100 0.872977 3.16150 0.951313 3.16200 0.973224 3.16250 0.973852 3.16300 0.979039 3.16350 0.983354 3.16400 0.983704 3.16450 0.982576 3.16500 0.978883 3.16550 0.969419 3.16600 0.931483 3.16650 0.847291 3.16700 0.810435 3.16750 0.896619 3.16800 0.961779 3.16850 0.963643 3.16900 0.948609 3.16950 0.955114 3.17000 0.973468 3.17050 0.976124 3.17100 0.961186 3.17150 0.926863 3.17200 0.861718 3.17250 0.815011 3.17300 0.741281 3.17350 0.766663 3.17400 0.903275 3.17450 0.934732 3.17500 0.830639 3.17550 0.686659 3.17600 0.748619 3.17650 0.910697 3.17700 0.960585 3.17750 0.958318 3.17800 0.952650 3.17850 0.957153 3.17900 0.966223 3.17950 0.970188 3.18000 0.969132 3.18050 0.955376 3.18100 0.891001 3.18150 0.693657 3.18200 0.592397 3.18250 0.785266 3.18300 0.918368 3.18350 0.876219 3.18400 0.667318 3.18450 0.524348 3.18500 0.698083 3.18550 0.895583 3.18600 0.948551 3.18650 0.952048 3.18700 0.945510 3.18750 0.934421 3.18800 0.930528 3.18850 0.926805 3.18900 0.922542 3.18950 0.895012 3.19000 0.832804 3.19050 0.726206 3.19100 0.489850 3.19150 0.208117 3.19200 0.201690 3.19250 0.417885 3.19300 0.460319 3.19350 0.430033 3.19400 0.653189 3.19450 0.858192 3.19500 0.916293 3.19550 0.910515 3.19600 0.844142 3.19650 0.761989 3.19700 0.695324 3.19750 0.526249 3.19800 0.271525 3.19850 0.195851 3.19900 0.286279 3.19950 0.425516 3.20000 0.559350 3.20050 0.736134 3.20100 0.757112 3.20150 0.542421 3.20200 0.216575 3.20250 8.74721E-02 3.20300 0.223656 3.20350 0.470549 3.20400 0.694308 3.20450 0.788522 3.20500 0.738277 3.20550 0.496497 3.20600 0.209099 3.20650 0.161143 3.20700 0.266429 3.20750 0.495759 3.20800 0.621190 3.20850 0.467155 3.20900 0.234696 3.20950 0.175865 3.21000 0.312157 3.21050 0.313021 3.21100 0.263176 3.21150 0.234222 3.21200 0.240528 3.21250 0.343903 3.21300 0.310191 3.21350 0.467391 3.21400 0.712678 3.21450 0.648611 3.21500 0.435642 3.21550 0.374932 3.21600 0.460313 3.21650 0.638390 3.21700 0.646816 3.21750 0.541501 3.21800 0.429542 3.21850 0.515505 3.21900 0.742962 3.21950 0.804359 3.22000 0.778070 3.22050 0.607875 3.22100 0.306640 3.22150 0.283885 3.22200 0.393062 3.22250 0.264640 3.22300 0.212674 3.22350 0.325291 3.22400 0.301725 3.22450 0.176513 3.22500 0.256840 3.22550 0.340643 3.22600 0.242395 3.22650 0.363061 3.22700 0.653523 3.22750 0.803705 3.22800 0.811319 3.22850 0.670424 3.22900 0.430267 3.22950 0.239733 3.23000 8.46591E-02 3.23050 4.17210E-02 3.23100 0.127076 3.23150 0.298467 3.23200 0.397493 3.23250 0.476625 3.23300 0.718094 3.23350 0.874254 3.23400 0.918314 3.23450 0.931914 3.23500 0.935854 3.23550 0.932063 3.23600 0.880212 3.23650 0.837640 3.23700 0.887418 3.23750 0.908567 3.23800 0.881510 3.23850 0.790457 3.23900 0.592514 3.23950 0.485439 3.24000 0.338618 3.24050 0.204305 3.24100 0.411464 3.24150 0.708056 3.24200 0.839487 3.24250 0.846709 3.24300 0.793635 3.24350 0.606999 3.24400 0.404947 3.24450 0.444872 3.24500 0.394503 3.24550 0.370789 3.24600 0.527478 3.24650 0.443854 3.24700 0.224968 3.24750 0.301574 3.24800 0.504563 3.24850 0.435309 3.24900 0.286354 3.24950 0.309534 3.25000 0.248860 3.25050 0.294550 3.25100 0.597309 3.25150 0.822699 3.25200 0.901763 3.25250 0.926175 3.25300 0.921652 3.25350 0.890969 3.25400 0.889685 3.25450 0.921096 3.25500 0.936674 3.25550 0.932779 3.25600 0.923908 3.25650 0.916214 3.25700 0.890954 3.25750 0.874063 3.25800 0.855686 3.25850 0.826873 3.25900 0.735485 3.25950 0.500186 3.26000 0.198810 3.26050 8.39780E-02 3.26100 0.187924 3.26150 0.381855 3.26200 0.511540 3.26250 0.448754 3.26300 0.236173 3.26350 0.232855 3.26400 0.512985 3.26450 0.748374 3.26500 0.847221 3.26550 0.888537 3.26600 0.889874 3.26650 0.848406 3.26700 0.796327 3.26750 0.632249 3.26800 0.438582 3.26850 0.568484 3.26900 0.737648 3.26950 0.656631 3.27000 0.369037 3.27050 0.170099 3.27100 0.194345 3.27150 0.183306 3.27200 0.164073 3.27250 0.305534 3.27300 0.553599 3.27350 0.761732 3.27400 0.841002 3.27450 0.860872 3.27500 0.867676 3.27550 0.877051 3.27600 0.868304 3.27650 0.870210 3.27700 0.880665 3.27750 0.861178 3.27800 0.835147 3.27850 0.803387 3.27900 0.650494 3.27950 0.331259 3.28000 1.03092E-01 3.28050 0.144306 3.28100 0.431149 3.28150 0.746096 3.28200 0.885414 3.28250 0.924374 3.28300 0.935643 3.28350 0.942296 3.28400 0.944544 3.28450 0.938377 3.28500 0.926847 3.28550 0.927994 3.28600 0.938667 3.28650 0.930623 3.28700 0.925407 3.28750 0.940549 3.28800 0.947302 3.28850 0.941044 3.28900 0.934280 3.28950 0.929518 3.29000 0.890570 3.29050 0.731982 3.29100 0.527197 3.29150 0.633871 3.29200 0.827627 3.29250 0.872217 3.29300 0.839976 3.29350 0.682757 3.29400 0.498551 3.29450 0.560467 3.29500 0.529294 3.29550 0.310872 3.29600 0.370828 3.29650 0.632644 3.29700 0.723318 3.29750 0.574746 3.29800 0.275939 3.29850 0.148915 3.29900 0.187524 3.29950 0.200564 3.30000 0.372385 3.30050 0.593196 3.30100 0.649042 3.30150 0.513762 3.30200 0.576965 3.30250 0.794993 3.30300 0.876865 3.30350 0.867296 3.30400 0.773104 3.30450 0.519265 3.30500 0.355621 3.30550 0.554754 3.30600 0.768791 3.30650 0.860551 3.30700 0.889241 3.30750 0.860436 3.30800 0.724231 3.30850 0.531470 3.30900 0.559063 3.30950 0.589115 3.31000 0.536321 3.31050 0.633001 3.31100 0.749855 3.31150 0.726666 3.31200 0.520128 3.31250 0.208805 3.31300 3.50122E-02 3.31350 3.01087E-03 3.31400 1.26671E-03 3.31450 3.80167E-03 3.31500 1.35262E-02 3.31550 2.71408E-02 3.31600 3.34067E-02 3.31650 4.18014E-02 3.31700 7.36682E-02 3.31750 0.122044 3.31800 0.126703 3.31850 0.134040 3.31900 0.111121 3.31950 9.55825E-02 3.32000 0.210154 3.32050 0.346944 3.32100 0.405499 3.32150 0.333834 3.32200 0.251975 3.32250 0.379761 3.32300 0.487623 3.32350 0.498639 3.32400 0.601451 3.32450 0.674567 3.32500 0.690361 3.32550 0.704372 3.32600 0.749284 3.32650 0.770722 3.32700 0.681506 3.32750 0.563265 3.32800 0.468280 3.32850 0.452546 3.32900 0.404902 3.32950 0.503752 3.33000 0.763725 3.33050 0.898567 3.33100 0.926654 3.33150 0.927781 3.33200 0.929823 3.33250 0.937668 3.33300 0.932619 3.33350 0.872614 3.33400 0.662674 3.33450 0.534527 3.33500 0.722461 3.33550 0.878062 3.33600 0.931973 3.33650 0.950493 3.33700 0.946962 3.33750 0.922459 3.33800 0.817444 3.33850 0.728850 3.33900 0.693643 3.33950 0.571146 3.34000 0.578143 3.34050 0.687782 3.34100 0.790606 3.34150 0.732030 3.34200 0.630775 3.34250 0.672466 3.34300 0.851666 3.34350 0.929390 3.34400 0.915487 3.34450 0.820378 3.34500 0.598257 3.34550 0.299419 3.34600 0.270836 3.34650 0.482349 3.34700 0.497619 3.34750 0.571485 3.34800 0.812295 3.34850 0.927370 3.34900 0.952117 3.34950 0.955612 3.35000 0.929426 3.35050 0.810463 3.35100 0.711726 3.35150 0.828405 3.35200 0.921983 3.35250 0.898060 3.35300 0.872892 3.35350 0.888445 3.35400 0.818606 3.35450 0.732328 3.35500 0.638457 3.35550 0.609000 3.35600 0.655601 3.35650 0.431378 3.35700 0.212085 3.35750 0.298015 3.35800 0.457460 3.35850 0.700208 3.35900 0.881195 3.35950 0.921450 3.36000 0.923010 3.36050 0.880014 3.36100 0.731258 3.36150 0.669058 3.36200 0.772374 3.36250 0.798552 3.36300 0.603631 3.36350 0.551893 3.36400 0.779823 3.36450 0.913802 3.36500 0.921848 3.36550 0.883246 3.36600 0.894855 3.36650 0.918896 3.36700 0.877561 3.36750 0.743041 3.36800 0.464940 3.36850 0.222155 3.36900 0.351468 3.36950 0.671682 3.37000 0.860901 3.37050 0.880463 3.37100 0.757050 3.37150 0.602160 3.37200 0.707731 3.37250 0.849178 3.37300 0.900511 3.37350 0.935921 3.37400 0.949898 3.37450 0.956225 3.37500 0.956622 3.37550 0.934129 3.37600 0.832512 3.37650 0.700960 3.37700 0.750747 3.37750 0.877735 3.37800 0.931510 3.37850 0.920751 3.37900 0.827866 3.37950 0.546992 3.38000 0.207306 3.38050 0.187789 3.38100 0.501241 3.38150 0.753812 3.38200 0.818282 3.38250 0.832678 3.38300 0.806243 3.38350 0.809017 3.38400 0.867590 3.38450 0.814805 3.38500 0.736118 3.38550 0.751630 3.38600 0.788096 3.38650 0.883794 3.38700 0.946163 3.38750 0.954523 3.38800 0.963240 3.38850 0.965491 3.38900 0.955193 3.38950 0.945517 3.39000 0.935408 3.39050 0.865575 3.39100 0.684179 3.39150 0.363389 3.39200 0.147977 3.39250 0.295101 3.39300 0.665525 3.39350 0.872481 3.39400 0.852606 3.39450 0.806390 3.39500 0.886410 3.39550 0.946926 3.39600 0.953120 3.39650 0.942419 3.39700 0.910869 3.39750 0.883465 3.39800 0.920427 3.39850 0.959429 3.39900 0.966122 3.39950 0.965888 3.40000 0.964562 3.40050 0.959133 3.40100 0.955429 3.40150 0.952306 3.40200 0.941270 3.40250 0.875214 3.40300 0.641708 3.40350 0.358788 3.40400 0.239321 3.40450 0.298555 3.40500 0.574377 3.40550 0.775403 3.40600 0.792986 3.40650 0.730946 3.40700 0.699110 3.40750 0.826285 3.40800 0.857636 3.40850 0.740297 3.40900 0.699973 3.40950 0.803932 3.41000 0.870337 3.41050 0.845349 3.41100 0.869324 3.41150 0.931802 3.41200 0.931212 3.41250 0.882666 3.41300 0.879496 3.41350 0.932583 3.41400 0.945585 3.41450 0.900443 3.41500 0.717920 3.41550 0.493264 3.41600 0.334241 3.41650 0.274816 3.41700 0.524915 3.41750 0.839073 3.41800 0.947135 3.41850 0.961991 3.41900 0.961002 3.41950 0.959999 3.42000 0.957211 3.42050 0.957721 3.42100 0.956905 3.42150 0.956752 3.42200 0.958729 3.42250 0.953321 3.42300 0.944235 3.42350 0.938257 3.42400 0.931174 3.42450 0.926684 3.42500 0.908780 3.42550 0.835615 3.42600 0.789815 3.42650 0.818993 3.42700 0.753777 3.42750 0.593311 3.42800 0.475669 3.42850 0.387997 3.42900 0.448967 3.42950 0.706849 3.43000 0.909537 3.43050 0.950941 3.43100 0.957356 3.43150 0.956556 3.43200 0.951796 3.43250 0.963593 3.43300 0.968264 3.43350 0.954482 3.43400 0.934225 3.43450 0.937634 3.43500 0.940937 3.43550 0.912258 3.43600 0.907996 3.43650 0.920403 3.43700 0.920670 3.43750 0.931723 3.43800 0.935852 3.43850 0.921656 3.43900 0.885740 3.43950 0.770118 3.44000 0.653705 3.44050 0.593934 3.44100 0.636492 3.44150 0.682416 3.44200 0.837907 3.44250 0.927737 3.44300 0.926145 3.44350 0.940609 3.44400 0.959339 3.44450 0.968757 3.44500 0.961495 3.44550 0.917923 3.44600 0.844306 3.44650 0.857763 3.44700 0.931068 3.44750 0.930468 3.44800 0.862567 3.44850 0.866287 3.44900 0.902996 3.44950 0.923655 3.45000 0.943901 3.45050 0.953359 3.45100 0.917704 3.45150 0.838238 3.45200 0.800668 3.45250 0.795415 3.45300 0.763456 3.45350 0.740103 3.45400 0.685250 3.45450 0.779611 3.45500 0.874728 3.45550 0.829543 3.45600 0.865265 3.45650 0.942162 3.45700 0.965817 3.45750 0.971008 3.45800 0.974527 3.45850 0.973906 3.45900 0.969949 3.45950 0.965975 3.46000 0.957669 3.46050 0.958242 3.46100 0.958821 3.46150 0.936755 3.46200 0.919475 3.46250 0.943985 3.46300 0.943677 3.46350 0.926200 3.46400 0.900749 3.46450 0.855791 3.46500 0.804392 3.46550 0.773715 3.46600 0.742394 3.46650 0.768408 3.46700 0.841000 3.46750 0.901808 3.46800 0.905265 3.46850 0.934322 3.46900 0.962645 3.46950 0.970549 3.47000 0.972980 3.47050 0.969704 3.47100 0.966060 3.47150 0.958420 3.47200 0.940794 3.47250 0.920784 3.47300 0.925739 3.47350 0.915190 3.47400 0.873087 3.47450 0.888806 3.47500 0.923229 3.47550 0.906547 3.47600 0.916203 3.47650 0.913899 3.47700 0.883410 3.47750 0.866386 3.47800 0.862903 3.47850 0.859224 3.47900 0.890929 3.47950 0.907703 3.48000 0.909419 3.48050 0.922517 3.48100 0.932526 3.48150 0.947587 3.48200 0.948336 3.48250 0.936223 3.48300 0.932291 3.48350 0.942180 3.48400 0.959903 3.48450 0.972356 3.48500 0.960773 3.48550 0.915780 3.48600 0.896888 3.48650 0.922925 3.48700 0.929716 3.48750 0.902589 3.48800 0.884601 3.48850 0.888542 3.48900 0.853630 3.48950 0.868533 3.49000 0.893525 3.49050 0.892129 3.49100 0.905550 3.49150 0.932652 3.49200 0.948645 3.49250 0.931404 3.49300 0.916768 3.49350 0.913462 3.49400 0.908071 3.49450 0.918627 3.49500 0.947276 3.49550 0.966971 3.49600 0.971297 3.49650 0.963422 3.49700 0.955938 3.49750 0.960099 3.49800 0.949178 3.49850 0.913843 3.49900 0.903277 3.49950 0.928701 3.50000 0.916092 3.50050 0.926237 3.50100 0.957892 3.50150 0.956503 3.50200 0.948687 3.50250 0.945300 3.50300 0.917185 3.50350 0.869709 3.50400 0.867302 3.50450 0.928201 3.50500 0.963235 3.50550 0.966528 3.50600 0.964750 3.50650 0.969629 3.50700 0.968409 3.50750 0.957432 3.50800 0.953337 3.50850 0.964700 3.50900 0.963699 3.50950 0.945694 3.51000 0.946416 3.51050 0.953799 3.51100 0.929929 3.51150 0.883554 3.51200 0.913951 3.51250 0.958877 3.51300 0.968084 3.51350 0.960897 3.51400 0.945299 3.51450 0.934072 3.51500 0.945875 3.51550 0.961818 3.51600 0.959915 3.51650 0.959839 3.51700 0.963237 3.51750 0.963498 3.51800 0.963229 3.51850 0.963537 3.51900 0.952780 3.51950 0.947303 3.52000 0.952410 3.52050 0.948184 3.52100 0.944332 3.52150 0.956223 3.52200 0.967925 3.52250 0.960877 3.52300 0.945014 3.52350 0.945427 3.52400 0.958456 3.52450 0.969761 3.52500 0.969107 3.52550 0.957964 3.52600 0.947315 3.52650 0.938212 3.52700 0.903172 3.52750 0.888101 3.52800 0.919719 3.52850 0.932343 3.52900 0.930589 3.52950 0.955547 3.53000 0.966193 3.53050 0.949302 3.53100 0.906320 3.53150 0.907267 3.53200 0.936225 3.53250 0.940923 3.53300 0.906834 3.53350 0.879392 3.53400 0.923352 3.53450 0.944981 3.53500 0.878656 3.53550 0.759260 3.53600 0.754393 3.53650 0.858428 3.53700 0.918962 3.53750 0.951193 3.53800 0.951346 3.53850 0.885979 3.53900 0.812809 3.53950 0.817626 3.54000 0.854790 3.54050 0.854844 3.54100 0.829168 3.54150 0.854172 3.54200 0.884243 3.54250 0.866413 3.54300 0.854518 3.54350 0.873003 3.54400 0.895926 3.54450 0.913682 3.54500 0.890408 3.54550 0.881525 3.54600 0.895960 3.54650 0.907632 3.54700 0.908812 3.54750 0.871626 3.54800 0.859899 3.54850 0.924517 3.54900 0.952282 3.54950 0.928271 3.55000 0.899211 3.55050 0.923922 3.55100 0.945666 3.55150 0.942808 3.55200 0.928646 3.55250 0.911709 3.55300 0.923847 3.55350 0.901387 3.55400 0.855161 3.55450 0.864056 3.55500 0.873092 3.55550 0.898631 3.55600 0.936643 3.55650 0.943086 3.55700 0.934157 3.55750 0.932456 3.55800 0.931784 3.55850 0.938929 3.55900 0.935141 3.55950 0.899877 3.56000 0.871921 3.56050 0.901541 3.56100 0.948855 3.56150 0.958914 3.56200 0.958503 3.56250 0.963258 3.56300 0.965085 3.56350 0.953583 3.56400 0.926084 3.56450 0.884535 3.56500 0.881881 3.56550 0.906704 3.56600 0.898395 3.56650 0.886223 3.56700 0.857887 3.56750 0.836020 3.56800 0.893727 3.56850 0.927875 3.56900 0.879367 3.56950 0.826559 3.57000 0.882100 3.57050 0.932522 3.57100 0.923562 3.57150 0.881867 3.57200 0.866240 3.57250 0.883643 3.57300 0.891969 3.57350 0.847236 3.57400 0.804469 3.57450 0.821359 3.57500 0.853838 3.57550 0.864893 3.57600 0.865111 3.57650 0.891033 3.57700 0.920547 3.57750 0.922517 3.57800 0.917367 3.57850 0.931453 3.57900 0.934496 3.57950 0.912785 3.58000 0.919756 3.58050 0.927386 3.58100 0.866778 3.58150 0.815407 3.58200 0.840710 3.58250 0.898035 3.58300 0.937369 3.58350 0.934427 3.58400 0.909646 3.58450 0.879553 3.58500 0.874711 3.58550 0.867903 3.58600 0.855161 3.58650 0.896903 3.58700 0.886616 3.58750 0.838346 3.58800 0.881971 3.58850 0.933394 3.58900 0.938334 3.58950 0.914374 3.59000 0.903644 3.59050 0.915227 3.59100 0.915507 3.59150 0.910163 3.59200 0.898077 3.59250 0.887020 3.59300 0.883055 3.59350 0.887080 3.59400 0.916847 3.59450 0.947209 3.59500 0.946351 3.59550 0.940150 3.59600 0.944876 3.59650 0.926088 3.59700 0.882549 3.59750 0.895561 3.59800 0.938200 3.59850 0.947834 3.59900 0.942448 3.59950 0.938339 3.60000 0.917257 3.60050 0.877647 3.60100 0.898906 3.60150 0.941817 3.60200 0.952048 3.60250 0.956553 3.60300 0.957527 3.60350 0.955091 3.60400 0.952915 3.60450 0.933248 3.60500 0.897581 3.60550 0.901115 3.60600 0.912280 3.60650 0.870167 3.60700 0.807533 3.60750 0.791990 3.60800 0.826427 3.60850 0.896437 3.60900 0.938177 3.60950 0.944205 3.61000 0.924852 3.61050 0.922689 3.61100 0.935907 3.61150 0.916428 3.61200 0.891749 3.61250 0.905671 3.61300 0.912726 3.61350 0.876031 3.61400 0.893147 3.61450 0.938227 3.61500 0.953030 3.61550 0.959277 3.61600 0.956464 3.61650 0.936288 3.61700 0.895973 3.61750 0.898596 3.61800 0.939962 3.61850 0.956623 3.61900 0.956900 3.61950 0.949708 3.62000 0.945213 3.62050 0.952477 3.62100 0.948600 3.62150 0.944735 3.62200 0.957778 3.62250 0.962461 3.62300 0.957246 3.62350 0.951719 3.62400 0.952041 3.62450 0.950964 3.62500 0.935901 3.62550 0.898845 3.62600 0.884380 3.62650 0.895868 3.62700 0.871990 3.62750 0.820088 3.62800 0.855970 3.62850 0.933959 3.62900 0.960988 3.62950 0.963313 3.63000 0.963128 3.63050 0.960023 3.63100 0.935763 3.63150 0.888257 3.63200 0.894698 3.63250 0.937017 3.63300 0.952515 3.63350 0.950886 3.63400 0.931678 3.63450 0.899731 3.63500 0.915601 3.63550 0.938327 3.63600 0.941885 3.63650 0.941924 3.63700 0.940434 3.63750 0.952949 3.63800 0.962514 3.63850 0.962234 3.63900 0.955985 3.63950 0.945941 3.64000 0.945788 3.64050 0.950981 3.64100 0.955630 3.64150 0.956803 3.64200 0.956321 3.64250 0.958949 3.64300 0.959973 3.64350 0.960664 3.64400 0.955318 3.64450 0.949449 3.64500 0.950450 3.64550 0.925271 3.64600 0.876637 3.64650 0.859151 3.64700 0.836995 3.64750 0.802784 3.64800 0.859275 3.64850 0.937563 3.64900 0.958321 3.64950 0.960407 3.65000 0.955881 3.65050 0.935646 3.65100 0.906374 3.65150 0.916214 3.65200 0.934818 3.65250 0.943031 3.65300 0.944690 3.65350 0.939893 3.65400 0.949044 3.65450 0.950604 3.65500 0.947874 3.65550 0.954284 3.65600 0.959541 3.65650 0.960866 3.65700 0.960550 3.65750 0.959723 3.65800 0.958480 3.65850 0.958542 3.65900 0.955612 3.65950 0.953420 3.66000 0.957716 3.66050 0.960768 3.66100 0.954450 3.66150 0.938030 3.66200 0.937093 3.66250 0.949150 3.66300 0.942064 3.66350 0.932389 3.66400 0.944345 3.66450 0.956497 3.66500 0.957733 3.66550 0.956908 3.66600 0.956025 3.66650 0.937581 3.66700 0.858404 3.66750 0.773729 3.66800 0.809182 3.66850 0.876456 3.66900 0.920003 3.66950 0.945280 3.67000 0.949404 3.67050 0.940199 3.67100 0.910055 3.67150 0.864136 3.67200 0.849856 3.67250 0.859767 3.67300 0.859187 3.67350 0.846003 3.67400 0.831769 3.67450 0.878836 3.67500 0.856210 3.67550 0.799027 3.67600 0.799760 3.67650 0.849226 3.67700 0.915802 3.67750 0.936782 3.67800 0.912042 3.67850 0.903118 3.67900 0.922868 3.67950 0.921008 3.68000 0.923520 3.68050 0.926579 3.68100 0.926862 3.68150 0.919216 3.68200 0.920999 3.68250 0.928991 3.68300 0.914855 3.68350 0.909011 3.68400 0.932141 3.68450 0.946163 3.68500 0.950466 3.68550 0.954178 3.68600 0.951547 3.68650 0.929166 3.68700 0.875682 3.68750 0.859601 3.68800 0.873028 3.68850 0.894840 3.68900 0.931189 3.68950 0.946528 3.69000 0.951074 3.69050 0.947556 3.69100 0.937292 3.69150 0.935822 3.69200 0.929292 3.69250 0.914140 3.69300 0.930947 3.69350 0.947394 3.69400 0.947416 3.69450 0.947163 3.69500 0.942285 3.69550 0.945636 3.69600 0.954704 3.69650 0.954193 3.69700 0.941326 3.69750 0.935661 3.69800 0.948744 3.69850 0.956100 3.69900 0.955470 3.69950 0.952220 3.70000 0.949464 3.70050 0.947561 3.70100 0.948760 3.70150 0.954742 3.70200 0.957702 3.70250 0.957937 3.70300 0.957704 3.70350 0.957270 3.70400 0.954643 3.70450 0.951360 3.70500 0.952056 3.70550 0.951006 3.70600 0.945770 3.70650 0.930439 3.70700 0.922548 3.70750 0.926628 3.70800 0.934038 3.70850 0.936375 3.70900 0.903445 3.70950 0.882846 3.71000 0.891409 3.71050 0.901868 3.71100 0.928437 3.71150 0.938689 3.71200 0.937999 3.71250 0.936016 3.71300 0.921042 3.71350 0.881337 3.71400 0.889461 3.71450 0.930326 3.71500 0.932213 3.71550 0.924302 3.71600 0.933242 3.71650 0.947356 3.71700 0.941503 3.71750 0.911876 3.71800 0.907920 3.71850 0.936590 3.71900 0.948796 3.71950 0.949710 3.72000 0.951365 3.72050 0.952735 3.72100 0.952050 3.72150 0.951961 3.72200 0.951560 3.72250 0.950264 3.72300 0.950007 3.72350 0.950332 3.72400 0.946849 3.72450 0.942955 3.72500 0.944462 3.72550 0.946432 3.72600 0.937751 3.72650 0.931045 3.72700 0.934623 3.72750 0.934603 3.72800 0.928638 3.72850 0.936472 3.72900 0.945149 3.72950 0.930388 3.73000 0.878069 3.73050 0.860205 3.73100 0.909951 3.73150 0.942886 3.73200 0.950124 3.73250 0.948110 3.73300 0.932670 3.73350 0.908456 3.73400 0.886842 3.73450 0.863841 3.73500 0.899069 3.73550 0.924609 3.73600 0.906507 3.73650 0.907417 3.73700 0.925700 3.73750 0.920371 3.73800 0.906907 3.73850 0.924384 3.73900 0.938865 3.73950 0.938658 3.74000 0.942298 3.74050 0.940206 3.74100 0.922391 3.74150 0.885018 3.74200 0.891771 3.74250 0.929324 3.74300 0.940905 3.74350 0.940096 3.74400 0.943700 3.74450 0.944691 3.74500 0.942212 3.74550 0.941783 3.74600 0.942349 3.74650 0.941717 3.74700 0.941991 3.74750 0.945678 3.74800 0.944581 3.74850 0.940878 3.74900 0.938062 3.74950 0.932117 3.75000 0.899876 3.75050 0.865114 3.75100 0.900388 3.75150 0.932785 3.75200 0.926605 3.75250 0.923447 3.75300 0.932378 3.75350 0.938416 3.75400 0.921922 3.75450 0.871800 3.75500 0.872188 3.75550 0.922640 3.75600 0.941501 3.75650 0.942789 3.75700 0.944763 3.75750 0.944055 3.75800 0.930029 3.75850 0.901654 3.75900 0.905667 3.75950 0.923418 3.76000 0.913207 3.76050 0.911874 3.76100 0.932129 3.76150 0.939606 3.76200 0.935262 3.76250 0.920768 3.76300 0.898019 3.76350 0.906853 3.76400 0.926015 3.76450 0.921383 3.76500 0.910073 3.76550 0.878260 3.76600 0.872561 3.76650 0.914432 3.76700 0.931654 3.76750 0.937308 3.76800 0.941692 3.76850 0.943201 3.76900 0.942452 3.76950 0.938827 3.77000 0.928828 3.77050 0.896673 3.77100 0.867158 3.77150 0.899643 3.77200 0.927268 3.77250 0.934884 3.77300 0.938675 3.77350 0.930306 3.77400 0.894836 3.77450 0.862631 3.77500 0.896464 3.77550 0.931780 3.77600 0.938854 3.77650 0.937980 3.77700 0.932634 3.77750 0.933122 3.77800 0.938793 3.77850 0.939429 3.77900 0.935184 3.77950 0.927727 3.78000 0.930182 3.78050 0.931709 3.78100 0.911485 3.78150 0.893550 3.78200 0.915248 3.78250 0.932790 3.78300 0.934150 3.78350 0.928157 3.78400 0.909863 3.78450 0.893317 3.78500 0.892837 3.78550 0.911687 3.78600 0.929699 3.78650 0.936321 3.78700 0.937182 3.78750 0.935612 3.78800 0.931519 3.78850 0.924863 3.78900 0.902808 3.78950 0.853690 3.79000 0.841900 3.79050 0.888697 3.79100 0.899090 3.79150 0.874720 3.79200 0.886100 3.79250 0.920494 3.79300 0.930601 3.79350 0.915685 3.79400 0.876802 3.79450 0.878718 3.79500 0.916834 3.79550 0.930172 3.79600 0.931193 3.79650 0.931476 3.79700 0.926743 3.79750 0.912376 3.79800 0.899385 3.79850 0.915912 3.79900 0.930605 3.79950 0.930251 3.80000 0.922275 3.80050 0.922143 3.80100 0.927319 3.80150 0.927451 3.80200 0.927806 3.80250 0.929537 3.80300 0.928757 3.80350 0.921441 3.80400 0.899801 3.80450 0.888154 3.80500 0.906717 3.80550 0.924416 3.80600 0.929197 3.80650 0.930794 3.80700 0.929987 3.80750 0.925672 3.80800 0.914990 3.80850 0.905939 3.80900 0.899362 3.80950 0.901918 3.81000 0.911155 3.81050 0.912217 3.81100 0.907999 3.81150 0.914501 3.81200 0.907648 3.81250 0.878559 3.81300 0.871396 3.81350 0.866071 3.81400 0.857239 3.81450 0.881508 3.81500 0.915050 3.81550 0.925625 3.81600 0.925674 3.81650 0.914607 3.81700 0.892660 3.81750 0.897223 3.81800 0.918311 3.81850 0.920119 3.81900 0.902556 3.81950 0.898328 3.82000 0.917762 3.82050 0.926920 3.82100 0.928334 3.82150 0.929017 3.82200 0.928856 3.82250 0.928963 3.82300 0.928726 3.82350 0.927230 3.82400 0.920239 3.82450 0.915502 3.82500 0.919529 3.82550 0.919656 3.82600 0.923261 3.82650 0.925718 3.82700 0.919091 3.82750 0.904191 3.82800 0.906639 3.82850 0.920056 3.82900 0.925007 3.82950 0.925211 3.83000 0.924883 3.83050 0.923470 3.83100 0.921535 3.83150 0.920292 3.83200 0.916980 3.83250 0.911526 3.83300 0.912049 3.83350 0.898557 3.83400 0.877582 3.83450 0.876125 3.83500 0.873951 3.83550 0.887489 3.83600 0.901969 3.83650 0.896289 3.83700 0.891827 3.83750 0.904988 3.83800 0.905702 3.83850 0.902151 3.83900 0.908147 3.83950 0.907419 3.84000 0.903458 3.84050 0.901534 3.84100 0.907768 3.84150 0.909086 3.84200 0.907170 3.84250 0.907203 3.84300 0.901438 3.84350 0.895419 3.84400 0.898175 3.84450 0.894736 3.84500 0.888385 3.84550 0.890968 3.84600 0.887148 3.84650 0.882521 3.84700 0.877438 3.84750 0.881467 3.84800 0.888676 3.84850 0.893875 3.84900 0.901605 3.84950 0.905661 3.85000 0.901693 3.85050 0.893832 3.85100 0.888552 3.85150 0.896461 3.85200 0.902764 3.85250 0.902770 3.85300 0.903896 3.85350 0.903785 3.85400 0.901893 3.85450 0.900865 3.85500 0.892898 3.85550 0.878873 3.85600 0.870518 3.85650 0.880831 3.85700 0.891815 3.85750 0.893516 3.85800 0.891539 3.85850 0.884247 3.85900 0.871688 3.85950 0.866859 3.86000 0.874359 3.86050 0.878809 3.86100 0.877739 3.86150 0.870645 3.86200 0.867207 3.86250 0.860285 3.86300 0.857616 3.86350 0.857616 3.86400 0.861373 3.86450 0.861431 3.86500 0.858028 3.86550 0.855213 3.86600 0.847457 3.86650 0.849141 3.86700 0.842916 3.86750 0.837250 3.86800 0.827011 3.86850 0.825227 3.86900 0.817496 3.86950 0.824437 3.87000 0.823015 3.87050 0.821470 3.87100 0.814600 3.87150 0.816815 3.87200 0.803373 3.87250 0.794406 3.87300 0.790290 3.87350 0.803279 3.87400 0.794914 3.87450 0.795960 3.87500 0.793137 3.87550 0.800080 3.87600 0.790848 3.87650 0.795720 3.87700 0.777758 3.87750 0.778835 3.87800 0.763146 3.87850 0.783537 3.87900 0.773600 3.87950 0.787414 3.88000 0.771176 3.88050 0.778252 3.88100 0.764849 3.88150 0.775734 3.88200 0.771553 3.88250 0.770202 3.88300 0.777867 3.88350 0.769159 3.88400 0.783888 3.88450 0.765064 3.88500 0.783867 3.88550 0.758678 3.88600 0.775110 3.88650 0.768182 3.88700 0.776628 3.88750 0.784267 3.88800 0.770434 3.88850 0.790383 3.88900 0.766714 3.88950 0.787321 3.89000 0.774275 3.89050 0.776642 3.89100 0.778058 3.89150 0.778179 3.89200 0.801082 3.89250 0.780286 3.89300 0.800587 3.89350 0.792846 3.89400 0.800228 3.89450 0.813858 3.89500 0.802728 3.89550 0.829085 3.89600 0.818642 3.89650 0.830523 3.89700 0.842055 3.89750 0.830284 3.89800 0.846659 3.89850 0.844890 3.89900 0.852682 3.89950 0.862854 3.90000 0.858421 3.90050 0.865934 3.90100 0.875806 3.90150 0.875606 3.90200 0.867403 3.90250 0.861125 3.90300 0.856016 3.90350 0.837602 3.90400 0.842767 3.90450 0.844057 3.90500 0.828002 3.90550 0.839817 3.90600 0.818910 3.90650 0.809439 3.90700 0.833037 3.90750 0.808596 3.90800 0.819508 3.90850 0.823713 3.90900 0.793778 3.90950 0.811833 3.91000 0.774555 3.91050 0.751832 3.91100 0.797041 3.91150 0.779991 3.91200 0.791990 3.91250 0.810021 3.91300 0.774358 3.91350 0.801923 3.91400 0.798882 3.91450 0.770916 3.91500 0.806702 3.91550 0.783009 3.91600 0.769207 3.91650 0.804367 3.91700 0.770844 3.91750 0.779912 3.91800 0.807344 3.91850 0.763763 3.91900 0.787400 3.91950 0.803665 3.92000 0.761555 3.92050 0.795571 3.92100 0.796438 3.92150 0.758724 3.92200 0.800827 3.92250 0.793502 3.92300 0.762855 3.92350 0.806084 3.92400 0.790088 3.92450 0.763916 3.92500 0.801453 3.92550 0.777236 3.92600 0.763287 3.92650 0.807545 3.92700 0.779617 3.92750 0.768704 3.92800 0.811629 3.92850 0.780229 3.92900 0.771407 3.92950 0.818360 3.93000 0.793956 3.93050 0.782159 3.93100 0.821785 3.93150 0.798395 3.93200 0.783563 3.93250 0.822445 3.93300 0.804857 3.93350 0.789000 3.93400 0.826638 3.93450 0.811891 3.93500 0.791612 3.93550 0.826833 3.93600 0.818617 3.93650 0.794508 3.93700 0.825884 3.93750 0.824173 3.93800 0.796177 3.93850 0.822917 3.93900 0.830454 3.93950 0.802728 3.94000 0.821858 3.94050 0.835511 3.94100 0.804791 3.94150 0.807606 3.94200 0.824007 3.94250 0.802379 3.94300 0.809184 3.94350 0.838984 3.94400 0.826825 3.94450 0.817147 3.94500 0.838744 3.94550 0.832704 3.94600 0.817153 3.94650 0.835370 3.94700 0.838579 3.94750 0.819660 3.94800 0.829818 3.94850 0.842990 3.94900 0.828789 3.94950 0.828609 3.95000 0.843315 3.95050 0.834852 3.95100 0.826725 3.95150 0.839850 3.95200 0.837967 3.95250 0.821698 3.95300 0.829299 3.95350 0.839619 3.95400 0.825000 3.95450 0.820725 3.95500 0.837216 3.95550 0.837163 3.95600 0.831801 3.95650 0.839691 3.95700 0.840750 3.95750 0.832875 3.95800 0.832496 3.95850 0.826060 3.95900 0.819936 3.95950 0.828257 3.96000 0.838252 3.96050 0.838305 3.96100 0.832826 3.96150 0.836390 3.96200 0.839439 3.96250 0.834936 3.96300 0.834106 3.96350 0.838123 3.96400 0.836587 3.96450 0.832532 3.96500 0.835211 3.96550 0.836506 3.96600 0.833419 3.96650 0.832621 3.96700 0.834792 3.96750 0.834187 3.96800 0.830477 3.96850 0.831338 3.96900 0.832950 3.96950 0.830737 3.97000 0.829514 3.97050 0.831007 3.97100 0.830440 3.97150 0.827375 3.97200 0.828173 3.97250 0.829135 3.97300 0.827664 3.97350 0.826265 3.97400 0.825511 3.97450 0.822606 3.97500 0.810896 3.97550 0.805542 3.97600 0.812903 3.97650 0.815329 3.97700 0.816207 3.97750 0.820252 3.97800 0.822824 3.97850 0.821232 3.97900 0.817784 3.97950 0.813052 3.98000 0.808779 3.98050 0.808101 3.98100 0.807428 3.98150 0.799935 3.98200 0.805205 3.98250 0.814153 3.98300 0.816043 3.98350 0.815537 3.98400 0.815483 3.98450 0.814255 3.98500 0.813752 3.98550 0.812937 3.98600 0.812273 3.98650 0.812170 3.98700 0.811505 3.98750 0.811284 3.98800 0.810109 3.98850 0.809644 3.98900 0.809318 3.98950 0.808340 3.99000 0.808011 3.99050 0.807054 3.99100 0.806770 3.99150 0.805809 3.99200 0.804086 3.99250 0.801399 3.99300 0.800418 3.99350 0.801883 3.99400 0.801775 3.99450 0.800565 3.99500 0.799542 3.99550 0.798779 3.99600 0.798086 3.99650 0.798631 3.99700 0.798746 3.99750 0.798100 3.99800 0.797432 3.99850 0.796848 3.99900 0.795769 3.99950 0.794321 4.00000 0.793263 4.00050 0.792460 4.00100 0.791906 4.00150 0.790770 4.00200 0.789996 4.00250 0.789282 4.00300 0.788595 4.00350 0.787513 4.00400 0.786554 4.00450 0.785536 4.00500 0.784638 4.00550 0.784021 4.00600 0.782618 4.00650 0.780995 4.00700 0.775564 4.00750 0.770433 4.00800 0.765232 4.00850 0.757148 4.00900 0.757792 4.00950 0.756861 4.01000 0.759298 4.01050 0.768317 4.01100 0.770548 4.01150 0.770972 4.01200 0.769822 4.01250 0.769100 4.01300 0.767485 4.01350 0.765223 4.01400 0.765563 4.01450 0.763732 4.01500 0.762289 4.01550 0.760590 4.01600 0.759253 4.01650 0.759907 4.01700 0.757148 4.01750 0.756945 4.01800 0.755749 4.01850 0.753165 4.01900 0.753944 4.01950 0.750041 4.02000 0.750373 4.02050 0.748762 4.02100 0.745739 4.02150 0.747494 4.02200 0.742465 4.02250 0.743530 4.02300 0.741628 4.02350 0.738010 4.02400 0.740852 4.02450 0.734761 4.02500 0.736114 4.02550 0.733957 4.02600 0.728735 4.02650 0.732631 4.02700 0.725807 4.02750 0.726901 4.02800 0.727063 4.02850 0.721243 4.02900 0.725600 4.02950 0.719416 4.03000 0.719085 4.03050 0.721076 4.03100 0.713298 4.03150 0.717759 4.03200 0.712527 4.03250 0.708457 4.03300 0.713619 4.03350 0.704902 4.03400 0.708598 4.03450 0.706877 4.03500 0.697022 4.03550 0.697391 4.03600 0.685643 4.03650 0.688292 4.03700 0.697357 4.03750 0.690877 4.03800 0.699090 4.03850 0.693976 4.03900 0.689388 4.03950 0.697016 4.04000 0.686202 4.04050 0.689952 4.04100 0.690084 4.04150 0.676406 4.04200 0.680439 4.04250 0.673635 4.04300 0.672087 4.04350 0.682467 4.04400 0.672222 4.04450 0.674923 4.04500 0.678092 4.04550 0.671753 4.04600 0.680591 4.04650 0.673689 4.04700 0.671418 4.04750 0.678680 4.04800 0.669166 4.04850 0.673266 4.04900 0.674266 4.04950 0.666165 4.05000 0.673390 4.05050 0.668879 4.05100 0.665713 4.05150 0.671790 4.05200 0.664507 4.05250 0.666431 4.05300 0.668763 4.05350 0.661806 4.05400 0.666112 4.05450 0.664741 4.05500 0.660522 4.05550 0.664381 4.05600 0.661264 4.05650 0.660885 4.05700 0.663735 4.05750 0.660073 4.05800 0.661080 4.05850 0.662057 4.05900 0.659388 4.05950 0.660228 4.06000 0.660142 4.06050 0.658821 4.06100 0.658988 4.06150 0.659079 4.06200 0.657548 4.06250 0.654597 4.06300 0.651550 4.06350 0.650216 4.06400 0.647559 4.06450 0.642944 4.06500 0.640364 4.06550 0.633352 4.06600 0.631183 4.06650 0.636216 4.06700 0.631714 4.06750 0.628857 4.06800 0.630853 4.06850 0.623109 4.06900 0.621957 4.06950 0.622982 4.07000 0.614772 4.07050 0.617389 4.07100 0.616443 4.07150 0.607690 4.07200 0.612120 4.07250 0.608249 4.07300 0.601014 4.07350 0.606759 4.07400 0.599692 4.07450 0.594709 4.07500 0.600943 4.07550 0.591631 4.07600 0.589207 4.07650 0.592944 4.07700 0.580809 4.07750 0.581454 4.07800 0.585150 4.07850 0.575752 4.07900 0.579831 4.07950 0.578633 4.08000 0.565349 4.08050 0.572882 4.08100 0.573585 4.08150 0.564527 4.08200 0.571876 4.08250 0.567617 4.08300 0.559065 4.08350 0.566456 4.08400 0.560799 4.08450 0.555039 4.08500 0.561607 4.08550 0.553861 4.08600 0.550834 4.08650 0.556923 4.08700 0.547084 4.08750 0.545627 4.08800 0.551482 4.08850 0.541618 4.08900 0.540525 4.08950 0.544633 4.09000 0.535922 4.09050 0.536957 4.09100 0.538536 4.09150 0.528791 4.09200 0.531837 4.09250 0.533723 4.09300 0.523976 4.09350 0.525478 4.09400 0.526841 4.09450 0.519121 4.09500 0.520014 4.09550 0.514918 4.09600 0.507542 4.09650 0.514729 4.09700 0.514821 4.09750 0.506707 4.09800 0.508551 4.09850 0.507943 4.09900 0.502017 4.09950 0.503890 4.10000 0.500565 4.10050 0.494693 4.10100 0.497707 4.10150 0.495578 4.10200 0.489234 4.10250 0.489486 4.10300 0.487684 4.10350 0.483577 4.10400 0.484567 4.10450 0.481145 4.10500 0.475654 4.10550 0.476932 4.10600 0.474882 4.10650 0.470113 4.10700 0.469343 4.10750 0.466443 4.10800 0.462777 4.10850 0.462775 4.10900 0.460147 4.10950 0.455150 4.11000 0.454054 4.11050 0.452066 4.11100 0.447959 4.11150 0.446527 4.11200 0.442661 4.11250 0.437438 4.11300 0.436298 4.11350 0.434320 4.11400 0.431779 4.11450 0.430495 4.11500 0.427799 4.11550 0.423068 4.11600 0.419921 4.11650 0.416893 4.11700 0.412462 4.11750 0.411159 4.11800 0.410682 4.11850 0.407446 4.11900 0.404547 4.11950 0.402311 4.12000 0.398946 4.12050 0.395920 4.12100 0.393190 4.12150 0.389319 4.12200 0.386284 4.12250 0.384075 4.12300 0.380870 4.12350 0.377507 4.12400 0.374187 4.12450 0.370612 4.12500 0.367789 4.12550 0.365124 4.12600 0.361552 4.12650 0.356997 4.12700 0.353454 4.12750 0.351058 4.12800 0.348513 4.12850 0.345645 4.12900 0.342480 4.12950 0.338538 4.13000 0.334527 4.13050 0.331755 4.13100 0.328949 4.13150 0.325707 4.13200 0.322348 4.13250 0.318336 4.13300 0.314242 4.13350 0.311537 4.13400 0.308689 4.13450 0.305240 4.13500 0.301753 4.13550 0.297682 4.13600 0.293539 4.13650 0.290778 4.13700 0.287876 4.13750 0.284380 4.13800 0.280770 4.13850 0.276724 4.13900 0.272669 4.13950 0.269695 4.14000 0.266630 4.14050 0.263127 4.14100 0.259452 4.14150 0.255420 4.14200 0.251279 4.14250 0.248076 4.14300 0.244996 4.14350 0.241532 4.14400 0.237879 4.14450 0.233991 4.14500 0.229863 4.14550 0.226430 4.14600 0.223260 4.14650 0.219746 4.14700 0.216084 4.14750 0.212160 4.14800 0.207682 4.14850 0.203708 4.14900 0.200850 4.14950 0.197747 4.15000 0.194214 4.15050 0.190534 4.15100 0.186569 4.15150 0.182330 4.15200 0.178744 4.15250 0.175597 4.15300 0.171951 4.15350 0.168292 4.15400 0.164681 4.15450 0.160857 4.15500 0.157487 4.15550 0.154384 4.15600 0.150954 4.15650 0.147419 4.15700 0.143876 4.15750 0.140206 4.15800 0.136330 4.15850 0.132830 4.15900 0.129759 4.15950 0.126502 4.16000 0.123112 4.16050 0.119692 4.16100 0.116244 4.16150 0.112833 4.16200 0.109603 4.16250 0.106390 4.16300 1.03140E-01 4.16350 9.99059E-02 4.16400 9.66974E-02 4.16450 9.34549E-02 4.16500 9.02848E-02 4.16550 8.72630E-02 4.16600 8.42312E-02 4.16650 8.12137E-02 4.16700 7.82405E-02 4.16750 7.52792E-02 4.16800 7.23399E-02 4.16850 6.94750E-02 4.16900 6.66983E-02 4.16950 6.39533E-02 4.17000 6.12338E-02 4.17050 5.85592E-02 4.17100 5.59368E-02 4.17150 5.33413E-02 4.17200 5.08086E-02 4.17250 4.83752E-02 4.17300 4.59705E-02 4.17350 4.36091E-02 4.17400 4.13232E-02 4.17450 3.90819E-02 4.17500 3.68913E-02 4.17550 3.47646E-02 4.17600 3.27242E-02 4.17650 3.07441E-02 4.17700 2.88065E-02 4.17750 2.69104E-02 4.17800 2.50773E-02 4.17850 2.33034E-02 4.17900 2.15705E-02 4.17950 1.98873E-02 4.18000 1.82441E-02 4.18050 1.66531E-02 4.18100 1.50602E-02 4.18150 1.35810E-02 4.18200 1.20403E-02 4.18250 1.07259E-02 4.18300 9.29839E-03 4.18350 8.17188E-03 4.18400 6.93094E-03 4.18450 5.92354E-03 4.18500 5.01647E-03 4.18550 4.05469E-03 4.18600 3.52783E-03 4.18650 2.60022E-03 4.18700 2.28597E-03 4.18750 1.62705E-03 4.18800 1.26226E-03 4.18850 1.01039E-03 4.18900 5.98714E-04 4.18950 5.19988E-04 4.19000 3.05751E-04 4.19050 1.81818E-04 4.19100 1.46604E-04 4.19150 5.89732E-05 4.19200 3.41927E-05 4.19250 2.08923E-05 4.19300 4.06534E-06 4.19350 2.17920E-07 4.19400 2.87676E-09 4.19450 0. 4.19500 0. 4.19550 0. 4.19600 0. 4.19650 0. 4.19700 0. 4.19750 0. 4.19800 0. 4.19850 0. 4.19900 0. 4.19950 0. 4.20000 0. 4.20050 0. 4.20100 0. 4.20150 0. 4.20200 0. 4.20250 0. 4.20300 0. 4.20350 0. 4.20400 0. 4.20450 0. 4.20500 0. 4.20550 0. 4.20600 0. 4.20650 0. 4.20700 0. 4.20750 0. 4.20800 0. 4.20850 0. 4.20900 0. 4.20950 0. 4.21000 0. 4.21050 0. 4.21100 0. 4.21150 0. 4.21200 0. 4.21250 0. 4.21300 0. 4.21350 0. 4.21400 0. 4.21450 0. 4.21500 0. 4.21550 0. 4.21600 0. 4.21650 0. 4.21700 0. 4.21750 0. 4.21800 0. 4.21850 0. 4.21900 0. 4.21950 0. 4.22000 0. 4.22050 0. 4.22100 0. 4.22150 0. 4.22200 0. 4.22250 0. 4.22300 0. 4.22350 0. 4.22400 0. 4.22450 0. 4.22500 0. 4.22550 0. 4.22600 0. 4.22650 0. 4.22700 0. 4.22750 0. 4.22800 0. 4.22850 0. 4.22900 0. 4.22950 0. 4.23000 0. 4.23050 0. 4.23100 0. 4.23150 0. 4.23200 0. 4.23250 0. 4.23300 0. 4.23350 0. 4.23400 0. 4.23450 0. 4.23500 0. 4.23550 0. 4.23600 0. 4.23650 0. 4.23700 0. 4.23750 0. 4.23800 0. 4.23850 0. 4.23900 0. 4.23950 0. 4.24000 0. 4.24050 0. 4.24100 0. 4.24150 0. 4.24200 0. 4.24250 0. 4.24300 0. 4.24350 0. 4.24400 0. 4.24450 0. 4.24500 0. 4.24550 0. 4.24600 0. 4.24650 0. 4.24700 0. 4.24750 0. 4.24800 0. 4.24850 0. 4.24900 0. 4.24950 0. 4.25000 0. 4.25050 0. 4.25100 0. 4.25150 0. 4.25200 0. 4.25250 0. 4.25300 0. 4.25350 0. 4.25400 0. 4.25450 0. 4.25500 0. 4.25550 0. 4.25600 0. 4.25650 0. 4.25700 0. 4.25750 0. 4.25800 0. 4.25850 0. 4.25900 0. 4.25950 0. 4.26000 0. 4.26050 0. 4.26100 0. 4.26150 0. 4.26200 0. 4.26250 0. 4.26300 0. 4.26350 0. 4.26400 0. 4.26450 0. 4.26500 0. 4.26550 0. 4.26600 0. 4.26650 0. 4.26700 0. 4.26750 0. 4.26800 0. 4.26850 0. 4.26900 0. 4.26950 0. 4.27000 0. 4.27050 0. 4.27100 0. 4.27150 0. 4.27200 0. 4.27250 0. 4.27300 0. 4.27350 0. 4.27400 0. 4.27450 0. 4.27500 0. 4.27550 0. 4.27600 0. 4.27650 0. 4.27700 0. 4.27750 0. 4.27800 0. 4.27850 0. 4.27900 0. 4.27950 0. 4.28000 0. 4.28050 0. 4.28100 0. 4.28150 0. 4.28200 0. 4.28250 0. 4.28300 0. 4.28350 0. 4.28400 0. 4.28450 0. 4.28500 0. 4.28550 0. 4.28600 0. 4.28650 0. 4.28700 0. 4.28750 0. 4.28800 0. 4.28850 0. 4.28900 0. 4.28950 0. 4.29000 0. 4.29050 0. 4.29100 0. 4.29150 0. 4.29200 0. 4.29250 0. 4.29300 0. 4.29350 0. 4.29400 0. 4.29450 0. 4.29500 0. 4.29550 0. 4.29600 0. 4.29650 0. 4.29700 0. 4.29750 0. 4.29800 0. 4.29850 0. 4.29900 0. 4.29950 0. 4.30000 0. 4.30050 0. 4.30100 0. 4.30150 0. 4.30200 0. 4.30250 0. 4.30300 0. 4.30350 0. 4.30400 0. 4.30450 0. 4.30500 0. 4.30550 0. 4.30600 0. 4.30650 0. 4.30700 0. 4.30750 0. 4.30800 0. 4.30850 0. 4.30900 0. 4.30950 0. 4.31000 0. 4.31050 0. 4.31100 0. 4.31150 0. 4.31200 0. 4.31250 0. 4.31300 0. 4.31350 0. 4.31400 0. 4.31450 0. 4.31500 0. 4.31550 0. 4.31600 0. 4.31650 0. 4.31700 0. 4.31750 0. 4.31800 0. 4.31850 0. 4.31900 0. 4.31950 0. 4.32000 0. 4.32050 0. 4.32100 0. 4.32150 0. 4.32200 0. 4.32250 0. 4.32300 0. 4.32350 0. 4.32400 0. 4.32450 0. 4.32500 0. 4.32550 0. 4.32600 0. 4.32650 0. 4.32700 0. 4.32750 0. 4.32800 0. 4.32850 0. 4.32900 0. 4.32950 0. 4.33000 0. 4.33050 0. 4.33100 0. 4.33150 0. 4.33200 0. 4.33250 0. 4.33300 0. 4.33350 0. 4.33400 0. 4.33450 0. 4.33500 0. 4.33550 0. 4.33600 0. 4.33650 0. 4.33700 0. 4.33750 0. 4.33800 0. 4.33850 0. 4.33900 0. 4.33950 0. 4.34000 0. 4.34050 0. 4.34100 0. 4.34150 0. 4.34200 0. 4.34250 0. 4.34300 0. 4.34350 0. 4.34400 0. 4.34450 0. 4.34500 0. 4.34550 0. 4.34600 0. 4.34650 0. 4.34700 0. 4.34750 0. 4.34800 0. 4.34850 0. 4.34900 0. 4.34950 0. 4.35000 0. 4.35050 0. 4.35100 0. 4.35150 0. 4.35200 0. 4.35250 0. 4.35300 0. 4.35350 0. 4.35400 0. 4.35450 0. 4.35500 0. 4.35550 0. 4.35600 0. 4.35650 0. 4.35700 0. 4.35750 0. 4.35800 0. 4.35850 0. 4.35900 0. 4.35950 0. 4.36000 0. 4.36050 0. 4.36100 0. 4.36150 0. 4.36200 0. 4.36250 0. 4.36300 0. 4.36350 0. 4.36400 0. 4.36450 0. 4.36500 0. 4.36550 0. 4.36600 0. 4.36650 0. 4.36700 0. 4.36750 0. 4.36800 0. 4.36850 0. 4.36900 0. 4.36950 0. 4.37000 0. 4.37050 0. 4.37100 0. 4.37150 1.45745E-09 4.37200 1.89976E-07 4.37250 4.72338E-06 4.37300 3.39044E-05 4.37350 6.98734E-05 4.37400 4.10755E-05 4.37450 7.34538E-06 4.37500 1.28891E-05 4.37550 9.75554E-05 4.37600 2.52611E-04 4.37650 2.15945E-04 4.37700 5.83381E-05 4.37750 2.88221E-05 4.37800 2.57909E-04 4.37850 8.91630E-04 4.37900 1.24768E-03 4.37950 1.53929E-03 4.38000 1.96160E-03 4.38050 1.23701E-03 4.38100 4.66956E-04 4.38150 1.91997E-04 4.38200 4.84889E-05 4.38250 1.52762E-05 4.38300 7.38050E-05 4.38350 3.29145E-04 4.38400 4.96661E-04 4.38450 2.15111E-04 4.38500 2.70901E-05 4.38550 4.54316E-06 4.38600 3.78773E-05 4.38650 1.16438E-04 4.38700 1.14703E-04 4.38750 3.99505E-05 4.38800 4.75128E-06 4.38850 1.50953E-06 4.38900 1.55983E-05 4.38950 4.84433E-05 4.39000 4.02808E-05 4.39050 8.91040E-06 4.39100 5.22384E-07 4.39150 8.81681E-09 4.39200 1.41008E-07 4.39250 3.35473E-06 4.39300 2.13106E-05 4.39350 3.65936E-05 4.39400 1.70251E-05 4.39450 2.15445E-06 4.39500 4.58233E-07 4.39550 7.33621E-06 4.39600 3.87604E-05 4.39650 5.75940E-05 4.39700 2.43400E-05 4.39750 2.92557E-06 4.39800 1.24957E-07 4.39850 1.40379E-06 4.39900 2.08596E-05 4.39950 8.92652E-05 4.40000 1.12751E-04 4.40050 4.28264E-05 4.40100 4.88213E-06 4.40150 7.90382E-07 4.40200 1.14748E-05 4.40250 6.14110E-05 4.40300 9.88700E-05 4.40350 4.93643E-05 4.40400 8.08794E-06 4.40450 5.09460E-07 4.40500 9.36044E-07 4.40550 9.44320E-06 4.40600 3.92555E-05 4.40650 8.75527E-05 4.40700 8.32043E-05 4.40750 2.51813E-05 4.40800 2.29733E-06 4.40850 2.45936E-06 4.40900 2.59770E-05 4.40950 1.37453E-04 4.41000 2.69817E-04 4.41050 1.77976E-04 4.41100 3.93874E-05 4.41150 3.10249E-06 4.41200 1.26939E-05 4.41250 1.81001E-04 4.41300 8.06423E-04 4.41350 1.19935E-03 4.41400 6.33457E-04 4.41450 1.19440E-04 4.41500 9.35754E-06 4.41550 5.50369E-05 4.41600 5.35522E-04 4.41650 1.82873E-03 4.41700 2.22286E-03 4.41750 9.24570E-04 4.41800 1.23985E-04 4.41850 1.03996E-05 4.41900 1.23113E-04 4.41950 8.98436E-04 4.42000 2.14764E-03 4.42050 1.75847E-03 4.42100 6.27424E-04 4.42150 2.04135E-04 4.42200 4.96044E-05 4.42250 9.21165E-05 4.42300 8.01634E-04 4.42350 2.46058E-03 4.42400 2.63355E-03 4.42450 1.71595E-03 4.42500 9.48818E-04 4.42550 2.35021E-04 4.42600 1.45257E-04 4.42650 9.98260E-04 4.42700 2.47239E-03 4.42750 3.05703E-03 4.42800 5.99212E-03 4.42850 7.43127E-03 4.42900 3.17459E-03 4.42950 4.97004E-04 4.43000 5.45414E-04 4.43050 2.09134E-03 4.43100 7.48731E-03 4.43150 2.07705E-02 4.43200 2.41198E-02 4.43250 1.09202E-02 4.43300 1.85035E-03 4.43350 1.53272E-04 4.43400 7.68504E-04 4.43450 7.40557E-03 4.43500 2.81424E-02 4.43550 3.74237E-02 4.43600 1.68647E-02 4.43650 2.83228E-03 4.43700 3.98465E-04 4.43750 9.84583E-04 4.43800 8.99221E-03 4.43850 2.94991E-02 4.43900 3.68256E-02 4.43950 2.60548E-02 4.44000 1.14614E-02 4.44050 3.78331E-03 4.44100 1.24692E-03 4.44150 3.34536E-03 4.44200 1.65728E-02 4.44250 4.74705E-02 4.44300 6.21879E-02 4.44350 3.59381E-02 4.44400 2.09443E-02 4.44450 1.27589E-02 4.44500 4.14917E-03 4.44550 1.26294E-02 4.44600 5.40787E-02 4.44650 7.95956E-02 4.44700 4.98576E-02 4.44750 4.66747E-02 4.44800 4.48139E-02 4.44850 1.79792E-02 4.44900 9.38092E-03 4.44950 3.54121E-02 4.45000 6.63210E-02 4.45050 5.00071E-02 4.45100 5.48736E-02 4.45150 6.82396E-02 4.45200 4.91982E-02 4.45250 2.71416E-02 4.45300 1.39817E-02 4.45350 2.82739E-02 4.45400 3.27536E-02 4.45450 3.67099E-02 4.45500 6.26726E-02 4.45550 5.59118E-02 4.45600 5.08018E-02 4.45650 3.73346E-02 4.45700 1.23777E-02 4.45750 8.11773E-03 4.45800 1.38328E-02 4.45850 3.98425E-02 4.45900 6.04592E-02 4.45950 6.74567E-02 4.46000 9.12996E-02 4.46050 5.46578E-02 4.46100 1.28652E-02 4.46150 8.48518E-03 4.46200 2.03308E-02 4.46250 5.61681E-02 4.46300 6.61649E-02 4.46350 6.20434E-02 4.46400 8.55826E-02 4.46450 5.19454E-02 4.46500 1.48358E-02 4.46550 8.78687E-03 4.46600 1.58777E-02 4.46650 4.46134E-02 4.46700 6.23438E-02 4.46750 5.19429E-02 4.46800 6.29921E-02 4.46850 4.42479E-02 4.46900 1.86556E-02 4.46950 1.63210E-02 4.47000 1.66989E-02 4.47050 4.96097E-02 4.47100 1.03858E-01 4.47150 7.99682E-02 4.47200 3.88077E-02 4.47250 4.50153E-02 4.47300 3.94336E-02 4.47350 2.52310E-02 4.47400 1.78227E-02 4.47450 1.76451E-02 4.47500 6.17339E-02 4.47550 0.105105 4.47600 7.09658E-02 4.47650 7.10820E-02 4.47700 0.109933 4.47750 6.84886E-02 4.47800 2.87308E-02 4.47850 3.33235E-02 4.47900 3.71116E-02 4.47950 6.19893E-02 4.48000 9.37548E-02 4.48050 7.08317E-02 4.48100 7.26721E-02 4.48150 0.116146 4.48200 8.06277E-02 4.48250 4.89525E-02 4.48300 9.69953E-02 4.48350 1.00434E-01 4.48400 9.13643E-02 4.48450 0.138209 4.48500 0.106413 4.48550 7.97803E-02 4.48600 0.136360 4.48650 0.122351 4.48700 7.01300E-02 4.48750 0.106394 4.48800 0.146659 4.48850 0.106203 4.48900 0.125071 4.48950 0.198020 4.49000 0.156973 4.49050 0.157898 4.49100 0.246504 4.49150 0.211197 4.49200 0.188060 4.49250 0.295959 4.49300 0.266987 4.49350 0.190025 4.49400 0.278656 4.49450 0.302146 4.49500 0.244458 4.49550 0.269450 4.49600 0.316912 4.49650 0.409150 4.49700 0.463783 4.49750 0.397145 4.49800 0.363814 4.49850 0.271170 4.49900 0.283891 4.49950 0.364703 4.50000 0.271629 4.50050 0.225996 4.50100 0.312102 4.50150 0.277067 4.50200 0.191142 4.50250 0.274353 4.50300 0.290309 4.50350 0.159419 4.50400 0.168762 4.50450 0.241677 4.50500 0.170121 4.50550 0.112904 4.50600 0.167374 4.50650 0.188593 4.50700 0.128868 4.50750 1.04182E-01 4.50800 0.180653 4.50850 0.195243 4.50900 0.110563 4.50950 0.150260 4.51000 0.240227 4.51050 0.168189 4.51100 0.119610 4.51150 0.221681 4.51200 0.239078 4.51250 0.131175 4.51300 0.141440 4.51350 0.242094 4.51400 0.193683 4.51450 0.106401 4.51500 0.178212 4.51550 0.222937 4.51600 0.124254 4.51650 1.01912E-01 4.51700 0.192672 4.51750 0.188176 4.51800 0.105007 4.51850 0.112480 4.51900 0.188709 4.51950 0.173521 4.52000 9.91521E-02 4.52050 0.139927 4.52100 0.237857 4.52150 0.193776 4.52200 0.107695 4.52250 0.187350 4.52300 0.273411 4.52350 0.186735 4.52400 0.120641 4.52450 0.222486 4.52500 0.281026 4.52550 0.173592 4.52600 0.122600 4.52650 0.238656 4.52700 0.277770 4.52750 0.162242 4.52800 0.149742 4.52850 0.284882 4.52900 0.288227 4.52950 0.153361 4.53000 0.160247 4.53050 0.283991 4.53100 0.260731 4.53150 0.137482 4.53200 0.133571 4.53250 0.232300 4.53300 0.244068 4.53350 0.152218 4.53400 0.151617 4.53450 0.237545 4.53500 0.252812 4.53550 0.161757 4.53600 0.151443 4.53650 0.277269 4.53700 0.318662 4.53750 0.187061 4.53800 0.147202 4.53850 0.269558 4.53900 0.302643 4.53950 0.195393 4.54000 0.183365 4.54050 0.354189 4.54100 0.412130 4.54150 0.261908 4.54200 0.207409 4.54250 0.375345 4.54300 0.442430 4.54350 0.285561 4.54400 0.199164 4.54450 0.329507 4.54500 0.385887 4.54550 0.246365 4.54600 0.175285 4.54650 0.342953 4.54700 0.427319 4.54750 0.284989 4.54800 0.187204 4.54850 0.304000 4.54900 0.401631 4.54950 0.326879 4.55000 0.230387 4.55050 0.279106 4.55100 0.381733 4.55150 0.370345 4.55200 0.286873 4.55250 0.246785 4.55300 0.340693 4.55350 0.418745 4.55400 0.372055 4.55450 0.251893 4.55500 0.300811 4.55550 0.427885 4.55600 0.447137 4.55650 0.289835 4.55700 0.259513 4.55750 0.439397 4.55800 0.528404 4.55850 0.364406 4.55900 0.226761 4.55950 0.378819 4.56000 0.546608 4.56050 0.483872 4.56100 0.324367 4.56150 0.427118 4.56200 0.608897 4.56250 0.574518 4.56300 0.388083 4.56350 0.401004 4.56400 0.579279 4.56450 0.597097 4.56500 0.413596 4.56550 0.269749 4.56600 0.346288 4.56650 0.478049 4.56700 0.447182 4.56750 0.330920 4.56800 0.440403 4.56850 0.589162 4.56900 0.537835 4.56950 0.426682 4.57000 0.404479 4.57050 0.522213 4.57100 0.569687 4.57150 0.507571 4.57200 0.414391 4.57250 0.354471 4.57300 0.356833 4.57350 0.396518 4.57400 0.494691 4.57450 0.479048 4.57500 0.522011 4.57550 0.555980 4.57600 0.574138 4.57650 0.529350 4.57700 0.497079 4.57750 0.560605 4.57800 0.616636 4.57850 0.626750 4.57900 0.536330 4.57950 0.479669 4.58000 0.434754 4.58050 0.463036 4.58100 0.560919 4.58150 0.513867 4.58200 0.534364 4.58250 0.664911 4.58300 0.721010 4.58350 0.618050 4.58400 0.480163 4.58450 0.551011 4.58500 0.695948 4.58550 0.722765 4.58600 0.619436 4.58650 0.563518 4.58700 0.591772 4.58750 0.510627 4.58800 0.520366 4.58850 0.556750 4.58900 0.641179 4.58950 0.747972 4.59000 0.762814 4.59050 0.683239 4.59100 0.618977 4.59150 0.702012 4.59200 0.775512 4.59250 0.752038 4.59300 0.677955 4.59350 0.656053 4.59400 0.696238 4.59450 0.607677 4.59500 0.467573 4.59550 0.546125 4.59600 0.670062 4.59650 0.748281 4.59700 0.757018 4.59750 0.727802 4.59800 0.720025 4.59850 0.727623 4.59900 0.755261 4.59950 0.763617 4.60000 0.758367 4.60050 0.747376 4.60100 0.725691 4.60150 0.717794 4.60200 0.587047 4.60250 0.478013 4.60300 0.594776 4.60350 0.714554 4.60400 0.766488 4.60450 0.756868 4.60500 0.730058 4.60550 0.682126 4.60600 0.701010 4.60650 0.750245 4.60700 0.774148 4.60750 0.796512 4.60800 0.787342 4.60850 0.757996 4.60900 0.734921 4.60950 0.615622 4.61000 0.488409 4.61050 0.602528 4.61100 0.741940 4.61150 0.784682 4.61200 0.789679 4.61250 0.795773 4.61300 0.807854 4.61350 0.795450 4.61400 0.776823 4.61450 0.791077 4.61500 0.818900 4.61550 0.817382 4.61600 0.782341 4.61650 0.757909 4.61700 0.686499 4.61750 0.521999 4.61800 0.555692 4.61850 0.712795 4.61900 0.793219 4.61950 0.818556 4.62000 0.809968 4.62050 0.807923 4.62100 0.813304 4.62150 0.801805 4.62200 0.758106 4.62250 0.753093 4.62300 0.789792 4.62350 0.788880 4.62400 0.779832 4.62450 0.744626 4.62500 0.582666 4.62550 0.390198 4.62600 0.452906 4.62650 0.673806 4.62700 0.801396 4.62750 0.824734 4.62800 0.810855 4.62850 0.809199 4.62900 0.826816 4.62950 0.831380 4.63000 0.824072 4.63050 0.819503 4.63100 0.831220 4.63150 0.835848 4.63200 0.816133 4.63250 0.736666 4.63300 0.574816 4.63350 0.563968 4.63400 0.730104 4.63450 0.804920 4.63500 0.828817 4.63550 0.843008 4.63600 0.834292 4.63650 0.789443 4.63700 0.757682 4.63750 0.800739 4.63800 0.837821 4.63850 0.835727 4.63900 0.832705 4.63950 0.841019 4.64000 0.829555 4.64050 0.745867 4.64100 0.578996 4.64150 0.597468 4.64200 0.767462 4.64250 0.832102 4.64300 0.834120 4.64350 0.840825 4.64400 0.849192 4.64450 0.837295 4.64500 0.760230 4.64550 0.642034 4.64600 0.696561 4.64650 0.812627 4.64700 0.842540 4.64750 0.840044 4.64800 0.831914 4.64850 0.777556 4.64900 0.645457 4.64950 0.620872 4.65000 0.763553 4.65050 0.840963 4.65100 0.856535 4.65150 0.855341 4.65200 0.851941 4.65250 0.855203 4.65300 0.857114 4.65350 0.857082 4.65400 0.848935 4.65450 0.835950 4.65500 0.832774 4.65550 0.840946 4.65600 0.815956 4.65650 0.723193 4.65700 0.641081 4.65750 0.648287 4.65800 0.762565 4.65850 0.839436 4.65900 0.854972 4.65950 0.853870 4.66000 0.822492 4.66050 0.708598 4.66100 0.617091 4.66150 0.725282 4.66200 0.818992 4.66250 0.835667 4.66300 0.849907 4.66350 0.858283 4.66400 0.861696 4.66450 0.866448 4.66500 0.869763 4.66550 0.867957 4.66600 0.869060 4.66650 0.872489 4.66700 0.871943 4.66750 0.864440 4.66800 0.858034 4.66850 0.866041 4.66900 0.871219 4.66950 0.868547 4.67000 0.867641 4.67050 0.867601 4.67100 0.865296 4.67150 0.866575 4.67200 0.868571 4.67250 0.860030 4.67300 0.829256 4.67350 0.723717 4.67400 0.525465 4.67450 0.538248 4.67500 0.746182 4.67550 0.844205 4.67600 0.845041 4.67650 0.784261 4.67700 0.757775 4.67750 0.812389 4.67800 0.803883 4.67850 0.684300 4.67900 0.601512 4.67950 0.704575 4.68000 0.768835 4.68050 0.728408 4.68100 0.564779 4.68150 0.505015 4.68200 0.620747 4.68250 0.603898 4.68300 0.681057 4.68350 0.820861 4.68400 0.865183 4.68450 0.867401 4.68500 0.859359 4.68550 0.860573 4.68600 0.867831 4.68650 0.868084 4.68700 0.865430 4.68750 0.861845 4.68800 0.854960 4.68850 0.850938 4.68900 0.846527 4.68950 0.834266 4.69000 0.821477 4.69050 0.747092 4.69100 0.579122 4.69150 0.578919 4.69200 0.728203 4.69250 0.766684 4.69300 0.771687 4.69350 0.795203 4.69400 0.786570 4.69450 0.746081 4.69500 0.685483 4.69550 0.569517 4.69600 0.543056 4.69650 0.607816 4.69700 0.676755 4.69750 0.712564 4.69800 0.702857 4.69850 0.704621 4.69900 0.691231 4.69950 0.557957 4.70000 0.453651 4.70050 0.577039 4.70100 0.676542 4.70150 0.680948 4.70200 0.726007 4.70250 0.736078 4.70300 0.704099 4.70350 0.655689 4.70400 0.703656 4.70450 0.714904 4.70500 0.660826 4.70550 0.573229 4.70600 0.511776 4.70650 0.574674 4.70700 0.603852 4.70750 0.539736 4.70800 0.528388 4.70850 0.470414 4.70900 0.466541 4.70950 0.593707 4.71000 0.614142 4.71050 0.620341 4.71100 0.630155 4.71150 0.632926 4.71200 0.663445 4.71250 0.635801 4.71300 0.600647 4.71350 0.610276 4.71400 0.577977 4.71450 0.606113 4.71500 0.648169 4.71550 0.614552 4.71600 0.606094 4.71650 0.611882 4.71700 0.570529 4.71750 0.451189 4.71800 0.436903 4.71850 0.563594 4.71900 0.634656 4.71950 0.656946 4.72000 0.703936 4.72050 0.708192 4.72100 0.642753 4.72150 0.615425 4.72200 0.646924 4.72250 0.670394 4.72300 0.714933 4.72350 0.731532 4.72400 0.692305 4.72450 0.653345 4.72500 0.620488 4.72550 0.624109 4.72600 0.624477 4.72650 0.494709 4.72700 0.450227 4.72750 0.440544 4.72800 0.310740 4.72850 0.367687 4.72900 0.513731 4.72950 0.595787 4.73000 0.716981 4.73050 0.762418 4.73100 0.787642 4.73150 0.793170 4.73200 0.772535 4.73250 0.815162 4.73300 0.861253 4.73350 0.864253 4.73400 0.845788 4.73450 0.843678 4.73500 0.781021 4.73550 0.607287 4.73600 0.564569 4.73650 0.742332 4.73700 0.835784 4.73750 0.813108 4.73800 0.749092 4.73850 0.682665 4.73900 0.663193 4.73950 0.684330 4.74000 0.701637 4.74050 0.684549 4.74100 0.663699 4.74150 0.660747 4.74200 0.657239 4.74250 0.680859 4.74300 0.687300 4.74350 0.662139 4.74400 0.657887 4.74450 0.570056 4.74500 0.408081 4.74550 0.437466 4.74600 0.584780 4.74650 0.663945 4.74700 0.623196 4.74750 0.545606 4.74800 0.600220 4.74850 0.657027 4.74900 0.649640 4.74950 0.655328 4.75000 0.696800 4.75050 0.744425 4.75100 0.748129 4.75150 0.740780 4.75200 0.738124 4.75250 0.745827 4.75300 0.743708 4.75350 0.706983 4.75400 0.588811 4.75450 0.503417 4.75500 0.604921 4.75550 0.704963 4.75600 0.739933 4.75650 0.755776 4.75700 0.771805 4.75750 0.755600 4.75800 0.745322 4.75850 0.730420 4.75900 0.731125 4.75950 0.726148 4.76000 0.708789 4.76050 0.589426 4.76100 0.515739 4.76150 0.643361 4.76200 0.724355 4.76250 0.726648 4.76300 0.670923 4.76350 0.578997 4.76400 0.515972 4.76450 0.641497 4.76500 0.735701 4.76550 0.763278 4.76600 0.758415 4.76650 0.731340 4.76700 0.712242 4.76750 0.596043 4.76800 0.525150 4.76850 0.651507 4.76900 0.759814 4.76950 0.773897 4.77000 0.763842 4.77050 0.762660 4.77100 0.749436 4.77150 0.756904 4.77200 0.752909 4.77250 0.695896 4.77300 0.593814 4.77350 0.537548 4.77400 0.633548 4.77450 0.707854 4.77500 0.709968 4.77550 0.648468 4.77600 0.556209 4.77650 0.447339 4.77700 0.456899 4.77750 0.600157 4.77800 0.685273 4.77850 0.749400 4.77900 0.779240 4.77950 0.764904 4.78000 0.749410 4.78050 0.697490 4.78100 0.715675 4.78150 0.774001 4.78200 0.768034 4.78250 0.675549 4.78300 0.510518 4.78350 0.406147 4.78400 0.288206 4.78450 0.172570 4.78500 0.262867 4.78550 0.457925 4.78600 0.648541 4.78650 0.751558 4.78700 0.760176 4.78750 0.674504 4.78800 0.601737 4.78850 0.668170 4.78900 0.750152 4.78950 0.734852 4.79000 0.612113 4.79050 0.431060 4.79100 0.427030 4.79150 0.548432 4.79200 0.694302 4.79250 0.715701 4.79300 0.622457 4.79350 0.650249 4.79400 0.727964 4.79450 0.703077 4.79500 0.612668 4.79550 0.688245 4.79600 0.769360 4.79650 0.774147 4.79700 0.802170 4.79750 0.811441 4.79800 0.741624 4.79850 0.614809 4.79900 0.615796 4.79950 0.707922 4.80000 0.763260 4.80050 0.790090 4.80100 0.809754 4.80150 0.753070 4.80200 0.592246 4.80250 0.497785 4.80300 0.469637 4.80350 0.526414 4.80400 0.711431 4.80450 0.779202 4.80500 0.722147 4.80550 0.614664 4.80600 0.569105 4.80650 0.688085 4.80700 0.761042 4.80750 0.765058 4.80800 0.760533 4.80850 0.736691 4.80900 0.620507 4.80950 0.490889 4.81000 0.480425 4.81050 0.401817 4.81100 0.279015 4.81150 0.238285 4.81200 0.180438 4.81250 9.74173E-02 4.81300 3.55621E-02 4.81350 8.14577E-03 4.81400 2.17195E-03 4.81450 2.01062E-02 4.81500 0.141790 4.81550 0.403876 4.81600 0.617347 4.81650 0.703843 4.81700 0.725496 4.81750 0.749887 4.81800 0.767941 4.81850 0.744553 4.81900 0.755550 4.81950 0.761361 4.82000 0.718029 4.82050 0.565820 4.82100 0.393617 4.82150 0.474360 4.82200 0.552953 4.82250 0.612290 4.82300 0.679701 4.82350 0.706343 4.82400 0.755354 4.82450 0.716698 4.82500 0.602095 4.82550 0.514619 4.82600 0.538330 4.82650 0.708099 4.82700 0.789166 4.82750 0.806050 4.82800 0.795635 4.82850 0.742044 4.82900 0.596950 4.82950 0.479017 4.83000 0.620498 4.83050 0.757390 4.83100 0.793663 4.83150 0.810594 4.83200 0.780772 4.83250 0.640200 4.83300 0.445442 4.83350 0.505438 4.83400 0.685670 4.83450 0.782357 4.83500 0.830806 4.83550 0.809275 4.83600 0.668628 4.83650 0.452788 4.83700 0.468499 4.83750 0.665062 4.83800 0.771693 4.83850 0.799321 4.83900 0.764617 4.83950 0.631356 4.84000 0.357103 4.84050 0.152292 4.84100 0.252014 4.84150 0.432618 4.84200 0.374438 4.84250 0.155458 4.84300 6.28569E-02 4.84350 0.113365 4.84400 0.228425 4.84450 0.479885 4.84500 0.703947 4.84550 0.797364 4.84600 0.818047 4.84650 0.783710 4.84700 0.612458 4.84750 0.397901 4.84800 0.494551 4.84850 0.720490 4.84900 0.814522 4.84950 0.828840 4.85000 0.798362 4.85050 0.670889 4.85100 0.433767 4.85150 0.413567 4.85200 0.576594 4.85250 0.510377 4.85300 0.277666 4.85350 0.282468 4.85400 0.458609 4.85450 0.410868 4.85500 0.383864 4.85550 0.620799 4.85600 0.798979 4.85650 0.848012 4.85700 0.849923 4.85750 0.789367 4.85800 0.592586 4.85850 0.417267 4.85900 0.574977 4.85950 0.788882 4.86000 0.863859 4.86050 0.870658 4.86100 0.834939 4.86150 0.685507 4.86200 0.460641 4.86250 0.530584 4.86300 0.766927 4.86350 0.865598 4.86400 0.880814 4.86450 0.857834 4.86500 0.741992 4.86550 0.512099 4.86600 0.493559 4.86650 0.725128 4.86700 0.847706 4.86750 0.867656 4.86800 0.861693 4.86850 0.790927 4.86900 0.589554 4.86950 0.482378 4.87000 0.677542 4.87050 0.822839 4.87100 0.847713 4.87150 0.870820 4.87200 0.849180 4.87250 0.694764 4.87300 0.515188 4.87350 0.631365 4.87400 0.816353 4.87450 0.877400 4.87500 0.889860 4.87550 0.865605 4.87600 0.752504 4.87650 0.562716 4.87700 0.598689 4.87750 0.790160 4.87800 0.859733 4.87850 0.857209 4.87900 0.846833 4.87950 0.801162 4.88000 0.645042 4.88050 0.597874 4.88100 0.769811 4.88150 0.867954 4.88200 0.892274 4.88250 0.898362 4.88300 0.866682 4.88350 0.730721 4.88400 0.612808 4.88450 0.735133 4.88500 0.842637 4.88550 0.795206 4.88600 0.607698 4.88650 0.526618 4.88700 0.622861 4.88750 0.616336 4.88800 0.709130 4.88850 0.844434 4.88900 0.885447 4.88950 0.889212 4.89000 0.874620 4.89050 0.811526 4.89100 0.655979 4.89150 0.525091 4.89200 0.362396 4.89250 0.230886 4.89300 0.422321 4.89350 0.688889 4.89400 0.787085 4.89450 0.733354 4.89500 0.697624 4.89550 0.784001 4.89600 0.824738 4.89650 0.802696 4.89700 0.725022 4.89750 0.542285 4.89800 0.259147 4.89850 6.65506E-02 4.89900 8.91169E-02 4.89950 0.309456 4.90000 0.576836 4.90050 0.736871 4.90100 0.804667 4.90150 0.804424 4.90200 0.758348 4.90250 0.795964 4.90300 0.868243 4.90350 0.890752 4.90400 0.895579 4.90450 0.899456 4.90500 0.887327 4.90550 0.837805 4.90600 0.820955 4.90650 0.842177 4.90700 0.791803 4.90750 0.605336 4.90800 0.450908 4.90850 0.550268 4.90900 0.701900 4.90950 0.805599 4.91000 0.880535 4.91050 0.910697 4.91100 0.916575 4.91150 0.919761 4.91200 0.917234 4.91250 0.896292 4.91300 0.873025 4.91350 0.886539 4.91400 0.906928 4.91450 0.912202 4.91500 0.905793 4.91550 0.860829 4.91600 0.753690 4.91650 0.729827 4.91700 0.836869 4.91750 0.901277 4.91800 0.914776 4.91850 0.921646 4.91900 0.923248 4.91950 0.914975 4.92000 0.899019 4.92050 0.897896 4.92100 0.914163 4.92150 0.922408 4.92200 0.923671 4.92250 0.923432 4.92300 0.921693 4.92350 0.912444 4.92400 0.903260 4.92450 0.910452 4.92500 0.914714 4.92550 0.905103 4.92600 0.894219 4.92650 0.901629 4.92700 0.911601 4.92750 0.905200 4.92800 0.902927 4.92850 0.914693 4.92900 0.920531 4.92950 0.919312 4.93000 0.914948 4.93050 0.910009 4.93100 0.897104 4.93150 0.872795 4.93200 0.844848 4.93250 0.748796 4.93300 0.508844 4.93350 0.328327 4.93400 0.268369 4.93450 0.304112 4.93500 0.558504 4.93550 0.761213 4.93600 0.850283 4.93650 0.888722 4.93700 0.901087 4.93750 0.904215 4.93800 0.905882 4.93850 0.903727 4.93900 0.890534 4.93950 0.884923 4.94000 0.896452 4.94050 0.897952 4.94100 0.885697 4.94150 0.853419 4.94200 0.753947 4.94250 0.511115 4.94300 0.286938 4.94350 0.415277 4.94400 0.691181 4.94450 0.831428 4.94500 0.872874 4.94550 0.885475 4.94600 0.892754 4.94650 0.885846 4.94700 0.871963 4.94750 0.881103 4.94800 0.887810 4.94850 0.873222 4.94900 0.846001 4.94950 0.841226 4.95000 0.840484 4.95050 0.804977 4.95100 0.749460 4.95150 0.652499 4.95200 0.433656 4.95250 0.178885 4.95300 0.122308 4.95350 0.206840 4.95400 0.167651 4.95450 8.32333E-02 4.95500 0.177114 4.95550 0.390483 4.95600 0.517064 4.95650 0.494249 4.95700 0.349747 4.95750 0.155425 4.95800 3.60030E-02 4.95850 2.91983E-02 4.95900 0.137671 4.95950 0.348444 4.96000 0.550491 4.96050 0.681161 4.96100 0.758091 4.96150 0.801530 4.96200 0.819314 4.96250 0.830355 4.96300 0.852599 4.96350 0.868109 4.96400 0.871210 4.96450 0.882879 4.96500 0.898115 4.96550 0.902808 4.96600 0.897266 4.96650 0.894569 4.96700 0.906400 4.96750 0.909608 4.96800 0.904752 4.96850 0.908448 4.96900 0.914552 4.96950 0.910934 4.97000 0.901875 4.97050 0.904815 4.97100 0.915721 4.97150 0.916645 4.97200 0.911112 4.97250 0.900285 4.97300 0.897409 4.97350 0.905036 4.97400 0.899399 4.97450 0.893851 4.97500 0.883525 4.97550 0.830868 4.97600 0.659202 4.97650 0.380964 4.97700 0.358490 4.97750 0.622520 4.97800 0.797679 4.97850 0.850080 4.97900 0.847964 4.97950 0.781486 4.98000 0.598841 4.98050 0.326375 4.98100 0.277042 4.98150 0.538119 4.98200 0.762314 4.98250 0.854728 4.98300 0.890579 4.98350 0.906904 4.98400 0.915272 4.98450 0.918136 4.98500 0.909510 4.98550 0.865938 4.98600 0.832236 4.98650 0.880441 4.98700 0.918884 4.98750 0.924630 4.98800 0.925437 4.98850 0.927141 4.98900 0.926206 4.98950 0.922568 4.99000 0.921826 4.99050 0.923215 4.99100 0.919328 4.99150 0.914689 4.99200 0.915728 4.99250 0.916695 4.99300 0.918148 4.99350 0.918296 4.99400 0.921394 4.99450 0.924775 4.99500 0.924046 4.99550 0.922574 4.99600 0.922327 4.99650 0.920933 4.99700 0.913692 4.99750 0.900774 4.99800 0.898561 4.99850 0.902930 4.99900 0.895375 4.99950 0.863371 5.00000 0.810439 5.00050 0.792185 5.00100 0.759818 5.00150 0.622549 5.00200 0.361530 5.00250 0.134370 5.00300 0.169277 5.00350 0.428795 5.00400 0.668715 5.00450 0.790279 5.00500 0.842940 5.00550 0.867617 5.00600 0.880745 5.00650 0.888906 5.00700 0.893607 5.00750 0.894915 5.00800 0.893267 5.00850 0.890179 5.00900 0.889614 5.00950 0.889363 5.01000 0.886010 5.01050 0.881820 5.01100 0.875621 5.01150 0.868860 5.01200 0.862267 5.01250 0.854039 5.01300 0.842320 5.01350 0.826701 5.01400 0.805162 5.01450 0.774552 5.01500 0.727762 5.01550 0.645511 5.01600 0.482977 5.01650 0.242374 5.01700 9.17023E-02 5.01750 7.43204E-02 5.01800 4.27656E-02 5.01850 8.54365E-03 5.01900 6.56119E-04 5.01950 2.49578E-04 5.02000 2.52280E-04 5.02050 2.95188E-03 5.02100 2.79753E-02 5.02150 0.117886 5.02200 0.271942 5.02250 0.428257 5.02300 0.547726 5.02350 0.629427 5.02400 0.682495 5.02450 0.713343 5.02500 0.725219 5.02550 0.729537 5.02600 0.727122 5.02650 0.700811 5.02700 0.638108 5.02750 0.517540 5.02800 0.325704 5.02850 0.126351 5.02900 2.71894E-02 5.02950 4.31819E-02 5.03000 0.178813 5.03050 0.391822 5.03100 0.549878 5.03150 0.587374 5.03200 0.619323 5.03250 0.730223 5.03300 0.809465 5.03350 0.841637 5.03400 0.859447 5.03450 0.865773 5.03500 0.853044 5.03550 0.860358 5.03600 0.889567 5.03650 0.902932 5.03700 0.906848 5.03750 0.908614 5.03800 0.903818 5.03850 0.874708 5.03900 0.841169 5.03950 0.865926 5.04000 0.904428 5.04050 0.919123 5.04100 0.922079 5.04150 0.921388 5.04200 0.913046 5.04250 0.888076 5.04300 0.881021 5.04350 0.901204 5.04400 0.916111 5.04450 0.920106 5.04500 0.911696 5.04550 0.907305 5.04600 0.916366 5.04650 0.916023 5.04700 0.904224 5.04750 0.897815 5.04800 0.843133 5.04850 0.760297 5.04900 0.822202 5.04950 0.906813 5.05000 0.927036 5.05050 0.930295 5.05100 0.931945 5.05150 0.932626 5.05200 0.932100 5.05250 0.929855 5.05300 0.929166 5.05350 0.930793 5.05400 0.930583 5.05450 0.929289 5.05500 0.928592 5.05550 0.923506 5.05600 0.901121 5.05650 0.873174 5.05700 0.889699 5.05750 0.912139 5.05800 0.910428 5.05850 0.891843 5.05900 0.836764 5.05950 0.661715 5.06000 0.399055 5.06050 0.422180 5.06100 0.689779 5.06150 0.846123 5.06200 0.890673 5.06250 0.903984 5.06300 0.913172 5.06350 0.920136 5.06400 0.922859 5.06450 0.923789 5.06500 0.924867 5.06550 0.925355 5.06600 0.925271 5.06650 0.923685 5.06700 0.920150 5.06750 0.919730 5.06800 0.920786 5.06850 0.920327 5.06900 0.919307 5.06950 0.917704 5.07000 0.917066 5.07050 0.915409 5.07100 0.910191 5.07150 0.905888 5.07200 0.906961 5.07250 0.906373 5.07300 0.903445 5.07350 0.899589 5.07400 0.894700 5.07450 0.887531 5.07500 0.872825 5.07550 0.854889 5.07600 0.850293 5.07650 0.842098 5.07700 0.826790 5.07750 0.807216 5.07800 0.781552 5.07850 0.757399 5.07900 0.721259 5.07950 0.659412 5.08000 0.571396 5.08050 0.448757 5.08100 0.291219 5.08150 0.136710 5.08200 3.68731E-02 5.08250 4.71039E-03 5.08300 3.91930E-03 5.08350 2.69501E-02 5.08400 8.30485E-02 5.08450 0.119724 5.08500 8.06327E-02 5.08550 2.52612E-02 5.08600 3.05160E-02 5.08650 0.139254 5.08700 0.337136 5.08750 0.518571 5.08800 0.632302 5.08850 0.706217 5.08900 0.762331 5.08950 0.798324 5.09000 0.821899 5.09050 0.838093 5.09100 0.848732 5.09150 0.857370 5.09200 0.859084 5.09250 0.855978 5.09300 0.867364 5.09350 0.878281 5.09400 0.880940 5.09450 0.880451 5.09500 0.877144 5.09550 0.869747 5.09600 0.851047 5.09650 0.805936 5.09700 0.748649 5.09750 0.671230 5.09800 0.481400 5.09850 0.214377 5.09900 9.60914E-02 5.09950 0.240977 5.10000 0.500371 5.10050 0.684104 5.10100 0.776498 5.10150 0.832239 5.10200 0.857213 5.10250 0.839682 5.10300 0.817595 5.10350 0.854007 5.10400 0.889682 5.10450 0.894187 5.10500 0.881832 5.10550 0.882951 5.10600 0.895977 5.10650 0.895459 5.10700 0.873492 5.10750 0.780051 5.10800 0.631925 5.10850 0.668742 5.10900 0.769185 5.10950 0.732340 5.11000 0.724572 5.11050 0.757531 5.11100 0.659584 5.11150 0.414822 5.11200 0.320324 5.11250 0.505235 5.11300 0.614701 5.11350 0.568199 5.11400 0.409382 5.11450 0.182705 5.11500 5.41840E-02 5.11550 0.115497 5.11600 0.335816 5.11650 0.564735 5.11700 0.708607 5.11750 0.779458 5.11800 0.815410 5.11850 0.848578 5.11900 0.869560 5.11950 0.880131 5.12000 0.887105 5.12050 0.891743 5.12100 0.893909 5.12150 0.890819 5.12200 0.882312 5.12250 0.884941 5.12300 0.893333 5.12350 0.893618 5.12400 0.881341 5.12450 0.820364 5.12500 0.694098 5.12550 0.696540 5.12600 0.813965 5.12650 0.861952 5.12700 0.861497 5.12750 0.828332 5.12800 0.807869 5.12850 0.833132 5.12900 0.826795 5.12950 0.721543 5.13000 0.558831 5.13050 0.597463 5.13100 0.757413 5.13150 0.821759 5.13200 0.827909 5.13250 0.820017 5.13300 0.806262 5.13350 0.786976 5.13400 0.760254 5.13450 0.722022 5.13500 0.667854 5.13550 0.588341 5.13600 0.464204 5.13650 0.288559 5.13700 0.114223 5.13750 2.32351E-02 5.13800 1.20032E-02 5.13850 4.90075E-02 5.13900 9.38655E-02 5.13950 7.71044E-02 5.14000 2.68936E-02 5.14050 9.03515E-03 5.14100 4.39264E-02 5.14150 0.152071 5.14200 0.290068 5.14250 0.384634 5.14300 0.418595 5.14350 0.406507 5.14400 0.366361 5.14450 0.301549 5.14500 0.213296 5.14550 0.118738 5.14600 4.52747E-02 5.14650 9.84843E-03 5.14700 1.01084E-03 5.14750 4.19953E-05 5.14800 1.96166E-05 5.14850 3.83762E-04 5.14900 2.54328E-03 5.14950 5.69234E-03 5.15000 8.87359E-03 5.15050 4.41223E-02 5.15100 0.154988 5.15150 0.302670 5.15200 0.427612 5.15250 0.519266 5.15300 0.577431 5.15350 0.588458 5.15400 0.600293 5.15450 0.674730 5.15500 0.729347 5.15550 0.746004 5.15600 0.747026 5.15650 0.715593 5.15700 0.685806 5.15750 0.734386 5.15800 0.769297 5.15850 0.799457 5.15900 0.825902 5.15950 0.806353 5.16000 0.760983 5.16050 0.792554 5.16100 0.831361 5.16150 0.786951 5.16200 0.705295 5.16250 0.720726 5.16300 0.806409 5.16350 0.852306 5.16400 0.850559 5.16450 0.853556 5.16500 0.869450 5.16550 0.873811 5.16600 0.870794 5.16650 0.858359 5.16700 0.837914 5.16750 0.838405 5.16800 0.832950 5.16850 0.814648 5.16900 0.808555 5.16950 0.793523 5.17000 0.761679 5.17050 0.713669 5.17100 0.640197 5.17150 0.518682 5.17200 0.327264 5.17250 0.127788 5.17300 5.70592E-02 5.17350 0.115877 5.17400 0.192733 5.17450 0.289853 5.17500 0.442921 5.17550 0.529036 5.17600 0.648778 5.17650 0.797829 5.17700 0.854241 5.17750 0.868641 5.17800 0.873097 5.17850 0.868955 5.17900 0.862379 5.17950 0.866251 5.18000 0.875896 5.18050 0.881051 5.18100 0.881590 5.18150 0.880150 5.18200 0.875689 5.18250 0.859303 5.18300 0.836699 5.18350 0.848280 5.18400 0.866882 5.18450 0.869520 5.18500 0.867005 5.18550 0.862763 5.18600 0.851654 5.18650 0.803548 5.18700 0.717678 5.18750 0.733727 5.18800 0.806562 5.18850 0.827511 5.18900 0.819998 5.18950 0.783954 5.19000 0.725039 5.19050 0.719037 5.19100 0.707834 5.19150 0.681905 5.19200 0.720184 5.19250 0.738519 5.19300 0.723167 5.19350 0.692405 5.19400 0.630119 5.19450 0.541790 5.19500 0.487970 5.19550 0.437082 5.19600 0.414073 5.19650 0.377037 5.19700 0.289568 5.19750 0.182818 5.19800 8.60844E-02 5.19850 2.57030E-02 5.19900 4.01882E-03 5.19950 2.75968E-04 5.20000 1.30486E-05 5.20050 4.30023E-05 5.20100 8.63149E-05 5.20150 6.32951E-05 5.20200 5.35923E-04 5.20250 6.79118E-03 5.20300 3.49327E-02 5.20350 9.02334E-02 5.20400 0.175752 5.20450 0.285733 5.20500 0.362380 5.20550 0.389308 5.20600 0.405660 5.20650 0.436620 5.20700 0.438379 5.20750 0.385614 5.20800 0.310848 5.20850 0.284028 5.20900 0.228665 5.20950 0.174114 5.21000 0.154803 5.21050 0.116951 5.21100 6.36240E-02 5.21150 2.37161E-02 5.21200 5.42342E-03 5.21250 6.39848E-04 5.21300 3.18588E-05 5.21350 5.39736E-07 5.21400 2.50503E-06 5.21450 8.78982E-05 5.21500 1.16953E-03 5.21550 6.82322E-03 5.21600 2.40752E-02 5.21650 6.77174E-02 5.21700 0.138812 5.21750 0.220242 5.21800 0.302018 5.21850 0.374292 5.21900 0.433874 5.21950 0.469450 5.22000 0.445407 5.22050 0.421820 5.22100 0.481066 5.22150 0.547905 5.22200 0.610377 5.22250 0.582492 5.22300 0.505570 5.22350 0.560000 5.22400 0.574775 5.22450 0.456961 5.22500 0.490434 5.22550 0.646032 5.22600 0.718339 5.22650 0.733201 5.22700 0.732826 5.22750 0.715325 5.22800 0.632760 5.22850 0.497242 5.22900 0.530176 5.22950 0.634497 5.23000 0.628541 5.23050 0.584769 5.23100 0.579590 5.23150 0.559925 5.23200 0.490666 5.23250 0.368046 5.23300 0.261685 5.23350 0.193110 5.23400 1.03328E-01 5.23450 3.23885E-02 5.23500 5.15729E-03 5.23550 3.64237E-04 5.23600 4.14137E-04 5.23650 5.64691E-03 5.23700 3.39909E-02 5.23750 1.01348E-01 5.23800 0.183745 5.23850 0.240334 5.23900 0.244682 5.23950 0.188810 5.24000 9.72294E-02 5.24050 2.74259E-02 5.24100 3.66085E-03 5.24150 4.95273E-03 5.24200 3.96735E-02 5.24250 0.144874 5.24300 0.297385 5.24350 0.434553 5.24400 0.529351 5.24450 0.565579 5.24500 0.554369 5.24550 0.605048 5.24600 0.671332 5.24650 0.697228 5.24700 0.720877 5.24750 0.729514 5.24800 0.715889 5.24850 0.665501 5.24900 0.550117 5.24950 0.402360 5.25000 0.238537 5.25050 9.64640E-02 5.25100 2.98057E-02 5.25150 7.42896E-02 5.25200 0.246921 5.25250 0.450395 5.25300 0.560536 5.25350 0.631215 5.25400 0.720876 5.25450 0.769450 5.25500 0.772097 5.25550 0.713149 5.25600 0.668164 5.25650 0.722128 5.25700 0.720141 5.25750 0.600486 5.25800 0.417051 5.25850 0.421536 5.25900 0.655543 5.25950 0.795730 5.26000 0.832484 5.26050 0.836954 5.26100 0.813990 5.26150 0.787221 5.26200 0.812185 5.26250 0.840031 5.26300 0.847299 5.26350 0.847621 5.26400 0.844812 5.26450 0.835543 5.26500 0.812124 5.26550 0.784372 5.26600 0.791169 5.26650 0.800164 5.26700 0.797749 5.26750 0.801877 5.26800 0.794326 5.26850 0.757307 5.26900 0.687718 5.26950 0.602093 5.27000 0.510715 5.27050 0.548764 5.27100 0.646577 5.27150 0.663878 5.27200 0.630361 5.27250 0.578754 5.27300 0.508348 5.27350 0.412193 5.27400 0.299225 5.27450 0.178532 5.27500 7.21419E-02 5.27550 1.65859E-02 5.27600 1.89778E-03 5.27650 1.41956E-04 5.27700 8.95184E-04 5.27750 8.95282E-03 5.27800 5.15688E-02 5.27850 0.151602 5.27900 0.271827 5.27950 0.359408 5.28000 0.350505 5.28050 0.281107 5.28100 0.368060 5.28150 0.512502 5.28200 0.571348 5.28250 0.588420 5.28300 0.547481 5.28350 0.434788 5.28400 0.427643 5.28450 0.521540 5.28500 0.546084 5.28550 0.521431 5.28600 0.481271 5.28650 0.435904 5.28700 0.389857 5.28750 0.336538 5.28800 0.269811 5.28850 0.195754 5.28900 0.123185 5.28950 6.22444E-02 5.29000 2.25138E-02 5.29050 5.05633E-03 5.29100 6.02626E-04 5.29150 3.27799E-05 5.29200 6.77782E-07 5.29250 1.11436E-06 5.29300 3.80502E-05 5.29350 5.40606E-04 5.29400 4.49051E-03 5.29450 2.26492E-02 5.29500 6.65216E-02 5.29550 0.131820 5.29600 0.206955 5.29650 0.282080 5.29700 0.350745 5.29750 0.410799 5.29800 0.462355 5.29850 0.506744 5.29900 0.544430 5.29950 0.574371 5.30000 0.597596 5.30050 0.614588 5.30100 0.623953 5.30150 0.623177 5.30200 0.595165 5.30250 0.514671 5.30300 0.436550 5.30350 0.357991 5.30400 0.202466 5.30450 0.134934 5.30500 0.117748 5.30550 5.26849E-02 5.30600 1.03618E-02 5.30650 1.08774E-02 5.30700 6.68695E-02 5.30750 0.205550 5.30800 0.376458 5.30850 0.512955 5.30900 0.604199 5.30950 0.664720 5.31000 0.705791 5.31050 0.733412 5.31100 0.752264 5.31150 0.767509 5.31200 0.781033 5.31250 0.792011 5.31300 0.798645 5.31350 0.803287 5.31400 0.809857 5.31450 0.814803 5.31500 0.816750 5.31550 0.813565 5.31600 0.805610 5.31650 0.804818 5.31700 0.812509 5.31750 0.812451 5.31800 0.788680 5.31850 0.731763 5.31900 0.633332 5.31950 0.449155 5.32000 0.336063 5.32050 0.377198 5.32100 0.388218 5.32150 0.485758 5.32200 0.650292 5.32250 0.762931 5.32300 0.804616 5.32350 0.810988 5.32400 0.809552 5.32450 0.801709 5.32500 0.777613 5.32550 0.758283 5.32600 0.774160 5.32650 0.784196 5.32700 0.770434 5.32750 0.717428 5.32800 0.554756 5.32850 0.328373 5.32900 0.363668 5.32950 0.592174 5.33000 0.714935 5.33050 0.747010 5.33100 0.753955 5.33150 0.752597 5.33200 0.747233 5.33250 0.740214 5.33300 0.733915 5.33350 0.727762 5.33400 0.719693 5.33450 0.709782 5.33500 0.698029 5.33550 0.686103 5.33600 0.673174 5.33650 0.657913 5.33700 0.641196 5.33750 0.623665 5.33800 0.605031 5.33850 0.584078 5.33900 0.560221 5.33950 0.533246 5.34000 0.503052 5.34050 0.470341 5.34100 0.434475 5.34150 0.394457 5.34200 0.348988 5.34250 0.297257 5.34300 0.239931 5.34350 0.176061 5.34400 0.105977 5.34450 4.34366E-02 5.34500 9.53290E-03 5.34550 1.61476E-03 5.34600 2.34086E-03 5.34650 2.67856E-03 5.34700 1.29685E-03 5.34750 2.82016E-04 5.34800 2.68318E-05 5.34850 9.78214E-07 5.34900 9.67941E-09 5.34950 0. 5.35000 0. 5.35050 0. 5.35100 0. 5.35150 0. 5.35200 0. 5.35250 0. 5.35300 0. 5.35350 5.31888E-09 5.35400 6.76332E-07 5.35450 1.98471E-05 5.35500 2.07038E-04 5.35550 8.71145E-04 5.35600 1.59270E-03 5.35650 1.28280E-03 5.35700 4.33812E-04 5.35750 5.68169E-05 5.35800 2.72815E-05 5.35850 5.92407E-04 5.35900 5.78010E-03 5.35950 2.71195E-02 5.36000 7.37757E-02 5.36050 0.139559 5.36100 0.210247 5.36150 0.276243 5.36200 0.333970 5.36250 0.380503 5.36300 0.403590 5.36350 0.370415 5.36400 0.311511 5.36450 0.317030 5.36500 0.434225 5.36550 0.548620 5.36600 0.594000 5.36650 0.613379 5.36700 0.618761 5.36750 0.598626 5.36800 0.572816 5.36850 0.597325 5.36900 0.644184 5.36950 0.653085 5.37000 0.633495 5.37050 0.596025 5.37100 0.498532 5.37150 0.305357 5.37200 0.211598 5.37250 0.369970 5.37300 0.455031 5.37350 0.348942 5.37400 0.400163 5.37450 0.587523 5.37500 0.660934 5.37550 0.635057 5.37600 0.504596 5.37650 0.263859 5.37700 0.136754 5.37750 0.273915 5.37800 0.470142 5.37850 0.523232 5.37900 0.449242 5.37950 0.287111 5.38000 0.111127 5.38050 2.30591E-02 5.38100 3.38744E-02 5.38150 0.154613 5.38200 0.355937 5.38250 0.513644 5.38300 0.592182 5.38350 0.643199 5.38400 0.688041 5.38450 0.710676 5.38500 0.715305 5.38550 0.709487 5.38600 0.668920 5.38650 0.518145 5.38700 0.312264 5.38750 0.361780 5.38800 0.584335 5.38850 0.702335 5.38900 0.735180 5.38950 0.745742 5.39000 0.750866 5.39050 0.753501 5.39100 0.752142 5.39150 0.745741 5.39200 0.732120 5.39250 0.678858 5.39300 0.539583 5.39350 0.469545 5.39400 0.584904 5.39450 0.680037 5.39500 0.704656 5.39550 0.699818 5.39600 0.685307 5.39650 0.660266 5.39700 0.596827 5.39750 0.443420 5.39800 0.218199 5.39850 0.140282 5.39900 0.307492 5.39950 0.501188 5.40000 0.591786 5.40050 0.623304 5.40100 0.631564 5.40150 0.628824 5.40200 0.622599 5.40250 0.613445 5.40300 0.601816 5.40350 0.588640 5.40400 0.572516 5.40450 0.553674 5.40500 0.531586 5.40550 0.505317 5.40600 0.470968 5.40650 0.431782 5.40700 0.392937 5.40750 0.349234 5.40800 0.287778 5.40850 0.184708 5.40900 0.105626 5.40950 8.74172E-02 5.41000 5.53687E-02 5.41050 1.94159E-02 5.41100 3.50767E-03 5.41150 2.85380E-04 5.41200 3.30660E-05 5.41250 5.04517E-04 5.41300 4.17533E-03 5.41350 1.59843E-02 5.41400 3.43283E-02 5.41450 4.96089E-02 5.41500 5.45485E-02 5.41550 4.84713E-02 5.41600 3.57202E-02 5.41650 2.00637E-02 5.41700 6.68404E-03 5.41750 1.01431E-03 5.41800 6.39959E-05 5.41850 2.26461E-06 5.41900 4.90469E-08 5.41950 2.11769E-11 5.42000 0. 5.42050 0. 5.42100 0. 5.42150 0. 5.42200 0. 5.42250 0. 5.42300 0. 5.42350 0. 5.42400 1.54473E-08 5.42450 1.08025E-06 5.42500 2.32928E-05 5.42550 2.08633E-04 5.42600 1.00074E-03 5.42650 3.01453E-03 5.42700 5.61037E-03 5.42750 5.71928E-03 5.42800 2.83265E-03 5.42850 3.27122E-03 5.42900 1.82158E-02 5.42950 5.54411E-02 5.43000 1.02955E-01 5.43050 0.147112 5.43100 0.186721 5.43150 0.222270 5.43200 0.252659 5.43250 0.279555 5.43300 0.300973 5.43350 0.304245 5.43400 0.312035 5.43450 0.347732 5.43500 0.374681 5.43550 0.380081 5.43600 0.350363 5.43650 0.270256 5.43700 0.198636 5.43750 0.230506 5.43800 0.321131 5.43850 0.340056 5.43900 0.290104 5.43950 0.250537 5.44000 0.236616 5.44050 0.190614 5.44100 0.118617 5.44150 5.12054E-02 5.44200 1.28428E-02 5.44250 1.54251E-03 5.44300 9.99536E-05 5.44350 6.84990E-04 5.44400 7.20201E-03 5.44450 3.46486E-02 5.44500 9.10499E-02 5.44550 0.154074 5.44600 0.177344 5.44650 0.127918 5.44700 1.02419E-01 5.44750 0.204017 5.44800 0.317710 5.44850 0.358619 5.44900 0.322736 5.44950 0.202020 5.45000 8.94850E-02 5.45050 8.54677E-02 5.45100 0.193745 5.45150 0.294163 5.45200 0.323718 5.45250 0.337427 5.45300 0.339716 5.45350 0.305743 5.45400 0.216641 5.45450 0.106806 5.45500 1.02932E-01 5.45550 0.174774 5.45600 0.204172 5.45650 0.191135 5.45700 0.162969 5.45750 0.130052 5.45800 9.90518E-02 5.45850 7.15272E-02 5.45900 4.75445E-02 5.45950 2.79514E-02 5.46000 1.37297E-02 5.46050 5.32218E-03 5.46100 1.49865E-03 5.46150 2.72313E-04 5.46200 2.67848E-05 5.46250 1.12693E-06 5.46300 1.45533E-08 5.46350 0. 5.46400 0. 5.46450 0. 5.46500 0. 5.46550 0. 5.46600 0. 5.46650 0. 5.46700 0. 5.46750 3.03549E-08 5.46800 2.13489E-06 5.46850 4.57886E-05 5.46900 3.95639E-04 5.46950 1.84622E-03 5.47000 5.58748E-03 5.47050 1.19854E-02 5.47100 2.22257E-02 5.47150 3.51332E-02 5.47200 4.62472E-02 5.47250 5.36877E-02 5.47300 5.60791E-02 5.47350 5.30440E-02 5.47400 4.50682E-02 5.47450 3.35459E-02 5.47500 2.09950E-02 5.47550 1.04162E-02 5.47600 3.76425E-03 5.47650 8.81722E-04 5.47700 1.14532E-04 5.47750 6.80370E-06 5.47800 1.46597E-07 5.47850 3.88584E-10 5.47900 0. 5.47950 6.44391E-08 5.48000 3.98057E-06 5.48050 8.43082E-05 5.48100 8.00408E-04 5.48150 4.12506E-03 5.48200 1.34735E-02 5.48250 3.14761E-02 5.48300 5.76296E-02 5.48350 8.80779E-02 5.48400 0.116000 5.48450 0.129750 5.48500 0.111790 5.48550 5.99735E-02 5.48600 1.92124E-02 5.48650 3.39319E-02 5.48700 0.107147 5.48750 0.169993 5.48800 0.154242 5.48850 0.110705 5.48900 0.113003 5.48950 0.182524 5.49000 0.184652 5.49050 0.198950 5.49100 0.348086 5.49150 0.473069 5.49200 0.523173 5.49250 0.532916 5.49300 0.502346 5.49350 0.491116 5.49400 0.550281 5.49450 0.597412 5.49500 0.615233 5.49550 0.623942 5.49600 0.630923 5.49650 0.636958 5.49700 0.638342 5.49750 0.634499 5.49800 0.633647 5.49850 0.634415 5.49900 0.629426 5.49950 0.614256 5.50000 0.583224 5.50050 0.514827 5.50100 0.358177 5.50150 0.149966 5.50200 3.93236E-02 5.50250 6.04801E-02 5.50300 0.182845 5.50350 0.366480 5.50400 0.511792 5.50450 0.574686 5.50500 0.587514 5.50550 0.537074 5.50600 0.385606 5.50650 0.300847 5.50700 0.431592 5.50750 0.538398 5.50800 0.551068 5.50850 0.579611 5.50900 0.611067 5.50950 0.603653 5.51000 0.550708 5.51050 0.499873 5.51100 0.528999 5.51150 0.560841 5.51200 0.557640 5.51250 0.544033 5.51300 0.522033 5.51350 0.489253 5.51400 0.448917 5.51450 0.406163 5.51500 0.344978 5.51550 0.262421 5.51600 0.183616 5.51650 1.01786E-01 5.51700 3.41895E-02 5.51750 5.70567E-03 5.51800 8.79390E-04 5.51850 4.19959E-03 5.51900 1.44159E-02 5.51950 2.31335E-02 5.52000 2.00896E-02 5.52050 1.01954E-02 5.52100 2.96492E-03 5.52150 4.52524E-04 5.52200 3.15935E-05 5.52250 8.44875E-07 5.52300 2.65635E-08 5.52350 2.44013E-06 5.52400 7.59352E-05 5.52450 9.61195E-04 5.52500 5.94500E-03 5.52550 2.10886E-02 5.52600 4.75673E-02 5.52650 7.14471E-02 5.52700 9.69348E-02 5.52750 0.153943 5.52800 0.195797 5.52850 0.174543 5.52900 0.137876 5.52950 0.151738 5.53000 0.144315 5.53050 9.59912E-02 5.53100 3.67680E-02 5.53150 6.64104E-03 5.53200 2.44910E-03 5.53250 1.90113E-02 5.53300 7.91757E-02 5.53350 0.178494 5.53400 0.274202 5.53450 0.338950 5.53500 0.366048 5.53550 0.386210 5.53600 0.415615 5.53650 0.416930 5.53700 0.375013 5.53750 0.323370 5.53800 0.280787 5.53850 0.190303 5.53900 7.70454E-02 5.53950 1.64788E-02 5.54000 2.01648E-02 5.54050 8.46797E-02 5.54100 0.186551 5.54150 0.272068 5.54200 0.325513 5.54250 0.344228 5.54300 0.338002 5.54350 0.316207 5.54400 0.279811 5.54450 0.234387 5.54500 0.181547 5.54550 0.120555 5.54600 6.17196E-02 5.54650 2.08133E-02 5.54700 3.85526E-03 5.54750 3.29736E-04 5.54800 2.20920E-05 5.54850 1.54864E-04 5.54900 7.87325E-04 5.54950 2.22683E-03 5.55000 3.53652E-03 5.55050 2.30437E-03 5.55100 6.17192E-04 5.55150 2.98423E-04 5.55200 1.83642E-03 5.55250 5.67850E-03 5.55300 8.04342E-03 5.55350 6.04253E-03 5.55400 2.62397E-03 5.55450 6.55999E-04 5.55500 8.58096E-05 5.55550 4.95827E-06 5.55600 1.00570E-07 5.55650 1.42085E-10 5.55700 2.29469E-10 5.55750 1.13957E-07 5.55800 4.96854E-06 5.55850 6.98112E-05 5.55900 3.80852E-04 5.55950 1.44136E-03 5.56000 6.34001E-03 5.56050 1.76034E-02 5.56100 2.89334E-02 5.56150 4.56527E-02 5.56200 7.00865E-02 5.56250 8.54037E-02 5.56300 8.68363E-02 5.56350 7.69647E-02 5.56400 5.46624E-02 5.56450 2.37520E-02 5.56500 5.58176E-03 5.56550 3.80790E-03 5.56600 4.92004E-03 5.56650 2.47108E-03 5.56700 4.45268E-04 5.56750 2.74335E-05 5.56800 1.23263E-06 5.56850 2.22203E-05 5.56900 2.09185E-04 5.56950 6.39915E-04 5.57000 7.02770E-04 5.57050 4.22882E-04 5.57100 1.24942E-03 5.57150 3.97686E-03 5.57200 6.09825E-03 5.57250 5.46108E-03 5.57300 3.38366E-03 5.57350 1.52947E-03 5.57400 4.71708E-04 5.57450 9.52347E-05 5.57500 1.21855E-05 5.57550 6.98121E-07 5.57600 1.25897E-08 5.57650 0. 5.57700 0. 5.57750 0. 5.57800 0. 5.57850 0. 5.57900 0. 5.57950 0. 5.58000 0. 5.58050 0. 5.58100 0. 5.58150 0. 5.58200 0. 5.58250 0. 5.58300 0. 5.58350 1.76648E-10 5.58400 1.05957E-07 5.58450 4.98160E-06 5.58500 7.68187E-05 5.58550 4.42321E-04 5.58600 9.72458E-04 5.58650 1.25999E-03 5.58700 5.45207E-03 5.58750 2.09932E-02 5.58800 4.50466E-02 5.58850 6.94624E-02 5.58900 9.17806E-02 5.58950 0.109747 5.59000 0.112703 5.59050 8.17191E-02 5.59100 3.71259E-02 5.59150 1.94040E-02 5.59200 3.41528E-02 5.59250 7.01345E-02 5.59300 0.129605 5.59350 0.205564 5.59400 0.251872 5.59450 0.272518 5.59500 0.283161 5.59550 0.286849 5.59600 0.271564 5.59650 0.252346 5.59700 0.261812 5.59750 0.270169 5.59800 0.258529 5.59850 0.230035 5.59900 0.184633 5.59950 0.131931 5.60000 8.66785E-02 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/conf.py0000644000175100001770000001603314635037352015506 0ustar00runnerdocker# -*- coding: utf-8 -*- # Licensed under a 3-clause BSD style license - see LICENSE.rst # # Astropy documentation build configuration file. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this file. # # All configuration values have a default. Some values are defined in # the global Astropy configuration which is loaded here before anything else. # See astropy.sphinx.conf for which values are set there. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('..')) # IMPORTANT: the above commented section was generated by sphinx-quickstart, but # is *NOT* appropriate for astropy or Astropy affiliated packages. It is left # commented out with this explanation to make it clear why this should not be # done. If the sys.path entry above is added, when the astropy.sphinx.conf # import occurs, it will import the *source* version of astropy instead of the # version installed (if invoked as "make html" or directly with sphinx), or the # version in the build directory (if "python setup.py build_sphinx" is used). # Thus, any C-extensions that are needed to build the documentation will *not* # be accessible, and the documentation will not build correctly. import sys import datetime from specreduce import __version__ try: from sphinx_astropy.conf.v1 import * # noqa except ImportError: print('ERROR: the documentation requires the sphinx-astropy package to be installed') sys.exit(1) # -- General configuration ---------------------------------------------------- # By default, highlight as Python 3. highlight_language = 'python3' # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.2' # To perform a Sphinx version check that needs to be more specific than # major.minor, call `check_sphinx_version("x.y.z")` here. # check_sphinx_version("1.2.1") # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns.append('_templates') # This is added to the end of RST files - a good place to put substitutions to # be used globally. rst_epilog += """ """ # -- Project information ------------------------------------------------------ # This does not *have* to match the package name, but typically does project = "specreduce" author = "Astropy Specreduce contributors" copyright = '{0}, {1}'.format( datetime.datetime.now().year, author) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. version = __version__.split('-', 1)[0] # The full version, including alpha/beta/rc tags. release = __version__ # -- Options for HTML output -------------------------------------------------- # A NOTE ON HTML THEMES # The global astropy configuration uses a custom theme, 'bootstrap-astropy', # which is installed along with astropy. A different theme can be used or # the options for this theme can be modified by overriding some of the # variables set in the global configuration. The variables set in the # global configuration are listed below, commented out. # Add any paths that contain custom themes here, relative to this directory. # To use a different custom theme, add the directory containing the theme. #html_theme_path = [] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. To override the custom theme, set this to the # name of a builtin theme or the name of a custom theme in html_theme_path. #html_theme = None html_static_path = ['_static'] # html_theme = None html_style = 'specreduce.css' html_theme_options = { 'logotext1': 'spec', # white, semi-bold 'logotext2': 'reduce', # orange, light 'logotext3': ':docs' # white, light } # Custom sidebar templates, maps document names to template names. #html_sidebars = {} html_sidebars['**'] = ['localtoc.html'] html_sidebars['index'] = ['globaltoc.html', 'localtoc.html'] # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = '' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '_static/logo_icon.ico' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = '{0} v{1}'.format(project, release) # Output file base name for HTML help builder. htmlhelp_basename = project + 'doc' # Prefixes that are ignored for sorting the Python module index modindex_common_prefix = ["specreduce."] # -- Options for LaTeX output ------------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [('index', project + '.tex', project + u' Documentation', author, 'manual')] # -- Options for manual page output ------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [('index', project.lower(), project + u' Documentation', [author], 1)] # -- Options for the edit_on_github extension --------------------------------- # -- Turn on nitpicky mode for sphinx (to warn about references not found) ---- # nitpicky = True intersphinx_mapping.update( { 'astropy': ('https://docs.astropy.org/en/stable/', None), 'ccdproc': ('https://ccdproc.readthedocs.io/en/stable/', None), 'specutils': ('https://specutils.readthedocs.io/en/stable/', None), 'gwcs': ('https://gwcs.readthedocs.io/en/stable/', None) } ) # # Some warnings are impossible to suppress, and you can list specific references # that should be ignored in a nitpick-exceptions file which should be inside # the docs/ directory. The format of the file should be: # # # # for example: # # py:class astropy.io.votable.tree.Element # py:class astropy.io.votable.tree.SimpleElement # py:class astropy.io.votable.tree.SimpleElementWithContent # # Uncomment the following lines to enable the exceptions: # # for line in open('nitpick-exceptions'): # if line.strip() == "" or line.startswith("#"): # continue # dtype, target = line.split(None, 1) # target = target.strip() # nitpick_ignore.append((dtype, six.u(target))) # -- Options for linkcheck output ------------------------------------------- linkcheck_retry = 5 linkcheck_ignore = [ "https://www.aanda.org/", ] linkcheck_timeout = 180 linkcheck_anchors = False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/extinction.rst0000644000175100001770000001157714635037352017135 0ustar00runnerdockerAtmospheric Extinction ====================== Introduction ------------ The Earth's atmosphere is highly chromatic in its transmission of light. The wavelength-dependence is dominated by scattering in the optical (320-700 nm) and molecular features in the near-infrared and infrared. Supported Optical Extinction Models ----------------------------------- ``specreduce`` offers support for average optical extinction models for a set of observatories: .. csv-table:: :header: "Model Name", "Observatory", "Lat", "Lon", "Elevation (m)", "Ref" "ctio", "Cerro Tololo Int'l Observatory", "-30.165", "70.815", "2215", "1" "kpno", "Kitt Peak Nat'l Observatory", "31.963", "111.6", "2120", "2" "lapalma", "Roque de Los Muchachos Observatory", "28.764", "17.895", "2396", "3" "mko", "Mauna Kea Int'l Observatory", "19.828", "155.48", "4160", "4" "mtham", "Lick Observatory, Mt. Hamilton Station", "37.341", "121.643", "1290", "5" "paranal", "European Southern Obs., Paranal Station", "-24.627", "70.405", "2635", "6" "apo", "Apache Point Observatory", "32.780", "105.82", "2788", "7" 1. The CTIO extinction curve was originally distributed with IRAF and comes from the work of Stone & Baldwin (1983 MN 204, 347) plus Baldwin & Stone (1984 MN 206, 241). The first of these papers lists the points from 3200-8370A while the second extended the flux calibration from 6056 to 10870A but the derived extinction curve was not given in the paper. The IRAF table follows SB83 out to 6436, the redder points presumably come from BS84 with averages used in the overlap region. More recent CTIO extinction curves are shown as Figures in Hamuy et al (92, PASP 104, 533 ; 94 PASP 106, 566). 2. The KPNO extinction table was originally distributed with IRAF. The ultimate provenance of this data is unclear, but it has been used as-is in this form for over 30 years. 3. Extinction table for Roque de Los Muchachos Observatory, La Palma. Described in https://www.ing.iac.es/Astronomy/observing/manuals/ps/tech_notes/tn031.pdf. 4. Median atmospheric extinction data for Mauna Kea Observatory measured by the Nearby SuperNova Factory: https://www.aanda.org/articles/aa/pdf/2013/01/aa19834-12.pdf. 5. Extinction table for Lick Observatory on Mt. Hamilton constructed from https://mthamilton.ucolick.org/techdocs/standards/lick_mean_extinct.html. 6. Updated extinction table for ESO-Paranal taken from https://www.aanda.org/articles/aa/pdf/2011/03/aa15537-10.pdf. 7. Extinction table for Apache Point Observatory. Based on the extinction table used for SDSS and available at https://www.apo.nmsu.edu/arc35m/Instruments/DIS/ (https://www.apo.nmsu.edu/arc35m/Instruments/DIS/images/apoextinct.dat). In each case, the extinction is given in magnitudes per airmass and the wavelengths are in Angstroms. Here is an example that uses the `~specreduce.calibration_data.AtmosphericExtinction` class to load each model and plots the extinction in magnitudes as well as fractional transmission as a function of wavelength: .. plot:: :include-source: import matplotlib.pyplot as plt from specreduce.calibration_data import AtmosphericExtinction, SUPPORTED_EXTINCTION_MODELS fig, ax = plt.subplots(2, 1, sharex=True) for model in SUPPORTED_EXTINCTION_MODELS: ext = AtmosphericExtinction(model=model) ax[0].plot(ext.spectral_axis, ext.extinction_mag, label=model) ax[1].plot(ext.spectral_axis, ext.transmission) ax[0].legend(fancybox=True, shadow=True) ax[1].set_xlabel("Wavelength (Angstroms)") ax[0].set_ylabel("Extinction (mag)") ax[1].set_ylabel("Transmission") plt.tight_layout() fig.show() A convenience class, `~specreduce.calibration_data.AtmosphericTransmission`, is provided for loading data files containing atmospheric transmission versus wavelength. The common use case for this would be loading the output of telluric models. By default it loads a telluric model for an airmass of 1 and 1 mm of precipitable water. Some resources for generating more realistic model atmospheric transmission spectra include https://mwvgroup.github.io/pwv_kpno/1.0.0/documentation/html/index.html and http://www.eso.org/sci/software/pipelines/skytools/molecfit. .. plot:: :include-source: import matplotlib.pyplot as plt from specreduce.calibration_data import AtmosphericTransmission, SUPPORTED_EXTINCTION_MODELS fig, ax = plt.subplots() ext_default = AtmosphericTransmission() ext_custom = AtmosphericTransmission(data_file="atm_transmission_secz1.5_1.6mm.dat") ax.plot(ext_default.spectral_axis, ext_default.transmission, label=r"sec $z$ = 1; 1 mm H$_{2}$O", linewidth=1) ax.plot(ext_custom.spectral_axis, ext_custom.transmission, label=r"sec $z$ = 1.5; 1.6 mm H$_{2}$O", linewidth=1) ax.legend(loc="upper center", bbox_to_anchor=(0.5, 1.12), ncol=2, fancybox=True, shadow=True) ax.set_xlabel("Wavelength (microns)") ax.set_ylabel("Transmission") fig.show() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/extraction_quickstart.rst0000644000175100001770000001500014635037352021364 0ustar00runnerdocker.. _extraction_quickstart: =============================== Spectral Extraction Quick Start =============================== Specreduce provides flexible functionality for extracting a 1D spectrum from a 2D spectral image, including steps for determining the trace of a spectrum, background subtraction, and extraction. Tracing ======= The `specreduce.tracing` module defines the trace of a spectrum on the 2D image. These traces can either be determined semi-automatically or manually, and are provided as the inputs for the remaining steps of the extraction process. Supported trace types include: * `~specreduce.tracing.ArrayTrace` * `~specreduce.tracing.FlatTrace` * `~specreduce.tracing.FitTrace` Each of these trace classes takes the 2D spectral image as input, as well as additional information needed to define or determine the trace (see the API docs above for required parameters for each of the available trace classes):: trace = specreduce.tracing.FlatTrace(image, 15) .. note:: The fit for `~specreduce.tracing.FitTrace` may be adversely affected by noise where the spectrum is faint. Narrowing the window parameter or lowering the order of the fitting function may improve the result for noisy data. Background ========== The `specreduce.background` module generates and subtracts a background image from the input 2D spectral image. The `~specreduce.background.Background` object is defined by one or more windows, and can be generated with: * `~specreduce.background.Background` * `Background.one_sided ` * `Background.two_sided ` The center of the window can either be passed as a float/integer or as a trace:: bg = specreduce.background.Background.one_sided(image, trace, separation=5, width=2) or, equivalently:: bg = specreduce.background.Background.one_sided(image, 15, separation=5, width=2) The background image can be accessed via `~specreduce.background.Background.bkg_image` and the background-subtracted image via `~specreduce.background.Background.sub_image` (or ``image - bg``). The background and trace steps can be done iteratively, to refine an automated trace using the background-subtracted image as input. Extraction ========== The `specreduce.extract` module extracts a 1D spectrum from an input 2D spectrum (likely a background-extracted spectrum from the previous step) and a defined window, using one of the following implemented methods: * `~specreduce.extract.BoxcarExtract` * `~specreduce.extract.HorneExtract` Each of these takes the input image and trace as inputs (see the API above for other required and optional parameters):: extract = specreduce.extract.BoxcarExtract(image-bg, trace, width=3) or:: extract = specreduce.extract.HorneExtract(image-bg, trace) For the Horne algorithm, the variance array is required. If the input image is an ``astropy.NDData`` object with ``image.uncertainty`` provided, then this will be used. Otherwise, the ``variance`` parameter must be set.:: extract = specreduce.extract.HorneExtract(image-bg, trace, variance=var_array) An optional mask array for the image may be supplied to HorneExtract as well. This follows the same convention and can either be attacted to ``image`` if it is and ``astropy.NDData`` object, or supplied as a keyword argrument. Note that any wavelengths columns containing any masked values will be omitted from the extraction. The previous examples in this section show how to initialize the BoxcarExtract or HorneExtract objects with their required parameters. To extract the 1D spectrum:: spectrum = extract.spectrum The ``extract`` object contains all the set options. The extracted 1D spectrum can be accessed via the ``spectrum`` property or by calling (e.g ``extract()``) the ``extract`` object (which also allows temporarily overriding any values):: spectrum2 = extract(width=6) or, for example to override the original ``trace_object``:: spectrum2 = extract(trace_object=new_trace) Spatial profile options ----------------------- The Horne algorithm provides two options for fitting the spatial profile to the cross_dispersion direction of the source: a Gaussian fit (default), or an empirical 'interpolated_profile' option. If the default Gaussian option is used, an optional background model may be supplied as well (default is a 2D Polynomial) to account for residual background in the spatial profile. This option is not supported for ``interpolated_profile``. If the ``interpolated_profile`` option is used, the image will be sampled in various wavelength bins (set by ``n_bins_interpolated_profile``), averaged in those bins, and samples are then interpolated between (linear by default, interpolation degree can be set with ``interp_degree_interpolated_profile``, which defaults to linear in x and y) to generate an empirical interpolated spatial profile. Since this option has two optional parameters to control the fit, the input can either be a string to indicate that ``interpolated_profile`` should be used for the spatial profile and to use the defaults for bins and interpolation degree, or to override these defaults a dictionary can be passed in. For example, to use the ``interpolated_profile`` option with default bins and interpolation degree:: interp_profile_extraction = extract(spatial_profile='interpolated_profile') Or, to override the default of 10 samples and use 20 samples:: interp_profile_extraction = extract(spatial_profile={'name': 'interpolated_profile', 'n_bins_interpolated_profile': 20) Or, to do a cubic interpolation instead of the default linear:: interp_profile_extraction = extract(spatial_profile={'name': 'interpolated_profile', 'interp_degree_interpolated_profile': 3) As usual, parameters can either be set when instantiating the HorneExtraxt object, or supplied/overridden when calling the extraction method on that object. Example Workflow ================ This will produce a 1D spectrum, with flux in units of the 2D spectrum. The wavelength units will be pixels. Wavelength and flux calibration steps are not included here. Putting all these steps together, a simple extraction process might look something like:: from specreduce.tracing import FlatTrace from specreduce.background import Background from specreduce.extract import BoxcarExtract trace = FlatTrace(image, 15) bg = Background.two_sided(image, trace, separation=5, width=2) extract = BoxcarExtract(image-bg, trace, width=3) spectrum = extract.spectrum ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/index.rst0000644000175100001770000000435214635037352016051 0ustar00runnerdocker######################## Specreduce Documentation ######################## The `specreduce `_ package aims to provide a data reduction toolkit for optical and infrared spectroscopy, on which applications such as pipeline processes for specific instruments can be built. The scope of its functionality is limited to basic spectroscopic reduction, currently encompassing the following three tasks: #. Determining the trace of a spectrum dispersed in a 2D image, either by setting a flat trace, providing a custom trace array, or fitting a spline, polynomial, or other model to the positions of the dispersed spectrum. #. Generating a background based on a region on one or both sides of this trace, and making available the background image, 1D spectrum of the background, and the background-subtracted image. #. Performing either a Horne (a.k.a. "optimal") or boxcar extraction on either the original or background-subtracted 2D spectrum, using the trace generated by the first task to generate a 1D spectrum. Further details about these capabilities are detailed in the sections linked below. Beyond these tasks, basic *image* processing steps (such as bias subtraction) are covered by `ccdproc `_ and other packages, data analysis by `specutils `_, and visualization by `matplotlib `_. A few examples will be provided that feature ``specreduce`` in conjunction with these complementary packages. .. note:: Specreduce is currently an incomplete work-in-progress and is liable to change. Please feel free to contribute code and suggestions through github. .. _spectral-extraction: ******************* Spectral Extraction ******************* .. toctree:: :maxdepth: 2 extraction_quickstart.rst *********** Calibration *********** .. toctree:: :maxdepth: 1 wavelength_calibration.rst extinction.rst specphot_standards.rst ***** Index ***** .. toctree:: :maxdepth: 1 api.rst * :ref:`genindex` * :ref:`modindex` * :ref:`search` **************** Development Docs **************** .. toctree:: :maxdepth: 1 process/index terms ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/make.bat0000644000175100001770000001064114635037352015613 0ustar00runnerdocker@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Astropy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Astropy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1108735 specreduce-1.4.1/docs/process/0000755000175100001770000000000014635037364015665 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_MOS_arc.odg0000644000175100001770000003132714635037352020356 0ustar00runnerdockerPKxL.++mimetypeapplication/vnd.oasis.opendocument.graphicsPKxL_Thumbnails/thumbnail.pngPNG  IHDRKPLTE555>>>AAAKKK\\\dddh#:IDATx܋r(v[Gs ɉݸIgGaD5ge|jjjjjjz4uv?_]/p)ݩUۖ,dR=;#j`u@Bd,̑"aaڵCƉyqڎ#2:$M5IBd5REs̋OQ{5J-Τ̹Cc,C]H#S d"uH⬔XdZ#H [9s1d1XjeDKHoԅ(@>x:Ӗ-]73J~ռh!jEMUͤI5aԚ0~峂m¬"s^Cl?j\QՋh Ѥ]\-E,QD±9u}$jj87ڹ$o#L&o=I9Ϩkk,IJ){/25eRɦs:L1M'&9u۬/_gBy'[yؐ߬A4 >yc˓[Ȯg>؋ףĺi0n%KNu_;jTjzUi Ӟfmuqm[d#mN,ij?9} 9|;b^cEşSIX$ȾCU (퀇PR￴Ԃ(ul:'hօ?:]vbSׂeD2'n.o{UcZU[*IDI(UK{4S$-YN5M蹮v>ϧwVeF{vr Cp\6үuelan.N^H9\ROڤZ 5+XREVzp ۖnJ]?bVpQHlyCn5n]\bO %k;W'sŐ(;s)(]my:N wp5Zy5!{= N9[[8U\s.o9Sk]ӾlۯmL{.cHJ9M7oPsOe}n% r߀mF^ҋqD:%ZI6؆%=IwϛnEk-=t1>%of6uEýy\p`ËkPKҰ$PKxL settings.xmlZr8}HQ0SSC$]f10b7a)Dܒ 4m⩮ŖιtϽK@ѫ\!3*:v"K}T̏De^ )UqSQ^ܾEX)(KBDWo[ŕUn&eX.8>Oi!GBA>oi}Ft_EcF% 㴰j-Lm> Be󄼛+@q/n1Unھ\7.R]aחY|DemUNQ1_'>z,ꦜ&2w}zV:,lv=mbtrr0C9j|Og[/^|< ΅QX\3SH\!wn&ÖX1]?"!6gt}?%,ub*vHHۘ0#YzLl#h uaU:[zꌔW'lJP]fI&Y,`Ua&새 È_7*j7CDԉTH\`S5I?9E!I3@hB>9$"C|pUӢW`(UL|u37LnDQE4\d4LJ2i}H`AҮ; OXVȻ>Z 軮9gQC%k;)+0l4u[)F@X ny[.- 캽6lo ܿ$rL C2w5 + jwQH璠 AXI:V%d8PjWYv(O~N=2?i YjN=HE;DtVmY9Co^k+m' hZNJ4F%u\Vj:?q+gn@7,m(AZBy/Z")T{"( [ Hr|X>Dlʜ G`!)2)'U;ap0A) دPu>M2@Fz\QuG.(n-%ZrBH\lM>SVzJEL9g(:[OG`>퇔X[*p*$|&ьDzQn+#gyܒidU?)_ yBž\}ܱ~Woaou|חn3-uj,c|]PB6 LZq50U/Qϫ|bؘݘLT;e8Yq$K֞cݸv/>4W?û˜^0ܔOy*a"1Aٔ|+V)*X $zcgY®x] PKoJy%&PKxL content.xml]ْ}WHޞncWndz8~CDE@JO1/7")B#yi /#eMY&iDa$YӋ WK窟9@8(k/'+_$$ ,ivIJE[xWYtB:lc.+%wo.ۭF6,n>Kdg:KeJpG(\Ny^LFZSy޴mtŢB*4eihZ.iNdm2ihHN:2|.'\G6siv0 ¤yVT1yA䋁u7PY-ee|ҟYJ'IҨ^uݜ-^ sZ^qD~x $To 4Ӳ΂tIḰYN-22GdHKP \c:aqkh|E]E,zEAc 曉!fǚBXҧ\q'@mb&ΒUPHSB^EمC{+q!H4=WI$̀`Izj-<iv{qX~y>:|j՛Z\yMDziS0FCb|z_NCv-K@E4.'ߒ4ɾۑ+ '5W4 ձdIbA" s`T^5r&|ltBMes[eAP'Jˏ#'CQÙ,\ILfx8wE+;T~W*JȟL鐧*Ox8բ?/ RԼjdt:M猤ЯS|xPF#ZK¾PmiD(rO_k>Z 1\uy5xdGR!rϷ_bu<̂rh!ah<{%_'Q.'ş‘vm b~` GgJ{"R?+75pY3Bwf`| \o#t뜹bͱсp) Ɂ`H|iŴ:SFoށ>:S/d@" $MI>Za":XaYȪJRq%ޝܩw'CO;6{1YQC%Bi.bd!*VyDjy;O_e,,aeѲ/[E4K:Hz'CZ!!da|'Cx8idO{'Dui~DY/Qtz:xK桺gpX %2Ϩک+ۺPf9e52#@ j )vT\_h6 ͏‹0A-&>E_RU^^FleZ6B>ֽˆVikLH6q3"0_iͪQ-K+xhFuN%C 4]֫5!c km6[zGUG+I+yiUPuI{.gb1Q!pfQ)UgU oBw ЯυtV/c ϯ֧D!?nPf!L@Yvüt/uo3o7UG`I) - /_ۺ; )5bW%i vfl`xl D֮"MݶH1[cl:AWBAdmKÖY--e43`k#O~z֦(ի_^^+ZZc ǬlcF<=0Аybmp5w ׵-=uQ]xӵ")9j/UZ.40܄'atmsĮŨ[E:k+V,7G8drns84`lCH!Ҽ–`X0Iĝq@}'4525Ǡ@ЗwAGv>qH {zSc0%RS.%0`L@HEeIeZIS%ZMF]xNNXA޳>aYf~܄<'Bɢ0WrF-Bdl[c+0elݐHg8=qq+Pw={ "T &6n4#HFFSN?3 ޹t ҉C8A25 C-dR;S^ŧ<7` NΓ.YEXputӾ!#k6wN=&a%92TMM%WND4Q Yӈ|ΦɰI[M^sY^Cٰ x4s<4%I&fwH#u=k<9>I'QxHN~9Vcnķ 䂜k!)[1R a6'I~i) }kJ~QBrHfs{LqmBR,yމw > >Y|4{,4^74C6 <QXDS኱fmOV/b7܏q~\ϫ` +f_膉) Yz5Yt CG"Pmm} XJ4v4r`"Xބ?#Ȝ\ݮzwoşs;|Heăd㾳]nݶwn&2[BB3־ߏo?۸}¸e`Bdp%b s00x}ahCj J*#dXX[ C9-!6 ?giհuz'8xGa1:qvN!tl- q$1̠a5lG°(  a*/*wM_ӁPK^ OtPKxLϣ[[5Pictures/100000000000002000000020B2FF2A327EABC87D.pngPNG  IHDR DPLTE3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3fOIDATxc'F*U0RU<4IENDB`PKxL styles.xml[_s۸覝ɱƹI.M^k;"! Ip@в%wA9N!v+Y0Yr_q0X?~yC.F߿s\W)]J&/G炖4c\sQNsы يݪ5.﬙ى0u/ɷeJ"+;Rܦp^rQ+6َ![S4{Ny& jRRTybn &9h[+{,Y?gVR,Qs!HVbnE>fD>E Y) /iH|Df3(C{i!ղ]@ Qy OV,h(!4PɵmE%dC/-rsdgyWXʻzaS"]XY)\y _,[Es?,~d{7WEzܔ/cDDAOFu\ %e;,:~̨l=p{.?5 RjCXy@IpwBo@k5`ruPSAM¶v%}N`Es,߂qY=,{DK.-+_E|-\\~汪5_EoD/'_^Wv uWhB_ X$#C 8E~%hhQIWRͼxQM3i]c) qpK%GZZ5<.⯣5>FHv'/jd*C&,_a:E$EmΨs %Һ~\Gpb孟IW&gFFdN덵QYy4[XK1RDa+QA%;$Z)Q Ś8TT X[S2t d!`E>E2`D-Z 76I*(n,iZ)(1հ^{V%#Ql޼QɊ̚^O@c) )1\h~jo]ͻ׷|fz#Kt{kI|_%]v g CE؞V-1>b@GJLF{X`d! Oϣwd+%HLbǓ&V1 Ěw_tP;&c@h Y7WS}_4N'nsJkM+JiQ0:CB(M.Zʖ ){WkbwMI L6m]'x?0< M!f벥솥,4e3DYF?qg}!'1e vl鋕H#T3Y:>ÃҔ$ x37KMNP8$B"t$:;Bx$zv2&OD>8=;!BO3N :C@;ؼ*Z¦Pz QSǚ-53MF5r\7) k/ znsI RT5[ZnQdZ|ǧLp2JxQwM̘Lf4bm+=+8iD.&vM}rvڛ@RggH_V߇%vv_ҷ4 .QZrp90GTf~/ G? K NCmq,+ԘoIrlﴺ~%X6\A7MNmRټ@F G5:[W?:?2xu4MxH8tKh>%:uC~n_|Do.7a t+hCkxpStȷ!B$w){j}xQh>T%Xiw5ĥ|˻4wԯW#.;dUa!OG2>N,&_Cq{m =8iӮ,q<}]g0.8BW}rT2Y3i9[y>FJw0";/wӶak[u.%:oc`w PK* D:PKxLConfigurations2/toolpanel/PKxLConfigurations2/menubar/PKxLConfigurations2/floater/PKxLConfigurations2/statusbar/PKxLConfigurations2/popupmenu/PKxLConfigurations2/images/Bitmaps/PKxLConfigurations2/progressbar/PKxLConfigurations2/toolbar/PKxL'Configurations2/accelerator/current.xmlPKPKxLMETA-INF/manifest.xmlTn0 UM;*Zlw`n8U H@ih%vld'YN$GA;,،OY\)~.ت,D]Cj$][1w2萣rRk+{~~ay+'ɝҮޟu4&m% &܏-TZtn`mV4qĊ_Nx L Raw arc exposures Standardize meta-data Linearity correction Initialize variance Add mask Attach slit traces Cut out slits Resample to linear co-ords Map spectral distortions Map pixels -> wavelength Calibrated arc Rectified arc Subtract dark Part-processed flats Processed dark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_MOS_flat.odg0000644000175100001770000003631514635037352020541 0ustar00runnerdockerPK!L.++mimetypeapplication/vnd.oasis.opendocument.graphicsPK!Lۗ Thumbnails/thumbnail.pngPNG  IHDRZPLTE''',,,555===EEESSSZZZcccnnnsss}}}5 IDATx훉v8 ,wmI9dJE-8 P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P P {Qta֑ҭ8By7V9JYVRy߸Ŵ୳u.ֵ R1Ot85r2(7ppl G t_Щ ;J8꾏_Cϗ#ժjgC9: ap.V\<'ѕXvl3XFec2*K;U7&P&Q=b0yUP}cN,@*Yk;Ͽ|8uPک?J6DOPjzqp6v/7? /5Qgb}NSzo!4 uX8Lj-Sn0xc#^)˿ɿʥnPT4FG&WPe*D]j{c[cZmmU-V#Zf[MK%ZѦ'˳J8ydku xvDG`7{0+Ki-$%gɅBםB֌c:{zձi {.: Uk;S[3\@܊F!nyhW>R#5odй8nQS~S*T{1ԶW#M t+YeչJ!OJV'vk hWˢS*M\puPlm{ q4!a*lE9aEH!ZCn m7`ds8獃)WI{Ԇ{w엸Bf m5МګMvRle 5\j^97 [\r5`Bl۲n9?tѱY; u& mQä; s}׍GXSӪ nr)Ml,ݟ<`H![ajN& ޽IOɉq]lw~ԄtE>z7ߣS(mn#ne[k} 'LQFqxN+F+/!%"(}"(m,+OU7[esI5PÅ vh8^rn*E8hs5)/_bD})(y@ekV?X*!kÍu566IxA8.z+R84;nуsbR7֧cJdBj׵O9ww:(䠧h]sBQ)t 9vye[GG`y -Wv@wËhx/L iR:S0^SO%4,'ke}?ʼb5ȸ^PQ_<#D_deb/(u_g]S/a7`=]N}!q^C,Op>{NNؿf5V3hΐ-NPrTx~?D$/5Nݩ:i|辽n.:>SgP+ya?4{{)6]M,!|iszQ+}ls#%mտkȍ)NilBP P P P P P P P P P P P P P P P P P P/g 9(IENDB`PK!Lmeta.xmlM W:fzڪJE)- :58N6Z3/3CtdʍZ5 M ulǸO]_^i:t\㮍&x5`0 Uqźj5C$Հq1O9t]PF/\?(F!W0MRὦ<nhBS˱֬si/ln@!TжފA^U7gs}4[C@Ƌ>(}¶~?B&bh\XX (\?}3/F .g׹P}>|Qڂkfr+.cfBX)=0J=[|H@<%G`Ӑ],%vHNwȍ0y1w(p¯q `*ߕ_ Lrˣ F!(g֖L;MH0b?8ꬾx=T([Gs ' ][`5'Ã{폝I opFڮ[SKEs>iz)lNC:q 0Tk4Zqd+Ⱥvѯ>$W?ߍ!v+l2e]Ng݀䙞 ԗ}Gq9e-o]ḷs1#ce_ϳ;ov?j7k WiI@"eIfF4fCw|ajAݎa4MioGy;~/,i]y' ?X  m~_w*ovJCi%QM`55 j}5A1sviZ@KM%d/'Jh@@ |= Ҏx\T鴳o޽,z$.p(mh( Nۚ: CqVq4n)"[*Vd:U;d #:fD-cNSp%ڶu4-ơ {X$U~7zG+? =HF*`aWRv2 ÄW7Bk%ˇaIOg k$SǼN&Z$W_St\gS6 W_.֊].Ώ@KHaj>ގ~W pI]sz}"$^D 9Y.gxㄟ9:mU_㴻N$O׵vZnkiƖG g2 ?6 $EZ,hN&;OKӔ:9y? Jo6]a+ }ΓVy*^ __wT~2UMhidK5(,uG`$?__I]4 fM o#[`yo 3?Lv,.5 ϛ,m046͋X', ugmm6\bZUߎ~[㦁t¢|5H>N$`fotqhr6a04ѫ tuBPb}0UID0iy/}zj 2&Hdܹw>PSS.lx(3Og:D5M/dAUs9`溜X_,gA"60L"@PIiZyYtϹBn@%09^jA\z{˲Un> 9jVIPˋϴx:r} ᗱΰ"Ԅ /(YI-We,\Ё~>rĥxȠAz떖ײKDigb(LJ6RiRJ |ԅw3` ǟg5,އq+*2 JVo΋u? 졬.P?5qaʶ:dPZxQ m+pUtӯ.mwT%?@">ֽ*6Om^n#Epۓwm$6H.V%tNi}ޒc>h,\=,b”=ɺFit'd:ƌR{=dc)4{^Q#C?Edp义47I4`LvxOybEOLϹfڮ 7|d2-OB2P"*vWܬ)'`u*vuK R yQ<;YD5ȇP*j DN y kh) /fQn|  tzT;( WW&6$xͅP{Z&Hs)Ty7^20b%:4l肅#tj84 -&(B{uT && فCȐPvl8vt ǖaafy:M5?\R]Wof̰wqLgƆ]lH('wwfO z 7 ) 1ivUKSb:3y r]uvċ<`"#b=wwd 䏾K@3t5&4d{^EksmkB7T8A .'d=b;TnObg _'8ߊ5ҴЊ3)yJ>42{k?|ܿ|~`ۑ~2]RDT06\SΠSny %6 z}ӕ\i &&Ť 9x62:XO{Ӟ"ctRùF>^xT6qڠ61̦'W5ߔ-ŌL9NJW̸nnM7?GI=O˹q-Vl]sH{{Ø\)0GTֳ@GvfԒ*dqn#U0"CačV{}L*lA=,Y;TzBhԢ߭xHTJg+♝%rUx_lk hP?(YE c:,;PK{GPK!Lϣ[[5Pictures/100000000000002000000020B2FF2A327EABC87D.pngPNG  IHDR DPLTE3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3fOIDATxc'F*U0RU<4IENDB`PK!L styles.xml[_s۸覝ɱƹI.Cr6w/$$$AΗ}~JB9r7 `~MzL\䗣p<"rۯgx*Ky"*c"MY伜娒\Вfx. Is{2#z5;[5t25;;t3t2:LRXdU|G.Gko6f2r凳F+*j$Ypǡoy3P)j!Y ,.尅9-^ Uvۦ2I$qfT{ D7[нU,y1XMB4Z(yv77+& {LӸA\d]_ahOk =FBs>z3UjxKV@Ã.5!c?d ղdt88/lݨu6َ!)ɍ'qeN XlA! [P"#hhQIWRf^ (&kmc) qpK%ZZ%<.⯢>FHv/jd*C&,_a:E$EmΨs >ot ;UjJrY]xUZ2l|b孟IR[D;kgh!`,|KQ‡DTG0M#R,(j& +M5rm8.bB2(  VL$%QVy°^M%MK I: *zZ ;굧mU2ņkXK`z4-K!V Hz D]I8/%PSѼ+R\odion,Rr﫤˔ ؼܾvдj=&G V xq #R M9:D{=z|K: -z̰b[N:&c@h Y79<8O' 'G٤'(h^NjB)ltRTH#HZ;skO@g@W2EnڐD E&o 0[-e,5dQ)S!⸾g!]wٚlpmhHkǶNCjt'U}3[ 'xPtsyB!G]J ɣt<8}q24NNap2ξ@:+6/`oV)*EB{"u b|VQM ڋ>(*6C҂jMꮖ[3eglَuČYdF-ֶӸCObb'g׫) ѹ,u{ejkλ^`XƐ%jWk@.8j;B臣aiHAâ-eŚ-RvZ]hq{ WˁNmR|G G5:[WN@p84A>ᬣ5/yuF4{qi2gaCe߹q- [o1[Aoz2Lw'ݣ3F )"}HIuZJpZiחϚ7q)_݌jU򈤽sJf \tz!JCf)0Ցwctn#ߍýdC#:894-ؾjrdzuC[Þ!tqz'G]&kFN9A_9 URa &CwOa嫅n <\D3FJ~ u/chXbs^HZBDER\ՕЃT~oLbb #PAI:_s [&eޯ.^c˵|(B_H]|--mREO.`YقV>*Yj=Ri~ J6GFS=V! Part-processedflat spectra Processed flat Attach wavelength calibration Derive “slit function” Project to raw co-ords Normalize continuum Cut out slits Resample to linear co-ords Sum over spatial axis Fit continuum Project to raw co-ords Divide by continuum Spatial flatness correction Divide by slit function Cut out slits Resample tolinear co-ords Calibrated arc Processed twilight flat Inputs Resample tolinear co-ords Inputs ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_MOS_science.odg0000644000175100001770000003730314635037352021222 0ustar00runnerdockerPKlL.++mimetypeapplication/vnd.oasis.opendocument.graphicsPKlLXz z Thumbnails/thumbnail.pngPNG  IHDRHPLTESSS[[[gggiiippp}}} IDATx흋ڸ;gVۺrU\({{M !͇p~%?ˏNݩ;uԝSwNݩ;uԝSwNݩ;uԝSw|Oqa_q$)ge'ˋURWr ap#|/Rz6ZY&m; njR9dTГwq a~/KTjqRpzFX چnyJSǺ}+ʼnԿEC+Z.Uۇ!F LکcT!sx7F·ENGz <GjൎD'i: K Cf}2E/7?6!^&mADZ98Cq 5f&g qK^GZK5ݹa(!DJD}鲃"դͯ!jJ VO|Y75_rNs}i܊t>:5vrR41!5NɤC}xtTz[ƹ~;`Շ[ Ռ^?Nz H$ZmW "Uj7W!!א%k)no¾Vl-n1Rryc" Hb%Ɣ up~;q$Uve/z+Xu赧?vڼl>oaٲKzEW\VSW۽NlQdW(ڞx,y~\Clq1SL>cr39ZĎڠT=T Fs1zNhmPJL~'y~=^.0'42B-QrVqԙ3rT 6g2<#f-J׊nYIpFS(Z>YO8`= L#ɺ!d݃P_?-}=^p_N~e7?'`"9z_^JQ%2.& !>֩ 0Wm}%Mεh@~i~ puZz?u3D#ԋ4Sv០׉οۢ.o-ANWE $mҋèQcUI%$۠ j^:,s )ddB 2r fjR KeԈ@!FQj#"oD <027zw^Hϓ!v=1VHwçg^_?Y5-w%%t,lL2>43sK瞧b[6s~ƗCyr'S[>]O[j3 al )אD$Ios(>A▯-sgR,f|> p|}5VA=KimSgWOC.5'zFmVd X''.}b5ru΋j8!ߍ}j,QԂ,<*7ߏTwW@t>w^x|܏zlu au2Iz6e'/Iꅍ:΢̚^nIǗnu|dȱr[VhVQ2 9ցlel%(BΩv[_ u~T@eLiO+~^j/-RQX->!;3ZEZo)R\ 8mH2A*~T!d'q7rokKM5N$ziA79݌%_ԶʵͰCF0#Vj(s؈=P l'ʚO^)s5d?U/펶|m{:yꛊ&sNjҏS+KfisckG ZaR ;R3Vf4^a^xErW)nmg;uR'zlg*ǶD[n1EW9NQ S;hFRN "" >0cD@X5owJАLWѥSwNݩ;uԝSwNݩ;uԝSwNݩ?Sr6M/IENDB`PKlLmeta.xml͎0} lETT."-6C0{qpjZFRK}1COO-(`*F1][i[q;Pi6%oNTKӹa< C4l"myui&Jp ӈo5ٵ΀_k75k:lLcBx>/meskFφ\ݘ\V5g_>!kC=o᳄=XվjbT-[Q1 T1YHlwMHm,O}xi W7j3V ؊/3|ZQ |\$"QwR,ݧ`;wlD$oe֯uӽ>x8^%9U/z/PKp/PKlL settings.xmlZ[s6~aNŐKcfb7a)D\IC}%,,+Ng[#H;|%"BUh ˂ŋW?}a8DU$BTR5Tw*ۗ**UVY[mjFB0},̥RӓόJe۶KuӘ# >m!xv(ʲWu2+uZZ^&rŐEyJ+@qt(n5UnھZ7.R)\aW_V(b"#VEY}(}®~ p<7"V71EKi;AB/Oc |yw_9*#1M.^88bᆙBr +ehq b5Sp@ໜ9Q{L3|"yr$~`R|@n(.Wsg3L$PHpH 9]lٿ<$8HgdM[G]ylYhXztBžM| iMK3[ꌔbMO~ߔz̑*LX3¶M<ه A_7*o9j"DCP(p[de0hK$ <"d934d\! #>dE0ԲzZ )oNvV\YS Cp7ls\g e8tW~,~֊53$9r4erDq/>qE&y5MjŖGNsPƢ[Cbokn $/--/$< ?Rcr,|xHҢ}vT?~%Q"(U,ԌU)uyC_G6sBCN"H3SMtG%x.S !q|Ir#X-h= df1Bw{~?5ĩ#Ԛ$-L')%) -ǻITͧΙXa:;D5E.Cpg &P̐UibJ"%q#FE@$th'DMMW?;OBH_|DQ^gkI,7Sx[N\XlDXZT"D(zr=UDxqnǭFH&ZGIz[ɲID'zyFqvkPqMJn ?;ެm|t8]GQda˵GK`|fMڶWD`# NP[LiI둭 T}NA9X ^ie[=\V]L*$ܿ]Ϛjvt^LZA [38 {br7!SN45Y97[k*/850f ^dp\Ӗg)z Ǻ}r˰u-N^"| vg ]YC֚AP״oVZxF%N#jB@P>% ݊!C%<Ѵ_o-S/PK+x'&PKlL content.xml]r㸕ORvSIHθ:{I;;;l&%J4EjIJ3'$[vk-B987߽\6(M'0'Zy,'7yKh^f&>Kj;ɯ&K $XU1Jab[_ϪJ)V^6f{cڙwO.YڙPTcP_"1/דX_M1l9EOvzel!}X>E6mWaelVwa MPY]gaMu)a݈vL]ۥ})Y٘'2W'2g^2T|UR}mA5ˢkViC*f/MӚVL뇽3loYZӕ4hB[&@xZU?}݇`8nGI^|ʳm%D$2)ж=(1HYN"O-F*0Z4]f) LA0ѷQ :'LCR6bׂ9mZq[e.M20|\YDv݁8[1sn¸\+ o*BMWLo~VjL;v,I!?NiN|X'1kJӶ`f>gqj}jꚎzrbW« H XDOד_4m]U8Ѹ[2LuY :*fl,*o>4Bils@G.!Zmqڍt`\6|:TLBn$XBtv>& ?G_D0nAG[K)iNe.6EJ^ާAܛר}X %L2u]f>5 ^yW2oE_" s +u&HT>͢TA-Aɋhm횭"XQe>aU`9.ҫUZ <[ќ*@؃b: @'Dkd_ fƄ+ x?KZ4e!> RV|F(pmҧ(l8GQ)꫉g ڧ&4PY%)N/x\H<f 9 P0;o,2 ׇ =R@߂./ZlFu"]\51МH МH>Whg6\p!͜5jLv0:=icھDVbEsDj2H?QqOßEem2~JW%߆]PXSf ɑV8~>+L!d44. ]ޢ^u1u([N˷P%,AGႎLUգKwի8JPRUwO`]%)LeޱzfYʵ}h·0nVVߠub=ȣ U48|ձ4"E4s,-}頲Ujnʕ_usu= 4ѿ[/B`1ޗ'Bh VvⳂ\."TF ='# HuM!BP8t۽ݫsw>/3ym&y}׸g=s{/9zꛝg>ǜ]XH6=99q3!w&l8܆q=aw8 0IuYU`?-Mvx[vE>M3zٲ"ۄ9)_}ˌxUUZt ]HzibEUC]qp}g@:[BUƛC:"BޛD>Bذ$B"oxQ9 !iM9M=G~]P.? +=n Vՙ scּ9clbjݔ fơ:ߨ<ԡMGR`~N\דh4 5>˫zlwʉeBjOe/Dס5j  _ |,Ԃd_q,[P==Vk/tS9,z>RFYL@eid:luW.M()r G 3G^к[M ;4gaR%.?i @-KALX0 ITDA zV^tD? 8[(~A@A>Q,~1H,MNٸPP}< $ 0BI1;Ij$\.dsټ mV+fYŌ1~-pLֶ,k  T-D*X*9gTbCPm*!8TeT1 ,pŊ-skG{O Dhe[z6x TzX>d asD ` a6S M[?wڬ@JHǪVd!2V;u9X >2 }~yD#!=J#- sw@sXҖ̞sbDccms)d#ƞ3a2øuPշ"шQyRx-$f GH1̾ [0K|솗6Ƞ襰`E26,iC{ZO9/3=Mn0", BGvP!_7=\B%Hy6_ܴ=>B⺣`\$jõp\i`4drze .f1&5QMbB9A&0/&Sċɠe.A1<$ [`yX1r ktQeމr4dz-DT9gW!}'}lܶB0!} @muJ#/? vd)-Zpc^[#l}ܣӹ»ؤA RL`FU9H -dqT\/)烝h8ک).6-!T~[{/#> ',xbWކذ/K/ru91<ia^GpN[zYG FqN̨ubkM [k9caC0mm"ޒCmqU Gp G.NPՅq1q7iyiqIm-[ڟhQ\b'is2& @,.$ޤ\wCQݧQ%~x1v;!"K!l`mɲ`,FqZrr˓'84|" 7*E~.b~L˽Zaq 3]Ǵڒz!0Thם tDm89`:ݿ=V*BE &}m`>g7 ɈߑX!#6~mZL|i)(l/B&{&A;E}ŔPǛ,i]f Z.mʆv\:򼧖‡ԃ:,ڢruCs[]XuEHJ]Aq0D+TLǒc;6&Kz,.%& w}iEi689No7^bxvoaE&ܗEl%AK&6mbhwA$0~^F,]D+Bs- ohiŞxy V"ai؇m Cs`ƃ6@ XyA0m hgHʱN|2VIBݵ@;\̾\6 nG;iiE̙cs\e0d[IC!ǟyw%4PqBX aj%x}$7%1LX K,֖%٩%  BeǹxXZKҬsAhkK.{Ɇ-bËKdy:kp=XG{æGBS^>G_,[Is?,~d7SwEjܔW/0CJ1 'j:]_ %E;,:~̨=p{n*Ԛ?9+,~LjlBxc_8  j4+8S(a6(wQ-ђ' Kˊb*9b@t52_KyJ 뿯7o—//_0x=̳]BZ4W=V6ɠ-N45IĤK)?f^[y8%$u8|`עFT[1<^A0`L_/z<$|B SOG"JOXhXkxf1yN)5>"kv'/ld*0x$,[a)04$MΰsR %-+aCM Zk ,oLr518+4:EƓ3:6vo)l/|K7D9TGEhDSTLVkjCe^fxaqko1ndj#E=IEMh_ +UPYҤ`5RpDE^`VfG- F6y%kuC5Nr%"LDpVu G4k/lp}gv`6ϷTmi)Uubn{l^sn_S[iZi5#txp8 n9bX<:|K6^;q8cE1,y70AwO9e21EQ}={e!ݷͧs>HK2/8ANclpZ'P#Ja_BAڡ]Xnx:lS ixJNG Okٺl aa&2I uяDMw9mYdk~Wz0wB$>&gRU{jDl)ζxP$tsj9w3dY"49!Bg g?K|.N3ӓ!4yqzvBgF' r`h BA[$4GM!kjX 7Rqݤ03艢Ta]9$-ZKQ֤jiE>B-}c(Ꚙ1LiVt{p\Lrz71U3":ӝ~OL|ys",}_Gc  {DJ5=wQstQt4 `|Md OvZ],R ^{k˶^q#{͆a-apvlx@p8=4A!ᬢ / ԍ{hyqi2gaCeĿ߸ӭy2eL} #߆ =Z}, piu5%|˻4wԯW#.;dzU򤁡!O&G2q]FOg\FluA'7à: -{\ Raw science and sky exposures Standardizemeta-data? Dark subtraction Divide by flat Linearity correction Initialize variance ADU -> electrons Add BPM Reduced data Object - sky Sky subtraction Select sky exposures Associate sky exposures Sky sub. along slit Subtract sky Interpolate sky Register WCS shifts Attach slit traces Attach wavelength calibration Cut out slits Trace object spectra Extract 1D spectra DAR flux correction Correct telluric absorption Resample to linear co-ords Scale exposures tocommon level Stack exposures Apply flux calibration ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_MOS_trace.odg0000644000175100001770000003151314635037352020704 0ustar00runnerdockerPK{L.++mimetypeapplication/vnd.oasis.opendocument.graphicsPK{LaThumbnails/thumbnail.pngPNG  IHDRKPLTE"""***555@@@ppp~~~Tw$IDATx : =cVM'- =p γݒ*{l_PC 5PC 5PC 5PC 5PC 5PC 5PC R.{o#^=uR=8ǍL|zw.zwԾacZYF|=HOQ$.I<4>cE7[%ё'k݉:o\ͥOXڡmޅ {QŔ5MQ݌"6F(1@ij޸ڷAc )bb_Ve~Ԗ6=N>ז='ډu45. H}ՆGH  \މzjv^|[BGg|nl[S)3O+ukߪM2,%PWTo˥Z}Mj;ѦZm.Mb{T4*j1Zx}l_sKʵڭX87R^׭}P?׭kV8eu/-O4̺:Nb!zGv|ϝuA>xˬsZxJY_[Ҏ^ןe$X.P#BmvlZNФ!).]-Bs.9:bZk '/>NW浭Crh\N9ܭȗ|i|n;1uw-4 I}}NrMutS-n*6݌[Y_ !k#{ 65b`^ͪsKyeGl#׃k-79M9.~J-Stĺ3PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PC 5PCo1IENDB`PK{Lmeta.xmlMo0++# \i{jWڬ[Dl7u 6M5dU93gñwi28A  x`_ ǍU)Tjj*U#VYB4 M7ZxROUb<Q\zCqo55KK.D+?6K21lzM R8g54m/zZiܚf`?>X!kC W0tUd.מ`xyˆqBpHFht %)]I&$[pƊqR(V7~nq=UKk >H-XV=u,!Jw&eiv5{N"&"M xo> Ӿ$c/ePKRIPK{L settings.xmlZ[s6~aNŐ&s16 oR@,y%9 Y.Y*NiuYxYPgW)} =Gcqa}S.buSY:b|-m#zg/G1]'hkg퓋CB&Jw/VG_b1JpL!•L8m )cZzDc]z[(=Yr>Tc<9Dw0E{)>` GJE Oq ($H8$W`6R{_sha $3Ȧ.HG<,t4\y,j=:`"&>Uť-}uFJ_'lJP=Hy,`a&Ä Èc7Cqu u!?-2W2TE%jOzMFch2eOHt"jZ )oNvV\Y[-9Å3$Zl߱(tWI׽ 5~z532$9r4erDq/>qE&x5MjGFsƢ[Cbo+n $/+-/$< 1YE K5PO?}K uEPY1(,ҵO]L],4#m17愆$D*ڑ-'ʕ3SMtGKx.S !q|Ar#X-h= Tf1Bw{85ĩ#Ԛ$-L')%)-ǻITͧʙXa:;D5E.uCog &P̐UibJ"%q#FE@$thŊ̑%1 ؙ|JE8$:[3O$`9T2X*pG*$vb&Ңь$zGQk#>gŋsҟP"[u?r^괶3kr׶$Q`ubN{NZl&Hvj!.ĪGEHO[/sI䊰LbR!ɤ~w=kqVi8[Oe{1i)l&݄LU;e$[sd+־n9ʾ4 n»˜t{qO[3n)-օ\: z17pZXvo5 ;vg FZkA; ^ӾZAshF:a"1 A|2w+V~ PRR,PwD~RNi?PKA}#&PK{L content.xml][s~(m'Iz47ƛv%fy+IYvδ%=/DR"ɷ83kK9\輺#E&33$^|?^AzOULRҤh'YU{>[Yaq1)J,HhgYUIQEՙ0]r2tOf¼T@ՃtmA Ǚ[[VFa|,l>_ZS|1GYmke*˛kO-Ψf9)@K9!^Gb2n0{K73&,RESEy-kB%rë<,*+@a64ik*U&;3>s<,IΉ{;=7ZӸ4Cs |;(ŀWխp6啷$Dž0)J7 Sa4y@vnNLaqc,vA[e 0Zۈ.rs93p&MH֟̄贛1SaB|,ة9i PuE8Tی!r#v&V&x̵ DjLqD fgvZst~B+9iȇV?KuuT~7rzD_U-e+] x "(Lͻo,-~%W$i*//H@M,,=7n2ͧMlm\۾ U']&H݇YoVM-)%tr&tsK^;IrB{H&t9Z6hly]) Ǟi])P bCLWuwT-C)ܜRiV3$/CRHpD$M Hꊡ=W^ycJF mڞCMs"ykyI@FY&mH|4[5. ъ#A-3fB!O/rj鍪`1=z{ "xdkfGXӠE]YQGˁ('& 6e~=ATRB[,g|LK "|_4nτ6pw>8gacQS,HSAhO {a=2 ibf*ڞyx#RVv.X'\ x?e&uȆ(dp x$։c}'kʹ4?u'.o?nyNfWyRjvG0񡤒nw'vWVaX=C{1VY?B%BY)l+b-B7c݉9viƸQ[FuQyFuښC}G1N~xl=}#w={j)ʻN:xnPhNzG==(,j{,h DD5׫("TUrhV}dz|ݢ5dW.\.N\֑Kd&YC[+nu}Wg*Y]t^q&AFcE{ :Ie-BBCH?"BD8BXџ%BҞ%>y~>B3z~^18Dr\uN/-ש~o'~6jJw8kh5@(I.7͵]EtUvH!v=SH: Y7bȽ6¯tUVwꑲb\e#QԚBMk-)њzYMުvAI"7Τ rKȈWn=RT$K//H2cJj>4Ns`9+ъY&e `Ǥ@6C7%1hOk,.(]72evX]"+Ju#Z8j說DЭa`$0iG?ў?TlzD>^tπ/0dޱS? BQ%].B;w>o*t~j@U:7 Cȥ|V*}^ɧ|4 V?lw#xV\C6[YVΏ[O+lqEs[:-״z{@V:8 9:ܩ~T;38"3Xӷlu9'"q*/1PVmigA?k~ܬ3e 4;%a%]Qub؇-ju]WJ׮q +9$Ld(ɀ>*#-̶Ldb{f0nw4H+xIO"uD6O"[ =Jv}cm !琦`8CKčBRhx^!Ph`G,4mm~8B_{* 8k;6pճobxN$#v)?rgxG7*3CCG>ifW޽ RR*Z4"/ E^/8 H6ばX!Tq/;1o+jV_RQMaA][/LƆiEl]ILܤ@ ֑,4ƳR4p|L|vbFpv&tc$4烡G=S~gdd9<.Q2*KCR-J&I'+3!|k6ߍZ!v AOMLn=8! |iLc(IeKQ9 )H6oV*dZIFFe YIx"3r﷿H#!8hf1# Sa|F!/Go8~`R-+8菴_vk-dr_-B5\ۆ?\4Xr9H6d +7,?G_xJWח%{OYyo^xvv[*}q5WKvMs9ǹEV˽d}7Ƴ!%фC'z* GH-isx\Wp?fT6cpoܞ ~蟚)!,Ok {gR7+ݮ23Z5\T0TP]qzS/XD˷`DqVKaA#ђ)Kˊb*f@t52_K_y*aDѫWIt?^.n ]V++xdPz$vT4dT~`⹔bco3/ h^xCZ~XJB\GfRI#{ Y\EW`W) {N ܏$e pvNǰ5dmY6gùkMKؒViݞ1d65GL >18+)X_LivK9fR7Zh^( JbMm,\[1,Np:0~,'$j J ɣt<8}q24NNap2ξ@:+6/`oV)*EB{"u b|*QM ڋ>(*6C҂jMꖖ[3vdgDl؎uČYdF-ֶӸCObb'g׫) ѹ,u{ejkλ=رJXƐ%jWk@.8j;B臣aiHAâ-eŚ-RvZ]hq{ WMÿe[T6/fQͰ8<;<8:?2xu4MиO8tKhht!`?U7MZ>l7¿vc,^.QdhWAhN>8p8F9ABÁj6BSXjv4'?ьѲ__$ylP wkQ+!N_B$UU]i=_~u$&`\1m09`_=`gd3Q_ \43 ;l{Ɩk$P/7^$.>6)"a5< 4{VotGe^PU2Z*mۗA)†Ѻyswc1ب1zj.WJ,b~7m^R~VPK7# :PK{LConfigurations2/toolpanel/PK{LConfigurations2/menubar/PK{LConfigurations2/floater/PK{LConfigurations2/statusbar/PK{LConfigurations2/popupmenu/PK{LConfigurations2/images/Bitmaps/PK{LConfigurations2/progressbar/PK{LConfigurations2/toolbar/PK{L'Configurations2/accelerator/current.xmlPKPK{LMETA-INF/manifest.xmlTn0 UM;*Zlw`n8U H@ih%vld'YN$GA;,،OY\)~.ت,D]Cj$][1w2萣rRk+{~~ay+'ɝҮޟu4&m% &܏-TZtn`mV4qĊ_Nx L Raw lamp flat spectra Standardizemeta-data Group lamp on/off exposures Subtract background Linearity correction Initialize variance Add mask Trace slits Part-processed flatswith slit traces ADU → electrons Stack Lamp on – lamp off ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_arcs.rst0000644000175100001770000000052514635037352020056 0ustar00runnerdocker************************ Near-IR, multi-slit arcs ************************ .. figure:: NIR_MOS_arc.svg :alt: DR flowchart for MOS wavelength calibration. :height: 1200 :width: 600 :scale: 50 % Reduction of arc exposures using previously-determined flat traces. Steps in grey are optional or alternative processing steps. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_flats.rst0000644000175100001770000000106314635037352020235 0ustar00runnerdocker************************* Near-IR, multi-slit flats ************************* .. figure:: NIR_MOS_trace.svg :alt: DR flowchart for MOS slit traces. :height: 1200 :width: 600 :scale: 50 % Tracing of lamp flat spectra. Steps in grey are optional or alternative processing steps. .. figure:: NIR_MOS_flat.svg :alt: DR flowchart for multi-slit lamp flat processing. :height: 1200 :width: 600 :scale: 50 % Reduction of lamp flat spectra to produce a normalized flat. Steps in grey are optional or alternative processing steps. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/NIR_science_data.rst0000644000175100001770000000072314635037352021530 0ustar00runnerdocker******************************** Near-IR, multi-slit science data ******************************** This example is based on plans for reduction of near-infrared, multi-slit spectra with a single detector array. .. figure:: NIR_MOS_science.svg :alt: DR flowchart for MOS science data. :height: 1200 :width: 600 :scale: 50 % Reduction of science exposures using previously-processed calibrations. Steps in grey are alternative processing options. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/process/index.rst0000644000175100001770000000147014635037352017525 0ustar00runnerdocker.. _specreduce-process: ************************************ Spectroscopic data reduction outline ************************************ Here are some examples of complete DR processes, to help guide development (including basic image reduction steps, provided by other packages). These are not a summary of functionality actually implemented in `specreduce `_ today. .. _specreduce-nir-mos: Near-IR, multi-slit spectroscopy ================================ This example, from Gemini, is based on plans for the reduction of near-infrared, multi-slit spectra (considering future use with optical data to a lesser extent). Some adjustments might be needed as the functionality takes form. .. toctree:: :maxdepth: 1 NIR_science_data NIR_flats NIR_arcs ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/specphot_standards.rst0000644000175100001770000002431714635037352020635 0ustar00runnerdocker.. _specphot_standards: Spectrophotometric Standards ============================ Introduction ------------ Instrument sensitivity as a function of wavelength is calibrated using observations of spectrophotometric standard stars. `specreduce `_ offers some convenience functions for accessing some databases of commonly used standard stars and loading the data into `~specutils.Spectrum1D` instances. Supported Databases ------------------- Probably the most well-curated database of spectrophotometric calibration data is the `CALSPEC `_ database at `MAST `_ (Ref.: `Bohlin, Gordon, & Tremblay 2014 `_). It also has the advantage of including data that extends well into both the UV and the IR. The `~specreduce.calibration_data.load_MAST_calspec` function provides a way to easily load CALSPEC data either directly from `MAST `_ (specifically, https://archive.stsci.edu/hlsps/reference-atlases/cdbs/calspec/) or from a previously downloaded local file. Here is an example of how to use it and of a CALSPEC standard that has both UV and IR coverage: .. plot:: :include-source: import matplotlib.pyplot as plt from specreduce.calibration_data import load_MAST_calspec spec = load_MAST_calspec("agk_81d266_stisnic_007.fits") fig, ax = plt.subplots() ax.step(spec.spectral_axis, spec.flux, where="mid") ax.set_yscale('log') ax.set_xlabel(f"Wavelength ({spec.spectral_axis.unit})") ax.set_ylabel(f"Flux ({spec.flux.unit})") ax.set_title("AGK+81 266") fig.show() The `specreduce_data `_ package provides several datasets of spectrophotometric standard spectra. The bulk of them are inherited from IRAF's `onedstds `_ datasets, but some more recently curated datasets from `ESO `_, the `Nearby Supernova Factory `_, and `Gemini `_ are included as well. The `~specreduce.calibration_data.load_onedstds` function is provided to load these data into `~specutils.Spectrum1D` instances. If `specreduce_data `_ is not installed, the data will be downloaded from the GitHub `repository `_. The available database names and their descriptions are listed here. Please refer to the `specreduce-data repository `_ for details on the specific data files that are available: - `bstdscal `_: Directory of the brighter KPNO IRS standards (i.e., those with HR numbers) at 29 bandpasses, data from various sources transformed to the Hayes and Latham system, unpublished. - `ctiocal `_: Directory containing fluxes for the southern tertiary standards as published by `Baldwin & Stone, 1984, MNRAS, 206, 241 `_ and `Stone and Baldwin, 1983, MNRAS, 204, 347 `_. - `ctionewcal `_: Directory containing fluxes at 50 Å steps in the blue range 3300-7550 Å for the tertiary standards of Baldwin and Stone derived from the revised calibration of `Hamuy et al., 1992, PASP, 104, 533 `_. This directory also contains the fluxes of the tertiaries in the red (6050-10000 Å) at 50 Å steps as will be published in PASP (Hamuy et al 1994). The combined fluxes are obtained by gray shifting the blue fluxes to match the red fluxes in the overlap region of 6500-7500 Å and averaging the red and blue fluxes in the overlap. The separate red and blue fluxes may be selected by following the star name with "red" or "blue"; i.e. CD 32 blue. - `iidscal `_: Directory of the KPNO IIDS standards at 29 bandpasses, data from various sources transformed to the Hayes and Latham system, unpublished. - `irscal `_: Directory of the KPNO IRS standards at 78 bandpasses, data from various sources transformed to the Hayes and Latham system, unpublished (note that in this directory the brighter standards have no values - the `bstdscal `_ directory must be used for these standards). - `oke1990 `_: Directory of spectrophotometric standards observed for use with the HST, Table VII, `Oke 1990, AJ, 99, 1621 `_ (no correction was applied). An arbitrary 1 Å bandpass is specified for these smoothed and interpolated flux "points". - `redcal `_: Directory of standard stars with flux data beyond 8370 Å. These stars are from the IRS or the IIDS directory but have data extending as far out into the red as the literature permits. Data from various sources. - `spechayescal `_: The KPNO spectrophotometric standards at the Hayes flux points, Table IV, Spectrophotometric Standards, `Massey et al., 1988, ApJ 328, p. 315 `_. - `spec16cal `_: Directory containing fluxes at 16 Å steps in the blue range 3300-7550 Å for the secondary standards, published in `Hamuy et al., 1992, PASP, 104, 533 `_. This directory also contains the fluxes of the secondaries in the red (6020-10300 Å) at 16 Å steps as will be published in PASP (`Hamuy et al 1994 `_). The combined fluxes are obtained by gray shifting the blue fluxes to match the red fluxes in the overlap region of 6500-7500 Å and averaging the blue and red fluxes in the overlap. The separate red and blue fluxes may be selected by following the star name with "red" or "blue"; i.e. HR 1544 blue. - `spec50cal `_: The KPNO spectrophotometric standards at 50 Å intervals. The data are from (1) Table V, Spectrophotometric Standards, `Massey et al., 1988, ApJ 328, p. 315 `_ and (2) Table 3, The Kitt Peak Spectrophotometric Standards: Extension to 1 micron, `Massey and Gronwall, 1990, ApJ 358, p. 344 `_. - `snfactory `_: Preferred standard stars from the LBL Nearby Supernova Factory project: https://ui.adsabs.harvard.edu/abs/2002SPIE.4836...61A/abstract Data compiled from https://snfactory.lbl.gov/snf/snf-specstars.html. See notes there for details and references. - `eso`_: Directories of spectrophotometric standards copied from ftp://ftp.eso.org/pub/stecf/standards/. See https://www.eso.org/sci/observing/tools/standards/spectra/stanlis.html for links, notes, and details. - `gemini `_: Directory of spectrophotometric standards used by Gemini. Originally copied from https://github.com/GeminiDRSoftware/DRAGONS/tree/master/geminidr/gemini/lookups/spectrophotometric_standards. Selecting Spectrophotometric Standard Stars ------------------------------------------- Many commonly used standard stars have spectra in multiple datasets, but the quality and systematics can differ. The `~specreduce.calibration_data.load_MAST_calspec` and `~specreduce.calibration_data.load_onedstds` functions can be useful tools for exploring and comparing spectra from the various databases. An example is shown here for `LTT 9491 `_ which has spectra available from MAST, ESO, and the Nearby Supernova factory: .. plot:: :include-source: import matplotlib.pyplot as plt from specreduce.calibration_data import load_MAST_calspec, load_onedstds s1 = load_MAST_calspec("ltt9491_002.fits") s2 = load_onedstds("snfactory", "LTT9491.dat") s3 = load_onedstds("eso", "ctiostan/ltt9491.dat") fig, ax = plt.subplots() ax.step(s1.spectral_axis, s1.flux, label="MAST", where="mid") ax.step(s2.spectral_axis, s2.flux, label="SNFactory", where="mid") ax.step(s3.spectral_axis, s3.flux, label="ESO", where="mid") ax.set_yscale('log') ax.set_xlabel(f"Wavelength ({s1.spectral_axis.unit})") ax.set_ylabel(f"Flux ({s1.flux.unit})") ax.set_title("LTT 9491") ax.legend() fig.show() The `MAST`_ data have the best UV coverage, but that's not useful from the ground and they only extend to 0.9 microns in the red in this case. The other data extend to 1.0 microns, but both spectra show systematics due to telluric absorption. The `SNFactory`_ data extend well past the atmospheric cutoff with no correction applied for atmospheric transmission. The `ESO`_ data, on the other hand, are not corrected for the telluric features in the near-IR while the `SNFactory`_ data are. Regions affected by such telluric systematics should be masked out before these spectra are used for calibration purposes. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/terms.rst0000644000175100001770000003705114635037352016076 0ustar00runnerdocker Terminology ----------- As part of a workshop at NOIRLab, 13-16 Nov 2024, the attendees extensively discussed terminology in an effort to generate a common understanding of, and the nuances in, many of the terms bandied about when discussing spectroscopy data and its reduction and analysis. The following is a living document that stemmed from that original discussion. .. note:: Below, relative terms that can have multiple meanings are highlighted in italics. 2D Spectrum/Image ================= - Image = 2D Image - Optical/IR, different for other wavelengths - Something that is not necessarily pure “raw” data, but data that exists prior to extraction - Refers to e.g. the 2D CCD images (optionally pre-processed) from which 1D spectra (flux vs. wavelength) are extracted .. KBW: I missed this discussion, so I don't know how we want to capture "Alt" definitions here... Seems a bit awkward. Alt Spectrum 2D =============== - Spectrum as a function of slit position? - Fiber dispersed - Lots of alt Spectra 2D - Multiple spectral orders? - Can get up to something like 5D for solar data: wavelength x space x space x time x polarization - Is there an IVOA definition that differs from both of the above? 1D Spectrum =========== - Flux versus spectral axis (wavelength/frequency). Could be calibrated but not necessarily. *Preprocessing* =============== - (As related to spectral reduction): Things like flat-fielding and bias subtraction that are done on a full CCD image before extractions are performed. - Alt term: instrument signature removal - Meaning of this depends on context (“What do others do before I start?”) - Typically done on raw/2d image - Work done before mine. *Post-processing* ================= - Typically done on the extracted spectra? Extraction ========== - The process of converting raw spectrum data on 2D image into flux versus spectral axis or pixel (i.e. Spectrum1D), not necessarily flux or spectral calibration. Rectified ND spectrum ===================== - Non-dispersion axes means something like ra/dec, or polarization? - Nearly always (maybe always?) Implies some amount of resampling - There is one dimension that is ENTIRELY a spectral axis, all others are not specified by calling it a “Rectified ND Spectrum”, although they often do have some kind of meaning Calibrated 2D image =================== - Not-resampled. - Calibrated from raw pixel to wavelength. .. KBW: Not really sure this is terminology, but I've left it as written in the workshop notes. Facilitating Data sharing, cross-matching, etc., standards via IVOA standards ============================================================================= - Data models (but see below) - COM - ObsCore - SSA - Not widely adopted, but could be! *Workflow* ========== - More holistic than a pipeline. Often a superset of pipeline with additional steps to facilitate data ingest, job orchestration, data collection/coordination, data archiving, etc. - Also analysis. *Pipeline* ========== - Organized code for **automatically** processing raw data into calibrated spectra and - Optionally derived quantities like redshifts, line fits, ... - More generically, the linking of several steps/jobs/codes/methods where outputs of one feed as inputs to another. - “Spectral reduction pipeline”? vs. “analysis pipeline” vs. “XYZ pipeline” - SDSS and JWST pipelines are different, Dragons has three pipelines. DESI has different pipelines depending on who you talk to. Classification ============== - Identifying the type of object a spectrum represents: star, galaxy, QSO, ... - Result of Model fitting (auto or by-eye). *Redshifting* ============= - Determining the redshift of a spectrum, which may or may not be independent of classification. - Sometimes also means “changing the redshift of the object to its redshift”, e.g. converting the “wavelength/frequency” axis to rest-frame - Related issues on GitHub: - `#258 `__ - `#455 `__ - `#820 `__ Heliocentric / barycentric correct ================================== - Converting a spectrum to some rest frame in order to measure a radial velocity for a nearby stellar source. - Heliocentric is “the frame where the sun is at rest” - Barycentric is “the frame where the barycenter of the solar system is at rest” - (Some of this is very very precisely defined at the GR level) *Archive* ========= - A physical or virtual location from which processed data can be accessed. This could include both PI/collaboration access and public access - Or unprocessed. - And metadata needed to reduce raw data. - Raw data bundle (science+all cals needed to reduce it) - Ideally would Supporting FAIR principles (Findable, Accessible, Interoperable, Reusable) - Noun or verb. Data Assembly ============= - A bundle of data prepared for collaboration access (to write papers, etc.) that will eventually become a data release. - Used internally by DESI, but deprecated. - It becomes the data release at the DR date - Sloan synonym: “Internal Product Launch” Data release ============ - A bundle of data specifically intended to be public - Can be raw or not raw - Somehow “pinned” data raw/reduced/analyzed with a particular version of pipelines. - Aspires to be frozen. - Can be either a noun or a verb Open Development ================ - Developing software in a way that the community can see both how it has been developed and why it was developed that way. - Usually, but not absolutely necessarily, implies the community is also free to contribute. - Not necessarily open source. - Repos are publicly visible, including issue tracker. Flux calibration ================ - Converting a 1D/2D spectrum from “counts” to astrophysical units of flux density *Telluric Correction* ===================== - Removing the telluric (atmospheric) absorption bands from spectra - Removing the *multiplicative* component of the sky - absorption - But there was some disagreement over whether this includes sky *Sky subtraction* ================= - Removing the *additive* component of the sky/emission so all “photons” come from the source - But there was some disagreement over whether this is overlapping with a Telluric correction IFU (Integral-Field Unit) ========================= - Covers a “contiguous” 2d field on the sky with spatial information along both axes - Fibers or similar are tightly bundled and contiguously cover a region on the sky. Or an image slicer. Or a microlens array. - May or may not be multi-object. - IFS (Integral field Spectrograph) and IFU are sometimes distinguished where IFS is the whole instrument but IFU is the head-unit that does the IF part MOS (Multi-Object Spectroscopy) =============================== - Could be a fiber or a slit - Multiple objects observed in the same exposure *Flux* ====== - Energy per time per area - Also used as a shorthand for “the not spectral unit part of a 1D spectrum” (would that be the “dependent variable”?) - Oftentimes used to mean “flux density” - `Spectrum1D `__ uses the attribute 'flux'. Should this be renamed to 'flux_density'? - The intent in specutils was to not agonize over this but just accept that it's a shorthand astronomers use, and there wasn't a better name (“y”, “data”, etc) Flux Density ============ - Flux per unit wavelength/energy/wavenumber, usually(?) in astrophysical units, e.g., W/m^2/nm *Row-stacked spectra* ===================== - Collection of 1D spectra in a 2D array (image?), one spectrum per row. - Shared spectral axis. - This is the format of specutils.Spectrum1D when it's a “vector” spectrum1D *Data cube* =========== - Spectral 3D matrix with 2 spatial dimensions and one spectral one. Product of IFU data with contiguous sky coverage - Doesn't even have to be spectral, although in the spectral context it usually is - Not always 3D (data hypercuboid??). - “Multi dimensional data blob” *Spectral data cube* ==================== - At least one axis is a spectral axis but who knows about the rest! - Hypercube. *[Spectral] Data format* ======================== - “Format” can mean data structure (i.e., in-memory, possibly bound to a particular language, though it doesn't have to be - see Apache Arrow) - “Format” can also mean a file format - “Format” can also be something even more technical like “how the bytes in a struct are packed“ Data Structures =============== - Python Data structures, which are Python classes. - NDData/NDCube/SpectrumCollection, Spectrum1D etc. - CCDData. Subclass of NDData - AstroData - from DRAGONS (collection of NDData-like objects, mapped to a file, plus metadata abstraction etc.) - Lots of classes to represent spectra - Link to issue about renaming Spectrum1D class in specutils. - arrays *Data Model* ============ - In the SDSS/DESI sphere, this has a meaning that is known to differ from other uses of the term. In SDSS/DESI this means a documentation product that describes all of the files in a data release, both file formats and how they are organized into a hierarchy of directories on disk. For example, see the `desidatamodel `__. - IVOA data model is a formalized thing that follows a specific XML schema - Data model is abstract, implementation could potentially be different. - In the IVOA it is not yet allowed to be anything other than XML although there's a lot of interest in changing that - Which is different from SQL data models - The word 'schema' is sometimes used here, but that is also ambiguous even within SQL flavors itself. *Spectroscopic search - Data discovery* ======================================= - Search for spectra from any/particular instrument based on position or other known properties of the sources. If available, all the spectra will be listed. - Example tool to do this: SPARCL (How-To Jupyter notebook available here) SSA = Simple Spectral Access [VO protocol] ========================================== - "Uniform interface to remotely discover and access one-dimensional spectra." See `here `__. - Not commonly (used in the US?). (Example of use Data Central) Reduction (of spectroscopic data) ================================= - Getting data from raw-off-the-instrument (or nearly so) to the point where analysis can be done. - The process of turning 2D spectral images to 1D spectra. Can be wavelength calibrated, sky subtracted, flux calibrated, but intermediate products are "reduced" compared to earlier steps of the process. - MAYBE: Can potentially be done automatically without a human-in-the-loop? - Required products vs optional products - Removing instrument signature. - "Reduction" is in the sense of reducing complexity, but it is often an inflation of bytes (in radio it is a literal reduction, in optical usually not) - Astronomy specific word. - Spectroscopic reduction: the process of going from raw data to science-ready spectra Analysis (of spectroscopic data) ================================ - Taking scientific measurements or achieving scientific results from already-reduced spectroscopic data - Analysis does not depend on the instrument.Rem - MAYBE: cannot be done automatically, requires a human to make some sort of judgment - Optional. - Spectroscopic analysis: the process of going from science-ready spectra to science Sky === - Model or observed sky background (really a foreground!) which was usually subtracted from the observed spectrum *Stacking* ========== - Combination of multiple spectra in a prescribed way to increase quality (e.g., S/N) - in some contexts like numpy arrays and astropy.table.vstack, it can refer to combining multiple objects / tables into a single object without coadding data. *Coadding* ========== - combining multiple spectra of the same object into a single spectrum, e.g. to improve signal-to-noise or combine spectra across multiple wavelength ranges. - Alternative term for “stacking” to disambiguate meanings Spectral fitting ================ - Modeling an observed spectrum with templates (possibly physically motivated) and/or mathematical functions Digital Twins ============= - Realistic fake data that potentially adapts to new states of the system over time. Trace fitting ============= - on a 2D CCD image from a multi-object spectrometer, typically wavelengths span in 1 direction and fibers/objects in the other direction. “trace fitting” is mapping the y vs. x of where the spectra actually go on the CCD image. - Different for slit-based and fiber-based spectrographs - slit-based: trace the *edges* of the slit spectrum along the spectral direction - fiber-based: trace the *center* of the fiber spectrum spatial point-spread function - Spectral tracing Wavelength calibration ====================== - calibrating what true wavelength is represented by the observed photons on a detector, e.g. what wavelength is row y of a detector? - Possibly a 2d process - The process of adding (the spectral part of) a WCS Visual Inspection (of spectra) ============================== - Humans looking at spectra and making decisions about what the “truth” is. - Can include identifying the presence/absence of features (qualitative) or assessing a quantitative fit (e.g., best-fit redshift value) *Spectral resolution* ===================== - Changes in spectral dispersion power as a function of wavelength due to instrument - Resolving power vs Resolution/Dispersion - Resolving power is the ability to distinguish close features - Dispersion is the change in wavelength/energy per pixel API === - Application Programming Interface - What makes a good API for spectroscopic software? - What is needed for different aspects of spectroscopic software (e.g., reduction vs. archive access)? *Spectral class* ================ - E.g., Spectrum1D - In SDSS, 'class' is short for 'classification'. - DESI uses SPECTYPE for spectral type (QSO, GALAXY, STAR) Package ======= - A software tool or collection of tools developed in the same “space” - Has a specific meaning in a Python context that’s more specific, but can be used more generally for multiple languages Spectral data visualization =========================== - Tools and procedures to display reduced spectral data Spectral decomposition ====================== - a form of spectral fitting that identifies separate components that appear in a spectrum; e.g, quasar + galaxy. - Goes with spectral fitting. Processing Steps ================ - For DESI (largely inherited from SDSS usage): - pre-processing (of CCD images, bias, dark, pixel-flat fielding) - extraction (getting counts vs. wavelength from 2D images) - sky subtraction (subtracting the additive non-signal sky component) - flux calibration (includes both instrument throughput and telluric absorption multiplicative corrections) - classification and redshift fitting (is it a galaxy, star, or quasar; at what redshift?) ---- Mentioned but not defined ------------------------- - WCS & Database archive - Cloud archiving - Modular functions which can be used by other pipelines. - Interactive Dashboard ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/docs/wavelength_calibration.rst0000644000175100001770000000474714635037352021465 0ustar00runnerdocker.. _wavelength_calibration: Wavelength Calibration ====================== Wavelength calibration is currently supported for 1D spectra. Given a list of spectral lines with known wavelengths and estimated pixel positions on an input calibration spectrum, you can currently use ``specreduce`` to: #. Fit an ``astropy`` model to the wavelength/pixel pairs to generate a spectral WCS solution for the dispersion. #. Apply the generated spectral WCS to other `~specutils.Spectrum1D` objects. 1D Wavelength Calibration ------------------------- The `~specreduce.wavelength_calibration.WavelengthCalibration1D` class can be used to fit a dispersion model to a list of line positions and wavelengths. Future development will implement catalogs of known lamp spectra for use in matching observed lines. In the example below, the line positions (``pixel_centers``) have already been extracted from ``lamp_spectrum``:: import astropy.units as u from specreduce import WavelengthCalibration1D pixel_centers = [10, 22, 31, 43] wavelengths = [5340, 5410, 5476, 5543]*u.AA test_cal = WavelengthCalibration1D(lamp_spectrum, line_pixels=pixel_centers, line_wavelengths=wavelengths) calibrated_spectrum = test_cal.apply_to_spectrum(science_spectrum) The example above uses the default model (`~astropy.modeling.functional_models.Linear1D`) to fit the input spectral lines, and then applies the calculated WCS solution to a second spectrum (``science_spectrum``). Any other 1D ``astropy`` model can be provided as the input ``model`` parameter to the `~specreduce.wavelength_calibration.WavelengthCalibration1D`. In the above example, the model fit and WCS construction is all done as part of the ``apply_to_spectrum()`` call, but you could also access the `~gwcs.wcs.WCS` object itself by calling:: test_cal.wcs The calculated WCS is a cached property that will be cleared if the ``line_list``, ``model``, or ``input_spectrum`` properties are updated, since these will alter the calculated dispersion fit. You can also provide the input pixel locations and wavelengths of the lines as an `~astropy.table.QTable` with (at minimum) columns ``pixel_center`` and ``wavelength``, using the ``matched_line_list`` input argument:: from astropy.table import QTable pixels = [10, 20, 30, 40]*u.pix wavelength = [5340, 5410, 5476, 5543]*u.AA line_list = QTable([pixels, wavelength], names=["pixel_center", "wavelength"]) test_cal = WavelengthCalibration1D(lamp_spectrum, matched_line_list=line_list)././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1108735 specreduce-1.4.1/licenses/0000755000175100001770000000000014635037364015064 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/licenses/KOSMOS_LICENSE0000644000175100001770000000217714635037352017170 0ustar00runnerdocker# NOTE: This license applies only to code used in part of the FitTrace class. MIT License Copyright (c) 2019 James Davenport Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/licenses/LICENSE.rst0000644000175100001770000000273514635037352016704 0ustar00runnerdockerCopyright (c) 2017, Astropy-specreduce Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Astropy Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/pyproject.toml0000644000175100001770000000540714635037352016176 0ustar00runnerdocker[project] name = "specreduce" dynamic = ["version"] authors = [ { name = "Astropy Specreduce contributors", email = "astropy-dev@googlegroups.com" } ] license = {file = "licenses/LICENSE.rst"} description = "Astropy coordinated package for Spectroscopic Reductions" readme = "README.rst" requires-python = ">=3.10" dependencies = [ "numpy", "astropy", "scipy", "specutils>=1.9.1", "gwcs", ] [project.optional-dependencies] test = [ "pytest-astropy", "photutils", "tox", ] docs = [ "sphinx-astropy", "matplotlib", "photutils", "synphot", ] all = [ "matplotlib", "photutils", "synphot", ] [project.urls] Homepage = "http://astropy.org/" Repository = "https://github.com/astropy/specreduce.git" Documentation = "https://specreduce.readthedocs.io/" [tool.setuptools] include-package-data = true [tool.setuptools.packages] find = {} # Scanning implicit namespaces is active by default [tool.setuptools.package-data] "specreduce.tests" = ["data/*.fits"] [tool.setuptools_scm] version_file = "specreduce/version.py" [build-system] requires = ["setuptools", "setuptools_scm", ] build-backend = 'setuptools.build_meta' [tool.pytest.ini_options] minversion = 7.0 testpaths = [ "specreduce", "docs", ] astropy_header = true doctest_plus = "enabled" text_file_format = "rst" addopts = [ "--color=yes", "--doctest-rst", ] xfail_strict = true filterwarnings = [ "error", "ignore:numpy\\.ufunc size changed:RuntimeWarning", "ignore:numpy\\.ndarray size changed:RuntimeWarning", "ignore:Can\\'t import specreduce_data package", # Python 3.12 warning from dateutil imported by matplotlib "ignore:.*utcfromtimestamp:DeprecationWarning", ] [tool.coverage] [tool.coverage.run] omit = [ "specreduce/_astropy_init*", "specreduce/conftest.py", "specreduce/tests/*", "specreduce/version*", "*/specreduce/_astropy_init*", "*/specreduce/conftest.py", "*/specreduce/tests/*", "*/specreduce/version*", ] [tool.coverage.report] exclude_lines = [ # Have to re-enable the standard pragma "pragma: no cover", # Don't complain about packages we have installed "except ImportError", # Don't complain if tests don't hit defensive assertion code: "raise AssertionError", "raise NotImplementedError", # Don't complain about script hooks "'def main(.*):'", # Ignore branches that don't pertain to this version of Python "pragma: py{ignore_python_version}", # Don't complain about IPython completion helper "def _ipython_key_completions_", ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1188734 specreduce-1.4.1/setup.cfg0000644000175100001770000000004614635037364015100 0ustar00runnerdocker[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1148734 specreduce-1.4.1/specreduce/0000755000175100001770000000000014635037364015401 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/__init__.py0000644000175100001770000000037614635037352017515 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst from specreduce.core import * # noqa from specreduce.wavelength_calibration import * # noqa try: from .version import version as __version__ except ImportError: __version__ = '' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/background.py0000644000175100001770000003377714635037352020110 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst import warnings from dataclasses import dataclass, field import numpy as np from astropy import units as u from astropy.nddata import NDData from astropy.utils.decorators import deprecated_attribute from specutils import Spectrum1D from specreduce.core import _ImageParser from specreduce.extract import _ap_weight_image from specreduce.tracing import Trace, FlatTrace __all__ = ['Background'] @dataclass class Background(_ImageParser): """ Determine the background from an image for subtraction. Example: :: trace = FlatTrace(image, trace_pos) bg = Background.two_sided(image, trace, bkg_sep, width=bkg_width) subtracted_image = image - bg Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like image with 2-D spectral image data traces : trace, int, float (single or list) Individual or list of trace object(s) (or integers/floats to define FlatTraces) to extract the background. If None, a FlatTrace at the center of the image (according to `disp_axis`) will be used. width : float width of extraction aperture in pixels statistic: string statistic to use when computing the background. 'average' will account for partial pixel weights, 'median' will include all partial pixels. disp_axis : int dispersion axis crossdisp_axis : int cross-dispersion axis """ # required so numpy won't call __rsub__ on individual elements # https://stackoverflow.com/a/58409215 __array_ufunc__ = None image: NDData traces: list = field(default_factory=list) width: float = 5 statistic: str = 'average' disp_axis: int = 1 crossdisp_axis: int = 0 # TO-DO: update bkg_array with Spectrum1D alternative (is bkg_image enough?) bkg_array = deprecated_attribute('bkg_array', '1.3') def __post_init__(self): """ Determine the background from an image for subtraction. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like image with 2-D spectral image data traces : List list of trace objects (or integers to define FlatTraces) to extract the background width : float width of each background aperture in pixels statistic: string statistic to use when computing the background. 'average' will account for partial pixel weights, 'median' will include all partial pixels. disp_axis : int dispersion axis crossdisp_axis : int cross-dispersion axis """ self.image = self._parse_image(self.image) if self.width < 0: raise ValueError("width must be positive") if self.width == 0: self._bkg_array = np.zeros(self.image.shape[self.disp_axis]) return self._set_traces() bkg_wimage = np.zeros_like(self.image.data, dtype=np.float64) for trace in self.traces: windows_max = trace.trace.data.max() + self.width/2 windows_min = trace.trace.data.min() - self.width/2 if windows_max >= self.image.shape[self.crossdisp_axis]: warnings.warn("background window extends beyond image boundaries " + f"({windows_max} >= {self.image.shape[self.crossdisp_axis]})") if windows_min < 0: warnings.warn("background window extends beyond image boundaries " + f"({windows_min} < 0)") # pass trace.trace.data to ignore any mask on the trace bkg_wimage += _ap_weight_image(trace, self.width, self.disp_axis, self.crossdisp_axis, self.image.shape) if np.any(bkg_wimage > 1): raise ValueError("background regions overlapped") if np.any(np.sum(bkg_wimage, axis=self.crossdisp_axis) == 0): raise ValueError("background window does not remain in bounds across entire dispersion axis") # noqa if self.statistic == 'median': # make it clear in the expose image that partial pixels are fully-weighted bkg_wimage[bkg_wimage > 0] = 1 self.bkg_wimage = bkg_wimage # mask user-highlighted and invalid values (if any) before taking stats or_mask = (np.logical_or(~np.isfinite(self.image.data), self.image.mask) if self.image.mask is not None else ~np.isfinite(self.image.data)) if self.statistic == 'average': image_ma = np.ma.masked_array(self.image.data, mask=or_mask) self._bkg_array = np.ma.average(image_ma, weights=self.bkg_wimage, axis=self.crossdisp_axis).data elif self.statistic == 'median': med_mask = np.logical_or(self.bkg_wimage == 0, or_mask) image_ma = np.ma.masked_array(self.image.data, mask=med_mask) self._bkg_array = np.ma.median(image_ma, axis=self.crossdisp_axis).data else: raise ValueError("statistic must be 'average' or 'median'") def _set_traces(self): """Determine `traces` from input. If an integer/float or list if int/float is passed in, use these to construct FlatTrace objects. These values must be positive. If None (which is initialized to an empty list), construct a FlatTrace using the center of image (according to disp. axis). Otherwise, any Trace object or list of Trace objects can be passed in.""" if self.traces == []: # assume a flat trace at the image center if nothing is passed in. trace_pos = self.image.shape[self.disp_axis] / 2. self.traces = [FlatTrace(self.image, trace_pos)] if isinstance(self.traces, Trace): # if just one trace, turn it into iterable. self.traces = [self.traces] return # finally, if float/int is passed in convert to FlatTrace(s) if isinstance(self.traces, (float, int)): # for a single number self.traces = [self.traces] if np.all([isinstance(x, (float, int)) for x in self.traces]): self.traces = [FlatTrace(self.image, trace_pos) for trace_pos in self.traces] return else: if not np.all([isinstance(x, Trace) for x in self.traces]): raise ValueError('`traces` must be a `Trace` object or list of ' '`Trace` objects, a number or list of numbers to ' 'define FlatTraces, or None to use a FlatTrace in ' 'the middle of the image.') @classmethod def two_sided(cls, image, trace_object, separation, **kwargs): """ Determine the background from an image for subtraction centered around an input trace. Example: :: trace = FitTrace(image, guess=trace_pos) bg = Background.two_sided(image, trace, bkg_sep, width=bkg_width) Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like Image with 2-D spectral image data. Assumes cross-dispersion (spatial) direction is axis 0 and dispersion (wavelength) direction is axis 1. trace_object: `~specreduce.tracing.Trace` estimated trace of the spectrum to center the background traces separation: float separation from ``trace_object`` for the background regions width : float width of each background aperture in pixels statistic: string statistic to use when computing the background. 'average' will account for partial pixel weights, 'median' will include all partial pixels. disp_axis : int dispersion axis crossdisp_axis : int cross-dispersion axis """ image = _ImageParser._get_data_from_image(image) if image is not None else cls.image kwargs['traces'] = [trace_object-separation, trace_object+separation] return cls(image=image, **kwargs) @classmethod def one_sided(cls, image, trace_object, separation, **kwargs): """ Determine the background from an image for subtraction above or below an input trace. Example: :: trace = FitTrace(image, guess=trace_pos) bg = Background.one_sided(image, trace, bkg_sep, width=bkg_width) Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like Image with 2-D spectral image data. Assumes cross-dispersion (spatial) direction is axis 0 and dispersion (wavelength) direction is axis 1. trace_object: `~specreduce.tracing.Trace` estimated trace of the spectrum to center the background traces separation: float separation from ``trace_object`` for the background, positive will be above the trace, negative below. width : float width of each background aperture in pixels statistic: string statistic to use when computing the background. 'average' will account for partial pixel weights, 'median' will include all partial pixels. disp_axis : int dispersion axis crossdisp_axis : int cross-dispersion axis """ image = _ImageParser._get_data_from_image(image) if image is not None else cls.image kwargs['traces'] = [trace_object+separation] return cls(image=image, **kwargs) def bkg_image(self, image=None): """ Expose the background tiled to the dimension of ``image``. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, optional Image with 2-D spectral image data. Assumes cross-dispersion (spatial) direction is axis 0 and dispersion (wavelength) direction is axis 1. If None, will extract the background from ``image`` used to initialize the class. [default: None] Returns ------- `~specutils.Spectrum1D` object with same shape as ``image``. """ image = self._parse_image(image) return Spectrum1D(np.tile(self._bkg_array, (image.shape[0], 1)) * image.unit, spectral_axis=image.spectral_axis) def bkg_spectrum(self, image=None): """ Expose the 1D spectrum of the background. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, optional Image with 2-D spectral image data. Assumes cross-dispersion (spatial) direction is axis 0 and dispersion (wavelength) direction is axis 1. If None, will extract the background from ``image`` used to initialize the class. [default: None] Returns ------- spec : `~specutils.Spectrum1D` The background 1-D spectrum, with flux expressed in the same units as the input image (or u.DN if none were provided) and the spectral axis expressed in pixel units. """ bkg_image = self.bkg_image(image) try: return bkg_image.collapse(np.nansum, axis=self.crossdisp_axis) except u.UnitTypeError: # can't collapse with a spectral axis in pixels because # SpectralCoord only allows frequency/wavelength equivalent units... ext1d = np.nansum(bkg_image.flux, axis=self.crossdisp_axis) return Spectrum1D(ext1d, bkg_image.spectral_axis) def sub_image(self, image=None): """ Subtract the computed background from ``image``. Parameters ---------- image : nddata-compatible image or None image with 2-D spectral image data. If None, will extract the background from ``image`` used to initialize the class. Returns ------- `~specutils.Spectrum1D` object with same shape as ``image``. """ image = self._parse_image(image) # a compare_wcs argument is needed for Spectrum1D.subtract() in order to # avoid a TypeError from SpectralCoord when image's spectral axis is in # pixels. it is not needed when image's spectral axis has physical units kwargs = ({'compare_wcs': None} if image.spectral_axis.unit == u.pix else {}) # https://docs.astropy.org/en/stable/nddata/mixins/ndarithmetic.html return image.subtract(self.bkg_image(image), **kwargs) def sub_spectrum(self, image=None): """ Expose the 1D spectrum of the background-subtracted image. Parameters ---------- image : nddata-compatible image or None image with 2-D spectral image data. If None, will extract the background from ``image`` used to initialize the class. Returns ------- spec : `~specutils.Spectrum1D` The background 1-D spectrum, with flux expressed in the same units as the input image (or u.DN if none were provided) and the spectral axis expressed in pixel units. """ sub_image = self.sub_image(image=image) try: return sub_image.collapse(np.nansum, axis=self.crossdisp_axis) except u.UnitTypeError: # can't collapse with a spectral axis in pixels because # SpectralCoord only allows frequency/wavelength equivalent units... ext1d = np.nansum(sub_image.flux, axis=self.crossdisp_axis) return Spectrum1D(ext1d, spectral_axis=sub_image.spectral_axis) def __rsub__(self, image): """ Subtract the background from an image. """ return self.sub_image(image) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/calibration_data.py0000644000175100001770000004602114635037352021233 0ustar00runnerdocker""" Utilities for defining, loading, and handling spectroscopic calibration data """ import warnings from pathlib import Path from typing import Sequence from astropy import units as u from astropy.table import Table, vstack, QTable from astropy.utils.data import download_file from astropy.utils.exceptions import AstropyUserWarning from astropy.coordinates import SpectralCoord from specutils import Spectrum1D from specutils.utils.wcs_utils import vac_to_air __all__ = [ 'get_reference_file_path', 'get_pypeit_data_path', 'get_available_line_catalogs', 'load_pypeit_calibration_lines', 'load_MAST_calspec', 'load_onedstds', 'AtmosphericExtinction', 'AtmosphericTransmission' ] SUPPORTED_EXTINCTION_MODELS = [ "kpno", "ctio", "apo", "lapalma", "mko", "mtham", "paranal" ] SPECPHOT_DATASETS = [ "bstdscal", "ctiocal", "ctionewcal", "eso", "gemini", "iidscal", "irscal", "oke1990", "redcal", "snfactory", "spec16cal", "spec50cal", "spechayescal" ] PYPEIT_CALIBRATION_LINELISTS = [ 'Ne_IR_MOSFIRE', 'ArII', 'CdI', 'OH_MOSFIRE_H', 'OH_triplespec', 'Ar_IR_MOSFIRE', 'OH_GNIRS', 'ThAr_XSHOOTER_VIS', 'ThAr_MagE', 'HgI', 'NeI', 'XeI', 'OH_MODS', 'ZnI', 'OH_GMOS', 'CuI', 'ThAr_XSHOOTER_VIS_air', 'ThAr_XSHOOTER_UVB', 'OH_NIRES', 'HeI', 'FeI', 'OH_MOSFIRE_J', 'KrI', 'Cd_DeVeny1200', 'Ar_IR_GNIRS', 'OH_MOSFIRE_Y', 'ThAr', 'FeII', 'OH_XSHOOTER', 'OH_FIRE_Echelle', 'OH_MOSFIRE_K', 'OH_R24000', 'Hg_DeVeny1200', 'ArI' ] def get_available_line_catalogs() -> dict: """ Returns a dictionary of available line catalogs. Currently only ``pypeit`` catalogs are fully supported. """ return { 'pypeit': PYPEIT_CALIBRATION_LINELISTS } def get_reference_file_path( path: str | Path | None = None, cache: bool = True, repo_url: str = "https://raw.githubusercontent.com/astropy/specreduce-data", repo_branch: str = "main", repo_data_path: str = "specreduce_data/reference_data", show_progress: bool = False ) -> Path | None: """ Utility to load reference data via GitHub raw user content. By default the ``specreduce_data`` repository at https://github.com/astropy/specreduce-data is used. Parameters ---------- path : Path of reference file relative to the reference_data directory within specified package. cache : Set whether file is cached if file is downloaded. repo_url : Base repository URL for the reference data. repo_branch : Branch of repository from which to fetch the reference data. repo_data_path : Path within the repository where the reference data is located. show_progress : Set whether download progress bar is shown if file is downloaded. Returns ------- file_path : Local path to reference data file or None if the path cannot be constructed or if the file itself is not valid. Examples -------- >>> from specreduce.calibration_data import get_reference_file_path >>> kpno_extinction_file = get_reference_file_path("extinction/kpnoextinct.dat") """ if path is None: return None remote_url = f"{repo_url}/{repo_branch}/{repo_data_path}/{path}" try: file_path = Path( download_file( remote_url, cache=cache, show_progress=show_progress, pkgname='specreduce' ) ) except Exception as e: msg = f"Downloading of {remote_url} failed: {e}" warnings.warn(msg, AstropyUserWarning) return None # final sanity check to make sure file_path is actually a file. if file_path.exists() and file_path.is_file(): return file_path else: warnings.warn(f"Able to construct {file_path}, but it is not a file.") return None def get_pypeit_data_path( path: str | Path | None = None, cache: bool = True, show_progress: bool = False ) -> Path | None: """ Convenience utility to facilitate access to ``pypeit`` reference data. The data is accessed directly from the release branch on GitHub and downloaded/cached using `~astropy.utils.data.download_file`. Parameters ---------- path : Filename of reference file relative to the reference_data directory within ``specreduce_data`` package. cache : Set whether file is cached if file is downloaded. show_progress : Set whether download progress bar is shown if file is downloaded. Returns ------- file_path : Path to reference data file or None if the path cannot be constructed or if the file itself is not valid. Examples -------- >>> from specreduce.calibration_data import get_pypeit_data_path >>> pypeit_he_linelist = get_pypeit_data_path("arc_lines/lists/HeI_lines.dat") """ repo_url = "https://raw.githubusercontent.com/pypeit/pypeit" repo_branch = "release" repo_data_path = "pypeit/data" return get_reference_file_path( path=path, cache=cache, repo_url=repo_url, repo_branch=repo_branch, repo_data_path=repo_data_path, show_progress=show_progress ) def load_pypeit_calibration_lines( lamps: Sequence | None = None, wave_air: bool = False, cache: bool = True, show_progress: bool = False ) -> QTable | None: """ Load reference calibration lines from ``pypeit`` linelists. The ``pypeit`` linelists are well-curated and have been tested across a wide range of spectrographs. The available linelists are defined by ``PYPEIT_CALIBRATION_LINELISTS``. Parameters ---------- lamps : Lamp string, comma-separated list of lamps, or sequence of lamps to include in output reference linelist. The parlance of "lamp" is retained here for consistency with its use in ``pypeit`` and elsewhere. In several of the supported cases the "lamp" is the sky itself (e.g. OH lines in the near-IR). The available lamps are defined by ``PYPEIT_CALIBRATION_LINELISTS``. wave_air : If True, convert the vacuum wavelengths used by ``pypeit`` to air wavelengths. cache : Toggle caching of downloaded data show_progress : Show download progress bar Returns ------- linelist: Table containing the combined calibration line list. ``pypeit`` linelists have the following columns: * ``ion``: Ion or molecule generating the line. * ``wavelength``: Vacuum wavelength of the line in Angstroms. * ``NIST``: Flag denoting if NIST is the ultimate reference for the line's wavelength. * ``Instr``: ``pypeit``-specific instrument flag. * ``amplitude``: Amplitude of the line. Beware, not consistent between lists. * ``Source``: Source of the line information. """ if lamps is None: return None if not isinstance(lamps, Sequence): raise ValueError(f"Invalid calibration lamps specification: {lamps}") if isinstance(lamps, str): if ',' in lamps: lamps = [lamp.strip() for lamp in lamps.split(',')] else: lamps = [lamps] linelists = [] for lamp in lamps: if lamp in PYPEIT_CALIBRATION_LINELISTS: list_path = f"arc_lines/lists/{lamp}_lines.dat" lines_file = get_pypeit_data_path( list_path, cache=cache, show_progress=show_progress ) lines_tab = Table.read( lines_file, format='ascii.fixed_width', comment='#' ) if lines_tab is not None: linelists.append(lines_tab) else: warnings.warn( f"{lamp} not in the list of supported calibration " "line lists: {PYPEIT_CALIBRATION_LINELISTS}." ) if len(linelists) == 0: warnings.warn(f"No calibration lines loaded from {lamps}.") linelist = None else: linelist = vstack(linelists) linelist.rename_column('wave', 'wavelength') # pypeit linelists use vacuum wavelengths in angstroms linelist['wavelength'] *= u.Angstrom if wave_air: linelist['wavelength'] = vac_to_air(linelist['wavelength']) linelist = QTable(linelist) return linelist def load_MAST_calspec( filename: str | Path, cache: bool = True, show_progress: bool = False ) -> Spectrum1D | None: """ Load a standard star spectrum from the ``calspec`` database at MAST. These spectra are provided in FITS format and are described in detail at: https://www.stsci.edu/hst/instrumentation/reference-data-for-calibration-and-tools/astronomical-catalogs/calspec If ``remote`` is True, the spectrum will be downloaded from MAST. Set ``remote`` to False to load a local file. .. note:: This function requires ``synphot`` to be installed separately. Parameters ---------- filename : FITS filename of a standard star spectrum, e.g. g191b2b_005.fits. If this is a local file, it will be loaded. If not, then a download from MAST will be attempted. cache : Toggle whether downloaded data is cached or not. show_progress : Toggle whether download progress bar is shown. Returns ------- spectrum : If the spectrum can be loaded, return it as a `~specutils.Spectrum1D`. Otherwise return None. The spectral_axis units are Å and the flux units are milli-Janskys. """ filename = Path(filename) if filename.exists() and filename.is_file(): file_path = filename else: url = f"https://archive.stsci.edu/hlsps/reference-atlases/cdbs/calspec/{filename}" try: file_path = download_file( url, cache=cache, show_progress=show_progress, pkgname='specreduce' ) except Exception as e: msg = f"Downloading of {url} failed: {e}" warnings.warn(msg, AstropyUserWarning) file_path = None if file_path is None: return None else: import synphot _, wave, flux = synphot.specio.read_fits_spec(file_path) # DEV: pllim does not think this is necessary at all but whatever. # the calspec data stores flux in synphot's FLAM units. convert to flux units # supported directly by astropy.units. mJy is chosen since it's the JWST # standard and can easily be converted to/from AB magnitudes. flux_mjy = synphot.units.convert_flux(wave, flux, u.mJy) spectrum = Spectrum1D(spectral_axis=wave, flux=flux_mjy) return spectrum def load_onedstds( dataset: str = "snfactory", specfile: str = "EG131.dat", cache: bool = True, show_progress: bool = False ) -> Spectrum1D | None: """ This is a convenience function for loading a standard star spectrum from the 'onedstds' dataset in the ``specreduce_data`` package. They will be downloaded from the repository on GitHub and cached by default. Parameters ---------- dataset : Standard star spectrum database. Valid options are described in :ref:`specphot_standards`. specfile : Filename of the standard star spectrum. cache : Enable caching of downloaded data. show_progress : Show download progress bar if data is downloaded. Returns ------- spectrum : If the spectrum can be loaded, return it as a `~specutils.Spectrum1D`. Otherwise return None. The spectral_axis units are Å and the flux units are milli-Janskys. """ if dataset not in SPECPHOT_DATASETS: msg = (f"Specfied dataset, {dataset}, not in list of supported datasets of " f"spectrophotometric standard stars: f{SPECPHOT_DATASETS}") warnings.warn(msg, AstropyUserWarning) return None spec_path = get_reference_file_path( path=Path("onedstds") / Path(dataset) / Path(specfile), cache=cache, show_progress=show_progress ) if spec_path is None: msg = f"Can't load {specfile} from {dataset}." warnings.warn(msg, AstropyUserWarning) return None t = Table.read(spec_path, format="ascii", names=['wavelength', 'ABmag', 'binsize']) # the specreduce_data standard star spectra all provide wavelengths in angstroms spectral_axis = t['wavelength'].data * u.angstrom # the specreduce_data standard star spectra all provide fluxes in AB mag flux = t['ABmag'].data * u.ABmag flux = flux.to(u.mJy) # convert to linear flux units spectrum = Spectrum1D(spectral_axis=spectral_axis, flux=flux) return spectrum class AtmosphericExtinction(Spectrum1D): """ Spectrum container for atmospheric extinction in magnitudes as a function of wavelength. If extinction and spectral_axis are provided, this will use them to build a custom model. If they are not, the 'model' parameter will be used to lookup and load a pre-defined atmospheric extinction model from the ``specreduce_data`` package. Parameters ---------- model : Name of atmospheric extinction model provided by ``specreduce_data``. Valid options are: kpno - Kitt Peak National Observatory (default) ctio - Cerro Tololo International Observatory apo - Apache Point Observatory lapalma - Roque de los Muchachos Observatory, La Palma, Canary Islands mko - Mauna Kea Observatories mtham - Lick Observatory, Mt. Hamilton station paranal - European Southern Observatory, Cerro Paranal station extinction : Optionally provided extinction data for this spectrum. Used along with spectral_axis to build custom atmospheric extinction model. If no units are provided, assumed to be given in magnitudes. spectral_axis : Optional Dispersion information with the same shape as the last (or only) dimension of flux, or one greater than the last dimension of flux if specifying bin edges. Used along with flux to build custom atmospheric extinction model. Properties ---------- extinction_mag : Extinction expressed in dimensionless magnitudes transmission : Extinction expressed as fractional transmission """ def __init__( self, model: str = "kpno", extinction: Sequence[float] | u.Quantity | None = None, spectral_axis: SpectralCoord | u.Quantity | None = None, cache: bool = True, show_progress: bool = False, **kwargs: str ) -> None: if extinction is not None: if not isinstance(extinction, u.Quantity): warnings.warn( "Input extinction is not a Quanitity. Assuming it is given in magnitudes...", AstropyUserWarning ) extinction = u.Magnitude( extinction, u.MagUnit(u.dimensionless_unscaled) ).to(u.dimensionless_unscaled) # Spectrum1D wants this to be linear if isinstance(extinction, (u.LogUnit, u.Magnitude)) or extinction.unit == u.mag: # if in log or magnitudes, recast into Magnitude with dimensionless physical units extinction = u.Magnitude( extinction.value, u.MagUnit(u.dimensionless_unscaled) ).to(u.dimensionless_unscaled) if extinction.unit != u.dimensionless_unscaled: # if we're given something linear that's not dimensionless_unscaled, # it's an error msg = "Input extinction must have unscaled dimensionless units." raise ValueError(msg) if extinction is None and spectral_axis is None: if model not in SUPPORTED_EXTINCTION_MODELS: msg = ( f"Requested extinction model, {model}, not in list " f"of available models: {SUPPORTED_EXTINCTION_MODELS}" ) raise ValueError(msg) model_file = Path("extinction") / Path(f"{model}extinct.dat") model_path = get_reference_file_path( path=model_file, cache=cache, show_progress=show_progress ) t = Table.read(model_path, format="ascii", names=['wavelength', 'extinction']) # the specreduce_data models all provide wavelengths in angstroms spectral_axis = t['wavelength'].data * u.angstrom # the specreduce_data models all provide extinction in magnitudes at an airmass of 1 extinction = u.Magnitude( t['extinction'].data, u.MagUnit(u.dimensionless_unscaled) ).to(u.dimensionless_unscaled) if spectral_axis is None: msg = "Missing spectral axis for input extinction data." raise ValueError(msg) super(AtmosphericExtinction, self).__init__( flux=extinction, spectral_axis=spectral_axis, unit=u.dimensionless_unscaled, **kwargs ) @property def extinction_mag(self) -> u.Quantity: """ This property returns the extinction in magnitudes """ return self.flux.to(u.mag(u.dimensionless_unscaled)) @property def transmission(self) -> u.Quantity: """ This property returns the transmission as a fraction between 0 and 1 """ return self.flux class AtmosphericTransmission(AtmosphericExtinction): """ Spectrum container for atmospheric transmission as a function of wavelength. Parameters ---------- data_file : Name to file containing atmospheric transmission data. Data is assumed to have two columns, wavelength and transmission (unscaled dimensionless). If this isn't provided, a model is built from a pre-calculated table of values from 0.9 to 5.6 microns. The values were generated by the ATRAN model, https://ntrs.nasa.gov/citations/19930010877 (Lord, S. D., 1992, NASA Technical Memorandum 103957). The extinction is given as a linear transmission fraction at an airmass of 1 and 1 mm of precipitable water. wave_unit : Units for spectral axis. """ def __init__( self, data_file: str | Path | None = None, wave_unit: u.Unit = u.um, **kwargs: str ) -> None: if data_file is None: data_path = Path("extinction") / Path("atm_trans_am1.0.dat") data_file = get_reference_file_path(path=data_path) t = Table.read(Path(data_file), format="ascii", names=['wavelength', 'extinction']) # spectral axis is given in microns spectral_axis = t['wavelength'].data * wave_unit # extinction is given in a dimensionless transmission fraction extinction = t['extinction'].data * u.dimensionless_unscaled super(AtmosphericTransmission, self).__init__( extinction=extinction, spectral_axis=spectral_axis, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/conftest.py0000644000175100001770000001026214635037352017576 0ustar00runnerdocker# This file is used to configure the behavior of pytest when using the Astropy # test infrastructure. It needs to live inside the package in order for it to # get picked up when running the tests inside an interpreter using # packagename.test import numpy as np import pytest from astropy import units as u from astropy.io import fits from astropy.nddata import CCDData, NDData, VarianceUncertainty from astropy.utils.data import get_pkg_data_filename from specutils import Spectrum1D, SpectralAxis try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS ASTROPY_HEADER = True except ImportError: ASTROPY_HEADER = False # Test image is comprised of 30 rows with 10 columns each. Row content # is row index itself. This makes it easy to predict what should be the # value extracted from a region centered at any arbitrary Y position. def _mk_test_data(imgtype, nrows=30, ncols=10): image_ones = np.ones(shape=(nrows, ncols)) image = image_ones.copy() for j in range(nrows): image[j, ::] *= j if imgtype == "raw": pass # no extra processing elif imgtype == "ccddata": image = CCDData(image, unit=u.Jy) else: # spectrum flux = image * u.DN uncert = VarianceUncertainty(image_ones) if imgtype == "spec_no_axis": image = Spectrum1D(flux, uncertainty=uncert) else: # "spec" image = Spectrum1D(flux, spectral_axis=np.arange(ncols) * u.um, uncertainty=uncert) return image @pytest.fixture def mk_test_img_raw(): return _mk_test_data("raw") @pytest.fixture def mk_test_img(): return _mk_test_data("ccddata") @pytest.fixture def mk_test_spec_no_spectral_axis(): return _mk_test_data("spec_no_axis") @pytest.fixture def mk_test_spec_with_spectral_axis(): return _mk_test_data("spec") # Test data file already transposed like this: # fn = download_file('https://stsci.box.com/shared/static/exnkul627fcuhy5akf2gswytud5tazmw.fits', cache=True) # noqa: E501 # img = fits.getdata(fn).T @pytest.fixture def all_images(): np.random.seed(7) filename = get_pkg_data_filename( "data/transposed_det_image_seq5_MIRIMAGE_P750Lexp1_s2d.fits", package="specreduce.tests") img = fits.getdata(filename) flux = img * (u.MJy / u.sr) sax = SpectralAxis(np.linspace(14.377, 3.677, flux.shape[-1]) * u.um) unc = VarianceUncertainty(np.random.rand(*flux.shape)) all_images = {} all_images['arr'] = img all_images['s1d'] = Spectrum1D(flux, spectral_axis=sax, uncertainty=unc) all_images['s1d_pix'] = Spectrum1D(flux, uncertainty=unc) all_images['ccd'] = CCDData(img, uncertainty=unc, unit=flux.unit) all_images['ndd'] = NDData(img, uncertainty=unc, unit=flux.unit) all_images['qnt'] = img * flux.unit return all_images @pytest.fixture def spec1d(): np.random.seed(7) flux = np.random.random(50)*u.Jy sa = np.arange(0, 50)*u.pix spec = Spectrum1D(flux, spectral_axis=sa) return spec @pytest.fixture def spec1d_with_emission_line(): np.random.seed(7) sa = np.arange(0, 200)*u.pix flux = (np.random.randn(200) + 10*np.exp(-0.01*((sa.value-130)**2)) + sa.value/100) * u.Jy spec = Spectrum1D(flux, spectral_axis=sa) return spec @pytest.fixture def spec1d_with_absorption_line(): np.random.seed(7) sa = np.arange(0, 200)*u.pix flux = (np.random.randn(200) - 10*np.exp(-0.01*((sa.value-130)**2)) + sa.value/100) * u.Jy spec = Spectrum1D(flux, spectral_axis=sa) return spec def pytest_configure(config): if ASTROPY_HEADER: config.option.astropy_header = True # Customize the following lines to add/remove entries from the list of # packages for which version numbers are displayed when running the tests. PYTEST_HEADER_MODULES.pop('Pandas', None) PYTEST_HEADER_MODULES.pop('h5py', None) PYTEST_HEADER_MODULES['astropy'] = 'astropy' PYTEST_HEADER_MODULES['specutils'] = 'specutils' PYTEST_HEADER_MODULES['photutils'] = 'photutils' PYTEST_HEADER_MODULES['synphot'] = 'synphot' from specreduce import __version__ TESTED_VERSIONS["specreduce"] = __version__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/core.py0000644000175100001770000001072014635037352016700 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst import inspect from dataclasses import dataclass import numpy as np from astropy import units as u from astropy.nddata import VarianceUncertainty from specutils import Spectrum1D __all__ = ['SpecreduceOperation'] class _ImageParser: """ Coerces images from accepted formats to Spectrum1D objects for internal use in specreduce's operation classes. Fills any and all of uncertainty, mask, units, and spectral axis that are missing in the provided image with generic values. Accepted image types are: - `~specutils.spectra.spectrum1d.Spectrum1D` (preferred) - `~astropy.nddata.ccddata.CCDData` - `~astropy.nddata.ndddata.NDDData` - `~astropy.units.quantity.Quantity` - `~numpy.ndarray` """ def _parse_image(self, image, disp_axis=1): """ Convert all accepted image types to a consistently formatted Spectrum1D object. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required The image to be parsed. If None, defaults to class' own image attribute. disp_axis : int, optional The index of the image's dispersion axis. Should not be changed until operations can handle variable image orientations. [default: 1] """ # would be nice to handle (cross)disp_axis consistently across # operations (public attribute? private attribute? argument only?) so # it can be called from self instead of via kwargs... if image is None: # useful for Background's instance methods return self.image img = self._get_data_from_image(image, disp_axis=disp_axis) return img @staticmethod def _get_data_from_image(image, disp_axis=1): """Extract data array from various input types for `image`. Retruns `np.ndarray` of image data.""" if isinstance(image, u.quantity.Quantity): img = image.value elif isinstance(image, np.ndarray): img = image else: # NDData, including CCDData and Spectrum1D img = image.data # mask and uncertainty are set as None when they aren't specified upon # creating a Spectrum1D object, so we must check whether these # attributes are absent *and* whether they are present but set as None if getattr(image, 'mask', None) is not None: mask = image.mask else: mask = ~np.isfinite(img) if getattr(image, 'uncertainty', None) is not None: uncertainty = image.uncertainty else: uncertainty = VarianceUncertainty(np.ones(img.shape)) unit = getattr(image, 'unit', u.Unit('DN')) spectral_axis = getattr(image, 'spectral_axis', np.arange(img.shape[disp_axis]) * u.pix) return Spectrum1D(img * unit, spectral_axis=spectral_axis, uncertainty=uncertainty, mask=mask) return img @dataclass class SpecreduceOperation(_ImageParser): """ An operation to perform as part of a spectroscopic reduction pipeline. This class primarily exists to define the basic API for operations: parameters for the operation are provided at object creation, and then the operation object is called with the data objects required for the operation, which then *return* the data objects resulting from the operation. """ def __call__(self): raise NotImplementedError('__call__ on a SpecreduceOperation needs to ' 'be overridden') @classmethod def as_function(cls, *args, **kwargs): """ Run this operation as a function. Syntactic sugar for e.g., ``Operation.as_function(arg1, arg2, keyword=value)`` maps to ``Operation(arg2, keyword=value)(arg1)`` (if the ``__call__`` of ``Operation`` has only one argument) """ argspec = inspect.getargs(SpecreduceOperation.__call__.__code__) if argspec.varargs: raise NotImplementedError('There is not a way to determine the ' 'number of inputs of a *args style ' 'operation') ninputs = len(argspec.args) - 1 callargs = args[:ninputs] noncallargs = args[ninputs:] op = cls(*noncallargs, **kwargs) return op(*callargs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/extract.py0000644000175100001770000010750514635037352017432 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst import warnings from dataclasses import dataclass, field import numpy as np from astropy import units as u from astropy.modeling import Model, models, fitting from astropy.nddata import NDData, VarianceUncertainty from scipy.integrate import trapezoid from scipy.interpolate import RectBivariateSpline from specutils import Spectrum1D from specreduce.core import SpecreduceOperation from specreduce.tracing import Trace, FlatTrace __all__ = ['BoxcarExtract', 'HorneExtract', 'OptimalExtract'] def _get_boxcar_weights(center, hwidth, npix): """ Compute weights given an aperture center, half width, and number of pixels. Based on `get_boxcar_weights()` from a JDAT Notebook by Karl Gordon: https://github.com/spacetelescope/jdat_notebooks/blob/main/notebooks/MIRI_LRS_spectral_extraction/miri_lrs_spectral_extraction.ipynb Parameters ---------- center : float, required The index of the aperture's center pixel on the larger image's cross-dispersion axis. hwidth : float, required Half of the aperture's width in the cross-dispersion direction. npix : float, required The number of pixels in the larger image's cross-dispersion axis. Returns ------- weights : `~numpy.ndarray` A 2D image with weights assigned to pixels that fall within the defined aperture. """ weights = np.zeros((npix)) if hwidth == 0: # the logic below would return all zeros anyways, so might as well save the time # (negative widths should be avoided by earlier logic!) return weights if center-hwidth > npix-0.5 or center+hwidth < -0.5: # entire window is out-of-bounds return weights lower_edge = max(-0.5, center-hwidth) # where -0.5 is lower bound of the image upper_edge = min(center+hwidth, npix-0.5) # where npix-0.5 is upper bound of the image # let's avoid recomputing the round repeatedly int_round_lower_edge = int(round(lower_edge)) int_round_upper_edge = int(round(upper_edge)) # inner pixels that get full weight # the round in conjunction with the +1 handles the half-pixel "offset", # the upper bound doesn't have the +1 because array slicing is inclusive on the lower index and # exclusive on the upper-index # NOTE: round(-0.5) == 0, which is helpful here for the case where lower_edge == -0.5 weights[int_round_lower_edge+1:int_round_upper_edge] = 1 # handle edge pixels (for cases where an edge pixel is fully-weighted, this will set it again, # but should still compute a weight of 1. By using N:N+1, we avoid index errors if the edge # is outside the image bounds. But we do need to avoid negative indices which would count # from the end of the array. if int_round_lower_edge >= 0: weights[int_round_lower_edge:int_round_lower_edge+1] = round(lower_edge) + 0.5 - lower_edge weights[int_round_upper_edge:int_round_upper_edge+1] = upper_edge - (round(upper_edge) - 0.5) return weights def _ap_weight_image(trace, width, disp_axis, crossdisp_axis, image_shape): """ Create a weight image that defines the desired extraction aperture. Based on `ap_weight_images()` from a JDAT Notebook by Karl Gordon: https://github.com/spacetelescope/jdat_notebooks/blob/main/notebooks/MIRI_LRS_spectral_extraction/miri_lrs_spectral_extraction.ipynb Parameters ---------- trace : `~specreduce.tracing.Trace`, required trace object width : float, required width of extraction aperture in pixels disp_axis : int, required dispersion axis crossdisp_axis : int, required cross-dispersion axis image_shape : tuple with 2 elements, required size (shape) of image Returns ------- wimage : `~numpy.ndarray` a 2D weight image defining the aperture """ wimage = np.zeros(image_shape) hwidth = 0.5 * width image_sizes = image_shape[crossdisp_axis] # loop in dispersion direction and compute weights. for i in range(image_shape[disp_axis]): # TODO trace must handle transposed data (disp_axis == 0) # pass trace.trace.data[i] to avoid any mask if part of the regions is out-of-bounds wimage[:, i] = _get_boxcar_weights(trace.trace.data[i], hwidth, image_sizes) return wimage @dataclass class BoxcarExtract(SpecreduceOperation): """ Does a standard boxcar extraction. Example: :: trace = FlatTrace(image, trace_pos) extract = BoxcarExtract(image, trace) spectrum = extract(width=width) Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required image with 2-D spectral image data trace_object : Trace, required trace object width : float, optional width of extraction aperture in pixels disp_axis : int, optional dispersion axis crossdisp_axis : int, optional cross-dispersion axis Returns ------- spec : `~specutils.Spectrum1D` The extracted 1d spectrum expressed in DN and pixel units """ image: NDData trace_object: Trace width: float = 5 disp_axis: int = 1 crossdisp_axis: int = 0 # TODO: should disp_axis and crossdisp_axis be defined in the Trace object? @property def spectrum(self): return self.__call__() def __call__(self, image=None, trace_object=None, width=None, disp_axis=None, crossdisp_axis=None): """ Extract the 1D spectrum using the boxcar method. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required image with 2-D spectral image data trace_object : Trace, required trace object width : float, optional width of extraction aperture in pixels [default: 5] disp_axis : int, optional dispersion axis [default: 1] crossdisp_axis : int, optional cross-dispersion axis [default: 0] Returns ------- spec : `~specutils.Spectrum1D` The extracted 1d spectrum with flux expressed in the same units as the input image, or u.DN, and pixel units """ image = image if image is not None else self.image trace_object = trace_object if trace_object is not None else self.trace_object width = width if width is not None else self.width disp_axis = disp_axis if disp_axis is not None else self.disp_axis crossdisp_axis = crossdisp_axis if crossdisp_axis is not None else self.crossdisp_axis # handle image processing based on its type self.image = self._parse_image(image) # TODO: this check can be removed if/when implemented as a check in FlatTrace if isinstance(trace_object, FlatTrace): if trace_object.trace_pos < 1: raise ValueError('trace_object.trace_pos must be >= 1') if width < 0: raise ValueError("width must be positive") # weight image to use for extraction wimg = _ap_weight_image( trace_object, width, disp_axis, crossdisp_axis, self.image.shape) # extract, assigning no weight to non-finite pixels outside the window # (non-finite pixels inside the window will still make it into the sum) image_windowed = np.where(wimg, self.image.data*wimg, 0) ext1d = np.sum(image_windowed, axis=crossdisp_axis) return Spectrum1D(ext1d * self.image.unit, spectral_axis=self.image.spectral_axis) @dataclass class HorneExtract(SpecreduceOperation): """ Perform a Horne (a.k.a. optimal) extraction on a two-dimensional spectrum. There are two options for fitting the spatial profile used for extraction - by default, a 1D gaussian is fit and as a uniform profile across the spectrum. Alternativley, the ``self profile`` option may be chosen - when this option is chosen, the spatial profile will be sampled at various locations (set by <>) and interpolated between to produce a smoothly varying spatial profile across the spectrum. If using the Gaussian option for the spatial profile, a background profile may be fit (but not subtracted) simultaneously to the data. By default, this is done with a 2nd degree polynomial. If using the ``interpolated_profile`` option, the background model must be set to None. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required The input 2D spectrum from which to extract a source. An NDData object must specify uncertainty and a mask. An array requires use of the ``variance``, ``mask``, & ``unit`` arguments. trace_object : `~specreduce.tracing.Trace`, required The associated 1D trace object created for the 2D image. disp_axis : int, optional The index of the image's dispersion axis. [default: 1] crossdisp_axis : int, optional The index of the image's cross-dispersion axis. [default: 0] bkgrd_prof : `~astropy.modeling.Model` or None, optional A model for the image's background flux. If ``spatial_profile`` is set to ``interpolated_profile``, then ``bkgrd_prof`` must be set to None. [default: models.Polynomial1D(2)]. spatial_profile : str or dict, optional The shape of the object profile. The first option is 'gaussian' to fit a uniform 1D gaussian to the average of pixels in the cross-dispersion direction. The other option is 'interpolated_profile' - when this option is used, the profile is sampled in bins and these samples are interpolated between to construct a continuously varying, empirical spatial profile for extraction. For this option, if passed in as a string (i.e spatial_profile='interpolated_profile') the default values for the number of bins used (10) and degree of interpolation (linear in x and y, by default) will be used. To set these parameters, pass in a dictionary with the keys 'n_bins_interpolated_profile' (which accepts an integer number of bins) and 'interp_degree' (which accepts an int, or tuple of ints for x and y degree, respectively). [default: gaussian] variance : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) The associated variances for each pixel in the image. Must have the same dimensions as ``image``. If all zeros, the variance will be ignored and treated as all ones. If any zeros, those elements will be excluded via masking. If any negative values, an error will be raised. [default: None] mask : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) Whether to mask each pixel in the image. Must have the same dimensions as ``image``. If blank, all non-NaN pixels are unmasked. [default: None] unit : `~astropy.units.Unit` or str, optional (Only used if ``image`` is not an NDData object.) The associated unit for the data in ``image``. If blank, fluxes are interpreted in DN. [default: None] """ image: NDData trace_object: Trace bkgrd_prof: Model = field(default=models.Polynomial1D(2)) spatial_profile: str = 'gaussian' # can actually be str, dict variance: np.ndarray = field(default=None) mask: np.ndarray = field(default=None) unit: np.ndarray = field(default=None) disp_axis: int = 1 crossdisp_axis: int = 0 # TODO: should disp_axis and crossdisp_axis be defined in the Trace object? @property def spectrum(self): return self.__call__() def _parse_image(self, image, variance=None, mask=None, unit=None, disp_axis=1): """ Convert all accepted image types to a consistently formatted Spectrum1D object. HorneExtract needs its own version of this method because it is more stringent in its requirements for input images. The extra arguments are needed to handle cases where these parameters were specified as arguments and those where they came as attributes of the image object. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required The image to be parsed. If None, defaults to class' own image attribute. variance : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) The associated variances for each pixel in the image. Must have the same dimensions as ``image``. If all zeros, the variance will be ignored and treated as all ones. If any zeros, those elements will be excluded via masking. If any negative values, an error will be raised. mask : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) Whether to mask each pixel in the image. Must have the same dimensions as ``image``. If blank, all non-NaN pixels are unmasked. unit : `~astropy.units.Unit` or str, optional (Only used if ``image`` is not an NDData object.) The associated unit for the data in ``image``. If blank, fluxes are interpreted in DN. disp_axis : int, optional The index of the image's dispersion axis. Should not be changed until operations can handle variable image orientations. [default: 1] """ if isinstance(image, np.ndarray): img = image elif isinstance(image, u.quantity.Quantity): img = image.value else: # NDData, including CCDData and Spectrum1D img = image.data # mask is set as None when not specified upon creating a Spectrum1D # object, so we must check whether it is absent *and* whether it's # present but set as None if getattr(image, 'mask', None) is not None: mask = image.mask elif mask is not None: pass else: # if user provides no mask at all, don't mask anywhere mask = np.zeros_like(img) if img.shape != mask.shape: raise ValueError('image and mask shapes must match.') # Process uncertainties, converting to variances when able and throwing # an error when uncertainties are missing or less easily converted if (hasattr(image, 'uncertainty') and image.uncertainty is not None): if image.uncertainty.uncertainty_type == 'var': variance = image.uncertainty.array elif image.uncertainty.uncertainty_type == 'std': warnings.warn("image NDData object's uncertainty " "interpreted as standard deviation. if " "incorrect, use VarianceUncertainty when " "assigning image object's uncertainty.") variance = image.uncertainty.array**2 elif image.uncertainty.uncertainty_type == 'ivar': variance = 1 / image.uncertainty.array else: # other options are InverseUncertainty and UnknownUncertainty raise ValueError("image NDData object has unexpected " "uncertainty type. instead, try " "VarianceUncertainty or StdDevUncertainty.") elif (hasattr(image, 'uncertainty') and image.uncertainty is None): # ignore variance arg to focus on updating NDData object raise ValueError('image NDData object lacks uncertainty') else: if variance is None: raise ValueError("if image is a numpy or Quantity array, a " "variance must be specified. consider " "wrapping it into one object by instead " "passing an NDData image.") elif image.shape != variance.shape: raise ValueError("image and variance shapes must match") if np.any(variance < 0): raise ValueError("variance must be fully positive") if np.all(variance == 0): # technically would result in infinities, but since they're all # zeros, we can override ones to simulate an unweighted case variance = np.ones_like(variance) if np.any(variance == 0): # exclude such elements by editing the input mask mask[variance == 0] = True # replace the variances to avoid a divide by zero warning variance[variance == 0] = np.nan variance = VarianceUncertainty(variance) unit = getattr(image, 'unit', u.Unit(unit) if unit is not None else u.Unit('DN')) spectral_axis = getattr(image, 'spectral_axis', np.arange(img.shape[disp_axis]) * u.pix) return Spectrum1D(img * unit, spectral_axis=spectral_axis, uncertainty=variance, mask=mask) def _fit_gaussian_spatial_profile(self, img, disp_axis, crossdisp_axis, or_mask, bkgrd_prof): """ Fits an 1D Gaussian profile to spectrum in `img`. Takes the mean of ``img`` along the cross-dispersion axis (i.e, takes the mean of each row for a horizontal trace). Any columns with non-finite values are omitted from the fit. Background model (optional) is fit simultaneously. Returns an `astropy.model.Gaussian1D` (or compound model, if `bkgrd_prof` is supplied) fit to data. """ # co-add signal in each image row nrows = img.shape[crossdisp_axis] ncols = img.shape[disp_axis] xd_pixels = np.arange(nrows) # for now, mask row with any non-finite value. row_mask = np.logical_or.reduce(or_mask, axis=disp_axis) coadd = np.ma.masked_array(np.sum(img, axis=disp_axis) / ncols, mask=row_mask) # use the sum of brightest row as an inital guess for Gaussian amplitude, # the the location of the brightest row as an initial guess for the mean gauss_prof = models.Gaussian1D(amplitude=coadd.max(), mean=coadd.argmax(), stddev=2) # Fit extraction kernel (Gaussian + background model) to coadded rows # with combined model (must exclude masked indices manually; # LevMarLSQFitter does not) if bkgrd_prof is not None: ext_prof = gauss_prof + bkgrd_prof else: # add a trivial constant model so attribute names are the same ext_prof = gauss_prof + models.Const1D(0, fixed={'amplitude': True}) fitter = fitting.LevMarLSQFitter() fit_ext_kernel = fitter(ext_prof, xd_pixels[~row_mask], coadd[~row_mask]) return fit_ext_kernel def _fit_self_spatial_profile(self, img, disp_axis, crossdisp_axis, or_mask, n_bins_interpolated_profile, kx, ky): """ Fit a spatial profile to spectrum by sampling the median profile in bins (number of which set be `n_bins_interpolated_profile` along the dispersion direction, and interpolating between samples. Columns (assuming horizontal trace) with any non-finite values will be omitted from the fit. Returns an interpolator object (RectBivariateSpline) that can be evaluated at any x,y. """ # boundaries of bins for sampling profile. sample_locs = np.linspace(0, img.shape[disp_axis]-1, n_bins_interpolated_profile+1, dtype=int) # centers of these bins, roughly bin_centers = [(sample_locs[i]+sample_locs[i+1]) // 2 for i in range(len(sample_locs) - 1)] # for now, since fitting isn't enabled for arrays with any nans # mask out the columns with any non-finite values to make sure # these don't contribute to the fit profile col_mask = np.logical_or.reduce(or_mask, axis=crossdisp_axis) # make a full mask for the image based on which cols have nans img_col_mask = np.tile(col_mask, (img.shape[0], 1)) # need to make a new masked array since this mask is different # omit all columns with nans from contributing to the fit new_masked_arr = np.ma.array(img.data.copy(), mask=img_col_mask) # sample at these locations, normalize to area so this just reflects the # shape of the spectrum any shifts in center location should be corrected # by _align_along_trace (this should be addressed later with a better way # to flatten the trace, because trace can be wiggly even if 'flat'...) samples = [] for i in range(n_bins_interpolated_profile): slicee = new_masked_arr[:, sample_locs[i]:sample_locs[i+1]] bin_median = np.ma.median(slicee, axis=disp_axis) bin_median_sum = np.ma.sum(bin_median) samples.append(bin_median / bin_median_sum) interp_2d = RectBivariateSpline(x=bin_centers, y=np.arange(img.shape[crossdisp_axis]), z=samples, kx=kx, ky=ky) return interp_2d def __call__(self, image=None, trace_object=None, disp_axis=None, crossdisp_axis=None, bkgrd_prof=None, spatial_profile=None, n_bins_interpolated_profile=None, interp_degree_interpolated_profile=None, variance=None, mask=None, unit=None): """ Run the Horne calculation on a region of an image and extract a 1D spectrum. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required The input 2D spectrum from which to extract a source. An NDData object must specify uncertainty and a mask. An array requires use of the ``variance``, ``mask``, & ``unit`` arguments. trace_object : `~specreduce.tracing.Trace`, required The associated 1D trace object created for the 2D image. disp_axis : int, optional The index of the image's dispersion axis. crossdisp_axis : int, optional The index of the image's cross-dispersion axis. bkgrd_prof : `~astropy.modeling.Model`, optional A model for the image's background flux. spatial_profile : str or dict, optional The shape of the object profile. The first option is 'gaussian' to fit a uniform 1D gaussian to the average of pixels in the cross-dispersion direction. The other option is 'interpolated_profile' - when this option is used, the profile is sampled in bins and these samples are interpolated between to construct a continuously varying, empirical spatial profile for extraction. For this option, if passed in as a string (i.e spatial_profile='interpolated_profile') the default values for the number of bins used (10) and degree of interpolation (linear in x and y, by default) will be used. To set these parameters, pass in a dictionary with the keys 'n_bins_interpolated_profile' (which accepts an integer number of bins) and 'interp_degree' (which accepts an int, or tuple of ints for x and y degree, respectively). [default: gaussian] variance : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) The associated variances for each pixel in the image. Must have the same dimensions as ``image``. If all zeros, the variance will be ignored and treated as all ones. If any zeros, those elements will be excluded via masking. If any negative values, an error will be raised. mask : `~numpy.ndarray`, optional (Only used if ``image`` is not an NDData object.) Whether to mask each pixel in the image. Must have the same dimensions as ``image``. If blank, all non-NaN pixels are unmasked. unit : `~astropy.units.Unit` or str, optional (Only used if ``image`` is not an NDData object.) The associated unit for the data in ``image``. If blank, fluxes are interpreted in DN. Returns ------- spec_1d : `~specutils.Spectrum1D` The final, Horne extracted 1D spectrum. """ image = image if image is not None else self.image trace_object = trace_object if trace_object is not None else self.trace_object disp_axis = disp_axis if disp_axis is not None else self.disp_axis crossdisp_axis = crossdisp_axis if crossdisp_axis is not None else self.crossdisp_axis bkgrd_prof = bkgrd_prof if bkgrd_prof is not None else self.bkgrd_prof spatial_profile = (spatial_profile if spatial_profile is not None else self.spatial_profile) variance = variance if variance is not None else self.variance mask = mask if mask is not None else self.mask unit = unit if unit is not None else self.unit # figure out what 'spatial_profile' was provided # put this parsing into another method at some point, its a lot.. interp_degree_interpolated_profile = None n_bins_interpolated_profile = None spatial_profile_choices = ('gaussian', 'interpolated_profile') if isinstance(spatial_profile, str): spatial_profile = spatial_profile.lower() if spatial_profile not in spatial_profile_choices: raise ValueError("spatial_profile must be one of" f"{', '.join(spatial_profile_choices)}") if spatial_profile == 'interpolated_profile': # use defaults bkgrd_prof = None n_bins_interpolated_profile = 10 interp_degree_interpolated_profile = 1 elif isinstance(spatial_profile, dict): # first, figure out what type of profile is indicated # right now, the only type that should use a dictionary is 'interpolated_profile' # but this may be extended in the future hence the 'name' key. also, # the gaussian option could be supplied as a single-key dict # will raise key error if not present, and also fail on .lower if not # a string - think this is informative enough spatial_profile_type = spatial_profile['name'].lower() if spatial_profile_type not in spatial_profile_choices: raise ValueError("spatial_profile must be one of" f"{', '.join(spatial_profile_choices)}") if spatial_profile_type == 'gaussian': spatial_profile = 'gaussian' else: if 'n_bins_interpolated_profile' in spatial_profile.keys(): n_bins_interpolated_profile = \ spatial_profile['n_bins_interpolated_profile'] else: # use default n_bins_interpolated_profile = 10 if 'interp_degree_interpolated_profile' in spatial_profile.keys(): interp_degree_interpolated_profile = \ spatial_profile['interp_degree_interpolated_profile'] else: # use default interp_degree_interpolated_profile = 1 spatial_profile = spatial_profile_type bkgrd_prof = None else: raise ValueError('``spatial_profile`` must either be string or dictionary.') # parse image and replace optional arguments with updated values self.image = self._parse_image(image, variance, mask, unit, disp_axis) variance = self.image.uncertainty.array mask = self.image.mask unit = self.image.unit img = np.ma.masked_array(self.image.data, mask=mask) # create separate mask including any previously uncaught non-finite # values for purposes of calculating fit or_mask = np.logical_or(img.mask, ~np.isfinite(self.image.data)) # If the trace is not flat, shift the rows in each column # so the image is aligned along the trace: if not isinstance(trace_object, FlatTrace): img = _align_along_trace( img, trace_object.trace, disp_axis=disp_axis, crossdisp_axis=crossdisp_axis) if self.spatial_profile == 'gaussian': # fit profile to average (mean) profile along crossdisp axis fit_ext_kernel = self._fit_gaussian_spatial_profile(img, disp_axis, crossdisp_axis, or_mask, bkgrd_prof) # this is just creating an array of the trace to shift the mean # when iterating over each wavelength. this needs to be fixed in the # future to actually account for the trace shape in a non-flat trace # (or possibly omitted all togehter as it might be redundant if # _align_along_trace is correcting this already) if isinstance(trace_object, FlatTrace): mean_init_guess = trace_object.trace else: mean_init_guess = np.broadcast_to( img.shape[crossdisp_axis] // 2, img.shape[disp_axis] ) else: # interpolated_profile # for now, bkgrd_prof must be None because a compound model can't # be created with a interpolator + model. i think there is a way # around this, but will follow up later if bkgrd_prof is not None: raise ValueError('When `spatial_profile`is `interpolated_profile`,' '`bkgrd_prof` must be None. Background should' ' be fit and subtracted from `img` beforehand.') # make sure n_bins doesnt exceed the number of (for now) finite # columns. update this when masking is fixed. n_finite_cols = np.logical_or.reduce(or_mask, axis=crossdisp_axis) n_finite_cols = np.count_nonzero(n_finite_cols.astype(int) == 0) # determine interpolation degree from input and make tuple if int # this can also be moved to another method to parse the input # 'spatial_profile' arg, eventually if isinstance(interp_degree_interpolated_profile, int): kx = ky = interp_degree_interpolated_profile else: # if input is tuple of ints if not isinstance(interp_degree_interpolated_profile, tuple): raise ValueError("``interp_degree_interpolated_profile`` must be ", "an integer or tuple of integers.") if not all(isinstance(x, int) for x in interp_degree_interpolated_profile): raise ValueError("``interp_degree_interpolated_profile`` must be ", "an integer or tuple of integers.") kx, ky = interp_degree_interpolated_profile if n_bins_interpolated_profile >= n_finite_cols: raise ValueError(f'`n_bins_interpolated_profile` ({n_bins_interpolated_profile}) ' 'must be less than the number of fully-finite ' f'wavelength columns ({n_finite_cols}).') interp_spatial_prof = self._fit_self_spatial_profile(img, disp_axis, crossdisp_axis, or_mask, n_bins_interpolated_profile, kx, ky) # add private attribute to save fit profile. should this be public? self._interp_spatial_prof = interp_spatial_prof col_mask = np.logical_or.reduce(or_mask, axis=crossdisp_axis) nonf_col = [np.nan] * img.shape[crossdisp_axis] # array of 'x' values for each wavelength for extraction nrows = img.shape[crossdisp_axis] xd_pixels = np.arange(nrows) kernel_vals = [] norms = [] for col_pix in range(img.shape[disp_axis]): # for now, skip columns with any non-finite values # NOTE: fit and other kernel operations should support masking again # once a fix is in for renormalizing columns with non-finite values if col_mask[col_pix]: kernel_vals.append(nonf_col) norms.append(np.nan) continue if self.spatial_profile == 'gaussian': # set compound model's mean to column's matching trace value # again, this is probably not necessary if bkgrd_prof is not None: # attr names will be diff. if not compound fit_ext_kernel.mean_0 = mean_init_guess[col_pix] else: fit_ext_kernel.mean = mean_init_guess[col_pix] # evaluate fit model (with shifted mean, based on trace) fitted_col = fit_ext_kernel(xd_pixels) # save result and normalization # this doesn't need to be in this loop, address later kernel_vals.append(fitted_col) norms.append(fit_ext_kernel.amplitude_0 * fit_ext_kernel.stddev_0 * np.sqrt(2*np.pi)) else: # interpolated_profile fitted_col = interp_spatial_prof(col_pix, xd_pixels) kernel_vals.append(fitted_col) norms.append(trapezoid(fitted_col, dx=1)[0]) # transform fit-specific information kernel_vals = np.vstack(kernel_vals).T norms = np.array(norms) # calculate kernel normalization g_x = np.sum(kernel_vals**2 / variance, axis=crossdisp_axis) # sum by column weights weighted_img = np.divide(img * kernel_vals, variance) result = np.sum(weighted_img, axis=crossdisp_axis) / g_x # multiply kernel normalization into the extracted signal extraction = result * norms # convert the extraction to a Spectrum1D object return Spectrum1D(extraction * unit, spectral_axis=self.image.spectral_axis) def _align_along_trace(img, trace_array, disp_axis=1, crossdisp_axis=0): """ Given an arbitrary trace ``trace_array`` (an np.ndarray), roll all columns of ``nddata`` to shift the NDData's pixels nearest to the trace to the center of the spatial dimension of the NDData. """ # TODO: this workflow does not support extraction for >2D spectra if not (disp_axis == 1 and crossdisp_axis == 0): # take the transpose to ensure the rows are the cross-disp axis: img = img.T n_rows, n_cols = img.shape # indices of all columns, in their original order rows = np.broadcast_to(np.arange(n_rows)[:, None], img.shape) cols = np.broadcast_to(np.arange(n_cols), img.shape) # we want to "roll" each column so that the trace sits in # the central row of the final image shifts = trace_array.astype(int) - n_rows // 2 # we wrap the indices so we don't index out of bounds shifted_rows = np.mod(rows + shifts[None, :], n_rows) return img[shifted_rows, cols] @dataclass class OptimalExtract(HorneExtract): """ An alias for `HorneExtract`. """ __doc__ += HorneExtract.__doc__ pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/fluxcal.py0000644000175100001770000002707214635037352017416 0ustar00runnerdockerimport os import numpy as np from astropy import units as u from astropy.constants import c as cc from astropy.table import Table from scipy.interpolate import UnivariateSpline from specutils import Spectrum1D from specreduce.core import SpecreduceOperation __all__ = ['FluxCalibration'] class FluxCalibration(SpecreduceOperation): """ Carries out routine flux calibration operations. Parameters ---------- object_spectrum : a Spectrum1D object The observed object spectrum to apply the sensfunc to, with the wavelength of the data points in Angstroms as the ``spectral_axis``, and the magnitudes of the data as the ``flux``. airmass : float The value of the airmass. Note: NOT the header keyword. zeropoint : float, optional Conversion factor for mag->flux. (Default is 48.60). """ def __call__(self, object_spectrum, airmass=1.00, zeropoint=48.60): self.object_spectrum = object_spectrum self.airmass = airmass self.zeropoint = zeropoint def mag2flux(self, spec_in=None): """ Convert magnitudes to flux units. This is important for dealing with standards and files from IRAF, which are stored in AB mag units. To be clear, this converts to "PHOTFLAM" units in IRAF-speak. Assumes the common flux zeropoint used in IRAF. Parameters ---------- spec_in: a Spectrum1D object, optional An input spectrum with wavelength of the data points in Angstroms as the ``spectral_axis`` and magnitudes of the data as the ``flux``. Returns ------- spec_out: specutils.Spectrum1D Containing both ``flux`` and ``spectral_axis`` data in which the ``flux`` has been properly converted from mag->flux. """ if spec_in is None: spec_in = self.object_spectrum lamb = spec_in.spectral_axis mag = spec_in.flux flux = (10.0**((mag + self.zeropt) / (-2.5))) * (cc.to('AA/s').value / lamb ** 2.0) flux = flux * u.erg / u.s / u.angstrom / (u.cm * u.cm) spec_out = Spectrum1D(spectral_axis=lamb, flux=flux) return spec_out @staticmethod def obs_extinction(obs_file): """ Load the observatory-specific airmass extinction file from the supplied library Parameters ---------- obs_file : str, {'apoextinct.dat', 'ctioextinct.dat', 'kpnoextinct.dat', 'ormextinct.dat'} The observatory-specific airmass extinction file. If not known for your observatory, use one of the provided files (e.g. `kpnoextinct.dat`). Following IRAF standard, extinction files have 2-column format wavelength (Angstroms), Extinction (Mag per Airmass) Returns ------- Xfile: an Astropy table Table with the observatory extinction data """ if len(obs_file) == 0: raise ValueError('Must select an observatory extinction file.') dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'datasets', 'extinction') if not os.path.isfile(os.path.join(dir, obs_file)): msg = "No valid standard star found at: " + os.path.join(dir, obs_file) raise ValueError(msg) # To read in the airmass extinction curve Xfile = Table.read(os.path.join(dir, obs_file), format='ascii', names=('wave', 'X')) Xfile['wave'].unit = 'AA' return Xfile def airmass_cor(self, Xfile): """ Correct the spectrum based on the airmass. Requires observatory extinction file. Parameters ---------- Xfile : astropy.table.Table The extinction table from `obs_extinction`, with columns ('wave', 'X') that have standard units of: (angstroms, mag/airmass). Returns ------- airmass_cor_spec: specutils.Spectrum1D The airmass-corrected Spectrum1D object. """ object_spectrum = self.mag2flux() airmass = self.airmass obj_wave, obj_flux = object_spectrum.spectral_axis, object_spectrum.flux # linear interpol airmass extinction onto observed wavelengths new_X = np.interp(obj_wave.value, Xfile['wave'], Xfile['X']) # air_cor in units of mag/airmass, convert to flux/airmass airmass_ext = 10.0**(0.4 * airmass * new_X) airmass_cor_spec = Spectrum1D(flux=obj_flux * airmass_ext, spectral_axis=obj_wave) return airmass_cor_spec def onedstd(self, stdstar): """ Load the onedstd from the supplied library. Parameters ---------- stdstar : str Name of the standard star file in the specreduce/datasets/onedstds directory to be used for the flux calibration. The user must provide the subdirectory and file name. For example: >>> standard_sensfunc(obj_wave, obj_flux, stdstar='spec50cal/bd284211.dat', mode='spline') # doctest: +SKIP If no std is supplied, or an improper path is given, raises a ValueError. Returns ------- standard: astropy.talbe.Table A table with the onedstd data. """ # noqa: E501 std_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'datasets', 'onedstds') if not os.path.isfile(os.path.join(std_dir, stdstar)): msg = "No valid standard star found at: " + os.path.join(std_dir, stdstar) raise ValueError(msg) standard = Table.read(os.path.join(std_dir, stdstar), format='ascii', names=('wave', 'mag', 'width')) standard['wave'].unit = u.angstrom standard['width'].unit = u.angstrom # Standard star spectrum is stored in magnitude units (IRAF conventions) std_flux = self.mag2flux(spec_in=Spectrum1D(flux=standard['mag'], spectral_axis=standard['wave'])) std_flux = std_flux.flux standard['mag'].unit = u.mag standard.add_column(std_flux, name='flux') return standard def standard_sensfunc(self, standard, mode='linear', polydeg=9, badlines=[6563, 4861, 4341], display=False): """ Compute the standard star sensitivity function. Parameters ---------- standard : astropy.table.Table output from ``onedstd``, has columns ('wave', 'width', 'mag', 'flux'). mode : str, optional Can be "linear", "spline", or "poly" (Default is linear). polydeg : float, optional if mode='poly', this is the order of the polynomial to fit through. (Default is 9.) display : bool, optional If True, plot the sensfunc. (Default is False.) This requires ``matplotlib`` to be installed. badlines : array-like list A list of values (lines) to mask-out of when generating sensfunc. Returns ------- sensfunc_spec : specutils.Spectrum1D The sensitivity function in the covered wavelength range for the given standard star. """ spec = self.mag2flux() obj_wave, obj_flux = spec.spectral_axis, spec.flux # Automatically exclude some lines b/c resolution dependent response badlines = np.array(badlines, dtype='float') # Balmer lines # Down-sample (ds) the observed flux to the standard's bins obj_flux_ds = np.array([], dtype=np.float) obj_wave_ds = np.array([], dtype=np.float) std_flux_ds = np.array([], dtype=np.float) for i in range(len(standard['flux'])): rng = np.where((obj_wave.value >= standard['wave'][i] - standard['width'][i] / 2.0) & (obj_wave.value < standard['wave'][i] + standard['width'][i] / 2.0))[0] IsH = np.where((badlines >= standard['wave'][i] - standard['width'][i] / 2.0) & (badlines < standard['wave'][i] + standard['width'][i] / 2.0))[0] # Does this bin contain observed spectra, and no Balmer lines? if (len(rng) > 1) and (len(IsH) == 0): obj_flux_ds = np.append(obj_flux_ds, np.nanmean(obj_flux.value[rng])) obj_wave_ds = np.append(obj_wave_ds, standard['wave'][i]) std_flux_ds = np.append(std_flux_ds, standard['flux'][i]) # the ratio between the standard star catalog flux and observed flux ratio = np.abs(std_flux_ds / obj_flux_ds) # The actual fit the log of this sensfunc ratio # Since IRAF does the 2.5*log(ratio), everything would be in mag units LogSensfunc = np.log10(ratio) # If invalid interpolation mode selected, make it spline if mode.lower() not in ('linear', 'spline', 'poly'): mode = 'spline' import warnings warnings.warn("WARNING: invalid mode set. Changing to default mode 'spline'") # Interpolate the calibration (sensfunc) on to observed wavelength grid if mode.lower() == 'linear': sensfunc2 = np.interp(obj_wave.value, obj_wave_ds, LogSensfunc) elif mode.lower() == 'spline': spl = UnivariateSpline(obj_wave_ds, LogSensfunc, ext=0, k=2, s=0.0025) sensfunc2 = spl(obj_wave.value) elif mode.lower() == 'poly': fit = np.polyfit(obj_wave_ds, LogSensfunc, polydeg) sensfunc2 = np.polyval(fit, obj_wave.value) sensfunc_out = (10 ** sensfunc2) * standard['flux'].unit / obj_flux.unit sensfunc_spec = Spectrum1D(spectral_axis=obj_wave, flux=sensfunc_out) if display is True: import matplotlib.pyplot as plt plt.figure() plt.plot(obj_wave, obj_flux * sensfunc_out, c="C0", label="Observed x sensfunc", alpha=0.5) # plt.scatter(standard['wave'], std_flux, color='C1', alpha=0.75, label="stdstar") plt.scatter(obj_wave_ds, std_flux_ds, color='C1', alpha=0.75) plt.xlabel("Wavelength") plt.ylabel("Flux") plt.xlim(np.nanmin(obj_wave.value), np.nanmax(obj_wave.value)) plt.ylim(np.nanmin(obj_flux.value * sensfunc_out.value) * 0.98, np.nanmax(obj_flux.value * sensfunc_out.value) * 1.02) # plt.legend() plt.show() return sensfunc_spec def apply_sensfunc(self, sensfunc): """ Apply the derived sensitivity function, converts observed units (e.g. ADU/s) to physical units (e.g. erg/s/cm2/A). Sensitivity function is first linearly interpolated onto the wavelength scale of the observed data, and then directly multiplied. Parameters ---------- sensfunc : astropy.table.Table The output of ``standard_sensfunc``, table has columns ('wave', 'S'). Returns ------- fluxcal_spec: specutils.Spectrum1D The sensfunc corrected ``Spectrum1D`` object. """ spec = self.mag2flux() obj_wave, obj_flux = spec.spectral_axis, spec.flux # Sort, in case the sensfunc wavelength axis is backwards ss = np.argsort(obj_wave.value) # Interpolate the sensfunc onto the observed wavelength axis sensfunc2 = np.interp(obj_wave.value, sensfunc['wave'][ss], sensfunc['S'][ss]) object_spectrum = obj_flux * (sensfunc2 * sensfunc['S'].unit) fluxcal_spec = Spectrum1D(spectral_axis=obj_wave, flux=object_spectrum) return fluxcal_spec ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/line_matching.py0000644000175100001770000001062714635037352020557 0ustar00runnerdockerfrom typing import Sequence import warnings import numpy as np import astropy.units as u from astropy.stats import gaussian_fwhm_to_sigma, gaussian_sigma_to_fwhm from astropy.modeling import models from astropy.table import QTable from astropy.wcs import WCS as astropy_WCS from gwcs.wcs import WCS as gWCS from specutils import Spectrum1D from specutils.fitting import find_lines_threshold, fit_lines __all__ = [ "find_arc_lines", "match_lines_wcs" ] def find_arc_lines( spectrum: Spectrum1D, fwhm: float | u.Quantity = 5.0 * u.pix, window: float = 3.0, noise_factor: float = 5.0 ) -> QTable: """ Find arc lines in a spectrum using `~specutils.fitting.find_lines_threshold` and then perform gaussian fits to each detected line to refine position and FWHM. Parameters ---------- spectrum : The extracted arc spectrum to search for lines. It should be background-subtracted and must have an "uncertainty" attribute. fwhm : Estimated full-width half-maximum of the lines in pixels. window : The window size in units of fwhm to use for the gaussian fits. noise_factor : The factor to multiply the uncertainty by to determine the noise threshold in the `~specutils.fitting.find_lines_threshold` routine. Returns ------- QTable A table of detected arc lines and their properties: centroid, fwhm, and amplitude. """ # If fwhm is a float, convert it to a Quantity with the same unit as the spectral axis # of the input spectrum. if not isinstance(fwhm, u.Quantity): fwhm *= spectrum.spectral_axis.unit if fwhm.unit != spectrum.spectral_axis.unit: raise ValueError("fwhm must have the same units as spectrum.spectral_axis.") detected_lines = find_lines_threshold(spectrum, noise_factor=noise_factor) detected_lines = detected_lines[detected_lines['line_type'] == 'emission'] centroids = [] widths = [] amplitudes = [] for r in detected_lines: g_init = models.Gaussian1D( amplitude=spectrum.flux[r['line_center_index']], mean=r['line_center'], stddev=fwhm * gaussian_fwhm_to_sigma ) g_fit = fit_lines(spectrum, g_init, window=window * fwhm) centroids.append(g_fit.mean.value * g_fit.mean.unit) widths.append(g_fit.stddev * gaussian_sigma_to_fwhm) amplitudes.append(g_fit.amplitude.value * g_fit.amplitude.unit) line_table = QTable() line_table['centroid'] = centroids line_table['fwhm'] = widths line_table['amplitude'] = amplitudes return line_table def match_lines_wcs( pixel_positions: Sequence[float], catalog_wavelengths: Sequence[float], spectral_wcs: gWCS | astropy_WCS, tolerance: float = 5.0, ) -> QTable: """ Use an input spectral WCS to match lines in an extracted spectrum to a catalog of known lines. Create matched table of pixel/wavelength positions for lines within a given tolerance of their WCS-predicted positions. Parameters ---------- pixel_positions : The pixel positions of the lines in the calibration spectrum. catalog_wavelengths : The wavelengths of the lines in the catalog. spectral_wcs : The spectral WCS of the calibration spectrum. tolerance : The matching tolerance in pixels Returns ------- QTable A table of the matched lines and their pixel/wavelength positions. """ # This routine uses numpy broadcasting which doesn't always behave with Quantity objects. # Pull out the np.ndarray values to avoid those issues. if isinstance(pixel_positions, u.Quantity): pixel_positions = pixel_positions.value # Extra sanity handling to make sure the input Sequence can be converted to an np.array try: pixel_positions = np.array(pixel_positions, dtype=float) except ValueError as e: raise ValueError(f"pixel_positions must be convertable to np.array with dtype=float: {e}") catalog_pixels = spectral_wcs.world_to_pixel(catalog_wavelengths) separations = pixel_positions[:, np.newaxis] - catalog_pixels matched_loc = np.where(np.abs(separations) < tolerance) matched_table = QTable() matched_table["pixel_center"] = pixel_positions[matched_loc[0]] * u.pix matched_table["wavelength"] = catalog_wavelengths[matched_loc[1]] if len(matched_table) == 0: warnings.warn("No lines matched within the given tolerance.") return matched_table ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/table_utils.py0000644000175100001770000000320114635037352020253 0ustar00runnerdocker"""Utility functions to parse main NIST table.""" import numpy as np from astropy.table import Table, vstack __all__ = [] def sort_table_by_element(table, elem_list): """Build table based on list of elements Parameters ---------- table: astropy table Table to sort elem_list: list list of strings to sort table by Returns ------- element_filtered_table: astropytable Filtered table based on inputs """ filtered_table_list = [table[np.where(table['Element'] == elem)] for elem in elem_list] element_filtered_table = vstack(filtered_table_list) return element_filtered_table def sort_table_by_wavelength(table, min_wave, max_wave): """Build table off of wavelength ranges Parameters ---------- min_wave: float Lower bound wavelength to filter on max_wave: float Upper bound wavelength to filter on Returns ------- wave_filtered_table: astropytable Filtered table based on inputs """ assert min_wave < max_wave, "Minimum wavelength greater than maximum wavelength." wave_filtered_table = table[ np.where( (table['Wavelength'] >= min_wave) & (table['Wavelength'] <= max_wave) ) ] return wave_filtered_table def main(): """A little example. """ t = Table.read('data/line_lists/NIST/NIST_combined.csv', format='csv') elements = ['He I', 'Ne I', 'Ar I'] sorted_by_elem = sort_table_by_element(t, elements) sorted_by_wave = sort_table_by_wavelength(t, 2000, 3000) print(sorted_by_wave) print(sorted_by_elem) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1148734 specreduce-1.4.1/specreduce/tests/0000755000175100001770000000000014635037364016543 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/__init__.py0000644000175100001770000000017114635037352020650 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst """ This packages contains affiliated package tests. """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1148734 specreduce-1.4.1/specreduce/tests/data/0000755000175100001770000000000014635037364017454 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/data/transposed_det_image_seq5_MIRIMAGE_P750Lexp1_s2d.fits0000644000175100001770000021450014635037352031126 0ustar00runnerdockerSIMPLE = T / conforms to FITS standard BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 387 NAXIS2 = 44 END ACV^߿V^j꿯ypyt\w0BlA?BrB6G.A*h8§_;$E[B5M>B0=U¾­XB]A%N*nBA@: `86'‡CCnյ8,nTi2 )¦ºrºyB njˆ?b·yBm/IBdҿ>xUhz‚X ]\ŽÄq9T 3(iҕ:L°—zlV])}t”ƒY)B~n@AxZGUxɪCڌopLBNb@€A?TQAUeL>hšcLdQJ-DlYK/_3A˗7B[~5a@E/ BA@O@֓jV@"0HÞ /0@eDV?D:G|'U}7A_A|0Ě??`eD) v$†k7ҍY/o@js#A&DI2F6dy}RlLBL@axAsA0@d /+~[Jz@5'tsDpX b>*oCV@֦z@rx?g߁{0_|A@M@p?G|0h/'/c [)7y/@!F\?4w@д 7.@Ǣ?>;@5T @s)< ߀`"W4h!w]É H jÉ]»$*BP%:On:±=Mv³p,๭ÓS=ڊ‡?!…D[oL|\3Fq@*oª5V)¾^ FQBBrďq—A+¬ZpW_gxYz±Œr醙AN F§:YGV‰WXX6B݃C? haL#yN3zA Iz ;`2l?iF d—%B4/{D)1CDBah]@Twb‹)?:WG *@3I46/@A=ȂA-)A^gEAGm۵ډi?ʊ..|9d;KmAǣ`hk "A;^ \bc,>}A[A-A/SثR}P; EfVL@FA%.9>/&#eg?2@=@-8 >vhB;vm@DFOY&@U@ӿyr>?8`%`tEAٔC?žA @Ĩ2@&ei1Y@Ʋ7oF?t@.+9';@s@A=*A}[܁\p2Vbߏ>R.&^@g"@?@C>Q@-@ /p@@@=EG.V̬e+6j#>@+S5UOfs7r²Ð%mUµYXA}9BMz²^m-?@!A~WB KnÀ$8©A@rCQ¾VºfAP B%I8ٹ YH¿K9wXPAJ B;h)JsG`'_kBQ8~¡cڷSAKٺB$!pA*5@5BA]!)>B5Ad f֎2Z‚n€ƷA1B>BA")xPA>@BpM#”BB@Ur K/=AA62Yg@hac#?iG#~B2WA #1m !cek@ AKRn [% &eJYb܆A[]uAyW\Abw%vxvADX}")?dA I@|s@ulvA%UA@rD[aADAЕmFAcy[wAX/AAKcln@r/"iG }AH4-r@ K? 1@X@[BU.>@3@Q+@@,@qAٿ@ӹ_AAֻ&q!YO]BA=wIMG>") @ܿBAw@v[6?E賗>NNf#0> @a ~2A >^AcIu1˿?8MZ?1? >ddK?f-;#>2Q?j?y?@'WPA1!Al3-[cW B ,3QgI+C CC«94Cž,@SuUB#[0¾EžGj]w5vž¦ B=%A̫¹d\c ֳc&@9դDg4APBH BD:yfKp,=QA@dwA"#$B|1mQDB_ zBXPAE>AqO0Ae2ר~@lr{@jA"Tۇۿ4ڽWI )~. A ́@ E@ᅬ[_@jlg׫N?G?A9) +AlWA֯$ĀzX@;@ A@vA5I '$ba.U.;@= @(@ѡ{AwARB~d.@Rs>BQAŇ dO@I@A.Aɱ ;v}x/8+XBOo@X8dYMX@>e=6w@}PUfmC@GM 4@si@؅g?0䫭K'EQ?[A*?lbiZw{?'@k=䠙SR?Y9 @NSBN‚J#kBԏv<4C~ OA/k´C#BŸ3{Mªe|C\]@½i]ԮRlݶ"@OBA7w™y۵ w?PR2xBTn &0 iB goj/' { ¥ȅ¦?µ0 FŒB0q&@nkAQ!A[µdQEA>}LFHAQg _Œ™=B%A1B7Z`_`:A,M8OU=S4h@>BdPF~}J&ZG;P3J?-g#P;AQ͵?(٥@Pf&v^^ \r_#s~Al;6>2|Cm`ULbAz8/19*[d,L?Mե78æ*U@H|r@-thZ b*|V&@!Bvqp0܀&%: 0bu@A&AY!qA?ږA?ZV> w(j@ihep2U@ JlAAQG6Aj(P^$]l")?85AAۥSA1i@M=tXH&?ujhE:@ {ӂ\@jR@2@e?̵=9c ۶.B?]c<͵»&GúF#~Ðy-èg;7U|½]5)kD82*“j2&A2e¦S\`AMB1"’O߭– ?9B~ë@7vzvnP_@Br8X!c@C OAAA}BCBFO@A>r‚Ii…}B*O2B>@N KVCXoUs6z™6yS@׎4A?M3 WЩA„BR-ÍBDA|88  |@£J-AӦ\@{6T䋲_΀Ok45s6Y@0+ʖ[HTAEB4dA-PAIbWBl1/A6@pb } s}@#K@ BtfA?ɷ]O B.e˖AyAĚbSd@6j[`^a7A>AJ3φĆ@\@ӈa@3(V@ m:k iXmb@|@m}@@21,$p7wATF@rт67Q} L3~ )\"2A.C_@I9@ў MvU?&@0@E@0+ A=iǿ|`gH'aAjB~ In('濖*?i/?[@'@G* (˩@KƼ4ߎ@U?X_uI?JM;@Z@wA(T͓`y/VۇIFE :?-@B*AmÒn,]ÍnU3u :/"?!'B3]wxB%D|̻¬`AHqAwp^Õ&AfIx",0CXmA3A2J[œ]sºBvAt<b%4B&$6p¿(.rBB4 )U7A=5'„,raKvA:ghÊ'e ¡T1ŸPCĜȓ M‰A@a:£KpA"R3 BA |"LBdB#'SFBqA@AyA&".4G43@kk=CT]BA }WB3Ao]B KAeBe^UBW[l0A C#OA >@U0@9kJ%1S@@zA?xFUHu@?BCI@NȅA4zOz]?Sz*j@ 9ATHKQ@XAgaJApA ?) ~R)}>ABA@6o*@eJ?A,uA9Z07 (zYƖp"6?}AA}@@F +c?3r@I9AT5A]'^,>虠r/?X?&E2JPݺǿA|_DA[1ËA|]l^0Bx DP<%žВ~BC]dCL|Mih/}A6CbCmC4#BgBѠ@Ÿ@›EB …`>%+B' \\Q >&A= BX ŸLG8fM–B\?[Ef*A@p!BSB;6A?A1Bu}AGd…Ac:B,+8TX{>}B yMA]?ڟA>4@W#=A{H@th+o!Yh)X #@~1BRDe!?€Th‡0vEB+ F6s-@=[@MX t RA?@]f`LAAF}O~^ӫM?{ɪBH@_gB)̾yMuGb`?@A A@BxK B<\?"xpԌVL"LcAdr!@LiZ@Sx?AF=khYn ?2Ig$ج>R5nݽ!7@m/P+O헀')ț @}&Ðƨw¬o&CnCl/*Ð@km&#UwTv TrB]DU=’.D:Bi&"VrfAP'"BN$yU¢8&f@·#EPn"0.nA´: (*'C0gBXSCAoZ8?doC5AȂ A§\A*hZ­PWLz#԰p¹kM}n8‹ t[k7B^~ozMOA~c)A JJT1S3CU [iW!Q,e[mÃA($B›71ucBGI3>*c j+"\SKSoW8bp9D@K!Gʮ|-@0Uj(j@tAP!A¬)3FG@ \˾AXAx.?n@KTk2Vǰ0A/AMByr8A#բA"=n@q8k+@:Nsmؔׯj?cGwgp¿A3-~8mC @'hbZ&tmB%m^@l,# \'a= HTE)BQA&{~€?"eF=,Bp€)C^)AGA`Tm||RU+; 緿%~@'θ4<.5yOZEA:fA!Kn(+3*fbԿ" wь{!<@b҇@̘FFh@A0??%&nL?+Bl|u.)?6kgoë?=A;6Aڮ.~AM#=cpBA;]j?xAG[QT)U4 o1?yNB@@?|Gt> _?N6@g@QAm3? ,x?gA2 J˹JAW]"ȝOh>AlSAz8eZn_@nL6ʕh$$kuJ@4Aǘ1?ӓ9@ %8&'ը#U}AR?c?S#߁ ‡&C3ZD §wӦ1 9BaXȢ?UBB4=@BG>B?8 Gf:M¥@ 0BN 1vŒov.B-AxQ?4o A6 B-[uHb JZ’tBY^B7zAt@-XB+0aXB :]A}RBBv ܖA}Ab…B8F2^?²B¤qϾNAUo~uBBtWA:z(`AAḆKB@o?@I|“rʝBD%AH)yj\3bA@z6Z>-lWxT3BJAm A'@jp3A$$Baj nB*p`Aҏ\Aga_:Hdӎ+^A0B+~ @ƤAAZAPNvA@俽΋@8dp=xR@5qALA>iWKJ_*`dc k AWBv%AZQ@H@y[3d$ |۵9FA+^yA a@Jin|V@9-@BAW#@@9f@ˏ@)@2ο#^8S'U@@A !TQ=@#r8@6翩@ʵ@W@H=ʣA/VcAžo͔jn#5|eJJ`yL BgÎcE!NP9 C:l~Kѩ/BԼCBDwFC BÖ|pB՟AA“{N kC-kRJrhl8B5P RA'! qtB0q{@;Ac9$4‹ySAB8Bi5h1#A 7@AgzA7'®)DžAI5nSCPyeUkwA 02BAp1OY"pxA+AAx͇ ciH(w)Enzw@%AAYw*6g*ªpªB #m1^}A2z@ }Z-t+B?2D@Hp4ͤ">y>A]P)xA]uBCָjBA\|~9FAA qm5A>F䬲xY |r&%A@y~k ;b,7@eݿ?.A|AB5@_5?u.?QAKq}A 6Lh?i@p`aASǜ@ТB\*@@}AT lc?6}&:2qAy=^s>'"}XuVF\ =z]@+pNAf@t2]T>ܬA nu."@w_ &K!+@ ş@RиNp#k-@Gd>ygD:λ?@$M;%5b! (YCAB 2A?4 T@7 @G0A@ JE9M8Az?_?L`3x/ku?1U9ègbVAX7ê]]ps:RIr,7`wdÄrA ENB­0>p=µwY~UBBQP’RB±¢kA8&OŠ&![qL ¶†lA-c[āyzB0BQgr§#A•‹`P(BB:@6"kŽl]pdBJ"B@8{hH=8\+{z1?.AuNw^KQ HZi ?PAD"C\5wA›hH .D B ZVU&C.T=CSÂBiܛB!r»4OSB²„iq -1>YhBRt6hXBq0Rx²&—ԘPK?Ϙh#¯£ 2A|AJpBAB:UB?jy@aR\-¼ A/V BJ™8An $MN!HA‚-d1@W+@Cu&6TIÜ@]A\i?,7.@GXB B(@U̇"aS @pFA,iq@P#9 J@A^?@Hl@AJj= @@uB?n:?@.@6@bA[=H6@ں,{l`r<_FN@I˧@`?AA(c3 +sUXR}?d>@ZAHzۥ@@ƈuC~Cɂ?}kBv-C6™7?BlBxB{k«:Loušj`1¡<’^%C7K|YY9["^GDkwaA(A*,?^BCSˆ gBB%v _%y#AޱA+ڤ£[rA@BLABBf|||1/AA @~Bn9A@„doBdrBNl@wA< AVWz9XB'z&h A(A 4;@+`?i2Ar‘(LA"=QBJw##B^[9GA{V3AD@zf[]A)B`@AYB.WW4F7Tr@UοuAyP$%[B9AA4@QWѡAIɿ$`@A@ATA?q( ޻0KvwA(h@*&DiA'Mi@k@1uZ8^?K ?Q.)\k$@>㽺Sw?C@ɗwAKU ?M+Eٚ?@IA9HA9f[?`A UA@ r0zms@T2xW{cz3h?d?Fg6@$,-?.@ִ?_8N ?FH@ƣl"z>#@`;A@M* '@-Ŀ.Rle)/ÐkZ{HBi ;jB drG)""`5BHC' åd@d%nvJZ_s:^=˼°b¯A S!CeZpB[[BB`-A$%Š8B&lfB'NF2A#&B-C( §&~ɟpBB.¢Œ?KAvS"©]dIT_?+`BAjќ„!]d2^VBzt+:;A4J$[BD@D+AU›=h>"qo, iAMAq/ˆg'7)AIE\_1A&u@ :pV›BtS=A-Aj5셿^y{A AF%R#x@DA+(@_!NA~w/7er@{J$A|ZVj@ϲA?Q{)CAAqfY@7 iGۨ@GӘ7@FUwQ#"AFՄG@̯0Ad7UH@@DN@M~F0<<?)Ax@jBj@pA@- q?'72x>ڿ6@ @G?BZ)4Bô-06ѮAc}»B$p)ª&fB<~BPI_WAf"OzGT([G\]BeO?^DFAw]QB7H{AGÁXF"9“Aa¤­O]--Nc96.@cÿ[ 4@SA"{Aq²ž^AAy\B¥S@CpB3 YBbBE1BB|:e‹PAmB*B6 LB%AdA5B%B3,`( B=BkAJѷBE ?gA'B4h)L‡.HA{ZZA0NW.^g@r!A!M* =WkAfк\?2@@6TTtǾAAƿȤ:a /!@ 77T@B @Ǚ{4>wp}ֶB^Z{p@@/黳A͟@ %Z@B+8t@A?IGBJ=@Ȓ?:,scAJ@\ziA*\E|O3C/hwZ*c?aAY,aTGÄWii\*@BAЕA|;?5A?}!@@AKu)A@1J n4@.UAN<@fAKA5|Ay[@Lz@(W@0E@E+ 3@G@;EXz-@j?ܔAS?CxBqGDBˮAo@g8|AaPFAsi¸I>_]@tVAA=g:]lv1Bp= B@!Ajk(A u( rU[ zB*eNBkAQj)G+AkfAAAک=zQiAQ5 YxB1@_@o`$y|:&8@]AA#]Kn4]1Avo#AO@:AA% 9w+b]@JrA2R] u4BAAv˝@3Bo5،F?yLv^? 1AC?D1u|т#AG<@0bAs$VB=@5A'odkAb1d@i8@Xf>Ȓo|DAw0vfP,:ۮAB }@-H0_ Žmg>uA v!0ţMi2N̒R@&QpqF@IAK1Nɮ!i.?M?K&ANG?e\A -@¿1GVRx&9)A* ,@!A_hq4@heD@>?#¿y'e {WG?r$F~>o@U/k>P@$@YHRºDX%S`GABsQCRMoBAN"ߍF£<L,Z/@/5F),`B^3Ŵ¹_CXA@F'+&*2OC~4YCPAoÐB>B:DRB֢d*,'p̍=3&B0& pZ@/gqvROvwe¯GGT¥]@=<`l`ʢ%vBvL+?pS=xvx>[Aw;mք<02IiA;5vy=/f6‡d"VI¸ĭA@iZ .OCi3O,PNBm" BdAr\=Q @}V.HSqk@q?'YO?/hMAAD?t" 4J?n`-T?@[Z@-`(z7.L"S@$9RO@[?A'u{<ȁ&w@ʀX1B,EAuÄ/z\‘BTpX;jW^Ȼ®yÚ5}Yoǽ¾ >BB: L+VjALÌ}^|C7ٵ5BBx…9[¨s<7AG©ߑ2Q _Th)cBkU|B$;f@W\€s'†0:hBs'/A U*Rv .A2:A9+$¡8ѣB1@sGj|AAwh #|Qٽއ$X0Bא jS)hACQ//1I`@>yAefӏ>X@?`@ B"{(@^}{ZRrAS @\(#A7@(=YAA0Bz?,6+C'+7YLA*X?X@\l'bω4GhAZ,b*R@s2z)a;{P/v }m~A\?xU,/^?왡>%!Y?SMc2A`A^)]?P4\BAV( VjR{C?-x<@'@Hy#@UԼ'?N55b@_pY 6]?y@ ƹ- !AFQXdFZ)>E<3= @ m?/q߾m^i@U@Ȥ:dΨB+&vsqAbhfI·uAT1Bl3oPcBAB&80B'LÃBc#qB?RA0&b¿s?X@2>^"2užSBYA,v-AA~j.FT€ЪAB/'‹/qtWBM?5lA'mWcA@+#Lm'^ƒ_)A"QFAw_A.eWE>U9WnܿFAZ)A@HA:`4nARq,AG[g@ (n AWI@(E@fAW7RMuApA2f?.f@T@DA~uAAg@A['@d,2p@.EAY?zUHA?k@A6B{Aun3K*&AMB?wL" ?xS?˶@U/AA!'zUXS@DARN<ؑi7{^@@Ev'BA'AxAŒ)f@k8]D@0,[E@s3> A@A[۬A$T>H@vAA&}IjnsAT)0 h@@0^,@nWB}b+W@]) ސ?A{7c$A4Jyϡ?!@NvO@^7?@sq@ >K̩?_;A@ջCâCC~kf( ‚&× Ѿho@;Sº&TA%6›8B_BB ABAŒ`k;oA=Ba3^kA Bhy3~m fGZA/NAAdQBAZJ!UB;AsAE>@%A Zvv=S/A ^̌RAUZt%"A39B€-h@NB8]C!M5|\J}hQAn @YAI;@S@c8kAA& -i@b$>Wظ@Qb@Ɠ#A|A@74A-z#@?fA@`>sA$@<|xAEkÌ&HK;XCS4G®pxsi?fMCC9†uPCC7B@ܡgAVƒ!y(zD;GAfѾ$Gpm:c?j—'A65B@yWAwB_N!AV4aıEªŸfA[}@@-Aj=rdt?&oHྀ>eA$?=ɛ@F@mCA\?ό?&RA?h@[ At@MJO?:ArjJ@A@(?A]AGA AErAϘANKAoAS zA'A]xAmA4B bAB9 B28BhBVYfByBqB*B垵CC g_ClQCbC2qCBBgٽ# gXB(.B!N¹-A]BZa·¥Qs’B%#BB7DmB>Z?JUil"FFCŠnNƒ[oŸDº€BfGRuheB4ZAA#BAG tQ-]BīXdBX F曞gKJٜO|r¤";ql,+CȱšCY1+sSV!2A˜z]A G3C8oxIB;>{?cAi@rÆAC xxy@Je@0@]|A@?9&A("٤gQYH2v_&Q@1B  h@&Au"m?=W}BAJ Ao;ZYdhB r e{E ]'A,]ӷeA$5Z@aEGc-@A\8@Av9Kپ@~UoىA=OB5cA@/A+A$@/A,NAkA1AALA`gnQAy(FA@NABK@ظx@Rz#A)AtAB BA bAA/tAABF,A! APAV/AwAOiABcBxB,BHB"BBPB̍BqBB@BCyCCC.C'MC.CCEPC6XCGC9[XCYICH>CnpC|CCoC^IC8C۸2"B{%ZB>l[C[BIlB̩C)Ž/Cee@.ŠgB,B'JG%Bbn8B/S\AʉKB4B}BZCSPC WC|BC9*DM~µ`cŠC!rBBPBT6BdB͊.B%BB-'!B/A!MDC0[BD"B1! hB9NOb@P;BW&A%B>BBmBH)BvZAtBCB>yBv!BSBSiQm@sA6xBABd8BB"DBI,BPBBHB`oBWBKtBEDBBBBCB8M~B B!BC+WC%5C%C bC33CGC5,CCK CdPD=jdDPDVJ]DeDuDfDoDD]DLDـDDDDďDÝD8dE IE9EGE!BE6E>E[EhfEjEIE)EE"EEIEgkCr@]C*B DCźdB9CCCAaDCCelCCC C)xCkhCC[9CCz Cy?C MCC}CCC C%CnC*CQ$C9C4C6C7 CDzCw^Ca~CV CIC4CDC]]CCC{3CC9CCdC(3C! CAC&C6CC0?CD1C8COD0D D1D^bD ,PD [D5D oD :pD DD ЅDRDpDKD"D2D'5D(KD%D'D!D)ʥD.D+@D0kD-ÔD3D6SD9vD7AD@JDASDF WDHרDOUDPDHDMDZDYDcgD`6D\DjhDb1D6DfDXaDD DP:D,CD2q D~$HDQ8DSDI.DfD MD8D6TDXDڿDaD\GDSRDK/DAOGDFduDRDPlDS 1Dx|Dn)DfB~Dy\D\DDDpDnDEavDisDxD^NDEdDy)DJ.D@Dn2CD)DDaD~DՏDMDk"DvDtD&DRDdDxcDDEDeDDdDsDkDrDDpD}DMDDz7D~DPMDDxDD3DuDJDjDD|D{JD\DIDDmD5DsSDʨDЭD_D+gDDԒDDD3DۂDagDDbDDED{2D DdD"DpDD3DDoEDWEfEE?EqE]yE aEEE E\E:EDExE1EGE!#EE(%E%E.bE.JZE.jE3gE4E:/E9E;qEBkEAEI2EFAEGoERbETEXhE]E[HE^E`FEg{EimElErEoEpjEuVEz@E{E-E\EVEEpEo#Eb#EX;EEwEqEEyWEk:EEEBeE EtnEE`+EEsEڲEYE?E\EFѷFBCF HF IF FFNbFnF[eF$F&F)אF/F4BPF:QFL}$FTեFTFXF]cFm5ZFrq"FwFzFFNFFFՔFbF}tFFȪF9(F-F G^ G ,UG 0)G&vGPgGG=G7SE:BY[DDD)SDDRDD3DxDD\DD8DDкDnD*DʹD~D"|DfDDD_,D[D߉vDD7D+DwDDDD D};DsJD E<DE$jDWEDDE LENEE6IE .E ǻEENEbEn EDEOEIEjuE' E"w#E"(E(E!rEE&KE!0E+-E"xE'SE)p.E%^E-ŸE)`E4;E=5E7E44E8GE9E9fE>E=FEAEE<3EFEH:EHQEOzEPEPuEXVETEZER?E]E[)Ea-EfEiE^EmEetEruEq ^EvF EsE~CE9EPE%nEWEsE6aEEELEEE-E8E E1EhEUE|E/EEחEqEoEKE7E E EmNEbjEdEESEEEłEņ1EHEˉE7E7=E E$EC-E|E5VE E4EZEtE.ExEEoE^ESFcFYFSF ~lFMFFF#|F%zkF$BF%F)F+4F.gF2IF5gF7EkF;JF>GFC?FJFNUFOFScnFXF[ڮFaFhjFpFy F~HFF#'F.FYFlFF+!FFmdF"FoFSFFFcFF FuF֝BFbF"FFvFbTG6G G)GGG"G%˂G+G1xG9!GPoGGYGY&$G_PGfX4GaGi GEwEBDDΚDDDLDq;DލDXDŮDvDcDD(EDDRDrDE FE E&DE EŁEYE GEEBEtEEEEE\EEcEE9E-E 5E*E&}E'E;TPE-+[E5 E*Y(E2E:9bE@E:E? 6EAEACE?!EBEOEP"xEVETEUEY/EX%lEXäERFEZE^E[{E^Ej"EgQEfEdEue!Es]EwfErɉEqLEpEzKEv EyEwѤEqEEEsEE"ELEE:nEEْEOLE“Ey3EEE%EEEE6E(E3EExEmEE[EnEE)EZOE`pE+1ELEeEETE£EmEEǶ(EiE̊rEiGEҙEӶEׁEEEIE₌EE*PEEOE&E$EGEEFFF,FbFF +FFyF6FFghF|F$F8IF0;FF F F"dAF%iF'F,*F3JF;*FD*+FL]FMoFL FMFSX*FUrwFWwF]F_އFb}Fg,8kE=lE@E<{EB8lEEmE@E@&EJEH'ELEKEOELߦES\EXo0EXFE]E]E\E[EeŀEe4KEaREnNEg8QEsEqZEoOEtE{ECErEE[EEEyEyE\E9E4|EEEEEUNEVEE\EiZEEE8E{mEEEEE4EE`EEME|UEsELEE!TE EyE͌EF EOEWEpTE޽EEGE E,2EpkEgE}E"XEEpE2CF2FFyxF1FaxF|FFF,F(F FIF"1F&+F'BF)F-J.F1fF3F;_F>!F>hF@jFEenFJvFOlFU_F[F`?FbFdFiUFm{FpfFq_F|YF FEFbFFRFaF+FJFlFF?F3KFpFFgFFLF(F?FFjFgF-G.GG?G Gn G#G)G)4JG/zG:G=G?#G:EBϯD0D`"qDPC9D@.D+DL̑DZ DK|D7D7uxD3 Df,dD^EDamD&TDQDgDQ9xDD DVUD\(DW=DTD[DcDXD"DD|Dx\4DcyDaDZDDVDDvD-Dz#D_DbrDPDDz(D#DiLDr 6DD DDZ DKDDn,EDDaDDDDkD&D0D̓D D-DDȠDDDn DMDD?DDDZDcDD̵DوD8DD~DD%DDrXDD'D/GDWDD .D=DƞDv#D_D,DьDvDRDDجDoDчD(DDDmD1DDD|DD |EiEvlEE(E S{E E E thEEJEEdE\EGElEYEEE &E#E$oE'E'E,E/E0E2E4E6cE:E>lEB6|PCDAC%Ce0E0KC#sCxCCUCCN,C9C#Cs2lC̀Cg_B$C5CCCxoC[CC 5C]dCCd_CC CACCxCUrCIiC `CCMC3CC]CUCBCC[^CKCy>CPCRCC KC=ClCaC$CNC{̘CCCPCCC@CCYCzCeCXC9DBCvCTC uC9CCCd]CCywC*C~ CCCZCCC%4CC]CC4CCCC%LCGDWCqC#CfCDDDJD wD DD$#D dD DD DD"GD DDGDFD|DD' DBD+/D(rD)gD1D"D4D7D9_D0ND3rD;fD;4D; DAЮDODJ4DSBDLDKKDMDTҮDQBDX˾D\~0Dh Dc`Dc>qDicDo3@DnDdDwDzDtDwP`Dp*DD9D#D\2DDwDWDDDD^lD#DTDD Dx@D1SDDtDVDDƋD DtMD~fD֗D23DˆDD2DEUD(EdEFELE6EEEE";E'9E36E5E:GE7E<}EKENEWGETEZlEgEEOEEhZEEDEEeEWEEpEgEœEF-FcEE[D1VASA%}C37n@4 ^ClCOYo;/$BS{Bs CbBTBSC3K—AB|ƒs]BxBB`G2sA&?&BB;BzWgÐ?•HB &BؠC 4;B?<:@ZAB)AyKAA>B LnSo_BAo^BՓB5[BZB6'e/wB4JvBBbBJL B$5BA A=B+AKaBBnQAB7;BBO{RB@A8iBc;@ϪBBoAWB4B<5AJB-@-XB iBh,B`B>YBlyBq`BtAzBKBڸB8B/BB}tKBB_ABBqBB)BTBBbF0B9m"B-B( BBB{BBBeBpBCKGBB BJBBΩBtJBKCByBBϛBnCBCC2CDbCC C ;0$z( ~A1A|R A#پ^WgϞAXAȑyB$Q @ A{;hAPAAyKP=c?A@!V=s\?>%A&AAF:C@wq@sIAp'`A8ADKATh0@Kiп,ȫu@EAďYAo?RZo@"gA9Q@i/3A[Ar/D\3@UBp AJ@vAfƾ-sRb. AA\?]A垯A|?=o@"AJA5ApAC?LB@AjAYAArAAԬAgB BZB0BH'BqBBjiBcA.AݾnB'ANB:ݑBGBUBF+ByBT 2BBMfBBwBi?B/BBTBĴeB@B+B BA{C CC|C*OC)CL-cCNCvFCHCqCCwCCC}CwCLAz>B9žgBb$aHCB\CV^Ú@D ‘:"C-בA BpC#B\ »6DB-C;!tBO@ܫ) \H/&# kVBF%Jz6\]`J7RuAqVḼVY_ɖA8P Ibn*y?ŏY?o(4@{cnd"A .޸6VA'&@օA^k5As#K?¾yEE2?)]W9@t#\#@п;]@7]rҖ-;A^u=j@74?ղ)˽yI@\!>S)@Y@JAAM@-@ב@@E#@m'@gAg@cA|AAvA{Ax*AA1AB B RAB%A/A7l5`=Ϫr6~FI),k-gC\B;BF 9 Âm4!CѾCX':AWR¤J†@<=f9>¼ [«6†85C(Aؗ´duHOAuA݉ZC'F ݶ‘ nAsy{VBe˜@$Y]g§˜9?}PR@ Y£Z@ѱ*8C{0[B޶6ȏ[9zA}5A ¯]CEvBf\N-5%r8ڑB^:eAstAkB@(B4ࣚ}@p5GD@@cA j;?B2za?DԚA?ClC@1KABeDq\ҎlCIyAo0}]YzAF W_I[.̲}`IAIB&\Ͽ$u@!,HA<& E}?!ru@T@"?#޽=޺@E<Č15`jcA@ ;M>OYA`A`)bl۾Ź _p6+s?iRA )XA~?HFA@=C\@ @.>@@QW*] {d@ GZ-7ؕ'GA,~> I=U=e0H>|}vQ@]A5`D?r"@7?Ak,Y@O?_I߁0l=YB`aۘ3 S@A4A+C Y)B4 B!"A60zBrBCF*8=B+B8 =W% $BCv"8A1N-54>šQQA?{ۼB6CC;AcÙP8 E}Sa.A"{Au"ï%BZcpBB\5AGh%9An7' ŸeDm9J¦4AA.2(ZœZAQSF{A}#A@$AD&BC]ߝAmonB<}g,S,¢AA1A*Bڴ/tbBC<fAhK\NzG@+@;iG=/r@9p T@42?7fO[j-ECAx-BQTDW…®c-;S¨ABjABu:p¸ A;o-«7ޠ>\²^‹AS£;|[Y^…e A,n2C-BX%o8[ABA1š&yBU$#$?wr M<5{:?PB:¾4„UZ ^l;Bt2f^`'2B :@M,WFKo b)BfkB$&Aw2Bt%QAO?WGngA~XJrA(r&-mA PA.:zA€[cQtA+@Z%PCLNAk?Ƚ g^@WA^AtsrˆdQ2?%fwwdEl#bifXWA6nA9LAB{Am)Dh4~0AL'AiU⼍SKAZAHCZb2A(M+Y8*A?hbJkno=>??drnA\.#$ @_XTAv2˅WhBZt\@/Ay$Q5d;V AޞD:.@6_7LAqt =dͽg8Sz"]S?:̬$Q@[:~,t̜ Ateb\#߄])@@\UDvZ ;@?TF<:.DB. [~2*B*;BE7;BU}v5A kLB{-ì\tvRjE)d@¤$§-åtš”f[-5aTH?`Cs|:¶9!{nœB)m{B )%B<Œ ¡jB#´hϋ¸6ApNA  “q™=CBB}BϫBy m— AOY– ,$BJaIsV++lD~B%‹mBV*}ov(B@S'U“+>o@LA:Af>p*yBA:@WA\b@#?//*X B=v?鿂B[^GBAG@(&h>uj)8L//A4w>}VA(2=3AvhO*=UA]@d(nPYX@Nӡ]hf.?@HA&@}l ~A^f1P뿺FB@}_Y!?z?kˇ6 u4Sθ@>@@(3[?1 @nWM `;'?!#+A96@9A8m#!E('W>}"A@RoVCŚ‮n@sg~'\Ax6ߙlqDu>@b5)T:Kw왢i-ӿAM.տ`Vq`B|CDf´ÆBª|+HaLuDIaHBiÂ[S(ª5|㵝i6\ JNA*;Bn0LSX+zãC8BCƶBսu* (WC440b7Biw^}Š?%b?AA-=y½~AT"TAZB4@qG µ*šxxt½_/%Bh$•mBT˜gQbA_ ‹9Y‡1B5I9Q@FΘyBB:.[w_p:95zR?7W]gA͇J‚MHND@6ݕgrA9oA5VG$,@A*?QA"S 1??/+o@I@A$G\BAU?P \1@Auk]>=”1Ac@8^nAhd@!>A3&@ʵͿV`@᣿.5A{]~"@ @$)bHFI?ШfA+vɘ"RmxB94]37O>=358|"HA` 0@1j>cnCz#d{ó,B 1@0M A .pwB9&~TœCU(<§H7“d/AI2H0@œ¹|B-TABmB (-@m?0B|a$6(BpBNmRN0~:c/i …A76CA.c}AB&mgB@>A tBQ¥,BXy†+q JZAS6YBqyB6IIZ>ރ§kA.@H2$LtC8AbX?V|EAtN¦mX ~A&Cn<"93M80p xU>y!yBA‚ fIBEl\@ 6!ۊTz/Jjlr=14`AB;Z AHAy~YB2BO~B (۸cBMB At8A.;,kΎ@^FAAj8Aɦ \A2BA?F.;JB*,4i@Q>25@?$E{7w—׭dAZE*uAA^A5zAO!f  A[AoyB8@ A6ANh|@@3j!?,v|?ٍzp>@OL V@A?Ҹ_A%2|BG@£@+\8&BafAd&4C 2BEJUl+ǚB\f=SA³&CµB]bBoARr@:d2@ڍCLqr(F俹?BėzBsE^';<#חJ[”~A$BA10 B"BXCA'aBPoLVB3At././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_background.py0000644000175100001770000001316714635037352022300 0ustar00runnerdockerimport numpy as np import pytest from specutils import Spectrum1D from specreduce.background import Background from specreduce.tracing import FlatTrace, ArrayTrace def test_background(mk_test_img_raw, mk_test_spec_no_spectral_axis, mk_test_spec_with_spectral_axis): img = mk_test_img_raw image = mk_test_spec_no_spectral_axis image_um = mk_test_spec_with_spectral_axis # # Try combinations of extraction center, and even/odd # extraction aperture sizes. # trace_pos = 15 trace = FlatTrace(image, trace_pos) bkg_sep = 5 bkg_width = 2 # all the following should be equivalent, whether image's spectral axis # is in pixels or physical units: bg1 = Background(image, [trace-bkg_sep, trace+bkg_sep], width=bkg_width) bg2 = Background.two_sided(image, trace, bkg_sep, width=bkg_width) bg3 = Background.two_sided(image, trace_pos, bkg_sep, width=bkg_width) assert np.allclose(bg1.bkg_image().flux, bg2.bkg_image().flux) assert np.allclose(bg1.bkg_image().flux, bg3.bkg_image().flux) bg4 = Background(image_um, [trace-bkg_sep, trace+bkg_sep], width=bkg_width) bg5 = Background.two_sided(image_um, trace, bkg_sep, width=bkg_width) bg6 = Background.two_sided(image_um, trace_pos, bkg_sep, width=bkg_width) assert np.allclose(bg1.bkg_image().flux, bg4.bkg_image().flux) assert np.allclose(bg1.bkg_image().flux, bg5.bkg_image().flux) assert np.allclose(bg1.bkg_image().flux, bg6.bkg_image().flux) # test that creating a one_sided background works Background.one_sided(image, trace, bkg_sep, width=bkg_width) # test that passing a single trace works bg = Background(image, trace, width=bkg_width) # test that image subtraction works sub1 = image - bg1 sub2 = bg1.sub_image(image) sub3 = bg1.sub_image() assert np.allclose(sub1.flux, sub2.flux) assert np.allclose(sub2.flux, sub3.flux) sub4 = image_um - bg4 sub5 = bg4.sub_image(image_um) sub6 = bg4.sub_image() assert np.allclose(sub1.flux, sub4.flux) assert np.allclose(sub4.flux, sub5.flux) assert np.allclose(sub5.flux, sub6.flux) bkg_spec = bg1.bkg_spectrum() assert isinstance(bkg_spec, Spectrum1D) sub_spec = bg1.sub_spectrum() assert isinstance(sub_spec, Spectrum1D) # test that width==0 results in no background bg = Background.two_sided(image, trace, bkg_sep, width=0) assert np.all(bg.bkg_image().flux == 0) # test that any NaNs in input image (whether in or outside the window) don't # propagate to _bkg_array (which affects bkg_image and sub_image methods) or # the final 1D spectra. img[0, 0] = np.nan # out of window img[trace_pos, 0] = np.nan # in window stats = ['average', 'median'] for st in stats: bg = Background(img, trace-bkg_sep, width=bkg_width, statistic=st) assert np.isnan(bg.image.flux).sum() == 2 assert np.isnan(bg._bkg_array).sum() == 0 assert np.isnan(bg.bkg_spectrum().flux).sum() == 0 assert np.isnan(bg.sub_spectrum().flux).sum() == 0 def test_warnings_errors(mk_test_spec_no_spectral_axis): image = mk_test_spec_no_spectral_axis # image.shape (30, 10) with pytest.warns(match="background window extends beyond image boundaries"): Background.two_sided(image, 25, 4, width=3) # bottom of top window near/on top-edge of image (these should warn, but not fail) with pytest.warns(match="background window extends beyond image boundaries"): Background.two_sided(image, 25, 8, width=5) with pytest.warns(match="background window extends beyond image boundaries"): Background.two_sided(image, 25, 8, width=6) with pytest.warns(match="background window extends beyond image boundaries"): Background.two_sided(image, 25, 8, width=7) with pytest.warns(match="background window extends beyond image boundaries"): Background.two_sided(image, 7, 5, width=6) trace = ArrayTrace(image, trace=np.arange(10)+20) # from 20 to 29 with pytest.warns(match="background window extends beyond image boundaries"): with pytest.raises(ValueError, match="background window does not remain in bounds across entire dispersion axis"): # noqa # 20 + 10 - 3 = 27 (lower edge of window on-image at right side of trace) # 29 + 10 - 3 = 36 (lower edge of window off-image at right side of trace) Background.one_sided(image, trace, 10, width=3) with pytest.raises(ValueError, match="width must be positive"): Background.two_sided(image, 25, 2, width=-1) def test_trace_inputs(mk_test_img_raw): image = mk_test_img_raw # When `Background` object is created with no Trace object passed in it should # create a FlatTrace in the middle of the image (according to disp. axis) background = Background(image, width=5) assert np.all(background.traces[0].trace.data == image.shape[1] / 2.) # FlatTrace(s) should be created if number or list of numbers is passed in for `traces` background = Background(image, 10., width=5) assert isinstance(background.traces[0], FlatTrace) assert background.traces[0].trace_pos == 10. traces = [10., 15] background = Background(image, traces, width=5) for i, trace_pos in enumerate(traces): assert background.traces[i].trace_pos == trace_pos # make sure error is raised if input for `traces` is invalid match_str = 'objects, a number or list of numbers to define FlatTraces, ' +\ 'or None to use a FlatTrace in the middle of the image.' with pytest.raises(ValueError, match=match_str): Background(image, 'non_valid_trace_pos') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_extinction.py0000644000175100001770000000450614635037352022342 0ustar00runnerdockerimport numpy as np import pytest from astropy import units as u from astropy.utils.exceptions import AstropyUserWarning from specreduce.calibration_data import ( AtmosphericExtinction, AtmosphericTransmission, SUPPORTED_EXTINCTION_MODELS ) @pytest.mark.remote_data def test_supported_models(): """ Test loading of supported models """ for model in SUPPORTED_EXTINCTION_MODELS: ext = AtmosphericExtinction(model=model) assert len(ext.extinction_mag) > 0 assert len(ext.transmission) > 0 @pytest.mark.remote_data def test_custom_mag_model(): """ Test creation of custom model from Quantity arrays """ wave = np.linspace(0.3, 2.0, 50) extinction = u.Magnitude(1. / wave, u.MagUnit(u.dimensionless_unscaled)) ext = AtmosphericExtinction(extinction=extinction, spectral_axis=wave * u.um) assert len(ext.extinction_mag) > 0 assert len(ext.transmission) > 0 @pytest.mark.remote_data def test_custom_raw_mag_model(): """ Test creation of custom model from Quantity arrays """ wave = np.linspace(0.3, 2.0, 50) extinction = 1. / wave * u.mag ext = AtmosphericExtinction(extinction=extinction, spectral_axis=wave * u.um) assert len(ext.extinction_mag) > 0 assert len(ext.transmission) > 0 @pytest.mark.remote_data def test_custom_linear_model(): """ Test creation of custom model from Quantity arrays """ wave = np.linspace(0.3, 2.0, 50) extinction = 1. / wave * u.dimensionless_unscaled ext = AtmosphericExtinction(extinction=extinction, spectral_axis=wave * u.um) assert len(ext.extinction_mag) > 0 assert len(ext.transmission) > 0 @pytest.mark.remote_data def test_missing_extinction_unit(): """ Test creation of custom model from Quantity arrays """ wave = np.linspace(0.3, 2.0, 50) extinction = 1. / wave with pytest.warns(AstropyUserWarning): ext = AtmosphericExtinction(extinction=extinction, spectral_axis=wave * u.um) assert len(ext.extinction_mag) > 0 assert len(ext.transmission) > 0 @pytest.mark.remote_data def test_transmission_model(): """ Test creating of default atmospheric transmission model """ ext = AtmosphericTransmission() assert len(ext.transmission) > 0 with pytest.warns(RuntimeWarning): assert len(ext.extinction_mag) > 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_extract.py0000644000175100001770000003104514635037352021626 0ustar00runnerdockerimport numpy as np import pytest from astropy import units as u from astropy.modeling import models from astropy.nddata import VarianceUncertainty, UnknownUncertainty from astropy.tests.helper import assert_quantity_allclose from specreduce.extract import ( BoxcarExtract, HorneExtract, OptimalExtract, _align_along_trace ) from specreduce.tracing import FlatTrace, ArrayTrace def add_gaussian_source(image, amps=2, stddevs=2, means=None): """ Modify `image.data` to add a horizontal spectrum across the image. Each column can have a different amplitude, stddev or mean position if these are arrays (otherwise, constant across image).""" nrows, ncols = image.shape if means is None: means = nrows // 2 if not isinstance(means, np.ndarray): means = np.ones(ncols) * means if not isinstance(amps, np.ndarray): amps = np.ones(ncols) * amps if not isinstance(stddevs, np.ndarray): stddevs = np.ones(ncols) * stddevs for i, col in enumerate(range(ncols)): mod = models.Gaussian1D(amplitude=amps[i], mean=means[i], stddev=stddevs[i]) image.data[:, i] = mod(np.arange(nrows)) def test_boxcar_extraction(mk_test_img): # # Try combinations of extraction center, and even/odd # extraction aperture sizes. # image = mk_test_img trace = FlatTrace(image, 15.0) boxcar = BoxcarExtract(image, trace) spectrum = boxcar.spectrum assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 75.)) assert spectrum.unit is not None and spectrum.unit == u.Jy trace.set_position(14.5) spectrum = boxcar() assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 72.5)) trace.set_position(14.7) spectrum = boxcar() assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 73.5)) trace.set_position(15.0) boxcar.width = 6 spectrum = boxcar() assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 90.)) trace.set_position(14.5) spectrum = boxcar(width=6) assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 87.)) trace.set_position(15.0) spectrum = boxcar(width=4.5) assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 67.5)) trace.set_position(15.0) spectrum = boxcar(width=4.7) assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 70.5)) trace.set_position(14.3) spectrum = boxcar(width=4.7) assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 67.15)) def test_boxcar_outside_image_condition(mk_test_img): # # Trace is such that extraction aperture lays partially outside the image # image = mk_test_img trace = FlatTrace(image, 3.0) boxcar = BoxcarExtract(image, trace) spectrum = boxcar(width=10.) assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 32.0)) def test_boxcar_array_trace(mk_test_img): image = mk_test_img trace_array = np.ones_like(image[1]) * 15. trace = ArrayTrace(image, trace_array) boxcar = BoxcarExtract(image, trace) spectrum = boxcar() assert np.allclose(spectrum.flux.value, np.full_like(spectrum.flux.value, 75.)) def test_horne_image_validation(mk_test_img): # # Test HorneExtract scenarios specific to its use with an image of # type `~numpy.ndarray` (instead of the default `~astropy.nddata.NDData`). # image = mk_test_img trace = FlatTrace(image, 15.0) extract = OptimalExtract(image.data, trace) # equivalent to HorneExtract # an array-type image must come with a variance argument with pytest.raises(ValueError, match=r'.*variance must be specified.*'): ext = extract() # an NDData-type image can't have an empty uncertainty attribute with pytest.raises(ValueError, match=r'.*NDData object lacks uncertainty'): ext = extract(image=image) # an NDData-type image's uncertainty must be of type VarianceUncertainty # or type StdDevUncertainty with pytest.raises(ValueError, match=r'.*unexpected uncertainty type.*'): err = UnknownUncertainty(np.ones_like(image)) image.uncertainty = err ext = extract(image=image) # an array-type image must have the same dimensions as its variance argument with pytest.raises(ValueError, match=r'.*shapes must match.*'): # remember variance, mask, and unit args are only checked if image # object doesn't have those attributes (e.g., numpy and Quantity arrays) err = np.ones_like(image[0]) ext = extract(image=image.data, variance=err) # an array-type image must have the same dimensions as its mask argument with pytest.raises(ValueError, match=r'.*shapes must match.*'): err = np.ones_like(image) mask = np.zeros_like(image[0]) ext = extract(image=image.data, variance=err, mask=mask) # an array-type image given without mask and unit arguments is fine # and produces an extraction with flux in DN and spectral axis in pixels err = np.ones_like(image) ext = extract(image=image.data, variance=err, mask=None, unit=None) assert ext.unit == u.Unit('DN') assert np.all(ext.spectral_axis == np.arange(image.shape[extract.disp_axis]) * u.pix) # ignore Astropy warning for extractions that aren't best fit with a Gaussian: @pytest.mark.filterwarnings("ignore:The fit may be unsuccessful") def test_horne_variance_errors(mk_test_img): image = mk_test_img trace = FlatTrace(image, 3.0) # all zeros are treated as non-weighted (i.e., as non-zero fluxes) image.uncertainty = VarianceUncertainty(np.zeros_like(image)) image.mask = np.zeros_like(image) extract = HorneExtract(image, trace) ext = extract.spectrum assert not np.all(ext == 0) # single zero value adjusts mask and does not raise error err = np.ones_like(image) err[0][0] = 0 image.uncertainty = VarianceUncertainty(err) ext = extract(image) assert not np.all(ext == 1) # single negative value raises error err = image.uncertainty.array err[0][0] = -1 with pytest.raises(ValueError, match='variance must be fully positive'): # remember variance, mask, and unit args are only checked if image # object doesn't have those attributes (e.g., numpy and Quantity arrays) ext = extract(image=image.data, variance=err, mask=image.mask, unit=u.Jy) @pytest.mark.filterwarnings("ignore:The fit may be unsuccessful") def test_horne_non_flat_trace(): # create a synthetic "2D spectrum" and its non-flat trace n_rows, n_cols = (10, 50) original = np.zeros((n_rows, n_cols)) original[n_rows // 2] = 1 # create small offsets along each column to specify a non-flat trace trace_offset = np.polyval([2e-3, -0.01, 0], np.arange(n_cols)).astype(int) exact_trace = n_rows // 2 - trace_offset # re-index the array with the offsets applied to the trace (make it non-flat): rows = np.broadcast_to(np.arange(n_rows)[:, None], original.shape) cols = np.broadcast_to(np.arange(n_cols), original.shape) roll_rows = np.mod(rows + trace_offset[None, :], n_rows) rolled = original[roll_rows, cols] # all zeros are treated as non-weighted (give non-zero fluxes) err = 0.1 * np.ones_like(rolled) mask = np.zeros_like(rolled).astype(bool) # unroll the trace using the Horne extract utility function for alignment: unrolled = _align_along_trace(rolled, n_rows // 2 - trace_offset) # ensure that mask is correctly unrolled back to its original alignment: np.testing.assert_allclose(unrolled, original) # Extract the spectrum from the non-flat image+trace extract_non_flat = HorneExtract( rolled, ArrayTrace(rolled, exact_trace), variance=err, mask=mask, unit=u.Jy )() # Also extract the spectrum from the image after alignment with a flat trace extract_flat = HorneExtract( unrolled, FlatTrace(unrolled, n_rows // 2), variance=err, mask=mask, unit=u.Jy )() # ensure both extractions are equivalent: assert_quantity_allclose(extract_non_flat.flux, extract_flat.flux) def test_horne_no_bkgrnd(mk_test_img): # Test HorneExtract when using bkgrd_prof=None image = mk_test_img trace = FlatTrace(image, 3.0) extract = HorneExtract(image.data, trace, bkgrd_prof=None, variance=np.ones(image.data.shape)) # This is just testing that it runs with no errors and returns something assert len(extract.spectrum.flux) == 10 def test_horne_interpolated_profile(mk_test_img): # basic test for HorneExtract using the spatial_profile == `interpolated_profile` # option add a perfectly gaussian source and make sure gaussian extraction # and self-profile extraction agree (since self=gaussian in this case) image = mk_test_img add_gaussian_source(image) # add source across image, flat trace trace = FlatTrace(image, image.shape[0] // 2) # horne extraction using spatial_profile=='Gaussian' horne_extract_gauss = HorneExtract(image.data, trace, spatial_profile='gaussian', bkgrd_prof=None, variance=np.ones(image.data.shape)) # horne extraction with spatial_profile=='interpolated_profile' horne_extract_self = HorneExtract(image.data, trace, spatial_profile={'name': 'interpolated_profile', 'n_bins_interpolated_profile': 3}, bkgrd_prof=None, variance=np.ones(image.data.shape)) assert_quantity_allclose(horne_extract_gauss.spectrum.flux, horne_extract_self.spectrum.flux) def test_horne_interpolated_profile_norm(mk_test_img): # ensure that when using spatial_profile == `interpolated_profile`, the fit profile # represents the shape as a funciton of wavelength, and correctly accounts # for variations in trace position and flux. image = mk_test_img nrows, ncols = image.shape # create sawtooth pattern trace. right now, the _align_along_trace function # will rectify the trace to the integer-pixel level, so in this test # case the specturm will be totally straightened out. trace_shape = np.ones(ncols) * nrows // 2 trace_shape[::2] += 4 trace = ArrayTrace(image, trace_shape) # add gaussian source to image with increasing amplitude and that follows # along the trace. looks like a sawtooth pattern of increasing brightness add_gaussian_source(image, amps=np.linspace(1, 5, image.shape[1]), means=trace_shape) # horne extraction with spatial_profile=='interpolated_profile' # also tests that non-default parameters in the input dictionary format work ex = HorneExtract(image.data, trace, spatial_profile={'name': 'interpolated_profile', 'n_bins_interpolated_profile': 3, 'interp_degree_interpolated_profile': (1, 1)}, bkgrd_prof=None, variance=np.ones(image.data.shape)) # need to run produce extract.spectrum to access _interp_spatial_prof ex.spectrum # evaulate interpolated profile on entire grid interp_prof = ex._interp_spatial_prof(np.arange(ncols), np.arange(nrows)).T # the shifting position and amplitude should be accounted for, so the fit # spatial profile should just represent the shape as a function of # wavelength in this case, that is a gaussian with the area normalized at # each wavelength and a constant mean position # make sure that the fit spatial prof is normalized correctly assert_quantity_allclose(np.sum(interp_prof, axis=0), 1.0) # and that shifts in trace position are accounted for (to integer level) assert (np.all(np.argmax(interp_prof, axis=0) == nrows // 2)) def test_horne_interpolated_nbins_fails(mk_test_img): # make sure that HorneProfile spatial_profile='interpolated_profile' correctly # fails when the number of samples is greater than the size of the image image = mk_test_img trace = FlatTrace(image, 5) with pytest.raises(ValueError): ex = HorneExtract(image.data, trace, spatial_profile={'name': 'interpolated_profile', 'n_bins_interpolated_profile': 100}) ex.spectrum ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_get_reference_file_path.py0000644000175100001770000000123214635037352024757 0ustar00runnerdockerimport pytest from specreduce.calibration_data import get_reference_file_path, get_pypeit_data_path @pytest.mark.remote_data def test_get_reference_file_path(): """ Test to make sure a calibration reference file provided by specreduce_data can be accessed. """ test_path = "extinction/apoextinct.dat" p = get_reference_file_path(path=test_path) assert p is not None @pytest.mark.remote_data def test_get_pypeit_data_path(): """ Test to make sure pypeit reference data can be loaded """ test_path = "arc_lines/lists/HeI_lines.dat" p = get_pypeit_data_path(path=test_path, show_progress=False) assert p is not None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_image_parsing.py0000644000175100001770000000760014635037352022761 0ustar00runnerdockerimport numpy as np from astropy import units as u from specutils import Spectrum1D from specreduce.core import _ImageParser from specreduce.extract import HorneExtract from specreduce.tracing import FlatTrace # (for use inside tests) def compare_images(all_images, key, collection, compare='s1d'): # save default values used for spectral axis and uncertainty when they are not # available from the image object or provided by the user unc_def = np.ones_like(all_images['arr']) sax_def = np.arange(unc_def.shape[1]) * u.pix # was input converted to Spectrum1D? assert isinstance(collection[key], Spectrum1D), (f"image '{key}' not " "of type Spectrum1D") # do key's fluxes match its comparison's fluxes? assert np.allclose(collection[key].data, collection[compare].data), (f"images '{key}' and " f"'{compare}' have unequal " "flux values") # if the image came with a spectral axis, was it kept? if not, was the # default spectral axis in pixels applied? sax_provided = hasattr(all_images[key], 'spectral_axis') assert np.allclose(collection[key].spectral_axis, (all_images[key].spectral_axis if sax_provided else sax_def)), (f"spectral axis of image '{key}' does " f"not match {'input' if sax_provided else 'default'}") # if the image came with an uncertainty, was it kept? if not, was the # default uncertainty created? unc_provided = hasattr(all_images[key], 'uncertainty') assert np.allclose(collection[key].uncertainty.array, (all_images[key].uncertainty.array if unc_provided else unc_def)), (f"uncertainty of image '{key}' does " f"not match {'input' if unc_provided else 'default'}") # were masks created despite none being given? (all indices should be False) assert (getattr(collection[key], 'mask', None) is not None), f"no mask was created for image '{key}'" assert np.all(collection[key].mask == 0), ("mask not all False " f"for image '{key}'") # test consistency of general image parser results def test_parse_general(all_images): all_images_parsed = {k: _ImageParser()._parse_image(im) for k, im in all_images.items()} for key in all_images_parsed.keys(): compare_images(all_images, key, all_images_parsed) # use verified general image parser results to check HorneExtract's image parser def test_parse_horne(all_images): # save default values used for uncertainty when it is # available from the image object or provided by the user unc_def = np.ones_like(all_images['arr']) # HorneExtract's parser is more stringent than the general one, hence the # separate test. Given proper inputs, both should produce the same results. images_collection = {k: {} for k in all_images.keys()} for key, col in images_collection.items(): img = all_images[key] col['general'] = _ImageParser()._parse_image(img) if hasattr(all_images[key], 'uncertainty'): defaults = {} else: # save default values of attributes used in general parser when # they are not available from the image object. HorneExtract always # requires a variance, so it's chosen here to be on equal footing # with the general case defaults = {'variance': unc_def, 'mask': ~np.isfinite(img), 'unit': getattr(img, 'unit', u.DN)} col[key] = HorneExtract(img, FlatTrace(img, 2))._parse_image(img, **defaults) compare_images(all_images, key, col, compare='general') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_line_matching.py0000644000175100001770000000764014635037352022761 0ustar00runnerdockerimport pytest import numpy as np from astropy.wcs import WCS from astropy.modeling import models from astropy.nddata import StdDevUncertainty from specutils import Spectrum1D from specutils.fitting import fit_generic_continuum from specreduce.extract import BoxcarExtract from specreduce.utils.synth_data import make_2d_arc_image from specreduce.tracing import FlatTrace from specreduce.calibration_data import load_pypeit_calibration_lines from specreduce.line_matching import match_lines_wcs, find_arc_lines @pytest.fixture def mk_test_data(): """ Create test data for the line matching routines. """ non_linear_header = { 'CTYPE1': 'AWAV-GRA', # Grating dispersion function with air wavelengths 'CUNIT1': 'Angstrom', # Dispersion units 'CRPIX1': 519.8, # Reference pixel [pix] 'CRVAL1': 7245.2, # Reference value [Angstrom] 'CDELT1': 2.956, # Linear dispersion [Angstrom/pix] 'PV1_0': 4.5e5, # Grating density [1/m] 'PV1_1': 1, # Diffraction order 'PV1_2': 27.0, # Incident angle [deg] 'PV1_3': 1.765, # Reference refraction 'PV1_4': -1.077e6, # Refraction derivative [1/m] 'CTYPE2': 'PIXEL', # Spatial detector coordinates 'CUNIT2': 'pix', # Spatial units 'CRPIX2': 1, # Reference pixel 'CRVAL2': 0, # Reference value 'CDELT2': 1 # Spatial units per pixel } linear_header = { 'CTYPE1': 'AWAV', # Grating dispersion function with air wavelengths 'CUNIT1': 'Angstrom', # Dispersion units 'CRPIX1': 519.8, # Reference pixel [pix] 'CRVAL1': 7245.2, # Reference value [Angstrom] 'CDELT1': 2.956, # Linear dispersion [Angstrom/pix] 'CTYPE2': 'PIXEL', # Spatial detector coordinates 'CUNIT2': 'pix', # Spatial units 'CRPIX2': 1, # Reference pixel 'CRVAL2': 0, # Reference value 'CDELT2': 1 # Spatial units per pixel } non_linear_wcs = WCS(header=non_linear_header) linear_wcs = WCS(header=linear_header) tilt_mod = models.Legendre1D(degree=2, c0=50, c1=0, c2=100) match_im = make_2d_arc_image( nx=1400, ny=1024, linelists=['HeI', 'NeI'], wcs=linear_wcs, line_fwhm=5, tilt_func=tilt_mod, amplitude_scale=5e-4 ) arclist = load_pypeit_calibration_lines(['HeI', 'NeI'])['wavelength'] trace = FlatTrace(match_im, 512) arc_sp = BoxcarExtract(match_im, trace, width=5).spectrum arc_sp.uncertainty = StdDevUncertainty(np.sqrt(arc_sp.flux).value) continuum = fit_generic_continuum(arc_sp, median_window=51) arc_sub = Spectrum1D( spectral_axis=arc_sp.spectral_axis, flux=arc_sp.flux - continuum(arc_sp.spectral_axis) ) arc_sub.uncertainty = arc_sp.uncertainty return linear_wcs, non_linear_wcs, arclist, arc_sub @pytest.mark.remote_data @pytest.mark.filterwarnings("ignore:No observer defined on WCS") @pytest.mark.filterwarnings("ignore:Model is linear in parameters") def test_find_arc_lines(mk_test_data): """ Test the find_arc_lines routine. """ _, _, _, arc_sub = mk_test_data lines = find_arc_lines(arc_sub, fwhm=5, window=5, noise_factor=5) assert len(lines) > 1 @pytest.mark.remote_data @pytest.mark.filterwarnings("ignore:No observer defined on WCS") @pytest.mark.filterwarnings("ignore:Model is linear in parameters") def test_match_lines_wcs(mk_test_data): """ Test the match_lines_wcs routine. """ linear_wcs, _, arclist, arc_sub = mk_test_data lines = find_arc_lines(arc_sub, fwhm=5, window=5, noise_factor=5) matched_lines = match_lines_wcs( pixel_positions=lines['centroid'], catalog_wavelengths=arclist, spectral_wcs=linear_wcs.spectral, tolerance=5 ) assert len(matched_lines) > 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_linelists.py0000644000175100001770000000414414635037352022162 0ustar00runnerdockerimport pytest from specreduce.calibration_data import load_pypeit_calibration_lines @pytest.mark.remote_data def test_pypeit_single(): """ Test to load a single linelist from ``pypeit`` by passing a string. """ line_tab = load_pypeit_calibration_lines('HeI', cache=True, show_progress=False) assert line_tab is not None assert "HeI" in line_tab['ion'] assert sorted(list(line_tab.columns)) == [ 'Instr', 'NIST', 'Source', 'amplitude', 'ion', 'wavelength' ] @pytest.mark.remote_data def test_pypeit_list(): """ Test to load and combine a set of linelists from ``pypeit`` by passing a list. """ line_tab = load_pypeit_calibration_lines(['HeI', 'NeI'], cache=True, show_progress=False) assert line_tab is not None assert "HeI" in line_tab['ion'] assert "NeI" in line_tab['ion'] @pytest.mark.remote_data def test_pypeit_comma_list(): """ Test to load and combine a set of linelists from ``pypeit`` by passing a comma-separated list. """ line_tab = load_pypeit_calibration_lines("HeI, NeI", cache=True, show_progress=False) assert line_tab is not None assert "HeI" in line_tab['ion'] assert "NeI" in line_tab['ion'] @pytest.mark.remote_data def test_pypeit_empty(): """ Test to make sure None is returned if an empty list is passed. """ with pytest.warns(UserWarning, match='No calibration lines'): line_tab = load_pypeit_calibration_lines([], cache=True, show_progress=False) assert line_tab is None @pytest.mark.remote_data def test_pypeit_input_validation(): """ Check that bad inputs for ``pypeit`` linelists raise the appropriate warnings and exceptions """ with pytest.raises(ValueError, match='.*Invalid calibration lamps specification.*'): _ = load_pypeit_calibration_lines({}, cache=True, show_progress=False) with pytest.warns() as record: _ = load_pypeit_calibration_lines(['HeI', 'ArIII'], cache=True, show_progress=False) if not record: pytest.fails("Expected warning about nonexistant linelist for ArIII.") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_specphot_stds.py0000644000175100001770000000063114635037352023033 0ustar00runnerdockerimport pytest from specreduce.calibration_data import load_MAST_calspec, load_onedstds @pytest.mark.remote_data def test_load_MAST(): sp = load_MAST_calspec("g191b2b_005.fits", show_progress=False) assert sp is not None assert len(sp.spectral_axis) > 0 @pytest.mark.remote_data def test_load_onedstds(): sp = load_onedstds() assert sp is not None assert len(sp.spectral_axis) > 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_synth_data.py0000644000175100001770000001226314635037352022313 0ustar00runnerdockerimport pytest from astropy import units as u from astropy.modeling import models from astropy.nddata import CCDData from astropy.wcs import WCS from specreduce.utils.synth_data import make_2d_trace_image, make_2d_arc_image, make_2d_spec_image def test_make_2d_trace_image(): ccdim = make_2d_trace_image( nx=3000, ny=1000, background=5, trace_center=None, trace_order=3, trace_coeffs={'c0': 0, 'c1': 50, 'c2': 100}, profile=models.Gaussian1D(amplitude=100, stddev=10) ) assert ccdim.data.shape == (1000, 3000) assert isinstance(ccdim, CCDData) @pytest.mark.remote_data @pytest.mark.filterwarnings("ignore:No observer defined on WCS") def test_make_2d_arc_image_defaults(): ccdim = make_2d_arc_image() assert isinstance(ccdim, CCDData) @pytest.mark.remote_data @pytest.mark.filterwarnings("ignore:No observer defined on WCS") def test_make_2d_arc_pass_wcs(): nx = 3000 ny = 1000 wave_unit = u.Angstrom extent = [3000, 6000] # test passing a valid WCS with dispersion along X wcs = WCS(naxis=2) wcs.wcs.ctype[0] = 'WAVE' wcs.wcs.ctype[1] = 'PIXEL' wcs.wcs.cunit[0] = wave_unit wcs.wcs.cunit[1] = u.pixel wcs.wcs.crval[0] = extent[0] wcs.wcs.cdelt[0] = (extent[1] - extent[0]) / nx wcs.wcs.crval[1] = 0 wcs.wcs.cdelt[1] = 1 ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=wcs ) assert ccdim.data.shape == (1000, 3000) assert isinstance(ccdim, CCDData) # test passing a tilt model tilt_model = models.Chebyshev1D(degree=2, c0=50, c1=0, c2=100) ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=wcs, tilt_func=tilt_model ) assert ccdim.data.shape == (1000, 3000) assert isinstance(ccdim, CCDData) # make sure WCS without spectral axis gets rejected wcs.wcs.ctype[0] = 'PIXEL' assert wcs.spectral.naxis == 0 with pytest.raises(ValueError, match='Provided WCS must have a spectral axis'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=wcs ) # test passing valid WCS with dispersion along Y while using air wavelengths wcs = WCS(naxis=2) wcs.wcs.ctype[1] = 'AWAV' wcs.wcs.ctype[0] = 'PIXEL' wcs.wcs.cunit[1] = wave_unit wcs.wcs.cunit[0] = u.pixel wcs.wcs.crval[1] = extent[0] wcs.wcs.cdelt[1] = (extent[1] - extent[0]) / nx wcs.wcs.crval[0] = 0 wcs.wcs.cdelt[0] = 1 ccdim = make_2d_arc_image( nx=ny, ny=nx, extent=None, wave_unit=None, wave_air=True, wcs=wcs, tilt_func=tilt_model ) assert ccdim.data.shape == (3000, 1000) assert isinstance(ccdim, CCDData) # make sure no WCS and no extent gets rejected with pytest.raises(ValueError, match='Must specify either a wavelength extent or a WCS'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=None ) # make sure if extent is provided, it has the right length with pytest.raises(ValueError, match='Wavelength extent must be of length 2'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=[1, 2, 3], wave_unit=None, wcs=None ) # make sure a 1D WCS gets rejected wcs = WCS(naxis=1) wcs.wcs.ctype[0] = 'WAVE' wcs.wcs.cunit[0] = wave_unit wcs.wcs.crval[0] = extent[0] wcs.wcs.cdelt[0] = (extent[1] - extent[0]) / nx with pytest.raises(ValueError, match='WCS must have NAXIS=2 for a 2D image'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=wcs ) # make sure a WCS with no spectral axis gets rejected wcs = WCS(naxis=2) wcs.wcs.ctype[1] = 'PIXEL' wcs.wcs.ctype[0] = 'PIXEL' wcs.wcs.cunit[1] = u.pixel wcs.wcs.cunit[0] = u.pixel wcs.wcs.crval[1] = extent[0] wcs.wcs.cdelt[1] = (extent[1] - extent[0]) / nx wcs.wcs.crval[0] = 0 wcs.wcs.cdelt[0] = 1 with pytest.raises(ValueError, match='Provided WCS must have a spectral axis'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=None, wave_unit=None, wcs=wcs ) # make sure invalid wave_unit is caught with pytest.raises(ValueError, match='Wavelength unit must be a length unit'): ccdim = make_2d_arc_image( nx=nx, ny=ny, extent=[100, 300], wave_unit=u.pixel ) # make sure a non-polynomial tilt_func gets rejected with pytest.raises( ValueError, match='The only tilt functions currently supported are 1D polynomials' ): ccdim = make_2d_arc_image( tilt_func=models.Gaussian1D ) @pytest.mark.remote_data @pytest.mark.filterwarnings("ignore:No observer defined on WCS") def test_make_2d_spec_image_defaults(): ccdim = make_2d_spec_image() assert isinstance(ccdim, CCDData) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_tracing.py0000644000175100001770000002037514635037352021607 0ustar00runnerdockerimport numpy as np import pytest from astropy.modeling import models from astropy.nddata import NDData import astropy.units as u from specreduce.utils.synth_data import make_2d_trace_image from specreduce.tracing import Trace, FlatTrace, ArrayTrace, FitTrace IM = make_2d_trace_image() # test basic trace class def test_basic_trace(): t_pos = IM.shape[0] / 2 t = Trace(IM) assert t[0] == t_pos assert t[0] == t[-1] assert t.shape[0] == IM.shape[1] t.shift(100) assert t[0] == 600. t.shift(-1000) assert np.ma.is_masked(t[0]) # test flat traces def test_flat_trace(): t = FlatTrace(IM, 550.) assert t.trace_pos == 550 assert t[0] == 550. assert t[0] == t[-1] t.set_position(400.) assert t[0] == 400. def test_negative_flat_trace_err(): # make sure correct error is raised when trying to create FlatTrace with # negative trace_pos with pytest.raises(ValueError, match='must be positive.'): FlatTrace(IM, trace_pos=-1) # test array traces def test_array_trace(): arr = np.ones_like(IM[0]) * 550. t = ArrayTrace(IM, arr) assert t[0] == 550. assert t[0] == t[-1] t.shift(100) assert t[0] == 650. t.shift(-1000) assert np.ma.is_masked(t[0]) arr_long = np.ones(5000) * 550. t_long = ArrayTrace(IM, arr_long) assert t_long.shape[0] == IM.shape[1] arr_short = np.ones(50) * 550. t_short = ArrayTrace(IM, arr_short) assert t_short[0] == 550. assert np.ma.is_masked(t_short[-1]) assert t_short.shape[0] == IM.shape[1] # test fitted traces @pytest.mark.filterwarnings("ignore:Model is linear in parameters") def test_fit_trace(): # create image (process adapted from compare_extractions.ipynb) np.random.seed(7) nrows = 200 ncols = 160 sigma_pix = 4 sigma_noise = 1 col_model = models.Gaussian1D(amplitude=1, mean=nrows/2, stddev=sigma_pix) noise = np.random.normal(scale=sigma_noise, size=(nrows, ncols)) index_arr = np.tile(np.arange(nrows), (ncols, 1)) img = col_model(index_arr.T) + noise # calculate trace on normal image t = FitTrace(img, bins=20) # test shifting shift_up = int(-img.shape[0]/4) t_shift_up = t.trace + shift_up shift_out = img.shape[0] t.shift(shift_up) assert np.sum(t.trace == t_shift_up) == t.trace.size, 'valid shift failed' t.shift(shift_out) assert t.trace.mask.all(), 'invalid values not masked' # test peak_method and trace_model options tg = FitTrace(img, bins=20, peak_method='gaussian', trace_model=models.Legendre1D(3)) tc = FitTrace(img, bins=20, peak_method='centroid', trace_model=models.Chebyshev1D(2)) tm = FitTrace(img, bins=20, peak_method='max', trace_model=models.Spline1D(degree=3)) # traces should all be close to 100 # (values may need to be updated on changes to seed, noise, etc.) assert np.max(abs(tg.trace-100)) < sigma_pix assert np.max(abs(tc.trace-100)) < 3 * sigma_pix assert np.max(abs(tm.trace-100)) < 6 * sigma_pix with pytest.raises(ValueError): t = FitTrace(img, peak_method='invalid') window = 10 guess = int(nrows/2) img_win_nans = img.copy() img_win_nans[guess - window:guess + window] = np.nan # ensure float bin values trigger a warning but no issues otherwise with pytest.warns(UserWarning, match='TRACE: Converting bins to int'): FitTrace(img, bins=20., trace_model=models.Polynomial1D(2)) # ensure non-equipped models are rejected with pytest.raises(ValueError, match=r'trace_model must be one of'): FitTrace(img, trace_model=models.Hermite1D(3)) # ensure a bin number below 4 is rejected with pytest.raises(ValueError, match='bins must be >= 4'): FitTrace(img, bins=3) # ensure a bin number below degree of trace model is rejected with pytest.raises(ValueError, match='bins must be > '): FitTrace(img, bins=4, trace_model=models.Chebyshev1D(5)) # ensure number of bins greater than number of dispersion pixels is rejected with pytest.raises(ValueError, match=r'bins must be <'): FitTrace(img, bins=ncols + 1) class TestMasksTracing(): def mk_img(self, nrows=200, ncols=160): np.random.seed(7) sigma_pix = 4 sigma_noise = 1 col_model = models.Gaussian1D(amplitude=1, mean=nrows/2, stddev=sigma_pix) noise = np.random.normal(scale=sigma_noise, size=(nrows, ncols)) index_arr = np.tile(np.arange(nrows), (ncols, 1)) img = col_model(index_arr.T) + noise return img * u.DN def test_window_fit_trace(self): """This test function will test that masked values are treated correctly in FitTrace, and produce the correct results and warning messages based on `peak_method`.""" img = self.mk_img() # create same-shaped variations of image with invalid values nrows = 200 ncols = 160 img_all_nans = np.tile(np.nan, (nrows, ncols)) window = 10 guess = int(nrows/2) img_win_nans = img.copy() img_win_nans[guess - window:guess + window] = np.nan # error on trace of otherwise valid image with all-nan window around guess with pytest.raises(ValueError, match='pixels in window region are masked'): FitTrace(img_win_nans, guess=guess, window=window) # error on trace of all-nan image with pytest.raises(ValueError, match=r'image is fully masked'): FitTrace(img_all_nans) @pytest.mark.filterwarnings("ignore:The fit may be unsuccessful") @pytest.mark.filterwarnings("ignore:Model is linear in parameters") @pytest.mark.filterwarnings("ignore:All pixels in bins") def test_fit_trace_all_nan_cols(self): # make sure that the actual trace that is fit is correct when # all-masked bin peaks are set to NaN img = self.mk_img(nrows=10, ncols=11) img[:, 7] = np.nan img[:, 4] = np.nan img[:, 0] = np.nan # peak_method = 'max' truth = [1.6346154, 2.2371795, 2.8397436, 3.4423077, 4.0448718, 4.6474359, 5.25, 5.8525641, 6.4551282, 7.0576923, 7.6602564] max_trace = FitTrace(img, peak_method='max') np.testing.assert_allclose(truth, max_trace.trace) # peak_method = 'gaussian' truth = [1.947455, 2.383634, 2.8198131, 3.2559921, 3.6921712, 4.1283502, 4.5645293, 5.0007083, 5.4368874, 5.8730665, 6.3092455] max_trace = FitTrace(img, peak_method='gaussian') np.testing.assert_allclose(truth, max_trace.trace) # peak_method = 'centroid' truth = [2.5318835, 2.782069, 3.0322546, 3.2824402, 3.5326257, 3.7828113, 4.0329969, 4.2831824, 4.533368, 4.7835536, 5.0337391] max_trace = FitTrace(img, peak_method='centroid') np.testing.assert_allclose(truth, max_trace.trace) @pytest.mark.filterwarnings("ignore:The fit may be unsuccessful") @pytest.mark.filterwarnings("ignore:Model is linear in parameters") def test_warn_msg_fit_trace_all_nan_cols(self): img = self.mk_img() # test that warning (dependent on choice of `peak_method`) is raised when a # few bins are masked, and that theyre listed individually mask = np.zeros(img.shape) mask[:, 100] = 1 mask[:, 20] = 1 mask[:, 30] = 1 nddat = NDData(data=img, mask=mask, unit=u.DN) match_str = 'All pixels in bins 20, 30, 100 are fully masked. Setting bin peaks to NaN.' with pytest.warns(UserWarning, match=match_str): FitTrace(nddat, peak_method='max') with pytest.warns(UserWarning, match=match_str): FitTrace(nddat, peak_method='centroid') with pytest.warns(UserWarning, match=match_str): FitTrace(nddat, peak_method='gaussian') # and when many bins are masked, that the message is consolidated mask = np.zeros(img.shape) mask[:, 0:21] = 1 nddat = NDData(data=img, mask=mask, unit=u.DN) with pytest.warns(UserWarning, match='All pixels in bins ' '0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 20 are ' 'fully masked. Setting bin peaks to NaN.'): FitTrace(nddat) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_utils.py0000644000175100001770000001751314635037352021320 0ustar00runnerdockerimport numpy as np import pytest from astropy.modeling import fitting, models from specreduce.tracing import FitTrace from specreduce.utils.utils import measure_cross_dispersion_profile from specutils import Spectrum1D from astropy.nddata import NDData import astropy.units as u def mk_gaussian_img(nrows=20, ncols=16, mean=10, stddev=4): """ Makes a simple horizontal gaussian image.""" # note: this should become a fixture eventually, since other tests use # similar functions to generate test data. np.random.seed(7) col_model = models.Gaussian1D(amplitude=1, mean=mean, stddev=stddev) index_arr = np.tile(np.arange(nrows), (ncols, 1)) return col_model(index_arr.T) def mk_img_non_flat_trace(nrows=40, ncols=100, amp=10, stddev=2): """ Makes an image with a gaussian source that has a non-flat trace dispersed along the x axis. """ spec2d = np.zeros((nrows, ncols)) for ii in range(spec2d.shape[1]): mgaus = models.Gaussian1D(amplitude=amp, mean=(9.+(20/spec2d.shape[1])*ii), stddev=stddev) rg = np.arange(0, spec2d.shape[0], 1) gaus = mgaus(rg) spec2d[:, ii] = gaus return spec2d class TestMeasureCrossDispersionProfile(): @pytest.mark.parametrize('pixel', [None, 1, [1, 2, 3]]) @pytest.mark.parametrize('width', [10, 9]) def test_measure_cross_dispersion_profile(self, pixel, width): """ Basic test for `measure_cross_dispersion_profile`. Parametrized over different options for `pixel` to test using all wavelengths, a single wavelength, and a set of wavelengths, as well as different input types (plain array, quantity, Spectrum1D, and NDData), as well as `width` to use a window of all rows and a smaller window. """ # test a few input formats images = [] mean = 5.0 stddev = 4.0 dat = mk_gaussian_img(nrows=10, ncols=10, mean=mean, stddev=stddev) images.append(dat) # test unitless images.append(dat * u.DN) images.append(NDData(dat * u.DN)) images.append(Spectrum1D(flux=dat * u.DN)) for img in images: # use a flat trace at trace_pos=10, a window of width 10 around the trace # and use all 20 columns in image to create an average (median) # cross dispersion profile cdp = measure_cross_dispersion_profile(img, width=width, pixel=pixel) # make sure that if we fit a gaussian to the measured average profile, # that we get out the same profile that was used to create the image. # this should be exact since theres no noise in the image fitter = fitting.LevMarLSQFitter() mod = models.Gaussian1D() fit_model = fitter(mod, np.arange(width), cdp) assert fit_model.mean.value == np.where(cdp == max(cdp))[0][0] assert fit_model.stddev.value == stddev # test passing in a FlatTrace, and check the profile cdp = measure_cross_dispersion_profile(img, width=width, pixel=pixel) fit_model = fitter(mod, np.arange(width), cdp) assert fit_model.mean.value == np.where(cdp == max(cdp))[0][0] np.testing.assert_allclose(fit_model.stddev.value, stddev) @pytest.mark.filterwarnings("ignore:Model is linear in parameters") def test_cross_dispersion_profile_non_flat_trace(self): """ Test measure_cross_dispersion_profile with a non-flat trace. Tests with 'align_along_trace' set to both True and False, to account for the changing center of the trace and measure the true profile shape, or to 'blur' the profile, respectivley. """ image = mk_img_non_flat_trace() # fit the trace trace_fit = FitTrace(image) # when not aligning along trace and using the entire image # rows for the window, the center of the profile should follow # the shape of the trace peak_locs = [9, 10, 12, 13, 15, 16, 17, 19, 20, 22, 23, 24, 26, 27, 29] for i, pixel in enumerate(range(0, image.shape[1], 7)): profile = measure_cross_dispersion_profile(image, trace=trace_fit, width=None, pixel=pixel, align_along_trace=False, statistic='mean') peak_loc = (np.where(profile == max(profile))[0][0]) assert peak_loc == peak_locs[i] # when align_along_trace = True, the shape of the profile should # not change since (there is some wiggling around though due to the # fact that the trace is rolled to the nearest integer value. this can # be smoothed with an interpolation option later on, but it is 'rough' # for now). In this test case, the peak positions will all either # be at pixel 20 or 21. for i, pixel in enumerate(range(0, image.shape[1], 7)): profile = measure_cross_dispersion_profile(image, trace=trace_fit, width=None, pixel=pixel, align_along_trace=True, statistic='mean') peak_loc = (np.where(profile == max(profile))[0][0]) assert peak_loc in [20, 21] def test_errors_warnings(self): img = mk_gaussian_img(nrows=10, ncols=10) with pytest.raises(ValueError, match='`crossdisp_axis` must be 0 or 1'): measure_cross_dispersion_profile(img, crossdisp_axis=2) with pytest.raises(ValueError, match='`trace` must be Trace object, ' 'number to specify the location ' 'of a FlatTrace, or None to use ' 'center of image.'): measure_cross_dispersion_profile(img, trace='not a trace or a number') with pytest.raises(ValueError, match="`statistic` must be 'median' " "or 'mean'."): measure_cross_dispersion_profile(img, statistic='n/a') with pytest.raises(ValueError, match='Both `pixel` and `pixel_range` ' 'can not be set simultaneously.'): measure_cross_dispersion_profile(img, pixel=2, pixel_range=(2, 3)) with pytest.raises(ValueError, match='`pixels` must be an integer, ' 'or list of integers to specify ' 'where the crossdisperion profile ' 'should be measured.'): measure_cross_dispersion_profile(img, pixel='str') with pytest.raises(ValueError, match='`pixel_range` must be a tuple ' 'of integers.'): measure_cross_dispersion_profile(img, pixel_range=(2, 3, 5)) with pytest.raises(ValueError, match='Pixels chosen to measure cross ' 'dispersion profile are out of ' 'image bounds.'): measure_cross_dispersion_profile(img, pixel_range=(2, 12)) with pytest.raises(ValueError, match='`width` must be an integer, ' 'or None to use all ' 'cross-dispersion pixels.'): measure_cross_dispersion_profile(img, width='.') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tests/test_wavelength_calibration.py0000644000175100001770000001264114635037352024670 0ustar00runnerdockerimport numpy as np import pytest from astropy import units as u from astropy.modeling.fitting import LinearLSQFitter from astropy.modeling.models import Polynomial1D from astropy.table import QTable from astropy.tests.helper import assert_quantity_allclose from numpy.testing import assert_allclose from specreduce import WavelengthCalibration1D def test_linear_from_list(spec1d): centers = [0, 10, 20, 30] w = [5000, 5100, 5198, 5305]*u.AA test = WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) spec2 = test.apply_to_spectrum(spec1d) assert_quantity_allclose(spec2.spectral_axis[0], 4998.8*u.AA) assert_quantity_allclose(spec2.spectral_axis[-1], 5495.169999*u.AA) def test_wavelength_from_table(spec1d): centers = [0, 10, 20, 30] w = [5000, 5100, 5198, 5305]*u.AA table = QTable([w], names=["wavelength"]) WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=table) def test_linear_from_table(spec1d): centers = [0, 10, 20, 30] w = [5000, 5100, 5198, 5305]*u.AA table = QTable([centers, w], names=["pixel_center", "wavelength"]) test = WavelengthCalibration1D(spec1d, matched_line_list=table) spec2 = test.apply_to_spectrum(spec1d) assert_quantity_allclose(spec2.spectral_axis[0], 4998.8*u.AA) assert_quantity_allclose(spec2.spectral_axis[-1], 5495.169999*u.AA) def test_poly_from_table(spec1d): # This test is mostly to prove that you can use other models centers = [0, 10, 20, 30, 40] w = [5005, 5110, 5214, 5330, 5438]*u.AA table = QTable([centers, w], names=["pixel_center", "wavelength"]) test = WavelengthCalibration1D(spec1d, matched_line_list=table, input_model=Polynomial1D(2), fitter=LinearLSQFitter()) test.apply_to_spectrum(spec1d) assert_allclose(test.fitted_model.parameters, [5.00477143e+03, 1.03457143e+01, 1.28571429e-02]) def test_replace_spectrum(spec1d, spec1d_with_emission_line): centers = [0, 10, 20, 30]*u.pix w = [5000, 5100, 5198, 5305]*u.AA test = WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) # Accessing this property causes fits the model and caches the resulting WCS test.wcs assert "wcs" in test.__dict__ # Replace the input spectrum, which should clear the cached properties test.input_spectrum = spec1d_with_emission_line assert "wcs" not in test.__dict__ def test_expected_errors(spec1d): centers = [0, 10, 20, 30, 40] w = [5005, 5110, 5214, 5330, 5438]*u.AA table = QTable([centers, w], names=["pixel_center", "wavelength"]) with pytest.raises(ValueError, match="Cannot specify line_wavelengths separately"): WavelengthCalibration1D(spec1d, matched_line_list=table, line_wavelengths=w) with pytest.raises(ValueError, match="must have the same length"): w2 = [5005, 5110, 5214, 5330, 5438, 5500]*u.AA WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w2) with pytest.raises(ValueError, match="astropy.units.Quantity array or" " as an astropy.table.QTable"): w2 = [5005, 5110, 5214, 5330, 5438] WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w2) with pytest.raises(ValueError, match="specify at least one"): WavelengthCalibration1D(spec1d, line_pixels=centers) def test_fit_residuals(spec1d): # test that fit residuals are all 0 when input is perfectly linear and model # is a linear model centers = np.array([0, 10, 20, 30]) w = (0.5 * centers + 2) * u.AA test = WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) test.apply_to_spectrum(spec1d) # have to apply for residuals to be computed assert_quantity_allclose(test.residuals, 0.*u.AA, atol=1e-07*u.AA) def test_fit_residuals_access(spec1d): # make sure that accessing residuals can be called before wcs/apply_to_spectrum centers = np.array([0, 10, 20, 30]) w = (0.5 * centers + 2) * u.AA test = WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) test.residuals test.wcs def test_unsorted_pixels_wavelengths(spec1d): # make sure an error is raised if input matched pixels/wavelengths are # not strictly increasing or decreasing. centers = np.array([0, 10, 5, 30]) w = (0.5 * centers + 2) * u.AA with pytest.raises(ValueError, match='Pixels must be strictly increasing or decreasing.'): WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) # now test that it fails when wavelengths are unsorted centers = np.array([0, 10, 20, 30]) w = np.array([2, 5, 6, 1]) * u.AA with pytest.raises(ValueError, match='Wavelengths must be strictly increasing or decreasing.'): WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=w) # and same if those wavelengths are provided in a table table = QTable([w], names=["wavelength"]) with pytest.raises(ValueError, match='Wavelengths must be strictly increasing or decreasing.'): WavelengthCalibration1D(spec1d, line_pixels=centers, line_wavelengths=table) # and again with decreasing pixels but unsorted wavelengths with pytest.raises(ValueError, match='Wavelengths must be strictly increasing or decreasing.'): WavelengthCalibration1D(spec1d, line_pixels=centers[::-1], line_wavelengths=w) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/tracing.py0000644000175100001770000003643614635037352017413 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see LICENSE.rst import warnings from copy import deepcopy from dataclasses import dataclass, field import numpy as np from astropy.modeling import Model, fitting, models from astropy.nddata import NDData from astropy.stats import gaussian_sigma_to_fwhm from astropy.utils.decorators import deprecated from specreduce.core import _ImageParser __all__ = ['Trace', 'FlatTrace', 'ArrayTrace', 'FitTrace'] @dataclass class Trace: """ Basic tracing class that by default traces the middle of the image. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required Image to be traced Properties ---------- shape : tuple Shape of the array describing the trace """ image: NDData def __post_init__(self): self.trace_pos = self.image.shape[0] / 2 self.trace = np.ones_like(self.image[0]) * self.trace_pos def __getitem__(self, i): return self.trace[i] @property def shape(self): return self.trace.shape def shift(self, delta): """ Shift the trace by delta pixels perpendicular to the axis being traced Parameters ---------- delta : float Shift to be applied to the trace """ # act on self.trace.data to ignore the mask and then re-mask when calling _bound_trace self.trace = np.asarray(self.trace.data) + delta self._bound_trace() def _bound_trace(self): """ Mask trace positions that are outside the upper/lower bounds of the image. """ ny = self.image.shape[0] self.trace = np.ma.masked_outside(self.trace, 0, ny-1) def __add__(self, delta): """ Return a copy of the trace shifted "forward" by delta pixels perpendicular to the axis being traced """ copy = deepcopy(self) copy.shift(delta) return copy def __sub__(self, delta): """ Return a copy of the trace shifted "backward" by delta pixels perpendicular to the axis being traced """ return self.__add__(-delta) @dataclass class FlatTrace(Trace, _ImageParser): """ Trace that is constant along the axis being traced. Example: :: trace = FlatTrace(image, trace_pos) Parameters ---------- trace_pos : float Position of the trace """ trace_pos: float def __post_init__(self): self.image = self._parse_image(self.image) self.set_position(self.trace_pos) def set_position(self, trace_pos): """ Set the trace position within the image Parameters ---------- trace_pos : float Position of the trace """ if trace_pos < 1: raise ValueError('`trace_pos` must be positive.') self.trace_pos = trace_pos self.trace = np.ones_like(self.image.data[0]) * self.trace_pos self._bound_trace() @dataclass class ArrayTrace(Trace, _ImageParser): """ Define a trace given an array of trace positions. Parameters ---------- trace : `numpy.ndarray` Array containing trace positions """ trace: np.ndarray def __post_init__(self): self.image = self._parse_image(self.image) nx = self.image.shape[1] nt = len(self.trace) if nt != nx: if nt > nx: # truncate trace to fit image self.trace = self.trace[0:nx] else: # assume trace starts at beginning of image and pad out trace to fit. # padding will be the last value of the trace, but will be masked out. padding = np.ma.MaskedArray(np.ones(nx - nt) * self.trace[-1], mask=True) self.trace = np.ma.hstack([self.trace, padding]) self._bound_trace() @dataclass class FitTrace(Trace, _ImageParser): """ Trace the spectrum aperture in an image. Bins along the image's dispersion (wavelength) direction, finds each bin's peak cross-dispersion (spatial) pixel, and uses a model to interpolate the function fitted to the peaks as a final trace. The number of bins, peak finding algorithm, and model used for fitting are customizable by the user. Example: :: trace = FitTrace(image, peak_method='gaussian', guess=trace_pos) Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required The image over which to run the trace. Assumes cross-dispersion (spatial) direction is axis 0 and dispersion (wavelength) direction is axis 1. bins : int, optional The number of bins in the dispersion (wavelength) direction into which to divide the image. If not set, defaults to one bin per dispersion (wavelength) pixel in the given image. If set, requires at least 4 or N bins for a degree N ``trace_model``, whichever is greater. [default: None] guess : int, optional A guess at the trace's location in the cross-dispersion (spatial) direction. If set, overrides the normal max peak finder. Good for tracing a fainter source if multiple traces are present. [default: None] window : int, optional Fit the trace to a region with size ``window * 2`` around the guess position. Useful for tracing faint sources if multiple traces are present, but potentially bad if the trace is substantially bent or warped. [default: None] trace_model : one of `~astropy.modeling.polynomial.Chebyshev1D`,\ `~astropy.modeling.polynomial.Legendre1D`,\ `~astropy.modeling.polynomial.Polynomial1D`,\ or `~astropy.modeling.spline.Spline1D`, optional The 1-D polynomial model used to fit the trace to the bins' peak pixels. Spline1D models are fit with Astropy's 'SplineSmoothingFitter', while the other models are fit with the 'LevMarLSQFitter'. [default: ``models.Polynomial1D(degree=1)``] peak_method : string, optional One of ``gaussian``, ``centroid``, or ``max``. ``gaussian``: Fits a gaussian to the window within each bin and adopts the central value as the peak. May work best with fewer bins on faint targets. (Based on the "kosmos" algorithm from James Davenport's same-named repository.) ``centroid``: Takes the centroid of the window within in bin. ``max``: Saves the position with the maximum flux in each bin. [default: ``max``] """ bins: int = None guess: float = None window: int = None trace_model: Model = field(default=models.Polynomial1D(degree=1)) peak_method: str = 'max' _crossdisp_axis = 0 _disp_axis = 1 def __post_init__(self): # parse image self.image = self._parse_image(self.image) # mask any previously uncaught invalid values or_mask = np.logical_or(self.image.mask, ~np.isfinite(self.image.data)) img = np.ma.masked_array(self.image.data, or_mask) # validate arguments valid_peak_methods = ('gaussian', 'centroid', 'max') if self.peak_method not in valid_peak_methods: raise ValueError(f"peak_method must be one of {valid_peak_methods}") if img.mask.all(): raise ValueError('image is fully masked. Check for invalid values') if self._crossdisp_axis != 0: raise ValueError('cross-dispersion axis must equal 0') if self._disp_axis != 1: raise ValueError('dispersion axis must equal 1') valid_models = (models.Spline1D, models.Legendre1D, models.Chebyshev1D, models.Polynomial1D) if not isinstance(self.trace_model, valid_models): raise ValueError("trace_model must be one of " f"{', '.join([m.name for m in valid_models])}.") cols = img.shape[self._disp_axis] model_deg = self.trace_model.degree if self.bins is None: self.bins = cols elif self.bins < 4: # many of the Astropy model fitters require four points at minimum raise ValueError('bins must be >= 4') elif self.bins <= model_deg: raise ValueError(f"bins must be > {model_deg} for " f"a degree {model_deg} model.") elif self.bins > cols: raise ValueError(f"bins must be <= {cols}, the length of the " "image's spatial direction") if not isinstance(self.bins, int): warnings.warn('TRACE: Converting bins to int') self.bins = int(self.bins) if (self.window is not None and (self.window > img.shape[self._disp_axis] or self.window < 1)): raise ValueError(f"window must be >= 2 and less than {cols}, the " "length of the image's spatial direction") elif self.window is not None and not isinstance(self.window, int): warnings.warn('TRACE: Converting window to int') self.window = int(self.window) # fit the trace self._fit_trace(img) def _fit_trace(self, img): yy = np.arange(img.shape[self._crossdisp_axis]) # set max peak location by user choice or wavelength with max avg flux ztot = img.sum(axis=self._disp_axis) / img.shape[self._disp_axis] peak_y = self.guess if self.guess is not None else ztot.argmax() # NOTE: peak finder can be bad if multiple objects are on slit if self.peak_method == 'gaussian': # guess the peak width as the FWHM, roughly converted to gaussian sigma yy_above_half_max = np.sum(ztot > (ztot.max() / 2)) width_guess = yy_above_half_max / gaussian_sigma_to_fwhm # enforce some (maybe sensible?) rules about trace peak width width_guess = (2 if width_guess < 2 else 25 if width_guess > 25 else width_guess) # fit a Gaussian to peak for fall-back answer, but don't use yet g1d_init = models.Gaussian1D(amplitude=ztot.max(), mean=peak_y, stddev=width_guess) offset_init = models.Const1D(np.ma.median(ztot)) profile = g1d_init + offset_init fitter = fitting.LevMarLSQFitter() popt_tot = fitter(profile, yy, ztot) # restrict fit to window (if one exists) ilum2 = (yy if self.window is None else yy[np.arange(peak_y - self.window, peak_y + self.window, dtype=int)]) # check if everything in window region is masked if img[ilum2].mask.all(): raise ValueError('All pixels in window region are masked. Check ' 'for invalid values or use a larger window value.') x_bins = np.linspace(0, img.shape[self._disp_axis], self.bins + 1, dtype=int) y_bins = np.tile(np.nan, self.bins) warn_bins = [] for i in range(self.bins): # binned columns, summed along disp. axis. # or just a single, unbinned column if no bins z_i = img[ilum2, x_bins[i]:x_bins[i+1]].sum(axis=self._disp_axis) # if this bin is fully masked, set bin peak to NaN so it can be # filtered in the final fit to all bin peaks for the trace if z_i.mask.all(): warn_bins.append(i) y_bins[i] = np.nan continue if self.peak_method == 'gaussian': peak_y_i = ilum2[z_i.argmax()] yy_i_above_half_max = np.sum(z_i > (z_i.max() / 2)) width_guess_i = yy_i_above_half_max / gaussian_sigma_to_fwhm # NOTE: original KOSMOS code mandated width be greater than 2 # (to avoid cosmic rays) and less than 25 (to avoid fitting noise). # we should extract values from img to derive similar limits # width_guess_i = (2 if width_guess_i < 2 # else 25 if width_guess_i > 25 # else width_guess_i) g1d_init_i = models.Gaussian1D(amplitude=z_i.max(), mean=peak_y_i, stddev=width_guess_i) offset_init_i = models.Const1D(np.ma.median(z_i)) profile_i = g1d_init_i + offset_init_i popt_i = fitter(profile_i, ilum2, z_i) # if gaussian fits off chip, then fall back to previous answer if not ilum2.min() <= popt_i.mean_0 <= ilum2.max(): y_bins[i] = popt_tot.mean_0.value else: y_bins[i] = popt_i.mean_0.value popt_tot = popt_i elif self.peak_method == 'centroid': z_i_cumsum = np.cumsum(z_i) # find the interpolated index where the cumulative array reaches # half the total cumulative values y_bins[i] = np.interp(z_i_cumsum[-1]/2., z_i_cumsum, ilum2) # NOTE this reflects current behavior, should eventually be changed # to set to nan by default (or zero fill / interpoate option once # available) elif self.peak_method == 'max': # TODO: implement smoothing with provided width y_bins[i] = ilum2[z_i.argmax()] # NOTE: a fully masked should eventually be changed to set to # nan by default (or zero fill / interpoate option once available) # warn about fully-masked bins if len(warn_bins) > 0: # if there are a ton of bins, we don't want to print them all out if len(warn_bins) > 20: warn_bins = warn_bins[0: 10] + ['...'] + [warn_bins[-1]] warnings.warn(f"All pixels in {'bins' if len(warn_bins) else 'bin'} " f"{', '.join([str(x) for x in warn_bins])}" " are fully masked. Setting bin" f" peak{'s' if len(warn_bins) else ''} to NaN.") # recenter bin positions x_bins = (x_bins[:-1] + x_bins[1:]) / 2 # interpolate the fitted trace over the entire wavelength axis y_finite = np.where(np.isfinite(y_bins))[0] if y_finite.size > 0: x_bins = x_bins[y_finite] y_bins = y_bins[y_finite] # use given model to bin y-values; interpolate over all wavelengths fitter = (fitting.SplineSmoothingFitter() if isinstance(self.trace_model, models.Spline1D) else fitting.LevMarLSQFitter()) self.trace_model_fit = fitter(self.trace_model, x_bins, y_bins) trace_x = np.arange(img.shape[self._disp_axis]) trace_y = self.trace_model_fit(trace_x) else: warnings.warn("TRACE ERROR: No valid points found in trace") trace_y = np.tile(np.nan, img.shape[self._disp_axis]) self.trace = np.ma.masked_invalid(trace_y) @deprecated('1.3', alternative='FitTrace') @dataclass class KosmosTrace(FitTrace): """ This class is pending deprecation. Please use `FitTrace` instead. """ __doc__ += FitTrace.__doc__ pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1148734 specreduce-1.4.1/specreduce/utils/0000755000175100001770000000000014635037364016541 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/utils/__init__.py0000644000175100001770000000011714635037352020646 0ustar00runnerdocker""" General purpose utilities for specreduce """ from .utils import * # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/utils/synth_data.py0000644000175100001770000003367514635037352021264 0ustar00runnerdocker# Licensed under a 3-clause BSD style license - see ../../licenses/LICENSE.rst from typing import Sequence import numpy as np from astropy import units as u from astropy.modeling import models, Model from astropy.nddata import CCDData from astropy.stats import gaussian_fwhm_to_sigma from astropy.wcs import WCS from specreduce.calibration_data import load_pypeit_calibration_lines __all__ = [ 'make_2d_trace_image', 'make_2d_arc_image', 'make_2d_spec_image' ] def make_2d_trace_image( nx: int = 3000, ny: int = 1000, background: int | float = 5, trace_center: int | float | None = None, trace_order: int = 3, trace_coeffs: dict[str, int | float] = {'c0': 0, 'c1': 50, 'c2': 100}, profile: Model = models.Moffat1D(amplitude=10, alpha=0.1), add_noise: bool = True ) -> CCDData: """ Create synthetic 2D spectroscopic image with a single source. The spatial (y-axis) position of the source along the dispersion (x-axis) direction is modeled using a Chebyshev polynomial. The flux units are counts and the noise is modeled as Poisson. Parameters ---------- nx : Size of image in X axis which is assumed to be the dispersion axis ny : Size of image in Y axis which is assumed to be the spatial axis background : Level of constant background in counts trace_center : Zeropoint of the trace. If None, then use center of Y (spatial) axis. trace_order : Order of the Chebyshev polynomial used to model the source's trace trace_coeffs : Dict containing the Chebyshev polynomial coefficients to use in the trace model profile : Model to use for the source's spatial profile add_noise : If True, add Poisson noise to the image Returns ------- ccd_im : CCDData instance containing synthetic 2D spectroscopic image """ x = np.arange(nx) y = np.arange(ny) xx, yy = np.meshgrid(x, y) if trace_center is None: trace_center = ny / 2 trace_mod = models.Chebyshev1D(degree=trace_order, **trace_coeffs) trace = yy - trace_center + trace_mod(xx/nx) z = background + profile(trace) if add_noise: from photutils.datasets import apply_poisson_noise trace_image = apply_poisson_noise(z) else: trace_image = z ccd_im = CCDData(trace_image, unit=u.count) return ccd_im def make_2d_arc_image( nx: int = 3000, ny: int = 1000, wcs: WCS | None = None, extent: Sequence[int | float] = (3500, 7000), wave_unit: u.Unit = u.Angstrom, wave_air: bool = False, background: int | float = 5, line_fwhm: float = 5., linelists: list[str] = ['HeI'], amplitude_scale: float = 1., tilt_func: Model = models.Legendre1D(degree=0), add_noise: bool = True ) -> CCDData: """ Create synthetic 2D spectroscopic image of reference emission lines, e.g. a calibration arc lamp. Currently, linelists from ``pypeit`` are supported and are selected by string or list of strings that is passed to `~specreduce.calibration_data.load_pypeit_calibration_lines`. If a ``wcs`` is not provided, one is created using ``extent`` and ``wave_unit`` with dispersion along the X axis. Parameters ---------- nx : Size of image in X axis which is assumed to be the dispersion axis ny : Size of image in Y axis which is assumed to be the spatial axis wcs : 2D WCS to apply to the image. Must have a spectral axis defined along with appropriate spectral wavelength units. extent : If ``wcs`` is not provided, this defines the beginning and end wavelengths of the dispersion axis. wave_unit : If ``wcs`` is not provided, this defines the wavelength units of the dispersion axis. wave_air : If True, convert the vacuum wavelengths used by ``pypeit`` to air wavelengths. background : Level of constant background in counts line_fwhm : Gaussian FWHM of the emission lines in pixels linelists : Specification for linelists to load from ``pypeit`` amplitude_scale : Scale factor to apply to amplitudes provided in the linelists tilt_func : The tilt function to apply along the cross-dispersion axis to simulate tilted or curved emission lines. add_noise : If True, add Poisson noise to the image; requires ``photutils`` to be installed. Returns ------- ccd_im : CCDData instance containing synthetic 2D spectroscopic image Examples -------- This is an example of modeling a spectrograph whose output is curved in the cross-dispersion direction: .. plot:: :include-source: import matplotlib.pyplot as plt import numpy as np from astropy.modeling import models import astropy.units as u from specreduce.utils.synth_data import make_2d_arc_image model_deg2 = models.Legendre1D(degree=2, c0=50, c1=0, c2=100) im = make_2d_arc_image( linelists=['HeI', 'ArI', 'ArII'], line_fwhm=3, tilt_func=model_deg2 ) fig = plt.figure(figsize=(10, 6)) plt.imshow(im) The FITS WCS standard implements ideal world coordinate functions based on the physics of simple dispersers. This is described in detail by Paper III, https://www.aanda.org/articles/aa/pdf/2006/05/aa3818-05.pdf. This can be used to model a non-linear dispersion relation based on the properties of a spectrograph. This example recreates Figure 5 in that paper using a spectrograph with a 450 lines/mm volume phase holographic grism. Standard gratings only use the first three ``PV`` terms: .. plot:: :include-source: import numpy as np import matplotlib.pyplot as plt from astropy.wcs import WCS import astropy.units as u from specreduce.utils.synth_data import make_2d_arc_image non_linear_header = { 'CTYPE1': 'AWAV-GRA', # Grating dispersion function with air wavelengths 'CUNIT1': 'Angstrom', # Dispersion units 'CRPIX1': 719.8, # Reference pixel [pix] 'CRVAL1': 7245.2, # Reference value [Angstrom] 'CDELT1': 2.956, # Linear dispersion [Angstrom/pix] 'PV1_0': 4.5e5, # Grating density [1/m] 'PV1_1': 1, # Diffraction order 'PV1_2': 27.0, # Incident angle [deg] 'PV1_3': 1.765, # Reference refraction 'PV1_4': -1.077e6, # Refraction derivative [1/m] 'CTYPE2': 'PIXEL', # Spatial detector coordinates 'CUNIT2': 'pix', # Spatial units 'CRPIX2': 1, # Reference pixel 'CRVAL2': 0, # Reference value 'CDELT2': 1 # Spatial units per pixel } linear_header = { 'CTYPE1': 'AWAV', # Grating dispersion function with air wavelengths 'CUNIT1': 'Angstrom', # Dispersion units 'CRPIX1': 719.8, # Reference pixel [pix] 'CRVAL1': 7245.2, # Reference value [Angstrom] 'CDELT1': 2.956, # Linear dispersion [Angstrom/pix] 'CTYPE2': 'PIXEL', # Spatial detector coordinates 'CUNIT2': 'pix', # Spatial units 'CRPIX2': 1, # Reference pixel 'CRVAL2': 0, # Reference value 'CDELT2': 1 # Spatial units per pixel } non_linear_wcs = WCS(non_linear_header) linear_wcs = WCS(linear_header) # this re-creates Paper III, Figure 5 pix_array = 200 + np.arange(1400) nlin = non_linear_wcs.spectral.pixel_to_world(pix_array) lin = linear_wcs.spectral.pixel_to_world(pix_array) resid = (nlin - lin).to(u.Angstrom) plt.plot(pix_array, resid) plt.xlabel("Pixel") plt.ylabel("Correction (Angstrom)") plt.show() nlin_im = make_2d_arc_image( nx=600, ny=512, linelists=['HeI', 'NeI'], line_fwhm=3, wave_air=True, wcs=non_linear_wcs ) lin_im = make_2d_arc_image( nx=600, ny=512, linelists=['HeI', 'NeI'], line_fwhm=3, wave_air=True, wcs=linear_wcs ) # subtracting the linear simulation from the non-linear one shows how the # positions of lines diverge between the two cases plt.imshow(nlin_im.data - lin_im.data) plt.show() """ if wcs is None: if extent is None: raise ValueError("Must specify either a wavelength extent or a WCS.") if len(extent) != 2: raise ValueError("Wavelength extent must be of length 2.") if u.get_physical_type(wave_unit) != 'length': raise ValueError("Wavelength unit must be a length unit.") wcs = WCS(naxis=2) wcs.wcs.ctype[0] = 'WAVE' wcs.wcs.ctype[1] = 'PIXEL' wcs.wcs.cunit[0] = wave_unit wcs.wcs.cunit[1] = u.pixel wcs.wcs.crval[0] = extent[0] wcs.wcs.cdelt[0] = (extent[1] - extent[0]) / nx wcs.wcs.crval[1] = 0 wcs.wcs.cdelt[1] = 1 else: if wcs.spectral.naxis != 1: raise ValueError("Provided WCS must have a spectral axis.") if wcs.naxis != 2: raise ValueError("WCS must have NAXIS=2 for a 2D image.") x = np.arange(nx) y = np.arange(ny) xx, yy = np.meshgrid(x, y) is_spectral = [a['coordinate_type'] == "spectral" for a in wcs.get_axis_types()] if is_spectral[0]: disp_axis = 0 else: disp_axis = 1 if tilt_func is not None: if not isinstance( tilt_func, (models.Legendre1D, models.Chebyshev1D, models.Polynomial1D, models.Hermite1D) ): raise ValueError( "The only tilt functions currently supported are 1D polynomials " "from astropy.models." ) if disp_axis == 0: xx = xx + tilt_func((yy - ny/2)/ny) else: yy = yy + tilt_func((xx - nx/2)/nx) z = background + np.zeros((ny, nx)) linelist = load_pypeit_calibration_lines(linelists, wave_air=wave_air) if linelist is not None: line_disp_positions = wcs.spectral.world_to_pixel(linelist['wavelength']) line_sigma = gaussian_fwhm_to_sigma * line_fwhm for line_pos, ampl in zip(line_disp_positions, linelist['amplitude']): line_mod = models.Gaussian1D( amplitude=ampl * amplitude_scale, mean=line_pos, stddev=line_sigma ) if disp_axis == 0: z += line_mod(xx) else: z += line_mod(yy) if add_noise: from photutils.datasets import apply_poisson_noise arc_image = apply_poisson_noise(z) else: arc_image = z ccd_im = CCDData(arc_image, unit=u.count, wcs=wcs) return ccd_im def make_2d_spec_image( nx: int = 3000, ny: int = 1000, wcs: WCS | None = None, extent: Sequence[int | float] = (6500, 9500), wave_unit: u.Unit = u.Angstrom, wave_air: bool = False, background: int | float = 5, line_fwhm: float = 5., linelists: list[str] = ['OH_GMOS'], amplitude_scale: float = 1., tilt_func: Model = models.Legendre1D(degree=0), trace_center: int | float | None = None, trace_order: int = 3, trace_coeffs: dict[str, int | float] = {'c0': 0, 'c1': 50, 'c2': 100}, source_profile: Model = models.Moffat1D(amplitude=10, alpha=0.1), add_noise: bool = True ) -> CCDData: """ Make a synthetic 2D spectrum image containing both emission lines and a trace of a continuum source. Parameters ---------- nx : Number of pixels in the dispersion direction. ny : Number of pixels in the spatial direction. wcs : 2D WCS to apply to the image. Must have a spectral axis defined along with appropriate spectral wavelength units. extent : If ``wcs`` is not provided, this defines the beginning and end wavelengths of the dispersion axis. wave_unit : If ``wcs`` is not provided, this defines the wavelength units of the dispersion axis. wave_air : If True, convert the vacuum wavelengths used by ``pypeit`` to air wavelengths. background : Constant background level in counts. line_fwhm : Gaussian FWHM of the emission lines in pixels linelists : Specification for linelists to load from ``pypeit`` amplitude_scale : Scale factor to apply to amplitudes provided in the linelists tilt_func : The tilt function to apply along the cross-dispersion axis to simulate tilted or curved emission lines. trace_center : Zeropoint of the trace. If None, then use center of Y (spatial) axis. trace_order : Order of the Chebyshev polynomial used to model the source's trace trace_coeffs : Dict containing the Chebyshev polynomial coefficients to use in the trace model source_profile : Model to use for the source's spatial profile add_noise : If True, add Poisson noise to the image; requires ``photutils`` to be installed. Returns ------- ccd_im : CCDData instance containing synthetic 2D spectroscopic image """ arc_image = make_2d_arc_image( nx=nx, ny=ny, wcs=wcs, extent=extent, wave_unit=wave_unit, wave_air=wave_air, background=0, line_fwhm=line_fwhm, linelists=linelists, amplitude_scale=amplitude_scale, tilt_func=tilt_func, add_noise=False ) trace_image = make_2d_trace_image( nx=nx, ny=ny, background=0, trace_center=trace_center, trace_order=trace_order, trace_coeffs=trace_coeffs, profile=source_profile, add_noise=False ) spec_image = arc_image.data + trace_image.data + background if add_noise: from photutils.datasets import apply_poisson_noise spec_image = apply_poisson_noise(spec_image) ccd_im = CCDData(spec_image, unit=u.count, wcs=arc_image.wcs) return ccd_im ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/utils/utils.py0000644000175100001770000002365714635037352020265 0ustar00runnerdockerimport numpy as np from specreduce.core import _ImageParser from specreduce.tracing import Trace, FlatTrace from specreduce.extract import _ap_weight_image, _align_along_trace __all__ = ['measure_cross_dispersion_profile', '_align_along_trace'] def measure_cross_dispersion_profile(image, trace=None, crossdisp_axis=0, width=None, pixel=None, pixel_range=None, statistic='median', align_along_trace=True): """ Return a 1D (quantity) array of the cross-dispersion profile measured at a specified pixel value ('wavelength', but potentially before calibration), or the average profile across several pixel values (or range of pixel values) along the dispersion axis. If a single number is specified for `pixel`, then the profile at that pixel (i.e wavelength) will be returned. If several pixels are specified in a list or array, then they will be averaged (median or mean, set by `statistic` which defaults to median). Alternatively, `pixel_range` can be specified as a tuple of integers specifying the minimum and maximum pixel range to average the profile. `pixel` and `pixel_range` cannot be set simultaneously, and the default is `pixel_range`=(min_image, max_image) to return an average profile across the entire wavelength range of the image. The window in the cross dispersion axis for measuring the profile at the pixel(s) specified is determined by `width` and `trace`. If a trace is provided (either as a Trace object, or as a number specifying the location on the cross-dispersion axis of a FlatTrace object) that will determine the center of the profile on the cross-dispersion axis. Otherwise, if `trace` is None, the center of the image will be the center of the returned profile (i.e., the center row assuming a horizontal trace). If `width` is none, a window size of half the image in the cross-dispersion axis will be used to measure the cross dispersion profile. Otherwise, an integer value can be set for `width` which will determine the size of the window around the trace used to measure the profile (this window moves with the trace if trace is not flat). By default, if a non-flat trace is used the image will be aligned along the trace. This can be controlled with the 'align_along_trace' parameter. Parameters ---------- image : `~astropy.nddata.NDData`-like or array-like, required 2D image to measure cross-dispersion profile. trace : Trace object, int, float, or None A Trace object, a number to specify a FlatTrace, or None to use the middle of the image. This is the position that defines the center of the cross-dispersion profile. [default: None] crossdisp_axis : int, optional The index of the image's cross-dispersion axis. [default: 0] width : tuple of int or None Width around 'trace' to calculate profile. If None, then all rows in the cross-dispersion axis will be used. [default: None] pixel: int, list of int, or None Pixel value(s) along the dispersion axis to return cross-dispersion profile. If several specified in list, then the average (method set by `statistic`) profile will be calculated. If None, and `pixel_range` is set, then `pixel_range` will be used. [default: None] pixel_range: tuple of int or None Tuple of (min, max) defining the pixel range (along dispersion axis) to calculate average cross-dispersion profile, up to and not inclusive of max. If None, and `pixel` is not None, `pixel` will be used. If None and `pixel` is also None, this will be interpreted as using the entire dispersion axis to generate an average profile for the whole image. [default: None] statistic: 'median' or 'mean' If `pixel` specifies multiple pixels, or `pixel_range` is specified, an average profile will be returned. This can be either `median` (default) or `mean`. This is ignored if only one pixel is specified. [default: median] align_along_trace: bool Relevant only for non-flat traces. If True, "roll" each column so that the trace sits in the central row before calculating average profile. This will prevent any 'blurring' from averaging a non-flat trace at different pixel/wavelengths. [default: True] """ if crossdisp_axis != 0 and crossdisp_axis != 1: raise ValueError('`crossdisp_axis` must be 0 or 1.') crossdisp_axis = int(crossdisp_axis) disp_axis = 1 if crossdisp_axis == 0 else 0 unit = getattr(image, 'unit', None) # parse image, which will return a spectrum1D (note: this is not ideal, # but will be addressed at some point) parser = _ImageParser() image = parser._parse_image(image, disp_axis=disp_axis) # which we then need to make back into a masked array # again this way of parsing the image is not ideal but # thats just how it is for now. image = np.ma.MaskedArray(image.data, mask=image.mask) # transpose if disp_axis = 0 just for simplicity of calculations # image is already copied so this won't modify input if disp_axis == 0: image = image.T nrows = image.shape[crossdisp_axis] ncols = image.shape[disp_axis] if not isinstance(trace, Trace): # `trace` can be a trace obj if trace is None: # if None, make a FlatTrace in the center of image trace_pos = nrows / 2 trace = FlatTrace(image, trace_pos) elif isinstance(trace, (float, int)): # if float/int make a FlatTrace trace = FlatTrace(image, trace) else: raise ValueError('`trace` must be Trace object, number to specify ' 'the location of a FlatTrace, or None to use center' ' of image.') if statistic not in ['median', 'mean']: raise ValueError("`statistic` must be 'median' or 'mean'.") # determine if there is one pixel/wavelength selected or many as either a # list or a tuple to specify a range if pixel is not None: if pixel_range is not None: raise ValueError('Both `pixel` and `pixel_range` can not be set' ' simultaneously.') if isinstance(pixel, (int, float)): pixels = np.array([int(pixel)]) elif np.all([isinstance(x, (int, float)) for x in pixel]): pixels = np.array([int(x) for x in pixel]) else: raise ValueError('`pixels` must be an integer, or list of integers ' 'to specify where the crossdisperion profile should ' 'be measured.') else: # range is specified if pixel_range is None: pixels = np.arange(0, ncols) else: # if not None, it should be a lower and upper bound if len(pixel_range) != 2: raise ValueError('`pixel_range` must be a tuple of integers.') pixels = np.arange(min(pixel_range), max(pixel_range)) # now that we have all pixels that should be included in the profile, make # sure that they are within image bounds. # note: Should just warn instead and clip out out-of-bounds pixels, and only # warn if there are none left? if np.any(pixels < 0) or np.any(pixels > ncols - 1): raise ValueError('Pixels chosen to measure cross dispersion profile are' ' out of image bounds.') # now that we know which pixel(s) on the disp. axis we want to include # figure out the range/window of pixels along the crossdisp axis to measure # the profile if width is None: # if None, use all rows width = nrows elif isinstance(width, (float, int)): width = int(width) else: raise ValueError('`width` must be an integer, or None to use all ' 'cross-dispersion pixels.') width = int(width) # rectify trace, if _align_along_trace is True and trace is not flat aligned_trace = None if align_along_trace: if not isinstance(trace, FlatTrace): # note: img was transposed according to `crossdisp_axis`: disp_axis will always be 1 aligned_trace = _align_along_trace(image, trace.trace, disp_axis=1, crossdisp_axis=0) # new trace will be a flat trace at the center of the image trace_pos = nrows / 2 trace = FlatTrace(aligned_trace, trace_pos) # create a weight image based on the trace and 'width' to mask around trace if width == nrows: wimg = np.zeros(image.shape) else: wimg = _ap_weight_image(trace, width, disp_axis, crossdisp_axis, image.shape) # invert mask to include, not exclude, pixels around trace wimg = (1 - wimg).astype(int) # now that we have figured out the mask for the window in cross-disp. axis, # select only the pixel(s) we want to include in measuring the avg. profile pixel_mask = np.ones((image.shape)) pixel_mask[:, pixels] = 0 # combine these masks to isolate the rows and cols used to measure profile combined_mask = np.logical_or(pixel_mask, wimg) if aligned_trace is not None: masked_arr = np.ma.MaskedArray(aligned_trace, combined_mask) else: masked_arr = np.ma.MaskedArray(image.data, combined_mask) # and measure the cross dispersion profile. if multiple pixels/wavelengths, # this will be an average. we already transposed data based on disp_axis so # axis is always 1 for this calculation if statistic == 'mean': avg_prof = np.ma.mean(masked_arr, axis=1) else: # must be median, we already checked. avg_prof = np.ma.median(masked_arr, axis=1) # and get profile avg_prof = avg_prof.data[~avg_prof.mask] # and re-apply original unit, if there was one if unit is not None: avg_prof *= unit return avg_prof ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894323.0 specreduce-1.4.1/specreduce/version.py0000644000175100001770000000063314635037363017441 0ustar00runnerdocker# file generated by setuptools_scm # don't change, don't track in version control TYPE_CHECKING = False if TYPE_CHECKING: from typing import Tuple, Union VERSION_TUPLE = Tuple[Union[int, str], ...] else: VERSION_TUPLE = object version: str __version__: str __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE __version__ = version = '1.4.1' __version_tuple__ = version_tuple = (1, 4, 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/specreduce/wavelength_calibration.py0000644000175100001770000002547614635037352022501 0ustar00runnerdockerfrom functools import cached_property import numpy as np from astropy import units as u from astropy.modeling.fitting import LMLSQFitter, LinearLSQFitter from astropy.modeling.models import Linear1D from astropy.table import QTable, hstack from gwcs import coordinate_frames as cf from gwcs import wcs from specutils import Spectrum1D __all__ = [ 'WavelengthCalibration1D' ] def _check_arr_monotonic(arr): # returns True if ``arr`` is either strictly increasing or strictly # decreasing, otherwise returns False. sorted_increasing = np.all(arr[1:] >= arr[:-1]) sorted_decreasing = np.all(arr[1:] <= arr[:-1]) return sorted_increasing or sorted_decreasing class WavelengthCalibration1D(): def __init__(self, input_spectrum, matched_line_list=None, line_pixels=None, line_wavelengths=None, catalog=None, input_model=Linear1D(), fitter=None): """ input_spectrum: `~specutils.Spectrum1D` A one-dimensional Spectrum1D calibration spectrum from an arc lamp or similar. matched_line_list: `~astropy.table.QTable`, optional An `~astropy.table.QTable` table with (minimally) columns named "pixel_center" and "wavelength" with known corresponding line pixel centers and wavelengths populated. line_pixels: list, array, `~astropy.table.QTable`, optional List or array of line pixel locations to anchor the wavelength solution fit. Can also be input as an `~astropy.table.QTable` table with (minimally) a column named "pixel_center". line_wavelengths: `~astropy.units.Quantity`, `~astropy.table.QTable`, optional `astropy.units.Quantity` array of line wavelength values corresponding to the line pixels defined in ``line_list``, assumed to be in the same order. Can also be input as an `~astropy.table.QTable` with (minimally) a "wavelength" column. catalog: list, str, `~astropy.table.QTable`, optional The name of a catalog of line wavelengths to load and use in automated and template-matching line matching. NOTE: This option is currently not implemented. input_model: `~astropy.modeling.Model` The model to fit for the wavelength solution. Defaults to a linear model. fitter: `~astropy.modeling.fitting.Fitter`, optional The fitter to use in optimizing the model fit. Defaults to `~astropy.modeling.fitting.LinearLSQFitter` if the model to fit is linear or `~astropy.modeling.fitting.LMLSQFitter` if the model to fit is non-linear. Note that either ``matched_line_list`` or ``line_pixels`` must be specified, and if ``matched_line_list`` is not input, at least one of ``line_wavelengths`` or ``catalog`` must be specified. """ self._input_spectrum = input_spectrum self._input_model = input_model self._cached_properties = ['fitted_model', 'residuals', 'wcs'] self.fitter = fitter self._potential_wavelengths = None self._catalog = catalog if not isinstance(input_spectrum, Spectrum1D): raise ValueError('Input spectrum must be Spectrum1D.') # We use either line_pixels or matched_line_list to create self._matched_line_list, # and check that various requirements are fulfilled by the input args. if matched_line_list is not None: pixel_arg = "matched_line_list" if not isinstance(matched_line_list, QTable): raise ValueError("matched_line_list must be an astropy.table.QTable.") self._matched_line_list = matched_line_list elif line_pixels is not None: pixel_arg = "line_pixels" if isinstance(line_pixels, (list, np.ndarray)): self._matched_line_list = QTable([line_pixels], names=["pixel_center"]) elif isinstance(line_pixels, QTable): self._matched_line_list = line_pixels else: raise ValueError("Either matched_line_list or line_pixels must be specified.") if "pixel_center" not in self._matched_line_list.columns: raise ValueError(f"{pixel_arg} must have a 'pixel_center' column.") if self._matched_line_list["pixel_center"].unit is None: self._matched_line_list["pixel_center"].unit = u.pix # check that pixels are monotonic if not _check_arr_monotonic(self._matched_line_list["pixel_center"]): raise ValueError('Pixels must be strictly increasing or decreasing.') # now that pixels have been determined from input, figure out wavelengths. if (line_wavelengths is None and catalog is None and "wavelength" not in self._matched_line_list.columns): raise ValueError("You must specify at least one of line_wavelengths, " "catalog, or 'wavelength' column in matched_line_list.") # Sanity checks on line_wavelengths value if line_wavelengths is not None: if (isinstance(self._matched_line_list, QTable) and "wavelength" in self._matched_line_list.columns): raise ValueError("Cannot specify line_wavelengths separately if there is" " a 'wavelength' column in matched_line_list.") if len(line_wavelengths) != len(self._matched_line_list): raise ValueError("If line_wavelengths is specified, it must have the same " f"length as {pixel_arg}") if not isinstance(line_wavelengths, (u.Quantity, QTable)): raise ValueError("line_wavelengths must be specified as an astropy.units.Quantity" " array or as an astropy.table.QTable") # make sure wavelengths (or freq) are monotonic and add wavelengths # to _matched_line_list if isinstance(line_wavelengths, u.Quantity): if not _check_arr_monotonic(line_wavelengths): if str(line_wavelengths.unit.physical_type) == "frequency": raise ValueError('Frequencies must be strictly increasing or decreasing.') raise ValueError('Wavelengths must be strictly increasing or decreasing.') self._matched_line_list["wavelength"] = line_wavelengths elif isinstance(line_wavelengths, QTable): if not _check_arr_monotonic(line_wavelengths['wavelength']): raise ValueError('Wavelengths must be strictly increasing or decreasing.') self._matched_line_list = hstack([self._matched_line_list, line_wavelengths]) # Parse desired catalogs of lines for matching. if catalog is not None: # For now we avoid going into the later logic and just throw an error raise NotImplementedError("No catalogs are available yet, please input " "wavelengths with line_wavelengths or as a " f"column in {pixel_arg}") if isinstance(catalog, QTable): if "wavelength" not in catalog.columns: raise ValueError("Catalog table must have a 'wavelength' column.") self._catalog = catalog else: # This will need to be updated to match up with Tim's catalog code if isinstance(catalog, list): self._catalog = catalog else: self._catalog = [catalog] for cat in self._catalog: if isinstance(cat, str): if cat not in self._available_catalogs: raise ValueError(f"Line list '{cat}' is not an available catalog.") def identify_lines(self): """ ToDo: Code matching algorithm between line pixel locations and potential line wavelengths from catalogs. """ pass def _clear_cache(self, *attrs): """ provide convenience function to clearing the cache for cached_properties """ if not len(attrs): attrs = self._cached_properties for attr in attrs: if attr in self.__dict__: del self.__dict__[attr] @property def available_catalogs(self): return self._available_catalogs @property def input_spectrum(self): return self._input_spectrum @input_spectrum.setter def input_spectrum(self, new_spectrum): # We want to clear the refined locations if a new calibration spectrum is provided self._clear_cache() self._input_spectrum = new_spectrum @property def input_model(self): return self._input_model @input_model.setter def input_model(self, input_model): self._clear_cache() self._input_model = input_model @cached_property def fitted_model(self): # computes and returns WCS after fitting self.model to self.refined_pixels x = self._matched_line_list["pixel_center"] y = self._matched_line_list["wavelength"] if self.fitter is None: # Flexible defaulting if self.fitter is None if self.input_model.linear: fitter = LinearLSQFitter(calc_uncertainties=True) else: fitter = LMLSQFitter(calc_uncertainties=True) else: fitter = self.fitter # Fit the model return fitter(self.input_model, x, y) @cached_property def residuals(self): """ calculate fit residuals between matched line list pixel centers and wavelengths and the evaluated fit model. """ x = self._matched_line_list["pixel_center"] y = self._matched_line_list["wavelength"] # Get the fit residuals by evaulating model return y - self.fitted_model(x) @cached_property def wcs(self): # Build a GWCS pipeline from the fitted model pixel_frame = cf.CoordinateFrame(1, "SPECTRAL", [0,], axes_names=["x",], unit=[u.pix,]) spectral_frame = cf.SpectralFrame(axes_names=["wavelength",], unit=[self._matched_line_list["wavelength"].unit,]) pipeline = [(pixel_frame, self.fitted_model), (spectral_frame, None)] wcsobj = wcs.WCS(pipeline) return wcsobj def apply_to_spectrum(self, spectrum=None): # returns spectrum1d with wavelength calibration applied # actual line refinement and WCS solution should already be done so that this can # be called on multiple science sources spectrum = self.input_spectrum if spectrum is None else spectrum updated_spectrum = Spectrum1D(spectrum.flux, wcs=self.wcs, mask=spectrum.mask, uncertainty=spectrum.uncertainty) return updated_spectrum ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1718894324.1148734 specreduce-1.4.1/specreduce.egg-info/0000755000175100001770000000000014635037364017073 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894323.0 specreduce-1.4.1/specreduce.egg-info/PKG-INFO0000644000175100001770000000747114635037363020200 0ustar00runnerdockerMetadata-Version: 2.1 Name: specreduce Version: 1.4.1 Summary: Astropy coordinated package for Spectroscopic Reductions Author-email: Astropy Specreduce contributors License: Copyright (c) 2017, Astropy-specreduce Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Astropy Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Project-URL: Homepage, http://astropy.org/ Project-URL: Repository, https://github.com/astropy/specreduce.git Project-URL: Documentation, https://specreduce.readthedocs.io/ Requires-Python: >=3.10 Description-Content-Type: text/x-rst Requires-Dist: numpy Requires-Dist: astropy Requires-Dist: scipy Requires-Dist: specutils>=1.9.1 Requires-Dist: gwcs Provides-Extra: test Requires-Dist: pytest-astropy; extra == "test" Requires-Dist: photutils; extra == "test" Requires-Dist: tox; extra == "test" Provides-Extra: docs Requires-Dist: sphinx-astropy; extra == "docs" Requires-Dist: matplotlib; extra == "docs" Requires-Dist: photutils; extra == "docs" Requires-Dist: synphot; extra == "docs" Provides-Extra: all Requires-Dist: matplotlib; extra == "all" Requires-Dist: photutils; extra == "all" Requires-Dist: synphot; extra == "all" Specreduce ========== .. image:: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml/badge.svg?branch=main :target: https://github.com/astropy/specreduce/actions/workflows/tox-tests.yml :alt: CI Status .. image:: https://codecov.io/gh/astropy/specreduce/graph/badge.svg?token=3fLGjZ2Pe0 :target: https://codecov.io/gh/astropy/specreduce :alt: Coverage .. image:: https://readthedocs.org/projects/specreduce/badge/?version=latest :target: http://specreduce.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.6608787.svg :target: https://zenodo.org/doi/10.5281/zenodo.6608787 :alt: Zenodo DOI 10.5281/zenodo.6608787 .. image:: http://img.shields.io/badge/powered%20by-AstroPy-orange.svg?style=flat :target: http://www.astropy.org/ :alt: Powered by Astropy Specreduce is an Astropy coordinated package with the goal of providing a shared set of Python utilities that can be used to reduce and calibrate spectroscopic data. License ------- Specreduce is licensed under a 3-clause BSD style license. Please see the licenses/LICENSE.rst file. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894324.0 specreduce-1.4.1/specreduce.egg-info/SOURCES.txt0000644000175100001770000000417014635037364020761 0ustar00runnerdocker.flake8 .gitignore .readthedocs.yaml CHANGES.rst CITATION.cff MANIFEST.in README.rst conftest.py pyproject.toml tox.ini .github/workflows/cron-tests.yml .github/workflows/publish-to-pypi.yml .github/workflows/tox-tests.yml docs/Makefile docs/api.rst docs/atm_transmission_secz1.5_1.6mm.dat docs/conf.py docs/extinction.rst docs/extraction_quickstart.rst docs/index.rst docs/make.bat docs/specphot_standards.rst docs/terms.rst docs/wavelength_calibration.rst docs/_static/logo_icon.ico docs/_static/logo_icon.png docs/_static/specreduce.css docs/_templates/autosummary/base.rst docs/_templates/autosummary/class.rst docs/_templates/autosummary/module.rst docs/process/NIR_MOS_arc.odg docs/process/NIR_MOS_arc.svg docs/process/NIR_MOS_flat.odg docs/process/NIR_MOS_flat.svg docs/process/NIR_MOS_science.odg docs/process/NIR_MOS_science.svg docs/process/NIR_MOS_trace.odg docs/process/NIR_MOS_trace.svg docs/process/NIR_arcs.rst docs/process/NIR_flats.rst docs/process/NIR_science_data.rst docs/process/index.rst licenses/KOSMOS_LICENSE licenses/LICENSE.rst specreduce/__init__.py specreduce/background.py specreduce/calibration_data.py specreduce/conftest.py specreduce/core.py specreduce/extract.py specreduce/fluxcal.py specreduce/line_matching.py specreduce/table_utils.py specreduce/tracing.py specreduce/version.py specreduce/wavelength_calibration.py specreduce.egg-info/PKG-INFO specreduce.egg-info/SOURCES.txt specreduce.egg-info/dependency_links.txt specreduce.egg-info/requires.txt specreduce.egg-info/top_level.txt specreduce/tests/__init__.py specreduce/tests/test_background.py specreduce/tests/test_extinction.py specreduce/tests/test_extract.py specreduce/tests/test_get_reference_file_path.py specreduce/tests/test_image_parsing.py specreduce/tests/test_line_matching.py specreduce/tests/test_linelists.py specreduce/tests/test_specphot_stds.py specreduce/tests/test_synth_data.py specreduce/tests/test_tracing.py specreduce/tests/test_utils.py specreduce/tests/test_wavelength_calibration.py specreduce/tests/data/transposed_det_image_seq5_MIRIMAGE_P750Lexp1_s2d.fits specreduce/utils/__init__.py specreduce/utils/synth_data.py specreduce/utils/utils.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894323.0 specreduce-1.4.1/specreduce.egg-info/dependency_links.txt0000644000175100001770000000000114635037363023140 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894323.0 specreduce-1.4.1/specreduce.egg-info/requires.txt0000644000175100001770000000024714635037363021475 0ustar00runnerdockernumpy astropy scipy specutils>=1.9.1 gwcs [all] matplotlib photutils synphot [docs] sphinx-astropy matplotlib photutils synphot [test] pytest-astropy photutils tox ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894323.0 specreduce-1.4.1/specreduce.egg-info/top_level.txt0000644000175100001770000000005714635037363021626 0ustar00runnerdockerdist docs licenses notebook_sandbox specreduce ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1718894314.0 specreduce-1.4.1/tox.ini0000644000175100001770000000527314635037352014576 0ustar00runnerdocker[tox] envlist = py{310,311,312}-test{,-alldeps}{,-oldestdeps,-devdeps,-predeps}{,-cov} linkcheck codestyle [testenv] # Pass through the following environment variables which may be needed for the CI passenv = HOME,WINDIR,CI setenv = devdeps: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/astropy/simple https://pypi.anaconda.org/liberfa/simple https://pypi.anaconda.org/scientific-python-nightly-wheels/simple # Run the tests in a temporary directory to make sure that we don't import # this package from the source tree changedir = .tmp/{envname} # tox environments are constructed with so-called 'factors' (or terms) # separated by hyphens, e.g. test-devdeps-cov. Lines below starting with factor: # will only take effect if that factor is included in the environment name. To # see a list of example environments that can be run, along with a description, # run: # # tox -l -v # description = run tests alldeps: with optional dependencies oldestdeps: with the oldest supported version of key dependencies devdeps: with the latest developer version of key dependencies predeps: with pre-releases of key dependencies cov: with test coverage # The following provides some specific pinnings for key packages deps = devdeps: numpy>=0.0.dev0 devdeps: scipy>=0.0.dev0 devdeps: pyerfa>=0.0.dev0 devdeps: astropy>=0.0.dev0 devdeps: git+https://github.com/astropy/specutils.git#egg=specutils devdeps: git+https://github.com/astropy/photutils.git#egg=photutils devdeps: git+https://github.com/spacetelescope/synphot_refactor.git#egg=synphot oldestdeps: numpy==1.22.* oldestdeps: astropy==5.1.* oldestdeps: scipy==1.8.* oldestdeps: matplotlib==3.5.* oldestdeps: photutils==1.0.* oldestdeps: specutils==1.9.* # The following indicates which extras_require from setup.cfg will be installed extras = test alldeps: all install_command = !devdeps: python -I -m pip install # Force dev dependency with C-extension (synphot) to also build with numpy-dev devdeps: python -I -m pip install -v --pre commands = pip freeze !cov: pytest --pyargs specreduce {toxinidir}/docs {posargs} cov: pytest --pyargs specreduce {toxinidir}/docs --cov specreduce --cov-config={toxinidir}/pyproject.toml {posargs} cov: coverage xml -o {toxinidir}/coverage.xml pip_pre = predeps: true !predeps: false [testenv:linkcheck] changedir = docs description = check the links in the HTML docs extras = docs commands = pip freeze sphinx-build -W -b linkcheck . _build/html [testenv:codestyle] skip_install = true changedir = . description = check code style, e.g., with flake8 deps = flake8 commands = flake8 specreduce --count